Reland of Implemented the GetSources() in native code. (patchset #1 id:1 of https://codereview.webrtc.org/2809613002/ )

Reason for revert:
Re-land, reverting did not fix bug.

https://bugs.chromium.org/p/webrtc/issues/detail?id=7465

Original issue's description:
> Revert of Implemented the GetSources() in native code. (patchset #11 id:510001 of https://codereview.webrtc.org/2770233003/ )
>
> Reason for revert:
> Suspected of WebRtcApprtcBrowserTest.MANUAL_WorksOnApprtc breakage, see
>
> https://bugs.chromium.org/p/webrtc/issues/detail?id=7465
>
> Original issue's description:
> > Added the GetSources() to the RtpReceiverInterface and implemented
> > it for the AudioRtpReceiver.
> >
> > This method returns a vector of RtpSource(both CSRC source and SSRC
> > source) which contains the ID of a source, the timestamp, the source
> > type (SSRC or CSRC) and the audio level.
> >
> > The RtpSource objects are buffered and maintained by the
> > RtpReceiver in webrtc/modules/rtp_rtcp/. When the method is called,
> > the info of the contributing source will be pulled along the object
> > chain:
> > AudioRtpReceiver -> VoiceChannel -> WebRtcVoiceMediaChannel ->
> > AudioReceiveStream -> voe::Channel -> RtpRtcp module
> >
> > Spec:https://w3c.github.io/webrtc-pc/archives/20151006/webrtc.html#widl-RTCRtpReceiver-getContributingSources-sequence-RTCRtpContributingSource
> >
> > BUG=chromium:703122
> > TBR=stefan@webrtc.org, danilchap@webrtc.org
> >
> > Review-Url: https://codereview.webrtc.org/2770233003
> > Cr-Commit-Position: refs/heads/master@{#17591}
> > Committed: 292084c376
>
> TBR=deadbeef@webrtc.org,solenberg@webrtc.org,hbos@webrtc.org,philipel@webrtc.org,stefan@webrtc.org,danilchap@webrtc.org,zhihuang@webrtc.org
> # Not skipping CQ checks because original CL landed more than 1 days ago.
> BUG=chromium:703122
>
> Review-Url: https://codereview.webrtc.org/2809613002
> Cr-Commit-Position: refs/heads/master@{#17616}
> Committed: fbcc5cb386

TBR=deadbeef@webrtc.org,solenberg@webrtc.org,philipel@webrtc.org,stefan@webrtc.org,danilchap@webrtc.org,zhihuang@webrtc.org,olka@webrtc.org
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=chromium:703122

Review-Url: https://codereview.webrtc.org/2810623003
Cr-Commit-Position: refs/heads/master@{#17621}
This commit is contained in:
hbos 2017-04-10 07:39:05 -07:00 committed by Commit bot
parent b0f7e39fd4
commit 8d609f6b6d
25 changed files with 563 additions and 44 deletions

View File

@ -15,6 +15,7 @@
#define WEBRTC_API_RTPRECEIVERINTERFACE_H_
#include <string>
#include <vector>
#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<int8_t> audio_level() const { return rtc::Optional<int8_t>(); }
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<RtpSource> GetSources() const {
return std::vector<RtpSource>();
}
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<RtpSource>, GetSources);
END_PROXY_MAP()
} // namespace webrtc

View File

@ -12,6 +12,7 @@
#define WEBRTC_API_TEST_MOCK_RTPRECEIVER_H_
#include <string>
#include <vector>
#include "webrtc/api/rtpreceiverinterface.h"
#include "webrtc/test/gmock.h"
@ -27,6 +28,7 @@ class MockRtpReceiver : public rtc::RefCountedObject<RtpReceiverInterface> {
MOCK_CONST_METHOD0(GetParameters, RtpParameters());
MOCK_METHOD1(SetParameters, bool(const RtpParameters&));
MOCK_METHOD1(SetObserver, void(RtpReceiverObserverInterface*));
MOCK_CONST_METHOD0(GetSources, std::vector<RtpSource>());
};
} // namespace webrtc

View File

@ -219,6 +219,11 @@ void AudioReceiveStream::SetGain(float gain) {
channel_proxy_->SetChannelOutputVolumeScaling(gain);
}
std::vector<RtpSource> 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) {

View File

@ -12,6 +12,7 @@
#define WEBRTC_AUDIO_AUDIO_RECEIVE_STREAM_H_
#include <memory>
#include <vector>
#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<AudioSinkInterface> sink) override;
void SetGain(float gain) override;
std::vector<webrtc::RtpSource> GetSources() const override;
// TODO(nisse): Intended to be part of an RtpPacketReceiver interface.
void OnRtpPacket(const RtpPacketReceived& packet);

View File

@ -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",

View File

@ -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<RtpSource> GetSources() const = 0;
protected:
virtual ~AudioReceiveStream() {}
};

View File

@ -97,6 +97,9 @@ class FakeAudioReceiveStream final : public webrtc::AudioReceiveStream {
int GetOutputLevel() const override { return 0; }
void SetSink(std::unique_ptr<webrtc::AudioSinkInterface> sink) override;
void SetGain(float gain) override;
std::vector<webrtc::RtpSource> GetSources() const override {
return std::vector<webrtc::RtpSource>();
}
int id_ = -1;
webrtc::AudioReceiveStream::Config config_;

View File

@ -1581,6 +1581,12 @@ class WebRtcVoiceMediaChannel::WebRtcAudioReceiveStream {
playout_ = playout;
}
std::vector<webrtc::RtpSource> 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<webrtc::RtpSource> 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);

View File

@ -16,6 +16,7 @@
#include <string>
#include <vector>
#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<webrtc::AudioSinkInterface> sink) override;
std::vector<webrtc::RtpSource> GetSources(uint32_t ssrc) const;
// implements Transport interface
bool SendRtp(const uint8_t* data,
size_t len,

View File

@ -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",

View File

@ -11,6 +11,9 @@
#ifndef WEBRTC_MODULES_RTP_RTCP_INCLUDE_RTP_RECEIVER_H_
#define WEBRTC_MODULES_RTP_RTCP_INCLUDE_RTP_RECEIVER_H_
#include <vector>
#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<RtpSource> GetSources() const = 0;
};
} // namespace webrtc

View File

@ -15,6 +15,9 @@
#include <stdlib.h>
#include <string.h>
#include <set>
#include <vector>
#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<RtpSource> RtpReceiverImpl::GetSources() const {
int64_t now_ms = clock_->TimeInMilliseconds();
std::vector<RtpSource> 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<uint32_t> 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<RtpSource>::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<RtpSource>::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

View File

@ -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 <list>
#include <memory>
#include <unordered_map>
#include <vector>
#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<RtpSource> GetSources() const override;
const std::vector<RtpSource>& ssrc_sources_for_testing() const {
return ssrc_sources_;
}
const std::list<RtpSource>& 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<RTPReceiverStrategy> 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<uint32_t, std::list<RtpSource>::iterator>
iterator_by_csrc_;
// The RtpSource objects are sorted chronologically.
std::list<RtpSource> csrc_sources_;
std::vector<RtpSource> ssrc_sources_;
};
} // namespace webrtc
#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_RECEIVER_IMPL_H_

View File

@ -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 <memory>
#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<RtpSource>& 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<RtpReceiver> 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<RtpReceiverImpl*>(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

View File

@ -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<webrtc::RtpSource> VoiceChannel::GetSources(uint32_t ssrc) const {
return worker_thread()->Invoke<std::vector<webrtc::RtpSource>>(
RTC_FROM_HERE,
Bind(&WebRtcVoiceMediaChannel::GetSources,
static_cast<WebRtcVoiceMediaChannel*>(media_channel()), ssrc));
}
void VoiceChannel::StartMediaMonitor(int cms) {
media_monitor_.reset(new VoiceMediaMonitor(media_channel(), worker_thread(),
rtc::Thread::Current()));

View File

@ -19,6 +19,7 @@
#include <vector>
#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<webrtc::RtpSource> GetSources(uint32_t ssrc) const;
// Monitoring functions
sigslot::signal2<VoiceChannel*, const std::vector<ConnectionInfo>&>
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<int>* crypto_suites) const override;

View File

@ -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)

View File

@ -97,6 +97,10 @@ void AudioRtpReceiver::Stop() {
stopped_ = true;
}
std::vector<RtpSource> AudioRtpReceiver::GetSources() const {
return channel_->GetSources(ssrc_);
}
void AudioRtpReceiver::Reconfigure() {
RTC_DCHECK(!stopped_);
if (!channel_) {

View File

@ -88,6 +88,8 @@ class AudioRtpReceiver : public ObserverInterface,
// Should call SetChannel(nullptr) before |channel| is destroyed.
void SetChannel(cricket::VoiceChannel* channel);
std::vector<RtpSource> GetSources() const override;
private:
void Reconfigure();
void OnFirstPacketReceived(cricket::BaseChannel* channel);

View File

@ -13,9 +13,9 @@
#include <string>
#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<RtpSource>());
};
} // namespace test
} // namespace webrtc

View File

@ -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<VideoFrame>* source,
const DegradationPreference& degradation_preference) {
void SetSource(
rtc::VideoSourceInterface<VideoFrame>* source,
const VideoSendStream::DegradationPreference& degradation_preference) {
// Called on libjingle's worker thread.
RTC_DCHECK_CALLED_SEQUENTIALLY(&main_checker_);
rtc::VideoSourceInterface<VideoFrame>* 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<int>::max();
break;
case DegradationPreference::kMaintainResolution:
case VideoSendStream::DegradationPreference::kMaintainResolution:
wants.max_pixel_count = std::numeric_limits<int>::max();
wants.target_pixel_count.reset();
break;
case DegradationPreference::kDegradationDisabled:
case VideoSendStream::DegradationPreference::kDegradationDisabled:
wants.max_pixel_count = std::numeric_limits<int>::max();
wants.target_pixel_count.reset();
wants.max_framerate_fps = std::numeric_limits<int>::max();
@ -298,22 +299,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<VideoFrame>* source_ GUARDED_BY(&crit_);
RTC_DISALLOW_COPY_AND_ASSIGN(VideoSourceProxy);
@ -347,7 +350,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()),
@ -373,7 +377,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();
@ -413,7 +417,8 @@ void ViEEncoder::SetBitrateObserver(
void ViEEncoder::SetSource(
rtc::VideoSourceInterface<VideoFrame>* 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] {
@ -425,8 +430,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();
});
@ -530,8 +537,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;
@ -794,9 +803,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_ >=
@ -806,7 +815,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 &&
@ -820,7 +829,7 @@ void ViEEncoder::AdaptDown(AdaptReason reason) {
return;
}
break;
case DegradationPreference::kDegradationDisabled:
case VideoSendStream::DegradationPreference::kDegradationDisabled:
return;
}
@ -843,19 +852,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();
}
@ -880,9 +889,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_) {
@ -891,11 +900,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;
}
@ -921,9 +930,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(
@ -934,7 +943,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(
@ -945,7 +954,7 @@ void ViEEncoder::AdaptUp(AdaptReason reason) {
LOG(LS_INFO) << "Scaling up framerate.";
}
break;
case DegradationPreference::kDegradationDisabled:
case VideoSendStream::DegradationPreference::kDegradationDisabled:
RTC_NOTREACHED();
}

View File

@ -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",

View File

@ -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<RtpSource> GetSources() const {
return rtp_receiver_->GetSources();
}
private:
class ProcessAndEncodeAudioTask;

View File

@ -402,6 +402,11 @@ void ChannelProxy::RegisterLegacyReceiveCodecs() {
channel()->RegisterLegacyReceiveCodecs();
}
std::vector<RtpSource> 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();

View File

@ -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<webrtc::RtpSource> GetSources() const;
private:
Channel* channel() const;