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"); }