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 <ostream>
6 : #include <string>
7 : #include <vector>
8 :
9 : #include "CSFLog.h"
10 :
11 : #include "nspr.h"
12 :
13 : #include "nricectx.h"
14 : #include "nricemediastream.h"
15 : #include "MediaPipelineFactory.h"
16 : #include "PeerConnectionImpl.h"
17 : #include "PeerConnectionMedia.h"
18 : #include "AudioConduit.h"
19 : #include "VideoConduit.h"
20 : #include "runnable_utils.h"
21 : #include "transportlayerice.h"
22 : #include "transportlayerdtls.h"
23 : #include "signaling/src/jsep/JsepSession.h"
24 : #include "signaling/src/jsep/JsepTransport.h"
25 :
26 : #include "MediaSegment.h"
27 : #include "MediaStreamGraph.h"
28 :
29 : #include "MediaStreamGraphImpl.h"
30 :
31 : #include "nsNetCID.h"
32 : #include "nsNetUtil.h"
33 : #include "nsIURI.h"
34 : #include "nsIScriptSecurityManager.h"
35 : #include "nsICancelable.h"
36 : #include "nsILoadInfo.h"
37 : #include "nsIContentPolicy.h"
38 : #include "nsIProxyInfo.h"
39 : #include "nsIProtocolProxyService.h"
40 :
41 : #include "nsProxyRelease.h"
42 :
43 : #include "MediaStreamList.h"
44 : #include "nsIScriptGlobalObject.h"
45 : #include "mozilla/Preferences.h"
46 : #include "mozilla/Telemetry.h"
47 : #include "mozilla/dom/RTCStatsReportBinding.h"
48 : #include "MediaStreamTrack.h"
49 : #include "VideoStreamTrack.h"
50 : #include "MediaStreamError.h"
51 : #include "MediaManager.h"
52 :
53 :
54 :
55 : namespace mozilla {
56 : using namespace dom;
57 :
58 : static const char* logTag = "PeerConnectionMedia";
59 :
60 : //XXX(pkerr) What about bitrate settings? Going with the defaults for now.
61 : RefPtr<WebRtcCallWrapper>
62 0 : CreateCall()
63 : {
64 0 : return WebRtcCallWrapper::Create();
65 : }
66 :
67 : nsresult
68 0 : PeerConnectionMedia::ReplaceTrack(const std::string& aOldStreamId,
69 : const std::string& aOldTrackId,
70 : MediaStreamTrack& aNewTrack,
71 : const std::string& aNewStreamId,
72 : const std::string& aNewTrackId)
73 : {
74 0 : RefPtr<LocalSourceStreamInfo> oldInfo(GetLocalStreamById(aOldStreamId));
75 :
76 0 : if (!oldInfo) {
77 0 : CSFLogError(logTag, "Failed to find stream id %s", aOldStreamId.c_str());
78 0 : return NS_ERROR_NOT_AVAILABLE;
79 : }
80 :
81 0 : nsresult rv = AddTrack(*aNewTrack.mOwningStream, aNewStreamId,
82 0 : aNewTrack, aNewTrackId);
83 0 : NS_ENSURE_SUCCESS(rv, rv);
84 :
85 0 : RefPtr<LocalSourceStreamInfo> newInfo(GetLocalStreamById(aNewStreamId));
86 :
87 0 : if (!newInfo) {
88 0 : CSFLogError(logTag, "Failed to add track id %s", aNewTrackId.c_str());
89 0 : MOZ_ASSERT(false);
90 : return NS_ERROR_FAILURE;
91 : }
92 :
93 0 : rv = newInfo->TakePipelineFrom(oldInfo, aOldTrackId, aNewTrack, aNewTrackId);
94 0 : NS_ENSURE_SUCCESS(rv, rv);
95 :
96 0 : return RemoveLocalTrack(aOldStreamId, aOldTrackId);
97 : }
98 :
99 : static void
100 0 : PipelineReleaseRef_m(RefPtr<MediaPipeline> pipeline)
101 0 : {}
102 :
103 : static void
104 0 : PipelineDetachTransport_s(RefPtr<MediaPipeline> pipeline,
105 : nsCOMPtr<nsIThread> mainThread)
106 : {
107 0 : pipeline->DetachTransport_s();
108 0 : mainThread->Dispatch(
109 : // Make sure we let go of our reference before dispatching
110 : // If the dispatch fails, well, we're hosed anyway.
111 0 : WrapRunnableNM(PipelineReleaseRef_m, pipeline.forget()),
112 0 : NS_DISPATCH_NORMAL);
113 0 : }
114 :
115 : void
116 0 : SourceStreamInfo::EndTrack(MediaStream* stream, dom::MediaStreamTrack* track)
117 : {
118 0 : if (!stream || !stream->AsSourceStream()) {
119 0 : return;
120 : }
121 :
122 0 : class Message : public ControlMessage {
123 : public:
124 0 : Message(MediaStream* stream, TrackID track)
125 0 : : ControlMessage(stream),
126 0 : track_id_(track) {}
127 :
128 0 : virtual void Run() override {
129 0 : mStream->AsSourceStream()->EndTrack(track_id_);
130 0 : }
131 : private:
132 : TrackID track_id_;
133 : };
134 :
135 0 : stream->GraphImpl()->AppendMessage(
136 0 : MakeUnique<Message>(stream, track->mTrackID));
137 : }
138 :
139 : void
140 0 : SourceStreamInfo::RemoveTrack(const std::string& trackId)
141 : {
142 0 : mTracks.erase(trackId);
143 :
144 0 : RefPtr<MediaPipeline> pipeline = GetPipelineByTrackId_m(trackId);
145 0 : if (pipeline) {
146 0 : mPipelines.erase(trackId);
147 0 : pipeline->ShutdownMedia_m();
148 0 : mParent->GetSTSThread()->Dispatch(
149 0 : WrapRunnableNM(PipelineDetachTransport_s,
150 0 : pipeline.forget(),
151 0 : mParent->GetMainThread()),
152 0 : NS_DISPATCH_NORMAL);
153 : }
154 0 : }
155 :
156 0 : void SourceStreamInfo::DetachTransport_s()
157 : {
158 0 : ASSERT_ON_THREAD(mParent->GetSTSThread());
159 : // walk through all the MediaPipelines and call the shutdown
160 : // transport functions. Must be on the STS thread.
161 0 : for (auto& pipeline : mPipelines) {
162 0 : pipeline.second->DetachTransport_s();
163 : }
164 0 : }
165 :
166 0 : void SourceStreamInfo::DetachMedia_m()
167 : {
168 0 : ASSERT_ON_THREAD(mParent->GetMainThread());
169 :
170 : // walk through all the MediaPipelines and call the shutdown
171 : // media functions. Must be on the main thread.
172 0 : for (auto& pipeline : mPipelines) {
173 0 : pipeline.second->ShutdownMedia_m();
174 : }
175 0 : mMediaStream = nullptr;
176 0 : }
177 :
178 : already_AddRefed<PeerConnectionImpl>
179 0 : PeerConnectionImpl::Constructor(const dom::GlobalObject& aGlobal, ErrorResult& rv)
180 : {
181 0 : RefPtr<PeerConnectionImpl> pc = new PeerConnectionImpl(&aGlobal);
182 :
183 0 : CSFLogDebug(logTag, "Created PeerConnection: %p", pc.get());
184 :
185 0 : return pc.forget();
186 : }
187 :
188 0 : PeerConnectionImpl* PeerConnectionImpl::CreatePeerConnection()
189 : {
190 0 : PeerConnectionImpl *pc = new PeerConnectionImpl();
191 :
192 0 : CSFLogDebug(logTag, "Created PeerConnection: %p", pc);
193 :
194 0 : return pc;
195 : }
196 :
197 0 : NS_IMETHODIMP PeerConnectionMedia::ProtocolProxyQueryHandler::
198 : OnProxyAvailable(nsICancelable *request,
199 : nsIChannel *aChannel,
200 : nsIProxyInfo *proxyinfo,
201 : nsresult result) {
202 :
203 0 : if (!pcm_->mProxyRequest) {
204 : // PeerConnectionMedia is no longer waiting
205 0 : return NS_OK;
206 : }
207 :
208 0 : CSFLogInfo(logTag, "%s: Proxy Available: %d", __FUNCTION__, (int)result);
209 :
210 0 : if (NS_SUCCEEDED(result) && proxyinfo) {
211 0 : SetProxyOnPcm(*proxyinfo);
212 : }
213 :
214 0 : pcm_->mProxyResolveCompleted = true;
215 0 : pcm_->mProxyRequest = nullptr;
216 0 : pcm_->FlushIceCtxOperationQueueIfReady();
217 :
218 0 : return NS_OK;
219 : }
220 :
221 : void
222 0 : PeerConnectionMedia::ProtocolProxyQueryHandler::SetProxyOnPcm(
223 : nsIProxyInfo& proxyinfo)
224 : {
225 0 : CSFLogInfo(logTag, "%s: Had proxyinfo", __FUNCTION__);
226 : nsresult rv;
227 0 : nsCString httpsProxyHost;
228 : int32_t httpsProxyPort;
229 :
230 0 : rv = proxyinfo.GetHost(httpsProxyHost);
231 0 : if (NS_FAILED(rv)) {
232 0 : CSFLogError(logTag, "%s: Failed to get proxy server host", __FUNCTION__);
233 0 : return;
234 : }
235 :
236 0 : rv = proxyinfo.GetPort(&httpsProxyPort);
237 0 : if (NS_FAILED(rv)) {
238 0 : CSFLogError(logTag, "%s: Failed to get proxy server port", __FUNCTION__);
239 0 : return;
240 : }
241 :
242 0 : if (pcm_->mIceCtxHdlr.get()) {
243 0 : assert(httpsProxyPort >= 0 && httpsProxyPort < (1 << 16));
244 : // Note that this could check if PrivacyRequested() is set on the PC and
245 : // remove "webrtc" from the ALPN list. But that would only work if the PC
246 : // was constructed with a peerIdentity constraint, not when isolated
247 : // streams are added. If we ever need to signal to the proxy that the
248 : // media is isolated, then we would need to restructure this code.
249 0 : pcm_->mProxyServer.reset(
250 : new NrIceProxyServer(httpsProxyHost.get(),
251 : static_cast<uint16_t>(httpsProxyPort),
252 0 : "webrtc,c-webrtc"));
253 : } else {
254 : CSFLogError(logTag, "%s: Failed to set proxy server (ICE ctx unavailable)",
255 0 : __FUNCTION__);
256 : }
257 : }
258 :
259 0 : NS_IMPL_ISUPPORTS(PeerConnectionMedia::ProtocolProxyQueryHandler, nsIProtocolProxyCallback)
260 :
261 : void
262 0 : PeerConnectionMedia::StunAddrsHandler::OnStunAddrsAvailable(
263 : const mozilla::net::NrIceStunAddrArray& addrs)
264 : {
265 0 : CSFLogInfo(logTag, "%s: receiving (%d) stun addrs", __FUNCTION__,
266 0 : (int)addrs.Length());
267 0 : if (pcm_) {
268 0 : pcm_->mStunAddrs = addrs;
269 0 : pcm_->mLocalAddrsCompleted = true;
270 0 : pcm_->mStunAddrsRequest = nullptr;
271 0 : pcm_->FlushIceCtxOperationQueueIfReady();
272 0 : pcm_ = nullptr;
273 : }
274 0 : }
275 :
276 0 : PeerConnectionMedia::PeerConnectionMedia(PeerConnectionImpl *parent)
277 : : mParent(parent),
278 0 : mParentHandle(parent->GetHandle()),
279 0 : mParentName(parent->GetName()),
280 : mIceCtxHdlr(nullptr),
281 0 : mDNSResolver(new NrIceResolver()),
282 : mUuidGen(MakeUnique<PCUuidGenerator>()),
283 0 : mMainThread(mParent->GetMainThread()),
284 0 : mSTSThread(mParent->GetSTSThread()),
285 : mProxyResolveCompleted(false),
286 : mIceRestartState(ICE_RESTART_NONE),
287 0 : mLocalAddrsCompleted(false) {
288 0 : }
289 :
290 : void
291 0 : PeerConnectionMedia::InitLocalAddrs()
292 : {
293 0 : if (XRE_IsContentProcess()) {
294 0 : CSFLogDebug(logTag, "%s: Get stun addresses via IPC",
295 0 : mParentHandle.c_str());
296 :
297 0 : nsCOMPtr<nsIEventTarget> target = mParent->GetWindow()
298 0 : ? mParent->GetWindow()->EventTargetFor(TaskCategory::Other)
299 0 : : nullptr;
300 :
301 : // We're in the content process, so send a request over IPC for the
302 : // stun address discovery.
303 : mStunAddrsRequest =
304 0 : new StunAddrsRequestChild(new StunAddrsHandler(this), target);
305 0 : mStunAddrsRequest->SendGetStunAddrs();
306 : } else {
307 : // No content process, so don't need to hold up the ice event queue
308 : // until completion of stun address discovery. We can let the
309 : // discovery of stun addresses happen in the same process.
310 0 : mLocalAddrsCompleted = true;
311 : }
312 0 : }
313 :
314 : nsresult
315 0 : PeerConnectionMedia::InitProxy()
316 : {
317 : // Allow mochitests to disable this, since mochitest configures a fake proxy
318 : // that serves up content.
319 : bool disable = Preferences::GetBool("media.peerconnection.disable_http_proxy",
320 0 : false);
321 0 : if (disable) {
322 0 : mProxyResolveCompleted = true;
323 0 : return NS_OK;
324 : }
325 :
326 : nsresult rv;
327 : nsCOMPtr<nsIProtocolProxyService> pps =
328 0 : do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID, &rv);
329 0 : if (NS_FAILED(rv)) {
330 0 : CSFLogError(logTag, "%s: Failed to get proxy service: %d", __FUNCTION__, (int)rv);
331 0 : return NS_ERROR_FAILURE;
332 : }
333 :
334 : // We use the following URL to find the "default" proxy address for all HTTPS
335 : // connections. We will only attempt one HTTP(S) CONNECT per peer connection.
336 : // "example.com" is guaranteed to be unallocated and should return the best default.
337 0 : nsCOMPtr<nsIURI> fakeHttpsLocation;
338 0 : rv = NS_NewURI(getter_AddRefs(fakeHttpsLocation), "https://example.com");
339 0 : if (NS_FAILED(rv)) {
340 0 : CSFLogError(logTag, "%s: Failed to set URI: %d", __FUNCTION__, (int)rv);
341 0 : return NS_ERROR_FAILURE;
342 : }
343 :
344 : nsCOMPtr<nsIScriptSecurityManager> secMan(
345 0 : do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv));
346 0 : if (NS_FAILED(rv)) {
347 0 : CSFLogError(logTag, "%s: Failed to get IOService: %d",
348 0 : __FUNCTION__, (int)rv);
349 0 : CSFLogError(logTag, "%s: Failed to get securityManager: %d", __FUNCTION__, (int)rv);
350 0 : return NS_ERROR_FAILURE;
351 : }
352 :
353 0 : nsCOMPtr<nsIPrincipal> systemPrincipal;
354 0 : rv = secMan->GetSystemPrincipal(getter_AddRefs(systemPrincipal));
355 0 : if (NS_FAILED(rv)) {
356 0 : CSFLogError(logTag, "%s: Failed to get systemPrincipal: %d", __FUNCTION__, (int)rv);
357 0 : return NS_ERROR_FAILURE;
358 : }
359 :
360 0 : nsCOMPtr<nsIChannel> channel;
361 0 : rv = NS_NewChannel(getter_AddRefs(channel),
362 : fakeHttpsLocation,
363 : systemPrincipal,
364 : nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
365 : nsIContentPolicy::TYPE_OTHER);
366 :
367 0 : if (NS_FAILED(rv)) {
368 0 : CSFLogError(logTag, "%s: Failed to get channel from URI: %d",
369 0 : __FUNCTION__, (int)rv);
370 0 : return NS_ERROR_FAILURE;
371 : }
372 :
373 0 : nsCOMPtr<nsIEventTarget> target = mParent->GetWindow()
374 0 : ? mParent->GetWindow()->EventTargetFor(TaskCategory::Network)
375 0 : : nullptr;
376 0 : RefPtr<ProtocolProxyQueryHandler> handler = new ProtocolProxyQueryHandler(this);
377 0 : rv = pps->AsyncResolve(channel,
378 : nsIProtocolProxyService::RESOLVE_PREFER_HTTPS_PROXY |
379 : nsIProtocolProxyService::RESOLVE_ALWAYS_TUNNEL,
380 0 : handler, target, getter_AddRefs(mProxyRequest));
381 0 : if (NS_FAILED(rv)) {
382 0 : CSFLogError(logTag, "%s: Failed to resolve protocol proxy: %d", __FUNCTION__, (int)rv);
383 0 : return NS_ERROR_FAILURE;
384 : }
385 :
386 0 : return NS_OK;
387 : }
388 :
389 0 : nsresult PeerConnectionMedia::Init(const std::vector<NrIceStunServer>& stun_servers,
390 : const std::vector<NrIceTurnServer>& turn_servers,
391 : NrIceCtx::Policy policy)
392 : {
393 0 : nsresult rv = InitProxy();
394 0 : NS_ENSURE_SUCCESS(rv, rv);
395 :
396 0 : bool ice_tcp = Preferences::GetBool("media.peerconnection.ice.tcp", false);
397 :
398 : // setup the stun local addresses IPC async call
399 0 : InitLocalAddrs();
400 :
401 : // TODO(ekr@rtfm.com): need some way to set not offerer later
402 : // Looks like a bug in the NrIceCtx API.
403 0 : mIceCtxHdlr = NrIceCtxHandler::Create("PC:" + mParentName,
404 0 : mParent->GetAllowIceLoopback(),
405 : ice_tcp,
406 0 : mParent->GetAllowIceLinkLocal(),
407 0 : policy);
408 0 : if(!mIceCtxHdlr) {
409 0 : CSFLogError(logTag, "%s: Failed to create Ice Context", __FUNCTION__);
410 0 : return NS_ERROR_FAILURE;
411 : }
412 :
413 0 : if (NS_FAILED(rv = mIceCtxHdlr->ctx()->SetStunServers(stun_servers))) {
414 0 : CSFLogError(logTag, "%s: Failed to set stun servers", __FUNCTION__);
415 0 : return rv;
416 : }
417 : // Give us a way to globally turn off TURN support
418 0 : bool disabled = Preferences::GetBool("media.peerconnection.turn.disable", false);
419 0 : if (!disabled) {
420 0 : if (NS_FAILED(rv = mIceCtxHdlr->ctx()->SetTurnServers(turn_servers))) {
421 0 : CSFLogError(logTag, "%s: Failed to set turn servers", __FUNCTION__);
422 0 : return rv;
423 : }
424 0 : } else if (turn_servers.size() != 0) {
425 0 : CSFLogError(logTag, "%s: Setting turn servers disabled", __FUNCTION__);
426 : }
427 0 : if (NS_FAILED(rv = mDNSResolver->Init())) {
428 0 : CSFLogError(logTag, "%s: Failed to initialize dns resolver", __FUNCTION__);
429 0 : return rv;
430 : }
431 0 : if (NS_FAILED(rv =
432 : mIceCtxHdlr->ctx()->SetResolver(mDNSResolver->AllocateResolver()))) {
433 0 : CSFLogError(logTag, "%s: Failed to get dns resolver", __FUNCTION__);
434 0 : return rv;
435 : }
436 0 : ConnectSignals(mIceCtxHdlr->ctx().get());
437 :
438 : // This webrtc:Call instance will be shared by audio and video media conduits.
439 0 : mCall = CreateCall();
440 :
441 0 : return NS_OK;
442 : }
443 :
444 : void
445 0 : PeerConnectionMedia::EnsureTransports(const JsepSession& aSession)
446 : {
447 0 : auto transports = aSession.GetTransports();
448 0 : for (size_t i = 0; i < transports.size(); ++i) {
449 0 : RefPtr<JsepTransport> transport = transports[i];
450 0 : RUN_ON_THREAD(
451 0 : GetSTSThread(),
452 0 : WrapRunnable(RefPtr<PeerConnectionMedia>(this),
453 : &PeerConnectionMedia::EnsureTransport_s,
454 : i,
455 0 : transport->mComponents),
456 0 : NS_DISPATCH_NORMAL);
457 : }
458 :
459 0 : GatherIfReady();
460 0 : }
461 :
462 : void
463 0 : PeerConnectionMedia::EnsureTransport_s(size_t aLevel, size_t aComponentCount)
464 : {
465 0 : RefPtr<NrIceMediaStream> stream(mIceCtxHdlr->ctx()->GetStream(aLevel));
466 0 : if (!stream) {
467 0 : CSFLogDebug(logTag, "%s: Creating ICE media stream=%u components=%u",
468 : mParentHandle.c_str(),
469 : static_cast<unsigned>(aLevel),
470 0 : static_cast<unsigned>(aComponentCount));
471 :
472 0 : std::ostringstream os;
473 0 : os << mParentName << " aLevel=" << aLevel;
474 : RefPtr<NrIceMediaStream> stream =
475 0 : mIceCtxHdlr->CreateStream(os.str(),
476 0 : aComponentCount);
477 :
478 0 : if (!stream) {
479 0 : CSFLogError(logTag, "Failed to create ICE stream.");
480 0 : return;
481 : }
482 :
483 0 : stream->SetLevel(aLevel);
484 0 : stream->SignalReady.connect(this, &PeerConnectionMedia::IceStreamReady_s);
485 0 : stream->SignalCandidate.connect(this,
486 0 : &PeerConnectionMedia::OnCandidateFound_s);
487 0 : mIceCtxHdlr->ctx()->SetStream(aLevel, stream);
488 : }
489 : }
490 :
491 : void
492 0 : PeerConnectionMedia::ActivateOrRemoveTransports(const JsepSession& aSession,
493 : const bool forceIceTcp)
494 : {
495 0 : auto transports = aSession.GetTransports();
496 0 : for (size_t i = 0; i < transports.size(); ++i) {
497 0 : RefPtr<JsepTransport> transport = transports[i];
498 :
499 0 : std::string ufrag;
500 0 : std::string pwd;
501 0 : std::vector<std::string> candidates;
502 :
503 0 : if (transport->mComponents) {
504 0 : MOZ_ASSERT(transport->mIce);
505 0 : CSFLogDebug(logTag, "Transport %u is active", static_cast<unsigned>(i));
506 0 : ufrag = transport->mIce->GetUfrag();
507 0 : pwd = transport->mIce->GetPassword();
508 0 : candidates = transport->mIce->GetCandidates();
509 : } else {
510 0 : CSFLogDebug(logTag, "Transport %u is disabled", static_cast<unsigned>(i));
511 : // Make sure the MediaPipelineFactory doesn't try to use these.
512 0 : RemoveTransportFlow(i, false);
513 0 : RemoveTransportFlow(i, true);
514 : }
515 :
516 0 : if (forceIceTcp) {
517 0 : candidates.erase(std::remove_if(candidates.begin(),
518 : candidates.end(),
519 0 : [](const std::string & s) {
520 0 : return s.find(" UDP ") != std::string::npos ||
521 0 : s.find(" udp ") != std::string::npos; }),
522 0 : candidates.end());
523 : }
524 :
525 0 : RUN_ON_THREAD(
526 0 : GetSTSThread(),
527 0 : WrapRunnable(RefPtr<PeerConnectionMedia>(this),
528 : &PeerConnectionMedia::ActivateOrRemoveTransport_s,
529 : i,
530 0 : transport->mComponents,
531 : ufrag,
532 : pwd,
533 : candidates),
534 0 : NS_DISPATCH_NORMAL);
535 : }
536 :
537 : // We can have more streams than m-lines due to rollback.
538 0 : RUN_ON_THREAD(
539 0 : GetSTSThread(),
540 0 : WrapRunnable(RefPtr<PeerConnectionMedia>(this),
541 : &PeerConnectionMedia::RemoveTransportsAtOrAfter_s,
542 : transports.size()),
543 0 : NS_DISPATCH_NORMAL);
544 0 : }
545 :
546 : void
547 0 : PeerConnectionMedia::ActivateOrRemoveTransport_s(
548 : size_t aMLine,
549 : size_t aComponentCount,
550 : const std::string& aUfrag,
551 : const std::string& aPassword,
552 : const std::vector<std::string>& aCandidateList) {
553 :
554 0 : if (!aComponentCount) {
555 0 : CSFLogDebug(logTag, "%s: Removing ICE media stream=%u",
556 : mParentHandle.c_str(),
557 0 : static_cast<unsigned>(aMLine));
558 0 : mIceCtxHdlr->ctx()->SetStream(aMLine, nullptr);
559 0 : return;
560 : }
561 :
562 0 : RefPtr<NrIceMediaStream> stream(mIceCtxHdlr->ctx()->GetStream(aMLine));
563 0 : if (!stream) {
564 0 : MOZ_ASSERT(false);
565 : return;
566 : }
567 :
568 0 : if (!stream->HasParsedAttributes()) {
569 0 : CSFLogDebug(logTag, "%s: Activating ICE media stream=%u components=%u",
570 : mParentHandle.c_str(),
571 : static_cast<unsigned>(aMLine),
572 0 : static_cast<unsigned>(aComponentCount));
573 :
574 0 : std::vector<std::string> attrs;
575 0 : for (const auto& candidate : aCandidateList) {
576 0 : attrs.push_back("candidate:" + candidate);
577 : }
578 0 : attrs.push_back("ice-ufrag:" + aUfrag);
579 0 : attrs.push_back("ice-pwd:" + aPassword);
580 :
581 0 : nsresult rv = stream->ParseAttributes(attrs);
582 0 : if (NS_FAILED(rv)) {
583 : CSFLogError(logTag, "Couldn't parse ICE attributes, rv=%u",
584 0 : static_cast<unsigned>(rv));
585 : }
586 :
587 0 : for (size_t c = aComponentCount; c < stream->components(); ++c) {
588 : // components are 1-indexed
589 0 : stream->DisableComponent(c + 1);
590 : }
591 : }
592 : }
593 :
594 : void
595 0 : PeerConnectionMedia::RemoveTransportsAtOrAfter_s(size_t aMLine)
596 : {
597 0 : for (size_t i = aMLine; i < mIceCtxHdlr->ctx()->GetStreamCount(); ++i) {
598 0 : mIceCtxHdlr->ctx()->SetStream(i, nullptr);
599 : }
600 0 : }
601 :
602 0 : nsresult PeerConnectionMedia::UpdateMediaPipelines(
603 : const JsepSession& session) {
604 0 : auto trackPairs = session.GetNegotiatedTrackPairs();
605 0 : MediaPipelineFactory factory(this);
606 : nsresult rv;
607 :
608 0 : for (auto pair : trackPairs) {
609 0 : if (pair.mReceiving) {
610 :
611 0 : rv = factory.CreateOrUpdateMediaPipeline(pair, *pair.mReceiving);
612 0 : if (NS_FAILED(rv)) {
613 0 : return rv;
614 : }
615 : }
616 :
617 0 : if (pair.mSending) {
618 0 : rv = factory.CreateOrUpdateMediaPipeline(pair, *pair.mSending);
619 0 : if (NS_FAILED(rv)) {
620 0 : return rv;
621 : }
622 : }
623 : }
624 :
625 0 : for (auto& stream : mRemoteSourceStreams) {
626 0 : stream->StartReceiving();
627 : }
628 :
629 0 : return NS_OK;
630 : }
631 :
632 : void
633 0 : PeerConnectionMedia::StartIceChecks(const JsepSession& aSession)
634 : {
635 : nsCOMPtr<nsIRunnable> runnable(
636 0 : WrapRunnable(
637 0 : RefPtr<PeerConnectionMedia>(this),
638 : &PeerConnectionMedia::StartIceChecks_s,
639 0 : aSession.IsIceControlling(),
640 0 : aSession.IsOfferer(),
641 0 : aSession.RemoteIsIceLite(),
642 : // Copy, just in case API changes to return a ref
643 0 : std::vector<std::string>(aSession.GetIceOptions())));
644 :
645 0 : PerformOrEnqueueIceCtxOperation(runnable);
646 0 : }
647 :
648 : void
649 0 : PeerConnectionMedia::StartIceChecks_s(
650 : bool aIsControlling,
651 : bool aIsOfferer,
652 : bool aIsIceLite,
653 : const std::vector<std::string>& aIceOptionsList) {
654 :
655 0 : CSFLogDebug(logTag, "Starting ICE Checking");
656 :
657 0 : std::vector<std::string> attributes;
658 0 : if (aIsIceLite) {
659 0 : attributes.push_back("ice-lite");
660 : }
661 :
662 0 : if (!aIceOptionsList.empty()) {
663 0 : attributes.push_back("ice-options:");
664 0 : for (const auto& option : aIceOptionsList) {
665 0 : attributes.back() += option + ' ';
666 : }
667 : }
668 :
669 0 : nsresult rv = mIceCtxHdlr->ctx()->ParseGlobalAttributes(attributes);
670 0 : if (NS_FAILED(rv)) {
671 0 : CSFLogError(logTag, "%s: couldn't parse global parameters", __FUNCTION__ );
672 : }
673 :
674 0 : mIceCtxHdlr->ctx()->SetControlling(aIsControlling ?
675 : NrIceCtx::ICE_CONTROLLING :
676 0 : NrIceCtx::ICE_CONTROLLED);
677 :
678 0 : mIceCtxHdlr->ctx()->StartChecks(aIsOfferer);
679 0 : }
680 :
681 : bool
682 0 : PeerConnectionMedia::IsIceRestarting() const
683 : {
684 0 : ASSERT_ON_THREAD(mMainThread);
685 :
686 0 : return (mIceRestartState != ICE_RESTART_NONE);
687 : }
688 :
689 : PeerConnectionMedia::IceRestartState
690 0 : PeerConnectionMedia::GetIceRestartState() const
691 : {
692 0 : ASSERT_ON_THREAD(mMainThread);
693 :
694 0 : return mIceRestartState;
695 : }
696 :
697 : void
698 0 : PeerConnectionMedia::BeginIceRestart(const std::string& ufrag,
699 : const std::string& pwd)
700 : {
701 0 : ASSERT_ON_THREAD(mMainThread);
702 0 : if (IsIceRestarting()) {
703 0 : return;
704 : }
705 :
706 0 : RefPtr<NrIceCtx> new_ctx = mIceCtxHdlr->CreateCtx(ufrag, pwd);
707 :
708 0 : RUN_ON_THREAD(GetSTSThread(),
709 0 : WrapRunnable(
710 0 : RefPtr<PeerConnectionMedia>(this),
711 : &PeerConnectionMedia::BeginIceRestart_s,
712 : new_ctx),
713 0 : NS_DISPATCH_NORMAL);
714 :
715 0 : mIceRestartState = ICE_RESTART_PROVISIONAL;
716 : }
717 :
718 : void
719 0 : PeerConnectionMedia::BeginIceRestart_s(RefPtr<NrIceCtx> new_ctx)
720 : {
721 0 : ASSERT_ON_THREAD(mSTSThread);
722 :
723 : // hold the original context so we can disconnect signals if needed
724 0 : RefPtr<NrIceCtx> originalCtx = mIceCtxHdlr->ctx();
725 :
726 0 : if (mIceCtxHdlr->BeginIceRestart(new_ctx)) {
727 0 : ConnectSignals(mIceCtxHdlr->ctx().get(), originalCtx.get());
728 : }
729 0 : }
730 :
731 : void
732 0 : PeerConnectionMedia::CommitIceRestart()
733 : {
734 0 : ASSERT_ON_THREAD(mMainThread);
735 0 : if (mIceRestartState != ICE_RESTART_PROVISIONAL) {
736 0 : return;
737 : }
738 :
739 0 : mIceRestartState = ICE_RESTART_COMMITTED;
740 : }
741 :
742 : void
743 0 : PeerConnectionMedia::FinalizeIceRestart()
744 : {
745 0 : ASSERT_ON_THREAD(mMainThread);
746 0 : if (!IsIceRestarting()) {
747 0 : return;
748 : }
749 :
750 0 : RUN_ON_THREAD(GetSTSThread(),
751 0 : WrapRunnable(
752 0 : RefPtr<PeerConnectionMedia>(this),
753 : &PeerConnectionMedia::FinalizeIceRestart_s),
754 0 : NS_DISPATCH_NORMAL);
755 :
756 0 : mIceRestartState = ICE_RESTART_NONE;
757 : }
758 :
759 : void
760 0 : PeerConnectionMedia::FinalizeIceRestart_s()
761 : {
762 0 : ASSERT_ON_THREAD(mSTSThread);
763 :
764 : // reset old streams since we don't need them anymore
765 0 : for (auto& transportFlow : mTransportFlows) {
766 0 : RefPtr<TransportFlow> aFlow = transportFlow.second;
767 0 : if (!aFlow) continue;
768 : TransportLayerIce* ice =
769 0 : static_cast<TransportLayerIce*>(aFlow->GetLayer(TransportLayerIce::ID()));
770 0 : ice->ResetOldStream();
771 : }
772 :
773 0 : mIceCtxHdlr->FinalizeIceRestart();
774 0 : }
775 :
776 : void
777 0 : PeerConnectionMedia::RollbackIceRestart()
778 : {
779 0 : ASSERT_ON_THREAD(mMainThread);
780 0 : if (mIceRestartState != ICE_RESTART_PROVISIONAL) {
781 0 : return;
782 : }
783 :
784 0 : RUN_ON_THREAD(GetSTSThread(),
785 0 : WrapRunnable(
786 0 : RefPtr<PeerConnectionMedia>(this),
787 : &PeerConnectionMedia::RollbackIceRestart_s),
788 0 : NS_DISPATCH_NORMAL);
789 :
790 0 : mIceRestartState = ICE_RESTART_NONE;
791 : }
792 :
793 : void
794 0 : PeerConnectionMedia::RollbackIceRestart_s()
795 : {
796 0 : ASSERT_ON_THREAD(mSTSThread);
797 :
798 : // hold the restart context so we can disconnect signals
799 0 : RefPtr<NrIceCtx> restartCtx = mIceCtxHdlr->ctx();
800 :
801 : // restore old streams since we're rolling back
802 0 : for (auto& transportFlow : mTransportFlows) {
803 0 : RefPtr<TransportFlow> aFlow = transportFlow.second;
804 0 : if (!aFlow) continue;
805 : TransportLayerIce* ice =
806 0 : static_cast<TransportLayerIce*>(aFlow->GetLayer(TransportLayerIce::ID()));
807 0 : ice->RestoreOldStream();
808 : }
809 :
810 0 : mIceCtxHdlr->RollbackIceRestart();
811 0 : ConnectSignals(mIceCtxHdlr->ctx().get(), restartCtx.get());
812 :
813 : // Fixup the telemetry by transferring abandoned ctx stats to current ctx.
814 0 : NrIceStats stats = restartCtx->Destroy();
815 0 : restartCtx = nullptr;
816 0 : mIceCtxHdlr->ctx()->AccumulateStats(stats);
817 0 : }
818 :
819 : bool
820 0 : PeerConnectionMedia::GetPrefDefaultAddressOnly() const
821 : {
822 0 : ASSERT_ON_THREAD(mMainThread); // will crash on STS thread
823 :
824 0 : uint64_t winId = mParent->GetWindow()->WindowID();
825 :
826 : bool default_address_only = Preferences::GetBool(
827 0 : "media.peerconnection.ice.default_address_only", false);
828 0 : default_address_only |=
829 0 : !MediaManager::Get()->IsActivelyCapturingOrHasAPermission(winId);
830 0 : return default_address_only;
831 : }
832 :
833 : bool
834 0 : PeerConnectionMedia::GetPrefProxyOnly() const
835 : {
836 0 : ASSERT_ON_THREAD(mMainThread); // will crash on STS thread
837 :
838 0 : return Preferences::GetBool("media.peerconnection.ice.proxy_only", false);
839 : }
840 :
841 : void
842 0 : PeerConnectionMedia::ConnectSignals(NrIceCtx *aCtx, NrIceCtx *aOldCtx)
843 : {
844 0 : aCtx->SignalGatheringStateChange.connect(
845 : this,
846 0 : &PeerConnectionMedia::IceGatheringStateChange_s);
847 0 : aCtx->SignalConnectionStateChange.connect(
848 : this,
849 0 : &PeerConnectionMedia::IceConnectionStateChange_s);
850 :
851 0 : if (aOldCtx) {
852 0 : MOZ_ASSERT(aCtx != aOldCtx);
853 0 : aOldCtx->SignalGatheringStateChange.disconnect(this);
854 0 : aOldCtx->SignalConnectionStateChange.disconnect(this);
855 :
856 : // if the old and new connection state and/or gathering state is
857 : // different fire the state update. Note: we don't fire the update
858 : // if the state is *INIT since updates for the INIT state aren't
859 : // sent during the normal flow. (mjf)
860 0 : if (aOldCtx->connection_state() != aCtx->connection_state() &&
861 0 : aCtx->connection_state() != NrIceCtx::ICE_CTX_INIT) {
862 0 : aCtx->SignalConnectionStateChange(aCtx, aCtx->connection_state());
863 : }
864 :
865 0 : if (aOldCtx->gathering_state() != aCtx->gathering_state() &&
866 0 : aCtx->gathering_state() != NrIceCtx::ICE_CTX_GATHER_INIT) {
867 0 : aCtx->SignalGatheringStateChange(aCtx, aCtx->gathering_state());
868 : }
869 : }
870 0 : }
871 :
872 : void
873 0 : PeerConnectionMedia::AddIceCandidate(const std::string& candidate,
874 : const std::string& mid,
875 : uint32_t aMLine) {
876 0 : RUN_ON_THREAD(GetSTSThread(),
877 0 : WrapRunnable(
878 0 : RefPtr<PeerConnectionMedia>(this),
879 : &PeerConnectionMedia::AddIceCandidate_s,
880 0 : std::string(candidate), // Make copies.
881 0 : std::string(mid),
882 : aMLine),
883 0 : NS_DISPATCH_NORMAL);
884 0 : }
885 :
886 : void
887 0 : PeerConnectionMedia::AddIceCandidate_s(const std::string& aCandidate,
888 : const std::string& aMid,
889 : uint32_t aMLine) {
890 0 : RefPtr<NrIceMediaStream> stream(mIceCtxHdlr->ctx()->GetStream(aMLine));
891 0 : if (!stream) {
892 0 : CSFLogError(logTag, "No ICE stream for candidate at level %u: %s",
893 0 : static_cast<unsigned>(aMLine), aCandidate.c_str());
894 0 : return;
895 : }
896 :
897 0 : nsresult rv = stream->ParseTrickleCandidate(aCandidate);
898 0 : if (NS_FAILED(rv)) {
899 : CSFLogError(logTag, "Couldn't process ICE candidate at level %u",
900 0 : static_cast<unsigned>(aMLine));
901 0 : return;
902 : }
903 : }
904 :
905 : void
906 0 : PeerConnectionMedia::UpdateNetworkState(bool online) {
907 0 : RUN_ON_THREAD(GetSTSThread(),
908 0 : WrapRunnable(
909 0 : RefPtr<PeerConnectionMedia>(this),
910 : &PeerConnectionMedia::UpdateNetworkState_s,
911 : online),
912 0 : NS_DISPATCH_NORMAL);
913 0 : }
914 :
915 : void
916 0 : PeerConnectionMedia::UpdateNetworkState_s(bool online) {
917 0 : mIceCtxHdlr->ctx()->UpdateNetworkState(online);
918 0 : }
919 :
920 : void
921 0 : PeerConnectionMedia::FlushIceCtxOperationQueueIfReady()
922 : {
923 0 : ASSERT_ON_THREAD(mMainThread);
924 :
925 0 : if (IsIceCtxReady()) {
926 0 : for (auto& mQueuedIceCtxOperation : mQueuedIceCtxOperations) {
927 0 : GetSTSThread()->Dispatch(mQueuedIceCtxOperation, NS_DISPATCH_NORMAL);
928 : }
929 0 : mQueuedIceCtxOperations.clear();
930 : }
931 0 : }
932 :
933 : void
934 0 : PeerConnectionMedia::PerformOrEnqueueIceCtxOperation(nsIRunnable* runnable)
935 : {
936 0 : ASSERT_ON_THREAD(mMainThread);
937 :
938 0 : if (IsIceCtxReady()) {
939 0 : GetSTSThread()->Dispatch(runnable, NS_DISPATCH_NORMAL);
940 : } else {
941 0 : mQueuedIceCtxOperations.push_back(runnable);
942 : }
943 0 : }
944 :
945 : void
946 0 : PeerConnectionMedia::GatherIfReady() {
947 0 : ASSERT_ON_THREAD(mMainThread);
948 :
949 0 : nsCOMPtr<nsIRunnable> runnable(WrapRunnable(
950 0 : RefPtr<PeerConnectionMedia>(this),
951 : &PeerConnectionMedia::EnsureIceGathering_s,
952 0 : GetPrefDefaultAddressOnly(),
953 0 : GetPrefProxyOnly()));
954 :
955 0 : PerformOrEnqueueIceCtxOperation(runnable);
956 0 : }
957 :
958 : void
959 0 : PeerConnectionMedia::EnsureIceGathering_s(bool aDefaultRouteOnly,
960 : bool aProxyOnly) {
961 0 : if (mProxyServer) {
962 0 : mIceCtxHdlr->ctx()->SetProxyServer(*mProxyServer);
963 0 : } else if (aProxyOnly) {
964 0 : IceGatheringStateChange_s(mIceCtxHdlr->ctx().get(),
965 0 : NrIceCtx::ICE_CTX_GATHER_COMPLETE);
966 0 : return;
967 : }
968 :
969 0 : if (mStunAddrs.Length()) {
970 0 : mIceCtxHdlr->ctx()->SetStunAddrs(mStunAddrs);
971 : }
972 :
973 : // Start gathering, but only if there are streams
974 0 : for (size_t i = 0; i < mIceCtxHdlr->ctx()->GetStreamCount(); ++i) {
975 0 : if (mIceCtxHdlr->ctx()->GetStream(i)) {
976 0 : mIceCtxHdlr->ctx()->StartGathering(aDefaultRouteOnly, aProxyOnly);
977 0 : return;
978 : }
979 : }
980 :
981 : // If there are no streams, we're probably in a situation where we've rolled
982 : // back while still waiting for our proxy configuration to come back. Make
983 : // sure content knows that the rollback has stuck wrt gathering.
984 0 : IceGatheringStateChange_s(mIceCtxHdlr->ctx().get(),
985 0 : NrIceCtx::ICE_CTX_GATHER_COMPLETE);
986 : }
987 :
988 : nsresult
989 0 : PeerConnectionMedia::AddTrack(DOMMediaStream& aMediaStream,
990 : const std::string& streamId,
991 : MediaStreamTrack& aTrack,
992 : const std::string& trackId)
993 : {
994 0 : ASSERT_ON_THREAD(mMainThread);
995 :
996 0 : CSFLogDebug(logTag, "%s: MediaStream: %p", __FUNCTION__, &aMediaStream);
997 :
998 : RefPtr<LocalSourceStreamInfo> localSourceStream =
999 0 : GetLocalStreamById(streamId);
1000 :
1001 0 : if (!localSourceStream) {
1002 0 : localSourceStream = new LocalSourceStreamInfo(&aMediaStream, this, streamId);
1003 0 : mLocalSourceStreams.AppendElement(localSourceStream);
1004 : }
1005 :
1006 0 : localSourceStream->AddTrack(trackId, &aTrack);
1007 0 : return NS_OK;
1008 : }
1009 :
1010 : nsresult
1011 0 : PeerConnectionMedia::RemoveLocalTrack(const std::string& streamId,
1012 : const std::string& trackId)
1013 : {
1014 0 : ASSERT_ON_THREAD(mMainThread);
1015 :
1016 0 : CSFLogDebug(logTag, "%s: stream: %s track: %s", __FUNCTION__,
1017 0 : streamId.c_str(), trackId.c_str());
1018 :
1019 : RefPtr<LocalSourceStreamInfo> localSourceStream =
1020 0 : GetLocalStreamById(streamId);
1021 0 : if (!localSourceStream) {
1022 0 : return NS_ERROR_ILLEGAL_VALUE;
1023 : }
1024 :
1025 0 : localSourceStream->RemoveTrack(trackId);
1026 0 : if (!localSourceStream->GetTrackCount()) {
1027 0 : mLocalSourceStreams.RemoveElement(localSourceStream);
1028 : }
1029 0 : return NS_OK;
1030 : }
1031 :
1032 : nsresult
1033 0 : PeerConnectionMedia::RemoveRemoteTrack(const std::string& streamId,
1034 : const std::string& trackId)
1035 : {
1036 0 : ASSERT_ON_THREAD(mMainThread);
1037 :
1038 0 : CSFLogDebug(logTag, "%s: stream: %s track: %s", __FUNCTION__,
1039 0 : streamId.c_str(), trackId.c_str());
1040 :
1041 : RefPtr<RemoteSourceStreamInfo> remoteSourceStream =
1042 0 : GetRemoteStreamById(streamId);
1043 0 : if (!remoteSourceStream) {
1044 0 : return NS_ERROR_ILLEGAL_VALUE;
1045 : }
1046 :
1047 0 : remoteSourceStream->RemoveTrack(trackId);
1048 0 : if (!remoteSourceStream->GetTrackCount()) {
1049 0 : mRemoteSourceStreams.RemoveElement(remoteSourceStream);
1050 : }
1051 0 : return NS_OK;
1052 : }
1053 :
1054 : void
1055 0 : PeerConnectionMedia::SelfDestruct()
1056 : {
1057 0 : ASSERT_ON_THREAD(mMainThread);
1058 :
1059 0 : CSFLogDebug(logTag, "%s: ", __FUNCTION__);
1060 :
1061 : // Shut down the media
1062 0 : for (uint32_t i=0; i < mLocalSourceStreams.Length(); ++i) {
1063 0 : mLocalSourceStreams[i]->DetachMedia_m();
1064 : }
1065 :
1066 0 : for (uint32_t i=0; i < mRemoteSourceStreams.Length(); ++i) {
1067 0 : mRemoteSourceStreams[i]->DetachMedia_m();
1068 : }
1069 :
1070 0 : if (mStunAddrsRequest) {
1071 0 : mStunAddrsRequest->Cancel();
1072 0 : mStunAddrsRequest = nullptr;
1073 : }
1074 :
1075 0 : if (mProxyRequest) {
1076 0 : mProxyRequest->Cancel(NS_ERROR_ABORT);
1077 0 : mProxyRequest = nullptr;
1078 : }
1079 :
1080 : // Shutdown the transport (async)
1081 0 : RUN_ON_THREAD(mSTSThread, WrapRunnable(
1082 : this, &PeerConnectionMedia::ShutdownMediaTransport_s),
1083 0 : NS_DISPATCH_NORMAL);
1084 :
1085 0 : CSFLogDebug(logTag, "%s: Media shut down", __FUNCTION__);
1086 0 : }
1087 :
1088 : void
1089 0 : PeerConnectionMedia::SelfDestruct_m()
1090 : {
1091 0 : CSFLogDebug(logTag, "%s: ", __FUNCTION__);
1092 :
1093 0 : ASSERT_ON_THREAD(mMainThread);
1094 :
1095 0 : mLocalSourceStreams.Clear();
1096 0 : mRemoteSourceStreams.Clear();
1097 :
1098 0 : mMainThread = nullptr;
1099 :
1100 : // Final self-destruct.
1101 0 : this->Release();
1102 0 : }
1103 :
1104 : void
1105 0 : PeerConnectionMedia::ShutdownMediaTransport_s()
1106 : {
1107 0 : ASSERT_ON_THREAD(mSTSThread);
1108 :
1109 0 : CSFLogDebug(logTag, "%s: ", __FUNCTION__);
1110 :
1111 : // Here we access m{Local|Remote}SourceStreams off the main thread.
1112 : // That's OK because by here PeerConnectionImpl has forgotten about us,
1113 : // so there is no chance of getting a call in here from outside.
1114 : // The dispatches from SelfDestruct() and to SelfDestruct_m() provide
1115 : // memory barriers that protect us from badness.
1116 0 : for (uint32_t i=0; i < mLocalSourceStreams.Length(); ++i) {
1117 0 : mLocalSourceStreams[i]->DetachTransport_s();
1118 : }
1119 :
1120 0 : for (uint32_t i=0; i < mRemoteSourceStreams.Length(); ++i) {
1121 0 : mRemoteSourceStreams[i]->DetachTransport_s();
1122 : }
1123 :
1124 0 : disconnect_all();
1125 0 : mTransportFlows.clear();
1126 :
1127 : #if !defined(MOZILLA_EXTERNAL_LINKAGE)
1128 0 : NrIceStats stats = mIceCtxHdlr->Destroy();
1129 :
1130 0 : CSFLogDebug(logTag, "Ice Telemetry: stun (retransmits: %d)"
1131 : " turn (401s: %d 403s: %d 438s: %d)",
1132 : stats.stun_retransmits, stats.turn_401s, stats.turn_403s,
1133 0 : stats.turn_438s);
1134 :
1135 0 : Telemetry::ScalarAdd(Telemetry::ScalarID::WEBRTC_NICER_STUN_RETRANSMITS,
1136 0 : stats.stun_retransmits);
1137 0 : Telemetry::ScalarAdd(Telemetry::ScalarID::WEBRTC_NICER_TURN_401S,
1138 0 : stats.turn_401s);
1139 0 : Telemetry::ScalarAdd(Telemetry::ScalarID::WEBRTC_NICER_TURN_403S,
1140 0 : stats.turn_403s);
1141 0 : Telemetry::ScalarAdd(Telemetry::ScalarID::WEBRTC_NICER_TURN_438S,
1142 0 : stats.turn_438s);
1143 : #endif
1144 :
1145 0 : mIceCtxHdlr = nullptr;
1146 :
1147 : // we're holding a ref to 'this' that's released by SelfDestruct_m
1148 0 : mMainThread->Dispatch(WrapRunnable(this, &PeerConnectionMedia::SelfDestruct_m),
1149 0 : NS_DISPATCH_NORMAL);
1150 0 : }
1151 :
1152 : LocalSourceStreamInfo*
1153 0 : PeerConnectionMedia::GetLocalStreamByIndex(int aIndex)
1154 : {
1155 0 : ASSERT_ON_THREAD(mMainThread);
1156 0 : if(aIndex < 0 || aIndex >= (int) mLocalSourceStreams.Length()) {
1157 0 : return nullptr;
1158 : }
1159 :
1160 0 : MOZ_ASSERT(mLocalSourceStreams[aIndex]);
1161 0 : return mLocalSourceStreams[aIndex];
1162 : }
1163 :
1164 : LocalSourceStreamInfo*
1165 0 : PeerConnectionMedia::GetLocalStreamById(const std::string& id)
1166 : {
1167 0 : ASSERT_ON_THREAD(mMainThread);
1168 0 : for (size_t i = 0; i < mLocalSourceStreams.Length(); ++i) {
1169 0 : if (id == mLocalSourceStreams[i]->GetId()) {
1170 0 : return mLocalSourceStreams[i];
1171 : }
1172 : }
1173 :
1174 0 : return nullptr;
1175 : }
1176 :
1177 : LocalSourceStreamInfo*
1178 0 : PeerConnectionMedia::GetLocalStreamByTrackId(const std::string& id)
1179 : {
1180 0 : ASSERT_ON_THREAD(mMainThread);
1181 0 : for (RefPtr<LocalSourceStreamInfo>& info : mLocalSourceStreams) {
1182 0 : if (info->HasTrack(id)) {
1183 0 : return info;
1184 : }
1185 : }
1186 :
1187 0 : return nullptr;
1188 : }
1189 :
1190 : RemoteSourceStreamInfo*
1191 0 : PeerConnectionMedia::GetRemoteStreamByIndex(size_t aIndex)
1192 : {
1193 0 : ASSERT_ON_THREAD(mMainThread);
1194 0 : MOZ_ASSERT(mRemoteSourceStreams.SafeElementAt(aIndex));
1195 0 : return mRemoteSourceStreams.SafeElementAt(aIndex);
1196 : }
1197 :
1198 : RemoteSourceStreamInfo*
1199 0 : PeerConnectionMedia::GetRemoteStreamById(const std::string& id)
1200 : {
1201 0 : ASSERT_ON_THREAD(mMainThread);
1202 0 : for (size_t i = 0; i < mRemoteSourceStreams.Length(); ++i) {
1203 0 : if (id == mRemoteSourceStreams[i]->GetId()) {
1204 0 : return mRemoteSourceStreams[i];
1205 : }
1206 : }
1207 :
1208 0 : return nullptr;
1209 : }
1210 :
1211 : RemoteSourceStreamInfo*
1212 0 : PeerConnectionMedia::GetRemoteStreamByTrackId(const std::string& id)
1213 : {
1214 0 : ASSERT_ON_THREAD(mMainThread);
1215 0 : for (RefPtr<RemoteSourceStreamInfo>& info : mRemoteSourceStreams) {
1216 0 : if (info->HasTrack(id)) {
1217 0 : return info;
1218 : }
1219 : }
1220 :
1221 0 : return nullptr;
1222 : }
1223 :
1224 :
1225 : nsresult
1226 0 : PeerConnectionMedia::AddRemoteStream(RefPtr<RemoteSourceStreamInfo> aInfo)
1227 : {
1228 0 : ASSERT_ON_THREAD(mMainThread);
1229 :
1230 0 : mRemoteSourceStreams.AppendElement(aInfo);
1231 :
1232 0 : return NS_OK;
1233 : }
1234 :
1235 : void
1236 0 : PeerConnectionMedia::IceGatheringStateChange_s(NrIceCtx* ctx,
1237 : NrIceCtx::GatheringState state)
1238 : {
1239 0 : ASSERT_ON_THREAD(mSTSThread);
1240 :
1241 0 : if (state == NrIceCtx::ICE_CTX_GATHER_COMPLETE) {
1242 : // Fire off EndOfLocalCandidates for each stream
1243 0 : for (size_t i = 0; ; ++i) {
1244 0 : RefPtr<NrIceMediaStream> stream(ctx->GetStream(i));
1245 0 : if (!stream) {
1246 0 : break;
1247 : }
1248 :
1249 0 : NrIceCandidate candidate;
1250 0 : NrIceCandidate rtcpCandidate;
1251 0 : GetDefaultCandidates(*stream, &candidate, &rtcpCandidate);
1252 0 : EndOfLocalCandidates(candidate.cand_addr.host,
1253 0 : candidate.cand_addr.port,
1254 : rtcpCandidate.cand_addr.host,
1255 0 : rtcpCandidate.cand_addr.port,
1256 0 : i);
1257 0 : }
1258 : }
1259 :
1260 : // ShutdownMediaTransport_s has not run yet because it unhooks this function
1261 : // from its signal, which means that SelfDestruct_m has not been dispatched
1262 : // yet either, so this PCMedia will still be around when this dispatch reaches
1263 : // main.
1264 0 : GetMainThread()->Dispatch(
1265 0 : WrapRunnable(this,
1266 : &PeerConnectionMedia::IceGatheringStateChange_m,
1267 : ctx,
1268 : state),
1269 0 : NS_DISPATCH_NORMAL);
1270 0 : }
1271 :
1272 : void
1273 0 : PeerConnectionMedia::IceConnectionStateChange_s(NrIceCtx* ctx,
1274 : NrIceCtx::ConnectionState state)
1275 : {
1276 0 : ASSERT_ON_THREAD(mSTSThread);
1277 : // ShutdownMediaTransport_s has not run yet because it unhooks this function
1278 : // from its signal, which means that SelfDestruct_m has not been dispatched
1279 : // yet either, so this PCMedia will still be around when this dispatch reaches
1280 : // main.
1281 0 : GetMainThread()->Dispatch(
1282 0 : WrapRunnable(this,
1283 : &PeerConnectionMedia::IceConnectionStateChange_m,
1284 : ctx,
1285 : state),
1286 0 : NS_DISPATCH_NORMAL);
1287 0 : }
1288 :
1289 : void
1290 0 : PeerConnectionMedia::OnCandidateFound_s(NrIceMediaStream *aStream,
1291 : const std::string &aCandidateLine)
1292 : {
1293 0 : ASSERT_ON_THREAD(mSTSThread);
1294 0 : MOZ_ASSERT(aStream);
1295 0 : MOZ_RELEASE_ASSERT(mIceCtxHdlr);
1296 :
1297 0 : CSFLogDebug(logTag, "%s: %s", __FUNCTION__, aStream->name().c_str());
1298 :
1299 0 : NrIceCandidate candidate;
1300 0 : NrIceCandidate rtcpCandidate;
1301 0 : GetDefaultCandidates(*aStream, &candidate, &rtcpCandidate);
1302 :
1303 : // ShutdownMediaTransport_s has not run yet because it unhooks this function
1304 : // from its signal, which means that SelfDestruct_m has not been dispatched
1305 : // yet either, so this PCMedia will still be around when this dispatch reaches
1306 : // main.
1307 0 : GetMainThread()->Dispatch(
1308 0 : WrapRunnable(this,
1309 : &PeerConnectionMedia::OnCandidateFound_m,
1310 : aCandidateLine,
1311 : candidate.cand_addr.host,
1312 0 : candidate.cand_addr.port,
1313 : rtcpCandidate.cand_addr.host,
1314 0 : rtcpCandidate.cand_addr.port,
1315 0 : aStream->GetLevel()),
1316 0 : NS_DISPATCH_NORMAL);
1317 0 : }
1318 :
1319 : void
1320 0 : PeerConnectionMedia::EndOfLocalCandidates(const std::string& aDefaultAddr,
1321 : uint16_t aDefaultPort,
1322 : const std::string& aDefaultRtcpAddr,
1323 : uint16_t aDefaultRtcpPort,
1324 : uint16_t aMLine)
1325 : {
1326 0 : GetMainThread()->Dispatch(
1327 0 : WrapRunnable(this,
1328 : &PeerConnectionMedia::EndOfLocalCandidates_m,
1329 : aDefaultAddr,
1330 : aDefaultPort,
1331 : aDefaultRtcpAddr,
1332 : aDefaultRtcpPort,
1333 : aMLine),
1334 0 : NS_DISPATCH_NORMAL);
1335 0 : }
1336 :
1337 : void
1338 0 : PeerConnectionMedia::GetDefaultCandidates(const NrIceMediaStream& aStream,
1339 : NrIceCandidate* aCandidate,
1340 : NrIceCandidate* aRtcpCandidate)
1341 : {
1342 0 : nsresult res = aStream.GetDefaultCandidate(1, aCandidate);
1343 : // Optional; component won't exist if doing rtcp-mux
1344 0 : if (NS_FAILED(aStream.GetDefaultCandidate(2, aRtcpCandidate))) {
1345 0 : aRtcpCandidate->cand_addr.host.clear();
1346 0 : aRtcpCandidate->cand_addr.port = 0;
1347 : }
1348 0 : if (NS_FAILED(res)) {
1349 0 : aCandidate->cand_addr.host.clear();
1350 0 : aCandidate->cand_addr.port = 0;
1351 0 : CSFLogError(logTag, "%s: GetDefaultCandidates failed for level %u, "
1352 : "res=%u",
1353 : __FUNCTION__,
1354 : static_cast<unsigned>(aStream.GetLevel()),
1355 0 : static_cast<unsigned>(res));
1356 : }
1357 0 : }
1358 :
1359 : void
1360 0 : PeerConnectionMedia::IceGatheringStateChange_m(NrIceCtx* ctx,
1361 : NrIceCtx::GatheringState state)
1362 : {
1363 0 : ASSERT_ON_THREAD(mMainThread);
1364 0 : SignalIceGatheringStateChange(ctx, state);
1365 0 : }
1366 :
1367 : void
1368 0 : PeerConnectionMedia::IceConnectionStateChange_m(NrIceCtx* ctx,
1369 : NrIceCtx::ConnectionState state)
1370 : {
1371 0 : ASSERT_ON_THREAD(mMainThread);
1372 0 : SignalIceConnectionStateChange(ctx, state);
1373 0 : }
1374 :
1375 : void
1376 0 : PeerConnectionMedia::IceStreamReady_s(NrIceMediaStream *aStream)
1377 : {
1378 0 : MOZ_ASSERT(aStream);
1379 :
1380 0 : CSFLogDebug(logTag, "%s: %s", __FUNCTION__, aStream->name().c_str());
1381 0 : }
1382 :
1383 : void
1384 0 : PeerConnectionMedia::OnCandidateFound_m(const std::string& aCandidateLine,
1385 : const std::string& aDefaultAddr,
1386 : uint16_t aDefaultPort,
1387 : const std::string& aDefaultRtcpAddr,
1388 : uint16_t aDefaultRtcpPort,
1389 : uint16_t aMLine)
1390 : {
1391 0 : ASSERT_ON_THREAD(mMainThread);
1392 0 : if (!aDefaultAddr.empty()) {
1393 0 : SignalUpdateDefaultCandidate(aDefaultAddr,
1394 : aDefaultPort,
1395 : aDefaultRtcpAddr,
1396 : aDefaultRtcpPort,
1397 0 : aMLine);
1398 : }
1399 0 : SignalCandidate(aCandidateLine, aMLine);
1400 0 : }
1401 :
1402 : void
1403 0 : PeerConnectionMedia::EndOfLocalCandidates_m(const std::string& aDefaultAddr,
1404 : uint16_t aDefaultPort,
1405 : const std::string& aDefaultRtcpAddr,
1406 : uint16_t aDefaultRtcpPort,
1407 : uint16_t aMLine) {
1408 0 : ASSERT_ON_THREAD(mMainThread);
1409 0 : if (!aDefaultAddr.empty()) {
1410 0 : SignalUpdateDefaultCandidate(aDefaultAddr,
1411 : aDefaultPort,
1412 : aDefaultRtcpAddr,
1413 : aDefaultRtcpPort,
1414 0 : aMLine);
1415 : }
1416 0 : SignalEndOfLocalCandidates(aMLine);
1417 0 : }
1418 :
1419 : void
1420 0 : PeerConnectionMedia::DtlsConnected_s(TransportLayer *layer,
1421 : TransportLayer::State state)
1422 : {
1423 0 : MOZ_ASSERT(layer->id() == "dtls");
1424 0 : TransportLayerDtls* dtlsLayer = static_cast<TransportLayerDtls*>(layer);
1425 0 : dtlsLayer->SignalStateChange.disconnect(this);
1426 :
1427 0 : bool privacyRequested = (dtlsLayer->GetNegotiatedAlpn() == "c-webrtc");
1428 0 : GetMainThread()->Dispatch(
1429 0 : WrapRunnableNM(&PeerConnectionMedia::DtlsConnected_m,
1430 : mParentHandle, privacyRequested),
1431 0 : NS_DISPATCH_NORMAL);
1432 0 : }
1433 :
1434 : void
1435 0 : PeerConnectionMedia::DtlsConnected_m(const std::string& aParentHandle,
1436 : bool aPrivacyRequested)
1437 : {
1438 0 : PeerConnectionWrapper pcWrapper(aParentHandle);
1439 0 : PeerConnectionImpl* pc = pcWrapper.impl();
1440 0 : if (pc) {
1441 0 : pc->SetDtlsConnected(aPrivacyRequested);
1442 : }
1443 0 : }
1444 :
1445 : void
1446 0 : PeerConnectionMedia::AddTransportFlow(int aIndex, bool aRtcp,
1447 : const RefPtr<TransportFlow> &aFlow)
1448 : {
1449 0 : int index_inner = GetTransportFlowIndex(aIndex, aRtcp);
1450 :
1451 0 : MOZ_ASSERT(!mTransportFlows[index_inner]);
1452 0 : mTransportFlows[index_inner] = aFlow;
1453 :
1454 0 : GetSTSThread()->Dispatch(
1455 0 : WrapRunnable(this, &PeerConnectionMedia::ConnectDtlsListener_s, aFlow),
1456 0 : NS_DISPATCH_NORMAL);
1457 0 : }
1458 :
1459 : void
1460 0 : PeerConnectionMedia::RemoveTransportFlow(int aIndex, bool aRtcp)
1461 : {
1462 0 : int index_inner = GetTransportFlowIndex(aIndex, aRtcp);
1463 0 : NS_ProxyRelease(
1464 : "PeerConnectionMedia::mTransportFlows",
1465 0 : GetSTSThread(), mTransportFlows[index_inner].forget());
1466 0 : }
1467 :
1468 : void
1469 0 : PeerConnectionMedia::ConnectDtlsListener_s(const RefPtr<TransportFlow>& aFlow)
1470 : {
1471 0 : TransportLayer* dtls = aFlow->GetLayer(TransportLayerDtls::ID());
1472 0 : if (dtls) {
1473 0 : dtls->SignalStateChange.connect(this, &PeerConnectionMedia::DtlsConnected_s);
1474 : }
1475 0 : }
1476 :
1477 : nsresult
1478 0 : LocalSourceStreamInfo::TakePipelineFrom(RefPtr<LocalSourceStreamInfo>& info,
1479 : const std::string& oldTrackId,
1480 : MediaStreamTrack& aNewTrack,
1481 : const std::string& newTrackId)
1482 : {
1483 0 : if (mPipelines.count(newTrackId)) {
1484 0 : CSFLogError(logTag, "%s: Pipeline already exists for %s/%s",
1485 0 : __FUNCTION__, mId.c_str(), newTrackId.c_str());
1486 0 : return NS_ERROR_INVALID_ARG;
1487 : }
1488 :
1489 0 : RefPtr<MediaPipeline> pipeline(info->ForgetPipelineByTrackId_m(oldTrackId));
1490 :
1491 0 : if (!pipeline) {
1492 : // Replacetrack can potentially happen in the middle of offer/answer, before
1493 : // the pipeline has been created.
1494 : CSFLogInfo(logTag, "%s: Replacing track before the pipeline has been "
1495 0 : "created, nothing to do.", __FUNCTION__);
1496 0 : return NS_OK;
1497 : }
1498 :
1499 : nsresult rv =
1500 0 : static_cast<MediaPipelineTransmit*>(pipeline.get())->ReplaceTrack(aNewTrack);
1501 0 : NS_ENSURE_SUCCESS(rv, rv);
1502 :
1503 0 : mPipelines[newTrackId] = pipeline;
1504 :
1505 0 : return NS_OK;
1506 : }
1507 :
1508 : /**
1509 : * Tells you if any local track is isolated to a specific peer identity.
1510 : * Obviously, we want all the tracks to be isolated equally so that they can
1511 : * all be sent or not. We check once when we are setting a local description
1512 : * and that determines if we flip the "privacy requested" bit on. Once the bit
1513 : * is on, all media originating from this peer connection is isolated.
1514 : *
1515 : * @returns true if any track has a peerIdentity set on it
1516 : */
1517 : bool
1518 0 : PeerConnectionMedia::AnyLocalTrackHasPeerIdentity() const
1519 : {
1520 0 : ASSERT_ON_THREAD(mMainThread);
1521 :
1522 0 : for (uint32_t u = 0; u < mLocalSourceStreams.Length(); u++) {
1523 0 : for (auto pair : mLocalSourceStreams[u]->GetMediaStreamTracks()) {
1524 0 : if (pair.second->GetPeerIdentity() != nullptr) {
1525 0 : return true;
1526 : }
1527 : }
1528 : }
1529 0 : return false;
1530 : }
1531 :
1532 : void
1533 0 : PeerConnectionMedia::UpdateRemoteStreamPrincipals_m(nsIPrincipal* aPrincipal)
1534 : {
1535 0 : ASSERT_ON_THREAD(mMainThread);
1536 :
1537 0 : for (uint32_t u = 0; u < mRemoteSourceStreams.Length(); u++) {
1538 0 : mRemoteSourceStreams[u]->UpdatePrincipal_m(aPrincipal);
1539 : }
1540 0 : }
1541 :
1542 : void
1543 0 : PeerConnectionMedia::UpdateSinkIdentity_m(MediaStreamTrack* aTrack,
1544 : nsIPrincipal* aPrincipal,
1545 : const PeerIdentity* aSinkIdentity)
1546 : {
1547 0 : ASSERT_ON_THREAD(mMainThread);
1548 :
1549 0 : for (uint32_t u = 0; u < mLocalSourceStreams.Length(); u++) {
1550 0 : mLocalSourceStreams[u]->UpdateSinkIdentity_m(aTrack, aPrincipal,
1551 0 : aSinkIdentity);
1552 : }
1553 0 : }
1554 :
1555 : void
1556 0 : LocalSourceStreamInfo::UpdateSinkIdentity_m(MediaStreamTrack* aTrack,
1557 : nsIPrincipal* aPrincipal,
1558 : const PeerIdentity* aSinkIdentity)
1559 : {
1560 0 : for (auto& pipeline_ : mPipelines) {
1561 : MediaPipelineTransmit* pipeline =
1562 0 : static_cast<MediaPipelineTransmit*>(pipeline_.second.get());
1563 0 : pipeline->UpdateSinkIdentity_m(aTrack, aPrincipal, aSinkIdentity);
1564 : }
1565 0 : }
1566 :
1567 0 : void RemoteSourceStreamInfo::UpdatePrincipal_m(nsIPrincipal* aPrincipal)
1568 : {
1569 : // This blasts away the existing principal.
1570 : // We only do this when we become certain that the all tracks are safe to make
1571 : // accessible to the script principal.
1572 0 : for (auto& trackPair : mTracks) {
1573 0 : MOZ_RELEASE_ASSERT(trackPair.second);
1574 : RemoteTrackSource& source =
1575 0 : static_cast<RemoteTrackSource&>(trackPair.second->GetSource());
1576 0 : source.SetPrincipal(aPrincipal);
1577 :
1578 0 : RefPtr<MediaPipeline> pipeline = GetPipelineByTrackId_m(trackPair.first);
1579 0 : if (pipeline) {
1580 0 : MOZ_ASSERT(pipeline->direction() == MediaPipeline::RECEIVE);
1581 0 : static_cast<MediaPipelineReceive*>(pipeline.get())
1582 0 : ->SetPrincipalHandle_m(MakePrincipalHandle(aPrincipal));
1583 : }
1584 : }
1585 0 : }
1586 :
1587 : bool
1588 0 : PeerConnectionMedia::AnyCodecHasPluginID(uint64_t aPluginID)
1589 : {
1590 0 : for (uint32_t i=0; i < mLocalSourceStreams.Length(); ++i) {
1591 0 : if (mLocalSourceStreams[i]->AnyCodecHasPluginID(aPluginID)) {
1592 0 : return true;
1593 : }
1594 : }
1595 0 : for (uint32_t i=0; i < mRemoteSourceStreams.Length(); ++i) {
1596 0 : if (mRemoteSourceStreams[i]->AnyCodecHasPluginID(aPluginID)) {
1597 0 : return true;
1598 : }
1599 : }
1600 0 : return false;
1601 : }
1602 :
1603 : bool
1604 0 : SourceStreamInfo::AnyCodecHasPluginID(uint64_t aPluginID)
1605 : {
1606 : // Scan the videoConduits for this plugin ID
1607 0 : for (auto& pipeline : mPipelines) {
1608 0 : if (pipeline.second->Conduit()->CodecPluginID() == aPluginID) {
1609 0 : return true;
1610 : }
1611 : }
1612 0 : return false;
1613 : }
1614 :
1615 : nsresult
1616 0 : SourceStreamInfo::StorePipeline(
1617 : const std::string& trackId,
1618 : const RefPtr<mozilla::MediaPipeline>& aPipeline)
1619 : {
1620 0 : MOZ_ASSERT(mPipelines.find(trackId) == mPipelines.end());
1621 0 : if (mPipelines.find(trackId) != mPipelines.end()) {
1622 0 : CSFLogError(logTag, "%s: Storing duplicate track", __FUNCTION__);
1623 0 : return NS_ERROR_FAILURE;
1624 : }
1625 :
1626 0 : mPipelines[trackId] = aPipeline;
1627 0 : return NS_OK;
1628 : }
1629 :
1630 : void
1631 0 : RemoteSourceStreamInfo::DetachMedia_m()
1632 : {
1633 0 : for (auto& webrtcIdAndTrack : mTracks) {
1634 0 : EndTrack(mMediaStream->GetInputStream(), webrtcIdAndTrack.second);
1635 : }
1636 0 : SourceStreamInfo::DetachMedia_m();
1637 0 : }
1638 :
1639 : void
1640 0 : RemoteSourceStreamInfo::RemoveTrack(const std::string& trackId)
1641 : {
1642 0 : auto it = mTracks.find(trackId);
1643 0 : if (it != mTracks.end()) {
1644 0 : EndTrack(mMediaStream->GetInputStream(), it->second);
1645 : }
1646 :
1647 0 : SourceStreamInfo::RemoveTrack(trackId);
1648 0 : }
1649 :
1650 : void
1651 0 : RemoteSourceStreamInfo::SyncPipeline(
1652 : RefPtr<MediaPipelineReceive> aPipeline)
1653 : {
1654 : // See if we have both audio and video here, and if so cross the streams and
1655 : // sync them
1656 : // TODO: Do we need to prevent multiple syncs if there is more than one audio
1657 : // or video track in a single media stream? What are we supposed to do in this
1658 : // case?
1659 0 : for (auto i = mPipelines.begin(); i != mPipelines.end(); ++i) {
1660 0 : if (i->second->IsVideo() != aPipeline->IsVideo()) {
1661 : // Ok, we have one video, one non-video - cross the streams!
1662 : WebrtcAudioConduit *audio_conduit =
1663 0 : static_cast<WebrtcAudioConduit*>(aPipeline->IsVideo() ?
1664 0 : i->second->Conduit() :
1665 0 : aPipeline->Conduit());
1666 : WebrtcVideoConduit *video_conduit =
1667 0 : static_cast<WebrtcVideoConduit*>(aPipeline->IsVideo() ?
1668 0 : aPipeline->Conduit() :
1669 0 : i->second->Conduit());
1670 0 : video_conduit->SyncTo(audio_conduit);
1671 0 : CSFLogDebug(logTag, "Syncing %p to %p, %s to %s",
1672 : video_conduit, audio_conduit,
1673 0 : i->first.c_str(), aPipeline->trackid().c_str());
1674 : }
1675 : }
1676 0 : }
1677 :
1678 : void
1679 0 : RemoteSourceStreamInfo::StartReceiving()
1680 : {
1681 0 : if (mReceiving || mPipelines.empty()) {
1682 0 : return;
1683 : }
1684 :
1685 0 : mReceiving = true;
1686 :
1687 0 : SourceMediaStream* source = GetMediaStream()->GetInputStream()->AsSourceStream();
1688 0 : source->SetPullEnabled(true);
1689 : // AdvanceKnownTracksTicksTime(HEAT_DEATH_OF_UNIVERSE) means that in
1690 : // theory per the API, we can't add more tracks before that
1691 : // time. However, the impl actually allows it, and it avoids a whole
1692 : // bunch of locking that would be required (and potential blocking)
1693 : // if we used smaller values and updated them on each NotifyPull.
1694 0 : source->AdvanceKnownTracksTime(STREAM_TIME_MAX);
1695 0 : CSFLogDebug(logTag, "Finished adding tracks to MediaStream %p", source);
1696 : }
1697 :
1698 0 : RefPtr<MediaPipeline> SourceStreamInfo::GetPipelineByTrackId_m(
1699 : const std::string& trackId) {
1700 0 : ASSERT_ON_THREAD(mParent->GetMainThread());
1701 :
1702 : // Refuse to hand out references if we're tearing down.
1703 : // (Since teardown involves a dispatch to and from STS before MediaPipelines
1704 : // are released, it is safe to start other dispatches to and from STS with a
1705 : // RefPtr<MediaPipeline>, since that reference won't be the last one
1706 : // standing)
1707 0 : if (mMediaStream) {
1708 0 : if (mPipelines.count(trackId)) {
1709 0 : return mPipelines[trackId];
1710 : }
1711 : }
1712 :
1713 0 : return nullptr;
1714 : }
1715 :
1716 : already_AddRefed<MediaPipeline>
1717 0 : LocalSourceStreamInfo::ForgetPipelineByTrackId_m(const std::string& trackId)
1718 : {
1719 0 : ASSERT_ON_THREAD(mParent->GetMainThread());
1720 :
1721 : // Refuse to hand out references if we're tearing down.
1722 : // (Since teardown involves a dispatch to and from STS before MediaPipelines
1723 : // are released, it is safe to start other dispatches to and from STS with a
1724 : // RefPtr<MediaPipeline>, since that reference won't be the last one
1725 : // standing)
1726 0 : if (mMediaStream) {
1727 0 : if (mPipelines.count(trackId)) {
1728 0 : RefPtr<MediaPipeline> pipeline(mPipelines[trackId]);
1729 0 : mPipelines.erase(trackId);
1730 0 : return pipeline.forget();
1731 : }
1732 : }
1733 :
1734 0 : return nullptr;
1735 : }
1736 :
1737 : auto
1738 0 : RemoteTrackSource::ApplyConstraints(
1739 : nsPIDOMWindowInner* aWindow,
1740 : const dom::MediaTrackConstraints& aConstraints,
1741 : dom::CallerType aCallerType) -> already_AddRefed<PledgeVoid>
1742 : {
1743 0 : RefPtr<PledgeVoid> p = new PledgeVoid();
1744 0 : p->Reject(new dom::MediaStreamError(aWindow,
1745 0 : NS_LITERAL_STRING("OverconstrainedError"),
1746 0 : NS_LITERAL_STRING("")));
1747 0 : return p.forget();
1748 : }
1749 :
1750 : } // namespace mozilla
|