diff --git a/webrtc/modules/audio_coding/neteq/dtmf_buffer.cc b/webrtc/modules/audio_coding/neteq/dtmf_buffer.cc index 779d1d340b..3685fc1ef4 100644 --- a/webrtc/modules/audio_coding/neteq/dtmf_buffer.cc +++ b/webrtc/modules/audio_coding/neteq/dtmf_buffer.cc @@ -99,7 +99,7 @@ int DtmfBuffer::ParseEvent(uint32_t rtp_timestamp, // existing one. int DtmfBuffer::InsertEvent(const DtmfEvent& event) { if (event.event_no < 0 || event.event_no > 15 || - event.volume < 0 || event.volume > 36 || + event.volume < 0 || event.volume > 63 || event.duration <= 0 || event.duration > 65535) { LOG(LS_WARNING) << "InsertEvent invalid parameters"; return kInvalidEventParameters; diff --git a/webrtc/modules/audio_coding/neteq/dtmf_buffer_unittest.cc b/webrtc/modules/audio_coding/neteq/dtmf_buffer_unittest.cc index 1252f819d1..d906d1ca52 100644 --- a/webrtc/modules/audio_coding/neteq/dtmf_buffer_unittest.cc +++ b/webrtc/modules/audio_coding/neteq/dtmf_buffer_unittest.cc @@ -282,7 +282,7 @@ TEST(DtmfBuffer, InvalidEvents) { // Invalid volume. event.volume = -1; EXPECT_EQ(DtmfBuffer::kInvalidEventParameters, buffer.InsertEvent(event)); - event.volume = 37; + event.volume = 64; EXPECT_EQ(DtmfBuffer::kInvalidEventParameters, buffer.InsertEvent(event)); event.volume = 0; // Valid value; diff --git a/webrtc/modules/audio_coding/neteq/dtmf_tone_generator.cc b/webrtc/modules/audio_coding/neteq/dtmf_tone_generator.cc index f4d5190c61..8b4b9d3f4f 100644 --- a/webrtc/modules/audio_coding/neteq/dtmf_tone_generator.cc +++ b/webrtc/modules/audio_coding/neteq/dtmf_tone_generator.cc @@ -30,7 +30,8 @@ #include "webrtc/modules/audio_coding/neteq/dtmf_tone_generator.h" -#include +#include "webrtc/base/arraysize.h" +#include "webrtc/base/checks.h" namespace webrtc { @@ -86,12 +87,16 @@ const int DtmfToneGenerator::kInitValue2[4][16] = { { 2851, 2582, 2851, 3148, 2582, 2851, 3148, 2582, 2851, 3148, 2582, 3148, 3476, 3476, 3476, 3476} }; -// Amplitude multipliers for volume values 0 through 36, corresponding to -// 0 dBm0 through -36 dBm0. Values are in Q14. -const int DtmfToneGenerator::kAmplitude[37] = { +// Amplitude multipliers for volume values 0 through 63, corresponding to +// 0 dBm0 through -63 dBm0. Values are in Q14. +// for a in range(0, 64): +// print round(16141.0 * 10**(-float(a)/20)) +const int DtmfToneGenerator::kAmplitude[64] = { 16141, 14386, 12821, 11427, 10184, 9077, 8090, 7210, 6426, 5727, 5104, 4549, 4054, 3614, 3221, 2870, 2558, 2280, 2032, 1811, 1614, 1439, 1282, 1143, - 1018, 908, 809, 721, 643, 573, 510, 455, 405, 361, 322, 287, 256 }; + 1018, 908, 809, 721, 643, 573, 510, 455, 405, 361, 322, 287, 256, 228, 203, + 181, 161, 144, 128, 114, 102, 91, 81, 72, 64, 57, 51, 45, 41, 36, 32, 29, + 26, 23, 20, 18, 16, 14, 13, 11 }; // Constructor. DtmfToneGenerator::DtmfToneGenerator() @@ -106,7 +111,7 @@ DtmfToneGenerator::DtmfToneGenerator() // Returns 0 on success, otherwise an error code. int DtmfToneGenerator::Init(int fs, int event, int attenuation) { initialized_ = false; - int fs_index; + size_t fs_index; if (fs == 8000) { fs_index = 0; } else if (fs == 16000) { @@ -116,7 +121,7 @@ int DtmfToneGenerator::Init(int fs, int event, int attenuation) { } else if (fs == 48000) { fs_index = 3; } else { - assert(false); + RTC_NOTREACHED(); fs_index = 1; // Default to 8000 Hz. } @@ -124,16 +129,32 @@ int DtmfToneGenerator::Init(int fs, int event, int attenuation) { return kParameterError; // Invalid event number. } - if (attenuation < 0 || attenuation > 36) { + if (attenuation < 0 || attenuation > 63) { return kParameterError; // Invalid attenuation. } // Look up oscillator coefficient for low and high frequencies. + RTC_DCHECK_LE(0u, fs_index); + RTC_DCHECK_GT(arraysize(kCoeff1), fs_index); + RTC_DCHECK_GT(arraysize(kCoeff2), fs_index); + RTC_DCHECK_LE(0, event); + RTC_DCHECK_GT(arraysize(kCoeff1[fs_index]), static_cast(event)); + RTC_DCHECK_GT(arraysize(kCoeff2[fs_index]), static_cast(event)); coeff1_ = kCoeff1[fs_index][event]; coeff2_ = kCoeff2[fs_index][event]; + // Look up amplitude multiplier. + RTC_DCHECK_LE(0, attenuation); + RTC_DCHECK_GT(arraysize(kAmplitude), static_cast(attenuation)); amplitude_ = kAmplitude[attenuation]; + // Initialize sample history. + RTC_DCHECK_LE(0u, fs_index); + RTC_DCHECK_GT(arraysize(kInitValue1), fs_index); + RTC_DCHECK_GT(arraysize(kInitValue2), fs_index); + RTC_DCHECK_LE(0, event); + RTC_DCHECK_GT(arraysize(kInitValue1[fs_index]), static_cast(event)); + RTC_DCHECK_GT(arraysize(kInitValue2[fs_index]), static_cast(event)); sample_history1_[0] = kInitValue1[fs_index][event]; sample_history1_[1] = 0; sample_history2_[0] = kInitValue2[fs_index][event]; diff --git a/webrtc/modules/audio_coding/neteq/dtmf_tone_generator.h b/webrtc/modules/audio_coding/neteq/dtmf_tone_generator.h index 36d902ad3f..9abd03eb09 100644 --- a/webrtc/modules/audio_coding/neteq/dtmf_tone_generator.h +++ b/webrtc/modules/audio_coding/neteq/dtmf_tone_generator.h @@ -38,7 +38,7 @@ class DtmfToneGenerator { static const int kCoeff2[4][16]; // 2nd oscillator model coefficient table. static const int kInitValue1[4][16]; // Initialization for 1st oscillator. static const int kInitValue2[4][16]; // Initialization for 2nd oscillator. - static const int kAmplitude[37]; // Amplitude for 0 through -36 dBm0. + static const int kAmplitude[64]; // Amplitude for 0 through -63 dBm0. static const int16_t kAmpMultiplier = 23171; // 3 dB attenuation (in Q15). bool initialized_; // True if generator is initialized properly. diff --git a/webrtc/modules/audio_coding/neteq/dtmf_tone_generator_unittest.cc b/webrtc/modules/audio_coding/neteq/dtmf_tone_generator_unittest.cc index 1da383fc65..9eea103ed5 100644 --- a/webrtc/modules/audio_coding/neteq/dtmf_tone_generator_unittest.cc +++ b/webrtc/modules/audio_coding/neteq/dtmf_tone_generator_unittest.cc @@ -70,7 +70,7 @@ class DtmfToneGeneratorTest : public ::testing::Test { ASSERT_EQ(0, tone_gen_.Init(fs_hz, event, 0)); // 0 attenuation. EXPECT_EQ(kNumSamples, tone_gen_.Generate(kNumSamples, &ref_signal)); // Test every 5 steps (to save time). - for (int attenuation = 1; attenuation <= 36; attenuation += 5) { + for (int attenuation = 1; attenuation <= 63; attenuation += 5) { std::ostringstream ss; ss << "Checking event " << event << " at sample rate " << fs_hz; ss << "; attenuation " << attenuation; @@ -164,8 +164,8 @@ TEST(DtmfToneGenerator, TestErrors) { tone_gen.Init(fs, 16, attenuation)); // Initialize with invalid attenuation -1. EXPECT_EQ(DtmfToneGenerator::kParameterError, tone_gen.Init(fs, event, -1)); - // Initialize with invalid attenuation 37. - EXPECT_EQ(DtmfToneGenerator::kParameterError, tone_gen.Init(fs, event, 37)); + // Initialize with invalid attenuation 64. + EXPECT_EQ(DtmfToneGenerator::kParameterError, tone_gen.Init(fs, event, 64)); EXPECT_FALSE(tone_gen.initialized()); // Should still be uninitialized. // Initialize with valid parameters. diff --git a/webrtc/modules/audio_coding/neteq/neteq_impl_unittest.cc b/webrtc/modules/audio_coding/neteq/neteq_impl_unittest.cc index 1859e566e7..8fba41e737 100644 --- a/webrtc/modules/audio_coding/neteq/neteq_impl_unittest.cc +++ b/webrtc/modules/audio_coding/neteq/neteq_impl_unittest.cc @@ -381,6 +381,39 @@ TEST_F(NetEqImplTest, InsertPacketsUntilBufferIsFull) { EXPECT_EQ(rtp_header.header.sequenceNumber, test_header->sequenceNumber); } +TEST_F(NetEqImplTest, TestDtmfPacket) { + UseNoMocks(); + CreateInstance(); + const size_t kPayloadLength = 4; + const uint8_t kPayloadType = 110; + const uint32_t kReceiveTime = 17; + const int kSampleRateHz = 8000; + // Event: 2, E bit, Volume: 63, Length: 4176. + uint8_t payload[kPayloadLength] = { 0x02, 0x80 + 0x3F, 0x10, 0xF0 }; + WebRtcRTPHeader rtp_header; + rtp_header.header.payloadType = kPayloadType; + rtp_header.header.sequenceNumber = 0x1234; + rtp_header.header.timestamp = 0x12345678; + rtp_header.header.ssrc = 0x87654321; + + EXPECT_EQ(NetEq::kOK, neteq_->RegisterPayloadType( + NetEqDecoder::kDecoderAVT, "telephone-event", kPayloadType)); + + // Insert one packet. + EXPECT_EQ(NetEq::kOK, + neteq_->InsertPacket(rtp_header, payload, kReceiveTime)); + + // Pull audio once. + const size_t kMaxOutputSize = static_cast(10 * kSampleRateHz / 1000); + AudioFrame output; + bool muted; + EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output, &muted)); + ASSERT_FALSE(muted); + ASSERT_EQ(kMaxOutputSize, output.samples_per_channel_); + EXPECT_EQ(1u, output.num_channels_); + EXPECT_EQ(AudioFrame::kNormalSpeech, output.speech_type_); +} + // This test verifies that timestamps propagate from the incoming packets // through to the sync buffer and to the playout timestamp. TEST_F(NetEqImplTest, VerifyTimestampPropagation) {