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}
This commit is contained in:
@ -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() {
|
void AcmReceiveTestOldApi::Run() {
|
||||||
for (rtc::scoped_ptr<Packet> packet(packet_source_->NextPacket()); packet;
|
for (rtc::scoped_ptr<Packet> packet(packet_source_->NextPacket()); packet;
|
||||||
packet.reset(packet_source_->NextPacket())) {
|
packet.reset(packet_source_->NextPacket())) {
|
||||||
|
|||||||
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
class AudioCodingModule;
|
class AudioCodingModule;
|
||||||
|
class AudioDecoder;
|
||||||
struct CodecInst;
|
struct CodecInst;
|
||||||
|
|
||||||
namespace test {
|
namespace test {
|
||||||
@ -44,6 +45,11 @@ class AcmReceiveTestOldApi {
|
|||||||
// files.
|
// files.
|
||||||
void RegisterNetEqTestCodecs();
|
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.
|
// Runs the test and returns true if successful.
|
||||||
void Run();
|
void Run();
|
||||||
|
|
||||||
|
|||||||
@ -476,8 +476,10 @@ int32_t AcmReceiver::AddCodec(int acm_codec_id,
|
|||||||
int channels,
|
int channels,
|
||||||
int sample_rate_hz,
|
int sample_rate_hz,
|
||||||
AudioDecoder* audio_decoder) {
|
AudioDecoder* audio_decoder) {
|
||||||
assert(acm_codec_id >= 0);
|
assert(acm_codec_id >= -1); // -1 means external decoder
|
||||||
NetEqDecoder neteq_decoder = ACMCodecDB::neteq_decoders_[acm_codec_id];
|
NetEqDecoder neteq_decoder = (acm_codec_id == -1)
|
||||||
|
? kDecoderArbitrary
|
||||||
|
: ACMCodecDB::neteq_decoders_[acm_codec_id];
|
||||||
|
|
||||||
// Make sure the right decoder is registered for Opus.
|
// Make sure the right decoder is registered for Opus.
|
||||||
if (neteq_decoder == kDecoderOpus && channels == 2) {
|
if (neteq_decoder == kDecoderOpus && channels == 2) {
|
||||||
@ -491,14 +493,15 @@ int32_t AcmReceiver::AddCodec(int acm_codec_id,
|
|||||||
auto it = decoders_.find(payload_type);
|
auto it = decoders_.find(payload_type);
|
||||||
if (it != decoders_.end()) {
|
if (it != decoders_.end()) {
|
||||||
const Decoder& decoder = it->second;
|
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) {
|
decoder.sample_rate_hz == sample_rate_hz) {
|
||||||
// Re-registering the same codec. Do nothing and return.
|
// Re-registering the same codec. Do nothing and return.
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Changing codec or number of channels. First unregister the old codec,
|
// Changing codec. First unregister the old codec, then register the new
|
||||||
// then register the new one.
|
// one.
|
||||||
if (neteq_->RemovePayloadType(payload_type) != NetEq::kOK) {
|
if (neteq_->RemovePayloadType(payload_type) != NetEq::kOK) {
|
||||||
LOG(LERROR) << "Cannot remove payload " << static_cast<int>(payload_type);
|
LOG(LERROR) << "Cannot remove payload " << static_cast<int>(payload_type);
|
||||||
return -1;
|
return -1;
|
||||||
|
|||||||
@ -93,21 +93,24 @@ class AcmReceiver {
|
|||||||
// Adds a new codec to the NetEq codec database.
|
// Adds a new codec to the NetEq codec database.
|
||||||
//
|
//
|
||||||
// Input:
|
// Input:
|
||||||
// - acm_codec_id : ACM codec ID.
|
// - acm_codec_id : ACM codec ID; -1 means external decoder.
|
||||||
// - payload_type : payload type.
|
// - payload_type : payload type.
|
||||||
// - sample_rate_hz : sample rate.
|
// - sample_rate_hz : sample rate.
|
||||||
// - audio_decoder : pointer to a decoder object. If it is NULL
|
// - audio_decoder : pointer to a decoder object. If it's null, then
|
||||||
// then NetEq will internally create the decoder
|
// NetEq will internally create a decoder object
|
||||||
// object. Otherwise, NetEq will store this pointer
|
// based on the value of |acm_codec_id| (which
|
||||||
// as the decoder corresponding with the given
|
// mustn't be -1). Otherwise, NetEq will use the
|
||||||
// payload type. NetEq won't acquire the ownership
|
// given decoder for the given payload type. NetEq
|
||||||
// of this pointer. It is up to the client of this
|
// won't take ownership of the decoder; it's up to
|
||||||
// class (ACM) to delete it. By providing
|
// the caller to delete it when it's no longer
|
||||||
// |audio_decoder| ACM will have control over the
|
// needed.
|
||||||
// decoder instance of the codec. This is essential
|
//
|
||||||
// for a codec like iSAC which encoder/decoder
|
// Providing an existing decoder object here is
|
||||||
// encoder has to know about decoder (bandwidth
|
// necessary for external decoders, but may also be
|
||||||
// estimator that is updated at decoding time).
|
// 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.
|
// Return value : 0 if OK.
|
||||||
// <0 if NetEq returned an error.
|
// <0 if NetEq returned an error.
|
||||||
|
|||||||
@ -667,6 +667,29 @@ int AudioCodingModuleImpl::RegisterReceiveCodec(const CodecInst& codec) {
|
|||||||
codec_manager_.GetAudioDecoder(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.
|
// Get current received codec.
|
||||||
int AudioCodingModuleImpl::ReceiveCodec(CodecInst* current_codec) const {
|
int AudioCodingModuleImpl::ReceiveCodec(CodecInst* current_codec) const {
|
||||||
CriticalSectionScoped lock(acm_crit_sect_);
|
CriticalSectionScoped lock(acm_crit_sect_);
|
||||||
|
|||||||
@ -137,6 +137,11 @@ class AudioCodingModuleImpl : public AudioCodingModule {
|
|||||||
// for codecs, CNG, DTMF, RED.
|
// for codecs, CNG, DTMF, RED.
|
||||||
int RegisterReceiveCodec(const CodecInst& receive_codec) override;
|
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.
|
// Get current received codec.
|
||||||
int ReceiveCodec(CodecInst* current_codec) const override;
|
int ReceiveCodec(CodecInst* current_codec) const override;
|
||||||
|
|
||||||
|
|||||||
@ -23,6 +23,8 @@
|
|||||||
#include "webrtc/modules/audio_coding/main/acm2/acm_send_test_oldapi.h"
|
#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.h"
|
||||||
#include "webrtc/modules/audio_coding/main/interface/audio_coding_module_typedefs.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_checksum.h"
|
||||||
#include "webrtc/modules/audio_coding/neteq/tools/audio_loop.h"
|
#include "webrtc/modules/audio_coding/neteq/tools/audio_loop.h"
|
||||||
#include "webrtc/modules/audio_coding/neteq/tools/constant_pcm_packet_source.h"
|
#include "webrtc/modules/audio_coding/neteq/tools/constant_pcm_packet_source.h"
|
||||||
@ -873,7 +875,16 @@ class AcmReceiverBitExactnessOldApi : public ::testing::Test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
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 =
|
const std::string input_file_name =
|
||||||
webrtc::test::ResourcePath("audio_coding/neteq_universal_new", "rtp");
|
webrtc::test::ResourcePath("audio_coding/neteq_universal_new", "rtp");
|
||||||
rtc::scoped_ptr<test::RtpFileSource> packet_source(
|
rtc::scoped_ptr<test::RtpFileSource> packet_source(
|
||||||
@ -901,6 +912,11 @@ class AcmReceiverBitExactnessOldApi : public ::testing::Test {
|
|||||||
output_freq_hz,
|
output_freq_hz,
|
||||||
test::AcmReceiveTestOldApi::kArbitraryChannels);
|
test::AcmReceiveTestOldApi::kArbitraryChannels);
|
||||||
ASSERT_NO_FATAL_FAILURE(test.RegisterNetEqTestCodecs());
|
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();
|
test.Run();
|
||||||
|
|
||||||
std::string checksum_string = checksum.Finish();
|
std::string checksum_string = checksum.Finish();
|
||||||
@ -915,10 +931,10 @@ class AcmReceiverBitExactnessOldApi : public ::testing::Test {
|
|||||||
#define MAYBE_8kHzOutput 8kHzOutput
|
#define MAYBE_8kHzOutput 8kHzOutput
|
||||||
#endif
|
#endif
|
||||||
TEST_F(AcmReceiverBitExactnessOldApi, MAYBE_8kHzOutput) {
|
TEST_F(AcmReceiverBitExactnessOldApi, MAYBE_8kHzOutput) {
|
||||||
Run(8000,
|
Run(8000, PlatformChecksum("dcee98c623b147ebe1b40dd30efa896e",
|
||||||
PlatformChecksum("dcee98c623b147ebe1b40dd30efa896e",
|
|
||||||
"adc92e173f908f93b96ba5844209815a",
|
"adc92e173f908f93b96ba5844209815a",
|
||||||
"908002dc01fc4eb1d2be24eb1d3f354b"));
|
"908002dc01fc4eb1d2be24eb1d3f354b"),
|
||||||
|
std::vector<ExternalDecoder>());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fails Android ARM64. https://code.google.com/p/webrtc/issues/detail?id=4199
|
// 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
|
#define MAYBE_16kHzOutput 16kHzOutput
|
||||||
#endif
|
#endif
|
||||||
TEST_F(AcmReceiverBitExactnessOldApi, MAYBE_16kHzOutput) {
|
TEST_F(AcmReceiverBitExactnessOldApi, MAYBE_16kHzOutput) {
|
||||||
Run(16000,
|
Run(16000, PlatformChecksum("f790e7a8cce4e2c8b7bb5e0e4c5dac0d",
|
||||||
PlatformChecksum("f790e7a8cce4e2c8b7bb5e0e4c5dac0d",
|
|
||||||
"8cffa6abcb3e18e33b9d857666dff66a",
|
"8cffa6abcb3e18e33b9d857666dff66a",
|
||||||
"a909560b5ca49fa472b17b7b277195e9"));
|
"a909560b5ca49fa472b17b7b277195e9"),
|
||||||
|
std::vector<ExternalDecoder>());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fails Android ARM64. https://code.google.com/p/webrtc/issues/detail?id=4199
|
// 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
|
#define MAYBE_32kHzOutput 32kHzOutput
|
||||||
#endif
|
#endif
|
||||||
TEST_F(AcmReceiverBitExactnessOldApi, MAYBE_32kHzOutput) {
|
TEST_F(AcmReceiverBitExactnessOldApi, MAYBE_32kHzOutput) {
|
||||||
Run(32000,
|
Run(32000, PlatformChecksum("306e0d990ee6e92de3fbecc0123ece37",
|
||||||
PlatformChecksum("306e0d990ee6e92de3fbecc0123ece37",
|
|
||||||
"3e126fe894720c3f85edadcc91964ba5",
|
"3e126fe894720c3f85edadcc91964ba5",
|
||||||
"441aab4b347fb3db4e9244337aca8d8e"));
|
"441aab4b347fb3db4e9244337aca8d8e"),
|
||||||
|
std::vector<ExternalDecoder>());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fails Android ARM64. https://code.google.com/p/webrtc/issues/detail?id=4199
|
// 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
|
#define MAYBE_48kHzOutput 48kHzOutput
|
||||||
#endif
|
#endif
|
||||||
TEST_F(AcmReceiverBitExactnessOldApi, MAYBE_48kHzOutput) {
|
TEST_F(AcmReceiverBitExactnessOldApi, MAYBE_48kHzOutput) {
|
||||||
Run(48000,
|
Run(48000, PlatformChecksum("aa7c232f63a67b2a72703593bdd172e0",
|
||||||
PlatformChecksum("aa7c232f63a67b2a72703593bdd172e0",
|
|
||||||
"0155665e93067c4e89256b944dd11999",
|
"0155665e93067c4e89256b944dd11999",
|
||||||
"4ee2730fa1daae755e8a8fd3abd779ec"));
|
"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
|
// This test verifies bit exactness for the send-side of ACM. The test setup is
|
||||||
|
|||||||
@ -29,6 +29,7 @@ struct WebRtcRTPHeader;
|
|||||||
class AudioFrame;
|
class AudioFrame;
|
||||||
class RTPFragmentationHeader;
|
class RTPFragmentationHeader;
|
||||||
class AudioEncoderMutable;
|
class AudioEncoderMutable;
|
||||||
|
class AudioDecoder;
|
||||||
|
|
||||||
#define WEBRTC_10MS_PCM_AUDIO 960 // 16 bits super wideband 48 kHz
|
#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
|
// -1 if failed to register the codec
|
||||||
// 0 if the codec registered successfully.
|
// 0 if the codec registered successfully.
|
||||||
//
|
//
|
||||||
virtual int32_t RegisterReceiveCodec(
|
virtual int RegisterReceiveCodec(const CodecInst& receive_codec) = 0;
|
||||||
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()
|
// int32_t UnregisterReceiveCodec()
|
||||||
|
|||||||
Reference in New Issue
Block a user