Adding SetOpusMaxBandwidth in VoE and ACM
This is a step to solve
https://code.google.com/p/webrtc/issues/detail?id=1906
In particular, we add an API in VoE and ACM to call Opus's API of setting maximum bandwidth.
TEST = added a test in voe_cmd_test and listened to the result
BUG=
R=henrika@google.com, henrika@webrtc.org, turaj@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/21129004
git-svn-id: http://webrtc.googlecode.com/svn/trunk/webrtc@6869 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/modules/audio_coding/main/acm2/acm_generic_codec.cc b/modules/audio_coding/main/acm2/acm_generic_codec.cc
index db776d2..565d291 100644
--- a/modules/audio_coding/main/acm2/acm_generic_codec.cc
+++ b/modules/audio_coding/main/acm2/acm_generic_codec.cc
@@ -1000,6 +1000,12 @@
return -1;
}
+int ACMGenericCodec::SetOpusMaxBandwidth(int /* max_bandwidth */) {
+ WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, unique_id_,
+ "The send-codec is not Opus, failed to set maximum bandwidth.");
+ return -1;
+}
+
} // namespace acm2
} // namespace webrtc
diff --git a/modules/audio_coding/main/acm2/acm_generic_codec.h b/modules/audio_coding/main/acm2/acm_generic_codec.h
index 80f239a..b88e28f 100644
--- a/modules/audio_coding/main/acm2/acm_generic_codec.h
+++ b/modules/audio_coding/main/acm2/acm_generic_codec.h
@@ -538,6 +538,23 @@
int16_t* payload_len_bytes);
///////////////////////////////////////////////////////////////////////////
+ // int SetOpusMaxBandwidth()
+ // Sets maximum required encoding bandwidth for Opus. This is to tell Opus
+ // that it is enough to code the input audio up to a bandwidth. A use case of
+ // this is when the receiver cannot render the full band. Opus can take this
+ // information to optimize the bit rate and increase the computation
+ // efficiency.
+ //
+ // Input:
+ // -max_bandwidth : maximum required bandwidth.
+ //
+ // Return value:
+ // -1 if failed or on codecs other than Opus
+ // 0 if succeeded.
+ //
+ virtual int SetOpusMaxBandwidth(int /* max_bandwidth */);
+
+ ///////////////////////////////////////////////////////////////////////////
// HasFrameToEncode()
// Returns true if there is enough audio buffered for encoding, such that
// calling Encode() will return a payload.
diff --git a/modules/audio_coding/main/acm2/acm_opus.cc b/modules/audio_coding/main/acm2/acm_opus.cc
index f75a348..c778982 100644
--- a/modules/audio_coding/main/acm2/acm_opus.cc
+++ b/modules/audio_coding/main/acm2/acm_opus.cc
@@ -261,6 +261,11 @@
return -1;
}
+int ACMOpus::SetOpusMaxBandwidth(int max_bandwidth) {
+ // Ask the encoder to change the maximum required bandwidth.
+ return WebRtcOpus_SetMaxBandwidth(encoder_inst_ptr_, max_bandwidth);
+}
+
#endif // WEBRTC_CODEC_OPUS
} // namespace acm2
diff --git a/modules/audio_coding/main/acm2/acm_opus.h b/modules/audio_coding/main/acm2/acm_opus.h
index b94adc4..8c2882c 100644
--- a/modules/audio_coding/main/acm2/acm_opus.h
+++ b/modules/audio_coding/main/acm2/acm_opus.h
@@ -38,6 +38,8 @@
virtual int SetPacketLossRate(int loss_rate) OVERRIDE;
+ virtual int SetOpusMaxBandwidth(int max_bandwidth) OVERRIDE;
+
protected:
void DestructEncoderSafe();
diff --git a/modules/audio_coding/main/acm2/audio_coding_module_impl.cc b/modules/audio_coding/main/acm2/audio_coding_module_impl.cc
index 26f5b54..164c0bb 100644
--- a/modules/audio_coding/main/acm2/audio_coding_module_impl.cc
+++ b/modules/audio_coding/main/acm2/audio_coding_module_impl.cc
@@ -1911,6 +1911,15 @@
frame_size_ms, rate_bit_per_sec, enforce_frame_size);
}
+// Informs Opus encoder about the maximum audio bandwidth needs to be encoded.
+int AudioCodingModuleImpl::SetOpusMaxBandwidth(int bandwidth_hz) {
+ CriticalSectionScoped lock(acm_crit_sect_);
+ if (!HaveValidEncoder("SetOpusMaxBandwidth")) {
+ return -1;
+ }
+ return codecs_[current_send_codec_idx_]->SetOpusMaxBandwidth(bandwidth_hz);
+}
+
int AudioCodingModuleImpl::PlayoutTimestamp(uint32_t* timestamp) {
return receiver_.GetPlayoutTimestamp(timestamp) ? 0 : -1;
}
diff --git a/modules/audio_coding/main/acm2/audio_coding_module_impl.h b/modules/audio_coding/main/acm2/audio_coding_module_impl.h
index 02290da..9e5cc37 100644
--- a/modules/audio_coding/main/acm2/audio_coding_module_impl.h
+++ b/modules/audio_coding/main/acm2/audio_coding_module_impl.h
@@ -232,6 +232,10 @@
int rate_bit_per_sec,
bool enforce_frame_size = false);
+ // If current send codec is Opus, informs it about the maximum audio
+ // bandwidth needs to be encoded.
+ int SetOpusMaxBandwidth(int bandwidth_hz);
+
int UnregisterReceiveCodec(uint8_t payload_type);
int EnableNack(size_t max_nack_list_size);
diff --git a/modules/audio_coding/main/interface/audio_coding_module.h b/modules/audio_coding/main/interface/audio_coding_module.h
index 4827004..aae7ead 100644
--- a/modules/audio_coding/main/interface/audio_coding_module.h
+++ b/modules/audio_coding/main/interface/audio_coding_module.h
@@ -916,6 +916,23 @@
bool enforce_frame_size = false) = 0;
///////////////////////////////////////////////////////////////////////////
+ // int SetOpusMaxBandwidth()
+ // If current send codec is Opus, informs it about maximum audio bandwidth
+ // needs to be encoded. A use case of this is when the receiver can only play
+ // audio up to frequency limit. Opus can use this information to optimize
+ // the bit rate and increase the computation efficiency.
+ //
+ // Input:
+ // -banbwidth_hz : maximum bandwidth in Hz.
+ //
+ // Return value:
+ // -1 if current send codec is not Opus or
+ // error occurred in setting the bandwidth,
+ // 0 maximum bandwidth is set successfully.
+ //
+ virtual int SetOpusMaxBandwidth(int banbwidth_hz) = 0;
+
+ ///////////////////////////////////////////////////////////////////////////
// statistics
//
diff --git a/voice_engine/channel.cc b/voice_engine/channel.cc
index c9364ef..3f13ba2 100644
--- a/voice_engine/channel.cc
+++ b/voice_engine/channel.cc
@@ -1749,6 +1749,19 @@
return 0;
}
+int Channel::SetOpusMaxBandwidth(int bandwidth_hz) {
+ WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
+ "Channel::SetOpusMaxBandwidth()");
+
+ if (audio_coding_->SetOpusMaxBandwidth(bandwidth_hz) != 0) {
+ _engineStatisticsPtr->SetLastError(
+ VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
+ "SetOpusMaxBandwidth() failed to set maximum encoding bandwidth");
+ return -1;
+ }
+ return 0;
+}
+
int32_t Channel::RegisterExternalTransport(Transport& transport)
{
WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
diff --git a/voice_engine/channel.h b/voice_engine/channel.h
index 8385ccc..a4f7ecd 100644
--- a/voice_engine/channel.h
+++ b/voice_engine/channel.h
@@ -207,6 +207,7 @@
int32_t SetRecPayloadType(const CodecInst& codec);
int32_t GetRecPayloadType(CodecInst& codec);
int32_t SetSendCNPayloadType(int type, PayloadFrequencies frequency);
+ int SetOpusMaxBandwidth(int bandwidth_hz);
// VoE dual-streaming.
int SetSecondarySendCodec(const CodecInst& codec, int red_payload_type);
diff --git a/voice_engine/include/voe_codec.h b/voice_engine/include/voe_codec.h
index 34a2232..56835f7 100644
--- a/voice_engine/include/voe_codec.h
+++ b/voice_engine/include/voe_codec.h
@@ -126,6 +126,14 @@
virtual int GetVADStatus(int channel, bool& enabled, VadModes& mode,
bool& disabledDTX) = 0;
+ // Sets the maximum audio bandwidth needs to be encoded in Hz,
+ // |bandwidth_hz|, for the Opus encoder on a specific |channel|.
+ // TODO(minyue): Make SetOpusMaxBandwidth() pure virtual when
+ // fakewebrtcvoiceengine in talk is ready.
+ virtual int SetOpusMaxBandwidth(int channel, int bandwidth_hz) {
+ return -1;
+ }
+
// Don't use. To be removed.
virtual int SetAMREncFormat(int channel, AmrMode mode) { return -1; }
virtual int SetAMRDecFormat(int channel, AmrMode mode) { return -1; }
diff --git a/voice_engine/test/auto_test/standard/codec_test.cc b/voice_engine/test/auto_test/standard/codec_test.cc
index 2970ab3..8ca4328 100644
--- a/voice_engine/test/auto_test/standard/codec_test.cc
+++ b/voice_engine/test/auto_test/standard/codec_test.cc
@@ -130,6 +130,33 @@
EXPECT_EQ(webrtc::kVadConventional, vad_mode);
}
+TEST_F(CodecTest, OpusMaxBandwidthCanBeSet) {
+ for (int i = 0; i < voe_codec_->NumOfCodecs(); ++i) {
+ voe_codec_->GetCodec(i, codec_instance_);
+ if (_stricmp("opus", codec_instance_.plname)) {
+ continue;
+ }
+ voe_codec_->SetSendCodec(channel_, codec_instance_);
+ // SetOpusMaxBandwidth can handle any integer as the bandwidth. Following
+ // tests some most commonly used numbers.
+ EXPECT_EQ(0, voe_codec_->SetOpusMaxBandwidth(channel_, 24000));
+ EXPECT_EQ(0, voe_codec_->SetOpusMaxBandwidth(channel_, 16000));
+ EXPECT_EQ(0, voe_codec_->SetOpusMaxBandwidth(channel_, 8000));
+ EXPECT_EQ(0, voe_codec_->SetOpusMaxBandwidth(channel_, 4000));
+ }
+}
+
+TEST_F(CodecTest, OpusMaxBandwidthCannotBeSetForNonOpus) {
+ for (int i = 0; i < voe_codec_->NumOfCodecs(); ++i) {
+ voe_codec_->GetCodec(i, codec_instance_);
+ if (!_stricmp("opus", codec_instance_.plname)) {
+ continue;
+ }
+ voe_codec_->SetSendCodec(channel_, codec_instance_);
+ EXPECT_EQ(-1, voe_codec_->SetOpusMaxBandwidth(channel_, 16000));
+ }
+}
+
// TODO(xians, phoglund): Re-enable when issue 372 is resolved.
TEST_F(CodecTest, DISABLED_ManualVerifySendCodecsForAllPacketSizes) {
for (int i = 0; i < voe_codec_->NumOfCodecs(); ++i) {
diff --git a/voice_engine/test/cmd_test/voe_cmd_test.cc b/voice_engine/test/cmd_test/voe_cmd_test.cc
index a30764a..5e63645 100644
--- a/voice_engine/test/cmd_test/voe_cmd_test.cc
+++ b/voice_engine/test/cmd_test/voe_cmd_test.cc
@@ -445,6 +445,7 @@
printf("%i. Remove a file-playing channel \n", option_index++);
printf("%i. Toggle Opus stereo (Opus must be selected again to apply "
"the setting) \n", option_index++);
+ printf("%i. Set Opus maximum audio bandwidth \n", option_index++);
printf("Select action or %i to stop the call: ", option_index);
int option_selection;
@@ -757,6 +758,12 @@
else
printf("\n Opus mono enabled (select Opus again to apply the "
"setting). \n");
+ } else if (option_selection == option_index++) {
+ printf("\n Input bandwidth in Hz: ");
+ int max_playback_rate;
+ ASSERT_EQ(1, scanf("%i", &max_playback_rate));
+ res = codec->SetOpusMaxBandwidth(chan, max_playback_rate);
+ VALIDATE;
} else {
break;
}
diff --git a/voice_engine/voe_codec_impl.cc b/voice_engine/voe_codec_impl.cc
index 4aa0556..5099407 100644
--- a/voice_engine/voe_codec_impl.cc
+++ b/voice_engine/voe_codec_impl.cc
@@ -418,6 +418,24 @@
return 0;
}
+int VoECodecImpl::SetOpusMaxBandwidth(int channel, int bandwidth_hz) {
+ WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
+ "SetOpusMaxBandwidth(channel=%d, bandwidth_hz=%d)", channel,
+ bandwidth_hz);
+ if (!_shared->statistics().Initialized()) {
+ _shared->SetLastError(VE_NOT_INITED, kTraceError);
+ return -1;
+ }
+ voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
+ voe::Channel* channelPtr = ch.channel();
+ if (channelPtr == NULL) {
+ _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
+ "SetOpusMaxBandwidth failed to locate channel");
+ return -1;
+ }
+ return channelPtr->SetOpusMaxBandwidth(bandwidth_hz);
+}
+
void VoECodecImpl::ACMToExternalCodecRepresentation(CodecInst& toInst,
const CodecInst& fromInst)
{
diff --git a/voice_engine/voe_codec_impl.h b/voice_engine/voe_codec_impl.h
index 1b9f00e..498854d 100644
--- a/voice_engine/voe_codec_impl.h
+++ b/voice_engine/voe_codec_impl.h
@@ -54,6 +54,8 @@
VadModes& mode,
bool& disabledDTX);
+ virtual int SetOpusMaxBandwidth(int channel, int bandwidth_hz);
+
// Dual-streaming
virtual int SetSecondarySendCodec(int channel, const CodecInst& codec,
int red_payload_type);