media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
michael@0 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4 #include <string>
michael@0 5
michael@0 6 #include "CSFLog.h"
michael@0 7
michael@0 8 #include "nspr.h"
michael@0 9 #include "cc_constants.h"
michael@0 10
michael@0 11 #include "nricectx.h"
michael@0 12 #include "nricemediastream.h"
michael@0 13 #include "PeerConnectionImpl.h"
michael@0 14 #include "PeerConnectionMedia.h"
michael@0 15 #include "AudioConduit.h"
michael@0 16 #include "VideoConduit.h"
michael@0 17 #include "runnable_utils.h"
michael@0 18
michael@0 19 #ifdef MOZILLA_INTERNAL_API
michael@0 20 #include "MediaStreamList.h"
michael@0 21 #include "nsIScriptGlobalObject.h"
michael@0 22 #include "mozilla/Preferences.h"
michael@0 23 #include "mozilla/dom/RTCStatsReportBinding.h"
michael@0 24 #endif
michael@0 25
michael@0 26 using namespace mozilla;
michael@0 27 using namespace mozilla::dom;
michael@0 28
michael@0 29 namespace sipcc {
michael@0 30
michael@0 31 static const char* logTag = "PeerConnectionMedia";
michael@0 32 static const mozilla::TrackID TRACK_AUDIO = 0;
michael@0 33 static const mozilla::TrackID TRACK_VIDEO = 1;
michael@0 34
michael@0 35 /* If the ExpectAudio hint is on we will add a track at the default first
michael@0 36 * audio track ID (0)
michael@0 37 * FIX - Do we need to iterate over the tracks instead of taking these hints?
michael@0 38 */
michael@0 39 void
michael@0 40 LocalSourceStreamInfo::ExpectAudio(const mozilla::TrackID aID)
michael@0 41 {
michael@0 42 mAudioTracks.AppendElement(aID);
michael@0 43 }
michael@0 44
michael@0 45 // If the ExpectVideo hint is on we will add a track at the default first
michael@0 46 // video track ID (1).
michael@0 47 void
michael@0 48 LocalSourceStreamInfo::ExpectVideo(const mozilla::TrackID aID)
michael@0 49 {
michael@0 50 mVideoTracks.AppendElement(aID);
michael@0 51 }
michael@0 52
michael@0 53 unsigned
michael@0 54 LocalSourceStreamInfo::AudioTrackCount()
michael@0 55 {
michael@0 56 return mAudioTracks.Length();
michael@0 57 }
michael@0 58
michael@0 59 unsigned
michael@0 60 LocalSourceStreamInfo::VideoTrackCount()
michael@0 61 {
michael@0 62 return mVideoTracks.Length();
michael@0 63 }
michael@0 64
michael@0 65 void LocalSourceStreamInfo::DetachTransport_s()
michael@0 66 {
michael@0 67 ASSERT_ON_THREAD(mParent->GetSTSThread());
michael@0 68 // walk through all the MediaPipelines and call the shutdown
michael@0 69 // functions for transport. Must be on the STS thread.
michael@0 70 for (std::map<int, mozilla::RefPtr<mozilla::MediaPipeline> >::iterator it =
michael@0 71 mPipelines.begin(); it != mPipelines.end();
michael@0 72 ++it) {
michael@0 73 it->second->ShutdownTransport_s();
michael@0 74 }
michael@0 75 }
michael@0 76
michael@0 77 void LocalSourceStreamInfo::DetachMedia_m()
michael@0 78 {
michael@0 79 ASSERT_ON_THREAD(mParent->GetMainThread());
michael@0 80 // walk through all the MediaPipelines and call the shutdown
michael@0 81 // functions. Must be on the main thread.
michael@0 82 for (std::map<int, mozilla::RefPtr<mozilla::MediaPipeline> >::iterator it =
michael@0 83 mPipelines.begin(); it != mPipelines.end();
michael@0 84 ++it) {
michael@0 85 it->second->ShutdownMedia_m();
michael@0 86 }
michael@0 87 mAudioTracks.Clear();
michael@0 88 mVideoTracks.Clear();
michael@0 89 mMediaStream = nullptr;
michael@0 90 }
michael@0 91
michael@0 92 void RemoteSourceStreamInfo::DetachTransport_s()
michael@0 93 {
michael@0 94 ASSERT_ON_THREAD(mParent->GetSTSThread());
michael@0 95 // walk through all the MediaPipelines and call the shutdown
michael@0 96 // transport functions. Must be on the STS thread.
michael@0 97 for (std::map<int, mozilla::RefPtr<mozilla::MediaPipeline> >::iterator it =
michael@0 98 mPipelines.begin(); it != mPipelines.end();
michael@0 99 ++it) {
michael@0 100 it->second->ShutdownTransport_s();
michael@0 101 }
michael@0 102 }
michael@0 103
michael@0 104 void RemoteSourceStreamInfo::DetachMedia_m()
michael@0 105 {
michael@0 106 ASSERT_ON_THREAD(mParent->GetMainThread());
michael@0 107
michael@0 108 // walk through all the MediaPipelines and call the shutdown
michael@0 109 // media functions. Must be on the main thread.
michael@0 110 for (std::map<int, mozilla::RefPtr<mozilla::MediaPipeline> >::iterator it =
michael@0 111 mPipelines.begin(); it != mPipelines.end();
michael@0 112 ++it) {
michael@0 113 it->second->ShutdownMedia_m();
michael@0 114 }
michael@0 115 mMediaStream = nullptr;
michael@0 116 }
michael@0 117
michael@0 118 already_AddRefed<PeerConnectionImpl>
michael@0 119 PeerConnectionImpl::Constructor(const dom::GlobalObject& aGlobal, ErrorResult& rv)
michael@0 120 {
michael@0 121 nsRefPtr<PeerConnectionImpl> pc = new PeerConnectionImpl(&aGlobal);
michael@0 122
michael@0 123 CSFLogDebug(logTag, "Created PeerConnection: %p", pc.get());
michael@0 124
michael@0 125 return pc.forget();
michael@0 126 }
michael@0 127
michael@0 128 PeerConnectionImpl* PeerConnectionImpl::CreatePeerConnection()
michael@0 129 {
michael@0 130 PeerConnectionImpl *pc = new PeerConnectionImpl();
michael@0 131
michael@0 132 CSFLogDebug(logTag, "Created PeerConnection: %p", pc);
michael@0 133
michael@0 134 return pc;
michael@0 135 }
michael@0 136
michael@0 137
michael@0 138 PeerConnectionMedia::PeerConnectionMedia(PeerConnectionImpl *parent)
michael@0 139 : mParent(parent),
michael@0 140 mLocalSourceStreamsLock("PeerConnectionMedia.mLocalSourceStreamsLock"),
michael@0 141 mIceCtx(nullptr),
michael@0 142 mDNSResolver(new mozilla::NrIceResolver()),
michael@0 143 mMainThread(mParent->GetMainThread()),
michael@0 144 mSTSThread(mParent->GetSTSThread()) {}
michael@0 145
michael@0 146 nsresult PeerConnectionMedia::Init(const std::vector<NrIceStunServer>& stun_servers,
michael@0 147 const std::vector<NrIceTurnServer>& turn_servers)
michael@0 148 {
michael@0 149 // TODO(ekr@rtfm.com): need some way to set not offerer later
michael@0 150 // Looks like a bug in the NrIceCtx API.
michael@0 151 mIceCtx = NrIceCtx::Create("PC:" + mParent->GetName(), true);
michael@0 152 if(!mIceCtx) {
michael@0 153 CSFLogError(logTag, "%s: Failed to create Ice Context", __FUNCTION__);
michael@0 154 return NS_ERROR_FAILURE;
michael@0 155 }
michael@0 156 nsresult rv;
michael@0 157 if (NS_FAILED(rv = mIceCtx->SetStunServers(stun_servers))) {
michael@0 158 CSFLogError(logTag, "%s: Failed to set stun servers", __FUNCTION__);
michael@0 159 return rv;
michael@0 160 }
michael@0 161 // Give us a way to globally turn off TURN support
michael@0 162 #ifdef MOZILLA_INTERNAL_API
michael@0 163 bool disabled = Preferences::GetBool("media.peerconnection.turn.disable", false);
michael@0 164 #else
michael@0 165 bool disabled = false;
michael@0 166 #endif
michael@0 167 if (!disabled) {
michael@0 168 if (NS_FAILED(rv = mIceCtx->SetTurnServers(turn_servers))) {
michael@0 169 CSFLogError(logTag, "%s: Failed to set turn servers", __FUNCTION__);
michael@0 170 return rv;
michael@0 171 }
michael@0 172 } else if (turn_servers.size() != 0) {
michael@0 173 CSFLogError(logTag, "%s: Setting turn servers disabled", __FUNCTION__);
michael@0 174 }
michael@0 175 if (NS_FAILED(rv = mDNSResolver->Init())) {
michael@0 176 CSFLogError(logTag, "%s: Failed to initialize dns resolver", __FUNCTION__);
michael@0 177 return rv;
michael@0 178 }
michael@0 179 if (NS_FAILED(rv = mIceCtx->SetResolver(mDNSResolver->AllocateResolver()))) {
michael@0 180 CSFLogError(logTag, "%s: Failed to get dns resolver", __FUNCTION__);
michael@0 181 return rv;
michael@0 182 }
michael@0 183 mIceCtx->SignalGatheringStateChange.connect(
michael@0 184 this,
michael@0 185 &PeerConnectionMedia::IceGatheringStateChange_s);
michael@0 186 mIceCtx->SignalConnectionStateChange.connect(
michael@0 187 this,
michael@0 188 &PeerConnectionMedia::IceConnectionStateChange_s);
michael@0 189
michael@0 190 // Create three streams to start with.
michael@0 191 // One each for audio, video and DataChannel
michael@0 192 // TODO: this will be re-visited
michael@0 193 RefPtr<NrIceMediaStream> audioStream =
michael@0 194 mIceCtx->CreateStream((mParent->GetName()+": stream1/audio").c_str(), 2);
michael@0 195 RefPtr<NrIceMediaStream> videoStream =
michael@0 196 mIceCtx->CreateStream((mParent->GetName()+": stream2/video").c_str(), 2);
michael@0 197 RefPtr<NrIceMediaStream> dcStream =
michael@0 198 mIceCtx->CreateStream((mParent->GetName()+": stream3/data").c_str(), 2);
michael@0 199
michael@0 200 if (!audioStream) {
michael@0 201 CSFLogError(logTag, "%s: audio stream is NULL", __FUNCTION__);
michael@0 202 return NS_ERROR_FAILURE;
michael@0 203 } else {
michael@0 204 mIceStreams.push_back(audioStream);
michael@0 205 }
michael@0 206
michael@0 207 if (!videoStream) {
michael@0 208 CSFLogError(logTag, "%s: video stream is NULL", __FUNCTION__);
michael@0 209 return NS_ERROR_FAILURE;
michael@0 210 } else {
michael@0 211 mIceStreams.push_back(videoStream);
michael@0 212 }
michael@0 213
michael@0 214 if (!dcStream) {
michael@0 215 CSFLogError(logTag, "%s: datachannel stream is NULL", __FUNCTION__);
michael@0 216 return NS_ERROR_FAILURE;
michael@0 217 } else {
michael@0 218 mIceStreams.push_back(dcStream);
michael@0 219 }
michael@0 220
michael@0 221 // TODO(ekr@rtfm.com): This is not connected to the PCCimpl.
michael@0 222 // Will need to do that later.
michael@0 223 for (std::size_t i=0; i<mIceStreams.size(); i++) {
michael@0 224 mIceStreams[i]->SignalReady.connect(this, &PeerConnectionMedia::IceStreamReady);
michael@0 225 }
michael@0 226
michael@0 227 // TODO(ekr@rtfm.com): When we have a generic error reporting mechanism,
michael@0 228 // figure out how to report that StartGathering failed. Bug 827982.
michael@0 229 RUN_ON_THREAD(mIceCtx->thread(),
michael@0 230 WrapRunnable(mIceCtx, &NrIceCtx::StartGathering), NS_DISPATCH_NORMAL);
michael@0 231
michael@0 232 return NS_OK;
michael@0 233 }
michael@0 234
michael@0 235 nsresult
michael@0 236 PeerConnectionMedia::AddStream(nsIDOMMediaStream* aMediaStream, uint32_t *stream_id)
michael@0 237 {
michael@0 238 if (!aMediaStream) {
michael@0 239 CSFLogError(logTag, "%s - aMediaStream is NULL", __FUNCTION__);
michael@0 240 return NS_ERROR_FAILURE;
michael@0 241 }
michael@0 242
michael@0 243 DOMMediaStream* stream = static_cast<DOMMediaStream*>(aMediaStream);
michael@0 244
michael@0 245 CSFLogDebug(logTag, "%s: MediaStream: %p",
michael@0 246 __FUNCTION__, aMediaStream);
michael@0 247
michael@0 248 // Adding tracks here based on nsDOMMediaStream expectation settings
michael@0 249 uint32_t hints = stream->GetHintContents();
michael@0 250 #ifdef MOZILLA_INTERNAL_API
michael@0 251 if (!Preferences::GetBool("media.peerconnection.video.enabled", true)) {
michael@0 252 hints &= ~(DOMMediaStream::HINT_CONTENTS_VIDEO);
michael@0 253 }
michael@0 254 #endif
michael@0 255
michael@0 256 if (!(hints & (DOMMediaStream::HINT_CONTENTS_AUDIO |
michael@0 257 DOMMediaStream::HINT_CONTENTS_VIDEO))) {
michael@0 258 CSFLogDebug(logTag, "Empty Stream !!");
michael@0 259 return NS_OK;
michael@0 260 }
michael@0 261
michael@0 262 // Now see if we already have a stream of this type, since we only
michael@0 263 // allow one of each.
michael@0 264 // TODO(ekr@rtfm.com): remove this when multiple of each stream
michael@0 265 // is allowed
michael@0 266 mozilla::MutexAutoLock lock(mLocalSourceStreamsLock);
michael@0 267 for (uint32_t u = 0; u < mLocalSourceStreams.Length(); u++) {
michael@0 268 nsRefPtr<LocalSourceStreamInfo> localSourceStream = mLocalSourceStreams[u];
michael@0 269
michael@0 270 if (localSourceStream->GetMediaStream()->GetHintContents() & hints) {
michael@0 271 CSFLogError(logTag, "Only one stream of any given type allowed");
michael@0 272 return NS_ERROR_FAILURE;
michael@0 273 }
michael@0 274 }
michael@0 275
michael@0 276 // OK, we're good to add
michael@0 277 nsRefPtr<LocalSourceStreamInfo> localSourceStream =
michael@0 278 new LocalSourceStreamInfo(stream, this);
michael@0 279 *stream_id = mLocalSourceStreams.Length();
michael@0 280
michael@0 281 if (hints & DOMMediaStream::HINT_CONTENTS_AUDIO) {
michael@0 282 localSourceStream->ExpectAudio(TRACK_AUDIO);
michael@0 283 }
michael@0 284
michael@0 285 if (hints & DOMMediaStream::HINT_CONTENTS_VIDEO) {
michael@0 286 localSourceStream->ExpectVideo(TRACK_VIDEO);
michael@0 287 }
michael@0 288
michael@0 289 mLocalSourceStreams.AppendElement(localSourceStream);
michael@0 290
michael@0 291 return NS_OK;
michael@0 292 }
michael@0 293
michael@0 294 nsresult
michael@0 295 PeerConnectionMedia::RemoveStream(nsIDOMMediaStream* aMediaStream, uint32_t *stream_id)
michael@0 296 {
michael@0 297 MOZ_ASSERT(aMediaStream);
michael@0 298
michael@0 299 DOMMediaStream* stream = static_cast<DOMMediaStream*>(aMediaStream);
michael@0 300
michael@0 301 CSFLogDebug(logTag, "%s: MediaStream: %p",
michael@0 302 __FUNCTION__, aMediaStream);
michael@0 303
michael@0 304 mozilla::MutexAutoLock lock(mLocalSourceStreamsLock);
michael@0 305 for (uint32_t u = 0; u < mLocalSourceStreams.Length(); u++) {
michael@0 306 nsRefPtr<LocalSourceStreamInfo> localSourceStream = mLocalSourceStreams[u];
michael@0 307 if (localSourceStream->GetMediaStream() == stream) {
michael@0 308 *stream_id = u;
michael@0 309 return NS_OK;
michael@0 310 }
michael@0 311 }
michael@0 312
michael@0 313 return NS_ERROR_ILLEGAL_VALUE;
michael@0 314 }
michael@0 315
michael@0 316 void
michael@0 317 PeerConnectionMedia::SelfDestruct()
michael@0 318 {
michael@0 319 ASSERT_ON_THREAD(mMainThread);
michael@0 320
michael@0 321 CSFLogDebug(logTag, "%s: ", __FUNCTION__);
michael@0 322
michael@0 323 // Shut down the media
michael@0 324 for (uint32_t i=0; i < mLocalSourceStreams.Length(); ++i) {
michael@0 325 mLocalSourceStreams[i]->DetachMedia_m();
michael@0 326 }
michael@0 327
michael@0 328 for (uint32_t i=0; i < mRemoteSourceStreams.Length(); ++i) {
michael@0 329 mRemoteSourceStreams[i]->DetachMedia_m();
michael@0 330 }
michael@0 331
michael@0 332 // Shutdown the transport (async)
michael@0 333 RUN_ON_THREAD(mSTSThread, WrapRunnable(
michael@0 334 this, &PeerConnectionMedia::ShutdownMediaTransport_s),
michael@0 335 NS_DISPATCH_NORMAL);
michael@0 336
michael@0 337 CSFLogDebug(logTag, "%s: Media shut down", __FUNCTION__);
michael@0 338 }
michael@0 339
michael@0 340 void
michael@0 341 PeerConnectionMedia::SelfDestruct_m()
michael@0 342 {
michael@0 343 CSFLogDebug(logTag, "%s: ", __FUNCTION__);
michael@0 344
michael@0 345 ASSERT_ON_THREAD(mMainThread);
michael@0 346 mLocalSourceStreams.Clear();
michael@0 347 mRemoteSourceStreams.Clear();
michael@0 348
michael@0 349 // Final self-destruct.
michael@0 350 this->Release();
michael@0 351 }
michael@0 352
michael@0 353 void
michael@0 354 PeerConnectionMedia::ShutdownMediaTransport_s()
michael@0 355 {
michael@0 356 ASSERT_ON_THREAD(mSTSThread);
michael@0 357
michael@0 358 CSFLogDebug(logTag, "%s: ", __FUNCTION__);
michael@0 359
michael@0 360 for (uint32_t i=0; i < mLocalSourceStreams.Length(); ++i) {
michael@0 361 mLocalSourceStreams[i]->DetachTransport_s();
michael@0 362 }
michael@0 363
michael@0 364 for (uint32_t i=0; i < mRemoteSourceStreams.Length(); ++i) {
michael@0 365 mRemoteSourceStreams[i]->DetachTransport_s();
michael@0 366 }
michael@0 367
michael@0 368 disconnect_all();
michael@0 369 mTransportFlows.clear();
michael@0 370 mIceStreams.clear();
michael@0 371 mIceCtx = nullptr;
michael@0 372
michael@0 373 mMainThread->Dispatch(WrapRunnable(this, &PeerConnectionMedia::SelfDestruct_m),
michael@0 374 NS_DISPATCH_NORMAL);
michael@0 375 }
michael@0 376
michael@0 377 LocalSourceStreamInfo*
michael@0 378 PeerConnectionMedia::GetLocalStream(int aIndex)
michael@0 379 {
michael@0 380 if(aIndex < 0 || aIndex >= (int) mLocalSourceStreams.Length()) {
michael@0 381 return nullptr;
michael@0 382 }
michael@0 383
michael@0 384 MOZ_ASSERT(mLocalSourceStreams[aIndex]);
michael@0 385 return mLocalSourceStreams[aIndex];
michael@0 386 }
michael@0 387
michael@0 388 RemoteSourceStreamInfo*
michael@0 389 PeerConnectionMedia::GetRemoteStream(int aIndex)
michael@0 390 {
michael@0 391 if(aIndex < 0 || aIndex >= (int) mRemoteSourceStreams.Length()) {
michael@0 392 return nullptr;
michael@0 393 }
michael@0 394
michael@0 395 MOZ_ASSERT(mRemoteSourceStreams[aIndex]);
michael@0 396 return mRemoteSourceStreams[aIndex];
michael@0 397 }
michael@0 398
michael@0 399 bool
michael@0 400 PeerConnectionMedia::SetUsingBundle_m(int level, bool decision)
michael@0 401 {
michael@0 402 ASSERT_ON_THREAD(mMainThread);
michael@0 403 for (size_t i = 0; i < mRemoteSourceStreams.Length(); ++i) {
michael@0 404 if (mRemoteSourceStreams[i]->SetUsingBundle_m(level, decision)) {
michael@0 405 // Found the MediaPipeline for |level|
michael@0 406 return true;
michael@0 407 }
michael@0 408 }
michael@0 409 CSFLogWarn(logTag, "Could not locate level %d to set bundle flag to %s",
michael@0 410 static_cast<int>(level),
michael@0 411 decision ? "true" : "false");
michael@0 412 return false;
michael@0 413 }
michael@0 414
michael@0 415 static void
michael@0 416 UpdateFilterFromRemoteDescription_s(
michael@0 417 RefPtr<mozilla::MediaPipeline> receive,
michael@0 418 RefPtr<mozilla::MediaPipeline> transmit,
michael@0 419 nsAutoPtr<mozilla::MediaPipelineFilter> filter) {
michael@0 420
michael@0 421 // Update filter, and make a copy of the final version.
michael@0 422 mozilla::MediaPipelineFilter *finalFilter(
michael@0 423 receive->UpdateFilterFromRemoteDescription_s(filter));
michael@0 424
michael@0 425 if (finalFilter) {
michael@0 426 filter = new mozilla::MediaPipelineFilter(*finalFilter);
michael@0 427 }
michael@0 428
michael@0 429 // Set same filter on transmit pipeline too.
michael@0 430 transmit->UpdateFilterFromRemoteDescription_s(filter);
michael@0 431 }
michael@0 432
michael@0 433 bool
michael@0 434 PeerConnectionMedia::UpdateFilterFromRemoteDescription_m(
michael@0 435 int level,
michael@0 436 nsAutoPtr<mozilla::MediaPipelineFilter> filter)
michael@0 437 {
michael@0 438 ASSERT_ON_THREAD(mMainThread);
michael@0 439
michael@0 440 RefPtr<mozilla::MediaPipeline> receive;
michael@0 441 for (size_t i = 0; !receive && i < mRemoteSourceStreams.Length(); ++i) {
michael@0 442 receive = mRemoteSourceStreams[i]->GetPipelineByLevel_m(level);
michael@0 443 }
michael@0 444
michael@0 445 RefPtr<mozilla::MediaPipeline> transmit;
michael@0 446 for (size_t i = 0; !transmit && i < mLocalSourceStreams.Length(); ++i) {
michael@0 447 transmit = mLocalSourceStreams[i]->GetPipelineByLevel_m(level);
michael@0 448 }
michael@0 449
michael@0 450 if (receive && transmit) {
michael@0 451 // GetPipelineByLevel_m will return nullptr if shutdown is in progress;
michael@0 452 // since shutdown is initiated in main, and involves a dispatch to STS
michael@0 453 // before the pipelines are released, our dispatch to STS will complete
michael@0 454 // before any release can happen due to a shutdown that hasn't started yet.
michael@0 455 RUN_ON_THREAD(GetSTSThread(),
michael@0 456 WrapRunnableNM(
michael@0 457 &UpdateFilterFromRemoteDescription_s,
michael@0 458 receive,
michael@0 459 transmit,
michael@0 460 filter
michael@0 461 ),
michael@0 462 NS_DISPATCH_NORMAL);
michael@0 463 return true;
michael@0 464 } else {
michael@0 465 CSFLogWarn(logTag, "Could not locate level %d to update filter",
michael@0 466 static_cast<int>(level));
michael@0 467 }
michael@0 468 return false;
michael@0 469 }
michael@0 470
michael@0 471 nsresult
michael@0 472 PeerConnectionMedia::AddRemoteStream(nsRefPtr<RemoteSourceStreamInfo> aInfo,
michael@0 473 int *aIndex)
michael@0 474 {
michael@0 475 MOZ_ASSERT(aIndex);
michael@0 476
michael@0 477 *aIndex = mRemoteSourceStreams.Length();
michael@0 478
michael@0 479 mRemoteSourceStreams.AppendElement(aInfo);
michael@0 480
michael@0 481 return NS_OK;
michael@0 482 }
michael@0 483
michael@0 484 nsresult
michael@0 485 PeerConnectionMedia::AddRemoteStreamHint(int aIndex, bool aIsVideo)
michael@0 486 {
michael@0 487 if (aIndex < 0 ||
michael@0 488 static_cast<unsigned int>(aIndex) >= mRemoteSourceStreams.Length()) {
michael@0 489 return NS_ERROR_ILLEGAL_VALUE;
michael@0 490 }
michael@0 491
michael@0 492 RemoteSourceStreamInfo *pInfo = mRemoteSourceStreams.ElementAt(aIndex);
michael@0 493 MOZ_ASSERT(pInfo);
michael@0 494
michael@0 495 if (aIsVideo) {
michael@0 496 pInfo->mTrackTypeHints |= DOMMediaStream::HINT_CONTENTS_VIDEO;
michael@0 497 } else {
michael@0 498 pInfo->mTrackTypeHints |= DOMMediaStream::HINT_CONTENTS_AUDIO;
michael@0 499 }
michael@0 500
michael@0 501 return NS_OK;
michael@0 502 }
michael@0 503
michael@0 504
michael@0 505 void
michael@0 506 PeerConnectionMedia::IceGatheringStateChange_s(NrIceCtx* ctx,
michael@0 507 NrIceCtx::GatheringState state)
michael@0 508 {
michael@0 509 ASSERT_ON_THREAD(mSTSThread);
michael@0 510 // ShutdownMediaTransport_s has not run yet because it unhooks this function
michael@0 511 // from its signal, which means that SelfDestruct_m has not been dispatched
michael@0 512 // yet either, so this PCMedia will still be around when this dispatch reaches
michael@0 513 // main.
michael@0 514 GetMainThread()->Dispatch(
michael@0 515 WrapRunnable(this,
michael@0 516 &PeerConnectionMedia::IceGatheringStateChange_m,
michael@0 517 ctx,
michael@0 518 state),
michael@0 519 NS_DISPATCH_NORMAL);
michael@0 520 }
michael@0 521
michael@0 522 void
michael@0 523 PeerConnectionMedia::IceConnectionStateChange_s(NrIceCtx* ctx,
michael@0 524 NrIceCtx::ConnectionState state)
michael@0 525 {
michael@0 526 ASSERT_ON_THREAD(mSTSThread);
michael@0 527 // ShutdownMediaTransport_s has not run yet because it unhooks this function
michael@0 528 // from its signal, which means that SelfDestruct_m has not been dispatched
michael@0 529 // yet either, so this PCMedia will still be around when this dispatch reaches
michael@0 530 // main.
michael@0 531 GetMainThread()->Dispatch(
michael@0 532 WrapRunnable(this,
michael@0 533 &PeerConnectionMedia::IceConnectionStateChange_m,
michael@0 534 ctx,
michael@0 535 state),
michael@0 536 NS_DISPATCH_NORMAL);
michael@0 537 }
michael@0 538
michael@0 539 void
michael@0 540 PeerConnectionMedia::IceGatheringStateChange_m(NrIceCtx* ctx,
michael@0 541 NrIceCtx::GatheringState state)
michael@0 542 {
michael@0 543 ASSERT_ON_THREAD(mMainThread);
michael@0 544 SignalIceGatheringStateChange(ctx, state);
michael@0 545 }
michael@0 546
michael@0 547 void
michael@0 548 PeerConnectionMedia::IceConnectionStateChange_m(NrIceCtx* ctx,
michael@0 549 NrIceCtx::ConnectionState state)
michael@0 550 {
michael@0 551 ASSERT_ON_THREAD(mMainThread);
michael@0 552 SignalIceConnectionStateChange(ctx, state);
michael@0 553 }
michael@0 554
michael@0 555 void
michael@0 556 PeerConnectionMedia::IceStreamReady(NrIceMediaStream *aStream)
michael@0 557 {
michael@0 558 MOZ_ASSERT(aStream);
michael@0 559
michael@0 560 CSFLogDebug(logTag, "%s: %s", __FUNCTION__, aStream->name().c_str());
michael@0 561 }
michael@0 562
michael@0 563 void
michael@0 564 LocalSourceStreamInfo::StorePipeline(int aTrack,
michael@0 565 mozilla::RefPtr<mozilla::MediaPipeline> aPipeline)
michael@0 566 {
michael@0 567 MOZ_ASSERT(mPipelines.find(aTrack) == mPipelines.end());
michael@0 568 if (mPipelines.find(aTrack) != mPipelines.end()) {
michael@0 569 CSFLogError(logTag, "%s: Storing duplicate track", __FUNCTION__);
michael@0 570 return;
michael@0 571 }
michael@0 572 //TODO: Revisit once we start supporting multiple streams or multiple tracks
michael@0 573 // of same type
michael@0 574 mPipelines[aTrack] = aPipeline;
michael@0 575 }
michael@0 576
michael@0 577 void
michael@0 578 RemoteSourceStreamInfo::StorePipeline(int aTrack,
michael@0 579 bool aIsVideo,
michael@0 580 mozilla::RefPtr<mozilla::MediaPipeline> aPipeline)
michael@0 581 {
michael@0 582 MOZ_ASSERT(mPipelines.find(aTrack) == mPipelines.end());
michael@0 583 if (mPipelines.find(aTrack) != mPipelines.end()) {
michael@0 584 CSFLogError(logTag, "%s: Request to store duplicate track %d", __FUNCTION__, aTrack);
michael@0 585 return;
michael@0 586 }
michael@0 587 CSFLogDebug(logTag, "%s track %d %s = %p", __FUNCTION__, aTrack, aIsVideo ? "video" : "audio",
michael@0 588 aPipeline.get());
michael@0 589 // See if we have both audio and video here, and if so cross the streams and sync them
michael@0 590 // XXX Needs to be adjusted when we support multiple streams of the same type
michael@0 591 for (std::map<int, bool>::iterator it = mTypes.begin(); it != mTypes.end(); ++it) {
michael@0 592 if (it->second != aIsVideo) {
michael@0 593 // Ok, we have one video, one non-video - cross the streams!
michael@0 594 mozilla::WebrtcAudioConduit *audio_conduit = static_cast<mozilla::WebrtcAudioConduit*>
michael@0 595 (aIsVideo ?
michael@0 596 mPipelines[it->first]->Conduit() :
michael@0 597 aPipeline->Conduit());
michael@0 598 mozilla::WebrtcVideoConduit *video_conduit = static_cast<mozilla::WebrtcVideoConduit*>
michael@0 599 (aIsVideo ?
michael@0 600 aPipeline->Conduit() :
michael@0 601 mPipelines[it->first]->Conduit());
michael@0 602 video_conduit->SyncTo(audio_conduit);
michael@0 603 CSFLogDebug(logTag, "Syncing %p to %p, %d to %d", video_conduit, audio_conduit,
michael@0 604 aTrack, it->first);
michael@0 605 }
michael@0 606 }
michael@0 607 //TODO: Revisit once we start supporting multiple streams or multiple tracks
michael@0 608 // of same type
michael@0 609 mPipelines[aTrack] = aPipeline;
michael@0 610 //TODO: move to attribute on Pipeline
michael@0 611 mTypes[aTrack] = aIsVideo;
michael@0 612 }
michael@0 613
michael@0 614 RefPtr<MediaPipeline> SourceStreamInfo::GetPipelineByLevel_m(int level) {
michael@0 615 ASSERT_ON_THREAD(mParent->GetMainThread());
michael@0 616
michael@0 617 // Refuse to hand out references if we're tearing down.
michael@0 618 // (Since teardown involves a dispatch to and from STS before MediaPipelines
michael@0 619 // are released, it is safe to start other dispatches to and from STS with a
michael@0 620 // RefPtr<MediaPipeline>, since that reference won't be the last one
michael@0 621 // standing)
michael@0 622 if (mMediaStream) {
michael@0 623 for (auto p = mPipelines.begin(); p != mPipelines.end(); ++p) {
michael@0 624 if (p->second->level() == level) {
michael@0 625 return p->second;
michael@0 626 }
michael@0 627 }
michael@0 628 }
michael@0 629
michael@0 630 return nullptr;
michael@0 631 }
michael@0 632
michael@0 633 bool RemoteSourceStreamInfo::SetUsingBundle_m(int aLevel, bool decision) {
michael@0 634 ASSERT_ON_THREAD(mParent->GetMainThread());
michael@0 635
michael@0 636 RefPtr<MediaPipeline> pipeline(GetPipelineByLevel_m(aLevel));
michael@0 637
michael@0 638 if (pipeline) {
michael@0 639 RUN_ON_THREAD(mParent->GetSTSThread(),
michael@0 640 WrapRunnable(
michael@0 641 pipeline,
michael@0 642 &MediaPipeline::SetUsingBundle_s,
michael@0 643 decision
michael@0 644 ),
michael@0 645 NS_DISPATCH_NORMAL);
michael@0 646 return true;
michael@0 647 }
michael@0 648 return false;
michael@0 649 }
michael@0 650
michael@0 651 } // namespace sipcc

mercurial