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