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',