Fix bug in DTMF generation where events with level > 36 would be ignored.
BUG=webrtc:2795 Review-Url: https://codereview.webrtc.org/2404183003 Cr-Commit-Position: refs/heads/master@{#14598}
This commit is contained in:
parent
113bdcadf3
commit
99df6c03c3
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -30,7 +30,8 @@
|
||||
|
||||
#include "webrtc/modules/audio_coding/neteq/dtmf_tone_generator.h"
|
||||
|
||||
#include <assert.h>
|
||||
#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<size_t>(event));
|
||||
RTC_DCHECK_GT(arraysize(kCoeff2[fs_index]), static_cast<size_t>(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<size_t>(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<size_t>(event));
|
||||
RTC_DCHECK_GT(arraysize(kInitValue2[fs_index]), static_cast<size_t>(event));
|
||||
sample_history1_[0] = kInitValue1[fs_index][event];
|
||||
sample_history1_[1] = 0;
|
||||
sample_history2_[0] = kInitValue2[fs_index][event];
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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<size_t>(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) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user