Bug 1258942: Lock around DeviceID access for audio inputs r=padenot
authorRandell Jesup <rjesup@jesup.org>
Fri, 01 Apr 2016 00:18:13 -0400
changeset 291187 ca5142203259cd252723d34e75d3e3b799b21765
parent 291186 05cd77a4d02b89dbaacb5d3583b9849123b448c2
child 291188 538d248fa252a4100082fd9bc3fdc08d322cda22
push id19656
push usergwagner@mozilla.com
push dateMon, 04 Apr 2016 13:43:23 +0000
treeherderb2g-inbound@e99061fde28a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspadenot
bugs1258942
milestone48.0a1
Bug 1258942: Lock around DeviceID access for audio inputs r=padenot MozReview-Commit-ID: DQ5FBW4H8mX
dom/media/GraphDriver.cpp
dom/media/webrtc/MediaEngineWebRTC.cpp
dom/media/webrtc/MediaEngineWebRTC.h
--- a/dom/media/GraphDriver.cpp
+++ b/dom/media/GraphDriver.cpp
@@ -614,50 +614,53 @@ AudioCallbackDriver::Init()
 
   input = output;
   input.channels = mInputChannels; // change to support optional stereo capture
 
   cubeb_stream* stream = nullptr;
   CubebUtils::AudioDeviceID input_id = nullptr, output_id = nullptr;
   // We have to translate the deviceID values to cubeb devid's since those can be
   // freed whenever enumerate is called.
-  if ((!mGraphImpl->mInputWanted
+  {
+    StaticMutexAutoLock lock(AudioInputCubeb::Mutex());
+    if ((!mGraphImpl->mInputWanted
 #ifdef MOZ_WEBRTC
-       || AudioInputCubeb::GetDeviceID(mGraphImpl->mInputDeviceID, input_id)
+         || AudioInputCubeb::GetDeviceID(mGraphImpl->mInputDeviceID, input_id)
 #endif
-       ) &&
-      (mGraphImpl->mOutputDeviceID == -1 // pass nullptr for ID for default output
+         ) &&
+        (mGraphImpl->mOutputDeviceID == -1 // pass nullptr for ID for default output
 #ifdef MOZ_WEBRTC
-       // XXX we should figure out how we would use a deviceID for output without webrtc.
-       // Currently we don't set this though, so it's ok
-       || AudioInputCubeb::GetDeviceID(mGraphImpl->mOutputDeviceID, output_id)
+         // XXX we should figure out how we would use a deviceID for output without webrtc.
+         // Currently we don't set this though, so it's ok
+         || AudioInputCubeb::GetDeviceID(mGraphImpl->mOutputDeviceID, output_id)
 #endif
-       ) &&
-      // XXX Only pass input input if we have an input listener.  Always
-      // set up output because it's easier, and it will just get silence.
-      // XXX Add support for adding/removing an input listener later.
-      cubeb_stream_init(CubebUtils::GetCubebContext(), &stream,
-                        "AudioCallbackDriver",
-                        input_id,
-                        mGraphImpl->mInputWanted ? &input : nullptr,
-                        output_id,
-                        mGraphImpl->mOutputWanted ? &output : nullptr, latency,
-                        DataCallback_s, StateCallback_s, this) == CUBEB_OK) {
-    mAudioStream.own(stream);
-  } else {
-    NS_WARNING("Could not create a cubeb stream for MediaStreamGraph, falling back to a SystemClockDriver");
-    // Fall back to a driver using a normal thread.
-    MonitorAutoLock lock(GraphImpl()->GetMonitor());
-    SetNextDriver(new SystemClockDriver(GraphImpl()));
-    NextDriver()->SetGraphTime(this, mIterationStart, mIterationEnd);
-    mGraphImpl->SetCurrentDriver(NextDriver());
-    NextDriver()->Start();
-    return;
+         ) &&
+        // XXX Only pass input input if we have an input listener.  Always
+        // set up output because it's easier, and it will just get silence.
+        // XXX Add support for adding/removing an input listener later.
+        cubeb_stream_init(CubebUtils::GetCubebContext(), &stream,
+                          "AudioCallbackDriver",
+                          input_id,
+                          mGraphImpl->mInputWanted ? &input : nullptr,
+                          output_id,
+                          mGraphImpl->mOutputWanted ? &output : nullptr, latency,
+                          DataCallback_s, StateCallback_s, this) == CUBEB_OK) {
+      mAudioStream.own(stream);
+    } else {
+      StaticMutexAutoUnlock unlock(AudioInputCubeb::Mutex());
+      NS_WARNING("Could not create a cubeb stream for MediaStreamGraph, falling back to a SystemClockDriver");
+      // Fall back to a driver using a normal thread.
+      MonitorAutoLock lock(GraphImpl()->GetMonitor());
+      SetNextDriver(new SystemClockDriver(GraphImpl()));
+      NextDriver()->SetGraphTime(this, mIterationStart, mIterationEnd);
+      mGraphImpl->SetCurrentDriver(NextDriver());
+      NextDriver()->Start();
+      return;
+    }
   }
-
   cubeb_stream_register_device_changed_callback(mAudioStream,
                                                 AudioCallbackDriver::DeviceChangedCallback_s);
 
   StartStream();
 
   STREAM_LOG(LogLevel::Debug, ("AudioCallbackDriver started."));
 }
 
--- a/dom/media/webrtc/MediaEngineWebRTC.cpp
+++ b/dom/media/webrtc/MediaEngineWebRTC.cpp
@@ -44,16 +44,17 @@ GetUserMediaLog()
 
 namespace mozilla {
 
 // statics from AudioInputCubeb
 nsTArray<int>* AudioInputCubeb::mDeviceIndexes;
 nsTArray<nsCString>* AudioInputCubeb::mDeviceNames;
 cubeb_device_collection* AudioInputCubeb::mDevices = nullptr;
 bool AudioInputCubeb::mAnyInUse = false;
+StaticMutex AudioInputCubeb::sMutex;
 
 // AudioDeviceID is an annoying opaque value that's really a string
 // pointer, and is freed when the cubeb_device_collection is destroyed
 
 void AudioInputCubeb::UpdateDeviceList()
 {
   cubeb_device_collection *devices = nullptr;
 
@@ -86,16 +87,17 @@ void AudioInputCubeb::UpdateDeviceList()
         (*mDeviceIndexes)[j] = i;
       } else {
         // new device, add to the array
         mDeviceIndexes->AppendElement(i);
         mDeviceNames->AppendElement(devices->device[i]->device_id);
       }
     }
   }
+  StaticMutexAutoLock lock(sMutex);
   // swap state
   if (mDevices) {
     cubeb_device_collection_destroy(mDevices);
   }
   mDevices = devices;
 }
 
 MediaEngineWebRTC::MediaEngineWebRTC(MediaEnginePrefs &aPrefs)
--- a/dom/media/webrtc/MediaEngineWebRTC.h
+++ b/dom/media/webrtc/MediaEngineWebRTC.h
@@ -8,16 +8,17 @@
 #include "prcvar.h"
 #include "prthread.h"
 #include "prprf.h"
 #include "nsIThread.h"
 #include "nsIRunnable.h"
 
 #include "mozilla/dom/File.h"
 #include "mozilla/Mutex.h"
+#include "mozilla/StaticMutex.h"
 #include "mozilla/Monitor.h"
 #include "mozilla/UniquePtr.h"
 #include "nsCOMPtr.h"
 #include "nsThreadUtils.h"
 #include "DOMMediaStream.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsComponentManagerUtils.h"
 #include "nsRefPtrHashtable.h"
@@ -190,18 +191,25 @@ public:
     }
     if (aIndex >= (int) mDeviceIndexes->Length()) {
       return -1;
     }
     // Note: if the device is gone, this will be -1
     return (*mDeviceIndexes)[aIndex]; // translate to mDevices index
   }
 
+  static StaticMutex& Mutex()
+  {
+    return sMutex;
+  }
+
   static bool GetDeviceID(int aDeviceIndex, CubebUtils::AudioDeviceID &aID)
   {
+    // Assert sMutex is held
+    sMutex.AssertCurrentThreadOwns();
     int dev_index = DeviceIndex(aDeviceIndex);
     if (dev_index != -1) {
       aID = mDevices->device[dev_index]->devid;
       return true;
     }
     return false;
   }
 
@@ -275,16 +283,17 @@ private:
   int mSelectedDevice;
   uint32_t mInUseCount;
 
   // pointers to avoid static constructors
   static nsTArray<int>* mDeviceIndexes;
   static nsTArray<nsCString>* mDeviceNames;
   static cubeb_device_collection *mDevices;
   static bool mAnyInUse;
+  static StaticMutex sMutex;
 };
 
 class AudioInputWebRTC final : public AudioInput
 {
 public:
   explicit AudioInputWebRTC(webrtc::VoiceEngine* aVoiceEngine) : AudioInput(aVoiceEngine) {}
 
   int GetNumOfRecordingDevices(int& aDevices)