Setting Opus target application.

This CL is to allow to set Opus target application at the creation of an encoder.

According to Opus spec, there are three applications:

OPUS_APPLICATION_VOIP
OPUS_APPLICATION_AUDIO
OPUS_APPLICATION_RESTRICTED_LOWDELAY

BUG=
R=henrik.lundin@webrtc.org, tina.legrand@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/37479004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@8103 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
minyue@webrtc.org
2015-01-20 16:01:50 +00:00
parent 853049fa30
commit 7dba7860c7
21 changed files with 489 additions and 317 deletions

View File

@ -999,6 +999,12 @@ int16_t ACMGenericCodec::REDPayloadISAC(const int32_t /* isac_rate */,
return -1;
}
int ACMGenericCodec::SetOpusApplication(OpusApplicationMode /*application*/) {
WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, unique_id_,
"The send-codec is not Opus, failed to set application.");
return -1;
}
int ACMGenericCodec::SetOpusMaxPlaybackRate(int /* frequency_hz */) {
WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, unique_id_,
"The send-codec is not Opus, failed to set maximum playback rate.");

View File

@ -525,6 +525,20 @@ class ACMGenericCodec {
uint8_t* payload,
int16_t* payload_len_bytes);
///////////////////////////////////////////////////////////////////////////
// int SetOpusApplication()
// Sets the intended application for the Opus encoder. Opus uses this to
// optimize the encoding for applications like VOIP and music.
//
// Input:
// - application : intended application.
//
// Return value:
// -1 if failed or on codecs other than Opus.
// 0 if succeeded.
//
virtual int SetOpusApplication(OpusApplicationMode /*application*/);
///////////////////////////////////////////////////////////////////////////
// int SetOpusMaxPlaybackRate()
// Sets maximum playback rate the receiver will render, if the codec is Opus.
@ -636,8 +650,8 @@ class ACMGenericCodec {
// See InitEncoder() for the description of function, input(s)/output(s)
// and return value.
//
int16_t InitEncoderSafe(WebRtcACMCodecParams* codec_params,
bool force_initialization)
virtual int16_t InitEncoderSafe(WebRtcACMCodecParams* codec_params,
bool force_initialization)
EXCLUSIVE_LOCKS_REQUIRED(codec_wrapper_lock_);
///////////////////////////////////////////////////////////////////////////

View File

@ -68,7 +68,8 @@ ACMOpus::ACMOpus(int16_t codec_id)
sample_freq_(32000), // Default sampling frequency.
bitrate_(20000), // Default bit-rate.
channels_(1), // Default mono.
packet_loss_rate_(0) { // Initial packet loss rate.
packet_loss_rate_(0), // Initial packet loss rate.
application_(kVoip) { // Initial application mode.
codec_id_ = codec_id;
// Opus has internal DTX, but we dont use it for now.
has_internal_dtx_ = false;
@ -113,6 +114,16 @@ int16_t ACMOpus::InternalEncode(uint8_t* bitstream,
return *bitstream_len_byte;
}
int16_t ACMOpus::InitEncoderSafe(WebRtcACMCodecParams* codec_params,
bool force_initialization) {
// Determine target application if codec is not initialized or a forced
// initialization is requested.
if (!encoder_initialized_ || force_initialization) {
application_ = (codec_params->codec_inst.channels == 1) ? kVoip : kAudio;
}
return ACMGenericCodec::InitEncoderSafe(codec_params, force_initialization);
}
int16_t ACMOpus::InternalInitEncoder(WebRtcACMCodecParams* codec_params) {
int16_t ret;
if (encoder_inst_ptr_ != NULL) {
@ -120,7 +131,8 @@ int16_t ACMOpus::InternalInitEncoder(WebRtcACMCodecParams* codec_params) {
encoder_inst_ptr_ = NULL;
}
ret = WebRtcOpus_EncoderCreate(&encoder_inst_ptr_,
codec_params->codec_inst.channels);
codec_params->codec_inst.channels,
application_);
// Store number of channels.
channels_ = codec_params->codec_inst.channels;
@ -251,6 +263,13 @@ int ACMOpus::SetOpusMaxPlaybackRate(int frequency_hz) {
return WebRtcOpus_SetMaxPlaybackRate(encoder_inst_ptr_, frequency_hz);
}
int ACMOpus::SetOpusApplication(OpusApplicationMode application) {
WriteLockScoped lockCodec(codec_wrapper_lock_);
application_ = application;
// Set Opus application invokes a reset of the encoder.
return InternalResetEncoder();
}
#endif // WEBRTC_CODEC_OPUS
} // namespace acm2

View File

@ -29,23 +29,29 @@ class ACMOpus : public ACMGenericCodec {
ACMGenericCodec* CreateInstance(void);
int16_t InternalEncode(uint8_t* bitstream,
int16_t* bitstream_len_byte) OVERRIDE
int16_t* bitstream_len_byte) override
EXCLUSIVE_LOCKS_REQUIRED(codec_wrapper_lock_);
int16_t InitEncoderSafe(WebRtcACMCodecParams* codec_params,
bool force_initialization) override
EXCLUSIVE_LOCKS_REQUIRED(codec_wrapper_lock_);
int16_t InternalInitEncoder(WebRtcACMCodecParams *codec_params);
virtual int SetFEC(bool enable_fec) OVERRIDE;
int SetFEC(bool enable_fec) override;
virtual int SetPacketLossRate(int loss_rate) OVERRIDE;
int SetOpusApplication(OpusApplicationMode mode) override;
virtual int SetOpusMaxPlaybackRate(int frequency_hz) OVERRIDE;
int SetPacketLossRate(int loss_rate) override;
int SetOpusMaxPlaybackRate(int frequency_hz) override;
protected:
void DestructEncoderSafe();
int16_t InternalCreateEncoder();
int16_t SetBitRateSafe(const int32_t rate) OVERRIDE
int16_t SetBitRateSafe(const int32_t rate) override
EXCLUSIVE_LOCKS_REQUIRED(codec_wrapper_lock_);
WebRtcOpusEncInst* encoder_inst_ptr_;
@ -54,6 +60,8 @@ class ACMOpus : public ACMGenericCodec {
int channels_;
int packet_loss_rate_;
OpusApplicationMode application_;
};
} // namespace acm2

View File

@ -35,6 +35,11 @@ class AcmOpusTest : public ACMOpus {
: ACMOpus(codec_id) {}
~AcmOpusTest() {}
int packet_loss_rate() { return packet_loss_rate_; }
OpusApplicationMode application() { return application_; }
bool encoder_initialized() {
ReadLockScoped cs(codec_wrapper_lock_);
return encoder_initialized_;
}
void TestSetPacketLossRate(int from, int to, int expected_return);
};
@ -82,6 +87,54 @@ TEST(AcmOpusTest, PacketLossRateOptimized) {
kPacketLossRate1);
opus.TestSetPacketLossRate(0, 0, 0);
}
TEST(AcmOpusTest, DefaultApplicationMode) {
AcmOpusTest opus(ACMCodecDB::kOpus);
WebRtcACMCodecParams params;
memcpy(&(params.codec_inst), &kOpusCodecInst, sizeof(CodecInst));
params.codec_inst.channels = 2;
// Codec is not initialized, and hence without force initialization (2nd
// argument being false), an initialization will take place.
EXPECT_FALSE(opus.encoder_initialized());
EXPECT_EQ(0, opus.InitEncoder(&params, false));
EXPECT_EQ(kAudio, opus.application());
params.codec_inst.channels = 1;
EXPECT_EQ(0, opus.InitEncoder(&params, true));
EXPECT_EQ(kVoip, opus.application());
}
TEST(AcmOpusTest, ChangeApplicationMode) {
AcmOpusTest opus(ACMCodecDB::kOpus);
WebRtcACMCodecParams params;
memcpy(&(params.codec_inst), &kOpusCodecInst, sizeof(CodecInst));
params.codec_inst.channels = 2;
// Codec is not initialized, and hence without force initialization (2nd
// argument being false), an initialization will take place.
EXPECT_EQ(0, opus.InitEncoder(&params, false));
EXPECT_EQ(kAudio, opus.application());
opus.SetOpusApplication(kVoip);
EXPECT_EQ(kVoip, opus.application());
}
TEST(AcmOpusTest, ResetWontChangeApplicationMode) {
AcmOpusTest opus(ACMCodecDB::kOpus);
WebRtcACMCodecParams params;
memcpy(&(params.codec_inst), &kOpusCodecInst, sizeof(CodecInst));
params.codec_inst.channels = 2;
// Codec is not initialized, and hence without force initialization (2nd
// argument being false), an initialization will take place.
EXPECT_EQ(0, opus.InitEncoder(&params, false));
EXPECT_EQ(kAudio, opus.application());
opus.ResetEncoder();
EXPECT_EQ(kAudio, opus.application());
}
#else
void AcmOpusTest:TestSetPacketLossRate(int /* from */, int /* to */,
int /* expected_return */) {

View File

@ -54,6 +54,8 @@ class AcmSendTestOldApi : public AudioPacketizationCallback,
size_t payload_len_bytes,
const RTPFragmentationHeader* fragmentation) OVERRIDE;
AudioCodingModule* acm() { return acm_.get(); }
private:
static const int kBlockSizeMs = 10;

View File

@ -1544,6 +1544,14 @@ int AudioCodingModuleImpl::ConfigISACBandwidthEstimator(
frame_size_ms, rate_bit_per_sec, enforce_frame_size);
}
int AudioCodingModuleImpl::SetOpusApplication(OpusApplicationMode application) {
CriticalSectionScoped lock(acm_crit_sect_);
if (!HaveValidEncoder("SetOpusApplication")) {
return -1;
}
return codecs_[current_send_codec_idx_]->SetOpusApplication(application);
}
// Informs Opus encoder of the maximum playback rate the receiver will render.
int AudioCodingModuleImpl::SetOpusMaxPlaybackRate(int frequency_hz) {
CriticalSectionScoped lock(acm_crit_sect_);

View File

@ -224,6 +224,8 @@ class AudioCodingModuleImpl : public AudioCodingModule {
int rate_bit_per_sec,
bool enforce_frame_size = false) OVERRIDE;
int SetOpusApplication(OpusApplicationMode application) override;
// If current send codec is Opus, informs it about the maximum playback rate
// the receiver will render.
virtual int SetOpusMaxPlaybackRate(int frequency_hz) OVERRIDE;

View File

@ -977,6 +977,22 @@ TEST_F(AcmSenderBitExactnessOldApi, MAYBE_Opus_stereo_20ms) {
test::AcmReceiveTestOldApi::kStereoOutput);
}
TEST_F(AcmSenderBitExactnessOldApi, Opus_stereo_20ms_voip) {
ASSERT_NO_FATAL_FAILURE(SetUpTest("opus", 48000, 2, 120, 960, 960));
// If not set, default will be kAudio in case of stereo.
send_test_->acm()->SetOpusApplication(kVoip);
Run(AcmReceiverBitExactnessOldApi::PlatformChecksum(
"9b9e12bc3cc793740966e11cbfa8b35b",
"57412a4b5771d19ff03ec35deffe7067",
"9b9e12bc3cc793740966e11cbfa8b35b"),
AcmReceiverBitExactnessOldApi::PlatformChecksum(
"c7340b1189652ab6b5e80dade7390cb4",
"cdfe85939c411d12b61701c566e22d26",
"c7340b1189652ab6b5e80dade7390cb4"),
50,
test::AcmReceiveTestOldApi::kStereoOutput);
}
// This test fixture is implemented to run ACM and change the desired output
// frequency during the call. The input packets are simply PCM16b-wb encoded
// payloads with a constant value of |kSampleValue|. The test fixture itself

View File

@ -874,6 +874,20 @@ class AudioCodingModule: public Module {
int init_rate_bps,
bool enforce_frame_size = false) = 0;
///////////////////////////////////////////////////////////////////////////
// int SetOpusApplication()
// Sets the intended application for the Opus encoder. Opus uses this to
// optimize the encoding for applications like VOIP and music.
//
// Input:
// - application : intended application.
//
// Return value:
// -1 if failed or on codecs other than Opus.
// 0 if succeeded.
//
virtual int SetOpusApplication(OpusApplicationMode /*application*/) = 0;
///////////////////////////////////////////////////////////////////////////
// int SetOpusMaxPlaybackRate()
// If current send codec is Opus, informs it about maximum playback rate the

View File

@ -200,6 +200,18 @@ enum ACMBackgroundNoiseMode {
Off
};
///////////////////////////////////////////////////////////////////////////
//
// Enumeration of Opus mode for intended application.
//
// kVoip : optimized for voice signals.
// kAudio : optimized for non-voice signals like music.
//
enum OpusApplicationMode {
kVoip = 0,
kAudio = 1,
};
} // namespace webrtc
#endif // WEBRTC_MODULES_AUDIO_CODING_MAIN_INTERFACE_AUDIO_CODING_MODULE_TYPEDEFS_H_

View File

@ -79,8 +79,8 @@ void OpusTest::Perform() {
in_file_mono_.ReadStereo(false);
// Create Opus encoders for mono and stereo.
ASSERT_GT(WebRtcOpus_EncoderCreate(&opus_mono_encoder_, 1), -1);
ASSERT_GT(WebRtcOpus_EncoderCreate(&opus_stereo_encoder_, 2), -1);
ASSERT_GT(WebRtcOpus_EncoderCreate(&opus_mono_encoder_, 1, 0), -1);
ASSERT_GT(WebRtcOpus_EncoderCreate(&opus_stereo_encoder_, 2, 1), -1);
// Create Opus decoders for mono and stereo for stand-alone testing of Opus.
ASSERT_GT(WebRtcOpus_DecoderCreate(&opus_mono_decoder_, 1), -1);