content/media/DOMMediaStream.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 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
michael@0 4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "DOMMediaStream.h"
michael@0 7 #include "nsContentUtils.h"
michael@0 8 #include "mozilla/dom/MediaStreamBinding.h"
michael@0 9 #include "mozilla/dom/LocalMediaStreamBinding.h"
michael@0 10 #include "mozilla/dom/AudioNode.h"
michael@0 11 #include "MediaStreamGraph.h"
michael@0 12 #include "AudioStreamTrack.h"
michael@0 13 #include "VideoStreamTrack.h"
michael@0 14
michael@0 15 using namespace mozilla;
michael@0 16 using namespace mozilla::dom;
michael@0 17
michael@0 18 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMMediaStream)
michael@0 19 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
michael@0 20 NS_INTERFACE_MAP_ENTRY(nsISupports)
michael@0 21 NS_INTERFACE_MAP_ENTRY(nsIDOMMediaStream)
michael@0 22 NS_INTERFACE_MAP_END
michael@0 23
michael@0 24 NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMMediaStream)
michael@0 25 NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMMediaStream)
michael@0 26
michael@0 27 NS_IMPL_CYCLE_COLLECTION_CLASS(DOMMediaStream)
michael@0 28
michael@0 29 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMMediaStream)
michael@0 30 tmp->Destroy();
michael@0 31 NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
michael@0 32 NS_IMPL_CYCLE_COLLECTION_UNLINK(mTracks)
michael@0 33 NS_IMPL_CYCLE_COLLECTION_UNLINK(mConsumersToKeepAlive)
michael@0 34 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
michael@0 35 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
michael@0 36 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMMediaStream)
michael@0 37 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
michael@0 38 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTracks)
michael@0 39 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConsumersToKeepAlive)
michael@0 40 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
michael@0 41 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
michael@0 42 NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(DOMMediaStream)
michael@0 43
michael@0 44 NS_IMPL_ISUPPORTS_INHERITED(DOMLocalMediaStream, DOMMediaStream,
michael@0 45 nsIDOMLocalMediaStream)
michael@0 46
michael@0 47 NS_IMPL_CYCLE_COLLECTION_INHERITED(DOMAudioNodeMediaStream, DOMMediaStream,
michael@0 48 mStreamNode)
michael@0 49
michael@0 50 NS_IMPL_ADDREF_INHERITED(DOMAudioNodeMediaStream, DOMMediaStream)
michael@0 51 NS_IMPL_RELEASE_INHERITED(DOMAudioNodeMediaStream, DOMMediaStream)
michael@0 52
michael@0 53 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DOMAudioNodeMediaStream)
michael@0 54 NS_INTERFACE_MAP_END_INHERITING(DOMMediaStream)
michael@0 55
michael@0 56 class DOMMediaStream::StreamListener : public MediaStreamListener {
michael@0 57 public:
michael@0 58 StreamListener(DOMMediaStream* aStream)
michael@0 59 : mStream(aStream)
michael@0 60 {}
michael@0 61
michael@0 62 // Main thread only
michael@0 63 void Forget() { mStream = nullptr; }
michael@0 64 DOMMediaStream* GetStream() { return mStream; }
michael@0 65
michael@0 66 class TrackChange : public nsRunnable {
michael@0 67 public:
michael@0 68 TrackChange(StreamListener* aListener,
michael@0 69 TrackID aID, TrackTicks aTrackOffset,
michael@0 70 uint32_t aEvents, MediaSegment::Type aType)
michael@0 71 : mListener(aListener), mID(aID), mEvents(aEvents), mType(aType)
michael@0 72 {
michael@0 73 }
michael@0 74
michael@0 75 NS_IMETHOD Run()
michael@0 76 {
michael@0 77 NS_ASSERTION(NS_IsMainThread(), "main thread only");
michael@0 78
michael@0 79 DOMMediaStream* stream = mListener->GetStream();
michael@0 80 if (!stream) {
michael@0 81 return NS_OK;
michael@0 82 }
michael@0 83
michael@0 84 nsRefPtr<MediaStreamTrack> track;
michael@0 85 if (mEvents & MediaStreamListener::TRACK_EVENT_CREATED) {
michael@0 86 track = stream->CreateDOMTrack(mID, mType);
michael@0 87 } else {
michael@0 88 track = stream->GetDOMTrackFor(mID);
michael@0 89 }
michael@0 90 if (mEvents & MediaStreamListener::TRACK_EVENT_ENDED) {
michael@0 91 track->NotifyEnded();
michael@0 92 }
michael@0 93 return NS_OK;
michael@0 94 }
michael@0 95
michael@0 96 StreamTime mEndTime;
michael@0 97 nsRefPtr<StreamListener> mListener;
michael@0 98 TrackID mID;
michael@0 99 uint32_t mEvents;
michael@0 100 MediaSegment::Type mType;
michael@0 101 };
michael@0 102
michael@0 103 /**
michael@0 104 * Notify that changes to one of the stream tracks have been queued.
michael@0 105 * aTrackEvents can be any combination of TRACK_EVENT_CREATED and
michael@0 106 * TRACK_EVENT_ENDED. aQueuedMedia is the data being added to the track
michael@0 107 * at aTrackOffset (relative to the start of the stream).
michael@0 108 * aQueuedMedia can be null if there is no output.
michael@0 109 */
michael@0 110 virtual void NotifyQueuedTrackChanges(MediaStreamGraph* aGraph, TrackID aID,
michael@0 111 TrackRate aTrackRate,
michael@0 112 TrackTicks aTrackOffset,
michael@0 113 uint32_t aTrackEvents,
michael@0 114 const MediaSegment& aQueuedMedia) MOZ_OVERRIDE
michael@0 115 {
michael@0 116 if (aTrackEvents & (TRACK_EVENT_CREATED | TRACK_EVENT_ENDED)) {
michael@0 117 nsRefPtr<TrackChange> runnable =
michael@0 118 new TrackChange(this, aID, aTrackOffset, aTrackEvents,
michael@0 119 aQueuedMedia.GetType());
michael@0 120 NS_DispatchToMainThread(runnable);
michael@0 121 }
michael@0 122 }
michael@0 123
michael@0 124 private:
michael@0 125 // These fields may only be accessed on the main thread
michael@0 126 DOMMediaStream* mStream;
michael@0 127 };
michael@0 128
michael@0 129 DOMMediaStream::DOMMediaStream()
michael@0 130 : mLogicalStreamStartTime(0),
michael@0 131 mStream(nullptr), mHintContents(0), mTrackTypesAvailable(0),
michael@0 132 mNotifiedOfMediaStreamGraphShutdown(false)
michael@0 133 {
michael@0 134 SetIsDOMBinding();
michael@0 135 }
michael@0 136
michael@0 137 DOMMediaStream::~DOMMediaStream()
michael@0 138 {
michael@0 139 Destroy();
michael@0 140 }
michael@0 141
michael@0 142 void
michael@0 143 DOMMediaStream::Destroy()
michael@0 144 {
michael@0 145 if (mListener) {
michael@0 146 mListener->Forget();
michael@0 147 mListener = nullptr;
michael@0 148 }
michael@0 149 if (mStream) {
michael@0 150 mStream->Destroy();
michael@0 151 mStream = nullptr;
michael@0 152 }
michael@0 153 }
michael@0 154
michael@0 155 JSObject*
michael@0 156 DOMMediaStream::WrapObject(JSContext* aCx)
michael@0 157 {
michael@0 158 return dom::MediaStreamBinding::Wrap(aCx, this);
michael@0 159 }
michael@0 160
michael@0 161 double
michael@0 162 DOMMediaStream::CurrentTime()
michael@0 163 {
michael@0 164 if (!mStream) {
michael@0 165 return 0.0;
michael@0 166 }
michael@0 167 return MediaTimeToSeconds(mStream->GetCurrentTime() - mLogicalStreamStartTime);
michael@0 168 }
michael@0 169
michael@0 170 void
michael@0 171 DOMMediaStream::GetAudioTracks(nsTArray<nsRefPtr<AudioStreamTrack> >& aTracks)
michael@0 172 {
michael@0 173 for (uint32_t i = 0; i < mTracks.Length(); ++i) {
michael@0 174 AudioStreamTrack* t = mTracks[i]->AsAudioStreamTrack();
michael@0 175 if (t) {
michael@0 176 aTracks.AppendElement(t);
michael@0 177 }
michael@0 178 }
michael@0 179 }
michael@0 180
michael@0 181 void
michael@0 182 DOMMediaStream::GetVideoTracks(nsTArray<nsRefPtr<VideoStreamTrack> >& aTracks)
michael@0 183 {
michael@0 184 for (uint32_t i = 0; i < mTracks.Length(); ++i) {
michael@0 185 VideoStreamTrack* t = mTracks[i]->AsVideoStreamTrack();
michael@0 186 if (t) {
michael@0 187 aTracks.AppendElement(t);
michael@0 188 }
michael@0 189 }
michael@0 190 }
michael@0 191
michael@0 192 bool
michael@0 193 DOMMediaStream::IsFinished()
michael@0 194 {
michael@0 195 return !mStream || mStream->IsFinished();
michael@0 196 }
michael@0 197
michael@0 198 void
michael@0 199 DOMMediaStream::InitSourceStream(nsIDOMWindow* aWindow, TrackTypeHints aHintContents)
michael@0 200 {
michael@0 201 mWindow = aWindow;
michael@0 202 SetHintContents(aHintContents);
michael@0 203 MediaStreamGraph* gm = MediaStreamGraph::GetInstance();
michael@0 204 InitStreamCommon(gm->CreateSourceStream(this));
michael@0 205 }
michael@0 206
michael@0 207 void
michael@0 208 DOMMediaStream::InitTrackUnionStream(nsIDOMWindow* aWindow, TrackTypeHints aHintContents)
michael@0 209 {
michael@0 210 mWindow = aWindow;
michael@0 211 SetHintContents(aHintContents);
michael@0 212 MediaStreamGraph* gm = MediaStreamGraph::GetInstance();
michael@0 213 InitStreamCommon(gm->CreateTrackUnionStream(this));
michael@0 214 }
michael@0 215
michael@0 216 void
michael@0 217 DOMMediaStream::InitStreamCommon(MediaStream* aStream)
michael@0 218 {
michael@0 219 mStream = aStream;
michael@0 220
michael@0 221 // Setup track listener
michael@0 222 mListener = new StreamListener(this);
michael@0 223 aStream->AddListener(mListener);
michael@0 224 }
michael@0 225
michael@0 226 already_AddRefed<DOMMediaStream>
michael@0 227 DOMMediaStream::CreateSourceStream(nsIDOMWindow* aWindow, TrackTypeHints aHintContents)
michael@0 228 {
michael@0 229 nsRefPtr<DOMMediaStream> stream = new DOMMediaStream();
michael@0 230 stream->InitSourceStream(aWindow, aHintContents);
michael@0 231 return stream.forget();
michael@0 232 }
michael@0 233
michael@0 234 already_AddRefed<DOMMediaStream>
michael@0 235 DOMMediaStream::CreateTrackUnionStream(nsIDOMWindow* aWindow, TrackTypeHints aHintContents)
michael@0 236 {
michael@0 237 nsRefPtr<DOMMediaStream> stream = new DOMMediaStream();
michael@0 238 stream->InitTrackUnionStream(aWindow, aHintContents);
michael@0 239 return stream.forget();
michael@0 240 }
michael@0 241
michael@0 242 void
michael@0 243 DOMMediaStream::SetTrackEnabled(TrackID aTrackID, bool aEnabled)
michael@0 244 {
michael@0 245 if (mStream) {
michael@0 246 mStream->SetTrackEnabled(aTrackID, aEnabled);
michael@0 247 }
michael@0 248 }
michael@0 249
michael@0 250 bool
michael@0 251 DOMMediaStream::CombineWithPrincipal(nsIPrincipal* aPrincipal)
michael@0 252 {
michael@0 253 return nsContentUtils::CombineResourcePrincipals(&mPrincipal, aPrincipal);
michael@0 254 }
michael@0 255
michael@0 256 MediaStreamTrack*
michael@0 257 DOMMediaStream::CreateDOMTrack(TrackID aTrackID, MediaSegment::Type aType)
michael@0 258 {
michael@0 259 MediaStreamTrack* track;
michael@0 260 switch (aType) {
michael@0 261 case MediaSegment::AUDIO:
michael@0 262 track = new AudioStreamTrack(this, aTrackID);
michael@0 263 mTrackTypesAvailable |= HINT_CONTENTS_AUDIO;
michael@0 264 break;
michael@0 265 case MediaSegment::VIDEO:
michael@0 266 track = new VideoStreamTrack(this, aTrackID);
michael@0 267 mTrackTypesAvailable |= HINT_CONTENTS_VIDEO;
michael@0 268 break;
michael@0 269 default:
michael@0 270 MOZ_CRASH("Unhandled track type");
michael@0 271 }
michael@0 272 mTracks.AppendElement(track);
michael@0 273
michael@0 274 CheckTracksAvailable();
michael@0 275
michael@0 276 return track;
michael@0 277 }
michael@0 278
michael@0 279 MediaStreamTrack*
michael@0 280 DOMMediaStream::GetDOMTrackFor(TrackID aTrackID)
michael@0 281 {
michael@0 282 for (uint32_t i = 0; i < mTracks.Length(); ++i) {
michael@0 283 MediaStreamTrack* t = mTracks[i];
michael@0 284 // We may add streams to our track list that are actually owned by
michael@0 285 // a different DOMMediaStream. Ignore those.
michael@0 286 if (t->GetTrackID() == aTrackID && t->GetStream() == this) {
michael@0 287 return t;
michael@0 288 }
michael@0 289 }
michael@0 290 return nullptr;
michael@0 291 }
michael@0 292
michael@0 293 void
michael@0 294 DOMMediaStream::NotifyMediaStreamGraphShutdown()
michael@0 295 {
michael@0 296 // No more tracks will ever be added, so just clear these callbacks now
michael@0 297 // to prevent leaks.
michael@0 298 mNotifiedOfMediaStreamGraphShutdown = true;
michael@0 299 mRunOnTracksAvailable.Clear();
michael@0 300
michael@0 301 mConsumersToKeepAlive.Clear();
michael@0 302 }
michael@0 303
michael@0 304 void
michael@0 305 DOMMediaStream::NotifyStreamStateChanged()
michael@0 306 {
michael@0 307 if (IsFinished()) {
michael@0 308 mConsumersToKeepAlive.Clear();
michael@0 309 }
michael@0 310 }
michael@0 311
michael@0 312 void
michael@0 313 DOMMediaStream::OnTracksAvailable(OnTracksAvailableCallback* aRunnable)
michael@0 314 {
michael@0 315 if (mNotifiedOfMediaStreamGraphShutdown) {
michael@0 316 // No more tracks will ever be added, so just delete the callback now.
michael@0 317 delete aRunnable;
michael@0 318 return;
michael@0 319 }
michael@0 320 mRunOnTracksAvailable.AppendElement(aRunnable);
michael@0 321 CheckTracksAvailable();
michael@0 322 }
michael@0 323
michael@0 324 void
michael@0 325 DOMMediaStream::CheckTracksAvailable()
michael@0 326 {
michael@0 327 if (mTrackTypesAvailable == 0) {
michael@0 328 return;
michael@0 329 }
michael@0 330 nsTArray<nsAutoPtr<OnTracksAvailableCallback> > callbacks;
michael@0 331 callbacks.SwapElements(mRunOnTracksAvailable);
michael@0 332
michael@0 333 for (uint32_t i = 0; i < callbacks.Length(); ++i) {
michael@0 334 OnTracksAvailableCallback* cb = callbacks[i];
michael@0 335 if (~mTrackTypesAvailable & cb->GetExpectedTracks()) {
michael@0 336 // Some expected tracks not available yet. Try this callback again later.
michael@0 337 *mRunOnTracksAvailable.AppendElement() = callbacks[i].forget();
michael@0 338 continue;
michael@0 339 }
michael@0 340 cb->NotifyTracksAvailable(this);
michael@0 341 }
michael@0 342 }
michael@0 343
michael@0 344 DOMLocalMediaStream::~DOMLocalMediaStream()
michael@0 345 {
michael@0 346 if (mStream) {
michael@0 347 // Make sure Listeners of this stream know it's going away
michael@0 348 Stop();
michael@0 349 }
michael@0 350 }
michael@0 351
michael@0 352 JSObject*
michael@0 353 DOMLocalMediaStream::WrapObject(JSContext* aCx)
michael@0 354 {
michael@0 355 return dom::LocalMediaStreamBinding::Wrap(aCx, this);
michael@0 356 }
michael@0 357
michael@0 358 void
michael@0 359 DOMLocalMediaStream::Stop()
michael@0 360 {
michael@0 361 if (mStream && mStream->AsSourceStream()) {
michael@0 362 mStream->AsSourceStream()->EndAllTrackAndFinish();
michael@0 363 }
michael@0 364 }
michael@0 365
michael@0 366 already_AddRefed<DOMLocalMediaStream>
michael@0 367 DOMLocalMediaStream::CreateSourceStream(nsIDOMWindow* aWindow,
michael@0 368 TrackTypeHints aHintContents)
michael@0 369 {
michael@0 370 nsRefPtr<DOMLocalMediaStream> stream = new DOMLocalMediaStream();
michael@0 371 stream->InitSourceStream(aWindow, aHintContents);
michael@0 372 return stream.forget();
michael@0 373 }
michael@0 374
michael@0 375 already_AddRefed<DOMLocalMediaStream>
michael@0 376 DOMLocalMediaStream::CreateTrackUnionStream(nsIDOMWindow* aWindow,
michael@0 377 TrackTypeHints aHintContents)
michael@0 378 {
michael@0 379 nsRefPtr<DOMLocalMediaStream> stream = new DOMLocalMediaStream();
michael@0 380 stream->InitTrackUnionStream(aWindow, aHintContents);
michael@0 381 return stream.forget();
michael@0 382 }
michael@0 383
michael@0 384 DOMAudioNodeMediaStream::DOMAudioNodeMediaStream(AudioNode* aNode)
michael@0 385 : mStreamNode(aNode)
michael@0 386 {
michael@0 387 }
michael@0 388
michael@0 389 already_AddRefed<DOMAudioNodeMediaStream>
michael@0 390 DOMAudioNodeMediaStream::CreateTrackUnionStream(nsIDOMWindow* aWindow,
michael@0 391 AudioNode* aNode,
michael@0 392 TrackTypeHints aHintContents)
michael@0 393 {
michael@0 394 nsRefPtr<DOMAudioNodeMediaStream> stream = new DOMAudioNodeMediaStream(aNode);
michael@0 395 stream->InitTrackUnionStream(aWindow, aHintContents);
michael@0 396 return stream.forget();
michael@0 397 }

mercurial