Bug 1446233 - P3: Add prefs to control audioipc client thread pool. r?kinetik draft
authorDan Glastonbury <dan.glastonbury@gmail.com>
Thu, 22 Mar 2018 15:33:25 +1000
changeset 771486 1c2b25fd16bd4eaa838b9bef8c916917c1008426
parent 771485 7291b11cb4719c466332d0d718911b3fbb52acc7
child 777077 7204431fa73cdb355fde9b32bbc90ae006e96f41
push id103686
push userbmo:dglastonbury@mozilla.com
push dateFri, 23 Mar 2018 04:11:47 +0000
reviewerskinetik
bugs1446233
milestone61.0a1
Bug 1446233 - P3: Add prefs to control audioipc client thread pool. r?kinetik MozReview-Commit-ID: 7TVfYE9DEwp
dom/media/CubebUtils.cpp
modules/libpref/init/all.js
--- a/dom/media/CubebUtils.cpp
+++ b/dom/media/CubebUtils.cpp
@@ -24,25 +24,30 @@
 #include "nsThreadUtils.h"
 #include "prdtoa.h"
 #include <algorithm>
 #include <stdint.h>
 #ifdef MOZ_WIDGET_ANDROID
 #include "GeneratedJNIWrappers.h"
 #endif
 
+#define AUDIOIPC_POOL_SIZE_DEFAULT 1
+#define AUDIOIPC_STACK_SIZE_DEFAULT (64*1024)
+
 #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"
 // Allows to get something non-default for the preferred sample-rate, to allow
 // troubleshooting in the field and testing.
 #define PREF_CUBEB_FORCE_SAMPLE_RATE "media.cubeb.force_sample_rate"
 #define PREF_CUBEB_LOGGING_LEVEL "media.cubeb.logging_level"
 #define PREF_CUBEB_SANDBOX "media.cubeb.sandbox"
+#define PREF_AUDIOIPC_POOL_SIZE "media.audioipc.pool_size"
+#define PREF_AUDIOIPC_STACK_SIZE "media.audioipc.stack_size"
 
 #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))
 #define MASK_3F         (MASK_STEREO | (1 << AudioConfig::CHANNEL_CENTER))
 #define MASK_3F_LFE     (MASK_3F | (1 << AudioConfig::CHANNEL_LFE))
 #define MASK_2F1        (MASK_STEREO | (1 << AudioConfig::CHANNEL_RCENTER))
@@ -56,22 +61,29 @@
 #define MASK_3F3R_LFE   (MASK_3F2_LFE | (1 << AudioConfig::CHANNEL_RCENTER))
 #define MASK_3F4_LFE    (MASK_3F2_LFE | (1 << AudioConfig::CHANNEL_RLS) | (1 << AudioConfig::CHANNEL_RRS))
 
 #if (defined(XP_LINUX) && !defined(MOZ_WIDGET_ANDROID)) || defined(XP_MACOSX)
 #define MOZ_CUBEB_REMOTING
 #endif
 
 extern "C" {
+
+struct AudioIpcInitParams {
+  int mServerConnection;
+  size_t mPoolSize;
+  size_t mStackSize;
+};
+
 // These functions are provided by audioipc-server crate
 extern void* audioipc_server_start();
 extern mozilla::ipc::FileDescriptor::PlatformHandleType audioipc_server_new_client(void*);
 extern void audioipc_server_stop(void*);
 // These functions are provided by audioipc-client crate
-extern int audioipc_client_init(cubeb**, const char*, int);
+extern int audioipc_client_init(cubeb**, const char*, const AudioIpcInitParams*);
 }
 
 namespace mozilla {
 
 namespace {
 
 #ifdef MOZ_CUBEB_REMOTING
 ////////////////////////////////////////////////////////////////////////////////
@@ -128,17 +140,19 @@ uint32_t sCubebMSGLatencyInFrames = 512;
 // If sCubebForcedSampleRate is zero, PreferredSampleRate will return the
 // preferred sample-rate for the audio backend in use. Otherwise, it will be
 // used as the preferred sample-rate.
 uint32_t sCubebForcedSampleRate = 0;
 bool sCubebPlaybackLatencyPrefSet = false;
 bool sCubebMSGLatencyPrefSet = false;
 bool sAudioStreamInitEverSucceeded = false;
 #ifdef MOZ_CUBEB_REMOTING
-bool sCubebSandbox;
+bool sCubebSandbox = false;
+size_t sAudioIPCPoolSize;
+size_t sAudioIPCStackSize;
 #endif
 StaticAutoPtr<char> sBrandName;
 StaticAutoPtr<char> sCubebBackendName;
 
 const char kBrandBundleURL[]      = "chrome://branding/locale/brand.properties";
 
 const char* AUDIOSTREAM_BACKEND_ID_STR[] = {
   "jack",
@@ -278,16 +292,26 @@ void PrefChanged(const char* aPref, void
     sCubebSandbox = Preferences::GetBool(aPref);
     MOZ_LOG(gCubebLog, LogLevel::Verbose, ("%s: %s", PREF_CUBEB_SANDBOX, sCubebSandbox ? "true" : "false"));
 
     if (sCubebSandbox && !sServerHandle && XRE_IsParentProcess()) {
       MOZ_LOG(gCubebLog, LogLevel::Debug, ("Starting cubeb server..."));
       StartSoundServer();
     }
   }
+  else if (strcmp(aPref, PREF_AUDIOIPC_POOL_SIZE) == 0) {
+    StaticMutexAutoLock lock(sMutex);
+    sAudioIPCPoolSize =  Preferences::GetUint(PREF_AUDIOIPC_POOL_SIZE,
+                                             AUDIOIPC_POOL_SIZE_DEFAULT);
+  }
+  else if (strcmp(aPref, PREF_AUDIOIPC_STACK_SIZE) == 0) {
+    StaticMutexAutoLock lock(sMutex);
+    sAudioIPCStackSize = Preferences::GetUint(PREF_AUDIOIPC_STACK_SIZE,
+                                             AUDIOIPC_STACK_SIZE_DEFAULT);
+  }
 #endif
 }
 
 bool GetFirstStream()
 {
   static bool sFirstStream = true;
 
   StaticMutexAutoLock lock(sMutex);
@@ -465,32 +489,40 @@ cubeb* GetCubebContextUnlocked()
   if (!sBrandName && NS_IsMainThread()) {
     InitBrandName();
   } else {
     NS_WARNING_ASSERTION(
       sBrandName, "Did not initialize sbrandName, and not on the main thread?");
   }
 
 #ifdef MOZ_CUBEB_REMOTING
+  MOZ_LOG(gCubebLog, LogLevel::Info, ("%s: %s", PREF_CUBEB_SANDBOX, sCubebSandbox ? "true" : "false"));
+
+  int rv = CUBEB_OK;
   if (sCubebSandbox) {
     if (XRE_IsParentProcess()) {
       // TODO: Don't use audio IPC when within the same process.
       MOZ_ASSERT(!sIPCConnection);
       sIPCConnection = new ipc::FileDescriptor(CreateAudioIPCConnection());
     } else {
       MOZ_DIAGNOSTIC_ASSERT(sIPCConnection);
     }
-  }
 
-  MOZ_LOG(gCubebLog, LogLevel::Info, ("%s: %s", PREF_CUBEB_SANDBOX, sCubebSandbox ? "true" : "false"));
+    AudioIpcInitParams initParams;
+    initParams.mPoolSize = sAudioIPCPoolSize;
+    initParams.mStackSize = sAudioIPCStackSize;
+    initParams.mServerConnection = sIPCConnection->ClonePlatformHandle().release();
 
-  int rv = sCubebSandbox
-    ? audioipc_client_init(&sCubebContext, sBrandName,
-                           sIPCConnection->ClonePlatformHandle().release())
-    : cubeb_init(&sCubebContext, sBrandName, sCubebBackendName.get());
+    MOZ_LOG(gCubebLog, LogLevel::Debug, ("%s: %d", PREF_AUDIOIPC_POOL_SIZE, (int) initParams.mPoolSize));
+    MOZ_LOG(gCubebLog, LogLevel::Debug, ("%s: %d", PREF_AUDIOIPC_STACK_SIZE, (int) initParams.mStackSize));
+
+    rv = audioipc_client_init(&sCubebContext, sBrandName, &initParams);
+  } else {
+    rv = cubeb_init(&sCubebContext, sBrandName, sCubebBackendName.get());
+  }
   sIPCConnection = nullptr;
 #else // !MOZ_CUBEB_REMOTING
   int rv = cubeb_init(&sCubebContext, sBrandName, sCubebBackendName.get());
 #endif // MOZ_CUBEB_REMOTING
   NS_WARNING_ASSERTION(rv == CUBEB_OK, "Could not get a cubeb context.");
   sCubebState = (rv == CUBEB_OK) ? CubebState::Initialized : CubebState::Uninitialized;
 
   return sCubebContext;
@@ -574,16 +606,18 @@ uint32_t GetCubebMSGLatencyInFrames(cube
 void InitLibrary()
 {
   Preferences::RegisterCallbackAndCall(PrefChanged, PREF_VOLUME_SCALE);
   Preferences::RegisterCallbackAndCall(PrefChanged, PREF_CUBEB_LATENCY_PLAYBACK);
   Preferences::RegisterCallbackAndCall(PrefChanged, PREF_CUBEB_LATENCY_MSG);
   Preferences::RegisterCallback(PrefChanged, PREF_CUBEB_FORCE_SAMPLE_RATE);
   Preferences::RegisterCallbackAndCall(PrefChanged, PREF_CUBEB_BACKEND);
   Preferences::RegisterCallbackAndCall(PrefChanged, PREF_CUBEB_SANDBOX);
+  Preferences::RegisterCallbackAndCall(PrefChanged, PREF_AUDIOIPC_POOL_SIZE);
+  Preferences::RegisterCallbackAndCall(PrefChanged, PREF_AUDIOIPC_STACK_SIZE);
   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);
   }
   // We don't want to call the callback on startup, because the pref is the
   // empty string by default ("", which means "logging disabled"). Because the
   // logging can be enabled via environment variables (MOZ_LOG="module:5"),
@@ -598,16 +632,18 @@ void InitLibrary()
     InitAudioIPCConnection();
   }
 #endif
 }
 
 void ShutdownLibrary()
 {
   Preferences::UnregisterCallback(PrefChanged, PREF_VOLUME_SCALE);
+  Preferences::UnregisterCallback(PrefChanged, PREF_AUDIOIPC_STACK_SIZE);
+  Preferences::UnregisterCallback(PrefChanged, PREF_AUDIOIPC_POOL_SIZE);
   Preferences::UnregisterCallback(PrefChanged, PREF_CUBEB_SANDBOX);
   Preferences::UnregisterCallback(PrefChanged, PREF_CUBEB_BACKEND);
   Preferences::UnregisterCallback(PrefChanged, PREF_CUBEB_LATENCY_PLAYBACK);
   Preferences::UnregisterCallback(PrefChanged, PREF_CUBEB_FORCE_SAMPLE_RATE);
   Preferences::UnregisterCallback(PrefChanged, PREF_CUBEB_LATENCY_MSG);
   Preferences::UnregisterCallback(PrefChanged, PREF_CUBEB_LOGGING_LEVEL);
 
   StaticMutexAutoLock lock(sMutex);
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -661,16 +661,21 @@ pref("media.decoder.skip-to-next-key-fra
 
 // Log level for cubeb, the audio input/output system. Valid values are
 // "verbose", "normal" and "" (log disabled).
 pref("media.cubeb.logging_level", "");
 
 // Cubeb sandbox (remoting) control
 #ifdef XP_LINUX
 pref("media.cubeb.sandbox", true);
+// The cubeb pulse audio backend effectively serializes callbacks so
+// only 1 thread is required.
+pref("media.audioipc.pool_size", 1);
+// 64 kB stack per pool thread.
+pref("media.audioipc.stack_size", 65536);
 #else
 pref("media.cubeb.sandbox", false);
 #endif
 
 // Set to true to force demux/decode warnings to be treated as errors.
 pref("media.playback.warnings-as-errors", false);
 
 // Weather we allow AMD switchable graphics