mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-11 19:06:33 +00:00
724 lines
19 KiB
C++
724 lines
19 KiB
C++
|
/* 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);
|
||
|
}
|