diff --git a/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.cc b/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.cc index 47474f218..861401588 100644 --- a/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.cc +++ b/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.cc @@ -36,6 +36,16 @@ namespace webrtc { namespace { static const int kInvalidPayloadType = 255; +std::map>::iterator +FindSampleRateInMap( + std::map>* cng_pt_map, + int sample_rate_hz) { + return find_if(cng_pt_map->begin(), cng_pt_map->end(), + [sample_rate_hz](decltype(*cng_pt_map->begin()) p) { + return p.second.first == sample_rate_hz; + }); +} + void SetCngPtInMap( std::map>* cng_pt_map, int sample_rate_hz, @@ -61,6 +71,11 @@ void SetCngPtInMap( default: FATAL() << "Unsupported frequency."; } + auto pt_iter = FindSampleRateInMap(cng_pt_map, sample_rate_hz); + if (pt_iter != cng_pt_map->end()) { + // Remove item in map with sample_rate_hz. + cng_pt_map->erase(pt_iter); + } (*cng_pt_map)[payload_type] = std::make_pair(sample_rate_hz, encoding_type); } } // namespace @@ -1417,14 +1432,8 @@ void ACMGenericCodecWrapper::ResetAudioEncoder() { // Attach CNG if needed. // Reverse-lookup from sample rate to complete key-value pair. - const int sample_rate_hz = audio_encoder_->sample_rate_hz(); - // Create a local const reference to cng_pt_. The reason is that GCC doesn't - // accept using "const decltype(...)" for the argument in the lambda below. - const auto& cng_pt = cng_pt_; - auto pt_iter = find_if(cng_pt.begin(), cng_pt.end(), - [sample_rate_hz](decltype(*cng_pt.begin()) p) { - return p.second.first == sample_rate_hz; - }); + auto pt_iter = + FindSampleRateInMap(&cng_pt_, audio_encoder_->sample_rate_hz()); if (acm_codec_params_.enable_dtx && pt_iter != cng_pt_.end()) { AudioEncoderCng::Config config; config.num_channels = acm_codec_params_.codec_inst.channels; diff --git a/webrtc/modules/audio_coding/main/acm2/audio_coding_module_unittest_oldapi.cc b/webrtc/modules/audio_coding/main/acm2/audio_coding_module_unittest_oldapi.cc index 329edd336..f27b4cf19 100644 --- a/webrtc/modules/audio_coding/main/acm2/audio_coding_module_unittest_oldapi.cc +++ b/webrtc/modules/audio_coding/main/acm2/audio_coding_module_unittest_oldapi.cc @@ -325,7 +325,8 @@ TEST_F(AudioCodingModuleTestOldApi, TransportCallbackIsInvokedForEachPacket) { // Introduce this class to set different expectations on the number of encoded // bytes. This class expects all encoded packets to be 9 bytes (matching one // CNG SID frame) or 0 bytes. This test depends on |input_frame_| containing -// (near-)zero values. +// (near-)zero values. It also introduces a way to register comfort noise with +// a custom payload type. class AudioCodingModuleTestWithComfortNoiseOldApi : public AudioCodingModuleTestOldApi { protected: @@ -335,53 +336,80 @@ class AudioCodingModuleTestWithComfortNoiseOldApi // at all. EXPECT_TRUE(encoded_bytes == 9 || encoded_bytes == 0); } + + void RegisterCngCodec(int rtp_payload_type) { + CodecInst codec; + AudioCodingModule::Codec("CN", &codec, kSampleRateHz, 1); + codec.pltype = rtp_payload_type; + ASSERT_EQ(0, acm_->RegisterReceiveCodec(codec)); + ASSERT_EQ(0, acm_->RegisterSendCodec(codec)); + } + + void DoTest(int blocks_per_packet, int cng_pt) { + const int kLoops = 40; + // This array defines the expected frame types, and when they should arrive. + // We expect a frame to arrive each time the speech encoder would have + // produced a packet, and once every 100 ms the frame should be non-empty, + // that is contain comfort noise. + const struct { + int ix; + FrameType type; + } expectation[] = {{2, kAudioFrameCN}, + {5, kFrameEmpty}, + {8, kFrameEmpty}, + {11, kAudioFrameCN}, + {14, kFrameEmpty}, + {17, kFrameEmpty}, + {20, kAudioFrameCN}, + {23, kFrameEmpty}, + {26, kFrameEmpty}, + {29, kFrameEmpty}, + {32, kAudioFrameCN}, + {35, kFrameEmpty}, + {38, kFrameEmpty}}; + for (int i = 0; i < kLoops; ++i) { + int num_calls_before = packet_cb_.num_calls(); + EXPECT_EQ(i / blocks_per_packet, num_calls_before); + InsertAudio(); + Encode(); + int num_calls = packet_cb_.num_calls(); + if (num_calls == num_calls_before + 1) { + EXPECT_EQ(expectation[num_calls - 1].ix, i); + EXPECT_EQ(expectation[num_calls - 1].type, packet_cb_.last_frame_type()) + << "Wrong frame type for lap " << i; + EXPECT_EQ(cng_pt, packet_cb_.last_payload_type()); + } else { + EXPECT_EQ(num_calls, num_calls_before); + } + } + } }; -// Checks that the transport callback is invoked once for frame period of the +// Checks that the transport callback is invoked once per frame period of the // underlying speech encoder, even when comfort noise is produced. // Also checks that the frame type is kAudioFrameCN or kFrameEmpty. +// This test and the next check the same thing, but differ in the order of +// speech codec and CNG registration. TEST_F(AudioCodingModuleTestWithComfortNoiseOldApi, - TransportCallbackTestForComfortNoise) { + TransportCallbackTestForComfortNoiseRegisterCngLast) { const int k10MsBlocksPerPacket = 3; packet_size_samples_ = k10MsBlocksPerPacket * kSampleRateHz / 100; RegisterCodec(); + const int kCngPayloadType = 105; + RegisterCngCodec(kCngPayloadType); ASSERT_EQ(0, acm_->SetVAD(true, true)); - const int kLoops = 40; - // This array defines the expected frame types, and when they should arrive. - // We expect a frame to arrive each time the speech encoder would have - // produced a packet, and once every 100 ms the frame should be non-empty, - // that is contain comfort noise. - const struct { - int ix; - FrameType type; - } expectation[] = {{2, kAudioFrameCN}, - {5, kFrameEmpty}, - {8, kFrameEmpty}, - {11, kAudioFrameCN}, - {14, kFrameEmpty}, - {17, kFrameEmpty}, - {20, kAudioFrameCN}, - {23, kFrameEmpty}, - {26, kFrameEmpty}, - {29, kFrameEmpty}, - {32, kAudioFrameCN}, - {35, kFrameEmpty}, - {38, kFrameEmpty}}; - for (int i = 0; i < kLoops; ++i) { - int num_calls_before = packet_cb_.num_calls(); - EXPECT_EQ(i / k10MsBlocksPerPacket, num_calls_before); - InsertAudio(); - Encode(); - int num_calls = packet_cb_.num_calls(); - if (num_calls == num_calls_before + 1) { - EXPECT_EQ(expectation[num_calls - 1].ix, i); - EXPECT_EQ(expectation[num_calls - 1].type, packet_cb_.last_frame_type()) - << "Wrong frame type for lap " << i; - EXPECT_EQ(98, packet_cb_.last_payload_type()); // Default CNG-wb type. - } else { - EXPECT_EQ(num_calls, num_calls_before); - } - } + DoTest(k10MsBlocksPerPacket, kCngPayloadType); +} + +TEST_F(AudioCodingModuleTestWithComfortNoiseOldApi, + TransportCallbackTestForComfortNoiseRegisterCngFirst) { + const int k10MsBlocksPerPacket = 3; + packet_size_samples_ = k10MsBlocksPerPacket * kSampleRateHz / 100; + const int kCngPayloadType = 105; + RegisterCngCodec(kCngPayloadType); + RegisterCodec(); + ASSERT_EQ(0, acm_->SetVAD(true, true)); + DoTest(k10MsBlocksPerPacket, kCngPayloadType); } // A multi-threaded test for ACM. This base class is using the PCM16b 16 kHz