diff --git a/talk/media/webrtc/fakewebrtcvoiceengine.h b/talk/media/webrtc/fakewebrtcvoiceengine.h index d031d10411..8ef57d34e9 100644 --- a/talk/media/webrtc/fakewebrtcvoiceengine.h +++ b/talk/media/webrtc/fakewebrtcvoiceengine.h @@ -188,9 +188,7 @@ class FakeWebRtcVoiceEngine red_type(117), nack_max_packets(0), send_ssrc(0), - send_audio_level_ext_(-1), receive_audio_level_ext_(-1), - send_absolute_sender_time_ext_(-1), receive_absolute_sender_time_ext_(-1), associate_send_channel(-1), neteq_capacity(-1), @@ -213,9 +211,7 @@ class FakeWebRtcVoiceEngine int red_type; int nack_max_packets; uint32_t send_ssrc; - int send_audio_level_ext_; int receive_audio_level_ext_; - int send_absolute_sender_time_ext_; int receive_absolute_sender_time_ext_; int associate_send_channel; DtmfInfo dtmf_info; @@ -267,14 +263,6 @@ class FakeWebRtcVoiceEngine bool IsInited() const { return inited_; } int GetLastChannel() const { return last_channel_; } - int GetChannelFromLocalSsrc(uint32_t local_ssrc) const { - for (std::map::const_iterator iter = channels_.begin(); - iter != channels_.end(); ++iter) { - if (local_ssrc == iter->second->send_ssrc) - return iter->first; - } - return -1; - } int GetNumChannels() const { return static_cast(channels_.size()); } uint32_t GetLocalSSRC(int channel) { return channels_[channel]->send_ssrc; @@ -364,15 +352,6 @@ class FakeWebRtcVoiceEngine channels_[++last_channel_] = ch; return last_channel_; } - int GetSendRtpExtensionId(int channel, const std::string& extension) { - WEBRTC_ASSERT_CHANNEL(channel); - if (extension == kRtpAudioLevelHeaderExtension) { - return channels_[channel]->send_audio_level_ext_; - } else if (extension == kRtpAbsoluteSenderTimeHeaderExtension) { - return channels_[channel]->send_absolute_sender_time_ext_; - } - return -1; - } int GetReceiveRtpExtensionId(int channel, const std::string& extension) { WEBRTC_ASSERT_CHANNEL(channel); if (extension == kRtpAudioLevelHeaderExtension) { @@ -729,13 +708,8 @@ class FakeWebRtcVoiceEngine } WEBRTC_STUB(GetLocalSSRC, (int channel, unsigned int& ssrc)); WEBRTC_STUB(GetRemoteSSRC, (int channel, unsigned int& ssrc)); - WEBRTC_FUNC(SetSendAudioLevelIndicationStatus, (int channel, bool enable, - unsigned char id)) { - WEBRTC_CHECK_CHANNEL(channel); - WEBRTC_CHECK_HEADER_EXTENSION_ID(enable, id); - channels_[channel]->send_audio_level_ext_ = (enable) ? id : -1; - return 0; - } + WEBRTC_STUB(SetSendAudioLevelIndicationStatus, (int channel, bool enable, + unsigned char id)); WEBRTC_FUNC(SetReceiveAudioLevelIndicationStatus, (int channel, bool enable, unsigned char id)) { WEBRTC_CHECK_CHANNEL(channel); @@ -743,13 +717,8 @@ class FakeWebRtcVoiceEngine channels_[channel]->receive_audio_level_ext_ = (enable) ? id : -1; return 0; } - WEBRTC_FUNC(SetSendAbsoluteSenderTimeStatus, (int channel, bool enable, - unsigned char id)) { - WEBRTC_CHECK_CHANNEL(channel); - WEBRTC_CHECK_HEADER_EXTENSION_ID(enable, id); - channels_[channel]->send_absolute_sender_time_ext_ = (enable) ? id : -1; - return 0; - } + WEBRTC_STUB(SetSendAbsoluteSenderTimeStatus, (int channel, bool enable, + unsigned char id)); WEBRTC_FUNC(SetReceiveAbsoluteSenderTimeStatus, (int channel, bool enable, unsigned char id)) { WEBRTC_CHECK_CHANNEL(channel); diff --git a/talk/media/webrtc/webrtcvoiceengine.cc b/talk/media/webrtc/webrtcvoiceengine.cc index a7e1a439bd..c13b22933a 100644 --- a/talk/media/webrtc/webrtcvoiceengine.cc +++ b/talk/media/webrtc/webrtcvoiceengine.cc @@ -396,6 +396,19 @@ webrtc::AudioState::Config MakeAudioStateConfig(VoEWrapper* voe_wrapper) { return config; } +std::vector FindAudioRtpHeaderExtensions( + const std::vector& extensions) { + std::vector result; + for (const auto& extension : extensions) { + if (extension.uri == kRtpAbsoluteSenderTimeHeaderExtension || + extension.uri == kRtpAudioLevelHeaderExtension) { + result.push_back({extension.uri, extension.id}); + } else { + LOG(LS_WARNING) << "Unsupported RTP extension: " << extension.ToString(); + } + } + return result; +} } // namespace { WebRtcVoiceEngine::WebRtcVoiceEngine() @@ -1337,27 +1350,49 @@ class WebRtcVoiceMediaChannel::WebRtcAudioSendStream : public AudioRenderer::Sink { public: WebRtcAudioSendStream(int ch, webrtc::AudioTransport* voe_audio_transport, - uint32_t ssrc, webrtc::Call* call) + uint32_t ssrc, const std::string& c_name, + const std::vector& extensions, + webrtc::Call* call) : channel_(ch), voe_audio_transport_(voe_audio_transport), - call_(call) { + call_(call), + config_(nullptr) { RTC_DCHECK_GE(ch, 0); // TODO(solenberg): Once we're not using FakeWebRtcVoiceEngine anymore: // RTC_DCHECK(voe_audio_transport); RTC_DCHECK(call); audio_capture_thread_checker_.DetachFromThread(); - webrtc::AudioSendStream::Config config(nullptr); - config.voe_channel_id = channel_; - config.rtp.ssrc = ssrc; - stream_ = call_->CreateAudioSendStream(config); - RTC_DCHECK(stream_); + config_.rtp.ssrc = ssrc; + config_.rtp.c_name = c_name; + config_.voe_channel_id = ch; + RecreateAudioSendStream(extensions); } + ~WebRtcAudioSendStream() override { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); Stop(); call_->DestroyAudioSendStream(stream_); } + void RecreateAudioSendStream( + const std::vector& extensions) { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + if (stream_) { + call_->DestroyAudioSendStream(stream_); + stream_ = nullptr; + } + config_.rtp.extensions = extensions; + RTC_DCHECK(!stream_); + stream_ = call_->CreateAudioSendStream(config_); + RTC_CHECK(stream_); + } + + webrtc::AudioSendStream::Stats GetStats() const { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + RTC_DCHECK(stream_); + return stream_->GetStats(); + } + // Starts the rendering by setting a sink to the renderer to get data // callback. // This method is called on the libjingle worker thread. @@ -1373,11 +1408,6 @@ class WebRtcVoiceMediaChannel::WebRtcAudioSendStream renderer_ = renderer; } - webrtc::AudioSendStream::Stats GetStats() const { - RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); - return stream_->GetStats(); - } - // Stops rendering by setting the sink of the renderer to nullptr. No data // callback will be received after this method. // This method is called on the libjingle worker thread. @@ -1428,6 +1458,9 @@ class WebRtcVoiceMediaChannel::WebRtcAudioSendStream const int channel_ = -1; webrtc::AudioTransport* const voe_audio_transport_ = nullptr; webrtc::Call* call_ = nullptr; + webrtc::AudioSendStream::Config config_; + // The stream is owned by WebRtcAudioSendStream and may be reallocated if + // configuration changes. webrtc::AudioSendStream* stream_ = nullptr; // Raw pointer to AudioRenderer owned by LocalAudioTrackHandler. @@ -1486,10 +1519,24 @@ bool WebRtcVoiceMediaChannel::SetSendParameters( RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); // TODO(pthatcher): Refactor this to be more clean now that we have // all the information at once. - return (SetSendCodecs(params.codecs) && - SetSendRtpHeaderExtensions(params.extensions) && - SetMaxSendBandwidth(params.max_bandwidth_bps) && - SetOptions(params.options)); + + if (!SetSendCodecs(params.codecs)) { + return false; + } + + std::vector send_rtp_extensions = + FindAudioRtpHeaderExtensions(params.extensions); + if (send_rtp_extensions_ != send_rtp_extensions) { + send_rtp_extensions_.swap(send_rtp_extensions); + for (auto& it : send_streams_) { + it.second->RecreateAudioSendStream(send_rtp_extensions_); + } + } + + if (!SetMaxSendBandwidth(params.max_bandwidth_bps)) { + return false; + } + return SetOptions(params.options); } bool WebRtcVoiceMediaChannel::SetRecvParameters( @@ -1870,26 +1917,8 @@ bool WebRtcVoiceMediaChannel::SetRecvRtpHeaderExtensions( receive_extensions_ = extensions; // Recreate AudioReceiveStream:s. - { - std::vector exts; - - const RtpHeaderExtension* audio_level_extension = - FindHeaderExtension(extensions, kRtpAudioLevelHeaderExtension); - if (audio_level_extension) { - exts.push_back({ - kRtpAudioLevelHeaderExtension, audio_level_extension->id}); - } - - const RtpHeaderExtension* send_time_extension = - FindHeaderExtension(extensions, kRtpAbsoluteSenderTimeHeaderExtension); - if (send_time_extension) { - exts.push_back({ - kRtpAbsoluteSenderTimeHeaderExtension, send_time_extension->id}); - } - - recv_rtp_extensions_.swap(exts); - RecreateAudioReceiveStreams(); - } + recv_rtp_extensions_ = FindAudioRtpHeaderExtensions(extensions); + RecreateAudioReceiveStreams(); return true; } @@ -1915,45 +1944,6 @@ bool WebRtcVoiceMediaChannel::SetChannelRecvRtpHeaderExtensions( return true; } -bool WebRtcVoiceMediaChannel::SetSendRtpHeaderExtensions( - const std::vector& extensions) { - RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); - if (send_extensions_ == extensions) { - return true; - } - - for (const auto& ch : send_streams_) { - if (!SetChannelSendRtpHeaderExtensions(ch.second->channel(), extensions)) { - return false; - } - } - - send_extensions_ = extensions; - return true; -} - -bool WebRtcVoiceMediaChannel::SetChannelSendRtpHeaderExtensions( - int channel_id, const std::vector& extensions) { - const RtpHeaderExtension* audio_level_extension = - FindHeaderExtension(extensions, kRtpAudioLevelHeaderExtension); - - if (!SetHeaderExtension( - &webrtc::VoERTP_RTCP::SetSendAudioLevelIndicationStatus, channel_id, - audio_level_extension)) { - return false; - } - - const RtpHeaderExtension* send_time_extension = - FindHeaderExtension(extensions, kRtpAbsoluteSenderTimeHeaderExtension); - if (!SetHeaderExtension( - &webrtc::VoERTP_RTCP::SetSendAbsoluteSenderTimeStatus, channel_id, - send_time_extension)) { - return false; - } - - return true; -} - bool WebRtcVoiceMediaChannel::SetPlayout(bool playout) { desired_playout_ = playout; return ChangePlayout(desired_playout_); @@ -2107,33 +2097,12 @@ bool WebRtcVoiceMediaChannel::AddSendStream(const StreamParams& sp) { return false; } - // Enable RTCP (for quality stats and feedback messages). - if (engine()->voe()->rtp()->SetRTCPStatus(channel, true) == -1) { - LOG_RTCERR2(SetRTCPStatus, channel, 1); - } - - SetChannelSendRtpHeaderExtensions(channel, send_extensions_); - - // Set the local (send) SSRC. - if (engine()->voe()->rtp()->SetLocalSSRC(channel, ssrc) == -1) { - LOG_RTCERR2(SetLocalSSRC, channel, ssrc); - DeleteChannel(channel); - return false; - } - - if (engine()->voe()->rtp()->SetRTCP_CNAME(channel, sp.cname.c_str()) == -1) { - LOG_RTCERR2(SetRTCP_CNAME, channel, sp.cname); - DeleteChannel(channel); - return false; - } - // Save the channel to send_streams_, so that RemoveSendStream() can still // delete the channel in case failure happens below. webrtc::AudioTransport* audio_transport = engine()->voe()->base()->audio_transport(); - send_streams_.insert( - std::make_pair(ssrc, - new WebRtcAudioSendStream(channel, audio_transport, ssrc, call_))); + send_streams_.insert(std::make_pair(ssrc, new WebRtcAudioSendStream( + channel, audio_transport, ssrc, sp.cname, send_rtp_extensions_, call_))); // Set the current codecs to be used for the new channel. We need to do this // after adding the channel to send_channels_, because of how max bitrate is @@ -2165,6 +2134,8 @@ bool WebRtcVoiceMediaChannel::AddSendStream(const StreamParams& sp) { bool WebRtcVoiceMediaChannel::RemoveSendStream(uint32_t ssrc) { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + LOG(LS_INFO) << "RemoveSendStream: " << ssrc; + auto it = send_streams_.find(ssrc); if (it == send_streams_.end()) { LOG(LS_WARNING) << "Try to remove stream with ssrc " << ssrc diff --git a/talk/media/webrtc/webrtcvoiceengine.h b/talk/media/webrtc/webrtcvoiceengine.h index e480c13bef..2f74dabd0f 100644 --- a/talk/media/webrtc/webrtcvoiceengine.h +++ b/talk/media/webrtc/webrtcvoiceengine.h @@ -245,8 +245,6 @@ class WebRtcVoiceMediaChannel final : public VoiceMediaChannel, private: bool SetSendCodecs(const std::vector& codecs); - bool SetSendRtpHeaderExtensions( - const std::vector& extensions); bool SetOptions(const AudioOptions& options); bool SetMaxSendBandwidth(int bps); bool SetRecvCodecs(const std::vector& codecs); @@ -290,9 +288,6 @@ class WebRtcVoiceMediaChannel final : public VoiceMediaChannel, bool SetChannelRecvRtpHeaderExtensions( int channel_id, const std::vector& extensions); - bool SetChannelSendRtpHeaderExtensions( - int channel_id, - const std::vector& extensions); rtc::ThreadChecker worker_thread_checker_; @@ -322,7 +317,7 @@ class WebRtcVoiceMediaChannel final : public VoiceMediaChannel, class WebRtcAudioSendStream; std::map send_streams_; - std::vector send_extensions_; + std::vector send_rtp_extensions_; class WebRtcAudioReceiveStream; std::map receive_channels_; diff --git a/talk/media/webrtc/webrtcvoiceengine_unittest.cc b/talk/media/webrtc/webrtcvoiceengine_unittest.cc index 0e2781b947..b123a8430b 100644 --- a/talk/media/webrtc/webrtcvoiceengine_unittest.cc +++ b/talk/media/webrtc/webrtcvoiceengine_unittest.cc @@ -124,12 +124,10 @@ class WebRtcVoiceEngineTestFake : public testing::Test { void SetupForMultiSendStream() { EXPECT_TRUE(SetupEngineWithSendStream()); // Remove stream added in Setup. - int default_channel_num = voe_.GetLastChannel(); - EXPECT_EQ(kSsrc1, voe_.GetLocalSSRC(default_channel_num)); + EXPECT_TRUE(call_.GetAudioSendStream(kSsrc1)); EXPECT_TRUE(channel_->RemoveSendStream(kSsrc1)); - // Verify the channel does not exist. - EXPECT_EQ(-1, voe_.GetChannelFromLocalSsrc(kSsrc1)); + EXPECT_FALSE(call_.GetAudioSendStream(kSsrc1)); } void DeliverPacket(const void* data, int len) { rtc::Buffer packet(reinterpret_cast(data), len); @@ -140,6 +138,12 @@ class WebRtcVoiceEngineTestFake : public testing::Test { engine_.Terminate(); } + const webrtc::AudioSendStream::Config& GetSendStreamConfig(uint32_t ssrc) { + const auto* send_stream = call_.GetAudioSendStream(ssrc); + EXPECT_TRUE(send_stream); + return send_stream->GetConfig(); + } + void TestInsertDtmf(uint32_t ssrc, bool caller) { EXPECT_TRUE(engine_.Init(rtc::Thread::Current())); channel_ = engine_.CreateChannel(&call_, cricket::AudioOptions()); @@ -212,41 +216,44 @@ class WebRtcVoiceEngineTestFake : public testing::Test { void TestSetSendRtpHeaderExtensions(const std::string& ext) { EXPECT_TRUE(SetupEngineWithSendStream()); - int channel_num = voe_.GetLastChannel(); // Ensure extensions are off by default. - EXPECT_EQ(-1, voe_.GetSendRtpExtensionId(channel_num, ext)); + EXPECT_EQ(0u, GetSendStreamConfig(kSsrc1).rtp.extensions.size()); // Ensure unknown extensions won't cause an error. send_parameters_.extensions.push_back(cricket::RtpHeaderExtension( "urn:ietf:params:unknownextention", 1)); EXPECT_TRUE(channel_->SetSendParameters(send_parameters_)); - EXPECT_EQ(-1, voe_.GetSendRtpExtensionId(channel_num, ext)); + EXPECT_EQ(0u, GetSendStreamConfig(kSsrc1).rtp.extensions.size()); // Ensure extensions stay off with an empty list of headers. send_parameters_.extensions.clear(); EXPECT_TRUE(channel_->SetSendParameters(send_parameters_)); - EXPECT_EQ(-1, voe_.GetSendRtpExtensionId(channel_num, ext)); + EXPECT_EQ(0u, GetSendStreamConfig(kSsrc1).rtp.extensions.size()); // Ensure extension is set properly. const int id = 1; send_parameters_.extensions.push_back(cricket::RtpHeaderExtension(ext, id)); EXPECT_TRUE(channel_->SetSendParameters(send_parameters_)); - EXPECT_EQ(id, voe_.GetSendRtpExtensionId(channel_num, ext)); + EXPECT_EQ(1u, GetSendStreamConfig(kSsrc1).rtp.extensions.size()); + 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. EXPECT_TRUE(channel_->AddSendStream( cricket::StreamParams::CreateLegacy(kSsrc2))); - int new_channel_num = voe_.GetLastChannel(); - EXPECT_NE(channel_num, new_channel_num); - EXPECT_EQ(id, voe_.GetSendRtpExtensionId(new_channel_num, ext)); + EXPECT_NE(call_.GetAudioSendStream(kSsrc1), + call_.GetAudioSendStream(kSsrc2)); + EXPECT_EQ(1u, GetSendStreamConfig(kSsrc2).rtp.extensions.size()); + EXPECT_EQ(ext, GetSendStreamConfig(kSsrc2).rtp.extensions[0].name); + EXPECT_EQ(id, GetSendStreamConfig(kSsrc2).rtp.extensions[0].id); // Ensure all extensions go back off with an empty list. send_parameters_.codecs.push_back(kPcmuCodec); send_parameters_.extensions.clear(); EXPECT_TRUE(channel_->SetSendParameters(send_parameters_)); - EXPECT_EQ(-1, voe_.GetSendRtpExtensionId(channel_num, ext)); - EXPECT_EQ(-1, voe_.GetSendRtpExtensionId(new_channel_num, ext)); + EXPECT_EQ(0u, GetSendStreamConfig(kSsrc1).rtp.extensions.size()); + EXPECT_EQ(0u, GetSendStreamConfig(kSsrc2).rtp.extensions.size()); } void TestSetRecvRtpHeaderExtensions(const std::string& ext) { @@ -1976,21 +1983,16 @@ TEST_F(WebRtcVoiceEngineTestFake, CreateAndDeleteMultipleSendStreams) { for (uint32_t ssrc : kSsrcs4) { EXPECT_TRUE(channel_->AddSendStream( cricket::StreamParams::CreateLegacy(ssrc))); - EXPECT_NE(nullptr, call_.GetAudioSendStream(ssrc)); - // Verify that we are in a sending state for all the created streams. - int channel_num = voe_.GetChannelFromLocalSsrc(ssrc); - EXPECT_TRUE(voe_.GetSend(channel_num)); + EXPECT_TRUE(voe_.GetSend(GetSendStreamConfig(ssrc).voe_channel_id)); } EXPECT_EQ(arraysize(kSsrcs4), call_.GetAudioSendStreams().size()); // Delete the send streams. for (uint32_t ssrc : kSsrcs4) { EXPECT_TRUE(channel_->RemoveSendStream(ssrc)); - EXPECT_EQ(nullptr, call_.GetAudioSendStream(ssrc)); - // Stream should already be deleted. + EXPECT_FALSE(call_.GetAudioSendStream(ssrc)); EXPECT_FALSE(channel_->RemoveSendStream(ssrc)); - EXPECT_EQ(-1, voe_.GetChannelFromLocalSsrc(ssrc)); } EXPECT_EQ(0u, call_.GetAudioSendStreams().size()); } @@ -2015,7 +2017,7 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecsWithMultipleSendStreams) { // Verify ISAC and VAD are corrected configured on all send channels. webrtc::CodecInst gcodec; for (uint32_t ssrc : kSsrcs4) { - int channel_num = voe_.GetChannelFromLocalSsrc(ssrc); + int channel_num = GetSendStreamConfig(ssrc).voe_channel_id; EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec)); EXPECT_STREQ("ISAC", gcodec.plname); EXPECT_TRUE(voe_.GetVAD(channel_num)); @@ -2026,7 +2028,7 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecsWithMultipleSendStreams) { parameters.codecs[0] = kPcmuCodec; EXPECT_TRUE(channel_->SetSendParameters(parameters)); for (uint32_t ssrc : kSsrcs4) { - int channel_num = voe_.GetChannelFromLocalSsrc(ssrc); + int channel_num = GetSendStreamConfig(ssrc).voe_channel_id; EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec)); EXPECT_STREQ("PCMU", gcodec.plname); EXPECT_FALSE(voe_.GetVAD(channel_num)); @@ -2049,7 +2051,7 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendWithMultipleSendStreams) { EXPECT_TRUE(channel_->SetSend(cricket::SEND_MICROPHONE)); for (uint32_t ssrc : kSsrcs4) { // Verify that we are in a sending state for all the send streams. - int channel_num = voe_.GetChannelFromLocalSsrc(ssrc); + int channel_num = GetSendStreamConfig(ssrc).voe_channel_id; EXPECT_TRUE(voe_.GetSend(channel_num)); } @@ -2057,7 +2059,7 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendWithMultipleSendStreams) { EXPECT_TRUE(channel_->SetSend(cricket::SEND_NOTHING)); for (uint32_t ssrc : kSsrcs4) { // Verify that we are in a stop state for all the send streams. - int channel_num = voe_.GetChannelFromLocalSsrc(ssrc); + int channel_num = GetSendStreamConfig(ssrc).voe_channel_id; EXPECT_FALSE(voe_.GetSend(channel_num)); } } @@ -2338,7 +2340,7 @@ TEST_F(WebRtcVoiceEngineTestFake, TraceFilterViaTraceOptions) { // SSRC is set in SetupEngine by calling AddSendStream. TEST_F(WebRtcVoiceEngineTestFake, SetSendSsrc) { EXPECT_TRUE(SetupEngineWithSendStream()); - EXPECT_EQ(kSsrc1, voe_.GetLocalSSRC(voe_.GetLastChannel())); + EXPECT_TRUE(call_.GetAudioSendStream(kSsrc1)); } TEST_F(WebRtcVoiceEngineTestFake, GetStats) { @@ -2399,7 +2401,7 @@ TEST_F(WebRtcVoiceEngineTestFake, GetStats) { // SSRC is set in SetupEngine by calling AddSendStream. TEST_F(WebRtcVoiceEngineTestFake, SetSendSsrcWithMultipleStreams) { EXPECT_TRUE(SetupEngineWithSendStream()); - EXPECT_EQ(kSsrc1, voe_.GetLocalSSRC(voe_.GetLastChannel())); + EXPECT_TRUE(call_.GetAudioSendStream(kSsrc1)); EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(2))); EXPECT_EQ(kSsrc1, voe_.GetLocalSSRC(voe_.GetLastChannel())); } @@ -2414,9 +2416,8 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendSsrcAfterCreatingReceiveChannel) { int receive_channel_num = voe_.GetLastChannel(); EXPECT_TRUE(channel_->AddSendStream( cricket::StreamParams::CreateLegacy(1234))); - int send_channel_num = voe_.GetLastChannel(); - EXPECT_EQ(1234U, voe_.GetLocalSSRC(send_channel_num)); + EXPECT_TRUE(call_.GetAudioSendStream(1234)); EXPECT_EQ(1234U, voe_.GetLocalSSRC(receive_channel_num)); } @@ -3053,6 +3054,8 @@ TEST_F(WebRtcVoiceEngineTestFake, ConfigureCombinedBweForNewRecvStreams) { EXPECT_EQ(arraysize(kSsrcs), call_.GetAudioReceiveStreams().size()); } +// TODO(solenberg): Remove, once recv streams are configured through Call. +// (This is then covered by TestSetRecvRtpHeaderExtensions.) TEST_F(WebRtcVoiceEngineTestFake, ConfiguresAudioReceiveStreamRtpExtensions) { // Test that setting the header extensions results in the expected state // changes on an associated Call. diff --git a/webrtc/audio/audio_receive_stream_unittest.cc b/webrtc/audio/audio_receive_stream_unittest.cc index 755d634d56..edd804fe51 100644 --- a/webrtc/audio/audio_receive_stream_unittest.cc +++ b/webrtc/audio/audio_receive_stream_unittest.cc @@ -20,6 +20,9 @@ namespace webrtc { namespace test { namespace { +using testing::_; +using testing::Return; + AudioDecodingCallStats MakeAudioDecodeStatsForTest() { AudioDecodingCallStats audio_decode_stats; audio_decode_stats.calls_to_silence_generator = 234; @@ -50,9 +53,9 @@ const AudioDecodingCallStats kAudioDecodeStats = MakeAudioDecodeStatsForTest(); struct ConfigHelper { ConfigHelper() { EXPECT_CALL(voice_engine_, - RegisterVoiceEngineObserver(testing::_)).WillOnce(testing::Return(0)); + RegisterVoiceEngineObserver(_)).WillOnce(Return(0)); EXPECT_CALL(voice_engine_, - DeRegisterVoiceEngineObserver()).WillOnce(testing::Return(0)); + DeRegisterVoiceEngineObserver()).WillOnce(Return(0)); AudioState::Config config; config.voice_engine = &voice_engine_; audio_state_ = AudioState::Create(config); @@ -69,9 +72,7 @@ struct ConfigHelper { MockVoiceEngine& voice_engine() { return voice_engine_; } void SetupMockForGetStats() { - using testing::_; using testing::DoAll; - using testing::Return; using testing::SetArgPointee; using testing::SetArgReferee; EXPECT_CALL(voice_engine_, GetRemoteSSRC(kChannelId, _)) @@ -94,7 +95,7 @@ struct ConfigHelper { private: MockRemoteBitrateEstimator remote_bitrate_estimator_; - MockVoiceEngine voice_engine_; + testing::StrictMock voice_engine_; rtc::scoped_refptr audio_state_; AudioReceiveStream::Config stream_config_; }; diff --git a/webrtc/audio/audio_send_stream.cc b/webrtc/audio/audio_send_stream.cc index da242498f9..14112deb9a 100644 --- a/webrtc/audio/audio_send_stream.cc +++ b/webrtc/audio/audio_send_stream.cc @@ -34,6 +34,7 @@ std::string AudioSendStream::Config::Rtp::ToString() const { } } ss << ']'; + ss << ", c_name: " << c_name; ss << '}'; return ss.str(); } @@ -58,6 +59,31 @@ AudioSendStream::AudioSendStream( LOG(LS_INFO) << "AudioSendStream: " << config_.ToString(); RTC_DCHECK_NE(config_.voe_channel_id, -1); RTC_DCHECK(audio_state_.get()); + + const int channel_id = config.voe_channel_id; + ScopedVoEInterface rtp(voice_engine()); + int error = rtp->SetRTCPStatus(channel_id, true); + RTC_DCHECK_EQ(0, error); + error = rtp->SetLocalSSRC(channel_id, config.rtp.ssrc); + RTC_DCHECK_EQ(0, error); + error = rtp->SetRTCP_CNAME(channel_id, config.rtp.c_name.c_str()); + 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(extension.id, 1); + RTC_DCHECK_LE(extension.id, 14); + if (extension.name == RtpExtension::kAbsSendTime) { + error = rtp->SetSendAbsoluteSenderTimeStatus(channel_id, true, + extension.id); + RTC_DCHECK_EQ(0, error); + } else if (extension.name == RtpExtension::kAudioLevel) { + error = rtp->SetSendAudioLevelIndicationStatus(channel_id, true, + extension.id); + RTC_DCHECK_EQ(0, error); + } else { + RTC_NOTREACHED() << "Registering unsupported RTP extension."; + } + } } AudioSendStream::~AudioSendStream() { @@ -65,19 +91,38 @@ AudioSendStream::~AudioSendStream() { LOG(LS_INFO) << "~AudioSendStream: " << config_.ToString(); } +void AudioSendStream::Start() { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); +} + +void AudioSendStream::Stop() { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); +} + +void AudioSendStream::SignalNetworkState(NetworkState state) { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); +} + +bool AudioSendStream::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; +} + webrtc::AudioSendStream::Stats AudioSendStream::GetStats() const { RTC_DCHECK(thread_checker_.CalledOnValidThread()); webrtc::AudioSendStream::Stats stats; stats.local_ssrc = config_.rtp.ssrc; - internal::AudioState* audio_state = - static_cast(audio_state_.get()); - VoiceEngine* voice_engine = audio_state->voice_engine(); - ScopedVoEInterface processing(voice_engine); - ScopedVoEInterface codec(voice_engine); - ScopedVoEInterface rtp(voice_engine); - ScopedVoEInterface volume(voice_engine); + ScopedVoEInterface processing(voice_engine()); + ScopedVoEInterface codec(voice_engine()); + ScopedVoEInterface rtp(voice_engine()); + ScopedVoEInterface volume(voice_engine()); unsigned int ssrc = 0; webrtc::CallStatistics call_stats = {0}; + // TODO(solenberg): Change error code checking to RTC_CHECK_EQ(..., -1), if + // possible... if (rtp->GetLocalSSRC(config_.voe_channel_id, ssrc) == -1 || rtp->GetRTCPStatistics(config_.voe_channel_id, call_stats) == -1) { return stats; @@ -153,6 +198,8 @@ webrtc::AudioSendStream::Stats AudioSendStream::GetStats() const { } } + internal::AudioState* audio_state = + static_cast(audio_state_.get()); stats.typing_noise_detected = audio_state->typing_noise_detected(); return stats; @@ -163,24 +210,12 @@ const webrtc::AudioSendStream::Config& AudioSendStream::config() const { return config_; } -void AudioSendStream::Start() { - RTC_DCHECK(thread_checker_.CalledOnValidThread()); -} - -void AudioSendStream::Stop() { - RTC_DCHECK(thread_checker_.CalledOnValidThread()); -} - -void AudioSendStream::SignalNetworkState(NetworkState state) { - RTC_DCHECK(thread_checker_.CalledOnValidThread()); -} - -bool AudioSendStream::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; +VoiceEngine* AudioSendStream::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_send_stream.h b/webrtc/audio/audio_send_stream.h index 3d911c1f5f..a4eb89d169 100644 --- a/webrtc/audio/audio_send_stream.h +++ b/webrtc/audio/audio_send_stream.h @@ -16,6 +16,9 @@ #include "webrtc/base/thread_checker.h" namespace webrtc { + +class VoiceEngine; + namespace internal { class AudioSendStream final : public webrtc::AudioSendStream { @@ -36,6 +39,8 @@ class AudioSendStream final : public webrtc::AudioSendStream { const webrtc::AudioSendStream::Config& config() const; private: + VoiceEngine* voice_engine() const; + rtc::ThreadChecker thread_checker_; const webrtc::AudioSendStream::Config config_; rtc::scoped_refptr audio_state_; diff --git a/webrtc/audio/audio_send_stream_unittest.cc b/webrtc/audio/audio_send_stream_unittest.cc index ada15acddf..1801e9df11 100644 --- a/webrtc/audio/audio_send_stream_unittest.cc +++ b/webrtc/audio/audio_send_stream_unittest.cc @@ -19,8 +19,14 @@ namespace webrtc { namespace test { namespace { +using testing::_; +using testing::Return; + const int kChannelId = 1; const uint32_t kSsrc = 1234; +const char* kCName = "foo_name"; +const int kAudioLevelId = 2; +const int kAbsSendTimeId = 3; const int kEchoDelayMedian = 254; const int kEchoDelayStdDev = -3; const int kEchoReturnLoss = -65; @@ -33,21 +39,45 @@ const ReportBlock kReportBlock = {456, 780, 123, 567, 890, 132, 143, 13354}; struct ConfigHelper { ConfigHelper() : stream_config_(nullptr) { + using testing::StrEq; + EXPECT_CALL(voice_engine_, - RegisterVoiceEngineObserver(testing::_)).WillOnce(testing::Return(0)); + RegisterVoiceEngineObserver(_)).WillOnce(Return(0)); EXPECT_CALL(voice_engine_, - DeRegisterVoiceEngineObserver()).WillOnce(testing::Return(0)); + DeRegisterVoiceEngineObserver()).WillOnce(Return(0)); AudioState::Config config; config.voice_engine = &voice_engine_; audio_state_ = AudioState::Create(config); + + EXPECT_CALL(voice_engine_, SetRTCPStatus(kChannelId, true)) + .WillOnce(Return(0)); + EXPECT_CALL(voice_engine_, SetLocalSSRC(kChannelId, kSsrc)) + .WillOnce(Return(0)); + EXPECT_CALL(voice_engine_, SetRTCP_CNAME(kChannelId, StrEq(kCName))) + .WillOnce(Return(0)); + EXPECT_CALL(voice_engine_, + SetSendAbsoluteSenderTimeStatus(kChannelId, true, kAbsSendTimeId)) + .WillOnce(Return(0)); + EXPECT_CALL(voice_engine_, + SetSendAudioLevelIndicationStatus(kChannelId, true, kAudioLevelId)) + .WillOnce(Return(0)); stream_config_.voe_channel_id = kChannelId; stream_config_.rtp.ssrc = kSsrc; + stream_config_.rtp.c_name = kCName; + stream_config_.rtp.extensions.push_back( + RtpExtension(RtpExtension::kAudioLevel, kAudioLevelId)); + stream_config_.rtp.extensions.push_back( + RtpExtension(RtpExtension::kAbsSendTime, kAbsSendTimeId)); } AudioSendStream::Config& config() { return stream_config_; } rtc::scoped_refptr audio_state() { return audio_state_; } void SetupMockForGetStats() { + using testing::DoAll; + using testing::SetArgPointee; + using testing::SetArgReferee; + std::vector report_blocks; webrtc::ReportBlock block = kReportBlock; report_blocks.push_back(block); // Has wrong SSRC. @@ -56,11 +86,6 @@ struct ConfigHelper { block.fraction_lost = 0; report_blocks.push_back(block); // Duplicate SSRC, bad fraction_lost. - using testing::_; - using testing::DoAll; - using testing::Return; - using testing::SetArgPointee; - using testing::SetArgReferee; EXPECT_CALL(voice_engine_, GetLocalSSRC(kChannelId, _)) .WillRepeatedly(DoAll(SetArgReferee<1>(0), Return(0))); EXPECT_CALL(voice_engine_, GetRTCPStatistics(kChannelId, _)) @@ -83,25 +108,26 @@ struct ConfigHelper { } private: - MockVoiceEngine voice_engine_; + testing::StrictMock voice_engine_; rtc::scoped_refptr audio_state_; AudioSendStream::Config stream_config_; }; } // namespace TEST(AudioSendStreamTest, ConfigToString) { - const int kAbsSendTimeId = 3; AudioSendStream::Config config(nullptr); config.rtp.ssrc = kSsrc; config.rtp.extensions.push_back( RtpExtension(RtpExtension::kAbsSendTime, kAbsSendTimeId)); + config.rtp.c_name = kCName; config.voe_channel_id = kChannelId; config.cng_payload_type = 42; config.red_payload_type = 17; EXPECT_EQ( "{rtp: {ssrc: 1234, extensions: [{name: " - "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time, id: 3}]}, " - "voe_channel_id: 1, cng_payload_type: 42, red_payload_type: 17}", + "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time, id: 3}], " + "c_name: foo_name}, voe_channel_id: 1, cng_payload_type: 42, " + "red_payload_type: 17}", config.ToString()); } diff --git a/webrtc/audio/audio_state_unittest.cc b/webrtc/audio/audio_state_unittest.cc index 170eff5e85..11fbdb4a86 100644 --- a/webrtc/audio/audio_state_unittest.cc +++ b/webrtc/audio/audio_state_unittest.cc @@ -30,7 +30,7 @@ struct ConfigHelper { MockVoiceEngine& voice_engine() { return voice_engine_; } private: - MockVoiceEngine voice_engine_; + testing::StrictMock voice_engine_; AudioState::Config config_; }; } // namespace diff --git a/webrtc/audio_send_stream.h b/webrtc/audio_send_stream.h index 89b73e6e3e..c5db82b91b 100644 --- a/webrtc/audio_send_stream.h +++ b/webrtc/audio_send_stream.h @@ -61,6 +61,9 @@ class AudioSendStream : public SendStream { // RTP header extensions used for the received stream. std::vector extensions; + + // RTCP CNAME, see RFC 3550. + std::string c_name; } rtp; // Transport for outgoing packets. The transport is expected to exist for diff --git a/webrtc/call/bitrate_estimator_tests.cc b/webrtc/call/bitrate_estimator_tests.cc index 6bccb43e56..54a78ea17c 100644 --- a/webrtc/call/bitrate_estimator_tests.cc +++ b/webrtc/call/bitrate_estimator_tests.cc @@ -118,13 +118,6 @@ class BitrateEstimatorTest : public test::CallTest { virtual ~BitrateEstimatorTest() { EXPECT_TRUE(streams_.empty()); } virtual void SetUp() { - EXPECT_CALL(mock_voice_engine_, - RegisterVoiceEngineObserver(testing::_)).WillOnce(testing::Return(0)); - EXPECT_CALL(mock_voice_engine_, - DeRegisterVoiceEngineObserver()).WillOnce(testing::Return(0)); - EXPECT_CALL(mock_voice_engine_, GetEventLog()) - .WillRepeatedly(testing::Return(nullptr)); - AudioState::Config audio_state_config; audio_state_config.voice_engine = &mock_voice_engine_; Call::Config config; @@ -265,7 +258,7 @@ class BitrateEstimatorTest : public test::CallTest { test::FakeDecoder fake_decoder_; }; - test::MockVoiceEngine mock_voice_engine_; + testing::NiceMock mock_voice_engine_; TraceObserver receiver_trace_; rtc::scoped_ptr send_transport_; rtc::scoped_ptr receive_transport_; diff --git a/webrtc/call/call_unittest.cc b/webrtc/call/call_unittest.cc index b26024d91e..75c8238a5b 100644 --- a/webrtc/call/call_unittest.cc +++ b/webrtc/call/call_unittest.cc @@ -20,12 +20,6 @@ namespace { struct CallHelper { CallHelper() { - EXPECT_CALL(voice_engine_, - RegisterVoiceEngineObserver(testing::_)).WillOnce(testing::Return(0)); - EXPECT_CALL(voice_engine_, - DeRegisterVoiceEngineObserver()).WillOnce(testing::Return(0)); - EXPECT_CALL(voice_engine_, - GetEventLog()).WillOnce(testing::Return(nullptr)); webrtc::AudioState::Config audio_state_config; audio_state_config.voice_engine = &voice_engine_; webrtc::Call::Config config; @@ -36,7 +30,7 @@ struct CallHelper { webrtc::Call* operator->() { return call_.get(); } private: - webrtc::test::MockVoiceEngine voice_engine_; + testing::NiceMock voice_engine_; rtc::scoped_ptr call_; }; } // namespace diff --git a/webrtc/config.h b/webrtc/config.h index 4b863c8d23..114303e616 100644 --- a/webrtc/config.h +++ b/webrtc/config.h @@ -49,10 +49,13 @@ struct FecConfig { int red_rtx_payload_type; }; -// RTP header extension to use for the video stream, see RFC 5285. +// RTP header extension, see RFC 5285. struct RtpExtension { RtpExtension(const std::string& name, int id) : name(name), id(id) {} std::string ToString() const; + bool operator==(const RtpExtension& rhs) const { + return name == rhs.name && id == rhs.id; + } static bool IsSupportedForAudio(const std::string& name); static bool IsSupportedForVideo(const std::string& name); diff --git a/webrtc/test/mock_voice_engine.h b/webrtc/test/mock_voice_engine.h index 77b4ec8c01..dead2260a3 100644 --- a/webrtc/test/mock_voice_engine.h +++ b/webrtc/test/mock_voice_engine.h @@ -19,7 +19,7 @@ namespace test { // NOTE: This class inherits from VoiceEngineImpl so that its clients will be // able to get the various interfaces as usual, via T::GetInterface(). -class MockVoiceEngine final : public VoiceEngineImpl { +class MockVoiceEngine : public VoiceEngineImpl { public: MockVoiceEngine() : VoiceEngineImpl(new Config(), true) { // Increase ref count so this object isn't automatically deleted whenever