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/rtptransportcontrollershim.h" | |
12 | |
13 #include <algorithm> // For "remove", "find". | |
14 #include <set> | |
15 #include <utility> // For std::move. | |
16 | |
17 #include "webrtc/api/proxy.h" | |
18 #include "webrtc/base/checks.h" | |
19 #include "webrtc/media/base/mediaconstants.h" | |
20 #include "webrtc/ortc/rtptransportshim.h" | |
21 | |
22 namespace { | |
23 | |
24 static const int kVideoClockrate = 90000; | |
pthatcher1
2017/02/10 22:36:53
It's already in mediaconstants.h :).
Taylor Brandstetter
2017/02/14 06:55:05
I was slightly confused because it was already def
| |
25 | |
26 // Returns false on invalid input. Certain message types are only valid for | |
27 // certain feedback types. | |
28 webrtc::RTCError ValidateAndConvertRtcpFeedback( | |
29 const webrtc::RtcpFeedback& feedback, | |
30 cricket::Codec* codec) { | |
pthatcher1
2017/02/10 22:36:53
Seem like it should be called AddCricketCodecFeedb
Taylor Brandstetter
2017/02/14 06:55:05
That doesn't communicate that these parameters are
| |
31 switch (feedback.type) { | |
32 case webrtc::RtcpFeedbackType::ACK: | |
33 if (feedback.message_type) { | |
34 return CreateAndLogError( | |
35 webrtc::RTCErrorType::INVALID_PARAMETER, | |
36 "Didn't expect message type in ACK RtcpFeedback."); | |
37 } | |
38 codec->AddFeedbackParam(cricket::FeedbackParam("ack")); | |
39 return webrtc::RTCError(); | |
40 case webrtc::RtcpFeedbackType::CCM: | |
41 if (!feedback.message_type) { | |
42 return CreateAndLogError(webrtc::RTCErrorType::INVALID_PARAMETER, | |
43 "Missing message type in CCM RtcpFeedback."); | |
44 } else if (*feedback.message_type != | |
45 webrtc::RtcpFeedbackMessageType::FIR) { | |
46 return CreateAndLogError(webrtc::RTCErrorType::INVALID_PARAMETER, | |
47 "Invalid message type in CCM RtcpFeedback."); | |
48 } | |
49 codec->AddFeedbackParam(cricket::FeedbackParam("ccm", "fir")); | |
pthatcher1
2017/02/10 22:36:53
You can use the strings in mediaconstants.h.
Taylor Brandstetter
2017/02/14 06:55:05
Done.
| |
50 return webrtc::RTCError(); | |
51 case webrtc::RtcpFeedbackType::NACK: | |
52 if (!feedback.message_type) { | |
53 return CreateAndLogError(webrtc::RTCErrorType::INVALID_PARAMETER, | |
54 "Missing message type in NACK RtcpFeedback."); | |
55 } | |
56 switch (*feedback.message_type) { | |
57 case webrtc::RtcpFeedbackMessageType::GENERIC_NACK: | |
58 codec->AddFeedbackParam(cricket::FeedbackParam("nack")); | |
59 return webrtc::RTCError(); | |
60 case webrtc::RtcpFeedbackMessageType::PLI: | |
61 codec->AddFeedbackParam(cricket::FeedbackParam("nack", "pli")); | |
62 return webrtc::RTCError(); | |
63 default: | |
64 return CreateAndLogError( | |
65 webrtc::RTCErrorType::INVALID_PARAMETER, | |
66 "Invalid message type in NACK RtcpFeedback."); | |
67 } | |
68 case webrtc::RtcpFeedbackType::REMB: | |
69 if (feedback.message_type) { | |
70 return CreateAndLogError( | |
71 webrtc::RTCErrorType::INVALID_PARAMETER, | |
72 "Didn't expect message type in REMB RtcpFeedback."); | |
73 } | |
74 codec->AddFeedbackParam(cricket::FeedbackParam("goog-remb")); | |
75 return webrtc::RTCError(); | |
76 case webrtc::RtcpFeedbackType::TRANSPORT_CC: | |
77 if (feedback.message_type) { | |
78 return CreateAndLogError( | |
79 webrtc::RTCErrorType::INVALID_PARAMETER, | |
80 "Didn't expect message type in transport-cc RtcpFeedback."); | |
81 } | |
82 codec->AddFeedbackParam(cricket::FeedbackParam("transport-cc")); | |
83 return webrtc::RTCError(); | |
84 } | |
85 } | |
86 | |
87 template <typename C> | |
88 webrtc::RTCError CodecSpecificConversion( | |
89 const webrtc::RtpCodecParameters& codec, | |
90 C* cricket_codec) {} | |
91 | |
92 template <> | |
93 webrtc::RTCError CodecSpecificConversion<cricket::AudioCodec>( | |
94 const webrtc::RtpCodecParameters& codec, | |
95 cricket::AudioCodec* cricket_codec) { | |
pthatcher1
2017/02/10 22:36:53
Seems like this could be called ToCricketAudioCode
| |
96 if (codec.kind != cricket::MEDIA_TYPE_AUDIO) { | |
97 return CreateAndLogError( | |
98 webrtc::RTCErrorType::INVALID_PARAMETER, | |
99 "Can't use video codec with audio sender or receiver."); | |
100 } | |
101 if (!codec.num_channels) { | |
102 // A default value for number of channels should have been filled already. | |
103 RTC_NOTREACHED(); | |
104 return CreateAndLogError(webrtc::RTCErrorType::INVALID_PARAMETER, | |
105 "Missing number of channels for audio codec."); | |
106 } | |
107 if (*codec.num_channels <= 0) { | |
108 return CreateAndLogError(webrtc::RTCErrorType::INVALID_RANGE, | |
109 "Number of channels must be positive."); | |
110 } | |
111 cricket_codec->channels = *codec.num_channels; | |
112 if (!codec.clock_rate) { | |
113 return CreateAndLogError(webrtc::RTCErrorType::INVALID_PARAMETER, | |
114 "Missing codec clock rate."); | |
115 } | |
116 if (*codec.clock_rate <= 0) { | |
117 return CreateAndLogError(webrtc::RTCErrorType::INVALID_RANGE, | |
118 "Clock rate must be positive."); | |
119 } | |
120 cricket_codec->clockrate = *codec.clock_rate; | |
121 return webrtc::RTCError(); | |
122 } | |
123 | |
124 // Video codec doesn't use num_channels or clock_rate, but they should at least | |
125 // be validated. | |
126 template <> | |
127 webrtc::RTCError CodecSpecificConversion<cricket::VideoCodec>( | |
128 const webrtc::RtpCodecParameters& codec, | |
pthatcher1
2017/02/10 22:36:53
And this could be called ToCricketVideoCodec.
| |
129 cricket::VideoCodec*) { | |
130 if (codec.kind != cricket::MEDIA_TYPE_VIDEO) { | |
131 return CreateAndLogError( | |
132 webrtc::RTCErrorType::INVALID_PARAMETER, | |
133 "Can't use video codec with video sender or receiver."); | |
134 } | |
135 if (codec.num_channels) { | |
136 return CreateAndLogError(webrtc::RTCErrorType::INVALID_PARAMETER, | |
137 "Video codec shouldn't have num_channels."); | |
138 } | |
139 if (!codec.clock_rate) { | |
140 // A default value should have been filled already. | |
141 RTC_NOTREACHED(); | |
142 return CreateAndLogError(webrtc::RTCErrorType::INVALID_PARAMETER, | |
143 "Missing codec clock rate."); | |
144 } | |
145 if (*codec.clock_rate != kVideoClockrate) { | |
146 return CreateAndLogError(webrtc::RTCErrorType::INVALID_PARAMETER, | |
147 "Video clock rate must be 90000."); | |
148 } | |
149 return webrtc::RTCError(); | |
150 } | |
151 | |
152 template <typename C> | |
153 webrtc::RTCError ValidateAndConvertCodecs( | |
154 const std::vector<webrtc::RtpCodecParameters>& codecs, | |
155 std::vector<C>* cricket_codecs) { | |
pthatcher1
2017/02/10 22:36:53
Similarly, this could be called ToCricketCodecs.
| |
156 std::ostringstream err_writer; | |
157 std::set<int> seen_payload_types; | |
158 for (const webrtc::RtpCodecParameters& codec : codecs) { | |
159 C cricket_codec; | |
160 // Start with audio/video specific conversion. | |
161 webrtc::RTCError err = CodecSpecificConversion(codec, &cricket_codec); | |
162 if (!err.ok()) { | |
163 return err; | |
164 } | |
165 cricket_codec.name = codec.name; | |
166 if (codec.payload_type < 0 || codec.payload_type > 127) { | |
pthatcher1
2017/02/10 22:36:53
127 could use a name constant somewhere. Perhaps
Taylor Brandstetter
2017/02/14 06:55:05
Done.
| |
167 err_writer << "Invalid payload type: " << codec.payload_type; | |
168 return CreateAndLogError(webrtc::RTCErrorType::INVALID_RANGE, | |
169 err_writer.str()); | |
170 } | |
171 if (!seen_payload_types.insert(codec.payload_type).second) { | |
172 err_writer << "Duplicate payload type: " << codec.payload_type; | |
173 return CreateAndLogError(webrtc::RTCErrorType::INVALID_PARAMETER, | |
174 err_writer.str()); | |
175 } | |
176 cricket_codec.id = codec.payload_type; | |
177 for (const webrtc::RtcpFeedback& feedback : codec.rtcp_feedback) { | |
178 webrtc::RTCError err = | |
179 ValidateAndConvertRtcpFeedback(feedback, &cricket_codec); | |
180 if (!err.ok()) { | |
181 return err; | |
182 } | |
183 } | |
184 cricket_codec.params.insert(codec.parameters.begin(), | |
185 codec.parameters.end()); | |
186 cricket_codecs->push_back(std::move(cricket_codec)); | |
187 } | |
188 return webrtc::RTCError(); | |
189 } | |
190 | |
191 webrtc::RTCError ValidateAndConvertHeaderExtensions( | |
192 const std::vector<webrtc::RtpHeaderExtensionParameters>& extensions, | |
193 cricket::RtpHeaderExtensions* cricket_extensions) { | |
pthatcher1
2017/02/10 22:36:53
Similarly, this could be called ToCricketRtpHeader
| |
194 std::ostringstream err_writer; | |
195 std::set<int> seen_header_extension_ids; | |
196 for (const webrtc::RtpHeaderExtensionParameters& extension : extensions) { | |
197 if (extension.id < 1 || extension.id > 14) { | |
198 err_writer << "Invalid header extension id: " << extension.id; | |
199 return CreateAndLogError(webrtc::RTCErrorType::INVALID_RANGE, | |
200 err_writer.str()); | |
201 } | |
202 if (!seen_header_extension_ids.insert(extension.id).second) { | |
203 err_writer << "Duplicate header extension id: " << extension.id; | |
204 return CreateAndLogError(webrtc::RTCErrorType::INVALID_PARAMETER, | |
205 err_writer.str()); | |
206 } | |
207 cricket_extensions->emplace_back(extension.uri, extension.id); | |
208 } | |
209 return webrtc::RTCError(); | |
210 } | |
211 | |
212 // Missing SSRC is treated differently for receiver encodings; this means | |
213 // SSRCs are unsignaled. | |
214 webrtc::RTCError ValidateAndConvertReceiverEncodings( | |
215 const std::vector<webrtc::RtpEncodingParameters> encodings, | |
216 cricket::StreamParamsVec* cricket_streams, | |
217 bool* receiving) { | |
218 if (encodings.size() > 1u) { | |
219 return CreateAndLogError(webrtc::RTCErrorType::UNSUPPORTED_PARAMETER, | |
220 "ORTC API implementation doesn't currently " | |
221 "support simulcast or layered encodings."); | |
222 } | |
223 if (encodings.size() == 1u) { | |
pthatcher1
2017/02/10 22:36:53
Doing the encodings.size() == 0 first and return a
Taylor Brandstetter
2017/02/14 06:55:05
Done.
| |
224 const webrtc::RtpEncodingParameters& encoding = encodings[0]; | |
225 *receiving = encoding.active; | |
226 if (encoding.ssrc) { | |
227 cricket::StreamParams stream_params; | |
228 stream_params.add_ssrc(*encoding.ssrc); | |
229 if (encoding.rtx && encoding.rtx->ssrc) { | |
230 stream_params.AddFidSsrc(*encoding.ssrc, *encoding.rtx->ssrc); | |
231 } | |
232 cricket_streams->push_back(std::move(stream_params)); | |
233 } | |
pthatcher1
2017/02/10 22:36:53
Similarly for !encoding.ssrc: return RTCError earl
Taylor Brandstetter
2017/02/14 06:55:05
Done
| |
234 } else { | |
235 *receiving = false; | |
236 } | |
237 return webrtc::RTCError(); | |
238 } | |
239 | |
240 // Codecs that will never be used, but will at least not be rejected by | |
241 // BaseChannel/MediaChannel classes. | |
242 void AddDefaultAudioCodec(cricket::AudioContentDescription* description) { | |
pthatcher1
2017/02/10 22:36:53
Should this be AddDummyAudioCodec and AddDummyVide
Taylor Brandstetter
2017/02/14 06:55:05
Done.
| |
243 description->AddCodec( | |
244 cricket::AudioCodec(0, cricket::kPcmuCodecName, 8000, 0, 1)); | |
245 } | |
246 | |
247 void AddDefaultVideoCodec(cricket::VideoContentDescription* description) { | |
248 description->AddCodec(cricket::VideoCodec(96, cricket::kVp8CodecName)); | |
249 } | |
250 | |
251 } // namespace | |
252 | |
253 namespace webrtc { | |
254 | |
255 BEGIN_OWNED_PROXY_MAP(RtpTransportController) | |
256 PROXY_SIGNALING_THREAD_DESTRUCTOR() | |
257 PROXY_CONSTMETHOD0(std::vector<RtpTransportInterface*>, GetTransports) | |
258 protected: | |
259 RtpTransportControllerShim* GetInternal() override { | |
260 return internal(); | |
261 } | |
262 END_PROXY_MAP() | |
263 | |
264 // static | |
265 std::unique_ptr<RtpTransportControllerInterface> | |
266 RtpTransportControllerShim::CreateProxied( | |
267 const cricket::MediaConfig& config, | |
268 cricket::ChannelManager* channel_manager, | |
269 webrtc::RtcEventLog* event_log, | |
270 rtc::Thread* signaling_thread, | |
271 rtc::Thread* worker_thread) { | |
272 return RtpTransportControllerProxyWithInternal< | |
273 RtpTransportControllerShim>::Create(signaling_thread, worker_thread, | |
274 new RtpTransportControllerShim( | |
275 config, channel_manager, | |
276 event_log, signaling_thread, | |
277 worker_thread)); | |
278 } | |
279 | |
280 RtpTransportControllerShim::~RtpTransportControllerShim() { | |
281 RTC_DCHECK_RUN_ON(signaling_thread_); | |
282 if (!transport_proxies_.empty()) { | |
283 LOG(LS_ERROR) | |
284 << "Destroying RtpTransportControllerShim while RtpTransports " | |
285 "are still using it; this is unsafe."; | |
286 } | |
287 if (voice_channel_) { | |
288 // This would mean audio RTP senders/receivers are still using us. | |
pthatcher1
2017/02/10 22:36:53
It could be more clear that you mean that the RtpS
Taylor Brandstetter
2017/02/14 06:55:05
Probably a crash. This is what we get if things ar
| |
289 DestroyVoiceChannel(); | |
290 } | |
291 if (voice_channel_) { | |
292 // This would mean video RTP senders/receivers are still using us. | |
293 DestroyVideoChannel(); | |
294 } | |
295 } | |
296 | |
297 std::vector<RtpTransportInterface*> RtpTransportControllerShim::GetTransports() | |
298 const { | |
299 RTC_DCHECK_RUN_ON(signaling_thread_); | |
300 return transport_proxies_; | |
301 } | |
302 | |
303 void RtpTransportControllerShim::AddTransport( | |
304 RtpTransportInterface* transport_proxy) { | |
305 RTC_DCHECK_RUN_ON(signaling_thread_); | |
306 transport_proxies_.push_back(transport_proxy); | |
307 } | |
308 | |
309 void RtpTransportControllerShim::RemoveTransport( | |
310 RtpTransportInterface* inner_transport) { | |
311 RTC_DCHECK_RUN_ON(signaling_thread_); | |
312 auto it = std::find_if(transport_proxies_.begin(), transport_proxies_.end(), | |
313 [inner_transport](RtpTransportInterface* proxy) { | |
314 return proxy->GetInternal() == inner_transport; | |
315 }); | |
316 if (it == transport_proxies_.end()) { | |
317 RTC_NOTREACHED(); | |
318 return; | |
319 } | |
320 transport_proxies_.erase(it); | |
pthatcher1
2017/02/10 22:36:53
It seems like it would be easier to have Add and R
Taylor Brandstetter
2017/02/14 06:55:05
Because AddTransport needs to take a proxy, becaus
| |
321 } | |
322 | |
323 RTCError RtpTransportControllerShim::SetRtcpParameters( | |
324 const RtcpParameters& parameters, | |
325 RtpTransportInterface* inner_transport) { | |
326 if (inner_transport == inner_audio_transport_) { | |
327 CopyRtcpParametersToDescriptions(parameters, &local_audio_description_, | |
328 &remote_audio_description_); | |
329 if (!voice_channel_->SetLocalContent(&local_audio_description_, | |
330 cricket::CA_OFFER, nullptr)) { | |
331 return CreateAndLogError(RTCErrorType::INTERNAL_ERROR, | |
332 "Failed to apply new RTCP parameters."); | |
333 } | |
334 if (!voice_channel_->SetRemoteContent(&remote_audio_description_, | |
335 cricket::CA_ANSWER, nullptr)) { | |
336 return CreateAndLogError(RTCErrorType::INTERNAL_ERROR, | |
337 "Failed to apply new RTCP parameters."); | |
338 } | |
339 } else if (inner_transport == inner_video_transport_) { | |
340 CopyRtcpParametersToDescriptions(parameters, &local_video_description_, | |
341 &remote_video_description_); | |
342 if (!video_channel_->SetLocalContent(&local_video_description_, | |
343 cricket::CA_OFFER, nullptr)) { | |
344 return CreateAndLogError(RTCErrorType::INTERNAL_ERROR, | |
345 "Failed to apply new RTCP parameters."); | |
346 } | |
347 if (!video_channel_->SetRemoteContent(&remote_video_description_, | |
348 cricket::CA_ANSWER, nullptr)) { | |
349 return CreateAndLogError(RTCErrorType::INTERNAL_ERROR, | |
350 "Failed to apply new RTCP parameters."); | |
351 } | |
352 } | |
353 return RTCError(); | |
354 } | |
355 | |
356 RTCError RtpTransportControllerShim::AttachAudioSender( | |
357 RtpTransportInterface* inner_transport) { | |
358 if (have_audio_sender_) { | |
359 return CreateAndLogError(RTCErrorType::UNSUPPORTED_OPERATION, | |
360 "Using two RtpSenders with the same " | |
361 "RtpTransportControllerShim is not currently " | |
362 "supported."); | |
363 } | |
364 if (inner_audio_transport_ && inner_audio_transport_ != inner_transport) { | |
365 return CreateAndLogError(RTCErrorType::UNSUPPORTED_PARAMETER, | |
366 "Using different transports for the audio " | |
367 "RtpSender and RtpReceiver is not currently " | |
368 "supported."); | |
369 } | |
370 // If setting new transport, extract its RTCP parameters and create voice | |
371 // channel. | |
372 if (!inner_audio_transport_) { | |
373 CopyRtcpParametersToDescriptions(inner_transport->GetRtcpParameters(), | |
374 &local_audio_description_, | |
375 &remote_audio_description_); | |
376 inner_audio_transport_ = inner_transport; | |
377 CreateVoiceChannel(); | |
378 } | |
379 have_audio_sender_ = true; | |
380 return RTCError(); | |
381 } | |
382 | |
383 RTCError RtpTransportControllerShim::AttachVideoSender( | |
384 RtpTransportInterface* inner_transport) { | |
385 if (have_video_sender_) { | |
386 return CreateAndLogError(RTCErrorType::UNSUPPORTED_OPERATION, | |
387 "Using two RtpSenders with the same " | |
388 "RtpTransportControllerShim is not currently " | |
389 "supported."); | |
390 } | |
391 if (inner_video_transport_ && inner_video_transport_ != inner_transport) { | |
392 return CreateAndLogError(RTCErrorType::UNSUPPORTED_PARAMETER, | |
393 "Using different transports for the video " | |
394 "RtpSender and RtpReceiver is not currently " | |
395 "supported."); | |
396 } | |
397 // If setting new transport, extract its RTCP parameters and create video | |
398 // channel. | |
399 if (!inner_video_transport_) { | |
400 CopyRtcpParametersToDescriptions(inner_transport->GetRtcpParameters(), | |
401 &local_video_description_, | |
402 &remote_video_description_); | |
403 inner_video_transport_ = inner_transport; | |
404 CreateVideoChannel(); | |
405 } | |
406 have_video_sender_ = true; | |
407 return RTCError(); | |
408 } | |
409 | |
410 RTCError RtpTransportControllerShim::AttachAudioReceiver( | |
411 RtpTransportInterface* inner_transport) { | |
412 if (have_audio_receiver_) { | |
413 return CreateAndLogError(RTCErrorType::UNSUPPORTED_OPERATION, | |
414 "Using two RtpReceivers with the same " | |
415 "RtpTransportControllerShim is not currently " | |
416 "supported."); | |
417 } | |
418 if (inner_audio_transport_ && inner_audio_transport_ != inner_transport) { | |
419 return CreateAndLogError(RTCErrorType::UNSUPPORTED_PARAMETER, | |
420 "Using different transports for the audio " | |
421 "RtpReceiver and RtpReceiver is not currently " | |
422 "supported."); | |
423 } | |
424 // If setting new transport, extract its RTCP parameters and create voice | |
425 // channel. | |
426 if (!inner_audio_transport_) { | |
427 CopyRtcpParametersToDescriptions(inner_transport->GetRtcpParameters(), | |
428 &local_audio_description_, | |
429 &remote_audio_description_); | |
430 inner_audio_transport_ = inner_transport; | |
431 CreateVoiceChannel(); | |
432 } | |
433 have_audio_receiver_ = true; | |
434 return RTCError(); | |
435 } | |
436 | |
437 RTCError RtpTransportControllerShim::AttachVideoReceiver( | |
438 RtpTransportInterface* inner_transport) { | |
439 if (have_video_receiver_) { | |
440 return CreateAndLogError(RTCErrorType::UNSUPPORTED_OPERATION, | |
441 "Using two RtpReceivers with the same " | |
442 "RtpTransportControllerShim is not currently " | |
443 "supported."); | |
444 } | |
445 if (inner_video_transport_ && inner_video_transport_ != inner_transport) { | |
446 return CreateAndLogError(RTCErrorType::UNSUPPORTED_PARAMETER, | |
447 "Using different transports for the video " | |
448 "RtpReceiver and RtpReceiver is not currently " | |
449 "supported."); | |
450 } | |
451 // If setting new transport, extract its RTCP parameters and create video | |
452 // channel. | |
453 if (!inner_video_transport_) { | |
454 CopyRtcpParametersToDescriptions(inner_transport->GetRtcpParameters(), | |
455 &local_video_description_, | |
456 &remote_video_description_); | |
457 inner_video_transport_ = inner_transport; | |
458 CreateVideoChannel(); | |
459 } | |
460 have_video_receiver_ = true; | |
461 return RTCError(); | |
462 } | |
463 | |
464 void RtpTransportControllerShim::DetachAudioSender() { | |
465 if (!have_audio_sender_) { | |
466 // Should be impossible unless RtpSenderShim is doing something wrong. | |
467 RTC_NOTREACHED(); | |
468 return; | |
469 } | |
470 // Empty parameters should result in sending being stopped. | |
471 RTCError err = | |
472 ValidateAndApplyAudioSenderParameters(RtpParameters(), nullptr); | |
473 RTC_DCHECK(err.ok()); | |
474 have_audio_sender_ = false; | |
475 if (!have_audio_receiver_) { | |
476 DestroyVoiceChannel(); | |
477 } | |
478 } | |
479 | |
480 void RtpTransportControllerShim::DetachVideoSender() { | |
481 if (!have_video_sender_) { | |
482 // Should be impossible unless RtpSenderShim is doing something wrong. | |
483 RTC_NOTREACHED(); | |
484 return; | |
485 } | |
486 // Empty parameters should result in sending being stopped. | |
487 RTCError err = | |
488 ValidateAndApplyVideoSenderParameters(RtpParameters(), nullptr); | |
489 RTC_DCHECK(err.ok()); | |
490 have_video_sender_ = false; | |
491 if (!have_video_receiver_) { | |
492 DestroyVideoChannel(); | |
493 } | |
494 } | |
495 | |
496 void RtpTransportControllerShim::DetachAudioReceiver() { | |
497 if (!have_audio_receiver_) { | |
498 // Should be impossible unless RtpReceiverShim is doing something wrong. | |
499 RTC_NOTREACHED(); | |
500 return; | |
501 } | |
502 // Empty parameters should result in receiving being stopped. | |
503 RTCError err = ValidateAndApplyAudioReceiverParameters(RtpParameters()); | |
504 RTC_DCHECK(err.ok()); | |
505 have_audio_receiver_ = false; | |
506 if (!have_audio_sender_) { | |
507 DestroyVoiceChannel(); | |
508 } | |
509 } | |
510 | |
511 void RtpTransportControllerShim::DetachVideoReceiver() { | |
512 if (!have_video_receiver_) { | |
513 // Should be impossible unless RtpReceiverShim is doing something wrong. | |
514 RTC_NOTREACHED(); | |
515 return; | |
516 } | |
517 // Empty parameters should result in receiving being stopped. | |
518 RTCError err = ValidateAndApplyVideoReceiverParameters(RtpParameters()); | |
519 RTC_DCHECK(err.ok()); | |
520 have_video_receiver_ = false; | |
521 if (!have_video_sender_) { | |
522 DestroyVideoChannel(); | |
523 } | |
524 } | |
525 | |
526 RTCError RtpTransportControllerShim::ValidateAndApplyAudioSenderParameters( | |
527 const RtpParameters& parameters, | |
528 uint32_t* primary_ssrc) { | |
529 RTC_DCHECK(voice_channel_); | |
530 RTC_DCHECK(have_audio_sender_); | |
531 | |
532 std::vector<cricket::AudioCodec> cricket_codecs; | |
533 RTCError err = ValidateAndConvertCodecs(parameters.codecs, &cricket_codecs); | |
534 if (!err.ok()) { | |
535 return err; | |
536 } | |
537 | |
538 cricket::RtpHeaderExtensions cricket_extensions; | |
539 err = ValidateAndConvertHeaderExtensions(parameters.header_extensions, | |
540 &cricket_extensions); | |
541 if (!err.ok()) { | |
542 return err; | |
543 } | |
544 | |
545 cricket::StreamParamsVec cricket_streams; | |
546 cricket::RtpTransceiverDirection local_direction = | |
547 cricket::RtpTransceiverDirection::FromMediaContentDirection( | |
548 local_audio_description_.direction()); | |
549 int bandwidth = cricket::kAutoBandwidth; | |
550 err = ValidateAndConvertSenderEncodings( | |
551 parameters.encodings, inner_audio_transport_->GetRtcpParameters().cname, | |
552 local_audio_description_, &cricket_streams, &local_direction.send, | |
553 &bandwidth); | |
554 if (!err.ok()) { | |
555 return err; | |
556 } | |
557 if (primary_ssrc && !cricket_streams.empty()) { | |
558 *primary_ssrc = cricket_streams[0].first_ssrc(); | |
559 } | |
560 | |
561 // Validation is done, so we can attempt applying the descriptions. Sent | |
562 // codecs and header extensions go in remote description, streams go in | |
563 // local. | |
564 remote_audio_description_.set_codecs(cricket_codecs); | |
565 remote_audio_description_.set_rtp_header_extensions(cricket_extensions); | |
566 remote_audio_description_.set_bandwidth(bandwidth); | |
567 local_audio_description_.mutable_streams() = cricket_streams; | |
568 // Direction set based on encoding "active" flag. | |
569 local_audio_description_.set_direction( | |
570 local_direction.ToMediaContentDirection()); | |
571 remote_audio_description_.set_direction( | |
572 local_direction.MakeReversed().ToMediaContentDirection()); | |
573 // Add default codec if there are no encodings; no codec and no encodings | |
574 // should be legal, but the media engine code doesn't support that. | |
575 if (local_audio_description_.streams().empty() && | |
576 remote_audio_description_.codecs().empty()) { | |
577 AddDefaultAudioCodec(&remote_audio_description_); | |
578 } | |
579 | |
580 // Set remote content first, to ensure the stream is created with the correct | |
581 // codec. | |
582 if (!voice_channel_->SetRemoteContent(&remote_audio_description_, | |
583 cricket::CA_OFFER, nullptr)) { | |
584 return CreateAndLogError( | |
585 RTCErrorType::INTERNAL_ERROR, | |
586 "Failed to apply remote parameters to media channel."); | |
587 } | |
588 if (!voice_channel_->SetLocalContent(&local_audio_description_, | |
589 cricket::CA_ANSWER, nullptr)) { | |
590 return CreateAndLogError( | |
591 RTCErrorType::INTERNAL_ERROR, | |
592 "Failed to apply local parameters to media channel."); | |
593 } | |
594 return RTCError(); | |
595 } | |
596 | |
597 RTCError RtpTransportControllerShim::ValidateAndApplyVideoSenderParameters( | |
598 const RtpParameters& parameters, | |
599 uint32_t* primary_ssrc) { | |
600 RTC_DCHECK(video_channel_); | |
601 RTC_DCHECK(have_video_sender_); | |
602 | |
603 std::vector<cricket::VideoCodec> cricket_codecs; | |
604 RTCError err = ValidateAndConvertCodecs(parameters.codecs, &cricket_codecs); | |
605 if (!err.ok()) { | |
606 return err; | |
607 } | |
608 | |
609 cricket::RtpHeaderExtensions cricket_extensions; | |
610 err = ValidateAndConvertHeaderExtensions(parameters.header_extensions, | |
611 &cricket_extensions); | |
612 if (!err.ok()) { | |
613 return err; | |
614 } | |
615 | |
616 cricket::StreamParamsVec cricket_streams; | |
617 cricket::RtpTransceiverDirection local_direction = | |
618 cricket::RtpTransceiverDirection::FromMediaContentDirection( | |
619 local_video_description_.direction()); | |
620 int bandwidth = cricket::kAutoBandwidth; | |
621 err = ValidateAndConvertSenderEncodings( | |
622 parameters.encodings, inner_video_transport_->GetRtcpParameters().cname, | |
623 local_video_description_, &cricket_streams, &local_direction.send, | |
624 &bandwidth); | |
625 if (!err.ok()) { | |
626 return err; | |
627 } | |
628 if (primary_ssrc && !cricket_streams.empty()) { | |
629 *primary_ssrc = cricket_streams[0].first_ssrc(); | |
630 } | |
631 | |
632 // Validation is done, so we can attempt applying the descriptions. Sent | |
633 // codecs and header extensions go in remote description, streams go in | |
634 // local. | |
635 remote_video_description_.set_codecs(cricket_codecs); | |
636 remote_video_description_.set_rtp_header_extensions(cricket_extensions); | |
637 remote_video_description_.set_bandwidth(bandwidth); | |
638 local_video_description_.mutable_streams() = cricket_streams; | |
639 // Direction set based on encoding "active" flag. | |
640 local_video_description_.set_direction( | |
641 local_direction.ToMediaContentDirection()); | |
642 remote_video_description_.set_direction( | |
643 local_direction.MakeReversed().ToMediaContentDirection()); | |
644 // Add default codec if there are no encodings; no codec and no encodings | |
645 // should be legal, but the media engine code doesn't support that. | |
646 if (local_video_description_.streams().empty() && | |
647 remote_video_description_.codecs().empty()) { | |
648 AddDefaultVideoCodec(&remote_video_description_); | |
649 } | |
650 | |
651 // Set remote content first, to ensure the stream is created with the correct | |
652 // codec. | |
653 if (!video_channel_->SetRemoteContent(&remote_video_description_, | |
654 cricket::CA_OFFER, nullptr)) { | |
655 return CreateAndLogError( | |
656 RTCErrorType::INTERNAL_ERROR, | |
657 "Failed to apply remote parameters to media channel."); | |
658 } | |
659 if (!video_channel_->SetLocalContent(&local_video_description_, | |
660 cricket::CA_ANSWER, nullptr)) { | |
661 return CreateAndLogError( | |
662 RTCErrorType::INTERNAL_ERROR, | |
663 "Failed to apply local parameters to media channel."); | |
664 } | |
665 return RTCError(); | |
666 } | |
667 | |
668 RTCError RtpTransportControllerShim::ValidateAndApplyAudioReceiverParameters( | |
669 const RtpParameters& parameters) { | |
670 RTC_DCHECK(voice_channel_); | |
671 RTC_DCHECK(have_audio_receiver_); | |
672 | |
673 std::vector<cricket::AudioCodec> cricket_codecs; | |
674 RTCError err = ValidateAndConvertCodecs(parameters.codecs, &cricket_codecs); | |
675 if (!err.ok()) { | |
676 return err; | |
677 } | |
678 | |
679 cricket::RtpHeaderExtensions cricket_extensions; | |
680 err = ValidateAndConvertHeaderExtensions(parameters.header_extensions, | |
681 &cricket_extensions); | |
682 if (!err.ok()) { | |
683 return err; | |
684 } | |
685 | |
686 cricket::StreamParamsVec cricket_streams; | |
687 cricket::RtpTransceiverDirection local_direction = | |
688 cricket::RtpTransceiverDirection::FromMediaContentDirection( | |
689 local_audio_description_.direction()); | |
690 int bandwidth = cricket::kAutoBandwidth; | |
691 err = ValidateAndConvertReceiverEncodings( | |
692 parameters.encodings, &cricket_streams, &local_direction.recv); | |
693 if (!err.ok()) { | |
694 return err; | |
695 } | |
696 | |
697 // Validation is done, so we can attempt applying the descriptions. Received | |
698 // codecs and header extensions go in local description, streams go in | |
699 // remote. | |
700 local_audio_description_.set_codecs(cricket_codecs); | |
701 local_audio_description_.set_rtp_header_extensions(cricket_extensions); | |
702 local_audio_description_.set_bandwidth(bandwidth); | |
703 remote_audio_description_.mutable_streams() = cricket_streams; | |
704 // Direction set based on encoding "active" flag. | |
705 local_audio_description_.set_direction( | |
706 local_direction.ToMediaContentDirection()); | |
707 remote_audio_description_.set_direction( | |
708 local_direction.MakeReversed().ToMediaContentDirection()); | |
709 // Add default codec if there are no encodings; no codec and no encodings | |
710 // should be legal, but the media engine code doesn't support that. | |
711 if (remote_audio_description_.streams().empty() && | |
712 local_audio_description_.codecs().empty()) { | |
713 AddDefaultAudioCodec(&local_audio_description_); | |
714 } | |
715 | |
716 if (!voice_channel_->SetLocalContent(&local_audio_description_, | |
717 cricket::CA_OFFER, nullptr)) { | |
718 return CreateAndLogError( | |
719 RTCErrorType::INTERNAL_ERROR, | |
720 "Failed to apply local parameters to media channel."); | |
721 } | |
722 if (!voice_channel_->SetRemoteContent(&remote_audio_description_, | |
723 cricket::CA_ANSWER, nullptr)) { | |
724 return CreateAndLogError( | |
725 RTCErrorType::INTERNAL_ERROR, | |
726 "Failed to apply remote parameters to media channel."); | |
727 } | |
728 return RTCError(); | |
729 } | |
730 | |
731 RTCError RtpTransportControllerShim::ValidateAndApplyVideoReceiverParameters( | |
732 const RtpParameters& parameters) { | |
733 RTC_DCHECK(video_channel_); | |
734 RTC_DCHECK(have_video_receiver_); | |
735 | |
736 std::vector<cricket::VideoCodec> cricket_codecs; | |
737 RTCError err = ValidateAndConvertCodecs(parameters.codecs, &cricket_codecs); | |
738 if (!err.ok()) { | |
739 return err; | |
740 } | |
741 | |
742 cricket::RtpHeaderExtensions cricket_extensions; | |
743 err = ValidateAndConvertHeaderExtensions(parameters.header_extensions, | |
744 &cricket_extensions); | |
745 if (!err.ok()) { | |
746 return err; | |
747 } | |
748 | |
749 cricket::StreamParamsVec cricket_streams; | |
750 cricket::RtpTransceiverDirection local_direction = | |
751 cricket::RtpTransceiverDirection::FromMediaContentDirection( | |
752 local_video_description_.direction()); | |
753 int bandwidth = cricket::kAutoBandwidth; | |
754 err = ValidateAndConvertReceiverEncodings( | |
755 parameters.encodings, &cricket_streams, &local_direction.recv); | |
756 if (!err.ok()) { | |
757 return err; | |
758 } | |
759 | |
760 // Validation is done, so we can attempt applying the descriptions. Received | |
761 // codecs and header extensions go in local description, streams go in | |
762 // remote. | |
763 local_video_description_.set_codecs(cricket_codecs); | |
764 local_video_description_.set_rtp_header_extensions(cricket_extensions); | |
765 local_video_description_.set_bandwidth(bandwidth); | |
766 remote_video_description_.mutable_streams() = cricket_streams; | |
767 // Direction set based on encoding "active" flag. | |
768 local_video_description_.set_direction( | |
769 local_direction.ToMediaContentDirection()); | |
770 remote_video_description_.set_direction( | |
771 local_direction.MakeReversed().ToMediaContentDirection()); | |
772 // Add default codec if there are no encodings; no codec and no encodings | |
773 // should be legal, but the media engine code doesn't support that. | |
774 if (remote_video_description_.streams().empty() && | |
775 local_video_description_.codecs().empty()) { | |
776 AddDefaultVideoCodec(&local_video_description_); | |
777 } | |
778 | |
779 if (!video_channel_->SetLocalContent(&local_video_description_, | |
780 cricket::CA_OFFER, nullptr)) { | |
781 return CreateAndLogError( | |
782 RTCErrorType::INTERNAL_ERROR, | |
783 "Failed to apply local parameters to media channel."); | |
784 } | |
785 if (!video_channel_->SetRemoteContent(&remote_video_description_, | |
786 cricket::CA_ANSWER, nullptr)) { | |
787 return CreateAndLogError( | |
788 RTCErrorType::INTERNAL_ERROR, | |
789 "Failed to apply remote parameters to media channel."); | |
790 } | |
791 return RTCError(); | |
792 } | |
793 | |
794 RtpTransportControllerShim::RtpTransportControllerShim( | |
795 const cricket::MediaConfig& config, | |
796 cricket::ChannelManager* channel_manager, | |
797 webrtc::RtcEventLog* event_log, | |
798 rtc::Thread* signaling_thread, | |
799 rtc::Thread* worker_thread) | |
800 : signaling_thread_(signaling_thread), | |
801 worker_thread_(worker_thread), | |
802 media_controller_(MediaControllerInterface::Create(config, | |
803 worker_thread, | |
804 channel_manager, | |
805 event_log)) { | |
806 RTC_DCHECK_RUN_ON(signaling_thread_); | |
807 RTC_DCHECK(channel_manager); | |
808 // MediaControllerInterface::Create should never fail. | |
809 RTC_DCHECK(media_controller_); | |
810 AddDefaultAudioCodec(&local_audio_description_); | |
811 AddDefaultAudioCodec(&remote_audio_description_); | |
812 AddDefaultVideoCodec(&local_video_description_); | |
813 AddDefaultVideoCodec(&remote_video_description_); | |
pthatcher1
2017/02/10 22:36:53
This could use a comment as to why you do it.
| |
814 } | |
815 | |
816 void RtpTransportControllerShim::CreateVoiceChannel() { | |
817 voice_channel_ = media_controller_->channel_manager()->CreateVoiceChannel( | |
818 media_controller_.get(), | |
819 inner_audio_transport_->GetRtpPacketTransport()->GetInternal(), | |
820 inner_audio_transport_->GetRtcpPacketTransport() | |
821 ? inner_audio_transport_->GetRtcpPacketTransport()->GetInternal() | |
822 : nullptr, | |
823 signaling_thread_, "audio", false, cricket::AudioOptions()); | |
824 RTC_DCHECK(voice_channel_); | |
825 voice_channel_->Enable(true); | |
826 } | |
827 | |
828 void RtpTransportControllerShim::CreateVideoChannel() { | |
829 video_channel_ = media_controller_->channel_manager()->CreateVideoChannel( | |
830 media_controller_.get(), | |
831 inner_video_transport_->GetRtpPacketTransport()->GetInternal(), | |
832 inner_video_transport_->GetRtcpPacketTransport() | |
833 ? inner_video_transport_->GetRtcpPacketTransport()->GetInternal() | |
834 : nullptr, | |
835 signaling_thread_, "audio", false, cricket::VideoOptions()); | |
836 RTC_DCHECK(video_channel_); | |
837 video_channel_->Enable(true); | |
838 } | |
839 | |
840 void RtpTransportControllerShim::DestroyVoiceChannel() { | |
841 RTC_DCHECK(voice_channel_); | |
842 media_controller_->channel_manager()->DestroyVoiceChannel(voice_channel_); | |
843 voice_channel_ = nullptr; | |
844 } | |
845 | |
846 void RtpTransportControllerShim::DestroyVideoChannel() { | |
847 RTC_DCHECK(video_channel_); | |
848 media_controller_->channel_manager()->DestroyVideoChannel(video_channel_); | |
849 video_channel_ = nullptr; | |
850 } | |
851 | |
852 void RtpTransportControllerShim::CopyRtcpParametersToDescriptions( | |
853 const RtcpParameters& params, | |
854 cricket::MediaContentDescription* local, | |
855 cricket::MediaContentDescription* remote) { | |
856 local->set_rtcp_mux(params.mux); | |
857 remote->set_rtcp_mux(params.mux); | |
858 local->set_rtcp_reduced_size(params.reduced_size); | |
859 remote->set_rtcp_reduced_size(params.reduced_size); | |
860 for (cricket::StreamParams& stream_params : local->mutable_streams()) { | |
861 stream_params.cname = params.cname; | |
862 } | |
863 } | |
864 | |
865 uint32_t RtpTransportControllerShim::GenerateUnusedSsrc( | |
866 const cricket::StreamParams& new_params) const { | |
867 uint32_t ssrc; | |
868 do { | |
869 ssrc = rtc::CreateRandomNonZeroId(); | |
870 } while ( | |
871 cricket::GetStreamBySsrc(local_audio_description_.streams(), ssrc) || | |
872 cricket::GetStreamBySsrc(remote_audio_description_.streams(), ssrc) || | |
873 cricket::GetStreamBySsrc(local_video_description_.streams(), ssrc) || | |
874 cricket::GetStreamBySsrc(remote_video_description_.streams(), ssrc) || | |
875 new_params.has_ssrc(ssrc)); | |
876 return ssrc; | |
877 } | |
878 | |
879 RTCError RtpTransportControllerShim::ValidateAndConvertSenderEncodings( | |
880 const std::vector<RtpEncodingParameters> encodings, | |
881 const std::string& cname, | |
882 const cricket::MediaContentDescription& description, | |
883 cricket::StreamParamsVec* cricket_streams, | |
884 bool* sending, | |
885 int* bandwidth) const { | |
886 if (encodings.size() > 1u) { | |
887 return CreateAndLogError(RTCErrorType::UNSUPPORTED_PARAMETER, | |
888 "ORTC API implementation doesn't currently " | |
889 "support simulcast or layered encodings."); | |
890 } | |
891 if (encodings.size() == 1u) { | |
pthatcher1
2017/02/10 22:36:53
This could use some early returns to push code to
| |
892 const RtpEncodingParameters& encoding = encodings[0]; | |
893 cricket::StreamParams stream_params; | |
894 stream_params.cname = cname; | |
895 if (encoding.ssrc) { | |
896 stream_params.add_ssrc(*encoding.ssrc); | |
897 } else { | |
898 // SSRC not provided; generate it or use the existing one. | |
899 if (!description.streams().empty()) { | |
900 stream_params.add_ssrc(description.streams()[0].first_ssrc()); | |
901 } else { | |
902 stream_params.add_ssrc(GenerateUnusedSsrc(stream_params)); | |
903 } | |
904 } | |
905 if (encoding.rtx) { | |
906 if (encoding.rtx->ssrc) { | |
907 stream_params.AddFidSsrc(stream_params.first_ssrc(), | |
908 *encoding.rtx->ssrc); | |
909 } else { | |
910 // SSRC not provided; generate it or use the existing one. | |
911 if (!description.streams().empty() && | |
912 description.streams()[0].has_ssrc_group( | |
913 cricket::kFidSsrcGroupSemantics)) { | |
914 stream_params.AddFidSsrc( | |
915 stream_params.first_ssrc(), | |
916 description.streams()[0] | |
917 .get_ssrc_group(cricket::kFidSsrcGroupSemantics) | |
918 ->ssrcs[1]); | |
919 } else { | |
920 stream_params.AddFidSsrc(stream_params.first_ssrc(), | |
921 GenerateUnusedSsrc(stream_params)); | |
922 } | |
923 } | |
924 } | |
925 cricket_streams->push_back(std::move(stream_params)); | |
926 if (encoding.max_bitrate_bps) { | |
927 *bandwidth = *encoding.max_bitrate_bps; | |
928 } | |
929 *sending = encoding.active; | |
930 } else { | |
931 *sending = false; | |
932 } | |
933 return RTCError(); | |
934 } | |
935 | |
936 } // namespace webrtc | |
OLD | NEW |