public void ParsePionDataChannelOnlyOfferSDPUnitTest() { logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name); logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name); string sdpStr = @"v=0 o=- 87119400 1595185172 IN IP4 0.0.0.0 s=- t=0 0 a=fingerprint:sha-256 81:5C:47:85:9C:3D:CC:E6:B5:94:0B:3B:65:D5:39:1A:CD:8F:48:2D:78:0F:9F:0B:18:93:BF:C9:F6:C9:8E:F8 a=group:BUNDLE 0 m=application 9 DTLS/SCTP 5000 c=IN IP4 0.0.0.0 a=setup:active a=mid:0 a=sendrecv a=sctpmap:5000 webrtc-datachannel 1024"; SDP sdp = SDP.ParseSDPDescription(sdpStr); logger.LogDebug(sdp.ToString()); SDP rndTripSdp = SDP.ParseSDPDescription(sdp.ToString()); Assert.Equal("BUNDLE 0", rndTripSdp.Group); Assert.Single(rndTripSdp.Media); Assert.Equal("sha-256 81:5C:47:85:9C:3D:CC:E6:B5:94:0B:3B:65:D5:39:1A:CD:8F:48:2D:78:0F:9F:0B:18:93:BF:C9:F6:C9:8E:F8", rndTripSdp.DtlsFingerprint); Assert.Single(rndTripSdp.Media.Single().ApplicationMediaFormats); Assert.Equal(5000, rndTripSdp.Media.Single().SctpPort.Value); Assert.Equal(1024, rndTripSdp.Media.Single().MaxMessageSize); }
public void ParseMediaFormatWithHyphenNameUnitTest() { logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name); logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name); string sdpStr = @"v=0 o=- 1970544282 0 IN IP4 127.0.0.1 s=- c=IN IP4 10.10.1.8 t=0 0 m=audio 57982 RTP/AVP 0 8 a=rtpmap:0 PCMU/8000 a=rtpmap:8 PCMA/8000 a=sendrecv m=video 57984 RTP/AVP 96 a=rtpmap:96 H263-1998/90000 a=fmtp:96 QCIF=3 a=sendrecv"; SDP sdp = SDP.ParseSDPDescription(sdpStr); logger.LogDebug(sdp.ToString()); SDP rndTripSdp = SDP.ParseSDPDescription(sdp.ToString()); Assert.Equal(96, rndTripSdp.Media.Where(x => x.Media == SDPMediaTypesEnum.video).Single().MediaFormats.Single().Key); Assert.Equal("H263-1998", rndTripSdp.Media.Where(x => x.Media == SDPMediaTypesEnum.video).Single().MediaFormats.Single().Value.Name()); }
public void ParseSDPUnitTest() { logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name); logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name); string sdpStr = "v=0" + m_CRLF + "o=root 3285 3285 IN IP4 10.0.0.4" + m_CRLF + "s=session" + m_CRLF + "c=IN IP4 10.0.0.4" + m_CRLF + "t=0 0" + m_CRLF + "m=audio 12228 RTP/AVP 0 101" + m_CRLF + "a=rtpmap:0 PCMU/8000" + m_CRLF + "a=rtpmap:101 telephone-event/8000" + m_CRLF + "a=fmtp:101 0-16" + m_CRLF + "a=silenceSupp:off - - - -" + m_CRLF + "a=ptime:20" + m_CRLF + "a=sendrecv"; SDP sdp = SDP.ParseSDPDescription(sdpStr); logger.LogDebug(sdp.ToString()); Assert.True(sdp.Connection.ConnectionAddress == "10.0.0.4", "The connection address was not parsed correctly."); Assert.True(sdp.Media[0].Media == SDPMediaTypesEnum.audio, "The media type not parsed correctly."); Assert.True(sdp.Media[0].Port == 12228, "The connection port was not parsed correctly."); Assert.True(sdp.Media[0].GetFormatListToString() == "0 101", "The media format list was incorrect."); Assert.True(sdp.Media[0].MediaFormats[0].ID == 0, "The highest priority media format ID was incorrect."); Assert.True(sdp.Media[0].MediaFormats[0].Name() == "PCMU", "The highest priority media format name was incorrect."); Assert.Equal(SDPWellKnownMediaFormatsEnum.PCMU.ToString(), sdp.Media[0].MediaFormats[0].Name()); Assert.True(sdp.Media[0].MediaFormats[0].Rtpmap == "PCMU/8000", "The highest priority media format rtpmap was incorrect."); }
public void ParseBriaSDPUnitTest() { logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name); logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name); string sdpStr = "v=0" + "o=- 5 2 IN IP4 10.1.1.2" + m_CRLF + "s=CounterPath Bria" + m_CRLF + "c=IN IP4 144.137.16.240" + m_CRLF + "t=0 0" + m_CRLF + "m=audio 34640 RTP/AVP 0 8 101" + m_CRLF + "a=sendrecv" + m_CRLF + "a=rtpmap:101 telephone-event/8000" + m_CRLF + "a=fmtp:101 0-15" + m_CRLF + "a=alt:1 1 : STu/ZtOu 7hiLQmUp 10.1.1.2 34640"; SDP sdp = SDP.ParseSDPDescription(sdpStr); logger.LogDebug(sdp.ToString()); Assert.True(sdp.Connection.ConnectionAddress == "144.137.16.240", "The connection address was not parsed correctly."); Assert.True(sdp.Media[0].Port == 34640, "The connection port was not parsed correctly."); Assert.True(sdp.Media[0].MediaFormats[0].Name() == "PCMU", "The highest priority media format name was incorrect."); Assert.Equal(SDPWellKnownMediaFormatsEnum.PCMU.ToString(), sdp.Media[0].MediaFormats[0].Name()); }
public void ParseMcpttTest() { logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name); logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name); string sdpStr = @"v=0 o=root 5936658357711814578 0 IN IP4 0.0.0.0 s=- t=0 0 m=audio 55316 RTP/AVP 0 101 a=rtpmap:0 PCMU/8000 a=label:1 a=rtpmap:101 telephone-event/8000 a=fmtp:101 0-15 a=ptime:20 a=sendrecv m=application 55317 udp MCPTT a=fmtp:MCPTT mc_queueing;mc_priority=4"; SDP sdp = SDP.ParseSDPDescription(sdpStr); logger.LogDebug(sdp.ToString()); SDP rndTripSdp = SDP.ParseSDPDescription(sdp.ToString()); Assert.Equal("MCPTT", rndTripSdp.Media.Where(x => x.Media == SDPMediaTypesEnum.application).Single().ApplicationMediaFormats.Single().Key); Assert.Equal("mc_queueing;mc_priority=4", rndTripSdp.Media.Where(x => x.Media == SDPMediaTypesEnum.application).Single().ApplicationMediaFormats.Single().Value.Fmtp); }
public void TIASBandwidthAttributeRoundTripTest() { logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name); logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name); string sdpStr = @"v=0 o=root 5936658357711814578 0 IN IP4 0.0.0.0 s=- t=0 0 m=audio 55316 RTP/AVP 0 101 a=rtpmap:0 PCMU/8000 a=label:1 a=rtpmap:101 telephone-event/8000 a=fmtp:101 0-15 a=ptime:20 a=sendrecv m=video 61682 UDP/TLS/RTP/SAVPF 96 c=IN IP4 192.168.11.50 b=TIAS:256000 a=rtpmap:96 VP8/90000 a=label:2 a=sendrecv "; SDP sdp = SDP.ParseSDPDescription(sdpStr); logger.LogDebug(sdp.ToString()); SDP rndTripSdp = SDP.ParseSDPDescription(sdp.ToString()); Assert.Equal(256000U, rndTripSdp.Media.Where(x => x.Media == SDPMediaTypesEnum.video).Single().TIASBandwidth); }
public void ParseOfferWithFmtpPreceedingRtmapTest() { logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name); logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name); string sdpStr = @"v=0 o=mozilla...THIS_IS_SDPARTA-80.0.1 5936658357711814578 0 IN IP4 0.0.0.0 s=- t=0 0 a=sendrecv a=fingerprint:sha-256 46:7C:4B:FD:47:E1:22:16:28:FC:52:94:C8:9D:7D:24:2F:C3:A8:66:02:17:0D:41:DF:34:99:1C:48:CB:9F:D5 a=group:BUNDLE 0 a=ice-options:trickle a=msid-semantic:WMS * m=video 9 UDP/TLS/RTP/SAVP 96 c=IN IP4 0.0.0.0 a=recvonly a=fmtp:96 max-fs=12288;max-fr=60 a=ice-pwd:8136ef42e22d9d6b31d23b39a662bf8d a=ice-ufrag:2cbeec1e a=mid:0 a=rtcp-mux a=rtpmap:96 VP8/90000 a=setup:active a=ssrc:2404235415 cname:{7c06c5db-d3db-4891-b729-df4919014c3f}"; SDP sdp = SDP.ParseSDPDescription(sdpStr); Assert.Equal(96, sdp.Media.Where(x => x.Media == SDPMediaTypesEnum.video).Single().MediaFormats.Single().Key); Assert.Equal("VP8", sdp.Media.Where(x => x.Media == SDPMediaTypesEnum.video).Single().MediaFormats.Single().Value.Name()); Assert.Equal("VP8/90000", sdp.Media.Where(x => x.Media == SDPMediaTypesEnum.video).Single().MediaFormats.Single().Value.Rtpmap); Assert.Equal("max-fs=12288;max-fr=60", sdp.Media.Where(x => x.Media == SDPMediaTypesEnum.video).Single().MediaFormats.Single().Value.Fmtp); }
private static void SDPAnswerReceived(WebRtcSession webRtcSession, string sdpAnswer) { try { logger.LogDebug("Answer SDP: " + sdpAnswer); var answerSDP = SDP.ParseSDPDescription(sdpAnswer); webRtcSession.SdpSessionID = answerSDP.SessionId; webRtcSession.RemoteIceUser = answerSDP.IceUfrag; webRtcSession.RemoteIcePassword = answerSDP.IcePwd; // All browsers seem to have gone to trickling ICE candidates now but just // in case one or more are given we can start the STUN dance immediately. if (answerSDP.IceCandidates != null) { foreach (var iceCandidate in answerSDP.IceCandidates) { webRtcSession.AppendRemoteIceCandidate(iceCandidate); } } OnMediaSampleReady += webRtcSession.SendMedia; if (_mfSampleGrabber.Paused) { _mfSampleGrabber.Start(); } } catch (Exception excp) { logger.LogError("Exception SDPAnswerReceived. " + excp.Message); } }
private static async void MessageReceived(WebSocketContext context, string msg) { //Console.WriteLine($"websocket recv: {msg}"); var offerSDP = SDP.ParseSDPDescription(msg); Console.WriteLine($"offer sdp: {offerSDP}"); var webRtcSession = new WebRtcSession( AddressFamily.InterNetwork, DTLS_CERTIFICATE_FINGERPRINT, null, null); webRtcSession.setRemoteDescription(new RTCSessionDescription { sdp = offerSDP, type = RTCSdpType.offer }); webRtcSession.OnReceiveReport += RtpSession_OnReceiveReport; webRtcSession.OnSendReport += RtpSession_OnSendReport; webRtcSession.OnRtpPacketReceived += RtpSession_OnRtpPacketReceived; webRtcSession.OnClose += (reason) => { Console.WriteLine($"webrtc session closed: {reason}"); _webRtcSessions.Remove(webRtcSession); }; // Add local recvonly tracks. This ensures that the SDP answer includes only // the codecs we support. MediaStreamTrack audioTrack = new MediaStreamTrack(null, SDPMediaTypesEnum.audio, false, new List <SDPMediaFormat> { new SDPMediaFormat(SDPMediaFormatsEnum.PCMU) }); audioTrack.Transceiver.SetStreamStatus(MediaStreamStatusEnum.RecvOnly); webRtcSession.addTrack(audioTrack); MediaStreamTrack videoTrack = new MediaStreamTrack(null, SDPMediaTypesEnum.video, false, new List <SDPMediaFormat> { new SDPMediaFormat(SDPMediaFormatsEnum.VP8) }); videoTrack.Transceiver.SetStreamStatus(MediaStreamStatusEnum.RecvOnly); webRtcSession.addTrack(videoTrack); var answerSdp = await webRtcSession.createAnswer(); webRtcSession.setLocalDescription(new RTCSessionDescription { sdp = answerSdp, type = RTCSdpType.answer }); Console.WriteLine($"answer sdp: {answerSdp}"); context.WebSocket.Send(answerSdp.ToString()); if (DoDtlsHandshake(webRtcSession)) { _webRtcSessions.Add(webRtcSession); } else { webRtcSession.Close("dtls handshake failed."); } }
public void ParseMediaFormatWithFowardSlashUnitTest() { logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name); logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name); string sdpStr = @"v=0 o=- 1970544282 0 IN IP4 127.0.0.1 s=- c=IN IP4 10.10.1.8 t=0 0 m=audio 57982 RTP/AVP 111 a=rtpmap:111 opus/48000/2 a=fmtp:111 minptime=10;useinbandfec=1 a=sendrecv"; SDP sdp = SDP.ParseSDPDescription(sdpStr); logger.LogDebug(sdp.ToString()); SDP rndTripSdp = SDP.ParseSDPDescription(sdp.ToString()); Assert.Equal(111, rndTripSdp.Media.Where(x => x.Media == SDPMediaTypesEnum.audio).Single().MediaFormats.Single().Key); Assert.Equal("opus", rndTripSdp.Media.Where(x => x.Media == SDPMediaTypesEnum.audio).Single().MediaFormats.Single().Value.Name()); }
public void GenerateLocalOfferWithAudioTrackUnitTest() { logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name); logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name); RTCPeerConnection pc = new RTCPeerConnection(null); pc.IceSession.StartGathering(); var audioTrack = new MediaStreamTrack(null, SDPMediaTypesEnum.audio, false, new List <SDPMediaFormat> { new SDPMediaFormat(SDPMediaFormatsEnum.PCMU) }); pc.addTrack(audioTrack); var offer = pc.createOffer(new RTCOfferOptions()); SDP offerSDP = SDP.ParseSDPDescription(offer.sdp); Assert.NotNull(offer); Assert.NotNull(offer.sdp); Assert.Equal(RTCSdpType.offer, offer.type); Assert.Single(offerSDP.Media); Assert.Contains(offerSDP.Media, x => x.Media == SDPMediaTypesEnum.audio); logger.LogDebug(offer.sdp); }
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 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"); }
/// <summary> /// Answers an incoming SIP call. /// </summary> public async Task <bool> Answer() { if (m_pendingIncomingCall == null) { StatusMessage(this, $"There was no pending call available to answer."); return(false); } else { var sipRequest = m_pendingIncomingCall.ClientTransaction.TransactionRequest; // Assume that if the INVITE request does not contain an SDP offer that it will be an // audio only call. bool hasAudio = true; bool hasVideo = false; if (sipRequest.Body != null) { SDP offerSDP = SDP.ParseSDPDescription(sipRequest.Body); hasAudio = offerSDP.Media.Any(x => x.Media == SDPMediaTypesEnum.audio && x.MediaStreamStatus != MediaStreamStatusEnum.Inactive); hasVideo = offerSDP.Media.Any(x => x.Media == SDPMediaTypesEnum.video && x.MediaStreamStatus != MediaStreamStatusEnum.Inactive); } MediaSession = CreateMediaSession(); m_userAgent.RemotePutOnHold += OnRemotePutOnHold; m_userAgent.RemoteTookOffHold += OnRemoteTookOffHold; bool result = await m_userAgent.Answer(m_pendingIncomingCall, MediaSession); m_pendingIncomingCall = null; return(result); } }
public void ParseICESessionAttributesUnitTest() { Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().Name); string sdpStr = "v=0" + m_CRLF + "o=jdoe 2890844526 2890842807 IN IP4 10.0.1.1" + m_CRLF + "s=" + m_CRLF + "c=IN IP4 192.0.2.3" + m_CRLF + "t=0 0" + m_CRLF + "a=ice-pwd:asd88fgpdd777uzjYhagZg" + m_CRLF + "a=ice-ufrag:8hhY" + m_CRLF + "m=audio 45664 RTP/AVP 0" + m_CRLF + "b=RS:0" + m_CRLF + "b=RR:0" + m_CRLF + "a=rtpmap:0 PCMU/8000" + m_CRLF + "a=candidate:1 1 UDP 2130706431 10.0.1.1 8998 typ host" + m_CRLF + "a=candidate:2 1 UDP 1694498815 192.0.2.3 45664 typ srflx raddr 10.0.1.1 rport 8998"; SDP sdp = SDP.ParseSDPDescription(sdpStr); Debug.WriteLine(sdp.ToString()); Assert.IsTrue(sdp.IceUfrag == "8hhY", "The ICE username was not parsed correctly."); Assert.IsTrue(sdp.IcePwd == "asd88fgpdd777uzjYhagZg", "The ICE password was not parsed correctly."); }
private void WebRtcAnswerReceived(WebSocketSharp.Net.WebSockets.WebSocketContext context, string webSocketID, string sdpAnswer) { try { logger.LogDebug("Answer SDP: " + sdpAnswer); var answerSDP = SDP.ParseSDPDescription(sdpAnswer); var conn = _webRtcConnections.Where(x => x.Key == webSocketID).Select(x => x.Value).SingleOrDefault(); if (conn.WebRtcSession == null) { logger.LogWarning("No WebRTC client entry exists for web socket ID " + webSocketID + ", ignoring."); } else { logger.LogDebug("New WebRTC client SDP answer for web socket ID " + webSocketID + "."); conn.WebRtcSession.setRemoteDescription(SdpType.answer, answerSDP); } context.WebSocket.CloseAsync(); } catch (Exception excp) { logger.LogError("Exception WebRtcAnswerReceived. " + excp.Message); } }
private static async Task WebSocketMessageReceived(WebSocketContext context, RTCPeerConnection pc, string message) { try { if (pc.localDescription == null) { //logger.LogDebug("Offer SDP: " + message); logger.LogDebug("Offer SDP received."); // Add local media tracks depending on what was offered. Also add local tracks with the same media ID as // the remote tracks so that the media announcement in the SDP answer are in the same order. SDP remoteSdp = SDP.ParseSDPDescription(message); var res = pc.setRemoteDescription(new RTCSessionDescriptionInit { sdp = message, type = RTCSdpType.offer }); if (res != SetDescriptionResultEnum.OK) { // No point continuing. Something will need to change and then try again. pc.Close("failed to set remote sdp"); } else { var answer = pc.createAnswer(null); await pc.setLocalDescription(answer); context.WebSocket.Send(answer.sdp); } } else if (pc.remoteDescription == null) { logger.LogDebug("Answer SDP: " + message); var res = pc.setRemoteDescription(new RTCSessionDescriptionInit { sdp = message, type = RTCSdpType.answer }); if (res != SetDescriptionResultEnum.OK) { // No point continuing. Something will need to change and then try again. pc.Close("failed to set remote sdp"); } } else { logger.LogDebug("ICE Candidate: " + message); if (string.IsNullOrWhiteSpace(message) || message.Trim().ToLower() == SDP.END_ICE_CANDIDATES_ATTRIBUTE) { logger.LogDebug("End of candidates message received."); } else { var candInit = Newtonsoft.Json.JsonConvert.DeserializeObject <RTCIceCandidateInit>(message); pc.addIceCandidate(candInit); } } } catch (Exception excp) { logger.LogError("Exception WebSocketMessageReceived. " + excp.Message); } }
public void ParseSDPUnitTest() { Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().Name); string sdpStr = "v=0" + m_CRLF + "o=root 3285 3285 IN IP4 10.0.0.4" + m_CRLF + "s=session" + m_CRLF + "c=IN IP4 10.0.0.4" + m_CRLF + "t=0 0" + m_CRLF + "m=audio 12228 RTP/AVP 0 101" + m_CRLF + "a=rtpmap:0 PCMU/8000" + m_CRLF + "a=rtpmap:101 telephone-event/8000" + m_CRLF + "a=fmtp:101 0-16" + m_CRLF + "a=silenceSupp:off - - - -" + m_CRLF + "a=ptime:20" + m_CRLF + "a=sendrecv"; SDP sdp = SDP.ParseSDPDescription(sdpStr); Debug.WriteLine(sdp.ToString()); Assert.IsTrue(sdp.Connection.ConnectionAddress == "10.0.0.4", "The connection address was not parsed correctly."); Assert.IsTrue(sdp.Media[0].Media == SDPMediaTypesEnum.audio, "The media type not parsed correctly."); Assert.IsTrue(sdp.Media[0].Port == 12228, "The connection port was not parsed correctly."); Assert.IsTrue(sdp.Media[0].GetFormatListToString() == "0 101", "The media format list was incorrect."); Assert.IsTrue(sdp.Media[0].MediaFormats[0].FormatID == 0, "The highest priority media format ID was incorrect."); Assert.IsTrue(sdp.Media[0].MediaFormats[0].Name == "PCMU", "The highest priority media format name was incorrect."); Assert.IsTrue(sdp.Media[0].MediaFormats[0].ClockRate == 8000, "The highest priority media format clockrate was incorrect."); }
public void ParseAudioAndVideoConnectionsUnitTest() { logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name); logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name); string sdpStr = "v=0" + m_CRLF + "o=Cisco-SIPUA 6396 0 IN IP4 101.180.234.134" + m_CRLF + "s=SIP Call" + m_CRLF + "t=0 0" + m_CRLF + "m=audio 19586 RTP/AVP 0" + m_CRLF + "c=IN IP4 101.180.234.134" + m_CRLF + "a=rtpmap:0 PCMU/8000" + m_CRLF + "a=sendrecv" + m_CRLF + "m=video 0 RTP/AVP 96" + m_CRLF + "c=IN IP4 10.0.0.10"; SDP sdp = SDP.ParseSDPDescription(sdpStr); logger.LogDebug(sdp.ToString()); Assert.True(sdp.Connection.ConnectionAddress == "101.180.234.134", "The connection address was not parsed correctly."); Assert.NotEmpty(sdp.Media); Assert.True(sdp.Media[0].Media == SDPMediaTypesEnum.audio, "The media type not parsed correctly."); Assert.Equal(SDPMediaFormatsEnum.PCMU, sdp.Media[0].MediaFormats[0].FormatCodec); Assert.True(sdp.Media[1].Media == SDPMediaTypesEnum.video, "The media type not parsed correctly."); Assert.True(sdp.Media[1].Connection.ConnectionAddress == "10.0.0.10", "The connection address was not parsed correctly."); }
public void ParseBadFormatSDPUnitTest() { logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name); logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name); string sdpStr = " v=0" + m_CRLF + " o=root 3285 3285 IN IP4 10.0.0.4" + m_CRLF + " s=session" + m_CRLF + " c=IN IP4 10.0.0.4" + m_CRLF + " t=0 0" + m_CRLF + " m=audio 12228 RTP/AVP 0 101" + m_CRLF + " a=rtpmap:0 PCMU/8000" + m_CRLF + " a=rtpmap:101 telephone-event/8000" + m_CRLF + " a=fmtp:101 0-16" + m_CRLF + " a=silenceSupp:off - - - -" + m_CRLF + " a=ptime:20" + m_CRLF + " a=sendrecv"; SDP sdp = SDP.ParseSDPDescription(sdpStr); logger.LogDebug(sdp.ToString()); logger.LogDebug($"audio format[0]: {sdp.Media[0].MediaFormats[0].ToString()}"); logger.LogDebug($"audio format[1]: {sdp.Media[0].MediaFormats[1].ToString()}"); Assert.True(sdp.Connection.ConnectionAddress == "10.0.0.4", "The connection address was not parsed correctly."); Assert.True(sdp.Username == "root", "The owner was not parsed correctly."); Assert.True(sdp.SessionName == "session", "The SessionName was not parsed correctly."); Assert.True(sdp.Media[0].Media == SDPMediaTypesEnum.audio, "The media type not parsed correctly."); Assert.Equal(SDPMediaFormatsEnum.PCMU, sdp.Media[0].MediaFormats[0].FormatCodec); Assert.Equal(SDPMediaFormatsEnum.Event, sdp.Media[0].MediaFormats[1].FormatCodec); }
public void SessionMediaSteamStatusRoundTripUnitTest() { logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name); logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name); string sdpStr = "v=0" + m_CRLF + "o=root 3285 3285 IN IP4 10.0.0.4" + m_CRLF + "s=session" + m_CRLF + "c=IN IP4 10.0.0.4" + m_CRLF + "t=0 0" + m_CRLF + "a=recvonly" + m_CRLF + "m=audio 12228 RTP/AVP 0 101" + m_CRLF + "a=rtpmap:0 PCMU/8000" + m_CRLF + "a=rtpmap:101 telephone-event/8000" + m_CRLF + "a=fmtp:101 0-16" + m_CRLF + "a=silenceSupp:off - - - -" + m_CRLF + "a=ptime:20"; SDP sdp = SDP.ParseSDPDescription(sdpStr); logger.LogDebug(sdp.ToString()); SDP sdpRoundTrip = SDP.ParseSDPDescription(sdp.ToString()); Assert.Equal(MediaStreamStatusEnum.RecvOnly, sdpRoundTrip.SessionMediaStreamStatus); }
private void HandleResponse(SIPResponse response, string sourceIP, string destinationIP) { VoipCall call = CreateVoipCallFromSipMessage(response, sourceIP, destinationIP); // Check if the voip calls hash set already contains this call. if (_voipCalls.Contains(call)) { if (response.StatusCode == (int)SipResponses.OK) { SDP SDPmessage = SDP.ParseSDPDescription(response.Body); GetCall(call).RTPPort = SDPmessage.Media[0].Port; HandleRTPPortAdded(call); foreach (var m in SDPmessage.Media[0].MediaFormats) { GetCall(call).RTPMediaType += $"{m.Value.Kind}:{m.Value.Rtpmap} "; } HandleRTPMediaTypeAdded(call); } else if (response.StatusCode >= (int)SipResponses.BadRequest && response.StatusCode < (int)SipResponses.InternalServerError) { GetCall(call).CallState = CallState.Rejected; HandleCallStateUpdate(call, CallState.Rejected); HandleFinishedCall(call); } } }
public void JsonRoundtripUnitTest() { RTCPeerConnection pcSrc = new RTCPeerConnection(null); var videoTrackSrc = new MediaStreamTrack(SDPMediaTypesEnum.video, false, new List <SDPAudioVideoMediaFormat> { new SDPAudioVideoMediaFormat(SDPMediaTypesEnum.video, 96, "VP8", 90000) }); pcSrc.addTrack(videoTrackSrc); var offer = pcSrc.createOffer(new RTCOfferOptions()); Assert.NotNull(offer.toJSON()); logger.LogDebug($"offer: {offer.toJSON()}"); var parseResult = RTCSessionDescriptionInit.TryParse(offer.toJSON(), out var init); Assert.True(parseResult); Assert.Equal(RTCSdpType.offer, init.type); Assert.NotNull(init.sdp); SDP sdp = SDP.ParseSDPDescription(init.sdp); Assert.Equal(0, sdp.Version); }
private void WebRtcAnswerReceived(string webSocketID, string sdpAnswer) { try { logger.Debug("Answer SDP: " + sdpAnswer); var answerSDP = SDP.ParseSDPDescription(sdpAnswer); var peer = _webRtcSessions.Where(x => x.Key == webSocketID).Select(x => x.Value.Peer).SingleOrDefault(); if (peer == null) { logger.Warn("No WebRTC client entry exists for web socket ID " + webSocketID + ", ignoring."); } else { logger.Debug("New WebRTC client SDP answer for web socket ID " + webSocketID + "."); peer.SdpSessionID = answerSDP.SessionId; peer.RemoteIceUser = answerSDP.IceUfrag; peer.RemoteIcePassword = answerSDP.IcePwd; foreach (var iceCandidate in answerSDP.IceCandidates) { peer.AppendRemoteIceCandidate(iceCandidate); } } } catch (Exception excp) { logger.Error("Exception SDPExchangeReceiver_SDPAnswerReceived. " + excp.Message); } }
/// <summary> /// An outgoing call was successfully answered. /// </summary> /// <param name="uac">The local SIP user agent client that initiated the call.</param> /// <param name="sipResponse">The SIP answer response received from the remote party.</param> private void CallAnswered(ISIPClientUserAgent uac, SIPResponse sipResponse) { StatusMessage("Call answered: " + sipResponse.StatusCode + " " + sipResponse.ReasonPhrase + "."); if (sipResponse.StatusCode >= 200 && sipResponse.StatusCode <= 299) { if (sipResponse.Header.ContentType != _sdpMimeContentType) { // Payload not SDP, I don't understand :(. StatusMessage("Call was hungup as the answer response content type was not recognised: " + sipResponse.Header.ContentType + ". :("); Hangup(); } else if (sipResponse.Body.IsNullOrBlank()) { // They said SDP but didn't give me any :(. StatusMessage("Call was hungup as the answer response had an empty SDP payload. :("); Hangup(); } SDP sdpAnswer = SDP.ParseSDPDescription(sipResponse.Body); System.Diagnostics.Debug.WriteLine(sipResponse.Body); _mediaManager.SetRemoteSDP(sdpAnswer); CallAnswer(); } else { CallFinished(); } }
public void ParseMultipleMediaAnnouncementsUnitTest() { Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().Name); string sdpStr = "v=0" + m_CRLF + "o=- 13064410510996677 3 IN IP4 10.1.1.2" + m_CRLF + "s=Bria 4 release 4.1.1 stamp 74246" + m_CRLF + "c=IN IP4 10.1.1.2" + m_CRLF + "b=AS:2064" + m_CRLF + "t=0 0" + m_CRLF + "m=audio 49290 RTP/AVP 0" + m_CRLF + "a=sendrecv" + m_CRLF + "m=video 56674 RTP/AVP 96" + m_CRLF + "b=TIAS:2000000" + m_CRLF + "a=rtpmap:96 VP8/90000" + m_CRLF + "a=sendrecv" + m_CRLF + "a=rtcp-fb:* nack pli"; SDP sdp = SDP.ParseSDPDescription(sdpStr); Debug.WriteLine(sdp.ToString()); Assert.AreEqual(2, sdp.Media.Count); Assert.AreEqual(49290, sdp.Media.Where(x => x.Media == SDPMediaTypesEnum.audio).FirstOrDefault().Port); Assert.AreEqual(56674, sdp.Media.Where(x => x.Media == SDPMediaTypesEnum.video).FirstOrDefault().Port); }
public void ParseWebRtcSDPUnitTest() { logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name); logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name); string sdpStr = @"v=0 o=- 1090343221 2 IN IP4 127.0.0.1 s=- t=0 0 a=group:BUNDLE audio video m=audio 11158 RTP/SAVP 0 c=IN IP4 127.0.0.1 a=candidate:1988909849 1 udp 1124657401 192.168.11.50 11158 typ host generation 0 a=candidate:1846148317 1 udp 2094219785 127.0.0.1 11158 typ host generation 0 a=candidate:2012632329 1 udp 2122820711 172.30.224.1 11158 typ host generation 0 a=end-of-candidates a=ice-ufrag:UWWAVCUMPZHPCLNIMZYA a=ice-pwd:IEUVYLWMXMQZKCMLTXQHZZVWXRCBLPPNUYFPCABK a=fingerprint:sha-256 C6:ED:8C:9D:06:50:77:23:0A:4A:D8:42:68:29:D0:70:2F:BB:C7:72:EC:98:5C:62:07:1B:0C:5D:CB:CE:BE:CD a=setup:actpass a=sendonly a=rtcp-mux a=mid:audio a=rtpmap:0 PCMU/8000 m=video 0 RTP/SAVP 100 c=IN IP4 127.0.0.1 a=ice-ufrag:UWWAVCUMPZHPCLNIMZYA a=ice-pwd:IEUVYLWMXMQZKCMLTXQHZZVWXRCBLPPNUYFPCABK a=fingerprint:sha-256 C6:ED:8C:9D:06:50:77:23:0A:4A:D8:42:68:29:D0:70:2F:BB:C7:72:EC:98:5C:62:07:1B:0C:5D:CB:CE:BE:CD a=bundle-only a=setup:actpass a=sendonly a=rtcp-mux a=mid:video a=rtpmap:100 VP8/90000"; SDP sdp = SDP.ParseSDPDescription(sdpStr); logger.LogDebug(sdp.ToString()); SDP rndTripSdp = SDP.ParseSDPDescription(sdp.ToString()); Assert.Equal("BUNDLE audio video", sdp.Group); Assert.Equal("BUNDLE audio video", rndTripSdp.Group); Assert.Equal("UWWAVCUMPZHPCLNIMZYA", sdp.Media[0].IceUfrag); Assert.Equal("UWWAVCUMPZHPCLNIMZYA", rndTripSdp.Media[0].IceUfrag); Assert.Equal("IEUVYLWMXMQZKCMLTXQHZZVWXRCBLPPNUYFPCABK", sdp.Media[0].IcePwd); Assert.Equal("IEUVYLWMXMQZKCMLTXQHZZVWXRCBLPPNUYFPCABK", rndTripSdp.Media[0].IcePwd); Assert.Equal(3, sdp.Media[0].IceCandidates.Count()); Assert.Equal(3, rndTripSdp.Media[0].IceCandidates.Count()); Assert.Equal("sha-256 C6:ED:8C:9D:06:50:77:23:0A:4A:D8:42:68:29:D0:70:2F:BB:C7:72:EC:98:5C:62:07:1B:0C:5D:CB:CE:BE:CD", sdp.Media[0].DtlsFingerprint); Assert.Equal("sha-256 C6:ED:8C:9D:06:50:77:23:0A:4A:D8:42:68:29:D0:70:2F:BB:C7:72:EC:98:5C:62:07:1B:0C:5D:CB:CE:BE:CD", rndTripSdp.Media[0].DtlsFingerprint); Assert.Equal("audio", sdp.Media[0].MediaID); Assert.Equal("audio", rndTripSdp.Media[0].MediaID); Assert.Equal("video", sdp.Media[1].MediaID); Assert.Equal("video", rndTripSdp.Media[1].MediaID); }
private static async Task WebSocketMessageReceived(WebSocketContext context, RTCPeerConnection pc, string message) { try { if (pc.localDescription == null) { //logger.LogDebug("Offer SDP: " + message); logger.LogDebug("Offer SDP received."); // Add local media tracks depending on what was offered. Also add local tracks with the same media ID as // the remote tracks so that the media announcement in the SDP answer are in the same order. SDP remoteSdp = SDP.ParseSDPDescription(message); foreach (var ann in remoteSdp.Media) { var capbilities = FilterCodecs(ann.Media, ann.MediaFormats); MediaStreamTrack track = new MediaStreamTrack(ann.Media, false, capbilities, MediaStreamStatusEnum.RecvOnly); pc.addTrack(track); } pc.setRemoteDescription(new RTCSessionDescriptionInit { sdp = message, type = RTCSdpType.offer }); var answer = pc.createAnswer(null); await pc.setLocalDescription(answer); Console.WriteLine(answer.sdp); context.WebSocket.Send(answer.sdp); } else if (pc.remoteDescription == null) { logger.LogDebug("Answer SDP: " + message); pc.setRemoteDescription(new RTCSessionDescriptionInit { sdp = message, type = RTCSdpType.answer }); } else { logger.LogDebug("ICE Candidate: " + message); if (string.IsNullOrWhiteSpace(message) || message.Trim().ToLower() == SDP.END_ICE_CANDIDATES_ATTRIBUTE) { logger.LogDebug("End of candidates message received."); } else { var candInit = Newtonsoft.Json.JsonConvert.DeserializeObject <RTCIceCandidateInit>(message); pc.addIceCandidate(candInit); } } } catch (Exception excp) { logger.LogError("Exception WebSocketMessageReceived. " + excp.Message); } }
public void RFC5118_4_9() { logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name); logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name); string sipMsg = "INVITE sip:[email protected] SIP/2.0" + CRLF + "To: sip:[email protected]" + CRLF + "From: sip:[email protected];tag=81x2" + CRLF + "Via: SIP/2.0/UDP [::ffff:192.0.2.10]:19823;branch=z9hG4bKbh19" + CRLF + "Via: SIP/2.0/UDP [::ffff:192.0.2.2];branch=z9hG4bKas3-111" + CRLF + "Call-ID: SSG9559905523997077@hlau_4100" + CRLF + "Contact: \"T. desk phone\" <sip:ted@[::ffff:192.0.2.2]>" + CRLF + "CSeq: 612 INVITE" + CRLF + "Max-Forwards: 70" + CRLF + "Content-Type: application/sdp" + CRLF + "Content-Length: 236" + CRLF + CRLF + "v=0" + CRLF + "o=assistant 971731711378798081 0 IN IP6 ::ffff:192.0.2.2" + CRLF + "s=Call me soon, please!" + CRLF + "c=IN IP6 ::ffff:192.0.2.2" + CRLF + "t=3338481189 3370017201" + CRLF + "m=audio 6000 RTP/AVP 2" + CRLF + "a=rtpmap:2 G726-32/8000" + CRLF + "m=video 6024 RTP/AVP 107" + CRLF + "a=rtpmap:107 H263-1998/90000"; SIPMessageBuffer sipMessageBuffer = SIPMessageBuffer.ParseSIPMessage(Encoding.UTF8.GetBytes(sipMsg), null, null); Assert.True(sipMessageBuffer != null, "The SIP message not parsed correctly."); SIPRequest sipRequest = SIPRequest.ParseSIPRequest(sipMessageBuffer); Assert.Equal(SIPMethodsEnum.INVITE, sipRequest.Method); IPAddress ip6; Assert.NotEmpty(sipRequest.Header.Vias.Via); Assert.True(IPAddress.TryParse(sipRequest.Header.Vias.TopViaHeader.Host, out ip6)); Assert.Equal(AddressFamily.InterNetworkV6, ip6.AddressFamily); Assert.Equal(19823, sipRequest.Header.Vias.TopViaHeader.Port); Assert.True(IPAddress.TryParse(sipRequest.Header.Vias.BottomViaHeader.ReceivedFromAddress, out ip6)); Assert.Equal(AddressFamily.InterNetworkV6, ip6.AddressFamily); Assert.NotEmpty(sipRequest.Header.Contact); Assert.True(IPAddress.TryParse(sipRequest.Header.Contact[0].ContactURI.HostAddress, out ip6)); Assert.Equal(AddressFamily.InterNetworkV6, ip6.AddressFamily); Assert.False(IPAddress.TryParse(sipRequest.URI.HostAddress, out ip6)); Assert.False(string.IsNullOrWhiteSpace(sipRequest.Body)); SDP sdp = SDP.ParseSDPDescription(sipRequest.Body); Assert.NotNull(sdp); Assert.NotNull(sdp.Connection); Assert.True(IPAddress.TryParse(sdp.Connection.ConnectionAddress, out ip6)); Assert.Equal(AddressFamily.InterNetworkV6, ip6.AddressFamily); Assert.NotEmpty(sdp.Media); logger.LogDebug("-----------------------------------------"); }
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"); }