Bug 1411866 - Uplift cubeb import to cf5ddc5. r=padenot, a=ritu
authorAlex Chronopoulos <achronop@gmail.com>
Thu, 26 Oct 2017 10:41:49 +0300
changeset 435295 b1dc78a5838b3bef69b4ae4d2c0c9bc351ef9ff7
parent 435294 7591c7732048a08c2adb1337461da7f41dcc4274
child 435296 3e4524e4b17905dcc3a854b581bac2391af46119
push id1567
push userjlorenzo@mozilla.com
push dateThu, 02 Nov 2017 12:36:05 +0000
treeherdermozilla-release@e512c14a0406 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspadenot, ritu
bugs1411866
milestone57.0
Bug 1411866 - Uplift cubeb import to cf5ddc5. r=padenot, a=ritu
media/libcubeb/bug-1411866-beta-uplift.patch
media/libcubeb/src/cubeb_audiounit.cpp
media/libcubeb/src/cubeb_utils.h
media/libcubeb/update.sh
new file mode 100644
--- /dev/null
+++ b/media/libcubeb/bug-1411866-beta-uplift.patch
@@ -0,0 +1,183 @@
+
+# HG changeset patch
+# User Alex Chronopoulos <achronop@gmail.com>
+# Date 1509003709 -10800
+# Node ID 80f6a508d20760644b70b035bb96852458b2a7c6
+# Parent  50954281973869a6ce2c5d78f53a9f8219565579
+Bug 1411866 - Uplift cubeb import to cf5ddc5.r?padenot
+
+diff --git a/media/libcubeb/src/cubeb_audiounit.cpp b/media/libcubeb/src/cubeb_audiounit.cpp
+--- a/media/libcubeb/src/cubeb_audiounit.cpp
++++ b/media/libcubeb/src/cubeb_audiounit.cpp
+@@ -646,23 +646,29 @@ audiounit_reinit_stream(cubeb_stream * s
+ 
+     audiounit_close_stream(stm);
+ 
+     /* Reinit occurs in 2 cases. When the device is not alive any more and when the
+      * default system device change. In both cases cubeb switch on the new default
+      * device. This is considered the most expected behavior for the user. */
+     if (flags & DEV_INPUT) {
+       r = audiounit_set_device_info(stm, 0, INPUT);
+-      assert(r == CUBEB_OK);
++      if (r != CUBEB_OK) {
++        LOG("(%p) Set input device info failed. This can happen when last media device is unplugged", stm);
++        return CUBEB_ERROR;
++      }
+     }
+     /* Always use the default output on reinit. This is not correct in every case
+      * but it is sufficient for Firefox and prevent reinit from reporting failures.
+      * It will change soon when reinit mechanism will be updated. */
+     r = audiounit_set_device_info(stm, 0, OUTPUT);
+-    assert(r == CUBEB_OK);
++    if (r != CUBEB_OK) {
++      LOG("(%p) Set output device info failed. This can happen when last media device is unplugged", stm);
++      return CUBEB_ERROR;
++    }
+ 
+     if (audiounit_setup_stream(stm) != CUBEB_OK) {
+       LOG("(%p) Stream reinit failed.", stm);
+       return CUBEB_ERROR;
+     }
+ 
+     if (vol_rv == CUBEB_OK) {
+       audiounit_stream_set_volume(stm, volume);
+@@ -692,16 +698,18 @@ event_addr_to_string(AudioObjectProperty
+       return "kAudioDevicePropertyDeviceIsAlive";
+     case kAudioDevicePropertyDataSource:
+       return "kAudioDevicePropertyDataSource";
+     default:
+       return "Unknown";
+   }
+ }
+ 
++static int audiounit_uninstall_system_changed_callback(cubeb_stream * stm);
++
+ static OSStatus
+ audiounit_property_listener_callback(AudioObjectID id, UInt32 address_count,
+                                      const AudioObjectPropertyAddress * addresses,
+                                      void * user)
+ {
+   cubeb_stream * stm = (cubeb_stream*) user;
+   if (stm->switching_device) {
+     LOG("Switching is already taking place. Skip Event %s for id=%d", event_addr_to_string(addresses[0].mSelector), id);
+@@ -770,16 +778,19 @@ audiounit_property_listener_callback(Aud
+       }
+     }
+   }
+ 
+   // Use a new thread, through the queue, to avoid deadlock when calling
+   // Get/SetProperties method from inside notify callback
+   dispatch_async(stm->context->serial_queue, ^() {
+     if (audiounit_reinit_stream(stm, switch_side) != CUBEB_OK) {
++      if (audiounit_uninstall_system_changed_callback(stm) != CUBEB_OK) {
++        LOG("(%p) Could not uninstall the device changed callback", stm);
++      }
+       stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STOPPED);
+       LOG("(%p) Could not reopen the stream after switching.", stm);
+     }
+     stm->switching_device = false;
+   });
+ 
+   return noErr;
+ }
+@@ -916,25 +927,25 @@ audiounit_uninstall_device_changed_callb
+   return r;
+ }
+ 
+ static int
+ audiounit_uninstall_system_changed_callback(cubeb_stream * stm)
+ {
+   OSStatus r;
+ 
+-  if (stm->output_unit) {
++  if (has_output(stm)) {
+     r = audiounit_remove_listener(stm, kAudioObjectSystemObject, kAudioHardwarePropertyDefaultOutputDevice,
+                                   kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
+     if (r != noErr) {
+       return CUBEB_ERROR;
+     }
+   }
+ 
+-  if (stm->input_unit) {
++  if (has_input(stm)) {
+     r = audiounit_remove_listener(stm, kAudioObjectSystemObject, kAudioHardwarePropertyDefaultInputDevice,
+                                   kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
+     if (r != noErr) {
+       return CUBEB_ERROR;
+     }
+   }
+   return CUBEB_OK;
+ }
+@@ -2493,29 +2504,29 @@ audiounit_stream_init(cubeb * context,
+                       cubeb_stream_params * input_stream_params,
+                       cubeb_devid output_device,
+                       cubeb_stream_params * output_stream_params,
+                       unsigned int latency_frames,
+                       cubeb_data_callback data_callback,
+                       cubeb_state_callback state_callback,
+                       void * user_ptr)
+ {
+-  std::unique_ptr<cubeb_stream, decltype(&audiounit_stream_destroy)> stm(nullptr, audiounit_stream_destroy);
++  std::unique_ptr<cubeb_stream, decltype(&audiounit_stream_destroy)> stm(new cubeb_stream(context),
++                                                                         audiounit_stream_destroy);
++  context->active_streams += 1;
+   int r;
+ 
+   assert(context);
+   *stream = NULL;
+   assert(latency_frames > 0);
+   if ((input_device && !input_stream_params) ||
+       (output_device && !output_stream_params)) {
+     return CUBEB_ERROR_INVALID_PARAMETER;
+   }
+ 
+-  stm.reset(new cubeb_stream(context));
+-
+   /* These could be different in the future if we have both
+    * full-duplex stream and different devices for input vs output. */
+   stm->data_callback = data_callback;
+   stm->state_callback = state_callback;
+   stm->user_ptr = user_ptr;
+   stm->latency_frames = latency_frames;
+   if (input_stream_params) {
+     stm->input_stream_params = *input_stream_params;
+@@ -2534,17 +2545,16 @@ audiounit_stream_init(cubeb * context,
+     }
+   }
+ 
+   auto_lock context_lock(context->mutex);
+   {
+     // It's not critical to lock here, because no other thread has been started
+     // yet, but it allows to assert that the lock has been taken in
+     // `audiounit_setup_stream`.
+-    context->active_streams += 1;
+     auto_lock lock(stm->mutex);
+     r = audiounit_setup_stream(stm.get());
+   }
+ 
+   if (r != CUBEB_OK) {
+     LOG("(%p) Could not setup the audiounit stream.", stm.get());
+     return r;
+   }
+diff --git a/media/libcubeb/src/cubeb_utils.h b/media/libcubeb/src/cubeb_utils.h
+--- a/media/libcubeb/src/cubeb_utils.h
++++ b/media/libcubeb/src/cubeb_utils.h
+@@ -12,17 +12,17 @@
+ 
+ #ifdef __cplusplus
+ 
+ #include <stdint.h>
+ #include <string.h>
+ #include <assert.h>
+ #include <mutex>
+ #include <type_traits>
+-#if defined(WIN32)
++#if defined(_WIN32)
+ #include "cubeb_utils_win.h"
+ #else
+ #include "cubeb_utils_unix.h"
+ #endif
+ 
+ /** Similar to memcpy, but accounts for the size of an element. */
+ template<typename T>
+ void PodCopy(T * destination, const T * source, size_t count)
--- a/media/libcubeb/src/cubeb_audiounit.cpp
+++ b/media/libcubeb/src/cubeb_audiounit.cpp
@@ -646,23 +646,29 @@ audiounit_reinit_stream(cubeb_stream * s
 
     audiounit_close_stream(stm);
 
     /* Reinit occurs in 2 cases. When the device is not alive any more and when the
      * default system device change. In both cases cubeb switch on the new default
      * device. This is considered the most expected behavior for the user. */
     if (flags & DEV_INPUT) {
       r = audiounit_set_device_info(stm, 0, INPUT);
-      assert(r == CUBEB_OK);
+      if (r != CUBEB_OK) {
+        LOG("(%p) Set input device info failed. This can happen when last media device is unplugged", stm);
+        return CUBEB_ERROR;
+      }
     }
     /* Always use the default output on reinit. This is not correct in every case
      * but it is sufficient for Firefox and prevent reinit from reporting failures.
      * It will change soon when reinit mechanism will be updated. */
     r = audiounit_set_device_info(stm, 0, OUTPUT);
-    assert(r == CUBEB_OK);
+    if (r != CUBEB_OK) {
+      LOG("(%p) Set output device info failed. This can happen when last media device is unplugged", stm);
+      return CUBEB_ERROR;
+    }
 
     if (audiounit_setup_stream(stm) != CUBEB_OK) {
       LOG("(%p) Stream reinit failed.", stm);
       return CUBEB_ERROR;
     }
 
     if (vol_rv == CUBEB_OK) {
       audiounit_stream_set_volume(stm, volume);
@@ -692,16 +698,18 @@ event_addr_to_string(AudioObjectProperty
       return "kAudioDevicePropertyDeviceIsAlive";
     case kAudioDevicePropertyDataSource:
       return "kAudioDevicePropertyDataSource";
     default:
       return "Unknown";
   }
 }
 
+static int audiounit_uninstall_system_changed_callback(cubeb_stream * stm);
+
 static OSStatus
 audiounit_property_listener_callback(AudioObjectID id, UInt32 address_count,
                                      const AudioObjectPropertyAddress * addresses,
                                      void * user)
 {
   cubeb_stream * stm = (cubeb_stream*) user;
   if (stm->switching_device) {
     LOG("Switching is already taking place. Skip Event %s for id=%d", event_addr_to_string(addresses[0].mSelector), id);
@@ -770,16 +778,19 @@ audiounit_property_listener_callback(Aud
       }
     }
   }
 
   // Use a new thread, through the queue, to avoid deadlock when calling
   // Get/SetProperties method from inside notify callback
   dispatch_async(stm->context->serial_queue, ^() {
     if (audiounit_reinit_stream(stm, switch_side) != CUBEB_OK) {
+      if (audiounit_uninstall_system_changed_callback(stm) != CUBEB_OK) {
+        LOG("(%p) Could not uninstall the device changed callback", stm);
+      }
       stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STOPPED);
       LOG("(%p) Could not reopen the stream after switching.", stm);
     }
     stm->switching_device = false;
   });
 
   return noErr;
 }
@@ -916,25 +927,25 @@ audiounit_uninstall_device_changed_callb
   return r;
 }
 
 static int
 audiounit_uninstall_system_changed_callback(cubeb_stream * stm)
 {
   OSStatus r;
 
-  if (stm->output_unit) {
+  if (has_output(stm)) {
     r = audiounit_remove_listener(stm, kAudioObjectSystemObject, kAudioHardwarePropertyDefaultOutputDevice,
                                   kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
     if (r != noErr) {
       return CUBEB_ERROR;
     }
   }
 
-  if (stm->input_unit) {
+  if (has_input(stm)) {
     r = audiounit_remove_listener(stm, kAudioObjectSystemObject, kAudioHardwarePropertyDefaultInputDevice,
                                   kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
     if (r != noErr) {
       return CUBEB_ERROR;
     }
   }
   return CUBEB_OK;
 }
@@ -2493,29 +2504,29 @@ audiounit_stream_init(cubeb * context,
                       cubeb_stream_params * input_stream_params,
                       cubeb_devid output_device,
                       cubeb_stream_params * output_stream_params,
                       unsigned int latency_frames,
                       cubeb_data_callback data_callback,
                       cubeb_state_callback state_callback,
                       void * user_ptr)
 {
-  std::unique_ptr<cubeb_stream, decltype(&audiounit_stream_destroy)> stm(nullptr, audiounit_stream_destroy);
+  std::unique_ptr<cubeb_stream, decltype(&audiounit_stream_destroy)> stm(new cubeb_stream(context),
+                                                                         audiounit_stream_destroy);
+  context->active_streams += 1;
   int r;
 
   assert(context);
   *stream = NULL;
   assert(latency_frames > 0);
   if ((input_device && !input_stream_params) ||
       (output_device && !output_stream_params)) {
     return CUBEB_ERROR_INVALID_PARAMETER;
   }
 
-  stm.reset(new cubeb_stream(context));
-
   /* These could be different in the future if we have both
    * full-duplex stream and different devices for input vs output. */
   stm->data_callback = data_callback;
   stm->state_callback = state_callback;
   stm->user_ptr = user_ptr;
   stm->latency_frames = latency_frames;
   if (input_stream_params) {
     stm->input_stream_params = *input_stream_params;
@@ -2534,17 +2545,16 @@ audiounit_stream_init(cubeb * context,
     }
   }
 
   auto_lock context_lock(context->mutex);
   {
     // It's not critical to lock here, because no other thread has been started
     // yet, but it allows to assert that the lock has been taken in
     // `audiounit_setup_stream`.
-    context->active_streams += 1;
     auto_lock lock(stm->mutex);
     r = audiounit_setup_stream(stm.get());
   }
 
   if (r != CUBEB_OK) {
     LOG("(%p) Could not setup the audiounit stream.", stm.get());
     return r;
   }
--- a/media/libcubeb/src/cubeb_utils.h
+++ b/media/libcubeb/src/cubeb_utils.h
@@ -12,17 +12,17 @@
 
 #ifdef __cplusplus
 
 #include <stdint.h>
 #include <string.h>
 #include <assert.h>
 #include <mutex>
 #include <type_traits>
-#if defined(WIN32)
+#if defined(_WIN32)
 #include "cubeb_utils_win.h"
 #else
 #include "cubeb_utils_unix.h"
 #endif
 
 /** Similar to memcpy, but accounts for the size of an element. */
 template<typename T>
 void PodCopy(T * destination, const T * source, size_t count)
--- a/media/libcubeb/update.sh
+++ b/media/libcubeb/update.sh
@@ -75,8 +75,11 @@ patch -p3 < disable-assert.patch
 echo "Applying prefer-pulse-rust.patch on top of $rev"
 patch -p3 < prefer-pulse-rust.patch
 
 echo "Applying pulse-handle-no-sinks.patch on top of $rev"
 patch -p3 < pulse-handle-no-sinks.patch
 
 echo "Applying bug-1405258-beta-uplift.patch on top of $rev"
 patch -p1 < bug-1405258-beta-uplift.patch
+
+echo "Applying bug-1411866-beta-uplift.patch on top of $rev"
+patch -p3 < bug-1411866-beta-uplift.patch