1 /* GStreamer
2 * Copyright (C) 2021 Seungha Yang <seungha@centricular.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "gstwinrtdevicewatcher.h"
25
26 /* workaround for GetCurrentTime collision */
27 #ifdef GetCurrentTime
28 #undef GetCurrentTime
29 #endif
30
31 #include <windows.foundation.h>
32 #include <wrl.h>
33 #include <wrl/wrappers/corewrappers.h>
34
35 /* *INDENT-OFF* */
36 typedef __FITypedEventHandler_2_Windows__CDevices__CEnumeration__CDeviceWatcher_Windows__CDevices__CEnumeration__CDeviceInformation IAddedHandler;
37 typedef __FITypedEventHandler_2_Windows__CDevices__CEnumeration__CDeviceWatcher_Windows__CDevices__CEnumeration__CDeviceInformationUpdate IUpdatedHandler;
38 typedef __FITypedEventHandler_2_Windows__CDevices__CEnumeration__CDeviceWatcher_Windows__CDevices__CEnumeration__CDeviceInformationUpdate IRemovedHandler;
39 typedef __FITypedEventHandler_2_Windows__CDevices__CEnumeration__CDeviceWatcher_IInspectable IEnumerationCompletedHandler;
40 typedef __FITypedEventHandler_2_Windows__CDevices__CEnumeration__CDeviceWatcher_IInspectable IStoppedHandler;
41
42 using namespace Microsoft::WRL;
43 using namespace Microsoft::WRL::Wrappers;
44 using namespace ABI::Windows::Foundation;
45 using namespace ABI::Windows::Devices;
46 using namespace ABI::Windows::Devices::Enumeration;
47
48 GST_DEBUG_CATEGORY_STATIC (gst_winrt_device_watcher_debug);
49 #define GST_CAT_DEFAULT gst_winrt_device_watcher_debug
50
51 static void
52 gst_winrt_device_watcher_device_added (GstWinRTDeviceWatcher * self,
53 IDeviceInformation * info);
54 static void
55 gst_winrt_device_watcher_device_updated (GstWinRTDeviceWatcher * self,
56 IDeviceInformationUpdate * info_update);
57 static void
58 gst_winrt_device_watcher_device_removed (GstWinRTDeviceWatcher * self,
59 IDeviceInformationUpdate * info_update);
60 static void
61 gst_winrt_device_watcher_device_enumeration_completed (GstWinRTDeviceWatcher *
62 self);
63 static void
64 gst_winrt_device_watcher_device_enumeration_stopped (GstWinRTDeviceWatcher *
65 self);
66
67 class AddedHandler
68 : public RuntimeClass<RuntimeClassFlags<ClassicCom>, IAddedHandler>
69 {
70 public:
AddedHandler()71 AddedHandler () {}
RuntimeClassInitialize(GstWinRTDeviceWatcher * listenr)72 HRESULT RuntimeClassInitialize (GstWinRTDeviceWatcher * listenr)
73 {
74 if (!listenr)
75 return E_INVALIDARG;
76
77 listener_ = listenr;
78 return S_OK;
79 }
80
IFACEMETHOD(Invoke)81 IFACEMETHOD(Invoke)
82 (IDeviceWatcher* sender, IDeviceInformation * arg)
83 {
84 gst_winrt_device_watcher_device_added (listener_, arg);
85
86 return S_OK;
87 }
88
89 private:
90 GstWinRTDeviceWatcher * listener_;
91 };
92
93 class UpdatedHandler
94 : public RuntimeClass<RuntimeClassFlags<ClassicCom>, IUpdatedHandler>
95 {
96 public:
UpdatedHandler()97 UpdatedHandler () {}
RuntimeClassInitialize(GstWinRTDeviceWatcher * listenr)98 HRESULT RuntimeClassInitialize (GstWinRTDeviceWatcher * listenr)
99 {
100 if (!listenr)
101 return E_INVALIDARG;
102
103 listener_ = listenr;
104 return S_OK;
105 }
106
IFACEMETHOD(Invoke)107 IFACEMETHOD(Invoke)
108 (IDeviceWatcher* sender, IDeviceInformationUpdate * arg)
109 {
110 gst_winrt_device_watcher_device_updated (listener_, arg);
111
112 return S_OK;
113 }
114
115 private:
116 GstWinRTDeviceWatcher * listener_;
117 };
118
119 class RemovedHandler
120 : public RuntimeClass<RuntimeClassFlags<ClassicCom>, IRemovedHandler>
121 {
122 public:
RemovedHandler()123 RemovedHandler () {}
RuntimeClassInitialize(GstWinRTDeviceWatcher * listenr)124 HRESULT RuntimeClassInitialize (GstWinRTDeviceWatcher * listenr)
125 {
126 if (!listenr)
127 return E_INVALIDARG;
128
129 listener_ = listenr;
130 return S_OK;
131 }
132
IFACEMETHOD(Invoke)133 IFACEMETHOD(Invoke)
134 (IDeviceWatcher* sender, IDeviceInformationUpdate * arg)
135 {
136 gst_winrt_device_watcher_device_removed (listener_, arg);
137
138 return S_OK;
139 }
140
141 private:
142 GstWinRTDeviceWatcher * listener_;
143 };
144
145 class EnumerationCompletedHandler
146 : public RuntimeClass<RuntimeClassFlags<ClassicCom>, IEnumerationCompletedHandler>
147 {
148 public:
EnumerationCompletedHandler()149 EnumerationCompletedHandler () {}
RuntimeClassInitialize(GstWinRTDeviceWatcher * listenr)150 HRESULT RuntimeClassInitialize (GstWinRTDeviceWatcher * listenr)
151 {
152 if (!listenr)
153 return E_INVALIDARG;
154
155 listener_ = listenr;
156 return S_OK;
157 }
158
IFACEMETHOD(Invoke)159 IFACEMETHOD(Invoke)
160 (IDeviceWatcher* sender, IInspectable * arg)
161 {
162 gst_winrt_device_watcher_device_enumeration_completed (listener_);
163
164 return S_OK;
165 }
166
167 private:
168 GstWinRTDeviceWatcher * listener_;
169 };
170
171 class StoppedHandler
172 : public RuntimeClass<RuntimeClassFlags<ClassicCom>, IStoppedHandler>
173 {
174 public:
StoppedHandler()175 StoppedHandler () {}
RuntimeClassInitialize(GstWinRTDeviceWatcher * listenr)176 HRESULT RuntimeClassInitialize (GstWinRTDeviceWatcher * listenr)
177 {
178 if (!listenr)
179 return E_INVALIDARG;
180
181 listener_ = listenr;
182 return S_OK;
183 }
184
IFACEMETHOD(Invoke)185 IFACEMETHOD(Invoke)
186 (IDeviceWatcher* sender, IInspectable * arg)
187 {
188 gst_winrt_device_watcher_device_enumeration_stopped (listener_);
189
190 return S_OK;
191 }
192
193 private:
194 GstWinRTDeviceWatcher * listener_;
195 };
196 /* *INDENT-ON* */
197
198 typedef struct
199 {
200 ComPtr < IDeviceWatcher > watcher;
201
202 EventRegistrationToken added_token;
203 EventRegistrationToken updated_token;
204 EventRegistrationToken removed_token;
205 EventRegistrationToken enum_completed_token;
206 EventRegistrationToken stopped_token;
207 } GstWinRTDeviceWatcherInner;
208
209 enum
210 {
211 PROP_0,
212 PROP_DEVICE_CLASS,
213 };
214
215 #define DEFAULT_DEVICE_CLASS GST_WINRT_DEVICE_CLASS_ALL
216
217 struct _GstWinRTDeviceWatcherPrivate
218 {
219 GMutex lock;
220 GCond cond;
221
222 GThread *thread;
223 GMainContext *context;
224 GMainLoop *loop;
225
226 gboolean running;
227
228 GstWinRTDeviceWatcherCallbacks callbacks;
229 gpointer user_data;
230
231 GstWinRTDeviceWatcherInner *inner;
232
233 GstWinRTDeviceClass device_class;
234 };
235
236 GType
gst_winrt_device_class_get_type(void)237 gst_winrt_device_class_get_type (void)
238 {
239 static gsize device_class_type = 0;
240
241 if (g_once_init_enter (&device_class_type)) {
242 static const GEnumValue classes[] = {
243 {GST_WINRT_DEVICE_CLASS_ALL, "All", "all"},
244 {GST_WINRT_DEVICE_CLASS_AUDIO_CAPTURE, "AudioCapture", "audio-capture"},
245 {GST_WINRT_DEVICE_CLASS_AUDIO_RENDER, "AudioRender", "audio-render"},
246 {GST_WINRT_DEVICE_CLASS_PORTABLE_STORAGE_DEVICE,
247 "PortableStorageDevice", "portable-storage-device"},
248 {GST_WINRT_DEVICE_CLASS_VIDEO_CAPTURE,
249 "VideoCapture", "video-capture"},
250 {0, nullptr, nullptr},
251 };
252 GType tmp = g_enum_register_static ("GstWinRTDeviceClass", classes);
253 g_once_init_leave (&device_class_type, tmp);
254 }
255
256 return (GType) device_class_type;
257 }
258
259 static void gst_winrt_device_watcher_constructed (GObject * object);
260 static void gst_winrt_device_watcher_finalize (GObject * object);
261 static void gst_winrt_device_watcher_set_property (GObject * object,
262 guint prop_id, const GValue * value, GParamSpec * pspec);
263 static void gst_winrt_device_watcher_get_property (GObject * object,
264 guint prop_id, GValue * value, GParamSpec * pspec);
265
266 static gpointer
267 gst_winrt_device_watcher_thread_func (GstWinRTDeviceWatcher * self);
268
269 #define gst_winrt_device_watcher_parent_class parent_class
270 G_DEFINE_TYPE_WITH_PRIVATE (GstWinRTDeviceWatcher, gst_winrt_device_watcher,
271 GST_TYPE_OBJECT);
272
273 static void
gst_winrt_device_watcher_class_init(GstWinRTDeviceWatcherClass * klass)274 gst_winrt_device_watcher_class_init (GstWinRTDeviceWatcherClass * klass)
275 {
276 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
277
278 gobject_class->constructed = gst_winrt_device_watcher_constructed;
279 gobject_class->finalize = gst_winrt_device_watcher_finalize;
280 gobject_class->set_property = gst_winrt_device_watcher_set_property;
281 gobject_class->get_property = gst_winrt_device_watcher_get_property;
282
283 g_object_class_install_property (gobject_class, PROP_DEVICE_CLASS,
284 g_param_spec_enum ("device-class", "Device Class",
285 "Device class to watch", GST_TYPE_WINRT_DEVICE_CLASS,
286 DEFAULT_DEVICE_CLASS,
287 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
288 G_PARAM_STATIC_STRINGS)));
289
290 GST_DEBUG_CATEGORY_INIT (gst_winrt_device_watcher_debug,
291 "winrtdevicewatcher", 0, "winrtdevicewatcher");
292 }
293
294 static void
gst_winrt_device_watcher_init(GstWinRTDeviceWatcher * self)295 gst_winrt_device_watcher_init (GstWinRTDeviceWatcher * self)
296 {
297 GstWinRTDeviceWatcherPrivate *priv;
298
299 self->priv = priv = (GstWinRTDeviceWatcherPrivate *)
300 gst_winrt_device_watcher_get_instance_private (self);
301
302 g_mutex_init (&priv->lock);
303 g_cond_init (&priv->cond);
304 priv->context = g_main_context_new ();
305 priv->loop = g_main_loop_new (priv->context, FALSE);
306 }
307
308 static void
gst_winrt_device_watcher_constructed(GObject * object)309 gst_winrt_device_watcher_constructed (GObject * object)
310 {
311 GstWinRTDeviceWatcher *self = GST_WINRT_DEVICE_WATCHER (object);
312 GstWinRTDeviceWatcherPrivate *priv = self->priv;
313
314 g_mutex_lock (&priv->lock);
315 priv->thread = g_thread_new ("GstWinRTDeviceWatcher",
316 (GThreadFunc) gst_winrt_device_watcher_thread_func, self);
317 while (!g_main_loop_is_running (priv->loop))
318 g_cond_wait (&priv->cond, &priv->lock);
319 g_mutex_unlock (&priv->lock);
320 }
321
322 static void
gst_winrt_device_watcher_finalize(GObject * object)323 gst_winrt_device_watcher_finalize (GObject * object)
324 {
325 GstWinRTDeviceWatcher *self = GST_WINRT_DEVICE_WATCHER (object);
326 GstWinRTDeviceWatcherPrivate *priv = self->priv;
327
328 g_main_loop_quit (priv->loop);
329 if (g_thread_self () != priv->thread) {
330 g_thread_join (priv->thread);
331 g_main_loop_unref (priv->loop);
332 g_main_context_unref (priv->context);
333 } else {
334 g_warning ("Trying join from self-thread");
335 }
336
337 g_mutex_clear (&priv->lock);
338 g_cond_clear (&priv->cond);
339
340 G_OBJECT_CLASS (parent_class)->finalize (object);
341 }
342
343 static void
gst_winrt_device_watcher_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)344 gst_winrt_device_watcher_set_property (GObject * object, guint prop_id,
345 const GValue * value, GParamSpec * pspec)
346 {
347 GstWinRTDeviceWatcher *self = GST_WINRT_DEVICE_WATCHER (object);
348 GstWinRTDeviceWatcherPrivate *priv = self->priv;
349
350 switch (prop_id) {
351 case PROP_DEVICE_CLASS:
352 priv->device_class = (GstWinRTDeviceClass) g_value_get_enum (value);
353 break;
354 default:
355 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
356 break;
357 }
358 }
359
360 static void
gst_winrt_device_watcher_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)361 gst_winrt_device_watcher_get_property (GObject * object, guint prop_id,
362 GValue * value, GParamSpec * pspec)
363 {
364 GstWinRTDeviceWatcher *self = GST_WINRT_DEVICE_WATCHER (object);
365 GstWinRTDeviceWatcherPrivate *priv = self->priv;
366
367 switch (prop_id) {
368 case PROP_DEVICE_CLASS:
369 g_value_set_enum (value, priv->device_class);
370 break;
371 default:
372 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
373 break;
374 }
375 }
376
377 static gboolean
loop_running_cb(GstWinRTDeviceWatcher * self)378 loop_running_cb (GstWinRTDeviceWatcher * self)
379 {
380 GstWinRTDeviceWatcherPrivate *priv = self->priv;
381
382 g_mutex_lock (&priv->lock);
383 g_cond_signal (&priv->cond);
384 g_mutex_unlock (&priv->lock);
385
386 return G_SOURCE_REMOVE;
387 }
388
389 static void
gst_winrt_device_watcher_thread_func_inner(GstWinRTDeviceWatcher * self)390 gst_winrt_device_watcher_thread_func_inner (GstWinRTDeviceWatcher * self)
391 {
392 GstWinRTDeviceWatcherPrivate *priv = self->priv;
393 GSource *idle_source;
394 HRESULT hr;
395 GstWinRTDeviceWatcherInner *inner = nullptr;
396 ComPtr < IDeviceInformationStatics > factory;
397 ComPtr < IDeviceWatcher > watcher;
398 ComPtr < IAddedHandler > added_handler;
399 ComPtr < IUpdatedHandler > updated_handler;
400 ComPtr < IRemovedHandler > removed_handler;
401 ComPtr < IEnumerationCompletedHandler > enum_completed_handler;
402 ComPtr < IStoppedHandler > stopped_handler;
403
404 g_main_context_push_thread_default (priv->context);
405
406 idle_source = g_idle_source_new ();
407 g_source_set_callback (idle_source,
408 (GSourceFunc) loop_running_cb, self, nullptr);
409 g_source_attach (idle_source, priv->context);
410 g_source_unref (idle_source);
411
412 hr = GetActivationFactory (HStringReference
413 (RuntimeClass_Windows_Devices_Enumeration_DeviceInformation).Get (),
414 &factory);
415 if (FAILED (hr)) {
416 GST_ERROR_OBJECT (self,
417 "Failed to get IDeviceInformationStatics, hr: 0x%x", (guint) hr);
418 goto run_loop;
419 }
420
421 hr = factory->CreateWatcherDeviceClass ((DeviceClass) priv->device_class,
422 &watcher);
423 if (FAILED (hr)) {
424 GST_ERROR_OBJECT (self,
425 "Failed to create IDeviceWatcher, hr: 0x%x", (guint) hr);
426 goto run_loop;
427 }
428
429 hr = MakeAndInitialize < AddedHandler > (&added_handler, self);
430 if (FAILED (hr)) {
431 GST_ERROR_OBJECT (self, "Failed to create added handler, hr: 0x%x", hr);
432 goto run_loop;
433 }
434
435 hr = MakeAndInitialize < UpdatedHandler > (&updated_handler, self);
436 if (FAILED (hr)) {
437 GST_ERROR_OBJECT (self, "Failed to create updated handler, hr: 0x%x", hr);
438 goto run_loop;
439 }
440
441 hr = MakeAndInitialize < RemovedHandler > (&removed_handler, self);
442 if (FAILED (hr)) {
443 GST_ERROR_OBJECT (self, "Failed to create removed handler, hr: 0x%x", hr);
444 goto run_loop;
445 }
446
447 hr = MakeAndInitialize < EnumerationCompletedHandler >
448 (&enum_completed_handler, self);
449 if (FAILED (hr)) {
450 GST_ERROR_OBJECT (self,
451 "Failed to create enumeration completed handler, hr: 0x%x", hr);
452 goto run_loop;
453 }
454
455 hr = MakeAndInitialize < StoppedHandler > (&stopped_handler, self);
456 if (FAILED (hr)) {
457 GST_ERROR_OBJECT (self, "Failed to create stopped handler, hr: 0x%x", hr);
458 goto run_loop;
459 }
460
461 inner = new GstWinRTDeviceWatcherInner ();
462 hr = watcher->add_Added (added_handler.Get (), &inner->added_token);
463 if (FAILED (hr)) {
464 GST_ERROR_OBJECT (self, "Failed to register added handler, hr: 0x%x", hr);
465 delete inner;
466 inner = nullptr;
467
468 goto run_loop;
469 }
470
471 hr = watcher->add_Updated (updated_handler.Get (), &inner->updated_token);
472 if (FAILED (hr)) {
473 GST_ERROR_OBJECT (self, "Failed to register updated handler, hr: 0x%x", hr);
474 delete inner;
475 inner = nullptr;
476
477 goto run_loop;
478 }
479
480 hr = watcher->add_Removed (removed_handler.Get (), &inner->removed_token);
481 if (FAILED (hr)) {
482 GST_ERROR_OBJECT (self, "Failed to register removed handler, hr: 0x%x", hr);
483 delete inner;
484 inner = nullptr;
485
486 goto run_loop;
487 }
488
489 hr = watcher->add_EnumerationCompleted (enum_completed_handler.Get (),
490 &inner->enum_completed_token);
491 if (FAILED (hr)) {
492 GST_ERROR_OBJECT (self,
493 "Failed to register enumeration completed handler, hr: 0x%x", hr);
494 delete inner;
495 inner = nullptr;
496
497 goto run_loop;
498 }
499
500 hr = watcher->add_Stopped (stopped_handler.Get (), &inner->stopped_token);
501 if (FAILED (hr)) {
502 GST_ERROR_OBJECT (self, "Failed to register stopped handler, hr: 0x%x", hr);
503 delete inner;
504 inner = nullptr;
505
506 goto run_loop;
507 }
508
509 inner->watcher = watcher;
510 priv->inner = inner;
511
512 run_loop:
513 GST_INFO_OBJECT (self, "Starting loop");
514 g_main_loop_run (priv->loop);
515 GST_INFO_OBJECT (self, "Stopped loop");
516
517 if (inner) {
518 if (priv->running)
519 watcher->Stop ();
520
521 watcher->remove_Added (inner->added_token);
522 watcher->remove_Updated (inner->updated_token);
523 watcher->remove_Removed (inner->removed_token);
524 watcher->remove_EnumerationCompleted (inner->enum_completed_token);
525 watcher->remove_Stopped (inner->stopped_token);
526
527 delete inner;
528 }
529
530 g_main_context_pop_thread_default (priv->context);
531 }
532
533 static gpointer
gst_winrt_device_watcher_thread_func(GstWinRTDeviceWatcher * self)534 gst_winrt_device_watcher_thread_func (GstWinRTDeviceWatcher * self)
535 {
536 RoInitializeWrapper initialize (RO_INIT_MULTITHREADED);
537
538 /* wrap with another function so that everything can happen
539 * before RoInitializeWrapper is destructed */
540 gst_winrt_device_watcher_thread_func_inner (self);
541
542 return nullptr;
543 }
544
545 static void
gst_winrt_device_watcher_device_added(GstWinRTDeviceWatcher * self,IDeviceInformation * info)546 gst_winrt_device_watcher_device_added (GstWinRTDeviceWatcher * self,
547 IDeviceInformation * info)
548 {
549 GstWinRTDeviceWatcherPrivate *priv = self->priv;
550
551 GST_DEBUG_OBJECT (self, "Device added");
552
553 if (priv->callbacks.added)
554 priv->callbacks.added (self, info, priv->user_data);
555 }
556
557 static void
gst_winrt_device_watcher_device_updated(GstWinRTDeviceWatcher * self,IDeviceInformationUpdate * info_update)558 gst_winrt_device_watcher_device_updated (GstWinRTDeviceWatcher * self,
559 IDeviceInformationUpdate * info_update)
560 {
561 GstWinRTDeviceWatcherPrivate *priv = self->priv;
562
563 GST_DEBUG_OBJECT (self, "Device updated");
564
565 if (priv->callbacks.updated)
566 priv->callbacks.updated (self, info_update, priv->user_data);
567 }
568
569 static void
gst_winrt_device_watcher_device_removed(GstWinRTDeviceWatcher * self,IDeviceInformationUpdate * info_update)570 gst_winrt_device_watcher_device_removed (GstWinRTDeviceWatcher * self,
571 IDeviceInformationUpdate * info_update)
572 {
573 GstWinRTDeviceWatcherPrivate *priv = self->priv;
574
575 GST_DEBUG_OBJECT (self, "Device removed");
576
577 if (priv->callbacks.removed)
578 priv->callbacks.removed (self, info_update, priv->user_data);
579 }
580
581 static void
gst_winrt_device_watcher_device_enumeration_completed(GstWinRTDeviceWatcher * self)582 gst_winrt_device_watcher_device_enumeration_completed (GstWinRTDeviceWatcher *
583 self)
584 {
585 GstWinRTDeviceWatcherPrivate *priv = self->priv;
586
587 GST_DEBUG_OBJECT (self, "Enumeration completed");
588
589 if (priv->callbacks.enumeration_completed)
590 priv->callbacks.enumeration_completed (self, priv->user_data);
591 }
592
593 static void
gst_winrt_device_watcher_device_enumeration_stopped(GstWinRTDeviceWatcher * self)594 gst_winrt_device_watcher_device_enumeration_stopped (GstWinRTDeviceWatcher *
595 self)
596 {
597 GST_DEBUG_OBJECT (self, "Stopped");
598 }
599
600 /**
601 * gst_winrt_device_watcher_new:
602 * @device_class: a #GstWinRTDeviceClass to watch
603 * @callbacks: a pointer to #GstWinRTDeviceWatcherCallbacks
604 * @user_data: a user_data argument for the callbacks
605 *
606 * Constructs a new #GstWinRTDeviceWatcher object for watching device update
607 * of @device_class
608 *
609 * Returns: (transfer full) (nullable): a new #GstWinRTDeviceWatcher
610 * or %NULL when failed to create/setup #GstWinRTDeviceWatcher object
611 *
612 * Since: 1.20
613 */
614 GstWinRTDeviceWatcher *
gst_winrt_device_watcher_new(GstWinRTDeviceClass device_class,const GstWinRTDeviceWatcherCallbacks * callbacks,gpointer user_data)615 gst_winrt_device_watcher_new (GstWinRTDeviceClass device_class,
616 const GstWinRTDeviceWatcherCallbacks * callbacks, gpointer user_data)
617 {
618 GstWinRTDeviceWatcher *self;
619 GstWinRTDeviceWatcherPrivate *priv;
620
621 g_return_val_if_fail (callbacks != nullptr, nullptr);
622
623 self = (GstWinRTDeviceWatcher *)
624 g_object_new (GST_TYPE_WINRT_DEVICE_WATCHER, "device-class", device_class,
625 nullptr);
626
627 priv = self->priv;
628 if (!priv->inner) {
629 gst_object_unref (self);
630 return nullptr;
631 }
632
633 priv->callbacks = *callbacks;
634 priv->user_data = user_data;
635
636 gst_object_ref_sink (self);
637
638 return self;
639 }
640
641 /**
642 * gst_winrt_device_watcher_start:
643 * @device_class: a #GstWinRTDeviceClass to watch
644 *
645 * Starts watching device update.
646 *
647 * Returns: %TRUE if successful
648 *
649 * Since: 1.20
650 */
651 gboolean
gst_winrt_device_watcher_start(GstWinRTDeviceWatcher * watcher)652 gst_winrt_device_watcher_start (GstWinRTDeviceWatcher * watcher)
653 {
654 GstWinRTDeviceWatcherPrivate *priv;
655 GstWinRTDeviceWatcherInner *inner;
656 HRESULT hr;
657
658 g_return_val_if_fail (GST_IS_WINRT_DEVICE_WATCHER (watcher), FALSE);
659
660 priv = watcher->priv;
661 inner = priv->inner;
662
663 GST_DEBUG_OBJECT (watcher, "Start");
664
665 g_mutex_lock (&priv->lock);
666 if (priv->running) {
667 GST_DEBUG_OBJECT (watcher, "Already running");
668 g_mutex_unlock (&priv->lock);
669
670 return TRUE;
671 }
672
673 hr = inner->watcher->Start ();
674 if (FAILED (hr)) {
675 GST_ERROR_OBJECT (watcher, "Failed to start watcher, hr: 0x%x", (guint) hr);
676 g_mutex_unlock (&priv->lock);
677
678 return FALSE;
679 }
680
681 priv->running = TRUE;
682 g_mutex_unlock (&priv->lock);
683
684 return TRUE;
685 }
686
687 /**
688 * gst_winrt_device_watcher_stop:
689 * @device_class: a #GstWinRTDeviceClass to watch
690 *
691 * Stops watching device update.
692 *
693 * Since: 1.20
694 */
695 void
gst_winrt_device_watcher_stop(GstWinRTDeviceWatcher * watcher)696 gst_winrt_device_watcher_stop (GstWinRTDeviceWatcher * watcher)
697 {
698 GstWinRTDeviceWatcherPrivate *priv;
699 GstWinRTDeviceWatcherInner *inner;
700 HRESULT hr;
701
702 g_return_if_fail (GST_IS_WINRT_DEVICE_WATCHER (watcher));
703
704 GST_DEBUG_OBJECT (watcher, "Stop");
705
706 priv = watcher->priv;
707 inner = priv->inner;
708
709 g_mutex_lock (&priv->lock);
710 if (!priv->running) {
711 g_mutex_unlock (&priv->lock);
712
713 return;
714 }
715
716 priv->running = FALSE;
717 hr = inner->watcher->Stop ();
718 if (FAILED (hr)) {
719 GST_WARNING_OBJECT (watcher,
720 "Failed to stop watcher, hr: 0x%x", (guint) hr);
721 }
722 g_mutex_unlock (&priv->lock);
723 }
724