Index: webrtc/ortc/rtptransportcontrolleradapter.cc |
diff --git a/webrtc/ortc/rtptransportcontrolleradapter.cc b/webrtc/ortc/rtptransportcontrolleradapter.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..6c88d2d53364e6dcda17c977a1015d608e12fc47 |
--- /dev/null |
+++ b/webrtc/ortc/rtptransportcontrolleradapter.cc |
@@ -0,0 +1,706 @@ |
+/* |
+ * Copyright 2017 The WebRTC project authors. All Rights Reserved. |
+ * |
+ * Use of this source code is governed by a BSD-style license |
+ * that can be found in the LICENSE file in the root of the source |
+ * tree. An additional intellectual property rights grant can be found |
+ * in the file PATENTS. All contributing project authors may |
+ * be found in the AUTHORS file in the root of the source tree. |
+ */ |
+ |
+#include "webrtc/ortc/rtptransportcontrolleradapter.h" |
+ |
+#include <algorithm> // For "remove", "find". |
+#include <utility> // For std::move. |
+ |
+#include "webrtc/api/proxy.h" |
+#include "webrtc/base/checks.h" |
+#include "webrtc/media/base/mediaconstants.h" |
+#include "webrtc/ortc/rtpparametersconversion.h" |
+#include "webrtc/ortc/rtptransportadapter.h" |
+ |
+namespace webrtc { |
+ |
+BEGIN_OWNED_PROXY_MAP(RtpTransportController) |
+PROXY_SIGNALING_THREAD_DESTRUCTOR() |
+PROXY_CONSTMETHOD0(std::vector<RtpTransportInterface*>, GetTransports) |
+protected: |
+RtpTransportControllerAdapter* GetInternal() override { |
+ return internal(); |
+} |
+END_PROXY_MAP() |
+ |
+// static |
+std::unique_ptr<RtpTransportControllerInterface> |
+RtpTransportControllerAdapter::CreateProxied( |
+ const cricket::MediaConfig& config, |
+ cricket::ChannelManager* channel_manager, |
+ webrtc::RtcEventLog* event_log, |
+ rtc::Thread* signaling_thread, |
+ rtc::Thread* worker_thread) { |
+ return RtpTransportControllerProxyWithInternal< |
+ RtpTransportControllerAdapter>::Create(signaling_thread, worker_thread, |
+ new RtpTransportControllerAdapter( |
+ config, channel_manager, |
+ event_log, signaling_thread, |
+ worker_thread)); |
+} |
+ |
+RtpTransportControllerAdapter::~RtpTransportControllerAdapter() { |
+ RTC_DCHECK_RUN_ON(signaling_thread_); |
+ if (!transport_proxies_.empty()) { |
+ LOG(LS_ERROR) |
+ << "Destroying RtpTransportControllerAdapter while RtpTransports " |
+ "are still using it; this is unsafe."; |
+ } |
+ if (voice_channel_) { |
+ // This would mean audio RTP senders/receivers that are using us haven't |
+ // been destroyed, and thus haven't called Detach yet. This isn't safe (see |
+ // error log above). |
+ DestroyVoiceChannel(); |
+ } |
+ if (voice_channel_) { |
+ // This would mean video RTP senders/receivers that are using us haven't |
+ // been destroyed, and thus haven't called Detach yet. This isn't safe (see |
+ // error log above). |
+ DestroyVideoChannel(); |
+ } |
+} |
+ |
+std::vector<RtpTransportInterface*> |
+RtpTransportControllerAdapter::GetTransports() const { |
+ RTC_DCHECK_RUN_ON(signaling_thread_); |
+ return transport_proxies_; |
pthatcher1
2017/02/17 23:10:22
What is this even used for? It seems like it's no
Taylor Brandstetter
2017/02/17 23:48:03
To return in GetTransports.
pthatcher1
2017/02/18 00:25:00
But why do we need GetTransports?
Taylor Brandstetter
2017/02/18 00:55:15
For consistency with other APIs, and for convenien
|
+} |
+ |
+void RtpTransportControllerAdapter::AddTransport( |
+ RtpTransportInterface* transport_proxy) { |
+ RTC_DCHECK_RUN_ON(signaling_thread_); |
+ transport_proxies_.push_back(transport_proxy); |
+} |
+ |
+void RtpTransportControllerAdapter::RemoveTransport( |
+ RtpTransportAdapter* inner_transport) { |
+ RTC_DCHECK_RUN_ON(signaling_thread_); |
+ auto it = std::find_if(transport_proxies_.begin(), transport_proxies_.end(), |
+ [inner_transport](RtpTransportInterface* proxy) { |
+ return proxy->GetInternal() == inner_transport; |
+ }); |
+ if (it == transport_proxies_.end()) { |
+ RTC_NOTREACHED(); |
+ return; |
+ } |
+ transport_proxies_.erase(it); |
+} |
+ |
+RTCError RtpTransportControllerAdapter::SetRtcpParameters( |
+ const RtcpParameters& parameters, |
+ RtpTransportInterface* inner_transport) { |
+ if (inner_transport == inner_audio_transport_) { |
+ CopyRtcpParametersToDescriptions(parameters, &local_audio_description_, |
+ &remote_audio_description_); |
+ if (!voice_channel_->SetLocalContent(&local_audio_description_, |
+ cricket::CA_OFFER, nullptr)) { |
+ LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, |
+ "Failed to apply new RTCP parameters."); |
+ } |
+ if (!voice_channel_->SetRemoteContent(&remote_audio_description_, |
+ cricket::CA_ANSWER, nullptr)) { |
+ LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, |
+ "Failed to apply new RTCP parameters."); |
+ } |
+ } else if (inner_transport == inner_video_transport_) { |
+ CopyRtcpParametersToDescriptions(parameters, &local_video_description_, |
+ &remote_video_description_); |
+ if (!video_channel_->SetLocalContent(&local_video_description_, |
+ cricket::CA_OFFER, nullptr)) { |
+ LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, |
+ "Failed to apply new RTCP parameters."); |
+ } |
+ if (!video_channel_->SetRemoteContent(&remote_video_description_, |
+ cricket::CA_ANSWER, nullptr)) { |
+ LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, |
+ "Failed to apply new RTCP parameters."); |
+ } |
+ } |
+ return RTCError::OK(); |
+} |
+ |
+RTCError RtpTransportControllerAdapter::AttachAudioSender( |
+ RtpTransportInterface* inner_transport) { |
+ if (have_audio_sender_) { |
+ LOG_AND_RETURN_ERROR(RTCErrorType::UNSUPPORTED_OPERATION, |
+ "Using two audio RtpSenders with the same " |
+ "RtpTransportControllerAdapter is not currently " |
+ "supported."); |
+ } |
+ if (inner_audio_transport_ && inner_audio_transport_ != inner_transport) { |
+ LOG_AND_RETURN_ERROR(RTCErrorType::UNSUPPORTED_PARAMETER, |
+ "Using different transports for the audio " |
+ "RtpSender and RtpReceiver is not currently " |
+ "supported."); |
+ } |
+ // If setting new transport, extract its RTCP parameters and create voice |
+ // channel. |
+ if (!inner_audio_transport_) { |
+ CopyRtcpParametersToDescriptions(inner_transport->GetRtcpParameters(), |
+ &local_audio_description_, |
+ &remote_audio_description_); |
+ inner_audio_transport_ = inner_transport; |
+ CreateVoiceChannel(); |
+ } |
+ have_audio_sender_ = true; |
+ return RTCError::OK(); |
+} |
+ |
+RTCError RtpTransportControllerAdapter::AttachVideoSender( |
+ RtpTransportInterface* inner_transport) { |
+ if (have_video_sender_) { |
+ LOG_AND_RETURN_ERROR(RTCErrorType::UNSUPPORTED_OPERATION, |
+ "Using two video RtpSenders with the same " |
+ "RtpTransportControllerAdapter is not currently " |
+ "supported."); |
+ } |
+ if (inner_video_transport_ && inner_video_transport_ != inner_transport) { |
+ LOG_AND_RETURN_ERROR(RTCErrorType::UNSUPPORTED_PARAMETER, |
+ "Using different transports for the video " |
+ "RtpSender and RtpReceiver is not currently " |
+ "supported."); |
+ } |
+ // If setting new transport, extract its RTCP parameters and create video |
+ // channel. |
+ if (!inner_video_transport_) { |
+ CopyRtcpParametersToDescriptions(inner_transport->GetRtcpParameters(), |
+ &local_video_description_, |
+ &remote_video_description_); |
+ inner_video_transport_ = inner_transport; |
+ CreateVideoChannel(); |
+ } |
+ have_video_sender_ = true; |
+ return RTCError::OK(); |
+} |
+ |
+RTCError RtpTransportControllerAdapter::AttachAudioReceiver( |
+ RtpTransportInterface* inner_transport) { |
+ if (have_audio_receiver_) { |
+ LOG_AND_RETURN_ERROR(RTCErrorType::UNSUPPORTED_OPERATION, |
+ "Using two audio RtpReceivers with the same " |
+ "RtpTransportControllerAdapter is not currently " |
+ "supported."); |
+ } |
+ if (inner_audio_transport_ && inner_audio_transport_ != inner_transport) { |
+ LOG_AND_RETURN_ERROR(RTCErrorType::UNSUPPORTED_PARAMETER, |
+ "Using different transports for the audio " |
+ "RtpReceiver and RtpReceiver is not currently " |
+ "supported."); |
+ } |
+ // If setting new transport, extract its RTCP parameters and create voice |
+ // channel. |
+ if (!inner_audio_transport_) { |
+ CopyRtcpParametersToDescriptions(inner_transport->GetRtcpParameters(), |
+ &local_audio_description_, |
+ &remote_audio_description_); |
+ inner_audio_transport_ = inner_transport; |
+ CreateVoiceChannel(); |
+ } |
+ have_audio_receiver_ = true; |
+ return RTCError::OK(); |
+} |
+ |
+RTCError RtpTransportControllerAdapter::AttachVideoReceiver( |
+ RtpTransportInterface* inner_transport) { |
+ if (have_video_receiver_) { |
+ LOG_AND_RETURN_ERROR(RTCErrorType::UNSUPPORTED_OPERATION, |
+ "Using two video RtpReceivers with the same " |
+ "RtpTransportControllerAdapter is not currently " |
+ "supported."); |
+ } |
+ if (inner_video_transport_ && inner_video_transport_ != inner_transport) { |
+ LOG_AND_RETURN_ERROR(RTCErrorType::UNSUPPORTED_PARAMETER, |
+ "Using different transports for the video " |
+ "RtpReceiver and RtpReceiver is not currently " |
+ "supported."); |
+ } |
+ // If setting new transport, extract its RTCP parameters and create video |
+ // channel. |
+ if (!inner_video_transport_) { |
+ CopyRtcpParametersToDescriptions(inner_transport->GetRtcpParameters(), |
+ &local_video_description_, |
+ &remote_video_description_); |
+ inner_video_transport_ = inner_transport; |
+ CreateVideoChannel(); |
+ } |
+ have_video_receiver_ = true; |
+ return RTCError::OK(); |
+} |
+ |
+void RtpTransportControllerAdapter::DetachAudioSender() { |
+ if (!have_audio_sender_) { |
+ // Should be impossible unless RtpSenderAdapter is doing something wrong. |
+ RTC_NOTREACHED(); |
+ return; |
+ } |
+ // Empty parameters should result in sending being stopped. |
+ RTCError err = |
+ ValidateAndApplyAudioSenderParameters(RtpParameters(), nullptr); |
+ RTC_DCHECK(err.ok()); |
+ have_audio_sender_ = false; |
+ if (!have_audio_receiver_) { |
+ DestroyVoiceChannel(); |
+ } |
+} |
+ |
+void RtpTransportControllerAdapter::DetachVideoSender() { |
+ if (!have_video_sender_) { |
+ // Should be impossible unless RtpSenderAdapter is doing something wrong. |
+ RTC_NOTREACHED(); |
+ return; |
+ } |
+ // Empty parameters should result in sending being stopped. |
+ RTCError err = |
+ ValidateAndApplyVideoSenderParameters(RtpParameters(), nullptr); |
+ RTC_DCHECK(err.ok()); |
+ have_video_sender_ = false; |
+ if (!have_video_receiver_) { |
+ DestroyVideoChannel(); |
+ } |
+} |
+ |
+void RtpTransportControllerAdapter::DetachAudioReceiver() { |
+ if (!have_audio_receiver_) { |
+ // Should be impossible unless RtpReceiverAdapter is doing something wrong. |
+ RTC_NOTREACHED(); |
+ return; |
+ } |
+ // Empty parameters should result in receiving being stopped. |
+ RTCError err = ValidateAndApplyAudioReceiverParameters(RtpParameters()); |
+ RTC_DCHECK(err.ok()); |
+ have_audio_receiver_ = false; |
+ if (!have_audio_sender_) { |
+ DestroyVoiceChannel(); |
+ } |
+} |
+ |
+void RtpTransportControllerAdapter::DetachVideoReceiver() { |
+ if (!have_video_receiver_) { |
+ // Should be impossible unless RtpReceiverAdapter is doing something wrong. |
+ RTC_NOTREACHED(); |
+ return; |
+ } |
+ // Empty parameters should result in receiving being stopped. |
+ RTCError err = ValidateAndApplyVideoReceiverParameters(RtpParameters()); |
+ RTC_DCHECK(err.ok()); |
+ have_video_receiver_ = false; |
+ if (!have_video_sender_) { |
+ DestroyVideoChannel(); |
+ } |
+} |
+ |
+RTCError RtpTransportControllerAdapter::ValidateAndApplyAudioSenderParameters( |
+ const RtpParameters& parameters, |
+ uint32_t* primary_ssrc) { |
+ RTC_DCHECK(voice_channel_); |
+ RTC_DCHECK(have_audio_sender_); |
+ |
+ auto codecs_result = ToCricketCodecs<cricket::AudioCodec>(parameters.codecs); |
+ if (!codecs_result.ok()) { |
+ return codecs_result.MoveError(); |
+ } |
+ |
+ auto extensions_result = ToRtpHeaderExtensions(parameters.header_extensions); |
+ if (!extensions_result.ok()) { |
+ return extensions_result.MoveError(); |
+ } |
+ |
+ auto stream_params_result = MakeStreamParamsVec( |
+ parameters.encodings, inner_audio_transport_->GetRtcpParameters().cname, |
+ local_audio_description_); |
+ if (!stream_params_result.ok()) { |
+ return stream_params_result.MoveError(); |
+ } |
+ |
+ cricket::RtpTransceiverDirection local_direction = |
+ cricket::RtpTransceiverDirection::FromMediaContentDirection( |
+ local_audio_description_.direction()); |
+ int bandwidth = cricket::kAutoBandwidth; |
+ if (parameters.encodings.size() == 1u) { |
+ if (parameters.encodings[0].max_bitrate_bps) { |
+ bandwidth = *parameters.encodings[0].max_bitrate_bps; |
+ } |
+ local_direction.send = parameters.encodings[0].active; |
+ } else { |
+ local_direction.send = false; |
+ } |
+ if (primary_ssrc && !stream_params_result.value().empty()) { |
+ *primary_ssrc = stream_params_result.value()[0].first_ssrc(); |
+ } |
+ |
+ // Validation is done, so we can attempt applying the descriptions. Sent |
+ // codecs and header extensions go in remote description, streams go in |
+ // local. |
+ // |
+ // If there are no codecs or encodings, just leave the previous set of |
+ // codecs. The media engine doesn't like an empty set of codecs. |
+ if (local_audio_description_.streams().empty() && |
+ remote_audio_description_.codecs().empty()) { |
+ } else { |
+ remote_audio_description_.set_codecs(codecs_result.MoveValue()); |
+ } |
+ remote_audio_description_.set_rtp_header_extensions( |
+ extensions_result.MoveValue()); |
+ remote_audio_description_.set_bandwidth(bandwidth); |
+ local_audio_description_.mutable_streams() = stream_params_result.MoveValue(); |
+ // Direction set based on encoding "active" flag. |
+ local_audio_description_.set_direction( |
+ local_direction.ToMediaContentDirection()); |
+ remote_audio_description_.set_direction( |
+ local_direction.Reversed().ToMediaContentDirection()); |
+ |
+ // Set remote content first, to ensure the stream is created with the correct |
+ // codec. |
+ if (!voice_channel_->SetRemoteContent(&remote_audio_description_, |
+ cricket::CA_OFFER, nullptr)) { |
+ LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, |
+ "Failed to apply remote parameters to media channel."); |
+ } |
+ if (!voice_channel_->SetLocalContent(&local_audio_description_, |
+ cricket::CA_ANSWER, nullptr)) { |
+ LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, |
+ "Failed to apply local parameters to media channel."); |
+ } |
+ return RTCError::OK(); |
+} |
+ |
+RTCError RtpTransportControllerAdapter::ValidateAndApplyVideoSenderParameters( |
+ const RtpParameters& parameters, |
+ uint32_t* primary_ssrc) { |
+ RTC_DCHECK(video_channel_); |
+ RTC_DCHECK(have_video_sender_); |
+ |
+ auto codecs_result = ToCricketCodecs<cricket::VideoCodec>(parameters.codecs); |
+ if (!codecs_result.ok()) { |
+ return codecs_result.MoveError(); |
+ } |
+ |
+ auto extensions_result = ToRtpHeaderExtensions(parameters.header_extensions); |
+ if (!extensions_result.ok()) { |
+ return extensions_result.MoveError(); |
+ } |
+ |
+ auto stream_params_result = MakeStreamParamsVec( |
+ parameters.encodings, inner_video_transport_->GetRtcpParameters().cname, |
+ local_video_description_); |
+ if (!stream_params_result.ok()) { |
+ return stream_params_result.MoveError(); |
+ } |
+ |
+ cricket::RtpTransceiverDirection local_direction = |
+ cricket::RtpTransceiverDirection::FromMediaContentDirection( |
+ local_video_description_.direction()); |
+ int bandwidth = cricket::kAutoBandwidth; |
+ if (parameters.encodings.size() == 1u) { |
+ if (parameters.encodings[0].max_bitrate_bps) { |
+ bandwidth = *parameters.encodings[0].max_bitrate_bps; |
+ } |
+ local_direction.send = parameters.encodings[0].active; |
+ } else { |
+ local_direction.send = false; |
+ } |
+ if (primary_ssrc && !stream_params_result.value().empty()) { |
+ *primary_ssrc = stream_params_result.value()[0].first_ssrc(); |
+ } |
+ |
+ // Validation is done, so we can attempt applying the descriptions. Sent |
+ // codecs and header extensions go in remote description, streams go in |
+ // local. |
+ // |
+ // If there are no codecs or encodings, just leave the previous set of |
+ // codecs. The media engine doesn't like an empty set of codecs. |
+ if (local_video_description_.streams().empty() && |
+ remote_video_description_.codecs().empty()) { |
+ } else { |
+ remote_video_description_.set_codecs(codecs_result.MoveValue()); |
+ } |
+ remote_video_description_.set_rtp_header_extensions( |
+ extensions_result.MoveValue()); |
+ remote_video_description_.set_bandwidth(bandwidth); |
+ local_video_description_.mutable_streams() = stream_params_result.MoveValue(); |
+ // Direction set based on encoding "active" flag. |
+ local_video_description_.set_direction( |
+ local_direction.ToMediaContentDirection()); |
+ remote_video_description_.set_direction( |
+ local_direction.Reversed().ToMediaContentDirection()); |
+ |
+ // Set remote content first, to ensure the stream is created with the correct |
+ // codec. |
+ if (!video_channel_->SetRemoteContent(&remote_video_description_, |
+ cricket::CA_OFFER, nullptr)) { |
+ LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, |
+ "Failed to apply remote parameters to media channel."); |
+ } |
+ if (!video_channel_->SetLocalContent(&local_video_description_, |
+ cricket::CA_ANSWER, nullptr)) { |
+ LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, |
+ "Failed to apply local parameters to media channel."); |
+ } |
+ return RTCError::OK(); |
+} |
+ |
+RTCError RtpTransportControllerAdapter::ValidateAndApplyAudioReceiverParameters( |
+ const RtpParameters& parameters) { |
+ RTC_DCHECK(voice_channel_); |
+ RTC_DCHECK(have_audio_receiver_); |
+ |
+ auto codecs_result = ToCricketCodecs<cricket::AudioCodec>(parameters.codecs); |
+ if (!codecs_result.ok()) { |
+ return codecs_result.MoveError(); |
+ } |
+ |
+ auto extensions_result = ToRtpHeaderExtensions(parameters.header_extensions); |
+ if (!extensions_result.ok()) { |
+ return extensions_result.MoveError(); |
+ } |
+ |
+ cricket::RtpTransceiverDirection local_direction = |
+ cricket::RtpTransceiverDirection::FromMediaContentDirection( |
+ local_audio_description_.direction()); |
+ auto stream_params_result = ToStreamParamsVec(parameters.encodings); |
+ if (!stream_params_result.ok()) { |
+ return stream_params_result.MoveError(); |
+ } |
+ local_direction.recv = |
+ !parameters.encodings.empty() && parameters.encodings[0].active; |
+ |
+ // Validation is done, so we can attempt applying the descriptions. Received |
+ // codecs and header extensions go in local description, streams go in |
+ // remote. |
+ // |
+ // If there are no codecs or encodings, just leave the previous set of |
+ // codecs. The media engine doesn't like an empty set of codecs. |
+ if (remote_audio_description_.streams().empty() && |
+ local_audio_description_.codecs().empty()) { |
+ } else { |
+ local_audio_description_.set_codecs(codecs_result.MoveValue()); |
+ } |
+ local_audio_description_.set_rtp_header_extensions( |
+ extensions_result.MoveValue()); |
+ remote_audio_description_.mutable_streams() = |
+ stream_params_result.MoveValue(); |
+ // Direction set based on encoding "active" flag. |
+ local_audio_description_.set_direction( |
+ local_direction.ToMediaContentDirection()); |
+ remote_audio_description_.set_direction( |
+ local_direction.Reversed().ToMediaContentDirection()); |
+ |
+ if (!voice_channel_->SetLocalContent(&local_audio_description_, |
+ cricket::CA_OFFER, nullptr)) { |
+ LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, |
+ "Failed to apply local parameters to media channel."); |
+ } |
+ if (!voice_channel_->SetRemoteContent(&remote_audio_description_, |
+ cricket::CA_ANSWER, nullptr)) { |
+ LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, |
+ "Failed to apply remote parameters to media channel."); |
+ } |
+ return RTCError::OK(); |
+} |
+ |
+RTCError RtpTransportControllerAdapter::ValidateAndApplyVideoReceiverParameters( |
+ const RtpParameters& parameters) { |
+ RTC_DCHECK(video_channel_); |
+ RTC_DCHECK(have_video_receiver_); |
+ |
+ auto codecs_result = ToCricketCodecs<cricket::VideoCodec>(parameters.codecs); |
+ if (!codecs_result.ok()) { |
+ return codecs_result.MoveError(); |
+ } |
+ |
+ auto extensions_result = ToRtpHeaderExtensions(parameters.header_extensions); |
+ if (!extensions_result.ok()) { |
+ return extensions_result.MoveError(); |
+ } |
+ |
+ cricket::RtpTransceiverDirection local_direction = |
+ cricket::RtpTransceiverDirection::FromMediaContentDirection( |
+ local_video_description_.direction()); |
+ int bandwidth = cricket::kAutoBandwidth; |
+ auto stream_params_result = ToStreamParamsVec(parameters.encodings); |
+ if (!stream_params_result.ok()) { |
+ return stream_params_result.MoveError(); |
+ } |
+ local_direction.recv = |
+ !parameters.encodings.empty() && parameters.encodings[0].active; |
+ |
+ // Validation is done, so we can attempt applying the descriptions. Received |
+ // codecs and header extensions go in local description, streams go in |
+ // remote. |
+ // |
+ // If there are no codecs or encodings, just leave the previous set of |
+ // codecs. The media engine doesn't like an empty set of codecs. |
+ if (remote_video_description_.streams().empty() && |
+ local_video_description_.codecs().empty()) { |
+ } else { |
+ local_video_description_.set_codecs(codecs_result.MoveValue()); |
+ } |
+ local_video_description_.set_rtp_header_extensions( |
+ extensions_result.MoveValue()); |
+ local_video_description_.set_bandwidth(bandwidth); |
+ remote_video_description_.mutable_streams() = |
+ stream_params_result.MoveValue(); |
+ // Direction set based on encoding "active" flag. |
+ local_video_description_.set_direction( |
+ local_direction.ToMediaContentDirection()); |
+ remote_video_description_.set_direction( |
+ local_direction.Reversed().ToMediaContentDirection()); |
+ |
+ if (!video_channel_->SetLocalContent(&local_video_description_, |
+ cricket::CA_OFFER, nullptr)) { |
+ LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, |
+ "Failed to apply local parameters to media channel."); |
+ } |
+ if (!video_channel_->SetRemoteContent(&remote_video_description_, |
+ cricket::CA_ANSWER, nullptr)) { |
+ LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, |
+ "Failed to apply remote parameters to media channel."); |
+ } |
+ return RTCError::OK(); |
+} |
+ |
+RtpTransportControllerAdapter::RtpTransportControllerAdapter( |
+ const cricket::MediaConfig& config, |
+ cricket::ChannelManager* channel_manager, |
+ webrtc::RtcEventLog* event_log, |
+ rtc::Thread* signaling_thread, |
+ rtc::Thread* worker_thread) |
+ : signaling_thread_(signaling_thread), |
+ worker_thread_(worker_thread), |
+ media_controller_(MediaControllerInterface::Create(config, |
+ worker_thread, |
+ channel_manager, |
+ event_log)) { |
+ RTC_DCHECK_RUN_ON(signaling_thread_); |
+ RTC_DCHECK(channel_manager); |
+ // MediaControllerInterface::Create should never fail. |
+ RTC_DCHECK(media_controller_); |
+ static const cricket::AudioCodec dummy_audio(0, cricket::kPcmuCodecName, 8000, |
+ 0, 1); |
+ static const cricket::VideoCodec dummy_video(96, cricket::kVp8CodecName); |
+ local_audio_description_.AddCodec(dummy_audio); |
+ remote_audio_description_.AddCodec(dummy_audio); |
+ local_video_description_.AddCodec(dummy_video); |
+ remote_video_description_.AddCodec(dummy_video); |
+} |
+ |
+void RtpTransportControllerAdapter::CreateVoiceChannel() { |
+ voice_channel_ = media_controller_->channel_manager()->CreateVoiceChannel( |
+ media_controller_.get(), |
+ inner_audio_transport_->GetRtpPacketTransport()->GetInternal(), |
+ inner_audio_transport_->GetRtcpPacketTransport() |
+ ? inner_audio_transport_->GetRtcpPacketTransport()->GetInternal() |
+ : nullptr, |
+ signaling_thread_, "audio", false, cricket::AudioOptions()); |
+ RTC_DCHECK(voice_channel_); |
+ voice_channel_->Enable(true); |
+} |
+ |
+void RtpTransportControllerAdapter::CreateVideoChannel() { |
+ video_channel_ = media_controller_->channel_manager()->CreateVideoChannel( |
+ media_controller_.get(), |
+ inner_video_transport_->GetRtpPacketTransport()->GetInternal(), |
+ inner_video_transport_->GetRtcpPacketTransport() |
+ ? inner_video_transport_->GetRtcpPacketTransport()->GetInternal() |
+ : nullptr, |
+ signaling_thread_, "audio", false, cricket::VideoOptions()); |
+ RTC_DCHECK(video_channel_); |
+ video_channel_->Enable(true); |
+} |
+ |
+void RtpTransportControllerAdapter::DestroyVoiceChannel() { |
+ RTC_DCHECK(voice_channel_); |
+ media_controller_->channel_manager()->DestroyVoiceChannel(voice_channel_); |
+ voice_channel_ = nullptr; |
+} |
+ |
+void RtpTransportControllerAdapter::DestroyVideoChannel() { |
+ RTC_DCHECK(video_channel_); |
+ media_controller_->channel_manager()->DestroyVideoChannel(video_channel_); |
+ video_channel_ = nullptr; |
+} |
+ |
+void RtpTransportControllerAdapter::CopyRtcpParametersToDescriptions( |
+ const RtcpParameters& params, |
+ cricket::MediaContentDescription* local, |
+ cricket::MediaContentDescription* remote) { |
+ local->set_rtcp_mux(params.mux); |
+ remote->set_rtcp_mux(params.mux); |
+ local->set_rtcp_reduced_size(params.reduced_size); |
+ remote->set_rtcp_reduced_size(params.reduced_size); |
+ for (cricket::StreamParams& stream_params : local->mutable_streams()) { |
+ stream_params.cname = params.cname; |
+ } |
+} |
+ |
+uint32_t RtpTransportControllerAdapter::GenerateUnusedSsrc( |
+ std::set<uint32_t>* new_ssrcs) const { |
+ uint32_t ssrc; |
+ do { |
+ ssrc = rtc::CreateRandomNonZeroId(); |
+ } while ( |
+ cricket::GetStreamBySsrc(local_audio_description_.streams(), ssrc) || |
+ cricket::GetStreamBySsrc(remote_audio_description_.streams(), ssrc) || |
+ cricket::GetStreamBySsrc(local_video_description_.streams(), ssrc) || |
+ cricket::GetStreamBySsrc(remote_video_description_.streams(), ssrc) || |
+ !new_ssrcs->insert(ssrc).second); |
+ return ssrc; |
+} |
+ |
+RTCErrorOr<cricket::StreamParamsVec> |
+RtpTransportControllerAdapter::MakeStreamParamsVec( |
+ std::vector<RtpEncodingParameters> encodings, |
+ const std::string& cname, |
+ const cricket::MediaContentDescription& description) const { |
+ if (encodings.size() > 1u) { |
+ LOG_AND_RETURN_ERROR(webrtc::RTCErrorType::UNSUPPORTED_PARAMETER, |
+ "ORTC API implementation doesn't currently " |
+ "support simulcast or layered encodings."); |
+ } else if (encodings.empty()) { |
+ return cricket::StreamParamsVec(); |
+ } |
+ RtpEncodingParameters& encoding = encodings[0]; |
+ std::set<uint32_t> new_ssrcs; |
+ if (encoding.ssrc) { |
+ new_ssrcs.insert(*encoding.ssrc); |
+ } |
+ if (encoding.rtx && encoding.rtx->ssrc) { |
+ new_ssrcs.insert(*encoding.rtx->ssrc); |
+ } |
+ // May need to fill missing SSRCs with generated ones. |
+ if (!encoding.ssrc) { |
+ if (!description.streams().empty()) { |
+ encoding.ssrc.emplace(description.streams()[0].first_ssrc()); |
+ } else { |
+ encoding.ssrc.emplace(GenerateUnusedSsrc(&new_ssrcs)); |
+ } |
+ } |
+ if (encoding.rtx && !encoding.rtx->ssrc) { |
+ uint32_t existing_rtx_ssrc; |
+ if (!description.streams().empty() && |
+ description.streams()[0].GetFidSsrc( |
+ description.streams()[0].first_ssrc(), &existing_rtx_ssrc)) { |
+ encoding.rtx->ssrc.emplace(existing_rtx_ssrc); |
+ } else { |
+ encoding.rtx->ssrc.emplace(GenerateUnusedSsrc(&new_ssrcs)); |
+ } |
+ } |
+ |
+ auto result = ToStreamParamsVec(encodings); |
+ if (!result.ok()) { |
+ return result.MoveError(); |
+ } |
+ // If conversion was successful, there should be one StreamParams. |
+ RTC_DCHECK_EQ(1u, result.value().size()); |
+ result.value()[0].cname = cname; |
+ return result; |
+} |
+ |
+} // namespace webrtc |