mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-10-22 02:13:46 +00:00
wasapi2: Add a new property for ICoreDispatcher setting
... so that ensure device activation on UI thread. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1466>
This commit is contained in:
parent
6d960781fc
commit
b10afc574e
5 changed files with 112 additions and 39 deletions
|
@ -77,14 +77,22 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT
|
HRESULT
|
||||||
RuntimeClassInitialize (GstWasapi2Client * listener)
|
RuntimeClassInitialize (GstWasapi2Client * listener, gpointer dispatcher)
|
||||||
{
|
{
|
||||||
if (!listener)
|
if (!listener)
|
||||||
return E_INVALIDARG;
|
return E_INVALIDARG;
|
||||||
|
|
||||||
listener_ = listener;
|
listener_ = listener;
|
||||||
|
|
||||||
findCoreDispatcher ();
|
if (dispatcher) {
|
||||||
|
ComPtr<IInspectable> inspectable =
|
||||||
|
reinterpret_cast<IInspectable*> (dispatcher);
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
hr = inspectable.As (&dispatcher_);
|
||||||
|
if (gst_wasapi2_result (hr))
|
||||||
|
GST_INFO("Main UI dispatcher is available");
|
||||||
|
}
|
||||||
|
|
||||||
return S_OK;
|
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<ICoreApplication> core_app;
|
|
||||||
ComPtr<ICoreApplicationView> core_app_view;
|
|
||||||
ComPtr<ICoreWindow> 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 <typename CB>
|
template <typename CB>
|
||||||
HRESULT
|
HRESULT
|
||||||
runOnUIThread (DWORD timeout, CB && cb)
|
runOnUIThread (DWORD timeout, CB && cb)
|
||||||
|
@ -242,6 +220,7 @@ struct _GstWasapi2Client
|
||||||
gchar *device_id;
|
gchar *device_id;
|
||||||
gchar *device_name;
|
gchar *device_name;
|
||||||
gint device_index;
|
gint device_index;
|
||||||
|
gpointer dispatcher;
|
||||||
|
|
||||||
IAudioClient3 *audio_client;
|
IAudioClient3 *audio_client;
|
||||||
IAudioCaptureClient *audio_capture_client;
|
IAudioCaptureClient *audio_capture_client;
|
||||||
|
@ -284,6 +263,7 @@ enum
|
||||||
PROP_DEVICE_INDEX,
|
PROP_DEVICE_INDEX,
|
||||||
PROP_DEVICE_CLASS,
|
PROP_DEVICE_CLASS,
|
||||||
PROP_LOW_LATENCY,
|
PROP_LOW_LATENCY,
|
||||||
|
PROP_DISPATCHER,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define DEFAULT_DEVICE_INDEX -1
|
#define DEFAULT_DEVICE_INDEX -1
|
||||||
|
@ -356,6 +336,9 @@ gst_wasapi2_client_class_init (GstWasapi2ClientClass * klass)
|
||||||
g_param_spec_boolean ("low-latency", "Low latency",
|
g_param_spec_boolean ("low-latency", "Low latency",
|
||||||
"Optimize all settings for lowest latency. Always safe to enable.",
|
"Optimize all settings for lowest latency. Always safe to enable.",
|
||||||
DEFAULT_LOW_LATENCY, param_flags));
|
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
|
static void
|
||||||
|
@ -468,6 +451,9 @@ gst_wasapi2_client_get_property (GObject * object, guint prop_id,
|
||||||
case PROP_LOW_LATENCY:
|
case PROP_LOW_LATENCY:
|
||||||
g_value_set_boolean (value, self->low_latency);
|
g_value_set_boolean (value, self->low_latency);
|
||||||
break;
|
break;
|
||||||
|
case PROP_DISPATCHER:
|
||||||
|
g_value_set_pointer (value, self->dispatcher);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -499,6 +485,9 @@ gst_wasapi2_client_set_property (GObject * object, guint prop_id,
|
||||||
case PROP_LOW_LATENCY:
|
case PROP_LOW_LATENCY:
|
||||||
self->low_latency = g_value_get_boolean (value);
|
self->low_latency = g_value_get_boolean (value);
|
||||||
break;
|
break;
|
||||||
|
case PROP_DISPATCHER:
|
||||||
|
self->dispatcher = g_value_get_pointer (value);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -604,7 +593,8 @@ gst_wasapi2_client_thread_func_internal (GstWasapi2Client * self)
|
||||||
self->device_class == GST_WASAPI2_CLIENT_DEVICE_CLASS_CAPTURE ? "capture" :
|
self->device_class == GST_WASAPI2_CLIENT_DEVICE_CLASS_CAPTURE ? "capture" :
|
||||||
"render", GST_STR_NULL (self->device_id), self->device_index);
|
"render", GST_STR_NULL (self->device_id), self->device_index);
|
||||||
|
|
||||||
hr = MakeAndInitialize<GstWasapiDeviceActivator> (&activator, self);
|
hr = MakeAndInitialize<GstWasapiDeviceActivator> (&activator,
|
||||||
|
self, self->dispatcher);
|
||||||
if (!gst_wasapi2_result (hr))
|
if (!gst_wasapi2_result (hr))
|
||||||
goto run_loop;
|
goto run_loop;
|
||||||
|
|
||||||
|
@ -1776,15 +1766,65 @@ gst_wasapi2_client_get_volume (GstWasapi2Client * client, gfloat * volume)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static HRESULT
|
||||||
|
find_dispatcher (ICoreDispatcher ** dispatcher)
|
||||||
|
{
|
||||||
|
HStringReference hstr_core_app =
|
||||||
|
HStringReference(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication);
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
ComPtr<ICoreApplication> core_app;
|
||||||
|
hr = GetActivationFactory (hstr_core_app.Get(), &core_app);
|
||||||
|
if (!gst_wasapi2_result (hr))
|
||||||
|
return hr;
|
||||||
|
|
||||||
|
ComPtr<ICoreApplicationView> core_app_view;
|
||||||
|
hr = core_app->GetCurrentView (&core_app_view);
|
||||||
|
if (!gst_wasapi2_result (hr))
|
||||||
|
return hr;
|
||||||
|
|
||||||
|
ComPtr<ICoreWindow> core_window;
|
||||||
|
hr = core_app_view->get_CoreWindow (&core_window);
|
||||||
|
if (!gst_wasapi2_result (hr))
|
||||||
|
return hr;
|
||||||
|
|
||||||
|
return core_window->get_Dispatcher (dispatcher);
|
||||||
|
}
|
||||||
|
|
||||||
GstWasapi2Client *
|
GstWasapi2Client *
|
||||||
gst_wasapi2_client_new (GstWasapi2ClientDeviceClass device_class,
|
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;
|
GstWasapi2Client *self;
|
||||||
|
ComPtr<ICoreDispatcher> 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,
|
self = (GstWasapi2Client *) g_object_new (GST_TYPE_WASAPI2_CLIENT,
|
||||||
"device-class", device_class, "low-latency", low_latency,
|
"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) {
|
if (!self->audio_client) {
|
||||||
gst_object_unref (self);
|
gst_object_unref (self);
|
||||||
|
|
|
@ -73,7 +73,8 @@ gboolean gst_wasapi2_client_get_volume (GstWasapi2Client * client,
|
||||||
GstWasapi2Client * gst_wasapi2_client_new (GstWasapi2ClientDeviceClass device_class,
|
GstWasapi2Client * gst_wasapi2_client_new (GstWasapi2ClientDeviceClass device_class,
|
||||||
gboolean low_latency,
|
gboolean low_latency,
|
||||||
gint device_index,
|
gint device_index,
|
||||||
const gchar * device_id);
|
const gchar * device_id,
|
||||||
|
gpointer dispatcher);
|
||||||
|
|
||||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GstWasapi2Client, gst_object_unref)
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GstWasapi2Client, gst_object_unref)
|
||||||
|
|
||||||
|
|
|
@ -182,7 +182,7 @@ gst_wasapi2_device_provider_probe_internal (GstWasapi2DeviceProvider * self,
|
||||||
gchar *device_id = NULL;
|
gchar *device_id = NULL;
|
||||||
gchar *device_name = 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)
|
if (!client)
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -69,6 +69,7 @@ enum
|
||||||
PROP_LOW_LATENCY,
|
PROP_LOW_LATENCY,
|
||||||
PROP_MUTE,
|
PROP_MUTE,
|
||||||
PROP_VOLUME,
|
PROP_VOLUME,
|
||||||
|
PROP_DISPATCHER,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstWasapi2Sink
|
struct _GstWasapi2Sink
|
||||||
|
@ -84,6 +85,7 @@ struct _GstWasapi2Sink
|
||||||
gboolean low_latency;
|
gboolean low_latency;
|
||||||
gboolean mute;
|
gboolean mute;
|
||||||
gdouble volume;
|
gdouble volume;
|
||||||
|
gpointer dispatcher;
|
||||||
|
|
||||||
gboolean mute_changed;
|
gboolean mute_changed;
|
||||||
gboolean volume_changed;
|
gboolean volume_changed;
|
||||||
|
@ -157,6 +159,14 @@ gst_wasapi2_sink_class_init (GstWasapi2SinkClass * klass)
|
||||||
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE |
|
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE |
|
||||||
G_PARAM_STATIC_STRINGS));
|
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_add_static_pad_template (element_class, &sink_template);
|
||||||
gst_element_class_set_static_metadata (element_class, "Wasapi2Sink",
|
gst_element_class_set_static_metadata (element_class, "Wasapi2Sink",
|
||||||
"Sink/Audio/Hardware",
|
"Sink/Audio/Hardware",
|
||||||
|
@ -233,6 +243,9 @@ gst_wasapi2_sink_set_property (GObject * object, guint prop_id,
|
||||||
case PROP_VOLUME:
|
case PROP_VOLUME:
|
||||||
gst_wasapi2_sink_set_volume (self, g_value_get_double (value));
|
gst_wasapi2_sink_set_volume (self, g_value_get_double (value));
|
||||||
break;
|
break;
|
||||||
|
case PROP_DISPATCHER:
|
||||||
|
self->dispatcher = g_value_get_pointer (value);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -258,6 +271,9 @@ gst_wasapi2_sink_get_property (GObject * object, guint prop_id,
|
||||||
case PROP_VOLUME:
|
case PROP_VOLUME:
|
||||||
g_value_set_double (value, gst_wasapi2_sink_get_volume (self));
|
g_value_set_double (value, gst_wasapi2_sink_get_volume (self));
|
||||||
break;
|
break;
|
||||||
|
case PROP_DISPATCHER:
|
||||||
|
g_value_set_pointer (value, self->dispatcher);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -303,7 +319,7 @@ gst_wasapi2_sink_open_unlocked (GstAudioSink * asink)
|
||||||
|
|
||||||
self->client =
|
self->client =
|
||||||
gst_wasapi2_client_new (GST_WASAPI2_CLIENT_DEVICE_CLASS_RENDER,
|
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;
|
return ! !self->client;
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,6 +67,7 @@ enum
|
||||||
PROP_LOW_LATENCY,
|
PROP_LOW_LATENCY,
|
||||||
PROP_MUTE,
|
PROP_MUTE,
|
||||||
PROP_VOLUME,
|
PROP_VOLUME,
|
||||||
|
PROP_DISPATCHER,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstWasapi2Src
|
struct _GstWasapi2Src
|
||||||
|
@ -82,6 +83,7 @@ struct _GstWasapi2Src
|
||||||
gboolean low_latency;
|
gboolean low_latency;
|
||||||
gboolean mute;
|
gboolean mute;
|
||||||
gdouble volume;
|
gdouble volume;
|
||||||
|
gpointer dispatcher;
|
||||||
|
|
||||||
gboolean mute_changed;
|
gboolean mute_changed;
|
||||||
gboolean volume_changed;
|
gboolean volume_changed;
|
||||||
|
@ -154,6 +156,14 @@ gst_wasapi2_src_class_init (GstWasapi2SrcClass * klass)
|
||||||
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE |
|
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE |
|
||||||
G_PARAM_STATIC_STRINGS));
|
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_add_static_pad_template (element_class, &src_template);
|
||||||
gst_element_class_set_static_metadata (element_class, "Wasapi2Src",
|
gst_element_class_set_static_metadata (element_class, "Wasapi2Src",
|
||||||
"Source/Audio/Hardware",
|
"Source/Audio/Hardware",
|
||||||
|
@ -230,6 +240,9 @@ gst_wasapi2_src_set_property (GObject * object, guint prop_id,
|
||||||
case PROP_VOLUME:
|
case PROP_VOLUME:
|
||||||
gst_wasapi2_src_set_volume (self, g_value_get_double (value));
|
gst_wasapi2_src_set_volume (self, g_value_get_double (value));
|
||||||
break;
|
break;
|
||||||
|
case PROP_DISPATCHER:
|
||||||
|
self->dispatcher = g_value_get_pointer (value);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -255,6 +268,9 @@ gst_wasapi2_src_get_property (GObject * object, guint prop_id,
|
||||||
case PROP_VOLUME:
|
case PROP_VOLUME:
|
||||||
g_value_set_double (value, gst_wasapi2_src_get_volume (self));
|
g_value_set_double (value, gst_wasapi2_src_get_volume (self));
|
||||||
break;
|
break;
|
||||||
|
case PROP_DISPATCHER:
|
||||||
|
g_value_set_pointer (value, self->dispatcher);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -300,7 +316,7 @@ gst_wasapi2_src_open_unlocked (GstAudioSrc * asrc)
|
||||||
|
|
||||||
self->client =
|
self->client =
|
||||||
gst_wasapi2_client_new (GST_WASAPI2_CLIENT_DEVICE_CLASS_CAPTURE,
|
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;
|
return ! !self->client;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue