Add support for send_encodings parameters in addTransceiver
This will later allow simulcast to be set up without any SDP manipulation. Currently limited to only one layer as the SDP generated is not spec compliant and more work is required to support simulcast. Initial encoding parameters are deferred and applied when the ssrc is set on the sender. This allows parameters to be changed before negotiation is completed. Bug: webrtc:7600 Change-Id: I0a31cd1c2bfc72ebb61ce0fa4fa69d87e3d8b74d Reviewed-on: https://webrtc-review.googlesource.com/95488 Commit-Queue: Florent Castelli <orphis@webrtc.org> Reviewed-by: Seth Hampson <shampson@webrtc.org> Reviewed-by: Erik Språng <sprang@webrtc.org> Cr-Commit-Position: refs/heads/master@{#24917}
This commit is contained in:
committed by
Commit Bot
parent
687a022888
commit
892acf01f6
@ -20,4 +20,9 @@ RtpSenderInterface::GetFrameEncryptor() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<RtpEncodingParameters> RtpSenderInterface::init_send_encodings()
|
||||
const {
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@ -55,6 +55,12 @@ class RtpSenderInterface : public rtc::RefCountInterface {
|
||||
// tracks.
|
||||
virtual std::vector<std::string> stream_ids() const = 0;
|
||||
|
||||
// Returns the list of encoding parameters that will be applied when the SDP
|
||||
// local description is set. These initial encoding parameters can be set by
|
||||
// PeerConnection::AddTransceiver, and later updated with Get/SetParameters.
|
||||
// TODO(orphis): Make it pure virtual once Chrome has updated
|
||||
virtual std::vector<RtpEncodingParameters> init_send_encodings() const;
|
||||
|
||||
virtual RtpParameters GetParameters() = 0;
|
||||
// Note that only a subset of the parameters can currently be changed. See
|
||||
// rtpparameters.h
|
||||
@ -90,6 +96,7 @@ PROXY_CONSTMETHOD0(uint32_t, ssrc)
|
||||
PROXY_CONSTMETHOD0(cricket::MediaType, media_type)
|
||||
PROXY_CONSTMETHOD0(std::string, id)
|
||||
PROXY_CONSTMETHOD0(std::vector<std::string>, stream_ids)
|
||||
PROXY_CONSTMETHOD0(std::vector<RtpEncodingParameters>, init_send_encodings)
|
||||
PROXY_METHOD0(RtpParameters, GetParameters);
|
||||
PROXY_METHOD1(RTCError, SetParameters, const RtpParameters&)
|
||||
PROXY_CONSTMETHOD0(rtc::scoped_refptr<DtmfSenderInterface>, GetDtmfSender);
|
||||
|
||||
@ -27,6 +27,7 @@ class MockRtpSender : public rtc::RefCountedObject<RtpSenderInterface> {
|
||||
MOCK_CONST_METHOD0(media_type, cricket::MediaType());
|
||||
MOCK_CONST_METHOD0(id, std::string());
|
||||
MOCK_CONST_METHOD0(stream_ids, std::vector<std::string>());
|
||||
MOCK_CONST_METHOD0(init_send_encodings, std::vector<RtpEncodingParameters>());
|
||||
MOCK_METHOD0(GetParameters, RtpParameters());
|
||||
MOCK_METHOD1(SetParameters, RTCError(const RtpParameters&));
|
||||
MOCK_CONST_METHOD0(GetDtmfSender, rtc::scoped_refptr<DtmfSenderInterface>());
|
||||
|
||||
@ -151,6 +151,11 @@ class RtpHelper : public Base {
|
||||
const webrtc::RtpParameters& parameters) {
|
||||
auto parameters_iterator = rtp_send_parameters_.find(ssrc);
|
||||
if (parameters_iterator != rtp_send_parameters_.end()) {
|
||||
auto result =
|
||||
ValidateRtpParameters(parameters_iterator->second, parameters);
|
||||
if (!result.ok())
|
||||
return result;
|
||||
|
||||
parameters_iterator->second = parameters;
|
||||
return webrtc::RTCError::OK();
|
||||
}
|
||||
|
||||
@ -37,4 +37,50 @@ webrtc::RtpParameters CreateRtpParametersWithEncodings(StreamParams sp) {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
webrtc::RTCError ValidateRtpParameters(
|
||||
const webrtc::RtpParameters& old_rtp_parameters,
|
||||
const webrtc::RtpParameters& rtp_parameters) {
|
||||
using webrtc::RTCErrorType;
|
||||
if (rtp_parameters.encodings.size() != old_rtp_parameters.encodings.size()) {
|
||||
LOG_AND_RETURN_ERROR(
|
||||
RTCErrorType::INVALID_MODIFICATION,
|
||||
"Attempted to set RtpParameters with different encoding count");
|
||||
}
|
||||
if (rtp_parameters.rtcp != old_rtp_parameters.rtcp) {
|
||||
LOG_AND_RETURN_ERROR(
|
||||
RTCErrorType::INVALID_MODIFICATION,
|
||||
"Attempted to set RtpParameters with modified RTCP parameters");
|
||||
}
|
||||
if (rtp_parameters.header_extensions !=
|
||||
old_rtp_parameters.header_extensions) {
|
||||
LOG_AND_RETURN_ERROR(
|
||||
RTCErrorType::INVALID_MODIFICATION,
|
||||
"Attempted to set RtpParameters with modified header extensions");
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < rtp_parameters.encodings.size(); ++i) {
|
||||
if (rtp_parameters.encodings[i].ssrc !=
|
||||
old_rtp_parameters.encodings[i].ssrc) {
|
||||
LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_MODIFICATION,
|
||||
"Attempted to set RtpParameters with modified SSRC");
|
||||
}
|
||||
if (rtp_parameters.encodings[i].bitrate_priority <= 0) {
|
||||
LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_RANGE,
|
||||
"Attempted to set RtpParameters bitrate_priority to "
|
||||
"an invalid number. bitrate_priority must be > 0.");
|
||||
}
|
||||
|
||||
if (rtp_parameters.encodings[i].min_bitrate_bps &&
|
||||
rtp_parameters.encodings[i].max_bitrate_bps) {
|
||||
if (*rtp_parameters.encodings[i].max_bitrate_bps <
|
||||
*rtp_parameters.encodings[i].min_bitrate_bps) {
|
||||
LOG_AND_RETURN_ERROR(webrtc::RTCErrorType::INVALID_RANGE,
|
||||
"Attempted to set RtpParameters min bitrate "
|
||||
"larger than max bitrate.");
|
||||
}
|
||||
}
|
||||
}
|
||||
return webrtc::RTCError::OK();
|
||||
}
|
||||
|
||||
}; // namespace cricket
|
||||
|
||||
@ -38,6 +38,10 @@ class Call;
|
||||
|
||||
namespace cricket {
|
||||
|
||||
webrtc::RTCError ValidateRtpParameters(
|
||||
const webrtc::RtpParameters& old_parameters,
|
||||
const webrtc::RtpParameters& new_parameters);
|
||||
|
||||
struct RtpCapabilities {
|
||||
RtpCapabilities();
|
||||
~RtpCapabilities();
|
||||
|
||||
@ -1722,7 +1722,8 @@ void WebRtcVideoChannel::WebRtcVideoSendStream::SetSendParameters(
|
||||
webrtc::RTCError WebRtcVideoChannel::WebRtcVideoSendStream::SetRtpParameters(
|
||||
const webrtc::RtpParameters& new_parameters) {
|
||||
RTC_DCHECK_RUN_ON(&thread_checker_);
|
||||
webrtc::RTCError error = ValidateRtpParameters(new_parameters);
|
||||
webrtc::RTCError error =
|
||||
ValidateRtpParameters(rtp_parameters_, new_parameters);
|
||||
if (!error.ok()) {
|
||||
return error;
|
||||
}
|
||||
@ -1784,49 +1785,6 @@ WebRtcVideoChannel::WebRtcVideoSendStream::GetRtpParameters() const {
|
||||
return rtp_parameters_;
|
||||
}
|
||||
|
||||
webrtc::RTCError
|
||||
WebRtcVideoChannel::WebRtcVideoSendStream::ValidateRtpParameters(
|
||||
const webrtc::RtpParameters& rtp_parameters) {
|
||||
using webrtc::RTCErrorType;
|
||||
RTC_DCHECK_RUN_ON(&thread_checker_);
|
||||
if (rtp_parameters.encodings.size() != rtp_parameters_.encodings.size()) {
|
||||
LOG_AND_RETURN_ERROR(
|
||||
RTCErrorType::INVALID_MODIFICATION,
|
||||
"Attempted to set RtpParameters with different encoding count");
|
||||
}
|
||||
if (rtp_parameters.rtcp != rtp_parameters_.rtcp) {
|
||||
LOG_AND_RETURN_ERROR(
|
||||
RTCErrorType::INVALID_MODIFICATION,
|
||||
"Attempted to set RtpParameters with modified RTCP parameters");
|
||||
}
|
||||
if (rtp_parameters.header_extensions != rtp_parameters_.header_extensions) {
|
||||
LOG_AND_RETURN_ERROR(
|
||||
RTCErrorType::INVALID_MODIFICATION,
|
||||
"Attempted to set RtpParameters with modified header extensions");
|
||||
}
|
||||
if (rtp_parameters.encodings[0].ssrc != rtp_parameters_.encodings[0].ssrc) {
|
||||
LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_MODIFICATION,
|
||||
"Attempted to set RtpParameters with modified SSRC");
|
||||
}
|
||||
if (rtp_parameters.encodings[0].bitrate_priority <= 0) {
|
||||
LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_RANGE,
|
||||
"Attempted to set RtpParameters bitrate_priority to "
|
||||
"an invalid number. bitrate_priority must be > 0.");
|
||||
}
|
||||
for (size_t i = 0; i < rtp_parameters.encodings.size(); ++i) {
|
||||
if (rtp_parameters.encodings[i].min_bitrate_bps &&
|
||||
rtp_parameters.encodings[i].max_bitrate_bps) {
|
||||
if (*rtp_parameters.encodings[i].max_bitrate_bps <
|
||||
*rtp_parameters.encodings[i].min_bitrate_bps) {
|
||||
LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_RANGE,
|
||||
"Attempted to set RtpParameters min bitrate "
|
||||
"larger than max bitrate.");
|
||||
}
|
||||
}
|
||||
}
|
||||
return webrtc::RTCError::OK();
|
||||
}
|
||||
|
||||
void WebRtcVideoChannel::WebRtcVideoSendStream::UpdateSendState() {
|
||||
RTC_DCHECK_RUN_ON(&thread_checker_);
|
||||
if (sending_) {
|
||||
|
||||
@ -303,8 +303,6 @@ class WebRtcVideoChannel : public VideoMediaChannel, public webrtc::Transport {
|
||||
webrtc::VideoEncoderConfig CreateVideoEncoderConfig(
|
||||
const VideoCodec& codec) const;
|
||||
void ReconfigureEncoder();
|
||||
webrtc::RTCError ValidateRtpParameters(
|
||||
const webrtc::RtpParameters& parameters);
|
||||
|
||||
// Calls Start or Stop according to whether or not |sending_| is true,
|
||||
// and whether or not the encoding in |rtp_parameters_| is active.
|
||||
|
||||
@ -900,38 +900,8 @@ class WebRtcVoiceMediaChannel::WebRtcAudioSendStream
|
||||
return rtp_parameters_;
|
||||
}
|
||||
|
||||
webrtc::RTCError ValidateRtpParameters(
|
||||
const webrtc::RtpParameters& rtp_parameters) {
|
||||
using webrtc::RTCErrorType;
|
||||
if (rtp_parameters.encodings.size() != rtp_parameters_.encodings.size()) {
|
||||
LOG_AND_RETURN_ERROR(
|
||||
RTCErrorType::INVALID_MODIFICATION,
|
||||
"Attempted to set RtpParameters with different encoding count");
|
||||
}
|
||||
if (rtp_parameters.rtcp != rtp_parameters_.rtcp) {
|
||||
LOG_AND_RETURN_ERROR(
|
||||
RTCErrorType::INVALID_MODIFICATION,
|
||||
"Attempted to set RtpParameters with modified RTCP parameters");
|
||||
}
|
||||
if (rtp_parameters.header_extensions != rtp_parameters_.header_extensions) {
|
||||
LOG_AND_RETURN_ERROR(
|
||||
RTCErrorType::INVALID_MODIFICATION,
|
||||
"Attempted to set RtpParameters with modified header extensions");
|
||||
}
|
||||
if (rtp_parameters.encodings[0].ssrc != rtp_parameters_.encodings[0].ssrc) {
|
||||
LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_MODIFICATION,
|
||||
"Attempted to set RtpParameters with modified SSRC");
|
||||
}
|
||||
if (rtp_parameters.encodings[0].bitrate_priority <= 0) {
|
||||
LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_RANGE,
|
||||
"Attempted to set RtpParameters bitrate_priority to "
|
||||
"an invalid number.");
|
||||
}
|
||||
return webrtc::RTCError::OK();
|
||||
}
|
||||
|
||||
webrtc::RTCError SetRtpParameters(const webrtc::RtpParameters& parameters) {
|
||||
webrtc::RTCError error = ValidateRtpParameters(parameters);
|
||||
webrtc::RTCError error = ValidateRtpParameters(rtp_parameters_, parameters);
|
||||
if (!error.ok()) {
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -221,8 +221,6 @@ class WebRtcVoiceMediaChannel final : public VoiceMediaChannel,
|
||||
int CreateVoEChannel();
|
||||
bool DeleteVoEChannel(int channel);
|
||||
bool SetMaxSendBitrate(int bps);
|
||||
webrtc::RTCError ValidateRtpParameters(
|
||||
const webrtc::RtpParameters& parameters);
|
||||
void SetupRecording();
|
||||
// Check if 'ssrc' is an unsignaled stream, and if so mark it as not being
|
||||
// unsignaled anymore (i.e. it is now removed, or signaled), and return true.
|
||||
|
||||
@ -1181,7 +1181,7 @@ PeerConnection::AddTrackPlanB(
|
||||
? cricket::MEDIA_TYPE_AUDIO
|
||||
: cricket::MEDIA_TYPE_VIDEO);
|
||||
auto new_sender =
|
||||
CreateSender(media_type, track->id(), track, adjusted_stream_ids);
|
||||
CreateSender(media_type, track->id(), track, adjusted_stream_ids, {});
|
||||
if (track->kind() == MediaStreamTrackInterface::kAudioKind) {
|
||||
new_sender->internal()->SetVoiceMediaChannel(voice_media_channel());
|
||||
GetAudioTransceiver()->internal()->AddSender(new_sender);
|
||||
@ -1237,7 +1237,7 @@ PeerConnection::AddTrackUnifiedPlan(
|
||||
if (FindSenderById(sender_id)) {
|
||||
sender_id = rtc::CreateRandomUuid();
|
||||
}
|
||||
auto sender = CreateSender(media_type, sender_id, track, stream_ids);
|
||||
auto sender = CreateSender(media_type, sender_id, track, stream_ids, {});
|
||||
auto receiver = CreateReceiver(media_type, rtc::CreateRandomUuid());
|
||||
transceiver = CreateAndAddTransceiver(sender, receiver);
|
||||
transceiver->internal()->set_created_by_addtrack(true);
|
||||
@ -1379,6 +1379,27 @@ PeerConnection::AddTransceiver(
|
||||
}
|
||||
|
||||
// TODO(bugs.webrtc.org/7600): Verify init.
|
||||
if (init.send_encodings.size() > 1) {
|
||||
LOG_AND_RETURN_ERROR(
|
||||
RTCErrorType::UNSUPPORTED_PARAMETER,
|
||||
"Attempted to create an encoder with more than 1 encoding parameter.");
|
||||
}
|
||||
|
||||
for (const auto& encoding : init.send_encodings) {
|
||||
if (encoding.ssrc.has_value()) {
|
||||
LOG_AND_RETURN_ERROR(
|
||||
RTCErrorType::UNSUPPORTED_PARAMETER,
|
||||
"Attempted to set an unimplemented parameter of RtpParameters.");
|
||||
}
|
||||
}
|
||||
|
||||
RtpParameters parameters;
|
||||
parameters.encodings = init.send_encodings;
|
||||
if (UnimplementedRtpParameterHasValue(parameters)) {
|
||||
LOG_AND_RETURN_ERROR(
|
||||
RTCErrorType::UNSUPPORTED_PARAMETER,
|
||||
"Attempted to set an unimplemented parameter of RtpParameters.");
|
||||
}
|
||||
|
||||
RTC_LOG(LS_INFO) << "Adding " << cricket::MediaTypeToString(media_type)
|
||||
<< " transceiver in response to a call to AddTransceiver.";
|
||||
@ -1387,7 +1408,8 @@ PeerConnection::AddTransceiver(
|
||||
std::string sender_id =
|
||||
(track && !FindSenderById(track->id()) ? track->id()
|
||||
: rtc::CreateRandomUuid());
|
||||
auto sender = CreateSender(media_type, sender_id, track, init.stream_ids);
|
||||
auto sender = CreateSender(media_type, sender_id, track, init.stream_ids,
|
||||
init.send_encodings);
|
||||
auto receiver = CreateReceiver(media_type, rtc::CreateRandomUuid());
|
||||
auto transceiver = CreateAndAddTransceiver(sender, receiver);
|
||||
transceiver->internal()->set_direction(init.direction);
|
||||
@ -1404,7 +1426,8 @@ PeerConnection::CreateSender(
|
||||
cricket::MediaType media_type,
|
||||
const std::string& id,
|
||||
rtc::scoped_refptr<MediaStreamTrackInterface> track,
|
||||
const std::vector<std::string>& stream_ids) {
|
||||
const std::vector<std::string>& stream_ids,
|
||||
const std::vector<RtpEncodingParameters>& send_encodings) {
|
||||
rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender;
|
||||
if (media_type == cricket::MEDIA_TYPE_AUDIO) {
|
||||
RTC_DCHECK(!track ||
|
||||
@ -1424,6 +1447,7 @@ PeerConnection::CreateSender(
|
||||
bool set_track_succeeded = sender->SetTrack(track);
|
||||
RTC_DCHECK(set_track_succeeded);
|
||||
sender->internal()->set_stream_ids(stream_ids);
|
||||
sender->internal()->set_init_send_encodings(send_encodings);
|
||||
return sender;
|
||||
}
|
||||
|
||||
@ -2733,7 +2757,8 @@ PeerConnection::AssociateTransceiver(cricket::ContentSource source,
|
||||
<< " at i=" << mline_index
|
||||
<< " in response to the remote description.";
|
||||
std::string sender_id = rtc::CreateRandomUuid();
|
||||
auto sender = CreateSender(media_desc->type(), sender_id, nullptr, {});
|
||||
auto sender =
|
||||
CreateSender(media_desc->type(), sender_id, nullptr, {}, {});
|
||||
std::string receiver_id;
|
||||
if (!media_desc->streams().empty()) {
|
||||
receiver_id = media_desc->streams()[0].id;
|
||||
@ -3382,7 +3407,7 @@ void PeerConnection::AddAudioTrack(AudioTrackInterface* track,
|
||||
|
||||
// Normal case; we've never seen this track before.
|
||||
auto new_sender = CreateSender(cricket::MEDIA_TYPE_AUDIO, track->id(), track,
|
||||
{stream->id()});
|
||||
{stream->id()}, {});
|
||||
new_sender->internal()->SetVoiceMediaChannel(voice_media_channel());
|
||||
GetAudioTransceiver()->internal()->AddSender(new_sender);
|
||||
// If the sender has already been configured in SDP, we call SetSsrc,
|
||||
@ -3427,7 +3452,7 @@ void PeerConnection::AddVideoTrack(VideoTrackInterface* track,
|
||||
|
||||
// Normal case; we've never seen this track before.
|
||||
auto new_sender = CreateSender(cricket::MEDIA_TYPE_VIDEO, track->id(), track,
|
||||
{stream->id()});
|
||||
{stream->id()}, {});
|
||||
new_sender->internal()->SetVideoMediaChannel(video_media_channel());
|
||||
GetVideoTransceiver()->internal()->AddSender(new_sender);
|
||||
const RtpSenderInfo* sender_info =
|
||||
@ -3739,9 +3764,10 @@ GetMediaDescriptionOptionsForTransceiver(
|
||||
cricket::SenderOptions sender_options;
|
||||
sender_options.track_id = transceiver->sender()->id();
|
||||
sender_options.stream_ids = transceiver->sender()->stream_ids();
|
||||
// TODO(bugs.webrtc.org/7600): Set num_sim_layers to the number of encodings
|
||||
// set in the RTP parameters when the transceiver was added.
|
||||
sender_options.num_sim_layers = 1;
|
||||
int num_send_encoding_layers =
|
||||
transceiver->sender()->init_send_encodings().size();
|
||||
sender_options.num_sim_layers =
|
||||
!num_send_encoding_layers ? 1 : num_send_encoding_layers;
|
||||
media_description_options.sender_options.push_back(sender_options);
|
||||
}
|
||||
return media_description_options;
|
||||
|
||||
@ -357,7 +357,8 @@ class PeerConnection : public PeerConnectionInternal,
|
||||
CreateSender(cricket::MediaType media_type,
|
||||
const std::string& id,
|
||||
rtc::scoped_refptr<MediaStreamTrackInterface> track,
|
||||
const std::vector<std::string>& stream_ids);
|
||||
const std::vector<std::string>& stream_ids,
|
||||
const std::vector<RtpEncodingParameters>& send_encodings);
|
||||
|
||||
rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
|
||||
CreateReceiver(cricket::MediaType media_type, const std::string& receiver_id);
|
||||
|
||||
@ -1376,6 +1376,132 @@ TEST_F(PeerConnectionRtpTestUnifiedPlan,
|
||||
EXPECT_FALSE(caller->observer()->negotiation_needed());
|
||||
}
|
||||
|
||||
// Test that AddTransceiver fails if trying to use simulcast using
|
||||
// send_encodings as it isn't currently supported.
|
||||
TEST_F(PeerConnectionRtpTestUnifiedPlan, CheckForUnsupportedSimulcast) {
|
||||
auto caller = CreatePeerConnection();
|
||||
|
||||
RtpTransceiverInit init;
|
||||
init.send_encodings.emplace_back();
|
||||
init.send_encodings.emplace_back();
|
||||
auto result = caller->pc()->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init);
|
||||
EXPECT_EQ(result.error().type(), RTCErrorType::UNSUPPORTED_PARAMETER);
|
||||
}
|
||||
|
||||
// Test that AddTransceiver fails if trying to use unimplemented RTP encoding
|
||||
// parameters with the send_encodings parameters.
|
||||
TEST_F(PeerConnectionRtpTestUnifiedPlan,
|
||||
CheckForUnsupportedEncodingParameters) {
|
||||
auto caller = CreatePeerConnection();
|
||||
|
||||
RtpTransceiverInit init;
|
||||
init.send_encodings.emplace_back();
|
||||
|
||||
auto default_send_encodings = init.send_encodings;
|
||||
|
||||
// Unimplemented RtpParameters: ssrc, codec_payload_type, fec, rtx, dtx,
|
||||
// ptime, scale_resolution_down_by, scale_framerate_down_by, rid,
|
||||
// dependency_rids.
|
||||
init.send_encodings[0].ssrc = 1;
|
||||
EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER,
|
||||
caller->pc()
|
||||
->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init)
|
||||
.error()
|
||||
.type());
|
||||
init.send_encodings = default_send_encodings;
|
||||
|
||||
init.send_encodings[0].codec_payload_type = 1;
|
||||
EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER,
|
||||
caller->pc()
|
||||
->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init)
|
||||
.error()
|
||||
.type());
|
||||
init.send_encodings = default_send_encodings;
|
||||
|
||||
init.send_encodings[0].fec = RtpFecParameters();
|
||||
EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER,
|
||||
caller->pc()
|
||||
->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init)
|
||||
.error()
|
||||
.type());
|
||||
init.send_encodings = default_send_encodings;
|
||||
|
||||
init.send_encodings[0].rtx = RtpRtxParameters();
|
||||
EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER,
|
||||
caller->pc()
|
||||
->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init)
|
||||
.error()
|
||||
.type());
|
||||
init.send_encodings = default_send_encodings;
|
||||
|
||||
init.send_encodings[0].dtx = DtxStatus::ENABLED;
|
||||
EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER,
|
||||
caller->pc()
|
||||
->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init)
|
||||
.error()
|
||||
.type());
|
||||
init.send_encodings = default_send_encodings;
|
||||
|
||||
init.send_encodings[0].ptime = 1;
|
||||
EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER,
|
||||
caller->pc()
|
||||
->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init)
|
||||
.error()
|
||||
.type());
|
||||
init.send_encodings = default_send_encodings;
|
||||
|
||||
init.send_encodings[0].scale_resolution_down_by = 2.0;
|
||||
EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER,
|
||||
caller->pc()
|
||||
->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init)
|
||||
.error()
|
||||
.type());
|
||||
init.send_encodings = default_send_encodings;
|
||||
|
||||
init.send_encodings[0].rid = "dummy_rid";
|
||||
EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER,
|
||||
caller->pc()
|
||||
->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init)
|
||||
.error()
|
||||
.type());
|
||||
init.send_encodings = default_send_encodings;
|
||||
|
||||
init.send_encodings[0].dependency_rids.push_back("dummy_rid");
|
||||
EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER,
|
||||
caller->pc()
|
||||
->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init)
|
||||
.error()
|
||||
.type());
|
||||
}
|
||||
|
||||
// Test that AddTransceiver transfers the send_encodings to the sender and they
|
||||
// are retained after SetLocalDescription().
|
||||
TEST_F(PeerConnectionRtpTestUnifiedPlan, SendEncodingsPassedToSender) {
|
||||
auto caller = CreatePeerConnection();
|
||||
|
||||
RtpTransceiverInit init;
|
||||
init.send_encodings.emplace_back();
|
||||
init.send_encodings[0].active = false;
|
||||
init.send_encodings[0].max_bitrate_bps = 180000;
|
||||
|
||||
auto result = caller->pc()->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init);
|
||||
ASSERT_TRUE(result.ok());
|
||||
|
||||
auto init_send_encodings = result.value()->sender()->init_send_encodings();
|
||||
EXPECT_FALSE(init_send_encodings[0].active);
|
||||
EXPECT_EQ(init_send_encodings[0].max_bitrate_bps, 180000);
|
||||
|
||||
auto parameters = result.value()->sender()->GetParameters();
|
||||
EXPECT_FALSE(parameters.encodings[0].active);
|
||||
EXPECT_EQ(parameters.encodings[0].max_bitrate_bps, 180000);
|
||||
|
||||
ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
|
||||
|
||||
parameters = result.value()->sender()->GetParameters();
|
||||
EXPECT_FALSE(parameters.encodings[0].active);
|
||||
EXPECT_EQ(parameters.encodings[0].max_bitrate_bps, 180000);
|
||||
}
|
||||
|
||||
// Test MSID signaling between Unified Plan and Plan B endpoints. There are two
|
||||
// options for this kind of signaling: media section based (a=msid) and ssrc
|
||||
// based (a=ssrc MSID). While JSEP only specifies media section MSID signaling,
|
||||
|
||||
112
pc/rtpsender.cc
112
pc/rtpsender.cc
@ -31,6 +31,20 @@ int GenerateUniqueId() {
|
||||
return ++g_unique_id;
|
||||
}
|
||||
|
||||
// Attaches the frame encryptor to the media channel through an invoke on a
|
||||
// worker thread. This set must be done on the corresponding worker thread that
|
||||
// the media channel was created on.
|
||||
void AttachFrameEncryptorToMediaChannel(
|
||||
rtc::Thread* worker_thread,
|
||||
webrtc::FrameEncryptorInterface* frame_encryptor,
|
||||
cricket::MediaChannel* media_channel) {
|
||||
if (media_channel) {
|
||||
return worker_thread->Invoke<void>(RTC_FROM_HERE, [&] {
|
||||
media_channel->SetFrameEncryptor(frame_encryptor);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Returns an true if any RtpEncodingParameters member that isn't implemented
|
||||
// contains a value.
|
||||
bool UnimplementedRtpEncodingParameterHasValue(
|
||||
@ -64,6 +78,8 @@ bool PerSenderRtpEncodingParameterHasValue(
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// Returns true if any RtpParameters member that isn't implemented contains a
|
||||
// value.
|
||||
bool UnimplementedRtpParameterHasValue(const RtpParameters& parameters) {
|
||||
@ -84,22 +100,6 @@ bool UnimplementedRtpParameterHasValue(const RtpParameters& parameters) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Attaches the frame encryptor to the media channel through an invoke on a
|
||||
// worker thread. This set must be done on the corresponding worker thread that
|
||||
// the media channel was created on.
|
||||
void AttachFrameEncryptorToMediaChannel(
|
||||
rtc::Thread* worker_thread,
|
||||
webrtc::FrameEncryptorInterface* frame_encryptor,
|
||||
cricket::MediaChannel* media_channel) {
|
||||
if (media_channel) {
|
||||
return worker_thread->Invoke<void>(RTC_FROM_HERE, [&] {
|
||||
media_channel->SetFrameEncryptor(frame_encryptor);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
LocalAudioSinkAdapter::LocalAudioSinkAdapter() : sink_(nullptr) {}
|
||||
|
||||
LocalAudioSinkAdapter::~LocalAudioSinkAdapter() {
|
||||
@ -137,6 +137,7 @@ AudioRtpSender::AudioRtpSender(rtc::Thread* worker_thread,
|
||||
DtmfSender::Create(rtc::Thread::Current(), this))),
|
||||
sink_adapter_(new LocalAudioSinkAdapter()) {
|
||||
RTC_DCHECK(worker_thread);
|
||||
init_parameters_.encodings.emplace_back();
|
||||
}
|
||||
|
||||
AudioRtpSender::~AudioRtpSender() {
|
||||
@ -242,9 +243,15 @@ bool AudioRtpSender::SetTrack(MediaStreamTrackInterface* track) {
|
||||
}
|
||||
|
||||
RtpParameters AudioRtpSender::GetParameters() {
|
||||
if (!media_channel_ || stopped_) {
|
||||
if (stopped_) {
|
||||
return RtpParameters();
|
||||
}
|
||||
if (!media_channel_) {
|
||||
RtpParameters result = init_parameters_;
|
||||
last_transaction_id_ = rtc::CreateRandomUuid();
|
||||
result.transaction_id = last_transaction_id_.value();
|
||||
return result;
|
||||
}
|
||||
return worker_thread_->Invoke<RtpParameters>(RTC_FROM_HERE, [&] {
|
||||
RtpParameters result = media_channel_->GetRtpSendParameters(ssrc_);
|
||||
last_transaction_id_ = rtc::CreateRandomUuid();
|
||||
@ -255,7 +262,7 @@ RtpParameters AudioRtpSender::GetParameters() {
|
||||
|
||||
RTCError AudioRtpSender::SetParameters(const RtpParameters& parameters) {
|
||||
TRACE_EVENT0("webrtc", "AudioRtpSender::SetParameters");
|
||||
if (!media_channel_ || stopped_) {
|
||||
if (stopped_) {
|
||||
return RTCError(RTCErrorType::INVALID_STATE);
|
||||
}
|
||||
if (!last_transaction_id_) {
|
||||
@ -276,6 +283,13 @@ RTCError AudioRtpSender::SetParameters(const RtpParameters& parameters) {
|
||||
RTCErrorType::UNSUPPORTED_PARAMETER,
|
||||
"Attempted to set an unimplemented parameter of RtpParameters.");
|
||||
}
|
||||
if (!media_channel_) {
|
||||
auto result = cricket::ValidateRtpParameters(init_parameters_, parameters);
|
||||
if (result.ok()) {
|
||||
init_parameters_ = parameters;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return worker_thread_->Invoke<RTCError>(RTC_FROM_HERE, [&] {
|
||||
RTCError result = media_channel_->SetRtpSendParameters(ssrc_, parameters);
|
||||
last_transaction_id_.reset();
|
||||
@ -318,6 +332,28 @@ void AudioRtpSender::SetSsrc(uint32_t ssrc) {
|
||||
stats_->AddLocalAudioTrack(track_.get(), ssrc_);
|
||||
}
|
||||
}
|
||||
if (!init_parameters_.encodings.empty()) {
|
||||
worker_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
|
||||
RTC_DCHECK(media_channel_);
|
||||
// Get the current parameters, which are constructed from the SDP.
|
||||
// The number of layers in the SDP is currently authoritative to support
|
||||
// SDP munging for Plan-B simulcast with "a=ssrc-group:SIM <ssrc-id>..."
|
||||
// lines as described in RFC 5576.
|
||||
// All fields should be default constructed and the SSRC field set, which
|
||||
// we need to copy.
|
||||
RtpParameters current_parameters =
|
||||
media_channel_->GetRtpSendParameters(ssrc_);
|
||||
for (size_t i = 0; i < init_parameters_.encodings.size(); ++i) {
|
||||
init_parameters_.encodings[i].ssrc =
|
||||
current_parameters.encodings[i].ssrc;
|
||||
current_parameters.encodings[i] = init_parameters_.encodings[i];
|
||||
}
|
||||
current_parameters.degradation_preference =
|
||||
init_parameters_.degradation_preference;
|
||||
media_channel_->SetRtpSendParameters(ssrc_, current_parameters);
|
||||
init_parameters_.encodings.clear();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void AudioRtpSender::Stop() {
|
||||
@ -399,6 +435,7 @@ VideoRtpSender::VideoRtpSender(rtc::Thread* worker_thread,
|
||||
const std::string& id)
|
||||
: worker_thread_(worker_thread), id_(id) {
|
||||
RTC_DCHECK(worker_thread);
|
||||
init_parameters_.encodings.emplace_back();
|
||||
}
|
||||
|
||||
VideoRtpSender::~VideoRtpSender() {
|
||||
@ -456,9 +493,15 @@ bool VideoRtpSender::SetTrack(MediaStreamTrackInterface* track) {
|
||||
}
|
||||
|
||||
RtpParameters VideoRtpSender::GetParameters() {
|
||||
if (!media_channel_ || stopped_) {
|
||||
if (stopped_) {
|
||||
return RtpParameters();
|
||||
}
|
||||
if (!media_channel_) {
|
||||
RtpParameters result = init_parameters_;
|
||||
last_transaction_id_ = rtc::CreateRandomUuid();
|
||||
result.transaction_id = last_transaction_id_.value();
|
||||
return result;
|
||||
}
|
||||
return worker_thread_->Invoke<RtpParameters>(RTC_FROM_HERE, [&] {
|
||||
RtpParameters result = media_channel_->GetRtpSendParameters(ssrc_);
|
||||
last_transaction_id_ = rtc::CreateRandomUuid();
|
||||
@ -469,7 +512,7 @@ RtpParameters VideoRtpSender::GetParameters() {
|
||||
|
||||
RTCError VideoRtpSender::SetParameters(const RtpParameters& parameters) {
|
||||
TRACE_EVENT0("webrtc", "VideoRtpSender::SetParameters");
|
||||
if (!media_channel_ || stopped_) {
|
||||
if (stopped_) {
|
||||
return RTCError(RTCErrorType::INVALID_STATE);
|
||||
}
|
||||
if (!last_transaction_id_) {
|
||||
@ -490,6 +533,13 @@ RTCError VideoRtpSender::SetParameters(const RtpParameters& parameters) {
|
||||
RTCErrorType::UNSUPPORTED_PARAMETER,
|
||||
"Attempted to set an unimplemented parameter of RtpParameters.");
|
||||
}
|
||||
if (!media_channel_) {
|
||||
auto result = cricket::ValidateRtpParameters(init_parameters_, parameters);
|
||||
if (result.ok()) {
|
||||
init_parameters_ = parameters;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return worker_thread_->Invoke<RTCError>(RTC_FROM_HERE, [&] {
|
||||
RTCError result = media_channel_->SetRtpSendParameters(ssrc_, parameters);
|
||||
last_transaction_id_.reset();
|
||||
@ -527,6 +577,28 @@ void VideoRtpSender::SetSsrc(uint32_t ssrc) {
|
||||
if (can_send_track()) {
|
||||
SetVideoSend();
|
||||
}
|
||||
if (!init_parameters_.encodings.empty()) {
|
||||
worker_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
|
||||
RTC_DCHECK(media_channel_);
|
||||
// Get the current parameters, which are constructed from the SDP.
|
||||
// The number of layers in the SDP is currently authoritative to support
|
||||
// SDP munging for Plan-B simulcast with "a=ssrc-group:SIM <ssrc-id>..."
|
||||
// lines as described in RFC 5576.
|
||||
// All fields should be default constructed and the SSRC field set, which
|
||||
// we need to copy.
|
||||
RtpParameters current_parameters =
|
||||
media_channel_->GetRtpSendParameters(ssrc_);
|
||||
for (size_t i = 0; i < init_parameters_.encodings.size(); ++i) {
|
||||
init_parameters_.encodings[i].ssrc =
|
||||
current_parameters.encodings[i].ssrc;
|
||||
current_parameters.encodings[i] = init_parameters_.encodings[i];
|
||||
}
|
||||
current_parameters.degradation_preference =
|
||||
init_parameters_.degradation_preference;
|
||||
media_channel_->SetRtpSendParameters(ssrc_, current_parameters);
|
||||
init_parameters_.encodings.clear();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void VideoRtpSender::Stop() {
|
||||
|
||||
@ -30,6 +30,8 @@ namespace webrtc {
|
||||
|
||||
class StatsCollector;
|
||||
|
||||
bool UnimplementedRtpParameterHasValue(const RtpParameters& parameters);
|
||||
|
||||
// Internal interface used by PeerConnection.
|
||||
class RtpSenderInternal : public RtpSenderInterface {
|
||||
public:
|
||||
@ -50,6 +52,8 @@ class RtpSenderInternal : public RtpSenderInterface {
|
||||
virtual void SetSsrc(uint32_t ssrc) = 0;
|
||||
|
||||
virtual void set_stream_ids(const std::vector<std::string>& stream_ids) = 0;
|
||||
virtual void set_init_send_encodings(
|
||||
const std::vector<RtpEncodingParameters>& init_send_encodings) = 0;
|
||||
|
||||
virtual void Stop() = 0;
|
||||
|
||||
@ -140,6 +144,14 @@ class AudioRtpSender : public DtmfProviderInterface,
|
||||
stream_ids_ = stream_ids;
|
||||
}
|
||||
|
||||
void set_init_send_encodings(
|
||||
const std::vector<RtpEncodingParameters>& init_send_encodings) override {
|
||||
init_parameters_.encodings = init_send_encodings;
|
||||
}
|
||||
std::vector<RtpEncodingParameters> init_send_encodings() const override {
|
||||
return init_parameters_.encodings;
|
||||
}
|
||||
|
||||
void Stop() override;
|
||||
|
||||
int AttachmentId() const override { return attachment_id_; }
|
||||
@ -167,6 +179,7 @@ class AudioRtpSender : public DtmfProviderInterface,
|
||||
rtc::Thread* const worker_thread_;
|
||||
const std::string id_;
|
||||
std::vector<std::string> stream_ids_;
|
||||
RtpParameters init_parameters_;
|
||||
cricket::VoiceMediaChannel* media_channel_ = nullptr;
|
||||
StatsCollector* stats_ = nullptr;
|
||||
rtc::scoped_refptr<AudioTrackInterface> track_;
|
||||
@ -211,6 +224,14 @@ class VideoRtpSender : public ObserverInterface,
|
||||
|
||||
std::vector<std::string> stream_ids() const override { return stream_ids_; }
|
||||
|
||||
void set_init_send_encodings(
|
||||
const std::vector<RtpEncodingParameters>& init_send_encodings) override {
|
||||
init_parameters_.encodings = init_send_encodings;
|
||||
}
|
||||
std::vector<RtpEncodingParameters> init_send_encodings() const override {
|
||||
return init_parameters_.encodings;
|
||||
}
|
||||
|
||||
RtpParameters GetParameters() override;
|
||||
RTCError SetParameters(const RtpParameters& parameters) override;
|
||||
|
||||
@ -251,6 +272,7 @@ class VideoRtpSender : public ObserverInterface,
|
||||
rtc::Thread* worker_thread_;
|
||||
const std::string id_;
|
||||
std::vector<std::string> stream_ids_;
|
||||
RtpParameters init_parameters_;
|
||||
cricket::VideoMediaChannel* media_channel_ = nullptr;
|
||||
rtc::scoped_refptr<VideoTrackInterface> track_;
|
||||
absl::optional<std::string> last_transaction_id_;
|
||||
|
||||
@ -47,6 +47,8 @@ static const uint32_t kVideoSsrc = 98;
|
||||
static const uint32_t kVideoSsrc2 = 100;
|
||||
static const uint32_t kAudioSsrc = 99;
|
||||
static const uint32_t kAudioSsrc2 = 101;
|
||||
static const uint32_t kVideoSsrcSimulcast = 102;
|
||||
static const uint32_t kVideoSimulcastLayerCount = 2;
|
||||
static const int kDefaultTimeout = 10000; // 10 seconds.
|
||||
} // namespace
|
||||
|
||||
@ -170,6 +172,18 @@ class RtpSenderReceiverTest : public testing::Test,
|
||||
|
||||
void CreateVideoRtpSender() { CreateVideoRtpSender(false); }
|
||||
|
||||
void CreateVideoRtpSenderWithSimulcast(
|
||||
int num_layers = kVideoSimulcastLayerCount) {
|
||||
std::vector<uint32_t> ssrcs;
|
||||
for (int i = 0; i < num_layers; ++i)
|
||||
ssrcs.push_back(kVideoSsrcSimulcast + i);
|
||||
cricket::StreamParams stream_params =
|
||||
cricket::CreateSimStreamParams("cname", ssrcs);
|
||||
video_media_channel_->AddSendStream(stream_params);
|
||||
uint32_t primary_ssrc = stream_params.first_ssrc();
|
||||
CreateVideoRtpSender(primary_ssrc);
|
||||
}
|
||||
|
||||
void CreateVideoRtpSender(bool is_screencast, uint32_t ssrc = kVideoSsrc) {
|
||||
AddVideoTrack(is_screencast);
|
||||
video_rtp_sender_ = new VideoRtpSender(worker_thread_, video_track_->id());
|
||||
@ -179,7 +193,6 @@ class RtpSenderReceiverTest : public testing::Test,
|
||||
video_rtp_sender_->SetSsrc(ssrc);
|
||||
VerifyVideoChannelInput(ssrc);
|
||||
}
|
||||
|
||||
void CreateVideoRtpSenderWithNoTrack() {
|
||||
video_rtp_sender_ = new VideoRtpSender(worker_thread_, /*id=*/"");
|
||||
video_rtp_sender_->SetVideoMediaChannel(video_media_channel_);
|
||||
@ -612,6 +625,63 @@ TEST_F(RtpSenderReceiverTest, AudioSenderCanSetParameters) {
|
||||
DestroyAudioRtpSender();
|
||||
}
|
||||
|
||||
TEST_F(RtpSenderReceiverTest, AudioSenderCanSetParametersBeforeNegotiation) {
|
||||
audio_rtp_sender_ = new AudioRtpSender(worker_thread_, /*id=*/"", nullptr);
|
||||
|
||||
RtpParameters params = audio_rtp_sender_->GetParameters();
|
||||
ASSERT_EQ(1u, params.encodings.size());
|
||||
params.encodings[0].max_bitrate_bps = 90000;
|
||||
EXPECT_TRUE(audio_rtp_sender_->SetParameters(params).ok());
|
||||
|
||||
params = audio_rtp_sender_->GetParameters();
|
||||
EXPECT_TRUE(audio_rtp_sender_->SetParameters(params).ok());
|
||||
EXPECT_EQ(params.encodings[0].max_bitrate_bps, 90000);
|
||||
|
||||
DestroyAudioRtpSender();
|
||||
}
|
||||
|
||||
TEST_F(RtpSenderReceiverTest, AudioSenderInitParametersMovedAfterNegotiation) {
|
||||
audio_track_ = AudioTrack::Create(kAudioTrackId, nullptr);
|
||||
EXPECT_TRUE(local_stream_->AddTrack(audio_track_));
|
||||
|
||||
audio_rtp_sender_ =
|
||||
new AudioRtpSender(worker_thread_, audio_track_->id(), nullptr);
|
||||
ASSERT_TRUE(audio_rtp_sender_->SetTrack(audio_track_));
|
||||
audio_rtp_sender_->set_stream_ids({local_stream_->id()});
|
||||
|
||||
std::vector<RtpEncodingParameters> init_encodings(1);
|
||||
init_encodings[0].max_bitrate_bps = 60000;
|
||||
audio_rtp_sender_->set_init_send_encodings(init_encodings);
|
||||
|
||||
RtpParameters params = audio_rtp_sender_->GetParameters();
|
||||
ASSERT_EQ(1u, params.encodings.size());
|
||||
EXPECT_EQ(params.encodings[0].max_bitrate_bps, 60000);
|
||||
|
||||
// Simulate the setLocalDescription call
|
||||
std::vector<uint32_t> ssrcs(1, 1);
|
||||
cricket::StreamParams stream_params =
|
||||
cricket::CreateSimStreamParams("cname", ssrcs);
|
||||
voice_media_channel_->AddSendStream(stream_params);
|
||||
audio_rtp_sender_->SetVoiceMediaChannel(voice_media_channel_);
|
||||
audio_rtp_sender_->SetSsrc(1);
|
||||
|
||||
params = audio_rtp_sender_->GetParameters();
|
||||
ASSERT_EQ(1u, params.encodings.size());
|
||||
EXPECT_EQ(params.encodings[0].max_bitrate_bps, 60000);
|
||||
|
||||
DestroyAudioRtpSender();
|
||||
}
|
||||
|
||||
TEST_F(RtpSenderReceiverTest,
|
||||
AudioSenderMustCallGetParametersBeforeSetParametersBeforeNegotiation) {
|
||||
audio_rtp_sender_ = new AudioRtpSender(worker_thread_, /*id=*/"", nullptr);
|
||||
|
||||
RtpParameters params;
|
||||
RTCError result = audio_rtp_sender_->SetParameters(params);
|
||||
EXPECT_EQ(RTCErrorType::INVALID_STATE, result.type());
|
||||
DestroyAudioRtpSender();
|
||||
}
|
||||
|
||||
TEST_F(RtpSenderReceiverTest,
|
||||
AudioSenderMustCallGetParametersBeforeSetParameters) {
|
||||
CreateAudioRtpSender();
|
||||
@ -792,6 +862,100 @@ TEST_F(RtpSenderReceiverTest, VideoSenderCanSetParameters) {
|
||||
DestroyVideoRtpSender();
|
||||
}
|
||||
|
||||
TEST_F(RtpSenderReceiverTest, VideoSenderCanSetParametersBeforeNegotiation) {
|
||||
video_rtp_sender_ = new VideoRtpSender(worker_thread_, /*id=*/"");
|
||||
|
||||
RtpParameters params = video_rtp_sender_->GetParameters();
|
||||
ASSERT_EQ(1u, params.encodings.size());
|
||||
params.encodings[0].max_bitrate_bps = 90000;
|
||||
EXPECT_TRUE(video_rtp_sender_->SetParameters(params).ok());
|
||||
|
||||
params = video_rtp_sender_->GetParameters();
|
||||
EXPECT_TRUE(video_rtp_sender_->SetParameters(params).ok());
|
||||
EXPECT_EQ(params.encodings[0].max_bitrate_bps, 90000);
|
||||
|
||||
DestroyVideoRtpSender();
|
||||
}
|
||||
|
||||
TEST_F(RtpSenderReceiverTest, VideoSenderInitParametersMovedAfterNegotiation) {
|
||||
AddVideoTrack(false);
|
||||
|
||||
video_rtp_sender_ = new VideoRtpSender(worker_thread_, video_track_->id());
|
||||
ASSERT_TRUE(video_rtp_sender_->SetTrack(video_track_));
|
||||
video_rtp_sender_->set_stream_ids({local_stream_->id()});
|
||||
|
||||
std::vector<RtpEncodingParameters> init_encodings(2);
|
||||
init_encodings[0].max_bitrate_bps = 60000;
|
||||
init_encodings[1].max_bitrate_bps = 900000;
|
||||
video_rtp_sender_->set_init_send_encodings(init_encodings);
|
||||
|
||||
RtpParameters params = video_rtp_sender_->GetParameters();
|
||||
ASSERT_EQ(2u, params.encodings.size());
|
||||
EXPECT_EQ(params.encodings[0].max_bitrate_bps, 60000);
|
||||
EXPECT_EQ(params.encodings[1].max_bitrate_bps, 900000);
|
||||
|
||||
// Simulate the setLocalDescription call
|
||||
std::vector<uint32_t> ssrcs;
|
||||
for (int i = 0; i < 2; ++i)
|
||||
ssrcs.push_back(kVideoSsrcSimulcast + i);
|
||||
cricket::StreamParams stream_params =
|
||||
cricket::CreateSimStreamParams("cname", ssrcs);
|
||||
video_media_channel_->AddSendStream(stream_params);
|
||||
video_rtp_sender_->SetVideoMediaChannel(video_media_channel_);
|
||||
video_rtp_sender_->SetSsrc(kVideoSsrcSimulcast);
|
||||
|
||||
params = video_rtp_sender_->GetParameters();
|
||||
ASSERT_EQ(2u, params.encodings.size());
|
||||
EXPECT_EQ(params.encodings[0].max_bitrate_bps, 60000);
|
||||
EXPECT_EQ(params.encodings[1].max_bitrate_bps, 900000);
|
||||
|
||||
DestroyVideoRtpSender();
|
||||
}
|
||||
|
||||
TEST_F(RtpSenderReceiverTest,
|
||||
VideoSenderInitParametersMovedAfterManualSimulcastAndNegotiation) {
|
||||
AddVideoTrack(false);
|
||||
|
||||
video_rtp_sender_ = new VideoRtpSender(worker_thread_, video_track_->id());
|
||||
ASSERT_TRUE(video_rtp_sender_->SetTrack(video_track_));
|
||||
video_rtp_sender_->set_stream_ids({local_stream_->id()});
|
||||
|
||||
std::vector<RtpEncodingParameters> init_encodings(1);
|
||||
init_encodings[0].max_bitrate_bps = 60000;
|
||||
video_rtp_sender_->set_init_send_encodings(init_encodings);
|
||||
|
||||
RtpParameters params = video_rtp_sender_->GetParameters();
|
||||
ASSERT_EQ(1u, params.encodings.size());
|
||||
EXPECT_EQ(params.encodings[0].max_bitrate_bps, 60000);
|
||||
|
||||
// Simulate the setLocalDescription call as if the user used SDP munging
|
||||
// to enable simulcast
|
||||
std::vector<uint32_t> ssrcs;
|
||||
for (int i = 0; i < 2; ++i)
|
||||
ssrcs.push_back(kVideoSsrcSimulcast + i);
|
||||
cricket::StreamParams stream_params =
|
||||
cricket::CreateSimStreamParams("cname", ssrcs);
|
||||
video_media_channel_->AddSendStream(stream_params);
|
||||
video_rtp_sender_->SetVideoMediaChannel(video_media_channel_);
|
||||
video_rtp_sender_->SetSsrc(kVideoSsrcSimulcast);
|
||||
|
||||
params = video_rtp_sender_->GetParameters();
|
||||
ASSERT_EQ(2u, params.encodings.size());
|
||||
EXPECT_EQ(params.encodings[0].max_bitrate_bps, 60000);
|
||||
|
||||
DestroyVideoRtpSender();
|
||||
}
|
||||
|
||||
TEST_F(RtpSenderReceiverTest,
|
||||
VideoSenderMustCallGetParametersBeforeSetParametersBeforeNegotiation) {
|
||||
video_rtp_sender_ = new VideoRtpSender(worker_thread_, /*id=*/"");
|
||||
|
||||
RtpParameters params;
|
||||
RTCError result = video_rtp_sender_->SetParameters(params);
|
||||
EXPECT_EQ(RTCErrorType::INVALID_STATE, result.type());
|
||||
DestroyVideoRtpSender();
|
||||
}
|
||||
|
||||
TEST_F(RtpSenderReceiverTest,
|
||||
VideoSenderMustCallGetParametersBeforeSetParameters) {
|
||||
CreateVideoRtpSender();
|
||||
@ -915,6 +1079,58 @@ TEST_F(RtpSenderReceiverTest,
|
||||
DestroyVideoRtpSender();
|
||||
}
|
||||
|
||||
TEST_F(RtpSenderReceiverTest,
|
||||
VideoSenderCantSetUnimplementedEncodingParametersWithSimulcast) {
|
||||
CreateVideoRtpSenderWithSimulcast();
|
||||
RtpParameters params = video_rtp_sender_->GetParameters();
|
||||
EXPECT_EQ(kVideoSimulcastLayerCount, params.encodings.size());
|
||||
|
||||
// Unimplemented RtpParameters: codec_payload_type, fec, rtx, dtx, ptime,
|
||||
// scale_resolution_down_by, scale_framerate_down_by, rid, dependency_rids.
|
||||
for (size_t i = 0; i < params.encodings.size(); i++) {
|
||||
params.encodings[i].codec_payload_type = 1;
|
||||
EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER,
|
||||
video_rtp_sender_->SetParameters(params).type());
|
||||
params = video_rtp_sender_->GetParameters();
|
||||
|
||||
params.encodings[i].fec = RtpFecParameters();
|
||||
EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER,
|
||||
video_rtp_sender_->SetParameters(params).type());
|
||||
params = video_rtp_sender_->GetParameters();
|
||||
|
||||
params.encodings[i].rtx = RtpRtxParameters();
|
||||
EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER,
|
||||
video_rtp_sender_->SetParameters(params).type());
|
||||
params = video_rtp_sender_->GetParameters();
|
||||
|
||||
params.encodings[i].dtx = DtxStatus::ENABLED;
|
||||
EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER,
|
||||
video_rtp_sender_->SetParameters(params).type());
|
||||
params = video_rtp_sender_->GetParameters();
|
||||
|
||||
params.encodings[i].ptime = 1;
|
||||
EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER,
|
||||
video_rtp_sender_->SetParameters(params).type());
|
||||
params = video_rtp_sender_->GetParameters();
|
||||
|
||||
params.encodings[i].scale_resolution_down_by = 2.0;
|
||||
EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER,
|
||||
video_rtp_sender_->SetParameters(params).type());
|
||||
params = video_rtp_sender_->GetParameters();
|
||||
|
||||
params.encodings[i].rid = "dummy_rid";
|
||||
EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER,
|
||||
video_rtp_sender_->SetParameters(params).type());
|
||||
params = video_rtp_sender_->GetParameters();
|
||||
|
||||
params.encodings[i].dependency_rids.push_back("dummy_rid");
|
||||
EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER,
|
||||
video_rtp_sender_->SetParameters(params).type());
|
||||
}
|
||||
|
||||
DestroyVideoRtpSender();
|
||||
}
|
||||
|
||||
// A video sender can have multiple simulcast layers, in which case it will
|
||||
// contain multiple RtpEncodingParameters. This tests that if this is the case
|
||||
// (simulcast), then we can't set the bitrate_priority, or max_bitrate_bps
|
||||
@ -922,14 +1138,9 @@ TEST_F(RtpSenderReceiverTest,
|
||||
// "per-sender."
|
||||
TEST_F(RtpSenderReceiverTest, VideoSenderCantSetPerSenderEncodingParameters) {
|
||||
// Add a simulcast specific send stream that contains 2 encoding parameters.
|
||||
std::vector<uint32_t> ssrcs({1, 2});
|
||||
cricket::StreamParams stream_params =
|
||||
cricket::CreateSimStreamParams("cname", ssrcs);
|
||||
video_media_channel_->AddSendStream(stream_params);
|
||||
uint32_t primary_ssrc = stream_params.first_ssrc();
|
||||
CreateVideoRtpSender(primary_ssrc);
|
||||
CreateVideoRtpSenderWithSimulcast();
|
||||
RtpParameters params = video_rtp_sender_->GetParameters();
|
||||
EXPECT_EQ(ssrcs.size(), params.encodings.size());
|
||||
EXPECT_EQ(kVideoSimulcastLayerCount, params.encodings.size());
|
||||
|
||||
params.encodings[1].bitrate_priority = 2.0;
|
||||
EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER,
|
||||
@ -939,6 +1150,22 @@ TEST_F(RtpSenderReceiverTest, VideoSenderCantSetPerSenderEncodingParameters) {
|
||||
DestroyVideoRtpSender();
|
||||
}
|
||||
|
||||
TEST_F(RtpSenderReceiverTest, VideoSenderCantSetReadOnlyEncodingParameters) {
|
||||
// Add a simulcast specific send stream that contains 2 encoding parameters.
|
||||
CreateVideoRtpSenderWithSimulcast();
|
||||
RtpParameters params = video_rtp_sender_->GetParameters();
|
||||
EXPECT_EQ(kVideoSimulcastLayerCount, params.encodings.size());
|
||||
|
||||
for (size_t i = 0; i < params.encodings.size(); i++) {
|
||||
params.encodings[i].ssrc = 1337;
|
||||
EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION,
|
||||
video_rtp_sender_->SetParameters(params).type());
|
||||
params = video_rtp_sender_->GetParameters();
|
||||
}
|
||||
|
||||
DestroyVideoRtpSender();
|
||||
}
|
||||
|
||||
TEST_F(RtpSenderReceiverTest, SetVideoMinMaxSendBitrate) {
|
||||
CreateVideoRtpSender();
|
||||
|
||||
@ -971,15 +1198,10 @@ TEST_F(RtpSenderReceiverTest, SetVideoMinMaxSendBitrate) {
|
||||
|
||||
TEST_F(RtpSenderReceiverTest, SetVideoMinMaxSendBitrateSimulcast) {
|
||||
// Add a simulcast specific send stream that contains 2 encoding parameters.
|
||||
std::vector<uint32_t> ssrcs({1, 2});
|
||||
cricket::StreamParams stream_params =
|
||||
cricket::CreateSimStreamParams("cname", ssrcs);
|
||||
video_media_channel_->AddSendStream(stream_params);
|
||||
uint32_t primary_ssrc = stream_params.first_ssrc();
|
||||
CreateVideoRtpSender(primary_ssrc);
|
||||
CreateVideoRtpSenderWithSimulcast();
|
||||
|
||||
RtpParameters params = video_rtp_sender_->GetParameters();
|
||||
EXPECT_EQ(ssrcs.size(), params.encodings.size());
|
||||
EXPECT_EQ(kVideoSimulcastLayerCount, params.encodings.size());
|
||||
params.encodings[0].min_bitrate_bps = 100;
|
||||
params.encodings[0].max_bitrate_bps = 1000;
|
||||
params.encodings[1].min_bitrate_bps = 200;
|
||||
@ -987,8 +1209,8 @@ TEST_F(RtpSenderReceiverTest, SetVideoMinMaxSendBitrateSimulcast) {
|
||||
EXPECT_TRUE(video_rtp_sender_->SetParameters(params).ok());
|
||||
|
||||
// Verify that the video channel received the new parameters.
|
||||
params = video_media_channel_->GetRtpSendParameters(primary_ssrc);
|
||||
EXPECT_EQ(ssrcs.size(), params.encodings.size());
|
||||
params = video_media_channel_->GetRtpSendParameters(kVideoSsrcSimulcast);
|
||||
EXPECT_EQ(kVideoSimulcastLayerCount, params.encodings.size());
|
||||
EXPECT_EQ(100, params.encodings[0].min_bitrate_bps);
|
||||
EXPECT_EQ(1000, params.encodings[0].max_bitrate_bps);
|
||||
EXPECT_EQ(200, params.encodings[1].min_bitrate_bps);
|
||||
|
||||
@ -29,6 +29,7 @@ class MockRtpSenderInternal : public RtpSenderInternal {
|
||||
MOCK_CONST_METHOD0(media_type, cricket::MediaType());
|
||||
MOCK_CONST_METHOD0(id, std::string());
|
||||
MOCK_CONST_METHOD0(stream_ids, std::vector<std::string>());
|
||||
MOCK_CONST_METHOD0(init_send_encodings, std::vector<RtpEncodingParameters>());
|
||||
MOCK_METHOD0(GetParameters, RtpParameters());
|
||||
MOCK_METHOD1(SetParameters, RTCError(const RtpParameters&));
|
||||
MOCK_CONST_METHOD0(GetDtmfSender, rtc::scoped_refptr<DtmfSenderInterface>());
|
||||
@ -42,6 +43,8 @@ class MockRtpSenderInternal : public RtpSenderInternal {
|
||||
MOCK_METHOD1(SetVideoMediaChannel, void(cricket::VideoMediaChannel*));
|
||||
MOCK_METHOD1(SetSsrc, void(uint32_t));
|
||||
MOCK_METHOD1(set_stream_ids, void(const std::vector<std::string>&));
|
||||
MOCK_METHOD1(set_init_send_encodings,
|
||||
void(const std::vector<RtpEncodingParameters>&));
|
||||
MOCK_METHOD0(Stop, void());
|
||||
MOCK_CONST_METHOD0(AttachmentId, int());
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user