Fix an issue with comfort noise in ACMGenericCodecWrapper
In some cases it was not possible to set another payload type for CNG than the default one. This CL fixes this. The problem was also dependent on whether the comfort noise codec was registered before or after the speech codec. A test is implement to expose the bug, registering comfort noise at a non-default payload type, and both before and after the speech codec. BUG=4228 R=kwiberg@webrtc.org Review URL: https://webrtc-codereview.appspot.com/35199004 Cr-Commit-Position: refs/heads/master@{#8380} git-svn-id: http://webrtc.googlecode.com/svn/trunk@8380 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
e9f0f591b5
commit
34509d9f33
@ -36,6 +36,16 @@ namespace webrtc {
|
||||
namespace {
|
||||
static const int kInvalidPayloadType = 255;
|
||||
|
||||
std::map<int, std::pair<int, WebRtcACMEncodingType>>::iterator
|
||||
FindSampleRateInMap(
|
||||
std::map<int, std::pair<int, WebRtcACMEncodingType>>* 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<int, std::pair<int, WebRtcACMEncodingType>>* 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;
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user