diff options
author | kwiberg <kwiberg@webrtc.org> | 2015-08-24 05:27:22 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-08-24 12:27:28 +0000 |
commit | 4e14f0961bcd3e70621039403776a14e017aae81 (patch) | |
tree | fa9df8f6554db8362ef45eaae4deeed6187be839 | |
parent | e7cdc7f5a08c3d9f4ca1edc24f6079230819cf19 (diff) | |
download | webrtc-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}
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() |