# HG changeset patch # User Matthew Gregan # Date 1525075172 -43200 # Node ID f38524bd2735d9885d9f5c69980f755f9816bed3 # Parent d7563a833c28daaf56edee0dff5428fc131cc172 Bug 1427011 - Disable default device switching in libcubeb's WASAPI backend. r=padenot diff --git a/dom/media/AudioStream.cpp b/dom/media/AudioStream.cpp --- a/dom/media/AudioStream.cpp +++ b/dom/media/AudioStream.cpp @@ -347,17 +347,17 @@ AudioStream::Init(uint32_t aNumChannels, mDumpFile = OpenDumpFile(aNumChannels, aRate); cubeb_stream_params params; params.rate = aRate; params.channels = mOutChannels; params.layout = static_cast(aChannelMap); params.format = ToCubebFormat::value; - params.prefs = CUBEB_STREAM_PREF_NONE; + params.prefs = CubebUtils::GetDefaultStreamPrefs(); mAudioClock.Init(aRate); cubeb* cubebContext = CubebUtils::GetCubebContext(); if (!cubebContext) { LOGE("Can't get cubeb context!"); CubebUtils::ReportCubebStreamInitFailure(true); return NS_ERROR_DOM_MEDIA_CUBEB_INITIALIZATION_ERR; diff --git a/dom/media/CubebUtils.cpp b/dom/media/CubebUtils.cpp --- a/dom/media/CubebUtils.cpp +++ b/dom/media/CubebUtils.cpp @@ -37,16 +37,18 @@ #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" // Hidden pref used by tests to force failure to obtain cubeb context #define PREF_CUBEB_FORCE_NULL_CONTEXT "media.cubeb.force_null_context" +// Hidden pref to disable BMO 1427011 experiment; can be removed once proven. +#define PREF_CUBEB_DISABLE_DEVICE_SWITCHING "media.cubeb.disable_device_switching" #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" #if defined(XP_LINUX) || defined(XP_MACOSX) #define MOZ_CUBEB_REMOTING #endif @@ -125,16 +127,17 @@ 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; bool sCubebForceNullContext = false; +bool sCubebDisableDeviceSwitching = true; #ifdef MOZ_CUBEB_REMOTING bool sCubebSandbox = false; size_t sAudioIPCPoolSize; size_t sAudioIPCStackSize; #endif StaticAutoPtr sBrandName; StaticAutoPtr sCubebBackendName; @@ -238,17 +241,22 @@ void PrefChanged(const char* aPref, void PodCopy(sCubebBackendName.get(), value.get(), value.Length()); sCubebBackendName[value.Length()] = 0; } } else if (strcmp(aPref, PREF_CUBEB_FORCE_NULL_CONTEXT) == 0) { StaticMutexAutoLock lock(sMutex); sCubebForceNullContext = Preferences::GetBool(aPref, false); MOZ_LOG(gCubebLog, LogLevel::Verbose, ("%s: %s", PREF_CUBEB_FORCE_NULL_CONTEXT, sCubebForceNullContext ? "true" : "false")); - } + } else if (strcmp(aPref, PREF_CUBEB_DISABLE_DEVICE_SWITCHING) == 0) { + StaticMutexAutoLock lock(sMutex); + sCubebDisableDeviceSwitching = Preferences::GetBool(aPref, true); + MOZ_LOG(gCubebLog, LogLevel::Verbose, + ("%s: %s", PREF_CUBEB_DISABLE_DEVICE_SWITCHING, sCubebDisableDeviceSwitching ? "true" : "false")); + } #ifdef MOZ_CUBEB_REMOTING else if (strcmp(aPref, PREF_CUBEB_SANDBOX) == 0) { StaticMutexAutoLock lock(sMutex); 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...")); @@ -689,16 +697,29 @@ void GetDeviceCollection(nsTArray 0); return sample_rate; } uint32_t AndroidGetAudioOutputFramesPerBuffer() diff --git a/dom/media/CubebUtils.h b/dom/media/CubebUtils.h --- a/dom/media/CubebUtils.h +++ b/dom/media/CubebUtils.h @@ -41,16 +41,17 @@ cubeb* GetCubebContext(); void ReportCubebStreamInitFailure(bool aIsFirstStream); void ReportCubebBackendUsed(); uint32_t GetCubebPlaybackLatencyInMilliseconds(); uint32_t GetCubebMSGLatencyInFrames(cubeb_stream_params * params); bool CubebLatencyPrefSet(); void GetCurrentBackend(nsAString& aBackend); void GetDeviceCollection(nsTArray>& aDeviceInfos, Side aSide); +cubeb_stream_prefs GetDefaultStreamPrefs(); #ifdef MOZ_WIDGET_ANDROID uint32_t AndroidGetAudioOutputSampleRate(); uint32_t AndroidGetAudioOutputFramesPerBuffer(); #endif } // namespace CubebUtils } // namespace mozilla diff --git a/dom/media/GraphDriver.cpp b/dom/media/GraphDriver.cpp --- a/dom/media/GraphDriver.cpp +++ b/dom/media/GraphDriver.cpp @@ -622,17 +622,17 @@ AudioCallbackDriver::Init() return true; } mBuffer = AudioCallbackBufferWrapper(mOutputChannels); mScratchBuffer = SpillBuffer(mOutputChannels); output.channels = mOutputChannels; output.layout = CUBEB_LAYOUT_UNDEFINED; - output.prefs = CUBEB_STREAM_PREF_NONE; + output.prefs = CubebUtils::GetDefaultStreamPrefs(); uint32_t latency_frames = CubebUtils::GetCubebMSGLatencyInFrames(&output); // Macbook and MacBook air don't have enough CPU to run very low latency // MediaStreamGraphs, cap the minimal latency to 512 frames int this case. if (IsMacbookOrMacbookAir()) { latency_frames = std::max((uint32_t) 512, latency_frames); } diff --git a/media/libcubeb/disable-device-switching.patch b/media/libcubeb/disable-device-switching.patch new file mode 100644 --- /dev/null +++ b/media/libcubeb/disable-device-switching.patch @@ -0,0 +1,87 @@ +diff --git a/media/libcubeb/include/cubeb.h b/media/libcubeb/include/cubeb.h +--- a/media/libcubeb/include/cubeb.h ++++ b/media/libcubeb/include/cubeb.h +@@ -216,20 +216,23 @@ enum { + CHANNEL_FRONT_CENTER | CHANNEL_LOW_FREQUENCY | + CHANNEL_BACK_LEFT | CHANNEL_BACK_RIGHT | + CHANNEL_SIDE_LEFT | CHANNEL_SIDE_RIGHT, + }; + + /** Miscellaneous stream preferences. */ + typedef enum { + CUBEB_STREAM_PREF_NONE = 0x00, /**< No stream preferences are requested. */ +- CUBEB_STREAM_PREF_LOOPBACK = 0x01 /**< Request a loopback stream. Should be +- specified on the input params and an +- output device to loopback from should +- be passed in place of an input device. */ ++ CUBEB_STREAM_PREF_LOOPBACK = 0x01, /**< Request a loopback stream. Should be ++ specified on the input params and an ++ output device to loopback from should ++ be passed in place of an input device. */ ++ CUBEB_STREAM_PREF_DISABLE_DEVICE_SWITCHING = 0x02, /**< Disable switching ++ default device on OS ++ changes. */ + } cubeb_stream_prefs; + + /** Stream format initialization parameters. */ + typedef struct { + cubeb_sample_format format; /**< Requested sample format. One of + #cubeb_sample_format. */ + uint32_t rate; /**< Requested sample rate. Valid range is [1000, 192000]. */ + uint32_t channels; /**< Requested channel count. Valid range is [1, 8]. */ +diff --git a/media/libcubeb/src/cubeb_wasapi.cpp b/media/libcubeb/src/cubeb_wasapi.cpp +--- a/media/libcubeb/src/cubeb_wasapi.cpp ++++ b/media/libcubeb/src/cubeb_wasapi.cpp +@@ -1829,21 +1829,26 @@ wasapi_stream_init(cubeb * context, cube + assert that the lock is held in the function. */ + auto_lock lock(stm->stream_reset_lock); + rv = setup_wasapi_stream(stm.get()); + } + if (rv != CUBEB_OK) { + return rv; + } + +- HRESULT hr = register_notification_client(stm.get()); +- if (FAILED(hr)) { +- /* this is not fatal, we can still play audio, but we won't be able +- to keep using the default audio endpoint if it changes. */ +- LOG("failed to register notification client, %lx", hr); ++ if (!((input_stream_params ? ++ (input_stream_params->prefs & CUBEB_STREAM_PREF_DISABLE_DEVICE_SWITCHING) : 0) || ++ (output_stream_params ? ++ (output_stream_params->prefs & CUBEB_STREAM_PREF_DISABLE_DEVICE_SWITCHING) : 0))) { ++ HRESULT hr = register_notification_client(stm.get()); ++ if (FAILED(hr)) { ++ /* this is not fatal, we can still play audio, but we won't be able ++ to keep using the default audio endpoint if it changes. */ ++ LOG("failed to register notification client, %lx", hr); ++ } + } + + *stream = stm.release(); + + LOG("Stream init succesfull (%p)", *stream); + return CUBEB_OK; + } + +@@ -1879,17 +1884,19 @@ void wasapi_stream_destroy(cubeb_stream + // Only free stm->emergency_bailout if we could join the thread. + // If we could not join the thread, stm->emergency_bailout is true + // and is still alive until the thread wakes up and exits cleanly. + if (stop_and_join_render_thread(stm)) { + delete stm->emergency_bailout.load(); + stm->emergency_bailout = nullptr; + } + +- unregister_notification_client(stm); ++ if (stm->notification_client) { ++ unregister_notification_client(stm); ++ } + + CloseHandle(stm->reconfigure_event); + CloseHandle(stm->refill_event); + CloseHandle(stm->input_available_event); + + // The variables intialized in wasapi_stream_init, + // must be destroyed in wasapi_stream_destroy. + stm->linear_input_buffer.reset(); diff --git a/media/libcubeb/include/cubeb.h b/media/libcubeb/include/cubeb.h --- a/media/libcubeb/include/cubeb.h +++ b/media/libcubeb/include/cubeb.h @@ -216,20 +216,23 @@ enum { CHANNEL_FRONT_CENTER | CHANNEL_LOW_FREQUENCY | CHANNEL_BACK_LEFT | CHANNEL_BACK_RIGHT | CHANNEL_SIDE_LEFT | CHANNEL_SIDE_RIGHT, }; /** Miscellaneous stream preferences. */ typedef enum { CUBEB_STREAM_PREF_NONE = 0x00, /**< No stream preferences are requested. */ - CUBEB_STREAM_PREF_LOOPBACK = 0x01 /**< Request a loopback stream. Should be - specified on the input params and an - output device to loopback from should - be passed in place of an input device. */ + CUBEB_STREAM_PREF_LOOPBACK = 0x01, /**< Request a loopback stream. Should be + specified on the input params and an + output device to loopback from should + be passed in place of an input device. */ + CUBEB_STREAM_PREF_DISABLE_DEVICE_SWITCHING = 0x02, /**< Disable switching + default device on OS + changes. */ } cubeb_stream_prefs; /** Stream format initialization parameters. */ typedef struct { cubeb_sample_format format; /**< Requested sample format. One of #cubeb_sample_format. */ uint32_t rate; /**< Requested sample rate. Valid range is [1000, 192000]. */ uint32_t channels; /**< Requested channel count. Valid range is [1, 8]. */ diff --git a/media/libcubeb/src/cubeb_wasapi.cpp b/media/libcubeb/src/cubeb_wasapi.cpp --- a/media/libcubeb/src/cubeb_wasapi.cpp +++ b/media/libcubeb/src/cubeb_wasapi.cpp @@ -1832,21 +1832,26 @@ wasapi_stream_init(cubeb * context, cube assert that the lock is held in the function. */ auto_lock lock(stm->stream_reset_lock); rv = setup_wasapi_stream(stm.get()); } if (rv != CUBEB_OK) { return rv; } - HRESULT hr = register_notification_client(stm.get()); - if (FAILED(hr)) { - /* this is not fatal, we can still play audio, but we won't be able - to keep using the default audio endpoint if it changes. */ - LOG("failed to register notification client, %lx", hr); + if (!((input_stream_params ? + (input_stream_params->prefs & CUBEB_STREAM_PREF_DISABLE_DEVICE_SWITCHING) : 0) || + (output_stream_params ? + (output_stream_params->prefs & CUBEB_STREAM_PREF_DISABLE_DEVICE_SWITCHING) : 0))) { + HRESULT hr = register_notification_client(stm.get()); + if (FAILED(hr)) { + /* this is not fatal, we can still play audio, but we won't be able + to keep using the default audio endpoint if it changes. */ + LOG("failed to register notification client, %lx", hr); + } } *stream = stm.release(); LOG("Stream init succesfull (%p)", *stream); return CUBEB_OK; } @@ -1882,17 +1887,19 @@ void wasapi_stream_destroy(cubeb_stream // Only free stm->emergency_bailout if we could join the thread. // If we could not join the thread, stm->emergency_bailout is true // and is still alive until the thread wakes up and exits cleanly. if (stop_and_join_render_thread(stm)) { delete stm->emergency_bailout.load(); stm->emergency_bailout = nullptr; } - unregister_notification_client(stm); + if (stm->notification_client) { + unregister_notification_client(stm); + } CloseHandle(stm->reconfigure_event); CloseHandle(stm->refill_event); CloseHandle(stm->input_available_event); // The variables intialized in wasapi_stream_init, // must be destroyed in wasapi_stream_destroy. stm->linear_input_buffer.reset(); diff --git a/media/libcubeb/update.sh b/media/libcubeb/update.sh --- a/media/libcubeb/update.sh +++ b/media/libcubeb/update.sh @@ -75,10 +75,14 @@ else fi echo "Applying disable-assert.patch on top of $rev" patch -p3 < disable-assert.patch echo "Applying prefer-pulse-rust.patch on top of $rev" patch -p3 < prefer-pulse-rust.patch +echo "Applying disable-device-switching.patch on top of $rev" +patch -p3 < disable-device-switching.patch + + echo "Applying mingw-ucrt.patch on top of $rev" patch -p1 < mingw-ucrt.patch