From fce4a945b872e4ca52e76a3872a3278a88e17b85 Mon Sep 17 00:00:00 2001 From: kwiberg Date: Tue, 27 Oct 2015 11:40:24 -0700 Subject: [PATCH] RentACodec: New class that takes over part of ACMCodecDB's job Following CLs will finish the takeover completely. After that, RentACodec will also start creating and owning codecs, at which point its name will start making sense. BUG=webrtc:5028 Review URL: https://codereview.webrtc.org/1412683006 Cr-Commit-Position: refs/heads/master@{#10432} --- webrtc/modules/audio_coding/BUILD.gn | 36 +++- .../main/acm2/acm_codec_database.cc | 21 +- .../main/acm2/acm_codec_database.h | 80 +------- .../audio_coding/main/acm2/acm_receiver.cc | 23 ++- .../main/acm2/acm_receiver_unittest_oldapi.cc | 186 +++++++++--------- .../main/acm2/audio_coding_module.cc | 56 +++--- .../main/acm2/audio_coding_module_impl.cc | 36 ++-- .../audio_coding/main/acm2/codec_manager.cc | 32 ++- .../audio_coding/main/acm2/rent_a_codec.cc | 59 ++++++ .../audio_coding/main/acm2/rent_a_codec.h | 129 ++++++++++++ .../main/audio_coding_module.gypi | 27 ++- 11 files changed, 418 insertions(+), 267 deletions(-) create mode 100644 webrtc/modules/audio_coding/main/acm2/rent_a_codec.cc create mode 100644 webrtc/modules/audio_coding/main/acm2/rent_a_codec.h diff --git a/webrtc/modules/audio_coding/BUILD.gn b/webrtc/modules/audio_coding/BUILD.gn index 7bbcd3aee2..d9a1a0247b 100644 --- a/webrtc/modules/audio_coding/BUILD.gn +++ b/webrtc/modules/audio_coding/BUILD.gn @@ -9,6 +9,39 @@ import("//build/config/arm.gni") import("../../build/webrtc.gni") +source_set("rent_a_codec") { + sources = [ + "main/acm2/acm_codec_database.cc", + "main/acm2/acm_codec_database.h", + "main/acm2/rent_a_codec.cc", + "main/acm2/rent_a_codec.h", + ] + configs += [ "../..:common_config" ] + public_configs = [ "../..:common_inherited_config" ] + deps = [ + "../..:webrtc_common", + ] + + defines = [] + if (rtc_include_opus) { + defines += [ "WEBRTC_CODEC_OPUS" ] + } + if (!build_with_mozilla) { + if (current_cpu == "arm") { + defines += [ "WEBRTC_CODEC_ISACFX" ] + } else { + defines += [ "WEBRTC_CODEC_ISAC" ] + } + defines += [ "WEBRTC_CODEC_G722" ] + } + if (!build_with_mozilla && !build_with_chromium) { + defines += [ + "WEBRTC_CODEC_ILBC", + "WEBRTC_CODEC_RED", + ] + } +} + config("audio_coding_config") { include_dirs = [ "main/interface", @@ -18,8 +51,6 @@ config("audio_coding_config") { source_set("audio_coding") { sources = [ - "main/acm2/acm_codec_database.cc", - "main/acm2/acm_codec_database.h", "main/acm2/acm_common_defs.h", "main/acm2/acm_receiver.cc", "main/acm2/acm_receiver.h", @@ -69,6 +100,7 @@ source_set("audio_coding") { ":g711", ":neteq", ":pcm16b", + ":rent_a_codec", "../..:rtc_event_log", "../..:webrtc_common", "../../common_audio", diff --git a/webrtc/modules/audio_coding/main/acm2/acm_codec_database.cc b/webrtc/modules/audio_coding/main/acm2/acm_codec_database.cc index bf12530832..a619e82910 100644 --- a/webrtc/modules/audio_coding/main/acm2/acm_codec_database.cc +++ b/webrtc/modules/audio_coding/main/acm2/acm_codec_database.cc @@ -223,7 +223,7 @@ const NetEqDecoder ACMCodecDB::neteq_decoders_[] = { // TODO(tlegrand): replace memcpy with a pointer to the data base memory. int ACMCodecDB::Codec(int codec_id, CodecInst* codec_inst) { // Error check to see that codec_id is not out of bounds. - if ((codec_id < 0) || (codec_id >= kNumCodecs)) { + if (static_cast(codec_id) >= RentACodec::NumberOfCodecs()) { return -1; } @@ -318,7 +318,7 @@ int ACMCodecDB::CodecId(const CodecInst& codec_inst) { } int ACMCodecDB::CodecId(const char* payload_name, int frequency, int channels) { - for (int id = 0; id < kNumCodecs; id++) { + for (const CodecInst& ci : RentACodec::Database()) { bool name_match = false; bool frequency_match = false; bool channels_match = false; @@ -326,11 +326,11 @@ int ACMCodecDB::CodecId(const char* payload_name, int frequency, int channels) { // Payload name, sampling frequency and number of channels need to match. // NOTE! If |frequency| is -1, the frequency is not applicable, and is // always treated as true, like for RED. - name_match = (STR_CASE_CMP(database_[id].plname, payload_name) == 0); - frequency_match = (frequency == database_[id].plfreq) || (frequency == -1); + name_match = (STR_CASE_CMP(ci.plname, payload_name) == 0); + frequency_match = (frequency == ci.plfreq) || (frequency == -1); // The number of channels must match for all codecs but Opus. if (STR_CASE_CMP(payload_name, "opus") != 0) { - channels_match = (channels == database_[id].channels); + channels_match = (channels == ci.channels); } else { // For opus we just check that number of channels is valid. channels_match = (channels == 1 || channels == 2); @@ -338,7 +338,7 @@ int ACMCodecDB::CodecId(const char* payload_name, int frequency, int channels) { if (name_match && frequency_match && channels_match) { // We have found a matching codec in the list. - return id; + return &ci - RentACodec::Database().data(); } } @@ -354,12 +354,9 @@ int ACMCodecDB::ReceiverCodecNumber(const CodecInst& codec_inst) { // Returns the codec sampling frequency for codec with id = "codec_id" in // database. int ACMCodecDB::CodecFreq(int codec_id) { - // Error check to see that codec_id is not out of bounds. - if (codec_id < 0 || codec_id >= kNumCodecs) { - return -1; - } - - return database_[codec_id].plfreq; + const size_t i = static_cast(codec_id); + const auto db = RentACodec::Database(); + return i < db.size() ? db[i].plfreq : -1; } // Checks if the payload type is in the valid range. diff --git a/webrtc/modules/audio_coding/main/acm2/acm_codec_database.h b/webrtc/modules/audio_coding/main/acm2/acm_codec_database.h index 13b300851f..0913b7944c 100644 --- a/webrtc/modules/audio_coding/main/acm2/acm_codec_database.h +++ b/webrtc/modules/audio_coding/main/acm2/acm_codec_database.h @@ -18,6 +18,7 @@ #include "webrtc/common_types.h" #include "webrtc/engine_configurations.h" +#include "webrtc/modules/audio_coding/main/acm2/rent_a_codec.h" #include "webrtc/modules/audio_coding/neteq/interface/neteq.h" namespace webrtc { @@ -27,85 +28,6 @@ namespace acm2 { // TODO(tlegrand): replace class ACMCodecDB with a namespace. class ACMCodecDB { public: - // Enum with array indexes for the supported codecs. NOTE! The order MUST - // be the same as when creating the database in acm_codec_database.cc. - enum { - kNone = -1 -#if (defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX)) - , kISAC -# if (defined(WEBRTC_CODEC_ISAC)) - , kISACSWB -# endif -#endif - // Mono - , kPCM16B - , kPCM16Bwb - , kPCM16Bswb32kHz - // Stereo - , kPCM16B_2ch - , kPCM16Bwb_2ch - , kPCM16Bswb32kHz_2ch - // Mono - , kPCMU - , kPCMA - // Stereo - , kPCMU_2ch - , kPCMA_2ch -#ifdef WEBRTC_CODEC_ILBC - , kILBC -#endif -#ifdef WEBRTC_CODEC_G722 - // Mono - , kG722 - // Stereo - , kG722_2ch -#endif -#ifdef WEBRTC_CODEC_OPUS - // Mono and stereo - , kOpus -#endif - , kCNNB - , kCNWB - , kCNSWB -#ifdef ENABLE_48000_HZ - , kCNFB -#endif - , kAVT -#ifdef WEBRTC_CODEC_RED - , kRED -#endif - , kNumCodecs - }; - - // Set unsupported codecs to -1 -#ifndef WEBRTC_CODEC_ISAC - enum {kISACSWB = -1}; -# ifndef WEBRTC_CODEC_ISACFX - enum {kISAC = -1}; -# endif -#endif - // 48 kHz not supported, always set to -1. - enum {kPCM16Bswb48kHz = -1}; -#ifndef WEBRTC_CODEC_ILBC - enum {kILBC = -1}; -#endif -#ifndef WEBRTC_CODEC_G722 - // Mono - enum {kG722 = -1}; - // Stereo - enum {kG722_2ch = -1}; -#endif -#ifndef WEBRTC_CODEC_OPUS - // Mono and stereo - enum {kOpus = -1}; -#endif -#ifndef WEBRTC_CODEC_RED - enum {kRED = -1}; -#endif -#ifndef ENABLE_48000_HZ - enum { kCNFB = -1 }; -#endif - // kMaxNumCodecs - Maximum number of codecs that can be activated in one // build. // kMaxNumPacketSize - Maximum number of allowed packet sizes for one codec. diff --git a/webrtc/modules/audio_coding/main/acm2/acm_receiver.cc b/webrtc/modules/audio_coding/main/acm2/acm_receiver.cc index bfcf76ce72..23ffafcb83 100644 --- a/webrtc/modules/audio_coding/main/acm2/acm_receiver.cc +++ b/webrtc/modules/audio_coding/main/acm2/acm_receiver.cc @@ -111,9 +111,13 @@ void SetAudioFrameActivityAndType(bool vad_enabled, } // Is the given codec a CNG codec? +// TODO(kwiberg): Move to RentACodec. bool IsCng(int codec_id) { - return (codec_id == ACMCodecDB::kCNNB || codec_id == ACMCodecDB::kCNWB || - codec_id == ACMCodecDB::kCNSWB || codec_id == ACMCodecDB::kCNFB); + auto i = RentACodec::CodecIdFromIndex(codec_id); + return (i && (*i == RentACodec::CodecId::kCNNB || + *i == RentACodec::CodecId::kCNWB || + *i == RentACodec::CodecId::kCNSWB || + *i == RentACodec::CodecId::kCNFB)); } } // namespace @@ -241,7 +245,8 @@ int AcmReceiver::InsertPacket(const WebRtcRTPHeader& rtp_header, if (last_audio_decoder_ && last_audio_decoder_->channels > 1) return 0; packet_type = InitialDelayManager::kCngPacket; - } else if (decoder->acm_codec_id == ACMCodecDB::kAVT) { + } else if (decoder->acm_codec_id == + *RentACodec::CodecIndexFromId(RentACodec::CodecId::kAVT)) { packet_type = InitialDelayManager::kAvtPacket; } else { if (decoder != last_audio_decoder_) { @@ -566,11 +571,13 @@ int AcmReceiver::last_audio_codec_id() const { } int AcmReceiver::RedPayloadType() const { - if (ACMCodecDB::kRED >= 0) { // This ensures that RED is defined in WebRTC. + const auto red_index = + RentACodec::CodecIndexFromId(RentACodec::CodecId::kRED); + if (red_index) { CriticalSectionScoped lock(crit_sect_.get()); for (const auto& decoder_pair : decoders_) { const Decoder& decoder = decoder_pair.second; - if (decoder.acm_codec_id == ACMCodecDB::kRED) + if (decoder.acm_codec_id == *red_index) return decoder.payload_type; } } @@ -737,8 +744,10 @@ const AcmReceiver::Decoder* AcmReceiver::RtpHeaderToDecoder( const RTPHeader& rtp_header, const uint8_t* payload) const { auto it = decoders_.find(rtp_header.payloadType); - if (ACMCodecDB::kRED >= 0 && // This ensures that RED is defined in WebRTC. - it != decoders_.end() && ACMCodecDB::kRED == it->second.acm_codec_id) { + const auto red_index = + RentACodec::CodecIndexFromId(RentACodec::CodecId::kRED); + if (red_index && // This ensures that RED is defined in WebRTC. + it != decoders_.end() && it->second.acm_codec_id == *red_index) { // This is a RED packet, get the payload of the audio codec. it = decoders_.find(payload[0] & 0x7F); } diff --git a/webrtc/modules/audio_coding/main/acm2/acm_receiver_unittest_oldapi.cc b/webrtc/modules/audio_coding/main/acm2/acm_receiver_unittest_oldapi.cc index 12ea300fe5..7330a9f437 100644 --- a/webrtc/modules/audio_coding/main/acm2/acm_receiver_unittest_oldapi.cc +++ b/webrtc/modules/audio_coding/main/acm2/acm_receiver_unittest_oldapi.cc @@ -37,6 +37,19 @@ bool CodecsEqual(const CodecInst& codec_a, const CodecInst& codec_b) { return true; } +struct CodecIdInst { + explicit CodecIdInst(RentACodec::CodecId codec_id) { + const auto codec_ix = RentACodec::CodecIndexFromId(codec_id); + EXPECT_TRUE(codec_ix); + id = *codec_ix; + const auto codec_inst = RentACodec::CodecInstById(codec_id); + EXPECT_TRUE(codec_inst); + inst = *codec_inst; + } + int id; + CodecInst inst; +}; + } // namespace class AcmReceiverTestOldApi : public AudioPacketizationCallback, @@ -57,9 +70,7 @@ class AcmReceiverTestOldApi : public AudioPacketizationCallback, void SetUp() override { ASSERT_TRUE(receiver_.get() != NULL); ASSERT_TRUE(acm_.get() != NULL); - for (int n = 0; n < ACMCodecDB::kNumCodecs; n++) { - ASSERT_EQ(0, ACMCodecDB::Codec(n, &codecs_[n])); - } + codecs_ = RentACodec::Database(); acm_->InitializeReceiver(); acm_->RegisterTransportCallback(this); @@ -103,14 +114,14 @@ class AcmReceiverTestOldApi : public AudioPacketizationCallback, } } - // Last element of id should be negative. - void AddSetOfCodecs(const int* id) { - int n = 0; - while (id[n] >= 0) { - ASSERT_EQ(0, receiver_->AddCodec(id[n], codecs_[id[n]].pltype, - codecs_[id[n]].channels, - codecs_[id[n]].plfreq, NULL)); - ++n; + template + void AddSetOfCodecs(const RentACodec::CodecId(&ids)[N]) { + for (auto id : ids) { + const auto i = RentACodec::CodecIndexFromId(id); + ASSERT_TRUE(i); + ASSERT_EQ( + 0, receiver_->AddCodec(*i, codecs_[*i].pltype, codecs_[*i].channels, + codecs_[*i].plfreq, nullptr)); } } @@ -144,7 +155,7 @@ class AcmReceiverTestOldApi : public AudioPacketizationCallback, } rtc::scoped_ptr receiver_; - CodecInst codecs_[ACMCodecDB::kMaxNumCodecs]; + rtc::ArrayView codecs_; rtc::scoped_ptr acm_; WebRtcRTPHeader rtp_header_; uint32_t timestamp_; @@ -155,14 +166,14 @@ class AcmReceiverTestOldApi : public AudioPacketizationCallback, TEST_F(AcmReceiverTestOldApi, DISABLED_ON_ANDROID(AddCodecGetCodec)) { // Add codec. - for (int n = 0; n < ACMCodecDB::kNumCodecs; ++n) { + for (size_t n = 0; n < codecs_.size(); ++n) { if (n & 0x1) // Just add codecs with odd index. EXPECT_EQ(0, receiver_->AddCodec(n, codecs_[n].pltype, codecs_[n].channels, codecs_[n].plfreq, NULL)); } // Get codec and compare. - for (int n = 0; n < ACMCodecDB::kNumCodecs; ++n) { + for (size_t n = 0; n < codecs_.size(); ++n) { CodecInst my_codec; if (n & 0x1) { // Codecs with odd index should match the reference. @@ -178,58 +189,52 @@ TEST_F(AcmReceiverTestOldApi, DISABLED_ON_ANDROID(AddCodecGetCodec)) { } TEST_F(AcmReceiverTestOldApi, DISABLED_ON_ANDROID(AddCodecChangePayloadType)) { - const int codec_id = ACMCodecDB::kPCMA; - CodecInst ref_codec1; - EXPECT_EQ(0, ACMCodecDB::Codec(codec_id, &ref_codec1)); - CodecInst ref_codec2 = ref_codec1; - ++ref_codec2.pltype; + const CodecIdInst codec1(RentACodec::CodecId::kPCMA); + CodecInst codec2 = codec1.inst; + ++codec2.pltype; CodecInst test_codec; // Register the same codec with different payloads. - EXPECT_EQ( - 0, receiver_->AddCodec(codec_id, ref_codec1.pltype, ref_codec1.channels, - ref_codec1.plfreq, NULL)); - EXPECT_EQ( - 0, receiver_->AddCodec(codec_id, ref_codec2.pltype, ref_codec2.channels, - ref_codec2.plfreq, NULL)); + EXPECT_EQ(0, receiver_->AddCodec(codec1.id, codec1.inst.pltype, + codec1.inst.channels, codec1.inst.plfreq, + nullptr)); + EXPECT_EQ(0, receiver_->AddCodec(codec1.id, codec2.pltype, codec2.channels, + codec2.plfreq, NULL)); // Both payload types should exist. - EXPECT_EQ(0, receiver_->DecoderByPayloadType(ref_codec1.pltype, &test_codec)); - EXPECT_EQ(true, CodecsEqual(ref_codec1, test_codec)); - EXPECT_EQ(0, receiver_->DecoderByPayloadType(ref_codec2.pltype, &test_codec)); - EXPECT_EQ(true, CodecsEqual(ref_codec2, test_codec)); + EXPECT_EQ(0, + receiver_->DecoderByPayloadType(codec1.inst.pltype, &test_codec)); + EXPECT_EQ(true, CodecsEqual(codec1.inst, test_codec)); + EXPECT_EQ(0, receiver_->DecoderByPayloadType(codec2.pltype, &test_codec)); + EXPECT_EQ(true, CodecsEqual(codec2, test_codec)); } TEST_F(AcmReceiverTestOldApi, DISABLED_ON_ANDROID(AddCodecChangeCodecId)) { - const int codec_id1 = ACMCodecDB::kPCMU; - CodecInst ref_codec1; - EXPECT_EQ(0, ACMCodecDB::Codec(codec_id1, &ref_codec1)); - const int codec_id2 = ACMCodecDB::kPCMA; - CodecInst ref_codec2; - EXPECT_EQ(0, ACMCodecDB::Codec(codec_id2, &ref_codec2)); - ref_codec2.pltype = ref_codec1.pltype; + const CodecIdInst codec1(RentACodec::CodecId::kPCMU); + CodecIdInst codec2(RentACodec::CodecId::kPCMA); + codec2.inst.pltype = codec1.inst.pltype; CodecInst test_codec; // Register the same payload type with different codec ID. - EXPECT_EQ( - 0, receiver_->AddCodec(codec_id1, ref_codec1.pltype, ref_codec1.channels, - ref_codec1.plfreq, NULL)); - EXPECT_EQ( - 0, receiver_->AddCodec(codec_id2, ref_codec2.pltype, ref_codec2.channels, - ref_codec2.plfreq, NULL)); + EXPECT_EQ(0, receiver_->AddCodec(codec1.id, codec1.inst.pltype, + codec1.inst.channels, codec1.inst.plfreq, + nullptr)); + EXPECT_EQ(0, receiver_->AddCodec(codec2.id, codec2.inst.pltype, + codec2.inst.channels, codec2.inst.plfreq, + nullptr)); // Make sure that the last codec is used. - EXPECT_EQ(0, receiver_->DecoderByPayloadType(ref_codec2.pltype, &test_codec)); - EXPECT_EQ(true, CodecsEqual(ref_codec2, test_codec)); + EXPECT_EQ(0, + receiver_->DecoderByPayloadType(codec2.inst.pltype, &test_codec)); + EXPECT_EQ(true, CodecsEqual(codec2.inst, test_codec)); } TEST_F(AcmReceiverTestOldApi, DISABLED_ON_ANDROID(AddCodecRemoveCodec)) { - CodecInst codec; - const int codec_id = ACMCodecDB::kPCMA; - EXPECT_EQ(0, ACMCodecDB::Codec(codec_id, &codec)); - const int payload_type = codec.pltype; - EXPECT_EQ(0, receiver_->AddCodec(codec_id, codec.pltype, codec.channels, - codec.plfreq, NULL)); + const CodecIdInst codec(RentACodec::CodecId::kPCMA); + const int payload_type = codec.inst.pltype; + EXPECT_EQ( + 0, receiver_->AddCodec(codec.id, codec.inst.pltype, codec.inst.channels, + codec.inst.plfreq, nullptr)); // Remove non-existing codec should not fail. ACM1 legacy. EXPECT_EQ(0, receiver_->RemoveCodec(payload_type + 1)); @@ -238,46 +243,43 @@ TEST_F(AcmReceiverTestOldApi, DISABLED_ON_ANDROID(AddCodecRemoveCodec)) { EXPECT_EQ(0, receiver_->RemoveCodec(payload_type)); // Ask for the removed codec, must fail. - EXPECT_EQ(-1, receiver_->DecoderByPayloadType(payload_type, &codec)); + CodecInst ci; + EXPECT_EQ(-1, receiver_->DecoderByPayloadType(payload_type, &ci)); } TEST_F(AcmReceiverTestOldApi, DISABLED_ON_ANDROID(SampleRate)) { - const int kCodecId[] = { - ACMCodecDB::kISAC, ACMCodecDB::kISACSWB, - -1 // Terminator. - }; + const RentACodec::CodecId kCodecId[] = {RentACodec::CodecId::kISAC, + RentACodec::CodecId::kISACSWB}; AddSetOfCodecs(kCodecId); AudioFrame frame; const int kOutSampleRateHz = 8000; // Different than codec sample rate. - int n = 0; - while (kCodecId[n] >= 0) { - const int num_10ms_frames = codecs_[kCodecId[n]].pacsize / - (codecs_[kCodecId[n]].plfreq / 100); - InsertOnePacketOfSilence(kCodecId[n]); + for (const auto codec_id : kCodecId) { + const CodecIdInst codec(codec_id); + const int num_10ms_frames = codec.inst.pacsize / (codec.inst.plfreq / 100); + InsertOnePacketOfSilence(codec.id); for (int k = 0; k < num_10ms_frames; ++k) { EXPECT_EQ(0, receiver_->GetAudio(kOutSampleRateHz, &frame)); } - EXPECT_EQ(std::min(32000, codecs_[kCodecId[n]].plfreq), + EXPECT_EQ(std::min(32000, codec.inst.plfreq), receiver_->current_sample_rate_hz()); - ++n; } } TEST_F(AcmReceiverTestOldApi, DISABLED_ON_ANDROID(PostdecodingVad)) { receiver_->EnableVad(); EXPECT_TRUE(receiver_->vad_enabled()); - - const int id = ACMCodecDB::kPCM16Bwb; - ASSERT_EQ(0, receiver_->AddCodec(id, codecs_[id].pltype, codecs_[id].channels, - codecs_[id].plfreq, NULL)); + const CodecIdInst codec(RentACodec::CodecId::kPCM16Bwb); + ASSERT_EQ( + 0, receiver_->AddCodec(codec.id, codec.inst.pltype, codec.inst.channels, + codec.inst.plfreq, nullptr)); const int kNumPackets = 5; - const int num_10ms_frames = codecs_[id].pacsize / (codecs_[id].plfreq / 100); + const int num_10ms_frames = codec.inst.pacsize / (codec.inst.plfreq / 100); AudioFrame frame; for (int n = 0; n < kNumPackets; ++n) { - InsertOnePacketOfSilence(id); + InsertOnePacketOfSilence(codec.id); for (int k = 0; k < num_10ms_frames; ++k) - ASSERT_EQ(0, receiver_->GetAudio(codecs_[id].plfreq, &frame)); + ASSERT_EQ(0, receiver_->GetAudio(codec.inst.plfreq, &frame)); } EXPECT_EQ(AudioFrame::kVadPassive, frame.vad_activity_); @@ -285,9 +287,9 @@ TEST_F(AcmReceiverTestOldApi, DISABLED_ON_ANDROID(PostdecodingVad)) { EXPECT_FALSE(receiver_->vad_enabled()); for (int n = 0; n < kNumPackets; ++n) { - InsertOnePacketOfSilence(id); + InsertOnePacketOfSilence(codec.id); for (int k = 0; k < num_10ms_frames; ++k) - ASSERT_EQ(0, receiver_->GetAudio(codecs_[id].plfreq, &frame)); + ASSERT_EQ(0, receiver_->GetAudio(codec.inst.plfreq, &frame)); } EXPECT_EQ(AudioFrame::kVadUnknown, frame.vad_activity_); } @@ -300,25 +302,20 @@ TEST_F(AcmReceiverTestOldApi, DISABLED_ON_ANDROID(PostdecodingVad)) { TEST_F(AcmReceiverTestOldApi, DISABLED_ON_ANDROID(IF_ISAC_FLOAT(LastAudioCodec))) { - const int kCodecId[] = { - ACMCodecDB::kISAC, ACMCodecDB::kPCMA, ACMCodecDB::kISACSWB, - ACMCodecDB::kPCM16Bswb32kHz, - -1 // Terminator. - }; + const RentACodec::CodecId kCodecId[] = { + RentACodec::CodecId::kISAC, RentACodec::CodecId::kPCMA, + RentACodec::CodecId::kISACSWB, RentACodec::CodecId::kPCM16Bswb32kHz}; AddSetOfCodecs(kCodecId); - const int kCngId[] = { // Not including full-band. - ACMCodecDB::kCNNB, ACMCodecDB::kCNWB, ACMCodecDB::kCNSWB, - -1 // Terminator. - }; + const RentACodec::CodecId kCngId[] = { + // Not including full-band. + RentACodec::CodecId::kCNNB, RentACodec::CodecId::kCNWB, + RentACodec::CodecId::kCNSWB}; AddSetOfCodecs(kCngId); // Register CNG at sender side. - int n = 0; - while (kCngId[n] > 0) { - ASSERT_EQ(0, acm_->RegisterSendCodec(codecs_[kCngId[n]])); - ++n; - } + for (auto id : kCngId) + ASSERT_EQ(0, acm_->RegisterSendCodec(CodecIdInst(id).inst)); CodecInst codec; // No audio payload is received. @@ -327,7 +324,8 @@ TEST_F(AcmReceiverTestOldApi, // Start with sending DTX. ASSERT_EQ(0, acm_->SetVAD(true, true, VADVeryAggr)); packet_sent_ = false; - InsertOnePacketOfSilence(kCodecId[0]); // Enough to test with one codec. + InsertOnePacketOfSilence(CodecIdInst(kCodecId[0]).id); // Enough to test + // with one codec. ASSERT_TRUE(packet_sent_); EXPECT_EQ(kAudioFrameCN, last_frame_type_); @@ -335,18 +333,19 @@ TEST_F(AcmReceiverTestOldApi, EXPECT_EQ(-1, receiver_->LastAudioCodec(&codec)); EXPECT_EQ(-1, receiver_->last_audio_codec_id()); - n = 0; - while (kCodecId[n] >= 0) { // Loop over codecs. + for (auto id : kCodecId) { + const CodecIdInst c(id); + // Set DTX off to send audio payload. acm_->SetVAD(false, false, VADAggr); packet_sent_ = false; - InsertOnePacketOfSilence(kCodecId[n]); + InsertOnePacketOfSilence(c.id); // Sanity check if Actually an audio payload received, and it should be // of type "speech." ASSERT_TRUE(packet_sent_); ASSERT_EQ(kAudioFrameSpeech, last_frame_type_); - EXPECT_EQ(kCodecId[n], receiver_->last_audio_codec_id()); + EXPECT_EQ(c.id, receiver_->last_audio_codec_id()); // Set VAD on to send DTX. Then check if the "Last Audio codec" returns // the expected codec. @@ -355,13 +354,12 @@ TEST_F(AcmReceiverTestOldApi, // Do as many encoding until a DTX is sent. while (last_frame_type_ != kAudioFrameCN) { packet_sent_ = false; - InsertOnePacketOfSilence(kCodecId[n]); + InsertOnePacketOfSilence(c.id); ASSERT_TRUE(packet_sent_); } - EXPECT_EQ(kCodecId[n], receiver_->last_audio_codec_id()); + EXPECT_EQ(c.id, receiver_->last_audio_codec_id()); EXPECT_EQ(0, receiver_->LastAudioCodec(&codec)); - EXPECT_TRUE(CodecsEqual(codecs_[kCodecId[n]], codec)); - ++n; + EXPECT_TRUE(CodecsEqual(c.inst, codec)); } } diff --git a/webrtc/modules/audio_coding/main/acm2/audio_coding_module.cc b/webrtc/modules/audio_coding/main/acm2/audio_coding_module.cc index 8a0980e619..7754a9c375 100644 --- a/webrtc/modules/audio_coding/main/acm2/audio_coding_module.cc +++ b/webrtc/modules/audio_coding/main/acm2/audio_coding_module.cc @@ -12,8 +12,8 @@ #include "webrtc/base/checks.h" #include "webrtc/common_types.h" -#include "webrtc/modules/audio_coding/main/acm2/acm_codec_database.h" #include "webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.h" +#include "webrtc/modules/audio_coding/main/acm2/rent_a_codec.h" #include "webrtc/system_wrappers/interface/clock.h" #include "webrtc/system_wrappers/interface/trace.h" @@ -38,29 +38,32 @@ AudioCodingModule* AudioCodingModule::Create(const Config& config) { return new acm2::AudioCodingModuleImpl(config); } -// Get number of supported codecs int AudioCodingModule::NumberOfCodecs() { - return acm2::ACMCodecDB::kNumCodecs; + return static_cast(acm2::RentACodec::NumberOfCodecs()); } -// Get supported codec parameters with id int AudioCodingModule::Codec(int list_id, CodecInst* codec) { - // Get the codec settings for the codec with the given list ID - return acm2::ACMCodecDB::Codec(list_id, codec); + auto codec_id = acm2::RentACodec::CodecIdFromIndex(list_id); + if (!codec_id) + return -1; + auto ci = acm2::RentACodec::CodecInstById(*codec_id); + if (!ci) + return -1; + *codec = *ci; + return 0; } -// Get supported codec parameters with name, frequency and number of channels. int AudioCodingModule::Codec(const char* payload_name, CodecInst* codec, int sampling_freq_hz, int channels) { - int codec_id; - - // Get the id of the codec from the database. - codec_id = acm2::ACMCodecDB::CodecId( + rtc::Maybe ci = acm2::RentACodec::CodecInstByParams( payload_name, sampling_freq_hz, channels); - if (codec_id < 0) { - // We couldn't find a matching codec, set the parameters to unacceptable + if (ci) { + *codec = *ci; + return 0; + } else { + // We couldn't find a matching codec, so set the parameters to unacceptable // values and return. codec->plname[0] = '\0'; codec->pltype = -1; @@ -69,35 +72,26 @@ int AudioCodingModule::Codec(const char* payload_name, codec->plfreq = 0; return -1; } - - // Get default codec settings. - acm2::ACMCodecDB::Codec(codec_id, codec); - - // Keep the number of channels from the function call. For most codecs it - // will be the same value as in default codec settings, but not for all. - codec->channels = channels; - - return 0; } -// Get supported codec Index with name, frequency and number of channels. int AudioCodingModule::Codec(const char* payload_name, int sampling_freq_hz, int channels) { - return acm2::ACMCodecDB::CodecId(payload_name, sampling_freq_hz, channels); + rtc::Maybe ci = acm2::RentACodec::CodecIdByParams( + payload_name, sampling_freq_hz, channels); + if (!ci) + return -1; + rtc::Maybe i = acm2::RentACodec::CodecIndexFromId(*ci); + return i ? *i : -1; } // Checks the validity of the parameters of the given codec bool AudioCodingModule::IsCodecValid(const CodecInst& codec) { - int codec_number = acm2::ACMCodecDB::CodecNumber(codec); - - if (codec_number < 0) { + bool valid = acm2::RentACodec::IsCodecValid(codec); + if (!valid) WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, -1, "Invalid codec setting"); - return false; - } else { - return true; - } + return valid; } } // namespace webrtc 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 467e749cce..91541073b0 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 @@ -36,20 +36,12 @@ namespace { // TODO(turajs): the same functionality is used in NetEq. If both classes // need them, make it a static function in ACMCodecDB. -bool IsCodecRED(const CodecInst* codec) { - return (STR_CASE_CMP(codec->plname, "RED") == 0); +bool IsCodecRED(const CodecInst& codec) { + return (STR_CASE_CMP(codec.plname, "RED") == 0); } -bool IsCodecRED(int index) { - return (IsCodecRED(&ACMCodecDB::database_[index])); -} - -bool IsCodecCN(const CodecInst* codec) { - return (STR_CASE_CMP(codec->plname, "CN") == 0); -} - -bool IsCodecCN(int index) { - return (IsCodecCN(&ACMCodecDB::database_[index])); +bool IsCodecCN(const CodecInst& codec) { + return (STR_CASE_CMP(codec.plname, "CN") == 0); } // Stereo-to-mono can be used as in-place. @@ -513,11 +505,12 @@ int AudioCodingModuleImpl::InitializeReceiverSafe() { receiver_.FlushBuffers(); // Register RED and CN. - for (int i = 0; i < ACMCodecDB::kNumCodecs; i++) { - if (IsCodecRED(i) || IsCodecCN(i)) { - uint8_t pl_type = static_cast(ACMCodecDB::database_[i].pltype); - int fs = ACMCodecDB::database_[i].plfreq; - if (receiver_.AddCodec(i, pl_type, 1, fs, NULL) < 0) { + auto db = RentACodec::Database(); + for (size_t i = 0; i < db.size(); i++) { + if (IsCodecRED(db[i]) || IsCodecCN(db[i])) { + if (receiver_.AddCodec(static_cast(i), + static_cast(db[i].pltype), 1, + db[i].plfreq, nullptr) < 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_, "Cannot register master codec."); return -1; @@ -561,11 +554,14 @@ int AudioCodingModuleImpl::RegisterReceiveCodec(const CodecInst& codec) { return -1; } - int codec_id = ACMCodecDB::ReceiverCodecNumber(codec); - if (codec_id < 0 || codec_id >= ACMCodecDB::kNumCodecs) { + auto codec_id = + RentACodec::CodecIdByParams(codec.plname, codec.plfreq, codec.channels); + if (!codec_id) { LOG_F(LS_ERROR) << "Wrong codec params to be registered as receive codec"; return -1; } + auto codec_index = RentACodec::CodecIndexFromId(*codec_id); + RTC_CHECK(codec_index) << "Invalid codec ID: " << static_cast(*codec_id); // Check if the payload-type is valid. if (!ACMCodecDB::ValidPayloadType(codec.pltype)) { @@ -576,7 +572,7 @@ int AudioCodingModuleImpl::RegisterReceiveCodec(const CodecInst& codec) { // Get |decoder| associated with |codec|. |decoder| is NULL if |codec| does // not own its decoder. - return receiver_.AddCodec(codec_id, codec.pltype, codec.channels, + return receiver_.AddCodec(*codec_index, codec.pltype, codec.channels, codec.plfreq, codec_manager_.GetAudioDecoder(codec)); } diff --git a/webrtc/modules/audio_coding/main/acm2/codec_manager.cc b/webrtc/modules/audio_coding/main/acm2/codec_manager.cc index 862feaaa70..7f3174939a 100644 --- a/webrtc/modules/audio_coding/main/acm2/codec_manager.cc +++ b/webrtc/modules/audio_coding/main/acm2/codec_manager.cc @@ -23,18 +23,10 @@ bool IsCodecRED(const CodecInst& codec) { return (STR_CASE_CMP(codec.plname, "RED") == 0); } -bool IsCodecRED(int index) { - return (IsCodecRED(ACMCodecDB::database_[index])); -} - bool IsCodecCN(const CodecInst& codec) { return (STR_CASE_CMP(codec.plname, "CN") == 0); } -bool IsCodecCN(int index) { - return (IsCodecCN(ACMCodecDB::database_[index])); -} - // Check if the given codec is a valid to be registered as send codec. int IsValidSendCodec(const CodecInst& send_codec, bool is_primary_encoder) { int dummy_id = 0; @@ -164,18 +156,18 @@ CodecManager::CodecManager() encoder_is_opus_(false) { // Register the default payload type for RED and for CNG at sampling rates of // 8, 16, 32 and 48 kHz. - for (int i = (ACMCodecDB::kNumCodecs - 1); i >= 0; i--) { - if (IsCodecRED(i) && ACMCodecDB::database_[i].plfreq == 8000) { - red_nb_pltype_ = static_cast(ACMCodecDB::database_[i].pltype); - } else if (IsCodecCN(i)) { - if (ACMCodecDB::database_[i].plfreq == 8000) { - cng_nb_pltype_ = static_cast(ACMCodecDB::database_[i].pltype); - } else if (ACMCodecDB::database_[i].plfreq == 16000) { - cng_wb_pltype_ = static_cast(ACMCodecDB::database_[i].pltype); - } else if (ACMCodecDB::database_[i].plfreq == 32000) { - cng_swb_pltype_ = static_cast(ACMCodecDB::database_[i].pltype); - } else if (ACMCodecDB::database_[i].plfreq == 48000) { - cng_fb_pltype_ = static_cast(ACMCodecDB::database_[i].pltype); + for (const CodecInst& ci : RentACodec::Database()) { + if (IsCodecRED(ci) && ci.plfreq == 8000) { + red_nb_pltype_ = static_cast(ci.pltype); + } else if (IsCodecCN(ci)) { + if (ci.plfreq == 8000) { + cng_nb_pltype_ = static_cast(ci.pltype); + } else if (ci.plfreq == 16000) { + cng_wb_pltype_ = static_cast(ci.pltype); + } else if (ci.plfreq == 32000) { + cng_swb_pltype_ = static_cast(ci.pltype); + } else if (ci.plfreq == 48000) { + cng_fb_pltype_ = static_cast(ci.pltype); } } } diff --git a/webrtc/modules/audio_coding/main/acm2/rent_a_codec.cc b/webrtc/modules/audio_coding/main/acm2/rent_a_codec.cc new file mode 100644 index 0000000000..45542093e8 --- /dev/null +++ b/webrtc/modules/audio_coding/main/acm2/rent_a_codec.cc @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "webrtc/modules/audio_coding/main/acm2/rent_a_codec.h" + +#include "webrtc/modules/audio_coding/main/acm2/acm_codec_database.h" +#include "webrtc/modules/audio_coding/main/acm2/acm_common_defs.h" + +namespace webrtc { +namespace acm2 { + +rtc::Maybe RentACodec::CodecIdByParams( + const char* payload_name, + int sampling_freq_hz, + int channels) { + return CodecIdFromIndex( + ACMCodecDB::CodecId(payload_name, sampling_freq_hz, channels)); +} + +rtc::Maybe RentACodec::CodecInstById(CodecId codec_id) { + rtc::Maybe mi = CodecIndexFromId(codec_id); + return mi ? rtc::Maybe(Database()[*mi]) : rtc::Maybe(); +} + +rtc::Maybe RentACodec::CodecInstByParams(const char* payload_name, + int sampling_freq_hz, + int channels) { + rtc::Maybe codec_id = + CodecIdByParams(payload_name, sampling_freq_hz, channels); + if (!codec_id) + return rtc::Maybe(); + rtc::Maybe ci = CodecInstById(*codec_id); + RTC_DCHECK(ci); + + // Keep the number of channels from the function call. For most codecs it + // will be the same value as in default codec settings, but not for all. + ci->channels = channels; + + return ci; +} + +bool RentACodec::IsCodecValid(const CodecInst& codec_inst) { + return ACMCodecDB::CodecNumber(codec_inst) >= 0; +} + +rtc::ArrayView RentACodec::Database() { + return rtc::ArrayView(ACMCodecDB::database_, + NumberOfCodecs()); +} + +} // namespace acm2 +} // namespace webrtc diff --git a/webrtc/modules/audio_coding/main/acm2/rent_a_codec.h b/webrtc/modules/audio_coding/main/acm2/rent_a_codec.h new file mode 100644 index 0000000000..8482d8f4f9 --- /dev/null +++ b/webrtc/modules/audio_coding/main/acm2/rent_a_codec.h @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_MAIN_ACM2_RENT_A_CODEC_H_ +#define WEBRTC_MODULES_AUDIO_CODING_MAIN_ACM2_RENT_A_CODEC_H_ + +#include + +#include "webrtc/base/array_view.h" +#include "webrtc/base/maybe.h" +#include "webrtc/typedefs.h" + +namespace webrtc { + +struct CodecInst; + +namespace acm2 { + +class RentACodec { + public: + enum class CodecId { +#if defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX) + kISAC, +#endif +#ifdef WEBRTC_CODEC_ISAC + kISACSWB, +#endif + // Mono + kPCM16B, + kPCM16Bwb, + kPCM16Bswb32kHz, + // Stereo + kPCM16B_2ch, + kPCM16Bwb_2ch, + kPCM16Bswb32kHz_2ch, + // Mono + kPCMU, + kPCMA, + // Stereo + kPCMU_2ch, + kPCMA_2ch, +#ifdef WEBRTC_CODEC_ILBC + kILBC, +#endif +#ifdef WEBRTC_CODEC_G722 + kG722, // Mono + kG722_2ch, // Stereo +#endif +#ifdef WEBRTC_CODEC_OPUS + kOpus, // Mono and stereo +#endif + kCNNB, + kCNWB, + kCNSWB, +#ifdef ENABLE_48000_HZ + kCNFB, +#endif + kAVT, +#ifdef WEBRTC_CODEC_RED + kRED, +#endif + kNumCodecs, // Implementation detail. Don't use. + +// Set unsupported codecs to -1. +#if !defined(WEBRTC_CODEC_ISAC) && !defined(WEBRTC_CODEC_ISACFX) + kISAC = -1, +#endif +#ifndef WEBRTC_CODEC_ISAC + kISACSWB = -1, +#endif + // 48 kHz not supported, always set to -1. + kPCM16Bswb48kHz = -1, +#ifndef WEBRTC_CODEC_ILBC + kILBC = -1, +#endif +#ifndef WEBRTC_CODEC_G722 + kG722 = -1, // Mono + kG722_2ch = -1, // Stereo +#endif +#ifndef WEBRTC_CODEC_OPUS + kOpus = -1, // Mono and stereo +#endif +#ifndef WEBRTC_CODEC_RED + kRED = -1, +#endif +#ifndef ENABLE_48000_HZ + kCNFB = -1, +#endif + + kNone = -1 + }; + + static inline size_t NumberOfCodecs() { + return static_cast(CodecId::kNumCodecs); + } + + static inline rtc::Maybe CodecIndexFromId(CodecId codec_id) { + const int i = static_cast(codec_id); + return i < static_cast(NumberOfCodecs()) ? i : rtc::Maybe(); + } + + static inline rtc::Maybe CodecIdFromIndex(int codec_index) { + return static_cast(codec_index) < NumberOfCodecs() + ? static_cast(codec_index) + : rtc::Maybe(); + } + + static rtc::Maybe CodecIdByParams(const char* payload_name, + int sampling_freq_hz, + int channels); + static rtc::Maybe CodecInstById(CodecId codec_id); + static rtc::Maybe CodecInstByParams(const char* payload_name, + int sampling_freq_hz, + int channels); + static bool IsCodecValid(const CodecInst& codec_inst); + static rtc::ArrayView Database(); +}; + +} // namespace acm2 +} // namespace webrtc + +#endif // WEBRTC_MODULES_AUDIO_CODING_MAIN_ACM2_RENT_A_CODEC_H_ diff --git a/webrtc/modules/audio_coding/main/audio_coding_module.gypi b/webrtc/modules/audio_coding/main/audio_coding_module.gypi index 295bccf700..17b3c427ac 100644 --- a/webrtc/modules/audio_coding/main/audio_coding_module.gypi +++ b/webrtc/modules/audio_coding/main/audio_coding_module.gypi @@ -42,6 +42,30 @@ ], }, 'targets': [ + { + 'target_name': 'rent_a_codec', + 'type': 'static_library', + 'defines': [ + '<@(audio_coding_defines)', + ], + 'dependencies': [ + '<(webrtc_root)/common.gyp:webrtc_common', + ], + 'include_dirs': [ + '<(webrtc_root)', + ], + 'direct_dependent_settings': { + 'include_dirs': [ + '<(webrtc_root)', + ], + }, + 'sources': [ + 'acm2/acm_codec_database.cc', + 'acm2/acm_codec_database.h', + 'acm2/rent_a_codec.cc', + 'acm2/rent_a_codec.h', + ], + }, { 'target_name': 'audio_coding_module', 'type': 'static_library', @@ -53,6 +77,7 @@ '<(webrtc_root)/common.gyp:webrtc_common', '<(webrtc_root)/webrtc.gyp:rtc_event_log', 'neteq', + 'rent_a_codec', ], 'include_dirs': [ 'interface', @@ -67,8 +92,6 @@ ], }, 'sources': [ - 'acm2/acm_codec_database.cc', - 'acm2/acm_codec_database.h', 'acm2/acm_common_defs.h', 'acm2/acm_receiver.cc', 'acm2/acm_receiver.h',