From a6a4267c7b2683516524fc730d74b62a3aeb3ef9 Mon Sep 17 00:00:00 2001 From: Seungha Yang Date: Thu, 28 May 2020 05:09:47 +0900 Subject: [PATCH] wasapi2: Add device provider implementation Similar to device provider implementation of wasapi plugin, this implementation supports only static probing. But we can implement runtime device add/remove/update monitoring using DeviceWatcher interface later. See https://docs.microsoft.com/en-us/uwp/api/windows.devices.enumeration.devicewatcher Part-of: --- sys/wasapi2/gstwasapi2device.c | 245 +++++++++++++++++++++++++++++++++++++++++ sys/wasapi2/gstwasapi2device.h | 37 +++++++ sys/wasapi2/meson.build | 1 + sys/wasapi2/plugin.c | 4 + 4 files changed, 287 insertions(+) create mode 100644 sys/wasapi2/gstwasapi2device.c create mode 100644 sys/wasapi2/gstwasapi2device.h diff --git a/sys/wasapi2/gstwasapi2device.c b/sys/wasapi2/gstwasapi2device.c new file mode 100644 index 0000000..ac51126 --- /dev/null +++ b/sys/wasapi2/gstwasapi2device.c @@ -0,0 +1,245 @@ +/* GStreamer + * Copyright (C) 2018 Nirbheek Chauhan + * Copyright (C) 2020 Seungha Yang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstwasapi2device.h" +#include "gstwasapi2client.h" + +GST_DEBUG_CATEGORY_EXTERN (gst_wasapi2_debug); +#define GST_CAT_DEFAULT gst_wasapi2_debug + +enum +{ + PROP_0, + PROP_DEVICE, +}; + +struct _GstWasapi2Device +{ + GstDevice parent; + + gchar *device_id; + const gchar *factory_name; +}; + +G_DEFINE_TYPE (GstWasapi2Device, gst_wasapi2_device, GST_TYPE_DEVICE); + +static void gst_wasapi2_device_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec); +static void gst_wasapi2_device_set_property (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec); +static void gst_wasapi2_device_finalize (GObject * object); +static GstElement *gst_wasapi2_device_create_element (GstDevice * device, + const gchar * name); + +static void +gst_wasapi2_device_class_init (GstWasapi2DeviceClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstDeviceClass *dev_class = GST_DEVICE_CLASS (klass); + + dev_class->create_element = gst_wasapi2_device_create_element; + + gobject_class->get_property = gst_wasapi2_device_get_property; + gobject_class->set_property = gst_wasapi2_device_set_property; + gobject_class->finalize = gst_wasapi2_device_finalize; + + g_object_class_install_property (gobject_class, PROP_DEVICE, + g_param_spec_string ("device", "Device", + "WASAPI playback device as a GUID string", NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); +} + +static void +gst_wasapi2_device_init (GstWasapi2Device * self) +{ +} + +static void +gst_wasapi2_device_finalize (GObject * object) +{ + GstWasapi2Device *self = GST_WASAPI2_DEVICE (object); + + g_free (self->device_id); + + G_OBJECT_CLASS (gst_wasapi2_device_parent_class)->finalize (object); +} + +static GstElement * +gst_wasapi2_device_create_element (GstDevice * device, const gchar * name) +{ + GstWasapi2Device *self = GST_WASAPI2_DEVICE (device); + GstElement *elem; + + elem = gst_element_factory_make (self->factory_name, name); + + g_object_set (elem, "device", self->device_id, NULL); + + return elem; +} + +static void +gst_wasapi2_device_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstWasapi2Device *self = GST_WASAPI2_DEVICE (object); + + switch (prop_id) { + case PROP_DEVICE: + g_value_set_string (value, self->device_id); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_wasapi2_device_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstWasapi2Device *self = GST_WASAPI2_DEVICE (object); + + switch (prop_id) { + case PROP_DEVICE: + self->device_id = g_value_dup_string (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +struct _GstWasapi2DeviceProvider +{ + GstDeviceProvider parent; +}; + +G_DEFINE_TYPE (GstWasapi2DeviceProvider, gst_wasapi2_device_provider, + GST_TYPE_DEVICE_PROVIDER); + +static GList *gst_wasapi2_device_provider_probe (GstDeviceProvider * provider); + +static void +gst_wasapi2_device_provider_class_init (GstWasapi2DeviceProviderClass * klass) +{ + GstDeviceProviderClass *provider_class = GST_DEVICE_PROVIDER_CLASS (klass); + + provider_class->probe = GST_DEBUG_FUNCPTR (gst_wasapi2_device_provider_probe); + + gst_device_provider_class_set_static_metadata (provider_class, + "WASAPI (Windows Audio Session API) Device Provider", + "Source/Sink/Audio", "List WASAPI source and sink devices", + "Nirbheek Chauhan , " + "Seungha Yang "); +} + +static void +gst_wasapi2_device_provider_init (GstWasapi2DeviceProvider * provider) +{ +} + +static void +gst_wasapi2_device_provider_probe_internal (GstWasapi2DeviceProvider * self, + GstWasapi2ClientDeviceClass client_class, GList ** devices) +{ + gint i; + const gchar *device_class, *factory_name; + + if (client_class == GST_WASAPI2_CLIENT_DEVICE_CLASS_RENDER) { + device_class = "Audio/Sink"; + factory_name = "wasapi2sink"; + } else { + device_class = "Audio/Source"; + factory_name = "wasapi2src"; + } + + for (i = 0;; i++) { + GstWasapi2Client *client = NULL; + GstDevice *device; + GstStructure *props = NULL; + GstCaps *caps = NULL; + gchar *device_id = NULL; + gchar *device_name = NULL; + + client = gst_wasapi2_client_new (client_class, FALSE, i, NULL); + + if (!client) + return; + + caps = gst_wasapi2_client_get_caps (client); + if (!caps) { + GST_WARNING_OBJECT (self, "Couldn't get caps from client %d", i); + goto next; + } + + g_object_get (client, + "device", &device_id, "device-name", &device_name, NULL); + if (!device_id) { + GST_WARNING_OBJECT (self, "Couldn't get device name from client %d", i); + goto next; + } + + if (!device_name) { + GST_WARNING_OBJECT (self, "Couldn't get device name from client %d", i); + goto next; + } + + props = gst_structure_new ("wasapi2-proplist", + "device.api", G_TYPE_STRING, "wasapi", + "device.id", G_TYPE_STRING, device_id, + "device.default", G_TYPE_BOOLEAN, i == 0, + "wasapi.device.description", G_TYPE_STRING, device_name, NULL); + + device = g_object_new (GST_TYPE_WASAPI2_DEVICE, "device", device_id, + "display-name", device_name, "caps", caps, + "device-class", device_class, "properties", props, NULL); + GST_WASAPI2_DEVICE (device)->factory_name = factory_name; + + *devices = g_list_append (*devices, device); + + next: + gst_clear_object (&client); + gst_clear_caps (&caps); + g_free (device_id); + g_free (device_name); + if (props) + gst_structure_free (props); + } + + return; +} + +static GList * +gst_wasapi2_device_provider_probe (GstDeviceProvider * provider) +{ + GstWasapi2DeviceProvider *self = GST_WASAPI2_DEVICE_PROVIDER (provider); + GList *devices = NULL; + + gst_wasapi2_device_provider_probe_internal (self, + GST_WASAPI2_CLIENT_DEVICE_CLASS_CAPTURE, &devices); + gst_wasapi2_device_provider_probe_internal (self, + GST_WASAPI2_CLIENT_DEVICE_CLASS_RENDER, &devices); + + return devices; +} diff --git a/sys/wasapi2/gstwasapi2device.h b/sys/wasapi2/gstwasapi2device.h new file mode 100644 index 0000000..697bba1 --- /dev/null +++ b/sys/wasapi2/gstwasapi2device.h @@ -0,0 +1,37 @@ +/* GStreamer + * Copyright (C) 2020 Seungha Yang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_WASAPI2_DEVICE_H__ +#define __GST_WASAPI2_DEVICE_H__ + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_WASAPI2_DEVICE (gst_wasapi2_device_get_type()) +#define GST_TYPE_WASAPI2_DEVICE_PROVIDER (gst_wasapi2_device_provider_get_type()) + +G_DECLARE_FINAL_TYPE (GstWasapi2Device, gst_wasapi2_device, + GST, WASAPI2_DEVICE, GstDevice); +G_DECLARE_FINAL_TYPE (GstWasapi2DeviceProvider, gst_wasapi2_device_provider, + GST, WASAPI2_DEVICE_PROVIDER, GstDeviceProvider); + +G_END_DECLS + +#endif /* __GST_WASAPI2_DEVICE_H__ */ \ No newline at end of file diff --git a/sys/wasapi2/meson.build b/sys/wasapi2/meson.build index 742c484..f5c774c 100644 --- a/sys/wasapi2/meson.build +++ b/sys/wasapi2/meson.build @@ -3,6 +3,7 @@ wasapi2_sources = [ 'gstwasapi2sink.c', 'gstwasapi2util.c', 'gstwasapi2client.cpp', + 'gstwasapi2device.c', 'plugin.c', ] diff --git a/sys/wasapi2/plugin.c b/sys/wasapi2/plugin.c index fa88cb0..b87785c 100644 --- a/sys/wasapi2/plugin.c +++ b/sys/wasapi2/plugin.c @@ -25,6 +25,7 @@ #include "gstwasapi2sink.h" #include "gstwasapi2src.h" +#include "gstwasapi2device.h" GST_DEBUG_CATEGORY (gst_wasapi2_debug); GST_DEBUG_CATEGORY (gst_wasapi2_client_debug); @@ -46,6 +47,9 @@ plugin_init (GstPlugin * plugin) gst_element_register (plugin, "wasapi2sink", rank, GST_TYPE_WASAPI2_SINK); gst_element_register (plugin, "wasapi2src", rank, GST_TYPE_WASAPI2_SRC); + gst_device_provider_register (plugin, "wasapi2deviceprovider", + rank, GST_TYPE_WASAPI2_DEVICE_PROVIDER); + return TRUE; } -- 2.7.4