/// <summary> /// Sends an RTP event for a DTMF tone as per RFC2833. Sending the event requires multiple packets to be sent. /// This method will hold onto the socket until all the packets required for the event have been sent. The send /// can be cancelled using the cancellation token. /// </summary> /// <param name="srcRtpSocket">The local RTP socket to send the event from.</param> /// <param name="dstRtpSocket">The remote RTP socket to send the event to.</param> /// <param name="rtpEvent">The RTP event to send.</param> /// <param name="startTimestamp">The RTP timestamp at the start of the event.</param> /// <param name="samplePeriod">The sample period in milliseconds being used for the media stream that the event /// is being inserted into. Should be set to 50ms if main media stream is dynamic or sample period is unknown.</param> /// <param name="timestampStep">The RTP timestamp step corresponding to the sampling period. This can change depending /// on the codec being used. For example using PCMU with a sampling frequency of 8000Hz the timestamp step /// for a sample period of 50ms is 400 (8000 / (1000 / 50)). For a sample period of 20ms it's 160 (8000 / (1000 / 20)).</param> /// <param name="cts">Token source to allow the operation to be cancelled prematurely.</param> public async Task SendDtmfEvent(Socket srcRtpSocket, IPEndPoint dstRtpSocket, RTPEvent rtpEvent, uint startTimestamp, ushort samplePeriod, ushort timestampStep, CancellationTokenSource cts) { try { // If only the minimum number of packets are being sent then they are both the start and end of the event. rtpEvent.EndOfEvent = (rtpEvent.TotalDuration <= timestampStep); rtpEvent.Duration = timestampStep; // Send the start of event packets. for (int i = 0; i < RTPEvent.DUPLICATE_COUNT && !cts.IsCancellationRequested; i++) { byte[] buffer = rtpEvent.GetEventPayload(); int markerBit = (i == 0) ? 1 : 0; // Set marker bit for the first packet in the event. SendRtpPacket(srcRtpSocket, dstRtpSocket, buffer, startTimestamp, markerBit, rtpEvent.PayloadTypeID); SeqNum++; PacketsSent++; } await Task.Delay(samplePeriod, cts.Token); if (!rtpEvent.EndOfEvent) { // Send the progressive event packets while ((rtpEvent.Duration + timestampStep) < rtpEvent.TotalDuration && !cts.IsCancellationRequested) { rtpEvent.Duration += timestampStep; byte[] buffer = rtpEvent.GetEventPayload(); SendRtpPacket(srcRtpSocket, dstRtpSocket, buffer, startTimestamp, 0, rtpEvent.PayloadTypeID); PacketsSent++; SeqNum++; await Task.Delay(samplePeriod, cts.Token); } // Send the end of event packets. for (int j = 0; j < RTPEvent.DUPLICATE_COUNT && !cts.IsCancellationRequested; j++) { rtpEvent.EndOfEvent = true; rtpEvent.Duration = rtpEvent.TotalDuration; byte[] buffer = rtpEvent.GetEventPayload(); SendRtpPacket(srcRtpSocket, dstRtpSocket, buffer, startTimestamp, 0, rtpEvent.PayloadTypeID); SeqNum++; PacketsSent++; } } } catch (System.Net.Sockets.SocketException sockExcp) { logger.LogError("SocketException SendDtmfEvent. " + sockExcp.Message); } catch (System.Threading.Tasks.TaskCanceledException) { logger.LogWarning("SendDtmfEvent was cancelled by caller."); } }
/// <summary> /// Sends an RTP event for a DTMF tone as per RFC2833. Sending the event requires multiple packets to be sent. /// This method will hold onto the socket until all the packets required for the event have been sent. The send /// can be cancelled using the cancellation token. /// </summary> /// <param name="rtpEvent">The RTP event to send.</param> /// <param name="cancellationToken">CancellationToken to allow the operation to be cancelled prematurely.</param> public async Task SendDtmfEvent( RTPEvent rtpEvent, CancellationToken cancellationToken) { if (m_rtpEventInProgress == true || DestinationEndPoint == null) { logger.LogWarning("SendDtmfEvent request ignored as an RTP event is already in progress."); } try { m_rtpEventInProgress = true; uint startTimestamp = m_lastRtpTimestamp; // The sample period in milliseconds being used for the media stream that the event // is being inserted into. Should be set to 50ms if main media stream is dynamic or // sample period is unknown. int samplePeriod = RTP_EVENT_DEFAULT_SAMPLE_PERIOD_MS; int clockRate = MediaFormat.ClockRate; // If the clock rate is unknown or dynamic cross our fingers and use 8KHz. if (clockRate == 0) { clockRate = DEFAULT_AUDIO_CLOCK_RATE; } // The RTP timestamp step corresponding to the sampling period. This can change depending // on the codec being used. For example using PCMU with a sampling frequency of 8000Hz and a sample period of 50ms // the timestamp step is 400 (8000 / (1000 / 50)). For a sample period of 20ms it's 160 (8000 / (1000 / 20)). ushort rtpTimestampStep = (ushort)(clockRate * samplePeriod / 1000); // If only the minimum number of packets are being sent then they are both the start and end of the event. rtpEvent.EndOfEvent = (rtpEvent.TotalDuration <= rtpTimestampStep); // The DTMF tone is generally multiple RTP events. Each event has a duration of the RTP timestamp step. rtpEvent.Duration = rtpTimestampStep; // Send the start of event packets. for (int i = 0; i < RTPEvent.DUPLICATE_COUNT && !cancellationToken.IsCancellationRequested; i++) { byte[] buffer = rtpEvent.GetEventPayload(); int markerBit = (i == 0) ? 1 : 0; // Set marker bit for the first packet in the event. SendRtpPacket(RtpChannel, DestinationEndPoint, buffer, startTimestamp, markerBit, rtpEvent.PayloadTypeID); SeqNum++; } await Task.Delay(samplePeriod, cancellationToken); if (!rtpEvent.EndOfEvent) { // Send the progressive event packets while ((rtpEvent.Duration + rtpTimestampStep) < rtpEvent.TotalDuration && !cancellationToken.IsCancellationRequested) { rtpEvent.Duration += rtpTimestampStep; byte[] buffer = rtpEvent.GetEventPayload(); SendRtpPacket(RtpChannel, DestinationEndPoint, buffer, startTimestamp, 0, rtpEvent.PayloadTypeID); SeqNum++; await Task.Delay(samplePeriod, cancellationToken); } // Send the end of event packets. for (int j = 0; j < RTPEvent.DUPLICATE_COUNT && !cancellationToken.IsCancellationRequested; j++) { rtpEvent.EndOfEvent = true; rtpEvent.Duration = rtpEvent.TotalDuration; byte[] buffer = rtpEvent.GetEventPayload(); SendRtpPacket(RtpChannel, DestinationEndPoint, buffer, startTimestamp, 0, rtpEvent.PayloadTypeID); SeqNum++; } } } catch (SocketException sockExcp) { logger.LogError("SocketException SendDtmfEvent. " + sockExcp.Message); } catch (TaskCanceledException) { logger.LogWarning("SendDtmfEvent was cancelled by caller."); } finally { m_rtpEventInProgress = false; } }