From 08cb5b482d79ff3d0c028860b7c55b94b7e1e449 Mon Sep 17 00:00:00 2001 From: Seungha Yang Date: Thu, 26 Aug 2021 19:47:51 +0900 Subject: [PATCH] libs: Introduce GstWinRT library Adding a helper library for various WinRT specific implementations. Currently this library supports only DeviceWatcher abstraction object which can be used for dynamic device add/remove detection. See also https://docs.microsoft.com/en-us/uwp/api/windows.devices.enumeration.devicewatcher?view=winrt-20348 Part-of: --- .../gst-plugins-bad/gst-libs/gst/meson.build | 3 +- .../gst-libs/gst/winrt/gstwinrt.h | 31 + .../gst/winrt/gstwinrtdevicewatcher.cpp | 723 ++++++++++++++++++ .../gst/winrt/gstwinrtdevicewatcher.h | 136 ++++ .../gst-libs/gst/winrt/meson.build | 86 +++ .../gst-libs/gst/winrt/winrt-prelude.h | 33 + 6 files changed, 1011 insertions(+), 1 deletion(-) create mode 100644 subprojects/gst-plugins-bad/gst-libs/gst/winrt/gstwinrt.h create mode 100644 subprojects/gst-plugins-bad/gst-libs/gst/winrt/gstwinrtdevicewatcher.cpp create mode 100644 subprojects/gst-plugins-bad/gst-libs/gst/winrt/gstwinrtdevicewatcher.h create mode 100644 subprojects/gst-plugins-bad/gst-libs/gst/winrt/meson.build create mode 100644 subprojects/gst-plugins-bad/gst-libs/gst/winrt/winrt-prelude.h diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/meson.build b/subprojects/gst-plugins-bad/gst-libs/gst/meson.build index a2862a3d86..77dadcf09c 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/meson.build +++ b/subprojects/gst-plugins-bad/gst-libs/gst/meson.build @@ -15,7 +15,8 @@ subdir('play') subdir('player') subdir('sctp') subdir('transcoder') +subdir('va') subdir('vulkan') subdir('wayland') subdir('webrtc') -subdir('va') +subdir('winrt') diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/winrt/gstwinrt.h b/subprojects/gst-plugins-bad/gst-libs/gst/winrt/gstwinrt.h new file mode 100644 index 0000000000..944c8c058d --- /dev/null +++ b/subprojects/gst-plugins-bad/gst-libs/gst/winrt/gstwinrt.h @@ -0,0 +1,31 @@ +/* GStreamer + * Copyright (C) 2021 Seungha Yang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_WINRT_H__ +#define __GST_WINRT_H__ + +#ifndef GST_USE_UNSTABLE_API +#pragma message ("The winrt library from gst-plugins-bad is unstable API and may change in future.") +#pragma message ("You can define GST_USE_UNSTABLE_API to avoid this warning.") +#endif + +#include +#include + +#endif /* __GST_WINRT_H__ */ diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/winrt/gstwinrtdevicewatcher.cpp b/subprojects/gst-plugins-bad/gst-libs/gst/winrt/gstwinrtdevicewatcher.cpp new file mode 100644 index 0000000000..3d6fc10af1 --- /dev/null +++ b/subprojects/gst-plugins-bad/gst-libs/gst/winrt/gstwinrtdevicewatcher.cpp @@ -0,0 +1,723 @@ +/* GStreamer + * Copyright (C) 2021 Seungha Yang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstwinrtdevicewatcher.h" + +/* workaround for GetCurrentTime collision */ +#ifdef GetCurrentTime +#undef GetCurrentTime +#endif + +#include +#include +#include + +/* *INDENT-OFF* */ +typedef __FITypedEventHandler_2_Windows__CDevices__CEnumeration__CDeviceWatcher_Windows__CDevices__CEnumeration__CDeviceInformation IAddedHandler; +typedef __FITypedEventHandler_2_Windows__CDevices__CEnumeration__CDeviceWatcher_Windows__CDevices__CEnumeration__CDeviceInformationUpdate IUpdatedHandler; +typedef __FITypedEventHandler_2_Windows__CDevices__CEnumeration__CDeviceWatcher_Windows__CDevices__CEnumeration__CDeviceInformationUpdate IRemovedHandler; +typedef __FITypedEventHandler_2_Windows__CDevices__CEnumeration__CDeviceWatcher_IInspectable IEnumerationCompletedHandler; +typedef __FITypedEventHandler_2_Windows__CDevices__CEnumeration__CDeviceWatcher_IInspectable IStoppedHandler; + +using namespace Microsoft::WRL; +using namespace Microsoft::WRL::Wrappers; +using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::Devices; +using namespace ABI::Windows::Devices::Enumeration; + +GST_DEBUG_CATEGORY_STATIC (gst_winrt_device_watcher_debug); +#define GST_CAT_DEFAULT gst_winrt_device_watcher_debug + +static void +gst_winrt_device_watcher_device_added (GstWinRTDeviceWatcher * self, + IDeviceInformation * info); +static void +gst_winrt_device_watcher_device_updated (GstWinRTDeviceWatcher * self, + IDeviceInformationUpdate * info_update); +static void +gst_winrt_device_watcher_device_removed (GstWinRTDeviceWatcher * self, + IDeviceInformationUpdate * info_update); +static void +gst_winrt_device_watcher_device_enumeration_completed (GstWinRTDeviceWatcher * + self); +static void +gst_winrt_device_watcher_device_enumeration_stopped (GstWinRTDeviceWatcher * + self); + +class AddedHandler + : public RuntimeClass, IAddedHandler> +{ +public: + AddedHandler () {} + HRESULT RuntimeClassInitialize (GstWinRTDeviceWatcher * listenr) + { + if (!listenr) + return E_INVALIDARG; + + listener_ = listenr; + return S_OK; + } + + IFACEMETHOD(Invoke) + (IDeviceWatcher* sender, IDeviceInformation * arg) + { + gst_winrt_device_watcher_device_added (listener_, arg); + + return S_OK; + } + +private: + GstWinRTDeviceWatcher * listener_; +}; + +class UpdatedHandler + : public RuntimeClass, IUpdatedHandler> +{ +public: + UpdatedHandler () {} + HRESULT RuntimeClassInitialize (GstWinRTDeviceWatcher * listenr) + { + if (!listenr) + return E_INVALIDARG; + + listener_ = listenr; + return S_OK; + } + + IFACEMETHOD(Invoke) + (IDeviceWatcher* sender, IDeviceInformationUpdate * arg) + { + gst_winrt_device_watcher_device_updated (listener_, arg); + + return S_OK; + } + +private: + GstWinRTDeviceWatcher * listener_; +}; + +class RemovedHandler + : public RuntimeClass, IRemovedHandler> +{ +public: + RemovedHandler () {} + HRESULT RuntimeClassInitialize (GstWinRTDeviceWatcher * listenr) + { + if (!listenr) + return E_INVALIDARG; + + listener_ = listenr; + return S_OK; + } + + IFACEMETHOD(Invoke) + (IDeviceWatcher* sender, IDeviceInformationUpdate * arg) + { + gst_winrt_device_watcher_device_removed (listener_, arg); + + return S_OK; + } + +private: + GstWinRTDeviceWatcher * listener_; +}; + +class EnumerationCompletedHandler + : public RuntimeClass, IEnumerationCompletedHandler> +{ +public: + EnumerationCompletedHandler () {} + HRESULT RuntimeClassInitialize (GstWinRTDeviceWatcher * listenr) + { + if (!listenr) + return E_INVALIDARG; + + listener_ = listenr; + return S_OK; + } + + IFACEMETHOD(Invoke) + (IDeviceWatcher* sender, IInspectable * arg) + { + gst_winrt_device_watcher_device_enumeration_completed (listener_); + + return S_OK; + } + +private: + GstWinRTDeviceWatcher * listener_; +}; + +class StoppedHandler + : public RuntimeClass, IStoppedHandler> +{ +public: + StoppedHandler () {} + HRESULT RuntimeClassInitialize (GstWinRTDeviceWatcher * listenr) + { + if (!listenr) + return E_INVALIDARG; + + listener_ = listenr; + return S_OK; + } + + IFACEMETHOD(Invoke) + (IDeviceWatcher* sender, IInspectable * arg) + { + gst_winrt_device_watcher_device_enumeration_stopped (listener_); + + return S_OK; + } + +private: + GstWinRTDeviceWatcher * listener_; +}; +/* *INDENT-ON* */ + +typedef struct +{ + ComPtr < IDeviceWatcher > watcher; + + EventRegistrationToken added_token; + EventRegistrationToken updated_token; + EventRegistrationToken removed_token; + EventRegistrationToken enum_completed_token; + EventRegistrationToken stopped_token; +} GstWinRTDeviceWatcherInner; + +enum +{ + PROP_0, + PROP_DEVICE_CLASS, +}; + +#define DEFAULT_DEVICE_CLASS GST_WINRT_DEVICE_CLASS_ALL + +struct _GstWinRTDeviceWatcherPrivate +{ + GMutex lock; + GCond cond; + + GThread *thread; + GMainContext *context; + GMainLoop *loop; + + gboolean running; + + GstWinRTDeviceWatcherCallbacks callbacks; + gpointer user_data; + + GstWinRTDeviceWatcherInner *inner; + + GstWinRTDeviceClass device_class; +}; + +GType +gst_winrt_device_class_get_type (void) +{ + static gsize device_class_type = 0; + + if (g_once_init_enter (&device_class_type)) { + static const GEnumValue classes[] = { + {GST_WINRT_DEVICE_CLASS_ALL, "All", "all"}, + {GST_WINRT_DEVICE_CLASS_AUDIO_CAPTURE, "AudioCapture", "audio-capture"}, + {GST_WINRT_DEVICE_CLASS_AUDIO_RENDER, "AudioRender", "audio-render"}, + {GST_WINRT_DEVICE_CLASS_PORTABLE_STORAGE_DEVICE, + "PortableStorageDevice", "portable-storage-device"}, + {GST_WINRT_DEVICE_CLASS_VIDEO_CAPTURE, + "VideoCapture", "video-capture"}, + {0, nullptr, nullptr}, + }; + GType tmp = g_enum_register_static ("GstWinRTDeviceClass", classes); + g_once_init_leave (&device_class_type, tmp); + } + + return (GType) device_class_type; +} + +static void gst_winrt_device_watcher_constructed (GObject * object); +static void gst_winrt_device_watcher_finalize (GObject * object); +static void gst_winrt_device_watcher_set_property (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec); +static void gst_winrt_device_watcher_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec); + +static gpointer +gst_winrt_device_watcher_thread_func (GstWinRTDeviceWatcher * self); + +#define gst_winrt_device_watcher_parent_class parent_class +G_DEFINE_TYPE_WITH_PRIVATE (GstWinRTDeviceWatcher, gst_winrt_device_watcher, + GST_TYPE_OBJECT); + +static void +gst_winrt_device_watcher_class_init (GstWinRTDeviceWatcherClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->constructed = gst_winrt_device_watcher_constructed; + gobject_class->finalize = gst_winrt_device_watcher_finalize; + gobject_class->set_property = gst_winrt_device_watcher_set_property; + gobject_class->get_property = gst_winrt_device_watcher_get_property; + + g_object_class_install_property (gobject_class, PROP_DEVICE_CLASS, + g_param_spec_enum ("device-class", "Device Class", + "Device class to watch", GST_TYPE_WINRT_DEVICE_CLASS, + DEFAULT_DEVICE_CLASS, + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS))); + + GST_DEBUG_CATEGORY_INIT (gst_winrt_device_watcher_debug, + "winrtdevicewatcher", 0, "winrtdevicewatcher"); +} + +static void +gst_winrt_device_watcher_init (GstWinRTDeviceWatcher * self) +{ + GstWinRTDeviceWatcherPrivate *priv; + + self->priv = priv = (GstWinRTDeviceWatcherPrivate *) + gst_winrt_device_watcher_get_instance_private (self); + + g_mutex_init (&priv->lock); + g_cond_init (&priv->cond); + priv->context = g_main_context_new (); + priv->loop = g_main_loop_new (priv->context, FALSE); +} + +static void +gst_winrt_device_watcher_constructed (GObject * object) +{ + GstWinRTDeviceWatcher *self = GST_WINRT_DEVICE_WATCHER (object); + GstWinRTDeviceWatcherPrivate *priv = self->priv; + + g_mutex_lock (&priv->lock); + priv->thread = g_thread_new ("GstWinRTDeviceWatcher", + (GThreadFunc) gst_winrt_device_watcher_thread_func, self); + while (!g_main_loop_is_running (priv->loop)) + g_cond_wait (&priv->cond, &priv->lock); + g_mutex_unlock (&priv->lock); +} + +static void +gst_winrt_device_watcher_finalize (GObject * object) +{ + GstWinRTDeviceWatcher *self = GST_WINRT_DEVICE_WATCHER (object); + GstWinRTDeviceWatcherPrivate *priv = self->priv; + + g_main_loop_quit (priv->loop); + if (g_thread_self () != priv->thread) { + g_thread_join (priv->thread); + g_main_loop_unref (priv->loop); + g_main_context_unref (priv->context); + } else { + g_warning ("Trying join from self-thread"); + } + + g_mutex_clear (&priv->lock); + g_cond_clear (&priv->cond); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gst_winrt_device_watcher_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstWinRTDeviceWatcher *self = GST_WINRT_DEVICE_WATCHER (object); + GstWinRTDeviceWatcherPrivate *priv = self->priv; + + switch (prop_id) { + case PROP_DEVICE_CLASS: + priv->device_class = (GstWinRTDeviceClass) g_value_get_enum (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_winrt_device_watcher_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstWinRTDeviceWatcher *self = GST_WINRT_DEVICE_WATCHER (object); + GstWinRTDeviceWatcherPrivate *priv = self->priv; + + switch (prop_id) { + case PROP_DEVICE_CLASS: + g_value_set_enum (value, priv->device_class); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static gboolean +loop_running_cb (GstWinRTDeviceWatcher * self) +{ + GstWinRTDeviceWatcherPrivate *priv = self->priv; + + g_mutex_lock (&priv->lock); + g_cond_signal (&priv->cond); + g_mutex_unlock (&priv->lock); + + return G_SOURCE_REMOVE; +} + +static void +gst_winrt_device_watcher_thread_func_inner (GstWinRTDeviceWatcher * self) +{ + GstWinRTDeviceWatcherPrivate *priv = self->priv; + GSource *idle_source; + HRESULT hr; + GstWinRTDeviceWatcherInner *inner = nullptr; + ComPtr < IDeviceInformationStatics > factory; + ComPtr < IDeviceWatcher > watcher; + ComPtr < IAddedHandler > added_handler; + ComPtr < IUpdatedHandler > updated_handler; + ComPtr < IRemovedHandler > removed_handler; + ComPtr < IEnumerationCompletedHandler > enum_completed_handler; + ComPtr < IStoppedHandler > stopped_handler; + + g_main_context_push_thread_default (priv->context); + + idle_source = g_idle_source_new (); + g_source_set_callback (idle_source, + (GSourceFunc) loop_running_cb, self, nullptr); + g_source_attach (idle_source, priv->context); + g_source_unref (idle_source); + + hr = GetActivationFactory (HStringReference + (RuntimeClass_Windows_Devices_Enumeration_DeviceInformation).Get (), + &factory); + if (FAILED (hr)) { + GST_ERROR_OBJECT (self, + "Failed to get IDeviceInformationStatics, hr: 0x%x", (guint) hr); + goto run_loop; + } + + hr = factory->CreateWatcherDeviceClass ((DeviceClass) priv->device_class, + &watcher); + if (FAILED (hr)) { + GST_ERROR_OBJECT (self, + "Failed to create IDeviceWatcher, hr: 0x%x", (guint) hr); + goto run_loop; + } + + hr = MakeAndInitialize < AddedHandler > (&added_handler, self); + if (FAILED (hr)) { + GST_ERROR_OBJECT (self, "Failed to create added handler, hr: 0x%x", hr); + goto run_loop; + } + + hr = MakeAndInitialize < UpdatedHandler > (&updated_handler, self); + if (FAILED (hr)) { + GST_ERROR_OBJECT (self, "Failed to create updated handler, hr: 0x%x", hr); + goto run_loop; + } + + hr = MakeAndInitialize < RemovedHandler > (&removed_handler, self); + if (FAILED (hr)) { + GST_ERROR_OBJECT (self, "Failed to create removed handler, hr: 0x%x", hr); + goto run_loop; + } + + hr = MakeAndInitialize < EnumerationCompletedHandler > + (&enum_completed_handler, self); + if (FAILED (hr)) { + GST_ERROR_OBJECT (self, + "Failed to create enumeration completed handler, hr: 0x%x", hr); + goto run_loop; + } + + hr = MakeAndInitialize < StoppedHandler > (&stopped_handler, self); + if (FAILED (hr)) { + GST_ERROR_OBJECT (self, "Failed to create stopped handler, hr: 0x%x", hr); + goto run_loop; + } + + inner = new GstWinRTDeviceWatcherInner (); + hr = watcher->add_Added (added_handler.Get (), &inner->added_token); + if (FAILED (hr)) { + GST_ERROR_OBJECT (self, "Failed to register added handler, hr: 0x%x", hr); + delete inner; + inner = nullptr; + + goto run_loop; + } + + hr = watcher->add_Updated (updated_handler.Get (), &inner->updated_token); + if (FAILED (hr)) { + GST_ERROR_OBJECT (self, "Failed to register updated handler, hr: 0x%x", hr); + delete inner; + inner = nullptr; + + goto run_loop; + } + + hr = watcher->add_Removed (removed_handler.Get (), &inner->removed_token); + if (FAILED (hr)) { + GST_ERROR_OBJECT (self, "Failed to register removed handler, hr: 0x%x", hr); + delete inner; + inner = nullptr; + + goto run_loop; + } + + hr = watcher->add_EnumerationCompleted (enum_completed_handler.Get (), + &inner->enum_completed_token); + if (FAILED (hr)) { + GST_ERROR_OBJECT (self, + "Failed to register enumeration completed handler, hr: 0x%x", hr); + delete inner; + inner = nullptr; + + goto run_loop; + } + + hr = watcher->add_Stopped (stopped_handler.Get (), &inner->stopped_token); + if (FAILED (hr)) { + GST_ERROR_OBJECT (self, "Failed to register stopped handler, hr: 0x%x", hr); + delete inner; + inner = nullptr; + + goto run_loop; + } + + inner->watcher = watcher; + priv->inner = inner; + +run_loop: + GST_INFO_OBJECT (self, "Starting loop"); + g_main_loop_run (priv->loop); + GST_INFO_OBJECT (self, "Stopped loop"); + + if (inner) { + if (priv->running) + watcher->Stop (); + + watcher->remove_Added (inner->added_token); + watcher->remove_Updated (inner->updated_token); + watcher->remove_Removed (inner->removed_token); + watcher->remove_EnumerationCompleted (inner->enum_completed_token); + watcher->remove_Stopped (inner->stopped_token); + + delete inner; + } + + g_main_context_pop_thread_default (priv->context); +} + +static gpointer +gst_winrt_device_watcher_thread_func (GstWinRTDeviceWatcher * self) +{ + RoInitializeWrapper initialize (RO_INIT_MULTITHREADED); + + /* wrap with another function so that everything can happen + * before RoInitializeWrapper is destructed */ + gst_winrt_device_watcher_thread_func_inner (self); + + return nullptr; +} + +static void +gst_winrt_device_watcher_device_added (GstWinRTDeviceWatcher * self, + IDeviceInformation * info) +{ + GstWinRTDeviceWatcherPrivate *priv = self->priv; + + GST_DEBUG_OBJECT (self, "Device added"); + + if (priv->callbacks.added) + priv->callbacks.added (self, info, priv->user_data); +} + +static void +gst_winrt_device_watcher_device_updated (GstWinRTDeviceWatcher * self, + IDeviceInformationUpdate * info_update) +{ + GstWinRTDeviceWatcherPrivate *priv = self->priv; + + GST_DEBUG_OBJECT (self, "Device updated"); + + if (priv->callbacks.updated) + priv->callbacks.updated (self, info_update, priv->user_data); +} + +static void +gst_winrt_device_watcher_device_removed (GstWinRTDeviceWatcher * self, + IDeviceInformationUpdate * info_update) +{ + GstWinRTDeviceWatcherPrivate *priv = self->priv; + + GST_DEBUG_OBJECT (self, "Device removed"); + + if (priv->callbacks.removed) + priv->callbacks.removed (self, info_update, priv->user_data); +} + +static void +gst_winrt_device_watcher_device_enumeration_completed (GstWinRTDeviceWatcher * + self) +{ + GstWinRTDeviceWatcherPrivate *priv = self->priv; + + GST_DEBUG_OBJECT (self, "Enumeration completed"); + + if (priv->callbacks.enumeration_completed) + priv->callbacks.enumeration_completed (self, priv->user_data); +} + +static void +gst_winrt_device_watcher_device_enumeration_stopped (GstWinRTDeviceWatcher * + self) +{ + GST_DEBUG_OBJECT (self, "Stopped"); +} + +/** + * gst_winrt_device_watcher_new: + * @device_class: a #GstWinRTDeviceClass to watch + * @callbacks: a pointer to #GstWinRTDeviceWatcherCallbacks + * @user_data: a user_data argument for the callbacks + * + * Constructs a new #GstWinRTDeviceWatcher object for watching device update + * of @device_class + * + * Returns: (transfer full) (nullable): a new #GstWinRTDeviceWatcher + * or %NULL when failed to create/setup #GstWinRTDeviceWatcher object + * + * Since: 1.20 + */ +GstWinRTDeviceWatcher * +gst_winrt_device_watcher_new (GstWinRTDeviceClass device_class, + const GstWinRTDeviceWatcherCallbacks * callbacks, gpointer user_data) +{ + GstWinRTDeviceWatcher *self; + GstWinRTDeviceWatcherPrivate *priv; + + g_return_val_if_fail (callbacks != nullptr, nullptr); + + self = (GstWinRTDeviceWatcher *) + g_object_new (GST_TYPE_WINRT_DEVICE_WATCHER, "device-class", device_class, + nullptr); + + priv = self->priv; + if (!priv->inner) { + gst_object_unref (self); + return nullptr; + } + + priv->callbacks = *callbacks; + priv->user_data = user_data; + + gst_object_ref_sink (self); + + return self; +} + +/** + * gst_winrt_device_watcher_start: + * @device_class: a #GstWinRTDeviceClass to watch + * + * Starts watching device update. + * + * Returns: %TRUE if successful + * + * Since: 1.20 + */ +gboolean +gst_winrt_device_watcher_start (GstWinRTDeviceWatcher * watcher) +{ + GstWinRTDeviceWatcherPrivate *priv; + GstWinRTDeviceWatcherInner *inner; + HRESULT hr; + + g_return_val_if_fail (GST_IS_WINRT_DEVICE_WATCHER (watcher), FALSE); + + priv = watcher->priv; + inner = priv->inner; + + GST_DEBUG_OBJECT (watcher, "Start"); + + g_mutex_lock (&priv->lock); + if (priv->running) { + GST_DEBUG_OBJECT (watcher, "Already running"); + g_mutex_unlock (&priv->lock); + + return TRUE; + } + + hr = inner->watcher->Start (); + if (FAILED (hr)) { + GST_ERROR_OBJECT (watcher, "Failed to start watcher, hr: 0x%x", (guint) hr); + g_mutex_unlock (&priv->lock); + + return FALSE; + } + + priv->running = TRUE; + g_mutex_unlock (&priv->lock); + + return TRUE; +} + +/** + * gst_winrt_device_watcher_stop: + * @device_class: a #GstWinRTDeviceClass to watch + * + * Stops watching device update. + * + * Since: 1.20 + */ +void +gst_winrt_device_watcher_stop (GstWinRTDeviceWatcher * watcher) +{ + GstWinRTDeviceWatcherPrivate *priv; + GstWinRTDeviceWatcherInner *inner; + HRESULT hr; + + g_return_if_fail (GST_IS_WINRT_DEVICE_WATCHER (watcher)); + + GST_DEBUG_OBJECT (watcher, "Stop"); + + priv = watcher->priv; + inner = priv->inner; + + g_mutex_lock (&priv->lock); + if (!priv->running) { + g_mutex_unlock (&priv->lock); + + return; + } + + priv->running = FALSE; + hr = inner->watcher->Stop (); + if (FAILED (hr)) { + GST_WARNING_OBJECT (watcher, + "Failed to stop watcher, hr: 0x%x", (guint) hr); + } + g_mutex_unlock (&priv->lock); +} diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/winrt/gstwinrtdevicewatcher.h b/subprojects/gst-plugins-bad/gst-libs/gst/winrt/gstwinrtdevicewatcher.h new file mode 100644 index 0000000000..f71471a4c1 --- /dev/null +++ b/subprojects/gst-plugins-bad/gst-libs/gst/winrt/gstwinrtdevicewatcher.h @@ -0,0 +1,136 @@ +/* GStreamer + * Copyright (C) 2021 Seungha Yang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_WINRT_DEVICE_WATCHER_H__ +#define __GST_WINRT_DEVICE_WATCHER_H__ + +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_WINRT_DEVICE_WATCHER (gst_winrt_device_watcher_get_type()) +#define GST_WINRT_DEVICE_WATCHER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_WINRT_DEVICE_WATCHER, GstWinRTDeviceWatcher)) +#define GST_WINRT_DEVICE_WATCHER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_WINRT_DEVICE_WATCHER, GstWinRTDeviceWatcherClass)) +#define GST_IS_WINRT_DEVICE_WATCHER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_WINRT_DEVICE_WATCHER)) +#define GST_IS_WINRT_DEVICE_WATCHER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_WINRT_DEVICE_WATCHER)) +#define GST_WINRT_DEVICE_WATCHER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GST_TYPE_WINRT_DEVICE_WATCHER, GstWinRTDeviceWatcherClass)) +#define GST_WINRT_DEVICE_WATCHER_CAST(obj) ((GstWinRTDeviceWatcher *)obj) + +typedef struct _GstWinRTDeviceWatcher GstWinRTDeviceWatcher; +typedef struct _GstWinRTDeviceWatcherClass GstWinRTDeviceWatcherClass; +typedef struct _GstWinRTDeviceWatcherPrivate GstWinRTDeviceWatcherPrivate; + +/* ABI::Windows::Devices::Enumeration::DeviceClass */ +#define GST_TYPE_WINRT_DEVICE_CLASS (gst_winrt_device_class_get_type ()) +typedef enum +{ + GST_WINRT_DEVICE_CLASS_ALL = 0, + GST_WINRT_DEVICE_CLASS_AUDIO_CAPTURE = 1, + GST_WINRT_DEVICE_CLASS_AUDIO_RENDER = 2, + GST_WINRT_DEVICE_CLASS_PORTABLE_STORAGE_DEVICE = 3, + GST_WINRT_DEVICE_CLASS_VIDEO_CAPTURE = 4, +} GstWinRTDeviceClass; + +typedef struct +{ + /** + * GstWinRTDeviceWatcherCallbacks::added: + * @watcher: a #GstWinRTDeviceWatcher + * @info: (transfer none): a IDeviceInformation interface handle + * @user_data: a user_data + * + * Called when a device is added to the collection enumerated by the DeviceWatcher + */ + void (*added) (GstWinRTDeviceWatcher * watcher, + __x_ABI_CWindows_CDevices_CEnumeration_CIDeviceInformation * info, + gpointer user_data); + + /** + * GstWinRTDeviceWatcherCallbacks::updated: + * @watcher: a #GstWinRTDeviceWatcher + * @info_update: (transfer none): a IDeviceInformationUpdate interface handle + * @user_data: a user_data + * + * Called when a device is updated in the collection of enumerated devices + */ + void (*updated) (GstWinRTDeviceWatcher * watcher, + __x_ABI_CWindows_CDevices_CEnumeration_CIDeviceInformationUpdate * info_update, + gpointer user_data); + + /** + * GstWinRTDeviceWatcherCallbacks::removed: + * @watcher: a #GstWinRTDeviceWatcher + * @info_update: (transfer none): a IDeviceInformationUpdate interface handle + * @user_data: a user_data + * + * Called when a device is removed from the collection of enumerated devices + */ + void (*removed) (GstWinRTDeviceWatcher * watcher, + __x_ABI_CWindows_CDevices_CEnumeration_CIDeviceInformationUpdate * info_update, + gpointer user_data); + + /** + * GstWinRTDeviceWatcherCallbacks::removed: + * @watcher: a #GstWinRTDeviceWatcher + * @user_data: a user_data + * + * Called when the enumeration of devices completes + */ + void (*enumeration_completed) (GstWinRTDeviceWatcher * watcher, + gpointer user_data); +} GstWinRTDeviceWatcherCallbacks; + +struct _GstWinRTDeviceWatcher +{ + GstObject parent; + + GstWinRTDeviceWatcherPrivate *priv; + + gpointer _gst_reserved[GST_PADDING]; +}; + +struct _GstWinRTDeviceWatcherClass +{ + GstObjectClass parent_class; + + gpointer _gst_reserved[GST_PADDING_LARGE]; +}; + +GST_WINRT_API +GType gst_winrt_device_class_get_type (void); + +GST_WINRT_API +GType gst_winrt_device_watcher_get_type (void); + +GST_WINRT_API +GstWinRTDeviceWatcher * gst_winrt_device_watcher_new (GstWinRTDeviceClass device_class, + const GstWinRTDeviceWatcherCallbacks * callbacks, + gpointer user_data); + +GST_WINRT_API +gboolean gst_winrt_device_watcher_start (GstWinRTDeviceWatcher * watcher); + +GST_WINRT_API +void gst_winrt_device_watcher_stop (GstWinRTDeviceWatcher * watcher); + +G_END_DECLS + +#endif /* __GST_WINRT_DEVICE_WATCHER_H__ */ diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/winrt/meson.build b/subprojects/gst-plugins-bad/gst-libs/gst/winrt/meson.build new file mode 100644 index 0000000000..4a28595ec2 --- /dev/null +++ b/subprojects/gst-plugins-bad/gst-libs/gst/winrt/meson.build @@ -0,0 +1,86 @@ +winrt_sources = [ + 'gstwinrtdevicewatcher.cpp', +] + +gstwinrt_dep = dependency('', required : false) + +extra_c_args = [ + '-DCOBJMACROS', +] +extra_comm_args = [ + '-DGST_USE_UNSTABLE_API', + '-DBUILDING_GST_WINRT' +] + +if host_system != 'windows' + subdir_done() +endif + +# TODO: Need to bump mingw tool chain +if cxx.get_id() != 'msvc' + subdir_done() +endif + +runtimeobject_lib = cc.find_library('runtimeobject', required : false) +if not runtimeobject_lib.found() + subdir_done() +endif + +winapi_app = cxx.compiles('''#include + #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) + #error "not winrt" + #endif + int main (int argc, char ** argv) { + return 0; + } ''', + dependencies: runtimeobject_lib, + name: 'building for WinRT') + +if not winapi_app + subdir_done() +endif + +win10_sdk = cxx.compiles('''#include + #ifndef WDK_NTDDI_VERSION + #error "unknown Windows SDK version" + #endif + #if (WDK_NTDDI_VERSION < 0x0A000000) + #error "Not a Windows 10 SDK" + #endif + ''', + name: 'building with Windows 10 SDK') + +if not win10_sdk + subdir_done() +endif + +building_for_win10 = cxx.compiles('''#include + #ifndef WINVER + #error "unknown minimum supported OS version" + #endif + #if (WINVER < 0x0A00) + #error "Windows 10 API is not guaranteed" + #endif + ''', + name: 'building for Windows 10') + +if not building_for_win10 + message('Bumping target Windows version to Windows 10 for building gstwinrt library') + extra_comm_args += ['-DWINVER=0x0A00', '-D_WIN32_WINNT=0x0A00', '-DNTDDI_VERSION=WDK_NTDDI_VERSION'] +endif + +gstwinrt = library('gstwinrt-' + api_version, + winrt_sources, + c_args : gst_plugins_bad_args + extra_c_args + extra_comm_args, + cpp_args : gst_plugins_bad_args + extra_comm_args, + include_directories : [configinc, libsinc], + version : libversion, + soversion : soversion, + install : true, + dependencies : [gstbase_dep, runtimeobject_lib] +) + +# Still non-public api, should not install headers +gstwinrt_dep = declare_dependency(link_with : gstwinrt, + include_directories : [libsinc], + dependencies : [gstbase_dep, runtimeobject_lib]) diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/winrt/winrt-prelude.h b/subprojects/gst-plugins-bad/gst-libs/gst/winrt/winrt-prelude.h new file mode 100644 index 0000000000..ed2c201738 --- /dev/null +++ b/subprojects/gst-plugins-bad/gst-libs/gst/winrt/winrt-prelude.h @@ -0,0 +1,33 @@ +/* GStreamer + * Copyright (C) 2021 GStreamer developers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_WINRT_PRELUDE_H__ +#define __GST_WINRT_PRELUDE_H__ + +#include + +#ifndef GST_WINRT_API +# ifdef BUILDING_GST_WINRT +# define GST_WINRT_API GST_API_EXPORT /* from config.h */ +# else +# define GST_WINRT_API GST_API_IMPORT +# endif +#endif + +#endif /* __GST_WIN32_PRELUDE_H__ */