Line data Source code
1 : /* This Source Code Form is subject to the terms of the Mozilla Public
2 : * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 : * You can obtain one at http://mozilla.org/MPL/2.0/. */
4 :
5 : #include "logging.h"
6 : #include "nsIGfxInfo.h"
7 : #include "nsServiceManagerUtils.h"
8 :
9 : #include "PeerConnectionImpl.h"
10 : #include "PeerConnectionMedia.h"
11 : #include "MediaPipelineFactory.h"
12 : #include "MediaPipelineFilter.h"
13 : #include "transportflow.h"
14 : #include "transportlayer.h"
15 : #include "transportlayerdtls.h"
16 : #include "transportlayerice.h"
17 :
18 : #include "signaling/src/jsep/JsepTrack.h"
19 : #include "signaling/src/jsep/JsepTransport.h"
20 : #include "signaling/src/common/PtrVector.h"
21 :
22 : #include "MediaStreamTrack.h"
23 : #include "nsIPrincipal.h"
24 : #include "nsIDocument.h"
25 : #include "mozilla/Preferences.h"
26 : #include "MediaEngine.h"
27 :
28 : #include "mozilla/Preferences.h"
29 :
30 : #include "WebrtcGmpVideoCodec.h"
31 :
32 : #include <stdlib.h>
33 :
34 : namespace mozilla {
35 :
36 0 : MOZ_MTLOG_MODULE("MediaPipelineFactory")
37 :
38 : static nsresult
39 0 : JsepCodecDescToCodecConfig(const JsepCodecDescription& aCodec,
40 : AudioCodecConfig** aConfig)
41 : {
42 0 : MOZ_ASSERT(aCodec.mType == SdpMediaSection::kAudio);
43 0 : if (aCodec.mType != SdpMediaSection::kAudio)
44 0 : return NS_ERROR_INVALID_ARG;
45 :
46 : const JsepAudioCodecDescription& desc =
47 0 : static_cast<const JsepAudioCodecDescription&>(aCodec);
48 :
49 : uint16_t pt;
50 :
51 0 : if (!desc.GetPtAsInt(&pt)) {
52 0 : MOZ_MTLOG(ML_ERROR, "Invalid payload type: " << desc.mDefaultPt);
53 0 : return NS_ERROR_INVALID_ARG;
54 : }
55 :
56 0 : *aConfig = new AudioCodecConfig(pt,
57 : desc.mName,
58 0 : desc.mClock,
59 0 : desc.mPacketSize,
60 0 : desc.mForceMono ? 1 : desc.mChannels,
61 0 : desc.mBitrate,
62 0 : desc.mFECEnabled);
63 0 : (*aConfig)->mMaxPlaybackRate = desc.mMaxPlaybackRate;
64 0 : (*aConfig)->mDtmfEnabled = desc.mDtmfEnabled;
65 :
66 0 : return NS_OK;
67 : }
68 :
69 : static std::vector<JsepCodecDescription*>
70 0 : GetCodecs(const JsepTrackNegotiatedDetails& aDetails)
71 : {
72 : // We do not try to handle cases where a codec is not used on the primary
73 : // encoding.
74 0 : if (aDetails.GetEncodingCount()) {
75 0 : return aDetails.GetEncoding(0).GetCodecs();
76 : }
77 0 : return std::vector<JsepCodecDescription*>();
78 : }
79 :
80 : static nsresult
81 0 : NegotiatedDetailsToAudioCodecConfigs(const JsepTrackNegotiatedDetails& aDetails,
82 : PtrVector<AudioCodecConfig>* aConfigs)
83 : {
84 0 : std::vector<JsepCodecDescription*> codecs(GetCodecs(aDetails));
85 0 : for (const JsepCodecDescription* codec : codecs) {
86 : AudioCodecConfig* config;
87 0 : if (NS_FAILED(JsepCodecDescToCodecConfig(*codec, &config))) {
88 0 : return NS_ERROR_INVALID_ARG;
89 : }
90 0 : aConfigs->values.push_back(config);
91 : }
92 0 : return NS_OK;
93 : }
94 :
95 : static nsresult
96 0 : JsepCodecDescToCodecConfig(const JsepCodecDescription& aCodec,
97 : VideoCodecConfig** aConfig)
98 : {
99 0 : MOZ_ASSERT(aCodec.mType == SdpMediaSection::kVideo);
100 0 : if (aCodec.mType != SdpMediaSection::kVideo) {
101 0 : MOZ_ASSERT(false, "JsepCodecDescription has wrong type");
102 : return NS_ERROR_INVALID_ARG;
103 : }
104 :
105 : const JsepVideoCodecDescription& desc =
106 0 : static_cast<const JsepVideoCodecDescription&>(aCodec);
107 :
108 : uint16_t pt;
109 :
110 0 : if (!desc.GetPtAsInt(&pt)) {
111 0 : MOZ_MTLOG(ML_ERROR, "Invalid payload type: " << desc.mDefaultPt);
112 0 : return NS_ERROR_INVALID_ARG;
113 : }
114 :
115 0 : UniquePtr<VideoCodecConfigH264> h264Config;
116 :
117 0 : if (desc.mName == "H264") {
118 0 : h264Config = MakeUnique<VideoCodecConfigH264>();
119 0 : size_t spropSize = sizeof(h264Config->sprop_parameter_sets);
120 0 : strncpy(h264Config->sprop_parameter_sets,
121 : desc.mSpropParameterSets.c_str(),
122 0 : spropSize);
123 0 : h264Config->sprop_parameter_sets[spropSize - 1] = '\0';
124 0 : h264Config->packetization_mode = desc.mPacketizationMode;
125 0 : h264Config->profile_level_id = desc.mProfileLevelId;
126 0 : h264Config->tias_bw = 0; // TODO. Issue 165.
127 : }
128 :
129 : VideoCodecConfig* configRaw;
130 0 : configRaw = new VideoCodecConfig(
131 0 : pt, desc.mName, desc.mConstraints, h264Config.get());
132 :
133 0 : configRaw->mAckFbTypes = desc.mAckFbTypes;
134 0 : configRaw->mNackFbTypes = desc.mNackFbTypes;
135 0 : configRaw->mCcmFbTypes = desc.mCcmFbTypes;
136 0 : configRaw->mRembFbSet = desc.RtcpFbRembIsSet();
137 0 : configRaw->mFECFbSet = desc.mFECEnabled;
138 0 : if (desc.mFECEnabled) {
139 0 : configRaw->mREDPayloadType = desc.mREDPayloadType;
140 0 : configRaw->mULPFECPayloadType = desc.mULPFECPayloadType;
141 : }
142 :
143 0 : *aConfig = configRaw;
144 0 : return NS_OK;
145 : }
146 :
147 : static nsresult
148 0 : NegotiatedDetailsToVideoCodecConfigs(const JsepTrackNegotiatedDetails& aDetails,
149 : PtrVector<VideoCodecConfig>* aConfigs)
150 : {
151 0 : std::vector<JsepCodecDescription*> codecs(GetCodecs(aDetails));
152 0 : for (const JsepCodecDescription* codec : codecs) {
153 : VideoCodecConfig* config;
154 0 : if (NS_FAILED(JsepCodecDescToCodecConfig(*codec, &config))) {
155 0 : return NS_ERROR_INVALID_ARG;
156 : }
157 :
158 0 : config->mTias = aDetails.GetTias();
159 :
160 0 : for (size_t i = 0; i < aDetails.GetEncodingCount(); ++i) {
161 0 : const JsepTrackEncoding& jsepEncoding(aDetails.GetEncoding(i));
162 0 : if (jsepEncoding.HasFormat(codec->mDefaultPt)) {
163 0 : VideoCodecConfig::SimulcastEncoding encoding;
164 0 : encoding.rid = jsepEncoding.mRid;
165 0 : encoding.constraints = jsepEncoding.mConstraints;
166 0 : config->mSimulcastEncodings.push_back(encoding);
167 : }
168 : }
169 :
170 0 : aConfigs->values.push_back(config);
171 : }
172 :
173 0 : return NS_OK;
174 : }
175 :
176 : // Accessing the PCMedia should be safe here because we shouldn't
177 : // have enqueued this function unless it was still active and
178 : // the ICE data is destroyed on the STS.
179 : static void
180 0 : FinalizeTransportFlow_s(RefPtr<PeerConnectionMedia> aPCMedia,
181 : RefPtr<TransportFlow> aFlow, size_t aLevel,
182 : bool aIsRtcp,
183 : nsAutoPtr<PtrVector<TransportLayer> > aLayerList)
184 : {
185 : TransportLayerIce* ice =
186 0 : static_cast<TransportLayerIce*>(aLayerList->values.front());
187 0 : ice->SetParameters(aPCMedia->ice_ctx(),
188 0 : aPCMedia->ice_media_stream(aLevel),
189 0 : aIsRtcp ? 2 : 1);
190 : nsAutoPtr<std::queue<TransportLayer*> > layerQueue(
191 0 : new std::queue<TransportLayer*>);
192 0 : for (auto& value : aLayerList->values) {
193 0 : layerQueue->push(value);
194 : }
195 0 : aLayerList->values.clear();
196 0 : (void)aFlow->PushLayers(layerQueue); // TODO(bug 854518): Process errors.
197 0 : }
198 :
199 : static void
200 0 : AddNewIceStreamForRestart_s(RefPtr<PeerConnectionMedia> aPCMedia,
201 : RefPtr<TransportFlow> aFlow,
202 : size_t aLevel,
203 : bool aIsRtcp)
204 : {
205 : TransportLayerIce* ice =
206 0 : static_cast<TransportLayerIce*>(aFlow->GetLayer("ice"));
207 0 : ice->SetParameters(aPCMedia->ice_ctx(),
208 0 : aPCMedia->ice_media_stream(aLevel),
209 0 : aIsRtcp ? 2 : 1);
210 0 : }
211 :
212 : nsresult
213 0 : MediaPipelineFactory::CreateOrGetTransportFlow(
214 : size_t aLevel,
215 : bool aIsRtcp,
216 : const JsepTransport& aTransport,
217 : RefPtr<TransportFlow>* aFlowOutparam)
218 : {
219 : nsresult rv;
220 0 : RefPtr<TransportFlow> flow;
221 :
222 0 : flow = mPCMedia->GetTransportFlow(aLevel, aIsRtcp);
223 0 : if (flow) {
224 0 : if (mPCMedia->IsIceRestarting()) {
225 0 : MOZ_MTLOG(ML_INFO, "Flow[" << flow->id() << "]: "
226 : << "detected ICE restart - level: "
227 : << aLevel << " rtcp: " << aIsRtcp);
228 :
229 0 : rv = mPCMedia->GetSTSThread()->Dispatch(
230 0 : WrapRunnableNM(AddNewIceStreamForRestart_s,
231 : mPCMedia, flow, aLevel, aIsRtcp),
232 0 : NS_DISPATCH_NORMAL);
233 0 : if (NS_FAILED(rv)) {
234 0 : MOZ_MTLOG(ML_ERROR, "Failed to dispatch AddNewIceStreamForRestart_s");
235 0 : return rv;
236 : }
237 : }
238 :
239 0 : *aFlowOutparam = flow;
240 0 : return NS_OK;
241 : }
242 :
243 0 : std::ostringstream osId;
244 0 : osId << mPC->GetHandle() << ":" << aLevel << ","
245 0 : << (aIsRtcp ? "rtcp" : "rtp");
246 0 : flow = new TransportFlow(osId.str());
247 :
248 : // The media streams are made on STS so we need to defer setup.
249 0 : auto ice = MakeUnique<TransportLayerIce>(mPC->GetHandle());
250 0 : auto dtls = MakeUnique<TransportLayerDtls>();
251 0 : dtls->SetRole(aTransport.mDtls->GetRole() ==
252 : JsepDtlsTransport::kJsepDtlsClient
253 : ? TransportLayerDtls::CLIENT
254 0 : : TransportLayerDtls::SERVER);
255 :
256 0 : RefPtr<DtlsIdentity> pcid = mPC->Identity();
257 0 : if (!pcid) {
258 0 : MOZ_MTLOG(ML_ERROR, "Failed to get DTLS identity.");
259 0 : return NS_ERROR_FAILURE;
260 : }
261 0 : dtls->SetIdentity(pcid);
262 :
263 : const SdpFingerprintAttributeList& fingerprints =
264 0 : aTransport.mDtls->GetFingerprints();
265 0 : for (const auto& fingerprint : fingerprints.mFingerprints) {
266 0 : std::ostringstream ss;
267 0 : ss << fingerprint.hashFunc;
268 0 : rv = dtls->SetVerificationDigest(ss.str(), &fingerprint.fingerprint[0],
269 0 : fingerprint.fingerprint.size());
270 0 : if (NS_FAILED(rv)) {
271 0 : MOZ_MTLOG(ML_ERROR, "Could not set fingerprint");
272 0 : return rv;
273 : }
274 : }
275 :
276 0 : std::vector<uint16_t> srtpCiphers;
277 0 : srtpCiphers.push_back(SRTP_AES128_CM_HMAC_SHA1_80);
278 0 : srtpCiphers.push_back(SRTP_AES128_CM_HMAC_SHA1_32);
279 :
280 0 : rv = dtls->SetSrtpCiphers(srtpCiphers);
281 0 : if (NS_FAILED(rv)) {
282 0 : MOZ_MTLOG(ML_ERROR, "Couldn't set SRTP ciphers");
283 0 : return rv;
284 : }
285 :
286 : // Always permits negotiation of the confidential mode.
287 : // Only allow non-confidential (which is an allowed default),
288 : // if we aren't confidential.
289 0 : std::set<std::string> alpn;
290 0 : std::string alpnDefault = "";
291 0 : alpn.insert("c-webrtc");
292 0 : if (!mPC->PrivacyRequested()) {
293 0 : alpnDefault = "webrtc";
294 0 : alpn.insert(alpnDefault);
295 : }
296 0 : rv = dtls->SetAlpn(alpn, alpnDefault);
297 0 : if (NS_FAILED(rv)) {
298 0 : MOZ_MTLOG(ML_ERROR, "Couldn't set ALPN");
299 0 : return rv;
300 : }
301 :
302 0 : nsAutoPtr<PtrVector<TransportLayer> > layers(new PtrVector<TransportLayer>);
303 0 : layers->values.push_back(ice.release());
304 0 : layers->values.push_back(dtls.release());
305 :
306 0 : rv = mPCMedia->GetSTSThread()->Dispatch(
307 0 : WrapRunnableNM(FinalizeTransportFlow_s, mPCMedia, flow, aLevel, aIsRtcp,
308 : layers),
309 0 : NS_DISPATCH_NORMAL);
310 0 : if (NS_FAILED(rv)) {
311 0 : MOZ_MTLOG(ML_ERROR, "Failed to dispatch FinalizeTransportFlow_s");
312 0 : return rv;
313 : }
314 :
315 0 : mPCMedia->AddTransportFlow(aLevel, aIsRtcp, flow);
316 :
317 0 : *aFlowOutparam = flow;
318 :
319 0 : return NS_OK;
320 : }
321 :
322 : nsresult
323 0 : MediaPipelineFactory::GetTransportParameters(
324 : const JsepTrackPair& aTrackPair,
325 : const JsepTrack& aTrack,
326 : size_t* aLevelOut,
327 : RefPtr<TransportFlow>* aRtpOut,
328 : RefPtr<TransportFlow>* aRtcpOut,
329 : nsAutoPtr<MediaPipelineFilter>* aFilterOut)
330 : {
331 0 : *aLevelOut = aTrackPair.mLevel;
332 :
333 0 : size_t transportLevel = aTrackPair.HasBundleLevel() ?
334 : aTrackPair.BundleLevel() :
335 0 : aTrackPair.mLevel;
336 :
337 : nsresult rv = CreateOrGetTransportFlow(
338 0 : transportLevel, false, *aTrackPair.mRtpTransport, aRtpOut);
339 0 : if (NS_FAILED(rv)) {
340 0 : return rv;
341 : }
342 0 : MOZ_ASSERT(aRtpOut);
343 :
344 0 : if (aTrackPair.mRtcpTransport) {
345 : rv = CreateOrGetTransportFlow(
346 0 : transportLevel, true, *aTrackPair.mRtcpTransport, aRtcpOut);
347 0 : if (NS_FAILED(rv)) {
348 0 : return rv;
349 : }
350 0 : MOZ_ASSERT(aRtcpOut);
351 : }
352 :
353 0 : if (aTrackPair.HasBundleLevel()) {
354 0 : bool receiving = aTrack.GetDirection() == sdp::kRecv;
355 :
356 0 : *aFilterOut = new MediaPipelineFilter;
357 :
358 0 : if (receiving) {
359 : // Add remote SSRCs so we can distinguish which RTP packets actually
360 : // belong to this pipeline (also RTCP sender reports).
361 0 : for (unsigned int ssrc : aTrack.GetSsrcs()) {
362 0 : (*aFilterOut)->AddRemoteSSRC(ssrc);
363 : }
364 :
365 : // TODO(bug 1105005): Tell the filter about the mid for this track
366 :
367 : // Add unique payload types as a last-ditch fallback
368 0 : auto uniquePts = aTrack.GetNegotiatedDetails()->GetUniquePayloadTypes();
369 0 : for (unsigned char& uniquePt : uniquePts) {
370 0 : (*aFilterOut)->AddUniquePT(uniquePt);
371 : }
372 : }
373 : }
374 :
375 0 : return NS_OK;
376 : }
377 :
378 : nsresult
379 0 : MediaPipelineFactory::CreateOrUpdateMediaPipeline(
380 : const JsepTrackPair& aTrackPair,
381 : const JsepTrack& aTrack)
382 : {
383 : // The GMP code is all the way on the other side of webrtc.org, and it is not
384 : // feasible to plumb this information all the way through. So, we set it (for
385 : // the duration of this call) in a global variable. This allows the GMP code
386 : // to report errors to the PC.
387 0 : WebrtcGmpPCHandleSetter setter(mPC->GetHandle());
388 :
389 0 : MOZ_ASSERT(aTrackPair.mRtpTransport);
390 :
391 0 : bool receiving = aTrack.GetDirection() == sdp::kRecv;
392 :
393 : size_t level;
394 0 : RefPtr<TransportFlow> rtpFlow;
395 0 : RefPtr<TransportFlow> rtcpFlow;
396 0 : nsAutoPtr<MediaPipelineFilter> filter;
397 :
398 : nsresult rv = GetTransportParameters(aTrackPair,
399 : aTrack,
400 : &level,
401 : &rtpFlow,
402 : &rtcpFlow,
403 0 : &filter);
404 0 : if (NS_FAILED(rv)) {
405 0 : MOZ_MTLOG(ML_ERROR, "Failed to get transport parameters for pipeline, rv="
406 : << static_cast<unsigned>(rv));
407 0 : return rv;
408 : }
409 :
410 0 : if (aTrack.GetMediaType() == SdpMediaSection::kApplication) {
411 : // GetTransportParameters has already done everything we need for
412 : // datachannel.
413 0 : return NS_OK;
414 : }
415 :
416 : // Find the stream we need
417 : SourceStreamInfo* stream;
418 0 : if (receiving) {
419 0 : stream = mPCMedia->GetRemoteStreamById(aTrack.GetStreamId());
420 : } else {
421 0 : stream = mPCMedia->GetLocalStreamById(aTrack.GetStreamId());
422 : }
423 :
424 0 : if (!stream) {
425 0 : MOZ_MTLOG(ML_ERROR, "Negotiated " << (receiving ? "recv" : "send")
426 : << " stream id " << aTrack.GetStreamId() << " was never added");
427 0 : MOZ_ASSERT(false);
428 : return NS_ERROR_FAILURE;
429 : }
430 :
431 0 : if (!stream->HasTrack(aTrack.GetTrackId())) {
432 0 : MOZ_MTLOG(ML_ERROR, "Negotiated " << (receiving ? "recv" : "send")
433 : << " track id " << aTrack.GetTrackId() << " was never added");
434 0 : MOZ_ASSERT(false);
435 : return NS_ERROR_FAILURE;
436 : }
437 :
438 0 : RefPtr<MediaSessionConduit> conduit;
439 0 : if (aTrack.GetMediaType() == SdpMediaSection::kAudio) {
440 0 : rv = GetOrCreateAudioConduit(aTrackPair, aTrack, &conduit);
441 0 : if (NS_FAILED(rv)) {
442 0 : return rv;
443 : }
444 0 : } else if (aTrack.GetMediaType() == SdpMediaSection::kVideo) {
445 0 : rv = GetOrCreateVideoConduit(aTrackPair, aTrack, &conduit);
446 0 : if (NS_FAILED(rv)) {
447 0 : return rv;
448 : }
449 0 : conduit->SetPCHandle(mPC->GetHandle());
450 : } else {
451 : // We've created the TransportFlow, nothing else to do here.
452 0 : return NS_OK;
453 : }
454 :
455 0 : if (aTrack.GetActive()) {
456 0 : if (receiving) {
457 0 : auto error = conduit->StartReceiving();
458 0 : if (error) {
459 0 : MOZ_MTLOG(ML_ERROR, "StartReceiving failed: " << error);
460 0 : return NS_ERROR_FAILURE;
461 : }
462 : } else {
463 0 : auto error = conduit->StartTransmitting();
464 0 : if (error) {
465 0 : MOZ_MTLOG(ML_ERROR, "StartTransmitting failed: " << error);
466 0 : return NS_ERROR_FAILURE;
467 : }
468 : }
469 : } else {
470 0 : if (receiving) {
471 0 : auto error = conduit->StopReceiving();
472 0 : if (error) {
473 0 : MOZ_MTLOG(ML_ERROR, "StopReceiving failed: " << error);
474 0 : return NS_ERROR_FAILURE;
475 : }
476 : } else {
477 0 : auto error = conduit->StopTransmitting();
478 0 : if (error) {
479 0 : MOZ_MTLOG(ML_ERROR, "StopTransmitting failed: " << error);
480 0 : return NS_ERROR_FAILURE;
481 : }
482 : }
483 : }
484 :
485 : RefPtr<MediaPipeline> pipeline =
486 0 : stream->GetPipelineByTrackId_m(aTrack.GetTrackId());
487 :
488 0 : if (pipeline && pipeline->level() != static_cast<int>(level)) {
489 0 : MOZ_MTLOG(ML_WARNING, "Track " << aTrack.GetTrackId() <<
490 : " has moved from level " << pipeline->level() <<
491 : " to level " << level <<
492 : ". This requires re-creating the MediaPipeline.");
493 : RefPtr<dom::MediaStreamTrack> domTrack =
494 0 : stream->GetTrackById(aTrack.GetTrackId());
495 0 : MOZ_ASSERT(domTrack, "MediaPipeline existed for a track, but no MediaStreamTrack");
496 :
497 : // Since we do not support changing the conduit on a pre-existing
498 : // MediaPipeline
499 0 : pipeline = nullptr;
500 0 : stream->RemoveTrack(aTrack.GetTrackId());
501 0 : stream->AddTrack(aTrack.GetTrackId(), domTrack);
502 : }
503 :
504 0 : if (pipeline) {
505 0 : pipeline->UpdateTransport_m(level, rtpFlow, rtcpFlow, filter);
506 0 : return NS_OK;
507 : }
508 :
509 0 : MOZ_MTLOG(ML_DEBUG,
510 : "Creating media pipeline"
511 : << " m-line index=" << aTrackPair.mLevel
512 : << " type=" << aTrack.GetMediaType()
513 : << " direction=" << aTrack.GetDirection());
514 :
515 0 : if (receiving) {
516 0 : rv = CreateMediaPipelineReceiving(aTrackPair, aTrack,
517 : level, rtpFlow, rtcpFlow, filter,
518 0 : conduit);
519 0 : if (NS_FAILED(rv))
520 0 : return rv;
521 : } else {
522 0 : rv = CreateMediaPipelineSending(aTrackPair, aTrack,
523 : level, rtpFlow, rtcpFlow, filter,
524 0 : conduit);
525 0 : if (NS_FAILED(rv))
526 0 : return rv;
527 : }
528 :
529 0 : return NS_OK;
530 : }
531 :
532 : nsresult
533 0 : MediaPipelineFactory::CreateMediaPipelineReceiving(
534 : const JsepTrackPair& aTrackPair,
535 : const JsepTrack& aTrack,
536 : size_t aLevel,
537 : RefPtr<TransportFlow> aRtpFlow,
538 : RefPtr<TransportFlow> aRtcpFlow,
539 : nsAutoPtr<MediaPipelineFilter> aFilter,
540 : const RefPtr<MediaSessionConduit>& aConduit)
541 : {
542 : // We will error out earlier if this isn't here.
543 : RefPtr<RemoteSourceStreamInfo> stream =
544 0 : mPCMedia->GetRemoteStreamById(aTrack.GetStreamId());
545 :
546 0 : RefPtr<MediaPipelineReceive> pipeline;
547 :
548 0 : TrackID numericTrackId = stream->GetNumericTrackId(aTrack.GetTrackId());
549 0 : MOZ_ASSERT(IsTrackIDExplicit(numericTrackId));
550 :
551 0 : MOZ_MTLOG(ML_DEBUG, __FUNCTION__ << ": Creating pipeline for "
552 : << numericTrackId << " -> " << aTrack.GetTrackId());
553 :
554 0 : if (aTrack.GetMediaType() == SdpMediaSection::kAudio) {
555 : pipeline = new MediaPipelineReceiveAudio(
556 0 : mPC->GetHandle(),
557 0 : mPC->GetMainThread().get(),
558 0 : mPC->GetSTSThread(),
559 0 : stream->GetMediaStream()->GetInputStream()->AsSourceStream(),
560 0 : aTrack.GetTrackId(),
561 : numericTrackId,
562 : aLevel,
563 0 : static_cast<AudioSessionConduit*>(aConduit.get()), // Ugly downcast.
564 : aRtpFlow,
565 : aRtcpFlow,
566 0 : aFilter);
567 0 : } else if (aTrack.GetMediaType() == SdpMediaSection::kVideo) {
568 : pipeline = new MediaPipelineReceiveVideo(
569 0 : mPC->GetHandle(),
570 0 : mPC->GetMainThread().get(),
571 0 : mPC->GetSTSThread(),
572 0 : stream->GetMediaStream()->GetInputStream()->AsSourceStream(),
573 0 : aTrack.GetTrackId(),
574 : numericTrackId,
575 : aLevel,
576 0 : static_cast<VideoSessionConduit*>(aConduit.get()), // Ugly downcast.
577 : aRtpFlow,
578 : aRtcpFlow,
579 0 : aFilter);
580 : } else {
581 0 : MOZ_ASSERT(false);
582 : MOZ_MTLOG(ML_ERROR, "Invalid media type in CreateMediaPipelineReceiving");
583 : return NS_ERROR_FAILURE;
584 : }
585 :
586 0 : nsresult rv = pipeline->Init();
587 0 : if (NS_FAILED(rv)) {
588 0 : MOZ_MTLOG(ML_ERROR, "Couldn't initialize receiving pipeline");
589 0 : return rv;
590 : }
591 :
592 0 : rv = stream->StorePipeline(aTrack.GetTrackId(),
593 0 : RefPtr<MediaPipeline>(pipeline));
594 0 : if (NS_FAILED(rv)) {
595 0 : MOZ_MTLOG(ML_ERROR, "Couldn't store receiving pipeline " <<
596 : static_cast<unsigned>(rv));
597 0 : return rv;
598 : }
599 :
600 0 : stream->SyncPipeline(pipeline);
601 :
602 0 : return NS_OK;
603 : }
604 :
605 : nsresult
606 0 : MediaPipelineFactory::CreateMediaPipelineSending(
607 : const JsepTrackPair& aTrackPair,
608 : const JsepTrack& aTrack,
609 : size_t aLevel,
610 : RefPtr<TransportFlow> aRtpFlow,
611 : RefPtr<TransportFlow> aRtcpFlow,
612 : nsAutoPtr<MediaPipelineFilter> aFilter,
613 : const RefPtr<MediaSessionConduit>& aConduit)
614 : {
615 : nsresult rv;
616 :
617 : // This is checked earlier
618 : RefPtr<LocalSourceStreamInfo> stream =
619 0 : mPCMedia->GetLocalStreamById(aTrack.GetStreamId());
620 :
621 : dom::MediaStreamTrack* track =
622 0 : stream->GetTrackById(aTrack.GetTrackId());
623 0 : MOZ_ASSERT(track);
624 :
625 : // Now we have all the pieces, create the pipeline
626 : RefPtr<MediaPipelineTransmit> pipeline = new MediaPipelineTransmit(
627 0 : mPC->GetHandle(),
628 0 : mPC->GetMainThread().get(),
629 0 : mPC->GetSTSThread(),
630 : track,
631 0 : aTrack.GetTrackId(),
632 : aLevel,
633 : aConduit,
634 : aRtpFlow,
635 : aRtcpFlow,
636 0 : aFilter);
637 :
638 : // implement checking for peerIdentity (where failure == black/silence)
639 0 : nsIDocument* doc = mPC->GetWindow()->GetExtantDoc();
640 0 : if (doc) {
641 0 : pipeline->UpdateSinkIdentity_m(track,
642 : doc->NodePrincipal(),
643 0 : mPC->GetPeerIdentity());
644 : } else {
645 0 : MOZ_MTLOG(ML_ERROR, "Cannot initialize pipeline without attached doc");
646 0 : return NS_ERROR_FAILURE; // Don't remove this till we know it's safe.
647 : }
648 :
649 0 : rv = pipeline->Init();
650 0 : if (NS_FAILED(rv)) {
651 0 : MOZ_MTLOG(ML_ERROR, "Couldn't initialize sending pipeline");
652 0 : return rv;
653 : }
654 :
655 0 : rv = stream->StorePipeline(aTrack.GetTrackId(),
656 0 : RefPtr<MediaPipeline>(pipeline));
657 0 : if (NS_FAILED(rv)) {
658 0 : MOZ_MTLOG(ML_ERROR, "Couldn't store receiving pipeline " <<
659 : static_cast<unsigned>(rv));
660 0 : return rv;
661 : }
662 :
663 0 : return NS_OK;
664 : }
665 :
666 : nsresult
667 0 : MediaPipelineFactory::GetOrCreateAudioConduit(
668 : const JsepTrackPair& aTrackPair,
669 : const JsepTrack& aTrack,
670 : RefPtr<MediaSessionConduit>* aConduitp)
671 : {
672 :
673 0 : if (!aTrack.GetNegotiatedDetails()) {
674 0 : MOZ_ASSERT(false, "Track is missing negotiated details");
675 : return NS_ERROR_INVALID_ARG;
676 : }
677 :
678 0 : bool receiving = aTrack.GetDirection() == sdp::kRecv;
679 :
680 : RefPtr<AudioSessionConduit> conduit =
681 0 : mPCMedia->GetAudioConduit(aTrackPair.mLevel);
682 :
683 0 : if (!conduit) {
684 0 : conduit = AudioSessionConduit::Create();
685 0 : if (!conduit) {
686 0 : MOZ_MTLOG(ML_ERROR, "Could not create audio conduit");
687 0 : return NS_ERROR_FAILURE;
688 : }
689 :
690 0 : mPCMedia->AddAudioConduit(aTrackPair.mLevel, conduit);
691 : }
692 :
693 0 : PtrVector<AudioCodecConfig> configs;
694 : nsresult rv = NegotiatedDetailsToAudioCodecConfigs(
695 0 : *aTrack.GetNegotiatedDetails(), &configs);
696 :
697 0 : if (NS_FAILED(rv)) {
698 0 : MOZ_MTLOG(ML_ERROR, "Failed to convert JsepCodecDescriptions to "
699 : "AudioCodecConfigs.");
700 0 : return rv;
701 : }
702 :
703 0 : if (configs.values.empty()) {
704 0 : MOZ_MTLOG(ML_ERROR, "Can't set up a conduit with 0 codecs");
705 0 : return NS_ERROR_FAILURE;
706 : }
707 :
708 0 : if (receiving) {
709 0 : auto error = conduit->ConfigureRecvMediaCodecs(configs.values);
710 :
711 0 : if (error) {
712 0 : MOZ_MTLOG(ML_ERROR, "ConfigureRecvMediaCodecs failed: " << error);
713 0 : return NS_ERROR_FAILURE;
714 : }
715 :
716 0 : if (!aTrackPair.mSending) {
717 : // No send track, but we still need to configure an SSRC for receiver
718 : // reports.
719 0 : if (!conduit->SetLocalSSRCs(std::vector<unsigned int>(1,aTrackPair.mRecvonlySsrc))) {
720 0 : MOZ_MTLOG(ML_ERROR, "SetLocalSSRC failed");
721 0 : return NS_ERROR_FAILURE;
722 : }
723 : }
724 : } else {
725 0 : auto ssrcs = aTrack.GetSsrcs();
726 0 : if (!ssrcs.empty()) {
727 0 : if (!conduit->SetLocalSSRCs(ssrcs)) {
728 0 : MOZ_MTLOG(ML_ERROR, "SetLocalSSRCs failed");
729 0 : return NS_ERROR_FAILURE;
730 : }
731 : }
732 :
733 0 : conduit->SetLocalCNAME(aTrack.GetCNAME().c_str());
734 :
735 0 : if (configs.values.size() > 1
736 0 : && configs.values.back()->mName == "telephone-event") {
737 : // we have a telephone event codec, so we need to make sure
738 : // the dynamic pt is set properly
739 0 : conduit->SetDtmfPayloadType(configs.values.back()->mType,
740 0 : configs.values.back()->mFreq);
741 : }
742 :
743 0 : auto error = conduit->ConfigureSendMediaCodec(configs.values[0]);
744 0 : if (error) {
745 0 : MOZ_MTLOG(ML_ERROR, "ConfigureSendMediaCodec failed: " << error);
746 0 : return NS_ERROR_FAILURE;
747 : }
748 :
749 : const SdpExtmapAttributeList::Extmap* audioLevelExt =
750 0 : aTrack.GetNegotiatedDetails()->GetExt(
751 0 : "urn:ietf:params:rtp-hdrext:ssrc-audio-level");
752 :
753 0 : if (audioLevelExt) {
754 0 : MOZ_MTLOG(ML_DEBUG, "Calling EnableAudioLevelExtension");
755 0 : error = conduit->EnableAudioLevelExtension(true, audioLevelExt->entry);
756 :
757 0 : if (error) {
758 0 : MOZ_MTLOG(ML_ERROR, "EnableAudioLevelExtension failed: " << error);
759 0 : return NS_ERROR_FAILURE;
760 : }
761 : }
762 : }
763 :
764 0 : *aConduitp = conduit;
765 :
766 0 : return NS_OK;
767 : }
768 :
769 : nsresult
770 0 : MediaPipelineFactory::GetOrCreateVideoConduit(
771 : const JsepTrackPair& aTrackPair,
772 : const JsepTrack& aTrack,
773 : RefPtr<MediaSessionConduit>* aConduitp)
774 : {
775 0 : if (!aTrack.GetNegotiatedDetails()) {
776 0 : MOZ_ASSERT(false, "Track is missing negotiated details");
777 : return NS_ERROR_INVALID_ARG;
778 : }
779 :
780 0 : bool receiving = aTrack.GetDirection() == sdp::kRecv;
781 :
782 : RefPtr<VideoSessionConduit> conduit =
783 0 : mPCMedia->GetVideoConduit(aTrackPair.mLevel);
784 :
785 0 : if (!conduit) {
786 0 : conduit = VideoSessionConduit::Create(mPCMedia->mCall);
787 0 : if (!conduit) {
788 0 : MOZ_MTLOG(ML_ERROR, "Could not create video conduit");
789 0 : return NS_ERROR_FAILURE;
790 : }
791 :
792 0 : mPCMedia->AddVideoConduit(aTrackPair.mLevel, conduit);
793 : }
794 :
795 0 : PtrVector<VideoCodecConfig> configs;
796 : nsresult rv = NegotiatedDetailsToVideoCodecConfigs(
797 0 : *aTrack.GetNegotiatedDetails(), &configs);
798 :
799 0 : if (NS_FAILED(rv)) {
800 0 : MOZ_MTLOG(ML_ERROR, "Failed to convert JsepCodecDescriptions to "
801 : "VideoCodecConfigs.");
802 0 : return rv;
803 : }
804 :
805 0 : if (configs.values.empty()) {
806 0 : MOZ_MTLOG(ML_ERROR, "Can't set up a conduit with 0 codecs");
807 0 : return NS_ERROR_FAILURE;
808 : }
809 :
810 : const std::vector<uint32_t>* ssrcs;
811 :
812 0 : const JsepTrackNegotiatedDetails* details = aTrack.GetNegotiatedDetails();
813 0 : std::vector<webrtc::RtpExtension> extmaps;
814 0 : if (details) {
815 : // @@NG read extmap from track
816 0 : details->ForEachRTPHeaderExtension(
817 0 : [&extmaps](const SdpExtmapAttributeList::Extmap& extmap)
818 0 : {
819 0 : extmaps.emplace_back(extmap.extensionname,extmap.entry);
820 0 : });
821 : }
822 :
823 0 : if (receiving) {
824 : // NOTE(pkerr) - the Call API requires the both local_ssrc and remote_ssrc be
825 : // set to a non-zero value or the CreateVideo...Stream call will fail.
826 0 : if (aTrackPair.mSending) {
827 0 : ssrcs = &aTrackPair.mSending->GetSsrcs();
828 0 : if (!ssrcs->empty()) {
829 0 : conduit->SetLocalSSRCs(*ssrcs);
830 : }
831 : } else {
832 : // No send track, but we still need to configure an SSRC for receiver
833 : // reports.
834 0 : if (!conduit->SetLocalSSRCs(std::vector<unsigned int>(1,aTrackPair.mRecvonlySsrc))) {
835 0 : MOZ_MTLOG(ML_ERROR, "SetLocalSSRCs failed");
836 0 : return NS_ERROR_FAILURE;
837 : }
838 : }
839 :
840 0 : ssrcs = &aTrack.GetSsrcs();
841 : // NOTE(pkerr) - this is new behavior. Needed because the CreateVideoReceiveStream
842 : // method of the Call API will assert (in debug) and fail if a value is not provided
843 : // for the remote_ssrc that will be used by the far-end sender.
844 0 : if (!ssrcs->empty()) {
845 0 : conduit->SetRemoteSSRC(ssrcs->front());
846 : }
847 :
848 0 : if (!extmaps.empty()) {
849 0 : conduit->SetLocalRTPExtensions(false, extmaps);
850 : }
851 0 : auto error = conduit->ConfigureRecvMediaCodecs(configs.values);
852 0 : if (error) {
853 0 : MOZ_MTLOG(ML_ERROR, "ConfigureRecvMediaCodecs failed: " << error);
854 0 : return NS_ERROR_FAILURE;
855 : }
856 : } else { //Create a send side
857 : // For now we only expect to have one ssrc per local track.
858 0 : ssrcs = &aTrack.GetSsrcs();
859 0 : if (ssrcs->empty()) {
860 0 : MOZ_MTLOG(ML_ERROR, "No SSRC set for send track");
861 0 : return NS_ERROR_FAILURE;
862 : }
863 :
864 0 : if (!conduit->SetLocalSSRCs(*ssrcs)) {
865 0 : MOZ_MTLOG(ML_ERROR, "SetLocalSSRC failed");
866 0 : return NS_ERROR_FAILURE;
867 : }
868 :
869 0 : conduit->SetLocalCNAME(aTrack.GetCNAME().c_str());
870 :
871 0 : rv = ConfigureVideoCodecMode(aTrack, *conduit);
872 0 : if (NS_FAILED(rv)) {
873 0 : return rv;
874 : }
875 :
876 0 : if (!extmaps.empty()) {
877 0 : conduit->SetLocalRTPExtensions(true, extmaps);
878 : }
879 0 : auto error = conduit->ConfigureSendMediaCodec(configs.values[0]);
880 0 : if (error) {
881 0 : MOZ_MTLOG(ML_ERROR, "ConfigureSendMediaCodec failed: " << error);
882 0 : return NS_ERROR_FAILURE;
883 : }
884 : }
885 :
886 0 : *aConduitp = conduit;
887 :
888 0 : return NS_OK;
889 : }
890 :
891 : nsresult
892 0 : MediaPipelineFactory::ConfigureVideoCodecMode(const JsepTrack& aTrack,
893 : VideoSessionConduit& aConduit)
894 : {
895 : RefPtr<LocalSourceStreamInfo> stream =
896 0 : mPCMedia->GetLocalStreamByTrackId(aTrack.GetTrackId());
897 :
898 : //get video track
899 : RefPtr<mozilla::dom::MediaStreamTrack> track =
900 0 : stream->GetTrackById(aTrack.GetTrackId());
901 :
902 : RefPtr<mozilla::dom::VideoStreamTrack> videotrack =
903 0 : track->AsVideoStreamTrack();
904 :
905 0 : if (!videotrack) {
906 0 : MOZ_MTLOG(ML_ERROR, "video track not available");
907 0 : return NS_ERROR_FAILURE;
908 : }
909 :
910 0 : dom::MediaSourceEnum source = videotrack->GetSource().GetMediaSource();
911 0 : webrtc::VideoCodecMode mode = webrtc::kRealtimeVideo;
912 0 : switch (source) {
913 : case dom::MediaSourceEnum::Browser:
914 : case dom::MediaSourceEnum::Screen:
915 : case dom::MediaSourceEnum::Application:
916 : case dom::MediaSourceEnum::Window:
917 0 : mode = webrtc::kScreensharing;
918 0 : break;
919 :
920 : case dom::MediaSourceEnum::Camera:
921 : default:
922 0 : mode = webrtc::kRealtimeVideo;
923 0 : break;
924 : }
925 :
926 0 : auto error = aConduit.ConfigureCodecMode(mode);
927 0 : if (error) {
928 0 : MOZ_MTLOG(ML_ERROR, "ConfigureCodecMode failed: " << error);
929 0 : return NS_ERROR_FAILURE;
930 : }
931 :
932 0 : return NS_OK;
933 : }
934 :
935 :
936 9 : } // namespace mozilla
|