1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,651 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.6 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 +#include <string> 1.8 + 1.9 +#include "CSFLog.h" 1.10 + 1.11 +#include "nspr.h" 1.12 +#include "cc_constants.h" 1.13 + 1.14 +#include "nricectx.h" 1.15 +#include "nricemediastream.h" 1.16 +#include "PeerConnectionImpl.h" 1.17 +#include "PeerConnectionMedia.h" 1.18 +#include "AudioConduit.h" 1.19 +#include "VideoConduit.h" 1.20 +#include "runnable_utils.h" 1.21 + 1.22 +#ifdef MOZILLA_INTERNAL_API 1.23 +#include "MediaStreamList.h" 1.24 +#include "nsIScriptGlobalObject.h" 1.25 +#include "mozilla/Preferences.h" 1.26 +#include "mozilla/dom/RTCStatsReportBinding.h" 1.27 +#endif 1.28 + 1.29 +using namespace mozilla; 1.30 +using namespace mozilla::dom; 1.31 + 1.32 +namespace sipcc { 1.33 + 1.34 +static const char* logTag = "PeerConnectionMedia"; 1.35 +static const mozilla::TrackID TRACK_AUDIO = 0; 1.36 +static const mozilla::TrackID TRACK_VIDEO = 1; 1.37 + 1.38 +/* If the ExpectAudio hint is on we will add a track at the default first 1.39 + * audio track ID (0) 1.40 + * FIX - Do we need to iterate over the tracks instead of taking these hints? 1.41 + */ 1.42 +void 1.43 +LocalSourceStreamInfo::ExpectAudio(const mozilla::TrackID aID) 1.44 +{ 1.45 + mAudioTracks.AppendElement(aID); 1.46 +} 1.47 + 1.48 +// If the ExpectVideo hint is on we will add a track at the default first 1.49 +// video track ID (1). 1.50 +void 1.51 +LocalSourceStreamInfo::ExpectVideo(const mozilla::TrackID aID) 1.52 +{ 1.53 + mVideoTracks.AppendElement(aID); 1.54 +} 1.55 + 1.56 +unsigned 1.57 +LocalSourceStreamInfo::AudioTrackCount() 1.58 +{ 1.59 + return mAudioTracks.Length(); 1.60 +} 1.61 + 1.62 +unsigned 1.63 +LocalSourceStreamInfo::VideoTrackCount() 1.64 +{ 1.65 + return mVideoTracks.Length(); 1.66 +} 1.67 + 1.68 +void LocalSourceStreamInfo::DetachTransport_s() 1.69 +{ 1.70 + ASSERT_ON_THREAD(mParent->GetSTSThread()); 1.71 + // walk through all the MediaPipelines and call the shutdown 1.72 + // functions for transport. Must be on the STS thread. 1.73 + for (std::map<int, mozilla::RefPtr<mozilla::MediaPipeline> >::iterator it = 1.74 + mPipelines.begin(); it != mPipelines.end(); 1.75 + ++it) { 1.76 + it->second->ShutdownTransport_s(); 1.77 + } 1.78 +} 1.79 + 1.80 +void LocalSourceStreamInfo::DetachMedia_m() 1.81 +{ 1.82 + ASSERT_ON_THREAD(mParent->GetMainThread()); 1.83 + // walk through all the MediaPipelines and call the shutdown 1.84 + // functions. Must be on the main thread. 1.85 + for (std::map<int, mozilla::RefPtr<mozilla::MediaPipeline> >::iterator it = 1.86 + mPipelines.begin(); it != mPipelines.end(); 1.87 + ++it) { 1.88 + it->second->ShutdownMedia_m(); 1.89 + } 1.90 + mAudioTracks.Clear(); 1.91 + mVideoTracks.Clear(); 1.92 + mMediaStream = nullptr; 1.93 +} 1.94 + 1.95 +void RemoteSourceStreamInfo::DetachTransport_s() 1.96 +{ 1.97 + ASSERT_ON_THREAD(mParent->GetSTSThread()); 1.98 + // walk through all the MediaPipelines and call the shutdown 1.99 + // transport functions. Must be on the STS thread. 1.100 + for (std::map<int, mozilla::RefPtr<mozilla::MediaPipeline> >::iterator it = 1.101 + mPipelines.begin(); it != mPipelines.end(); 1.102 + ++it) { 1.103 + it->second->ShutdownTransport_s(); 1.104 + } 1.105 +} 1.106 + 1.107 +void RemoteSourceStreamInfo::DetachMedia_m() 1.108 +{ 1.109 + ASSERT_ON_THREAD(mParent->GetMainThread()); 1.110 + 1.111 + // walk through all the MediaPipelines and call the shutdown 1.112 + // media functions. Must be on the main thread. 1.113 + for (std::map<int, mozilla::RefPtr<mozilla::MediaPipeline> >::iterator it = 1.114 + mPipelines.begin(); it != mPipelines.end(); 1.115 + ++it) { 1.116 + it->second->ShutdownMedia_m(); 1.117 + } 1.118 + mMediaStream = nullptr; 1.119 +} 1.120 + 1.121 +already_AddRefed<PeerConnectionImpl> 1.122 +PeerConnectionImpl::Constructor(const dom::GlobalObject& aGlobal, ErrorResult& rv) 1.123 +{ 1.124 + nsRefPtr<PeerConnectionImpl> pc = new PeerConnectionImpl(&aGlobal); 1.125 + 1.126 + CSFLogDebug(logTag, "Created PeerConnection: %p", pc.get()); 1.127 + 1.128 + return pc.forget(); 1.129 +} 1.130 + 1.131 +PeerConnectionImpl* PeerConnectionImpl::CreatePeerConnection() 1.132 +{ 1.133 + PeerConnectionImpl *pc = new PeerConnectionImpl(); 1.134 + 1.135 + CSFLogDebug(logTag, "Created PeerConnection: %p", pc); 1.136 + 1.137 + return pc; 1.138 +} 1.139 + 1.140 + 1.141 +PeerConnectionMedia::PeerConnectionMedia(PeerConnectionImpl *parent) 1.142 + : mParent(parent), 1.143 + mLocalSourceStreamsLock("PeerConnectionMedia.mLocalSourceStreamsLock"), 1.144 + mIceCtx(nullptr), 1.145 + mDNSResolver(new mozilla::NrIceResolver()), 1.146 + mMainThread(mParent->GetMainThread()), 1.147 + mSTSThread(mParent->GetSTSThread()) {} 1.148 + 1.149 +nsresult PeerConnectionMedia::Init(const std::vector<NrIceStunServer>& stun_servers, 1.150 + const std::vector<NrIceTurnServer>& turn_servers) 1.151 +{ 1.152 + // TODO(ekr@rtfm.com): need some way to set not offerer later 1.153 + // Looks like a bug in the NrIceCtx API. 1.154 + mIceCtx = NrIceCtx::Create("PC:" + mParent->GetName(), true); 1.155 + if(!mIceCtx) { 1.156 + CSFLogError(logTag, "%s: Failed to create Ice Context", __FUNCTION__); 1.157 + return NS_ERROR_FAILURE; 1.158 + } 1.159 + nsresult rv; 1.160 + if (NS_FAILED(rv = mIceCtx->SetStunServers(stun_servers))) { 1.161 + CSFLogError(logTag, "%s: Failed to set stun servers", __FUNCTION__); 1.162 + return rv; 1.163 + } 1.164 + // Give us a way to globally turn off TURN support 1.165 +#ifdef MOZILLA_INTERNAL_API 1.166 + bool disabled = Preferences::GetBool("media.peerconnection.turn.disable", false); 1.167 +#else 1.168 + bool disabled = false; 1.169 +#endif 1.170 + if (!disabled) { 1.171 + if (NS_FAILED(rv = mIceCtx->SetTurnServers(turn_servers))) { 1.172 + CSFLogError(logTag, "%s: Failed to set turn servers", __FUNCTION__); 1.173 + return rv; 1.174 + } 1.175 + } else if (turn_servers.size() != 0) { 1.176 + CSFLogError(logTag, "%s: Setting turn servers disabled", __FUNCTION__); 1.177 + } 1.178 + if (NS_FAILED(rv = mDNSResolver->Init())) { 1.179 + CSFLogError(logTag, "%s: Failed to initialize dns resolver", __FUNCTION__); 1.180 + return rv; 1.181 + } 1.182 + if (NS_FAILED(rv = mIceCtx->SetResolver(mDNSResolver->AllocateResolver()))) { 1.183 + CSFLogError(logTag, "%s: Failed to get dns resolver", __FUNCTION__); 1.184 + return rv; 1.185 + } 1.186 + mIceCtx->SignalGatheringStateChange.connect( 1.187 + this, 1.188 + &PeerConnectionMedia::IceGatheringStateChange_s); 1.189 + mIceCtx->SignalConnectionStateChange.connect( 1.190 + this, 1.191 + &PeerConnectionMedia::IceConnectionStateChange_s); 1.192 + 1.193 + // Create three streams to start with. 1.194 + // One each for audio, video and DataChannel 1.195 + // TODO: this will be re-visited 1.196 + RefPtr<NrIceMediaStream> audioStream = 1.197 + mIceCtx->CreateStream((mParent->GetName()+": stream1/audio").c_str(), 2); 1.198 + RefPtr<NrIceMediaStream> videoStream = 1.199 + mIceCtx->CreateStream((mParent->GetName()+": stream2/video").c_str(), 2); 1.200 + RefPtr<NrIceMediaStream> dcStream = 1.201 + mIceCtx->CreateStream((mParent->GetName()+": stream3/data").c_str(), 2); 1.202 + 1.203 + if (!audioStream) { 1.204 + CSFLogError(logTag, "%s: audio stream is NULL", __FUNCTION__); 1.205 + return NS_ERROR_FAILURE; 1.206 + } else { 1.207 + mIceStreams.push_back(audioStream); 1.208 + } 1.209 + 1.210 + if (!videoStream) { 1.211 + CSFLogError(logTag, "%s: video stream is NULL", __FUNCTION__); 1.212 + return NS_ERROR_FAILURE; 1.213 + } else { 1.214 + mIceStreams.push_back(videoStream); 1.215 + } 1.216 + 1.217 + if (!dcStream) { 1.218 + CSFLogError(logTag, "%s: datachannel stream is NULL", __FUNCTION__); 1.219 + return NS_ERROR_FAILURE; 1.220 + } else { 1.221 + mIceStreams.push_back(dcStream); 1.222 + } 1.223 + 1.224 + // TODO(ekr@rtfm.com): This is not connected to the PCCimpl. 1.225 + // Will need to do that later. 1.226 + for (std::size_t i=0; i<mIceStreams.size(); i++) { 1.227 + mIceStreams[i]->SignalReady.connect(this, &PeerConnectionMedia::IceStreamReady); 1.228 + } 1.229 + 1.230 + // TODO(ekr@rtfm.com): When we have a generic error reporting mechanism, 1.231 + // figure out how to report that StartGathering failed. Bug 827982. 1.232 + RUN_ON_THREAD(mIceCtx->thread(), 1.233 + WrapRunnable(mIceCtx, &NrIceCtx::StartGathering), NS_DISPATCH_NORMAL); 1.234 + 1.235 + return NS_OK; 1.236 +} 1.237 + 1.238 +nsresult 1.239 +PeerConnectionMedia::AddStream(nsIDOMMediaStream* aMediaStream, uint32_t *stream_id) 1.240 +{ 1.241 + if (!aMediaStream) { 1.242 + CSFLogError(logTag, "%s - aMediaStream is NULL", __FUNCTION__); 1.243 + return NS_ERROR_FAILURE; 1.244 + } 1.245 + 1.246 + DOMMediaStream* stream = static_cast<DOMMediaStream*>(aMediaStream); 1.247 + 1.248 + CSFLogDebug(logTag, "%s: MediaStream: %p", 1.249 + __FUNCTION__, aMediaStream); 1.250 + 1.251 + // Adding tracks here based on nsDOMMediaStream expectation settings 1.252 + uint32_t hints = stream->GetHintContents(); 1.253 +#ifdef MOZILLA_INTERNAL_API 1.254 + if (!Preferences::GetBool("media.peerconnection.video.enabled", true)) { 1.255 + hints &= ~(DOMMediaStream::HINT_CONTENTS_VIDEO); 1.256 + } 1.257 +#endif 1.258 + 1.259 + if (!(hints & (DOMMediaStream::HINT_CONTENTS_AUDIO | 1.260 + DOMMediaStream::HINT_CONTENTS_VIDEO))) { 1.261 + CSFLogDebug(logTag, "Empty Stream !!"); 1.262 + return NS_OK; 1.263 + } 1.264 + 1.265 + // Now see if we already have a stream of this type, since we only 1.266 + // allow one of each. 1.267 + // TODO(ekr@rtfm.com): remove this when multiple of each stream 1.268 + // is allowed 1.269 + mozilla::MutexAutoLock lock(mLocalSourceStreamsLock); 1.270 + for (uint32_t u = 0; u < mLocalSourceStreams.Length(); u++) { 1.271 + nsRefPtr<LocalSourceStreamInfo> localSourceStream = mLocalSourceStreams[u]; 1.272 + 1.273 + if (localSourceStream->GetMediaStream()->GetHintContents() & hints) { 1.274 + CSFLogError(logTag, "Only one stream of any given type allowed"); 1.275 + return NS_ERROR_FAILURE; 1.276 + } 1.277 + } 1.278 + 1.279 + // OK, we're good to add 1.280 + nsRefPtr<LocalSourceStreamInfo> localSourceStream = 1.281 + new LocalSourceStreamInfo(stream, this); 1.282 + *stream_id = mLocalSourceStreams.Length(); 1.283 + 1.284 + if (hints & DOMMediaStream::HINT_CONTENTS_AUDIO) { 1.285 + localSourceStream->ExpectAudio(TRACK_AUDIO); 1.286 + } 1.287 + 1.288 + if (hints & DOMMediaStream::HINT_CONTENTS_VIDEO) { 1.289 + localSourceStream->ExpectVideo(TRACK_VIDEO); 1.290 + } 1.291 + 1.292 + mLocalSourceStreams.AppendElement(localSourceStream); 1.293 + 1.294 + return NS_OK; 1.295 +} 1.296 + 1.297 +nsresult 1.298 +PeerConnectionMedia::RemoveStream(nsIDOMMediaStream* aMediaStream, uint32_t *stream_id) 1.299 +{ 1.300 + MOZ_ASSERT(aMediaStream); 1.301 + 1.302 + DOMMediaStream* stream = static_cast<DOMMediaStream*>(aMediaStream); 1.303 + 1.304 + CSFLogDebug(logTag, "%s: MediaStream: %p", 1.305 + __FUNCTION__, aMediaStream); 1.306 + 1.307 + mozilla::MutexAutoLock lock(mLocalSourceStreamsLock); 1.308 + for (uint32_t u = 0; u < mLocalSourceStreams.Length(); u++) { 1.309 + nsRefPtr<LocalSourceStreamInfo> localSourceStream = mLocalSourceStreams[u]; 1.310 + if (localSourceStream->GetMediaStream() == stream) { 1.311 + *stream_id = u; 1.312 + return NS_OK; 1.313 + } 1.314 + } 1.315 + 1.316 + return NS_ERROR_ILLEGAL_VALUE; 1.317 +} 1.318 + 1.319 +void 1.320 +PeerConnectionMedia::SelfDestruct() 1.321 +{ 1.322 + ASSERT_ON_THREAD(mMainThread); 1.323 + 1.324 + CSFLogDebug(logTag, "%s: ", __FUNCTION__); 1.325 + 1.326 + // Shut down the media 1.327 + for (uint32_t i=0; i < mLocalSourceStreams.Length(); ++i) { 1.328 + mLocalSourceStreams[i]->DetachMedia_m(); 1.329 + } 1.330 + 1.331 + for (uint32_t i=0; i < mRemoteSourceStreams.Length(); ++i) { 1.332 + mRemoteSourceStreams[i]->DetachMedia_m(); 1.333 + } 1.334 + 1.335 + // Shutdown the transport (async) 1.336 + RUN_ON_THREAD(mSTSThread, WrapRunnable( 1.337 + this, &PeerConnectionMedia::ShutdownMediaTransport_s), 1.338 + NS_DISPATCH_NORMAL); 1.339 + 1.340 + CSFLogDebug(logTag, "%s: Media shut down", __FUNCTION__); 1.341 +} 1.342 + 1.343 +void 1.344 +PeerConnectionMedia::SelfDestruct_m() 1.345 +{ 1.346 + CSFLogDebug(logTag, "%s: ", __FUNCTION__); 1.347 + 1.348 + ASSERT_ON_THREAD(mMainThread); 1.349 + mLocalSourceStreams.Clear(); 1.350 + mRemoteSourceStreams.Clear(); 1.351 + 1.352 + // Final self-destruct. 1.353 + this->Release(); 1.354 +} 1.355 + 1.356 +void 1.357 +PeerConnectionMedia::ShutdownMediaTransport_s() 1.358 +{ 1.359 + ASSERT_ON_THREAD(mSTSThread); 1.360 + 1.361 + CSFLogDebug(logTag, "%s: ", __FUNCTION__); 1.362 + 1.363 + for (uint32_t i=0; i < mLocalSourceStreams.Length(); ++i) { 1.364 + mLocalSourceStreams[i]->DetachTransport_s(); 1.365 + } 1.366 + 1.367 + for (uint32_t i=0; i < mRemoteSourceStreams.Length(); ++i) { 1.368 + mRemoteSourceStreams[i]->DetachTransport_s(); 1.369 + } 1.370 + 1.371 + disconnect_all(); 1.372 + mTransportFlows.clear(); 1.373 + mIceStreams.clear(); 1.374 + mIceCtx = nullptr; 1.375 + 1.376 + mMainThread->Dispatch(WrapRunnable(this, &PeerConnectionMedia::SelfDestruct_m), 1.377 + NS_DISPATCH_NORMAL); 1.378 +} 1.379 + 1.380 +LocalSourceStreamInfo* 1.381 +PeerConnectionMedia::GetLocalStream(int aIndex) 1.382 +{ 1.383 + if(aIndex < 0 || aIndex >= (int) mLocalSourceStreams.Length()) { 1.384 + return nullptr; 1.385 + } 1.386 + 1.387 + MOZ_ASSERT(mLocalSourceStreams[aIndex]); 1.388 + return mLocalSourceStreams[aIndex]; 1.389 +} 1.390 + 1.391 +RemoteSourceStreamInfo* 1.392 +PeerConnectionMedia::GetRemoteStream(int aIndex) 1.393 +{ 1.394 + if(aIndex < 0 || aIndex >= (int) mRemoteSourceStreams.Length()) { 1.395 + return nullptr; 1.396 + } 1.397 + 1.398 + MOZ_ASSERT(mRemoteSourceStreams[aIndex]); 1.399 + return mRemoteSourceStreams[aIndex]; 1.400 +} 1.401 + 1.402 +bool 1.403 +PeerConnectionMedia::SetUsingBundle_m(int level, bool decision) 1.404 +{ 1.405 + ASSERT_ON_THREAD(mMainThread); 1.406 + for (size_t i = 0; i < mRemoteSourceStreams.Length(); ++i) { 1.407 + if (mRemoteSourceStreams[i]->SetUsingBundle_m(level, decision)) { 1.408 + // Found the MediaPipeline for |level| 1.409 + return true; 1.410 + } 1.411 + } 1.412 + CSFLogWarn(logTag, "Could not locate level %d to set bundle flag to %s", 1.413 + static_cast<int>(level), 1.414 + decision ? "true" : "false"); 1.415 + return false; 1.416 +} 1.417 + 1.418 +static void 1.419 +UpdateFilterFromRemoteDescription_s( 1.420 + RefPtr<mozilla::MediaPipeline> receive, 1.421 + RefPtr<mozilla::MediaPipeline> transmit, 1.422 + nsAutoPtr<mozilla::MediaPipelineFilter> filter) { 1.423 + 1.424 + // Update filter, and make a copy of the final version. 1.425 + mozilla::MediaPipelineFilter *finalFilter( 1.426 + receive->UpdateFilterFromRemoteDescription_s(filter)); 1.427 + 1.428 + if (finalFilter) { 1.429 + filter = new mozilla::MediaPipelineFilter(*finalFilter); 1.430 + } 1.431 + 1.432 + // Set same filter on transmit pipeline too. 1.433 + transmit->UpdateFilterFromRemoteDescription_s(filter); 1.434 +} 1.435 + 1.436 +bool 1.437 +PeerConnectionMedia::UpdateFilterFromRemoteDescription_m( 1.438 + int level, 1.439 + nsAutoPtr<mozilla::MediaPipelineFilter> filter) 1.440 +{ 1.441 + ASSERT_ON_THREAD(mMainThread); 1.442 + 1.443 + RefPtr<mozilla::MediaPipeline> receive; 1.444 + for (size_t i = 0; !receive && i < mRemoteSourceStreams.Length(); ++i) { 1.445 + receive = mRemoteSourceStreams[i]->GetPipelineByLevel_m(level); 1.446 + } 1.447 + 1.448 + RefPtr<mozilla::MediaPipeline> transmit; 1.449 + for (size_t i = 0; !transmit && i < mLocalSourceStreams.Length(); ++i) { 1.450 + transmit = mLocalSourceStreams[i]->GetPipelineByLevel_m(level); 1.451 + } 1.452 + 1.453 + if (receive && transmit) { 1.454 + // GetPipelineByLevel_m will return nullptr if shutdown is in progress; 1.455 + // since shutdown is initiated in main, and involves a dispatch to STS 1.456 + // before the pipelines are released, our dispatch to STS will complete 1.457 + // before any release can happen due to a shutdown that hasn't started yet. 1.458 + RUN_ON_THREAD(GetSTSThread(), 1.459 + WrapRunnableNM( 1.460 + &UpdateFilterFromRemoteDescription_s, 1.461 + receive, 1.462 + transmit, 1.463 + filter 1.464 + ), 1.465 + NS_DISPATCH_NORMAL); 1.466 + return true; 1.467 + } else { 1.468 + CSFLogWarn(logTag, "Could not locate level %d to update filter", 1.469 + static_cast<int>(level)); 1.470 + } 1.471 + return false; 1.472 +} 1.473 + 1.474 +nsresult 1.475 +PeerConnectionMedia::AddRemoteStream(nsRefPtr<RemoteSourceStreamInfo> aInfo, 1.476 + int *aIndex) 1.477 +{ 1.478 + MOZ_ASSERT(aIndex); 1.479 + 1.480 + *aIndex = mRemoteSourceStreams.Length(); 1.481 + 1.482 + mRemoteSourceStreams.AppendElement(aInfo); 1.483 + 1.484 + return NS_OK; 1.485 +} 1.486 + 1.487 +nsresult 1.488 +PeerConnectionMedia::AddRemoteStreamHint(int aIndex, bool aIsVideo) 1.489 +{ 1.490 + if (aIndex < 0 || 1.491 + static_cast<unsigned int>(aIndex) >= mRemoteSourceStreams.Length()) { 1.492 + return NS_ERROR_ILLEGAL_VALUE; 1.493 + } 1.494 + 1.495 + RemoteSourceStreamInfo *pInfo = mRemoteSourceStreams.ElementAt(aIndex); 1.496 + MOZ_ASSERT(pInfo); 1.497 + 1.498 + if (aIsVideo) { 1.499 + pInfo->mTrackTypeHints |= DOMMediaStream::HINT_CONTENTS_VIDEO; 1.500 + } else { 1.501 + pInfo->mTrackTypeHints |= DOMMediaStream::HINT_CONTENTS_AUDIO; 1.502 + } 1.503 + 1.504 + return NS_OK; 1.505 +} 1.506 + 1.507 + 1.508 +void 1.509 +PeerConnectionMedia::IceGatheringStateChange_s(NrIceCtx* ctx, 1.510 + NrIceCtx::GatheringState state) 1.511 +{ 1.512 + ASSERT_ON_THREAD(mSTSThread); 1.513 + // ShutdownMediaTransport_s has not run yet because it unhooks this function 1.514 + // from its signal, which means that SelfDestruct_m has not been dispatched 1.515 + // yet either, so this PCMedia will still be around when this dispatch reaches 1.516 + // main. 1.517 + GetMainThread()->Dispatch( 1.518 + WrapRunnable(this, 1.519 + &PeerConnectionMedia::IceGatheringStateChange_m, 1.520 + ctx, 1.521 + state), 1.522 + NS_DISPATCH_NORMAL); 1.523 +} 1.524 + 1.525 +void 1.526 +PeerConnectionMedia::IceConnectionStateChange_s(NrIceCtx* ctx, 1.527 + NrIceCtx::ConnectionState state) 1.528 +{ 1.529 + ASSERT_ON_THREAD(mSTSThread); 1.530 + // ShutdownMediaTransport_s has not run yet because it unhooks this function 1.531 + // from its signal, which means that SelfDestruct_m has not been dispatched 1.532 + // yet either, so this PCMedia will still be around when this dispatch reaches 1.533 + // main. 1.534 + GetMainThread()->Dispatch( 1.535 + WrapRunnable(this, 1.536 + &PeerConnectionMedia::IceConnectionStateChange_m, 1.537 + ctx, 1.538 + state), 1.539 + NS_DISPATCH_NORMAL); 1.540 +} 1.541 + 1.542 +void 1.543 +PeerConnectionMedia::IceGatheringStateChange_m(NrIceCtx* ctx, 1.544 + NrIceCtx::GatheringState state) 1.545 +{ 1.546 + ASSERT_ON_THREAD(mMainThread); 1.547 + SignalIceGatheringStateChange(ctx, state); 1.548 +} 1.549 + 1.550 +void 1.551 +PeerConnectionMedia::IceConnectionStateChange_m(NrIceCtx* ctx, 1.552 + NrIceCtx::ConnectionState state) 1.553 +{ 1.554 + ASSERT_ON_THREAD(mMainThread); 1.555 + SignalIceConnectionStateChange(ctx, state); 1.556 +} 1.557 + 1.558 +void 1.559 +PeerConnectionMedia::IceStreamReady(NrIceMediaStream *aStream) 1.560 +{ 1.561 + MOZ_ASSERT(aStream); 1.562 + 1.563 + CSFLogDebug(logTag, "%s: %s", __FUNCTION__, aStream->name().c_str()); 1.564 +} 1.565 + 1.566 +void 1.567 +LocalSourceStreamInfo::StorePipeline(int aTrack, 1.568 + mozilla::RefPtr<mozilla::MediaPipeline> aPipeline) 1.569 +{ 1.570 + MOZ_ASSERT(mPipelines.find(aTrack) == mPipelines.end()); 1.571 + if (mPipelines.find(aTrack) != mPipelines.end()) { 1.572 + CSFLogError(logTag, "%s: Storing duplicate track", __FUNCTION__); 1.573 + return; 1.574 + } 1.575 + //TODO: Revisit once we start supporting multiple streams or multiple tracks 1.576 + // of same type 1.577 + mPipelines[aTrack] = aPipeline; 1.578 +} 1.579 + 1.580 +void 1.581 +RemoteSourceStreamInfo::StorePipeline(int aTrack, 1.582 + bool aIsVideo, 1.583 + mozilla::RefPtr<mozilla::MediaPipeline> aPipeline) 1.584 +{ 1.585 + MOZ_ASSERT(mPipelines.find(aTrack) == mPipelines.end()); 1.586 + if (mPipelines.find(aTrack) != mPipelines.end()) { 1.587 + CSFLogError(logTag, "%s: Request to store duplicate track %d", __FUNCTION__, aTrack); 1.588 + return; 1.589 + } 1.590 + CSFLogDebug(logTag, "%s track %d %s = %p", __FUNCTION__, aTrack, aIsVideo ? "video" : "audio", 1.591 + aPipeline.get()); 1.592 + // See if we have both audio and video here, and if so cross the streams and sync them 1.593 + // XXX Needs to be adjusted when we support multiple streams of the same type 1.594 + for (std::map<int, bool>::iterator it = mTypes.begin(); it != mTypes.end(); ++it) { 1.595 + if (it->second != aIsVideo) { 1.596 + // Ok, we have one video, one non-video - cross the streams! 1.597 + mozilla::WebrtcAudioConduit *audio_conduit = static_cast<mozilla::WebrtcAudioConduit*> 1.598 + (aIsVideo ? 1.599 + mPipelines[it->first]->Conduit() : 1.600 + aPipeline->Conduit()); 1.601 + mozilla::WebrtcVideoConduit *video_conduit = static_cast<mozilla::WebrtcVideoConduit*> 1.602 + (aIsVideo ? 1.603 + aPipeline->Conduit() : 1.604 + mPipelines[it->first]->Conduit()); 1.605 + video_conduit->SyncTo(audio_conduit); 1.606 + CSFLogDebug(logTag, "Syncing %p to %p, %d to %d", video_conduit, audio_conduit, 1.607 + aTrack, it->first); 1.608 + } 1.609 + } 1.610 + //TODO: Revisit once we start supporting multiple streams or multiple tracks 1.611 + // of same type 1.612 + mPipelines[aTrack] = aPipeline; 1.613 + //TODO: move to attribute on Pipeline 1.614 + mTypes[aTrack] = aIsVideo; 1.615 +} 1.616 + 1.617 +RefPtr<MediaPipeline> SourceStreamInfo::GetPipelineByLevel_m(int level) { 1.618 + ASSERT_ON_THREAD(mParent->GetMainThread()); 1.619 + 1.620 + // Refuse to hand out references if we're tearing down. 1.621 + // (Since teardown involves a dispatch to and from STS before MediaPipelines 1.622 + // are released, it is safe to start other dispatches to and from STS with a 1.623 + // RefPtr<MediaPipeline>, since that reference won't be the last one 1.624 + // standing) 1.625 + if (mMediaStream) { 1.626 + for (auto p = mPipelines.begin(); p != mPipelines.end(); ++p) { 1.627 + if (p->second->level() == level) { 1.628 + return p->second; 1.629 + } 1.630 + } 1.631 + } 1.632 + 1.633 + return nullptr; 1.634 +} 1.635 + 1.636 +bool RemoteSourceStreamInfo::SetUsingBundle_m(int aLevel, bool decision) { 1.637 + ASSERT_ON_THREAD(mParent->GetMainThread()); 1.638 + 1.639 + RefPtr<MediaPipeline> pipeline(GetPipelineByLevel_m(aLevel)); 1.640 + 1.641 + if (pipeline) { 1.642 + RUN_ON_THREAD(mParent->GetSTSThread(), 1.643 + WrapRunnable( 1.644 + pipeline, 1.645 + &MediaPipeline::SetUsingBundle_s, 1.646 + decision 1.647 + ), 1.648 + NS_DISPATCH_NORMAL); 1.649 + return true; 1.650 + } 1.651 + return false; 1.652 +} 1.653 + 1.654 +} // namespace sipcc