From b10afc574e72d1f55ba4ce8f5f7572c3df48acf1 Mon Sep 17 00:00:00 2001 From: Seungha Yang Date: Fri, 24 Jul 2020 21:53:37 +0900 Subject: [PATCH] wasapi2: Add a new property for ICoreDispatcher setting ... so that ensure device activation on UI thread. Part-of: --- sys/wasapi2/gstwasapi2client.cpp | 110 ++++++++++++++++++++++++++------------- sys/wasapi2/gstwasapi2client.h | 3 +- sys/wasapi2/gstwasapi2device.c | 2 +- sys/wasapi2/gstwasapi2sink.c | 18 ++++++- sys/wasapi2/gstwasapi2src.c | 18 ++++++- 5 files changed, 112 insertions(+), 39 deletions(-) diff --git a/sys/wasapi2/gstwasapi2client.cpp b/sys/wasapi2/gstwasapi2client.cpp index 07d6343..e2f1627 100644 --- a/sys/wasapi2/gstwasapi2client.cpp +++ b/sys/wasapi2/gstwasapi2client.cpp @@ -77,14 +77,22 @@ public: } HRESULT - RuntimeClassInitialize (GstWasapi2Client * listener) + RuntimeClassInitialize (GstWasapi2Client * listener, gpointer dispatcher) { if (!listener) return E_INVALIDARG; listener_ = listener; - findCoreDispatcher (); + if (dispatcher) { + ComPtr inspectable = + reinterpret_cast (dispatcher); + HRESULT hr; + + hr = inspectable.As (&dispatcher_); + if (gst_wasapi2_result (hr)) + GST_INFO("Main UI dispatcher is available"); + } return S_OK; } @@ -150,36 +158,6 @@ public: }); } - /* Try to find ICoreDispatcher of main UI so that active audio - * interface on main UI thread */ - void findCoreDispatcher(void) - { - HRESULT hr; - HStringReference hstr_core_app = - HStringReference(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication); - ComPtr core_app; - ComPtr core_app_view; - ComPtr core_window; - - hr = GetActivationFactory (hstr_core_app.Get(), &core_app); - if (!gst_wasapi2_result (hr)) - return; - - hr = core_app->GetCurrentView (&core_app_view); - if (!gst_wasapi2_result (hr)) - return; - - hr = core_app_view->get_CoreWindow (&core_window); - if (!gst_wasapi2_result (hr)) - return; - - hr = core_window->get_Dispatcher (&dispatcher_); - if (!gst_wasapi2_result (hr)) - return; - - GST_DEBUG ("Main UI dispatcher is available"); - } - template HRESULT runOnUIThread (DWORD timeout, CB && cb) @@ -242,6 +220,7 @@ struct _GstWasapi2Client gchar *device_id; gchar *device_name; gint device_index; + gpointer dispatcher; IAudioClient3 *audio_client; IAudioCaptureClient *audio_capture_client; @@ -284,6 +263,7 @@ enum PROP_DEVICE_INDEX, PROP_DEVICE_CLASS, PROP_LOW_LATENCY, + PROP_DISPATCHER, }; #define DEFAULT_DEVICE_INDEX -1 @@ -356,6 +336,9 @@ gst_wasapi2_client_class_init (GstWasapi2ClientClass * klass) g_param_spec_boolean ("low-latency", "Low latency", "Optimize all settings for lowest latency. Always safe to enable.", DEFAULT_LOW_LATENCY, param_flags)); + g_object_class_install_property (gobject_class, PROP_DISPATCHER, + g_param_spec_pointer ("dispatcher", "Dispatcher", + "ICoreDispatcher COM object to use", param_flags)); } static void @@ -468,6 +451,9 @@ gst_wasapi2_client_get_property (GObject * object, guint prop_id, case PROP_LOW_LATENCY: g_value_set_boolean (value, self->low_latency); break; + case PROP_DISPATCHER: + g_value_set_pointer (value, self->dispatcher); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -499,6 +485,9 @@ gst_wasapi2_client_set_property (GObject * object, guint prop_id, case PROP_LOW_LATENCY: self->low_latency = g_value_get_boolean (value); break; + case PROP_DISPATCHER: + self->dispatcher = g_value_get_pointer (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -604,7 +593,8 @@ gst_wasapi2_client_thread_func_internal (GstWasapi2Client * self) self->device_class == GST_WASAPI2_CLIENT_DEVICE_CLASS_CAPTURE ? "capture" : "render", GST_STR_NULL (self->device_id), self->device_index); - hr = MakeAndInitialize (&activator, self); + hr = MakeAndInitialize (&activator, + self, self->dispatcher); if (!gst_wasapi2_result (hr)) goto run_loop; @@ -1776,15 +1766,65 @@ gst_wasapi2_client_get_volume (GstWasapi2Client * client, gfloat * volume) return TRUE; } +static HRESULT +find_dispatcher (ICoreDispatcher ** dispatcher) +{ + HStringReference hstr_core_app = + HStringReference(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication); + HRESULT hr; + + ComPtr core_app; + hr = GetActivationFactory (hstr_core_app.Get(), &core_app); + if (!gst_wasapi2_result (hr)) + return hr; + + ComPtr core_app_view; + hr = core_app->GetCurrentView (&core_app_view); + if (!gst_wasapi2_result (hr)) + return hr; + + ComPtr core_window; + hr = core_app_view->get_CoreWindow (&core_window); + if (!gst_wasapi2_result (hr)) + return hr; + + return core_window->get_Dispatcher (dispatcher); +} + GstWasapi2Client * gst_wasapi2_client_new (GstWasapi2ClientDeviceClass device_class, - gboolean low_latency, gint device_index, const gchar * device_id) + gboolean low_latency, gint device_index, const gchar * device_id, + gpointer dispatcher) { GstWasapi2Client *self; + ComPtr core_dispatcher; + /* Multiple COM init is allowed */ + RoInitializeWrapper init_wrapper (RO_INIT_MULTITHREADED); + + /* If application didn't pass ICoreDispatcher object, + * try to get dispatcher object for the current thread */ + if (!dispatcher) { + HRESULT hr; + + hr = find_dispatcher (&core_dispatcher); + if (gst_wasapi2_result (hr)) { + GST_DEBUG ("UI dispatcher is available"); + dispatcher = core_dispatcher.Get (); + } else { + GST_DEBUG ("UI dispatcher is unavailable"); + } + } else { + GST_DEBUG ("Use user passed UI dispatcher"); + } self = (GstWasapi2Client *) g_object_new (GST_TYPE_WASAPI2_CLIENT, "device-class", device_class, "low-latency", low_latency, - "device-index", device_index, "device", device_id, NULL); + "device-index", device_index, "device", device_id, + "dispatcher", dispatcher, NULL); + + /* Reset explicitly to ensure that it happens before + * RoInitializeWrapper dtor is called */ + core_dispatcher.Reset (); if (!self->audio_client) { gst_object_unref (self); diff --git a/sys/wasapi2/gstwasapi2client.h b/sys/wasapi2/gstwasapi2client.h index adc9125..7c9bd12 100644 --- a/sys/wasapi2/gstwasapi2client.h +++ b/sys/wasapi2/gstwasapi2client.h @@ -73,7 +73,8 @@ gboolean gst_wasapi2_client_get_volume (GstWasapi2Client * client, GstWasapi2Client * gst_wasapi2_client_new (GstWasapi2ClientDeviceClass device_class, gboolean low_latency, gint device_index, - const gchar * device_id); + const gchar * device_id, + gpointer dispatcher); G_DEFINE_AUTOPTR_CLEANUP_FUNC (GstWasapi2Client, gst_object_unref) diff --git a/sys/wasapi2/gstwasapi2device.c b/sys/wasapi2/gstwasapi2device.c index ac51126..3688c2e 100644 --- a/sys/wasapi2/gstwasapi2device.c +++ b/sys/wasapi2/gstwasapi2device.c @@ -182,7 +182,7 @@ gst_wasapi2_device_provider_probe_internal (GstWasapi2DeviceProvider * self, gchar *device_id = NULL; gchar *device_name = NULL; - client = gst_wasapi2_client_new (client_class, FALSE, i, NULL); + client = gst_wasapi2_client_new (client_class, FALSE, i, NULL, NULL); if (!client) return; diff --git a/sys/wasapi2/gstwasapi2sink.c b/sys/wasapi2/gstwasapi2sink.c index a55767c..280f837 100644 --- a/sys/wasapi2/gstwasapi2sink.c +++ b/sys/wasapi2/gstwasapi2sink.c @@ -69,6 +69,7 @@ enum PROP_LOW_LATENCY, PROP_MUTE, PROP_VOLUME, + PROP_DISPATCHER, }; struct _GstWasapi2Sink @@ -84,6 +85,7 @@ struct _GstWasapi2Sink gboolean low_latency; gboolean mute; gdouble volume; + gpointer dispatcher; gboolean mute_changed; gboolean volume_changed; @@ -157,6 +159,14 @@ gst_wasapi2_sink_class_init (GstWasapi2SinkClass * klass) GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_DISPATCHER, + g_param_spec_pointer ("dispatcher", "Dispatcher", + "ICoreDispatcher COM object to use. In order for application to ask " + "permission of audio device, device activation should be running " + "on UI thread via ICoreDispatcher", + GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + gst_element_class_add_static_pad_template (element_class, &sink_template); gst_element_class_set_static_metadata (element_class, "Wasapi2Sink", "Sink/Audio/Hardware", @@ -233,6 +243,9 @@ gst_wasapi2_sink_set_property (GObject * object, guint prop_id, case PROP_VOLUME: gst_wasapi2_sink_set_volume (self, g_value_get_double (value)); break; + case PROP_DISPATCHER: + self->dispatcher = g_value_get_pointer (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -258,6 +271,9 @@ gst_wasapi2_sink_get_property (GObject * object, guint prop_id, case PROP_VOLUME: g_value_set_double (value, gst_wasapi2_sink_get_volume (self)); break; + case PROP_DISPATCHER: + g_value_set_pointer (value, self->dispatcher); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -303,7 +319,7 @@ gst_wasapi2_sink_open_unlocked (GstAudioSink * asink) self->client = gst_wasapi2_client_new (GST_WASAPI2_CLIENT_DEVICE_CLASS_RENDER, - self->low_latency, -1, self->device_id); + self->low_latency, -1, self->device_id, self->dispatcher); return ! !self->client; } diff --git a/sys/wasapi2/gstwasapi2src.c b/sys/wasapi2/gstwasapi2src.c index 7f3bbee..f6a0fce 100644 --- a/sys/wasapi2/gstwasapi2src.c +++ b/sys/wasapi2/gstwasapi2src.c @@ -67,6 +67,7 @@ enum PROP_LOW_LATENCY, PROP_MUTE, PROP_VOLUME, + PROP_DISPATCHER, }; struct _GstWasapi2Src @@ -82,6 +83,7 @@ struct _GstWasapi2Src gboolean low_latency; gboolean mute; gdouble volume; + gpointer dispatcher; gboolean mute_changed; gboolean volume_changed; @@ -154,6 +156,14 @@ gst_wasapi2_src_class_init (GstWasapi2SrcClass * klass) GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_DISPATCHER, + g_param_spec_pointer ("dispatcher", "Dispatcher", + "ICoreDispatcher COM object to use. In order for application to ask " + "permission of audio device, device activation should be running " + "on UI thread via ICoreDispatcher", + GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + gst_element_class_add_static_pad_template (element_class, &src_template); gst_element_class_set_static_metadata (element_class, "Wasapi2Src", "Source/Audio/Hardware", @@ -230,6 +240,9 @@ gst_wasapi2_src_set_property (GObject * object, guint prop_id, case PROP_VOLUME: gst_wasapi2_src_set_volume (self, g_value_get_double (value)); break; + case PROP_DISPATCHER: + self->dispatcher = g_value_get_pointer (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -255,6 +268,9 @@ gst_wasapi2_src_get_property (GObject * object, guint prop_id, case PROP_VOLUME: g_value_set_double (value, gst_wasapi2_src_get_volume (self)); break; + case PROP_DISPATCHER: + g_value_set_pointer (value, self->dispatcher); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -300,7 +316,7 @@ gst_wasapi2_src_open_unlocked (GstAudioSrc * asrc) self->client = gst_wasapi2_client_new (GST_WASAPI2_CLIENT_DEVICE_CLASS_CAPTURE, - self->low_latency, -1, self->device_id); + self->low_latency, -1, self->device_id, self->dispatcher); return ! !self->client; } -- 2.7.4