Esempio n. 1
0
        private static async Task StartFfmpegListener(string sdpPath, CancellationToken cancel)
        {
            while (!File.Exists(FFMPEG_SDP_FILE) && !cancel.IsCancellationRequested)
            {
                await Task.Delay(500);
            }

            if (!cancel.IsCancellationRequested)
            {
                var sdp = SDP.ParseSDPDescription(File.ReadAllText(FFMPEG_SDP_FILE));

                // The SDP is only expected to contain a single video media announcement.
                var videoAnn = sdp.Media.Single(x => x.Media == SDPMediaTypesEnum.video);
                _ffmpegVideoFormat = videoAnn.MediaFormats.Values.First();

                _ffmpegListener = new RTPSession(false, false, false, IPAddress.Loopback, FFMPEG_DEFAULT_RTP_PORT);
                _ffmpegListener.AcceptRtpFromAny = true;
                MediaStreamTrack videoTrack = new MediaStreamTrack(SDPMediaTypesEnum.video, false, new List <SDPAudioVideoMediaFormat> {
                    _ffmpegVideoFormat
                }, MediaStreamStatusEnum.RecvOnly);
                _ffmpegListener.addTrack(videoTrack);

                _ffmpegListener.SetRemoteDescription(SIP.App.SdpType.answer, sdp);

                // Set a dummy destination end point or the RTP session will end up sending RTCP reports
                // to itself.
                var dummyIPEndPoint = new IPEndPoint(IPAddress.Loopback, 0);
                _ffmpegListener.SetDestination(SDPMediaTypesEnum.video, dummyIPEndPoint, dummyIPEndPoint);

                await _ffmpegListener.Start();
            }
        }
        public void NoMatchingMediaTest()
        {
            logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name);
            logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name);

            RTPSession       localSession    = new RTPSession(false, false, false);
            MediaStreamTrack localAudioTrack = new MediaStreamTrack(SDPMediaTypesEnum.audio, false, new List <SDPAudioVideoMediaFormat> {
                new SDPAudioVideoMediaFormat(SDPWellKnownMediaFormatsEnum.PCMU)
            });

            localSession.addTrack(localAudioTrack);

            RTPSession remoteSession = new RTPSession(false, false, false);
            // The track for the track for the remote session is still local relative to the session it's being added to.
            MediaStreamTrack remoteVideoTrack = new MediaStreamTrack(SDPMediaTypesEnum.video, false, new List <SDPAudioVideoMediaFormat> {
                new SDPAudioVideoMediaFormat(SDPMediaTypesEnum.video, 96, "VP8", 90000)
            });

            remoteSession.addTrack(remoteVideoTrack);

            var result = localSession.SetRemoteDescription(SIP.App.SdpType.offer, remoteSession.CreateOffer(IPAddress.Loopback));

            logger.LogDebug($"Set remote description on local session result {result}.");

            Assert.Equal(SetDescriptionResultEnum.NoMatchingMediaType, result);

            localSession.Close("normal");
            remoteSession.Close("normal");
        }
        public void NoLocalTracksTest()
        {
            logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name);
            logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name);

            // Create two RTP sessions. First one acts as the local session to generate the offer.
            // Second one acts as the remote session to generate the answer.

            // A local session is created but NO media tracks are added to it.
            RTPSession localSession = new RTPSession(false, false, false);

            // Create a remote session WITH an audio track.
            RTPSession remoteSession = new RTPSession(false, false, false);
            // The track for the track for the remote session is still local relative to the session it's being added to.
            MediaStreamTrack remoteAudioTrack = new MediaStreamTrack(SDPMediaTypesEnum.audio, false, new List <SDPAudioVideoMediaFormat> {
                new SDPAudioVideoMediaFormat(SDPWellKnownMediaFormatsEnum.PCMU)
            });

            remoteSession.addTrack(remoteAudioTrack);

            var offer = remoteSession.CreateOffer(IPAddress.Loopback);

            // Give the offer to the local session that is missing any media tracks.
            var result = localSession.SetRemoteDescription(SIP.App.SdpType.offer, offer);

            logger.LogDebug($"Set remote description on local session result {result}.");

            Assert.Equal(SetDescriptionResultEnum.NoMatchingMediaType, result);

            localSession.Close("normal");
            remoteSession.Close("normal");
        }
        public void CheckSelectedAudioForamtAttributeUnitTest()
        {
            logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name);
            logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name);

            string remoteSdp =
                @"v=0
o=- 1986548327 0 IN IP4 127.0.0.1
s=-
c=IN IP4 127.0.0.1
t=0 0
m=audio 60640 RTP/AVP 0 111 8
a=rtpmap:0 PCMU/8000
a=rtpmap:111 OPUS/48000/2";

            // Create a local session with an audio track.
            RTPSession       rtpSession      = new RTPSession(false, false, false);
            MediaStreamTrack localAudioTrack = new MediaStreamTrack(SDPWellKnownMediaFormatsEnum.PCMA, SDPWellKnownMediaFormatsEnum.G723);

            rtpSession.addTrack(localAudioTrack);

            var offer = SDP.ParseSDPDescription(remoteSdp);

            logger.LogDebug($"Remote offer: {offer}");

            var result = rtpSession.SetRemoteDescription(SIP.App.SdpType.offer, offer);

            logger.LogDebug($"Set remote description on local session result {result}.");

            Assert.Equal(SetDescriptionResultEnum.OK, result);
            Assert.Equal(8, rtpSession.AudioLocalTrack.Capabilities.Single(x => x.Name() == "PCMA").ID);
            Assert.Equal("PCMA", rtpSession.GetSendingFormat(SDPMediaTypesEnum.audio).Name());

            rtpSession.Close("normal");
        }
        public void MediaOrderMatchesRemoteOfferUnitTest()
        {
            logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name);
            logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name);

            // By default offers made by us always put audio first. Create a remote SDP offer
            // with the video first.
            string remoteSdp =
                @"v=0
o=- 1986548327 0 IN IP4 127.0.0.1
s=-
c=IN IP4 127.0.0.1
t=0 0
m=video 60638 RTP/AVP 100
a=rtpmap:100 VP8/90000
a=sendrecv
m=audio 60640 RTP/AVP 0 111
a=rtpmap:0 PCMU/8000
a=rtpmap:111 OPUS/48000/2
a=sendrecv";

            // Create a local session and add the video track first.
            RTPSession       rtpSession      = new RTPSession(false, false, false);
            MediaStreamTrack localAudioTrack = new MediaStreamTrack(SDPMediaTypesEnum.audio, false, new List <SDPAudioVideoMediaFormat> {
                new SDPAudioVideoMediaFormat(SDPWellKnownMediaFormatsEnum.PCMU),
                new SDPAudioVideoMediaFormat(SDPMediaTypesEnum.audio, 110, "OPUS/48000/2")
            });

            rtpSession.addTrack(localAudioTrack);
            MediaStreamTrack localVideoTrack = new MediaStreamTrack(SDPMediaTypesEnum.video, false, new List <SDPAudioVideoMediaFormat> {
                new SDPAudioVideoMediaFormat(SDPMediaTypesEnum.video, 96, "VP8", 90000)
            });

            rtpSession.addTrack(localVideoTrack);

            var offer = SDP.ParseSDPDescription(remoteSdp);

            logger.LogDebug($"Remote offer: {offer}");

            var result = rtpSession.SetRemoteDescription(SIP.App.SdpType.offer, offer);

            logger.LogDebug($"Set remote description on local session result {result}.");

            Assert.Equal(SetDescriptionResultEnum.OK, result);

            var answer = rtpSession.CreateAnswer(null);

            logger.LogDebug($"Local answer: {answer}");

            Assert.Equal(111, rtpSession.AudioLocalTrack.Capabilities.Single(x => x.Name() == "OPUS").ID);
            Assert.Equal(100, rtpSession.VideoLocalTrack.Capabilities.Single(x => x.Name() == "VP8").ID);

            //Assert.True(SDPAudioVideoMediaFormat.AreMatch(offer.Media.Single(x => x.Media == SDPMediaTypesEnum.audio)., answer.Media.First().Media));
            //Assert.Equal(offer.Media.Last().Media, answer.Media.Last().Media);

            rtpSession.Close("normal");
        }
        public void MediaOrderMatchesRemoteOfferUnitTest()
        {
            logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name);
            logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name);

            // By default offers made by us always put audio first. Create a remote SDP offer
            // with the video first.
            string remoteSdp =
                @"v=0
o=- 1986548327 0 IN IP4 127.0.0.1
s=-
c=IN IP4 127.0.0.1
t=0 0
m=video 60638 RTP/AVP 100
a=rtpmap:100 VP8/90000
a=sendrecv
m=audio 60640 RTP/AVP 0
a=rtpmap:0 PCMU/8000
a=sendrecv";

            // Create a local session and add the video track first.
            RTPSession       localSession    = new RTPSession(false, false, false);
            MediaStreamTrack localAudioTrack = new MediaStreamTrack(SDPMediaTypesEnum.audio, false, new List <SDPMediaFormat> {
                new SDPMediaFormat(SDPMediaFormatsEnum.PCMU)
            });

            localSession.addTrack(localAudioTrack);
            MediaStreamTrack localVideoTrack = new MediaStreamTrack(SDPMediaTypesEnum.video, false, new List <SDPMediaFormat> {
                new SDPMediaFormat(SDPMediaFormatsEnum.VP8)
            });

            localSession.addTrack(localVideoTrack);

            var offer = SDP.ParseSDPDescription(remoteSdp);

            logger.LogDebug($"Remote offer: {offer}");

            var result = localSession.SetRemoteDescription(SIP.App.SdpType.offer, offer);

            logger.LogDebug($"Set remote description on local session result {result}.");

            Assert.Equal(SetDescriptionResultEnum.OK, result);

            var answer = localSession.CreateAnswer(null);

            logger.LogDebug($"Local answer: {answer}");

            Assert.Equal(offer.Media.First().Media, answer.Media.First().Media);
            Assert.Equal(offer.Media.Last().Media, answer.Media.Last().Media);

            localSession.Close("normal");
        }
        public void AudioOnlyOfferAnswerTest()
        {
            logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name);
            logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name);

            // Create two RTP sessions. First one acts as the local session to generate the offer.
            // Second one acts as the remote session to generate the answer.

            RTPSession       localSession    = new RTPSession(false, false, false);
            MediaStreamTrack localAudioTrack = new MediaStreamTrack(SDPMediaTypesEnum.audio, false, new List <SDPAudioVideoMediaFormat> {
                new SDPAudioVideoMediaFormat(SDPWellKnownMediaFormatsEnum.PCMU)
            });

            localSession.addTrack(localAudioTrack);

            // Generate the offer to send to the remote party.
            var offer = localSession.CreateOffer(IPAddress.Loopback);

            logger.LogDebug("Local offer: " + offer.ToString());

            RTPSession remoteSession = new RTPSession(false, false, false);
            // The track for the track for the remote session is still local relative to the session it's being added to.
            MediaStreamTrack remoteAudioTrack = new MediaStreamTrack(SDPMediaTypesEnum.audio, false, new List <SDPAudioVideoMediaFormat> {
                new SDPAudioVideoMediaFormat(SDPWellKnownMediaFormatsEnum.PCMU)
            });

            remoteSession.addTrack(remoteAudioTrack);

            var result = remoteSession.SetRemoteDescription(SIP.App.SdpType.offer, offer);

            logger.LogDebug($"Set remote description on remote session result {result}.");

            Assert.Equal(SetDescriptionResultEnum.OK, result);

            // Get the answer from the remote session.
            var answer = remoteSession.CreateAnswer(IPAddress.Loopback);

            logger.LogDebug("Remote answer: " + offer.ToString());

            // Provide the answer back to the local session.
            result = localSession.SetRemoteDescription(SIP.App.SdpType.answer, answer);

            logger.LogDebug($"Set remote description on local session result {result}.");

            Assert.Equal(SetDescriptionResultEnum.OK, result);

            localSession.Close("normal");
            remoteSession.Close("normal");
        }
        public void AudioVideoOfferNoLocalAudioUnitTest()
        {
            logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name);
            logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name);

            // Create two RTP sessions. First one acts as the local session to generate the offer.
            // Second one acts as the remote session to generate the answer.

            // A local session is created but only has a video track added to it.
            RTPSession       localSession    = new RTPSession(false, false, false);
            MediaStreamTrack localVideoTrack = new MediaStreamTrack(SDPMediaTypesEnum.video, false, new List <SDPAudioVideoMediaFormat> {
                new SDPAudioVideoMediaFormat(SDPMediaTypesEnum.video, 96, "VP8", 90000)
            });

            localSession.addTrack(localVideoTrack);

            // Create a remote session with both audio and video tracks.
            RTPSession remoteSession = new RTPSession(false, false, false);
            // The track for the track for the remote session is still local relative to the session it's being added to.
            MediaStreamTrack remoteAudioTrack = new MediaStreamTrack(SDPMediaTypesEnum.audio, false, new List <SDPAudioVideoMediaFormat> {
                new SDPAudioVideoMediaFormat(SDPWellKnownMediaFormatsEnum.PCMU)
            });

            remoteSession.addTrack(remoteAudioTrack);
            MediaStreamTrack remoteVideoTrack = new MediaStreamTrack(SDPMediaTypesEnum.video, false, new List <SDPAudioVideoMediaFormat> {
                new SDPAudioVideoMediaFormat(SDPMediaTypesEnum.video, 96, "VP8", 90000)
            });

            remoteSession.addTrack(remoteVideoTrack);

            var offer = remoteSession.CreateOffer(IPAddress.Loopback);

            // Give the offer to the local session that is missing a video tracks.
            var result = localSession.SetRemoteDescription(SIP.App.SdpType.offer, offer);

            logger.LogDebug($"Set remote description on local session result {result}.");

            Assert.Equal(SetDescriptionResultEnum.OK, result);

            var answer = localSession.CreateAnswer(null);

            Assert.Equal(MediaStreamStatusEnum.Inactive, answer.Media.Where(x => x.Media == SDPMediaTypesEnum.audio).Single().MediaStreamStatus);
            Assert.Equal(MediaStreamStatusEnum.SendRecv, answer.Media.Where(x => x.Media == SDPMediaTypesEnum.video).Single().MediaStreamStatus);

            localSession.Close("normal");
            remoteSession.Close("normal");
        }
        public void ModifiedWellKnownFormatIDUnitTest()
        {
            logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name);
            logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name);

            string remoteSdp =
                @"v=0
o=- 1986548327 0 IN IP4 127.0.0.1
c=IN IP4 127.0.0.1
m=audio 60640 RTP/AVP 8 12
a=rtpmap:8 OPUS/48000/2
a=rtpmap:12 PCMA/8000";

            // Create a local session with an audio track.
            RTPSession       rtpSession      = new RTPSession(false, false, false);
            MediaStreamTrack localAudioTrack = new MediaStreamTrack(
                SDPWellKnownMediaFormatsEnum.PCMU,
                SDPWellKnownMediaFormatsEnum.PCMA,
                SDPWellKnownMediaFormatsEnum.G722);

            rtpSession.addTrack(localAudioTrack);

            var offer = SDP.ParseSDPDescription(remoteSdp);

            logger.LogDebug($"Remote offer: {offer}");

            var result = rtpSession.SetRemoteDescription(SIP.App.SdpType.offer, offer);

            logger.LogDebug($"Set remote description on local session result {result}.");

            Assert.Equal(SetDescriptionResultEnum.OK, result);
            Assert.Equal(12, rtpSession.AudioLocalTrack.Capabilities.Single(x => x.Name() == "PCMA").ID);
            Assert.Equal("PCMA", rtpSession.GetSendingFormat(SDPMediaTypesEnum.audio).Name());

            var answer = rtpSession.CreateAnswer(null);

            logger.LogDebug($"Local answer: {answer}");

            Assert.Equal(12, answer.Media.Single().MediaFormats.Single().Key);
            Assert.Equal("PCMA", answer.Media.Single().MediaFormats.Single().Value.Name());

            rtpSession.Close("normal");
        }
        public void SetRemoteSDPNoMediaStreamAttributeUnitTest()
        {
            logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name);
            logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name);

            string remoteSdp =
                @"v=0
o=- 1986548327 0 IN IP4 127.0.0.1
s=-
c=IN IP4 127.0.0.1
t=0 0
m=audio 60640 RTP/AVP 0 111
a=rtpmap:0 PCMU/8000
a=rtpmap:111 OPUS/48000/2";

            // Create a local session with an audio track.
            RTPSession       rtpSession      = new RTPSession(false, false, false);
            MediaStreamTrack localAudioTrack = new MediaStreamTrack(new AudioFormat(SDPWellKnownMediaFormatsEnum.PCMU));

            rtpSession.addTrack(localAudioTrack);

            var offer = SDP.ParseSDPDescription(remoteSdp);

            logger.LogDebug($"Remote offer: {offer}");

            var result = rtpSession.SetRemoteDescription(SIP.App.SdpType.offer, offer);

            logger.LogDebug($"Set remote description on local session result {result}.");

            Assert.Equal(SetDescriptionResultEnum.OK, result);

            var answer = rtpSession.CreateAnswer(null);

            logger.LogDebug($"Local answer: {answer}");

            Assert.Equal(0, rtpSession.AudioLocalTrack.Capabilities.Single(x => x.Name() == "PCMU").ID);
            Assert.Equal(MediaStreamStatusEnum.SendRecv, rtpSession.AudioLocalTrack.StreamStatus);
            Assert.NotNull(rtpSession.AudioRemoteTrack);
            Assert.Equal(MediaStreamStatusEnum.SendRecv, rtpSession.AudioRemoteTrack.StreamStatus);

            rtpSession.Close("normal");
        }
        public void NoRemoteMediaTest()
        {
            logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name);
            logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name);

            RTPSession       localSession    = new RTPSession(false, false, false);
            MediaStreamTrack localAudioTrack = new MediaStreamTrack(SDPMediaTypesEnum.audio, false, new List <SDPAudioVideoMediaFormat> {
                new SDPAudioVideoMediaFormat(SDPWellKnownMediaFormatsEnum.PCMU)
            });

            localSession.addTrack(localAudioTrack);

            var remoteOffer = new SDP();

            var result = localSession.SetRemoteDescription(SIP.App.SdpType.offer, remoteOffer);

            logger.LogDebug($"Set remote description on local session result {result}.");

            Assert.Equal(SetDescriptionResultEnum.NoRemoteMedia, result);

            localSession.Close("normal");
        }
        public void InvalidPortInRemoteOfferTest()
        {
            logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name);
            logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name);

            RTPSession       localSession    = new RTPSession(false, false, false);
            MediaStreamTrack localAudioTrack = new MediaStreamTrack(SDPMediaTypesEnum.audio, false, new List <SDPAudioVideoMediaFormat> {
                new SDPAudioVideoMediaFormat(SDPWellKnownMediaFormatsEnum.PCMU)
            });

            localSession.addTrack(localAudioTrack);

            var remoteOffer = new SDP();

            remoteOffer.SessionId = Crypto.GetRandomInt(5).ToString();

            remoteOffer.Connection = new SDPConnectionInformation(IPAddress.Loopback);

            SDPMediaAnnouncement audioAnnouncement = new SDPMediaAnnouncement(
                SDPMediaTypesEnum.audio,
                66000,
                new List <SDPAudioVideoMediaFormat> {
                new SDPAudioVideoMediaFormat(SDPWellKnownMediaFormatsEnum.PCMU)
            });

            audioAnnouncement.Transport = RTPSession.RTP_MEDIA_PROFILE;

            remoteOffer.Media.Add(audioAnnouncement);

            var result = localSession.SetRemoteDescription(SIP.App.SdpType.offer, remoteOffer);

            logger.LogDebug($"Set remote description on local session result {result}.");

            Assert.Null(localSession.AudioDestinationEndPoint);

            localSession.Close("normal");
        }