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.

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

mercurial