/// <summary> /// Handling packets received on the RTP socket. One of the simplest, if not the simplest, cases is /// PCMU audio packets. THe handling can get substantially more complicated if the RTP socket is being /// used to multiplex different protocols. This is what WebRTC does with STUN, RTP and RTCP. /// </summary> /// <param name="rtpSocket">The raw RTP socket.</param> /// <param name="rtpSendSession">The session infor for the RTP pakcets being sent.</param> private static async void RecvRtp(Socket rtpSocket, RTPSession rtpRecvSession, CancellationTokenSource cts) { try { DateTime lastRecvReportAt = DateTime.Now; uint packetReceivedCount = 0; uint bytesReceivedCount = 0; byte[] buffer = new byte[512]; IPEndPoint anyEndPoint = new IPEndPoint((rtpSocket.AddressFamily == AddressFamily.InterNetworkV6) ? IPAddress.IPv6Any : IPAddress.Any, 0); Log.LogDebug($"Listening on RTP socket {rtpSocket.LocalEndPoint}."); using (var waveOutEvent = new WaveOutEvent()) { var waveProvider = new BufferedWaveProvider(new WaveFormat(8000, 16, 1)); waveProvider.DiscardOnBufferOverflow = true; waveOutEvent.Init(waveProvider); waveOutEvent.Play(); var recvResult = await rtpSocket.ReceiveFromAsync(buffer, SocketFlags.None, anyEndPoint); Log.LogDebug($"Initial RTP packet recieved from {recvResult.RemoteEndPoint}."); while (recvResult.ReceivedBytes > 0 && !cts.IsCancellationRequested) { var rtpPacket = rtpRecvSession.RtpReceive(buffer, 0, recvResult.ReceivedBytes, recvResult.RemoteEndPoint as IPEndPoint); packetReceivedCount++; bytesReceivedCount += (uint)rtpPacket.Payload.Length; for (int index = 0; index < rtpPacket.Payload.Length; index++) { short pcm = NAudio.Codecs.MuLawDecoder.MuLawToLinearSample(rtpPacket.Payload[index]); byte[] pcmSample = new byte[] { (byte)(pcm & 0xFF), (byte)(pcm >> 8) }; waveProvider.AddSamples(pcmSample, 0, 2); } if (DateTime.Now.Subtract(lastRecvReportAt).TotalSeconds > RTP_REPORTING_PERIOD_SECONDS) { // This is typically where RTCP receiver (RR) reports would be sent. Omitted here for brevity. lastRecvReportAt = DateTime.Now; var remoteRtpEndPoint = recvResult.RemoteEndPoint as IPEndPoint; Log.LogDebug($"RTP recv report {rtpSocket.LocalEndPoint}<-{remoteRtpEndPoint} pkts {packetReceivedCount} bytes {bytesReceivedCount}"); } recvResult = await rtpSocket.ReceiveFromAsync(buffer, SocketFlags.None, anyEndPoint); } } } catch (ObjectDisposedException) { } // This is how .Net deals with an in use socket being closed. Safe to ignore. catch (Exception excp) { Log.LogError($"Exception processing RTP. {excp}"); } }