Bug 1360334 - Improve error handling. r=padenot
authorAndreas Pehrson <pehrsons@mozilla.com>
Fri, 08 Sep 2017 16:41:36 +0200
changeset 429448 0821986e4f3bef817c0e56ae802421a3b191d8f5
parent 429447 146cf615f80da6fea8f6f5ac341624d888a37d0d
child 429449 7677154bc3e03ab6e2fa5b1901ada5280509b07d
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspadenot
bugs1360334
milestone57.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1360334 - Improve error handling. r=padenot MozReview-Commit-ID: 5tIXzzisg0V
dom/media/GraphDriver.cpp
dom/media/GraphDriver.h
--- a/dom/media/GraphDriver.cpp
+++ b/dom/media/GraphDriver.cpp
@@ -30,17 +30,18 @@ StaticRefPtr<nsIThreadPool> AsyncCubebTa
 
 GraphDriver::GraphDriver(MediaStreamGraphImpl* aGraphImpl)
   : mIterationStart(0),
     mIterationEnd(0),
     mGraphImpl(aGraphImpl),
     mWaitState(WAITSTATE_RUNNING),
     mCurrentTimeStamp(TimeStamp::Now()),
     mPreviousDriver(nullptr),
-    mNextDriver(nullptr)
+    mNextDriver(nullptr),
+    mScheduled(false)
 { }
 
 void GraphDriver::SetGraphTime(GraphDriver* aPreviousDriver,
                                GraphTime aLastSwitchNextIterationStart,
                                GraphTime aLastSwitchNextIterationEnd)
 {
   GraphImpl()->GetMonitor().AssertCurrentThreadOwns();
   // We set mIterationEnd here, because the first thing a driver do when it
@@ -130,16 +131,22 @@ void GraphDriver::SetNextDriver(GraphDri
 }
 
 void GraphDriver::SetPreviousDriver(GraphDriver* aPreviousDriver)
 {
   GraphImpl()->GetMonitor().AssertCurrentThreadOwns();
   mPreviousDriver = aPreviousDriver;
 }
 
+bool GraphDriver::Scheduled()
+{
+  GraphImpl()->GetMonitor().AssertCurrentThreadOwns();
+  return mScheduled;
+}
+
 ThreadedDriver::ThreadedDriver(MediaStreamGraphImpl* aGraphImpl)
   : GraphDriver(aGraphImpl)
 { }
 
 class MediaStreamGraphShutdownThreadRunnable : public Runnable {
 public:
   explicit MediaStreamGraphShutdownThreadRunnable(
     already_AddRefed<nsIThread> aThread)
@@ -176,26 +183,26 @@ public:
     , mDriver(aDriver)
   {
   }
   NS_IMETHOD Run() override
   {
     LOG(LogLevel::Debug,
         ("Starting a new system driver for graph %p", mDriver->mGraphImpl));
 
-    GraphDriver* previousDriver = nullptr;
+    RefPtr<GraphDriver> previousDriver;
     {
       MonitorAutoLock mon(mDriver->mGraphImpl->GetMonitor());
       previousDriver = mDriver->PreviousDriver();
     }
     if (previousDriver) {
       LOG(LogLevel::Debug,
           ("%p releasing an AudioCallbackDriver(%p), for graph %p",
            mDriver.get(),
-           previousDriver,
+           previousDriver.get(),
            mDriver->GraphImpl()));
       MOZ_ASSERT(!mDriver->AsAudioCallbackDriver());
       RefPtr<AsyncCubebTask> releaseEvent =
         new AsyncCubebTask(previousDriver->AsAudioCallbackDriver(), AsyncCubebOperation::SHUTDOWN);
       releaseEvent->Dispatch();
 
       MonitorAutoLock mon(mDriver->mGraphImpl->GetMonitor());
       mDriver->SetPreviousDriver(nullptr);
@@ -219,17 +226,18 @@ ThreadedDriver::Start()
   LOG(LogLevel::Debug,
       ("Starting thread for a SystemClockDriver  %p", mGraphImpl));
   Unused << NS_WARN_IF(mThread);
   if (!mThread) { // Ensure we haven't already started it
     nsCOMPtr<nsIRunnable> event = new MediaStreamGraphInitThreadRunnable(this);
     // Note: mThread may be null during event->Run() if we pass to NewNamedThread!  See AudioInitTask
     nsresult rv = NS_NewNamedThread("MediaStreamGrph", getter_AddRefs(mThread));
     if (NS_SUCCEEDED(rv)) {
-      mThread->EventTarget()->Dispatch(event.forget(), NS_DISPATCH_NORMAL);
+      rv = mThread->EventTarget()->Dispatch(event.forget(), NS_DISPATCH_NORMAL);
+      mScheduled = NS_SUCCEEDED(rv);
     }
   }
 }
 
 void
 ThreadedDriver::Resume()
 {
   Start();
@@ -791,17 +799,18 @@ AudioCallbackDriver::Start()
     }
   }
 
   LOG(LogLevel::Debug,
       ("Starting new audio driver off main thread, "
        "to ensure it runs after previous shutdown."));
   RefPtr<AsyncCubebTask> initEvent =
     new AsyncCubebTask(AsAudioCallbackDriver(), AsyncCubebOperation::INIT);
-  initEvent->Dispatch();
+  nsresult rv = initEvent->Dispatch();
+  mScheduled = NS_SUCCEEDED(rv);
 }
 
 bool
 AudioCallbackDriver::StartStream()
 {
   if (cubeb_stream_start(mAudioStream) != CUBEB_OK) {
     NS_WARNING("Could not start cubeb stream for MSG.");
     return false;
@@ -1064,23 +1073,35 @@ AudioCallbackDriver::DataCallback(const 
   }
   return aFrames;
 }
 
 void
 AudioCallbackDriver::StateCallback(cubeb_state aState)
 {
   LOG(LogLevel::Debug, ("AudioCallbackDriver State: %d", aState));
-  // If we don't have an audio stream here, this means that the stream
-  // initialization has failed. A fallback on a SystemCallDriver will happen at
-  // the callsite of `cubeb_stream_init`.
-  if (aState == CUBEB_STATE_ERROR && mAudioStream) {
+
+  if (aState == CUBEB_STATE_ERROR) {
+    if (!mAudioStream) {
+      // If we don't have an audio stream here, this means that the stream
+      // initialization has failed. A fallback on a SystemCallDriver will happen at
+      // the callsite of `cubeb_stream_init`.
+      return;
+    }
+
+    MonitorAutoLock lock(GraphImpl()->GetMonitor());
+
+    if (NextDriver() && NextDriver()->Scheduled()) {
+      // We are switching to another driver that has already been scheduled
+      // to be initialized and started. There's nothing for us to do here.
+      return;
+    }
+
     // Fall back to a driver using a normal thread. If needed,
     // the graph will try to re-open an audio stream later.
-    MonitorAutoLock lock(GraphImpl()->GetMonitor());
     SystemClockDriver* nextDriver = new SystemClockDriver(GraphImpl());
     SetNextDriver(nextDriver);
     RemoveCallback();
     nextDriver->MarkAsFallback();
     nextDriver->SetGraphTime(this, mIterationStart, mIterationEnd);
     // We're not using SwitchAtNextIteration here, because there
     // won't be a next iteration if we don't restart things manually:
     // the audio stream just signaled that it's in error state.
--- a/dom/media/GraphDriver.h
+++ b/dom/media/GraphDriver.h
@@ -145,16 +145,19 @@ public:
 
   // Those are simply or setting the associated pointer, but assert that the
   // lock is held.
   GraphDriver* NextDriver();
   GraphDriver* PreviousDriver();
   void SetNextDriver(GraphDriver* aNextDriver);
   void SetPreviousDriver(GraphDriver* aPreviousDriver);
 
+  /* Return whether we have been scheduled to start. */
+  bool Scheduled();
+
   /**
    * If we are running a real time graph, get the current time stamp to schedule
    * video frames. This has to be reimplemented by real time drivers.
    */
   virtual TimeStamp GetCurrentTimeStamp() {
     return mCurrentTimeStamp;
   }
 
@@ -248,16 +251,19 @@ protected:
   // check whether we're changing driver (in Switching()), from the graph
   // thread.
   // This must be accessed using the {Set,Get}PreviousDriver methods.
   RefPtr<GraphDriver> mPreviousDriver;
   // This is non-null only when this driver is going to switch to an other
   // driver at the end of this iteration.
   // This must be accessed using the {Set,Get}NextDriver methods.
   RefPtr<GraphDriver> mNextDriver;
+  // This is initially false, but set to true as soon the driver has been
+  // scheduled to start through GraphDriver::Start().
+  bool mScheduled;
   virtual ~GraphDriver()
   { }
 };
 
 class MediaStreamGraphInitThreadRunnable;
 
 /**
  * This class is a driver that manages its own thread.