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