From 7add0584390dcfb236165a6472ede6c2a94eaeed Mon Sep 17 00:00:00 2001 From: solenberg Date: Fri, 20 Nov 2015 09:59:34 -0800 Subject: [PATCH] Move some receive stream configuration into webrtc::AudioReceiveStream. Simplify creation of VoE channels and Call streams in WVoMC. BUG=webrtc:4690 Review URL: https://codereview.webrtc.org/1454073002 Cr-Commit-Position: refs/heads/master@{#10731} --- talk/media/webrtc/fakewebrtcvoiceengine.h | 32 +- talk/media/webrtc/webrtcvoiceengine.cc | 323 +++++++----------- talk/media/webrtc/webrtcvoiceengine.h | 27 +- .../webrtc/webrtcvoiceengine_unittest.cc | 56 +-- webrtc/audio/audio_receive_stream.cc | 149 ++++---- webrtc/audio/audio_receive_stream.h | 2 + webrtc/audio/audio_receive_stream_unittest.cc | 22 +- 7 files changed, 274 insertions(+), 337 deletions(-) diff --git a/talk/media/webrtc/fakewebrtcvoiceengine.h b/talk/media/webrtc/fakewebrtcvoiceengine.h index 8ef57d34e9..f0bd6a6e85 100644 --- a/talk/media/webrtc/fakewebrtcvoiceengine.h +++ b/talk/media/webrtc/fakewebrtcvoiceengine.h @@ -188,8 +188,6 @@ class FakeWebRtcVoiceEngine red_type(117), nack_max_packets(0), send_ssrc(0), - receive_audio_level_ext_(-1), - receive_absolute_sender_time_ext_(-1), associate_send_channel(-1), neteq_capacity(-1), neteq_fast_accelerate(false) { @@ -211,8 +209,6 @@ class FakeWebRtcVoiceEngine int red_type; int nack_max_packets; uint32_t send_ssrc; - int receive_audio_level_ext_; - int receive_absolute_sender_time_ext_; int associate_send_channel; DtmfInfo dtmf_info; std::vector recv_codecs; @@ -352,15 +348,6 @@ class FakeWebRtcVoiceEngine channels_[++last_channel_] = ch; return last_channel_; } - int GetReceiveRtpExtensionId(int channel, const std::string& extension) { - WEBRTC_ASSERT_CHANNEL(channel); - if (extension == kRtpAudioLevelHeaderExtension) { - return channels_[channel]->receive_audio_level_ext_; - } else if (extension == kRtpAbsoluteSenderTimeHeaderExtension) { - return channels_[channel]->receive_absolute_sender_time_ext_; - } - return -1; - } int GetNumSetSendCodecs() const { return num_set_send_codecs_; } @@ -710,23 +697,12 @@ class FakeWebRtcVoiceEngine WEBRTC_STUB(GetRemoteSSRC, (int channel, unsigned int& ssrc)); WEBRTC_STUB(SetSendAudioLevelIndicationStatus, (int channel, bool enable, unsigned char id)); - WEBRTC_FUNC(SetReceiveAudioLevelIndicationStatus, (int channel, bool enable, - unsigned char id)) { - WEBRTC_CHECK_CHANNEL(channel); - WEBRTC_CHECK_HEADER_EXTENSION_ID(enable, id); - channels_[channel]->receive_audio_level_ext_ = (enable) ? id : -1; - return 0; - } + WEBRTC_STUB(SetReceiveAudioLevelIndicationStatus, (int channel, bool enable, + unsigned char id)); WEBRTC_STUB(SetSendAbsoluteSenderTimeStatus, (int channel, bool enable, unsigned char id)); - WEBRTC_FUNC(SetReceiveAbsoluteSenderTimeStatus, (int channel, bool enable, - unsigned char id)) { - WEBRTC_CHECK_CHANNEL(channel); - WEBRTC_CHECK_HEADER_EXTENSION_ID(enable, id); - channels_[channel]->receive_absolute_sender_time_ext_ = (enable) ? id : -1; - return 0; - } - + WEBRTC_STUB(SetReceiveAbsoluteSenderTimeStatus, (int channel, bool enable, + unsigned char id)); WEBRTC_STUB(SetRTCPStatus, (int channel, bool enable)); WEBRTC_STUB(GetRTCPStatus, (int channel, bool& enabled)); WEBRTC_STUB(SetRTCP_CNAME, (int channel, const char cname[256])); diff --git a/talk/media/webrtc/webrtcvoiceengine.cc b/talk/media/webrtc/webrtcvoiceengine.cc index d124305cd0..c81ecdf78e 100644 --- a/talk/media/webrtc/webrtcvoiceengine.cc +++ b/talk/media/webrtc/webrtcvoiceengine.cc @@ -1135,6 +1135,7 @@ bool WebRtcVoiceEngine::FindWebRtcCodec(const AudioCodec& in, } return false; } + const std::vector& WebRtcVoiceEngine::rtp_header_extensions() const { RTC_DCHECK(signal_thread_checker_.CalledOnValidThread()); @@ -1353,8 +1354,7 @@ class WebRtcVoiceMediaChannel::WebRtcAudioSendStream uint32_t ssrc, const std::string& c_name, const std::vector& extensions, webrtc::Call* call) - : channel_(ch), - voe_audio_transport_(voe_audio_transport), + : voe_audio_transport_(voe_audio_transport), call_(call), config_(nullptr) { RTC_DCHECK_GE(ch, 0); @@ -1429,7 +1429,7 @@ class WebRtcVoiceMediaChannel::WebRtcAudioSendStream RTC_DCHECK(!worker_thread_checker_.CalledOnValidThread()); RTC_DCHECK(audio_capture_thread_checker_.CalledOnValidThread()); RTC_DCHECK(voe_audio_transport_); - voe_audio_transport_->OnData(channel_, + voe_audio_transport_->OnData(config_.voe_channel_id, audio_data, bits_per_sample, sample_rate, @@ -1449,13 +1449,12 @@ class WebRtcVoiceMediaChannel::WebRtcAudioSendStream // Accessor to the VoE channel ID. int channel() const { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); - return channel_; + return config_.voe_channel_id; } private: rtc::ThreadChecker worker_thread_checker_; rtc::ThreadChecker audio_capture_thread_checker_; - const int channel_ = -1; webrtc::AudioTransport* const voe_audio_transport_ = nullptr; webrtc::Call* call_ = nullptr; webrtc::AudioSendStream::Config config_; @@ -1473,18 +1472,72 @@ class WebRtcVoiceMediaChannel::WebRtcAudioSendStream class WebRtcVoiceMediaChannel::WebRtcAudioReceiveStream { public: - explicit WebRtcAudioReceiveStream(int voe_channel_id) - : channel_(voe_channel_id) {} + WebRtcAudioReceiveStream(int ch, uint32_t remote_ssrc, uint32_t local_ssrc, + bool use_combined_bwe, const std::string& sync_group, + const std::vector& extensions, + webrtc::Call* call) + : call_(call), + config_() { + RTC_DCHECK_GE(ch, 0); + RTC_DCHECK(call); + config_.rtp.remote_ssrc = remote_ssrc; + config_.rtp.local_ssrc = local_ssrc; + config_.voe_channel_id = ch; + config_.sync_group = sync_group; + RecreateAudioReceiveStream(use_combined_bwe, extensions); + } - int channel() { return channel_; } + ~WebRtcAudioReceiveStream() { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + call_->DestroyAudioReceiveStream(stream_); + } + + void RecreateAudioReceiveStream( + const std::vector& extensions) { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + RecreateAudioReceiveStream(config_.combined_audio_video_bwe, extensions); + } + void RecreateAudioReceiveStream(bool use_combined_bwe) { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + RecreateAudioReceiveStream(use_combined_bwe, config_.rtp.extensions); + } + + webrtc::AudioReceiveStream::Stats GetStats() const { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + RTC_DCHECK(stream_); + return stream_->GetStats(); + } + + int channel() const { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + return config_.voe_channel_id; + } private: - int channel_; + void RecreateAudioReceiveStream(bool use_combined_bwe, + const std::vector& extensions) { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + if (stream_) { + call_->DestroyAudioReceiveStream(stream_); + stream_ = nullptr; + } + config_.rtp.extensions = extensions; + config_.combined_audio_video_bwe = use_combined_bwe; + RTC_DCHECK(!stream_); + stream_ = call_->CreateAudioReceiveStream(config_); + RTC_CHECK(stream_); + } + + rtc::ThreadChecker worker_thread_checker_; + webrtc::Call* call_ = nullptr; + webrtc::AudioReceiveStream::Config config_; + // The stream is owned by WebRtcAudioReceiveStream and may be reallocated if + // configuration changes. + webrtc::AudioReceiveStream* stream_ = nullptr; RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(WebRtcAudioReceiveStream); }; -// WebRtcVoiceMediaChannel WebRtcVoiceMediaChannel::WebRtcVoiceMediaChannel(WebRtcVoiceEngine* engine, const AudioOptions& options, webrtc::Call* call) @@ -1498,19 +1551,15 @@ WebRtcVoiceMediaChannel::WebRtcVoiceMediaChannel(WebRtcVoiceEngine* engine, WebRtcVoiceMediaChannel::~WebRtcVoiceMediaChannel() { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); LOG(LS_VERBOSE) << "WebRtcVoiceMediaChannel::~WebRtcVoiceMediaChannel"; - - // Remove any remaining send streams. + // TODO(solenberg): Should be able to delete the streams directly, without + // going through RemoveNnStream(), once stream objects handle + // all (de)configuration. while (!send_streams_.empty()) { RemoveSendStream(send_streams_.begin()->first); } - - // Remove any remaining receive streams. - while (!receive_channels_.empty()) { - RemoveRecvStream(receive_channels_.begin()->first); + while (!recv_streams_.empty()) { + RemoveRecvStream(recv_streams_.begin()->first); } - RTC_DCHECK(receive_streams_.empty()); - - // Unregister ourselves from the engine. engine()->UnregisterChannel(this); } @@ -1544,8 +1593,21 @@ bool WebRtcVoiceMediaChannel::SetRecvParameters( RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); // TODO(pthatcher): Refactor this to be more clean now that we have // all the information at once. - return (SetRecvCodecs(params.codecs) && - SetRecvRtpHeaderExtensions(params.extensions)); + + if (!SetRecvCodecs(params.codecs)) { + return false; + } + + std::vector recv_rtp_extensions = + FindAudioRtpHeaderExtensions(params.extensions); + if (recv_rtp_extensions_ != recv_rtp_extensions) { + recv_rtp_extensions_.swap(recv_rtp_extensions); + for (auto& it : recv_streams_) { + it.second->RecreateAudioReceiveStream(recv_rtp_extensions_); + } + } + + return true; } bool WebRtcVoiceMediaChannel::SetOptions(const AudioOptions& options) { @@ -1579,7 +1641,10 @@ bool WebRtcVoiceMediaChannel::SetOptions(const AudioOptions& options) { } // TODO(solenberg): Don't recreate unless options changed. - RecreateAudioReceiveStreams(); + for (auto& it : recv_streams_) { + it.second->RecreateAudioReceiveStream( + options_.combined_audio_video_bwe.value_or(false)); + } LOG(LS_INFO) << "Set voice channel options. Current options: " << options_.ToString(); @@ -1865,7 +1930,7 @@ bool WebRtcVoiceMediaChannel::SetSendCodecs( } // Set nack status on receive channels and update |nack_enabled_|. - for (const auto& ch : receive_channels_) { + for (const auto& ch : recv_streams_) { SetNack(ch.second->channel(), nack_enabled_); } @@ -1901,49 +1966,6 @@ bool WebRtcVoiceMediaChannel::SetSendCodec( return true; } -bool WebRtcVoiceMediaChannel::SetRecvRtpHeaderExtensions( - const std::vector& extensions) { - RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); - if (receive_extensions_ == extensions) { - return true; - } - - for (const auto& ch : receive_channels_) { - if (!SetChannelRecvRtpHeaderExtensions(ch.second->channel(), extensions)) { - return false; - } - } - - receive_extensions_ = extensions; - - // Recreate AudioReceiveStream:s. - recv_rtp_extensions_ = FindAudioRtpHeaderExtensions(extensions); - RecreateAudioReceiveStreams(); - - return true; -} - -bool WebRtcVoiceMediaChannel::SetChannelRecvRtpHeaderExtensions( - int channel_id, const std::vector& extensions) { - const RtpHeaderExtension* audio_level_extension = - FindHeaderExtension(extensions, kRtpAudioLevelHeaderExtension); - if (!SetHeaderExtension( - &webrtc::VoERTP_RTCP::SetReceiveAudioLevelIndicationStatus, channel_id, - audio_level_extension)) { - return false; - } - - const RtpHeaderExtension* send_time_extension = - FindHeaderExtension(extensions, kRtpAbsoluteSenderTimeHeaderExtension); - if (!SetHeaderExtension( - &webrtc::VoERTP_RTCP::SetReceiveAbsoluteSenderTimeStatus, channel_id, - send_time_extension)) { - return false; - } - - return true; -} - bool WebRtcVoiceMediaChannel::SetPlayout(bool playout) { desired_playout_ = playout; return ChangePlayout(desired_playout_); @@ -1963,7 +1985,7 @@ bool WebRtcVoiceMediaChannel::ChangePlayout(bool playout) { return true; } - for (const auto& ch : receive_channels_) { + for (const auto& ch : recv_streams_) { if (!SetPlayout(ch.second->channel(), playout)) { LOG(LS_ERROR) << "SetPlayout " << playout << " on channel " << ch.second->channel() << " failed"; @@ -2068,7 +2090,7 @@ int WebRtcVoiceMediaChannel::CreateVoEChannel() { return id; } -bool WebRtcVoiceMediaChannel::DeleteChannel(int channel) { +bool WebRtcVoiceMediaChannel::DeleteVoEChannel(int channel) { if (engine()->voe()->network()->DeRegisterExternalTransport(channel) == -1) { LOG_RTCERR1(DeRegisterExternalTransport, channel); } @@ -2117,10 +2139,10 @@ bool WebRtcVoiceMediaChannel::AddSendStream(const StreamParams& sp) { // with the same SSRC in order to send receiver reports. if (send_streams_.size() == 1) { receiver_reports_ssrc_ = ssrc; - for (const auto& ch : receive_channels_) { - int recv_channel = ch.second->channel(); + for (const auto& stream : recv_streams_) { + int recv_channel = stream.second->channel(); if (engine()->voe()->rtp()->SetLocalSSRC(recv_channel, ssrc) != 0) { - LOG_RTCERR2(SetLocalSSRC, ch.second->channel(), ssrc); + LOG_RTCERR2(SetLocalSSRC, recv_channel, ssrc); return false; } engine()->voe()->base()->AssociateSendChannel(recv_channel, channel); @@ -2146,15 +2168,12 @@ bool WebRtcVoiceMediaChannel::RemoveSendStream(uint32_t ssrc) { int channel = it->second->channel(); ChangeSend(channel, SEND_NOTHING); - // Delete the WebRtcVoiceChannelRenderer object connected to the channel, - // this will disconnect the audio renderer with the send channel. - delete it->second; - send_streams_.erase(it); - - // Clean up and delete the send channel. + // Clean up and delete the send stream+channel. LOG(LS_INFO) << "Removing audio send stream " << ssrc << " with VoiceEngine channel #" << channel << "."; - if (!DeleteChannel(channel)) { + delete it->second; + send_streams_.erase(it); + if (!DeleteVoEChannel(channel)) { return false; } if (send_streams_.empty()) { @@ -2171,7 +2190,7 @@ bool WebRtcVoiceMediaChannel::AddRecvStream(const StreamParams& sp) { return false; } - uint32_t ssrc = sp.first_ssrc(); + const uint32_t ssrc = sp.first_ssrc(); if (ssrc == 0) { LOG(LS_WARNING) << "AddRecvStream with ssrc==0 is not supported."; return false; @@ -2183,52 +2202,19 @@ bool WebRtcVoiceMediaChannel::AddRecvStream(const StreamParams& sp) { RemoveRecvStream(ssrc); } - if (receive_channels_.find(ssrc) != receive_channels_.end()) { + if (GetReceiveChannelId(ssrc) != -1) { LOG(LS_ERROR) << "Stream already exists with ssrc " << ssrc; return false; } - RTC_DCHECK(receive_stream_params_.find(ssrc) == receive_stream_params_.end()); // Create a new channel for receiving audio data. - int channel = CreateVoEChannel(); + const int channel = CreateVoEChannel(); if (channel == -1) { return false; } - if (!ConfigureRecvChannel(channel)) { - DeleteChannel(channel); - return false; - } - - WebRtcAudioReceiveStream* stream = new WebRtcAudioReceiveStream(channel); - receive_channels_.insert(std::make_pair(ssrc, stream)); - receive_stream_params_[ssrc] = sp; - AddAudioReceiveStream(ssrc); - - LOG(LS_INFO) << "New audio stream " << ssrc - << " registered to VoiceEngine channel #" - << channel << "."; - return true; -} - -bool WebRtcVoiceMediaChannel::ConfigureRecvChannel(int channel) { - RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); - - int send_channel = GetSendChannelId(receiver_reports_ssrc_); - if (send_channel != -1) { - // Associate receive channel with first send channel (so the receive channel - // can obtain RTT from the send channel) - engine()->voe()->base()->AssociateSendChannel(channel, send_channel); - LOG(LS_INFO) << "VoiceEngine channel #" << channel - << " is associated with channel #" << send_channel << "."; - } - if (engine()->voe()->rtp()->SetLocalSSRC(channel, - receiver_reports_ssrc_) == -1) { - LOG_RTCERR1(SetLocalSSRC, channel); - return false; - } // Turn off all supported codecs. - int ncodecs = engine()->voe()->codec()->NumOfCodecs(); + const int ncodecs = engine()->voe()->codec()->NumOfCodecs(); for (int i = 0; i < ncodecs; ++i) { webrtc::CodecInst voe_codec; if (engine()->voe()->codec()->GetCodec(i, voe_codec) != -1) { @@ -2236,6 +2222,7 @@ bool WebRtcVoiceMediaChannel::ConfigureRecvChannel(int channel) { if (engine()->voe()->codec()->SetRecPayloadType( channel, voe_codec) == -1) { LOG_RTCERR2(SetRecPayloadType, channel, ToString(voe_codec)); + DeleteVoEChannel(channel); return false; } } @@ -2249,19 +2236,29 @@ bool WebRtcVoiceMediaChannel::ConfigureRecvChannel(int channel) { if (engine()->voe()->codec()->SetRecPayloadType( channel, voe_codec) == -1) { LOG_RTCERR2(SetRecPayloadType, channel, ToString(voe_codec)); + DeleteVoEChannel(channel); return false; } } } - SetNack(channel, nack_enabled_); - - // Set RTP header extension for the new channel. - if (!SetChannelRecvRtpHeaderExtensions(channel, receive_extensions_)) { - return false; + const int send_channel = GetSendChannelId(receiver_reports_ssrc_); + if (send_channel != -1) { + // Associate receive channel with first send channel (so the receive channel + // can obtain RTT from the send channel) + engine()->voe()->base()->AssociateSendChannel(channel, send_channel); + LOG(LS_INFO) << "VoiceEngine channel #" << channel + << " is associated with channel #" << send_channel << "."; } + recv_streams_.insert(std::make_pair(ssrc, new WebRtcAudioReceiveStream( + channel, ssrc, receiver_reports_ssrc_, + options_.combined_audio_video_bwe.value_or(false), sp.sync_label, + recv_rtp_extensions_, call_))); + + SetNack(channel, nack_enabled_); SetPlayout(channel, playout_); + return true; } @@ -2269,28 +2266,26 @@ bool WebRtcVoiceMediaChannel::RemoveRecvStream(uint32_t ssrc) { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); LOG(LS_INFO) << "RemoveRecvStream: " << ssrc; - auto it = receive_channels_.find(ssrc); - if (it == receive_channels_.end()) { + const auto it = recv_streams_.find(ssrc); + if (it == recv_streams_.end()) { LOG(LS_WARNING) << "Try to remove stream with ssrc " << ssrc << " which doesn't exist."; return false; } - RemoveAudioReceiveStream(ssrc); - receive_stream_params_.erase(ssrc); - - const int channel = it->second->channel(); - delete it->second; - receive_channels_.erase(it); - // Deregister default channel, if that's the one being destroyed. if (IsDefaultRecvStream(ssrc)) { default_recv_ssrc_ = -1; } - LOG(LS_INFO) << "Removing audio stream " << ssrc + const int channel = it->second->channel(); + + // Clean up and delete the receive stream+channel. + LOG(LS_INFO) << "Removing audio receive stream " << ssrc << " with VoiceEngine channel #" << channel << "."; - return DeleteChannel(channel); + delete it->second; + recv_streams_.erase(it); + return DeleteVoEChannel(channel); } bool WebRtcVoiceMediaChannel::SetLocalRenderer(uint32_t ssrc, @@ -2320,7 +2315,7 @@ bool WebRtcVoiceMediaChannel::GetActiveStreams( AudioInfo::StreamList* actives) { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); actives->clear(); - for (const auto& ch : receive_channels_) { + for (const auto& ch : recv_streams_) { int level = GetOutputLevel(ch.second->channel()); if (level > 0) { actives->push_back(std::make_pair(ch.first, level)); @@ -2332,7 +2327,7 @@ bool WebRtcVoiceMediaChannel::GetActiveStreams( int WebRtcVoiceMediaChannel::GetOutputLevel() { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); int highest = 0; - for (const auto& ch : receive_channels_) { + for (const auto& ch : recv_streams_) { highest = std::max(GetOutputLevel(ch.second->channel()), highest); } return highest; @@ -2647,7 +2642,7 @@ bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) { // Get SSRC and stats for each receiver. RTC_DCHECK(info->receivers.size() == 0); - for (const auto& stream : receive_streams_) { + for (const auto& stream : recv_streams_) { webrtc::AudioReceiveStream::Stats stats = stream.second->GetStats(); VoiceReceiverInfo rinfo; rinfo.add_ssrc(stats.remote_ssrc); @@ -2689,8 +2684,8 @@ int WebRtcVoiceMediaChannel::GetOutputLevel(int channel) { int WebRtcVoiceMediaChannel::GetReceiveChannelId(uint32_t ssrc) const { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); - const auto it = receive_channels_.find(ssrc); - if (it != receive_channels_.end()) { + const auto it = recv_streams_.find(ssrc); + if (it != recv_streams_.end()) { return it->second->channel(); } return -1; @@ -2763,59 +2758,6 @@ bool WebRtcVoiceMediaChannel::SetPlayout(int channel, bool playout) { return true; } -bool WebRtcVoiceMediaChannel::SetHeaderExtension(ExtensionSetterFunction setter, - int channel_id, const RtpHeaderExtension* extension) { - bool enable = false; - int id = 0; - std::string uri; - if (extension) { - enable = true; - id = extension->id; - uri = extension->uri; - } - if ((engine()->voe()->rtp()->*setter)(channel_id, enable, id) != 0) { - LOG_RTCERR4(*setter, uri, channel_id, enable, id); - return false; - } - return true; -} - -void WebRtcVoiceMediaChannel::RecreateAudioReceiveStreams() { - RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); - for (const auto& it : receive_channels_) { - RemoveAudioReceiveStream(it.first); - } - for (const auto& it : receive_channels_) { - AddAudioReceiveStream(it.first); - } -} - -void WebRtcVoiceMediaChannel::AddAudioReceiveStream(uint32_t ssrc) { - RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); - WebRtcAudioReceiveStream* stream = receive_channels_[ssrc]; - RTC_DCHECK(stream != nullptr); - RTC_DCHECK(receive_streams_.find(ssrc) == receive_streams_.end()); - webrtc::AudioReceiveStream::Config config; - config.rtp.remote_ssrc = ssrc; - // Only add RTP extensions if we support combined A/V BWE. - config.rtp.extensions = recv_rtp_extensions_; - config.combined_audio_video_bwe = - options_.combined_audio_video_bwe.value_or(false); - config.voe_channel_id = stream->channel(); - config.sync_group = receive_stream_params_[ssrc].sync_label; - webrtc::AudioReceiveStream* s = call_->CreateAudioReceiveStream(config); - receive_streams_.insert(std::make_pair(ssrc, s)); -} - -void WebRtcVoiceMediaChannel::RemoveAudioReceiveStream(uint32_t ssrc) { - RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); - auto stream_it = receive_streams_.find(ssrc); - if (stream_it != receive_streams_.end()) { - call_->DestroyAudioReceiveStream(stream_it->second); - receive_streams_.erase(stream_it); - } -} - bool WebRtcVoiceMediaChannel::SetRecvCodecsInternal( const std::vector& new_codecs) { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); @@ -2824,7 +2766,7 @@ bool WebRtcVoiceMediaChannel::SetRecvCodecsInternal( if (engine()->FindWebRtcCodec(codec, &voe_codec)) { LOG(LS_INFO) << ToString(codec); voe_codec.pltype = codec.id; - for (const auto& ch : receive_channels_) { + for (const auto& ch : recv_streams_) { if (engine()->voe()->codec()->SetRecPayloadType( ch.second->channel(), voe_codec) == -1) { LOG_RTCERR2(SetRecPayloadType, ch.second->channel(), @@ -2839,7 +2781,6 @@ bool WebRtcVoiceMediaChannel::SetRecvCodecsInternal( } return true; } - } // namespace cricket #endif // HAVE_WEBRTC_VOICE diff --git a/talk/media/webrtc/webrtcvoiceengine.h b/talk/media/webrtc/webrtcvoiceengine.h index 2f74dabd0f..c26aa063a8 100644 --- a/talk/media/webrtc/webrtcvoiceengine.h +++ b/talk/media/webrtc/webrtcvoiceengine.h @@ -248,8 +248,6 @@ class WebRtcVoiceMediaChannel final : public VoiceMediaChannel, bool SetOptions(const AudioOptions& options); bool SetMaxSendBandwidth(int bps); bool SetRecvCodecs(const std::vector& codecs); - bool SetRecvRtpHeaderExtensions( - const std::vector& extensions); bool SetLocalRenderer(uint32_t ssrc, AudioRenderer* renderer); bool MuteStream(uint32_t ssrc, bool mute); @@ -260,35 +258,20 @@ class WebRtcVoiceMediaChannel final : public VoiceMediaChannel, const std::vector& all_codecs, webrtc::CodecInst* send_codec); bool SetPlayout(int channel, bool playout); - - typedef int (webrtc::VoERTP_RTCP::* ExtensionSetterFunction)(int, bool, - unsigned char); - void SetNack(int channel, bool nack_enabled); bool SetSendCodec(int channel, const webrtc::CodecInst& send_codec); bool ChangePlayout(bool playout); bool ChangeSend(SendFlags send); bool ChangeSend(int channel, SendFlags send); - bool ConfigureRecvChannel(int channel); int CreateVoEChannel(); - bool DeleteChannel(int channel); + bool DeleteVoEChannel(int channel); bool IsDefaultRecvStream(uint32_t ssrc) { return default_recv_ssrc_ == static_cast(ssrc); } bool SetSendCodecs(int channel, const std::vector& codecs); bool SetSendBitrateInternal(int bps); - - bool SetHeaderExtension(ExtensionSetterFunction setter, int channel_id, - const RtpHeaderExtension* extension); - void RecreateAudioReceiveStreams(); - void AddAudioReceiveStream(uint32_t ssrc); - void RemoveAudioReceiveStream(uint32_t ssrc); bool SetRecvCodecsInternal(const std::vector& new_codecs); - bool SetChannelRecvRtpHeaderExtensions( - int channel_id, - const std::vector& extensions); - rtc::ThreadChecker worker_thread_checker_; WebRtcVoiceEngine* const engine_ = nullptr; @@ -320,13 +303,7 @@ class WebRtcVoiceMediaChannel final : public VoiceMediaChannel, std::vector send_rtp_extensions_; class WebRtcAudioReceiveStream; - std::map receive_channels_; - std::map receive_streams_; - std::map receive_stream_params_; - // receive_channels_ can be read from WebRtc callback thread. Access from - // the WebRtc thread must be synchronized with edits on the worker thread. - // Reads on the worker thread are ok. - std::vector receive_extensions_; + std::map recv_streams_; std::vector recv_rtp_extensions_; RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(WebRtcVoiceMediaChannel); diff --git a/talk/media/webrtc/webrtcvoiceengine_unittest.cc b/talk/media/webrtc/webrtcvoiceengine_unittest.cc index 2322e1089f..630983344c 100644 --- a/talk/media/webrtc/webrtcvoiceengine_unittest.cc +++ b/talk/media/webrtc/webrtcvoiceengine_unittest.cc @@ -144,6 +144,12 @@ class WebRtcVoiceEngineTestFake : public testing::Test { return send_stream->GetConfig(); } + const webrtc::AudioReceiveStream::Config& GetRecvStreamConfig(uint32_t ssrc) { + const auto* recv_stream = call_.GetAudioReceiveStream(ssrc); + EXPECT_TRUE(recv_stream); + return recv_stream->GetConfig(); + } + void TestInsertDtmf(uint32_t ssrc, bool caller) { EXPECT_TRUE(engine_.Init(rtc::Thread::Current())); channel_ = engine_.CreateChannel(&call_, cricket::AudioOptions()); @@ -239,7 +245,7 @@ class WebRtcVoiceEngineTestFake : public testing::Test { EXPECT_EQ(ext, GetSendStreamConfig(kSsrc1).rtp.extensions[0].name); EXPECT_EQ(id, GetSendStreamConfig(kSsrc1).rtp.extensions[0].id); - // Ensure extension is set properly on new channels. + // Ensure extension is set properly on new stream. EXPECT_TRUE(channel_->AddSendStream( cricket::StreamParams::CreateLegacy(kSsrc2))); EXPECT_NE(call_.GetAudioSendStream(kSsrc1), @@ -258,42 +264,43 @@ class WebRtcVoiceEngineTestFake : public testing::Test { void TestSetRecvRtpHeaderExtensions(const std::string& ext) { EXPECT_TRUE(SetupEngineWithRecvStream()); - int channel_num = voe_.GetLastChannel(); // Ensure extensions are off by default. - EXPECT_EQ(-1, voe_.GetReceiveRtpExtensionId(channel_num, ext)); + EXPECT_EQ(0u, GetRecvStreamConfig(kSsrc1).rtp.extensions.size()); - cricket::AudioRecvParameters parameters; // Ensure unknown extensions won't cause an error. - parameters.extensions.push_back(cricket::RtpHeaderExtension( + recv_parameters_.extensions.push_back(cricket::RtpHeaderExtension( "urn:ietf:params:unknownextention", 1)); - EXPECT_TRUE(channel_->SetRecvParameters(parameters)); - EXPECT_EQ(-1, voe_.GetReceiveRtpExtensionId(channel_num, ext)); + EXPECT_TRUE(channel_->SetRecvParameters(recv_parameters_)); + EXPECT_EQ(0u, GetRecvStreamConfig(kSsrc1).rtp.extensions.size()); // Ensure extensions stay off with an empty list of headers. - parameters.extensions.clear(); - EXPECT_TRUE(channel_->SetRecvParameters(parameters)); - EXPECT_EQ(-1, voe_.GetReceiveRtpExtensionId(channel_num, ext)); + recv_parameters_.extensions.clear(); + EXPECT_TRUE(channel_->SetRecvParameters(recv_parameters_)); + EXPECT_EQ(0u, GetRecvStreamConfig(kSsrc1).rtp.extensions.size()); // Ensure extension is set properly. const int id = 2; - parameters.extensions.push_back(cricket::RtpHeaderExtension(ext, id)); - EXPECT_TRUE(channel_->SetRecvParameters(parameters)); - EXPECT_EQ(id, voe_.GetReceiveRtpExtensionId(channel_num, ext)); + recv_parameters_.extensions.push_back(cricket::RtpHeaderExtension(ext, id)); + EXPECT_TRUE(channel_->SetRecvParameters(recv_parameters_)); + EXPECT_EQ(1u, GetRecvStreamConfig(kSsrc1).rtp.extensions.size()); + EXPECT_EQ(ext, GetRecvStreamConfig(kSsrc1).rtp.extensions[0].name); + EXPECT_EQ(id, GetRecvStreamConfig(kSsrc1).rtp.extensions[0].id); - // Ensure extension is set properly on new channel. - // The first stream to occupy the default channel. + // Ensure extension is set properly on new stream. EXPECT_TRUE(channel_->AddRecvStream( cricket::StreamParams::CreateLegacy(kSsrc2))); - int new_channel_num = voe_.GetLastChannel(); - EXPECT_NE(channel_num, new_channel_num); - EXPECT_EQ(id, voe_.GetReceiveRtpExtensionId(new_channel_num, ext)); + EXPECT_NE(call_.GetAudioReceiveStream(kSsrc1), + call_.GetAudioReceiveStream(kSsrc2)); + EXPECT_EQ(1u, GetRecvStreamConfig(kSsrc2).rtp.extensions.size()); + EXPECT_EQ(ext, GetRecvStreamConfig(kSsrc2).rtp.extensions[0].name); + EXPECT_EQ(id, GetRecvStreamConfig(kSsrc2).rtp.extensions[0].id); // Ensure all extensions go back off with an empty list. - parameters.extensions.clear(); - EXPECT_TRUE(channel_->SetRecvParameters(parameters)); - EXPECT_EQ(-1, voe_.GetReceiveRtpExtensionId(channel_num, ext)); - EXPECT_EQ(-1, voe_.GetReceiveRtpExtensionId(new_channel_num, ext)); + recv_parameters_.extensions.clear(); + EXPECT_TRUE(channel_->SetRecvParameters(recv_parameters_)); + EXPECT_EQ(0u, GetRecvStreamConfig(kSsrc1).rtp.extensions.size()); + EXPECT_EQ(0u, GetRecvStreamConfig(kSsrc2).rtp.extensions.size()); } webrtc::AudioSendStream::Stats GetAudioSendStreamStats() const { @@ -2402,8 +2409,9 @@ TEST_F(WebRtcVoiceEngineTestFake, GetStats) { TEST_F(WebRtcVoiceEngineTestFake, SetSendSsrcWithMultipleStreams) { EXPECT_TRUE(SetupEngineWithSendStream()); EXPECT_TRUE(call_.GetAudioSendStream(kSsrc1)); - EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(2))); - EXPECT_EQ(kSsrc1, voe_.GetLocalSSRC(voe_.GetLastChannel())); + EXPECT_TRUE(channel_->AddRecvStream( + cricket::StreamParams::CreateLegacy(kSsrc2))); + EXPECT_EQ(kSsrc1, GetRecvStreamConfig(kSsrc2).rtp.local_ssrc); } // Test that the local SSRC is the same on sending and receiving channels if the diff --git a/webrtc/audio/audio_receive_stream.cc b/webrtc/audio/audio_receive_stream.cc index bdccea2c37..82e8ddfb22 100644 --- a/webrtc/audio/audio_receive_stream.cc +++ b/webrtc/audio/audio_receive_stream.cc @@ -73,19 +73,35 @@ AudioReceiveStream::AudioReceiveStream( RTC_DCHECK(remote_bitrate_estimator_); RTC_DCHECK(audio_state_.get()); RTC_DCHECK(rtp_header_parser_); - for (const auto& ext : config.rtp.extensions) { + + const int channel_id = config.voe_channel_id; + ScopedVoEInterface rtp(voice_engine()); + int error = rtp->SetLocalSSRC(channel_id, config.rtp.local_ssrc); + RTC_DCHECK_EQ(0, error); + for (const auto& extension : config.rtp.extensions) { // One-byte-extension local identifiers are in the range 1-14 inclusive. - RTC_DCHECK_GE(ext.id, 1); - RTC_DCHECK_LE(ext.id, 14); - if (ext.name == RtpExtension::kAudioLevel) { - RTC_CHECK(rtp_header_parser_->RegisterRtpHeaderExtension( - kRtpExtensionAudioLevel, ext.id)); - } else if (ext.name == RtpExtension::kAbsSendTime) { - RTC_CHECK(rtp_header_parser_->RegisterRtpHeaderExtension( - kRtpExtensionAbsoluteSendTime, ext.id)); - } else if (ext.name == RtpExtension::kTransportSequenceNumber) { - RTC_CHECK(rtp_header_parser_->RegisterRtpHeaderExtension( - kRtpExtensionTransportSequenceNumber, ext.id)); + RTC_DCHECK_GE(extension.id, 1); + RTC_DCHECK_LE(extension.id, 14); + if (extension.name == RtpExtension::kAudioLevel) { + error = rtp->SetReceiveAudioLevelIndicationStatus(channel_id, true, + extension.id); + RTC_DCHECK_EQ(0, error); + bool registered = rtp_header_parser_->RegisterRtpHeaderExtension( + kRtpExtensionAudioLevel, extension.id); + RTC_DCHECK(registered); + } else if (extension.name == RtpExtension::kAbsSendTime) { + error = rtp->SetReceiveAbsoluteSenderTimeStatus(channel_id, true, + extension.id); + RTC_DCHECK_EQ(0, error); + bool registered = rtp_header_parser_->RegisterRtpHeaderExtension( + kRtpExtensionAbsoluteSendTime, extension.id); + RTC_DCHECK(registered); + } else if (extension.name == RtpExtension::kTransportSequenceNumber) { + // TODO(holmer): Need to do something here or in DeliverRtp() to actually + // handle audio packets with this header extension. + bool registered = rtp_header_parser_->RegisterRtpHeaderExtension( + kRtpExtensionTransportSequenceNumber, extension.id); + RTC_DCHECK(registered); } else { RTC_NOTREACHED() << "Unsupported RTP extension."; } @@ -97,18 +113,61 @@ AudioReceiveStream::~AudioReceiveStream() { LOG(LS_INFO) << "~AudioReceiveStream: " << config_.ToString(); } +void AudioReceiveStream::Start() { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); +} + +void AudioReceiveStream::Stop() { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); +} + +void AudioReceiveStream::SignalNetworkState(NetworkState state) { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); +} + +bool AudioReceiveStream::DeliverRtcp(const uint8_t* packet, size_t length) { + // TODO(solenberg): Tests call this function on a network thread, libjingle + // calls on the worker thread. We should move towards always using a network + // thread. Then this check can be enabled. + // RTC_DCHECK(!thread_checker_.CalledOnValidThread()); + return false; +} + +bool AudioReceiveStream::DeliverRtp(const uint8_t* packet, + size_t length, + const PacketTime& packet_time) { + // TODO(solenberg): Tests call this function on a network thread, libjingle + // calls on the worker thread. We should move towards always using a network + // thread. Then this check can be enabled. + // RTC_DCHECK(!thread_checker_.CalledOnValidThread()); + RTPHeader header; + if (!rtp_header_parser_->Parse(packet, length, &header)) { + return false; + } + + // Only forward if the parsed header has absolute sender time. RTP timestamps + // may have different rates for audio and video and shouldn't be mixed. + if (config_.combined_audio_video_bwe && + header.extension.hasAbsoluteSendTime) { + int64_t arrival_time_ms = TickTime::MillisecondTimestamp(); + if (packet_time.timestamp >= 0) + arrival_time_ms = (packet_time.timestamp + 500) / 1000; + size_t payload_size = length - header.headerLength; + remote_bitrate_estimator_->IncomingPacket(arrival_time_ms, payload_size, + header, false); + } + return true; +} + webrtc::AudioReceiveStream::Stats AudioReceiveStream::GetStats() const { RTC_DCHECK(thread_checker_.CalledOnValidThread()); webrtc::AudioReceiveStream::Stats stats; stats.remote_ssrc = config_.rtp.remote_ssrc; - internal::AudioState* audio_state = - static_cast(audio_state_.get()); - VoiceEngine* voice_engine = audio_state->voice_engine(); - ScopedVoEInterface codec(voice_engine); - ScopedVoEInterface neteq(voice_engine); - ScopedVoEInterface rtp(voice_engine); - ScopedVoEInterface sync(voice_engine); - ScopedVoEInterface volume(voice_engine); + ScopedVoEInterface codec(voice_engine()); + ScopedVoEInterface neteq(voice_engine()); + ScopedVoEInterface rtp(voice_engine()); + ScopedVoEInterface sync(voice_engine()); + ScopedVoEInterface volume(voice_engine()); webrtc::CallStatistics call_stats = {0}; int error = rtp->GetRTCPStatistics(config_.voe_channel_id, call_stats); @@ -175,50 +234,12 @@ const webrtc::AudioReceiveStream::Config& AudioReceiveStream::config() const { return config_; } -void AudioReceiveStream::Start() { - RTC_DCHECK(thread_checker_.CalledOnValidThread()); -} - -void AudioReceiveStream::Stop() { - RTC_DCHECK(thread_checker_.CalledOnValidThread()); -} - -void AudioReceiveStream::SignalNetworkState(NetworkState state) { - RTC_DCHECK(thread_checker_.CalledOnValidThread()); -} - -bool AudioReceiveStream::DeliverRtcp(const uint8_t* packet, size_t length) { - // TODO(solenberg): Tests call this function on a network thread, libjingle - // calls on the worker thread. We should move towards always using a network - // thread. Then this check can be enabled. - // RTC_DCHECK(!thread_checker_.CalledOnValidThread()); - return false; -} - -bool AudioReceiveStream::DeliverRtp(const uint8_t* packet, - size_t length, - const PacketTime& packet_time) { - // TODO(solenberg): Tests call this function on a network thread, libjingle - // calls on the worker thread. We should move towards always using a network - // thread. Then this check can be enabled. - // RTC_DCHECK(!thread_checker_.CalledOnValidThread()); - RTPHeader header; - if (!rtp_header_parser_->Parse(packet, length, &header)) { - return false; - } - - // Only forward if the parsed header has absolute sender time. RTP timestamps - // may have different rates for audio and video and shouldn't be mixed. - if (config_.combined_audio_video_bwe && - header.extension.hasAbsoluteSendTime) { - int64_t arrival_time_ms = TickTime::MillisecondTimestamp(); - if (packet_time.timestamp >= 0) - arrival_time_ms = (packet_time.timestamp + 500) / 1000; - size_t payload_size = length - header.headerLength; - remote_bitrate_estimator_->IncomingPacket(arrival_time_ms, payload_size, - header, false); - } - return true; +VoiceEngine* AudioReceiveStream::voice_engine() const { + internal::AudioState* audio_state = + static_cast(audio_state_.get()); + VoiceEngine* voice_engine = audio_state->voice_engine(); + RTC_DCHECK(voice_engine); + return voice_engine; } } // namespace internal } // namespace webrtc diff --git a/webrtc/audio/audio_receive_stream.h b/webrtc/audio/audio_receive_stream.h index a461aadc5f..e7a2952a2a 100644 --- a/webrtc/audio/audio_receive_stream.h +++ b/webrtc/audio/audio_receive_stream.h @@ -44,6 +44,8 @@ class AudioReceiveStream final : public webrtc::AudioReceiveStream { const webrtc::AudioReceiveStream::Config& config() const; private: + VoiceEngine* voice_engine() const; + rtc::ThreadChecker thread_checker_; RemoteBitrateEstimator* const remote_bitrate_estimator_; const webrtc::AudioReceiveStream::Config config_; diff --git a/webrtc/audio/audio_receive_stream_unittest.cc b/webrtc/audio/audio_receive_stream_unittest.cc index 715b52a592..5efd5b0e1c 100644 --- a/webrtc/audio/audio_receive_stream_unittest.cc +++ b/webrtc/audio/audio_receive_stream_unittest.cc @@ -38,7 +38,8 @@ const int kChannelId = 2; const uint32_t kRemoteSsrc = 1234; const uint32_t kLocalSsrc = 5678; const size_t kAbsoluteSendTimeLength = 4; -const int kAbsSendTimeId = 3; +const int kAbsSendTimeId = 2; +const int kAudioLevelId = 3; const int kJitterBufferDelay = -7; const int kPlayoutBufferDelay = 302; const unsigned int kSpeechOutputLevel = 99; @@ -59,10 +60,23 @@ struct ConfigHelper { AudioState::Config config; config.voice_engine = &voice_engine_; audio_state_ = AudioState::Create(config); + + EXPECT_CALL(voice_engine_, SetLocalSSRC(kChannelId, kLocalSsrc)) + .WillOnce(Return(0)); + EXPECT_CALL(voice_engine_, + SetReceiveAbsoluteSenderTimeStatus(kChannelId, true, kAbsSendTimeId)) + .WillOnce(Return(0)); + EXPECT_CALL(voice_engine_, + SetReceiveAudioLevelIndicationStatus(kChannelId, true, kAudioLevelId)) + .WillOnce(Return(0)); stream_config_.voe_channel_id = kChannelId; stream_config_.rtp.local_ssrc = kLocalSsrc; stream_config_.rtp.remote_ssrc = kRemoteSsrc; - } + stream_config_.rtp.extensions.push_back( + RtpExtension(RtpExtension::kAbsSendTime, kAbsSendTimeId)); + stream_config_.rtp.extensions.push_back( + RtpExtension(RtpExtension::kAudioLevel, kAudioLevelId)); +} MockRemoteBitrateEstimator* remote_bitrate_estimator() { return &remote_bitrate_estimator_; @@ -144,7 +158,7 @@ TEST(AudioReceiveStreamTest, ConfigToString) { config.combined_audio_video_bwe = true; EXPECT_EQ( "{rtp: {remote_ssrc: 1234, local_ssrc: 5678, extensions: [{name: " - "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time, id: 3}]}, " + "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time, id: 2}]}, " "receive_transport: nullptr, rtcp_send_transport: nullptr, " "voe_channel_id: 2, combined_audio_video_bwe: true}", config.ToString()); @@ -159,8 +173,6 @@ TEST(AudioReceiveStreamTest, ConstructDestruct) { TEST(AudioReceiveStreamTest, AudioPacketUpdatesBweWithTimestamp) { ConfigHelper helper; helper.config().combined_audio_video_bwe = true; - helper.config().rtp.extensions.push_back( - RtpExtension(RtpExtension::kAbsSendTime, kAbsSendTimeId)); internal::AudioReceiveStream recv_stream( helper.remote_bitrate_estimator(), helper.config(), helper.audio_state()); uint8_t rtp_packet[30];