diff --git a/webrtc/api/rtpreceiverinterface.h b/webrtc/api/rtpreceiverinterface.h index 8607d935a2..fd233abe31 100644 --- a/webrtc/api/rtpreceiverinterface.h +++ b/webrtc/api/rtpreceiverinterface.h @@ -15,6 +15,7 @@ #define WEBRTC_API_RTPRECEIVERINTERFACE_H_ #include +#include #include "webrtc/api/mediatypes.h" #include "webrtc/api/mediastreaminterface.h" @@ -25,6 +26,41 @@ namespace webrtc { +enum class RtpSourceType { + SSRC, + CSRC, +}; + +class RtpSource { + public: + RtpSource() = delete; + RtpSource(int64_t timestamp_ms, uint32_t source_id, RtpSourceType source_type) + : timestamp_ms_(timestamp_ms), + source_id_(source_id), + source_type_(source_type) {} + + int64_t timestamp_ms() const { return timestamp_ms_; } + void update_timestamp_ms(int64_t timestamp_ms) { + RTC_DCHECK_LE(timestamp_ms_, timestamp_ms); + timestamp_ms_ = timestamp_ms; + } + + // The identifier of the source can be the CSRC or the SSRC. + uint32_t source_id() const { return source_id_; } + + // The source can be either a contributing source or a synchronization source. + RtpSourceType source_type() const { return source_type_; } + + // This isn't implemented yet and will always return an empty Optional. + // TODO(zhihuang): Implement this to return real audio level. + rtc::Optional audio_level() const { return rtc::Optional(); } + + private: + int64_t timestamp_ms_; + uint32_t source_id_; + RtpSourceType source_type_; +}; + class RtpReceiverObserverInterface { public: // Note: Currently if there are multiple RtpReceivers of the same media type, @@ -61,6 +97,13 @@ class RtpReceiverInterface : public rtc::RefCountInterface { // Must call SetObserver(nullptr) before the observer is destroyed. virtual void SetObserver(RtpReceiverObserverInterface* observer) = 0; + // TODO(zhihuang): Remove the default implementation once the subclasses + // implement this. Currently, the only relevant subclass is the + // content::FakeRtpReceiver in Chromium. + virtual std::vector GetSources() const { + return std::vector(); + } + protected: virtual ~RtpReceiverInterface() {} }; @@ -76,7 +119,8 @@ BEGIN_SIGNALING_PROXY_MAP(RtpReceiver) PROXY_CONSTMETHOD0(RtpParameters, GetParameters); PROXY_METHOD1(bool, SetParameters, const RtpParameters&) PROXY_METHOD1(void, SetObserver, RtpReceiverObserverInterface*); -END_PROXY_MAP() + PROXY_CONSTMETHOD0(std::vector, GetSources); + END_PROXY_MAP() } // namespace webrtc diff --git a/webrtc/api/test/mock_rtpreceiver.h b/webrtc/api/test/mock_rtpreceiver.h index 25f5c28caa..552a653100 100644 --- a/webrtc/api/test/mock_rtpreceiver.h +++ b/webrtc/api/test/mock_rtpreceiver.h @@ -12,6 +12,7 @@ #define WEBRTC_API_TEST_MOCK_RTPRECEIVER_H_ #include +#include #include "webrtc/api/rtpreceiverinterface.h" #include "webrtc/test/gmock.h" @@ -27,6 +28,7 @@ class MockRtpReceiver : public rtc::RefCountedObject { MOCK_CONST_METHOD0(GetParameters, RtpParameters()); MOCK_METHOD1(SetParameters, bool(const RtpParameters&)); MOCK_METHOD1(SetObserver, void(RtpReceiverObserverInterface*)); + MOCK_CONST_METHOD0(GetSources, std::vector()); }; } // namespace webrtc diff --git a/webrtc/audio/audio_receive_stream.cc b/webrtc/audio/audio_receive_stream.cc index fbd61ccfd4..cb90a68a0f 100644 --- a/webrtc/audio/audio_receive_stream.cc +++ b/webrtc/audio/audio_receive_stream.cc @@ -219,6 +219,11 @@ void AudioReceiveStream::SetGain(float gain) { channel_proxy_->SetChannelOutputVolumeScaling(gain); } +std::vector AudioReceiveStream::GetSources() const { + RTC_DCHECK_RUN_ON(&worker_thread_checker_); + return channel_proxy_->GetSources(); +} + AudioMixer::Source::AudioFrameInfo AudioReceiveStream::GetAudioFrameWithInfo( int sample_rate_hz, AudioFrame* audio_frame) { diff --git a/webrtc/audio/audio_receive_stream.h b/webrtc/audio/audio_receive_stream.h index adac883876..20ed4613a7 100644 --- a/webrtc/audio/audio_receive_stream.h +++ b/webrtc/audio/audio_receive_stream.h @@ -12,6 +12,7 @@ #define WEBRTC_AUDIO_AUDIO_RECEIVE_STREAM_H_ #include +#include #include "webrtc/api/audio/audio_mixer.h" #include "webrtc/audio/audio_state.h" @@ -49,6 +50,7 @@ class AudioReceiveStream final : public webrtc::AudioReceiveStream, int GetOutputLevel() const override; void SetSink(std::unique_ptr sink) override; void SetGain(float gain) override; + std::vector GetSources() const override; // TODO(nisse): Intended to be part of an RtpPacketReceiver interface. void OnRtpPacket(const RtpPacketReceived& packet); diff --git a/webrtc/call/BUILD.gn b/webrtc/call/BUILD.gn index 47129530e1..d4b9ba3423 100644 --- a/webrtc/call/BUILD.gn +++ b/webrtc/call/BUILD.gn @@ -23,6 +23,7 @@ rtc_source_set("call_interfaces") { deps = [ "..:webrtc_common", "../api:audio_mixer_api", + "../api:libjingle_peerconnection_api", "../api:transport_api", "../api/audio_codecs:audio_codecs_api", "../base:rtc_base", diff --git a/webrtc/call/audio_receive_stream.h b/webrtc/call/audio_receive_stream.h index 3959da1369..e3bdd45247 100644 --- a/webrtc/call/audio_receive_stream.h +++ b/webrtc/call/audio_receive_stream.h @@ -18,6 +18,7 @@ #include "webrtc/api/audio_codecs/audio_decoder_factory.h" #include "webrtc/api/call/transport.h" +#include "webrtc/api/rtpreceiverinterface.h" #include "webrtc/base/optional.h" #include "webrtc/base/scoped_ref_ptr.h" #include "webrtc/common_types.h" @@ -133,6 +134,8 @@ class AudioReceiveStream { // is potentially forwarded to any attached AudioSinkInterface implementation. virtual void SetGain(float gain) = 0; + virtual std::vector GetSources() const = 0; + protected: virtual ~AudioReceiveStream() {} }; diff --git a/webrtc/media/engine/fakewebrtccall.h b/webrtc/media/engine/fakewebrtccall.h index 6b2542245e..1ddf95ae15 100644 --- a/webrtc/media/engine/fakewebrtccall.h +++ b/webrtc/media/engine/fakewebrtccall.h @@ -97,6 +97,9 @@ class FakeAudioReceiveStream final : public webrtc::AudioReceiveStream { int GetOutputLevel() const override { return 0; } void SetSink(std::unique_ptr sink) override; void SetGain(float gain) override; + std::vector GetSources() const override { + return std::vector(); + } int id_ = -1; webrtc::AudioReceiveStream::Config config_; diff --git a/webrtc/media/engine/webrtcvoiceengine.cc b/webrtc/media/engine/webrtcvoiceengine.cc index d3a928ba86..4aa97e049e 100644 --- a/webrtc/media/engine/webrtcvoiceengine.cc +++ b/webrtc/media/engine/webrtcvoiceengine.cc @@ -1581,6 +1581,12 @@ class WebRtcVoiceMediaChannel::WebRtcAudioReceiveStream { playout_ = playout; } + std::vector GetSources() { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + RTC_DCHECK(stream_); + return stream_->GetSources(); + } + private: void RecreateAudioReceiveStream() { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); @@ -2600,6 +2606,15 @@ void WebRtcVoiceMediaChannel::SetRawAudioSink( it->second->SetRawAudioSink(std::move(sink)); } +std::vector WebRtcVoiceMediaChannel::GetSources( + uint32_t ssrc) const { + auto it = recv_streams_.find(ssrc); + RTC_DCHECK(it != recv_streams_.end()) + << "Attempting to get contributing sources for SSRC:" << ssrc + << " which doesn't exist."; + return it->second->GetSources(); +} + int WebRtcVoiceMediaChannel::GetReceiveChannelId(uint32_t ssrc) const { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); const auto it = recv_streams_.find(ssrc); diff --git a/webrtc/media/engine/webrtcvoiceengine.h b/webrtc/media/engine/webrtcvoiceengine.h index a27c8f3aeb..4d71c89334 100644 --- a/webrtc/media/engine/webrtcvoiceengine.h +++ b/webrtc/media/engine/webrtcvoiceengine.h @@ -16,6 +16,7 @@ #include #include +#include "webrtc/api/rtpreceiverinterface.h" #include "webrtc/base/buffer.h" #include "webrtc/base/constructormagic.h" #include "webrtc/base/networkroute.h" @@ -210,6 +211,8 @@ class WebRtcVoiceMediaChannel final : public VoiceMediaChannel, uint32_t ssrc, std::unique_ptr sink) override; + std::vector GetSources(uint32_t ssrc) const; + // implements Transport interface bool SendRtp(const uint8_t* data, size_t len, diff --git a/webrtc/modules/rtp_rtcp/BUILD.gn b/webrtc/modules/rtp_rtcp/BUILD.gn index c1d69e07bb..ec1766641e 100644 --- a/webrtc/modules/rtp_rtcp/BUILD.gn +++ b/webrtc/modules/rtp_rtcp/BUILD.gn @@ -167,6 +167,7 @@ rtc_static_library("rtp_rtcp") { deps = [ "../..:webrtc_common", + "../../api:libjingle_peerconnection_api", "../../api:transport_api", "../../api/audio_codecs:audio_codecs_api", "../../base:gtest_prod", @@ -274,6 +275,7 @@ if (rtc_include_tests) { "source/rtp_packet_history_unittest.cc", "source/rtp_packet_unittest.cc", "source/rtp_payload_registry_unittest.cc", + "source/rtp_receiver_unittest.cc", "source/rtp_rtcp_impl_unittest.cc", "source/rtp_sender_unittest.cc", "source/rtp_utility_unittest.cc", diff --git a/webrtc/modules/rtp_rtcp/include/rtp_receiver.h b/webrtc/modules/rtp_rtcp/include/rtp_receiver.h index 54a99c93a1..95bade62fe 100644 --- a/webrtc/modules/rtp_rtcp/include/rtp_receiver.h +++ b/webrtc/modules/rtp_rtcp/include/rtp_receiver.h @@ -11,6 +11,9 @@ #ifndef WEBRTC_MODULES_RTP_RTCP_INCLUDE_RTP_RECEIVER_H_ #define WEBRTC_MODULES_RTP_RTCP_INCLUDE_RTP_RECEIVER_H_ +#include + +#include "webrtc/api/rtpreceiverinterface.h" #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h" #include "webrtc/typedefs.h" @@ -89,6 +92,8 @@ class RtpReceiver { // Returns the current energy of the RTP stream received. virtual int32_t Energy(uint8_t array_of_energy[kRtpCsrcSize]) const = 0; + + virtual std::vector GetSources() const = 0; }; } // namespace webrtc diff --git a/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.cc b/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.cc index 79e43ef073..9dd43c416a 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.cc @@ -15,6 +15,9 @@ #include #include +#include +#include + #include "webrtc/base/logging.h" #include "webrtc/common_types.h" #include "webrtc/modules/rtp_rtcp/include/rtp_payload_registry.h" @@ -25,6 +28,9 @@ namespace webrtc { using RtpUtility::Payload; +// Only return the sources in the last 10 seconds. +const int64_t kGetSourcesTimeoutMs = 10000; + RtpReceiver* RtpReceiver::CreateVideoReceiver( Clock* clock, RtpData* incoming_payload_callback, @@ -53,11 +59,10 @@ RtpReceiver* RtpReceiver::CreateAudioReceiver( RTPReceiverStrategy::CreateAudioStrategy(incoming_payload_callback)); } -RtpReceiverImpl::RtpReceiverImpl( - Clock* clock, - RtpFeedback* incoming_messages_callback, - RTPPayloadRegistry* rtp_payload_registry, - RTPReceiverStrategy* rtp_media_receiver) +RtpReceiverImpl::RtpReceiverImpl(Clock* clock, + RtpFeedback* incoming_messages_callback, + RTPPayloadRegistry* rtp_payload_registry, + RTPReceiverStrategy* rtp_media_receiver) : clock_(clock), rtp_payload_registry_(rtp_payload_registry), rtp_media_receiver_(rtp_media_receiver), @@ -160,6 +165,8 @@ bool RtpReceiverImpl::IncomingRtpPacket( webrtc_rtp_header.header = rtp_header; CheckCSRC(webrtc_rtp_header); + UpdateSources(); + size_t payload_data_length = payload_length - rtp_header.paddingLength; bool is_first_packet_in_frame = false; @@ -203,6 +210,45 @@ TelephoneEventHandler* RtpReceiverImpl::GetTelephoneEventHandler() { return rtp_media_receiver_->GetTelephoneEventHandler(); } +std::vector RtpReceiverImpl::GetSources() const { + int64_t now_ms = clock_->TimeInMilliseconds(); + std::vector sources; + + { + rtc::CritScope lock(&critical_section_rtp_receiver_); + + RTC_DCHECK(std::is_sorted(ssrc_sources_.begin(), ssrc_sources_.end(), + [](const RtpSource& lhs, const RtpSource& rhs) { + return lhs.timestamp_ms() < rhs.timestamp_ms(); + })); + RTC_DCHECK(std::is_sorted(csrc_sources_.begin(), csrc_sources_.end(), + [](const RtpSource& lhs, const RtpSource& rhs) { + return lhs.timestamp_ms() < rhs.timestamp_ms(); + })); + + std::set selected_ssrcs; + for (auto rit = ssrc_sources_.rbegin(); rit != ssrc_sources_.rend(); + ++rit) { + if ((now_ms - rit->timestamp_ms()) > kGetSourcesTimeoutMs) { + break; + } + if (selected_ssrcs.insert(rit->source_id()).second) { + sources.push_back(*rit); + } + } + + for (auto rit = csrc_sources_.rbegin(); rit != csrc_sources_.rend(); + ++rit) { + if ((now_ms - rit->timestamp_ms()) > kGetSourcesTimeoutMs) { + break; + } + sources.push_back(*rit); + } + } // End critsect. + + return sources; +} + bool RtpReceiverImpl::Timestamp(uint32_t* timestamp) const { rtc::CritScope lock(&critical_section_rtp_receiver_); if (!HaveReceivedFrame()) @@ -461,4 +507,54 @@ void RtpReceiverImpl::CheckCSRC(const WebRtcRTPHeader& rtp_header) { } } +void RtpReceiverImpl::UpdateSources() { + rtc::CritScope lock(&critical_section_rtp_receiver_); + int64_t now_ms = clock_->TimeInMilliseconds(); + + for (size_t i = 0; i < num_csrcs_; ++i) { + auto map_it = iterator_by_csrc_.find(current_remote_csrc_[i]); + if (map_it == iterator_by_csrc_.end()) { + // If it is a new CSRC, append a new object to the end of the list. + csrc_sources_.emplace_back(now_ms, current_remote_csrc_[i], + RtpSourceType::CSRC); + } else { + // If it is an existing CSRC, move the object to the end of the list. + map_it->second->update_timestamp_ms(now_ms); + csrc_sources_.splice(csrc_sources_.end(), csrc_sources_, map_it->second); + } + // Update the unordered_map. + iterator_by_csrc_[current_remote_csrc_[i]] = std::prev(csrc_sources_.end()); + } + + // If this is the first packet or the SSRC is changed, insert a new + // contributing source that uses the SSRC. + if (ssrc_sources_.empty() || ssrc_sources_.rbegin()->source_id() != ssrc_) { + ssrc_sources_.emplace_back(now_ms, ssrc_, RtpSourceType::SSRC); + } else { + ssrc_sources_.rbegin()->update_timestamp_ms(now_ms); + } + + RemoveOutdatedSources(now_ms); +} + +void RtpReceiverImpl::RemoveOutdatedSources(int64_t now_ms) { + std::list::iterator it; + for (it = csrc_sources_.begin(); it != csrc_sources_.end(); ++it) { + if ((now_ms - it->timestamp_ms()) <= kGetSourcesTimeoutMs) { + break; + } + iterator_by_csrc_.erase(it->source_id()); + } + csrc_sources_.erase(csrc_sources_.begin(), it); + + std::vector::iterator vec_it; + for (vec_it = ssrc_sources_.begin(); vec_it != ssrc_sources_.end(); + ++vec_it) { + if ((now_ms - vec_it->timestamp_ms()) <= kGetSourcesTimeoutMs) { + break; + } + } + ssrc_sources_.erase(ssrc_sources_.begin(), vec_it); +} + } // namespace webrtc diff --git a/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.h b/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.h index 4b5524877c..43965d325c 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.h +++ b/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.h @@ -11,7 +11,10 @@ #ifndef WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_RECEIVER_IMPL_H_ #define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_RECEIVER_IMPL_H_ +#include #include +#include +#include #include "webrtc/base/criticalsection.h" #include "webrtc/modules/rtp_rtcp/include/rtp_receiver.h" @@ -56,6 +59,16 @@ class RtpReceiverImpl : public RtpReceiver { TelephoneEventHandler* GetTelephoneEventHandler() override; + std::vector GetSources() const override; + + const std::vector& ssrc_sources_for_testing() const { + return ssrc_sources_; + } + + const std::list& csrc_sources_for_testing() const { + return csrc_sources_; + } + private: bool HaveReceivedFrame() const; @@ -66,6 +79,9 @@ class RtpReceiverImpl : public RtpReceiver { bool* is_red, PayloadUnion* payload); + void UpdateSources(); + void RemoveOutdatedSources(int64_t now_ms); + Clock* clock_; RTPPayloadRegistry* rtp_payload_registry_; std::unique_ptr rtp_media_receiver_; @@ -84,6 +100,12 @@ class RtpReceiverImpl : public RtpReceiver { uint32_t last_received_timestamp_; int64_t last_received_frame_time_ms_; uint16_t last_received_sequence_number_; + + std::unordered_map::iterator> + iterator_by_csrc_; + // The RtpSource objects are sorted chronologically. + std::list csrc_sources_; + std::vector ssrc_sources_; }; } // namespace webrtc #endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_RECEIVER_IMPL_H_ diff --git a/webrtc/modules/rtp_rtcp/source/rtp_receiver_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtp_receiver_unittest.cc new file mode 100644 index 0000000000..459e8e0315 --- /dev/null +++ b/webrtc/modules/rtp_rtcp/source/rtp_receiver_unittest.cc @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include + +#include "webrtc/common_types.h" +#include "webrtc/modules/rtp_rtcp/include/rtp_header_parser.h" +#include "webrtc/modules/rtp_rtcp/include/rtp_payload_registry.h" +#include "webrtc/modules/rtp_rtcp/include/rtp_receiver.h" +#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.h" +#include "webrtc/test/gtest.h" + +namespace webrtc { + +const uint32_t kTestRate = 64000u; +const uint8_t kTestPayload[] = {'t', 'e', 's', 't'}; +const uint8_t kPcmuPayloadType = 96; +const int64_t kGetSourcesTimeoutMs = 10000; +const int kSourceListsSize = 20; + +class RtpReceiverTest : public ::testing::Test { + protected: + RtpReceiverTest() + : fake_clock_(123456), + rtp_receiver_( + RtpReceiver::CreateAudioReceiver(&fake_clock_, + nullptr, + nullptr, + &rtp_payload_registry_)) { + CodecInst voice_codec = {}; + voice_codec.pltype = kPcmuPayloadType; + voice_codec.plfreq = 8000; + voice_codec.rate = kTestRate; + memcpy(voice_codec.plname, "PCMU", 5); + rtp_receiver_->RegisterReceivePayload(voice_codec); + } + ~RtpReceiverTest() {} + + bool FindSourceByIdAndType(const std::vector& sources, + uint32_t source_id, + RtpSourceType type, + RtpSource* source) { + for (size_t i = 0; i < sources.size(); ++i) { + if (sources[i].source_id() == source_id && + sources[i].source_type() == type) { + (*source) = sources[i]; + return true; + } + } + return false; + } + + SimulatedClock fake_clock_; + RTPPayloadRegistry rtp_payload_registry_; + std::unique_ptr rtp_receiver_; +}; + +TEST_F(RtpReceiverTest, GetSources) { + RTPHeader header; + header.payloadType = kPcmuPayloadType; + header.ssrc = 1; + header.timestamp = fake_clock_.TimeInMilliseconds(); + header.numCSRCs = 2; + header.arrOfCSRCs[0] = 111; + header.arrOfCSRCs[1] = 222; + PayloadUnion payload_specific = {AudioPayload()}; + bool in_order = false; + RtpSource source(0, 0, RtpSourceType::SSRC); + + EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(header, kTestPayload, 4, + payload_specific, in_order)); + auto sources = rtp_receiver_->GetSources(); + // One SSRC source and two CSRC sources. + ASSERT_EQ(3u, sources.size()); + ASSERT_TRUE(FindSourceByIdAndType(sources, 1u, RtpSourceType::SSRC, &source)); + EXPECT_EQ(fake_clock_.TimeInMilliseconds(), source.timestamp_ms()); + ASSERT_TRUE( + FindSourceByIdAndType(sources, 222u, RtpSourceType::CSRC, &source)); + EXPECT_EQ(fake_clock_.TimeInMilliseconds(), source.timestamp_ms()); + ASSERT_TRUE( + FindSourceByIdAndType(sources, 111u, RtpSourceType::CSRC, &source)); + EXPECT_EQ(fake_clock_.TimeInMilliseconds(), source.timestamp_ms()); + + // Advance the fake clock and the method is expected to return the + // contributing source object with same source id and updated timestamp. + fake_clock_.AdvanceTimeMilliseconds(1); + EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(header, kTestPayload, 4, + payload_specific, in_order)); + sources = rtp_receiver_->GetSources(); + ASSERT_EQ(3u, sources.size()); + ASSERT_TRUE(FindSourceByIdAndType(sources, 1u, RtpSourceType::SSRC, &source)); + EXPECT_EQ(fake_clock_.TimeInMilliseconds(), source.timestamp_ms()); + ASSERT_TRUE( + FindSourceByIdAndType(sources, 222u, RtpSourceType::CSRC, &source)); + EXPECT_EQ(fake_clock_.TimeInMilliseconds(), source.timestamp_ms()); + ASSERT_TRUE( + FindSourceByIdAndType(sources, 111u, RtpSourceType::CSRC, &source)); + EXPECT_EQ(fake_clock_.TimeInMilliseconds(), source.timestamp_ms()); + + // Test the edge case that the sources are still there just before the + // timeout. + int64_t prev_timestamp = fake_clock_.TimeInMilliseconds(); + fake_clock_.AdvanceTimeMilliseconds(kGetSourcesTimeoutMs); + sources = rtp_receiver_->GetSources(); + ASSERT_EQ(3u, sources.size()); + ASSERT_TRUE(FindSourceByIdAndType(sources, 1u, RtpSourceType::SSRC, &source)); + EXPECT_EQ(prev_timestamp, source.timestamp_ms()); + ASSERT_TRUE( + FindSourceByIdAndType(sources, 222u, RtpSourceType::CSRC, &source)); + EXPECT_EQ(prev_timestamp, source.timestamp_ms()); + ASSERT_TRUE( + FindSourceByIdAndType(sources, 111u, RtpSourceType::CSRC, &source)); + EXPECT_EQ(prev_timestamp, source.timestamp_ms()); + + // Time out. + fake_clock_.AdvanceTimeMilliseconds(1); + sources = rtp_receiver_->GetSources(); + // All the sources should be out of date. + ASSERT_EQ(0u, sources.size()); +} + +// Test the case that the SSRC is changed. +TEST_F(RtpReceiverTest, GetSourcesChangeSSRC) { + int64_t prev_time = -1; + int64_t cur_time = fake_clock_.TimeInMilliseconds(); + RTPHeader header; + header.payloadType = kPcmuPayloadType; + header.ssrc = 1; + header.timestamp = cur_time; + PayloadUnion payload_specific = {AudioPayload()}; + bool in_order = false; + RtpSource source(0, 0, RtpSourceType::SSRC); + + EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(header, kTestPayload, 4, + payload_specific, in_order)); + auto sources = rtp_receiver_->GetSources(); + ASSERT_EQ(1u, sources.size()); + EXPECT_EQ(1u, sources[0].source_id()); + EXPECT_EQ(cur_time, sources[0].timestamp_ms()); + + // The SSRC is changed and the old SSRC is expected to be returned. + fake_clock_.AdvanceTimeMilliseconds(100); + prev_time = cur_time; + cur_time = fake_clock_.TimeInMilliseconds(); + header.ssrc = 2; + header.timestamp = cur_time; + EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(header, kTestPayload, 4, + payload_specific, in_order)); + sources = rtp_receiver_->GetSources(); + ASSERT_EQ(2u, sources.size()); + ASSERT_TRUE(FindSourceByIdAndType(sources, 2u, RtpSourceType::SSRC, &source)); + EXPECT_EQ(cur_time, source.timestamp_ms()); + ASSERT_TRUE(FindSourceByIdAndType(sources, 1u, RtpSourceType::SSRC, &source)); + EXPECT_EQ(prev_time, source.timestamp_ms()); + + // The SSRC is changed again and happen to be changed back to 1. No + // duplication is expected. + fake_clock_.AdvanceTimeMilliseconds(100); + header.ssrc = 1; + header.timestamp = cur_time; + prev_time = cur_time; + cur_time = fake_clock_.TimeInMilliseconds(); + EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(header, kTestPayload, 4, + payload_specific, in_order)); + sources = rtp_receiver_->GetSources(); + ASSERT_EQ(2u, sources.size()); + ASSERT_TRUE(FindSourceByIdAndType(sources, 1u, RtpSourceType::SSRC, &source)); + EXPECT_EQ(cur_time, source.timestamp_ms()); + ASSERT_TRUE(FindSourceByIdAndType(sources, 2u, RtpSourceType::SSRC, &source)); + EXPECT_EQ(prev_time, source.timestamp_ms()); + + // Old SSRC source timeout. + fake_clock_.AdvanceTimeMilliseconds(kGetSourcesTimeoutMs); + cur_time = fake_clock_.TimeInMilliseconds(); + EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(header, kTestPayload, 4, + payload_specific, in_order)); + sources = rtp_receiver_->GetSources(); + ASSERT_EQ(1u, sources.size()); + EXPECT_EQ(1u, sources[0].source_id()); + EXPECT_EQ(cur_time, sources[0].timestamp_ms()); + EXPECT_EQ(RtpSourceType::SSRC, sources[0].source_type()); +} + +TEST_F(RtpReceiverTest, GetSourcesRemoveOutdatedSource) { + int64_t timestamp = fake_clock_.TimeInMilliseconds(); + bool in_order = false; + RTPHeader header; + header.payloadType = kPcmuPayloadType; + header.timestamp = timestamp; + PayloadUnion payload_specific = {AudioPayload()}; + header.numCSRCs = 1; + RtpSource source(0, 0, RtpSourceType::SSRC); + + for (size_t i = 0; i < kSourceListsSize; ++i) { + header.ssrc = i; + header.arrOfCSRCs[0] = (i + 1); + EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(header, kTestPayload, 4, + payload_specific, in_order)); + } + + auto sources = rtp_receiver_->GetSources(); + // Expect |kSourceListsSize| SSRC sources and |kSourceListsSize| CSRC sources. + ASSERT_TRUE(sources.size() == 2 * kSourceListsSize); + for (size_t i = 0; i < kSourceListsSize; ++i) { + // The SSRC source IDs are expected to be 19, 18, 17 ... 0 + ASSERT_TRUE( + FindSourceByIdAndType(sources, i, RtpSourceType::SSRC, &source)); + EXPECT_EQ(timestamp, source.timestamp_ms()); + + // The CSRC source IDs are expected to be 20, 19, 18 ... 1 + ASSERT_TRUE( + FindSourceByIdAndType(sources, (i + 1), RtpSourceType::CSRC, &source)); + EXPECT_EQ(timestamp, source.timestamp_ms()); + } + + fake_clock_.AdvanceTimeMilliseconds(kGetSourcesTimeoutMs); + for (size_t i = 0; i < kSourceListsSize; ++i) { + // The SSRC source IDs are expected to be 19, 18, 17 ... 0 + ASSERT_TRUE( + FindSourceByIdAndType(sources, i, RtpSourceType::SSRC, &source)); + EXPECT_EQ(timestamp, source.timestamp_ms()); + + // The CSRC source IDs are expected to be 20, 19, 18 ... 1 + ASSERT_TRUE( + FindSourceByIdAndType(sources, (i + 1), RtpSourceType::CSRC, &source)); + EXPECT_EQ(timestamp, source.timestamp_ms()); + } + + // Timeout. All the existing objects are out of date and are expected to be + // removed. + fake_clock_.AdvanceTimeMilliseconds(1); + header.ssrc = 111; + header.arrOfCSRCs[0] = 222; + EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(header, kTestPayload, 4, + payload_specific, in_order)); + auto rtp_receiver_impl = static_cast(rtp_receiver_.get()); + auto ssrc_sources = rtp_receiver_impl->ssrc_sources_for_testing(); + ASSERT_EQ(1u, ssrc_sources.size()); + EXPECT_EQ(111u, ssrc_sources.begin()->source_id()); + EXPECT_EQ(RtpSourceType::SSRC, ssrc_sources.begin()->source_type()); + EXPECT_EQ(fake_clock_.TimeInMilliseconds(), + ssrc_sources.begin()->timestamp_ms()); + + auto csrc_sources = rtp_receiver_impl->csrc_sources_for_testing(); + ASSERT_EQ(1u, csrc_sources.size()); + EXPECT_EQ(222u, csrc_sources.begin()->source_id()); + EXPECT_EQ(RtpSourceType::CSRC, csrc_sources.begin()->source_type()); + EXPECT_EQ(fake_clock_.TimeInMilliseconds(), + csrc_sources.begin()->timestamp_ms()); +} + +} // namespace webrtc diff --git a/webrtc/pc/channel.cc b/webrtc/pc/channel.cc index 5634648336..d45e220d5c 100644 --- a/webrtc/pc/channel.cc +++ b/webrtc/pc/channel.cc @@ -23,6 +23,7 @@ #include "webrtc/base/trace_event.h" #include "webrtc/media/base/mediaconstants.h" #include "webrtc/media/base/rtputils.h" +#include "webrtc/media/engine/webrtcvoiceengine.h" #include "webrtc/p2p/base/packettransportinternal.h" #include "webrtc/pc/channelmanager.h" @@ -1676,6 +1677,13 @@ bool VoiceChannel::GetStats(VoiceMediaInfo* stats) { media_channel(), stats)); } +std::vector VoiceChannel::GetSources(uint32_t ssrc) const { + return worker_thread()->Invoke>( + RTC_FROM_HERE, + Bind(&WebRtcVoiceMediaChannel::GetSources, + static_cast(media_channel()), ssrc)); +} + void VoiceChannel::StartMediaMonitor(int cms) { media_monitor_.reset(new VoiceMediaMonitor(media_channel(), worker_thread(), rtc::Thread::Current())); diff --git a/webrtc/pc/channel.h b/webrtc/pc/channel.h index bc98bc9fc8..2bec643b47 100644 --- a/webrtc/pc/channel.h +++ b/webrtc/pc/channel.h @@ -19,6 +19,7 @@ #include #include "webrtc/api/call/audio_sink.h" +#include "webrtc/api/rtpreceiverinterface.h" #include "webrtc/base/asyncinvoker.h" #include "webrtc/base/asyncudpsocket.h" #include "webrtc/base/criticalsection.h" @@ -488,6 +489,8 @@ class VoiceChannel : public BaseChannel { // Get statistics about the current media session. bool GetStats(VoiceMediaInfo* stats); + std::vector GetSources(uint32_t ssrc) const; + // Monitoring functions sigslot::signal2&> SignalConnectionMonitor; @@ -529,7 +532,6 @@ class VoiceChannel : public BaseChannel { void HandleEarlyMediaTimeout(); bool InsertDtmf_w(uint32_t ssrc, int event, int duration); bool SetOutputVolume_w(uint32_t ssrc, double volume); - bool GetStats_w(VoiceMediaInfo* stats); void OnMessage(rtc::Message* pmsg) override; void GetSrtpCryptoSuites_n(std::vector* crypto_suites) const override; diff --git a/webrtc/pc/peerconnection_integrationtest.cc b/webrtc/pc/peerconnection_integrationtest.cc index b4acdaa423..d818300c23 100644 --- a/webrtc/pc/peerconnection_integrationtest.cc +++ b/webrtc/pc/peerconnection_integrationtest.cc @@ -2755,6 +2755,24 @@ TEST_F(PeerConnectionIntegrationTest, CodecNamesAreCaseInsensitive) { kMaxWaitForFramesMs); } +TEST_F(PeerConnectionIntegrationTest, GetSources) { + ASSERT_TRUE(CreatePeerConnectionWrappers()); + ConnectFakeSignaling(); + caller()->AddAudioOnlyMediaStream(); + caller()->CreateAndSetAndSignalOffer(); + ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout); + // Wait for one audio frame received by callee. + ExpectNewFramesReceivedWithWait(0, 0, 1, 0, kMaxWaitForFramesMs); + ASSERT_GT(callee()->pc()->GetReceivers().size(), 0u); + auto receiver = callee()->pc()->GetReceivers()[0]; + ASSERT_EQ(receiver->media_type(), cricket::MEDIA_TYPE_AUDIO); + + auto contributing_sources = receiver->GetSources(); + ASSERT_GT(receiver->GetParameters().encodings.size(), 0u); + EXPECT_EQ(receiver->GetParameters().encodings[0].ssrc, + contributing_sources[0].source_id()); +} + } // namespace #endif // if !defined(THREAD_SANITIZER) diff --git a/webrtc/pc/rtpreceiver.cc b/webrtc/pc/rtpreceiver.cc index 6073b15a97..96974ee9f7 100644 --- a/webrtc/pc/rtpreceiver.cc +++ b/webrtc/pc/rtpreceiver.cc @@ -97,6 +97,10 @@ void AudioRtpReceiver::Stop() { stopped_ = true; } +std::vector AudioRtpReceiver::GetSources() const { + return channel_->GetSources(ssrc_); +} + void AudioRtpReceiver::Reconfigure() { RTC_DCHECK(!stopped_); if (!channel_) { diff --git a/webrtc/pc/rtpreceiver.h b/webrtc/pc/rtpreceiver.h index 513f90c7ab..9853f9824e 100644 --- a/webrtc/pc/rtpreceiver.h +++ b/webrtc/pc/rtpreceiver.h @@ -88,6 +88,8 @@ class AudioRtpReceiver : public ObserverInterface, // Should call SetChannel(nullptr) before |channel| is destroyed. void SetChannel(cricket::VoiceChannel* channel); + std::vector GetSources() const override; + private: void Reconfigure(); void OnFirstPacketReceived(cricket::BaseChannel* channel); diff --git a/webrtc/test/mock_voe_channel_proxy.h b/webrtc/test/mock_voe_channel_proxy.h index a0ccd45647..26645d46d4 100644 --- a/webrtc/test/mock_voe_channel_proxy.h +++ b/webrtc/test/mock_voe_channel_proxy.h @@ -13,9 +13,9 @@ #include +#include "webrtc/modules/rtp_rtcp/source/rtp_packet_received.h" #include "webrtc/test/gmock.h" #include "webrtc/voice_engine/channel_proxy.h" -#include "webrtc/modules/rtp_rtcp/source/rtp_packet_received.h" namespace webrtc { namespace test { @@ -99,6 +99,7 @@ class MockVoEChannelProxy : public voe::ChannelProxy { MOCK_METHOD1(OnTwccBasedUplinkPacketLossRate, void(float packet_loss_rate)); MOCK_METHOD1(OnRecoverableUplinkPacketLossRate, void(float recoverable_packet_loss_rate)); + MOCK_CONST_METHOD0(GetSources, std::vector()); }; } // namespace test } // namespace webrtc diff --git a/webrtc/video/vie_encoder.cc b/webrtc/video/vie_encoder.cc index ecf3a547ee..1ad8253d70 100644 --- a/webrtc/video/vie_encoder.cc +++ b/webrtc/video/vie_encoder.cc @@ -33,7 +33,6 @@ namespace webrtc { namespace { -using DegradationPreference = VideoSendStream::DegradationPreference; // Time interval for logging frame counts. const int64_t kFrameLogIntervalMs = 60000; @@ -152,11 +151,13 @@ class ViEEncoder::VideoSourceProxy { public: explicit VideoSourceProxy(ViEEncoder* vie_encoder) : vie_encoder_(vie_encoder), - degradation_preference_(DegradationPreference::kDegradationDisabled), + degradation_preference_( + VideoSendStream::DegradationPreference::kDegradationDisabled), source_(nullptr) {} - void SetSource(rtc::VideoSourceInterface* source, - const DegradationPreference& degradation_preference) { + void SetSource( + rtc::VideoSourceInterface* source, + const VideoSendStream::DegradationPreference& degradation_preference) { // Called on libjingle's worker thread. RTC_DCHECK_CALLED_SEQUENTIALLY(&main_checker_); rtc::VideoSourceInterface* old_source = nullptr; @@ -192,16 +193,16 @@ class ViEEncoder::VideoSourceProxy { // Clear any constraints from the current sink wants that don't apply to // the used degradation_preference. switch (degradation_preference_) { - case DegradationPreference::kBalanced: + case VideoSendStream::DegradationPreference::kBalanced: FALLTHROUGH(); - case DegradationPreference::kMaintainFramerate: + case VideoSendStream::DegradationPreference::kMaintainFramerate: wants.max_framerate_fps = std::numeric_limits::max(); break; - case DegradationPreference::kMaintainResolution: + case VideoSendStream::DegradationPreference::kMaintainResolution: wants.max_pixel_count = std::numeric_limits::max(); wants.target_pixel_count.reset(); break; - case DegradationPreference::kDegradationDisabled: + case VideoSendStream::DegradationPreference::kDegradationDisabled: wants.max_pixel_count = std::numeric_limits::max(); wants.target_pixel_count.reset(); wants.max_framerate_fps = std::numeric_limits::max(); @@ -302,22 +303,24 @@ class ViEEncoder::VideoSourceProxy { bool IsResolutionScalingEnabledLocked() const EXCLUSIVE_LOCKS_REQUIRED(&crit_) { return degradation_preference_ == - DegradationPreference::kMaintainFramerate || - degradation_preference_ == DegradationPreference::kBalanced; + VideoSendStream::DegradationPreference::kMaintainFramerate || + degradation_preference_ == + VideoSendStream::DegradationPreference::kBalanced; } bool IsFramerateScalingEnabledLocked() const EXCLUSIVE_LOCKS_REQUIRED(&crit_) { // TODO(sprang): Also accept kBalanced here? return degradation_preference_ == - DegradationPreference::kMaintainResolution; + VideoSendStream::DegradationPreference::kMaintainResolution; } rtc::CriticalSection crit_; rtc::SequencedTaskChecker main_checker_; ViEEncoder* const vie_encoder_; rtc::VideoSinkWants sink_wants_ GUARDED_BY(&crit_); - DegradationPreference degradation_preference_ GUARDED_BY(&crit_); + VideoSendStream::DegradationPreference degradation_preference_ + GUARDED_BY(&crit_); rtc::VideoSourceInterface* source_ GUARDED_BY(&crit_); RTC_DISALLOW_COPY_AND_ASSIGN(VideoSourceProxy); @@ -351,7 +354,8 @@ ViEEncoder::ViEEncoder(uint32_t number_of_cores, last_observed_bitrate_bps_(0), encoder_paused_and_dropped_frame_(false), clock_(Clock::GetRealTimeClock()), - degradation_preference_(DegradationPreference::kDegradationDisabled), + degradation_preference_( + VideoSendStream::DegradationPreference::kDegradationDisabled), last_captured_timestamp_(0), delta_ntp_internal_ms_(clock_->CurrentNtpInMilliseconds() - clock_->TimeInMilliseconds()), @@ -377,7 +381,7 @@ ViEEncoder::~ViEEncoder() { void ViEEncoder::Stop() { RTC_DCHECK_RUN_ON(&thread_checker_); - source_proxy_->SetSource(nullptr, DegradationPreference()); + source_proxy_->SetSource(nullptr, VideoSendStream::DegradationPreference()); encoder_queue_.PostTask([this] { RTC_DCHECK_RUN_ON(&encoder_queue_); overuse_detector_.StopCheckForOveruse(); @@ -417,7 +421,8 @@ void ViEEncoder::SetBitrateObserver( void ViEEncoder::SetSource( rtc::VideoSourceInterface* source, - const VideoSendStream::DegradationPreference& degradation_preference) { + const VideoSendStream::VideoSendStream::DegradationPreference& + degradation_preference) { RTC_DCHECK_RUN_ON(&thread_checker_); source_proxy_->SetSource(source, degradation_preference); encoder_queue_.PostTask([this, degradation_preference] { @@ -429,8 +434,10 @@ void ViEEncoder::SetSource( } degradation_preference_ = degradation_preference; bool allow_scaling = - degradation_preference_ == DegradationPreference::kMaintainFramerate || - degradation_preference_ == DegradationPreference::kBalanced; + degradation_preference_ == + VideoSendStream::DegradationPreference::kMaintainFramerate || + degradation_preference_ == + VideoSendStream::DegradationPreference::kBalanced; initial_rampup_ = allow_scaling ? 0 : kMaxInitialFramedrop; ConfigureQualityScaler(); }); @@ -534,8 +541,10 @@ void ViEEncoder::ConfigureQualityScaler() { RTC_DCHECK_RUN_ON(&encoder_queue_); const auto scaling_settings = settings_.encoder->GetScalingSettings(); const bool degradation_preference_allows_scaling = - degradation_preference_ == DegradationPreference::kMaintainFramerate || - degradation_preference_ == DegradationPreference::kBalanced; + degradation_preference_ == + VideoSendStream::DegradationPreference::kMaintainFramerate || + degradation_preference_ == + VideoSendStream::DegradationPreference::kBalanced; const bool quality_scaling_allowed = degradation_preference_allows_scaling && scaling_settings.enabled; @@ -798,9 +807,9 @@ void ViEEncoder::AdaptDown(AdaptReason reason) { int max_downgrades = 0; switch (degradation_preference_) { - case DegradationPreference::kBalanced: + case VideoSendStream::DegradationPreference::kBalanced: FALLTHROUGH(); - case DegradationPreference::kMaintainFramerate: + case VideoSendStream::DegradationPreference::kMaintainFramerate: max_downgrades = kMaxCpuResolutionDowngrades; if (downgrade_requested && adaptation_request.input_pixel_count_ >= @@ -810,7 +819,7 @@ void ViEEncoder::AdaptDown(AdaptReason reason) { return; } break; - case DegradationPreference::kMaintainResolution: + case VideoSendStream::DegradationPreference::kMaintainResolution: max_downgrades = kMaxCpuFramerateDowngrades; if (adaptation_request.framerate_fps_ <= 0 || (downgrade_requested && @@ -824,7 +833,7 @@ void ViEEncoder::AdaptDown(AdaptReason reason) { return; } break; - case DegradationPreference::kDegradationDisabled: + case VideoSendStream::DegradationPreference::kDegradationDisabled: return; } @@ -847,19 +856,19 @@ void ViEEncoder::AdaptDown(AdaptReason reason) { IncrementScaleCounter(reason, 1); switch (degradation_preference_) { - case DegradationPreference::kBalanced: + case VideoSendStream::DegradationPreference::kBalanced: FALLTHROUGH(); - case DegradationPreference::kMaintainFramerate: + case VideoSendStream::DegradationPreference::kMaintainFramerate: source_proxy_->RequestResolutionLowerThan( adaptation_request.input_pixel_count_); LOG(LS_INFO) << "Scaling down resolution."; break; - case DegradationPreference::kMaintainResolution: + case VideoSendStream::DegradationPreference::kMaintainResolution: source_proxy_->RequestFramerateLowerThan( adaptation_request.framerate_fps_); LOG(LS_INFO) << "Scaling down framerate."; break; - case DegradationPreference::kDegradationDisabled: + case VideoSendStream::DegradationPreference::kDegradationDisabled: RTC_NOTREACHED(); } @@ -884,9 +893,9 @@ void ViEEncoder::AdaptUp(AdaptReason reason) { last_adaptation_request_ && last_adaptation_request_->mode_ == AdaptationRequest::Mode::kAdaptUp; switch (degradation_preference_) { - case DegradationPreference::kBalanced: + case VideoSendStream::DegradationPreference::kBalanced: FALLTHROUGH(); - case DegradationPreference::kMaintainFramerate: + case VideoSendStream::DegradationPreference::kMaintainFramerate: if (adapt_up_requested && adaptation_request.input_pixel_count_ <= last_adaptation_request_->input_pixel_count_) { @@ -895,11 +904,11 @@ void ViEEncoder::AdaptUp(AdaptReason reason) { return; } break; - case DegradationPreference::kMaintainResolution: + case VideoSendStream::DegradationPreference::kMaintainResolution: // TODO(sprang): Don't request higher framerate if we are already at // max requested fps? break; - case DegradationPreference::kDegradationDisabled: + case VideoSendStream::DegradationPreference::kDegradationDisabled: return; } @@ -925,9 +934,9 @@ void ViEEncoder::AdaptUp(AdaptReason reason) { const int scale_sum = std::accumulate(current_scale_counters.begin(), current_scale_counters.end(), 0); switch (degradation_preference_) { - case DegradationPreference::kBalanced: + case VideoSendStream::DegradationPreference::kBalanced: FALLTHROUGH(); - case DegradationPreference::kMaintainFramerate: + case VideoSendStream::DegradationPreference::kMaintainFramerate: if (scale_sum == 0) { LOG(LS_INFO) << "Removing resolution down-scaling setting."; source_proxy_->RequestHigherResolutionThan( @@ -938,7 +947,7 @@ void ViEEncoder::AdaptUp(AdaptReason reason) { LOG(LS_INFO) << "Scaling up resolution."; } break; - case DegradationPreference::kMaintainResolution: + case VideoSendStream::DegradationPreference::kMaintainResolution: if (scale_sum == 0) { LOG(LS_INFO) << "Removing framerate down-scaling setting."; source_proxy_->RequestHigherFramerateThan( @@ -949,7 +958,7 @@ void ViEEncoder::AdaptUp(AdaptReason reason) { LOG(LS_INFO) << "Scaling up framerate."; } break; - case DegradationPreference::kDegradationDisabled: + case VideoSendStream::DegradationPreference::kDegradationDisabled: RTC_NOTREACHED(); } diff --git a/webrtc/voice_engine/BUILD.gn b/webrtc/voice_engine/BUILD.gn index 7a4641f849..ca774f2800 100644 --- a/webrtc/voice_engine/BUILD.gn +++ b/webrtc/voice_engine/BUILD.gn @@ -134,6 +134,7 @@ rtc_static_library("voice_engine") { "..:webrtc_common", "../api:audio_mixer_api", "../api:call_api", + "../api:libjingle_peerconnection_api", "../api:transport_api", "../api/audio_codecs:audio_codecs_api", "../api/audio_codecs:builtin_audio_decoder_factory", diff --git a/webrtc/voice_engine/channel.h b/webrtc/voice_engine/channel.h index b43c7379b5..f114d72613 100644 --- a/webrtc/voice_engine/channel.h +++ b/webrtc/voice_engine/channel.h @@ -29,6 +29,7 @@ #include "webrtc/modules/audio_processing/rms_level.h" #include "webrtc/modules/rtp_rtcp/include/remote_ntp_time_estimator.h" #include "webrtc/modules/rtp_rtcp/include/rtp_header_parser.h" +#include "webrtc/modules/rtp_rtcp/include/rtp_receiver.h" #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h" #include "webrtc/voice_engine/audio_level.h" #include "webrtc/voice_engine/file_player.h" @@ -53,7 +54,6 @@ class ReceiveStatistics; class RemoteNtpTimeEstimator; class RtcEventLog; class RTPPayloadRegistry; -class RtpReceiver; class RTPReceiverAudio; class RtpPacketReceived; class RtpRtcp; @@ -403,6 +403,10 @@ class Channel void OnRecoverableUplinkPacketLossRate(float recoverable_packet_loss_rate); + std::vector GetSources() const { + return rtp_receiver_->GetSources(); + } + private: class ProcessAndEncodeAudioTask; diff --git a/webrtc/voice_engine/channel_proxy.cc b/webrtc/voice_engine/channel_proxy.cc index ac96fe98d3..f00548efbf 100644 --- a/webrtc/voice_engine/channel_proxy.cc +++ b/webrtc/voice_engine/channel_proxy.cc @@ -402,6 +402,11 @@ void ChannelProxy::RegisterLegacyReceiveCodecs() { channel()->RegisterLegacyReceiveCodecs(); } +std::vector ChannelProxy::GetSources() const { + RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); + return channel()->GetSources(); +} + 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 d964bd4b5e..829b094cc6 100644 --- a/webrtc/voice_engine/channel_proxy.h +++ b/webrtc/voice_engine/channel_proxy.h @@ -12,6 +12,7 @@ #define WEBRTC_VOICE_ENGINE_CHANNEL_PROXY_H_ #include "webrtc/api/audio/audio_mixer.h" +#include "webrtc/api/rtpreceiverinterface.h" #include "webrtc/base/constructormagic.h" #include "webrtc/base/race_checker.h" #include "webrtc/base/thread_checker.h" @@ -125,6 +126,7 @@ class ChannelProxy { virtual void OnRecoverableUplinkPacketLossRate( float recoverable_packet_loss_rate); virtual void RegisterLegacyReceiveCodecs(); + virtual std::vector GetSources() const; private: Channel* channel() const;