OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include "webrtc/modules/rtp_rtcp/source/rtp_sender_audio.h" | 11 #include "webrtc/modules/rtp_rtcp/source/rtp_sender_audio.h" |
12 | 12 |
13 #include <assert.h> //assert | 13 #include <string.h> |
14 #include <string.h> //memcpy | |
15 | 14 |
16 #include "webrtc/base/trace_event.h" | 15 #include "webrtc/base/trace_event.h" |
17 #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h" | 16 #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h" |
18 #include "webrtc/modules/rtp_rtcp/source/byte_io.h" | 17 #include "webrtc/modules/rtp_rtcp/source/byte_io.h" |
19 #include "webrtc/system_wrappers/include/tick_util.h" | 18 #include "webrtc/system_wrappers/include/tick_util.h" |
20 | 19 |
21 namespace webrtc { | 20 namespace webrtc { |
22 | 21 |
23 static const int kDtmfFrequencyHz = 8000; | 22 static const int kDtmfFrequencyHz = 8000; |
24 | 23 |
(...skipping 16 matching lines...) Expand all Loading... |
41 _dtmfTimestampLastSent(0), | 40 _dtmfTimestampLastSent(0), |
42 _REDPayloadType(-1), | 41 _REDPayloadType(-1), |
43 _inbandVADactive(false), | 42 _inbandVADactive(false), |
44 _cngNBPayloadType(-1), | 43 _cngNBPayloadType(-1), |
45 _cngWBPayloadType(-1), | 44 _cngWBPayloadType(-1), |
46 _cngSWBPayloadType(-1), | 45 _cngSWBPayloadType(-1), |
47 _cngFBPayloadType(-1), | 46 _cngFBPayloadType(-1), |
48 _lastPayloadType(-1), | 47 _lastPayloadType(-1), |
49 _audioLevel_dBov(0) {} | 48 _audioLevel_dBov(0) {} |
50 | 49 |
51 RTPSenderAudio::~RTPSenderAudio() { | 50 RTPSenderAudio::~RTPSenderAudio() {} |
52 } | |
53 | 51 |
54 int RTPSenderAudio::AudioFrequency() const { | 52 int RTPSenderAudio::AudioFrequency() const { |
55 return kDtmfFrequencyHz; | 53 return kDtmfFrequencyHz; |
56 } | 54 } |
57 | 55 |
58 // set audio packet size, used to determine when it's time to send a DTMF packet | 56 // set audio packet size, used to determine when it's time to send a DTMF packet |
59 // in silence (CNG) | 57 // in silence (CNG) |
60 int32_t | 58 int32_t RTPSenderAudio::SetAudioPacketSize(uint16_t packetSizeSamples) { |
61 RTPSenderAudio::SetAudioPacketSize(const uint16_t packetSizeSamples) | 59 CriticalSectionScoped cs(_sendAudioCritsect.get()); |
62 { | |
63 CriticalSectionScoped cs(_sendAudioCritsect.get()); | |
64 | 60 |
65 _packetSizeSamples = packetSizeSamples; | 61 _packetSizeSamples = packetSizeSamples; |
66 return 0; | 62 return 0; |
67 } | 63 } |
68 | 64 |
69 int32_t RTPSenderAudio::RegisterAudioPayload( | 65 int32_t RTPSenderAudio::RegisterAudioPayload( |
70 const char payloadName[RTP_PAYLOAD_NAME_SIZE], | 66 const char payloadName[RTP_PAYLOAD_NAME_SIZE], |
71 const int8_t payloadType, | 67 const int8_t payloadType, |
72 const uint32_t frequency, | 68 const uint32_t frequency, |
73 const uint8_t channels, | 69 const uint8_t channels, |
74 const uint32_t rate, | 70 const uint32_t rate, |
75 RtpUtility::Payload*& payload) { | 71 RtpUtility::Payload*& payload) { |
76 if (RtpUtility::StringCompare(payloadName, "cn", 2)) { | 72 if (RtpUtility::StringCompare(payloadName, "cn", 2)) { |
(...skipping 26 matching lines...) Expand all Loading... |
103 payload = new RtpUtility::Payload; | 99 payload = new RtpUtility::Payload; |
104 payload->typeSpecific.Audio.frequency = frequency; | 100 payload->typeSpecific.Audio.frequency = frequency; |
105 payload->typeSpecific.Audio.channels = channels; | 101 payload->typeSpecific.Audio.channels = channels; |
106 payload->typeSpecific.Audio.rate = rate; | 102 payload->typeSpecific.Audio.rate = rate; |
107 payload->audio = true; | 103 payload->audio = true; |
108 payload->name[RTP_PAYLOAD_NAME_SIZE - 1] = '\0'; | 104 payload->name[RTP_PAYLOAD_NAME_SIZE - 1] = '\0'; |
109 strncpy(payload->name, payloadName, RTP_PAYLOAD_NAME_SIZE - 1); | 105 strncpy(payload->name, payloadName, RTP_PAYLOAD_NAME_SIZE - 1); |
110 return 0; | 106 return 0; |
111 } | 107 } |
112 | 108 |
113 bool | 109 bool RTPSenderAudio::MarkerBit(FrameType frameType, int8_t payload_type) { |
114 RTPSenderAudio::MarkerBit(const FrameType frameType, | 110 CriticalSectionScoped cs(_sendAudioCritsect.get()); |
115 const int8_t payload_type) | 111 // for audio true for first packet in a speech burst |
116 { | 112 bool markerBit = false; |
117 CriticalSectionScoped cs(_sendAudioCritsect.get()); | 113 if (_lastPayloadType != payload_type) { |
118 // for audio true for first packet in a speech burst | 114 if (payload_type != -1 && (_cngNBPayloadType == payload_type || |
119 bool markerBit = false; | 115 _cngWBPayloadType == payload_type || |
120 if (_lastPayloadType != payload_type) { | 116 _cngSWBPayloadType == payload_type || |
121 if (payload_type != -1 && (_cngNBPayloadType == payload_type || | 117 _cngFBPayloadType == payload_type)) { |
122 _cngWBPayloadType == payload_type || | 118 // Only set a marker bit when we change payload type to a non CNG |
123 _cngSWBPayloadType == payload_type || | 119 return false; |
124 _cngFBPayloadType == payload_type)) { | 120 } |
125 // Only set a marker bit when we change payload type to a non CNG | 121 |
| 122 // payload_type differ |
| 123 if (_lastPayloadType == -1) { |
| 124 if (frameType != kAudioFrameCN) { |
| 125 // first packet and NOT CNG |
| 126 return true; |
| 127 } else { |
| 128 // first packet and CNG |
| 129 _inbandVADactive = true; |
126 return false; | 130 return false; |
127 } | 131 } |
128 | |
129 // payload_type differ | |
130 if (_lastPayloadType == -1) { | |
131 if (frameType != kAudioFrameCN) { | |
132 // first packet and NOT CNG | |
133 return true; | |
134 } else { | |
135 // first packet and CNG | |
136 _inbandVADactive = true; | |
137 return false; | |
138 } | |
139 } | |
140 | |
141 // not first packet AND | |
142 // not CNG AND | |
143 // payload_type changed | |
144 | |
145 // set a marker bit when we change payload type | |
146 markerBit = true; | |
147 } | 132 } |
148 | 133 |
149 // For G.723 G.729, AMR etc we can have inband VAD | 134 // not first packet AND |
150 if(frameType == kAudioFrameCN) | 135 // not CNG AND |
151 { | 136 // payload_type changed |
152 _inbandVADactive = true; | |
153 | 137 |
154 } else if(_inbandVADactive) | 138 // set a marker bit when we change payload type |
155 { | 139 markerBit = true; |
156 _inbandVADactive = false; | 140 } |
157 markerBit = true; | 141 |
158 } | 142 // For G.723 G.729, AMR etc we can have inband VAD |
159 return markerBit; | 143 if (frameType == kAudioFrameCN) { |
| 144 _inbandVADactive = true; |
| 145 } else if (_inbandVADactive) { |
| 146 _inbandVADactive = false; |
| 147 markerBit = true; |
| 148 } |
| 149 return markerBit; |
160 } | 150 } |
161 | 151 |
162 int32_t RTPSenderAudio::SendAudio( | 152 int32_t RTPSenderAudio::SendAudio(FrameType frameType, |
163 const FrameType frameType, | 153 int8_t payloadType, |
164 const int8_t payloadType, | 154 uint32_t captureTimeStamp, |
165 const uint32_t captureTimeStamp, | 155 const uint8_t* payloadData, |
166 const uint8_t* payloadData, | 156 size_t dataSize, |
167 const size_t dataSize, | 157 const RTPFragmentationHeader* fragmentation) { |
168 const RTPFragmentationHeader* fragmentation) { | |
169 // TODO(pwestin) Breakup function in smaller functions. | 158 // TODO(pwestin) Breakup function in smaller functions. |
170 size_t payloadSize = dataSize; | 159 size_t payloadSize = dataSize; |
171 size_t maxPayloadLength = _rtpSender->MaxPayloadLength(); | 160 size_t maxPayloadLength = _rtpSender->MaxPayloadLength(); |
172 bool dtmfToneStarted = false; | 161 bool dtmfToneStarted = false; |
173 uint16_t dtmfLengthMS = 0; | 162 uint16_t dtmfLengthMS = 0; |
174 uint8_t key = 0; | 163 uint8_t key = 0; |
175 int red_payload_type; | 164 int red_payload_type; |
176 uint8_t audio_level_dbov; | 165 uint8_t audio_level_dbov; |
177 int8_t dtmf_payload_type; | 166 int8_t dtmf_payload_type; |
178 uint16_t packet_size_samples; | 167 uint16_t packet_size_samples; |
179 { | 168 { |
180 CriticalSectionScoped cs(_sendAudioCritsect.get()); | 169 CriticalSectionScoped cs(_sendAudioCritsect.get()); |
181 red_payload_type = _REDPayloadType; | 170 red_payload_type = _REDPayloadType; |
182 audio_level_dbov = _audioLevel_dBov; | 171 audio_level_dbov = _audioLevel_dBov; |
183 dtmf_payload_type = _dtmfPayloadType; | 172 dtmf_payload_type = _dtmfPayloadType; |
184 packet_size_samples = _packetSizeSamples; | 173 packet_size_samples = _packetSizeSamples; |
185 } | 174 } |
186 | 175 |
187 // Check if we have pending DTMFs to send | 176 // Check if we have pending DTMFs to send |
188 if (!_dtmfEventIsOn && PendingDTMF()) { | 177 if (!_dtmfEventIsOn && PendingDTMF()) { |
189 int64_t delaySinceLastDTMF = _clock->TimeInMilliseconds() - | 178 int64_t delaySinceLastDTMF = |
190 _dtmfTimeLastSent; | 179 _clock->TimeInMilliseconds() - _dtmfTimeLastSent; |
191 | 180 |
192 if (delaySinceLastDTMF > 100) { | 181 if (delaySinceLastDTMF > 100) { |
193 // New tone to play | 182 // New tone to play |
194 _dtmfTimestamp = captureTimeStamp; | 183 _dtmfTimestamp = captureTimeStamp; |
195 if (NextDTMF(&key, &dtmfLengthMS, &_dtmfLevel) >= 0) { | 184 if (NextDTMF(&key, &dtmfLengthMS, &_dtmfLevel) >= 0) { |
196 _dtmfEventFirstPacketSent = false; | 185 _dtmfEventFirstPacketSent = false; |
197 _dtmfKey = key; | 186 _dtmfKey = key; |
198 _dtmfLengthSamples = (kDtmfFrequencyHz / 1000) * dtmfLengthMS; | 187 _dtmfLengthSamples = (kDtmfFrequencyHz / 1000) * dtmfLengthMS; |
199 dtmfToneStarted = true; | 188 dtmfToneStarted = true; |
200 _dtmfEventIsOn = true; | 189 _dtmfEventIsOn = true; |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
288 markerBit, captureTimeStamp, | 277 markerBit, captureTimeStamp, |
289 _clock->TimeInMilliseconds()); | 278 _clock->TimeInMilliseconds()); |
290 } | 279 } |
291 if (rtpHeaderLength <= 0) { | 280 if (rtpHeaderLength <= 0) { |
292 return -1; | 281 return -1; |
293 } | 282 } |
294 if (maxPayloadLength < (rtpHeaderLength + payloadSize)) { | 283 if (maxPayloadLength < (rtpHeaderLength + payloadSize)) { |
295 // Too large payload buffer. | 284 // Too large payload buffer. |
296 return -1; | 285 return -1; |
297 } | 286 } |
298 if (red_payload_type >= 0 && // Have we configured RED? | 287 if (red_payload_type >= 0 && // Have we configured RED? |
299 fragmentation && fragmentation->fragmentationVectorSize > 1 && | 288 fragmentation && fragmentation->fragmentationVectorSize > 1 && |
300 !markerBit) { | 289 !markerBit) { |
301 if (timestampOffset <= 0x3fff) { | 290 if (timestampOffset <= 0x3fff) { |
302 if (fragmentation->fragmentationVectorSize != 2) { | 291 if (fragmentation->fragmentationVectorSize != 2) { |
303 // we only support 2 codecs when using RED | 292 // we only support 2 codecs when using RED |
304 return -1; | 293 return -1; |
305 } | 294 } |
306 // only 0x80 if we have multiple blocks | 295 // only 0x80 if we have multiple blocks |
307 dataBuffer[rtpHeaderLength++] = | 296 dataBuffer[rtpHeaderLength++] = |
308 0x80 + fragmentation->fragmentationPlType[1]; | 297 0x80 + fragmentation->fragmentationPlType[1]; |
309 size_t blockLength = fragmentation->fragmentationLength[1]; | 298 size_t blockLength = fragmentation->fragmentationLength[1]; |
310 | 299 |
311 // sanity blockLength | 300 // sanity blockLength |
312 if (blockLength > 0x3ff) { // block length 10 bits 1023 bytes | 301 if (blockLength > 0x3ff) { // block length 10 bits 1023 bytes |
313 return -1; | 302 return -1; |
314 } | 303 } |
315 uint32_t REDheader = (timestampOffset << 10) + blockLength; | 304 uint32_t REDheader = (timestampOffset << 10) + blockLength; |
316 ByteWriter<uint32_t>::WriteBigEndian(dataBuffer + rtpHeaderLength, | 305 ByteWriter<uint32_t>::WriteBigEndian(dataBuffer + rtpHeaderLength, |
317 REDheader); | 306 REDheader); |
318 rtpHeaderLength += 3; | 307 rtpHeaderLength += 3; |
319 | 308 |
320 dataBuffer[rtpHeaderLength++] = fragmentation->fragmentationPlType[0]; | 309 dataBuffer[rtpHeaderLength++] = fragmentation->fragmentationPlType[0]; |
321 // copy the RED data | 310 // copy the RED data |
322 memcpy(dataBuffer + rtpHeaderLength, | 311 memcpy(dataBuffer + rtpHeaderLength, |
323 payloadData + fragmentation->fragmentationOffset[1], | 312 payloadData + fragmentation->fragmentationOffset[1], |
324 fragmentation->fragmentationLength[1]); | 313 fragmentation->fragmentationLength[1]); |
325 | 314 |
326 // copy the normal data | 315 // copy the normal data |
327 memcpy(dataBuffer + rtpHeaderLength + | 316 memcpy( |
328 fragmentation->fragmentationLength[1], | 317 dataBuffer + rtpHeaderLength + fragmentation->fragmentationLength[1], |
329 payloadData + fragmentation->fragmentationOffset[0], | 318 payloadData + fragmentation->fragmentationOffset[0], |
330 fragmentation->fragmentationLength[0]); | 319 fragmentation->fragmentationLength[0]); |
331 | 320 |
332 payloadSize = fragmentation->fragmentationLength[0] + | 321 payloadSize = fragmentation->fragmentationLength[0] + |
333 fragmentation->fragmentationLength[1]; | 322 fragmentation->fragmentationLength[1]; |
334 } else { | 323 } else { |
335 // silence for too long send only new data | 324 // silence for too long send only new data |
336 dataBuffer[rtpHeaderLength++] = fragmentation->fragmentationPlType[0]; | 325 dataBuffer[rtpHeaderLength++] = fragmentation->fragmentationPlType[0]; |
337 memcpy(dataBuffer + rtpHeaderLength, | 326 memcpy(dataBuffer + rtpHeaderLength, |
338 payloadData + fragmentation->fragmentationOffset[0], | 327 payloadData + fragmentation->fragmentationOffset[0], |
339 fragmentation->fragmentationLength[0]); | 328 fragmentation->fragmentationLength[0]); |
340 | 329 |
341 payloadSize = fragmentation->fragmentationLength[0]; | 330 payloadSize = fragmentation->fragmentationLength[0]; |
342 } | 331 } |
| 332 } else { |
| 333 if (fragmentation && fragmentation->fragmentationVectorSize > 0) { |
| 334 // use the fragment info if we have one |
| 335 dataBuffer[rtpHeaderLength++] = fragmentation->fragmentationPlType[0]; |
| 336 memcpy(dataBuffer + rtpHeaderLength, |
| 337 payloadData + fragmentation->fragmentationOffset[0], |
| 338 fragmentation->fragmentationLength[0]); |
| 339 |
| 340 payloadSize = fragmentation->fragmentationLength[0]; |
343 } else { | 341 } else { |
344 if (fragmentation && fragmentation->fragmentationVectorSize > 0) { | 342 memcpy(dataBuffer + rtpHeaderLength, payloadData, payloadSize); |
345 // use the fragment info if we have one | |
346 dataBuffer[rtpHeaderLength++] = fragmentation->fragmentationPlType[0]; | |
347 memcpy(dataBuffer + rtpHeaderLength, | |
348 payloadData + fragmentation->fragmentationOffset[0], | |
349 fragmentation->fragmentationLength[0]); | |
350 | |
351 payloadSize = fragmentation->fragmentationLength[0]; | |
352 } else { | |
353 memcpy(dataBuffer + rtpHeaderLength, payloadData, payloadSize); | |
354 } | |
355 } | 343 } |
356 { | |
357 CriticalSectionScoped cs(_sendAudioCritsect.get()); | |
358 _lastPayloadType = payloadType; | |
359 } | |
360 // Update audio level extension, if included. | |
361 size_t packetSize = payloadSize + rtpHeaderLength; | |
362 RtpUtility::RtpHeaderParser rtp_parser(dataBuffer, packetSize); | |
363 RTPHeader rtp_header; | |
364 rtp_parser.Parse(rtp_header); | |
365 _rtpSender->UpdateAudioLevel(dataBuffer, packetSize, rtp_header, | |
366 (frameType == kAudioFrameSpeech), | |
367 audio_level_dbov); | |
368 TRACE_EVENT_ASYNC_END2("webrtc", "Audio", captureTimeStamp, "timestamp", | |
369 _rtpSender->Timestamp(), "seqnum", | |
370 _rtpSender->SequenceNumber()); | |
371 return _rtpSender->SendToNetwork(dataBuffer, payloadSize, rtpHeaderLength, | |
372 TickTime::MillisecondTimestamp(), | |
373 kAllowRetransmission, | |
374 RtpPacketSender::kHighPriority); | |
375 } | 344 } |
376 | 345 { |
377 // Audio level magnitude and voice activity flag are set for each RTP packet | |
378 int32_t | |
379 RTPSenderAudio::SetAudioLevel(const uint8_t level_dBov) | |
380 { | |
381 if (level_dBov > 127) | |
382 { | |
383 return -1; | |
384 } | |
385 CriticalSectionScoped cs(_sendAudioCritsect.get()); | 346 CriticalSectionScoped cs(_sendAudioCritsect.get()); |
386 _audioLevel_dBov = level_dBov; | 347 _lastPayloadType = payloadType; |
387 return 0; | 348 } |
| 349 // Update audio level extension, if included. |
| 350 size_t packetSize = payloadSize + rtpHeaderLength; |
| 351 RtpUtility::RtpHeaderParser rtp_parser(dataBuffer, packetSize); |
| 352 RTPHeader rtp_header; |
| 353 rtp_parser.Parse(rtp_header); |
| 354 _rtpSender->UpdateAudioLevel(dataBuffer, packetSize, rtp_header, |
| 355 (frameType == kAudioFrameSpeech), |
| 356 audio_level_dbov); |
| 357 TRACE_EVENT_ASYNC_END2("webrtc", "Audio", captureTimeStamp, "timestamp", |
| 358 _rtpSender->Timestamp(), "seqnum", |
| 359 _rtpSender->SequenceNumber()); |
| 360 return _rtpSender->SendToNetwork(dataBuffer, payloadSize, rtpHeaderLength, |
| 361 TickTime::MillisecondTimestamp(), |
| 362 kAllowRetransmission, |
| 363 RtpPacketSender::kHighPriority); |
388 } | 364 } |
389 | 365 |
390 // Set payload type for Redundant Audio Data RFC 2198 | 366 // Audio level magnitude and voice activity flag are set for each RTP packet |
391 int32_t | 367 int32_t RTPSenderAudio::SetAudioLevel(uint8_t level_dBov) { |
392 RTPSenderAudio::SetRED(const int8_t payloadType) | 368 if (level_dBov > 127) { |
393 { | 369 return -1; |
394 if(payloadType < -1 ) | 370 } |
395 { | 371 CriticalSectionScoped cs(_sendAudioCritsect.get()); |
396 return -1; | 372 _audioLevel_dBov = level_dBov; |
397 } | 373 return 0; |
398 CriticalSectionScoped cs(_sendAudioCritsect.get()); | |
399 _REDPayloadType = payloadType; | |
400 return 0; | |
401 } | 374 } |
402 | 375 |
403 // Get payload type for Redundant Audio Data RFC 2198 | 376 // Set payload type for Redundant Audio Data RFC 2198 |
404 int32_t | 377 int32_t RTPSenderAudio::SetRED(int8_t payloadType) { |
405 RTPSenderAudio::RED(int8_t& payloadType) const | 378 if (payloadType < -1) { |
406 { | 379 return -1; |
407 CriticalSectionScoped cs(_sendAudioCritsect.get()); | 380 } |
408 if(_REDPayloadType == -1) | 381 CriticalSectionScoped cs(_sendAudioCritsect.get()); |
409 { | 382 _REDPayloadType = payloadType; |
410 // not configured | 383 return 0; |
411 return -1; | 384 } |
412 } | 385 |
413 payloadType = _REDPayloadType; | 386 // Get payload type for Redundant Audio Data RFC 2198 |
414 return 0; | 387 int32_t RTPSenderAudio::RED(int8_t& payloadType) const { |
| 388 CriticalSectionScoped cs(_sendAudioCritsect.get()); |
| 389 if (_REDPayloadType == -1) { |
| 390 // not configured |
| 391 return -1; |
| 392 } |
| 393 payloadType = _REDPayloadType; |
| 394 return 0; |
415 } | 395 } |
416 | 396 |
417 // Send a TelephoneEvent tone using RFC 2833 (4733) | 397 // Send a TelephoneEvent tone using RFC 2833 (4733) |
418 int32_t RTPSenderAudio::SendTelephoneEvent(const uint8_t key, | 398 int32_t RTPSenderAudio::SendTelephoneEvent(uint8_t key, |
419 const uint16_t time_ms, | 399 uint16_t time_ms, |
420 const uint8_t level) { | 400 uint8_t level) { |
421 { | 401 { |
422 CriticalSectionScoped lock(_sendAudioCritsect.get()); | 402 CriticalSectionScoped lock(_sendAudioCritsect.get()); |
423 if (_dtmfPayloadType < 0) { | 403 if (_dtmfPayloadType < 0) { |
424 // TelephoneEvent payloadtype not configured | 404 // TelephoneEvent payloadtype not configured |
425 return -1; | 405 return -1; |
426 } | 406 } |
427 } | 407 } |
428 return AddDTMF(key, time_ms, level); | 408 return AddDTMF(key, time_ms, level); |
429 } | 409 } |
430 | 410 |
431 int32_t | 411 int32_t RTPSenderAudio::SendTelephoneEventPacket(bool ended, |
432 RTPSenderAudio::SendTelephoneEventPacket(bool ended, | 412 int8_t dtmf_payload_type, |
433 int8_t dtmf_payload_type, | 413 uint32_t dtmfTimeStamp, |
434 uint32_t dtmfTimeStamp, | 414 uint16_t duration, |
435 uint16_t duration, | 415 bool markerBit) { |
436 bool markerBit) | 416 uint8_t dtmfbuffer[IP_PACKET_SIZE]; |
437 { | 417 uint8_t sendCount = 1; |
438 uint8_t dtmfbuffer[IP_PACKET_SIZE]; | 418 int32_t retVal = 0; |
439 uint8_t sendCount = 1; | |
440 int32_t retVal = 0; | |
441 | 419 |
442 if(ended) | 420 if (ended) { |
443 { | 421 // resend last packet in an event 3 times |
444 // resend last packet in an event 3 times | 422 sendCount = 3; |
445 sendCount = 3; | 423 } |
446 } | 424 do { |
447 do | 425 // Send DTMF data |
448 { | 426 _rtpSender->BuildRTPheader(dtmfbuffer, dtmf_payload_type, markerBit, |
449 //Send DTMF data | 427 dtmfTimeStamp, _clock->TimeInMilliseconds()); |
450 _rtpSender->BuildRTPheader(dtmfbuffer, dtmf_payload_type, markerBit, | |
451 dtmfTimeStamp, _clock->TimeInMilliseconds()); | |
452 | 428 |
453 // reset CSRC and X bit | 429 // reset CSRC and X bit |
454 dtmfbuffer[0] &= 0xe0; | 430 dtmfbuffer[0] &= 0xe0; |
455 | 431 |
456 //Create DTMF data | 432 // Create DTMF data |
457 /* From RFC 2833: | 433 /* From RFC 2833: |
458 | 434 |
459 0 1 2 3 | 435 0 1 2 3 |
460 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 | 436 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 |
461 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 437 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
462 | event |E|R| volume | duration | | 438 | event |E|R| volume | duration | |
463 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 439 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
464 */ | 440 */ |
465 // R bit always cleared | 441 // R bit always cleared |
466 uint8_t R = 0x00; | 442 uint8_t R = 0x00; |
467 uint8_t volume = _dtmfLevel; | 443 uint8_t volume = _dtmfLevel; |
468 | 444 |
469 // First packet un-ended | 445 // First packet un-ended |
470 uint8_t E = ended ? 0x80 : 0x00; | 446 uint8_t E = ended ? 0x80 : 0x00; |
471 | 447 |
472 // First byte is Event number, equals key number | 448 // First byte is Event number, equals key number |
473 dtmfbuffer[12] = _dtmfKey; | 449 dtmfbuffer[12] = _dtmfKey; |
474 dtmfbuffer[13] = E|R|volume; | 450 dtmfbuffer[13] = E | R | volume; |
475 ByteWriter<uint16_t>::WriteBigEndian(dtmfbuffer + 14, duration); | 451 ByteWriter<uint16_t>::WriteBigEndian(dtmfbuffer + 14, duration); |
476 | 452 |
477 TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), | 453 TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), |
478 "Audio::SendTelephoneEvent", "timestamp", | 454 "Audio::SendTelephoneEvent", "timestamp", |
479 dtmfTimeStamp, "seqnum", | 455 dtmfTimeStamp, "seqnum", _rtpSender->SequenceNumber()); |
480 _rtpSender->SequenceNumber()); | 456 retVal = _rtpSender->SendToNetwork( |
481 retVal = _rtpSender->SendToNetwork( | 457 dtmfbuffer, 4, 12, TickTime::MillisecondTimestamp(), |
482 dtmfbuffer, 4, 12, TickTime::MillisecondTimestamp(), | 458 kAllowRetransmission, RtpPacketSender::kHighPriority); |
483 kAllowRetransmission, RtpPacketSender::kHighPriority); | 459 sendCount--; |
484 sendCount--; | 460 } while (sendCount > 0 && retVal == 0); |
485 | 461 |
486 }while (sendCount > 0 && retVal == 0); | 462 return retVal; |
487 | |
488 return retVal; | |
489 } | 463 } |
490 } // namespace webrtc | 464 } // namespace webrtc |
OLD | NEW |