Enable setting the maximum bitrate limit in RtpSender.

This change allows the application to limit the bitrate of the outgoing
audio and video streams at runtime. The API roughly follows the WebRTC
API draft, defining the RTCRtpParameters structure witn exactly one
encoding (simulcast streams are not exposed in the API for now).
(https://www.w3.org/TR/webrtc/#idl-def-RTCRtpParameters)

BUG=

Review URL: https://codereview.webrtc.org/1788583004

Cr-Commit-Position: refs/heads/master@{#12025}
This commit is contained in:
skvlad 2016-03-16 19:07:43 -07:00 committed by Commit bot
parent df6416aa50
commit dc1c62cd30
20 changed files with 551 additions and 12 deletions

View File

@ -301,6 +301,7 @@
'remoteaudiosource.h',
'remotevideocapturer.cc',
'remotevideocapturer.h',
'rtpparameters.h',
'rtpreceiver.cc',
'rtpreceiver.h',
'rtpreceiverinterface.h',

View File

@ -11,6 +11,7 @@
#ifndef WEBRTC_API_MEDIASTREAMPROVIDER_H_
#define WEBRTC_API_MEDIASTREAMPROVIDER_H_
#include "webrtc/api/rtpsenderinterface.h"
#include "webrtc/base/basictypes.h"
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/media/base/videosinkinterface.h"
@ -62,6 +63,10 @@ class AudioProviderInterface {
uint32_t ssrc,
rtc::scoped_ptr<webrtc::AudioSinkInterface> sink) = 0;
virtual RtpParameters GetAudioRtpParameters(uint32_t ssrc) const = 0;
virtual bool SetAudioRtpParameters(uint32_t ssrc,
const RtpParameters& parameters) = 0;
protected:
virtual ~AudioProviderInterface() {}
};
@ -82,6 +87,10 @@ class VideoProviderInterface {
bool enable,
const cricket::VideoOptions* options) = 0;
virtual RtpParameters GetVideoRtpParameters(uint32_t ssrc) const = 0;
virtual bool SetVideoRtpParameters(uint32_t ssrc,
const RtpParameters& parameters) = 0;
protected:
virtual ~VideoProviderInterface() {}
};

View File

@ -0,0 +1,30 @@
/*
* Copyright 2015 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.
*/
#ifndef WEBRTC_API_RTPPARAMETERS_H_
#define WEBRTC_API_RTPPARAMETERS_H_
#include <vector>
namespace webrtc {
// These structures are defined as part of the RtpSender interface.
// See http://w3c.github.io/webrtc-pc/#rtcrtpsender-interface for details.
struct RtpEncodingParameters {
int max_bitrate_bps = -1;
};
struct RtpParameters {
std::vector<RtpEncodingParameters> encodings;
};
} // namespace webrtc
#endif // WEBRTC_API_RTPPARAMETERS_H_

View File

@ -199,6 +199,14 @@ void AudioRtpSender::SetAudioSend() {
provider_->SetAudioSend(ssrc_, track_->enabled(), options, source);
}
RtpParameters AudioRtpSender::GetParameters() const {
return provider_->GetAudioRtpParameters(ssrc_);
}
bool AudioRtpSender::SetParameters(const RtpParameters& parameters) {
return provider_->SetAudioRtpParameters(ssrc_, parameters);
}
VideoRtpSender::VideoRtpSender(VideoTrackInterface* track,
const std::string& stream_id,
VideoProviderInterface* provider)
@ -330,4 +338,12 @@ void VideoRtpSender::SetVideoSend() {
provider_->SetVideoSend(ssrc_, track_->enabled(), &options);
}
RtpParameters VideoRtpSender::GetParameters() const {
return provider_->GetVideoRtpParameters(ssrc_);
}
bool VideoRtpSender::SetParameters(const RtpParameters& parameters) {
return provider_->SetVideoRtpParameters(ssrc_, parameters);
}
} // namespace webrtc

View File

@ -97,6 +97,9 @@ class AudioRtpSender : public ObserverInterface,
void Stop() override;
RtpParameters GetParameters() const;
bool SetParameters(const RtpParameters& parameters);
private:
bool can_send_track() const { return track_ && ssrc_; }
// Helper function to construct options for
@ -158,6 +161,9 @@ class VideoRtpSender : public ObserverInterface,
void Stop() override;
RtpParameters GetParameters() const;
bool SetParameters(const RtpParameters& parameters);
private:
bool can_send_track() const { return track_ && ssrc_; }
// Helper function to construct options for

View File

@ -18,6 +18,7 @@
#include "webrtc/api/mediastreaminterface.h"
#include "webrtc/api/proxy.h"
#include "webrtc/api/rtpparameters.h"
#include "webrtc/base/refcount.h"
#include "webrtc/base/scoped_ref_ptr.h"
#include "webrtc/pc/mediasession.h"
@ -51,6 +52,9 @@ class RtpSenderInterface : public rtc::RefCountInterface {
virtual void Stop() = 0;
virtual RtpParameters GetParameters() const = 0;
virtual bool SetParameters(const RtpParameters& parameters) = 0;
protected:
virtual ~RtpSenderInterface() {}
};
@ -66,6 +70,8 @@ PROXY_CONSTMETHOD0(std::string, id)
PROXY_METHOD1(void, set_stream_id, const std::string&)
PROXY_CONSTMETHOD0(std::string, stream_id)
PROXY_METHOD0(void, Stop)
PROXY_CONSTMETHOD0(RtpParameters, GetParameters);
PROXY_METHOD1(bool, SetParameters, const RtpParameters&)
END_PROXY()
} // namespace webrtc

View File

@ -27,6 +27,7 @@
using ::testing::_;
using ::testing::Exactly;
using ::testing::Return;
static const char kStreamLabel1[] = "local_stream_1";
static const char kVideoTrackId[] = "video_1";
@ -52,6 +53,9 @@ class MockAudioProvider : public AudioProviderInterface {
const cricket::AudioOptions& options,
cricket::AudioSource* source));
MOCK_METHOD2(SetAudioPlayoutVolume, void(uint32_t ssrc, double volume));
MOCK_CONST_METHOD1(GetAudioRtpParameters, RtpParameters(uint32_t ssrc));
MOCK_METHOD2(SetAudioRtpParameters,
bool(uint32_t ssrc, const RtpParameters&));
void SetRawAudioSink(uint32_t,
rtc::scoped_ptr<AudioSinkInterface> sink) override {
@ -76,6 +80,10 @@ class MockVideoProvider : public VideoProviderInterface {
void(uint32_t ssrc,
bool enable,
const cricket::VideoOptions* options));
MOCK_CONST_METHOD1(GetVideoRtpParameters, RtpParameters(uint32_t ssrc));
MOCK_METHOD2(SetVideoRtpParameters,
bool(uint32_t ssrc, const RtpParameters&));
};
class FakeVideoTrackSource : public VideoTrackSource {
@ -497,4 +505,30 @@ TEST_F(RtpSenderReceiverTest, VideoSenderSsrcChanged) {
EXPECT_CALL(video_provider_, SetVideoSend(kVideoSsrc2, false, _)).Times(1);
}
TEST_F(RtpSenderReceiverTest, AudioSenderCanSetParameters) {
CreateAudioRtpSender();
EXPECT_CALL(audio_provider_, GetAudioRtpParameters(kAudioSsrc))
.WillOnce(Return(RtpParameters()));
EXPECT_CALL(audio_provider_, SetAudioRtpParameters(kAudioSsrc, _))
.WillOnce(Return(true));
RtpParameters params = audio_rtp_sender_->GetParameters();
EXPECT_TRUE(audio_rtp_sender_->SetParameters(params));
DestroyAudioRtpSender();
}
TEST_F(RtpSenderReceiverTest, VideoSenderCanSetParameters) {
CreateVideoRtpSender();
EXPECT_CALL(video_provider_, GetVideoRtpParameters(kVideoSsrc))
.WillOnce(Return(RtpParameters()));
EXPECT_CALL(video_provider_, SetVideoRtpParameters(kVideoSsrc, _))
.WillOnce(Return(true));
RtpParameters params = video_rtp_sender_->GetParameters();
EXPECT_TRUE(video_rtp_sender_->SetParameters(params));
DestroyVideoRtpSender();
}
} // namespace webrtc

View File

@ -1244,6 +1244,23 @@ void WebRtcSession::SetRawAudioSink(uint32_t ssrc,
voice_channel_->SetRawAudioSink(ssrc, rtc::ScopedToUnique(std::move(sink)));
}
RtpParameters WebRtcSession::GetAudioRtpParameters(uint32_t ssrc) const {
ASSERT(signaling_thread()->IsCurrent());
if (voice_channel_) {
return voice_channel_->GetRtpParameters(ssrc);
}
return RtpParameters();
}
bool WebRtcSession::SetAudioRtpParameters(uint32_t ssrc,
const RtpParameters& parameters) {
ASSERT(signaling_thread()->IsCurrent());
if (!voice_channel_) {
return false;
}
return voice_channel_->SetRtpParameters(ssrc, parameters);
}
bool WebRtcSession::SetCaptureDevice(uint32_t ssrc,
cricket::VideoCapturer* camera) {
ASSERT(signaling_thread()->IsCurrent());
@ -1297,6 +1314,23 @@ void WebRtcSession::SetVideoSend(uint32_t ssrc,
}
}
RtpParameters WebRtcSession::GetVideoRtpParameters(uint32_t ssrc) const {
ASSERT(signaling_thread()->IsCurrent());
if (video_channel_) {
return video_channel_->GetRtpParameters(ssrc);
}
return RtpParameters();
}
bool WebRtcSession::SetVideoRtpParameters(uint32_t ssrc,
const RtpParameters& parameters) {
ASSERT(signaling_thread()->IsCurrent());
if (!video_channel_) {
return false;
}
return video_channel_->SetRtpParameters(ssrc, parameters);
}
bool WebRtcSession::CanInsertDtmf(const std::string& track_id) {
ASSERT(signaling_thread()->IsCurrent());
if (!voice_channel_) {

View File

@ -245,6 +245,10 @@ class WebRtcSession : public AudioProviderInterface,
void SetRawAudioSink(uint32_t ssrc,
rtc::scoped_ptr<AudioSinkInterface> sink) override;
RtpParameters GetAudioRtpParameters(uint32_t ssrc) const override;
bool SetAudioRtpParameters(uint32_t ssrc,
const RtpParameters& parameters) override;
// Implements VideoMediaProviderInterface.
bool SetCaptureDevice(uint32_t ssrc, cricket::VideoCapturer* camera) override;
void SetVideoPlayout(
@ -255,6 +259,10 @@ class WebRtcSession : public AudioProviderInterface,
bool enable,
const cricket::VideoOptions* options) override;
RtpParameters GetVideoRtpParameters(uint32_t ssrc) const override;
bool SetVideoRtpParameters(uint32_t ssrc,
const RtpParameters& parameters) override;
// Implements DtmfProviderInterface.
virtual bool CanInsertDtmf(const std::string& track_id);
virtual bool InsertDtmf(const std::string& track_id,

View File

@ -3385,6 +3385,25 @@ TEST_F(WebRtcSessionTest, SetAudioPlayout) {
EXPECT_EQ(1, volume);
}
TEST_F(WebRtcSessionTest, AudioMaxSendBitrateNotImplemented) {
// This test verifies that RtpParameters for audio RtpSenders cannot be
// changed.
// TODO(skvlad): Update the test after adding support for bitrate limiting in
// WebRtcAudioSendStream.
Init();
SendAudioVideoStream1();
CreateAndSetRemoteOfferAndLocalAnswer();
cricket::FakeVoiceMediaChannel* channel = media_engine_->GetVoiceChannel(0);
ASSERT_TRUE(channel != NULL);
uint32_t send_ssrc = channel->send_streams()[0].first_ssrc();
webrtc::RtpParameters params = session_->GetAudioRtpParameters(send_ssrc);
EXPECT_EQ(0, params.encodings.size());
params.encodings.push_back(webrtc::RtpEncodingParameters());
EXPECT_FALSE(session_->SetAudioRtpParameters(send_ssrc, params));
}
TEST_F(WebRtcSessionTest, SetAudioSend) {
Init();
SendAudioVideoStream1();
@ -3451,6 +3470,34 @@ TEST_F(WebRtcSessionTest, SetVideoPlayout) {
EXPECT_TRUE(channel->sinks().begin()->second == NULL);
}
TEST_F(WebRtcSessionTest, SetVideoMaxSendBitrate) {
Init();
SendAudioVideoStream1();
CreateAndSetRemoteOfferAndLocalAnswer();
cricket::FakeVideoMediaChannel* channel = media_engine_->GetVideoChannel(0);
ASSERT_TRUE(channel != NULL);
uint32_t send_ssrc = channel->send_streams()[0].first_ssrc();
EXPECT_EQ(-1, channel->max_bps());
webrtc::RtpParameters params = session_->GetVideoRtpParameters(send_ssrc);
EXPECT_EQ(1, params.encodings.size());
EXPECT_EQ(-1, params.encodings[0].max_bitrate_bps);
params.encodings[0].max_bitrate_bps = 1000;
EXPECT_TRUE(session_->SetVideoRtpParameters(send_ssrc, params));
// Read back the parameters and verify they have been changed.
params = session_->GetVideoRtpParameters(send_ssrc);
EXPECT_EQ(1, params.encodings.size());
EXPECT_EQ(1000, params.encodings[0].max_bitrate_bps);
// Verify that the video channel received the new parameters.
params = channel->GetRtpParameters(send_ssrc);
EXPECT_EQ(1, params.encodings.size());
EXPECT_EQ(1000, params.encodings[0].max_bitrate_bps);
// Verify that the global bitrate limit has not been changed.
EXPECT_EQ(-1, channel->max_bps());
}
TEST_F(WebRtcSessionTest, SetVideoSend) {
Init();
SendAudioVideoStream1();

View File

@ -96,9 +96,14 @@ template <class Base> class RtpHelper : public Base {
return false;
}
send_streams_.push_back(sp);
rtp_parameters_[sp.first_ssrc()] = CreateRtpParametersWithOneEncoding();
return true;
}
virtual bool RemoveSendStream(uint32_t ssrc) {
auto parameters_iterator = rtp_parameters_.find(ssrc);
if (parameters_iterator != rtp_parameters_.end()) {
rtp_parameters_.erase(parameters_iterator);
}
return RemoveStreamBySsrc(&send_streams_, ssrc);
}
virtual bool AddRecvStream(const StreamParams& sp) {
@ -112,6 +117,26 @@ template <class Base> class RtpHelper : public Base {
virtual bool RemoveRecvStream(uint32_t ssrc) {
return RemoveStreamBySsrc(&receive_streams_, ssrc);
}
virtual webrtc::RtpParameters GetRtpParameters(uint32_t ssrc) const {
auto parameters_iterator = rtp_parameters_.find(ssrc);
if (parameters_iterator != rtp_parameters_.end()) {
return parameters_iterator->second;
}
return webrtc::RtpParameters();
}
virtual bool SetRtpParameters(uint32_t ssrc,
const webrtc::RtpParameters& parameters) {
auto parameters_iterator = rtp_parameters_.find(ssrc);
if (parameters_iterator != rtp_parameters_.end()) {
parameters_iterator->second = parameters;
return true;
}
// Replicate the behavior of the real media channel: return false
// when setting parameters for unknown SSRCs.
return false;
}
bool IsStreamMuted(uint32_t ssrc) const {
bool ret = muted_streams_.find(ssrc) != muted_streams_.end();
// If |ssrc = 0| check if the first send stream is muted.
@ -204,6 +229,7 @@ template <class Base> class RtpHelper : public Base {
std::vector<StreamParams> send_streams_;
std::vector<StreamParams> receive_streams_;
std::set<uint32_t> muted_streams_;
std::map<uint32_t, webrtc::RtpParameters> rtp_parameters_;
bool fail_set_send_codecs_;
bool fail_set_recv_codecs_;
uint32_t send_ssrc_;
@ -224,8 +250,7 @@ class FakeVoiceMediaChannel : public RtpHelper<VoiceMediaChannel> {
};
explicit FakeVoiceMediaChannel(FakeVoiceEngine* engine,
const AudioOptions& options)
: engine_(engine),
time_since_last_typing_(-1) {
: engine_(engine), time_since_last_typing_(-1), max_bps_(-1) {
output_scalings_[0] = 1.0; // For default channel.
SetOptions(options);
}
@ -237,7 +262,7 @@ class FakeVoiceMediaChannel : public RtpHelper<VoiceMediaChannel> {
return dtmf_info_queue_;
}
const AudioOptions& options() const { return options_; }
int max_bps() const { return max_bps_; }
virtual bool SetSendParameters(const AudioSendParameters& params) {
return (SetSendCodecs(params.codecs) &&
SetSendRtpHeaderExtensions(params.extensions) &&
@ -249,6 +274,7 @@ class FakeVoiceMediaChannel : public RtpHelper<VoiceMediaChannel> {
return (SetRecvCodecs(params.codecs) &&
SetRecvRtpHeaderExtensions(params.extensions));
}
virtual bool SetPlayout(bool playout) {
set_playout(playout);
return true;
@ -374,7 +400,10 @@ class FakeVoiceMediaChannel : public RtpHelper<VoiceMediaChannel> {
send_codecs_ = codecs;
return true;
}
bool SetMaxSendBandwidth(int bps) { return true; }
bool SetMaxSendBandwidth(int bps) {
max_bps_ = bps;
return true;
}
bool SetOptions(const AudioOptions& options) {
// Does a "merge" of current options and set options.
options_.SetAll(options);
@ -407,6 +436,7 @@ class FakeVoiceMediaChannel : public RtpHelper<VoiceMediaChannel> {
AudioOptions options_;
std::map<uint32_t, VoiceChannelAudioSink*> local_sinks_;
std::unique_ptr<webrtc::AudioSinkInterface> sink_;
int max_bps_;
};
// A helper function to compare the FakeVoiceMediaChannel::DtmfInfo.
@ -443,7 +473,6 @@ class FakeVideoMediaChannel : public RtpHelper<VideoMediaChannel> {
SetSendRtpHeaderExtensions(params.extensions) &&
SetMaxSendBandwidth(params.max_bandwidth_bps));
}
virtual bool SetRecvParameters(const VideoRecvParameters& params) {
return (SetRecvCodecs(params.codecs) &&
SetRecvRtpHeaderExtensions(params.extensions));

View File

@ -15,6 +15,7 @@
#include <string>
#include <vector>
#include "webrtc/api/rtpparameters.h"
#include "webrtc/base/basictypes.h"
#include "webrtc/base/buffer.h"
#include "webrtc/base/dscp.h"
@ -79,6 +80,17 @@ static std::string VectorToString(const std::vector<T>& vals) {
return ost.str();
}
template <typename T>
static T MinPositive(T a, T b) {
if (a <= 0) {
return b;
}
if (b <= 0) {
return a;
}
return std::min(a, b);
}
// Construction-time settings, passed to
// MediaControllerInterface::Create, and passed on when creating
// MediaChannels.
@ -975,6 +987,9 @@ class VideoMediaChannel : public MediaChannel {
virtual bool SetSendParameters(const VideoSendParameters& params) = 0;
virtual bool SetRecvParameters(const VideoRecvParameters& params) = 0;
virtual webrtc::RtpParameters GetRtpParameters(uint32_t ssrc) const = 0;
virtual bool SetRtpParameters(uint32_t ssrc,
const webrtc::RtpParameters& parameters) = 0;
// Gets the currently set codecs/payload types to be used for outgoing media.
virtual bool GetSendCodec(VideoCodec* send_codec) = 0;
// Starts or stops transmission (and potentially capture) of local video.

View File

@ -35,3 +35,14 @@ MediaEngineFactory::MediaEngineCreateFunction
}; // namespace cricket
#endif // DISABLE_MEDIA_ENGINE_FACTORY
namespace cricket {
webrtc::RtpParameters CreateRtpParametersWithOneEncoding() {
webrtc::RtpParameters parameters;
webrtc::RtpEncodingParameters encoding;
parameters.encodings.push_back(encoding);
return parameters;
}
}; // namespace cricket

View File

@ -19,6 +19,7 @@
#include <vector>
#include "webrtc/audio_state.h"
#include "webrtc/api/rtpparameters.h"
#include "webrtc/base/fileutils.h"
#include "webrtc/base/sigslotrepeater.h"
#include "webrtc/media/base/codec.h"
@ -204,6 +205,8 @@ class DataEngineInterface {
virtual const std::vector<DataCodec>& data_codecs() = 0;
};
webrtc::RtpParameters CreateRtpParametersWithOneEncoding();
} // namespace cricket
#endif // WEBRTC_MEDIA_BASE_MEDIAENGINE_H_

View File

@ -818,6 +818,32 @@ bool WebRtcVideoChannel2::SetSendParameters(const VideoSendParameters& params) {
send_params_ = params;
return true;
}
webrtc::RtpParameters WebRtcVideoChannel2::GetRtpParameters(
uint32_t ssrc) const {
rtc::CritScope stream_lock(&stream_crit_);
auto it = send_streams_.find(ssrc);
if (it == send_streams_.end()) {
LOG(LS_WARNING) << "Attempting to get RTP parameters for stream with ssrc "
<< ssrc << " which doesn't exist.";
return webrtc::RtpParameters();
}
return it->second->rtp_parameters();
}
bool WebRtcVideoChannel2::SetRtpParameters(
uint32_t ssrc,
const webrtc::RtpParameters& parameters) {
rtc::CritScope stream_lock(&stream_crit_);
auto it = send_streams_.find(ssrc);
if (it == send_streams_.end()) {
LOG(LS_ERROR) << "Attempting to set RTP parameters for stream with ssrc "
<< ssrc << " which doesn't exist.";
return false;
}
return it->second->SetRtpParameters(parameters);
}
bool WebRtcVideoChannel2::GetChangedRecvParameters(
const VideoRecvParameters& params,
@ -1476,6 +1502,7 @@ WebRtcVideoChannel2::WebRtcVideoSendStream::WebRtcVideoSendStream(
external_encoder_factory_(external_encoder_factory),
stream_(nullptr),
parameters_(config, options, max_bitrate_bps, codec_settings),
rtp_parameters_(CreateRtpParametersWithOneEncoding()),
pending_encoder_reconfiguration_(false),
allocated_encoder_(nullptr, webrtc::kVideoCodecUnknown, false),
sending_(false),
@ -1763,8 +1790,6 @@ void WebRtcVideoChannel2::WebRtcVideoSendStream::SetSendParameters(
recreate_stream = true;
}
if (params.max_bandwidth_bps) {
// Max bitrate has changed, reconfigure encoder settings on the next frame
// or stream recreation.
parameters_.max_bitrate_bps = *params.max_bandwidth_bps;
pending_encoder_reconfiguration_ = true;
}
@ -1798,6 +1823,31 @@ void WebRtcVideoChannel2::WebRtcVideoSendStream::SetSendParameters(
}
}
bool WebRtcVideoChannel2::WebRtcVideoSendStream::SetRtpParameters(
const webrtc::RtpParameters& new_parameters) {
if (!ValidateRtpParameters(new_parameters)) {
return false;
}
rtc::CritScope cs(&lock_);
if (new_parameters.encodings[0].max_bitrate_bps !=
rtp_parameters_.encodings[0].max_bitrate_bps) {
pending_encoder_reconfiguration_ = true;
}
rtp_parameters_ = new_parameters;
return true;
}
bool WebRtcVideoChannel2::WebRtcVideoSendStream::ValidateRtpParameters(
const webrtc::RtpParameters& rtp_parameters) {
if (rtp_parameters.encodings.size() != 1) {
LOG(LS_ERROR)
<< "Attempted to set RtpParameters without exactly one encoding";
return false;
}
return true;
}
webrtc::VideoEncoderConfig
WebRtcVideoChannel2::WebRtcVideoSendStream::CreateVideoEncoderConfig(
const Dimensions& dimensions,
@ -1837,9 +1887,11 @@ WebRtcVideoChannel2::WebRtcVideoSendStream::CreateVideoEncoderConfig(
stream_count = 1;
}
encoder_config.streams =
CreateVideoStreams(clamped_codec, parameters_.options,
parameters_.max_bitrate_bps, stream_count);
int stream_max_bitrate =
MinPositive(rtp_parameters_.encodings[0].max_bitrate_bps,
parameters_.max_bitrate_bps);
encoder_config.streams = CreateVideoStreams(
clamped_codec, parameters_.options, stream_max_bitrate, stream_count);
// Conference mode screencast uses 2 temporal layers split at 100kbit.
if (parameters_.conference_mode && is_screencast &&

View File

@ -145,6 +145,9 @@ class WebRtcVideoChannel2 : public VideoMediaChannel, public webrtc::Transport {
bool SetSendParameters(const VideoSendParameters& params) override;
bool SetRecvParameters(const VideoRecvParameters& params) override;
webrtc::RtpParameters GetRtpParameters(uint32_t ssrc) const override;
bool SetRtpParameters(uint32_t ssrc,
const webrtc::RtpParameters& parameters) override;
bool GetSendCodec(VideoCodec* send_codec) override;
bool SetSend(bool send) override;
bool SetVideoSend(uint32_t ssrc,
@ -245,6 +248,7 @@ class WebRtcVideoChannel2 : public VideoMediaChannel, public webrtc::Transport {
void SetOptions(const VideoOptions& options);
// TODO(pbos): Move logic from SetOptions into this method.
void SetSendParameters(const ChangedSendParameters& send_params);
bool SetRtpParameters(const webrtc::RtpParameters& parameters);
void OnFrame(const cricket::VideoFrame& frame) override;
bool SetCapturer(VideoCapturer* capturer);
@ -254,6 +258,8 @@ class WebRtcVideoChannel2 : public VideoMediaChannel, public webrtc::Transport {
void Start();
void Stop();
webrtc::RtpParameters rtp_parameters() const { return rtp_parameters_; }
// Implements webrtc::LoadObserver.
void OnLoadUpdate(Load load) override;
@ -338,6 +344,7 @@ class WebRtcVideoChannel2 : public VideoMediaChannel, public webrtc::Transport {
const VideoCodec& codec) const EXCLUSIVE_LOCKS_REQUIRED(lock_);
void SetDimensions(int width, int height)
EXCLUSIVE_LOCKS_REQUIRED(lock_);
bool ValidateRtpParameters(const webrtc::RtpParameters& parameters);
rtc::ThreadChecker thread_checker_;
rtc::AsyncInvoker invoker_;
@ -358,7 +365,15 @@ class WebRtcVideoChannel2 : public VideoMediaChannel, public webrtc::Transport {
rtc::CriticalSection lock_;
webrtc::VideoSendStream* stream_ GUARDED_BY(lock_);
// Contains settings that are the same for all streams in the MediaChannel,
// such as codecs, header extensions, and the global bitrate limit for the
// entire channel.
VideoSendStreamParameters parameters_ GUARDED_BY(lock_);
// Contains settings that are unique for each stream, such as max_bitrate.
// TODO(skvlad): Move ssrcs_ and ssrc_groups_ into rtp_parameters_.
// TODO(skvlad): Combine parameters_ and rtp_parameters_ once we have only
// one stream per MediaChannel.
webrtc::RtpParameters rtp_parameters_;
bool pending_encoder_reconfiguration_ GUARDED_BY(lock_);
VideoEncoderSettings encoder_settings_ GUARDED_BY(lock_);
AllocatedEncoder allocated_encoder_ GUARDED_BY(lock_);

View File

@ -1080,6 +1080,38 @@ class WebRtcVideoChannel2Test : public WebRtcVideoEngine2Test {
return AddSendStream(CreateSimStreamParams("cname", ssrcs));
}
int GetMaxEncoderBitrate(cricket::FakeVideoCapturer& capturer) {
EXPECT_TRUE(capturer.CaptureFrame());
std::vector<FakeVideoSendStream*> streams =
fake_call_->GetVideoSendStreams();
EXPECT_TRUE(streams.size() > 0);
FakeVideoSendStream* stream = streams[streams.size() - 1];
webrtc::VideoEncoderConfig encoder_config = stream->GetEncoderConfig();
EXPECT_EQ(1, encoder_config.streams.size());
return encoder_config.streams[0].max_bitrate_bps;
}
void SetAndExpectMaxBitrate(cricket::FakeVideoCapturer& capturer,
int global_max,
int stream_max,
int expected_encoder_bitrate) {
VideoSendParameters limited_send_params = send_parameters_;
limited_send_params.max_bandwidth_bps = global_max;
EXPECT_TRUE(channel_->SetSendParameters(limited_send_params));
webrtc::RtpParameters parameters = channel_->GetRtpParameters(last_ssrc_);
EXPECT_EQ(1UL, parameters.encodings.size());
parameters.encodings[0].max_bitrate_bps = stream_max;
EXPECT_TRUE(channel_->SetRtpParameters(last_ssrc_, parameters));
// Read back the parameteres and verify they have the correct value
parameters = channel_->GetRtpParameters(last_ssrc_);
EXPECT_EQ(1UL, parameters.encodings.size());
EXPECT_EQ(stream_max, parameters.encodings[0].max_bitrate_bps);
// Verify that the new value propagated down to the encoder
EXPECT_EQ(expected_encoder_bitrate, GetMaxEncoderBitrate(capturer));
}
std::unique_ptr<FakeCall> fake_call_;
std::unique_ptr<VideoMediaChannel> channel_;
cricket::VideoSendParameters send_parameters_;
@ -3113,6 +3145,66 @@ TEST_F(WebRtcVideoChannel2Test, RedRtxPacketDoesntCreateUnsignalledStream) {
TestReceiveUnsignalledSsrcPacket(kRedRtxPayloadType, false);
}
TEST_F(WebRtcVideoChannel2Test, CanSentMaxBitrateForExistingStream) {
AddSendStream();
cricket::FakeVideoCapturer capturer;
EXPECT_TRUE(channel_->SetCapturer(last_ssrc_, &capturer));
cricket::VideoFormat capture_format_hd =
capturer.GetSupportedFormats()->front();
EXPECT_EQ(1280, capture_format_hd.width);
EXPECT_EQ(720, capture_format_hd.height);
EXPECT_EQ(cricket::CS_RUNNING, capturer.Start(capture_format_hd));
EXPECT_TRUE(channel_->SetSend(true));
int default_encoder_bitrate = GetMaxEncoderBitrate(capturer);
EXPECT_TRUE(default_encoder_bitrate > 1000);
// TODO(skvlad): Resolve the inconsistency between the interpretation
// of the global bitrate limit for audio and video:
// - Audio: max_bandwidth_bps = 0 - fail the operation,
// max_bandwidth_bps = -1 - remove the bandwidth limit
// - Video: max_bandwidth_bps = 0 - remove the bandwidth limit,
// max_bandwidth_bps = -1 - do not change the previously set
// limit.
SetAndExpectMaxBitrate(capturer, 1000, 0, 1000);
SetAndExpectMaxBitrate(capturer, 1000, 800, 800);
SetAndExpectMaxBitrate(capturer, 600, 800, 600);
SetAndExpectMaxBitrate(capturer, 0, 800, 800);
SetAndExpectMaxBitrate(capturer, 0, 0, default_encoder_bitrate);
EXPECT_TRUE(channel_->SetCapturer(last_ssrc_, NULL));
}
TEST_F(WebRtcVideoChannel2Test, CannotSetMaxBitrateForNonexistentStream) {
webrtc::RtpParameters nonexistent_parameters =
channel_->GetRtpParameters(last_ssrc_);
EXPECT_EQ(0, nonexistent_parameters.encodings.size());
nonexistent_parameters.encodings.push_back(webrtc::RtpEncodingParameters());
EXPECT_FALSE(channel_->SetRtpParameters(last_ssrc_, nonexistent_parameters));
}
TEST_F(WebRtcVideoChannel2Test,
CannotSetRtpParametersWithIncorrectNumberOfEncodings) {
// This test verifies that setting RtpParameters succeeds only if
// the structure contains exactly one encoding.
// TODO(skvlad): Update this test when we strat supporting setting parameters
// for each encoding individually.
AddSendStream();
// Setting RtpParameters with no encoding is expected to fail.
webrtc::RtpParameters parameters;
EXPECT_FALSE(channel_->SetRtpParameters(last_ssrc_, parameters));
// Setting RtpParameters with exactly one encoding should succeed.
parameters.encodings.push_back(webrtc::RtpEncodingParameters());
EXPECT_TRUE(channel_->SetRtpParameters(last_ssrc_, parameters));
// Two or more encodings should result in failure.
parameters.encodings.push_back(webrtc::RtpEncodingParameters());
EXPECT_FALSE(channel_->SetRtpParameters(last_ssrc_, parameters));
}
void WebRtcVideoChannel2Test::TestReceiverLocalSsrcConfiguration(
bool receiver_first) {
EXPECT_TRUE(channel_->SetSendParameters(send_parameters_));

View File

@ -1384,6 +1384,30 @@ void VoiceChannel::SetRawAudioSink(
InvokeOnWorker(Bind(&SetRawAudioSink_w, media_channel(), ssrc, &sink));
}
webrtc::RtpParameters VoiceChannel::GetRtpParameters(uint32_t ssrc) const {
return worker_thread()->Invoke<webrtc::RtpParameters>(
Bind(&VoiceChannel::GetRtpParameters_w, this, ssrc));
}
webrtc::RtpParameters VoiceChannel::GetRtpParameters_w(uint32_t ssrc) const {
// Not yet implemented.
// TODO(skvlad): Add support for limiting send bitrate for audio channels.
return webrtc::RtpParameters();
}
bool VoiceChannel::SetRtpParameters(uint32_t ssrc,
const webrtc::RtpParameters& parameters) {
return InvokeOnWorker(
Bind(&VoiceChannel::SetRtpParameters_w, this, ssrc, parameters));
}
bool VoiceChannel::SetRtpParameters_w(uint32_t ssrc,
webrtc::RtpParameters parameters) {
// Not yet implemented.
// TODO(skvlad): Add support for limiting send bitrate for audio channels.
return false;
}
bool VoiceChannel::GetStats(VoiceMediaInfo* stats) {
return InvokeOnWorker(Bind(&VoiceMediaChannel::GetStats,
media_channel(), stats));
@ -1536,7 +1560,9 @@ bool VoiceChannel::SetRemoteContent_w(const MediaContentDescription* content,
if (audio->agc_minus_10db()) {
send_params.options.adjust_agc_delta = rtc::Optional<int>(kAgcMinus10db);
}
if (!media_channel()->SetSendParameters(send_params)) {
bool parameters_applied = media_channel()->SetSendParameters(send_params);
if (!parameters_applied) {
SafeSetError("Failed to set remote audio description send parameters.",
error_desc);
return false;
@ -1661,6 +1687,25 @@ bool VideoChannel::SetVideoSend(uint32_t ssrc,
ssrc, mute, options));
}
webrtc::RtpParameters VideoChannel::GetRtpParameters(uint32_t ssrc) const {
return worker_thread()->Invoke<webrtc::RtpParameters>(
Bind(&VideoChannel::GetRtpParameters_w, this, ssrc));
}
webrtc::RtpParameters VideoChannel::GetRtpParameters_w(uint32_t ssrc) const {
return media_channel()->GetRtpParameters(ssrc);
}
bool VideoChannel::SetRtpParameters(uint32_t ssrc,
const webrtc::RtpParameters& parameters) {
return InvokeOnWorker(
Bind(&VideoChannel::SetRtpParameters_w, this, ssrc, parameters));
}
bool VideoChannel::SetRtpParameters_w(uint32_t ssrc,
webrtc::RtpParameters parameters) {
return media_channel()->SetRtpParameters(ssrc, parameters);
}
void VideoChannel::ChangeState() {
// Send outgoing data if we're the active call, we have the remote content,
// and we have had some form of connectivity.
@ -1768,7 +1813,10 @@ bool VideoChannel::SetRemoteContent_w(const MediaContentDescription* content,
if (video->conference_mode()) {
send_params.conference_mode = true;
}
if (!media_channel()->SetSendParameters(send_params)) {
bool parameters_applied = media_channel()->SetSendParameters(send_params);
if (!parameters_applied) {
SafeSetError("Failed to set remote video description send parameters.",
error_desc);
return false;

View File

@ -361,6 +361,8 @@ class VoiceChannel : public BaseChannel {
bool SetOutputVolume(uint32_t ssrc, double volume);
void SetRawAudioSink(uint32_t ssrc,
std::unique_ptr<webrtc::AudioSinkInterface> sink);
webrtc::RtpParameters GetRtpParameters(uint32_t ssrc) const;
bool SetRtpParameters(uint32_t ssrc, const webrtc::RtpParameters& parameters);
// Get statistics about the current media session.
bool GetStats(VoiceMediaInfo* stats);
@ -381,6 +383,8 @@ class VoiceChannel : public BaseChannel {
int GetInputLevel_w();
int GetOutputLevel_w();
void GetActiveStreams_w(AudioInfo::StreamList* actives);
webrtc::RtpParameters GetRtpParameters_w(uint32_t ssrc) const;
bool SetRtpParameters_w(uint32_t ssrc, webrtc::RtpParameters parameters);
private:
// overrides from BaseChannel
@ -452,6 +456,8 @@ class VideoChannel : public BaseChannel {
sigslot::signal2<VideoChannel*, const VideoMediaInfo&> SignalMediaMonitor;
bool SetVideoSend(uint32_t ssrc, bool enable, const VideoOptions* options);
webrtc::RtpParameters GetRtpParameters(uint32_t ssrc) const;
bool SetRtpParameters(uint32_t ssrc, const webrtc::RtpParameters& parameters);
private:
// overrides from BaseChannel
@ -464,6 +470,8 @@ class VideoChannel : public BaseChannel {
ContentAction action,
std::string* error_desc);
bool GetStats_w(VideoMediaInfo* stats);
webrtc::RtpParameters GetRtpParameters_w(uint32_t ssrc) const;
bool SetRtpParameters_w(uint32_t ssrc, webrtc::RtpParameters parameters);
virtual void OnMessage(rtc::Message* pmsg);
virtual void GetSrtpCryptoSuites(std::vector<int>* crypto_suites) const;

View File

@ -1769,6 +1769,53 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
EXPECT_FALSE(media_channel1_->ready_to_send());
}
bool SetRemoteContentWithBitrateLimit(int remote_limit) {
typename T::Content content;
CreateContent(0, kPcmuCodec, kH264Codec, &content);
content.set_bandwidth(remote_limit);
return channel1_->SetRemoteContent(&content, CA_OFFER, NULL);
}
webrtc::RtpParameters BitrateLimitedParameters(int limit) {
webrtc::RtpParameters parameters;
webrtc::RtpEncodingParameters encoding;
encoding.max_bitrate_bps = limit;
parameters.encodings.push_back(encoding);
return parameters;
}
void VerifyMaxBitrate(const webrtc::RtpParameters& parameters,
int expected_bitrate) {
EXPECT_EQ(1UL, parameters.encodings.size());
EXPECT_EQ(expected_bitrate, parameters.encodings[0].max_bitrate_bps);
}
void DefaultMaxBitrateIsUnlimited() {
CreateChannels(0, 0);
EXPECT_TRUE(
channel1_->SetLocalContent(&local_media_content1_, CA_OFFER, NULL));
EXPECT_EQ(media_channel1_->max_bps(), -1);
VerifyMaxBitrate(media_channel1_->GetRtpParameters(kSsrc1), -1);
}
void CanChangeMaxBitrate() {
CreateChannels(0, 0);
EXPECT_TRUE(
channel1_->SetLocalContent(&local_media_content1_, CA_OFFER, NULL));
EXPECT_TRUE(
channel1_->SetRtpParameters(kSsrc1, BitrateLimitedParameters(1000)));
VerifyMaxBitrate(channel1_->GetRtpParameters(kSsrc1), 1000);
VerifyMaxBitrate(media_channel1_->GetRtpParameters(kSsrc1), 1000);
EXPECT_EQ(-1, media_channel1_->max_bps());
EXPECT_TRUE(
channel1_->SetRtpParameters(kSsrc1, BitrateLimitedParameters(-1)));
VerifyMaxBitrate(channel1_->GetRtpParameters(kSsrc1), -1);
VerifyMaxBitrate(media_channel1_->GetRtpParameters(kSsrc1), -1);
EXPECT_EQ(-1, media_channel1_->max_bps());
}
protected:
// TODO(pbos): Remove playout from all media channels and let renderers mute
// themselves.
@ -2229,6 +2276,26 @@ TEST_F(VoiceChannelTest, SendBundleToBundleWithRtcpMuxSecure) {
Base::SendBundleToBundle(kAudioPts, arraysize(kAudioPts), true, true);
}
TEST_F(VoiceChannelTest, GetRtpParametersIsNotImplemented) {
// These tests verify that the Get/SetRtpParameters methods for VoiceChannel
// always fail as they are not implemented.
// TODO(skvlad): Replace with full tests when support for bitrate limiting
// for audio RtpSenders is added.
CreateChannels(0, 0);
EXPECT_TRUE(
channel1_->SetLocalContent(&local_media_content1_, CA_OFFER, NULL));
webrtc::RtpParameters voice_parameters = channel1_->GetRtpParameters(kSsrc1);
EXPECT_EQ(0UL, voice_parameters.encodings.size());
}
TEST_F(VoiceChannelTest, SetRtpParametersIsNotImplemented) {
CreateChannels(0, 0);
EXPECT_TRUE(
channel1_->SetLocalContent(&local_media_content1_, CA_OFFER, NULL));
EXPECT_FALSE(
channel1_->SetRtpParameters(kSsrc1, BitrateLimitedParameters(1000)));
}
// VideoChannelTest
TEST_F(VideoChannelTest, TestInit) {
Base::TestInit();
@ -2457,6 +2524,14 @@ TEST_F(VideoChannelTest, TestOnReadyToSendWithRtcpMux) {
Base::TestOnReadyToSendWithRtcpMux();
}
TEST_F(VideoChannelTest, DefaultMaxBitrateIsUnlimited) {
Base::DefaultMaxBitrateIsUnlimited();
}
TEST_F(VideoChannelTest, CanChangeMaxBitrate) {
Base::CanChangeMaxBitrate();
}
// DataChannelTest
class DataChannelTest