2018-08-02 11:25:27 +02:00
|
|
|
/* PipeWire
|
|
|
|
|
*
|
2018-11-05 17:48:52 +01:00
|
|
|
* Copyright © 2018 Wim Taymans
|
2018-08-02 11:25:27 +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:
|
2018-08-02 11:25:27 +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.
|
|
|
|
|
*
|
|
|
|
|
* 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.
|
2018-08-02 11:25:27 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <math.h>
|
|
|
|
|
#include <time.h>
|
|
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
|
|
#include <spa/node/node.h>
|
|
|
|
|
#include <spa/utils/hook.h>
|
|
|
|
|
#include <spa/param/audio/format-utils.h>
|
2018-10-18 15:16:59 +02:00
|
|
|
#include <spa/param/props.h>
|
2018-11-16 16:41:13 +01:00
|
|
|
#include <spa/debug/pod.h>
|
2019-09-30 21:23:29 +02:00
|
|
|
#include <spa/support/dbus.h>
|
2019-12-11 10:57:10 +01:00
|
|
|
#include <spa/monitor/device.h>
|
2018-08-02 11:25:27 +02:00
|
|
|
|
2019-01-14 12:58:23 +01:00
|
|
|
#include "pipewire/pipewire.h"
|
2018-08-02 11:25:27 +02:00
|
|
|
#include "pipewire/private.h"
|
2019-11-04 17:27:41 +01:00
|
|
|
#include "extensions/session-manager.h"
|
2018-08-02 11:25:27 +02:00
|
|
|
|
2019-09-30 21:23:29 +02:00
|
|
|
#include <dbus/dbus.h>
|
|
|
|
|
|
2019-11-14 18:35:29 +01:00
|
|
|
#include "media-session.h"
|
|
|
|
|
|
2018-09-11 15:25:35 +02:00
|
|
|
#define NAME "media-session"
|
|
|
|
|
|
2019-11-26 12:53:28 +01:00
|
|
|
#define sm_object_emit(o,m,v,...) spa_hook_list_call(&(o)->hooks, struct sm_object_events, m, v, ##__VA_ARGS__)
|
|
|
|
|
|
|
|
|
|
#define sm_object_emit_update(s) sm_object_emit(s, update, 0)
|
|
|
|
|
|
2019-11-14 18:35:29 +01:00
|
|
|
#define sm_media_session_emit(s,m,v,...) spa_hook_list_call(&s->hooks, struct sm_media_session_events, m, v, ##__VA_ARGS__)
|
|
|
|
|
|
2019-11-26 12:53:28 +01:00
|
|
|
#define sm_media_session_emit_create(s,obj) sm_media_session_emit(s, create, 0, obj)
|
2019-11-14 18:35:29 +01:00
|
|
|
#define sm_media_session_emit_remove(s,obj) sm_media_session_emit(s, remove, 0, obj)
|
|
|
|
|
#define sm_media_session_emit_rescan(s,seq) sm_media_session_emit(s, rescan, 0, seq)
|
|
|
|
|
|
2019-11-20 16:18:46 +01:00
|
|
|
void * sm_stream_monitor_start(struct sm_media_session *sess);
|
|
|
|
|
void * sm_metadata_start(struct sm_media_session *sess);
|
|
|
|
|
void * sm_alsa_midi_start(struct sm_media_session *sess);
|
|
|
|
|
void * sm_v4l2_monitor_start(struct sm_media_session *sess);
|
|
|
|
|
void * sm_bluez5_monitor_start(struct sm_media_session *sess);
|
|
|
|
|
void * sm_alsa_monitor_start(struct sm_media_session *sess);
|
2019-11-28 11:13:53 +01:00
|
|
|
void * sm_alsa_endpoint_start(struct sm_media_session *sess);
|
2019-11-14 18:35:29 +01:00
|
|
|
int sm_policy_ep_start(struct sm_media_session *sess);
|
|
|
|
|
|
|
|
|
|
/** user data to add to an object */
|
|
|
|
|
struct data {
|
|
|
|
|
struct spa_list link;
|
|
|
|
|
const char *id;
|
|
|
|
|
size_t size;
|
|
|
|
|
};
|
2019-07-10 20:24:11 +02:00
|
|
|
|
2019-11-19 16:08:40 +01:00
|
|
|
struct param {
|
|
|
|
|
struct sm_param this;
|
|
|
|
|
};
|
|
|
|
|
|
2019-11-18 13:10:21 +01:00
|
|
|
struct sync {
|
|
|
|
|
struct spa_list link;
|
|
|
|
|
int seq;
|
|
|
|
|
void (*callback) (void *data);
|
|
|
|
|
void *data;
|
|
|
|
|
};
|
|
|
|
|
|
2018-08-02 11:25:27 +02:00
|
|
|
struct impl {
|
2019-11-14 18:35:29 +01:00
|
|
|
struct sm_media_session this;
|
2019-11-20 16:18:46 +01:00
|
|
|
uint32_t session_id;
|
|
|
|
|
|
|
|
|
|
struct pw_main_loop *loop;
|
|
|
|
|
struct spa_dbus *dbus;
|
2018-08-02 11:25:27 +02:00
|
|
|
|
2019-12-11 07:46:59 +01:00
|
|
|
struct pw_core *monitor_core;
|
2019-12-06 11:48:40 +01:00
|
|
|
struct spa_hook monitor_listener;
|
2018-09-11 15:25:35 +02:00
|
|
|
|
2019-12-11 07:46:59 +01:00
|
|
|
struct pw_core *policy_core;
|
2019-12-06 11:48:40 +01:00
|
|
|
struct spa_hook policy_listener;
|
2019-11-14 18:35:29 +01:00
|
|
|
|
2019-12-11 09:44:48 +01:00
|
|
|
struct pw_registry *registry;
|
2019-11-14 18:35:29 +01:00
|
|
|
struct spa_hook registry_listener;
|
|
|
|
|
|
|
|
|
|
struct pw_map globals;
|
2019-11-19 16:07:41 +01:00
|
|
|
struct spa_list global_list;
|
|
|
|
|
|
2019-11-14 18:35:29 +01:00
|
|
|
struct spa_hook_list hooks;
|
|
|
|
|
|
2019-12-11 16:31:58 +01:00
|
|
|
struct pw_client_session *client_session;
|
|
|
|
|
struct spa_hook proxy_client_session_listener;
|
2019-11-14 18:35:29 +01:00
|
|
|
struct spa_hook client_session_listener;
|
|
|
|
|
|
2019-11-15 17:13:45 +01:00
|
|
|
struct spa_list endpoint_link_list; /** list of struct endpoint_link */
|
|
|
|
|
struct pw_map endpoint_links; /** map of endpoint_link */
|
|
|
|
|
|
2019-11-18 13:10:21 +01:00
|
|
|
struct spa_list sync_list; /** list of struct sync */
|
2019-11-15 12:07:26 +01:00
|
|
|
int rescan_seq;
|
|
|
|
|
int last_seq;
|
2019-11-14 18:35:29 +01:00
|
|
|
};
|
|
|
|
|
|
2019-11-15 17:13:45 +01:00
|
|
|
struct endpoint_link {
|
|
|
|
|
uint32_t id;
|
|
|
|
|
|
|
|
|
|
struct pw_endpoint_link_info info;
|
|
|
|
|
|
|
|
|
|
struct impl *impl;
|
|
|
|
|
|
|
|
|
|
struct spa_list link; /**< link in struct impl endpoint_link_list */
|
|
|
|
|
struct spa_list link_list; /**< list of struct link */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct link {
|
|
|
|
|
struct pw_proxy *proxy; /**< proxy for link */
|
|
|
|
|
struct spa_hook listener; /**< proxy listener */
|
|
|
|
|
|
|
|
|
|
uint32_t output_node;
|
|
|
|
|
uint32_t output_port;
|
|
|
|
|
uint32_t input_node;
|
|
|
|
|
uint32_t input_port;
|
|
|
|
|
|
|
|
|
|
struct endpoint_link *endpoint_link;
|
|
|
|
|
struct spa_list link; /**< link in struct endpoint_link link_list */
|
|
|
|
|
};
|
|
|
|
|
|
2019-11-29 13:21:55 +01:00
|
|
|
struct object_info {
|
|
|
|
|
uint32_t type;
|
|
|
|
|
uint32_t version;
|
|
|
|
|
const void *events;
|
|
|
|
|
size_t size;
|
|
|
|
|
int (*init) (void *object);
|
|
|
|
|
void (*destroy) (void *object);
|
|
|
|
|
};
|
|
|
|
|
|
2019-11-14 18:35:29 +01:00
|
|
|
static void add_object(struct impl *impl, struct sm_object *obj)
|
|
|
|
|
{
|
|
|
|
|
size_t size = pw_map_get_size(&impl->globals);
|
2019-11-19 16:07:41 +01:00
|
|
|
while (obj->id > size)
|
|
|
|
|
pw_map_insert_at(&impl->globals, size++, NULL);
|
|
|
|
|
pw_map_insert_at(&impl->globals, obj->id, obj);
|
|
|
|
|
spa_list_append(&impl->global_list, &obj->link);
|
2019-11-14 18:35:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void remove_object(struct impl *impl, struct sm_object *obj)
|
|
|
|
|
{
|
2019-11-19 16:07:41 +01:00
|
|
|
pw_map_insert_at(&impl->globals, obj->id, NULL);
|
|
|
|
|
spa_list_remove(&obj->link);
|
2019-11-14 18:35:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void *find_object(struct impl *impl, uint32_t id)
|
|
|
|
|
{
|
|
|
|
|
void *obj;
|
|
|
|
|
if ((obj = pw_map_lookup(&impl->globals, id)) != NULL)
|
|
|
|
|
return obj;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct data *object_find_data(struct sm_object *obj, const char *id)
|
|
|
|
|
{
|
|
|
|
|
struct data *d;
|
|
|
|
|
spa_list_for_each(d, &obj->data, link) {
|
|
|
|
|
if (strcmp(d->id, id) == 0)
|
|
|
|
|
return d;
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void *sm_object_add_data(struct sm_object *obj, const char *id, size_t size)
|
|
|
|
|
{
|
|
|
|
|
struct data *d;
|
|
|
|
|
|
|
|
|
|
d = object_find_data(obj, id);
|
|
|
|
|
if (d != NULL) {
|
|
|
|
|
if (d->size == size)
|
|
|
|
|
goto done;
|
|
|
|
|
spa_list_remove(&d->link);
|
|
|
|
|
free(d);
|
|
|
|
|
}
|
|
|
|
|
d = calloc(1, sizeof(struct data) + size);
|
|
|
|
|
d->id = id;
|
|
|
|
|
d->size = size;
|
|
|
|
|
|
|
|
|
|
spa_list_append(&obj->data, &d->link);
|
|
|
|
|
done:
|
|
|
|
|
return SPA_MEMBER(d, sizeof(struct data), void);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void *sm_object_get_data(struct sm_object *obj, const char *id)
|
|
|
|
|
{
|
|
|
|
|
struct data *d;
|
|
|
|
|
d = object_find_data(obj, id);
|
|
|
|
|
if (d == NULL)
|
|
|
|
|
return NULL;
|
|
|
|
|
return SPA_MEMBER(d, sizeof(struct data), void);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int sm_object_remove_data(struct sm_object *obj, const char *id)
|
|
|
|
|
{
|
|
|
|
|
struct data *d;
|
|
|
|
|
d = object_find_data(obj, id);
|
|
|
|
|
if (d == NULL)
|
|
|
|
|
return -ENOENT;
|
|
|
|
|
spa_list_remove(&d->link);
|
|
|
|
|
free(d);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-28 11:13:53 +01:00
|
|
|
int sm_object_destroy(struct sm_object *obj)
|
2019-11-14 18:35:29 +01:00
|
|
|
{
|
2019-11-28 11:13:53 +01:00
|
|
|
pw_proxy_destroy(obj->proxy);
|
|
|
|
|
return 0;
|
2019-11-14 18:35:29 +01:00
|
|
|
}
|
|
|
|
|
|
2019-11-19 16:08:40 +01:00
|
|
|
static struct param *add_param(struct spa_list *param_list,
|
|
|
|
|
uint32_t id, const struct spa_pod *param)
|
|
|
|
|
{
|
|
|
|
|
struct param *p;
|
|
|
|
|
|
|
|
|
|
if (param == NULL || !spa_pod_is_object(param)) {
|
|
|
|
|
errno = EINVAL;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
if (id == SPA_ID_INVALID)
|
|
|
|
|
id = SPA_POD_OBJECT_ID(param);
|
|
|
|
|
|
|
|
|
|
p = malloc(sizeof(struct param) + SPA_POD_SIZE(param));
|
|
|
|
|
if (p == NULL)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
p->this.id = id;
|
|
|
|
|
p->this.param = SPA_MEMBER(p, sizeof(struct param), struct spa_pod);
|
|
|
|
|
memcpy(p->this.param, param, SPA_POD_SIZE(param));
|
|
|
|
|
|
2019-11-26 12:53:28 +01:00
|
|
|
spa_list_append(param_list, &p->this.link);
|
2019-11-19 16:08:40 +01:00
|
|
|
|
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2019-11-27 12:19:09 +01:00
|
|
|
static uint32_t clear_params(struct spa_list *param_list, uint32_t id)
|
2019-11-19 16:08:40 +01:00
|
|
|
{
|
|
|
|
|
struct param *p, *t;
|
2019-11-27 12:19:09 +01:00
|
|
|
uint32_t count = 0;
|
2019-11-19 16:08:40 +01:00
|
|
|
|
2019-11-26 12:53:28 +01:00
|
|
|
spa_list_for_each_safe(p, t, param_list, this.link) {
|
2019-11-19 16:08:40 +01:00
|
|
|
if (id == SPA_ID_INVALID || p->this.id == id) {
|
2019-11-26 12:53:28 +01:00
|
|
|
spa_list_remove(&p->this.link);
|
2019-11-19 16:08:40 +01:00
|
|
|
free(p);
|
2019-11-27 12:19:09 +01:00
|
|
|
count++;
|
2019-11-19 16:08:40 +01:00
|
|
|
}
|
|
|
|
|
}
|
2019-11-27 12:19:09 +01:00
|
|
|
return count;
|
2019-11-19 16:08:40 +01:00
|
|
|
}
|
|
|
|
|
|
2019-11-28 11:13:53 +01:00
|
|
|
/**
|
|
|
|
|
* Clients
|
|
|
|
|
*/
|
|
|
|
|
static void client_event_info(void *object, const struct pw_client_info *info)
|
|
|
|
|
{
|
|
|
|
|
struct sm_client *client = object;
|
|
|
|
|
struct impl *impl = SPA_CONTAINER_OF(client->obj.session, struct impl, this);
|
|
|
|
|
|
|
|
|
|
pw_log_debug(NAME" %p: client %d info", impl, client->obj.id);
|
|
|
|
|
client->info = pw_client_info_update(client->info, info);
|
|
|
|
|
|
|
|
|
|
client->obj.avail |= SM_CLIENT_CHANGE_MASK_INFO;
|
|
|
|
|
client->obj.changed |= SM_CLIENT_CHANGE_MASK_INFO;
|
|
|
|
|
pw_proxy_sync(client->obj.proxy, 1);
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-11 14:53:39 +01:00
|
|
|
static const struct pw_client_events client_events = {
|
|
|
|
|
PW_VERSION_CLIENT_EVENTS,
|
2019-11-28 11:13:53 +01:00
|
|
|
.info = client_event_info,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void client_destroy(void *object)
|
|
|
|
|
{
|
|
|
|
|
struct sm_client *client = object;
|
|
|
|
|
if (client->info)
|
|
|
|
|
pw_client_info_free(client->info);
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-29 13:21:55 +01:00
|
|
|
static const struct object_info client_info = {
|
|
|
|
|
.type = PW_TYPE_INTERFACE_Client,
|
2019-12-11 14:53:39 +01:00
|
|
|
.version = PW_VERSION_CLIENT,
|
2019-11-29 13:21:55 +01:00
|
|
|
.events = &client_events,
|
|
|
|
|
.size = sizeof(struct sm_client),
|
|
|
|
|
.init = NULL,
|
|
|
|
|
.destroy = client_destroy,
|
|
|
|
|
};
|
|
|
|
|
|
2019-11-28 11:13:53 +01:00
|
|
|
/**
|
|
|
|
|
* Device
|
|
|
|
|
*/
|
|
|
|
|
static void device_event_info(void *object, const struct pw_device_info *info)
|
|
|
|
|
{
|
|
|
|
|
struct sm_device *device = object;
|
|
|
|
|
struct impl *impl = SPA_CONTAINER_OF(device->obj.session, struct impl, this);
|
|
|
|
|
|
|
|
|
|
pw_log_debug(NAME" %p: device %d info", impl, device->obj.id);
|
|
|
|
|
device->info = pw_device_info_update(device->info, info);
|
|
|
|
|
|
|
|
|
|
device->obj.avail |= SM_DEVICE_CHANGE_MASK_INFO;
|
|
|
|
|
device->obj.changed |= SM_DEVICE_CHANGE_MASK_INFO;
|
|
|
|
|
|
|
|
|
|
if (info->change_mask & PW_DEVICE_CHANGE_MASK_PARAMS) {
|
2019-12-11 15:00:41 +01:00
|
|
|
pw_device_enum_params((struct pw_device*)device->obj.proxy,
|
2019-11-28 11:13:53 +01:00
|
|
|
1, SPA_PARAM_Profile, 0, UINT32_MAX, NULL);
|
|
|
|
|
}
|
|
|
|
|
pw_proxy_sync(device->obj.proxy, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void device_event_param(void *object, int seq,
|
|
|
|
|
uint32_t id, uint32_t index, uint32_t next,
|
|
|
|
|
const struct spa_pod *param)
|
|
|
|
|
{
|
|
|
|
|
struct sm_device *device = object;
|
|
|
|
|
struct impl *impl = SPA_CONTAINER_OF(device->obj.session, struct impl, this);
|
|
|
|
|
|
|
|
|
|
pw_log_debug(NAME" %p: device %p param %d index:%d", impl, device, id, index);
|
|
|
|
|
device->n_params -= clear_params(&device->param_list, id);
|
|
|
|
|
|
|
|
|
|
if (add_param(&device->param_list, id, param) != NULL)
|
|
|
|
|
device->n_params++;
|
|
|
|
|
|
|
|
|
|
device->obj.avail |= SM_DEVICE_CHANGE_MASK_PARAMS;
|
|
|
|
|
device->obj.changed |= SM_DEVICE_CHANGE_MASK_PARAMS;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-11 15:00:41 +01:00
|
|
|
static const struct pw_device_events device_events = {
|
|
|
|
|
PW_VERSION_DEVICE_EVENTS,
|
2019-11-28 11:13:53 +01:00
|
|
|
.info = device_event_info,
|
|
|
|
|
.param = device_event_param,
|
|
|
|
|
};
|
|
|
|
|
|
2019-11-29 13:21:55 +01:00
|
|
|
static int device_init(void *object)
|
|
|
|
|
{
|
|
|
|
|
struct sm_device *device = object;
|
|
|
|
|
spa_list_init(&device->node_list);
|
|
|
|
|
spa_list_init(&device->param_list);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-28 11:13:53 +01:00
|
|
|
static void device_destroy(void *object)
|
|
|
|
|
{
|
|
|
|
|
struct sm_device *device = object;
|
|
|
|
|
struct sm_node *node;
|
|
|
|
|
|
|
|
|
|
spa_list_consume(node, &device->node_list, link) {
|
|
|
|
|
node->device = NULL;
|
|
|
|
|
spa_list_remove(&node->link);
|
|
|
|
|
}
|
|
|
|
|
clear_params(&device->param_list, SPA_ID_INVALID);
|
|
|
|
|
device->n_params = 0;
|
|
|
|
|
|
|
|
|
|
if (device->info)
|
|
|
|
|
pw_device_info_free(device->info);
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-29 13:21:55 +01:00
|
|
|
static const struct object_info device_info = {
|
|
|
|
|
.type = PW_TYPE_INTERFACE_Device,
|
2019-12-11 15:00:41 +01:00
|
|
|
.version = PW_VERSION_DEVICE,
|
2019-11-29 13:21:55 +01:00
|
|
|
.events = &device_events,
|
|
|
|
|
.size = sizeof(struct sm_device),
|
|
|
|
|
.init = device_init,
|
|
|
|
|
.destroy = device_destroy,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const struct object_info spa_device_info = {
|
|
|
|
|
.type = SPA_TYPE_INTERFACE_Device,
|
|
|
|
|
.version = SPA_VERSION_DEVICE,
|
|
|
|
|
.size = sizeof(struct sm_device),
|
|
|
|
|
.init = device_init,
|
|
|
|
|
.destroy = device_destroy,
|
|
|
|
|
};
|
|
|
|
|
|
2019-11-14 18:35:29 +01:00
|
|
|
/**
|
|
|
|
|
* Node
|
|
|
|
|
*/
|
|
|
|
|
static void node_event_info(void *object, const struct pw_node_info *info)
|
|
|
|
|
{
|
|
|
|
|
struct sm_node *node = object;
|
|
|
|
|
struct impl *impl = SPA_CONTAINER_OF(node->obj.session, struct impl, this);
|
2019-11-19 16:08:40 +01:00
|
|
|
uint32_t i;
|
2019-11-14 18:35:29 +01:00
|
|
|
|
|
|
|
|
pw_log_debug(NAME" %p: node %d info", impl, node->obj.id);
|
|
|
|
|
node->info = pw_node_info_update(node->info, info);
|
|
|
|
|
|
2019-11-27 12:18:40 +01:00
|
|
|
node->obj.avail |= SM_NODE_CHANGE_MASK_INFO;
|
|
|
|
|
node->obj.changed |= SM_NODE_CHANGE_MASK_INFO;
|
2019-11-19 16:08:40 +01:00
|
|
|
|
|
|
|
|
if (info->change_mask & PW_NODE_CHANGE_MASK_PARAMS &&
|
2019-11-27 12:18:40 +01:00
|
|
|
(node->obj.mask & SM_NODE_CHANGE_MASK_PARAMS) &&
|
2019-11-19 16:08:40 +01:00
|
|
|
!node->subscribe) {
|
|
|
|
|
uint32_t subscribe[info->n_params], n_subscribe = 0;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < info->n_params; i++) {
|
|
|
|
|
switch (info->params[i].id) {
|
|
|
|
|
case SPA_PARAM_PropInfo:
|
|
|
|
|
case SPA_PARAM_Props:
|
|
|
|
|
case SPA_PARAM_EnumFormat:
|
|
|
|
|
subscribe[n_subscribe++] = info->params[i].id;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (n_subscribe > 0) {
|
2019-11-26 12:53:28 +01:00
|
|
|
pw_log_debug(NAME" %p: node %d subscribe %d params", impl,
|
|
|
|
|
node->obj.id, n_subscribe);
|
2019-12-11 15:26:11 +01:00
|
|
|
pw_node_subscribe_params((struct pw_node*)node->obj.proxy,
|
2019-11-19 16:08:40 +01:00
|
|
|
subscribe, n_subscribe);
|
|
|
|
|
node->subscribe = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-11-28 11:13:53 +01:00
|
|
|
node->last_id = SPA_ID_INVALID;
|
|
|
|
|
pw_proxy_sync(node->obj.proxy, 1);
|
2019-11-19 16:08:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void node_event_param(void *object, int seq,
|
|
|
|
|
uint32_t id, uint32_t index, uint32_t next,
|
|
|
|
|
const struct spa_pod *param)
|
|
|
|
|
{
|
|
|
|
|
struct sm_node *node = object;
|
|
|
|
|
struct impl *impl = SPA_CONTAINER_OF(node->obj.session, struct impl, this);
|
|
|
|
|
|
2019-11-26 12:53:28 +01:00
|
|
|
pw_log_debug(NAME" %p: node %p param %d index:%d", impl, node, id, index);
|
2019-11-28 11:13:53 +01:00
|
|
|
|
|
|
|
|
if (node->last_id != id) {
|
|
|
|
|
pw_log_debug(NAME" %p: node %p clear param %d", impl, node, id);
|
|
|
|
|
node->n_params -= clear_params(&node->param_list, id);
|
|
|
|
|
node->last_id = id;
|
|
|
|
|
}
|
2019-11-19 16:08:40 +01:00
|
|
|
|
2019-11-27 12:19:09 +01:00
|
|
|
if (add_param(&node->param_list, id, param) != NULL)
|
|
|
|
|
node->n_params++;
|
2019-11-19 16:08:40 +01:00
|
|
|
|
2019-11-27 12:18:40 +01:00
|
|
|
node->obj.avail |= SM_NODE_CHANGE_MASK_PARAMS;
|
|
|
|
|
node->obj.changed |= SM_NODE_CHANGE_MASK_PARAMS;
|
2019-11-14 18:35:29 +01:00
|
|
|
}
|
|
|
|
|
|
2019-12-11 15:26:11 +01:00
|
|
|
static const struct pw_node_events node_events = {
|
|
|
|
|
PW_VERSION_NODE_EVENTS,
|
2019-11-14 18:35:29 +01:00
|
|
|
.info = node_event_info,
|
2019-11-19 16:08:40 +01:00
|
|
|
.param = node_event_param,
|
2019-11-14 18:35:29 +01:00
|
|
|
};
|
|
|
|
|
|
2019-11-29 13:21:55 +01:00
|
|
|
static int node_init(void *object)
|
|
|
|
|
{
|
|
|
|
|
struct sm_node *node = object;
|
|
|
|
|
struct impl *impl = SPA_CONTAINER_OF(node->obj.session, struct impl, this);
|
|
|
|
|
struct pw_properties *props = node->obj.props;
|
|
|
|
|
const char *str;
|
|
|
|
|
|
|
|
|
|
spa_list_init(&node->port_list);
|
|
|
|
|
spa_list_init(&node->param_list);
|
|
|
|
|
|
|
|
|
|
if (props) {
|
|
|
|
|
if ((str = pw_properties_get(props, PW_KEY_DEVICE_ID)) != NULL)
|
|
|
|
|
node->device = find_object(impl, atoi(str));
|
|
|
|
|
pw_log_debug(NAME" %p: node %d parent device %s", impl, node->obj.id, str);
|
|
|
|
|
if (node->device) {
|
|
|
|
|
spa_list_append(&node->device->node_list, &node->link);
|
|
|
|
|
node->device->obj.changed |= SM_DEVICE_CHANGE_MASK_NODES;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-14 18:35:29 +01:00
|
|
|
static void node_destroy(void *object)
|
|
|
|
|
{
|
|
|
|
|
struct sm_node *node = object;
|
|
|
|
|
struct sm_port *port;
|
|
|
|
|
|
|
|
|
|
spa_list_consume(port, &node->port_list, link) {
|
|
|
|
|
port->node = NULL;
|
|
|
|
|
spa_list_remove(&port->link);
|
|
|
|
|
}
|
2019-11-19 16:08:40 +01:00
|
|
|
clear_params(&node->param_list, SPA_ID_INVALID);
|
2019-11-27 12:19:09 +01:00
|
|
|
node->n_params = 0;
|
2019-11-19 16:08:40 +01:00
|
|
|
|
2019-11-28 11:13:53 +01:00
|
|
|
if (node->device) {
|
|
|
|
|
spa_list_remove(&node->link);
|
|
|
|
|
node->device->obj.changed |= SM_DEVICE_CHANGE_MASK_NODES;
|
|
|
|
|
}
|
2019-11-14 18:35:29 +01:00
|
|
|
if (node->info)
|
|
|
|
|
pw_node_info_free(node->info);
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-29 13:21:55 +01:00
|
|
|
static const struct object_info node_info = {
|
|
|
|
|
.type = PW_TYPE_INTERFACE_Node,
|
2019-12-11 15:26:11 +01:00
|
|
|
.version = PW_VERSION_NODE,
|
2019-11-29 13:21:55 +01:00
|
|
|
.events = &node_events,
|
|
|
|
|
.size = sizeof(struct sm_node),
|
|
|
|
|
.init = node_init,
|
|
|
|
|
.destroy = node_destroy,
|
|
|
|
|
};
|
|
|
|
|
|
2019-11-14 18:35:29 +01:00
|
|
|
/**
|
|
|
|
|
* Port
|
|
|
|
|
*/
|
|
|
|
|
static void port_event_info(void *object, const struct pw_port_info *info)
|
|
|
|
|
{
|
|
|
|
|
struct sm_port *port = object;
|
|
|
|
|
struct impl *impl = SPA_CONTAINER_OF(port->obj.session, struct impl, this);
|
|
|
|
|
|
|
|
|
|
pw_log_debug(NAME" %p: port %d info", impl, port->obj.id);
|
|
|
|
|
port->info = pw_port_info_update(port->info, info);
|
|
|
|
|
|
2019-11-27 12:18:40 +01:00
|
|
|
port->obj.avail |= SM_PORT_CHANGE_MASK_INFO;
|
|
|
|
|
port->obj.changed |= SM_PORT_CHANGE_MASK_INFO;
|
2019-11-28 11:13:53 +01:00
|
|
|
pw_proxy_sync(port->obj.proxy, 1);
|
2019-11-14 18:35:29 +01:00
|
|
|
}
|
|
|
|
|
|
2019-12-11 15:59:26 +01:00
|
|
|
static const struct pw_port_events port_events = {
|
|
|
|
|
PW_VERSION_PORT_EVENTS,
|
2019-11-14 18:35:29 +01:00
|
|
|
.info = port_event_info,
|
|
|
|
|
};
|
|
|
|
|
|
2019-11-29 13:21:55 +01:00
|
|
|
static int port_init(void *object)
|
|
|
|
|
{
|
|
|
|
|
struct sm_port *port = object;
|
|
|
|
|
struct impl *impl = SPA_CONTAINER_OF(port->obj.session, struct impl, this);
|
|
|
|
|
struct pw_properties *props = port->obj.props;
|
|
|
|
|
const char *str;
|
|
|
|
|
|
|
|
|
|
if (props) {
|
|
|
|
|
if ((str = pw_properties_get(props, PW_KEY_PORT_DIRECTION)) != NULL)
|
|
|
|
|
port->direction = strcmp(str, "out") == 0 ?
|
|
|
|
|
PW_DIRECTION_OUTPUT : PW_DIRECTION_INPUT;
|
|
|
|
|
if ((str = pw_properties_get(props, PW_KEY_NODE_ID)) != NULL)
|
|
|
|
|
port->node = find_object(impl, atoi(str));
|
|
|
|
|
|
|
|
|
|
pw_log_debug(NAME" %p: port %d parent node %s direction:%d", impl,
|
|
|
|
|
port->obj.id, str, port->direction);
|
|
|
|
|
if (port->node) {
|
|
|
|
|
spa_list_append(&port->node->port_list, &port->link);
|
|
|
|
|
port->node->obj.changed |= SM_NODE_CHANGE_MASK_PORTS;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-14 18:35:29 +01:00
|
|
|
static void port_destroy(void *object)
|
|
|
|
|
{
|
|
|
|
|
struct sm_port *port = object;
|
|
|
|
|
if (port->info)
|
|
|
|
|
pw_port_info_free(port->info);
|
|
|
|
|
if (port->node) {
|
|
|
|
|
spa_list_remove(&port->link);
|
2019-11-27 12:18:40 +01:00
|
|
|
port->node->obj.changed |= SM_NODE_CHANGE_MASK_PORTS;
|
2019-11-14 18:35:29 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-29 13:21:55 +01:00
|
|
|
static const struct object_info port_info = {
|
|
|
|
|
.type = PW_TYPE_INTERFACE_Port,
|
2019-12-11 15:59:26 +01:00
|
|
|
.version = PW_VERSION_PORT,
|
2019-11-29 13:21:55 +01:00
|
|
|
.events = &port_events,
|
|
|
|
|
.size = sizeof(struct sm_port),
|
|
|
|
|
.init = port_init,
|
|
|
|
|
.destroy = port_destroy,
|
|
|
|
|
};
|
|
|
|
|
|
2019-11-20 16:18:46 +01:00
|
|
|
/**
|
|
|
|
|
* Session
|
|
|
|
|
*/
|
|
|
|
|
static void session_event_info(void *object, const struct pw_session_info *info)
|
|
|
|
|
{
|
|
|
|
|
struct sm_session *sess = object;
|
|
|
|
|
struct impl *impl = SPA_CONTAINER_OF(sess->obj.session, struct impl, this);
|
|
|
|
|
struct pw_session_info *i = sess->info;
|
|
|
|
|
|
|
|
|
|
pw_log_debug(NAME" %p: session %d info", impl, sess->obj.id);
|
|
|
|
|
if (i == NULL && info) {
|
|
|
|
|
i = sess->info = calloc(1, sizeof(struct pw_session_info));
|
|
|
|
|
i->version = PW_VERSION_SESSION_INFO;
|
|
|
|
|
i->id = info->id;
|
|
|
|
|
}
|
|
|
|
|
i->change_mask = info->change_mask;
|
|
|
|
|
if (info->change_mask & PW_SESSION_CHANGE_MASK_PROPS) {
|
|
|
|
|
if (i->props)
|
|
|
|
|
pw_properties_free ((struct pw_properties *)i->props);
|
|
|
|
|
i->props = (struct spa_dict *) pw_properties_new_dict (info->props);
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-27 12:18:40 +01:00
|
|
|
sess->obj.avail |= SM_SESSION_CHANGE_MASK_INFO;
|
|
|
|
|
sess->obj.changed |= SM_SESSION_CHANGE_MASK_INFO;
|
2019-11-28 11:13:53 +01:00
|
|
|
pw_proxy_sync(sess->obj.proxy, 1);
|
2019-11-20 16:18:46 +01:00
|
|
|
}
|
|
|
|
|
|
2019-12-11 16:39:24 +01:00
|
|
|
static const struct pw_session_events session_events = {
|
|
|
|
|
PW_VERSION_SESSION_EVENTS,
|
2019-11-20 16:18:46 +01:00
|
|
|
.info = session_event_info,
|
|
|
|
|
};
|
|
|
|
|
|
2019-11-29 13:21:55 +01:00
|
|
|
static int session_init(void *object)
|
|
|
|
|
{
|
|
|
|
|
struct sm_session *sess = object;
|
|
|
|
|
struct impl *impl = SPA_CONTAINER_OF(sess->obj.session, struct impl, this);
|
|
|
|
|
|
|
|
|
|
if (sess->obj.id == impl->session_id)
|
|
|
|
|
impl->this.session = sess;
|
|
|
|
|
|
|
|
|
|
spa_list_init(&sess->endpoint_list);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-20 16:18:46 +01:00
|
|
|
static void session_destroy(void *object)
|
|
|
|
|
{
|
|
|
|
|
struct sm_session *sess = object;
|
|
|
|
|
struct sm_endpoint *endpoint;
|
|
|
|
|
|
|
|
|
|
if (sess->info) {
|
|
|
|
|
free(sess->info);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
spa_list_consume(endpoint, &sess->endpoint_list, link) {
|
|
|
|
|
endpoint->session = NULL;
|
|
|
|
|
spa_list_remove(&endpoint->link);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-29 13:21:55 +01:00
|
|
|
static const struct object_info session_info = {
|
|
|
|
|
.type = PW_TYPE_INTERFACE_Session,
|
2019-12-11 16:39:24 +01:00
|
|
|
.version = PW_VERSION_SESSION,
|
2019-11-29 13:21:55 +01:00
|
|
|
.events = &session_events,
|
|
|
|
|
.size = sizeof(struct sm_session),
|
|
|
|
|
.init = session_init,
|
|
|
|
|
.destroy = session_destroy,
|
|
|
|
|
};
|
|
|
|
|
|
2019-11-14 18:35:29 +01:00
|
|
|
/**
|
|
|
|
|
* Endpoint
|
|
|
|
|
*/
|
|
|
|
|
static void endpoint_event_info(void *object, const struct pw_endpoint_info *info)
|
|
|
|
|
{
|
|
|
|
|
struct sm_endpoint *endpoint = object;
|
|
|
|
|
struct impl *impl = SPA_CONTAINER_OF(endpoint->obj.session, struct impl, this);
|
|
|
|
|
struct pw_endpoint_info *i = endpoint->info;
|
|
|
|
|
const char *str;
|
|
|
|
|
|
|
|
|
|
pw_log_debug(NAME" %p: endpoint %d info", impl, endpoint->obj.id);
|
|
|
|
|
if (i == NULL && info) {
|
2019-11-15 17:13:45 +01:00
|
|
|
i = endpoint->info = calloc(1, sizeof(struct pw_endpoint_info));
|
|
|
|
|
i->id = info->id;
|
|
|
|
|
i->name = info->name ? strdup(info->name) : NULL;
|
|
|
|
|
i->media_class = info->media_class ? strdup(info->media_class) : NULL;
|
|
|
|
|
i->direction = info->direction;
|
|
|
|
|
i->flags = info->flags;
|
2019-11-14 18:35:29 +01:00
|
|
|
}
|
|
|
|
|
i->change_mask = info->change_mask;
|
|
|
|
|
if (info->change_mask & PW_ENDPOINT_CHANGE_MASK_SESSION) {
|
|
|
|
|
i->session_id = info->session_id;
|
|
|
|
|
}
|
|
|
|
|
if (info->change_mask & PW_ENDPOINT_CHANGE_MASK_PROPS) {
|
|
|
|
|
if (i->props)
|
|
|
|
|
pw_properties_free ((struct pw_properties *)i->props);
|
|
|
|
|
i->props = (struct spa_dict *) pw_properties_new_dict (info->props);
|
|
|
|
|
if ((str = spa_dict_lookup(i->props, PW_KEY_PRIORITY_SESSION)) != NULL)
|
|
|
|
|
endpoint->priority = pw_properties_parse_int(str);
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-27 12:18:40 +01:00
|
|
|
endpoint->obj.avail |= SM_ENDPOINT_CHANGE_MASK_INFO;
|
|
|
|
|
endpoint->obj.changed |= SM_ENDPOINT_CHANGE_MASK_INFO;
|
2019-11-28 11:13:53 +01:00
|
|
|
pw_proxy_sync(endpoint->obj.proxy, 1);
|
2019-11-14 18:35:29 +01:00
|
|
|
}
|
|
|
|
|
|
2019-12-11 16:43:53 +01:00
|
|
|
static const struct pw_endpoint_events endpoint_events = {
|
|
|
|
|
PW_VERSION_ENDPOINT_EVENTS,
|
2019-11-14 18:35:29 +01:00
|
|
|
.info = endpoint_event_info,
|
|
|
|
|
};
|
|
|
|
|
|
2019-11-29 13:21:55 +01:00
|
|
|
static int endpoint_init(void *object)
|
|
|
|
|
{
|
|
|
|
|
struct sm_endpoint *endpoint = object;
|
|
|
|
|
struct impl *impl = SPA_CONTAINER_OF(endpoint->obj.session, struct impl, this);
|
|
|
|
|
struct pw_properties *props = endpoint->obj.props;
|
|
|
|
|
const char *str;
|
|
|
|
|
|
|
|
|
|
if (props) {
|
|
|
|
|
if ((str = pw_properties_get(props, PW_KEY_SESSION_ID)) != NULL)
|
|
|
|
|
endpoint->session = find_object(impl, atoi(str));
|
|
|
|
|
pw_log_debug(NAME" %p: endpoint %d parent session %s", impl,
|
|
|
|
|
endpoint->obj.id, str);
|
|
|
|
|
if (endpoint->session) {
|
|
|
|
|
spa_list_append(&endpoint->session->endpoint_list, &endpoint->link);
|
|
|
|
|
endpoint->session->obj.changed |= SM_SESSION_CHANGE_MASK_ENDPOINTS;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
spa_list_init(&endpoint->stream_list);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-14 18:35:29 +01:00
|
|
|
static void endpoint_destroy(void *object)
|
|
|
|
|
{
|
|
|
|
|
struct sm_endpoint *endpoint = object;
|
|
|
|
|
struct sm_endpoint_stream *stream;
|
|
|
|
|
|
|
|
|
|
if (endpoint->info) {
|
|
|
|
|
free(endpoint->info->name);
|
|
|
|
|
free(endpoint->info->media_class);
|
|
|
|
|
free(endpoint->info);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
spa_list_consume(stream, &endpoint->stream_list, link) {
|
|
|
|
|
stream->endpoint = NULL;
|
|
|
|
|
spa_list_remove(&stream->link);
|
|
|
|
|
}
|
2019-11-20 16:18:46 +01:00
|
|
|
if (endpoint->session) {
|
|
|
|
|
endpoint->session = NULL;
|
|
|
|
|
spa_list_remove(&endpoint->link);
|
|
|
|
|
}
|
2019-11-14 18:35:29 +01:00
|
|
|
}
|
|
|
|
|
|
2019-11-29 13:21:55 +01:00
|
|
|
static const struct object_info endpoint_info = {
|
|
|
|
|
.type = PW_TYPE_INTERFACE_Endpoint,
|
2019-12-11 16:43:53 +01:00
|
|
|
.version = PW_VERSION_ENDPOINT,
|
2019-11-29 13:21:55 +01:00
|
|
|
.events = &endpoint_events,
|
|
|
|
|
.size = sizeof(struct sm_endpoint),
|
|
|
|
|
.init = endpoint_init,
|
|
|
|
|
.destroy = endpoint_destroy,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2019-11-14 18:35:29 +01:00
|
|
|
/**
|
|
|
|
|
* Endpoint Stream
|
|
|
|
|
*/
|
|
|
|
|
static void endpoint_stream_event_info(void *object, const struct pw_endpoint_stream_info *info)
|
|
|
|
|
{
|
|
|
|
|
struct sm_endpoint_stream *stream = object;
|
|
|
|
|
struct impl *impl = SPA_CONTAINER_OF(stream->obj.session, struct impl, this);
|
|
|
|
|
|
|
|
|
|
pw_log_debug(NAME" %p: endpoint stream %d info", impl, stream->obj.id);
|
|
|
|
|
if (stream->info == NULL && info) {
|
2019-11-15 17:13:45 +01:00
|
|
|
stream->info = calloc(1, sizeof(struct pw_endpoint_stream_info));
|
|
|
|
|
stream->info->version = PW_VERSION_ENDPOINT_STREAM_INFO;
|
|
|
|
|
stream->info->id = info->id;
|
|
|
|
|
stream->info->endpoint_id = info->endpoint_id;
|
|
|
|
|
stream->info->name = info->name ? strdup(info->name) : NULL;
|
2019-11-14 18:35:29 +01:00
|
|
|
}
|
|
|
|
|
stream->info->change_mask = info->change_mask;
|
|
|
|
|
|
2019-11-27 12:18:40 +01:00
|
|
|
stream->obj.avail |= SM_ENDPOINT_CHANGE_MASK_INFO;
|
|
|
|
|
stream->obj.changed |= SM_ENDPOINT_CHANGE_MASK_INFO;
|
2019-11-28 11:13:53 +01:00
|
|
|
pw_proxy_sync(stream->obj.proxy, 1);
|
2019-11-14 18:35:29 +01:00
|
|
|
}
|
|
|
|
|
|
2019-12-11 16:48:00 +01:00
|
|
|
static const struct pw_endpoint_stream_events endpoint_stream_events = {
|
|
|
|
|
PW_VERSION_ENDPOINT_STREAM_EVENTS,
|
2019-11-14 18:35:29 +01:00
|
|
|
.info = endpoint_stream_event_info,
|
|
|
|
|
};
|
|
|
|
|
|
2019-11-29 13:21:55 +01:00
|
|
|
static int endpoint_stream_init(void *object)
|
|
|
|
|
{
|
|
|
|
|
struct sm_endpoint_stream *stream = object;
|
|
|
|
|
struct impl *impl = SPA_CONTAINER_OF(stream->obj.session, struct impl, this);
|
|
|
|
|
struct pw_properties *props = stream->obj.props;
|
|
|
|
|
const char *str;
|
|
|
|
|
|
|
|
|
|
if (props) {
|
|
|
|
|
if ((str = pw_properties_get(props, PW_KEY_ENDPOINT_ID)) != NULL)
|
|
|
|
|
stream->endpoint = find_object(impl, atoi(str));
|
|
|
|
|
pw_log_debug(NAME" %p: stream %d parent endpoint %s", impl,
|
|
|
|
|
stream->obj.id, str);
|
|
|
|
|
if (stream->endpoint) {
|
|
|
|
|
spa_list_append(&stream->endpoint->stream_list, &stream->link);
|
|
|
|
|
stream->endpoint->obj.changed |= SM_ENDPOINT_CHANGE_MASK_STREAMS;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
spa_list_init(&stream->link_list);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-14 18:35:29 +01:00
|
|
|
static void endpoint_stream_destroy(void *object)
|
|
|
|
|
{
|
|
|
|
|
struct sm_endpoint_stream *stream = object;
|
|
|
|
|
|
|
|
|
|
if (stream->info) {
|
|
|
|
|
free(stream->info->name);
|
|
|
|
|
free(stream->info);
|
|
|
|
|
}
|
|
|
|
|
if (stream->endpoint) {
|
|
|
|
|
stream->endpoint = NULL;
|
|
|
|
|
spa_list_remove(&stream->link);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-11-29 13:21:55 +01:00
|
|
|
|
|
|
|
|
static const struct object_info endpoint_stream_info = {
|
|
|
|
|
.type = PW_TYPE_INTERFACE_EndpointStream,
|
2019-12-11 16:48:00 +01:00
|
|
|
.version = PW_VERSION_ENDPOINT_STREAM,
|
2019-11-29 13:21:55 +01:00
|
|
|
.events = &endpoint_stream_events,
|
|
|
|
|
.size = sizeof(struct sm_endpoint_stream),
|
|
|
|
|
.init = endpoint_stream_init,
|
|
|
|
|
.destroy = endpoint_stream_destroy,
|
|
|
|
|
};
|
|
|
|
|
|
2019-11-15 17:13:45 +01:00
|
|
|
/**
|
|
|
|
|
* Endpoint Link
|
|
|
|
|
*/
|
|
|
|
|
static void endpoint_link_event_info(void *object, const struct pw_endpoint_link_info *info)
|
|
|
|
|
{
|
|
|
|
|
struct sm_endpoint_link *link = object;
|
|
|
|
|
struct impl *impl = SPA_CONTAINER_OF(link->obj.session, struct impl, this);
|
|
|
|
|
|
|
|
|
|
pw_log_debug(NAME" %p: endpoint link %d info", impl, link->obj.id);
|
|
|
|
|
if (link->info == NULL && info) {
|
|
|
|
|
link->info = calloc(1, sizeof(struct pw_endpoint_link_info));
|
|
|
|
|
link->info->version = PW_VERSION_ENDPOINT_LINK_INFO;
|
|
|
|
|
link->info->id = info->id;
|
|
|
|
|
link->info->session_id = info->session_id;
|
|
|
|
|
link->info->output_endpoint_id = info->output_endpoint_id;
|
|
|
|
|
link->info->output_stream_id = info->output_stream_id;
|
|
|
|
|
link->info->input_endpoint_id = info->input_endpoint_id;
|
|
|
|
|
link->info->input_stream_id = info->input_stream_id;
|
|
|
|
|
}
|
|
|
|
|
link->info->change_mask = info->change_mask;
|
|
|
|
|
|
2019-11-27 12:18:40 +01:00
|
|
|
link->obj.avail |= SM_ENDPOINT_LINK_CHANGE_MASK_INFO;
|
|
|
|
|
link->obj.changed |= SM_ENDPOINT_LINK_CHANGE_MASK_INFO;
|
2019-11-28 11:13:53 +01:00
|
|
|
pw_proxy_sync(link->obj.proxy, 1);
|
2019-11-15 17:13:45 +01:00
|
|
|
}
|
|
|
|
|
|
2019-12-11 16:36:12 +01:00
|
|
|
static const struct pw_endpoint_link_events endpoint_link_events = {
|
|
|
|
|
PW_VERSION_ENDPOINT_LINK_EVENTS,
|
2019-11-15 17:13:45 +01:00
|
|
|
.info = endpoint_link_event_info,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void endpoint_link_destroy(void *object)
|
|
|
|
|
{
|
|
|
|
|
struct sm_endpoint_link *link = object;
|
|
|
|
|
|
|
|
|
|
if (link->info) {
|
|
|
|
|
free(link->info->error);
|
|
|
|
|
free(link->info);
|
|
|
|
|
}
|
|
|
|
|
if (link->output) {
|
|
|
|
|
link->output = NULL;
|
|
|
|
|
spa_list_remove(&link->output_link);
|
|
|
|
|
}
|
|
|
|
|
if (link->input) {
|
|
|
|
|
link->input = NULL;
|
|
|
|
|
spa_list_remove(&link->input_link);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-29 13:21:55 +01:00
|
|
|
static const struct object_info endpoint_link_info = {
|
|
|
|
|
.type = PW_TYPE_INTERFACE_EndpointLink,
|
2019-12-11 16:48:00 +01:00
|
|
|
.version = PW_VERSION_ENDPOINT_LINK,
|
2019-11-29 13:21:55 +01:00
|
|
|
.events = &endpoint_link_events,
|
|
|
|
|
.size = sizeof(struct sm_endpoint_link),
|
|
|
|
|
.init = NULL,
|
|
|
|
|
.destroy = endpoint_link_destroy,
|
|
|
|
|
};
|
|
|
|
|
|
2019-11-14 18:35:29 +01:00
|
|
|
/**
|
|
|
|
|
* Proxy
|
|
|
|
|
*/
|
|
|
|
|
static void
|
2019-11-28 11:13:53 +01:00
|
|
|
destroy_proxy(void *data)
|
2019-11-14 18:35:29 +01:00
|
|
|
{
|
|
|
|
|
struct sm_object *obj = data;
|
|
|
|
|
struct impl *impl = SPA_CONTAINER_OF(obj->session, struct impl, this);
|
|
|
|
|
|
|
|
|
|
sm_media_session_emit_remove(impl, obj);
|
|
|
|
|
|
|
|
|
|
if (obj->destroy)
|
|
|
|
|
obj->destroy(obj);
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-28 11:13:53 +01:00
|
|
|
static void done_proxy(void *data, int seq)
|
|
|
|
|
{
|
|
|
|
|
struct sm_object *obj = data;
|
|
|
|
|
pw_log_debug("done %p proxy %p avail:%08x update:%08x", obj,
|
|
|
|
|
obj->proxy, obj->avail, obj->changed);
|
|
|
|
|
if (obj->changed) {
|
|
|
|
|
sm_object_emit_update(obj);
|
|
|
|
|
}
|
|
|
|
|
obj->changed = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-29 13:21:55 +01:00
|
|
|
static void bound_proxy(void *data, uint32_t id)
|
|
|
|
|
{
|
|
|
|
|
struct sm_object *obj = data;
|
|
|
|
|
struct impl *impl = SPA_CONTAINER_OF(obj->session, struct impl, this);
|
|
|
|
|
|
|
|
|
|
pw_log_debug("bound %p proxy %p id:%d", obj, obj->proxy, id);
|
|
|
|
|
|
|
|
|
|
if (obj->id == SPA_ID_INVALID) {
|
|
|
|
|
obj->id = id;
|
|
|
|
|
pw_log_debug("bound %p proxy %p id:%d", obj, obj->proxy, id);
|
|
|
|
|
add_object(impl, obj);
|
|
|
|
|
sm_media_session_emit_create(impl, obj);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-14 18:35:29 +01:00
|
|
|
static const struct pw_proxy_events proxy_events = {
|
|
|
|
|
PW_VERSION_PROXY_EVENTS,
|
|
|
|
|
.destroy = destroy_proxy,
|
2019-11-28 11:13:53 +01:00
|
|
|
.done = done_proxy,
|
2019-11-29 13:21:55 +01:00
|
|
|
.bound = bound_proxy,
|
2019-11-14 18:35:29 +01:00
|
|
|
};
|
|
|
|
|
|
2019-11-29 13:21:55 +01:00
|
|
|
static const struct object_info *get_object_info(struct impl *impl, uint32_t type)
|
2019-11-14 18:35:29 +01:00
|
|
|
{
|
2019-11-29 13:21:55 +01:00
|
|
|
const struct object_info *info;
|
2019-11-14 18:35:29 +01:00
|
|
|
switch (type) {
|
|
|
|
|
case PW_TYPE_INTERFACE_Client:
|
2019-11-29 13:21:55 +01:00
|
|
|
info = &client_info;
|
|
|
|
|
break;
|
|
|
|
|
case SPA_TYPE_INTERFACE_Device:
|
|
|
|
|
info = &spa_device_info;
|
2019-11-14 18:35:29 +01:00
|
|
|
break;
|
2019-11-28 11:13:53 +01:00
|
|
|
case PW_TYPE_INTERFACE_Device:
|
2019-11-29 13:21:55 +01:00
|
|
|
info = &device_info;
|
2019-11-28 11:13:53 +01:00
|
|
|
break;
|
2019-11-14 18:35:29 +01:00
|
|
|
case PW_TYPE_INTERFACE_Node:
|
2019-11-29 13:21:55 +01:00
|
|
|
info = &node_info;
|
2019-11-14 18:35:29 +01:00
|
|
|
break;
|
|
|
|
|
case PW_TYPE_INTERFACE_Port:
|
2019-11-29 13:21:55 +01:00
|
|
|
info = &port_info;
|
2019-11-14 18:35:29 +01:00
|
|
|
break;
|
2019-11-20 16:18:46 +01:00
|
|
|
case PW_TYPE_INTERFACE_Session:
|
2019-11-29 13:21:55 +01:00
|
|
|
info = &session_info;
|
2019-11-20 16:18:46 +01:00
|
|
|
break;
|
2019-11-14 18:35:29 +01:00
|
|
|
case PW_TYPE_INTERFACE_Endpoint:
|
2019-11-29 13:21:55 +01:00
|
|
|
info = &endpoint_info;
|
2019-11-14 18:35:29 +01:00
|
|
|
break;
|
|
|
|
|
case PW_TYPE_INTERFACE_EndpointStream:
|
2019-11-29 13:21:55 +01:00
|
|
|
info = &endpoint_stream_info;
|
2019-11-14 18:35:29 +01:00
|
|
|
break;
|
2019-11-15 17:13:45 +01:00
|
|
|
case PW_TYPE_INTERFACE_EndpointLink:
|
2019-11-29 13:21:55 +01:00
|
|
|
info = &endpoint_link_info;
|
2019-11-15 17:13:45 +01:00
|
|
|
break;
|
2019-11-14 18:35:29 +01:00
|
|
|
default:
|
2019-11-29 13:21:55 +01:00
|
|
|
info = NULL;
|
|
|
|
|
break;
|
2019-11-14 18:35:29 +01:00
|
|
|
}
|
2019-11-29 13:21:55 +01:00
|
|
|
return info;
|
|
|
|
|
}
|
2019-11-14 18:35:29 +01:00
|
|
|
|
2019-11-29 13:21:55 +01:00
|
|
|
static struct sm_object *init_object(struct impl *impl, const struct object_info *info,
|
|
|
|
|
struct pw_proxy *proxy, uint32_t id,
|
|
|
|
|
const struct spa_dict *props)
|
|
|
|
|
{
|
|
|
|
|
struct sm_object *obj;
|
|
|
|
|
|
|
|
|
|
obj = pw_proxy_get_user_data(proxy);
|
2019-11-14 18:35:29 +01:00
|
|
|
obj->session = &impl->this;
|
|
|
|
|
obj->id = id;
|
2019-11-29 13:21:55 +01:00
|
|
|
obj->type = info->type;
|
2019-11-14 18:35:29 +01:00
|
|
|
obj->props = props ? pw_properties_new_dict(props) : pw_properties_new(NULL, NULL);
|
|
|
|
|
obj->proxy = proxy;
|
2019-11-29 13:21:55 +01:00
|
|
|
obj->destroy = info->destroy;
|
|
|
|
|
obj->mask |= SM_OBJECT_CHANGE_MASK_PROPERTIES | SM_OBJECT_CHANGE_MASK_BIND;
|
|
|
|
|
obj->avail |= obj->mask;
|
2019-11-26 12:53:28 +01:00
|
|
|
spa_hook_list_init(&obj->hooks);
|
2019-11-14 18:35:29 +01:00
|
|
|
spa_list_init(&obj->data);
|
|
|
|
|
|
2019-11-29 13:21:55 +01:00
|
|
|
pw_proxy_add_listener(obj->proxy, &obj->proxy_listener, &proxy_events, obj);
|
|
|
|
|
if (info->events != NULL)
|
|
|
|
|
pw_proxy_add_object_listener(obj->proxy, &obj->object_listener, info->events, obj);
|
|
|
|
|
SPA_FLAG_UPDATE(obj->mask, SM_OBJECT_CHANGE_MASK_LISTENER, info->events != NULL);
|
2019-11-14 18:35:29 +01:00
|
|
|
|
2019-11-29 13:21:55 +01:00
|
|
|
if (info->init)
|
|
|
|
|
info->init(obj);
|
2019-11-28 11:13:53 +01:00
|
|
|
|
2019-11-29 13:21:55 +01:00
|
|
|
if (id != SPA_ID_INVALID) {
|
|
|
|
|
add_object(impl, obj);
|
|
|
|
|
sm_media_session_emit_create(impl, obj);
|
2019-11-14 18:35:29 +01:00
|
|
|
}
|
2019-11-29 13:21:55 +01:00
|
|
|
return obj;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct sm_object *
|
|
|
|
|
create_object(struct impl *impl, struct pw_proxy *proxy,
|
|
|
|
|
const struct spa_dict *props)
|
|
|
|
|
{
|
|
|
|
|
uint32_t type;
|
|
|
|
|
const struct object_info *info;
|
|
|
|
|
struct sm_object *obj;
|
|
|
|
|
|
|
|
|
|
type = pw_proxy_get_type(proxy, NULL);
|
|
|
|
|
|
|
|
|
|
info = get_object_info(impl, type);
|
|
|
|
|
if (info == NULL) {
|
|
|
|
|
pw_log_error(NAME" %p: unknown object type %d", impl, type);
|
|
|
|
|
errno = ENOTSUP;
|
|
|
|
|
return NULL;
|
2019-11-14 18:35:29 +01:00
|
|
|
}
|
2019-11-29 13:21:55 +01:00
|
|
|
obj = init_object(impl, info, proxy, SPA_ID_INVALID, props);
|
|
|
|
|
|
|
|
|
|
pw_log_debug(NAME" %p: created new object %p proxy %p", impl, obj, obj->proxy);
|
|
|
|
|
|
|
|
|
|
return obj;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct sm_object *
|
|
|
|
|
bind_object(struct impl *impl, const struct object_info *info, uint32_t id,
|
|
|
|
|
uint32_t permissions, uint32_t type, uint32_t version,
|
|
|
|
|
const struct spa_dict *props)
|
|
|
|
|
{
|
|
|
|
|
int res;
|
|
|
|
|
struct pw_proxy *proxy;
|
|
|
|
|
struct sm_object *obj;
|
|
|
|
|
|
2019-12-11 09:44:48 +01:00
|
|
|
proxy = pw_registry_bind(impl->registry,
|
2019-11-29 13:21:55 +01:00
|
|
|
id, type, info->version, info->size);
|
|
|
|
|
if (proxy == NULL) {
|
|
|
|
|
res = -errno;
|
|
|
|
|
goto error;
|
2019-11-14 18:35:29 +01:00
|
|
|
}
|
2019-11-29 13:21:55 +01:00
|
|
|
obj = init_object(impl, info, proxy, id, props);
|
2019-11-14 18:35:29 +01:00
|
|
|
|
2019-11-29 13:21:55 +01:00
|
|
|
pw_log_debug(NAME" %p: bound new object %p proxy %p id:%d", impl, obj, obj->proxy, obj->id);
|
2019-11-14 18:35:29 +01:00
|
|
|
|
2019-11-29 13:21:55 +01:00
|
|
|
return obj;
|
2019-11-14 18:35:29 +01:00
|
|
|
|
|
|
|
|
error:
|
|
|
|
|
pw_log_warn(NAME" %p: can't handle global %d: %s", impl, id, spa_strerror(res));
|
2019-11-29 13:21:55 +01:00
|
|
|
errno = -res;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
update_object(struct impl *impl, const struct object_info *info,
|
|
|
|
|
struct sm_object *obj, uint32_t id,
|
|
|
|
|
uint32_t permissions, uint32_t type, uint32_t version,
|
|
|
|
|
const struct spa_dict *props)
|
|
|
|
|
{
|
|
|
|
|
pw_properties_update(obj->props, props);
|
|
|
|
|
|
|
|
|
|
if (obj->type == type)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
spa_hook_remove(&obj->proxy_listener);
|
|
|
|
|
if (SPA_FLAG_IS_SET(obj->mask, SM_OBJECT_CHANGE_MASK_LISTENER))
|
|
|
|
|
spa_hook_remove(&obj->object_listener);
|
|
|
|
|
|
2019-12-11 09:44:48 +01:00
|
|
|
obj->proxy = pw_registry_bind(impl->registry,
|
2019-11-29 13:21:55 +01:00
|
|
|
id, info->type, info->version, 0);
|
|
|
|
|
obj->type = type;
|
|
|
|
|
|
|
|
|
|
pw_proxy_add_listener(obj->proxy, &obj->proxy_listener, &proxy_events, obj);
|
|
|
|
|
if (info->events)
|
|
|
|
|
pw_proxy_add_object_listener(obj->proxy, &obj->object_listener, info->events, obj);
|
|
|
|
|
|
|
|
|
|
SPA_FLAG_UPDATE(obj->mask, SM_OBJECT_CHANGE_MASK_LISTENER, info->events != NULL);
|
|
|
|
|
|
|
|
|
|
sm_media_session_emit_create(impl, obj);
|
|
|
|
|
|
|
|
|
|
return 0;
|
2019-11-14 18:35:29 +01:00
|
|
|
}
|
|
|
|
|
|
2019-11-26 12:53:28 +01:00
|
|
|
static void
|
|
|
|
|
registry_global(void *data, uint32_t id,
|
|
|
|
|
uint32_t permissions, uint32_t type, uint32_t version,
|
|
|
|
|
const struct spa_dict *props)
|
|
|
|
|
{
|
|
|
|
|
struct impl *impl = data;
|
|
|
|
|
struct sm_object *obj;
|
2019-11-29 13:21:55 +01:00
|
|
|
const struct object_info *info;
|
2019-11-26 12:53:28 +01:00
|
|
|
|
2019-11-29 13:21:55 +01:00
|
|
|
pw_log_debug(NAME " %p: new global '%d' %s/%d", impl, id,
|
|
|
|
|
spa_debug_type_find_name(pw_type_info(), type), version);
|
|
|
|
|
|
|
|
|
|
info = get_object_info(impl, type);
|
|
|
|
|
if (info == NULL)
|
|
|
|
|
return;
|
2019-11-26 12:53:28 +01:00
|
|
|
|
|
|
|
|
obj = find_object(impl, id);
|
|
|
|
|
if (obj == NULL) {
|
2019-11-29 13:21:55 +01:00
|
|
|
bind_object(impl, info, id, permissions, type, version, props);
|
2019-11-26 12:53:28 +01:00
|
|
|
} else {
|
2019-11-29 13:21:55 +01:00
|
|
|
pw_log_debug(NAME " %p: our object %d appeared %d/%d",
|
|
|
|
|
impl, id, obj->type, type);
|
|
|
|
|
update_object(impl, info, obj, id, permissions, type, version, props);
|
2019-11-26 12:53:28 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int sm_object_add_listener(struct sm_object *obj, struct spa_hook *listener,
|
|
|
|
|
const struct sm_object_events *events, void *data)
|
|
|
|
|
{
|
|
|
|
|
spa_hook_list_append(&obj->hooks, listener, events, data);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-14 18:35:29 +01:00
|
|
|
int sm_media_session_add_listener(struct sm_media_session *sess, struct spa_hook *listener,
|
|
|
|
|
const struct sm_media_session_events *events, void *data)
|
|
|
|
|
{
|
|
|
|
|
struct impl *impl = SPA_CONTAINER_OF(sess, struct impl, this);
|
2019-11-19 16:07:41 +01:00
|
|
|
struct spa_hook_list save;
|
|
|
|
|
struct sm_object *obj;
|
|
|
|
|
|
|
|
|
|
spa_hook_list_isolate(&impl->hooks, &save, listener, events, data);
|
|
|
|
|
|
|
|
|
|
spa_list_for_each(obj, &impl->global_list, link)
|
2019-11-26 12:53:28 +01:00
|
|
|
sm_media_session_emit_create(impl, obj);
|
2019-11-19 16:07:41 +01:00
|
|
|
|
|
|
|
|
spa_hook_list_join(&impl->hooks, &save);
|
|
|
|
|
|
2019-11-14 18:35:29 +01:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct sm_object *sm_media_session_find_object(struct sm_media_session *sess, uint32_t id)
|
|
|
|
|
{
|
|
|
|
|
struct impl *impl = SPA_CONTAINER_OF(sess, struct impl, this);
|
|
|
|
|
return find_object(impl, id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int sm_media_session_schedule_rescan(struct sm_media_session *sess)
|
|
|
|
|
{
|
|
|
|
|
struct impl *impl = SPA_CONTAINER_OF(sess, struct impl, this);
|
2019-11-28 11:13:53 +01:00
|
|
|
if (impl->policy_core)
|
2019-12-11 07:46:59 +01:00
|
|
|
impl->rescan_seq = pw_core_sync(impl->policy_core, 0, impl->last_seq);
|
2019-11-15 12:07:26 +01:00
|
|
|
return impl->rescan_seq;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-18 13:10:21 +01:00
|
|
|
int sm_media_session_sync(struct sm_media_session *sess,
|
|
|
|
|
void (*callback) (void *data), void *data)
|
|
|
|
|
{
|
|
|
|
|
struct impl *impl = SPA_CONTAINER_OF(sess, struct impl, this);
|
|
|
|
|
struct sync *sync;
|
|
|
|
|
|
|
|
|
|
sync = calloc(1, sizeof(struct sync));
|
|
|
|
|
if (sync == NULL)
|
|
|
|
|
return -errno;
|
|
|
|
|
|
|
|
|
|
spa_list_append(&impl->sync_list, &sync->link);
|
|
|
|
|
sync->callback = callback;
|
|
|
|
|
sync->data = data;
|
2019-12-11 07:46:59 +01:00
|
|
|
sync->seq = pw_core_sync(impl->policy_core, 0, impl->last_seq);
|
2019-11-18 13:10:21 +01:00
|
|
|
return sync->seq;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void roundtrip_callback(void *data)
|
|
|
|
|
{
|
|
|
|
|
int *done = data;
|
|
|
|
|
*done = 1;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-15 12:07:26 +01:00
|
|
|
int sm_media_session_roundtrip(struct sm_media_session *sess)
|
|
|
|
|
{
|
|
|
|
|
struct impl *impl = SPA_CONTAINER_OF(sess, struct impl, this);
|
2019-11-20 16:18:46 +01:00
|
|
|
struct pw_loop *loop = impl->this.loop;
|
2019-11-18 13:10:21 +01:00
|
|
|
int done, res;
|
2019-11-15 12:07:26 +01:00
|
|
|
|
2019-11-28 11:13:53 +01:00
|
|
|
if (impl->policy_core == NULL)
|
2019-11-15 12:07:26 +01:00
|
|
|
return -EIO;
|
|
|
|
|
|
2019-11-18 13:10:21 +01:00
|
|
|
done = 0;
|
|
|
|
|
if ((res = sm_media_session_sync(sess, roundtrip_callback, &done)) < 0)
|
|
|
|
|
return res;
|
|
|
|
|
|
|
|
|
|
pw_log_debug(NAME" %p: roundtrip %d", impl, res);
|
2019-11-15 12:07:26 +01:00
|
|
|
|
2019-11-20 16:18:46 +01:00
|
|
|
pw_loop_enter(loop);
|
2019-11-18 13:10:21 +01:00
|
|
|
while (!done) {
|
2019-11-20 16:18:46 +01:00
|
|
|
if ((res = pw_loop_iterate(loop, -1)) < 0) {
|
2019-11-15 12:07:26 +01:00
|
|
|
pw_log_warn(NAME" %p: iterate error %d (%s)",
|
|
|
|
|
loop, res, spa_strerror(res));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-11-20 16:18:46 +01:00
|
|
|
pw_loop_leave(loop);
|
2019-11-15 12:07:26 +01:00
|
|
|
|
2019-11-18 13:10:21 +01:00
|
|
|
pw_log_debug(NAME" %p: roundtrip done", impl);
|
2019-11-15 12:07:26 +01:00
|
|
|
|
2019-11-18 13:10:21 +01:00
|
|
|
return 0;
|
2019-11-14 18:35:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
registry_global_remove(void *data, uint32_t id)
|
|
|
|
|
{
|
|
|
|
|
struct impl *impl = data;
|
|
|
|
|
struct sm_object *obj;
|
|
|
|
|
|
|
|
|
|
pw_log_debug(NAME " %p: remove global '%d'", impl, id);
|
|
|
|
|
|
|
|
|
|
if ((obj = find_object(impl, id)) == NULL)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
remove_object(impl, obj);
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-11 09:44:48 +01:00
|
|
|
static const struct pw_registry_events registry_events = {
|
|
|
|
|
PW_VERSION_REGISTRY_EVENTS,
|
2019-11-14 18:35:29 +01:00
|
|
|
.global = registry_global,
|
|
|
|
|
.global_remove = registry_global_remove,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct pw_proxy *sm_media_session_export(struct sm_media_session *sess,
|
|
|
|
|
uint32_t type, struct pw_properties *properties,
|
|
|
|
|
void *object, size_t user_data_size)
|
|
|
|
|
{
|
|
|
|
|
struct impl *impl = SPA_CONTAINER_OF(sess, struct impl, this);
|
2019-12-11 07:46:59 +01:00
|
|
|
return pw_core_export(impl->monitor_core, type,
|
2019-11-14 18:35:29 +01:00
|
|
|
properties, object, user_data_size);
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-29 13:21:55 +01:00
|
|
|
struct sm_device *sm_media_session_export_device(struct sm_media_session *sess,
|
|
|
|
|
struct pw_properties *properties, struct spa_device *object)
|
|
|
|
|
{
|
|
|
|
|
struct impl *impl = SPA_CONTAINER_OF(sess, struct impl, this);
|
|
|
|
|
struct sm_device *device;
|
|
|
|
|
struct pw_proxy *proxy;
|
|
|
|
|
|
|
|
|
|
pw_log_debug(NAME " %p: device %p", impl, object);
|
|
|
|
|
|
2019-12-11 07:46:59 +01:00
|
|
|
proxy = pw_core_export(impl->monitor_core, SPA_TYPE_INTERFACE_Device,
|
2019-11-29 13:21:55 +01:00
|
|
|
properties, object, sizeof(struct sm_device));
|
|
|
|
|
|
|
|
|
|
device = (struct sm_device *) create_object(impl, proxy, &properties->dict);
|
|
|
|
|
|
|
|
|
|
return device;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-14 18:35:29 +01:00
|
|
|
struct pw_proxy *sm_media_session_create_object(struct sm_media_session *sess,
|
|
|
|
|
const char *factory_name, uint32_t type, uint32_t version,
|
|
|
|
|
const struct spa_dict *props, size_t user_data_size)
|
|
|
|
|
{
|
|
|
|
|
struct impl *impl = SPA_CONTAINER_OF(sess, struct impl, this);
|
2019-12-11 07:46:59 +01:00
|
|
|
return pw_core_create_object(impl->policy_core,
|
2019-11-14 18:35:29 +01:00
|
|
|
factory_name, type, version, props, user_data_size);
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-26 12:53:28 +01:00
|
|
|
struct sm_node *sm_media_session_create_node(struct sm_media_session *sess,
|
2019-11-29 13:21:55 +01:00
|
|
|
const char *factory_name, const struct spa_dict *props)
|
2019-11-26 12:53:28 +01:00
|
|
|
{
|
|
|
|
|
struct impl *impl = SPA_CONTAINER_OF(sess, struct impl, this);
|
|
|
|
|
struct sm_node *node;
|
|
|
|
|
struct pw_proxy *proxy;
|
|
|
|
|
|
|
|
|
|
pw_log_debug(NAME " %p: node '%s'", impl, factory_name);
|
|
|
|
|
|
2019-12-11 07:46:59 +01:00
|
|
|
proxy = pw_core_create_object(impl->policy_core,
|
2019-11-26 12:53:28 +01:00
|
|
|
factory_name,
|
|
|
|
|
PW_TYPE_INTERFACE_Node,
|
2019-12-11 15:26:11 +01:00
|
|
|
PW_VERSION_NODE,
|
2019-11-26 12:53:28 +01:00
|
|
|
props,
|
2019-11-29 13:21:55 +01:00
|
|
|
sizeof(struct sm_node));
|
2019-11-26 12:53:28 +01:00
|
|
|
|
2019-11-29 13:21:55 +01:00
|
|
|
node = (struct sm_node *)create_object(impl, proxy, props);
|
2019-11-26 12:53:28 +01:00
|
|
|
|
|
|
|
|
return node;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-15 17:13:45 +01:00
|
|
|
static void check_endpoint_link(struct endpoint_link *link)
|
2019-11-15 12:08:46 +01:00
|
|
|
{
|
2019-11-15 17:13:45 +01:00
|
|
|
if (!spa_list_is_empty(&link->link_list))
|
|
|
|
|
return;
|
2019-11-15 12:08:46 +01:00
|
|
|
|
2019-11-15 17:13:45 +01:00
|
|
|
if (link->impl) {
|
|
|
|
|
spa_list_remove(&link->link);
|
|
|
|
|
pw_map_remove(&link->impl->endpoint_links, link->id);
|
2019-11-15 12:08:46 +01:00
|
|
|
|
2019-12-11 16:31:58 +01:00
|
|
|
pw_client_session_link_update(link->impl->client_session,
|
2019-11-15 17:13:45 +01:00
|
|
|
link->id,
|
|
|
|
|
PW_CLIENT_SESSION_LINK_UPDATE_DESTROYED,
|
|
|
|
|
0, NULL, NULL);
|
2019-11-15 12:08:46 +01:00
|
|
|
|
2019-11-15 17:13:45 +01:00
|
|
|
link->impl = NULL;
|
|
|
|
|
free(link);
|
2019-11-15 12:08:46 +01:00
|
|
|
}
|
2019-11-15 17:13:45 +01:00
|
|
|
}
|
|
|
|
|
|
2019-12-11 16:51:38 +01:00
|
|
|
static void proxy_link_destroy(void *data)
|
2019-11-15 17:13:45 +01:00
|
|
|
{
|
|
|
|
|
struct link *l = data;
|
|
|
|
|
|
|
|
|
|
if (l->endpoint_link) {
|
|
|
|
|
spa_list_remove(&l->link);
|
|
|
|
|
check_endpoint_link(l->endpoint_link);
|
|
|
|
|
l->endpoint_link = NULL;
|
2019-11-15 12:08:46 +01:00
|
|
|
}
|
2019-11-15 17:13:45 +01:00
|
|
|
}
|
|
|
|
|
|
2019-12-11 16:51:38 +01:00
|
|
|
static const struct pw_proxy_events proxy_link_events = {
|
2019-11-15 17:13:45 +01:00
|
|
|
PW_VERSION_PROXY_EVENTS,
|
2019-12-11 16:51:38 +01:00
|
|
|
.destroy = proxy_link_destroy
|
2019-11-15 17:13:45 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static int link_nodes(struct impl *impl, struct endpoint_link *link,
|
|
|
|
|
struct sm_node *outnode, struct sm_node *innode)
|
|
|
|
|
{
|
|
|
|
|
struct pw_properties *props;
|
|
|
|
|
struct sm_port *outport, *inport;
|
2019-11-15 12:08:46 +01:00
|
|
|
|
|
|
|
|
pw_log_debug(NAME" %p: linking %d -> %d", impl, outnode->obj.id, innode->obj.id);
|
|
|
|
|
|
|
|
|
|
props = pw_properties_new(NULL, NULL);
|
|
|
|
|
pw_properties_setf(props, PW_KEY_LINK_OUTPUT_NODE, "%d", outnode->obj.id);
|
|
|
|
|
pw_properties_setf(props, PW_KEY_LINK_INPUT_NODE, "%d", innode->obj.id);
|
|
|
|
|
|
|
|
|
|
for (outport = spa_list_first(&outnode->port_list, struct sm_port, link),
|
|
|
|
|
inport = spa_list_first(&innode->port_list, struct sm_port, link);
|
|
|
|
|
!spa_list_is_end(outport, &outnode->port_list, link) &&
|
|
|
|
|
!spa_list_is_end(inport, &innode->port_list, link);) {
|
|
|
|
|
|
|
|
|
|
pw_log_debug(NAME" %p: port %d:%d -> %d:%d", impl,
|
|
|
|
|
outport->direction, outport->obj.id,
|
|
|
|
|
inport->direction, inport->obj.id);
|
|
|
|
|
|
|
|
|
|
if (outport->direction == PW_DIRECTION_OUTPUT &&
|
|
|
|
|
inport->direction == PW_DIRECTION_INPUT) {
|
2019-11-15 17:13:45 +01:00
|
|
|
struct link *l;
|
|
|
|
|
struct pw_proxy *p;
|
2019-11-15 12:08:46 +01:00
|
|
|
|
|
|
|
|
pw_properties_setf(props, PW_KEY_LINK_OUTPUT_PORT, "%d", outport->obj.id);
|
|
|
|
|
pw_properties_setf(props, PW_KEY_LINK_INPUT_PORT, "%d", inport->obj.id);
|
|
|
|
|
|
2019-12-11 07:46:59 +01:00
|
|
|
p = pw_core_create_object(impl->policy_core,
|
2019-11-15 17:13:45 +01:00
|
|
|
"link-factory",
|
|
|
|
|
PW_TYPE_INTERFACE_Link,
|
2019-12-11 15:11:56 +01:00
|
|
|
PW_VERSION_LINK,
|
2019-11-15 17:13:45 +01:00
|
|
|
&props->dict, sizeof(struct link));
|
|
|
|
|
if (p == NULL)
|
|
|
|
|
return -errno;
|
|
|
|
|
|
|
|
|
|
l = pw_proxy_get_user_data(p);
|
|
|
|
|
l->proxy = p;
|
|
|
|
|
l->output_node = outnode->obj.id;
|
|
|
|
|
l->output_port = outport->obj.id;
|
|
|
|
|
l->input_node = innode->obj.id;
|
|
|
|
|
l->input_port = inport->obj.id;
|
2019-12-11 16:51:38 +01:00
|
|
|
pw_proxy_add_listener(p, &l->listener, &proxy_link_events, l);
|
2019-11-15 17:13:45 +01:00
|
|
|
|
|
|
|
|
if (link) {
|
|
|
|
|
l->endpoint_link = link;
|
|
|
|
|
spa_list_append(&link->link_list, &l->link);
|
|
|
|
|
}
|
2019-11-15 12:08:46 +01:00
|
|
|
|
|
|
|
|
outport = spa_list_next(outport, link);
|
|
|
|
|
inport = spa_list_next(inport, link);
|
|
|
|
|
} else {
|
|
|
|
|
if (outport->direction != PW_DIRECTION_OUTPUT)
|
|
|
|
|
outport = spa_list_next(outport, link);
|
|
|
|
|
if (inport->direction != PW_DIRECTION_INPUT)
|
|
|
|
|
inport = spa_list_next(inport, link);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pw_properties_free(props);
|
|
|
|
|
|
2019-11-15 17:13:45 +01:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int sm_media_session_create_links(struct sm_media_session *sess,
|
|
|
|
|
const struct spa_dict *dict)
|
|
|
|
|
{
|
|
|
|
|
struct impl *impl = SPA_CONTAINER_OF(sess, struct impl, this);
|
|
|
|
|
struct sm_object *obj;
|
|
|
|
|
struct sm_node *outnode = NULL, *innode = NULL;
|
|
|
|
|
struct sm_endpoint *outendpoint = NULL, *inendpoint = NULL;
|
|
|
|
|
struct sm_endpoint_stream *outstream = NULL, *instream = NULL;
|
|
|
|
|
struct endpoint_link *link = NULL;
|
|
|
|
|
const char *str;
|
|
|
|
|
int res;
|
|
|
|
|
|
|
|
|
|
sm_media_session_roundtrip(sess);
|
|
|
|
|
|
|
|
|
|
/* find output node */
|
|
|
|
|
if ((str = spa_dict_lookup(dict, PW_KEY_LINK_OUTPUT_NODE)) != NULL &&
|
|
|
|
|
(obj = find_object(impl, atoi(str))) != NULL &&
|
|
|
|
|
obj->type == PW_TYPE_INTERFACE_Node) {
|
|
|
|
|
outnode = (struct sm_node*)obj;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* find input node */
|
|
|
|
|
if ((str = spa_dict_lookup(dict, PW_KEY_LINK_INPUT_NODE)) != NULL &&
|
|
|
|
|
(obj = find_object(impl, atoi(str))) != NULL &&
|
|
|
|
|
obj->type == PW_TYPE_INTERFACE_Node) {
|
|
|
|
|
innode = (struct sm_node*)obj;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* find endpoints and streams */
|
|
|
|
|
if ((str = spa_dict_lookup(dict, PW_KEY_ENDPOINT_LINK_OUTPUT_ENDPOINT)) != NULL &&
|
|
|
|
|
(obj = find_object(impl, atoi(str))) != NULL &&
|
|
|
|
|
obj->type == PW_TYPE_INTERFACE_Endpoint) {
|
|
|
|
|
outendpoint = (struct sm_endpoint*)obj;
|
|
|
|
|
}
|
|
|
|
|
if ((str = spa_dict_lookup(dict, PW_KEY_ENDPOINT_LINK_OUTPUT_STREAM)) != NULL &&
|
|
|
|
|
(obj = find_object(impl, atoi(str))) != NULL &&
|
|
|
|
|
obj->type == PW_TYPE_INTERFACE_EndpointStream) {
|
|
|
|
|
outstream = (struct sm_endpoint_stream*)obj;
|
|
|
|
|
}
|
|
|
|
|
if ((str = spa_dict_lookup(dict, PW_KEY_ENDPOINT_LINK_INPUT_ENDPOINT)) != NULL &&
|
|
|
|
|
(obj = find_object(impl, atoi(str))) != NULL &&
|
|
|
|
|
obj->type == PW_TYPE_INTERFACE_Endpoint) {
|
|
|
|
|
inendpoint = (struct sm_endpoint*)obj;
|
|
|
|
|
}
|
|
|
|
|
if ((str = spa_dict_lookup(dict, PW_KEY_ENDPOINT_LINK_INPUT_STREAM)) != NULL &&
|
|
|
|
|
(obj = find_object(impl, atoi(str))) != NULL &&
|
|
|
|
|
obj->type == PW_TYPE_INTERFACE_EndpointStream) {
|
|
|
|
|
instream = (struct sm_endpoint_stream*)obj;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (outendpoint != NULL && inendpoint != NULL) {
|
|
|
|
|
link = calloc(1, sizeof(struct endpoint_link));
|
|
|
|
|
if (link == NULL)
|
|
|
|
|
return -errno;
|
|
|
|
|
|
|
|
|
|
link->id = pw_map_insert_new(&impl->endpoint_links, link);
|
|
|
|
|
link->impl = impl;
|
|
|
|
|
spa_list_init(&link->link_list);
|
|
|
|
|
spa_list_append(&impl->endpoint_link_list, &link->link);
|
|
|
|
|
|
|
|
|
|
link->info.version = PW_VERSION_ENDPOINT_LINK_INFO;
|
|
|
|
|
link->info.id = link->id;
|
2019-11-20 16:18:46 +01:00
|
|
|
link->info.session_id = impl->this.session->obj.id;
|
2019-11-15 17:13:45 +01:00
|
|
|
link->info.output_endpoint_id = outendpoint->info->id;
|
|
|
|
|
link->info.output_stream_id = outstream ? outstream->info->id : SPA_ID_INVALID;
|
|
|
|
|
link->info.input_endpoint_id = inendpoint->info->id;
|
|
|
|
|
link->info.input_stream_id = instream ? instream->info->id : SPA_ID_INVALID;
|
|
|
|
|
link->info.change_mask =
|
|
|
|
|
PW_ENDPOINT_LINK_CHANGE_MASK_STATE |
|
|
|
|
|
PW_ENDPOINT_LINK_CHANGE_MASK_PROPS;
|
|
|
|
|
link->info.state = PW_ENDPOINT_LINK_STATE_ACTIVE;
|
|
|
|
|
link->info.props = (struct spa_dict*) dict;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* link the nodes, record the link proxies in the endpoint_link */
|
|
|
|
|
if (outnode != NULL && innode != NULL)
|
|
|
|
|
res = link_nodes(impl, link, outnode, innode);
|
|
|
|
|
else
|
|
|
|
|
res = 0;
|
|
|
|
|
|
|
|
|
|
if (link != NULL) {
|
|
|
|
|
/* now create the endpoint link */
|
2019-12-11 16:31:58 +01:00
|
|
|
pw_client_session_link_update(impl->client_session,
|
2019-11-15 17:13:45 +01:00
|
|
|
link->id,
|
|
|
|
|
PW_CLIENT_SESSION_UPDATE_INFO,
|
|
|
|
|
0, NULL,
|
|
|
|
|
&link->info);
|
|
|
|
|
}
|
2019-11-15 12:08:46 +01:00
|
|
|
return res;
|
|
|
|
|
}
|
2019-11-14 18:35:29 +01:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Session implementation
|
|
|
|
|
*/
|
|
|
|
|
static int client_session_set_param(void *object, uint32_t id, uint32_t flags,
|
|
|
|
|
const struct spa_pod *param)
|
|
|
|
|
{
|
|
|
|
|
struct impl *impl = object;
|
|
|
|
|
pw_proxy_error((struct pw_proxy*)impl->client_session,
|
|
|
|
|
-ENOTSUP, "Session:SetParam not supported");
|
|
|
|
|
return -ENOTSUP;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int client_session_link_set_param(void *object, uint32_t link_id, uint32_t id, uint32_t flags,
|
|
|
|
|
const struct spa_pod *param)
|
|
|
|
|
{
|
|
|
|
|
struct impl *impl = object;
|
|
|
|
|
pw_proxy_error((struct pw_proxy*)impl->client_session,
|
|
|
|
|
-ENOTSUP, "Session:LinkSetParam not supported");
|
|
|
|
|
return -ENOTSUP;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int client_session_link_request_state(void *object, uint32_t link_id, uint32_t state)
|
|
|
|
|
{
|
|
|
|
|
return -ENOTSUP;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-11 16:31:58 +01:00
|
|
|
static const struct pw_client_session_events client_session_events = {
|
|
|
|
|
PW_VERSION_CLIENT_SESSION_METHODS,
|
2019-11-14 18:35:29 +01:00
|
|
|
.set_param = client_session_set_param,
|
|
|
|
|
.link_set_param = client_session_link_set_param,
|
|
|
|
|
.link_request_state = client_session_link_request_state,
|
|
|
|
|
};
|
|
|
|
|
|
2019-12-11 16:31:58 +01:00
|
|
|
static void proxy_client_session_bound(void *data, uint32_t id)
|
2019-11-29 13:21:55 +01:00
|
|
|
{
|
|
|
|
|
struct impl *impl = data;
|
|
|
|
|
struct pw_session_info info;
|
|
|
|
|
|
|
|
|
|
impl->session_id = id;
|
|
|
|
|
|
|
|
|
|
spa_zero(info);
|
|
|
|
|
info.version = PW_VERSION_SESSION_INFO;
|
|
|
|
|
info.id = id;
|
|
|
|
|
|
|
|
|
|
pw_log_debug("got sesssion id:%d", id);
|
|
|
|
|
|
2019-12-11 16:31:58 +01:00
|
|
|
pw_client_session_update(impl->client_session,
|
2019-11-29 13:21:55 +01:00
|
|
|
PW_CLIENT_SESSION_UPDATE_INFO,
|
|
|
|
|
0, NULL,
|
|
|
|
|
&info);
|
|
|
|
|
|
|
|
|
|
/* start monitors */
|
|
|
|
|
sm_metadata_start(&impl->this);
|
|
|
|
|
sm_alsa_midi_start(&impl->this);
|
|
|
|
|
sm_bluez5_monitor_start(&impl->this);
|
|
|
|
|
sm_alsa_monitor_start(&impl->this);
|
|
|
|
|
sm_alsa_endpoint_start(&impl->this);
|
|
|
|
|
sm_v4l2_monitor_start(&impl->this);
|
|
|
|
|
sm_stream_monitor_start(&impl->this);
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-11 16:31:58 +01:00
|
|
|
static const struct pw_proxy_events proxy_client_session_events = {
|
2019-11-29 13:21:55 +01:00
|
|
|
PW_VERSION_PROXY_EVENTS,
|
2019-12-11 16:31:58 +01:00
|
|
|
.bound = proxy_client_session_bound,
|
2019-11-29 13:21:55 +01:00
|
|
|
};
|
|
|
|
|
|
2019-11-14 18:35:29 +01:00
|
|
|
static int start_session(struct impl *impl)
|
|
|
|
|
{
|
2019-12-10 18:19:56 +01:00
|
|
|
impl->monitor_core = pw_context_connect(impl->this.context, NULL, 0);
|
2019-12-06 11:48:40 +01:00
|
|
|
if (impl->monitor_core == NULL) {
|
|
|
|
|
pw_log_error("can't start monitor: %m");
|
|
|
|
|
return -errno;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-11 07:46:59 +01:00
|
|
|
impl->client_session = pw_core_create_object(impl->monitor_core,
|
2019-11-14 18:35:29 +01:00
|
|
|
"client-session",
|
|
|
|
|
PW_TYPE_INTERFACE_ClientSession,
|
2019-12-11 16:31:58 +01:00
|
|
|
PW_VERSION_CLIENT_SESSION,
|
2019-11-14 18:35:29 +01:00
|
|
|
NULL, 0);
|
|
|
|
|
|
2019-11-29 13:21:55 +01:00
|
|
|
pw_proxy_add_listener((struct pw_proxy*)impl->client_session,
|
2019-12-11 16:31:58 +01:00
|
|
|
&impl->proxy_client_session_listener,
|
|
|
|
|
&proxy_client_session_events, impl);
|
2019-11-29 13:21:55 +01:00
|
|
|
|
2019-12-11 16:31:58 +01:00
|
|
|
pw_client_session_add_listener(impl->client_session,
|
2019-11-14 18:35:29 +01:00
|
|
|
&impl->client_session_listener,
|
2019-11-29 13:21:55 +01:00
|
|
|
&client_session_events, impl);
|
2019-11-14 18:35:29 +01:00
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void core_done(void *data, uint32_t id, int seq)
|
|
|
|
|
{
|
|
|
|
|
struct impl *impl = data;
|
2019-11-18 13:10:21 +01:00
|
|
|
struct sync *s, *t;
|
2019-11-15 12:07:26 +01:00
|
|
|
impl->last_seq = seq;
|
2019-11-18 13:10:21 +01:00
|
|
|
|
|
|
|
|
spa_list_for_each_safe(s, t, &impl->sync_list, link) {
|
|
|
|
|
if (s->seq == seq) {
|
|
|
|
|
spa_list_remove(&s->link);
|
|
|
|
|
s->callback(s->data);
|
|
|
|
|
free(s);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-11-15 12:07:26 +01:00
|
|
|
if (impl->rescan_seq == seq) {
|
|
|
|
|
pw_log_trace(NAME" %p: rescan %u %d", impl, id, seq);
|
2019-11-14 18:35:29 +01:00
|
|
|
sm_media_session_emit_rescan(impl, seq);
|
2019-11-15 12:07:26 +01:00
|
|
|
}
|
2019-11-14 18:35:29 +01:00
|
|
|
}
|
|
|
|
|
|
2019-12-06 11:48:40 +01:00
|
|
|
static void core_error(void *data, uint32_t id, int seq, int res, const char *message)
|
2019-11-14 18:35:29 +01:00
|
|
|
{
|
2019-12-06 11:48:40 +01:00
|
|
|
struct impl *impl = data;
|
2019-11-14 18:35:29 +01:00
|
|
|
|
2019-12-06 11:48:40 +01:00
|
|
|
pw_log_error("error id:%u seq:%d res:%d (%s): %s",
|
|
|
|
|
id, seq, res, spa_strerror(res), message);
|
2019-11-14 18:35:29 +01:00
|
|
|
|
2019-12-06 11:48:40 +01:00
|
|
|
if (id == 0) {
|
2019-11-20 16:18:46 +01:00
|
|
|
pw_main_loop_quit(impl->loop);
|
2019-11-14 18:35:29 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-02 11:25:27 +02:00
|
|
|
|
2019-12-11 07:46:59 +01:00
|
|
|
static const struct pw_core_events core_events = {
|
|
|
|
|
PW_VERSION_CORE_EVENTS,
|
2019-12-06 11:48:40 +01:00
|
|
|
.done = core_done,
|
|
|
|
|
.error = core_error
|
2019-11-28 11:13:53 +01:00
|
|
|
};
|
|
|
|
|
|
2019-12-06 11:48:40 +01:00
|
|
|
static int start_policy(struct impl *impl)
|
2018-08-02 11:25:27 +02:00
|
|
|
{
|
2019-12-10 18:19:56 +01:00
|
|
|
impl->policy_core = pw_context_connect(impl->this.context, NULL, 0);
|
2019-12-06 11:48:40 +01:00
|
|
|
if (impl->policy_core == NULL) {
|
|
|
|
|
pw_log_error("can't start policy: %m");
|
|
|
|
|
return -errno;
|
|
|
|
|
}
|
2018-09-26 13:22:21 +02:00
|
|
|
|
2019-12-11 07:46:59 +01:00
|
|
|
pw_core_add_listener(impl->policy_core,
|
2019-12-06 11:48:40 +01:00
|
|
|
&impl->policy_listener,
|
|
|
|
|
&core_events, impl);
|
2019-12-11 09:44:48 +01:00
|
|
|
impl->registry = pw_core_get_registry(impl->policy_core,
|
|
|
|
|
PW_VERSION_REGISTRY, 0);
|
|
|
|
|
pw_registry_add_listener(impl->registry,
|
2019-12-06 11:48:40 +01:00
|
|
|
&impl->registry_listener,
|
|
|
|
|
®istry_events, impl);
|
2018-08-02 11:25:27 +02:00
|
|
|
|
2019-12-06 11:48:40 +01:00
|
|
|
return sm_policy_ep_start(&impl->this);
|
2018-08-02 11:25:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
struct impl impl = { 0, };
|
2019-11-20 16:18:46 +01:00
|
|
|
const struct spa_support *support;
|
|
|
|
|
uint32_t n_support;
|
2018-08-02 11:25:27 +02:00
|
|
|
|
|
|
|
|
pw_init(&argc, &argv);
|
|
|
|
|
|
2019-11-20 16:18:46 +01:00
|
|
|
impl.loop = pw_main_loop_new(NULL);
|
|
|
|
|
impl.this.loop = pw_main_loop_get_loop(impl.loop);
|
2019-12-10 18:19:56 +01:00
|
|
|
impl.this.context = pw_context_new(impl.this.loop, NULL, 0);
|
2018-08-02 11:25:27 +02:00
|
|
|
|
2019-12-10 18:19:56 +01:00
|
|
|
pw_context_add_spa_lib(impl.this.context, "api.bluez5.*", "bluez5/libspa-bluez5");
|
|
|
|
|
pw_context_add_spa_lib(impl.this.context, "api.alsa.*", "alsa/libspa-alsa");
|
|
|
|
|
pw_context_add_spa_lib(impl.this.context, "api.v4l2.*", "v4l2/libspa-v4l2");
|
2019-07-10 20:24:11 +02:00
|
|
|
|
2019-11-14 18:35:29 +01:00
|
|
|
pw_map_init(&impl.globals, 64, 64);
|
2019-11-19 16:07:41 +01:00
|
|
|
spa_list_init(&impl.global_list);
|
2019-11-15 17:13:45 +01:00
|
|
|
pw_map_init(&impl.endpoint_links, 64, 64);
|
|
|
|
|
spa_list_init(&impl.endpoint_link_list);
|
2019-11-18 13:10:21 +01:00
|
|
|
spa_list_init(&impl.sync_list);
|
2019-11-14 18:35:29 +01:00
|
|
|
spa_hook_list_init(&impl.hooks);
|
2018-08-02 11:25:27 +02:00
|
|
|
|
2019-12-10 18:19:56 +01:00
|
|
|
support = pw_context_get_support(impl.this.context, &n_support);
|
2019-11-20 16:18:46 +01:00
|
|
|
|
|
|
|
|
impl.dbus = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_DBus);
|
|
|
|
|
if (impl.dbus)
|
|
|
|
|
impl.this.dbus_connection = spa_dbus_get_connection(impl.dbus, DBUS_BUS_SESSION);
|
|
|
|
|
if (impl.this.dbus_connection == NULL)
|
|
|
|
|
pw_log_warn("no dbus connection");
|
|
|
|
|
else
|
|
|
|
|
pw_log_debug("got dbus connection %p", impl.this.dbus_connection);
|
|
|
|
|
|
2019-12-06 11:48:40 +01:00
|
|
|
if (start_session(&impl) < 0)
|
|
|
|
|
return -1;
|
|
|
|
|
if (start_policy(&impl) < 0)
|
|
|
|
|
return -1;
|
2019-11-03 10:31:14 +01:00
|
|
|
|
2019-11-20 16:18:46 +01:00
|
|
|
pw_main_loop_run(impl.loop);
|
2018-08-02 11:25:27 +02:00
|
|
|
|
2019-12-10 18:19:56 +01:00
|
|
|
pw_context_destroy(impl.this.context);
|
2019-11-20 16:18:46 +01:00
|
|
|
pw_main_loop_destroy(impl.loop);
|
2018-08-02 11:25:27 +02:00
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|