Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(13)

Side by Side Diff: webrtc/media/engine/webrtcvoiceengine.cc

Issue 2337473002: Multi frequency DTMF support - receiver side (Closed)
Patch Set: rebase Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (c) 2004 The WebRTC project authors. All Rights Reserved. 2 * Copyright (c) 2004 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
(...skipping 406 matching lines...) Expand 10 before | Expand all | Expand 10 after
417 return false; 417 return false;
418 } 418 }
419 419
420 static const AudioCodec* GetPreferredCodec( 420 static const AudioCodec* GetPreferredCodec(
421 const std::vector<AudioCodec>& codecs, 421 const std::vector<AudioCodec>& codecs,
422 webrtc::CodecInst* out) { 422 webrtc::CodecInst* out) {
423 RTC_DCHECK(out); 423 RTC_DCHECK(out);
424 // Select the preferred send codec (the first non-telephone-event/CN codec). 424 // Select the preferred send codec (the first non-telephone-event/CN codec).
425 for (const AudioCodec& codec : codecs) { 425 for (const AudioCodec& codec : codecs) {
426 if (IsCodec(codec, kDtmfCodecName) || IsCodec(codec, kCnCodecName)) { 426 if (IsCodec(codec, kDtmfCodecName) || IsCodec(codec, kCnCodecName)) {
427 // Skip telephone-event/CN codec, which will be handled later. 427 // Skip telephone-event/CN codecs - they will be handled later.
428 continue; 428 continue;
429 } 429 }
430 430
431 // We'll use the first codec in the list to actually send audio data. 431 // We'll use the first codec in the list to actually send audio data.
432 // Be sure to use the payload type requested by the remote side. 432 // Be sure to use the payload type requested by the remote side.
433 // Ignore codecs we don't know about. The negotiation step should prevent 433 // Ignore codecs we don't know about. The negotiation step should prevent
434 // this, but double-check to be sure. 434 // this, but double-check to be sure.
435 if (!ToCodecInst(codec, out)) { 435 if (!ToCodecInst(codec, out)) {
436 LOG(LS_WARNING) << "Unknown codec " << ToString(codec); 436 LOG(LS_WARNING) << "Unknown codec " << ToString(codec);
437 continue; 437 continue;
438 } 438 }
439 return &codec; 439 return &codec;
440 } 440 }
441 return nullptr; 441 return nullptr;
442 } 442 }
443 443
444 private: 444 private:
445 static const int kMaxNumPacketSize = 6; 445 static const int kMaxNumPacketSize = 6;
446 struct CodecPref { 446 struct CodecPref {
447 const char* name; 447 const char* name;
448 int clockrate; 448 int clockrate;
449 size_t channels; 449 size_t channels;
450 int payload_type; 450 int payload_type;
451 bool is_multi_rate; 451 bool is_multi_rate;
452 int packet_sizes_ms[kMaxNumPacketSize]; 452 int packet_sizes_ms[kMaxNumPacketSize];
453 int max_bitrate_bps; 453 int max_bitrate_bps;
454 }; 454 };
455 // Note: keep the supported packet sizes in ascending order. 455 // Note: keep the supported packet sizes in ascending order.
456 static const CodecPref kCodecPrefs[11]; 456 static const CodecPref kCodecPrefs[14];
457 457
458 static int SelectPacketSize(const CodecPref& codec_pref, int ptime_ms) { 458 static int SelectPacketSize(const CodecPref& codec_pref, int ptime_ms) {
459 int selected_packet_size_ms = codec_pref.packet_sizes_ms[0]; 459 int selected_packet_size_ms = codec_pref.packet_sizes_ms[0];
460 for (int packet_size_ms : codec_pref.packet_sizes_ms) { 460 for (int packet_size_ms : codec_pref.packet_sizes_ms) {
461 if (packet_size_ms && packet_size_ms <= ptime_ms) { 461 if (packet_size_ms && packet_size_ms <= ptime_ms) {
462 selected_packet_size_ms = packet_size_ms; 462 selected_packet_size_ms = packet_size_ms;
463 } 463 }
464 } 464 }
465 return selected_packet_size_ms; 465 return selected_packet_size_ms;
466 } 466 }
467 467
468 // Changes RTP timestamp rate of G722. This is due to the "bug" in the RFC 468 // Changes RTP timestamp rate of G722. This is due to the "bug" in the RFC
469 // which says that G722 should be advertised as 8 kHz although it is a 16 kHz 469 // which says that G722 should be advertised as 8 kHz although it is a 16 kHz
470 // codec. 470 // codec.
471 static void MaybeFixupG722(webrtc::CodecInst* voe_codec, int new_plfreq) { 471 static void MaybeFixupG722(webrtc::CodecInst* voe_codec, int new_plfreq) {
472 if (IsCodec(*voe_codec, kG722CodecName)) { 472 if (IsCodec(*voe_codec, kG722CodecName)) {
473 // If the ASSERT triggers, the codec definition in WebRTC VoiceEngine 473 // If the ASSERT triggers, the codec definition in WebRTC VoiceEngine
474 // has changed, and this special case is no longer needed. 474 // has changed, and this special case is no longer needed.
475 RTC_DCHECK(voe_codec->plfreq != new_plfreq); 475 RTC_DCHECK(voe_codec->plfreq != new_plfreq);
476 voe_codec->plfreq = new_plfreq; 476 voe_codec->plfreq = new_plfreq;
477 } 477 }
478 } 478 }
479 }; 479 };
480 480
481 const WebRtcVoiceCodecs::CodecPref WebRtcVoiceCodecs::kCodecPrefs[11] = { 481 const WebRtcVoiceCodecs::CodecPref WebRtcVoiceCodecs::kCodecPrefs[14] = {
482 {kOpusCodecName, 48000, 2, 111, true, {10, 20, 40, 60}, kOpusMaxBitrateBps}, 482 {kOpusCodecName, 48000, 2, 111, true, {10, 20, 40, 60}, kOpusMaxBitrateBps},
483 {kIsacCodecName, 16000, 1, 103, true, {30, 60}, kIsacMaxBitrateBps}, 483 {kIsacCodecName, 16000, 1, 103, true, {30, 60}, kIsacMaxBitrateBps},
484 {kIsacCodecName, 32000, 1, 104, true, {30}, kIsacMaxBitrateBps}, 484 {kIsacCodecName, 32000, 1, 104, true, {30}, kIsacMaxBitrateBps},
485 // G722 should be advertised as 8000 Hz because of the RFC "bug". 485 // G722 should be advertised as 8000 Hz because of the RFC "bug".
486 {kG722CodecName, 8000, 1, 9, false, {10, 20, 30, 40, 50, 60}}, 486 {kG722CodecName, 8000, 1, 9, false, {10, 20, 30, 40, 50, 60}},
487 {kIlbcCodecName, 8000, 1, 102, false, {20, 30, 40, 60}}, 487 {kIlbcCodecName, 8000, 1, 102, false, {20, 30, 40, 60}},
488 {kPcmuCodecName, 8000, 1, 0, false, {10, 20, 30, 40, 50, 60}}, 488 {kPcmuCodecName, 8000, 1, 0, false, {10, 20, 30, 40, 50, 60}},
489 {kPcmaCodecName, 8000, 1, 8, false, {10, 20, 30, 40, 50, 60}}, 489 {kPcmaCodecName, 8000, 1, 8, false, {10, 20, 30, 40, 50, 60}},
490 {kCnCodecName, 32000, 1, 106, false, {}}, 490 {kCnCodecName, 32000, 1, 106, false, {}},
491 {kCnCodecName, 16000, 1, 105, false, {}}, 491 {kCnCodecName, 16000, 1, 105, false, {}},
492 {kCnCodecName, 8000, 1, 13, false, {}}, 492 {kCnCodecName, 8000, 1, 13, false, {}},
493 {kDtmfCodecName, 8000, 1, 126, false, {}}}; 493 {kDtmfCodecName, 48000, 1, 110, false, {}},
494 {kDtmfCodecName, 32000, 1, 112, false, {}},
495 {kDtmfCodecName, 16000, 1, 113, false, {}},
496 {kDtmfCodecName, 8000, 1, 126, false, {}}
497 };
494 498
495 rtc::Optional<int> ComputeSendBitrate(int max_send_bitrate_bps, 499 rtc::Optional<int> ComputeSendBitrate(int max_send_bitrate_bps,
496 int rtp_max_bitrate_bps, 500 int rtp_max_bitrate_bps,
497 const webrtc::CodecInst& codec_inst) { 501 const webrtc::CodecInst& codec_inst) {
498 const int bps = MinPositive(max_send_bitrate_bps, rtp_max_bitrate_bps); 502 const int bps = MinPositive(max_send_bitrate_bps, rtp_max_bitrate_bps);
499 const int codec_rate = codec_inst.rate; 503 const int codec_rate = codec_inst.rate;
500 504
501 if (bps <= 0) { 505 if (bps <= 0) {
502 return rtc::Optional<int>(codec_rate); 506 return rtc::Optional<int>(codec_rate);
503 } 507 }
(...skipping 613 matching lines...) Expand 10 before | Expand all | Expand 10 after
1117 RTC_DCHECK(apm_); 1121 RTC_DCHECK(apm_);
1118 return apm_; 1122 return apm_;
1119 } 1123 }
1120 1124
1121 AudioCodecs WebRtcVoiceEngine::CollectRecvCodecs() const { 1125 AudioCodecs WebRtcVoiceEngine::CollectRecvCodecs() const {
1122 PayloadTypeMapper mapper; 1126 PayloadTypeMapper mapper;
1123 AudioCodecs out; 1127 AudioCodecs out;
1124 const std::vector<webrtc::AudioCodecSpec>& specs = 1128 const std::vector<webrtc::AudioCodecSpec>& specs =
1125 decoder_factory_->GetSupportedDecoders(); 1129 decoder_factory_->GetSupportedDecoders();
1126 1130
1127 // Only generate CN payload types for these clockrates 1131 // Only generate CN payload types for these clockrates:
1128 std::map<int, bool, std::greater<int>> generate_cn = {{ 8000, false }, 1132 std::map<int, bool, std::greater<int>> generate_cn = {{ 8000, false },
1129 { 16000, false }, 1133 { 16000, false },
1130 { 32000, false }}; 1134 { 32000, false }};
1135 // Only generate telephone-event payload types for these clockrates:
1136 std::map<int, bool, std::greater<int>> generate_dtmf = {{ 8000, false },
1137 { 16000, false },
1138 { 32000, false },
1139 { 48000, false }};
1131 1140
1132 auto map_format = [&mapper, &out] (const webrtc::SdpAudioFormat& format) { 1141 auto map_format = [&mapper, &out] (const webrtc::SdpAudioFormat& format) {
1133 rtc::Optional<AudioCodec> opt_codec = mapper.ToAudioCodec(format); 1142 rtc::Optional<AudioCodec> opt_codec = mapper.ToAudioCodec(format);
1134 if (!opt_codec) { 1143 if (!opt_codec) {
1135 LOG(LS_ERROR) << "Unable to assign payload type to format: " << format; 1144 LOG(LS_ERROR) << "Unable to assign payload type to format: " << format;
1136 return false; 1145 return false;
1137 } 1146 }
1138 1147
1139 auto& codec = *opt_codec; 1148 auto& codec = *opt_codec;
1140 if (IsCodec(codec, kOpusCodecName)) { 1149 if (IsCodec(codec, kOpusCodecName)) {
1141 // TODO(ossu): Set this specifically for Opus for now, until we have a 1150 // TODO(ossu): Set this specifically for Opus for now, until we have a
1142 // better way of dealing with rtcp-fb parameters. 1151 // better way of dealing with rtcp-fb parameters.
1143 codec.AddFeedbackParam( 1152 codec.AddFeedbackParam(
1144 FeedbackParam(kRtcpFbParamTransportCc, kParamValueEmpty)); 1153 FeedbackParam(kRtcpFbParamTransportCc, kParamValueEmpty));
1145 } 1154 }
1146 out.push_back(codec); 1155 out.push_back(codec);
1147 return true; 1156 return true;
1148 }; 1157 };
1149 1158
1150 for (const auto& spec : specs) { 1159 for (const auto& spec : specs) {
1151 if (map_format(spec.format) && spec.allow_comfort_noise) { 1160 if (map_format(spec.format)) {
1152 // Generate a CN entry if the decoder allows it and we support the 1161 if (spec.allow_comfort_noise) {
1153 // clockrate. 1162 // Generate a CN entry if the decoder allows it and we support the
1154 auto cn = generate_cn.find(spec.format.clockrate_hz); 1163 // clockrate.
1155 if (cn != generate_cn.end()) { 1164 auto cn = generate_cn.find(spec.format.clockrate_hz);
1156 cn->second = true; 1165 if (cn != generate_cn.end()) {
1166 cn->second = true;
1167 }
1168 }
1169
1170 // Generate a telephone-event entry if we support the clockrate.
1171 auto dtmf = generate_dtmf.find(spec.format.clockrate_hz);
1172 if (dtmf != generate_dtmf.end()) {
1173 dtmf->second = true;
1157 } 1174 }
1158 } 1175 }
1159 } 1176 }
1160 1177
1161 // Add CN codecs after "proper" audio codecs 1178 // Add CN codecs after "proper" audio codecs.
1162 for (const auto& cn : generate_cn) { 1179 for (const auto& cn : generate_cn) {
1163 if (cn.second) { 1180 if (cn.second) {
1164 map_format({kCnCodecName, cn.first, 1}); 1181 map_format({kCnCodecName, cn.first, 1});
1165 } 1182 }
1166 } 1183 }
1167 1184
1168 // Add telephone-event codec last 1185 // Add telephone-event codecs last.
1169 map_format({kDtmfCodecName, 8000, 1}); 1186 for (const auto& dtmf : generate_dtmf) {
1187 if (dtmf.second) {
1188 map_format({kDtmfCodecName, dtmf.first, 1});
1189 }
1190 }
1170 1191
1171 return out; 1192 return out;
1172 } 1193 }
1173 1194
1174 class WebRtcVoiceMediaChannel::WebRtcAudioSendStream 1195 class WebRtcVoiceMediaChannel::WebRtcAudioSendStream
1175 : public AudioSource::Sink { 1196 : public AudioSource::Sink {
1176 public: 1197 public:
1177 WebRtcAudioSendStream( 1198 WebRtcAudioSendStream(
1178 int ch, 1199 int ch,
1179 webrtc::AudioTransport* voe_audio_transport, 1200 webrtc::AudioTransport* voe_audio_transport,
(...skipping 607 matching lines...) Expand 10 before | Expand all | Expand 10 after
1787 LOG(LS_ERROR) << "Codec payload types overlap."; 1808 LOG(LS_ERROR) << "Codec payload types overlap.";
1788 return false; 1809 return false;
1789 } 1810 }
1790 1811
1791 std::vector<AudioCodec> new_codecs; 1812 std::vector<AudioCodec> new_codecs;
1792 // Find all new codecs. We allow adding new codecs but don't allow changing 1813 // Find all new codecs. We allow adding new codecs but don't allow changing
1793 // the payload type of codecs that is already configured since we might 1814 // the payload type of codecs that is already configured since we might
1794 // already be receiving packets with that payload type. 1815 // already be receiving packets with that payload type.
1795 for (const AudioCodec& codec : codecs) { 1816 for (const AudioCodec& codec : codecs) {
1796 AudioCodec old_codec; 1817 AudioCodec old_codec;
1818 // TODO(solenberg): This isn't strictly correct. It should be possible to
1819 // add an additional payload type for a codec. That would result in a new
1820 // decoder object being allocated. What shouldn't work is to remove a PT
1821 // mapping that was previously configured.
1797 if (FindCodec(recv_codecs_, codec, &old_codec)) { 1822 if (FindCodec(recv_codecs_, codec, &old_codec)) {
1798 if (old_codec.id != codec.id) { 1823 if (old_codec.id != codec.id) {
1799 LOG(LS_ERROR) << codec.name << " payload type changed."; 1824 LOG(LS_ERROR) << codec.name << " payload type changed.";
1800 return false; 1825 return false;
1801 } 1826 }
1802 } else { 1827 } else {
1803 new_codecs.push_back(codec); 1828 new_codecs.push_back(codec);
1804 } 1829 }
1805 } 1830 }
1806 if (new_codecs.empty()) { 1831 if (new_codecs.empty()) {
(...skipping 771 matching lines...) Expand 10 before | Expand all | Expand 10 after
2578 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); 2603 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
2579 const auto it = send_streams_.find(ssrc); 2604 const auto it = send_streams_.find(ssrc);
2580 if (it != send_streams_.end()) { 2605 if (it != send_streams_.end()) {
2581 return it->second->channel(); 2606 return it->second->channel();
2582 } 2607 }
2583 return -1; 2608 return -1;
2584 } 2609 }
2585 } // namespace cricket 2610 } // namespace cricket
2586 2611
2587 #endif // HAVE_WEBRTC_VOICE 2612 #endif // HAVE_WEBRTC_VOICE
OLDNEW
« no previous file with comments | « webrtc/media/engine/payload_type_mapper_unittest.cc ('k') | webrtc/media/engine/webrtcvoiceengine_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698