| 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 |