Adding Opus DTX support in ACM.
This solution does not use the existing VAD/DTX logic of ACM, since Opus DTX is codec feature, while ACM VAD/DTX is mainly for setting the WebRTC VAD/DTX. During the development of this CL, two old bugs were found and are fixed in this CL too. They are in webrtc/modules/audio_coding/test/Channels.cc and webrtc/modules/audio_coding/main/acm2/acm_opus_unittest.cc respectively. BUG=webrtc:1014 R=henrik.lundin@webrtc.org, tina.legrand@webrtc.org Review URL: https://webrtc-codereview.appspot.com/38469004 Cr-Commit-Position: refs/heads/master@{#8573} git-svn-id: http://webrtc.googlecode.com/svn/trunk@8573 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
a1c9803e32
commit
0561716ae2
@ -53,7 +53,8 @@ AudioEncoderOpus::Config::Config()
|
||||
bitrate_bps(64000),
|
||||
fec_enabled(false),
|
||||
max_playback_rate_hz(48000),
|
||||
complexity(kDefaultComplexity) {
|
||||
complexity(kDefaultComplexity),
|
||||
dtx_enabled(false) {
|
||||
}
|
||||
|
||||
bool AudioEncoderOpus::Config::IsOk() const {
|
||||
@ -65,6 +66,8 @@ bool AudioEncoderOpus::Config::IsOk() const {
|
||||
return false;
|
||||
if (complexity < 0 || complexity > 10)
|
||||
return false;
|
||||
if (dtx_enabled && application != kVoip)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -89,7 +92,11 @@ AudioEncoderOpus::AudioEncoderOpus(const Config& config)
|
||||
CHECK_EQ(0,
|
||||
WebRtcOpus_SetMaxPlaybackRate(inst_, config.max_playback_rate_hz));
|
||||
CHECK_EQ(0, WebRtcOpus_SetComplexity(inst_, config.complexity));
|
||||
|
||||
if (config.dtx_enabled) {
|
||||
CHECK_EQ(0, WebRtcOpus_EnableDtx(inst_));
|
||||
} else {
|
||||
CHECK_EQ(0, WebRtcOpus_DisableDtx(inst_));
|
||||
}
|
||||
}
|
||||
|
||||
AudioEncoderOpus::~AudioEncoderOpus() {
|
||||
@ -193,6 +200,8 @@ void AudioEncoderOpus::EncodeInternal(uint32_t rtp_timestamp,
|
||||
info->encoded_bytes = r;
|
||||
info->encoded_timestamp = first_timestamp_in_buffer_;
|
||||
info->payload_type = payload_type_;
|
||||
// Allows Opus to send empty packets.
|
||||
info->send_even_if_empty = true;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
@ -39,6 +39,7 @@ class AudioEncoderOpus final : public AudioEncoder {
|
||||
bool fec_enabled;
|
||||
int max_playback_rate_hz;
|
||||
int complexity;
|
||||
bool dtx_enabled;
|
||||
};
|
||||
|
||||
explicit AudioEncoderOpus(const Config& config);
|
||||
|
@ -115,6 +115,7 @@ ACMGenericCodec::ACMGenericCodec(const CodecInst& codec_inst,
|
||||
max_playback_rate_hz_(48000),
|
||||
max_payload_size_bytes_(-1),
|
||||
max_rate_bps_(-1),
|
||||
opus_dtx_enabled_(false),
|
||||
is_opus_(false),
|
||||
is_isac_(false),
|
||||
first_frame_(true),
|
||||
@ -275,10 +276,12 @@ int16_t ACMGenericCodec::InitEncoder(WebRtcACMCodecParams* codec_params,
|
||||
WriteLockScoped wl(codec_wrapper_lock_);
|
||||
bitrate_bps_ = 0;
|
||||
loss_rate_ = 0;
|
||||
opus_dtx_enabled_ = false;
|
||||
acm_codec_params_ = *codec_params;
|
||||
if (force_initialization)
|
||||
opus_application_set_ = false;
|
||||
opus_application_ = GetOpusApplication(codec_params->codec_inst.channels);
|
||||
opus_application_ = GetOpusApplication(codec_params->codec_inst.channels,
|
||||
opus_dtx_enabled_);
|
||||
opus_application_set_ = true;
|
||||
ResetAudioEncoder();
|
||||
return 0;
|
||||
@ -325,8 +328,9 @@ void ACMGenericCodec::ResetAudioEncoder() {
|
||||
config.fec_enabled = fec_enabled_;
|
||||
config.bitrate_bps = codec_inst.rate;
|
||||
config.max_playback_rate_hz = max_playback_rate_hz_;
|
||||
config.dtx_enabled = opus_dtx_enabled_;
|
||||
config.payload_type = codec_inst.pltype;
|
||||
switch (GetOpusApplication(config.num_channels)) {
|
||||
switch (GetOpusApplication(config.num_channels, config.dtx_enabled)) {
|
||||
case kVoip:
|
||||
config.application = AudioEncoderOpus::ApplicationMode::kVoip;
|
||||
break;
|
||||
@ -478,10 +482,10 @@ void ACMGenericCodec::ResetAudioEncoder() {
|
||||
}
|
||||
|
||||
OpusApplicationMode ACMGenericCodec::GetOpusApplication(
|
||||
int num_channels) const {
|
||||
int num_channels, bool enable_dtx) const {
|
||||
if (opus_application_set_)
|
||||
return opus_application_;
|
||||
return num_channels == 1 ? kVoip : kAudio;
|
||||
return num_channels == 1 || enable_dtx ? kVoip : kAudio;
|
||||
}
|
||||
|
||||
int32_t ACMGenericCodec::Add10MsData(const uint32_t timestamp,
|
||||
@ -586,6 +590,28 @@ AudioDecoder* ACMGenericCodec::Decoder() {
|
||||
return decoder_proxy_.IsSet() ? &decoder_proxy_ : nullptr;
|
||||
}
|
||||
|
||||
int ACMGenericCodec::EnableOpusDtx() {
|
||||
WriteLockScoped wl(codec_wrapper_lock_);
|
||||
if (!is_opus_)
|
||||
return -1; // Needed for tests to pass.
|
||||
if (GetOpusApplication(encoder_->NumChannels(), true) != kVoip) {
|
||||
// Opus DTX can only be enabled when application mode is KVoip.
|
||||
return -1;
|
||||
}
|
||||
opus_dtx_enabled_ = true;
|
||||
ResetAudioEncoder();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ACMGenericCodec::DisableOpusDtx() {
|
||||
WriteLockScoped wl(codec_wrapper_lock_);
|
||||
if (!is_opus_)
|
||||
return -1; // Needed for tests to pass.
|
||||
opus_dtx_enabled_ = false;
|
||||
ResetAudioEncoder();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ACMGenericCodec::SetFEC(bool enable_fec) {
|
||||
if (!HasInternalFEC())
|
||||
return enable_fec ? -1 : 0;
|
||||
@ -599,6 +625,10 @@ int ACMGenericCodec::SetFEC(bool enable_fec) {
|
||||
|
||||
int ACMGenericCodec::SetOpusApplication(OpusApplicationMode application) {
|
||||
WriteLockScoped wl(codec_wrapper_lock_);
|
||||
if (opus_dtx_enabled_ && application == kAudio) {
|
||||
// Opus can only be set to kAudio when DTX is off.
|
||||
return -1;
|
||||
}
|
||||
opus_application_ = application;
|
||||
opus_application_set_ = true;
|
||||
ResetAudioEncoder();
|
||||
|
@ -393,6 +393,23 @@ class ACMGenericCodec {
|
||||
//
|
||||
int SetOpusMaxPlaybackRate(int /* frequency_hz */);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// EnableOpusDtx()
|
||||
// Enable the DTX, if the codec is Opus. If current Opus application mode is
|
||||
// audio, a failure will be triggered.
|
||||
// Return value:
|
||||
// -1 if failed or on codecs other than Opus.
|
||||
// 0 if succeeded.
|
||||
int EnableOpusDtx();
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// DisbleOpusDtx()
|
||||
// Disable the DTX, if the codec is Opus.
|
||||
// Return value:
|
||||
// -1 if failed or on codecs other than Opus.
|
||||
// 0 if succeeded.
|
||||
int DisableOpusDtx();
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// HasFrameToEncode()
|
||||
// Returns true if there is enough audio buffered for encoding, such that
|
||||
@ -469,7 +486,8 @@ class ACMGenericCodec {
|
||||
|
||||
void ResetAudioEncoder() EXCLUSIVE_LOCKS_REQUIRED(codec_wrapper_lock_);
|
||||
|
||||
OpusApplicationMode GetOpusApplication(int num_channels) const
|
||||
OpusApplicationMode GetOpusApplication(int num_channels,
|
||||
bool enable_dtx) const
|
||||
EXCLUSIVE_LOCKS_REQUIRED(codec_wrapper_lock_);
|
||||
|
||||
rtc::scoped_ptr<AudioEncoder> audio_encoder_ GUARDED_BY(codec_wrapper_lock_);
|
||||
@ -485,6 +503,7 @@ class ACMGenericCodec {
|
||||
int max_playback_rate_hz_ GUARDED_BY(codec_wrapper_lock_);
|
||||
int max_payload_size_bytes_ GUARDED_BY(codec_wrapper_lock_);
|
||||
int max_rate_bps_ GUARDED_BY(codec_wrapper_lock_);
|
||||
bool opus_dtx_enabled_ GUARDED_BY(codec_wrapper_lock_);
|
||||
bool is_opus_ GUARDED_BY(codec_wrapper_lock_);
|
||||
bool is_isac_ GUARDED_BY(codec_wrapper_lock_);
|
||||
bool first_frame_ GUARDED_BY(codec_wrapper_lock_);
|
||||
|
@ -100,6 +100,27 @@ TEST_F(AcmGenericCodecOpusTest, ResetWontChangeApplicationMode) {
|
||||
// Verify that the mode is still kVoip.
|
||||
EXPECT_EQ(AudioEncoderOpus::kVoip, GetAudioEncoderOpus()->application());
|
||||
}
|
||||
|
||||
TEST_F(AcmGenericCodecOpusTest, ToggleDtx) {
|
||||
// Create a stereo encoder.
|
||||
acm_codec_params_.codec_inst.channels = 2;
|
||||
CreateCodec();
|
||||
// Verify that the mode is still kAudio.
|
||||
EXPECT_EQ(AudioEncoderOpus::kAudio, GetAudioEncoderOpus()->application());
|
||||
|
||||
// DTX is not allowed in audio mode.
|
||||
EXPECT_EQ(-1, codec_wrapper_->EnableOpusDtx());
|
||||
|
||||
EXPECT_EQ(0, codec_wrapper_->SetOpusApplication(kVoip));
|
||||
EXPECT_EQ(0, codec_wrapper_->EnableOpusDtx());
|
||||
|
||||
// Audio mode is not allowed when DTX is on.
|
||||
EXPECT_EQ(-1, codec_wrapper_->SetOpusApplication(kAudio));
|
||||
EXPECT_EQ(AudioEncoderOpus::kVoip, GetAudioEncoderOpus()->application());
|
||||
|
||||
EXPECT_EQ(0, codec_wrapper_->DisableOpusDtx());
|
||||
EXPECT_EQ(0, codec_wrapper_->SetOpusApplication(kAudio));
|
||||
}
|
||||
#endif // WEBRTC_CODEC_OPUS
|
||||
|
||||
} // namespace acm2
|
||||
|
@ -1374,6 +1374,22 @@ int AudioCodingModuleImpl::SetOpusMaxPlaybackRate(int frequency_hz) {
|
||||
return codecs_[current_send_codec_idx_]->SetOpusMaxPlaybackRate(frequency_hz);
|
||||
}
|
||||
|
||||
int AudioCodingModuleImpl::EnableOpusDtx() {
|
||||
CriticalSectionScoped lock(acm_crit_sect_);
|
||||
if (!HaveValidEncoder("EnableOpusDtx")) {
|
||||
return -1;
|
||||
}
|
||||
return codecs_[current_send_codec_idx_]->EnableOpusDtx();
|
||||
}
|
||||
|
||||
int AudioCodingModuleImpl::DisableOpusDtx() {
|
||||
CriticalSectionScoped lock(acm_crit_sect_);
|
||||
if (!HaveValidEncoder("DisableOpusDtx")) {
|
||||
return -1;
|
||||
}
|
||||
return codecs_[current_send_codec_idx_]->DisableOpusDtx();
|
||||
}
|
||||
|
||||
int AudioCodingModuleImpl::PlayoutTimestamp(uint32_t* timestamp) {
|
||||
return receiver_.GetPlayoutTimestamp(timestamp) ? 0 : -1;
|
||||
}
|
||||
|
@ -223,6 +223,10 @@ class AudioCodingModuleImpl : public AudioCodingModule {
|
||||
// the receiver will render.
|
||||
virtual int SetOpusMaxPlaybackRate(int frequency_hz) OVERRIDE;
|
||||
|
||||
int EnableOpusDtx() override;
|
||||
|
||||
int DisableOpusDtx() override;
|
||||
|
||||
virtual int UnregisterReceiveCodec(uint8_t payload_type) OVERRIDE;
|
||||
|
||||
virtual int EnableNack(size_t max_nack_list_size) OVERRIDE;
|
||||
|
@ -905,6 +905,30 @@ class AudioCodingModule {
|
||||
//
|
||||
virtual int SetOpusMaxPlaybackRate(int frequency_hz) = 0;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// int EnableOpusDtx()
|
||||
// If current send codec is Opus, enables its internal DTX.
|
||||
// Currently, this can be only called when Opus application mode is VOIP.
|
||||
// Use SetOpusApplication() to switch to VOIP mode when necessary.
|
||||
//
|
||||
// Return value:
|
||||
// -1 if current send codec is not Opus or
|
||||
// error occurred in enabling DTX.
|
||||
// 0 Opus DTX is enabled successfully.
|
||||
//
|
||||
virtual int EnableOpusDtx() = 0;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// int DisableOpusDtx()
|
||||
// If current send codec is Opus, disables its internal DTX.
|
||||
//
|
||||
// Return value:
|
||||
// -1 if current send codec is not Opus or
|
||||
// error occurred in disabling DTX.
|
||||
// 0 Opus DTX is disabled successfully.
|
||||
//
|
||||
virtual int DisableOpusDtx() = 0;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// statistics
|
||||
//
|
||||
|
@ -43,7 +43,9 @@ int32_t Channel::SendData(FrameType frameType,
|
||||
rtpInfo.type.Audio.isCNG = false;
|
||||
}
|
||||
if (frameType == kFrameEmpty) {
|
||||
// Skip this frame
|
||||
// When frame is empty, we should not transmit it. The frame size of the
|
||||
// next non-empty frame will be based on the previous frame size.
|
||||
_useLastFrameSize = _lastFrameSizeSample > 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -101,6 +103,7 @@ int32_t Channel::SendData(FrameType frameType,
|
||||
if (!_isStereo) {
|
||||
CalcStatistics(rtpInfo, payloadSize);
|
||||
}
|
||||
_useLastFrameSize = false;
|
||||
_lastInTimestamp = timeStamp;
|
||||
_totalBytes += payloadDataSize;
|
||||
_channelCritSect->Leave();
|
||||
@ -153,22 +156,31 @@ void Channel::CalcStatistics(WebRtcRTPHeader& rtpInfo, size_t payloadSize) {
|
||||
|
||||
if (!newPayload) {
|
||||
if (!currentPayloadStr->newPacket) {
|
||||
uint32_t lastFrameSizeSample = (uint32_t)(
|
||||
(uint32_t) rtpInfo.header.timestamp
|
||||
- (uint32_t) currentPayloadStr->lastTimestamp);
|
||||
assert(lastFrameSizeSample > 0);
|
||||
if (!_useLastFrameSize) {
|
||||
_lastFrameSizeSample = (uint32_t) ((uint32_t) rtpInfo.header.timestamp -
|
||||
(uint32_t) currentPayloadStr->lastTimestamp);
|
||||
}
|
||||
assert(_lastFrameSizeSample > 0);
|
||||
int k = 0;
|
||||
while ((currentPayloadStr->frameSizeStats[k].frameSizeSample
|
||||
!= lastFrameSizeSample)
|
||||
&& (currentPayloadStr->frameSizeStats[k].frameSizeSample != 0)) {
|
||||
k++;
|
||||
for (; k < MAX_NUM_FRAMESIZES; ++k) {
|
||||
if ((currentPayloadStr->frameSizeStats[k].frameSizeSample ==
|
||||
_lastFrameSizeSample) ||
|
||||
(currentPayloadStr->frameSizeStats[k].frameSizeSample == 0)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (k == MAX_NUM_FRAMESIZES) {
|
||||
// New frame size found but no space to count statistics on it. Skip it.
|
||||
printf("No memory to store statistics for payload %d : frame size %d\n",
|
||||
_lastPayloadType, _lastFrameSizeSample);
|
||||
return;
|
||||
}
|
||||
ACMTestFrameSizeStats* currentFrameSizeStats = &(currentPayloadStr
|
||||
->frameSizeStats[k]);
|
||||
currentFrameSizeStats->frameSizeSample = (int16_t) lastFrameSizeSample;
|
||||
currentFrameSizeStats->frameSizeSample = (int16_t) _lastFrameSizeSample;
|
||||
|
||||
// increment the number of encoded samples.
|
||||
currentFrameSizeStats->totalEncodedSamples += lastFrameSizeSample;
|
||||
currentFrameSizeStats->totalEncodedSamples += _lastFrameSizeSample;
|
||||
// increment the number of recveived packets
|
||||
currentFrameSizeStats->numPackets++;
|
||||
// increment the total number of bytes (this is based on
|
||||
@ -220,6 +232,8 @@ Channel::Channel(int16_t chID)
|
||||
_isStereo(false),
|
||||
_leftChannel(true),
|
||||
_lastInTimestamp(0),
|
||||
_useLastFrameSize(false),
|
||||
_lastFrameSizeSample(0),
|
||||
_packetLoss(0),
|
||||
_useFECTestWithPacketLoss(false),
|
||||
_beginTime(TickTime::MillisecondTimestamp()),
|
||||
|
@ -111,6 +111,8 @@ class Channel : public AudioPacketizationCallback {
|
||||
WebRtcRTPHeader _rtpInfo;
|
||||
bool _leftChannel;
|
||||
uint32_t _lastInTimestamp;
|
||||
bool _useLastFrameSize;
|
||||
uint32_t _lastFrameSizeSample;
|
||||
// FEC Test variables
|
||||
int16_t _packetLoss;
|
||||
bool _useFECTestWithPacketLoss;
|
||||
|
@ -10,367 +10,279 @@
|
||||
|
||||
#include "webrtc/modules/audio_coding/main/test/TestVADDTX.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "webrtc/common_types.h"
|
||||
#include "webrtc/engine_configurations.h"
|
||||
#include "webrtc/modules/audio_coding/main/acm2/acm_common_defs.h"
|
||||
#include "webrtc/modules/audio_coding/main/interface/audio_coding_module_typedefs.h"
|
||||
#include "webrtc/modules/audio_coding/main/test/PCMFile.h"
|
||||
#include "webrtc/modules/audio_coding/main/test/utility.h"
|
||||
#include "webrtc/system_wrappers/interface/trace.h"
|
||||
#include "webrtc/test/testsupport/fileutils.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
TestVADDTX::TestVADDTX()
|
||||
: _acmA(AudioCodingModule::Create(0)),
|
||||
_acmB(AudioCodingModule::Create(1)),
|
||||
_channelA2B(NULL) {}
|
||||
|
||||
TestVADDTX::~TestVADDTX() {
|
||||
if (_channelA2B != NULL) {
|
||||
delete _channelA2B;
|
||||
_channelA2B = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void TestVADDTX::Perform() {
|
||||
const std::string file_name = webrtc::test::ResourcePath(
|
||||
"audio_coding/testfile32kHz", "pcm");
|
||||
_inFileA.Open(file_name, 32000, "rb");
|
||||
|
||||
EXPECT_EQ(0, _acmA->InitializeReceiver());
|
||||
EXPECT_EQ(0, _acmB->InitializeReceiver());
|
||||
|
||||
uint8_t numEncoders = _acmA->NumberOfCodecs();
|
||||
CodecInst myCodecParam;
|
||||
for (uint8_t n = 0; n < numEncoders; n++) {
|
||||
EXPECT_EQ(0, _acmB->Codec(n, &myCodecParam));
|
||||
if (!strcmp(myCodecParam.plname, "opus")) {
|
||||
// Register Opus as mono.
|
||||
myCodecParam.channels = 1;
|
||||
}
|
||||
EXPECT_EQ(0, _acmB->RegisterReceiveCodec(myCodecParam));
|
||||
}
|
||||
|
||||
// Create and connect the channel
|
||||
_channelA2B = new Channel;
|
||||
_acmA->RegisterTransportCallback(_channelA2B);
|
||||
_channelA2B->RegisterReceiverACM(_acmB.get());
|
||||
|
||||
_acmA->RegisterVADCallback(&_monitor);
|
||||
|
||||
int16_t testCntr = 1;
|
||||
|
||||
#ifdef WEBRTC_CODEC_ISAC
|
||||
// Open outputfile
|
||||
OpenOutFile(testCntr++);
|
||||
|
||||
// Register iSAC WB as send codec
|
||||
char nameISAC[] = "ISAC";
|
||||
RegisterSendCodec('A', nameISAC, 16000);
|
||||
|
||||
// Run the five test cased
|
||||
runTestCases();
|
||||
|
||||
// Close file
|
||||
_outFileB.Close();
|
||||
|
||||
// Open outputfile
|
||||
OpenOutFile(testCntr++);
|
||||
|
||||
// Register iSAC SWB as send codec
|
||||
RegisterSendCodec('A', nameISAC, 32000);
|
||||
|
||||
// Run the five test cased
|
||||
runTestCases();
|
||||
|
||||
// Close file
|
||||
_outFileB.Close();
|
||||
const CodecInst kIsacWb = {103, "ISAC", 16000, 480, 1, 32000};
|
||||
const CodecInst kIsacSwb = {104, "ISAC", 32000, 960, 1, 56000};
|
||||
#endif
|
||||
|
||||
#ifdef WEBRTC_CODEC_ILBC
|
||||
// Open outputfile
|
||||
OpenOutFile(testCntr++);
|
||||
|
||||
// Register iLBC as send codec
|
||||
char nameILBC[] = "ilbc";
|
||||
RegisterSendCodec('A', nameILBC);
|
||||
|
||||
// Run the five test cased
|
||||
runTestCases();
|
||||
|
||||
// Close file
|
||||
_outFileB.Close();
|
||||
|
||||
const CodecInst kIlbc = {102, "ILBC", 8000, 240, 1, 13300};
|
||||
#endif
|
||||
|
||||
#ifdef WEBRTC_CODEC_OPUS
|
||||
// Open outputfile
|
||||
OpenOutFile(testCntr++);
|
||||
|
||||
// Register Opus as send codec
|
||||
char nameOPUS[] = "opus";
|
||||
RegisterSendCodec('A', nameOPUS);
|
||||
|
||||
// Run the five test cased
|
||||
runTestCases();
|
||||
|
||||
// Close file
|
||||
_outFileB.Close();
|
||||
|
||||
const CodecInst kOpus = {120, "opus", 48000, 960, 1, 64000};
|
||||
const CodecInst kOpusStereo = {120, "opus", 48000, 960, 2, 64000};
|
||||
#endif
|
||||
}
|
||||
|
||||
void TestVADDTX::runTestCases() {
|
||||
// #1 DTX = OFF, VAD = OFF, VADNormal
|
||||
SetVAD(false, false, VADNormal);
|
||||
Run();
|
||||
VerifyTest();
|
||||
|
||||
// #2 DTX = ON, VAD = ON, VADAggr
|
||||
SetVAD(true, true, VADAggr);
|
||||
Run();
|
||||
VerifyTest();
|
||||
|
||||
// #3 DTX = ON, VAD = ON, VADLowBitrate
|
||||
SetVAD(true, true, VADLowBitrate);
|
||||
Run();
|
||||
VerifyTest();
|
||||
|
||||
// #4 DTX = ON, VAD = ON, VADVeryAggr
|
||||
SetVAD(true, true, VADVeryAggr);
|
||||
Run();
|
||||
VerifyTest();
|
||||
|
||||
// #5 DTX = ON, VAD = ON, VADNormal
|
||||
SetVAD(true, true, VADNormal);
|
||||
Run();
|
||||
VerifyTest();
|
||||
}
|
||||
|
||||
void TestVADDTX::runTestInternalDTX(int expected_result) {
|
||||
// #6 DTX = ON, VAD = ON, VADNormal
|
||||
SetVAD(true, true, VADNormal);
|
||||
EXPECT_EQ(expected_result, _acmA->ReplaceInternalDTXWithWebRtc(true));
|
||||
if (expected_result == 0) {
|
||||
Run();
|
||||
VerifyTest();
|
||||
}
|
||||
}
|
||||
|
||||
void TestVADDTX::SetVAD(bool statusDTX, bool statusVAD, int16_t vadMode) {
|
||||
bool dtxEnabled, vadEnabled;
|
||||
ACMVADMode vadModeSet;
|
||||
|
||||
EXPECT_EQ(0, _acmA->SetVAD(statusDTX, statusVAD, (ACMVADMode) vadMode));
|
||||
EXPECT_EQ(0, _acmA->VAD(&dtxEnabled, &vadEnabled, &vadModeSet));
|
||||
|
||||
// Requested VAD/DTX settings
|
||||
_setStruct.statusDTX = statusDTX;
|
||||
_setStruct.statusVAD = statusVAD;
|
||||
_setStruct.vadMode = (ACMVADMode) vadMode;
|
||||
|
||||
// VAD settings after setting VAD in ACM
|
||||
_getStruct.statusDTX = dtxEnabled;
|
||||
_getStruct.statusVAD = vadEnabled;
|
||||
_getStruct.vadMode = vadModeSet;
|
||||
}
|
||||
|
||||
VADDTXstruct TestVADDTX::GetVAD() {
|
||||
VADDTXstruct retStruct;
|
||||
bool dtxEnabled, vadEnabled;
|
||||
ACMVADMode vadModeSet;
|
||||
|
||||
EXPECT_EQ(0, _acmA->VAD(&dtxEnabled, &vadEnabled, &vadModeSet));
|
||||
|
||||
retStruct.statusDTX = dtxEnabled;
|
||||
retStruct.statusVAD = vadEnabled;
|
||||
retStruct.vadMode = vadModeSet;
|
||||
return retStruct;
|
||||
}
|
||||
|
||||
int16_t TestVADDTX::RegisterSendCodec(char side, char* codecName,
|
||||
int32_t samplingFreqHz,
|
||||
int32_t rateKbps) {
|
||||
std::cout << std::flush;
|
||||
AudioCodingModule* myACM;
|
||||
switch (side) {
|
||||
case 'A': {
|
||||
myACM = _acmA.get();
|
||||
break;
|
||||
}
|
||||
case 'B': {
|
||||
myACM = _acmB.get();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (myACM == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
CodecInst myCodecParam;
|
||||
for (int16_t codecCntr = 0; codecCntr < myACM->NumberOfCodecs();
|
||||
codecCntr++) {
|
||||
EXPECT_EQ(0, myACM->Codec((uint8_t) codecCntr, &myCodecParam));
|
||||
if (!STR_CASE_CMP(myCodecParam.plname, codecName)) {
|
||||
if ((samplingFreqHz == -1) || (myCodecParam.plfreq == samplingFreqHz)) {
|
||||
if ((rateKbps == -1) || (myCodecParam.rate == rateKbps)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We only allow VAD/DTX when sending mono.
|
||||
myCodecParam.channels = 1;
|
||||
EXPECT_EQ(0, myACM->RegisterSendCodec(myCodecParam));
|
||||
|
||||
// initialization was succesful
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TestVADDTX::Run() {
|
||||
AudioFrame audioFrame;
|
||||
|
||||
uint16_t SamplesIn10MsecA = _inFileA.PayloadLength10Ms();
|
||||
uint32_t timestampA = 1;
|
||||
int32_t outFreqHzB = _outFileB.SamplingFrequency();
|
||||
|
||||
while (!_inFileA.EndOfFile()) {
|
||||
_inFileA.Read10MsData(audioFrame);
|
||||
audioFrame.timestamp_ = timestampA;
|
||||
timestampA += SamplesIn10MsecA;
|
||||
EXPECT_GE(_acmA->Add10MsData(audioFrame), 0);
|
||||
EXPECT_EQ(0, _acmB->PlayoutData10Ms(outFreqHzB, &audioFrame));
|
||||
_outFileB.Write10MsData(audioFrame.data_, audioFrame.samples_per_channel_);
|
||||
}
|
||||
#ifdef PRINT_STAT
|
||||
_monitor.PrintStatistics();
|
||||
#endif
|
||||
_inFileA.Rewind();
|
||||
_monitor.GetStatistics(_statCounter);
|
||||
_monitor.ResetStatistics();
|
||||
}
|
||||
|
||||
void TestVADDTX::OpenOutFile(int16_t test_number) {
|
||||
std::string file_name;
|
||||
std::stringstream file_stream;
|
||||
file_stream << webrtc::test::OutputPath();
|
||||
file_stream << "testVADDTX_outFile_";
|
||||
file_stream << test_number << ".pcm";
|
||||
file_name = file_stream.str();
|
||||
_outFileB.Open(file_name, 16000, "wb");
|
||||
}
|
||||
|
||||
int16_t TestVADDTX::VerifyTest() {
|
||||
// Verify empty frame result
|
||||
uint8_t statusEF = 0;
|
||||
uint8_t vadPattern = 0;
|
||||
uint8_t emptyFramePattern[6];
|
||||
CodecInst myCodecParam;
|
||||
_acmA->SendCodec(&myCodecParam);
|
||||
|
||||
// TODO(minyue): Remove these treatment on Opus when DTX is properly handled
|
||||
// by ACMOpus.
|
||||
if (STR_CASE_CMP(myCodecParam.plname, "opus") == 0) {
|
||||
_setStruct.statusDTX = false;
|
||||
_setStruct.statusVAD = false;
|
||||
}
|
||||
|
||||
bool isReplaced = false;
|
||||
_acmA->IsInternalDTXReplacedWithWebRtc(&isReplaced);
|
||||
bool webRtcDtxInUse = _getStruct.statusDTX && isReplaced;
|
||||
bool codecDtxInUse = _getStruct.statusDTX && !isReplaced;
|
||||
|
||||
// Check for error in VAD/DTX settings
|
||||
if (_getStruct.statusDTX != _setStruct.statusDTX) {
|
||||
// DTX status doesn't match expected.
|
||||
vadPattern |= 1;
|
||||
}
|
||||
if (!_getStruct.statusVAD && webRtcDtxInUse) {
|
||||
// WebRTC DTX cannot run without WebRTC VAD.
|
||||
vadPattern |= 2;
|
||||
}
|
||||
if ((!_getStruct.statusDTX || codecDtxInUse) &&
|
||||
(_getStruct.statusVAD != _setStruct.statusVAD)) {
|
||||
// Using no DTX or codec Internal DTX should not affect setting of VAD.
|
||||
vadPattern |= 4;
|
||||
}
|
||||
if (_getStruct.vadMode != _setStruct.vadMode) {
|
||||
// VAD Mode doesn't match expected.
|
||||
vadPattern |= 8;
|
||||
}
|
||||
|
||||
// Set expected empty frame pattern
|
||||
int ii;
|
||||
for (ii = 0; ii < 6; ii++) {
|
||||
emptyFramePattern[ii] = 0;
|
||||
}
|
||||
// 0 - "kNoEncoding", not important to check.
|
||||
// Codecs with packetsize != 80 samples will get this output.
|
||||
// 1 - "kActiveNormalEncoded", expect to receive some frames with this label .
|
||||
// 2 - "kPassiveNormalEncoded".
|
||||
// 3 - "kPassiveDTXNB".
|
||||
// 4 - "kPassiveDTXWB".
|
||||
// 5 - "kPassiveDTXSWB".
|
||||
emptyFramePattern[0] = 1;
|
||||
emptyFramePattern[1] = 1;
|
||||
emptyFramePattern[2] = _getStruct.statusVAD && !webRtcDtxInUse;
|
||||
emptyFramePattern[3] = webRtcDtxInUse && (_acmA->SendFrequency() == 8000);
|
||||
emptyFramePattern[4] = webRtcDtxInUse && (_acmA->SendFrequency() == 16000);
|
||||
emptyFramePattern[5] = webRtcDtxInUse && (_acmA->SendFrequency() == 32000);
|
||||
|
||||
// Check pattern 1-5 (skip 0)
|
||||
for (int ii = 1; ii < 6; ii++) {
|
||||
if (emptyFramePattern[ii]) {
|
||||
statusEF |= (_statCounter[ii] == 0);
|
||||
} else {
|
||||
statusEF |= (_statCounter[ii] > 0);
|
||||
}
|
||||
}
|
||||
EXPECT_EQ(0, statusEF);
|
||||
EXPECT_EQ(0, vadPattern);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ActivityMonitor::ActivityMonitor() {
|
||||
_counter[0] = _counter[1] = _counter[2] = _counter[3] = _counter[4] =
|
||||
_counter[5] = 0;
|
||||
ResetStatistics();
|
||||
}
|
||||
|
||||
ActivityMonitor::~ActivityMonitor() {
|
||||
}
|
||||
|
||||
int32_t ActivityMonitor::InFrameType(int16_t frameType) {
|
||||
_counter[frameType]++;
|
||||
int32_t ActivityMonitor::InFrameType(int16_t frame_type) {
|
||||
counter_[frame_type]++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ActivityMonitor::PrintStatistics() {
|
||||
printf("\n");
|
||||
printf("kActiveNormalEncoded kPassiveNormalEncoded kPassiveDTXWB ");
|
||||
printf("kPassiveDTXNB kPassiveDTXSWB kFrameEmpty\n");
|
||||
printf("%19u", _counter[1]);
|
||||
printf("%22u", _counter[2]);
|
||||
printf("%14u", _counter[3]);
|
||||
printf("%14u", _counter[4]);
|
||||
printf("%14u", _counter[5]);
|
||||
printf("%11u", _counter[0]);
|
||||
printf("kPassiveDTXNB kPassiveDTXSWB kNoEncoding\n");
|
||||
printf("%19u", counter_[1]);
|
||||
printf("%22u", counter_[2]);
|
||||
printf("%14u", counter_[3]);
|
||||
printf("%14u", counter_[4]);
|
||||
printf("%14u", counter_[5]);
|
||||
printf("%11u", counter_[0]);
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
void ActivityMonitor::ResetStatistics() {
|
||||
_counter[0] = _counter[1] = _counter[2] = _counter[3] = _counter[4] =
|
||||
_counter[5] = 0;
|
||||
memset(counter_, 0, sizeof(counter_));
|
||||
}
|
||||
|
||||
void ActivityMonitor::GetStatistics(uint32_t* getCounter) {
|
||||
for (int ii = 0; ii < 6; ii++) {
|
||||
getCounter[ii] = _counter[ii];
|
||||
void ActivityMonitor::GetStatistics(uint32_t* counter) {
|
||||
memcpy(counter, counter_, sizeof(counter_));
|
||||
}
|
||||
|
||||
TestVadDtx::TestVadDtx()
|
||||
: acm_send_(AudioCodingModule::Create(0)),
|
||||
acm_receive_(AudioCodingModule::Create(1)),
|
||||
channel_(new Channel),
|
||||
monitor_(new ActivityMonitor) {
|
||||
EXPECT_EQ(0, acm_send_->RegisterTransportCallback(channel_.get()));
|
||||
channel_->RegisterReceiverACM(acm_receive_.get());
|
||||
EXPECT_EQ(0, acm_send_->RegisterVADCallback(monitor_.get()));
|
||||
assert(monitor_->kPacketTypes == this->kPacketTypes);
|
||||
}
|
||||
|
||||
void TestVadDtx::RegisterCodec(CodecInst codec_param) {
|
||||
// Set the codec for sending and receiving.
|
||||
EXPECT_EQ(0, acm_send_->RegisterSendCodec(codec_param));
|
||||
EXPECT_EQ(0, acm_receive_->RegisterReceiveCodec(codec_param));
|
||||
channel_->SetIsStereo(codec_param.channels > 1);
|
||||
}
|
||||
|
||||
// Encoding a file and see if the numbers that various packets occur follow
|
||||
// the expectation.
|
||||
void TestVadDtx::Run(std::string in_filename, int frequency, int channels,
|
||||
std::string out_filename, bool append,
|
||||
const int* expects) {
|
||||
monitor_->ResetStatistics();
|
||||
|
||||
PCMFile in_file;
|
||||
in_file.Open(in_filename, frequency, "rb");
|
||||
in_file.ReadStereo(channels > 1);
|
||||
|
||||
PCMFile out_file;
|
||||
if (append) {
|
||||
out_file.Open(out_filename, kOutputFreqHz, "ab");
|
||||
} else {
|
||||
out_file.Open(out_filename, kOutputFreqHz, "wb");
|
||||
}
|
||||
|
||||
uint16_t frame_size_samples = in_file.PayloadLength10Ms();
|
||||
uint32_t time_stamp = 0x12345678;
|
||||
AudioFrame audio_frame;
|
||||
while (!in_file.EndOfFile()) {
|
||||
in_file.Read10MsData(audio_frame);
|
||||
audio_frame.timestamp_ = time_stamp;
|
||||
time_stamp += frame_size_samples;
|
||||
EXPECT_GE(acm_send_->Add10MsData(audio_frame), 0);
|
||||
acm_receive_->PlayoutData10Ms(kOutputFreqHz, &audio_frame);
|
||||
out_file.Write10MsData(audio_frame);
|
||||
}
|
||||
|
||||
in_file.Close();
|
||||
out_file.Close();
|
||||
|
||||
#ifdef PRINT_STAT
|
||||
monitor_->PrintStatistics();
|
||||
#endif
|
||||
|
||||
uint32_t stats[kPacketTypes];
|
||||
monitor_->GetStatistics(stats);
|
||||
monitor_->ResetStatistics();
|
||||
|
||||
for (int i = 0; i < kPacketTypes; i++) {
|
||||
switch (expects[i]) {
|
||||
case 0: {
|
||||
EXPECT_EQ(static_cast<uint32_t>(0), stats[i]) << "stats["
|
||||
<< i
|
||||
<< "] error.";
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
EXPECT_GT(stats[i], static_cast<uint32_t>(0)) << "stats["
|
||||
<< i
|
||||
<< "] error.";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Following is the implementation of TestWebRtcVadDtx.
|
||||
TestWebRtcVadDtx::TestWebRtcVadDtx()
|
||||
: vad_enabled_(false),
|
||||
dtx_enabled_(false),
|
||||
use_webrtc_dtx_(false),
|
||||
output_file_num_(0) {
|
||||
}
|
||||
|
||||
void TestWebRtcVadDtx::Perform() {
|
||||
// Go through various test cases.
|
||||
#ifdef WEBRTC_CODEC_ISAC
|
||||
// Register iSAC WB as send codec
|
||||
RegisterCodec(kIsacWb);
|
||||
RunTestCases();
|
||||
|
||||
// Register iSAC SWB as send codec
|
||||
RegisterCodec(kIsacSwb);
|
||||
RunTestCases();
|
||||
#endif
|
||||
|
||||
#ifdef WEBRTC_CODEC_ILBC
|
||||
// Register iLBC as send codec
|
||||
RegisterCodec(kIlbc);
|
||||
RunTestCases();
|
||||
#endif
|
||||
|
||||
#ifdef WEBRTC_CODEC_OPUS
|
||||
// Register Opus as send codec
|
||||
RegisterCodec(kOpus);
|
||||
RunTestCases();
|
||||
#endif
|
||||
}
|
||||
|
||||
// Test various configurations on VAD/DTX.
|
||||
void TestWebRtcVadDtx::RunTestCases() {
|
||||
// #1 DTX = OFF, VAD = OFF, VADNormal
|
||||
SetVAD(false, false, VADNormal);
|
||||
Test(true);
|
||||
|
||||
// #2 DTX = ON, VAD = ON, VADAggr
|
||||
SetVAD(true, true, VADAggr);
|
||||
Test(false);
|
||||
|
||||
// #3 DTX = ON, VAD = ON, VADLowBitrate
|
||||
SetVAD(true, true, VADLowBitrate);
|
||||
Test(false);
|
||||
|
||||
// #4 DTX = ON, VAD = ON, VADVeryAggr
|
||||
SetVAD(true, true, VADVeryAggr);
|
||||
Test(false);
|
||||
|
||||
// #5 DTX = ON, VAD = ON, VADNormal
|
||||
SetVAD(true, true, VADNormal);
|
||||
Test(false);
|
||||
}
|
||||
|
||||
// Set the expectation and run the test.
|
||||
void TestWebRtcVadDtx::Test(bool new_outfile) {
|
||||
int expects[kPacketTypes];
|
||||
int frequency = acm_send_->SendFrequency();
|
||||
expects[0] = -1; // Do not care.
|
||||
expects[1] = 1;
|
||||
expects[2] = vad_enabled_ && !use_webrtc_dtx_;
|
||||
expects[3] = use_webrtc_dtx_ && (frequency == 8000);
|
||||
expects[4] = use_webrtc_dtx_ && (frequency == 16000);
|
||||
expects[5] = use_webrtc_dtx_ && (frequency == 32000);
|
||||
if (new_outfile) {
|
||||
output_file_num_++;
|
||||
}
|
||||
std::stringstream out_filename;
|
||||
out_filename << webrtc::test::OutputPath()
|
||||
<< "testWebRtcVadDtx_outFile_"
|
||||
<< output_file_num_
|
||||
<< ".pcm";
|
||||
Run(webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm"),
|
||||
32000, 1, out_filename.str(), !new_outfile, expects);
|
||||
}
|
||||
|
||||
void TestWebRtcVadDtx::SetVAD(bool enable_dtx, bool enable_vad,
|
||||
ACMVADMode vad_mode) {
|
||||
ACMVADMode mode;
|
||||
EXPECT_EQ(0, acm_send_->SetVAD(enable_dtx, enable_vad, vad_mode));
|
||||
EXPECT_EQ(0, acm_send_->VAD(&dtx_enabled_, &vad_enabled_, &mode));
|
||||
|
||||
CodecInst codec_param;
|
||||
acm_send_->SendCodec(&codec_param);
|
||||
if (STR_CASE_CMP(codec_param.plname, "opus") == 0) {
|
||||
// If send codec is Opus, WebRTC VAD/DTX cannot be used.
|
||||
enable_dtx = enable_vad = false;
|
||||
}
|
||||
|
||||
EXPECT_EQ(dtx_enabled_ , enable_dtx); // DTX should be set as expected.
|
||||
|
||||
bool replaced = false;
|
||||
acm_send_->IsInternalDTXReplacedWithWebRtc(&replaced);
|
||||
|
||||
use_webrtc_dtx_ = dtx_enabled_ && replaced;
|
||||
|
||||
if (use_webrtc_dtx_) {
|
||||
EXPECT_TRUE(vad_enabled_); // WebRTC DTX cannot run without WebRTC VAD.
|
||||
}
|
||||
|
||||
if (!dtx_enabled_ || !use_webrtc_dtx_) {
|
||||
// Using no DTX or codec Internal DTX should not affect setting of VAD.
|
||||
EXPECT_EQ(enable_vad, vad_enabled_);
|
||||
}
|
||||
}
|
||||
|
||||
// Following is the implementation of TestOpusDtx.
|
||||
void TestOpusDtx::Perform() {
|
||||
#ifdef WEBRTC_CODEC_OPUS
|
||||
int expects[kPacketTypes] = {0, 1, 0, 0, 0, 0};
|
||||
|
||||
// Register Opus as send codec
|
||||
std::string out_filename = webrtc::test::OutputPath() +
|
||||
"testOpusDtx_outFile_mono.pcm";
|
||||
RegisterCodec(kOpus);
|
||||
EXPECT_EQ(0, acm_send_->DisableOpusDtx());
|
||||
|
||||
Run(webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm"),
|
||||
32000, 1, out_filename, false, expects);
|
||||
|
||||
EXPECT_EQ(0, acm_send_->EnableOpusDtx());
|
||||
expects[0] = 1;
|
||||
Run(webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm"),
|
||||
32000, 1, out_filename, true, expects);
|
||||
|
||||
// Register stereo Opus as send codec
|
||||
out_filename = webrtc::test::OutputPath() + "testOpusDtx_outFile_stereo.pcm";
|
||||
RegisterCodec(kOpusStereo);
|
||||
EXPECT_EQ(0, acm_send_->DisableOpusDtx());
|
||||
expects[0] = 0;
|
||||
Run(webrtc::test::ResourcePath("audio_coding/teststereo32kHz", "pcm"),
|
||||
32000, 2, out_filename, false, expects);
|
||||
|
||||
// Opus DTX should only work in Voip mode.
|
||||
EXPECT_EQ(0, acm_send_->SetOpusApplication(kVoip));
|
||||
EXPECT_EQ(0, acm_send_->EnableOpusDtx());
|
||||
|
||||
expects[0] = 1;
|
||||
Run(webrtc::test::ResourcePath("audio_coding/teststereo32kHz", "pcm"),
|
||||
32000, 2, out_filename, true, expects);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
@ -11,73 +11,97 @@
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_MAIN_TEST_TESTVADDTX_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_MAIN_TEST_TESTVADDTX_H_
|
||||
|
||||
|
||||
#include "webrtc/base/scoped_ptr.h"
|
||||
#include "webrtc/common_types.h"
|
||||
#include "webrtc/modules/audio_coding/main/interface/audio_coding_module.h"
|
||||
#include "webrtc/modules/audio_coding/main/interface/audio_coding_module_typedefs.h"
|
||||
#include "webrtc/modules/audio_coding/main/test/ACMTest.h"
|
||||
#include "webrtc/modules/audio_coding/main/test/Channel.h"
|
||||
#include "webrtc/modules/audio_coding/main/test/PCMFile.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
typedef struct {
|
||||
bool statusDTX;
|
||||
bool statusVAD;
|
||||
ACMVADMode vadMode;
|
||||
} VADDTXstruct;
|
||||
|
||||
class ActivityMonitor : public ACMVADCallback {
|
||||
public:
|
||||
static const int kPacketTypes = 6;
|
||||
|
||||
ActivityMonitor();
|
||||
~ActivityMonitor();
|
||||
int32_t InFrameType(int16_t frameType);
|
||||
int32_t InFrameType(int16_t frame_type);
|
||||
void PrintStatistics();
|
||||
void ResetStatistics();
|
||||
void GetStatistics(uint32_t* getCounter);
|
||||
void GetStatistics(uint32_t* stats);
|
||||
private:
|
||||
// Counting according to
|
||||
// enum WebRtcACMEncodingType {
|
||||
// kNoEncoding,
|
||||
// kActiveNormalEncoded,
|
||||
// kPassiveNormalEncoded,
|
||||
// kPassiveDTXNB,
|
||||
// kPassiveDTXWB,
|
||||
// kPassiveDTXSWB
|
||||
// };
|
||||
uint32_t _counter[6];
|
||||
// counter_[0] - kNoEncoding,
|
||||
// counter_[1] - kActiveNormalEncoded,
|
||||
// counter_[2] - kPassiveNormalEncoded,
|
||||
// counter_[3] - kPassiveDTXNB,
|
||||
// counter_[4] - kPassiveDTXWB,
|
||||
// counter_[5] - kPassiveDTXSWB
|
||||
uint32_t counter_[kPacketTypes];
|
||||
};
|
||||
|
||||
class TestVADDTX : public ACMTest {
|
||||
|
||||
// TestVadDtx is to verify that VAD/DTX perform as they should. It runs through
|
||||
// an audio file and check if the occurrence of various packet types follows
|
||||
// expectation. TestVadDtx needs its derived class to implement the Perform()
|
||||
// to put the test together.
|
||||
class TestVadDtx : public ACMTest {
|
||||
public:
|
||||
TestVADDTX();
|
||||
~TestVADDTX();
|
||||
static const int kOutputFreqHz = 16000;
|
||||
static const int kPacketTypes = 6;
|
||||
|
||||
TestVadDtx();
|
||||
|
||||
virtual void Perform() = 0;
|
||||
|
||||
protected:
|
||||
void RegisterCodec(CodecInst codec_param);
|
||||
|
||||
// Encoding a file and see if the numbers that various packets occur follow
|
||||
// the expectation. Saves result to a file.
|
||||
// expects[x] means
|
||||
// -1 : do not care,
|
||||
// 0 : there have been no packets of type |x|,
|
||||
// 1 : there have been packets of type |x|,
|
||||
// with |x| indicates the following packet types
|
||||
// 0 - kNoEncoding
|
||||
// 1 - kActiveNormalEncoded
|
||||
// 2 - kPassiveNormalEncoded
|
||||
// 3 - kPassiveDTXNB
|
||||
// 4 - kPassiveDTXWB
|
||||
// 5 - kPassiveDTXSWB
|
||||
void Run(std::string in_filename, int frequency, int channels,
|
||||
std::string out_filename, bool append, const int* expects);
|
||||
|
||||
rtc::scoped_ptr<AudioCodingModule> acm_send_;
|
||||
rtc::scoped_ptr<AudioCodingModule> acm_receive_;
|
||||
rtc::scoped_ptr<Channel> channel_;
|
||||
rtc::scoped_ptr<ActivityMonitor> monitor_;
|
||||
};
|
||||
|
||||
// TestWebRtcVadDtx is to verify that the WebRTC VAD/DTX perform as they should.
|
||||
class TestWebRtcVadDtx final : public TestVadDtx {
|
||||
public:
|
||||
TestWebRtcVadDtx();
|
||||
|
||||
void Perform() override;
|
||||
|
||||
void Perform();
|
||||
private:
|
||||
// Registration can be based on codec name only, codec name and sampling
|
||||
// frequency, or codec name, sampling frequency and rate.
|
||||
int16_t RegisterSendCodec(char side,
|
||||
char* codecName,
|
||||
int32_t samplingFreqHz = -1,
|
||||
int32_t rateKhz = -1);
|
||||
void Run();
|
||||
void OpenOutFile(int16_t testNumber);
|
||||
void runTestCases();
|
||||
void runTestInternalDTX(int expected_result);
|
||||
void SetVAD(bool statusDTX, bool statusVAD, int16_t vadMode);
|
||||
VADDTXstruct GetVAD();
|
||||
int16_t VerifyTest();
|
||||
rtc::scoped_ptr<AudioCodingModule> _acmA;
|
||||
rtc::scoped_ptr<AudioCodingModule> _acmB;
|
||||
void RunTestCases();
|
||||
void Test(bool new_outfile);
|
||||
void SetVAD(bool enable_dtx, bool enable_vad, ACMVADMode vad_mode);
|
||||
|
||||
Channel* _channelA2B;
|
||||
bool vad_enabled_;
|
||||
bool dtx_enabled_;
|
||||
bool use_webrtc_dtx_;
|
||||
int output_file_num_;
|
||||
};
|
||||
|
||||
PCMFile _inFileA;
|
||||
PCMFile _outFileB;
|
||||
|
||||
ActivityMonitor _monitor;
|
||||
uint32_t _statCounter[6];
|
||||
|
||||
VADDTXstruct _setStruct;
|
||||
VADDTXstruct _getStruct;
|
||||
// TestOpusDtx is to verify that the Opus DTX performs as it should.
|
||||
class TestOpusDtx final : public TestVadDtx {
|
||||
public:
|
||||
void Perform() override;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
@ -82,11 +82,19 @@ TEST(AudioCodingModuleTest, DISABLED_ON_ANDROID(TestStereo)) {
|
||||
Trace::ReturnTrace();
|
||||
}
|
||||
|
||||
TEST(AudioCodingModuleTest, DISABLED_ON_ANDROID(TestVADDTX)) {
|
||||
TEST(AudioCodingModuleTest, DISABLED_ON_ANDROID(TestWebRtcVadDtx)) {
|
||||
Trace::CreateTrace();
|
||||
Trace::SetTraceFile((webrtc::test::OutputPath() +
|
||||
"acm_vaddtx_trace.txt").c_str());
|
||||
webrtc::TestVADDTX().Perform();
|
||||
webrtc::TestWebRtcVadDtx().Perform();
|
||||
Trace::ReturnTrace();
|
||||
}
|
||||
|
||||
TEST(AudioCodingModuleTest, TestOpusDtx) {
|
||||
Trace::CreateTrace();
|
||||
Trace::SetTraceFile((webrtc::test::OutputPath() +
|
||||
"acm_opusdtx_trace.txt").c_str());
|
||||
webrtc::TestOpusDtx().Perform();
|
||||
Trace::ReturnTrace();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user