Bug 923992 - Call GetDefaultAudioEndpoint when needed rather than caching its result when called at cubeb init time. r=padenot
☠☠ backed out by c5d32149691a ☠ ☠
authorMatthew Gregan <kinetik@flim.org>
Thu, 28 Nov 2013 14:12:45 +1300
changeset 157846 de7d74796ced3fade645e1be2e2f3d54fbbabf70
parent 157845 36b6702581d435354bbda1a58223b3c7230fbfa1
child 157847 7c4fd87a40737bd4c8a2b7b258c613dd6fb19b80
push id36866
push usermgregan@mozilla.com
push dateThu, 28 Nov 2013 01:13:22 +0000
treeherdermozilla-inbound@de7d74796ced [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspadenot
bugs923992
milestone28.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 923992 - Call GetDefaultAudioEndpoint when needed rather than caching its result when called at cubeb init time. r=padenot
media/libcubeb/README_MOZILLA
media/libcubeb/src/cubeb_wasapi.cpp
--- a/media/libcubeb/README_MOZILLA
+++ b/media/libcubeb/README_MOZILLA
@@ -1,8 +1,8 @@
 The source from this directory was copied from the cubeb 
 git repository using the update.sh script.  The only changes
 made were those applied by update.sh and the addition of
 Makefile.in build files for the Mozilla build system.
 
 The cubeb git repository is: git://github.com/kinetiknz/cubeb.git
 
-The git commit ID used was 8c78a282aa0320e997436d6832024efe1527ca1c.
+The git commit ID used was 6ba033d2a3ebd10c1d4a2b9d2032c3675c9176ce.
--- a/media/libcubeb/src/cubeb_wasapi.cpp
+++ b/media/libcubeb/src/cubeb_wasapi.cpp
@@ -83,17 +83,16 @@ typedef HANDLE (WINAPI *set_mm_thread_ch
 typedef BOOL (WINAPI *revert_mm_thread_characteristics_function)(HANDLE handle);
 
 extern cubeb_ops const wasapi_ops;
 }
 
 struct cubeb
 {
   cubeb_ops const * ops;
-  IMMDevice * device;
   /* Library dynamically opened to increase the render
    * thread priority, and the two function pointers we need. */
   HMODULE mmcss_module;
   set_mm_thread_characteristics_function set_mm_thread_characteristics;
   revert_mm_thread_characteristics_function revert_mm_thread_characteristics;
 };
 
 
@@ -419,57 +418,59 @@ HANDLE WINAPI set_mm_thread_characterist
 {
   return (HANDLE)1;
 }
 
 BOOL WINAPI revert_mm_thread_characteristics_noop(HANDLE mmcss_handle)
 {
   return true;
 }
+
+HRESULT get_default_endpoint(IMMDevice ** device)
+{
+  IMMDeviceEnumerator * enumerator;
+  HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator),
+                                NULL, CLSCTX_INPROC_SERVER,
+                                IID_PPV_ARGS(&enumerator));
+  if (FAILED(hr)) {
+    LOG("Could not get device enumerator.");
+    return hr;
+  }
+  /* eMultimedia is okay for now ("Music, movies, narration, [...]").
+   * We will need to change this when we distinguish streams by use-case, other
+   * possible values being eConsole ("Games, system notification sounds [...]")
+   * and eCommunication ("Voice communication"). */
+  hr = enumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, device);
+  if (FAILED(hr)) {
+    LOG("Could not get default audio endpoint.");
+    SafeRelease(enumerator);
+    return hr;
+  }
+
+  SafeRelease(enumerator);
+
+  return ERROR_SUCCESS;
+}
 } // namespace anonymous
 
 extern "C" {
 int wasapi_init(cubeb ** context, char const * context_name)
 {
   HRESULT hr;
-  IMMDeviceEnumerator * enumerator = NULL;
 
   hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
   if (FAILED(hr)) {
     LOG("Could not init COM.");
     return CUBEB_ERROR;
   }
 
   cubeb * ctx = (cubeb *)calloc(1, sizeof(cubeb));
 
   ctx->ops = &wasapi_ops;
 
-  hr = CoCreateInstance(__uuidof(MMDeviceEnumerator),
-                        NULL, CLSCTX_INPROC_SERVER,
-                        IID_PPV_ARGS(&enumerator));
-  if (FAILED(hr)) {
-    LOG("Could not get device enumerator.");
-    wasapi_destroy(ctx);
-    return CUBEB_ERROR;
-  }
-
-  /* eMultimedia is okay for now ("Music, movies, narration, [...]").
-   * We will need to change this when we distinguish streams by use-case, other
-   * possible values being eConsole ("Games, system notification sounds [...]")
-   * and eCommunication ("Voice communication"). */
-  hr = enumerator->GetDefaultAudioEndpoint(eRender,
-                                           eMultimedia,
-                                           &ctx->device);
-  if (FAILED(hr)) {
-    LOG("Could not get default audio endpoint.");
-    SafeRelease(enumerator);
-    wasapi_destroy(ctx);
-    return CUBEB_ERROR;
-  }
-
   ctx->mmcss_module = LoadLibraryA("Avrt.dll");
 
   if (ctx->mmcss_module) {
     ctx->set_mm_thread_characteristics =
       (set_mm_thread_characteristics_function) GetProcAddress(
           ctx->mmcss_module, "AvSetMmThreadCharacteristicsA");
     ctx->revert_mm_thread_characteristics =
       (revert_mm_thread_characteristics_function) GetProcAddress(
@@ -480,59 +481,63 @@ int wasapi_init(cubeb ** context, char c
     }
   } else {
     // This is not a fatal error, but we might end up glitching when
     // the system is under high load.
     LOG("Could not load Avrt.dll");
     ctx->set_mm_thread_characteristics = &set_mm_thread_characteristics_noop;
     ctx->revert_mm_thread_characteristics = &revert_mm_thread_characteristics_noop;
   }
-  
-  SafeRelease(enumerator);
 
   *context = ctx;
 
   return CUBEB_OK;
 }
 }
 
 namespace {
 
 void wasapi_destroy(cubeb * context)
 {
-  SafeRelease(context->device);
   if (context->mmcss_module) {
     FreeLibrary(context->mmcss_module);
   }
   free(context);
 }
 
 char const* wasapi_get_backend_id(cubeb * context)
 {
   return "wasapi";
 }
 
 int
 wasapi_get_max_channel_count(cubeb * ctx, uint32_t * max_channels)
 {
-  HRESULT hr;
   IAudioClient * client;
   WAVEFORMATEX * mix_format;
 
   assert(ctx && max_channels);
 
-  hr = ctx->device->Activate(__uuidof(IAudioClient),
-                             CLSCTX_INPROC_SERVER,
-                             NULL, (void **)&client);
+  IMMDevice * device;
+  HRESULT hr = get_default_endpoint(&device);
+  if (FAILED(hr)) {
+    return CUBEB_ERROR;
+  }
+
+  hr = device->Activate(__uuidof(IAudioClient),
+                        CLSCTX_INPROC_SERVER,
+                        NULL, (void **)&client);
+  SafeRelease(device);
   if (FAILED(hr)) {
     return CUBEB_ERROR;
   }
 
   hr = client->GetMixFormat(&mix_format);
   if (FAILED(hr)) {
+    SafeRelease(client);
     return CUBEB_ERROR;
   }
 
   *max_channels = mix_format->nChannels;
 
   CoTaskMemFree(mix_format);
   SafeRelease(client);
 
@@ -541,26 +546,36 @@ wasapi_get_max_channel_count(cubeb * ctx
 
 int
 wasapi_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency_ms)
 {
   HRESULT hr;
   IAudioClient * client;
   REFERENCE_TIME default_period;
 
-  hr = ctx->device->Activate(__uuidof(IAudioClient),
-                             CLSCTX_INPROC_SERVER,
-                             NULL, (void **)&client);
+  IMMDevice * device;
+  hr = get_default_endpoint(&device);
+  if (FAILED(hr)) {
+    return CUBEB_ERROR;
+  }
 
+  hr = device->Activate(__uuidof(IAudioClient),
+                        CLSCTX_INPROC_SERVER,
+                        NULL, (void **)&client);
+  SafeRelease(device);
   if (FAILED(hr)) {
     return CUBEB_ERROR;
   }
 
   /* The second parameter is for exclusive mode, that we don't use. */
-  hr= client->GetDevicePeriod(&default_period, NULL);
+  hr = client->GetDevicePeriod(&default_period, NULL);
+  if (FAILED(hr)) {
+    SafeRelease(client);
+    return CUBEB_ERROR;
+  }
 
   /* According to the docs, the best latency we can achieve is by synchronizing
    * the stream and the engine.
    * http://msdn.microsoft.com/en-us/library/windows/desktop/dd370871%28v=vs.85%29.aspx */
   *latency_ms = hns_to_ms(default_period);
 
   SafeRelease(client);
 
@@ -569,26 +584,31 @@ wasapi_get_min_latency(cubeb * ctx, cube
 
 int
 wasapi_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate)
 {
   HRESULT hr;
   IAudioClient * client;
   WAVEFORMATEX * mix_format;
 
-  hr = ctx->device->Activate(__uuidof(IAudioClient),
-                             CLSCTX_INPROC_SERVER,
-                             NULL, (void **)&client);
+  IMMDevice * device;
+  hr = get_default_endpoint(&device);
+  if (FAILED(hr)) {
+    return CUBEB_ERROR;
+  };
 
+  hr = device->Activate(__uuidof(IAudioClient),
+                        CLSCTX_INPROC_SERVER,
+                        NULL, (void **)&client);
+  SafeRelease(device);
   if (FAILED(hr)) {
     return CUBEB_ERROR;
   }
 
   hr = client->GetMixFormat(&mix_format);
-
   if (FAILED(hr)) {
     SafeRelease(client);
     return CUBEB_ERROR;
   }
 
   *rate = mix_format->nSamplesPerSec;
 
   CoTaskMemFree(mix_format);
@@ -706,30 +726,43 @@ wasapi_stream_init(cubeb * context, cube
 
   if (!stm->refill_event) {
     SafeRelease(stm->shutdown_event);
     LOG("Can't create the refill event, error: %d.", GetLastError());
     wasapi_stream_destroy(stm);
     return CUBEB_ERROR;
   }
 
+  IMMDevice * device;
+  hr = get_default_endpoint(&device);
+  if (FAILED(hr)) {
+    wasapi_stream_destroy(stm);
+    return CUBEB_ERROR;
+  }
+
   /* Get a client. We will get all other interfaces we need from
    * this pointer. */
-  hr = context->device->Activate(__uuidof(IAudioClient),
-                                 CLSCTX_INPROC_SERVER,
-                                 NULL, (void **)&stm->client);
+  hr = device->Activate(__uuidof(IAudioClient),
+                        CLSCTX_INPROC_SERVER,
+                        NULL, (void **)&stm->client);
+  SafeRelease(device);
   if (FAILED(hr)) {
     LOG("Could not activate the device to get an audio client.");
     wasapi_stream_destroy(stm);
     return CUBEB_ERROR;
   }
 
   /* We have to distinguish between the format the mixer uses,
   * and the format the stream we want to play uses. */
-  stm->client->GetMixFormat(&mix_format);
+  hr = stm->client->GetMixFormat(&mix_format);
+  if (FAILED(hr)) {
+    LOG("Could not fetch current mix format from the audio client.");
+    wasapi_stream_destroy(stm);
+    return CUBEB_ERROR;
+  }
 
   handle_channel_layout(stm, &mix_format, &stream_params);
 
   /* Shared mode WASAPI always supports float32 sample format, so this
    * is safe. */
   stm->mix_params.format = CUBEB_SAMPLE_FLOAT32NE;
 
   stm->mix_params.rate = mix_format->nSamplesPerSec;
@@ -805,25 +838,25 @@ wasapi_stream_init(cubeb * context, cube
   hr = stm->client->SetEventHandle(stm->refill_event);
   if (FAILED(hr)) {
     LOG("Could set the event handle for the client.");
     wasapi_stream_destroy(stm);
     return CUBEB_ERROR;
   }
 
   hr = stm->client->GetService(__uuidof(IAudioRenderClient),
-                                     (void **)&stm->render_client);
+                               (void **)&stm->render_client);
   if (FAILED(hr)) {
     LOG("Could not get the render client.");
     wasapi_stream_destroy(stm);
     return CUBEB_ERROR;
   }
 
   hr = stm->client->GetService(__uuidof(IAudioClock),
-                                     (void **)&stm->audio_clock);
+                               (void **)&stm->audio_clock);
   if (FAILED(hr)) {
     LOG("Could not get the IAudioClock.");
     wasapi_stream_destroy(stm);
     return CUBEB_ERROR;
   }
 
   hr = stm->audio_clock->GetFrequency(&stm->clock_freq);
   if (FAILED(hr)) {