blob: 5e0b62112357ba849fec33d5e3428e1e5c235932 [file] [log] [blame]
deadbeefe814a0d2017-02-25 18:15:09 -08001/*
2 * Copyright 2017 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "webrtc/ortc/rtptransportcontrolleradapter.h"
12
13#include <algorithm> // For "remove", "find".
deadbeefe814a0d2017-02-25 18:15:09 -080014#include <set>
zhihuangd3501ad2017-03-03 14:39:06 -080015#include <sstream>
deadbeefe814a0d2017-02-25 18:15:09 -080016#include <unordered_map>
17#include <utility> // For std::move.
18
19#include "webrtc/api/proxy.h"
deadbeefe814a0d2017-02-25 18:15:09 -080020#include "webrtc/media/base/mediaconstants.h"
21#include "webrtc/ortc/ortcrtpreceiveradapter.h"
22#include "webrtc/ortc/ortcrtpsenderadapter.h"
23#include "webrtc/ortc/rtpparametersconversion.h"
24#include "webrtc/ortc/rtptransportadapter.h"
Edward Lemurc20978e2017-07-06 19:44:34 +020025#include "webrtc/rtc_base/checks.h"
deadbeefe814a0d2017-02-25 18:15:09 -080026
27namespace webrtc {
28
29// Note: It's assumed that each individual list doesn't have conflicts, since
30// they should have been detected already by rtpparametersconversion.cc. This
31// only needs to detect conflicts *between* A and B.
32template <typename C1, typename C2>
33static RTCError CheckForIdConflicts(
34 const std::vector<C1>& codecs_a,
35 const cricket::RtpHeaderExtensions& extensions_a,
36 const cricket::StreamParamsVec& streams_a,
37 const std::vector<C2>& codecs_b,
38 const cricket::RtpHeaderExtensions& extensions_b,
39 const cricket::StreamParamsVec& streams_b) {
40 std::ostringstream oss;
41 // Since it's assumed that C1 and C2 are different types, codecs_a and
42 // codecs_b should never contain the same payload type, and thus we can just
43 // use a set.
44 std::set<int> seen_payload_types;
45 for (const C1& codec : codecs_a) {
46 seen_payload_types.insert(codec.id);
47 }
48 for (const C2& codec : codecs_b) {
49 if (!seen_payload_types.insert(codec.id).second) {
50 oss << "Same payload type used for audio and video codecs: " << codec.id;
51 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER, oss.str());
52 }
53 }
54 // Audio and video *may* use the same header extensions, so use a map.
55 std::unordered_map<int, std::string> seen_extensions;
56 for (const webrtc::RtpExtension& extension : extensions_a) {
57 seen_extensions[extension.id] = extension.uri;
58 }
59 for (const webrtc::RtpExtension& extension : extensions_b) {
60 if (seen_extensions.find(extension.id) != seen_extensions.end() &&
61 seen_extensions.at(extension.id) != extension.uri) {
62 oss << "Same ID used for different RTP header extensions: "
63 << extension.id;
64 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER, oss.str());
65 }
66 }
67 std::set<uint32_t> seen_ssrcs;
68 for (const cricket::StreamParams& stream : streams_a) {
69 seen_ssrcs.insert(stream.ssrcs.begin(), stream.ssrcs.end());
70 }
71 for (const cricket::StreamParams& stream : streams_b) {
72 for (uint32_t ssrc : stream.ssrcs) {
73 if (!seen_ssrcs.insert(ssrc).second) {
74 oss << "Same SSRC used for audio and video senders: " << ssrc;
75 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER, oss.str());
76 }
77 }
78 }
79 return RTCError::OK();
80}
81
82BEGIN_OWNED_PROXY_MAP(RtpTransportController)
83PROXY_SIGNALING_THREAD_DESTRUCTOR()
84PROXY_CONSTMETHOD0(std::vector<RtpTransportInterface*>, GetTransports)
85protected:
86RtpTransportControllerAdapter* GetInternal() override {
87 return internal();
88}
89END_PROXY_MAP()
90
91// static
92std::unique_ptr<RtpTransportControllerInterface>
93RtpTransportControllerAdapter::CreateProxied(
94 const cricket::MediaConfig& config,
95 cricket::ChannelManager* channel_manager,
96 webrtc::RtcEventLog* event_log,
97 rtc::Thread* signaling_thread,
98 rtc::Thread* worker_thread) {
99 std::unique_ptr<RtpTransportControllerAdapter> wrapped(
100 new RtpTransportControllerAdapter(config, channel_manager, event_log,
101 signaling_thread, worker_thread));
102 return RtpTransportControllerProxyWithInternal<
103 RtpTransportControllerAdapter>::Create(signaling_thread, worker_thread,
104 std::move(wrapped));
105}
106
107RtpTransportControllerAdapter::~RtpTransportControllerAdapter() {
108 RTC_DCHECK_RUN_ON(signaling_thread_);
109 if (!transport_proxies_.empty()) {
110 LOG(LS_ERROR)
111 << "Destroying RtpTransportControllerAdapter while RtpTransports "
112 "are still using it; this is unsafe.";
113 }
114 if (voice_channel_) {
115 // This would mean audio RTP senders/receivers that are using us haven't
116 // been destroyed. This isn't safe (see error log above).
117 DestroyVoiceChannel();
118 }
119 if (voice_channel_) {
120 // This would mean video RTP senders/receivers that are using us haven't
121 // been destroyed. This isn't safe (see error log above).
122 DestroyVideoChannel();
123 }
nisseeaabdf62017-05-05 02:23:02 -0700124 // Call must be destroyed on the worker thread.
125 worker_thread_->Invoke<void>(
126 RTC_FROM_HERE,
127 rtc::Bind(&RtpTransportControllerAdapter::Close_w, this));
deadbeefe814a0d2017-02-25 18:15:09 -0800128}
129
130RTCErrorOr<std::unique_ptr<RtpTransportInterface>>
131RtpTransportControllerAdapter::CreateProxiedRtpTransport(
132 const RtcpParameters& rtcp_parameters,
133 PacketTransportInterface* rtp,
134 PacketTransportInterface* rtcp) {
135 auto result =
136 RtpTransportAdapter::CreateProxied(rtcp_parameters, rtp, rtcp, this);
137 if (result.ok()) {
138 transport_proxies_.push_back(result.value().get());
139 transport_proxies_.back()->GetInternal()->SignalDestroyed.connect(
140 this, &RtpTransportControllerAdapter::OnRtpTransportDestroyed);
141 }
142 return result;
143}
144
zhihuangd3501ad2017-03-03 14:39:06 -0800145RTCErrorOr<std::unique_ptr<SrtpTransportInterface>>
146RtpTransportControllerAdapter::CreateProxiedSrtpTransport(
147 const RtcpParameters& rtcp_parameters,
148 PacketTransportInterface* rtp,
149 PacketTransportInterface* rtcp) {
150 auto result =
151 RtpTransportAdapter::CreateSrtpProxied(rtcp_parameters, rtp, rtcp, this);
152 if (result.ok()) {
153 transport_proxies_.push_back(result.value().get());
154 transport_proxies_.back()->GetInternal()->SignalDestroyed.connect(
155 this, &RtpTransportControllerAdapter::OnRtpTransportDestroyed);
156 }
157 return result;
158}
159
deadbeefe814a0d2017-02-25 18:15:09 -0800160RTCErrorOr<std::unique_ptr<OrtcRtpSenderInterface>>
161RtpTransportControllerAdapter::CreateProxiedRtpSender(
162 cricket::MediaType kind,
163 RtpTransportInterface* transport_proxy) {
164 RTC_DCHECK(transport_proxy);
165 RTC_DCHECK(std::find(transport_proxies_.begin(), transport_proxies_.end(),
166 transport_proxy) != transport_proxies_.end());
167 std::unique_ptr<OrtcRtpSenderAdapter> new_sender(
168 new OrtcRtpSenderAdapter(kind, transport_proxy, this));
169 RTCError err;
170 switch (kind) {
171 case cricket::MEDIA_TYPE_AUDIO:
172 err = AttachAudioSender(new_sender.get(), transport_proxy->GetInternal());
173 break;
174 case cricket::MEDIA_TYPE_VIDEO:
175 err = AttachVideoSender(new_sender.get(), transport_proxy->GetInternal());
176 break;
177 case cricket::MEDIA_TYPE_DATA:
178 RTC_NOTREACHED();
179 }
180 if (!err.ok()) {
181 return std::move(err);
182 }
183
184 return OrtcRtpSenderAdapter::CreateProxy(std::move(new_sender));
185}
186
187RTCErrorOr<std::unique_ptr<OrtcRtpReceiverInterface>>
188RtpTransportControllerAdapter::CreateProxiedRtpReceiver(
189 cricket::MediaType kind,
190 RtpTransportInterface* transport_proxy) {
191 RTC_DCHECK(transport_proxy);
192 RTC_DCHECK(std::find(transport_proxies_.begin(), transport_proxies_.end(),
193 transport_proxy) != transport_proxies_.end());
194 std::unique_ptr<OrtcRtpReceiverAdapter> new_receiver(
195 new OrtcRtpReceiverAdapter(kind, transport_proxy, this));
196 RTCError err;
197 switch (kind) {
198 case cricket::MEDIA_TYPE_AUDIO:
199 err = AttachAudioReceiver(new_receiver.get(),
200 transport_proxy->GetInternal());
201 break;
202 case cricket::MEDIA_TYPE_VIDEO:
203 err = AttachVideoReceiver(new_receiver.get(),
204 transport_proxy->GetInternal());
205 break;
206 case cricket::MEDIA_TYPE_DATA:
207 RTC_NOTREACHED();
208 }
209 if (!err.ok()) {
210 return std::move(err);
211 }
212
213 return OrtcRtpReceiverAdapter::CreateProxy(std::move(new_receiver));
214}
215
216std::vector<RtpTransportInterface*>
217RtpTransportControllerAdapter::GetTransports() const {
218 RTC_DCHECK_RUN_ON(signaling_thread_);
219 return transport_proxies_;
220}
221
222RTCError RtpTransportControllerAdapter::SetRtcpParameters(
223 const RtcpParameters& parameters,
224 RtpTransportInterface* inner_transport) {
225 do {
226 if (inner_transport == inner_audio_transport_) {
227 CopyRtcpParametersToDescriptions(parameters, &local_audio_description_,
228 &remote_audio_description_);
229 if (!voice_channel_->SetLocalContent(&local_audio_description_,
230 cricket::CA_OFFER, nullptr)) {
231 break;
232 }
233 if (!voice_channel_->SetRemoteContent(&remote_audio_description_,
234 cricket::CA_ANSWER, nullptr)) {
235 break;
236 }
237 } else if (inner_transport == inner_video_transport_) {
238 CopyRtcpParametersToDescriptions(parameters, &local_video_description_,
239 &remote_video_description_);
240 if (!video_channel_->SetLocalContent(&local_video_description_,
241 cricket::CA_OFFER, nullptr)) {
242 break;
243 }
244 if (!video_channel_->SetRemoteContent(&remote_video_description_,
245 cricket::CA_ANSWER, nullptr)) {
246 break;
247 }
248 }
249 return RTCError::OK();
250 } while (false);
251 LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
252 "Failed to apply new RTCP parameters.");
253}
254
255RTCError RtpTransportControllerAdapter::ValidateAndApplyAudioSenderParameters(
256 const RtpParameters& parameters,
257 uint32_t* primary_ssrc) {
258 RTC_DCHECK(voice_channel_);
259 RTC_DCHECK(have_audio_sender_);
260
261 auto codecs_result = ToCricketCodecs<cricket::AudioCodec>(parameters.codecs);
262 if (!codecs_result.ok()) {
263 return codecs_result.MoveError();
264 }
265
266 auto extensions_result =
267 ToCricketRtpHeaderExtensions(parameters.header_extensions);
268 if (!extensions_result.ok()) {
269 return extensions_result.MoveError();
270 }
271
272 auto stream_params_result = MakeSendStreamParamsVec(
273 parameters.encodings, inner_audio_transport_->GetRtcpParameters().cname,
274 local_audio_description_);
275 if (!stream_params_result.ok()) {
276 return stream_params_result.MoveError();
277 }
278
279 // Check that audio/video sender aren't using the same IDs to refer to
280 // different things, if they share the same transport.
281 if (inner_audio_transport_ == inner_video_transport_) {
282 RTCError err = CheckForIdConflicts(
283 codecs_result.value(), extensions_result.value(),
284 stream_params_result.value(), remote_video_description_.codecs(),
285 remote_video_description_.rtp_header_extensions(),
286 local_video_description_.streams());
287 if (!err.ok()) {
288 return err;
289 }
290 }
291
292 cricket::RtpTransceiverDirection local_direction =
293 cricket::RtpTransceiverDirection::FromMediaContentDirection(
294 local_audio_description_.direction());
295 int bandwidth = cricket::kAutoBandwidth;
296 if (parameters.encodings.size() == 1u) {
297 if (parameters.encodings[0].max_bitrate_bps) {
298 bandwidth = *parameters.encodings[0].max_bitrate_bps;
299 }
300 local_direction.send = parameters.encodings[0].active;
301 } else {
302 local_direction.send = false;
303 }
304 if (primary_ssrc && !stream_params_result.value().empty()) {
305 *primary_ssrc = stream_params_result.value()[0].first_ssrc();
306 }
307
308 // Validation is done, so we can attempt applying the descriptions. Sent
309 // codecs and header extensions go in remote description, streams go in
310 // local.
311 //
312 // If there are no codecs or encodings, just leave the previous set of
313 // codecs. The media engine doesn't like an empty set of codecs.
314 if (local_audio_description_.streams().empty() &&
315 remote_audio_description_.codecs().empty()) {
316 } else {
317 remote_audio_description_.set_codecs(codecs_result.MoveValue());
318 }
319 remote_audio_description_.set_rtp_header_extensions(
320 extensions_result.MoveValue());
321 remote_audio_description_.set_bandwidth(bandwidth);
322 local_audio_description_.mutable_streams() = stream_params_result.MoveValue();
323 // Direction set based on encoding "active" flag.
324 local_audio_description_.set_direction(
325 local_direction.ToMediaContentDirection());
326 remote_audio_description_.set_direction(
327 local_direction.Reversed().ToMediaContentDirection());
328
329 // Set remote content first, to ensure the stream is created with the correct
330 // codec.
331 if (!voice_channel_->SetRemoteContent(&remote_audio_description_,
332 cricket::CA_OFFER, nullptr)) {
333 LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
334 "Failed to apply remote parameters to media channel.");
335 }
336 if (!voice_channel_->SetLocalContent(&local_audio_description_,
337 cricket::CA_ANSWER, nullptr)) {
338 LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
339 "Failed to apply local parameters to media channel.");
340 }
341 return RTCError::OK();
342}
343
344RTCError RtpTransportControllerAdapter::ValidateAndApplyVideoSenderParameters(
345 const RtpParameters& parameters,
346 uint32_t* primary_ssrc) {
347 RTC_DCHECK(video_channel_);
348 RTC_DCHECK(have_video_sender_);
349
350 auto codecs_result = ToCricketCodecs<cricket::VideoCodec>(parameters.codecs);
351 if (!codecs_result.ok()) {
352 return codecs_result.MoveError();
353 }
354
355 auto extensions_result =
356 ToCricketRtpHeaderExtensions(parameters.header_extensions);
357 if (!extensions_result.ok()) {
358 return extensions_result.MoveError();
359 }
360
361 auto stream_params_result = MakeSendStreamParamsVec(
362 parameters.encodings, inner_video_transport_->GetRtcpParameters().cname,
363 local_video_description_);
364 if (!stream_params_result.ok()) {
365 return stream_params_result.MoveError();
366 }
367
368 // Check that audio/video sender aren't using the same IDs to refer to
369 // different things, if they share the same transport.
370 if (inner_audio_transport_ == inner_video_transport_) {
371 RTCError err = CheckForIdConflicts(
372 codecs_result.value(), extensions_result.value(),
373 stream_params_result.value(), remote_audio_description_.codecs(),
374 remote_audio_description_.rtp_header_extensions(),
375 local_audio_description_.streams());
376 if (!err.ok()) {
377 return err;
378 }
379 }
380
381 cricket::RtpTransceiverDirection local_direction =
382 cricket::RtpTransceiverDirection::FromMediaContentDirection(
383 local_video_description_.direction());
384 int bandwidth = cricket::kAutoBandwidth;
385 if (parameters.encodings.size() == 1u) {
386 if (parameters.encodings[0].max_bitrate_bps) {
387 bandwidth = *parameters.encodings[0].max_bitrate_bps;
388 }
389 local_direction.send = parameters.encodings[0].active;
390 } else {
391 local_direction.send = false;
392 }
393 if (primary_ssrc && !stream_params_result.value().empty()) {
394 *primary_ssrc = stream_params_result.value()[0].first_ssrc();
395 }
396
397 // Validation is done, so we can attempt applying the descriptions. Sent
398 // codecs and header extensions go in remote description, streams go in
399 // local.
400 //
401 // If there are no codecs or encodings, just leave the previous set of
402 // codecs. The media engine doesn't like an empty set of codecs.
403 if (local_video_description_.streams().empty() &&
404 remote_video_description_.codecs().empty()) {
405 } else {
406 remote_video_description_.set_codecs(codecs_result.MoveValue());
407 }
408 remote_video_description_.set_rtp_header_extensions(
409 extensions_result.MoveValue());
410 remote_video_description_.set_bandwidth(bandwidth);
411 local_video_description_.mutable_streams() = stream_params_result.MoveValue();
412 // Direction set based on encoding "active" flag.
413 local_video_description_.set_direction(
414 local_direction.ToMediaContentDirection());
415 remote_video_description_.set_direction(
416 local_direction.Reversed().ToMediaContentDirection());
417
418 // Set remote content first, to ensure the stream is created with the correct
419 // codec.
420 if (!video_channel_->SetRemoteContent(&remote_video_description_,
421 cricket::CA_OFFER, nullptr)) {
422 LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
423 "Failed to apply remote parameters to media channel.");
424 }
425 if (!video_channel_->SetLocalContent(&local_video_description_,
426 cricket::CA_ANSWER, nullptr)) {
427 LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
428 "Failed to apply local parameters to media channel.");
429 }
430 return RTCError::OK();
431}
432
433RTCError RtpTransportControllerAdapter::ValidateAndApplyAudioReceiverParameters(
434 const RtpParameters& parameters) {
435 RTC_DCHECK(voice_channel_);
436 RTC_DCHECK(have_audio_receiver_);
437
438 auto codecs_result = ToCricketCodecs<cricket::AudioCodec>(parameters.codecs);
439 if (!codecs_result.ok()) {
440 return codecs_result.MoveError();
441 }
442
443 auto extensions_result =
444 ToCricketRtpHeaderExtensions(parameters.header_extensions);
445 if (!extensions_result.ok()) {
446 return extensions_result.MoveError();
447 }
448
449 cricket::RtpTransceiverDirection local_direction =
450 cricket::RtpTransceiverDirection::FromMediaContentDirection(
451 local_audio_description_.direction());
452 auto stream_params_result = ToCricketStreamParamsVec(parameters.encodings);
453 if (!stream_params_result.ok()) {
454 return stream_params_result.MoveError();
455 }
456
457 // Check that audio/video receive aren't using the same IDs to refer to
458 // different things, if they share the same transport.
459 if (inner_audio_transport_ == inner_video_transport_) {
460 RTCError err = CheckForIdConflicts(
461 codecs_result.value(), extensions_result.value(),
462 stream_params_result.value(), local_video_description_.codecs(),
463 local_video_description_.rtp_header_extensions(),
464 remote_video_description_.streams());
465 if (!err.ok()) {
466 return err;
467 }
468 }
469
470 local_direction.recv =
471 !parameters.encodings.empty() && parameters.encodings[0].active;
472
473 // Validation is done, so we can attempt applying the descriptions. Received
474 // codecs and header extensions go in local description, streams go in
475 // remote.
476 //
477 // If there are no codecs or encodings, just leave the previous set of
478 // codecs. The media engine doesn't like an empty set of codecs.
479 if (remote_audio_description_.streams().empty() &&
480 local_audio_description_.codecs().empty()) {
481 } else {
482 local_audio_description_.set_codecs(codecs_result.MoveValue());
483 }
484 local_audio_description_.set_rtp_header_extensions(
485 extensions_result.MoveValue());
486 remote_audio_description_.mutable_streams() =
487 stream_params_result.MoveValue();
488 // Direction set based on encoding "active" flag.
489 local_audio_description_.set_direction(
490 local_direction.ToMediaContentDirection());
491 remote_audio_description_.set_direction(
492 local_direction.Reversed().ToMediaContentDirection());
493
494 if (!voice_channel_->SetLocalContent(&local_audio_description_,
495 cricket::CA_OFFER, nullptr)) {
496 LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
497 "Failed to apply local parameters to media channel.");
498 }
499 if (!voice_channel_->SetRemoteContent(&remote_audio_description_,
500 cricket::CA_ANSWER, nullptr)) {
501 LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
502 "Failed to apply remote parameters to media channel.");
503 }
504 return RTCError::OK();
505}
506
507RTCError RtpTransportControllerAdapter::ValidateAndApplyVideoReceiverParameters(
508 const RtpParameters& parameters) {
509 RTC_DCHECK(video_channel_);
510 RTC_DCHECK(have_video_receiver_);
511
512 auto codecs_result = ToCricketCodecs<cricket::VideoCodec>(parameters.codecs);
513 if (!codecs_result.ok()) {
514 return codecs_result.MoveError();
515 }
516
517 auto extensions_result =
518 ToCricketRtpHeaderExtensions(parameters.header_extensions);
519 if (!extensions_result.ok()) {
520 return extensions_result.MoveError();
521 }
522
523 cricket::RtpTransceiverDirection local_direction =
524 cricket::RtpTransceiverDirection::FromMediaContentDirection(
525 local_video_description_.direction());
526 int bandwidth = cricket::kAutoBandwidth;
527 auto stream_params_result = ToCricketStreamParamsVec(parameters.encodings);
528 if (!stream_params_result.ok()) {
529 return stream_params_result.MoveError();
530 }
531
532 // Check that audio/video receiver aren't using the same IDs to refer to
533 // different things, if they share the same transport.
534 if (inner_audio_transport_ == inner_video_transport_) {
535 RTCError err = CheckForIdConflicts(
536 codecs_result.value(), extensions_result.value(),
537 stream_params_result.value(), local_audio_description_.codecs(),
538 local_audio_description_.rtp_header_extensions(),
539 remote_audio_description_.streams());
540 if (!err.ok()) {
541 return err;
542 }
543 }
544
545 local_direction.recv =
546 !parameters.encodings.empty() && parameters.encodings[0].active;
547
548 // Validation is done, so we can attempt applying the descriptions. Received
549 // codecs and header extensions go in local description, streams go in
550 // remote.
551 //
552 // If there are no codecs or encodings, just leave the previous set of
553 // codecs. The media engine doesn't like an empty set of codecs.
554 if (remote_video_description_.streams().empty() &&
555 local_video_description_.codecs().empty()) {
556 } else {
557 local_video_description_.set_codecs(codecs_result.MoveValue());
558 }
559 local_video_description_.set_rtp_header_extensions(
560 extensions_result.MoveValue());
561 local_video_description_.set_bandwidth(bandwidth);
562 remote_video_description_.mutable_streams() =
563 stream_params_result.MoveValue();
564 // Direction set based on encoding "active" flag.
565 local_video_description_.set_direction(
566 local_direction.ToMediaContentDirection());
567 remote_video_description_.set_direction(
568 local_direction.Reversed().ToMediaContentDirection());
569
570 if (!video_channel_->SetLocalContent(&local_video_description_,
571 cricket::CA_OFFER, nullptr)) {
572 LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
573 "Failed to apply local parameters to media channel.");
574 }
575 if (!video_channel_->SetRemoteContent(&remote_video_description_,
576 cricket::CA_ANSWER, nullptr)) {
577 LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
578 "Failed to apply remote parameters to media channel.");
579 }
580 return RTCError::OK();
581}
582
583RtpTransportControllerAdapter::RtpTransportControllerAdapter(
584 const cricket::MediaConfig& config,
585 cricket::ChannelManager* channel_manager,
586 webrtc::RtcEventLog* event_log,
587 rtc::Thread* signaling_thread,
588 rtc::Thread* worker_thread)
589 : signaling_thread_(signaling_thread),
590 worker_thread_(worker_thread),
nisseeaabdf62017-05-05 02:23:02 -0700591 media_config_(config),
592 channel_manager_(channel_manager),
593 event_log_(event_log) {
deadbeefe814a0d2017-02-25 18:15:09 -0800594 RTC_DCHECK_RUN_ON(signaling_thread_);
nisseeaabdf62017-05-05 02:23:02 -0700595 RTC_DCHECK(channel_manager_);
deadbeefe814a0d2017-02-25 18:15:09 -0800596 // Add "dummy" codecs to the descriptions, because the media engines
597 // currently reject empty lists of codecs. Note that these codecs will never
598 // actually be used, because when parameters are set, the dummy codecs will
599 // be replaced by actual codecs before any send/receive streams are created.
600 static const cricket::AudioCodec dummy_audio(0, cricket::kPcmuCodecName, 8000,
601 0, 1);
602 static const cricket::VideoCodec dummy_video(96, cricket::kVp8CodecName);
603 local_audio_description_.AddCodec(dummy_audio);
604 remote_audio_description_.AddCodec(dummy_audio);
605 local_video_description_.AddCodec(dummy_video);
606 remote_video_description_.AddCodec(dummy_video);
nisseeaabdf62017-05-05 02:23:02 -0700607
608 worker_thread_->Invoke<void>(
609 RTC_FROM_HERE,
610 rtc::Bind(&RtpTransportControllerAdapter::Init_w, this));
611}
612
613// TODO(nisse): Duplicates corresponding method in PeerConnection (used
614// to be in MediaController).
615void RtpTransportControllerAdapter::Init_w() {
616 RTC_DCHECK(worker_thread_->IsCurrent());
617 RTC_DCHECK(!call_);
618
619 const int kMinBandwidthBps = 30000;
620 const int kStartBandwidthBps = 300000;
621 const int kMaxBandwidthBps = 2000000;
622
623 webrtc::Call::Config call_config(event_log_);
624 call_config.audio_state = channel_manager_->media_engine()->GetAudioState();
625 call_config.bitrate_config.min_bitrate_bps = kMinBandwidthBps;
626 call_config.bitrate_config.start_bitrate_bps = kStartBandwidthBps;
627 call_config.bitrate_config.max_bitrate_bps = kMaxBandwidthBps;
628
629 call_.reset(webrtc::Call::Create(call_config));
630}
631
632void RtpTransportControllerAdapter::Close_w() {
633 call_.reset();
deadbeefe814a0d2017-02-25 18:15:09 -0800634}
635
636RTCError RtpTransportControllerAdapter::AttachAudioSender(
637 OrtcRtpSenderAdapter* sender,
638 RtpTransportInterface* inner_transport) {
639 if (have_audio_sender_) {
640 LOG_AND_RETURN_ERROR(RTCErrorType::UNSUPPORTED_OPERATION,
641 "Using two audio RtpSenders with the same "
642 "RtpTransportControllerAdapter is not currently "
643 "supported.");
644 }
645 if (inner_audio_transport_ && inner_audio_transport_ != inner_transport) {
646 LOG_AND_RETURN_ERROR(RTCErrorType::UNSUPPORTED_OPERATION,
647 "Using different transports for the audio "
648 "RtpSender and RtpReceiver is not currently "
649 "supported.");
650 }
zhihuangd3501ad2017-03-03 14:39:06 -0800651 RTCError err = MaybeSetCryptos(inner_transport, &local_audio_description_,
652 &remote_audio_description_);
653 if (!err.ok()) {
654 return err;
655 }
deadbeefe814a0d2017-02-25 18:15:09 -0800656 // If setting new transport, extract its RTCP parameters and create voice
657 // channel.
658 if (!inner_audio_transport_) {
659 CopyRtcpParametersToDescriptions(inner_transport->GetRtcpParameters(),
660 &local_audio_description_,
661 &remote_audio_description_);
662 inner_audio_transport_ = inner_transport;
663 CreateVoiceChannel();
664 }
665 have_audio_sender_ = true;
666 sender->SignalDestroyed.connect(
667 this, &RtpTransportControllerAdapter::OnAudioSenderDestroyed);
668 return RTCError::OK();
669}
670
671RTCError RtpTransportControllerAdapter::AttachVideoSender(
672 OrtcRtpSenderAdapter* sender,
673 RtpTransportInterface* inner_transport) {
674 if (have_video_sender_) {
675 LOG_AND_RETURN_ERROR(RTCErrorType::UNSUPPORTED_OPERATION,
676 "Using two video RtpSenders with the same "
677 "RtpTransportControllerAdapter is not currently "
678 "supported.");
679 }
680 if (inner_video_transport_ && inner_video_transport_ != inner_transport) {
681 LOG_AND_RETURN_ERROR(RTCErrorType::UNSUPPORTED_OPERATION,
682 "Using different transports for the video "
683 "RtpSender and RtpReceiver is not currently "
684 "supported.");
685 }
zhihuangd3501ad2017-03-03 14:39:06 -0800686 RTCError err = MaybeSetCryptos(inner_transport, &local_video_description_,
687 &remote_video_description_);
688 if (!err.ok()) {
689 return err;
690 }
deadbeefe814a0d2017-02-25 18:15:09 -0800691 // If setting new transport, extract its RTCP parameters and create video
692 // channel.
693 if (!inner_video_transport_) {
694 CopyRtcpParametersToDescriptions(inner_transport->GetRtcpParameters(),
695 &local_video_description_,
696 &remote_video_description_);
697 inner_video_transport_ = inner_transport;
698 CreateVideoChannel();
699 }
700 have_video_sender_ = true;
701 sender->SignalDestroyed.connect(
702 this, &RtpTransportControllerAdapter::OnVideoSenderDestroyed);
703 return RTCError::OK();
704}
705
706RTCError RtpTransportControllerAdapter::AttachAudioReceiver(
707 OrtcRtpReceiverAdapter* receiver,
708 RtpTransportInterface* inner_transport) {
709 if (have_audio_receiver_) {
710 LOG_AND_RETURN_ERROR(RTCErrorType::UNSUPPORTED_OPERATION,
711 "Using two audio RtpReceivers with the same "
712 "RtpTransportControllerAdapter is not currently "
713 "supported.");
714 }
715 if (inner_audio_transport_ && inner_audio_transport_ != inner_transport) {
716 LOG_AND_RETURN_ERROR(RTCErrorType::UNSUPPORTED_OPERATION,
717 "Using different transports for the audio "
718 "RtpReceiver and RtpReceiver is not currently "
719 "supported.");
720 }
zhihuangd3501ad2017-03-03 14:39:06 -0800721 RTCError err = MaybeSetCryptos(inner_transport, &local_audio_description_,
722 &remote_audio_description_);
723 if (!err.ok()) {
724 return err;
725 }
deadbeefe814a0d2017-02-25 18:15:09 -0800726 // If setting new transport, extract its RTCP parameters and create voice
727 // channel.
728 if (!inner_audio_transport_) {
729 CopyRtcpParametersToDescriptions(inner_transport->GetRtcpParameters(),
730 &local_audio_description_,
731 &remote_audio_description_);
732 inner_audio_transport_ = inner_transport;
733 CreateVoiceChannel();
734 }
735 have_audio_receiver_ = true;
736 receiver->SignalDestroyed.connect(
737 this, &RtpTransportControllerAdapter::OnAudioReceiverDestroyed);
738 return RTCError::OK();
739}
740
741RTCError RtpTransportControllerAdapter::AttachVideoReceiver(
742 OrtcRtpReceiverAdapter* receiver,
743 RtpTransportInterface* inner_transport) {
744 if (have_video_receiver_) {
745 LOG_AND_RETURN_ERROR(RTCErrorType::UNSUPPORTED_OPERATION,
746 "Using two video RtpReceivers with the same "
747 "RtpTransportControllerAdapter is not currently "
748 "supported.");
749 }
750 if (inner_video_transport_ && inner_video_transport_ != inner_transport) {
751 LOG_AND_RETURN_ERROR(RTCErrorType::UNSUPPORTED_OPERATION,
752 "Using different transports for the video "
753 "RtpReceiver and RtpReceiver is not currently "
754 "supported.");
755 }
zhihuangd3501ad2017-03-03 14:39:06 -0800756 RTCError err = MaybeSetCryptos(inner_transport, &local_video_description_,
757 &remote_video_description_);
758 if (!err.ok()) {
759 return err;
760 }
deadbeefe814a0d2017-02-25 18:15:09 -0800761 // If setting new transport, extract its RTCP parameters and create video
762 // channel.
763 if (!inner_video_transport_) {
764 CopyRtcpParametersToDescriptions(inner_transport->GetRtcpParameters(),
765 &local_video_description_,
766 &remote_video_description_);
767 inner_video_transport_ = inner_transport;
768 CreateVideoChannel();
769 }
770 have_video_receiver_ = true;
771 receiver->SignalDestroyed.connect(
772 this, &RtpTransportControllerAdapter::OnVideoReceiverDestroyed);
773 return RTCError::OK();
774}
775
776void RtpTransportControllerAdapter::OnRtpTransportDestroyed(
777 RtpTransportAdapter* transport) {
778 RTC_DCHECK_RUN_ON(signaling_thread_);
779 auto it = std::find_if(transport_proxies_.begin(), transport_proxies_.end(),
780 [transport](RtpTransportInterface* proxy) {
781 return proxy->GetInternal() == transport;
782 });
783 if (it == transport_proxies_.end()) {
784 RTC_NOTREACHED();
785 return;
786 }
787 transport_proxies_.erase(it);
788}
789
790void RtpTransportControllerAdapter::OnAudioSenderDestroyed() {
791 if (!have_audio_sender_) {
792 RTC_NOTREACHED();
793 return;
794 }
795 // Empty parameters should result in sending being stopped.
796 RTCError err =
797 ValidateAndApplyAudioSenderParameters(RtpParameters(), nullptr);
798 RTC_DCHECK(err.ok());
799 have_audio_sender_ = false;
800 if (!have_audio_receiver_) {
801 DestroyVoiceChannel();
802 }
803}
804
805void RtpTransportControllerAdapter::OnVideoSenderDestroyed() {
806 if (!have_video_sender_) {
807 RTC_NOTREACHED();
808 return;
809 }
810 // Empty parameters should result in sending being stopped.
811 RTCError err =
812 ValidateAndApplyVideoSenderParameters(RtpParameters(), nullptr);
813 RTC_DCHECK(err.ok());
814 have_video_sender_ = false;
815 if (!have_video_receiver_) {
816 DestroyVideoChannel();
817 }
818}
819
820void RtpTransportControllerAdapter::OnAudioReceiverDestroyed() {
821 if (!have_audio_receiver_) {
822 RTC_NOTREACHED();
823 return;
824 }
825 // Empty parameters should result in receiving being stopped.
826 RTCError err = ValidateAndApplyAudioReceiverParameters(RtpParameters());
827 RTC_DCHECK(err.ok());
828 have_audio_receiver_ = false;
829 if (!have_audio_sender_) {
830 DestroyVoiceChannel();
831 }
832}
833
834void RtpTransportControllerAdapter::OnVideoReceiverDestroyed() {
835 if (!have_video_receiver_) {
836 RTC_NOTREACHED();
837 return;
838 }
839 // Empty parameters should result in receiving being stopped.
840 RTCError err = ValidateAndApplyVideoReceiverParameters(RtpParameters());
841 RTC_DCHECK(err.ok());
842 have_video_receiver_ = false;
843 if (!have_video_sender_) {
844 DestroyVideoChannel();
845 }
846}
847
848void RtpTransportControllerAdapter::CreateVoiceChannel() {
nisseeaabdf62017-05-05 02:23:02 -0700849 voice_channel_ = channel_manager_->CreateVoiceChannel(
850 call_.get(), media_config_,
deadbeefe814a0d2017-02-25 18:15:09 -0800851 inner_audio_transport_->GetRtpPacketTransport()->GetInternal(),
852 inner_audio_transport_->GetRtcpPacketTransport()
853 ? inner_audio_transport_->GetRtcpPacketTransport()->GetInternal()
854 : nullptr,
855 signaling_thread_, "audio", false, cricket::AudioOptions());
856 RTC_DCHECK(voice_channel_);
857 voice_channel_->Enable(true);
858}
859
860void RtpTransportControllerAdapter::CreateVideoChannel() {
nisseeaabdf62017-05-05 02:23:02 -0700861 video_channel_ = channel_manager_->CreateVideoChannel(
862 call_.get(), media_config_,
deadbeefe814a0d2017-02-25 18:15:09 -0800863 inner_video_transport_->GetRtpPacketTransport()->GetInternal(),
864 inner_video_transport_->GetRtcpPacketTransport()
865 ? inner_video_transport_->GetRtcpPacketTransport()->GetInternal()
866 : nullptr,
867 signaling_thread_, "video", false, cricket::VideoOptions());
868 RTC_DCHECK(video_channel_);
869 video_channel_->Enable(true);
870}
871
872void RtpTransportControllerAdapter::DestroyVoiceChannel() {
873 RTC_DCHECK(voice_channel_);
nisseeaabdf62017-05-05 02:23:02 -0700874 channel_manager_->DestroyVoiceChannel(voice_channel_);
deadbeefe814a0d2017-02-25 18:15:09 -0800875 voice_channel_ = nullptr;
876 inner_audio_transport_ = nullptr;
877}
878
879void RtpTransportControllerAdapter::DestroyVideoChannel() {
880 RTC_DCHECK(video_channel_);
nisseeaabdf62017-05-05 02:23:02 -0700881 channel_manager_->DestroyVideoChannel(video_channel_);
deadbeefe814a0d2017-02-25 18:15:09 -0800882 video_channel_ = nullptr;
883 inner_video_transport_ = nullptr;
884}
885
886void RtpTransportControllerAdapter::CopyRtcpParametersToDescriptions(
887 const RtcpParameters& params,
888 cricket::MediaContentDescription* local,
889 cricket::MediaContentDescription* remote) {
890 local->set_rtcp_mux(params.mux);
891 remote->set_rtcp_mux(params.mux);
892 local->set_rtcp_reduced_size(params.reduced_size);
893 remote->set_rtcp_reduced_size(params.reduced_size);
894 for (cricket::StreamParams& stream_params : local->mutable_streams()) {
895 stream_params.cname = params.cname;
896 }
897}
898
899uint32_t RtpTransportControllerAdapter::GenerateUnusedSsrc(
900 std::set<uint32_t>* new_ssrcs) const {
901 uint32_t ssrc;
902 do {
903 ssrc = rtc::CreateRandomNonZeroId();
904 } while (
905 cricket::GetStreamBySsrc(local_audio_description_.streams(), ssrc) ||
906 cricket::GetStreamBySsrc(remote_audio_description_.streams(), ssrc) ||
907 cricket::GetStreamBySsrc(local_video_description_.streams(), ssrc) ||
908 cricket::GetStreamBySsrc(remote_video_description_.streams(), ssrc) ||
909 !new_ssrcs->insert(ssrc).second);
910 return ssrc;
911}
912
913RTCErrorOr<cricket::StreamParamsVec>
914RtpTransportControllerAdapter::MakeSendStreamParamsVec(
915 std::vector<RtpEncodingParameters> encodings,
916 const std::string& cname,
917 const cricket::MediaContentDescription& description) const {
918 if (encodings.size() > 1u) {
919 LOG_AND_RETURN_ERROR(webrtc::RTCErrorType::UNSUPPORTED_PARAMETER,
920 "ORTC API implementation doesn't currently "
921 "support simulcast or layered encodings.");
922 } else if (encodings.empty()) {
923 return cricket::StreamParamsVec();
924 }
925 RtpEncodingParameters& encoding = encodings[0];
926 std::set<uint32_t> new_ssrcs;
927 if (encoding.ssrc) {
928 new_ssrcs.insert(*encoding.ssrc);
929 }
930 if (encoding.rtx && encoding.rtx->ssrc) {
931 new_ssrcs.insert(*encoding.rtx->ssrc);
932 }
933 // May need to fill missing SSRCs with generated ones.
934 if (!encoding.ssrc) {
935 if (!description.streams().empty()) {
936 encoding.ssrc.emplace(description.streams()[0].first_ssrc());
937 } else {
938 encoding.ssrc.emplace(GenerateUnusedSsrc(&new_ssrcs));
939 }
940 }
941 if (encoding.rtx && !encoding.rtx->ssrc) {
942 uint32_t existing_rtx_ssrc;
943 if (!description.streams().empty() &&
944 description.streams()[0].GetFidSsrc(
945 description.streams()[0].first_ssrc(), &existing_rtx_ssrc)) {
946 encoding.rtx->ssrc.emplace(existing_rtx_ssrc);
947 } else {
948 encoding.rtx->ssrc.emplace(GenerateUnusedSsrc(&new_ssrcs));
949 }
950 }
951
952 auto result = ToCricketStreamParamsVec(encodings);
953 if (!result.ok()) {
954 return result.MoveError();
955 }
956 // If conversion was successful, there should be one StreamParams.
957 RTC_DCHECK_EQ(1u, result.value().size());
958 result.value()[0].cname = cname;
959 return result;
960}
961
zhihuangd3501ad2017-03-03 14:39:06 -0800962RTCError RtpTransportControllerAdapter::MaybeSetCryptos(
963 RtpTransportInterface* rtp_transport,
964 cricket::MediaContentDescription* local_description,
965 cricket::MediaContentDescription* remote_description) {
966 if (rtp_transport->GetInternal()->is_srtp_transport()) {
967 if (!rtp_transport->GetInternal()->send_key() ||
968 !rtp_transport->GetInternal()->receive_key()) {
969 LOG_AND_RETURN_ERROR(webrtc::RTCErrorType::UNSUPPORTED_PARAMETER,
970 "The SRTP send key or receive key is not set.")
971 }
972 std::vector<cricket::CryptoParams> cryptos;
973 cryptos.push_back(*(rtp_transport->GetInternal()->receive_key()));
974 local_description->set_cryptos(cryptos);
975
976 cryptos.clear();
977 cryptos.push_back(*(rtp_transport->GetInternal()->send_key()));
978 remote_description->set_cryptos(cryptos);
979 }
980 return RTCError::OK();
981}
982
deadbeefe814a0d2017-02-25 18:15:09 -0800983} // namespace webrtc