| /* GStreamer | |
| * Copyright (C) 2021 Seungha Yang <seungha@centricular.com> | |
| * | |
| * 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 <windows.foundation.h> | |
| #include <wrl.h> | |
| #include <wrl/wrappers/corewrappers.h> | |
| /* *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<RuntimeClassFlags<ClassicCom>, 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<RuntimeClassFlags<ClassicCom>, 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<RuntimeClassFlags<ClassicCom>, 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<RuntimeClassFlags<ClassicCom>, 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<RuntimeClassFlags<ClassicCom>, 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); | |
| } |