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}
diff --git a/webrtc/api/api.gyp b/webrtc/api/api.gyp
index 93db18b..cb902fb 100644
--- a/webrtc/api/api.gyp
+++ b/webrtc/api/api.gyp
@@ -301,6 +301,7 @@
'remoteaudiosource.h',
'remotevideocapturer.cc',
'remotevideocapturer.h',
+ 'rtpparameters.h',
'rtpreceiver.cc',
'rtpreceiver.h',
'rtpreceiverinterface.h',
diff --git a/webrtc/api/mediastreamprovider.h b/webrtc/api/mediastreamprovider.h
index 0db7a5c..6814c41 100644
--- a/webrtc/api/mediastreamprovider.h
+++ b/webrtc/api/mediastreamprovider.h
@@ -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 @@
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 @@
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() {}
};
diff --git a/webrtc/api/rtpparameters.h b/webrtc/api/rtpparameters.h
new file mode 100644
index 0000000..e71a1ae
--- /dev/null
+++ b/webrtc/api/rtpparameters.h
@@ -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_
diff --git a/webrtc/api/rtpsender.cc b/webrtc/api/rtpsender.cc
index 9c6dfb8..1e28883 100644
--- a/webrtc/api/rtpsender.cc
+++ b/webrtc/api/rtpsender.cc
@@ -199,6 +199,14 @@
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 @@
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
diff --git a/webrtc/api/rtpsender.h b/webrtc/api/rtpsender.h
index 25cc4ed..879a332 100644
--- a/webrtc/api/rtpsender.h
+++ b/webrtc/api/rtpsender.h
@@ -97,6 +97,9 @@
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 @@
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
diff --git a/webrtc/api/rtpsenderinterface.h b/webrtc/api/rtpsenderinterface.h
index c3dd52f..776d01a 100644
--- a/webrtc/api/rtpsenderinterface.h
+++ b/webrtc/api/rtpsenderinterface.h
@@ -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 @@
virtual void Stop() = 0;
+ virtual RtpParameters GetParameters() const = 0;
+ virtual bool SetParameters(const RtpParameters& parameters) = 0;
+
protected:
virtual ~RtpSenderInterface() {}
};
@@ -66,6 +70,8 @@
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
diff --git a/webrtc/api/rtpsenderreceiver_unittest.cc b/webrtc/api/rtpsenderreceiver_unittest.cc
index 22fa14f..b26526f 100644
--- a/webrtc/api/rtpsenderreceiver_unittest.cc
+++ b/webrtc/api/rtpsenderreceiver_unittest.cc
@@ -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 @@
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 @@
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 @@
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
diff --git a/webrtc/api/webrtcsession.cc b/webrtc/api/webrtcsession.cc
index 3d9b6fb..593d429 100644
--- a/webrtc/api/webrtcsession.cc
+++ b/webrtc/api/webrtcsession.cc
@@ -1244,6 +1244,23 @@
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 @@
}
}
+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_) {
diff --git a/webrtc/api/webrtcsession.h b/webrtc/api/webrtcsession.h
index 9495116..e884678 100644
--- a/webrtc/api/webrtcsession.h
+++ b/webrtc/api/webrtcsession.h
@@ -245,6 +245,10 @@
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 @@
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,
diff --git a/webrtc/api/webrtcsession_unittest.cc b/webrtc/api/webrtcsession_unittest.cc
index c0fff52..77c4854 100644
--- a/webrtc/api/webrtcsession_unittest.cc
+++ b/webrtc/api/webrtcsession_unittest.cc
@@ -3385,6 +3385,25 @@
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 @@
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();
diff --git a/webrtc/media/base/fakemediaengine.h b/webrtc/media/base/fakemediaengine.h
index 831ac06..7f9561d 100644
--- a/webrtc/media/base/fakemediaengine.h
+++ b/webrtc/media/base/fakemediaengine.h
@@ -96,9 +96,14 @@
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 @@
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 @@
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 @@
};
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 @@
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 @@
return (SetRecvCodecs(params.codecs) &&
SetRecvRtpHeaderExtensions(params.extensions));
}
+
virtual bool SetPlayout(bool playout) {
set_playout(playout);
return true;
@@ -374,7 +400,10 @@
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 @@
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 @@
SetSendRtpHeaderExtensions(params.extensions) &&
SetMaxSendBandwidth(params.max_bandwidth_bps));
}
-
virtual bool SetRecvParameters(const VideoRecvParameters& params) {
return (SetRecvCodecs(params.codecs) &&
SetRecvRtpHeaderExtensions(params.extensions));
diff --git a/webrtc/media/base/mediachannel.h b/webrtc/media/base/mediachannel.h
index 68efbe7..f07c33a 100644
--- a/webrtc/media/base/mediachannel.h
+++ b/webrtc/media/base/mediachannel.h
@@ -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 @@
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 @@
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.
diff --git a/webrtc/media/base/mediaengine.cc b/webrtc/media/base/mediaengine.cc
index df17ee7..4027137 100644
--- a/webrtc/media/base/mediaengine.cc
+++ b/webrtc/media/base/mediaengine.cc
@@ -35,3 +35,14 @@
}; // 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
\ No newline at end of file
diff --git a/webrtc/media/base/mediaengine.h b/webrtc/media/base/mediaengine.h
index f113840..001eb1f 100644
--- a/webrtc/media/base/mediaengine.h
+++ b/webrtc/media/base/mediaengine.h
@@ -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 @@
virtual const std::vector<DataCodec>& data_codecs() = 0;
};
+webrtc::RtpParameters CreateRtpParametersWithOneEncoding();
+
} // namespace cricket
#endif // WEBRTC_MEDIA_BASE_MEDIAENGINE_H_
diff --git a/webrtc/media/engine/webrtcvideoengine2.cc b/webrtc/media/engine/webrtcvideoengine2.cc
index 6442613..5fe36c4 100644
--- a/webrtc/media/engine/webrtcvideoengine2.cc
+++ b/webrtc/media/engine/webrtcvideoengine2.cc
@@ -818,6 +818,32 @@
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 @@
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 @@
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 @@
}
}
+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 @@
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 &&
diff --git a/webrtc/media/engine/webrtcvideoengine2.h b/webrtc/media/engine/webrtcvideoengine2.h
index 4461027..850bcae 100644
--- a/webrtc/media/engine/webrtcvideoengine2.h
+++ b/webrtc/media/engine/webrtcvideoengine2.h
@@ -145,6 +145,9 @@
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 @@
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 @@
void Start();
void Stop();
+ webrtc::RtpParameters rtp_parameters() const { return rtp_parameters_; }
+
// Implements webrtc::LoadObserver.
void OnLoadUpdate(Load load) override;
@@ -338,6 +344,7 @@
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 @@
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_);
diff --git a/webrtc/media/engine/webrtcvideoengine2_unittest.cc b/webrtc/media/engine/webrtcvideoengine2_unittest.cc
index f5e4cff..b44eb99 100644
--- a/webrtc/media/engine/webrtcvideoengine2_unittest.cc
+++ b/webrtc/media/engine/webrtcvideoengine2_unittest.cc
@@ -1080,6 +1080,38 @@
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 @@
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_));
diff --git a/webrtc/pc/channel.cc b/webrtc/pc/channel.cc
index 2920af5..d9aa851 100644
--- a/webrtc/pc/channel.cc
+++ b/webrtc/pc/channel.cc
@@ -1384,6 +1384,30 @@
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 @@
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 @@
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 @@
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;
diff --git a/webrtc/pc/channel.h b/webrtc/pc/channel.h
index 60b19f8..1937b04 100644
--- a/webrtc/pc/channel.h
+++ b/webrtc/pc/channel.h
@@ -361,6 +361,8 @@
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 @@
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 @@
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 @@
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;
diff --git a/webrtc/pc/channel_unittest.cc b/webrtc/pc/channel_unittest.cc
index 7b4a31a..3752db1 100644
--- a/webrtc/pc/channel_unittest.cc
+++ b/webrtc/pc/channel_unittest.cc
@@ -1769,6 +1769,53 @@
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 @@
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 @@
Base::TestOnReadyToSendWithRtcpMux();
}
+TEST_F(VideoChannelTest, DefaultMaxBitrateIsUnlimited) {
+ Base::DefaultMaxBitrateIsUnlimited();
+}
+
+TEST_F(VideoChannelTest, CanChangeMaxBitrate) {
+ Base::CanChangeMaxBitrate();
+}
+
// DataChannelTest
class DataChannelTest