aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkwiberg <kwiberg@webrtc.org>2015-08-24 05:27:22 -0700
committerCommit bot <commit-bot@chromium.org>2015-08-24 12:27:28 +0000
commit4e14f0961bcd3e70621039403776a14e017aae81 (patch)
treefa9df8f6554db8362ef45eaae4deeed6187be839
parente7cdc7f5a08c3d9f4ca1edc24f6079230819cf19 (diff)
downloadwebrtc-4e14f0961bcd3e70621039403776a14e017aae81.tar.gz
Add support for external decoders in ACM
Test added too. COAUTHOR=henrik.lundin@webrtc.org BUG=4474 TBR=minyue@webrtc.org Review URL: https://codereview.webrtc.org/1312493004 Cr-Commit-Position: refs/heads/master@{#9765}
-rw-r--r--webrtc/modules/audio_coding/main/acm2/acm_receive_test_oldapi.cc9
-rw-r--r--webrtc/modules/audio_coding/main/acm2/acm_receive_test_oldapi.h6
-rw-r--r--webrtc/modules/audio_coding/main/acm2/acm_receiver.cc13
-rw-r--r--webrtc/modules/audio_coding/main/acm2/acm_receiver.h29
-rw-r--r--webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.cc23
-rw-r--r--webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.h5
-rw-r--r--webrtc/modules/audio_coding/main/acm2/audio_coding_module_unittest_oldapi.cc92
-rw-r--r--webrtc/modules/audio_coding/main/interface/audio_coding_module.h9
8 files changed, 149 insertions, 37 deletions
diff --git a/webrtc/modules/audio_coding/main/acm2/acm_receive_test_oldapi.cc b/webrtc/modules/audio_coding/main/acm2/acm_receive_test_oldapi.cc
index 96a1fc5fdc..dd570e67da 100644
--- a/webrtc/modules/audio_coding/main/acm2/acm_receive_test_oldapi.cc
+++ b/webrtc/modules/audio_coding/main/acm2/acm_receive_test_oldapi.cc
@@ -143,6 +143,15 @@ void AcmReceiveTestOldApi::RegisterNetEqTestCodecs() {
}
}
+int AcmReceiveTestOldApi::RegisterExternalReceiveCodec(
+ int rtp_payload_type,
+ AudioDecoder* external_decoder,
+ int sample_rate_hz,
+ int num_channels) {
+ return acm_->RegisterExternalReceiveCodec(rtp_payload_type, external_decoder,
+ sample_rate_hz, num_channels);
+}
+
void AcmReceiveTestOldApi::Run() {
for (rtc::scoped_ptr<Packet> packet(packet_source_->NextPacket()); packet;
packet.reset(packet_source_->NextPacket())) {
diff --git a/webrtc/modules/audio_coding/main/acm2/acm_receive_test_oldapi.h b/webrtc/modules/audio_coding/main/acm2/acm_receive_test_oldapi.h
index 5e5ff9a0a0..8e80ca79b5 100644
--- a/webrtc/modules/audio_coding/main/acm2/acm_receive_test_oldapi.h
+++ b/webrtc/modules/audio_coding/main/acm2/acm_receive_test_oldapi.h
@@ -17,6 +17,7 @@
namespace webrtc {
class AudioCodingModule;
+class AudioDecoder;
struct CodecInst;
namespace test {
@@ -44,6 +45,11 @@ class AcmReceiveTestOldApi {
// files.
void RegisterNetEqTestCodecs();
+ int RegisterExternalReceiveCodec(int rtp_payload_type,
+ AudioDecoder* external_decoder,
+ int sample_rate_hz,
+ int num_channels);
+
// Runs the test and returns true if successful.
void Run();
diff --git a/webrtc/modules/audio_coding/main/acm2/acm_receiver.cc b/webrtc/modules/audio_coding/main/acm2/acm_receiver.cc
index ae5a04f25e..4c11197f49 100644
--- a/webrtc/modules/audio_coding/main/acm2/acm_receiver.cc
+++ b/webrtc/modules/audio_coding/main/acm2/acm_receiver.cc
@@ -476,8 +476,10 @@ int32_t AcmReceiver::AddCodec(int acm_codec_id,
int channels,
int sample_rate_hz,
AudioDecoder* audio_decoder) {
- assert(acm_codec_id >= 0);
- NetEqDecoder neteq_decoder = ACMCodecDB::neteq_decoders_[acm_codec_id];
+ assert(acm_codec_id >= -1); // -1 means external decoder
+ NetEqDecoder neteq_decoder = (acm_codec_id == -1)
+ ? kDecoderArbitrary
+ : ACMCodecDB::neteq_decoders_[acm_codec_id];
// Make sure the right decoder is registered for Opus.
if (neteq_decoder == kDecoderOpus && channels == 2) {
@@ -491,14 +493,15 @@ int32_t AcmReceiver::AddCodec(int acm_codec_id,
auto it = decoders_.find(payload_type);
if (it != decoders_.end()) {
const Decoder& decoder = it->second;
- if (decoder.acm_codec_id == acm_codec_id && decoder.channels == channels &&
+ if (acm_codec_id != -1 && decoder.acm_codec_id == acm_codec_id &&
+ decoder.channels == channels &&
decoder.sample_rate_hz == sample_rate_hz) {
// Re-registering the same codec. Do nothing and return.
return 0;
}
- // Changing codec or number of channels. First unregister the old codec,
- // then register the new one.
+ // Changing codec. First unregister the old codec, then register the new
+ // one.
if (neteq_->RemovePayloadType(payload_type) != NetEq::kOK) {
LOG(LERROR) << "Cannot remove payload " << static_cast<int>(payload_type);
return -1;
diff --git a/webrtc/modules/audio_coding/main/acm2/acm_receiver.h b/webrtc/modules/audio_coding/main/acm2/acm_receiver.h
index 46207fd449..fe2724993e 100644
--- a/webrtc/modules/audio_coding/main/acm2/acm_receiver.h
+++ b/webrtc/modules/audio_coding/main/acm2/acm_receiver.h
@@ -93,21 +93,24 @@ class AcmReceiver {
// Adds a new codec to the NetEq codec database.
//
// Input:
- // - acm_codec_id : ACM codec ID.
+ // - acm_codec_id : ACM codec ID; -1 means external decoder.
// - payload_type : payload type.
// - sample_rate_hz : sample rate.
- // - audio_decoder : pointer to a decoder object. If it is NULL
- // then NetEq will internally create the decoder
- // object. Otherwise, NetEq will store this pointer
- // as the decoder corresponding with the given
- // payload type. NetEq won't acquire the ownership
- // of this pointer. It is up to the client of this
- // class (ACM) to delete it. By providing
- // |audio_decoder| ACM will have control over the
- // decoder instance of the codec. This is essential
- // for a codec like iSAC which encoder/decoder
- // encoder has to know about decoder (bandwidth
- // estimator that is updated at decoding time).
+ // - audio_decoder : pointer to a decoder object. If it's null, then
+ // NetEq will internally create a decoder object
+ // based on the value of |acm_codec_id| (which
+ // mustn't be -1). Otherwise, NetEq will use the
+ // given decoder for the given payload type. NetEq
+ // won't take ownership of the decoder; it's up to
+ // the caller to delete it when it's no longer
+ // needed.
+ //
+ // Providing an existing decoder object here is
+ // necessary for external decoders, but may also be
+ // used for built-in decoders if NetEq doesn't have
+ // all the info it needs to construct them properly
+ // (e.g. iSAC, where the decoder needs to be paired
+ // with an encoder).
//
// Return value : 0 if OK.
// <0 if NetEq returned an error.
diff --git a/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.cc b/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.cc
index 9c3183271b..32d60a7ae4 100644
--- a/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.cc
+++ b/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.cc
@@ -667,6 +667,29 @@ int AudioCodingModuleImpl::RegisterReceiveCodec(const CodecInst& codec) {
codec_manager_.GetAudioDecoder(codec));
}
+int AudioCodingModuleImpl::RegisterExternalReceiveCodec(
+ int rtp_payload_type,
+ AudioDecoder* external_decoder,
+ int sample_rate_hz,
+ int num_channels) {
+ CriticalSectionScoped lock(acm_crit_sect_);
+ DCHECK(receiver_initialized_);
+ if (num_channels > 2 || num_channels < 0) {
+ LOG_F(LS_ERROR) << "Unsupported number of channels: " << num_channels;
+ return -1;
+ }
+
+ // Check if the payload-type is valid.
+ if (!ACMCodecDB::ValidPayloadType(rtp_payload_type)) {
+ LOG_F(LS_ERROR) << "Invalid payload-type " << rtp_payload_type
+ << " for external decoder.";
+ return -1;
+ }
+
+ return receiver_.AddCodec(-1 /* external */, rtp_payload_type, num_channels,
+ sample_rate_hz, external_decoder);
+}
+
// Get current received codec.
int AudioCodingModuleImpl::ReceiveCodec(CodecInst* current_codec) const {
CriticalSectionScoped lock(acm_crit_sect_);
diff --git a/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.h b/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.h
index 19ca01bf9e..beb49bc4ce 100644
--- a/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.h
+++ b/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.h
@@ -137,6 +137,11 @@ class AudioCodingModuleImpl : public AudioCodingModule {
// for codecs, CNG, DTMF, RED.
int RegisterReceiveCodec(const CodecInst& receive_codec) override;
+ int RegisterExternalReceiveCodec(int rtp_payload_type,
+ AudioDecoder* external_decoder,
+ int sample_rate_hz,
+ int num_channels) override;
+
// Get current received codec.
int ReceiveCodec(CodecInst* current_codec) const override;
diff --git a/webrtc/modules/audio_coding/main/acm2/audio_coding_module_unittest_oldapi.cc b/webrtc/modules/audio_coding/main/acm2/audio_coding_module_unittest_oldapi.cc
index 71c436b829..0af6af8002 100644
--- a/webrtc/modules/audio_coding/main/acm2/audio_coding_module_unittest_oldapi.cc
+++ b/webrtc/modules/audio_coding/main/acm2/audio_coding_module_unittest_oldapi.cc
@@ -23,6 +23,8 @@
#include "webrtc/modules/audio_coding/main/acm2/acm_send_test_oldapi.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/neteq/audio_decoder_impl.h"
+#include "webrtc/modules/audio_coding/neteq/mock/mock_audio_decoder.h"
#include "webrtc/modules/audio_coding/neteq/tools/audio_checksum.h"
#include "webrtc/modules/audio_coding/neteq/tools/audio_loop.h"
#include "webrtc/modules/audio_coding/neteq/tools/constant_pcm_packet_source.h"
@@ -873,7 +875,16 @@ class AcmReceiverBitExactnessOldApi : public ::testing::Test {
}
protected:
- void Run(int output_freq_hz, const std::string& checksum_ref) {
+ struct ExternalDecoder {
+ int rtp_payload_type;
+ AudioDecoder* external_decoder;
+ int sample_rate_hz;
+ int num_channels;
+ };
+
+ void Run(int output_freq_hz,
+ const std::string& checksum_ref,
+ const std::vector<ExternalDecoder>& external_decoders) {
const std::string input_file_name =
webrtc::test::ResourcePath("audio_coding/neteq_universal_new", "rtp");
rtc::scoped_ptr<test::RtpFileSource> packet_source(
@@ -901,6 +912,11 @@ class AcmReceiverBitExactnessOldApi : public ::testing::Test {
output_freq_hz,
test::AcmReceiveTestOldApi::kArbitraryChannels);
ASSERT_NO_FATAL_FAILURE(test.RegisterNetEqTestCodecs());
+ for (const auto& ed : external_decoders) {
+ ASSERT_EQ(0, test.RegisterExternalReceiveCodec(
+ ed.rtp_payload_type, ed.external_decoder,
+ ed.sample_rate_hz, ed.num_channels));
+ }
test.Run();
std::string checksum_string = checksum.Finish();
@@ -915,10 +931,10 @@ class AcmReceiverBitExactnessOldApi : public ::testing::Test {
#define MAYBE_8kHzOutput 8kHzOutput
#endif
TEST_F(AcmReceiverBitExactnessOldApi, MAYBE_8kHzOutput) {
- Run(8000,
- PlatformChecksum("dcee98c623b147ebe1b40dd30efa896e",
- "adc92e173f908f93b96ba5844209815a",
- "908002dc01fc4eb1d2be24eb1d3f354b"));
+ Run(8000, PlatformChecksum("dcee98c623b147ebe1b40dd30efa896e",
+ "adc92e173f908f93b96ba5844209815a",
+ "908002dc01fc4eb1d2be24eb1d3f354b"),
+ std::vector<ExternalDecoder>());
}
// Fails Android ARM64. https://code.google.com/p/webrtc/issues/detail?id=4199
@@ -928,10 +944,10 @@ TEST_F(AcmReceiverBitExactnessOldApi, MAYBE_8kHzOutput) {
#define MAYBE_16kHzOutput 16kHzOutput
#endif
TEST_F(AcmReceiverBitExactnessOldApi, MAYBE_16kHzOutput) {
- Run(16000,
- PlatformChecksum("f790e7a8cce4e2c8b7bb5e0e4c5dac0d",
- "8cffa6abcb3e18e33b9d857666dff66a",
- "a909560b5ca49fa472b17b7b277195e9"));
+ Run(16000, PlatformChecksum("f790e7a8cce4e2c8b7bb5e0e4c5dac0d",
+ "8cffa6abcb3e18e33b9d857666dff66a",
+ "a909560b5ca49fa472b17b7b277195e9"),
+ std::vector<ExternalDecoder>());
}
// Fails Android ARM64. https://code.google.com/p/webrtc/issues/detail?id=4199
@@ -941,10 +957,10 @@ TEST_F(AcmReceiverBitExactnessOldApi, MAYBE_16kHzOutput) {
#define MAYBE_32kHzOutput 32kHzOutput
#endif
TEST_F(AcmReceiverBitExactnessOldApi, MAYBE_32kHzOutput) {
- Run(32000,
- PlatformChecksum("306e0d990ee6e92de3fbecc0123ece37",
- "3e126fe894720c3f85edadcc91964ba5",
- "441aab4b347fb3db4e9244337aca8d8e"));
+ Run(32000, PlatformChecksum("306e0d990ee6e92de3fbecc0123ece37",
+ "3e126fe894720c3f85edadcc91964ba5",
+ "441aab4b347fb3db4e9244337aca8d8e"),
+ std::vector<ExternalDecoder>());
}
// Fails Android ARM64. https://code.google.com/p/webrtc/issues/detail?id=4199
@@ -954,10 +970,52 @@ TEST_F(AcmReceiverBitExactnessOldApi, MAYBE_32kHzOutput) {
#define MAYBE_48kHzOutput 48kHzOutput
#endif
TEST_F(AcmReceiverBitExactnessOldApi, MAYBE_48kHzOutput) {
- Run(48000,
- PlatformChecksum("aa7c232f63a67b2a72703593bdd172e0",
- "0155665e93067c4e89256b944dd11999",
- "4ee2730fa1daae755e8a8fd3abd779ec"));
+ Run(48000, PlatformChecksum("aa7c232f63a67b2a72703593bdd172e0",
+ "0155665e93067c4e89256b944dd11999",
+ "4ee2730fa1daae755e8a8fd3abd779ec"),
+ std::vector<ExternalDecoder>());
+}
+
+// Fails Android ARM64. https://code.google.com/p/webrtc/issues/detail?id=4199
+#if defined(WEBRTC_ANDROID) && defined(__aarch64__)
+#define MAYBE_48kHzOutputExternalDecoder DISABLED_48kHzOutputExternalDecoder
+#else
+#define MAYBE_48kHzOutputExternalDecoder 48kHzOutputExternalDecoder
+#endif
+TEST_F(AcmReceiverBitExactnessOldApi, MAYBE_48kHzOutputExternalDecoder) {
+ AudioDecoderPcmU decoder;
+ MockAudioDecoder mock_decoder;
+ // Set expectations on the mock decoder and also delegate the calls to the
+ // real decoder.
+ EXPECT_CALL(mock_decoder, Init())
+ .Times(AtLeast(1))
+ .WillRepeatedly(Invoke(&decoder, &AudioDecoderPcmU::Init));
+ EXPECT_CALL(mock_decoder, IncomingPacket(_, _, _, _, _))
+ .Times(AtLeast(1))
+ .WillRepeatedly(Invoke(&decoder, &AudioDecoderPcmU::IncomingPacket));
+ EXPECT_CALL(mock_decoder, Channels())
+ .Times(AtLeast(1))
+ .WillRepeatedly(Invoke(&decoder, &AudioDecoderPcmU::Channels));
+ EXPECT_CALL(mock_decoder, Decode(_, _, _, _, _, _))
+ .Times(AtLeast(1))
+ .WillRepeatedly(Invoke(&decoder, &AudioDecoderPcmU::Decode));
+ EXPECT_CALL(mock_decoder, HasDecodePlc())
+ .Times(AtLeast(1))
+ .WillRepeatedly(Invoke(&decoder, &AudioDecoderPcmU::HasDecodePlc));
+ ExternalDecoder ed;
+ ed.rtp_payload_type = 0;
+ ed.external_decoder = &mock_decoder;
+ ed.sample_rate_hz = 8000;
+ ed.num_channels = 1;
+ std::vector<ExternalDecoder> external_decoders;
+ external_decoders.push_back(ed);
+
+ Run(48000, PlatformChecksum("aa7c232f63a67b2a72703593bdd172e0",
+ "0155665e93067c4e89256b944dd11999",
+ "4ee2730fa1daae755e8a8fd3abd779ec"),
+ external_decoders);
+
+ EXPECT_CALL(mock_decoder, Die());
}
// This test verifies bit exactness for the send-side of ACM. The test setup is
diff --git a/webrtc/modules/audio_coding/main/interface/audio_coding_module.h b/webrtc/modules/audio_coding/main/interface/audio_coding_module.h
index b7d9a91b2f..7357528132 100644
--- a/webrtc/modules/audio_coding/main/interface/audio_coding_module.h
+++ b/webrtc/modules/audio_coding/main/interface/audio_coding_module.h
@@ -29,6 +29,7 @@ struct WebRtcRTPHeader;
class AudioFrame;
class RTPFragmentationHeader;
class AudioEncoderMutable;
+class AudioDecoder;
#define WEBRTC_10MS_PCM_AUDIO 960 // 16 bits super wideband 48 kHz
@@ -576,8 +577,12 @@ class AudioCodingModule {
// -1 if failed to register the codec
// 0 if the codec registered successfully.
//
- virtual int32_t RegisterReceiveCodec(
- const CodecInst& receive_codec) = 0;
+ virtual int RegisterReceiveCodec(const CodecInst& receive_codec) = 0;
+
+ virtual int RegisterExternalReceiveCodec(int rtp_payload_type,
+ AudioDecoder* external_decoder,
+ int sample_rate_hz,
+ int num_channels) = 0;
///////////////////////////////////////////////////////////////////////////
// int32_t UnregisterReceiveCodec()