OLD | NEW |
---|---|
(Empty) | |
1 /* | |
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". | |
14 #include <utility> // For std::move. | |
15 | |
16 #include "webrtc/api/proxy.h" | |
17 #include "webrtc/base/checks.h" | |
18 #include "webrtc/media/base/mediaconstants.h" | |
19 #include "webrtc/ortc/rtpparametersconversion.h" | |
20 #include "webrtc/ortc/rtptransportadapter.h" | |
21 | |
22 namespace webrtc { | |
23 | |
24 BEGIN_OWNED_PROXY_MAP(RtpTransportController) | |
25 PROXY_SIGNALING_THREAD_DESTRUCTOR() | |
26 PROXY_CONSTMETHOD0(std::vector<RtpTransportInterface*>, GetTransports) | |
27 protected: | |
28 RtpTransportControllerAdapter* GetInternal() override { | |
29 return internal(); | |
30 } | |
31 END_PROXY_MAP() | |
32 | |
33 // static | |
34 std::unique_ptr<RtpTransportControllerInterface> | |
35 RtpTransportControllerAdapter::CreateProxied( | |
36 const cricket::MediaConfig& config, | |
37 cricket::ChannelManager* channel_manager, | |
38 webrtc::RtcEventLog* event_log, | |
39 rtc::Thread* signaling_thread, | |
40 rtc::Thread* worker_thread) { | |
41 return RtpTransportControllerProxyWithInternal< | |
42 RtpTransportControllerAdapter>::Create(signaling_thread, worker_thread, | |
43 new RtpTransportControllerAdapter( | |
44 config, channel_manager, | |
45 event_log, signaling_thread, | |
46 worker_thread)); | |
47 } | |
48 | |
49 RtpTransportControllerAdapter::~RtpTransportControllerAdapter() { | |
50 RTC_DCHECK_RUN_ON(signaling_thread_); | |
51 if (!transport_proxies_.empty()) { | |
52 LOG(LS_ERROR) | |
53 << "Destroying RtpTransportControllerAdapter while RtpTransports " | |
54 "are still using it; this is unsafe."; | |
55 } | |
56 if (voice_channel_) { | |
57 // This would mean audio RTP senders/receivers that are using us haven't | |
58 // been destroyed, and thus haven't called Detach yet. This isn't safe (see | |
59 // error log above). | |
60 DestroyVoiceChannel(); | |
61 } | |
62 if (voice_channel_) { | |
63 // This would mean video RTP senders/receivers that are using us haven't | |
64 // been destroyed, and thus haven't called Detach yet. This isn't safe (see | |
65 // error log above). | |
66 DestroyVideoChannel(); | |
67 } | |
68 } | |
69 | |
70 std::vector<RtpTransportInterface*> | |
71 RtpTransportControllerAdapter::GetTransports() const { | |
72 RTC_DCHECK_RUN_ON(signaling_thread_); | |
73 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
| |
74 } | |
75 | |
76 void RtpTransportControllerAdapter::AddTransport( | |
77 RtpTransportInterface* transport_proxy) { | |
78 RTC_DCHECK_RUN_ON(signaling_thread_); | |
79 transport_proxies_.push_back(transport_proxy); | |
80 } | |
81 | |
82 void RtpTransportControllerAdapter::RemoveTransport( | |
83 RtpTransportAdapter* inner_transport) { | |
84 RTC_DCHECK_RUN_ON(signaling_thread_); | |
85 auto it = std::find_if(transport_proxies_.begin(), transport_proxies_.end(), | |
86 [inner_transport](RtpTransportInterface* proxy) { | |
87 return proxy->GetInternal() == inner_transport; | |
88 }); | |
89 if (it == transport_proxies_.end()) { | |
90 RTC_NOTREACHED(); | |
91 return; | |
92 } | |
93 transport_proxies_.erase(it); | |
94 } | |
95 | |
96 RTCError RtpTransportControllerAdapter::SetRtcpParameters( | |
97 const RtcpParameters& parameters, | |
98 RtpTransportInterface* inner_transport) { | |
99 if (inner_transport == inner_audio_transport_) { | |
100 CopyRtcpParametersToDescriptions(parameters, &local_audio_description_, | |
101 &remote_audio_description_); | |
102 if (!voice_channel_->SetLocalContent(&local_audio_description_, | |
103 cricket::CA_OFFER, nullptr)) { | |
104 LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, | |
105 "Failed to apply new RTCP parameters."); | |
106 } | |
107 if (!voice_channel_->SetRemoteContent(&remote_audio_description_, | |
108 cricket::CA_ANSWER, nullptr)) { | |
109 LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, | |
110 "Failed to apply new RTCP parameters."); | |
111 } | |
112 } else if (inner_transport == inner_video_transport_) { | |
113 CopyRtcpParametersToDescriptions(parameters, &local_video_description_, | |
114 &remote_video_description_); | |
115 if (!video_channel_->SetLocalContent(&local_video_description_, | |
116 cricket::CA_OFFER, nullptr)) { | |
117 LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, | |
118 "Failed to apply new RTCP parameters."); | |
119 } | |
120 if (!video_channel_->SetRemoteContent(&remote_video_description_, | |
121 cricket::CA_ANSWER, nullptr)) { | |
122 LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, | |
123 "Failed to apply new RTCP parameters."); | |
124 } | |
125 } | |
126 return RTCError::OK(); | |
127 } | |
128 | |
129 RTCError RtpTransportControllerAdapter::AttachAudioSender( | |
130 RtpTransportInterface* inner_transport) { | |
131 if (have_audio_sender_) { | |
132 LOG_AND_RETURN_ERROR(RTCErrorType::UNSUPPORTED_OPERATION, | |
133 "Using two audio RtpSenders with the same " | |
134 "RtpTransportControllerAdapter is not currently " | |
135 "supported."); | |
136 } | |
137 if (inner_audio_transport_ && inner_audio_transport_ != inner_transport) { | |
138 LOG_AND_RETURN_ERROR(RTCErrorType::UNSUPPORTED_PARAMETER, | |
139 "Using different transports for the audio " | |
140 "RtpSender and RtpReceiver is not currently " | |
141 "supported."); | |
142 } | |
143 // If setting new transport, extract its RTCP parameters and create voice | |
144 // channel. | |
145 if (!inner_audio_transport_) { | |
146 CopyRtcpParametersToDescriptions(inner_transport->GetRtcpParameters(), | |
147 &local_audio_description_, | |
148 &remote_audio_description_); | |
149 inner_audio_transport_ = inner_transport; | |
150 CreateVoiceChannel(); | |
151 } | |
152 have_audio_sender_ = true; | |
153 return RTCError::OK(); | |
154 } | |
155 | |
156 RTCError RtpTransportControllerAdapter::AttachVideoSender( | |
157 RtpTransportInterface* inner_transport) { | |
158 if (have_video_sender_) { | |
159 LOG_AND_RETURN_ERROR(RTCErrorType::UNSUPPORTED_OPERATION, | |
160 "Using two video RtpSenders with the same " | |
161 "RtpTransportControllerAdapter is not currently " | |
162 "supported."); | |
163 } | |
164 if (inner_video_transport_ && inner_video_transport_ != inner_transport) { | |
165 LOG_AND_RETURN_ERROR(RTCErrorType::UNSUPPORTED_PARAMETER, | |
166 "Using different transports for the video " | |
167 "RtpSender and RtpReceiver is not currently " | |
168 "supported."); | |
169 } | |
170 // If setting new transport, extract its RTCP parameters and create video | |
171 // channel. | |
172 if (!inner_video_transport_) { | |
173 CopyRtcpParametersToDescriptions(inner_transport->GetRtcpParameters(), | |
174 &local_video_description_, | |
175 &remote_video_description_); | |
176 inner_video_transport_ = inner_transport; | |
177 CreateVideoChannel(); | |
178 } | |
179 have_video_sender_ = true; | |
180 return RTCError::OK(); | |
181 } | |
182 | |
183 RTCError RtpTransportControllerAdapter::AttachAudioReceiver( | |
184 RtpTransportInterface* inner_transport) { | |
185 if (have_audio_receiver_) { | |
186 LOG_AND_RETURN_ERROR(RTCErrorType::UNSUPPORTED_OPERATION, | |
187 "Using two audio RtpReceivers with the same " | |
188 "RtpTransportControllerAdapter is not currently " | |
189 "supported."); | |
190 } | |
191 if (inner_audio_transport_ && inner_audio_transport_ != inner_transport) { | |
192 LOG_AND_RETURN_ERROR(RTCErrorType::UNSUPPORTED_PARAMETER, | |
193 "Using different transports for the audio " | |
194 "RtpReceiver and RtpReceiver is not currently " | |
195 "supported."); | |
196 } | |
197 // If setting new transport, extract its RTCP parameters and create voice | |
198 // channel. | |
199 if (!inner_audio_transport_) { | |
200 CopyRtcpParametersToDescriptions(inner_transport->GetRtcpParameters(), | |
201 &local_audio_description_, | |
202 &remote_audio_description_); | |
203 inner_audio_transport_ = inner_transport; | |
204 CreateVoiceChannel(); | |
205 } | |
206 have_audio_receiver_ = true; | |
207 return RTCError::OK(); | |
208 } | |
209 | |
210 RTCError RtpTransportControllerAdapter::AttachVideoReceiver( | |
211 RtpTransportInterface* inner_transport) { | |
212 if (have_video_receiver_) { | |
213 LOG_AND_RETURN_ERROR(RTCErrorType::UNSUPPORTED_OPERATION, | |
214 "Using two video RtpReceivers with the same " | |
215 "RtpTransportControllerAdapter is not currently " | |
216 "supported."); | |
217 } | |
218 if (inner_video_transport_ && inner_video_transport_ != inner_transport) { | |
219 LOG_AND_RETURN_ERROR(RTCErrorType::UNSUPPORTED_PARAMETER, | |
220 "Using different transports for the video " | |
221 "RtpReceiver and RtpReceiver is not currently " | |
222 "supported."); | |
223 } | |
224 // If setting new transport, extract its RTCP parameters and create video | |
225 // channel. | |
226 if (!inner_video_transport_) { | |
227 CopyRtcpParametersToDescriptions(inner_transport->GetRtcpParameters(), | |
228 &local_video_description_, | |
229 &remote_video_description_); | |
230 inner_video_transport_ = inner_transport; | |
231 CreateVideoChannel(); | |
232 } | |
233 have_video_receiver_ = true; | |
234 return RTCError::OK(); | |
235 } | |
236 | |
237 void RtpTransportControllerAdapter::DetachAudioSender() { | |
238 if (!have_audio_sender_) { | |
239 // Should be impossible unless RtpSenderAdapter is doing something wrong. | |
240 RTC_NOTREACHED(); | |
241 return; | |
242 } | |
243 // Empty parameters should result in sending being stopped. | |
244 RTCError err = | |
245 ValidateAndApplyAudioSenderParameters(RtpParameters(), nullptr); | |
246 RTC_DCHECK(err.ok()); | |
247 have_audio_sender_ = false; | |
248 if (!have_audio_receiver_) { | |
249 DestroyVoiceChannel(); | |
250 } | |
251 } | |
252 | |
253 void RtpTransportControllerAdapter::DetachVideoSender() { | |
254 if (!have_video_sender_) { | |
255 // Should be impossible unless RtpSenderAdapter is doing something wrong. | |
256 RTC_NOTREACHED(); | |
257 return; | |
258 } | |
259 // Empty parameters should result in sending being stopped. | |
260 RTCError err = | |
261 ValidateAndApplyVideoSenderParameters(RtpParameters(), nullptr); | |
262 RTC_DCHECK(err.ok()); | |
263 have_video_sender_ = false; | |
264 if (!have_video_receiver_) { | |
265 DestroyVideoChannel(); | |
266 } | |
267 } | |
268 | |
269 void RtpTransportControllerAdapter::DetachAudioReceiver() { | |
270 if (!have_audio_receiver_) { | |
271 // Should be impossible unless RtpReceiverAdapter is doing something wrong. | |
272 RTC_NOTREACHED(); | |
273 return; | |
274 } | |
275 // Empty parameters should result in receiving being stopped. | |
276 RTCError err = ValidateAndApplyAudioReceiverParameters(RtpParameters()); | |
277 RTC_DCHECK(err.ok()); | |
278 have_audio_receiver_ = false; | |
279 if (!have_audio_sender_) { | |
280 DestroyVoiceChannel(); | |
281 } | |
282 } | |
283 | |
284 void RtpTransportControllerAdapter::DetachVideoReceiver() { | |
285 if (!have_video_receiver_) { | |
286 // Should be impossible unless RtpReceiverAdapter is doing something wrong. | |
287 RTC_NOTREACHED(); | |
288 return; | |
289 } | |
290 // Empty parameters should result in receiving being stopped. | |
291 RTCError err = ValidateAndApplyVideoReceiverParameters(RtpParameters()); | |
292 RTC_DCHECK(err.ok()); | |
293 have_video_receiver_ = false; | |
294 if (!have_video_sender_) { | |
295 DestroyVideoChannel(); | |
296 } | |
297 } | |
298 | |
299 RTCError RtpTransportControllerAdapter::ValidateAndApplyAudioSenderParameters( | |
300 const RtpParameters& parameters, | |
301 uint32_t* primary_ssrc) { | |
302 RTC_DCHECK(voice_channel_); | |
303 RTC_DCHECK(have_audio_sender_); | |
304 | |
305 auto codecs_result = ToCricketCodecs<cricket::AudioCodec>(parameters.codecs); | |
306 if (!codecs_result.ok()) { | |
307 return codecs_result.MoveError(); | |
308 } | |
309 | |
310 auto extensions_result = ToRtpHeaderExtensions(parameters.header_extensions); | |
311 if (!extensions_result.ok()) { | |
312 return extensions_result.MoveError(); | |
313 } | |
314 | |
315 auto stream_params_result = MakeStreamParamsVec( | |
316 parameters.encodings, inner_audio_transport_->GetRtcpParameters().cname, | |
317 local_audio_description_); | |
318 if (!stream_params_result.ok()) { | |
319 return stream_params_result.MoveError(); | |
320 } | |
321 | |
322 cricket::RtpTransceiverDirection local_direction = | |
323 cricket::RtpTransceiverDirection::FromMediaContentDirection( | |
324 local_audio_description_.direction()); | |
325 int bandwidth = cricket::kAutoBandwidth; | |
326 if (parameters.encodings.size() == 1u) { | |
327 if (parameters.encodings[0].max_bitrate_bps) { | |
328 bandwidth = *parameters.encodings[0].max_bitrate_bps; | |
329 } | |
330 local_direction.send = parameters.encodings[0].active; | |
331 } else { | |
332 local_direction.send = false; | |
333 } | |
334 if (primary_ssrc && !stream_params_result.value().empty()) { | |
335 *primary_ssrc = stream_params_result.value()[0].first_ssrc(); | |
336 } | |
337 | |
338 // Validation is done, so we can attempt applying the descriptions. Sent | |
339 // codecs and header extensions go in remote description, streams go in | |
340 // local. | |
341 // | |
342 // If there are no codecs or encodings, just leave the previous set of | |
343 // codecs. The media engine doesn't like an empty set of codecs. | |
344 if (local_audio_description_.streams().empty() && | |
345 remote_audio_description_.codecs().empty()) { | |
346 } else { | |
347 remote_audio_description_.set_codecs(codecs_result.MoveValue()); | |
348 } | |
349 remote_audio_description_.set_rtp_header_extensions( | |
350 extensions_result.MoveValue()); | |
351 remote_audio_description_.set_bandwidth(bandwidth); | |
352 local_audio_description_.mutable_streams() = stream_params_result.MoveValue(); | |
353 // Direction set based on encoding "active" flag. | |
354 local_audio_description_.set_direction( | |
355 local_direction.ToMediaContentDirection()); | |
356 remote_audio_description_.set_direction( | |
357 local_direction.Reversed().ToMediaContentDirection()); | |
358 | |
359 // Set remote content first, to ensure the stream is created with the correct | |
360 // codec. | |
361 if (!voice_channel_->SetRemoteContent(&remote_audio_description_, | |
362 cricket::CA_OFFER, nullptr)) { | |
363 LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, | |
364 "Failed to apply remote parameters to media channel."); | |
365 } | |
366 if (!voice_channel_->SetLocalContent(&local_audio_description_, | |
367 cricket::CA_ANSWER, nullptr)) { | |
368 LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, | |
369 "Failed to apply local parameters to media channel."); | |
370 } | |
371 return RTCError::OK(); | |
372 } | |
373 | |
374 RTCError RtpTransportControllerAdapter::ValidateAndApplyVideoSenderParameters( | |
375 const RtpParameters& parameters, | |
376 uint32_t* primary_ssrc) { | |
377 RTC_DCHECK(video_channel_); | |
378 RTC_DCHECK(have_video_sender_); | |
379 | |
380 auto codecs_result = ToCricketCodecs<cricket::VideoCodec>(parameters.codecs); | |
381 if (!codecs_result.ok()) { | |
382 return codecs_result.MoveError(); | |
383 } | |
384 | |
385 auto extensions_result = ToRtpHeaderExtensions(parameters.header_extensions); | |
386 if (!extensions_result.ok()) { | |
387 return extensions_result.MoveError(); | |
388 } | |
389 | |
390 auto stream_params_result = MakeStreamParamsVec( | |
391 parameters.encodings, inner_video_transport_->GetRtcpParameters().cname, | |
392 local_video_description_); | |
393 if (!stream_params_result.ok()) { | |
394 return stream_params_result.MoveError(); | |
395 } | |
396 | |
397 cricket::RtpTransceiverDirection local_direction = | |
398 cricket::RtpTransceiverDirection::FromMediaContentDirection( | |
399 local_video_description_.direction()); | |
400 int bandwidth = cricket::kAutoBandwidth; | |
401 if (parameters.encodings.size() == 1u) { | |
402 if (parameters.encodings[0].max_bitrate_bps) { | |
403 bandwidth = *parameters.encodings[0].max_bitrate_bps; | |
404 } | |
405 local_direction.send = parameters.encodings[0].active; | |
406 } else { | |
407 local_direction.send = false; | |
408 } | |
409 if (primary_ssrc && !stream_params_result.value().empty()) { | |
410 *primary_ssrc = stream_params_result.value()[0].first_ssrc(); | |
411 } | |
412 | |
413 // Validation is done, so we can attempt applying the descriptions. Sent | |
414 // codecs and header extensions go in remote description, streams go in | |
415 // local. | |
416 // | |
417 // If there are no codecs or encodings, just leave the previous set of | |
418 // codecs. The media engine doesn't like an empty set of codecs. | |
419 if (local_video_description_.streams().empty() && | |
420 remote_video_description_.codecs().empty()) { | |
421 } else { | |
422 remote_video_description_.set_codecs(codecs_result.MoveValue()); | |
423 } | |
424 remote_video_description_.set_rtp_header_extensions( | |
425 extensions_result.MoveValue()); | |
426 remote_video_description_.set_bandwidth(bandwidth); | |
427 local_video_description_.mutable_streams() = stream_params_result.MoveValue(); | |
428 // Direction set based on encoding "active" flag. | |
429 local_video_description_.set_direction( | |
430 local_direction.ToMediaContentDirection()); | |
431 remote_video_description_.set_direction( | |
432 local_direction.Reversed().ToMediaContentDirection()); | |
433 | |
434 // Set remote content first, to ensure the stream is created with the correct | |
435 // codec. | |
436 if (!video_channel_->SetRemoteContent(&remote_video_description_, | |
437 cricket::CA_OFFER, nullptr)) { | |
438 LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, | |
439 "Failed to apply remote parameters to media channel."); | |
440 } | |
441 if (!video_channel_->SetLocalContent(&local_video_description_, | |
442 cricket::CA_ANSWER, nullptr)) { | |
443 LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, | |
444 "Failed to apply local parameters to media channel."); | |
445 } | |
446 return RTCError::OK(); | |
447 } | |
448 | |
449 RTCError RtpTransportControllerAdapter::ValidateAndApplyAudioReceiverParameters( | |
450 const RtpParameters& parameters) { | |
451 RTC_DCHECK(voice_channel_); | |
452 RTC_DCHECK(have_audio_receiver_); | |
453 | |
454 auto codecs_result = ToCricketCodecs<cricket::AudioCodec>(parameters.codecs); | |
455 if (!codecs_result.ok()) { | |
456 return codecs_result.MoveError(); | |
457 } | |
458 | |
459 auto extensions_result = ToRtpHeaderExtensions(parameters.header_extensions); | |
460 if (!extensions_result.ok()) { | |
461 return extensions_result.MoveError(); | |
462 } | |
463 | |
464 cricket::RtpTransceiverDirection local_direction = | |
465 cricket::RtpTransceiverDirection::FromMediaContentDirection( | |
466 local_audio_description_.direction()); | |
467 auto stream_params_result = ToStreamParamsVec(parameters.encodings); | |
468 if (!stream_params_result.ok()) { | |
469 return stream_params_result.MoveError(); | |
470 } | |
471 local_direction.recv = | |
472 !parameters.encodings.empty() && parameters.encodings[0].active; | |
473 | |
474 // Validation is done, so we can attempt applying the descriptions. Received | |
475 // codecs and header extensions go in local description, streams go in | |
476 // remote. | |
477 // | |
478 // If there are no codecs or encodings, just leave the previous set of | |
479 // codecs. The media engine doesn't like an empty set of codecs. | |
480 if (remote_audio_description_.streams().empty() && | |
481 local_audio_description_.codecs().empty()) { | |
482 } else { | |
483 local_audio_description_.set_codecs(codecs_result.MoveValue()); | |
484 } | |
485 local_audio_description_.set_rtp_header_extensions( | |
486 extensions_result.MoveValue()); | |
487 remote_audio_description_.mutable_streams() = | |
488 stream_params_result.MoveValue(); | |
489 // Direction set based on encoding "active" flag. | |
490 local_audio_description_.set_direction( | |
491 local_direction.ToMediaContentDirection()); | |
492 remote_audio_description_.set_direction( | |
493 local_direction.Reversed().ToMediaContentDirection()); | |
494 | |
495 if (!voice_channel_->SetLocalContent(&local_audio_description_, | |
496 cricket::CA_OFFER, nullptr)) { | |
497 LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, | |
498 "Failed to apply local parameters to media channel."); | |
499 } | |
500 if (!voice_channel_->SetRemoteContent(&remote_audio_description_, | |
501 cricket::CA_ANSWER, nullptr)) { | |
502 LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, | |
503 "Failed to apply remote parameters to media channel."); | |
504 } | |
505 return RTCError::OK(); | |
506 } | |
507 | |
508 RTCError RtpTransportControllerAdapter::ValidateAndApplyVideoReceiverParameters( | |
509 const RtpParameters& parameters) { | |
510 RTC_DCHECK(video_channel_); | |
511 RTC_DCHECK(have_video_receiver_); | |
512 | |
513 auto codecs_result = ToCricketCodecs<cricket::VideoCodec>(parameters.codecs); | |
514 if (!codecs_result.ok()) { | |
515 return codecs_result.MoveError(); | |
516 } | |
517 | |
518 auto extensions_result = ToRtpHeaderExtensions(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 = ToStreamParamsVec(parameters.encodings); | |
528 if (!stream_params_result.ok()) { | |
529 return stream_params_result.MoveError(); | |
530 } | |
531 local_direction.recv = | |
532 !parameters.encodings.empty() && parameters.encodings[0].active; | |
533 | |
534 // Validation is done, so we can attempt applying the descriptions. Received | |
535 // codecs and header extensions go in local description, streams go in | |
536 // remote. | |
537 // | |
538 // If there are no codecs or encodings, just leave the previous set of | |
539 // codecs. The media engine doesn't like an empty set of codecs. | |
540 if (remote_video_description_.streams().empty() && | |
541 local_video_description_.codecs().empty()) { | |
542 } else { | |
543 local_video_description_.set_codecs(codecs_result.MoveValue()); | |
544 } | |
545 local_video_description_.set_rtp_header_extensions( | |
546 extensions_result.MoveValue()); | |
547 local_video_description_.set_bandwidth(bandwidth); | |
548 remote_video_description_.mutable_streams() = | |
549 stream_params_result.MoveValue(); | |
550 // Direction set based on encoding "active" flag. | |
551 local_video_description_.set_direction( | |
552 local_direction.ToMediaContentDirection()); | |
553 remote_video_description_.set_direction( | |
554 local_direction.Reversed().ToMediaContentDirection()); | |
555 | |
556 if (!video_channel_->SetLocalContent(&local_video_description_, | |
557 cricket::CA_OFFER, nullptr)) { | |
558 LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, | |
559 "Failed to apply local parameters to media channel."); | |
560 } | |
561 if (!video_channel_->SetRemoteContent(&remote_video_description_, | |
562 cricket::CA_ANSWER, nullptr)) { | |
563 LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, | |
564 "Failed to apply remote parameters to media channel."); | |
565 } | |
566 return RTCError::OK(); | |
567 } | |
568 | |
569 RtpTransportControllerAdapter::RtpTransportControllerAdapter( | |
570 const cricket::MediaConfig& config, | |
571 cricket::ChannelManager* channel_manager, | |
572 webrtc::RtcEventLog* event_log, | |
573 rtc::Thread* signaling_thread, | |
574 rtc::Thread* worker_thread) | |
575 : signaling_thread_(signaling_thread), | |
576 worker_thread_(worker_thread), | |
577 media_controller_(MediaControllerInterface::Create(config, | |
578 worker_thread, | |
579 channel_manager, | |
580 event_log)) { | |
581 RTC_DCHECK_RUN_ON(signaling_thread_); | |
582 RTC_DCHECK(channel_manager); | |
583 // MediaControllerInterface::Create should never fail. | |
584 RTC_DCHECK(media_controller_); | |
585 static const cricket::AudioCodec dummy_audio(0, cricket::kPcmuCodecName, 8000, | |
586 0, 1); | |
587 static const cricket::VideoCodec dummy_video(96, cricket::kVp8CodecName); | |
588 local_audio_description_.AddCodec(dummy_audio); | |
589 remote_audio_description_.AddCodec(dummy_audio); | |
590 local_video_description_.AddCodec(dummy_video); | |
591 remote_video_description_.AddCodec(dummy_video); | |
592 } | |
593 | |
594 void RtpTransportControllerAdapter::CreateVoiceChannel() { | |
595 voice_channel_ = media_controller_->channel_manager()->CreateVoiceChannel( | |
596 media_controller_.get(), | |
597 inner_audio_transport_->GetRtpPacketTransport()->GetInternal(), | |
598 inner_audio_transport_->GetRtcpPacketTransport() | |
599 ? inner_audio_transport_->GetRtcpPacketTransport()->GetInternal() | |
600 : nullptr, | |
601 signaling_thread_, "audio", false, cricket::AudioOptions()); | |
602 RTC_DCHECK(voice_channel_); | |
603 voice_channel_->Enable(true); | |
604 } | |
605 | |
606 void RtpTransportControllerAdapter::CreateVideoChannel() { | |
607 video_channel_ = media_controller_->channel_manager()->CreateVideoChannel( | |
608 media_controller_.get(), | |
609 inner_video_transport_->GetRtpPacketTransport()->GetInternal(), | |
610 inner_video_transport_->GetRtcpPacketTransport() | |
611 ? inner_video_transport_->GetRtcpPacketTransport()->GetInternal() | |
612 : nullptr, | |
613 signaling_thread_, "audio", false, cricket::VideoOptions()); | |
614 RTC_DCHECK(video_channel_); | |
615 video_channel_->Enable(true); | |
616 } | |
617 | |
618 void RtpTransportControllerAdapter::DestroyVoiceChannel() { | |
619 RTC_DCHECK(voice_channel_); | |
620 media_controller_->channel_manager()->DestroyVoiceChannel(voice_channel_); | |
621 voice_channel_ = nullptr; | |
622 } | |
623 | |
624 void RtpTransportControllerAdapter::DestroyVideoChannel() { | |
625 RTC_DCHECK(video_channel_); | |
626 media_controller_->channel_manager()->DestroyVideoChannel(video_channel_); | |
627 video_channel_ = nullptr; | |
628 } | |
629 | |
630 void RtpTransportControllerAdapter::CopyRtcpParametersToDescriptions( | |
631 const RtcpParameters& params, | |
632 cricket::MediaContentDescription* local, | |
633 cricket::MediaContentDescription* remote) { | |
634 local->set_rtcp_mux(params.mux); | |
635 remote->set_rtcp_mux(params.mux); | |
636 local->set_rtcp_reduced_size(params.reduced_size); | |
637 remote->set_rtcp_reduced_size(params.reduced_size); | |
638 for (cricket::StreamParams& stream_params : local->mutable_streams()) { | |
639 stream_params.cname = params.cname; | |
640 } | |
641 } | |
642 | |
643 uint32_t RtpTransportControllerAdapter::GenerateUnusedSsrc( | |
644 std::set<uint32_t>* new_ssrcs) const { | |
645 uint32_t ssrc; | |
646 do { | |
647 ssrc = rtc::CreateRandomNonZeroId(); | |
648 } while ( | |
649 cricket::GetStreamBySsrc(local_audio_description_.streams(), ssrc) || | |
650 cricket::GetStreamBySsrc(remote_audio_description_.streams(), ssrc) || | |
651 cricket::GetStreamBySsrc(local_video_description_.streams(), ssrc) || | |
652 cricket::GetStreamBySsrc(remote_video_description_.streams(), ssrc) || | |
653 !new_ssrcs->insert(ssrc).second); | |
654 return ssrc; | |
655 } | |
656 | |
657 RTCErrorOr<cricket::StreamParamsVec> | |
658 RtpTransportControllerAdapter::MakeStreamParamsVec( | |
659 std::vector<RtpEncodingParameters> encodings, | |
660 const std::string& cname, | |
661 const cricket::MediaContentDescription& description) const { | |
662 if (encodings.size() > 1u) { | |
663 LOG_AND_RETURN_ERROR(webrtc::RTCErrorType::UNSUPPORTED_PARAMETER, | |
664 "ORTC API implementation doesn't currently " | |
665 "support simulcast or layered encodings."); | |
666 } else if (encodings.empty()) { | |
667 return cricket::StreamParamsVec(); | |
668 } | |
669 RtpEncodingParameters& encoding = encodings[0]; | |
670 std::set<uint32_t> new_ssrcs; | |
671 if (encoding.ssrc) { | |
672 new_ssrcs.insert(*encoding.ssrc); | |
673 } | |
674 if (encoding.rtx && encoding.rtx->ssrc) { | |
675 new_ssrcs.insert(*encoding.rtx->ssrc); | |
676 } | |
677 // May need to fill missing SSRCs with generated ones. | |
678 if (!encoding.ssrc) { | |
679 if (!description.streams().empty()) { | |
680 encoding.ssrc.emplace(description.streams()[0].first_ssrc()); | |
681 } else { | |
682 encoding.ssrc.emplace(GenerateUnusedSsrc(&new_ssrcs)); | |
683 } | |
684 } | |
685 if (encoding.rtx && !encoding.rtx->ssrc) { | |
686 uint32_t existing_rtx_ssrc; | |
687 if (!description.streams().empty() && | |
688 description.streams()[0].GetFidSsrc( | |
689 description.streams()[0].first_ssrc(), &existing_rtx_ssrc)) { | |
690 encoding.rtx->ssrc.emplace(existing_rtx_ssrc); | |
691 } else { | |
692 encoding.rtx->ssrc.emplace(GenerateUnusedSsrc(&new_ssrcs)); | |
693 } | |
694 } | |
695 | |
696 auto result = ToStreamParamsVec(encodings); | |
697 if (!result.ok()) { | |
698 return result.MoveError(); | |
699 } | |
700 // If conversion was successful, there should be one StreamParams. | |
701 RTC_DCHECK_EQ(1u, result.value().size()); | |
702 result.value()[0].cname = cname; | |
703 return result; | |
704 } | |
705 | |
706 } // namespace webrtc | |
OLD | NEW |