diff --git a/webrtc/audio/audio_receive_stream.cc b/webrtc/audio/audio_receive_stream.cc index 8c073d9c8c..f64d3051e6 100644 --- a/webrtc/audio/audio_receive_stream.cc +++ b/webrtc/audio/audio_receive_stream.cc @@ -94,10 +94,7 @@ AudioReceiveStream::AudioReceiveStream( channel_proxy_->GetAudioDecoderFactory()); channel_proxy_->RegisterExternalTransport(config.rtcp_send_transport); - - for (const auto& kv : config.decoder_map) { - channel_proxy_->SetRecPayloadType(kv.first, kv.second); - } + channel_proxy_->SetReceiveCodecs(config.decoder_map); for (const auto& extension : config.rtp.extensions) { if (extension.uri == RtpExtension::kAudioLevelUri) { diff --git a/webrtc/audio/audio_receive_stream_unittest.cc b/webrtc/audio/audio_receive_stream_unittest.cc index e6b81a8bab..9025550b4f 100644 --- a/webrtc/audio/audio_receive_stream_unittest.cc +++ b/webrtc/audio/audio_receive_stream_unittest.cc @@ -8,6 +8,7 @@ * be found in the AUTHORS file in the root of the source tree. */ +#include #include #include @@ -111,6 +112,11 @@ struct ConfigHelper { .Times(1) .After(expect_set); EXPECT_CALL(*channel_proxy_, DisassociateSendChannel()).Times(1); + EXPECT_CALL(*channel_proxy_, SetReceiveCodecs(_)) + .WillRepeatedly( + Invoke([](const std::map& codecs) { + EXPECT_THAT(codecs, testing::IsEmpty()); + })); return channel_proxy_; })); stream_config_.voe_channel_id = kChannelId; diff --git a/webrtc/call/call_unittest.cc b/webrtc/call/call_unittest.cc index 99d6812d68..a45b91cb72 100644 --- a/webrtc/call/call_unittest.cc +++ b/webrtc/call/call_unittest.cc @@ -9,6 +9,7 @@ */ #include +#include #include #include "webrtc/call/audio_state.h" @@ -141,6 +142,11 @@ TEST(CallTest, CreateDestroy_AssociateAudioSendReceiveStreams_RecvFirst) { new testing::NiceMock(); EXPECT_CALL(*channel_proxy, GetAudioDecoderFactory()) .WillRepeatedly(testing::ReturnRef(decoder_factory)); + EXPECT_CALL(*channel_proxy, SetReceiveCodecs(testing::_)) + .WillRepeatedly(testing::Invoke( + [](const std::map& codecs) { + EXPECT_THAT(codecs, testing::IsEmpty()); + })); // If being called for the send channel, save a pointer to the channel // proxy for later. if (channel_id == kRecvChannelId) { @@ -188,6 +194,11 @@ TEST(CallTest, CreateDestroy_AssociateAudioSendReceiveStreams_SendFirst) { new testing::NiceMock(); EXPECT_CALL(*channel_proxy, GetAudioDecoderFactory()) .WillRepeatedly(testing::ReturnRef(decoder_factory)); + EXPECT_CALL(*channel_proxy, SetReceiveCodecs(testing::_)) + .WillRepeatedly(testing::Invoke( + [](const std::map& codecs) { + EXPECT_THAT(codecs, testing::IsEmpty()); + })); // If being called for the send channel, save a pointer to the channel // proxy for later. if (channel_id == kRecvChannelId) { diff --git a/webrtc/media/engine/fakewebrtcvoiceengine.h b/webrtc/media/engine/fakewebrtcvoiceengine.h index e7d95d09e7..180d06bcaf 100644 --- a/webrtc/media/engine/fakewebrtcvoiceengine.h +++ b/webrtc/media/engine/fakewebrtcvoiceengine.h @@ -117,8 +117,6 @@ class FakeWebRtcVoiceEngine return -1; } Channel* ch = new Channel(); - auto db = webrtc::acm2::RentACodec::Database(); - ch->recv_codecs.assign(db.begin(), db.end()); ch->neteq_capacity = config.acm_config.neteq_config.max_packets_in_buffer; ch->neteq_fast_accelerate = config.acm_config.neteq_config.enable_fast_accelerate; diff --git a/webrtc/media/engine/webrtcvoiceengine.cc b/webrtc/media/engine/webrtcvoiceengine.cc index 7c6d7940f6..31a9d27184 100644 --- a/webrtc/media/engine/webrtcvoiceengine.cc +++ b/webrtc/media/engine/webrtcvoiceengine.cc @@ -132,13 +132,6 @@ std::string ToString(const AudioCodec& codec) { return ss.str(); } -std::string ToString(const webrtc::CodecInst& codec) { - std::stringstream ss; - ss << codec.plname << "/" << codec.plfreq << "/" << codec.channels - << " (" << codec.pltype << ")"; - return ss.str(); -} - bool IsCodec(const AudioCodec& codec, const char* ref_name) { return (_stricmp(codec.name.c_str(), ref_name) == 0); } @@ -1466,7 +1459,8 @@ class WebRtcVoiceMediaChannel::WebRtcAudioReceiveStream { const std::vector& extensions, webrtc::Call* call, webrtc::Transport* rtcp_send_transport, - const rtc::scoped_refptr& decoder_factory) + const rtc::scoped_refptr& decoder_factory, + const std::map& decoder_map) : call_(call), config_() { RTC_DCHECK_GE(ch, 0); RTC_DCHECK(call); @@ -1479,6 +1473,7 @@ class WebRtcVoiceMediaChannel::WebRtcAudioReceiveStream { config_.voe_channel_id = ch; config_.sync_group = sync_group; config_.decoder_factory = decoder_factory; + config_.decoder_map = decoder_map; RecreateAudioReceiveStream(); } @@ -1867,8 +1862,9 @@ bool WebRtcVoiceMediaChannel::SetRecvCodecs( ChangePlayout(false); } + decoder_map_ = std::move(decoder_map); for (auto& kv : recv_streams_) { - kv.second->RecreateAudioReceiveStream(decoder_map); + kv.second->RecreateAudioReceiveStream(decoder_map_); } recv_codecs_ = codecs; @@ -2225,38 +2221,12 @@ bool WebRtcVoiceMediaChannel::AddRecvStream(const StreamParams& sp) { return false; } - // Turn off all supported codecs. - // TODO(solenberg): Remove once "no codecs" is the default state of a stream. - for (webrtc::CodecInst voe_codec : webrtc::acm2::RentACodec::Database()) { - voe_codec.pltype = -1; - if (engine()->voe()->codec()->SetRecPayloadType(channel, voe_codec) == -1) { - LOG_RTCERR2(SetRecPayloadType, channel, ToString(voe_codec)); - DeleteVoEChannel(channel); - return false; - } - } - - // Only enable those configured for this channel. - for (const auto& codec : recv_codecs_) { - webrtc::CodecInst voe_codec = {0}; - if (WebRtcVoiceEngine::ToCodecInst(codec, &voe_codec)) { - voe_codec.pltype = codec.id; - if (engine()->voe()->codec()->SetRecPayloadType( - channel, voe_codec) == -1) { - LOG_RTCERR2(SetRecPayloadType, channel, ToString(voe_codec)); - DeleteVoEChannel(channel); - return false; - } - } - } - recv_streams_.insert(std::make_pair( - ssrc, new WebRtcAudioReceiveStream(channel, ssrc, receiver_reports_ssrc_, - recv_transport_cc_enabled_, - recv_nack_enabled_, - sp.sync_label, recv_rtp_extensions_, - call_, this, - engine()->decoder_factory_))); + ssrc, + new WebRtcAudioReceiveStream( + channel, ssrc, receiver_reports_ssrc_, recv_transport_cc_enabled_, + recv_nack_enabled_, sp.sync_label, recv_rtp_extensions_, call_, this, + engine()->decoder_factory_, decoder_map_))); recv_streams_[ssrc]->SetPlayout(playout_); return true; diff --git a/webrtc/media/engine/webrtcvoiceengine.h b/webrtc/media/engine/webrtcvoiceengine.h index c777c6c03e..64f7afabf6 100644 --- a/webrtc/media/engine/webrtcvoiceengine.h +++ b/webrtc/media/engine/webrtcvoiceengine.h @@ -251,7 +251,12 @@ class WebRtcVoiceMediaChannel final : public VoiceMediaChannel, WebRtcVoiceEngine* const engine_ = nullptr; std::vector send_codecs_; + + // TODO(kwiberg): decoder_map_ and recv_codecs_ store the exact same + // information, in slightly different formats. Eliminate recv_codecs_. + std::map decoder_map_; std::vector recv_codecs_; + int max_send_bitrate_bps_ = 0; AudioOptions options_; rtc::Optional dtmf_payload_type_; diff --git a/webrtc/media/engine/webrtcvoiceengine_unittest.cc b/webrtc/media/engine/webrtcvoiceengine_unittest.cc index 2d41ecd43b..3777b3daa3 100644 --- a/webrtc/media/engine/webrtcvoiceengine_unittest.cc +++ b/webrtc/media/engine/webrtcvoiceengine_unittest.cc @@ -31,6 +31,7 @@ #include "webrtc/test/gtest.h" #include "webrtc/voice_engine/transmit_mixer.h" +using testing::ContainerEq; using testing::Return; using testing::StrictMock; @@ -795,26 +796,12 @@ TEST_F(WebRtcVoiceEngineTestFake, SetRecvCodecs) { parameters.codecs[2].id = 126; EXPECT_TRUE(channel_->SetRecvParameters(parameters)); EXPECT_TRUE(AddRecvStream(kSsrcX)); - int channel_num = voe_.GetLastChannel(); - - webrtc::CodecInst gcodec; - rtc::strcpyn(gcodec.plname, arraysize(gcodec.plname), "ISAC"); - gcodec.plfreq = 16000; - gcodec.channels = 1; - EXPECT_EQ(0, voe_.GetRecPayloadType(channel_num, gcodec)); - EXPECT_EQ(106, gcodec.pltype); - EXPECT_STREQ("ISAC", gcodec.plname); - - rtc::strcpyn(gcodec.plname, arraysize(gcodec.plname), "telephone-event"); - gcodec.plfreq = 8000; - EXPECT_EQ(0, voe_.GetRecPayloadType(channel_num, gcodec)); - EXPECT_EQ(126, gcodec.pltype); - EXPECT_STREQ("telephone-event", gcodec.plname); - - gcodec.plfreq = 32000; - EXPECT_EQ(0, voe_.GetRecPayloadType(channel_num, gcodec)); - EXPECT_EQ(107, gcodec.pltype); - EXPECT_STREQ("telephone-event", gcodec.plname); + EXPECT_THAT(GetRecvStreamConfig(kSsrcX).decoder_map, + (ContainerEq>( + {{0, {"PCMU", 8000, 1}}, + {106, {"ISAC", 16000, 1}}, + {126, {"telephone-event", 8000, 1}}, + {107, {"telephone-event", 32000, 1}}}))); } // Test that we fail to set an unknown inbound codec. @@ -845,16 +832,11 @@ TEST_F(WebRtcVoiceEngineTestFake, SetRecvCodecsWithOpusNoStereo) { parameters.codecs.push_back(kOpusCodec); EXPECT_TRUE(channel_->SetRecvParameters(parameters)); EXPECT_TRUE(AddRecvStream(kSsrcX)); - int channel_num = voe_.GetLastChannel(); - webrtc::CodecInst opus; - cricket::WebRtcVoiceEngine::ToCodecInst(kOpusCodec, &opus); - // Even without stereo parameters, recv codecs still specify channels = 2. - EXPECT_EQ(2, opus.channels); - EXPECT_EQ(111, opus.pltype); - EXPECT_STREQ("opus", opus.plname); - opus.pltype = 0; - EXPECT_EQ(0, voe_.GetRecPayloadType(channel_num, opus)); - EXPECT_EQ(111, opus.pltype); + EXPECT_THAT(GetRecvStreamConfig(kSsrcX).decoder_map, + (ContainerEq>( + {{0, {"PCMU", 8000, 1}}, + {103, {"ISAC", 16000, 1}}, + {111, {"opus", 48000, 2}}}))); } // Test that we can decode OPUS with stereo = 0. @@ -867,16 +849,11 @@ TEST_F(WebRtcVoiceEngineTestFake, SetRecvCodecsWithOpus0Stereo) { parameters.codecs[2].params["stereo"] = "0"; EXPECT_TRUE(channel_->SetRecvParameters(parameters)); EXPECT_TRUE(AddRecvStream(kSsrcX)); - int channel_num2 = voe_.GetLastChannel(); - webrtc::CodecInst opus; - cricket::WebRtcVoiceEngine::ToCodecInst(kOpusCodec, &opus); - // Even when stereo is off, recv codecs still specify channels = 2. - EXPECT_EQ(2, opus.channels); - EXPECT_EQ(111, opus.pltype); - EXPECT_STREQ("opus", opus.plname); - opus.pltype = 0; - EXPECT_EQ(0, voe_.GetRecPayloadType(channel_num2, opus)); - EXPECT_EQ(111, opus.pltype); + EXPECT_THAT(GetRecvStreamConfig(kSsrcX).decoder_map, + (ContainerEq>( + {{0, {"PCMU", 8000, 1}}, + {103, {"ISAC", 16000, 1}}, + {111, {"opus", 48000, 2, {{"stereo", "0"}}}}}))); } // Test that we can decode OPUS with stereo = 1. @@ -889,15 +866,11 @@ TEST_F(WebRtcVoiceEngineTestFake, SetRecvCodecsWithOpus1Stereo) { parameters.codecs[2].params["stereo"] = "1"; EXPECT_TRUE(channel_->SetRecvParameters(parameters)); EXPECT_TRUE(AddRecvStream(kSsrcX)); - int channel_num2 = voe_.GetLastChannel(); - webrtc::CodecInst opus; - cricket::WebRtcVoiceEngine::ToCodecInst(kOpusCodec, &opus); - EXPECT_EQ(2, opus.channels); - EXPECT_EQ(111, opus.pltype); - EXPECT_STREQ("opus", opus.plname); - opus.pltype = 0; - EXPECT_EQ(0, voe_.GetRecPayloadType(channel_num2, opus)); - EXPECT_EQ(111, opus.pltype); + EXPECT_THAT(GetRecvStreamConfig(kSsrcX).decoder_map, + (ContainerEq>( + {{0, {"PCMU", 8000, 1}}, + {103, {"ISAC", 16000, 1}}, + {111, {"opus", 48000, 2, {{"stereo", "1"}}}}}))); } // Test that changes to recv codecs are applied to all streams. @@ -911,28 +884,15 @@ TEST_F(WebRtcVoiceEngineTestFake, SetRecvCodecsWithMultipleStreams) { parameters.codecs[0].id = 106; // collide with existing CN 32k parameters.codecs[2].id = 126; EXPECT_TRUE(channel_->SetRecvParameters(parameters)); - EXPECT_TRUE(AddRecvStream(kSsrcX)); - int channel_num2 = voe_.GetLastChannel(); - - webrtc::CodecInst gcodec; - rtc::strcpyn(gcodec.plname, arraysize(gcodec.plname), "ISAC"); - gcodec.plfreq = 16000; - gcodec.channels = 1; - EXPECT_EQ(0, voe_.GetRecPayloadType(channel_num2, gcodec)); - EXPECT_EQ(106, gcodec.pltype); - EXPECT_STREQ("ISAC", gcodec.plname); - - rtc::strcpyn(gcodec.plname, arraysize(gcodec.plname), "telephone-event"); - gcodec.plfreq = 8000; - gcodec.channels = 1; - EXPECT_EQ(0, voe_.GetRecPayloadType(channel_num2, gcodec)); - EXPECT_EQ(126, gcodec.pltype); - EXPECT_STREQ("telephone-event", gcodec.plname); - - gcodec.plfreq = 32000; - EXPECT_EQ(0, voe_.GetRecPayloadType(channel_num2, gcodec)); - EXPECT_EQ(107, gcodec.pltype); - EXPECT_STREQ("telephone-event", gcodec.plname); + for (const auto& ssrc : {kSsrcX, kSsrcY}) { + EXPECT_TRUE(AddRecvStream(ssrc)); + EXPECT_THAT(GetRecvStreamConfig(ssrc).decoder_map, + (ContainerEq>( + {{0, {"PCMU", 8000, 1}}, + {106, {"ISAC", 16000, 1}}, + {126, {"telephone-event", 8000, 1}}, + {107, {"telephone-event", 32000, 1}}}))); + } } TEST_F(WebRtcVoiceEngineTestFake, SetRecvCodecsAfterAddingStreams) { @@ -2961,12 +2921,9 @@ TEST_F(WebRtcVoiceEngineTestFake, AddRecvStreamUnsupportedCodec) { parameters.codecs.push_back(kPcmuCodec); EXPECT_TRUE(channel_->SetRecvParameters(parameters)); EXPECT_TRUE(AddRecvStream(kSsrcX)); - int channel_num2 = voe_.GetLastChannel(); - webrtc::CodecInst gcodec; - rtc::strcpyn(gcodec.plname, arraysize(gcodec.plname), "opus"); - gcodec.plfreq = 48000; - gcodec.channels = 2; - EXPECT_EQ(-1, voe_.GetRecPayloadType(channel_num2, gcodec)); + EXPECT_THAT(GetRecvStreamConfig(kSsrcX).decoder_map, + (ContainerEq>( + {{0, {"PCMU", 8000, 1}}, {103, {"ISAC", 16000, 1}}}))); } // Test that we properly clean up any streams that were added, even if diff --git a/webrtc/modules/audio_coding/acm2/acm_receiver.cc b/webrtc/modules/audio_coding/acm2/acm_receiver.cc index 21dbc747ec..4980d279e7 100644 --- a/webrtc/modules/audio_coding/acm2/acm_receiver.cc +++ b/webrtc/modules/audio_coding/acm2/acm_receiver.cc @@ -179,6 +179,10 @@ int AcmReceiver::GetAudio(int desired_freq_hz, return 0; } +void AcmReceiver::SetCodecs(const std::map& codecs) { + neteq_->SetCodecs(codecs); +} + int32_t AcmReceiver::AddCodec(int acm_codec_id, uint8_t payload_type, size_t channels, diff --git a/webrtc/modules/audio_coding/acm2/acm_receiver.h b/webrtc/modules/audio_coding/acm2/acm_receiver.h index 63ed43d8fa..8f0963f0af 100644 --- a/webrtc/modules/audio_coding/acm2/acm_receiver.h +++ b/webrtc/modules/audio_coding/acm2/acm_receiver.h @@ -79,6 +79,9 @@ class AcmReceiver { // int GetAudio(int desired_freq_hz, AudioFrame* audio_frame, bool* muted); + // Replace the current set of decoders with the specified set. + void SetCodecs(const std::map& codecs); + // // Adds a new codec to the NetEq codec database. // diff --git a/webrtc/modules/audio_coding/acm2/audio_coding_module.cc b/webrtc/modules/audio_coding/acm2/audio_coding_module.cc index daeea3577e..bc814f6d6f 100644 --- a/webrtc/modules/audio_coding/acm2/audio_coding_module.cc +++ b/webrtc/modules/audio_coding/acm2/audio_coding_module.cc @@ -121,6 +121,8 @@ class AudioCodingModuleImpl final : public AudioCodingModule { // Get current playout frequency. int PlayoutFrequency() const override; + void SetReceiveCodecs(const std::map& codecs) override; + bool RegisterReceiveCodec(int rtp_payload_type, const SdpAudioFormat& audio_format) override; @@ -318,16 +320,6 @@ void UpdateCodecTypeHistogram(size_t codec_type) { webrtc::AudioEncoder::CodecType::kMaxLoggedAudioCodecTypes)); } -// 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 IsCodecCN(const CodecInst& codec) { - return (STR_CASE_CMP(codec.plname, "CN") == 0); -} - // Stereo-to-mono can be used as in-place. int DownMix(const AudioFrame& frame, size_t length_out_buff, @@ -956,19 +948,6 @@ int AudioCodingModuleImpl::InitializeReceiverSafe() { receiver_.SetMaximumDelay(0); receiver_.FlushBuffers(); - // Register RED and CN. - auto db = acm2::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, db[i].plname) < 0) { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_, - "Cannot register master codec."); - return -1; - } - } - } receiver_initialized_ = true; return 0; } @@ -987,6 +966,12 @@ int AudioCodingModuleImpl::PlayoutFrequency() const { return receiver_.last_output_sample_rate_hz(); } +void AudioCodingModuleImpl::SetReceiveCodecs( + const std::map& codecs) { + rtc::CritScope lock(&acm_crit_sect_); + receiver_.SetCodecs(codecs); +} + bool AudioCodingModuleImpl::RegisterReceiveCodec( int rtp_payload_type, const SdpAudioFormat& audio_format) { diff --git a/webrtc/modules/audio_coding/include/audio_coding_module.h b/webrtc/modules/audio_coding/include/audio_coding_module.h index 1893b626de..b5cbff2d3a 100644 --- a/webrtc/modules/audio_coding/include/audio_coding_module.h +++ b/webrtc/modules/audio_coding/include/audio_coding_module.h @@ -485,6 +485,10 @@ class AudioCodingModule { // virtual int32_t PlayoutFrequency() const = 0; + // Replace any existing decoders with the given payload type -> decoder map. + virtual void SetReceiveCodecs( + const std::map& codecs) = 0; + // Registers a decoder for the given payload type. Returns true iff // successful. virtual bool RegisterReceiveCodec(int rtp_payload_type, diff --git a/webrtc/modules/audio_coding/neteq/decoder_database.cc b/webrtc/modules/audio_coding/neteq/decoder_database.cc index d147d676ed..8cd438656a 100644 --- a/webrtc/modules/audio_coding/neteq/decoder_database.cc +++ b/webrtc/modules/audio_coding/neteq/decoder_database.cc @@ -123,6 +123,38 @@ void DecoderDatabase::Reset() { active_cng_decoder_type_ = -1; } +std::vector DecoderDatabase::SetCodecs( + const std::map& codecs) { + // First collect all payload types that we'll remove or reassign, then remove + // them from the database. + std::vector changed_payload_types; + for (const std::pair kv : decoders_) { + auto i = codecs.find(kv.first); + if (i == codecs.end() || i->second != kv.second.GetFormat()) { + changed_payload_types.push_back(kv.first); + } + } + for (int pl_type : changed_payload_types) { + Remove(pl_type); + } + + // Enter the new and changed payload type mappings into the database. + for (const auto& kv : codecs) { + const int& rtp_payload_type = kv.first; + const SdpAudioFormat& audio_format = kv.second; + RTC_DCHECK_GE(rtp_payload_type, 0); + RTC_DCHECK_LE(rtp_payload_type, 0x7f); + if (decoders_.count(rtp_payload_type) == 0) { + decoders_.insert(std::make_pair( + rtp_payload_type, DecoderInfo(audio_format, decoder_factory_.get()))); + } else { + // The mapping for this payload type hasn't changed. + } + } + + return changed_payload_types; +} + int DecoderDatabase::RegisterPayload(uint8_t rtp_payload_type, NetEqDecoder codec_type, const std::string& name) { diff --git a/webrtc/modules/audio_coding/neteq/decoder_database.h b/webrtc/modules/audio_coding/neteq/decoder_database.h index ec470f8d5f..35d1d0da08 100644 --- a/webrtc/modules/audio_coding/neteq/decoder_database.h +++ b/webrtc/modules/audio_coding/neteq/decoder_database.h @@ -149,6 +149,11 @@ class DecoderDatabase { // using InsertExternal(). virtual void Reset(); + // Replaces the existing set of decoders with the given set. Returns the + // payload types that were reassigned or removed while doing so. + virtual std::vector SetCodecs( + const std::map& codecs); + // Registers |rtp_payload_type| as a decoder of type |codec_type|. The |name| // is only used to populate the name field in the DecoderInfo struct in the // database, and can be arbitrary (including empty). Returns kOK on success; diff --git a/webrtc/modules/audio_coding/neteq/include/neteq.h b/webrtc/modules/audio_coding/neteq/include/neteq.h index ea05940598..450318e456 100644 --- a/webrtc/modules/audio_coding/neteq/include/neteq.h +++ b/webrtc/modules/audio_coding/neteq/include/neteq.h @@ -157,6 +157,9 @@ class NetEq { // Returns kOK on success, or kFail in case of an error. virtual int GetAudio(AudioFrame* audio_frame, bool* muted) = 0; + // Replaces the current set of decoders with the given one. + virtual void SetCodecs(const std::map& codecs) = 0; + // Associates |rtp_payload_type| with |codec| and |codec_name|, and stores the // information in the codec database. Returns 0 on success, -1 on failure. // The name is only used to provide information back to the caller about the diff --git a/webrtc/modules/audio_coding/neteq/neteq_impl.cc b/webrtc/modules/audio_coding/neteq/neteq_impl.cc index 5015b7e9fe..501e5672d1 100644 --- a/webrtc/modules/audio_coding/neteq/neteq_impl.cc +++ b/webrtc/modules/audio_coding/neteq/neteq_impl.cc @@ -212,6 +212,15 @@ int NetEqImpl::GetAudio(AudioFrame* audio_frame, bool* muted) { return kOK; } +void NetEqImpl::SetCodecs(const std::map& codecs) { + rtc::CritScope lock(&crit_sect_); + const std::vector changed_payload_types = + decoder_database_->SetCodecs(codecs); + for (const int pt : changed_payload_types) { + packet_buffer_->DiscardPacketsWithPayloadType(pt); + } +} + int NetEqImpl::RegisterPayloadType(NetEqDecoder codec, const std::string& name, uint8_t rtp_payload_type) { diff --git a/webrtc/modules/audio_coding/neteq/neteq_impl.h b/webrtc/modules/audio_coding/neteq/neteq_impl.h index a8c3462708..88c0308f68 100644 --- a/webrtc/modules/audio_coding/neteq/neteq_impl.h +++ b/webrtc/modules/audio_coding/neteq/neteq_impl.h @@ -111,6 +111,8 @@ class NetEqImpl : public webrtc::NetEq { int GetAudio(AudioFrame* audio_frame, bool* muted) override; + void SetCodecs(const std::map& codecs) override; + int RegisterPayloadType(NetEqDecoder codec, const std::string& codec_name, uint8_t rtp_payload_type) override; diff --git a/webrtc/modules/rtp_rtcp/BUILD.gn b/webrtc/modules/rtp_rtcp/BUILD.gn index 541edd9258..c1d69e07bb 100644 --- a/webrtc/modules/rtp_rtcp/BUILD.gn +++ b/webrtc/modules/rtp_rtcp/BUILD.gn @@ -168,6 +168,7 @@ rtc_static_library("rtp_rtcp") { deps = [ "../..:webrtc_common", "../../api:transport_api", + "../../api/audio_codecs:audio_codecs_api", "../../base:gtest_prod", "../../base:rtc_base_approved", "../../base:rtc_task_queue", @@ -175,6 +176,7 @@ rtc_static_library("rtp_rtcp") { "../../common_video", "../../logging:rtc_event_log_api", "../../system_wrappers", + "../audio_coding:audio_format_conversion", "../remote_bitrate_estimator", ] diff --git a/webrtc/modules/rtp_rtcp/include/rtp_payload_registry.h b/webrtc/modules/rtp_rtcp/include/rtp_payload_registry.h index 767bd07f26..029de5dfcc 100644 --- a/webrtc/modules/rtp_rtcp/include/rtp_payload_registry.h +++ b/webrtc/modules/rtp_rtcp/include/rtp_payload_registry.h @@ -15,6 +15,7 @@ #include #include +#include "webrtc/api/audio_codecs/audio_format.h" #include "webrtc/base/criticalsection.h" #include "webrtc/base/deprecation.h" #include "webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.h" @@ -43,6 +44,10 @@ class RTPPayloadRegistry { // TODO(magjed): Split RTPPayloadRegistry into separate Audio and Video class // and simplify the code. http://crbug/webrtc/6743. + + // Replace all audio receive payload types with the given map. + void SetAudioReceivePayloads(std::map codecs); + int32_t RegisterReceivePayload(const CodecInst& audio_codec, bool* created_new_payload_type); int32_t RegisterReceivePayload(const VideoCodec& video_codec); diff --git a/webrtc/modules/rtp_rtcp/source/rtp_payload_registry.cc b/webrtc/modules/rtp_rtcp/source/rtp_payload_registry.cc index 1023bf8bb2..234fd7fce5 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_payload_registry.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_payload_registry.cc @@ -16,6 +16,7 @@ #include "webrtc/base/logging.h" #include "webrtc/base/stringutils.h" #include "webrtc/common_types.h" +#include "webrtc/modules/audio_coding/codecs/audio_format_conversion.h" #include "webrtc/modules/rtp_rtcp/source/byte_io.h" namespace webrtc { @@ -119,6 +120,31 @@ RTPPayloadRegistry::RTPPayloadRegistry() RTPPayloadRegistry::~RTPPayloadRegistry() = default; +void RTPPayloadRegistry::SetAudioReceivePayloads( + std::map codecs) { + rtc::CritScope cs(&crit_sect_); + +#if RTC_DCHECK_IS_ON + RTC_DCHECK(!used_for_video_); + used_for_audio_ = true; +#endif + + payload_type_map_.clear(); + for (const auto& kv : codecs) { + const int& rtp_payload_type = kv.first; + const SdpAudioFormat& audio_format = kv.second; + const CodecInst ci = SdpToCodecInst(rtp_payload_type, audio_format); + RTC_DCHECK(IsPayloadTypeValid(rtp_payload_type)); + payload_type_map_.insert( + std::make_pair(rtp_payload_type, CreatePayloadType(ci))); + } + + // Clear the value of last received payload type since it might mean + // something else now. + last_received_payload_type_ = -1; + last_received_media_payload_type_ = -1; +} + int32_t RTPPayloadRegistry::RegisterReceivePayload(const CodecInst& audio_codec, bool* created_new_payload) { rtc::CritScope cs(&crit_sect_); diff --git a/webrtc/test/mock_voe_channel_proxy.h b/webrtc/test/mock_voe_channel_proxy.h index d704e1933b..450dd7bcb7 100644 --- a/webrtc/test/mock_voe_channel_proxy.h +++ b/webrtc/test/mock_voe_channel_proxy.h @@ -87,6 +87,8 @@ class MockVoEChannelProxy : public voe::ChannelProxy { MOCK_METHOD1(SetSendCodec, bool(const CodecInst& codec_inst)); MOCK_METHOD2(SetSendCNPayloadType, bool(int type, PayloadFrequencies frequency)); + MOCK_METHOD1(SetReceiveCodecs, + void(const std::map& codecs)); MOCK_METHOD1(OnTwccBasedUplinkPacketLossRate, void(float packet_loss_rate)); MOCK_METHOD1(OnRecoverableUplinkPacketLossRate, void(float recoverable_packet_loss_rate)); diff --git a/webrtc/test/mock_voice_engine.h b/webrtc/test/mock_voice_engine.h index ca3fe4f466..6b1f9cf31f 100644 --- a/webrtc/test/mock_voice_engine.h +++ b/webrtc/test/mock_voice_engine.h @@ -52,6 +52,11 @@ class MockVoiceEngine : public VoiceEngineImpl { new testing::NiceMock(); EXPECT_CALL(*proxy, GetAudioDecoderFactory()) .WillRepeatedly(testing::ReturnRef(decoder_factory_)); + EXPECT_CALL(*proxy, SetReceiveCodecs(testing::_)) + .WillRepeatedly(testing::Invoke( + [](const std::map& codecs) { + EXPECT_THAT(codecs, testing::IsEmpty()); + })); return proxy; })); diff --git a/webrtc/voice_engine/channel.cc b/webrtc/voice_engine/channel.cc index d2b30ca8f7..3b562f9156 100644 --- a/webrtc/voice_engine/channel.cc +++ b/webrtc/voice_engine/channel.cc @@ -987,9 +987,10 @@ int32_t Channel::Init() { return -1; } - // --- Register all supported codecs to the receiving side of the - // RTP/RTCP module + return 0; +} +void Channel::RegisterLegacyCodecs() { CodecInst codec; const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs(); @@ -1041,8 +1042,6 @@ int32_t Channel::Init() { } } } - - return 0; } void Channel::Terminate() { @@ -1360,6 +1359,11 @@ int32_t Channel::GetVADStatus(bool& enabledVAD, return 0; } +void Channel::SetReceiveCodecs(const std::map& codecs) { + rtp_payload_registry_->SetAudioReceivePayloads(codecs); + audio_coding_->SetReceiveCodecs(codecs); +} + int32_t Channel::SetRecPayloadType(const CodecInst& codec) { return SetRecPayloadType(codec.pltype, CodecInstToSdp(codec)); } diff --git a/webrtc/voice_engine/channel.h b/webrtc/voice_engine/channel.h index 0a12f21e92..1365ae843e 100644 --- a/webrtc/voice_engine/channel.h +++ b/webrtc/voice_engine/channel.h @@ -151,6 +151,7 @@ class Channel uint32_t instanceId, const VoEBase::ChannelConfig& config); int32_t Init(); + void RegisterLegacyCodecs(); void Terminate(); int32_t SetEngineInformation(Statistics& engineStatistics, OutputMixer& outputMixer, @@ -168,6 +169,8 @@ class Channel // go. const rtc::scoped_refptr& GetAudioDecoderFactory() const; + void SetReceiveCodecs(const std::map& codecs); + // API methods // VoEBase diff --git a/webrtc/voice_engine/channel_proxy.cc b/webrtc/voice_engine/channel_proxy.cc index 45cbf10819..d67011e680 100644 --- a/webrtc/voice_engine/channel_proxy.cc +++ b/webrtc/voice_engine/channel_proxy.cc @@ -173,6 +173,12 @@ void ChannelProxy::SetRecPayloadType(int payload_type, RTC_DCHECK_EQ(0, result); } +void ChannelProxy::SetReceiveCodecs( + const std::map& codecs) { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + channel()->SetReceiveCodecs(codecs); +} + void ChannelProxy::SetSink(std::unique_ptr sink) { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); channel()->SetSink(std::move(sink)); @@ -379,6 +385,11 @@ void ChannelProxy::OnRecoverableUplinkPacketLossRate( channel()->OnRecoverableUplinkPacketLossRate(recoverable_packet_loss_rate); } +void ChannelProxy::RegisterLegacyCodecs() { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + channel()->RegisterLegacyCodecs(); +} + Channel* ChannelProxy::channel() const { RTC_DCHECK(channel_owner_.channel()); return channel_owner_.channel(); diff --git a/webrtc/voice_engine/channel_proxy.h b/webrtc/voice_engine/channel_proxy.h index 685a168845..b808096f45 100644 --- a/webrtc/voice_engine/channel_proxy.h +++ b/webrtc/voice_engine/channel_proxy.h @@ -82,6 +82,7 @@ class ChannelProxy { virtual void SetBitrate(int bitrate_bps, int64_t probing_interval_ms); virtual void SetRecPayloadType(int payload_type, const SdpAudioFormat& format); + virtual void SetReceiveCodecs(const std::map& codecs); virtual void SetSink(std::unique_ptr sink); virtual void SetInputMute(bool muted); virtual void RegisterExternalTransport(Transport* transport); @@ -119,6 +120,7 @@ class ChannelProxy { virtual void OnTwccBasedUplinkPacketLossRate(float packet_loss_rate); virtual void OnRecoverableUplinkPacketLossRate( float recoverable_packet_loss_rate); + virtual void RegisterLegacyCodecs(); private: Channel* channel() const; diff --git a/webrtc/voice_engine/test/auto_test/fakes/conference_transport.cc b/webrtc/voice_engine/test/auto_test/fakes/conference_transport.cc index b15d72fecb..f1eee9c6a2 100644 --- a/webrtc/voice_engine/test/auto_test/fakes/conference_transport.cc +++ b/webrtc/voice_engine/test/auto_test/fakes/conference_transport.cc @@ -15,6 +15,8 @@ #include "webrtc/base/byteorder.h" #include "webrtc/base/timeutils.h" #include "webrtc/system_wrappers/include/sleep.h" +#include "webrtc/voice_engine/channel_proxy.h" +#include "webrtc/voice_engine/voice_engine_impl.h" namespace { static const unsigned int kReflectorSsrc = 0x0000; @@ -62,6 +64,9 @@ ConferenceTransport::ConferenceTransport() EXPECT_EQ(0, local_base_->Init()); local_sender_ = local_base_->CreateChannel(); + static_cast(local_voe_) + ->GetChannelProxy(local_sender_) + ->RegisterLegacyCodecs(); EXPECT_EQ(0, local_network_->RegisterExternalTransport(local_sender_, *this)); EXPECT_EQ(0, local_rtp_rtcp_->SetLocalSSRC(local_sender_, kLocalSsrc)); EXPECT_EQ(0, local_rtp_rtcp_-> @@ -72,6 +77,9 @@ ConferenceTransport::ConferenceTransport() EXPECT_EQ(0, remote_base_->Init()); reflector_ = remote_base_->CreateChannel(); + static_cast(remote_voe_) + ->GetChannelProxy(reflector_) + ->RegisterLegacyCodecs(); EXPECT_EQ(0, remote_network_->RegisterExternalTransport(reflector_, *this)); EXPECT_EQ(0, remote_rtp_rtcp_->SetLocalSSRC(reflector_, kReflectorSsrc)); @@ -222,6 +230,9 @@ void ConferenceTransport::SetRtt(unsigned int rtt_ms) { unsigned int ConferenceTransport::AddStream(std::string file_name, webrtc::FileFormats format) { const int new_sender = remote_base_->CreateChannel(); + static_cast(remote_voe_) + ->GetChannelProxy(new_sender) + ->RegisterLegacyCodecs(); EXPECT_EQ(0, remote_network_->RegisterExternalTransport(new_sender, *this)); const unsigned int remote_ssrc = kFirstRemoteSsrc + stream_count_++; @@ -235,6 +246,9 @@ unsigned int ConferenceTransport::AddStream(std::string file_name, new_sender, file_name.c_str(), true, false, format, 1.0)); const int new_receiver = local_base_->CreateChannel(); + static_cast(local_voe_) + ->GetChannelProxy(new_receiver) + ->RegisterLegacyCodecs(); EXPECT_EQ(0, local_base_->AssociateSendChannel(new_receiver, local_sender_)); EXPECT_EQ(0, local_network_->RegisterExternalTransport(new_receiver, *this)); diff --git a/webrtc/voice_engine/test/auto_test/fixtures/after_streaming_fixture.cc b/webrtc/voice_engine/test/auto_test/fixtures/after_streaming_fixture.cc index 0fbe63550d..5582124a38 100644 --- a/webrtc/voice_engine/test/auto_test/fixtures/after_streaming_fixture.cc +++ b/webrtc/voice_engine/test/auto_test/fixtures/after_streaming_fixture.cc @@ -16,5 +16,6 @@ AfterStreamingFixture::AfterStreamingFixture() webrtc::VoiceEngineImpl* voe_impl = static_cast(voice_engine_); channel_proxy_ = voe_impl->GetChannelProxy(channel_); + channel_proxy_->RegisterLegacyCodecs(); ResumePlaying(); } diff --git a/webrtc/voice_engine/test/auto_test/standard/codec_before_streaming_test.cc b/webrtc/voice_engine/test/auto_test/standard/codec_before_streaming_test.cc index a733b12705..d9a5e2b794 100644 --- a/webrtc/voice_engine/test/auto_test/standard/codec_before_streaming_test.cc +++ b/webrtc/voice_engine/test/auto_test/standard/codec_before_streaming_test.cc @@ -8,7 +8,9 @@ * be found in the AUTHORS file in the root of the source tree. */ +#include "webrtc/voice_engine/channel_proxy.h" #include "webrtc/voice_engine/test/auto_test/fixtures/after_initialization_fixture.h" +#include "webrtc/voice_engine/voice_engine_impl.h" class CodecBeforeStreamingTest : public AfterInitializationFixture { protected: @@ -19,6 +21,9 @@ class CodecBeforeStreamingTest : public AfterInitializationFixture { codec_instance_.pacsize = 480; channel_ = voe_base_->CreateChannel(); + static_cast(voice_engine_) + ->GetChannelProxy(channel_) + ->RegisterLegacyCodecs(); } void TearDown() {