Exemple #1
0
 public IRTCRtpSender AddTrack(IMediaStreamTrack track, IMediaStream stream) =>
 RTCRtpSender.Create(JsRuntime, JsRuntime.CallJsMethod <JsObjectRef>(NativeObject, "addTrack",
                                                                     new object[]
 {
     ((MediaStreamTrack)track).NativeObject,
     ((MediaStream)stream).NativeObject
 }));
Exemple #2
0
        void Peer_OnAddRemoteTrack(IMediaStreamTrack track)
        {
            Logger.Debug("MediaChannel", "@peer:remote_track:add");

            RunOnUiThread(() => {
                if (remoteTracksHolder.AddTrack(track))
                {
                    var streamId = streamIdChecker.GetStreamIdForTrackId(track.Id);

                    Logger.Debug("MediaChannel", $"streamId:{streamId}");

                    if (mediaOption.UpstreamIsRequired() &&
                        clientId == streamId)
                    {
                        Logger.Debug("MediaChannel", "ignore, this track is mine");
                        return;
                    }

                    if (track.Kind == "audio")
                    {
                        OnAddRemoteAudioTrack?.Invoke(track);
                    }
                    else if (track.Kind == "video")
                    {
                        OnAddRemoteVideoTrack?.Invoke(track);
                    }
                }
            });
        }
Exemple #3
0
        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs args)
        {
            base.OnElementPropertyChanged(sender, args);

            if (args.PropertyName == Media.StreamProperty.PropertyName)
            {
                _stream     = Element.Stream;
                _videoTrack = Element.Stream.GetVideoTracks().FirstOrDefault();
                _audioTrack = _stream.GetAudioTracks().FirstOrDefault();
                _mediaView.SetTrack(_videoTrack);
            }
            else if (args.PropertyName == Media.LabelProperty.PropertyName)
            {
                _label = Element.Label;
            }
            else if (args.PropertyName == Media.HangupProperty.PropertyName)
            {
                _hangup = Element.Hangup;
            }
            else if (args.PropertyName == Media.VideoMutedProperty.PropertyName)
            {
            }
            else if (args.PropertyName == Media.AudioMutedProperty.PropertyName)
            {
            }
            else if (args.PropertyName == Media.CameraTypeProperty.PropertyName)
            {
                _cameraType = Element.CameraType;
            }
            else if (args.PropertyName == Media.ShowControlsProperty.PropertyName)
            {
                _showControls = Element.ShowControls;
            }
        }
Exemple #4
0
        private void PeerConnection_OnTrack(IRTCTrackEvent Event)
        {
            if (Event.Track.Kind == "video")
            {
                _peerVideoTrack = Event.Track;

                if (_peerVideoTrack != null)
                {
                    _peerVideoTrack.Element = MediaElementMaker.Bind(Devices.Instance.PeerVideo);
                    ((MediaStreamTrack)_peerVideoTrack).OnFrameRateChanged += (float frameRate) =>
                    {
                        FramesPerSecondChanged?.Invoke("PEER", frameRate.ToString("0.0"));
                    };
                    ((MediaStreamTrack)_peerVideoTrack).OnResolutionChanged += (uint width, uint height) =>
                    {
                        ResolutionChanged?.Invoke("PEER", width, height);
                    };
                }
            }
            else if (Event.Track.Kind == "audio")
            {
                _peerAudioTrack = Event.Track;
            }

            OnAddRemoteTrack?.Invoke(Event.Track);
        }
Exemple #5
0
        public Task Shutdown()
        {
            if (this.peerConnection != null)
            {
                this.peerConnection.OnIceCandidate -= this.peerConnection_OnIceCandidate;
                this.peerConnection.OnTrack        -= this.peerConnection_OnTrack;

                if (this.remoteVideoTrack != null)
                {
                    this.remoteVideoTrack.Element = null;
                }
                if (this.localVideoTrack != null)
                {
                    this.localVideoTrack.Element = null;
                }

                (this.remoteVideoTrack as IDisposable)?.Dispose();
                (this.localVideoTrack as IDisposable)?.Dispose();
                (this.remoteAudioTrack as IDisposable)?.Dispose();
                (this.localAudioTrack as IDisposable)?.Dispose();

                this.remoteVideoTrack = null;
                this.localVideoTrack  = null;
                this.remoteAudioTrack = null;
                this.localAudioTrack  = null;

                (this.peerConnection as IDisposable)?.Dispose();
                this.peerConnection = null;

                GC.Collect();
            }

            return(Task.CompletedTask);
        }
Exemple #6
0
        public Task Shutdown()
        {
            foreach (RTCPeerConnection pc in this.peerConnections)
            {
                pc.OnIceCandidate -= this.peerConnection_OnIceCandidate;
                pc.OnTrack        -= this.peerConnection_OnTrack;
                (pc as IDisposable)?.Dispose();
            }

            this.peerConnections.Clear();

            if (this.remoteVideoTrack != null)
            {
                this.remoteVideoTrack.Element = null;
            }
            if (this.localVideoTrack != null)
            {
                this.localVideoTrack.Element = null;
            }

            (this.remoteVideoTrack as IDisposable)?.Dispose();
            (this.localVideoTrack as IDisposable)?.Dispose();
            (this.remoteAudioTrack as IDisposable)?.Dispose();
            (this.localAudioTrack as IDisposable)?.Dispose();

            this.remoteVideoTrack = null;
            this.localVideoTrack  = null;
            this.remoteAudioTrack = null;
            this.localAudioTrack  = null;

            GC.Collect();

            return(Task.CompletedTask);
        }
Exemple #7
0
        public void SetTrack(IMediaStreamTrack videoTrack)
        {
            var cameraDevices = Webrtc.RTCCameraVideoCapturer.CaptureDevices;

            _isCamera = cameraDevices.Any(device => device.ModelID == videoTrack.Id);

            var nativeVideoTrack = videoTrack.NativeObject as Webrtc.RTCVideoTrack;

            if (_isCamera)
            {
                _cameraView = new Webrtc.RTCCameraPreviewView();
                AddSubview(_cameraView);

                var nativeVideoSource = nativeVideoTrack.Source;
                /*var*/ _videoCapturer  = new Webrtc.RTCCameraVideoCapturer();
                _videoCapturer.Delegate = nativeVideoSource;

                var cameraDevice = Webrtc.RTCCameraVideoCapturer.CaptureDevices
                                   ////                .FirstOrDefault(device => device.Position == cameraType.ToNative());
                                   // Get the selected device by matching RTCMediaStreamTrack.TrackId with AVCaptureDevice.ModelID from
                                   // RTCCameraVideoCapturer.CaptureDevices list.
                                   .Single(device => device.ModelID == videoTrack.Id);

                var formats = Webrtc.RTCCameraVideoCapturer.SupportedFormatsForDevice(cameraDevice);
                System.Diagnostics.Debug.WriteLine($"============= Capture Formats =============== ");
                int index = 0;
                foreach (var f in formats)
                {
                    CMVideoFormatDescription desc = (CMVideoFormatDescription)f.FormatDescription;
                    var dim             = desc.Dimensions;
                    var maxSupportedFps = 0d;
                    foreach (var fpsRange in f.VideoSupportedFrameRateRanges)
                    {
                        maxSupportedFps = Math.Max(maxSupportedFps, fpsRange.MaxFrameRate);
                    }
                    System.Diagnostics.Debug.WriteLine($"index:{index++} width:{dim.Width} height:{dim.Height} fpsMax:{maxSupportedFps}");
                }


                var format = Webrtc.RTCCameraVideoCapturer.SupportedFormatsForDevice(cameraDevice)[6 /*0*/];
                CMVideoFormatDescription videoFormatDescription = (CMVideoFormatDescription)format.FormatDescription;
                var capturerDimensions = videoFormatDescription.Dimensions;
                var capturerSize       = new CGSize(capturerDimensions.Width, capturerDimensions.Height);
                var fps = 30;
                _videoCapturer.StartCaptureWithDevice(cameraDevice, format, fps);

                _cameraView.CaptureSession = _videoCapturer.CaptureSession;
            }
            else
            {
                _rendererView          = new Webrtc.RTCEAGLVideoView();
                _rendererView.Delegate = this;
                AddSubview(_rendererView);

                nativeVideoTrack.AddRenderer(_rendererView);
            }

            SetNeedsLayout();
        }
Exemple #8
0
        public IRtpTransceiver AddTransceiverWithTrack(IMediaStreamTrack track)
        {
            var rtpTransceiver = _peerConnection.AddTransceiverWithTrack(track.ToNative <RTCMediaStreamTrack>());

            if (rtpTransceiver == null)
            {
                return(null);
            }
            return(new RtpTransceiverNative(rtpTransceiver));
        }
Exemple #9
0
        public IRtpSender AddTrack(IMediaStreamTrack track, string[] streamIds)
        {
            var rtpSender = _peerConnection.AddTrack(track.ToNative <RTCMediaStreamTrack>(), streamIds);

            if (rtpSender == null)
            {
                return(null);
            }
            return(new RtpSenderNative(rtpSender));
        }
Exemple #10
0
 public static void SetNativeMediaSource(this IMediaStreamTrack track, Webrtc.MediaSource nativeSource)
 {
     if (_mediaSourceStore.ContainsKey(track.Id))
     {
         _mediaSourceStore[track.Id] = nativeSource;
     }
     else
     {
         _mediaSourceStore.Add(track.Id, nativeSource);
     }
 }
Exemple #11
0
        void Channel_OnRemoveRemoteVideoTrack(string trackId)
        {
            Sora.Logger.Debug("ViewModel", "Channel_OnRemoveRemoteVideo");

            if (remoteVideoTrack != null)
            {
                Sora.Logger.Debug("ViewModel", "try to unbound video from view");
                remoteVideoTrack.Element = null;
                remoteVideoTrack         = null;
                Sora.Logger.Debug("ViewModel", "unbound video from view");
            }
        }
Exemple #12
0
        public async Task ReplaceTrackAsync(IMediaStreamTrack track)
        {
            if (Closed)
            {
                // This must be done here. Otherwise there is no chance to stop the given track.
                if (track is not null && _stopTracks)
                {
                    try { track.Stop(); }
                    catch { }
                }
                throw new Exception("closed");
            }
            else if (track is not null && track.ReadyState == MediaStreamTrackState.Ended)
            {
                throw new Exception("track ended");
            }

            // Do nothing if this is the same track as the current handled one.
            if (track == Track)
            {
                Console.WriteLine("replaceTrack() | same track, ignored");
                return;
            }

            if (!_zeroRtpOnPause || !Paused)
            {
                await OnReplaceTrackAsync?.Invoke(this, track);
            }

            // Destroy the previous track.
            DestroyTrack();

            // Set the new track.
            Track = track;

            // If this Producer was paused/resumed and the state of the new
            // track does not match, fix it.
            if (Track is not null && _disableTrackOnPause)
            {
                if (!Paused)
                {
                    Track.Enabled = true;
                }
                else if (Paused)
                {
                    Track.Enabled = false;
                }
            }

            // Handle the effective track.
            HandleTrack();
        }
Exemple #13
0
        void Channel_OnAddRemoteAudioTrack(IMediaStreamTrack track)
        {
            Sora.Logger.Debug("ViewModel", "Channel_OnAddRemoteAudio");

            if (remoteAudioTrack != null)
            {
                Sora.Logger.Debug("ViewModel", "remote audio already exists");
                return;
            }

            remoteAudioTrack         = track;
            remoteAudioTrack.Enabled = true;
        }
Exemple #14
0
 public IRTCRtpTransceiver AddTransceiver(IMediaStreamTrack track, RTCRtpTransceiverInit init)
 {
     if (init is null)
     {
         return(RTCRtpTransceiver.Create(((Webrtc.RTCPeerConnection)NativeObject).AddTransceiverWithTrack(
                                             (Webrtc.RTCMediaStreamTrack)track.NativeObject)));
     }
     else
     {
         return(RTCRtpTransceiver.Create(((Webrtc.RTCPeerConnection)NativeObject).AddTransceiverWithTrack(
                                             (Webrtc.RTCMediaStreamTrack)track.NativeObject, init.ToNative())));
     }
 }
Exemple #15
0
        void Channel_OnAddLocalAudioTrack(IMediaStreamTrack track)
        {
            Sora.Logger.Debug("ViewModel", "Channel_OnAddLocalAudio");

            if (localAudioTrack != null)
            {
                Sora.Logger.Debug("ViewModel", "local audio already exists");
                return;
            }

            localAudioTrack         = track;
            localAudioTrack.Enabled = true;
        }
Exemple #16
0
        void Peer_OnAddLocalAudioTrack(IMediaStreamTrack track)
        {
            Logger.Debug("MediaChannel", "@peer:local_audio_track:add");

            if (localAudioTrack == null)
            {
                localAudioTrack = track;
            }

            RunOnUiThread(() => {
                OnAddLocalAudioTrack?.Invoke(track);
            });
        }
Exemple #17
0
        void Peer_OnAddLocalVideoTrack(IVideoCapturer capturer, IMediaStreamTrack track)
        {
            Logger.Debug("MediaChannel", "@peer:local_video_track:add");

            if (localVideoTrack == null)
            {
                localVideoTrack = track;
            }

            RunOnUiThread(() => {
                OnAddLocalVideoTrack?.Invoke(capturer, track);
            });
        }
Exemple #18
0
        void Channel_OnAddRemoteVideoTrack(IMediaStreamTrack track)
        {
            Sora.Logger.Debug("ViewModel", "Channel_OnAddRemoteVideo");

            // TODO check trackId
            if (remoteVideoTrack == null)
            {
                Sora.Logger.Debug("ViewModel", "try to bind video to view");
                remoteVideoTrack         = track;
                remoteVideoTrack.Element =
                    MediaElementMaker.Bind(RemoteVideoView);
                Sora.Logger.Debug("ViewModel", "bound video to view");
            }
        }
Exemple #19
0
        public void RemoveTrack(IMediaStreamTrack track)
        {
            switch (track.Kind)
            {
            case MediaStreamTrackKind.Video:
                ((Webrtc.MediaStream)NativeObject).RemoveTrack(track.NativeObject as Webrtc.VideoTrack);
                break;

            case MediaStreamTrackKind.Audio:
                ((Webrtc.MediaStream)NativeObject).RemoveTrack(track.NativeObject as Webrtc.AudioTrack);
                break;
            }
            ;
        }
Exemple #20
0
        private async Task <RTCPeerConnection> buildPeerConnection(MediaOptions mediaOptions)
        {
            return(await Task.Run(() =>
            {
                var factory = new WebRtcFactory(new WebRtcFactoryConfiguration());

                var peerConnection = new RTCPeerConnection(
                    new RTCConfiguration()
                {
                    Factory = factory,
                    BundlePolicy = RTCBundlePolicy.Balanced,
                    IceTransportPolicy = RTCIceTransportPolicy.All
                });

                peerConnection.OnTrack += this.peerConnection_OnTrack;

                if ((mediaOptions.SendVideo || mediaOptions.LocalLoopback) && this.localVideoTrack == null)
                {
                    if (mediaOptions.SendVideo || mediaOptions.LocalLoopback)
                    {
                        this.localVideoTrack = this.getLocalVideo(factory);
                    }
                }

                if (mediaOptions.SendAudio && this.localAudioTrack == null)
                {
                    if (mediaOptions.SendAudio)
                    {
                        this.localAudioTrack = this.getLocalAudio(factory);
                    }
                }

                if (mediaOptions.SendVideo)
                {
                    peerConnection.AddTrack(this.localVideoTrack);
                }
                if (mediaOptions.SendAudio)
                {
                    peerConnection.AddTrack(this.localAudioTrack);
                }

                if (mediaOptions.LocalLoopback)
                {
                    this.localVideoTrack.Element = MediaElementMaker.Bind(this.localVideo);
                }

                return peerConnection;
            }));
        }
Exemple #21
0
        public Task ReplaceOutgoingTrackAsync(IMediaStreamTrack track, IMediaStreamTrack newTrack)
        {
            foreach (var peerContext in _connectionContext.PeerContexts)
            {
                var peerConnection = peerContext.PeerConnection;
                peerConnection
                .GetSenders()
                //.Where(sender => sender.Track.Kind == MediaStreamTrackKind.Video)
                //.Select(sender => sender.ReplaceTrack(newVideoTrack));
                .First(sender => sender.Track.Kind == track.Kind)
                .ReplaceTrack(newTrack);
            }

            return(Task.CompletedTask);
        }
Exemple #22
0
        public bool AddTrack(IMediaStreamTrack track)
        {
            if (track.Kind == "audio" && !audioTracks.ContainsKey(track.Id))
            {
                audioTracks[track.Id] = track;
                return(true);
            }

            if (track.Kind == "video" && !videoTracks.ContainsKey(track.Id))
            {
                videoTracks[track.Id] = track;
                return(true);
            }
            return(false);
        }
Exemple #23
0
        public Consumer(string id, string localId, string producerId, IRTCRtpReceiver rtpReceiver,
                        IMediaStreamTrack track, RtpParameters rtpParameters, Dictionary <string, object> appData)
        {
            Id            = id;
            LocalId       = localId;
            ProducerId    = producerId;
            RtpReceiver   = rtpReceiver;
            Track         = track;
            RtpParameters = rtpParameters;
            AppData       = appData;
            Paused        = !track.Enabled;
            Closed        = false;

            HandleTrack();
        }
Exemple #24
0
        void Channel_OnAddLocalVideoTrack(
            IVideoCapturer capturer, IMediaStreamTrack track)
        {
            Sora.Logger.Debug("ViewModel", "Channel_OnAddLocalVideo");

            if (localVideoTrack != null)
            {
                Debug.WriteLine("local video track already exists");
                return;
            }

            localVideoTrack         = track;
            localVideoTrack.Enabled = true;
            localVideoTrack.Element =
                MediaElementMaker.Bind(LocalVideoView);
        }
Exemple #25
0
        public void RemoveTrack(IMediaStreamTrack track)
        {
            if (GetTrackById(track.Id) != null)
            {
                switch (track.Kind)
                {
                case MediaStreamTrackKind.Audio:
                    ((Webrtc.RTCMediaStream)NativeObject).RemoveAudioTrack((Webrtc.RTCAudioTrack)track.NativeObject);
                    break;

                case MediaStreamTrackKind.Video:
                    ((Webrtc.RTCMediaStream)NativeObject).RemoveVideoTrack((Webrtc.RTCVideoTrack)track.NativeObject);
                    break;
                }
            }
            ;
        }
Exemple #26
0
 private void peerConnection_OnTrack(IRTCTrackEvent ev)
 {
     if (ev.Track.Kind == "video")
     {
         this.remoteVideoTrack = ev.Track;
         if (this.mediaOptions.ReceiveVideo)
         {
             this.remoteVideoTrack.Element = MediaElementMaker.Bind(this.remoteVideo);
         }
     }
     else if (ev.Track.Kind == "audio")
     {
         if (this.mediaOptions.ReceiveAudio)
         {
             this.remoteAudioTrack = ev.Track;
         }
     }
 }
Exemple #27
0
        public Producer(string id, string localId, IRTCRtpSender rtpSender, IMediaStreamTrack track,
                        RtpParameters rtpParameters, bool stopTracks, bool disableTrackOnPause, bool zeroRtpOnPause,
                        Dictionary <string, object> appData)
        {
            Id                   = id;
            LocalId              = localId;
            RtpSender            = rtpSender;
            Track                = track;
            RtpParameters        = rtpParameters;
            _stopTracks          = stopTracks;
            _disableTrackOnPause = disableTrackOnPause;
            _zeroRtpOnPause      = zeroRtpOnPause;
            AppData              = appData;

            Kind   = track.Kind.ToMediaSoup();
            Paused = disableTrackOnPause ? !Track.Enabled : false;

            HandleTrack();
        }
Exemple #28
0
        void ClosePeer()
        {
            Logger.Debug("MediaChannel", "Close Peer");

            if (peer == null)
            {
                Logger.Debug("MediaChannel", "peer not found");
                return;
            }

            peer.OnConnect            -= Peer_OnConnect;
            peer.OnClose              -= Peer_OnClose;
            peer.OnError              -= Peer_OnError;
            peer.OnIceCandidate       -= Peer_OnIceCandidate;
            peer.OnAddLocalAudioTrack -= Peer_OnAddLocalAudioTrack;
            peer.OnAddLocalVideoTrack -= Peer_OnAddLocalVideoTrack;
            peer.OnAddRemoteTrack     -= Peer_OnAddRemoteTrack;
            peer.OnRemoveRemoteTrack  -= Peer_OnRemoveRemoteTrack;

            Logger.Debug("MediaChannel", "dispose local media tracks");

            if (localAudioTrack != null)
            {
                Logger.Debug("MediaChannel", "dispose local audio track");
                (localAudioTrack as IDisposable)?.Dispose();
                localAudioTrack = null;
            }

            if (localVideoTrack != null)
            {
                Logger.Debug("MediaChannel", "dispose local video track");
                (localVideoTrack as IDisposable)?.Dispose();
                localVideoTrack = null;
            }

            Logger.Debug("MediaChannel", "dispose remote media tracks");
            remoteTracksHolder.Dispose();

            Logger.Debug("MediaChannel", "Close Peer");
            peer.Close();

            peer = null;
        }
Exemple #29
0
        public void Stop()
        {
            if (mediaChannel == null)
            {
                Debug.WriteLine("media channel is already stopped");
                return;
            }

            mediaChannel.OnConnect                -= Channel_OnConnect;
            mediaChannel.OnDisconnect             -= Channel_OnDisconnect;
            mediaChannel.OnError                  -= Channel_OnError;
            mediaChannel.OnAddRemoteAudioTrack    -= Channel_OnAddRemoteAudioTrack;
            mediaChannel.OnRemoveRemoteAudioTrack -= Channel_OnRemoveRemoteAudioTrack;
            mediaChannel.OnAddRemoteVideoTrack    -= Channel_OnAddRemoteVideoTrack;
            mediaChannel.OnRemoveRemoteVideoTrack -= Channel_OnRemoveRemoteVideoTrack;
            mediaChannel.OnAddLocalVideoTrack     -= Channel_OnAddLocalVideoTrack;
            mediaChannel.OnAddLocalAudioTrack     -= Channel_OnAddLocalAudioTrack;

            localAudioTrack  = null;
            remoteAudioTrack = null;

            if (localVideoTrack != null)
            {
                localVideoTrack.Element = null;
                localVideoTrack         = null;
            }

            if (remoteVideoTrack != null)
            {
                remoteVideoTrack.Element = null;
                remoteVideoTrack         = null;
            }


            mediaChannel.Disconnect();
            mediaChannel = null;

            StateText    = "OFFLINE";
            IsRunning    = false;
            IsNotRunning = true;
        }
Exemple #30
0
        /// <summary>
        /// Closes a peer connection.
        /// </summary>
        public void ClosePeerConnection()
        {
            lock (MediaLock)
            {
                if (PeerConnection != null)
                {
                    _peerId = -1;

                    PeerConnection.OnIceCandidate -= PeerConnection_OnIceCandidate;
                    PeerConnection.OnTrack        -= PeerConnection_OnTrack;
                    PeerConnection.OnRemoveTrack  -= PeerConnection_OnRemoveTrack;

                    if (_peerVideoTrack != null)
                    {
                        _peerVideoTrack.Element = null;
                    }
                    if (_selfVideoTrack != null)
                    {
                        _selfVideoTrack.Element = null;
                    }

                    (_peerVideoTrack as IDisposable)?.Dispose();
                    (_peerAudioTrack as IDisposable)?.Dispose();
                    (_selfVideoTrack as IDisposable)?.Dispose();
                    (_selfAudioTrack as IDisposable)?.Dispose();

                    _peerVideoTrack = null;
                    _peerAudioTrack = null;
                    _selfVideoTrack = null;
                    _selfAudioTrack = null;

                    OnPeerConnectionClosed?.Invoke();

                    PeerConnection = null;

                    OnReadyToConnect?.Invoke();

                    GC.Collect(); // Ensure all references are truly dropped.
                }
            }
        }