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: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/947>
This commit is contained in:
Seungha Yang 2021-08-26 19:47:51 +09:00
parent b8d6962c9b
commit 08cb5b482d
6 changed files with 1011 additions and 1 deletions

View file

@ -15,7 +15,8 @@ subdir('play')
subdir('player')
subdir('sctp')
subdir('transcoder')
subdir('va')
subdir('vulkan')
subdir('wayland')
subdir('webrtc')
subdir('va')
subdir('winrt')

View file

@ -0,0 +1,31 @@
/* 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.
*/
#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 <gst/gst.h>
#include <gst/winrt/gstwinrtdevicewatcher.h>
#endif /* __GST_WINRT_H__ */

View file

@ -0,0 +1,723 @@
/* 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);
}

View file

@ -0,0 +1,136 @@
/* 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.
*/
#ifndef __GST_WINRT_DEVICE_WATCHER_H__
#define __GST_WINRT_DEVICE_WATCHER_H__
#include <gst/gst.h>
#include <gst/winrt/winrt-prelude.h>
#include <windows.devices.enumeration.h>
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__ */

View file

@ -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 <winapifamily.h>
#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 <windows.h>
#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 <windows.h>
#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])

View file

@ -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 <gst/gst.h>
#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__ */