Bug 1341238 - Introduce (hidden) pref to force a particular libcubeb backend. r=kinetik draft
authorDamien Zammit <damien@zamaudio.com>
Tue, 14 Mar 2017 17:36:03 +0100
changeset 498421 c97bc807031f522e94d41b203e2b5f376e7c240e
parent 498420 a08de26a9459d9695c3a55f13475e26e43ba8b66
child 498422 94bcfb9914152e43e8bcc31210d7175af8bcaf53
push id49176
push userpaul@paul.cx
push dateTue, 14 Mar 2017 17:54:33 +0000
reviewerskinetik
bugs1341238
milestone55.0a1
Bug 1341238 - Introduce (hidden) pref to force a particular libcubeb backend. r=kinetik This pref is going to be mostly static, but we need to access it very early so we're using an observer. MozReview-Commit-ID: 5G7epuxQ6a3
dom/media/CubebUtils.cpp
--- a/dom/media/CubebUtils.cpp
+++ b/dom/media/CubebUtils.cpp
@@ -15,16 +15,17 @@
 #include "mozilla/Telemetry.h"
 #include "mozilla/Logging.h"
 #include "nsThreadUtils.h"
 #include "CubebUtils.h"
 #include "nsAutoRef.h"
 #include "prdtoa.h"
 
 #define PREF_VOLUME_SCALE "media.volume_scale"
+#define PREF_CUBEB_BACKEND "media.cubeb.backend"
 #define PREF_CUBEB_LATENCY_PLAYBACK "media.cubeb_latency_playback_ms"
 #define PREF_CUBEB_LATENCY_MSG "media.cubeb_latency_msg_frames"
 #define PREF_CUBEB_LOG_LEVEL "media.cubeb.log_level"
 
 #define MASK_MONO       (1 << AudioConfig::CHANNEL_MONO)
 #define MASK_MONO_LFE   (MASK_MONO | (1 << AudioConfig::CHANNEL_LFE))
 #define MASK_STEREO     ((1 << AudioConfig::CHANNEL_LEFT) | (1 << AudioConfig::CHANNEL_RIGHT))
 #define MASK_STEREO_LFE (MASK_STEREO | (1 << AudioConfig::CHANNEL_LFE))
@@ -68,16 +69,17 @@ enum class CubebState {
 cubeb* sCubebContext;
 double sVolumeScale;
 uint32_t sCubebPlaybackLatencyInMilliseconds;
 uint32_t sCubebMSGLatencyInFrames;
 bool sCubebPlaybackLatencyPrefSet;
 bool sCubebMSGLatencyPrefSet;
 bool sAudioStreamInitEverSucceeded = false;
 StaticAutoPtr<char> sBrandName;
+StaticAutoPtr<char> sCubebBackendName;
 
 const char kBrandBundleURL[]      = "chrome://branding/locale/brand.properties";
 
 const char* AUDIOSTREAM_BACKEND_ID_STR[] = {
   "jack",
   "pulse",
   "alsa",
   "audiounit",
@@ -163,16 +165,27 @@ void PrefChanged(const char* aPref, void
       cubebLog->SetLevel(LogLevel::Verbose);
     } else if (strcmp(utf8.get(), "normal") == 0) {
       cubeb_set_log_callback(CUBEB_LOG_NORMAL, CubebLogCallback);
       cubebLog->SetLevel(LogLevel::Error);
     } else if (utf8.IsEmpty()) {
       cubeb_set_log_callback(CUBEB_LOG_DISABLED, nullptr);
       cubebLog->SetLevel(LogLevel::Disabled);
     }
+  } else if (strcmp(aPref, PREF_CUBEB_BACKEND) == 0) {
+    nsAdoptingString value = Preferences::GetString(aPref);
+    if (value.IsEmpty()) {
+      sCubebBackendName = nullptr;
+    } else {
+      /* cubeb expects a c-string. */
+      const char* ascii = NS_LossyConvertUTF16toASCII(value).get();
+      sCubebBackendName = new char[value.Length() + 1];
+      PodCopy(sCubebBackendName.get(), ascii, value.Length());
+      sCubebBackendName[value.Length()] = 0;
+    }
   }
 }
 
 bool GetFirstStream()
 {
   static bool sFirstStream = true;
 
   StaticMutexAutoLock lock(sMutex);
@@ -323,17 +336,17 @@ cubeb* GetCubebContextUnlocked()
 
   if (!sBrandName && NS_IsMainThread()) {
     InitBrandName();
   } else {
     NS_WARNING_ASSERTION(
       sBrandName, "Did not initialize sbrandName, and not on the main thread?");
   }
 
-  int rv = cubeb_init(&sCubebContext, sBrandName);
+  int rv = cubeb_init(&sCubebContext, sBrandName, sCubebBackendName.get());
   NS_WARNING_ASSERTION(rv == CUBEB_OK, "Could not get a cubeb context.");
   sCubebState = (rv == CUBEB_OK) ? CubebState::Initialized : CubebState::Uninitialized;
 
   if (MOZ_LOG_TEST(gCubebLog, LogLevel::Verbose)) {
     cubeb_set_log_callback(CUBEB_LOG_VERBOSE, CubebLogCallback);
   } else if (MOZ_LOG_TEST(gCubebLog, LogLevel::Error)) {
     cubeb_set_log_callback(CUBEB_LOG_NORMAL, CubebLogCallback);
   }
@@ -403,37 +416,41 @@ Maybe<uint32_t> GetCubebMSGLatencyInFram
 }
 
 void InitLibrary()
 {
   PrefChanged(PREF_VOLUME_SCALE, nullptr);
   Preferences::RegisterCallback(PrefChanged, PREF_VOLUME_SCALE);
   PrefChanged(PREF_CUBEB_LATENCY_PLAYBACK, nullptr);
   PrefChanged(PREF_CUBEB_LATENCY_MSG, nullptr);
+  PrefChanged(PREF_CUBEB_BACKEND, nullptr);
+  Preferences::RegisterCallback(PrefChanged, PREF_CUBEB_BACKEND);
   Preferences::RegisterCallback(PrefChanged, PREF_CUBEB_LATENCY_PLAYBACK);
   Preferences::RegisterCallback(PrefChanged, PREF_CUBEB_LATENCY_MSG);
   Preferences::RegisterCallback(PrefChanged, PREF_CUBEB_LOG_LEVEL);
 #ifndef MOZ_WIDGET_ANDROID
   NS_DispatchToMainThread(NS_NewRunnableFunction(&InitBrandName));
 #endif
 }
 
 void ShutdownLibrary()
 {
   Preferences::UnregisterCallback(PrefChanged, PREF_VOLUME_SCALE);
+  Preferences::UnregisterCallback(PrefChanged, PREF_CUBEB_BACKEND);
   Preferences::UnregisterCallback(PrefChanged, PREF_CUBEB_LATENCY_PLAYBACK);
   Preferences::UnregisterCallback(PrefChanged, PREF_CUBEB_LATENCY_MSG);
   Preferences::UnregisterCallback(PrefChanged, PREF_CUBEB_LOG_LEVEL);
 
   StaticMutexAutoLock lock(sMutex);
   if (sCubebContext) {
     cubeb_destroy(sCubebContext);
     sCubebContext = nullptr;
   }
   sBrandName = nullptr;
+  sCubebBackendName = nullptr;
   // This will ensure we don't try to re-create a context.
   sCubebState = CubebState::Shutdown;
 }
 
 uint32_t MaxNumberOfChannels()
 {
   cubeb* cubebContext = GetCubebContext();
   uint32_t maxNumberOfChannels;