2015-07-08 17:40:37 +02:00
|
|
|
/* GStreamer
|
|
|
|
|
*
|
2018-11-05 17:48:52 +01:00
|
|
|
* Copyright © 2018 Wim Taymans
|
2015-07-08 17:40:37 +02:00
|
|
|
*
|
2018-11-05 17:48:52 +01:00
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
|
|
|
* to deal in the Software without restriction, including without limitation
|
|
|
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
|
* Software is furnished to do so, subject to the following conditions:
|
2015-07-08 17:40:37 +02:00
|
|
|
*
|
2018-11-05 17:48:52 +01:00
|
|
|
* The above copyright notice and this permission notice (including the next
|
|
|
|
|
* paragraph) shall be included in all copies or substantial portions of the
|
|
|
|
|
* Software.
|
2015-07-08 17:40:37 +02:00
|
|
|
*
|
2018-11-05 17:48:52 +01:00
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
|
|
|
* DEALINGS IN THE SOFTWARE.
|
2015-07-08 17:40:37 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
|
#include "config.h"
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
#include <gst/gst.h>
|
|
|
|
|
|
2017-05-23 19:15:33 +02:00
|
|
|
#include "gstpipewireformat.h"
|
|
|
|
|
#include "gstpipewiredeviceprovider.h"
|
|
|
|
|
#include "gstpipewiresrc.h"
|
|
|
|
|
#include "gstpipewiresink.h"
|
2015-07-08 17:40:37 +02:00
|
|
|
|
2017-05-23 19:15:33 +02:00
|
|
|
GST_DEBUG_CATEGORY_EXTERN (pipewire_debug);
|
|
|
|
|
#define GST_CAT_DEFAULT pipewire_debug
|
2015-07-08 17:40:37 +02:00
|
|
|
|
2017-05-23 19:15:33 +02:00
|
|
|
G_DEFINE_TYPE (GstPipeWireDevice, gst_pipewire_device, GST_TYPE_DEVICE);
|
2015-07-08 17:40:37 +02:00
|
|
|
|
|
|
|
|
enum
|
|
|
|
|
{
|
2016-11-24 17:00:42 +01:00
|
|
|
PROP_ID = 1,
|
2015-07-08 17:40:37 +02:00
|
|
|
};
|
|
|
|
|
|
2015-07-09 17:34:01 +02:00
|
|
|
static GstElement *
|
2017-05-23 19:15:33 +02:00
|
|
|
gst_pipewire_device_create_element (GstDevice * device, const gchar * name)
|
2015-07-08 17:40:37 +02:00
|
|
|
{
|
2017-05-23 19:15:33 +02:00
|
|
|
GstPipeWireDevice *pipewire_dev = GST_PIPEWIRE_DEVICE (device);
|
2015-07-09 17:34:01 +02:00
|
|
|
GstElement *elem;
|
2017-01-20 15:53:03 +01:00
|
|
|
gchar *str;
|
2015-07-09 17:34:01 +02:00
|
|
|
|
2017-05-23 19:15:33 +02:00
|
|
|
elem = gst_element_factory_make (pipewire_dev->element, name);
|
|
|
|
|
str = g_strdup_printf ("%u", pipewire_dev->id);
|
2017-01-20 15:53:03 +01:00
|
|
|
g_object_set (elem, "path", str, NULL);
|
|
|
|
|
g_free (str);
|
2015-07-09 17:34:01 +02:00
|
|
|
|
|
|
|
|
return elem;
|
2015-07-08 17:40:37 +02:00
|
|
|
}
|
|
|
|
|
|
2015-07-09 17:34:01 +02:00
|
|
|
static gboolean
|
2017-05-23 19:15:33 +02:00
|
|
|
gst_pipewire_device_reconfigure_element (GstDevice * device, GstElement * element)
|
2015-07-08 17:40:37 +02:00
|
|
|
{
|
2017-05-23 19:15:33 +02:00
|
|
|
GstPipeWireDevice *pipewire_dev = GST_PIPEWIRE_DEVICE (device);
|
2017-01-20 15:53:03 +01:00
|
|
|
gchar *str;
|
2015-07-08 17:40:37 +02:00
|
|
|
|
2017-05-23 19:15:33 +02:00
|
|
|
if (!strcmp (pipewire_dev->element, "pipewiresrc")) {
|
|
|
|
|
if (!GST_IS_PIPEWIRE_SRC (element))
|
2015-07-09 17:34:01 +02:00
|
|
|
return FALSE;
|
2017-05-23 19:15:33 +02:00
|
|
|
} else if (!strcmp (pipewire_dev->element, "pipewiresink")) {
|
|
|
|
|
if (!GST_IS_PIPEWIRE_SINK (element))
|
2015-07-09 17:34:01 +02:00
|
|
|
return FALSE;
|
|
|
|
|
} else {
|
|
|
|
|
g_assert_not_reached ();
|
|
|
|
|
}
|
2015-07-08 17:40:37 +02:00
|
|
|
|
2017-05-23 19:15:33 +02:00
|
|
|
str = g_strdup_printf ("%u", pipewire_dev->id);
|
2017-01-20 15:53:03 +01:00
|
|
|
g_object_set (element, "path", str, NULL);
|
|
|
|
|
g_free (str);
|
2015-07-09 17:34:01 +02:00
|
|
|
|
|
|
|
|
return TRUE;
|
2015-07-08 17:40:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
2017-05-23 19:15:33 +02:00
|
|
|
gst_pipewire_device_get_property (GObject * object, guint prop_id,
|
2015-07-09 17:34:01 +02:00
|
|
|
GValue * value, GParamSpec * pspec)
|
2015-07-08 17:40:37 +02:00
|
|
|
{
|
2017-05-23 19:15:33 +02:00
|
|
|
GstPipeWireDevice *device;
|
2015-07-09 17:34:01 +02:00
|
|
|
|
2017-05-23 19:15:33 +02:00
|
|
|
device = GST_PIPEWIRE_DEVICE_CAST (object);
|
2015-07-08 17:40:37 +02:00
|
|
|
|
|
|
|
|
switch (prop_id) {
|
2016-11-24 17:00:42 +01:00
|
|
|
case PROP_ID:
|
|
|
|
|
g_value_set_uint (value, device->id);
|
2015-07-08 17:40:37 +02:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2017-05-23 19:15:33 +02:00
|
|
|
gst_pipewire_device_set_property (GObject * object, guint prop_id,
|
2015-07-09 17:34:01 +02:00
|
|
|
const GValue * value, GParamSpec * pspec)
|
2015-07-08 17:40:37 +02:00
|
|
|
{
|
2017-05-23 19:15:33 +02:00
|
|
|
GstPipeWireDevice *device;
|
2015-07-09 17:34:01 +02:00
|
|
|
|
2017-05-23 19:15:33 +02:00
|
|
|
device = GST_PIPEWIRE_DEVICE_CAST (object);
|
2015-07-08 17:40:37 +02:00
|
|
|
|
|
|
|
|
switch (prop_id) {
|
2016-11-24 17:00:42 +01:00
|
|
|
case PROP_ID:
|
|
|
|
|
device->id = g_value_get_uint (value);
|
2015-07-08 17:40:37 +02:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-09 17:34:01 +02:00
|
|
|
static void
|
2017-05-23 19:15:33 +02:00
|
|
|
gst_pipewire_device_finalize (GObject * object)
|
2015-07-09 17:34:01 +02:00
|
|
|
{
|
2017-05-23 19:15:33 +02:00
|
|
|
G_OBJECT_CLASS (gst_pipewire_device_parent_class)->finalize (object);
|
2015-07-09 17:34:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2017-05-23 19:15:33 +02:00
|
|
|
gst_pipewire_device_class_init (GstPipeWireDeviceClass * klass)
|
2015-07-09 17:34:01 +02:00
|
|
|
{
|
|
|
|
|
GstDeviceClass *dev_class = GST_DEVICE_CLASS (klass);
|
|
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
|
|
2017-05-23 19:15:33 +02:00
|
|
|
dev_class->create_element = gst_pipewire_device_create_element;
|
|
|
|
|
dev_class->reconfigure_element = gst_pipewire_device_reconfigure_element;
|
2015-07-09 17:34:01 +02:00
|
|
|
|
2017-05-23 19:15:33 +02:00
|
|
|
object_class->get_property = gst_pipewire_device_get_property;
|
|
|
|
|
object_class->set_property = gst_pipewire_device_set_property;
|
|
|
|
|
object_class->finalize = gst_pipewire_device_finalize;
|
2015-07-09 17:34:01 +02:00
|
|
|
|
2016-11-24 17:00:42 +01:00
|
|
|
g_object_class_install_property (object_class, PROP_ID,
|
|
|
|
|
g_param_spec_uint ("id", "Id",
|
2017-05-23 19:15:33 +02:00
|
|
|
"The internal id of the PipeWire device", 0, G_MAXUINT32, SPA_ID_INVALID,
|
2015-07-09 17:34:01 +02:00
|
|
|
G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2017-05-23 19:15:33 +02:00
|
|
|
gst_pipewire_device_init (GstPipeWireDevice * device)
|
2015-07-09 17:34:01 +02:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-23 19:15:33 +02:00
|
|
|
G_DEFINE_TYPE (GstPipeWireDeviceProvider, gst_pipewire_device_provider,
|
2015-07-09 17:34:01 +02:00
|
|
|
GST_TYPE_DEVICE_PROVIDER);
|
|
|
|
|
|
|
|
|
|
enum
|
|
|
|
|
{
|
|
|
|
|
PROP_0,
|
|
|
|
|
PROP_CLIENT_NAME,
|
|
|
|
|
PROP_LAST
|
|
|
|
|
};
|
|
|
|
|
|
2018-08-03 17:42:49 +02:00
|
|
|
struct pending {
|
|
|
|
|
struct spa_list link;
|
|
|
|
|
uint32_t seq;
|
|
|
|
|
void (*callback) (void *data);
|
|
|
|
|
void *data;
|
|
|
|
|
};
|
|
|
|
|
|
2018-08-13 15:20:25 +02:00
|
|
|
struct remote_data {
|
2018-08-03 17:42:49 +02:00
|
|
|
uint32_t seq;
|
|
|
|
|
GstPipeWireDeviceProvider *self;
|
2019-01-10 10:08:14 +01:00
|
|
|
struct spa_hook core_listener;
|
2018-08-03 17:42:49 +02:00
|
|
|
struct pw_registry_proxy *registry;
|
|
|
|
|
struct spa_hook registry_listener;
|
|
|
|
|
struct spa_list nodes;
|
|
|
|
|
struct spa_list ports;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct node_data {
|
|
|
|
|
struct spa_list link;
|
|
|
|
|
GstPipeWireDeviceProvider *self;
|
|
|
|
|
struct pw_node_proxy *proxy;
|
2018-08-13 15:20:25 +02:00
|
|
|
struct spa_hook proxy_listener;
|
2018-08-03 17:42:49 +02:00
|
|
|
uint32_t id;
|
|
|
|
|
uint32_t parent_id;
|
|
|
|
|
struct spa_hook node_listener;
|
|
|
|
|
struct pw_node_info *info;
|
|
|
|
|
GstCaps *caps;
|
|
|
|
|
GstDevice *dev;
|
|
|
|
|
struct pending pending;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct port_data {
|
|
|
|
|
struct spa_list link;
|
|
|
|
|
struct node_data *node_data;
|
|
|
|
|
struct pw_port_proxy *proxy;
|
2018-08-13 15:20:25 +02:00
|
|
|
struct spa_hook proxy_listener;
|
2018-08-03 17:42:49 +02:00
|
|
|
uint32_t id;
|
|
|
|
|
struct spa_hook port_listener;
|
|
|
|
|
struct pending pending;
|
|
|
|
|
};
|
|
|
|
|
|
2018-08-13 15:20:25 +02:00
|
|
|
static struct node_data *find_node_data(struct remote_data *rd, uint32_t id)
|
2018-08-03 17:42:49 +02:00
|
|
|
{
|
|
|
|
|
struct node_data *n;
|
|
|
|
|
spa_list_for_each(n, &rd->nodes, link) {
|
|
|
|
|
if (n->id == id)
|
|
|
|
|
return n;
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-08 17:40:37 +02:00
|
|
|
static GstDevice *
|
2018-08-03 17:42:49 +02:00
|
|
|
new_node (GstPipeWireDeviceProvider *self, struct node_data *data)
|
2015-07-08 17:40:37 +02:00
|
|
|
{
|
2015-07-17 17:01:46 +02:00
|
|
|
GstStructure *props;
|
2016-12-22 17:08:19 +01:00
|
|
|
const gchar *klass = NULL;
|
2017-05-23 19:15:33 +02:00
|
|
|
GstPipeWireDeviceType type;
|
2018-08-03 17:42:49 +02:00
|
|
|
const struct pw_node_info *info = data->info;
|
2018-08-13 15:20:25 +02:00
|
|
|
const gchar *element = NULL;
|
|
|
|
|
GstPipeWireDevice *gstdev;
|
2015-07-08 17:40:37 +02:00
|
|
|
|
2017-06-02 10:40:43 +02:00
|
|
|
if (info->max_input_ports > 0 && info->max_output_ports == 0) {
|
2017-05-23 19:15:33 +02:00
|
|
|
type = GST_PIPEWIRE_DEVICE_TYPE_SINK;
|
2018-08-13 15:20:25 +02:00
|
|
|
element = "pipewiresink";
|
2018-02-20 10:31:55 +01:00
|
|
|
} else if (info->max_output_ports > 0 && info->max_input_ports == 0) {
|
2017-05-23 19:15:33 +02:00
|
|
|
type = GST_PIPEWIRE_DEVICE_TYPE_SOURCE;
|
2018-08-13 15:20:25 +02:00
|
|
|
element = "pipewiresrc";
|
2017-02-01 08:58:21 +01:00
|
|
|
} else {
|
2017-07-04 10:50:53 +02:00
|
|
|
return NULL;
|
2017-02-01 08:58:21 +01:00
|
|
|
}
|
2015-07-08 17:40:37 +02:00
|
|
|
|
2017-05-23 19:15:33 +02:00
|
|
|
props = gst_structure_new_empty ("pipewire-proplist");
|
2016-12-22 17:08:19 +01:00
|
|
|
if (info->props) {
|
2018-08-03 17:42:49 +02:00
|
|
|
const struct spa_dict_item *item;
|
2016-12-22 17:08:19 +01:00
|
|
|
spa_dict_for_each (item, info->props)
|
|
|
|
|
gst_structure_set (props, item->key, G_TYPE_STRING, item->value, NULL);
|
2015-07-17 17:01:46 +02:00
|
|
|
|
2017-01-20 15:53:03 +01:00
|
|
|
klass = spa_dict_lookup (info->props, "media.class");
|
2016-12-22 17:08:19 +01:00
|
|
|
}
|
2015-07-17 17:01:46 +02:00
|
|
|
if (klass == NULL)
|
|
|
|
|
klass = "unknown/unknown";
|
|
|
|
|
|
2018-08-13 15:20:25 +02:00
|
|
|
gstdev = g_object_new (GST_TYPE_PIPEWIRE_DEVICE,
|
|
|
|
|
"display-name", info->name, "caps", data->caps, "device-class", klass,
|
|
|
|
|
"id", data->id, "properties", props, NULL);
|
|
|
|
|
|
|
|
|
|
gstdev->id = data->id;
|
|
|
|
|
gstdev->type = type;
|
|
|
|
|
gstdev->element = element;
|
|
|
|
|
if (props)
|
|
|
|
|
gst_structure_free (props);
|
|
|
|
|
|
|
|
|
|
return GST_DEVICE (gstdev);
|
2015-07-08 17:40:37 +02:00
|
|
|
}
|
|
|
|
|
|
2018-08-03 17:42:49 +02:00
|
|
|
static void do_add_node(void *data)
|
2015-07-09 17:34:01 +02:00
|
|
|
{
|
2018-08-03 17:42:49 +02:00
|
|
|
struct port_data *p = data;
|
|
|
|
|
struct node_data *nd = p->node_data;
|
|
|
|
|
GstPipeWireDeviceProvider *self = nd->self;
|
2015-07-09 17:34:01 +02:00
|
|
|
|
2018-08-03 17:42:49 +02:00
|
|
|
if (nd->dev)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
nd->dev = new_node (self, nd);
|
|
|
|
|
if (nd->dev) {
|
|
|
|
|
if(self->list_only)
|
|
|
|
|
*self->devices = g_list_prepend (*self->devices, gst_object_ref_sink (nd->dev));
|
|
|
|
|
else
|
|
|
|
|
gst_device_provider_device_add (GST_DEVICE_PROVIDER (self), nd->dev);
|
|
|
|
|
}
|
2015-07-09 17:34:01 +02:00
|
|
|
}
|
|
|
|
|
|
2019-01-10 10:08:14 +01:00
|
|
|
static void add_pending(GstPipeWireDeviceProvider *self, struct pending *p,
|
|
|
|
|
void (*callback) (void *data), void *data)
|
|
|
|
|
{
|
|
|
|
|
spa_list_append(&self->pending, &p->link);
|
|
|
|
|
p->callback = callback;
|
|
|
|
|
p->data = data;
|
|
|
|
|
pw_log_debug("add pending %d", p->seq);
|
2019-02-25 12:29:57 +01:00
|
|
|
self->seq = p->seq = pw_core_proxy_sync(self->core_proxy, 0, self->seq);
|
2019-01-10 10:08:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void remove_pending(struct pending *p)
|
|
|
|
|
{
|
|
|
|
|
if (p->seq != SPA_ID_INVALID) {
|
|
|
|
|
pw_log_debug("remove pending %d", p->seq);
|
|
|
|
|
spa_list_remove(&p->link);
|
|
|
|
|
p->seq = SPA_ID_INVALID;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-18 12:31:36 +01:00
|
|
|
static int
|
2019-01-10 10:08:14 +01:00
|
|
|
on_core_info (void *data, const struct pw_core_info *info)
|
2015-07-17 17:01:46 +02:00
|
|
|
{
|
2019-01-10 10:08:14 +01:00
|
|
|
GstPipeWireDeviceProvider *self = data;
|
|
|
|
|
GstDeviceProvider *provider = (GstDeviceProvider*)self;
|
2015-07-17 17:01:46 +02:00
|
|
|
const gchar *value;
|
|
|
|
|
|
2016-12-22 17:08:19 +01:00
|
|
|
if (info == NULL || info->props == NULL)
|
2019-02-18 12:31:36 +01:00
|
|
|
return -EINVAL;
|
2016-12-22 17:08:19 +01:00
|
|
|
|
2017-01-20 15:53:03 +01:00
|
|
|
value = spa_dict_lookup (info->props, "monitors");
|
2015-07-17 17:01:46 +02:00
|
|
|
if (value) {
|
2017-01-20 15:53:03 +01:00
|
|
|
gchar **monitors = g_strsplit (value, ",", -1);
|
2015-07-17 17:01:46 +02:00
|
|
|
gint i;
|
|
|
|
|
|
2016-01-07 12:15:57 +01:00
|
|
|
GST_DEBUG_OBJECT (provider, "have hidden providers: %s", value);
|
2015-07-17 17:01:46 +02:00
|
|
|
|
2017-01-20 15:53:03 +01:00
|
|
|
for (i = 0; monitors[i]; i++) {
|
|
|
|
|
if (strcmp (monitors[i], "v4l2") == 0)
|
|
|
|
|
gst_device_provider_hide_provider (provider, "v4l2deviceprovider");
|
|
|
|
|
else if (strcmp (monitors[i], "alsa") == 0)
|
|
|
|
|
gst_device_provider_hide_provider (provider, "pulsedeviceprovider");
|
2015-07-17 17:01:46 +02:00
|
|
|
}
|
2017-01-20 15:53:03 +01:00
|
|
|
g_strfreev (monitors);
|
2015-07-17 17:01:46 +02:00
|
|
|
}
|
2019-02-18 12:31:36 +01:00
|
|
|
return 0;
|
2015-07-17 17:01:46 +02:00
|
|
|
}
|
|
|
|
|
|
2019-02-18 12:31:36 +01:00
|
|
|
static int
|
|
|
|
|
on_core_done (void *data, uint32_t id, uint32_t seq)
|
2017-07-11 12:24:03 +02:00
|
|
|
{
|
2017-08-04 10:18:54 +02:00
|
|
|
GstPipeWireDeviceProvider *self = data;
|
2018-08-03 17:42:49 +02:00
|
|
|
struct pending *p, *t;
|
|
|
|
|
|
|
|
|
|
spa_list_for_each_safe(p, t, &self->pending, link) {
|
|
|
|
|
if (p->seq == seq) {
|
|
|
|
|
remove_pending(p);
|
|
|
|
|
if (p->callback)
|
|
|
|
|
p->callback(p->data);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pw_log_debug("check %d %d", seq, self->seq);
|
|
|
|
|
if (seq == self->seq) {
|
2017-07-11 12:24:03 +02:00
|
|
|
self->end = true;
|
2017-08-23 10:45:08 +02:00
|
|
|
if (self->main_loop)
|
|
|
|
|
pw_thread_loop_signal (self->main_loop, FALSE);
|
|
|
|
|
}
|
2019-02-18 12:31:36 +01:00
|
|
|
return 0;
|
2017-07-11 12:24:03 +02:00
|
|
|
}
|
|
|
|
|
|
2019-01-10 10:08:14 +01:00
|
|
|
static const struct pw_core_proxy_events core_events = {
|
|
|
|
|
PW_VERSION_CORE_EVENTS,
|
|
|
|
|
.info = on_core_info,
|
|
|
|
|
.done = on_core_done,
|
|
|
|
|
};
|
|
|
|
|
|
2017-08-04 10:18:54 +02:00
|
|
|
static void
|
|
|
|
|
on_state_changed (void *data, enum pw_remote_state old, enum pw_remote_state state, const char *error)
|
|
|
|
|
{
|
2019-01-10 10:08:14 +01:00
|
|
|
struct remote_data *rd = data;
|
|
|
|
|
GstPipeWireDeviceProvider *self = rd->self;
|
2017-08-04 10:18:54 +02:00
|
|
|
|
|
|
|
|
GST_DEBUG ("got remote state %d", state);
|
|
|
|
|
|
|
|
|
|
switch (state) {
|
|
|
|
|
case PW_REMOTE_STATE_CONNECTING:
|
|
|
|
|
break;
|
|
|
|
|
case PW_REMOTE_STATE_UNCONNECTED:
|
|
|
|
|
case PW_REMOTE_STATE_CONNECTED:
|
2019-01-10 10:08:14 +01:00
|
|
|
self->core_proxy = pw_remote_get_core_proxy(self->remote);
|
|
|
|
|
pw_core_proxy_add_listener(self->core_proxy, &rd->core_listener, &core_events, self);
|
2017-08-04 10:18:54 +02:00
|
|
|
break;
|
|
|
|
|
case PW_REMOTE_STATE_ERROR:
|
|
|
|
|
GST_ERROR_OBJECT (self, "remote error: %s", error);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2017-09-19 13:16:22 +02:00
|
|
|
if (self->main_loop)
|
|
|
|
|
pw_thread_loop_signal (self->main_loop, FALSE);
|
2017-08-04 10:18:54 +02:00
|
|
|
}
|
|
|
|
|
|
2019-02-18 12:31:36 +01:00
|
|
|
static int port_event_info(void *data, const struct pw_port_info *info)
|
2018-08-03 17:42:49 +02:00
|
|
|
{
|
|
|
|
|
struct port_data *port_data = data;
|
2018-08-13 15:20:25 +02:00
|
|
|
pw_log_debug("%p", port_data);
|
2019-02-18 12:31:36 +01:00
|
|
|
return 0;
|
2018-08-03 17:42:49 +02:00
|
|
|
}
|
2017-08-04 10:18:54 +02:00
|
|
|
|
2019-02-25 12:29:57 +01:00
|
|
|
static int port_event_param(void *data, uint32_t seq, uint32_t id,
|
|
|
|
|
uint32_t index, uint32_t next, const struct spa_pod *param)
|
2018-08-03 17:42:49 +02:00
|
|
|
{
|
|
|
|
|
struct port_data *port_data = data;
|
|
|
|
|
struct node_data *node_data = port_data->node_data;
|
|
|
|
|
GstCaps *c1;
|
2017-07-13 15:21:52 +02:00
|
|
|
|
2018-08-13 15:20:25 +02:00
|
|
|
pw_log_debug("%p", port_data);
|
|
|
|
|
|
2018-08-23 17:47:57 +02:00
|
|
|
c1 = gst_caps_from_format (param);
|
2018-08-03 17:42:49 +02:00
|
|
|
if (c1 && node_data->caps)
|
|
|
|
|
gst_caps_append (node_data->caps, c1);
|
2019-02-18 12:31:36 +01:00
|
|
|
return 0;
|
2018-08-03 17:42:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct pw_port_proxy_events port_events = {
|
|
|
|
|
PW_VERSION_PORT_PROXY_EVENTS,
|
|
|
|
|
.info = port_event_info,
|
|
|
|
|
.param = port_event_param
|
2017-08-04 10:18:54 +02:00
|
|
|
};
|
|
|
|
|
|
2019-02-18 12:31:36 +01:00
|
|
|
static int node_event_info(void *data, const struct pw_node_info *info)
|
2017-07-11 12:24:03 +02:00
|
|
|
{
|
2017-08-04 10:18:54 +02:00
|
|
|
struct node_data *node_data = data;
|
2018-08-13 15:20:25 +02:00
|
|
|
pw_log_debug("%p", node_data);
|
2018-08-03 17:42:49 +02:00
|
|
|
node_data->info = pw_node_info_update(node_data->info, info);
|
2019-02-18 12:31:36 +01:00
|
|
|
return 0;
|
2017-07-11 12:24:03 +02:00
|
|
|
}
|
|
|
|
|
|
2017-08-04 16:49:13 +02:00
|
|
|
static const struct pw_node_proxy_events node_events = {
|
|
|
|
|
PW_VERSION_NODE_PROXY_EVENTS,
|
2017-08-04 10:18:54 +02:00
|
|
|
.info = node_event_info
|
2017-07-11 12:24:03 +02:00
|
|
|
};
|
|
|
|
|
|
2018-08-13 15:20:25 +02:00
|
|
|
static void
|
|
|
|
|
destroy_node_proxy (void *data)
|
|
|
|
|
{
|
|
|
|
|
struct node_data *nd = data;
|
|
|
|
|
GstPipeWireDeviceProvider *self = nd->self;
|
|
|
|
|
GstDeviceProvider *provider = GST_DEVICE_PROVIDER (self);
|
|
|
|
|
|
|
|
|
|
pw_log_debug("destroy %p", nd);
|
|
|
|
|
|
|
|
|
|
remove_pending(&nd->pending);
|
|
|
|
|
|
|
|
|
|
if (nd->dev != NULL) {
|
|
|
|
|
gst_device_provider_device_remove (provider, GST_DEVICE (nd->dev));
|
|
|
|
|
}
|
|
|
|
|
if (nd->caps)
|
|
|
|
|
gst_caps_unref(nd->caps);
|
|
|
|
|
if (nd->info)
|
|
|
|
|
pw_node_info_free(nd->info);
|
|
|
|
|
|
|
|
|
|
spa_list_remove(&nd->link);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct pw_proxy_events proxy_node_events = {
|
|
|
|
|
PW_VERSION_PROXY_EVENTS,
|
|
|
|
|
.destroy = destroy_node_proxy,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
destroy_port_proxy (void *data)
|
|
|
|
|
{
|
|
|
|
|
struct port_data *pd = data;
|
|
|
|
|
pw_log_debug("destroy %p", pd);
|
|
|
|
|
remove_pending(&pd->pending);
|
|
|
|
|
spa_list_remove(&pd->link);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct pw_proxy_events proxy_port_events = {
|
|
|
|
|
PW_VERSION_PROXY_EVENTS,
|
|
|
|
|
.destroy = destroy_port_proxy,
|
|
|
|
|
};
|
2017-07-13 15:21:52 +02:00
|
|
|
|
2019-02-18 12:31:36 +01:00
|
|
|
static int registry_event_global(void *data, uint32_t id, uint32_t parent_id, uint32_t permissions,
|
|
|
|
|
uint32_t type, uint32_t version,
|
|
|
|
|
const struct spa_dict *props)
|
2017-07-11 12:24:03 +02:00
|
|
|
{
|
2018-08-13 15:20:25 +02:00
|
|
|
struct remote_data *rd = data;
|
2017-08-04 10:18:54 +02:00
|
|
|
GstPipeWireDeviceProvider *self = rd->self;
|
|
|
|
|
struct node_data *nd;
|
2017-07-11 12:24:03 +02:00
|
|
|
|
2018-08-27 15:03:11 +02:00
|
|
|
if (type == PW_TYPE_INTERFACE_Node) {
|
2018-08-03 17:42:49 +02:00
|
|
|
struct pw_node_proxy *node;
|
|
|
|
|
|
|
|
|
|
node = pw_registry_proxy_bind(rd->registry,
|
2018-08-27 15:03:11 +02:00
|
|
|
id, PW_TYPE_INTERFACE_Node,
|
2018-08-03 17:42:49 +02:00
|
|
|
PW_VERSION_NODE, sizeof(*nd));
|
|
|
|
|
if (node == NULL)
|
|
|
|
|
goto no_mem;
|
|
|
|
|
|
|
|
|
|
nd = pw_proxy_get_user_data((struct pw_proxy*)node);
|
|
|
|
|
nd->self = self;
|
|
|
|
|
nd->proxy = node;
|
|
|
|
|
nd->id = id;
|
|
|
|
|
nd->parent_id = parent_id;
|
|
|
|
|
nd->caps = gst_caps_new_empty ();
|
|
|
|
|
spa_list_append(&rd->nodes, &nd->link);
|
|
|
|
|
pw_node_proxy_add_listener(node, &nd->node_listener, &node_events, nd);
|
2018-08-13 15:20:25 +02:00
|
|
|
pw_proxy_add_listener((struct pw_proxy*)node, &nd->proxy_listener, &proxy_node_events, nd);
|
|
|
|
|
add_pending(self, &nd->pending, NULL, NULL);
|
2018-08-03 17:42:49 +02:00
|
|
|
}
|
2018-08-27 15:03:11 +02:00
|
|
|
else if (type == PW_TYPE_INTERFACE_Port) {
|
2018-08-03 17:42:49 +02:00
|
|
|
struct pw_port_proxy *port;
|
|
|
|
|
struct port_data *pd;
|
|
|
|
|
|
|
|
|
|
if ((nd = find_node_data(rd, parent_id)) == NULL)
|
2019-02-18 12:31:36 +01:00
|
|
|
return -EINVAL;
|
2018-08-03 17:42:49 +02:00
|
|
|
|
|
|
|
|
port = pw_registry_proxy_bind(rd->registry,
|
2018-08-27 15:03:11 +02:00
|
|
|
id, PW_TYPE_INTERFACE_Port,
|
2018-08-03 17:42:49 +02:00
|
|
|
PW_VERSION_PORT, sizeof(*pd));
|
|
|
|
|
if (port == NULL)
|
|
|
|
|
goto no_mem;
|
|
|
|
|
|
|
|
|
|
pd = pw_proxy_get_user_data((struct pw_proxy*)port);
|
|
|
|
|
pd->node_data = nd;
|
|
|
|
|
pd->proxy = port;
|
|
|
|
|
pd->id = id;
|
|
|
|
|
spa_list_append(&rd->ports, &pd->link);
|
|
|
|
|
pw_port_proxy_add_listener(port, &pd->port_listener, &port_events, pd);
|
2018-08-13 15:20:25 +02:00
|
|
|
pw_proxy_add_listener((struct pw_proxy*)port, &pd->proxy_listener, &proxy_port_events, pd);
|
2018-11-28 17:31:00 +01:00
|
|
|
pw_port_proxy_enum_params((struct pw_port_proxy*)port,
|
|
|
|
|
SPA_PARAM_EnumFormat, 0, 0, NULL);
|
|
|
|
|
add_pending(self, &pd->pending, do_add_node, pd);
|
2018-08-03 17:42:49 +02:00
|
|
|
}
|
2017-08-04 10:18:54 +02:00
|
|
|
|
2019-02-18 12:31:36 +01:00
|
|
|
return 0;
|
2017-07-11 12:24:03 +02:00
|
|
|
|
|
|
|
|
no_mem:
|
|
|
|
|
GST_ERROR_OBJECT(self, "failed to create proxy");
|
2019-02-18 12:31:36 +01:00
|
|
|
return -ENOMEM;
|
2017-07-11 12:24:03 +02:00
|
|
|
}
|
|
|
|
|
|
2019-02-18 12:31:36 +01:00
|
|
|
static int registry_event_global_remove(void *data, uint32_t id)
|
2017-07-11 12:24:03 +02:00
|
|
|
{
|
2019-02-18 12:31:36 +01:00
|
|
|
return 0;
|
2017-07-11 12:24:03 +02:00
|
|
|
}
|
|
|
|
|
|
2017-08-04 16:49:13 +02:00
|
|
|
static const struct pw_registry_proxy_events registry_events = {
|
|
|
|
|
PW_VERSION_REGISTRY_PROXY_EVENTS,
|
2017-08-04 10:18:54 +02:00
|
|
|
.global = registry_event_global,
|
|
|
|
|
.global_remove = registry_event_global_remove,
|
|
|
|
|
};
|
|
|
|
|
|
2017-08-04 16:49:13 +02:00
|
|
|
static const struct pw_remote_events remote_events = {
|
|
|
|
|
PW_VERSION_REMOTE_EVENTS,
|
|
|
|
|
.state_changed = on_state_changed,
|
2017-07-11 12:24:03 +02:00
|
|
|
};
|
|
|
|
|
|
2019-01-10 10:08:14 +01:00
|
|
|
|
2015-07-08 17:40:37 +02:00
|
|
|
static GList *
|
2017-05-23 19:15:33 +02:00
|
|
|
gst_pipewire_device_provider_probe (GstDeviceProvider * provider)
|
2015-07-08 17:40:37 +02:00
|
|
|
{
|
2017-05-23 19:15:33 +02:00
|
|
|
GstPipeWireDeviceProvider *self = GST_PIPEWIRE_DEVICE_PROVIDER (provider);
|
|
|
|
|
struct pw_loop *l = NULL;
|
2017-07-11 12:24:03 +02:00
|
|
|
struct pw_core *c = NULL;
|
|
|
|
|
struct pw_remote *r = NULL;
|
2018-08-13 15:20:25 +02:00
|
|
|
struct remote_data *data;
|
2017-08-08 16:56:29 +02:00
|
|
|
struct spa_hook listener;
|
2015-07-08 17:40:37 +02:00
|
|
|
|
2015-07-17 17:01:46 +02:00
|
|
|
GST_DEBUG_OBJECT (self, "starting probe");
|
|
|
|
|
|
2017-08-08 18:22:44 +02:00
|
|
|
if (!(l = pw_loop_new (NULL)))
|
2015-07-08 17:40:37 +02:00
|
|
|
return NULL;
|
|
|
|
|
|
2019-01-08 17:30:12 +01:00
|
|
|
if (!(c = pw_core_new (l, NULL, 0)))
|
2017-07-11 12:24:03 +02:00
|
|
|
return NULL;
|
|
|
|
|
|
2018-08-13 15:20:25 +02:00
|
|
|
if (!(r = pw_remote_new (c, NULL, sizeof(*data))))
|
2015-07-08 17:40:37 +02:00
|
|
|
goto failed;
|
|
|
|
|
|
2018-08-13 15:20:25 +02:00
|
|
|
data = pw_remote_get_user_data(r);
|
|
|
|
|
data->self = self;
|
|
|
|
|
spa_list_init(&data->nodes);
|
|
|
|
|
spa_list_init(&data->ports);
|
|
|
|
|
|
2018-08-03 17:42:49 +02:00
|
|
|
spa_list_init(&self->pending);
|
2019-01-10 10:08:14 +01:00
|
|
|
pw_remote_add_listener(r, &listener, &remote_events, data);
|
2017-07-11 12:24:03 +02:00
|
|
|
|
2019-01-10 10:08:14 +01:00
|
|
|
if (pw_remote_connect (r) < 0)
|
|
|
|
|
goto failed;
|
2015-07-08 17:40:37 +02:00
|
|
|
|
|
|
|
|
for (;;) {
|
2017-07-11 12:24:03 +02:00
|
|
|
enum pw_remote_state state;
|
2017-08-04 10:18:54 +02:00
|
|
|
const char *error = NULL;
|
2015-07-08 17:40:37 +02:00
|
|
|
|
2017-08-04 10:18:54 +02:00
|
|
|
state = pw_remote_get_state(r, &error);
|
2015-07-08 17:40:37 +02:00
|
|
|
|
|
|
|
|
if (state <= 0) {
|
2017-08-04 10:18:54 +02:00
|
|
|
GST_ERROR_OBJECT (self, "Failed to connect: %s", error);
|
2015-07-08 17:40:37 +02:00
|
|
|
goto failed;
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-11 12:24:03 +02:00
|
|
|
if (state == PW_REMOTE_STATE_CONNECTED)
|
2015-07-08 17:40:37 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* Wait until something happens */
|
2017-05-23 19:15:33 +02:00
|
|
|
pw_loop_iterate (l, -1);
|
2015-07-08 17:40:37 +02:00
|
|
|
}
|
|
|
|
|
GST_DEBUG_OBJECT (self, "connected");
|
|
|
|
|
|
2017-07-11 12:24:03 +02:00
|
|
|
self->end = FALSE;
|
|
|
|
|
self->list_only = TRUE;
|
|
|
|
|
self->devices = NULL;
|
2015-07-17 17:01:46 +02:00
|
|
|
|
2018-08-23 17:47:57 +02:00
|
|
|
data->registry = pw_core_proxy_get_registry(self->core_proxy,
|
2018-08-27 15:03:11 +02:00
|
|
|
PW_TYPE_INTERFACE_Registry, PW_VERSION_REGISTRY, 0);
|
2018-08-13 15:20:25 +02:00
|
|
|
pw_registry_proxy_add_listener(data->registry, &data->registry_listener, ®istry_events, data);
|
2019-02-25 12:29:57 +01:00
|
|
|
pw_core_proxy_sync(self->core_proxy, 0, self->seq++);
|
2015-07-17 17:01:46 +02:00
|
|
|
|
2015-07-08 17:40:37 +02:00
|
|
|
for (;;) {
|
2017-08-04 10:18:54 +02:00
|
|
|
if (pw_remote_get_state(r, NULL) <= 0)
|
2015-07-08 17:40:37 +02:00
|
|
|
break;
|
2017-07-11 12:24:03 +02:00
|
|
|
if (self->end)
|
2015-07-08 17:40:37 +02:00
|
|
|
break;
|
2017-05-23 19:15:33 +02:00
|
|
|
pw_loop_iterate (l, -1);
|
2015-07-08 17:40:37 +02:00
|
|
|
}
|
|
|
|
|
|
2017-07-11 12:24:03 +02:00
|
|
|
pw_remote_disconnect (r);
|
|
|
|
|
pw_remote_destroy (r);
|
|
|
|
|
pw_core_destroy (c);
|
2017-05-23 19:15:33 +02:00
|
|
|
pw_loop_destroy (l);
|
2015-07-08 17:40:37 +02:00
|
|
|
|
2017-07-11 12:24:03 +02:00
|
|
|
return *self->devices;
|
2015-07-08 17:40:37 +02:00
|
|
|
|
|
|
|
|
failed:
|
2017-05-23 19:15:33 +02:00
|
|
|
pw_loop_destroy (l);
|
2015-07-08 17:40:37 +02:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
2017-05-23 19:15:33 +02:00
|
|
|
gst_pipewire_device_provider_start (GstDeviceProvider * provider)
|
2015-07-08 17:40:37 +02:00
|
|
|
{
|
2017-05-23 19:15:33 +02:00
|
|
|
GstPipeWireDeviceProvider *self = GST_PIPEWIRE_DEVICE_PROVIDER (provider);
|
2018-08-13 15:20:25 +02:00
|
|
|
struct remote_data *data;
|
2015-07-08 17:40:37 +02:00
|
|
|
|
2015-07-17 17:01:46 +02:00
|
|
|
GST_DEBUG_OBJECT (self, "starting provider");
|
|
|
|
|
|
2017-08-08 18:22:44 +02:00
|
|
|
self->loop = pw_loop_new (NULL);
|
2017-07-11 12:24:03 +02:00
|
|
|
self->list_only = FALSE;
|
2018-08-03 17:42:49 +02:00
|
|
|
spa_list_init(&self->pending);
|
2015-07-08 17:40:37 +02:00
|
|
|
|
2017-06-01 19:25:01 +02:00
|
|
|
if (!(self->main_loop = pw_thread_loop_new (self->loop, "pipewire-device-monitor"))) {
|
2017-05-23 19:15:33 +02:00
|
|
|
GST_ERROR_OBJECT (self, "Could not create PipeWire mainloop");
|
2016-11-24 17:00:42 +01:00
|
|
|
goto failed_main_loop;
|
2015-07-08 17:40:37 +02:00
|
|
|
}
|
2015-07-09 11:35:18 +02:00
|
|
|
|
2019-01-08 17:30:12 +01:00
|
|
|
if (!(self->core = pw_core_new (self->loop, NULL, 0))) {
|
2017-07-11 12:24:03 +02:00
|
|
|
GST_ERROR_OBJECT (self, "Could not create PipeWire core");
|
|
|
|
|
goto failed_core;
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-13 09:41:41 +01:00
|
|
|
if (pw_thread_loop_start (self->main_loop) < 0) {
|
2017-05-23 19:15:33 +02:00
|
|
|
GST_ERROR_OBJECT (self, "Could not start PipeWire mainloop");
|
2016-11-24 17:00:42 +01:00
|
|
|
goto failed_start;
|
2015-07-08 17:40:37 +02:00
|
|
|
}
|
|
|
|
|
|
2017-06-01 19:25:01 +02:00
|
|
|
pw_thread_loop_lock (self->main_loop);
|
2015-07-08 17:40:37 +02:00
|
|
|
|
2018-08-13 15:20:25 +02:00
|
|
|
if (!(self->remote = pw_remote_new (self->core, NULL, sizeof(*data)))) {
|
2017-07-11 12:24:03 +02:00
|
|
|
GST_ERROR_OBJECT (self, "Failed to create remote");
|
|
|
|
|
goto failed_remote;
|
2015-07-08 17:40:37 +02:00
|
|
|
}
|
2018-08-13 15:20:25 +02:00
|
|
|
data = pw_remote_get_user_data(self->remote);
|
|
|
|
|
data->self = self;
|
|
|
|
|
spa_list_init(&data->nodes);
|
|
|
|
|
spa_list_init(&data->ports);
|
2019-01-10 10:08:14 +01:00
|
|
|
pw_remote_add_listener (self->remote, &self->remote_listener, &remote_events, data);
|
|
|
|
|
|
|
|
|
|
if (pw_remote_connect (self->remote) < 0)
|
|
|
|
|
goto not_running;
|
2015-07-08 17:40:37 +02:00
|
|
|
|
2015-07-17 17:01:46 +02:00
|
|
|
for (;;) {
|
2017-07-11 12:24:03 +02:00
|
|
|
enum pw_remote_state state;
|
2017-08-04 10:18:54 +02:00
|
|
|
const char *error = NULL;
|
2015-07-17 17:01:46 +02:00
|
|
|
|
2017-08-04 10:18:54 +02:00
|
|
|
state = pw_remote_get_state(self->remote, &error);
|
2015-07-17 17:01:46 +02:00
|
|
|
|
|
|
|
|
if (state <= 0) {
|
2017-08-04 10:18:54 +02:00
|
|
|
GST_WARNING_OBJECT (self, "Failed to connect: %s", error);
|
2015-07-17 17:01:46 +02:00
|
|
|
goto not_running;
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-11 12:24:03 +02:00
|
|
|
if (state == PW_REMOTE_STATE_CONNECTED)
|
2015-07-17 17:01:46 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* Wait until something happens */
|
2017-06-01 19:25:01 +02:00
|
|
|
pw_thread_loop_wait (self->main_loop);
|
2015-07-17 17:01:46 +02:00
|
|
|
}
|
|
|
|
|
GST_DEBUG_OBJECT (self, "connected");
|
2017-07-11 12:24:03 +02:00
|
|
|
|
2018-08-23 17:47:57 +02:00
|
|
|
self->registry = pw_core_proxy_get_registry(self->core_proxy,
|
2018-08-27 15:03:11 +02:00
|
|
|
PW_TYPE_INTERFACE_Registry, PW_VERSION_REGISTRY, 0);
|
2017-08-04 10:18:54 +02:00
|
|
|
|
|
|
|
|
data->registry = self->registry;
|
|
|
|
|
|
|
|
|
|
pw_registry_proxy_add_listener(self->registry, &data->registry_listener, ®istry_events, data);
|
2019-02-25 12:29:57 +01:00
|
|
|
pw_core_proxy_sync(self->core_proxy, 0, self->seq++);
|
2017-07-11 12:24:03 +02:00
|
|
|
|
2017-08-23 10:45:08 +02:00
|
|
|
for (;;) {
|
|
|
|
|
if (self->end)
|
|
|
|
|
break;
|
|
|
|
|
pw_thread_loop_wait (self->main_loop);
|
|
|
|
|
}
|
|
|
|
|
GST_DEBUG_OBJECT (self, "started");
|
|
|
|
|
|
2017-06-01 19:25:01 +02:00
|
|
|
pw_thread_loop_unlock (self->main_loop);
|
2015-07-08 17:40:37 +02:00
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
2015-07-17 17:01:46 +02:00
|
|
|
not_running:
|
2017-07-11 12:24:03 +02:00
|
|
|
pw_remote_destroy (self->remote);
|
|
|
|
|
self->remote = NULL;
|
|
|
|
|
failed_remote:
|
2017-06-01 19:25:01 +02:00
|
|
|
pw_thread_loop_unlock (self->main_loop);
|
2016-11-24 17:00:42 +01:00
|
|
|
failed_start:
|
2017-07-11 12:24:03 +02:00
|
|
|
pw_core_destroy (self->core);
|
|
|
|
|
self->core = NULL;
|
|
|
|
|
failed_core:
|
2017-06-01 19:25:01 +02:00
|
|
|
pw_thread_loop_destroy (self->main_loop);
|
2016-11-24 17:00:42 +01:00
|
|
|
self->main_loop = NULL;
|
|
|
|
|
failed_main_loop:
|
2017-05-23 19:15:33 +02:00
|
|
|
pw_loop_destroy (self->loop);
|
2016-11-24 17:00:42 +01:00
|
|
|
self->loop = NULL;
|
2017-02-01 08:58:21 +01:00
|
|
|
return TRUE;
|
2015-07-08 17:40:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2017-05-23 19:15:33 +02:00
|
|
|
gst_pipewire_device_provider_stop (GstDeviceProvider * provider)
|
2015-07-08 17:40:37 +02:00
|
|
|
{
|
2017-05-23 19:15:33 +02:00
|
|
|
GstPipeWireDeviceProvider *self = GST_PIPEWIRE_DEVICE_PROVIDER (provider);
|
2015-07-08 17:40:37 +02:00
|
|
|
|
2017-08-08 18:22:44 +02:00
|
|
|
GST_DEBUG_OBJECT (self, "stopping provider");
|
|
|
|
|
|
2017-07-11 12:24:03 +02:00
|
|
|
if (self->remote) {
|
|
|
|
|
pw_remote_disconnect (self->remote);
|
|
|
|
|
pw_remote_destroy (self->remote);
|
|
|
|
|
self->remote = NULL;
|
2016-11-24 17:00:42 +01:00
|
|
|
}
|
2017-07-11 20:54:10 +02:00
|
|
|
if (self->core) {
|
|
|
|
|
pw_core_destroy (self->core);
|
|
|
|
|
self->core = NULL;
|
|
|
|
|
}
|
2016-11-24 17:00:42 +01:00
|
|
|
if (self->main_loop) {
|
2017-06-01 19:25:01 +02:00
|
|
|
pw_thread_loop_destroy (self->main_loop);
|
2016-11-24 17:00:42 +01:00
|
|
|
self->main_loop = NULL;
|
2015-07-08 17:40:37 +02:00
|
|
|
}
|
2015-07-17 17:01:46 +02:00
|
|
|
if (self->loop) {
|
2017-05-23 19:15:33 +02:00
|
|
|
pw_loop_destroy (self->loop);
|
2016-11-24 17:00:42 +01:00
|
|
|
self->loop = NULL;
|
2015-07-17 17:01:46 +02:00
|
|
|
}
|
2015-07-08 17:40:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2017-05-23 19:15:33 +02:00
|
|
|
gst_pipewire_device_provider_set_property (GObject * object,
|
2015-07-09 17:34:01 +02:00
|
|
|
guint prop_id, const GValue * value, GParamSpec * pspec)
|
2015-07-08 17:40:37 +02:00
|
|
|
{
|
2017-05-23 19:15:33 +02:00
|
|
|
GstPipeWireDeviceProvider *self = GST_PIPEWIRE_DEVICE_PROVIDER (object);
|
2015-07-08 17:40:37 +02:00
|
|
|
|
2015-07-09 17:34:01 +02:00
|
|
|
switch (prop_id) {
|
|
|
|
|
case PROP_CLIENT_NAME:
|
|
|
|
|
g_free (self->client_name);
|
|
|
|
|
if (!g_value_get_string (value)) {
|
|
|
|
|
GST_WARNING_OBJECT (self,
|
2017-05-23 19:15:33 +02:00
|
|
|
"Empty PipeWire client name not allowed. "
|
2015-07-09 17:34:01 +02:00
|
|
|
"Resetting to default value");
|
2018-09-19 13:38:39 +02:00
|
|
|
self->client_name = g_strdup(pw_get_client_name ());
|
2015-07-09 17:34:01 +02:00
|
|
|
} else
|
|
|
|
|
self->client_name = g_value_dup_string (value);
|
2015-07-08 17:40:37 +02:00
|
|
|
break;
|
|
|
|
|
default:
|
2015-07-09 17:34:01 +02:00
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
2015-07-08 17:40:37 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2017-05-23 19:15:33 +02:00
|
|
|
gst_pipewire_device_provider_get_property (GObject * object,
|
2015-07-09 17:34:01 +02:00
|
|
|
guint prop_id, GValue * value, GParamSpec * pspec)
|
2015-07-08 17:40:37 +02:00
|
|
|
{
|
2017-05-23 19:15:33 +02:00
|
|
|
GstPipeWireDeviceProvider *self = GST_PIPEWIRE_DEVICE_PROVIDER (object);
|
2015-07-08 17:40:37 +02:00
|
|
|
|
|
|
|
|
switch (prop_id) {
|
2015-07-09 17:34:01 +02:00
|
|
|
case PROP_CLIENT_NAME:
|
|
|
|
|
g_value_set_string (value, self->client_name);
|
2015-07-08 17:40:37 +02:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-09 17:34:01 +02:00
|
|
|
static void
|
2017-05-23 19:15:33 +02:00
|
|
|
gst_pipewire_device_provider_finalize (GObject * object)
|
2015-07-09 17:34:01 +02:00
|
|
|
{
|
2017-05-23 19:15:33 +02:00
|
|
|
GstPipeWireDeviceProvider *self = GST_PIPEWIRE_DEVICE_PROVIDER (object);
|
2015-07-09 17:34:01 +02:00
|
|
|
|
|
|
|
|
g_free (self->client_name);
|
|
|
|
|
|
2017-05-23 19:15:33 +02:00
|
|
|
G_OBJECT_CLASS (gst_pipewire_device_provider_parent_class)->finalize (object);
|
2015-07-09 17:34:01 +02:00
|
|
|
}
|
2015-07-08 17:40:37 +02:00
|
|
|
|
|
|
|
|
static void
|
2017-05-23 19:15:33 +02:00
|
|
|
gst_pipewire_device_provider_class_init (GstPipeWireDeviceProviderClass * klass)
|
2015-07-08 17:40:37 +02:00
|
|
|
{
|
2015-07-09 17:34:01 +02:00
|
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
|
|
|
GstDeviceProviderClass *dm_class = GST_DEVICE_PROVIDER_CLASS (klass);
|
2015-07-08 17:40:37 +02:00
|
|
|
|
2017-05-23 19:15:33 +02:00
|
|
|
gobject_class->set_property = gst_pipewire_device_provider_set_property;
|
|
|
|
|
gobject_class->get_property = gst_pipewire_device_provider_get_property;
|
|
|
|
|
gobject_class->finalize = gst_pipewire_device_provider_finalize;
|
2015-07-08 17:40:37 +02:00
|
|
|
|
2017-05-23 19:15:33 +02:00
|
|
|
dm_class->probe = gst_pipewire_device_provider_probe;
|
|
|
|
|
dm_class->start = gst_pipewire_device_provider_start;
|
|
|
|
|
dm_class->stop = gst_pipewire_device_provider_stop;
|
2015-07-09 17:34:01 +02:00
|
|
|
|
|
|
|
|
g_object_class_install_property (gobject_class,
|
|
|
|
|
PROP_CLIENT_NAME,
|
|
|
|
|
g_param_spec_string ("client-name", "Client Name",
|
2018-09-19 13:38:39 +02:00
|
|
|
"The PipeWire client_name_to_use", pw_get_client_name (),
|
2015-07-09 17:34:01 +02:00
|
|
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
|
|
|
|
|
GST_PARAM_MUTABLE_READY));
|
|
|
|
|
|
|
|
|
|
gst_device_provider_class_set_static_metadata (dm_class,
|
2017-05-23 19:15:33 +02:00
|
|
|
"PipeWire Device Provider", "Sink/Source/Audio/Video",
|
|
|
|
|
"List and provide PipeWire source and sink devices",
|
2015-07-09 17:34:01 +02:00
|
|
|
"Wim Taymans <wim.taymans@gmail.com>");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2017-05-23 19:15:33 +02:00
|
|
|
gst_pipewire_device_provider_init (GstPipeWireDeviceProvider * self)
|
2015-07-09 17:34:01 +02:00
|
|
|
{
|
2018-09-19 13:38:39 +02:00
|
|
|
self->client_name = g_strdup(pw_get_client_name ());
|
2015-07-08 17:40:37 +02:00
|
|
|
}
|