Minor updates to AudioEncoderCng
Removing sample_rate_hz_ from AudioEncoderCng and from the config struct. The sample rate will now be read from the underlying speech codec. BUG=3926 COAUTHOR:kwiberg@webrtc.org R=tina.legrand@webrtc.org Review URL: https://webrtc-codereview.appspot.com/40559004 Cr-Commit-Position: refs/heads/master@{#8173} git-svn-id: http://webrtc.googlecode.com/svn/trunk@8173 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
db1ebf6c0c
commit
8bb32d600b
@ -15,8 +15,7 @@
|
|||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
|
|
||||||
AudioEncoderCng::Config::Config()
|
AudioEncoderCng::Config::Config()
|
||||||
: sample_rate_hz(8000),
|
: num_channels(1),
|
||||||
num_channels(1),
|
|
||||||
payload_type(13),
|
payload_type(13),
|
||||||
speech_encoder(NULL),
|
speech_encoder(NULL),
|
||||||
vad_mode(Vad::kVadNormal),
|
vad_mode(Vad::kVadNormal),
|
||||||
@ -26,8 +25,6 @@ AudioEncoderCng::Config::Config()
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool AudioEncoderCng::Config::IsOk() const {
|
bool AudioEncoderCng::Config::IsOk() const {
|
||||||
if (sample_rate_hz != 8000 && sample_rate_hz != 16000)
|
|
||||||
return false;
|
|
||||||
if (num_channels != 1)
|
if (num_channels != 1)
|
||||||
return false;
|
return false;
|
||||||
if (!speech_encoder)
|
if (!speech_encoder)
|
||||||
@ -44,8 +41,6 @@ bool AudioEncoderCng::Config::IsOk() const {
|
|||||||
|
|
||||||
AudioEncoderCng::AudioEncoderCng(const Config& config)
|
AudioEncoderCng::AudioEncoderCng(const Config& config)
|
||||||
: speech_encoder_(config.speech_encoder),
|
: speech_encoder_(config.speech_encoder),
|
||||||
sample_rate_hz_(config.sample_rate_hz),
|
|
||||||
num_channels_(config.num_channels),
|
|
||||||
cng_payload_type_(config.payload_type),
|
cng_payload_type_(config.payload_type),
|
||||||
num_cng_coefficients_(config.num_cng_coefficients),
|
num_cng_coefficients_(config.num_cng_coefficients),
|
||||||
first_timestamp_in_buffer_(0),
|
first_timestamp_in_buffer_(0),
|
||||||
@ -60,7 +55,7 @@ AudioEncoderCng::AudioEncoderCng(const Config& config)
|
|||||||
CNG_enc_inst* cng_inst;
|
CNG_enc_inst* cng_inst;
|
||||||
CHECK_EQ(WebRtcCng_CreateEnc(&cng_inst), 0) << "WebRtcCng_CreateEnc failed.";
|
CHECK_EQ(WebRtcCng_CreateEnc(&cng_inst), 0) << "WebRtcCng_CreateEnc failed.";
|
||||||
cng_inst_.reset(cng_inst); // Transfer ownership to scoped_ptr.
|
cng_inst_.reset(cng_inst); // Transfer ownership to scoped_ptr.
|
||||||
CHECK_EQ(WebRtcCng_InitEnc(cng_inst_.get(), sample_rate_hz_,
|
CHECK_EQ(WebRtcCng_InitEnc(cng_inst_.get(), sample_rate_hz(),
|
||||||
config.sid_frame_interval_ms,
|
config.sid_frame_interval_ms,
|
||||||
config.num_cng_coefficients),
|
config.num_cng_coefficients),
|
||||||
0)
|
0)
|
||||||
@ -71,7 +66,7 @@ AudioEncoderCng::~AudioEncoderCng() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int AudioEncoderCng::sample_rate_hz() const {
|
int AudioEncoderCng::sample_rate_hz() const {
|
||||||
return sample_rate_hz_;
|
return speech_encoder_->sample_rate_hz();
|
||||||
}
|
}
|
||||||
|
|
||||||
int AudioEncoderCng::rtp_timestamp_rate_hz() const {
|
int AudioEncoderCng::rtp_timestamp_rate_hz() const {
|
||||||
@ -79,7 +74,7 @@ int AudioEncoderCng::rtp_timestamp_rate_hz() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int AudioEncoderCng::num_channels() const {
|
int AudioEncoderCng::num_channels() const {
|
||||||
return num_channels_;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int AudioEncoderCng::Num10MsFramesInNextPacket() const {
|
int AudioEncoderCng::Num10MsFramesInNextPacket() const {
|
||||||
@ -124,7 +119,7 @@ bool AudioEncoderCng::EncodeInternal(uint32_t rtp_timestamp,
|
|||||||
}
|
}
|
||||||
CHECK_LE(frames_in_buffer_, 6)
|
CHECK_LE(frames_in_buffer_, 6)
|
||||||
<< "Frame size cannot be larger than 60 ms when using VAD/CNG.";
|
<< "Frame size cannot be larger than 60 ms when using VAD/CNG.";
|
||||||
const size_t samples_per_10ms_frame = 10 * sample_rate_hz_ / 1000;
|
const size_t samples_per_10ms_frame = 10 * sample_rate_hz() / 1000;
|
||||||
CHECK_EQ(speech_buffer_.size(),
|
CHECK_EQ(speech_buffer_.size(),
|
||||||
static_cast<size_t>(frames_in_buffer_) * samples_per_10ms_frame);
|
static_cast<size_t>(frames_in_buffer_) * samples_per_10ms_frame);
|
||||||
|
|
||||||
@ -144,12 +139,12 @@ bool AudioEncoderCng::EncodeInternal(uint32_t rtp_timestamp,
|
|||||||
// block.
|
// block.
|
||||||
Vad::Activity activity = vad_->VoiceActivity(
|
Vad::Activity activity = vad_->VoiceActivity(
|
||||||
&speech_buffer_[0], samples_per_10ms_frame * blocks_in_first_vad_call,
|
&speech_buffer_[0], samples_per_10ms_frame * blocks_in_first_vad_call,
|
||||||
sample_rate_hz_);
|
sample_rate_hz());
|
||||||
if (activity == Vad::kPassive && blocks_in_second_vad_call > 0) {
|
if (activity == Vad::kPassive && blocks_in_second_vad_call > 0) {
|
||||||
// Only check the second block if the first was passive.
|
// Only check the second block if the first was passive.
|
||||||
activity = vad_->VoiceActivity(
|
activity = vad_->VoiceActivity(
|
||||||
&speech_buffer_[samples_per_10ms_frame * blocks_in_first_vad_call],
|
&speech_buffer_[samples_per_10ms_frame * blocks_in_first_vad_call],
|
||||||
samples_per_10ms_frame * blocks_in_second_vad_call, sample_rate_hz_);
|
samples_per_10ms_frame * blocks_in_second_vad_call, sample_rate_hz());
|
||||||
}
|
}
|
||||||
DCHECK_NE(activity, Vad::kError);
|
DCHECK_NE(activity, Vad::kError);
|
||||||
|
|
||||||
@ -181,7 +176,7 @@ bool AudioEncoderCng::EncodeInternal(uint32_t rtp_timestamp,
|
|||||||
bool AudioEncoderCng::EncodePassive(uint8_t* encoded, size_t* encoded_bytes) {
|
bool AudioEncoderCng::EncodePassive(uint8_t* encoded, size_t* encoded_bytes) {
|
||||||
bool force_sid = last_frame_active_;
|
bool force_sid = last_frame_active_;
|
||||||
bool output_produced = false;
|
bool output_produced = false;
|
||||||
const size_t samples_per_10ms_frame = 10 * sample_rate_hz_ / 1000;
|
const size_t samples_per_10ms_frame = 10 * sample_rate_hz() / 1000;
|
||||||
for (int i = 0; i < frames_in_buffer_; ++i) {
|
for (int i = 0; i < frames_in_buffer_; ++i) {
|
||||||
int16_t encoded_bytes_tmp = 0;
|
int16_t encoded_bytes_tmp = 0;
|
||||||
if (WebRtcCng_Encode(cng_inst_.get(),
|
if (WebRtcCng_Encode(cng_inst_.get(),
|
||||||
@ -195,7 +190,6 @@ bool AudioEncoderCng::EncodePassive(uint8_t* encoded, size_t* encoded_bytes) {
|
|||||||
output_produced = true;
|
output_produced = true;
|
||||||
force_sid = false;
|
force_sid = false;
|
||||||
}
|
}
|
||||||
CHECK(!force_sid) << "SID frame not produced despite being forced.";
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -203,7 +197,7 @@ bool AudioEncoderCng::EncodePassive(uint8_t* encoded, size_t* encoded_bytes) {
|
|||||||
bool AudioEncoderCng::EncodeActive(size_t max_encoded_bytes,
|
bool AudioEncoderCng::EncodeActive(size_t max_encoded_bytes,
|
||||||
uint8_t* encoded,
|
uint8_t* encoded,
|
||||||
EncodedInfo* info) {
|
EncodedInfo* info) {
|
||||||
const size_t samples_per_10ms_frame = 10 * sample_rate_hz_ / 1000;
|
const size_t samples_per_10ms_frame = 10 * sample_rate_hz() / 1000;
|
||||||
for (int i = 0; i < frames_in_buffer_; ++i) {
|
for (int i = 0; i < frames_in_buffer_; ++i) {
|
||||||
if (!speech_encoder_->Encode(first_timestamp_in_buffer_,
|
if (!speech_encoder_->Encode(first_timestamp_in_buffer_,
|
||||||
&speech_buffer_[i * samples_per_10ms_frame],
|
&speech_buffer_[i * samples_per_10ms_frame],
|
||||||
|
@ -34,7 +34,8 @@ class AudioEncoderCngTest : public ::testing::Test {
|
|||||||
AudioEncoderCngTest()
|
AudioEncoderCngTest()
|
||||||
: mock_vad_(new MockVad(Vad::kVadNormal)),
|
: mock_vad_(new MockVad(Vad::kVadNormal)),
|
||||||
timestamp_(4711),
|
timestamp_(4711),
|
||||||
num_audio_samples_10ms_(0) {
|
num_audio_samples_10ms_(0),
|
||||||
|
sample_rate_hz_(8000) {
|
||||||
memset(encoded_, 0, kMaxEncodedBytes);
|
memset(encoded_, 0, kMaxEncodedBytes);
|
||||||
memset(audio_, 0, kMaxNumSamples * 2);
|
memset(audio_, 0, kMaxNumSamples * 2);
|
||||||
config_.speech_encoder = &mock_encoder_;
|
config_.speech_encoder = &mock_encoder_;
|
||||||
@ -57,10 +58,10 @@ class AudioEncoderCngTest : public ::testing::Test {
|
|||||||
void CreateCng() {
|
void CreateCng() {
|
||||||
// The config_ parameters may be changed by the TEST_Fs up until CreateCng()
|
// The config_ parameters may be changed by the TEST_Fs up until CreateCng()
|
||||||
// is called, thus we cannot use the values until now.
|
// is called, thus we cannot use the values until now.
|
||||||
num_audio_samples_10ms_ = 10 * config_.sample_rate_hz / 1000;
|
num_audio_samples_10ms_ = 10 * sample_rate_hz_ / 1000;
|
||||||
ASSERT_LE(num_audio_samples_10ms_, kMaxNumSamples);
|
ASSERT_LE(num_audio_samples_10ms_, kMaxNumSamples);
|
||||||
EXPECT_CALL(mock_encoder_, sample_rate_hz())
|
EXPECT_CALL(mock_encoder_, sample_rate_hz())
|
||||||
.WillRepeatedly(Return(config_.sample_rate_hz));
|
.WillRepeatedly(Return(sample_rate_hz_));
|
||||||
// Max10MsFramesInAPacket() is just used to verify that the SID frame period
|
// Max10MsFramesInAPacket() is just used to verify that the SID frame period
|
||||||
// is not too small. The return value does not matter that much, as long as
|
// is not too small. The return value does not matter that much, as long as
|
||||||
// it is smaller than 10.
|
// it is smaller than 10.
|
||||||
@ -133,17 +134,16 @@ class AudioEncoderCngTest : public ::testing::Test {
|
|||||||
|
|
||||||
// Let the VAD decision be passive, since an active decision may lead to
|
// Let the VAD decision be passive, since an active decision may lead to
|
||||||
// early termination of the decision loop.
|
// early termination of the decision loop.
|
||||||
const int sample_rate_hz = config_.sample_rate_hz;
|
|
||||||
InSequence s;
|
InSequence s;
|
||||||
EXPECT_CALL(
|
EXPECT_CALL(
|
||||||
*mock_vad_,
|
*mock_vad_,
|
||||||
VoiceActivity(_, expected_first_block_size_ms * sample_rate_hz / 1000,
|
VoiceActivity(_, expected_first_block_size_ms * sample_rate_hz_ / 1000,
|
||||||
sample_rate_hz)).WillOnce(Return(Vad::kPassive));
|
sample_rate_hz_)).WillOnce(Return(Vad::kPassive));
|
||||||
if (expected_second_block_size_ms > 0) {
|
if (expected_second_block_size_ms > 0) {
|
||||||
EXPECT_CALL(*mock_vad_,
|
EXPECT_CALL(*mock_vad_,
|
||||||
VoiceActivity(
|
VoiceActivity(
|
||||||
_, expected_second_block_size_ms * sample_rate_hz / 1000,
|
_, expected_second_block_size_ms * sample_rate_hz_ / 1000,
|
||||||
sample_rate_hz)).WillOnce(Return(Vad::kPassive));
|
sample_rate_hz_)).WillOnce(Return(Vad::kPassive));
|
||||||
}
|
}
|
||||||
|
|
||||||
// With this call to Encode(), |mock_vad_| should be called according to the
|
// With this call to Encode(), |mock_vad_| should be called according to the
|
||||||
@ -184,6 +184,7 @@ class AudioEncoderCngTest : public ::testing::Test {
|
|||||||
size_t num_audio_samples_10ms_;
|
size_t num_audio_samples_10ms_;
|
||||||
uint8_t encoded_[kMaxEncodedBytes];
|
uint8_t encoded_[kMaxEncodedBytes];
|
||||||
AudioEncoder::EncodedInfo encoded_info_;
|
AudioEncoder::EncodedInfo encoded_info_;
|
||||||
|
int sample_rate_hz_;
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(AudioEncoderCngTest, CreateAndDestroy) {
|
TEST_F(AudioEncoderCngTest, CreateAndDestroy) {
|
||||||
@ -427,20 +428,6 @@ TEST_F(AudioEncoderCngDeathTest, WrongFrameSize) {
|
|||||||
EXPECT_DEATH(Encode(), "");
|
EXPECT_DEATH(Encode(), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(AudioEncoderCngDeathTest, WrongSampleRates) {
|
|
||||||
config_.sample_rate_hz = 32000;
|
|
||||||
EXPECT_DEATH(CreateCng(), "Invalid configuration");
|
|
||||||
config_.sample_rate_hz = 48000;
|
|
||||||
EXPECT_DEATH(CreateCng(), "Invalid configuration");
|
|
||||||
config_.sample_rate_hz = 0;
|
|
||||||
EXPECT_DEATH(CreateCng(), "Invalid configuration");
|
|
||||||
config_.sample_rate_hz = -8000;
|
|
||||||
// Don't use CreateCng() here, since the built-in sanity checks will prevent
|
|
||||||
// the test from reaching the expected point-of-death.
|
|
||||||
EXPECT_DEATH(cng_.reset(new AudioEncoderCng(config_)),
|
|
||||||
"Invalid configuration");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(AudioEncoderCngDeathTest, WrongNumCoefficients) {
|
TEST_F(AudioEncoderCngDeathTest, WrongNumCoefficients) {
|
||||||
config_.num_cng_coefficients = -1;
|
config_.num_cng_coefficients = -1;
|
||||||
EXPECT_DEATH(CreateCng(), "Invalid configuration");
|
EXPECT_DEATH(CreateCng(), "Invalid configuration");
|
||||||
|
@ -22,13 +22,12 @@ namespace webrtc {
|
|||||||
|
|
||||||
class Vad;
|
class Vad;
|
||||||
|
|
||||||
class AudioEncoderCng : public AudioEncoder {
|
class AudioEncoderCng final : public AudioEncoder {
|
||||||
public:
|
public:
|
||||||
struct Config {
|
struct Config {
|
||||||
Config();
|
Config();
|
||||||
bool IsOk() const;
|
bool IsOk() const;
|
||||||
|
|
||||||
int sample_rate_hz;
|
|
||||||
int num_channels;
|
int num_channels;
|
||||||
int payload_type;
|
int payload_type;
|
||||||
// Caller keeps ownership of the AudioEncoder object.
|
// Caller keeps ownership of the AudioEncoder object.
|
||||||
@ -76,8 +75,6 @@ class AudioEncoderCng : public AudioEncoder {
|
|||||||
EncodedInfo* info);
|
EncodedInfo* info);
|
||||||
|
|
||||||
AudioEncoder* speech_encoder_;
|
AudioEncoder* speech_encoder_;
|
||||||
const int sample_rate_hz_;
|
|
||||||
const int num_channels_;
|
|
||||||
const int cng_payload_type_;
|
const int cng_payload_type_;
|
||||||
const int num_cng_coefficients_;
|
const int num_cng_coefficients_;
|
||||||
std::vector<int16_t> speech_buffer_;
|
std::vector<int16_t> speech_buffer_;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user