Remote Peer

Remote Peer

Following are the static events in HuddleClient.These event gets invoked when any peer is added, leave or updateMetadata in the current room. Subscribe to this event to get the notification

public Dictionary<string, GameObject> RemotePeers => _remotePeers;
private Dictionary<string, GameObject> _remotePeers = new Dictionary<string, GameObject>();
 
private void SubscribeEvents() 
{
    HuddleClient.PeerAdded += OnPeerAdded;
    HuddleClient.PeerLeft += OnPeerLeft;
 
    HuddleClient.PeerMetadata += OnPeerMetadataUpdated;
}
 
private void UnSubscribeEvents()
{
    HuddleClient.PeerAdded -= OnPeerAdded;
    HuddleClient.PeerLeft -= OnPeerLeft;
 
    HuddleClient.PeerMetadata -= OnPeerMetadataUpdated;
}
 
 
private void OnPeerLeft(string peerId)
{
    if (peerId.Equals(_localPeerId)) 
    {
        return;
    }
 
    Destroy(_remotePeers[peerId]);
    _remotePeers.Remove(peerId);
}
 
private void OnPeerAdded(string peerId)
{
    if (peerId.Equals(_localPeerId))
    {
        return;
    }
 
    //instantiate remote peer prefab for webgl and for native
    GameObject tempRemotePeer = null;
#if !UNITY_WEBGL
    //Instantiate remote peer section for webgl
#else
    //Instantiate remote peer section for native
#endif
 
    _remotePeers[peerId] = tempRemotePeer;
    Debug.Log("Peer Added");
 
}
 
 private void OnPeerMetadataUpdated(string peerId)
{
    if (peerId.Equals(_localPeerId))
    {
        return;
    }
 
    Debug.Log($"Get metadata for {peerId}");
    string metadata =  _huddleClientInstance.GetMetadataOfRemotePeers(peerId);
    PeerMedataUpdate?.Invoke(peerId,JsonConvert.DeserializeObject<MetadataInfo>(metadata));
}

Remote Peer Section Component

To render video and audio from a remote peer, you can create RemotePeerSections for both WebGL and native platforms by extending the RemotePeerBase class. Below are examples for native platforms and WebGL separately.

RemotePeer Section for Native platforms

 
public class RemotePeerNative : RemotePeerBase
    {
        
#if !UNITY_WEBGL
 
        private VideoStreamTrack _videotrack;
 
        private GameObject _audioRef;
 
        public RemotePeer RemotePeer => _remotePeer;
        private RemotePeer _remotePeer;
 
        List<Tuple<Action<Consumer<Mediasoup.Types.AppData>, string>, Consumer<Mediasoup.Types.AppData>, string>> ConsumeTasks =
                            new List<Tuple<Action<Consumer<Mediasoup.Types.AppData>, string>, Consumer<Mediasoup.Types.AppData>, string>>();
        List<Tuple<Action<string, string>, string, string>> CloseConsumerTasks =
                                new List<Tuple<Action<string, string>, string, string>>();
 
 
        void Start()
        {
 
        }
 
        void Update()
        {
            while (ConsumeTasks.Count > 0)
            {
                ConsumeTasks[0].Item1.Invoke(ConsumeTasks[0].Item2, ConsumeTasks[0].Item3);
                ConsumeTasks.RemoveAt(0);
            }
 
            while (CloseConsumerTasks.Count > 0)
            {
                CloseConsumerTasks[0].Item1.Invoke(CloseConsumerTasks[0].Item2, CloseConsumerTasks[0].Item3);
                CloseConsumerTasks.RemoveAt(0);
            }
 
            if (_videotrack != null && _videotrack.ReadyState == TrackState.Live && _videotrack.Enabled)
            {
                Debug.Log($"tex format {_videotrack.Texture == null}");
 
                _videoTexture.texture = _videotrack.Texture;
            }
        }
 
        public override void Init(string remotePeerId)
        {
            base.Init(remotePeerId);
            _remotePeer = Room.Instance.GetRemotePeerById(remotePeerId);
 
            _remotePeer.On("stream-playable", async (arg) =>
            {
                Debug.Log("Play stream");
                try
                {
                    Consumer<Mediasoup.Types.AppData> consumer = arg[0] as Consumer<Mediasoup.Types.AppData>;
                    string label = arg[1] as string;
 
                    Debug.Log(consumer.track.ReadyState);
 
                    if (label.Equals("audio"))
                    {
                        var temp = new Tuple<Action<Consumer<Mediasoup.Types.AppData>, string>, Consumer<Mediasoup.Types.AppData>, string>(EnableAudio, consumer, label);
                        ConsumeTasks.Add(temp);
                    }
                    else if (label.Equals("video"))
                    {
                        var temp = new Tuple<Action<Consumer<Mediasoup.Types.AppData>, string>, Consumer<Mediasoup.Types.AppData>, string>(EnableVideo, consumer, label);
                        ConsumeTasks.Add(temp);
                    }
 
                }
                catch (Exception ex)
                {
                    Debug.LogError(ex);
                }
            });
 
            _remotePeer.On("stream-closed", async (arg) =>
            {
                Debug.Log("Close stream");
                var temp = new Tuple<Action<string, string>, string, string>(OnCloseTrack, arg[0] as string, arg[1] as string);
                CloseConsumerTasks.Add(temp);
            });
 
            Room.Instance.On("peer-left", async (arg) => DestroyThisObject());
 
        }
 
        public override void SetMetadata(MetadataInfo metadata)
        {
            _nameText.text = metadata.Name;
            base.SetMetadata(metadata);
        }
 
        public void EnableVideo(Consumer<Mediasoup.Types.AppData> consumer, string label)
        {
            Debug.Log("Play video stream");
            try
            {
                _videotrack = consumer.track as VideoStreamTrack;
                _videotrack.OnVideoReceived += (tex) =>
                {
                    Debug.Log($"tex format {tex.graphicsFormat}");
                    _videoTexture.texture = tex;
 
                };
                _videotrack.Enabled = true;
            }
            catch (Exception ex)
            {
                Debug.LogError($"Texture format issue {ex}");
            }
        }
 
        public void EnableAudio(Consumer<Mediasoup.Types.AppData> consumer, string label)
        {
            SetAudioSource(consumer.track);
            //_micStatus.color = Color.green;
        }
 
        private void SetAudioSource(MediaStreamTrack track)
        {
            try
            {
                _audioRef = new GameObject("AudioSource");
                _audioRef.transform.SetParent(this.transform);
                AudioSource aud = _audioRef.AddComponent<AudioSource>();
 
                AudioStreamTrack audioTrack = track as AudioStreamTrack;
 
                aud.SetTrack(audioTrack);
                aud.loop = true;
                aud.Play();
            }
            catch (Exception ex)
            {
                Debug.LogError($"Cant play audio {ex}");
            }
        }
 
        public void DisableVideo(string peerId)
        {
            _videotrack.OnVideoReceived -= (tex) => { _videoTexture.texture = tex; };
            _videotrack.Enabled = false;
            //_videoTexture.texture = _defaultTextureForVideo;
        }
 
        public void DisableAudio(string peerId)
        {
            Destroy(_audioRef);
            _audioRef = null;
            //_micStatus.color = Color.red;
        }
 
        public void OnCloseTrack(string label, string peerId)
        {
            if (label.Equals("audio"))
            {
                DisableAudio(peerId);
            }
 
            if (label.Equals("video"))
            {
                DisableVideo(peerId);
            }
        }
 
        protected override void PeerMetadataUpdated(string peerId, MetadataInfo metadata)
        {
            if (peerId.Equals(_remotePeer.PeerId)) 
            {
                _nameText.text = metadata.Name;
                base.PeerMetadataUpdated(peerId, metadata);
            }
 
        }
 
        public override void DestroyThisObject()
        {
            if (_audioRef!=null) 
            {
                AudioSource aud = _audioRef.AddComponent<AudioSource>();
                if (aud.isPlaying) 
                {
                    aud.Stop();
                }
            }
 
            base.DestroyThisObject();
        }
 
#endif
 
    }
 

RemotePeer Section for Webgl platform

 
public class RemotePeerWebgl : RemotePeerBase
    {
        public bool IsVideoPlaying => _isVideoPlaying;
        private bool _isVideoPlaying = false;
 
        private int m_TextureId = -1;
 
        public Texture2D Texture { get; private set; }
 
        private bool isVideoPlaying = false;
 
#if UNITY_WEBGL
 
        void Start()
        {
            GetNewTextureId();
        }
 
        void Update()
        {
            if (isVideoPlaying)
            {
                SetupTexture();
            }
        }
 
        public override void Init(string remotePeerId)
        {
            base.Init(remotePeerId);
        }
 
        public override void SetMetadata(MetadataInfo metadata)
        {
            _nameText.text = metadata.Name;
            base.SetMetadata(metadata);
        }
 
        public void GetNewTextureId()
        {
            m_TextureId = Huddle01JSNative.NewTexture();
        }
 
        public void SetupTexture()
        {
            if (Texture != null)
                UnityEngine.Object.Destroy(Texture);
            Texture = Texture2D.CreateExternalTexture(1280, 720, TextureFormat.RGBA32, false, true, (IntPtr)m_TextureId);
            _videoTexture.texture = Texture;
            
        }
 
        public void EnableVideo(string peerId) 
        {
            isVideoPlaying = true;
            Huddle01JSNative.AttachVideo(peerId, m_TextureId);
        }
 
        public void DisableVideo()
        {
            isVideoPlaying = false;
            _videoTexture.texture = _defaultTexture; 
        }
 
        public override void EnableAudio()
        {
            base.EnableAudio();
        }
 
        public override void DisableAudio()
        {
            base.DisableAudio();
        }
 
#endif
    }
 
Audio/Video Infrastructure designed for developers to empower them to ship simple yet powerful Audio/Video Apps.
support
company
Copyright © 2024 Graphene 01, Inc. All Rights Reserved.