mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
node: add port and node params
Add a new struct spa_param_info that lists the available params on a node/port and if they are readable/writable/updated. We can use this to replace and improve the PARAM_List and also to notify property change and updates. Update elements and code to deal with this new param stuff. Add port and node info to most elements and signal changes. Use async enum_params in -inspect and use the param info to know which ones to enumerate. Use the port info to know what parameters to update in the remote-node.
This commit is contained in:
parent
3d25adc598
commit
499dd3ff22
52 changed files with 1979 additions and 1461 deletions
|
|
@ -1 +1 @@
|
|||
Subproject commit cc9fd857ad106dcd74327ccfedc334aadd79caaa
|
||||
Subproject commit 91938991dc062085401f28ef8e847b9b2925b749
|
||||
|
|
@ -41,12 +41,12 @@ struct spa_device_info {
|
|||
#define SPA_VERSION_DEVICE_INFO 0
|
||||
uint32_t version;
|
||||
|
||||
#define SPA_DEVICE_CHANGE_MASK_INFO (1<<0)
|
||||
#define SPA_DEVICE_CHANGE_MASK_PROPS (1<<0)
|
||||
#define SPA_DEVICE_CHANGE_MASK_PARAMS (1<<1)
|
||||
uint64_t change_mask;
|
||||
const struct spa_dict *info;
|
||||
const struct spa_dict *props;
|
||||
struct spa_param_info *params;
|
||||
uint32_t n_params;
|
||||
uint32_t *params;
|
||||
};
|
||||
|
||||
#define SPA_DEVICE_INFO_INIT() (struct spa_device_info){ SPA_VERSION_DEVICE_INFO, }
|
||||
|
|
@ -58,9 +58,9 @@ struct spa_device_object_info {
|
|||
uint32_t type;
|
||||
const struct spa_handle_factory *factory;
|
||||
|
||||
#define SPA_DEVICE_OBJECT_CHANGE_MASK_INFO (1<<0)
|
||||
#define SPA_DEVICE_OBJECT_CHANGE_MASK_PROPS (1<<0)
|
||||
uint64_t change_mask;
|
||||
const struct spa_dict *info;
|
||||
const struct spa_dict *props;
|
||||
};
|
||||
|
||||
#define SPA_DEVICE_OBJECT_INFO_INIT() (struct spa_device_object_info){ SPA_VERSION_DEVICE_OBJECT_INFO, }
|
||||
|
|
|
|||
|
|
@ -55,9 +55,7 @@ struct spa_io_buffers {
|
|||
#define SPA_STATUS_OK 0
|
||||
#define SPA_STATUS_NEED_BUFFER (1<<0)
|
||||
#define SPA_STATUS_HAVE_BUFFER (1<<1)
|
||||
#define SPA_STATUS_FORMAT_CHANGED (1<<2)
|
||||
#define SPA_STATUS_PORT_CHANGED (1<<3)
|
||||
#define SPA_STATUS_PARAM_CHANGED (1<<4)
|
||||
#define SPA_STATUS_STOPPED (1<<2)
|
||||
int32_t status; /**< the status code */
|
||||
uint32_t buffer_id; /**< a buffer id */
|
||||
};
|
||||
|
|
|
|||
|
|
@ -52,12 +52,16 @@ struct spa_node_info {
|
|||
uint32_t max_output_ports;
|
||||
#define SPA_NODE_CHANGE_MASK_FLAGS (1u<<0)
|
||||
#define SPA_NODE_CHANGE_MASK_PROPS (1u<<1)
|
||||
#define SPA_NODE_CHANGE_MASK_PARAMS (1u<<2)
|
||||
uint64_t change_mask;
|
||||
|
||||
#define SPA_NODE_FLAG_DYNAMIC_INPUT_PORTS (1u<<0) /**< input ports can be added/removed */
|
||||
#define SPA_NODE_FLAG_DYNAMIC_OUTPUT_PORTS (1u<<1) /**< output ports can be added/removed */
|
||||
#define SPA_NODE_FLAG_RT (1u<<2) /**< node can do real-time processing */
|
||||
uint32_t flags;
|
||||
struct spa_dict *props;
|
||||
struct spa_dict *props; /**< extra node properties */
|
||||
struct spa_param_info *params; /**< parameter information */
|
||||
uint32_t n_params; /**< number of items in \a params */
|
||||
};
|
||||
|
||||
#define SPA_NODE_INFO_INIT() (struct spa_node_info) { 0, }
|
||||
|
|
@ -71,6 +75,7 @@ struct spa_port_info {
|
|||
#define SPA_PORT_CHANGE_MASK_FLAGS (1u<<0)
|
||||
#define SPA_PORT_CHANGE_MASK_RATE (1u<<1)
|
||||
#define SPA_PORT_CHANGE_MASK_PROPS (1u<<2)
|
||||
#define SPA_PORT_CHANGE_MASK_PARAMS (1u<<3)
|
||||
uint64_t change_mask;
|
||||
|
||||
#define SPA_PORT_FLAG_REMOVABLE (1u<<0) /**< port can be removed */
|
||||
|
|
@ -90,6 +95,8 @@ struct spa_port_info {
|
|||
uint32_t flags; /**< port flags */
|
||||
uint32_t rate; /**< rate of sequence numbers on port */
|
||||
const struct spa_dict *props; /**< extra port properties */
|
||||
struct spa_param_info *params; /**< parameter information */
|
||||
uint32_t n_params; /**< number of items in \a params */
|
||||
};
|
||||
|
||||
#define SPA_PORT_INFO_INIT() (struct spa_port_info) { 0, }
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ extern "C" {
|
|||
/** different parameter types that can be queried */
|
||||
enum spa_param_type {
|
||||
SPA_PARAM_Invalid, /**< invalid */
|
||||
SPA_PARAM_List, /**< available params as SPA_TYPE_OBJECT_ParamList */
|
||||
SPA_PARAM_PropInfo, /**< property information as SPA_TYPE_OBJECT_PropInfo */
|
||||
SPA_PARAM_Props, /**< properties as SPA_TYPE_OBJECT_Props */
|
||||
SPA_PARAM_EnumFormat, /**< available formats as SPA_TYPE_OBJECT_Format */
|
||||
|
|
|
|||
|
|
@ -41,7 +41,6 @@ extern "C" {
|
|||
|
||||
static const struct spa_type_info spa_type_param[] = {
|
||||
{ SPA_PARAM_Invalid, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ID_BASE "Invalid", NULL },
|
||||
{ SPA_PARAM_List, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ID_BASE "List", NULL },
|
||||
{ SPA_PARAM_PropInfo, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ID_BASE "PropInfo", NULL },
|
||||
{ SPA_PARAM_Props, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ID_BASE "Props", NULL },
|
||||
{ SPA_PARAM_EnumFormat, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ID_BASE "EnumFormat", NULL },
|
||||
|
|
@ -57,16 +56,6 @@ static const struct spa_type_info spa_type_param[] = {
|
|||
#define SPA_TYPE_INFO_Param SPA_TYPE_INFO_OBJECT_BASE "Param"
|
||||
#define SPA_TYPE_INFO_PARAM_BASE SPA_TYPE_INFO_Param ":"
|
||||
|
||||
/* object with supported parameter id */
|
||||
#define SPA_TYPE_INFO_PARAM_List SPA_TYPE_INFO_PARAM_BASE "List"
|
||||
#define SPA_TYPE_INFO_PARAM_LIST_BASE SPA_TYPE_INFO_PARAM_List ":"
|
||||
|
||||
static const struct spa_type_info spa_type_param_list[] = {
|
||||
{ SPA_PARAM_LIST_START, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_LIST_BASE, spa_type_param },
|
||||
{ SPA_PARAM_LIST_id, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_LIST_BASE "id", spa_type_param },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
#define SPA_TYPE_INFO_Props SPA_TYPE_INFO_PARAM_BASE "Props"
|
||||
#define SPA_TYPE_INFO_PROPS_BASE SPA_TYPE_INFO_Props ":"
|
||||
|
||||
|
|
|
|||
|
|
@ -72,6 +72,19 @@ struct spa_fraction {
|
|||
uint32_t denom;
|
||||
};
|
||||
|
||||
struct spa_param_info {
|
||||
uint32_t id;
|
||||
#define SPA_PARAM_INFO_SERIAL (1<<0) /**< bit to signal update even when the
|
||||
* read/write flags don't change */
|
||||
#define SPA_PARAM_INFO_READ (1<<1)
|
||||
#define SPA_PARAM_INFO_WRITE (1<<2)
|
||||
#define SPA_PARAM_INFO_READWRITE (SPA_PARAM_INFO_WRITE|SPA_PARAM_INFO_READ)
|
||||
uint32_t flags;
|
||||
uint32_t padding[6];
|
||||
};
|
||||
|
||||
#define SPA_PARAM_INFO(id,flags) (struct spa_param_info){ (id), (flags) }
|
||||
|
||||
#define SPA_N_ELEMENTS(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
|
||||
#define SPA_MIN(a,b) \
|
||||
|
|
|
|||
|
|
@ -123,7 +123,6 @@ static const struct spa_type_info spa_types[] = {
|
|||
|
||||
{ SPA_TYPE_OBJECT_START, SPA_TYPE_Object, SPA_TYPE_INFO_Object, NULL },
|
||||
{ SPA_TYPE_OBJECT_MonitorItem, SPA_TYPE_Object, SPA_TYPE_INFO_MonitorItem, spa_type_monitor_item },
|
||||
{ SPA_TYPE_OBJECT_ParamList, SPA_TYPE_Object, SPA_TYPE_INFO_PARAM_List, spa_type_param_list, },
|
||||
{ SPA_TYPE_OBJECT_PropInfo, SPA_TYPE_Object, SPA_TYPE_INFO_PropInfo, spa_type_prop_info, },
|
||||
{ SPA_TYPE_OBJECT_Props, SPA_TYPE_Object, SPA_TYPE_INFO_Props, spa_type_props },
|
||||
{ SPA_TYPE_OBJECT_Format, SPA_TYPE_Object, SPA_TYPE_INFO_Format, spa_type_format },
|
||||
|
|
|
|||
|
|
@ -94,7 +94,6 @@ enum {
|
|||
/* Objects */
|
||||
SPA_TYPE_OBJECT_START = 0x50000,
|
||||
SPA_TYPE_OBJECT_MonitorItem,
|
||||
SPA_TYPE_OBJECT_ParamList,
|
||||
SPA_TYPE_OBJECT_PropInfo,
|
||||
SPA_TYPE_OBJECT_Props,
|
||||
SPA_TYPE_OBJECT_Format,
|
||||
|
|
|
|||
|
|
@ -117,8 +117,7 @@ static int emit_node(struct impl *this, snd_pcm_info_t *pcminfo, uint32_t id)
|
|||
else
|
||||
info.factory = &spa_alsa_source_factory;
|
||||
|
||||
info.change_mask = SPA_DEVICE_OBJECT_CHANGE_MASK_INFO;
|
||||
|
||||
info.change_mask = SPA_DEVICE_OBJECT_CHANGE_MASK_PROPS;
|
||||
snprintf(device_name, 128, "%s,%d", this->props.device, snd_pcm_info_get_device(pcminfo));
|
||||
items[0] = SPA_DICT_ITEM_INIT("alsa.device", device_name);
|
||||
items[1] = SPA_DICT_ITEM_INIT("alsa.pcm.id", snd_pcm_info_get_id(pcminfo));
|
||||
|
|
@ -126,7 +125,7 @@ static int emit_node(struct impl *this, snd_pcm_info_t *pcminfo, uint32_t id)
|
|||
items[3] = SPA_DICT_ITEM_INIT("alsa.pcm.subname", snd_pcm_info_get_subdevice_name(pcminfo));
|
||||
items[4] = SPA_DICT_ITEM_INIT("alsa.pcm.class", get_class(pcminfo));
|
||||
items[5] = SPA_DICT_ITEM_INIT("alsa.pcm.subclass", get_subclass(pcminfo));
|
||||
info.info = &SPA_DICT_INIT_ARRAY(items);
|
||||
info.props = &SPA_DICT_INIT_ARRAY(items);
|
||||
|
||||
this->callbacks->object_info(this->callbacks_data, id, &info);
|
||||
|
||||
|
|
@ -214,7 +213,7 @@ static int emit_info(struct impl *this)
|
|||
snd_ctl_t *ctl_hndl;
|
||||
snd_ctl_card_info_t *info;
|
||||
struct spa_device_info dinfo;
|
||||
uint32_t params[] = { SPA_PARAM_EnumProfile, SPA_PARAM_Profile };
|
||||
struct spa_param_info params[2];
|
||||
|
||||
spa_log_info(this->log, "open card %s", this->props.device);
|
||||
if ((err = snd_ctl_open(&ctl_hndl, this->props.device, 0)) < 0) {
|
||||
|
|
@ -230,8 +229,8 @@ static int emit_info(struct impl *this)
|
|||
}
|
||||
|
||||
dinfo = SPA_DEVICE_INFO_INIT();
|
||||
dinfo.change_mask = SPA_DEVICE_CHANGE_MASK_INFO | SPA_DEVICE_CHANGE_MASK_PARAMS;
|
||||
|
||||
dinfo.change_mask = SPA_DEVICE_CHANGE_MASK_PROPS;
|
||||
items[0] = SPA_DICT_ITEM_INIT("device.api", "alsa");
|
||||
items[1] = SPA_DICT_ITEM_INIT("device.path", (char *)this->props.device);
|
||||
items[2] = SPA_DICT_ITEM_INIT("device.nick", snd_ctl_card_info_get_id(info));
|
||||
|
|
@ -242,7 +241,11 @@ static int emit_info(struct impl *this)
|
|||
items[7] = SPA_DICT_ITEM_INIT("alsa.card.name", snd_ctl_card_info_get_name(info));
|
||||
items[8] = SPA_DICT_ITEM_INIT("alsa.card.longname", snd_ctl_card_info_get_longname(info));
|
||||
items[9] = SPA_DICT_ITEM_INIT("alsa.card.mixername", snd_ctl_card_info_get_mixername(info));
|
||||
dinfo.info = &SPA_DICT_INIT(items, 10);
|
||||
dinfo.props = &SPA_DICT_INIT(items, 10);
|
||||
|
||||
dinfo.change_mask |= SPA_DEVICE_CHANGE_MASK_PARAMS;
|
||||
params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumProfile, SPA_PARAM_INFO_READ);
|
||||
params[1] = SPA_PARAM_INFO(SPA_PARAM_Profile, SPA_PARAM_INFO_READWRITE);
|
||||
dinfo.n_params = SPA_N_ELEMENTS(params);
|
||||
dinfo.params = params;
|
||||
|
||||
|
|
@ -303,19 +306,6 @@ static int impl_enum_params(struct spa_device *device, int seq,
|
|||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
|
||||
switch (id) {
|
||||
case SPA_PARAM_List:
|
||||
{
|
||||
uint32_t list[] = { SPA_PARAM_EnumProfile,
|
||||
SPA_PARAM_Profile };
|
||||
|
||||
if (result.index < SPA_N_ELEMENTS(list))
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_ParamList, id,
|
||||
SPA_PARAM_LIST_id, SPA_POD_Id(list[result.index]));
|
||||
else
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
case SPA_PARAM_EnumProfile:
|
||||
{
|
||||
switch (result.index) {
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include <asoundlib.h>
|
||||
|
||||
#include <spa/node/node.h>
|
||||
#include <spa/node/utils.h>
|
||||
#include <spa/param/audio/format.h>
|
||||
#include <spa/pod/filter.h>
|
||||
#include <spa/debug/pod.h>
|
||||
|
|
@ -74,19 +75,6 @@ static int impl_node_enum_params(struct spa_node *node, int seq,
|
|||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
|
||||
switch (id) {
|
||||
case SPA_PARAM_List:
|
||||
{
|
||||
uint32_t list[] = { SPA_PARAM_PropInfo,
|
||||
SPA_PARAM_Props };
|
||||
|
||||
if (result.index < SPA_N_ELEMENTS(list))
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_ParamList, id,
|
||||
SPA_PARAM_LIST_id, SPA_POD_Id(list[result.index]));
|
||||
else
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
case SPA_PARAM_PropInfo:
|
||||
{
|
||||
struct props *p = &this->props;
|
||||
|
|
@ -253,23 +241,19 @@ static const struct spa_dict_item node_info_items[] = {
|
|||
|
||||
static void emit_node_info(struct state *this)
|
||||
{
|
||||
if (this->callbacks && this->callbacks->info) {
|
||||
struct spa_node_info info;
|
||||
|
||||
info = SPA_NODE_INFO_INIT();
|
||||
info.max_input_ports = 1;
|
||||
info.change_mask = SPA_NODE_CHANGE_MASK_PROPS;
|
||||
info.props = &SPA_DICT_INIT_ARRAY(node_info_items);
|
||||
|
||||
this->callbacks->info(this->callbacks_data, &info);
|
||||
if (this->callbacks && this->callbacks->info && this->info.change_mask) {
|
||||
this->info.props = &SPA_DICT_INIT_ARRAY(node_info_items);
|
||||
this->callbacks->info(this->callbacks_data, &this->info);
|
||||
this->info.change_mask = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_port_info(struct state *this)
|
||||
{
|
||||
if (this->callbacks && this->callbacks->port_info && this->info.change_mask) {
|
||||
this->callbacks->port_info(this->callbacks_data, SPA_DIRECTION_INPUT, 0, &this->info);
|
||||
this->info.change_mask = 0;
|
||||
if (this->callbacks && this->callbacks->port_info && this->port_info.change_mask) {
|
||||
this->callbacks->port_info(this->callbacks_data,
|
||||
SPA_DIRECTION_INPUT, 0, &this->port_info);
|
||||
this->port_info.change_mask = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -335,22 +319,6 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
|
||||
switch (id) {
|
||||
case SPA_PARAM_List:
|
||||
{
|
||||
uint32_t list[] = { SPA_PARAM_EnumFormat,
|
||||
SPA_PARAM_Format,
|
||||
SPA_PARAM_Buffers,
|
||||
SPA_PARAM_Meta,
|
||||
SPA_PARAM_IO, };
|
||||
|
||||
if (result.index < SPA_N_ELEMENTS(list))
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_ParamList, id,
|
||||
SPA_PARAM_LIST_id, SPA_POD_Id(list[result.index]));
|
||||
else
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
case SPA_PARAM_EnumFormat:
|
||||
return spa_alsa_enum_format(this, seq, start, num, filter);
|
||||
|
||||
|
|
@ -382,9 +350,6 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
break;
|
||||
|
||||
case SPA_PARAM_Meta:
|
||||
if (!this->have_format)
|
||||
return -EIO;
|
||||
|
||||
switch (result.index) {
|
||||
case 0:
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
|
|
@ -456,6 +421,9 @@ static int port_set_format(struct spa_node *node,
|
|||
int err;
|
||||
|
||||
if (format == NULL) {
|
||||
if (!this->have_format)
|
||||
return 0;
|
||||
|
||||
spa_log_debug(this->log, "clear format");
|
||||
spa_alsa_pause(this);
|
||||
clear_buffers(this);
|
||||
|
|
@ -481,11 +449,17 @@ static int port_set_format(struct spa_node *node,
|
|||
this->have_format = true;
|
||||
}
|
||||
|
||||
this->port_info.change_mask |= SPA_PORT_CHANGE_MASK_RATE;
|
||||
this->port_info.rate = this->rate;
|
||||
this->port_info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
|
||||
if (this->have_format) {
|
||||
this->info.change_mask |= SPA_PORT_CHANGE_MASK_RATE;
|
||||
this->info.rate = this->rate;
|
||||
emit_port_info(this);
|
||||
this->port_params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_READWRITE);
|
||||
this->port_params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, SPA_PARAM_INFO_READ);
|
||||
} else {
|
||||
this->port_params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
this->port_params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
|
||||
}
|
||||
emit_port_info(this);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -734,15 +708,34 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
|
||||
this->node = impl_node;
|
||||
this->stream = SND_PCM_STREAM_PLAYBACK;
|
||||
|
||||
this->info = SPA_NODE_INFO_INIT();
|
||||
this->info.max_input_ports = 1;
|
||||
this->info.change_mask = SPA_NODE_CHANGE_MASK_PROPS;
|
||||
this->info.change_mask |= SPA_NODE_CHANGE_MASK_PARAMS;
|
||||
this->params[0] = SPA_PARAM_INFO(SPA_PARAM_PropInfo, SPA_PARAM_INFO_READ);
|
||||
this->params[1] = SPA_PARAM_INFO(SPA_PARAM_Props, SPA_PARAM_INFO_READWRITE);
|
||||
this->info.params = this->params;
|
||||
this->info.n_params = 2;
|
||||
|
||||
reset_props(&this->props);
|
||||
|
||||
this->info = SPA_PORT_INFO_INIT();
|
||||
this->info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
this->info.flags = SPA_PORT_FLAG_CAN_USE_BUFFERS |
|
||||
this->port_info = SPA_PORT_INFO_INIT();
|
||||
this->port_info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
this->port_info.flags = SPA_PORT_FLAG_CAN_USE_BUFFERS |
|
||||
SPA_PORT_FLAG_LIVE |
|
||||
SPA_PORT_FLAG_PHYSICAL |
|
||||
SPA_PORT_FLAG_TERMINAL;
|
||||
|
||||
this->port_info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
|
||||
this->port_params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
|
||||
this->port_params[1] = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
|
||||
this->port_params[2] = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
|
||||
this->port_params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
this->port_params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
|
||||
this->port_info.params = this->port_params;
|
||||
this->port_info.n_params = 5;
|
||||
|
||||
spa_list_init(&this->ready);
|
||||
|
||||
for (i = 0; info && i < info->n_items; i++) {
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include <asoundlib.h>
|
||||
|
||||
#include <spa/node/node.h>
|
||||
#include <spa/node/utils.h>
|
||||
#include <spa/utils/list.h>
|
||||
#include <spa/param/audio/format.h>
|
||||
#include <spa/pod/filter.h>
|
||||
|
|
@ -76,19 +77,6 @@ static int impl_node_enum_params(struct spa_node *node, int seq,
|
|||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
|
||||
switch (id) {
|
||||
case SPA_PARAM_List:
|
||||
{
|
||||
uint32_t list[] = { SPA_PARAM_PropInfo,
|
||||
SPA_PARAM_Props, };
|
||||
|
||||
if (result.index < SPA_N_ELEMENTS(list))
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_ParamList, id,
|
||||
SPA_PARAM_LIST_id, SPA_POD_Id(list[result.index]));
|
||||
else
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
case SPA_PARAM_PropInfo:
|
||||
switch (result.index) {
|
||||
case 0:
|
||||
|
|
@ -253,23 +241,19 @@ static const struct spa_dict_item node_info_items[] = {
|
|||
|
||||
static void emit_node_info(struct state *this)
|
||||
{
|
||||
if (this->callbacks && this->callbacks->info) {
|
||||
struct spa_node_info info;
|
||||
|
||||
info = SPA_NODE_INFO_INIT();
|
||||
info.max_output_ports = 1;
|
||||
info.change_mask = SPA_NODE_CHANGE_MASK_PROPS;
|
||||
info.props = &SPA_DICT_INIT_ARRAY(node_info_items);
|
||||
|
||||
this->callbacks->info(this->callbacks_data, &info);
|
||||
if (this->callbacks && this->callbacks->info && this->info.change_mask) {
|
||||
this->info.props = &SPA_DICT_INIT_ARRAY(node_info_items);
|
||||
this->callbacks->info(this->callbacks_data, &this->info);
|
||||
this->info.change_mask = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_port_info(struct state *this)
|
||||
{
|
||||
if (this->callbacks && this->callbacks->port_info && this->info.change_mask) {
|
||||
this->callbacks->port_info(this->callbacks_data, SPA_DIRECTION_OUTPUT, 0, &this->info);
|
||||
this->info.change_mask = 0;
|
||||
if (this->callbacks && this->callbacks->port_info && this->port_info.change_mask) {
|
||||
this->callbacks->port_info(this->callbacks_data,
|
||||
SPA_DIRECTION_OUTPUT, 0, &this->port_info);
|
||||
this->port_info.change_mask = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -346,21 +330,6 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
|
||||
switch (id) {
|
||||
case SPA_PARAM_List:
|
||||
{
|
||||
uint32_t list[] = { SPA_PARAM_EnumFormat,
|
||||
SPA_PARAM_Format,
|
||||
SPA_PARAM_Buffers,
|
||||
SPA_PARAM_Meta };
|
||||
|
||||
if (result.index < SPA_N_ELEMENTS(list))
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_ParamList, id,
|
||||
SPA_PARAM_LIST_id, SPA_POD_Id(list[result.index]));
|
||||
else
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
case SPA_PARAM_EnumFormat:
|
||||
return spa_alsa_enum_format(this, seq, start, num, filter);
|
||||
|
||||
|
|
@ -392,9 +361,6 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
break;
|
||||
|
||||
case SPA_PARAM_Meta:
|
||||
if (!this->have_format)
|
||||
return -EIO;
|
||||
|
||||
switch (result.index) {
|
||||
case 0:
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
|
|
@ -460,6 +426,9 @@ static int port_set_format(struct spa_node *node,
|
|||
int err;
|
||||
|
||||
if (format == NULL) {
|
||||
if (!this->have_format)
|
||||
return 0;
|
||||
|
||||
spa_alsa_pause(this);
|
||||
clear_buffers(this);
|
||||
spa_alsa_close(this);
|
||||
|
|
@ -484,11 +453,17 @@ static int port_set_format(struct spa_node *node,
|
|||
this->have_format = true;
|
||||
}
|
||||
|
||||
this->port_info.change_mask |= SPA_PORT_CHANGE_MASK_RATE;
|
||||
this->port_info.rate = this->rate;
|
||||
this->port_info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
|
||||
if (this->have_format) {
|
||||
this->info.rate = this->rate;
|
||||
this->info.change_mask |= SPA_PORT_CHANGE_MASK_RATE;
|
||||
emit_port_info(this);
|
||||
this->port_params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_READWRITE);
|
||||
this->port_params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, SPA_PARAM_INFO_READ);
|
||||
} else {
|
||||
this->port_params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
this->port_params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
|
||||
}
|
||||
emit_port_info(this);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -499,15 +474,22 @@ impl_node_port_set_param(struct spa_node *node,
|
|||
uint32_t id, uint32_t flags,
|
||||
const struct spa_pod *param)
|
||||
{
|
||||
int res;
|
||||
|
||||
spa_return_val_if_fail(node != NULL, -EINVAL);
|
||||
|
||||
spa_return_val_if_fail(CHECK_PORT(node, direction, port_id), -EINVAL);
|
||||
|
||||
if (id == SPA_PARAM_Format) {
|
||||
return port_set_format(node, direction, port_id, flags, param);
|
||||
switch (id) {
|
||||
case SPA_PARAM_Format:
|
||||
res = port_set_format(node, direction, port_id, flags, param);
|
||||
break;
|
||||
|
||||
default:
|
||||
res = -ENOENT;
|
||||
break;
|
||||
}
|
||||
else
|
||||
return -ENOENT;
|
||||
return res;
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -747,14 +729,30 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
|
||||
this->node = impl_node;
|
||||
this->stream = SND_PCM_STREAM_CAPTURE;
|
||||
|
||||
this->info.max_output_ports = 1;
|
||||
this->info.change_mask = SPA_NODE_CHANGE_MASK_PROPS;
|
||||
this->info.change_mask |= SPA_NODE_CHANGE_MASK_PARAMS;
|
||||
this->params[0] = SPA_PARAM_INFO(SPA_PARAM_PropInfo, SPA_PARAM_INFO_READ);
|
||||
this->params[1] = SPA_PARAM_INFO(SPA_PARAM_Props, SPA_PARAM_INFO_READWRITE);
|
||||
this->info.params = this->params;
|
||||
this->info.n_params = 2;
|
||||
reset_props(&this->props);
|
||||
|
||||
this->info = SPA_PORT_INFO_INIT();
|
||||
this->info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
this->info.flags = SPA_PORT_FLAG_CAN_USE_BUFFERS |
|
||||
this->port_info = SPA_PORT_INFO_INIT();
|
||||
this->port_info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
this->port_info.flags = SPA_PORT_FLAG_CAN_USE_BUFFERS |
|
||||
SPA_PORT_FLAG_LIVE |
|
||||
SPA_PORT_FLAG_PHYSICAL |
|
||||
SPA_PORT_FLAG_TERMINAL;
|
||||
this->port_info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
|
||||
this->port_params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
|
||||
this->port_params[1] = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
|
||||
this->port_params[2] = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
|
||||
this->port_params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
this->port_params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
|
||||
this->port_info.params = this->port_params;
|
||||
this->port_info.n_params = 5;
|
||||
|
||||
spa_list_init(&this->free);
|
||||
spa_list_init(&this->ready);
|
||||
|
|
|
|||
|
|
@ -58,10 +58,10 @@ struct props {
|
|||
|
||||
struct buffer {
|
||||
uint32_t id;
|
||||
#define BUFFER_FLAG_OUT (1<<0)
|
||||
uint32_t flags;
|
||||
struct spa_buffer *buf;
|
||||
struct spa_meta_header *h;
|
||||
#define BUFFER_FLAG_OUT (1<<0)
|
||||
struct spa_list link;
|
||||
};
|
||||
|
||||
|
|
@ -80,8 +80,6 @@ struct state {
|
|||
struct spa_handle handle;
|
||||
struct spa_node node;
|
||||
|
||||
uint32_t seq;
|
||||
|
||||
struct spa_log *log;
|
||||
struct spa_loop *main_loop;
|
||||
struct spa_loop *data_loop;
|
||||
|
|
@ -92,6 +90,8 @@ struct state {
|
|||
const struct spa_node_callbacks *callbacks;
|
||||
void *callbacks_data;
|
||||
|
||||
struct spa_node_info info;
|
||||
struct spa_param_info params[8];
|
||||
struct props props;
|
||||
|
||||
bool opened;
|
||||
|
|
@ -108,7 +108,8 @@ struct state {
|
|||
int channels;
|
||||
size_t frame_size;
|
||||
|
||||
struct spa_port_info info;
|
||||
struct spa_port_info port_info;
|
||||
struct spa_param_info port_params[8];
|
||||
struct spa_io_buffers *io;
|
||||
struct spa_io_range *range;
|
||||
struct spa_io_clock *clock;
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include <spa/utils/list.h>
|
||||
#include <spa/node/node.h>
|
||||
#include <spa/node/io.h>
|
||||
#include <spa/node/utils.h>
|
||||
#include <spa/param/audio/format-utils.h>
|
||||
#include <spa/param/param.h>
|
||||
#include <spa/pod/filter.h>
|
||||
|
|
@ -76,6 +77,7 @@ struct port {
|
|||
struct spa_io_buffers *io;
|
||||
struct spa_io_sequence *control;
|
||||
struct spa_port_info info;
|
||||
struct spa_param_info params[8];
|
||||
|
||||
bool have_format;
|
||||
struct spa_audio_info format;
|
||||
|
|
@ -98,18 +100,20 @@ struct impl {
|
|||
struct spa_log *log;
|
||||
struct spa_cpu *cpu;
|
||||
|
||||
struct props props;
|
||||
|
||||
const struct spa_node_callbacks *callbacks;
|
||||
void *user_data;
|
||||
|
||||
struct spa_node_info info;
|
||||
struct props props;
|
||||
struct spa_param_info params[8];
|
||||
|
||||
bool started;
|
||||
|
||||
struct port in_port;
|
||||
struct port out_port;
|
||||
|
||||
bool started;
|
||||
|
||||
uint32_t cpu_flags;
|
||||
channelmix_func_t convert;
|
||||
uint32_t cpu_flags;
|
||||
uint32_t n_matrix;
|
||||
float matrix[4096];
|
||||
};
|
||||
|
|
@ -457,19 +461,6 @@ static int impl_node_enum_params(struct spa_node *node, int seq,
|
|||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
|
||||
switch (id) {
|
||||
case SPA_PARAM_List:
|
||||
{
|
||||
uint32_t list[] = { SPA_PARAM_PropInfo,
|
||||
SPA_PARAM_Props };
|
||||
|
||||
if (result.index < SPA_N_ELEMENTS(list))
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_ParamList, id,
|
||||
SPA_PARAM_LIST_id, SPA_POD_Id(list[result.index]));
|
||||
else
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
case SPA_PARAM_PropInfo:
|
||||
{
|
||||
struct props *p = &this->props;
|
||||
|
|
@ -592,6 +583,14 @@ static int impl_node_send_command(struct spa_node *node, const struct spa_comman
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void emit_info(struct impl *this)
|
||||
{
|
||||
if (this->callbacks && this->callbacks->info && this->info.change_mask) {
|
||||
this->callbacks->info(this->user_data, &this->info);
|
||||
this->info.change_mask = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_port_info(struct impl *this, struct port *port)
|
||||
{
|
||||
if (this->callbacks && this->callbacks->port_info && port->info.change_mask) {
|
||||
|
|
@ -614,20 +613,22 @@ impl_node_set_callbacks(struct spa_node *node,
|
|||
this->callbacks = callbacks;
|
||||
this->user_data = user_data;
|
||||
|
||||
emit_info(this);
|
||||
emit_port_info(this, GET_IN_PORT(this, 0));
|
||||
emit_port_info(this, GET_OUT_PORT(this, 0));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int impl_node_add_port(struct spa_node *node, enum spa_direction direction, uint32_t port_id,
|
||||
static int impl_node_add_port(struct spa_node *node,
|
||||
enum spa_direction direction, uint32_t port_id,
|
||||
const struct spa_dict *props)
|
||||
{
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static int
|
||||
impl_node_remove_port(struct spa_node *node, enum spa_direction direction, uint32_t port_id)
|
||||
static int impl_node_remove_port(struct spa_node *node,
|
||||
enum spa_direction direction, uint32_t port_id)
|
||||
{
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
|
@ -703,22 +704,6 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
|
||||
switch (id) {
|
||||
case SPA_PARAM_List:
|
||||
{
|
||||
uint32_t list[] = { SPA_PARAM_EnumFormat,
|
||||
SPA_PARAM_Format,
|
||||
SPA_PARAM_Buffers,
|
||||
SPA_PARAM_Meta,
|
||||
SPA_PARAM_IO };
|
||||
|
||||
if (result.index < SPA_N_ELEMENTS(list))
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_ParamList, id,
|
||||
SPA_PARAM_LIST_id, SPA_POD_Id(list[result.index]));
|
||||
else
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
case SPA_PARAM_EnumFormat:
|
||||
if ((res = port_enum_formats(node, direction, port_id,
|
||||
result.index, ¶m, &b)) <= 0)
|
||||
|
|
@ -764,9 +749,6 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
break;
|
||||
}
|
||||
case SPA_PARAM_Meta:
|
||||
if (!port->have_format)
|
||||
return -EIO;
|
||||
|
||||
switch (result.index) {
|
||||
case 0:
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
|
|
@ -870,6 +852,15 @@ static int port_set_format(struct spa_node *node,
|
|||
|
||||
spa_log_debug(this->log, NAME " %p: set format on port %d %d", this, port_id, res);
|
||||
}
|
||||
if (port->have_format) {
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_READWRITE);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, SPA_PARAM_INFO_READ);
|
||||
} else {
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
|
||||
}
|
||||
emit_port_info(this, port);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -1206,6 +1197,14 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
this->cpu_flags = spa_cpu_get_flags(this->cpu);
|
||||
|
||||
this->node = impl_node;
|
||||
this->info = SPA_NODE_INFO_INIT();
|
||||
this->info.change_mask = SPA_NODE_CHANGE_MASK_FLAGS;
|
||||
this->info.flags = SPA_NODE_FLAG_RT;
|
||||
this->params[0] = SPA_PARAM_INFO(SPA_PARAM_PropInfo, SPA_PARAM_INFO_READ);
|
||||
this->params[1] = SPA_PARAM_INFO(SPA_PARAM_Props, SPA_PARAM_INFO_READWRITE);
|
||||
this->info.params = this->params;
|
||||
this->info.n_params = 2;
|
||||
props_reset(&this->props);
|
||||
|
||||
port = GET_OUT_PORT(this, 0);
|
||||
port->direction = SPA_DIRECTION_OUTPUT;
|
||||
|
|
@ -1213,6 +1212,13 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
port->info = SPA_PORT_INFO_INIT();
|
||||
port->info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
port->info.flags = SPA_PORT_FLAG_CAN_USE_BUFFERS;
|
||||
port->params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
|
||||
port->params[1] = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
|
||||
port->params[2] = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
|
||||
port->info.params = port->params;
|
||||
port->info.n_params = 5;
|
||||
spa_list_init(&port->queue);
|
||||
|
||||
port = GET_IN_PORT(this, 0);
|
||||
|
|
@ -1221,10 +1227,15 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
port->info = SPA_PORT_INFO_INIT();
|
||||
port->info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
port->info.flags = SPA_PORT_FLAG_CAN_USE_BUFFERS;
|
||||
port->params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
|
||||
port->params[1] = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
|
||||
port->params[2] = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
|
||||
port->info.params = port->params;
|
||||
port->info.n_params = 0;
|
||||
spa_list_init(&port->queue);
|
||||
|
||||
props_reset(&this->props);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
#include <spa/utils/list.h>
|
||||
#include <spa/node/node.h>
|
||||
#include <spa/node/io.h>
|
||||
#include <spa/node/utils.h>
|
||||
#include <spa/param/audio/format-utils.h>
|
||||
#include <spa/param/param.h>
|
||||
#include <spa/pod/filter.h>
|
||||
|
|
@ -79,8 +80,7 @@ struct port {
|
|||
struct spa_io_range *ctrl;
|
||||
|
||||
struct spa_port_info info;
|
||||
struct spa_dict info_props;
|
||||
struct spa_dict_item info_props_items[2];
|
||||
struct spa_param_info params[8];
|
||||
|
||||
bool have_format;
|
||||
struct spa_audio_info format;
|
||||
|
|
@ -103,7 +103,9 @@ struct impl {
|
|||
struct spa_log *log;
|
||||
struct spa_cpu *cpu;
|
||||
|
||||
struct spa_node_info info;
|
||||
struct props props;
|
||||
struct spa_param_info params[8];
|
||||
|
||||
const struct spa_node_callbacks *callbacks;
|
||||
void *user_data;
|
||||
|
|
@ -227,9 +229,22 @@ static int impl_node_send_command(struct spa_node *node, const struct spa_comman
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void emit_info(struct impl *this)
|
||||
{
|
||||
if (this->callbacks && this->callbacks->info && this->info.change_mask) {
|
||||
this->callbacks->info(this->user_data, &this->info);
|
||||
this->info.change_mask = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_port_info(struct impl *this, struct port *port)
|
||||
{
|
||||
if (this->callbacks && this->callbacks->port_info && port->info.change_mask) {
|
||||
struct spa_dict_item items[1];
|
||||
|
||||
items[0] = SPA_DICT_ITEM_INIT("port.dsp", "32 bit float mono audio");
|
||||
port->info.props = &SPA_DICT_INIT_ARRAY(items);
|
||||
|
||||
this->callbacks->port_info(this->user_data, port->direction, port->id, &port->info);
|
||||
port->info.change_mask = 0;
|
||||
}
|
||||
|
|
@ -249,6 +264,7 @@ impl_node_set_callbacks(struct spa_node *node,
|
|||
this->callbacks = callbacks;
|
||||
this->user_data = user_data;
|
||||
|
||||
emit_info(this);
|
||||
emit_port_info(this, GET_IN_PORT(this, 0));
|
||||
emit_port_info(this, GET_OUT_PORT(this, 0));
|
||||
|
||||
|
|
@ -388,22 +404,6 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
|
||||
switch (id) {
|
||||
case SPA_PARAM_List:
|
||||
{
|
||||
uint32_t list[] = { SPA_PARAM_EnumFormat,
|
||||
SPA_PARAM_Format,
|
||||
SPA_PARAM_Buffers,
|
||||
SPA_PARAM_Meta,
|
||||
SPA_PARAM_IO };
|
||||
|
||||
if (result.index < SPA_N_ELEMENTS(list))
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_ParamList, id,
|
||||
SPA_PARAM_LIST_id, SPA_POD_Id(list[result.index]));
|
||||
else
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
case SPA_PARAM_EnumFormat:
|
||||
if ((res = port_enum_formats(node, direction, port_id,
|
||||
result.index, ¶m, &b)) <= 0)
|
||||
|
|
@ -451,9 +451,6 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
break;
|
||||
}
|
||||
case SPA_PARAM_Meta:
|
||||
if (!port->have_format)
|
||||
return -EIO;
|
||||
|
||||
switch (result.index) {
|
||||
case 0:
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
|
|
@ -582,6 +579,13 @@ static int port_set_format(struct spa_node *node,
|
|||
spa_log_debug(this->log, NAME " %p: set format on port %d %d %d",
|
||||
this, port_id, res, port->stride);
|
||||
}
|
||||
if (port->have_format) {
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_READWRITE);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, SPA_PARAM_INFO_READ);
|
||||
} else {
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -907,10 +911,13 @@ static int init_port(struct impl *this, enum spa_direction direction, uint32_t p
|
|||
port->info = SPA_PORT_INFO_INIT();
|
||||
port->info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS | SPA_PORT_CHANGE_MASK_PROPS;
|
||||
port->info.flags = flags;
|
||||
|
||||
port->info_props_items[0] = SPA_DICT_ITEM_INIT("port.dsp", "32 bit float mono audio");
|
||||
port->info_props = SPA_DICT_INIT(port->info_props_items, 1);
|
||||
port->info.props = &port->info_props;
|
||||
port->params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
|
||||
port->params[1] = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
|
||||
port->params[2] = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
|
||||
port->info.params = port->params;
|
||||
port->info.n_params = 5;
|
||||
port->have_format = false;
|
||||
emit_port_info(this, port);
|
||||
|
||||
|
|
@ -957,11 +964,16 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
if (this->cpu)
|
||||
this->cpu_flags = spa_cpu_get_flags(this->cpu);
|
||||
|
||||
this->info = SPA_NODE_INFO_INIT();
|
||||
this->info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
this->info.flags = SPA_NODE_FLAG_RT;
|
||||
this->info.params = this->params;
|
||||
this->info.n_params = 0;
|
||||
props_reset(&this->props);
|
||||
|
||||
init_port(this, SPA_DIRECTION_OUTPUT, 0, SPA_PORT_FLAG_CAN_USE_BUFFERS);
|
||||
init_port(this, SPA_DIRECTION_INPUT, 0, SPA_PORT_FLAG_CAN_USE_BUFFERS);
|
||||
|
||||
props_reset(&this->props);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include <spa/utils/list.h>
|
||||
#include <spa/node/node.h>
|
||||
#include <spa/node/io.h>
|
||||
#include <spa/node/utils.h>
|
||||
#include <spa/param/audio/format-utils.h>
|
||||
#include <spa/param/param.h>
|
||||
#include <spa/pod/filter.h>
|
||||
|
|
@ -62,8 +63,7 @@ struct port {
|
|||
struct spa_io_range *ctrl;
|
||||
|
||||
struct spa_port_info info;
|
||||
struct spa_dict info_props;
|
||||
struct spa_dict_item info_props_items[3];
|
||||
struct spa_param_info params[8];
|
||||
char position[16];
|
||||
|
||||
bool have_format;
|
||||
|
|
@ -86,6 +86,9 @@ struct impl {
|
|||
struct spa_log *log;
|
||||
struct spa_cpu *cpu;
|
||||
|
||||
struct spa_node_info info;
|
||||
struct spa_param_info params[8];
|
||||
|
||||
const struct spa_node_callbacks *callbacks;
|
||||
void *user_data;
|
||||
|
||||
|
|
@ -117,17 +120,24 @@ struct impl {
|
|||
|
||||
static void emit_node_info(struct impl *this)
|
||||
{
|
||||
if (this->callbacks && this->callbacks->info) {
|
||||
struct spa_node_info info = SPA_NODE_INFO_INIT();
|
||||
info.max_input_ports = MAX_PORTS;
|
||||
info.max_output_ports = MAX_PORTS+1;
|
||||
info.change_mask = 0;
|
||||
this->callbacks->info(this->user_data, &info);
|
||||
if (this->callbacks && this->callbacks->info && this->info.change_mask) {
|
||||
this->callbacks->info(this->user_data, &this->info);
|
||||
this->info.change_mask = 0;
|
||||
}
|
||||
}
|
||||
static void emit_port_info(struct impl *this, struct port *port)
|
||||
{
|
||||
if (this->callbacks && this->callbacks->port_info && port->info.change_mask) {
|
||||
struct spa_dict_item items[3];
|
||||
uint32_t n_items = 0;
|
||||
|
||||
if (port->info.change_mask & SPA_PORT_CHANGE_MASK_PROPS) {
|
||||
items[n_items++] = SPA_DICT_ITEM_INIT("port.dsp", "32 bit float mono audio");
|
||||
items[n_items++] = SPA_DICT_ITEM_INIT("port.channel", port->position);
|
||||
if (port->direction == SPA_DIRECTION_OUTPUT)
|
||||
items[n_items++] = SPA_DICT_ITEM_INIT("port.monitor", "1");
|
||||
port->info.props = &SPA_DICT_INIT(items, n_items);
|
||||
}
|
||||
this->callbacks->port_info(this->user_data, port->direction, port->id, &port->info);
|
||||
port->info.change_mask = 0;
|
||||
}
|
||||
|
|
@ -137,7 +147,6 @@ static int init_port(struct impl *this, enum spa_direction direction, uint32_t p
|
|||
uint32_t rate, uint32_t position)
|
||||
{
|
||||
struct port *port = GET_PORT(this, direction, port_id);
|
||||
int n_items = 0;
|
||||
|
||||
port->direction = direction;
|
||||
port->id = port_id;
|
||||
|
|
@ -145,14 +154,17 @@ static int init_port(struct impl *this, enum spa_direction direction, uint32_t p
|
|||
snprintf(port->position, 16, "%s", rindex(spa_type_audio_channel[position].name, ':')+1);
|
||||
|
||||
port->info = SPA_PORT_INFO_INIT();
|
||||
port->info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS | SPA_PORT_CHANGE_MASK_PROPS;
|
||||
port->info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
port->info.flags = SPA_PORT_FLAG_CAN_USE_BUFFERS;
|
||||
port->info_props_items[n_items++] = SPA_DICT_ITEM_INIT("port.dsp", "32 bit float mono audio");
|
||||
port->info_props_items[n_items++] = SPA_DICT_ITEM_INIT("port.channel", port->position);
|
||||
if (direction == SPA_DIRECTION_OUTPUT)
|
||||
port->info_props_items[n_items++] = SPA_DICT_ITEM_INIT("port.monitor", "1");
|
||||
port->info_props = SPA_DICT_INIT(port->info_props_items, n_items);
|
||||
port->info.props = &port->info_props;
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_PROPS;
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
|
||||
port->params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
|
||||
port->params[1] = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
|
||||
port->params[2] = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
|
||||
port->info.params = port->params;
|
||||
port->info.n_params = 5;
|
||||
|
||||
port->n_buffers = 0;
|
||||
port->have_format = false;
|
||||
|
|
@ -195,18 +207,8 @@ static int impl_node_enum_params(struct spa_node *node, int seq,
|
|||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
|
||||
switch (id) {
|
||||
case SPA_PARAM_List:
|
||||
{
|
||||
uint32_t list[] = { SPA_PARAM_Profile };
|
||||
|
||||
if (result.index < SPA_N_ELEMENTS(list))
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_ParamList, id,
|
||||
SPA_PARAM_LIST_id, SPA_POD_Id(list[result.index]));
|
||||
else
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
case SPA_PARAM_Profile:
|
||||
return -ENOTSUP;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -440,22 +442,6 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
|
||||
switch (id) {
|
||||
case SPA_PARAM_List:
|
||||
{
|
||||
uint32_t list[] = { SPA_PARAM_EnumFormat,
|
||||
SPA_PARAM_Format,
|
||||
SPA_PARAM_Buffers,
|
||||
SPA_PARAM_Meta,
|
||||
SPA_PARAM_IO, };
|
||||
|
||||
if (result.index < SPA_N_ELEMENTS(list))
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_ParamList, id,
|
||||
SPA_PARAM_LIST_id, SPA_POD_Id(list[result.index]));
|
||||
else
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
case SPA_PARAM_EnumFormat:
|
||||
if ((res = port_enum_formats(node, direction, port_id, result.index, ¶m, &b)) <= 0)
|
||||
return res;
|
||||
|
|
@ -486,9 +472,6 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
SPA_PARAM_BUFFERS_align, SPA_POD_Int(16));
|
||||
break;
|
||||
case SPA_PARAM_Meta:
|
||||
if (!port->have_format)
|
||||
return -EIO;
|
||||
|
||||
switch (result.index) {
|
||||
case 0:
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
|
|
@ -669,6 +652,14 @@ static int port_set_format(struct spa_node *node,
|
|||
|
||||
port->have_format = true;
|
||||
}
|
||||
if (port->have_format) {
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_READWRITE);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, SPA_PARAM_INFO_READ);
|
||||
} else {
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
|
||||
}
|
||||
emit_port_info(this, port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1066,12 +1057,30 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
|
||||
this->node = impl_node;
|
||||
|
||||
this->info = SPA_NODE_INFO_INIT();
|
||||
this->info.max_input_ports = MAX_PORTS;
|
||||
this->info.max_output_ports = MAX_PORTS+1;
|
||||
this->info.change_mask = SPA_NODE_CHANGE_MASK_FLAGS;
|
||||
this->info.flags = SPA_NODE_FLAG_RT;
|
||||
this->info.change_mask |= SPA_NODE_CHANGE_MASK_PARAMS;
|
||||
this->params[0] = SPA_PARAM_INFO(SPA_PARAM_Profile, SPA_PARAM_INFO_WRITE);
|
||||
this->info.params = this->params;
|
||||
this->info.n_params = 1;
|
||||
|
||||
port = GET_OUT_PORT(this, 0);
|
||||
port->direction = SPA_DIRECTION_OUTPUT;
|
||||
port->id = 0;
|
||||
port->info = SPA_PORT_INFO_INIT();
|
||||
port->info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
port->info.flags = SPA_PORT_FLAG_CAN_USE_BUFFERS;
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
|
||||
port->params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
|
||||
port->params[1] = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
|
||||
port->params[2] = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
|
||||
port->info.params = port->params;
|
||||
port->info.n_params = 5;
|
||||
spa_list_init(&port->queue);
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include <spa/utils/list.h>
|
||||
#include <spa/node/node.h>
|
||||
#include <spa/node/io.h>
|
||||
#include <spa/node/utils.h>
|
||||
#include <spa/param/audio/format-utils.h>
|
||||
#include <spa/param/param.h>
|
||||
#include <spa/pod/filter.h>
|
||||
|
|
@ -75,6 +76,7 @@ struct port {
|
|||
struct spa_io_range *io_range;
|
||||
struct spa_io_sequence *io_control;
|
||||
struct spa_port_info info;
|
||||
struct spa_param_info params[8];
|
||||
|
||||
bool have_format;
|
||||
struct spa_audio_info format;
|
||||
|
|
@ -96,6 +98,7 @@ struct impl {
|
|||
struct spa_log *log;
|
||||
struct spa_cpu *cpu;
|
||||
|
||||
struct spa_node_info info;
|
||||
struct props props;
|
||||
|
||||
const struct spa_node_callbacks *callbacks;
|
||||
|
|
@ -172,8 +175,8 @@ static int apply_props(struct impl *this, const struct spa_pod *param)
|
|||
SPA_POD_OBJECT_FOREACH(obj, prop) {
|
||||
switch (prop->key) {
|
||||
case SPA_PROP_rate:
|
||||
spa_pod_get_double(&prop->value, &p->rate);
|
||||
resample_update_rate(&this->resample, p->rate);
|
||||
if (spa_pod_get_double(&prop->value, &p->rate) == 0)
|
||||
resample_update_rate(&this->resample, p->rate);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
@ -230,6 +233,14 @@ static int impl_node_send_command(struct spa_node *node, const struct spa_comman
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void emit_node_info(struct impl *this)
|
||||
{
|
||||
if (this->callbacks && this->callbacks->info && this->info.change_mask) {
|
||||
this->callbacks->info(this->user_data, &this->info);
|
||||
this->info.change_mask = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_port_info(struct impl *this, struct port *port)
|
||||
{
|
||||
if (this->callbacks && this->callbacks->port_info && port->info.change_mask) {
|
||||
|
|
@ -252,6 +263,7 @@ impl_node_set_callbacks(struct spa_node *node,
|
|||
this->callbacks = callbacks;
|
||||
this->user_data = user_data;
|
||||
|
||||
emit_node_info(this);
|
||||
emit_port_info(this, GET_IN_PORT(this, 0));
|
||||
emit_port_info(this, GET_OUT_PORT(this, 0));
|
||||
|
||||
|
|
@ -349,22 +361,6 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
|
||||
switch (id) {
|
||||
case SPA_PARAM_List:
|
||||
{
|
||||
uint32_t list[] = { SPA_PARAM_EnumFormat,
|
||||
SPA_PARAM_Format,
|
||||
SPA_PARAM_Buffers,
|
||||
SPA_PARAM_Meta,
|
||||
SPA_PARAM_IO };
|
||||
|
||||
if (result.index < SPA_N_ELEMENTS(list))
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_ParamList, id,
|
||||
SPA_PARAM_LIST_id, SPA_POD_Id(list[result.index]));
|
||||
else
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
case SPA_PARAM_EnumFormat:
|
||||
if ((res = port_enum_formats(node, direction, port_id,
|
||||
result.index, ¶m, &b)) <= 0)
|
||||
|
|
@ -409,9 +405,6 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
break;
|
||||
}
|
||||
case SPA_PARAM_Meta:
|
||||
if (!port->have_format)
|
||||
return -EIO;
|
||||
|
||||
switch (result.index) {
|
||||
case 0:
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
|
|
@ -513,6 +506,16 @@ static int port_set_format(struct spa_node *node,
|
|||
|
||||
spa_log_debug(this->log, NAME " %p: set format on port %d %d", this, port_id, res);
|
||||
}
|
||||
|
||||
if (port->have_format) {
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
|
||||
} else {
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_READWRITE);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, SPA_PARAM_INFO_READ);
|
||||
}
|
||||
emit_port_info(this, port);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -888,12 +891,24 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
|
||||
this->node = impl_node;
|
||||
|
||||
this->info = SPA_NODE_INFO_INIT();
|
||||
this->info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
this->info.flags = SPA_NODE_FLAG_RT;
|
||||
|
||||
port = GET_OUT_PORT(this, 0);
|
||||
port->direction = SPA_DIRECTION_OUTPUT;
|
||||
port->id = 0;
|
||||
port->info = SPA_PORT_INFO_INIT();
|
||||
port->info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
port->info.flags = SPA_PORT_FLAG_CAN_USE_BUFFERS;
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
|
||||
port->params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
|
||||
port->params[1] = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
|
||||
port->params[2] = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
|
||||
port->info.params = port->params;
|
||||
port->info.n_params = 5;
|
||||
spa_list_init(&port->queue);
|
||||
|
||||
port = GET_IN_PORT(this, 0);
|
||||
|
|
@ -902,6 +917,14 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
port->info = SPA_PORT_INFO_INIT();
|
||||
port->info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
port->info.flags = SPA_PORT_FLAG_CAN_USE_BUFFERS;
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
|
||||
port->params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
|
||||
port->params[1] = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
|
||||
port->params[2] = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
|
||||
port->info.params = port->params;
|
||||
port->info.n_params = 5;
|
||||
spa_list_init(&port->queue);
|
||||
|
||||
props_reset(&this->props);
|
||||
|
|
|
|||
|
|
@ -64,6 +64,8 @@ struct port {
|
|||
struct spa_io_range *ctrl;
|
||||
|
||||
struct spa_port_info info;
|
||||
struct spa_param_info params[8];
|
||||
|
||||
struct spa_dict info_props;
|
||||
struct spa_dict_item info_props_items[2];
|
||||
char position[8];
|
||||
|
|
@ -88,6 +90,9 @@ struct impl {
|
|||
struct spa_log *log;
|
||||
struct spa_cpu *cpu;
|
||||
|
||||
struct spa_node_info info;
|
||||
struct spa_param_info params[8];
|
||||
|
||||
const struct spa_node_callbacks *callbacks;
|
||||
void *user_data;
|
||||
|
||||
|
|
@ -113,12 +118,9 @@ struct impl {
|
|||
|
||||
static void emit_node_info(struct impl *this)
|
||||
{
|
||||
if (this->callbacks && this->callbacks->info) {
|
||||
struct spa_node_info info = SPA_NODE_INFO_INIT();
|
||||
info.max_input_ports = 1;
|
||||
info.max_output_ports = MAX_PORTS;
|
||||
info.change_mask = 0;
|
||||
this->callbacks->info(this->user_data, &info);
|
||||
if (this->callbacks && this->callbacks->info && this->info.change_mask) {
|
||||
this->callbacks->info(this->user_data, &this->info);
|
||||
this->info.change_mask = 0;
|
||||
}
|
||||
}
|
||||
static void emit_port_info(struct impl *this, struct port *port)
|
||||
|
|
@ -140,13 +142,25 @@ static int init_port(struct impl *this, enum spa_direction direction,
|
|||
snprintf(port->position, 7, "%s", rindex(spa_type_audio_channel[position].name, ':')+1);
|
||||
|
||||
port->info = SPA_PORT_INFO_INIT();
|
||||
port->info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS | SPA_PORT_CHANGE_MASK_PROPS;
|
||||
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
port->info.flags = SPA_PORT_FLAG_CAN_USE_BUFFERS;
|
||||
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_PROPS;
|
||||
port->info_props_items[0] = SPA_DICT_ITEM_INIT("port.dsp", "32 bit float mono audio");
|
||||
port->info_props_items[1] = SPA_DICT_ITEM_INIT("port.channel", port->position);
|
||||
port->info_props = SPA_DICT_INIT(port->info_props_items, 2);
|
||||
port->info.props = &port->info_props;
|
||||
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
|
||||
port->params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
|
||||
port->params[1] = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
|
||||
port->params[2] = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
|
||||
port->info.params = port->params;
|
||||
port->info.n_params = 5;
|
||||
|
||||
spa_list_init(&port->queue);
|
||||
|
||||
port->n_buffers = 0;
|
||||
|
|
@ -190,18 +204,6 @@ static int impl_node_enum_params(struct spa_node *node, int seq,
|
|||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
|
||||
switch (id) {
|
||||
case SPA_PARAM_List:
|
||||
{
|
||||
uint32_t list[] = { SPA_PARAM_Profile };
|
||||
|
||||
if (result.index < SPA_N_ELEMENTS(list))
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_ParamList, id,
|
||||
SPA_PARAM_LIST_id, SPA_POD_Id(list[result.index]));
|
||||
else
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -431,22 +433,6 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
|
||||
switch (id) {
|
||||
case SPA_PARAM_List:
|
||||
{
|
||||
uint32_t list[] = { SPA_PARAM_EnumFormat,
|
||||
SPA_PARAM_Format,
|
||||
SPA_PARAM_Buffers,
|
||||
SPA_PARAM_Meta,
|
||||
SPA_PARAM_IO };
|
||||
|
||||
if (result.index < SPA_N_ELEMENTS(list))
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_ParamList, id,
|
||||
SPA_PARAM_LIST_id, SPA_POD_Id(list[result.index]));
|
||||
else
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
case SPA_PARAM_EnumFormat:
|
||||
if ((res = port_enum_formats(node, direction, port_id,
|
||||
result.index, ¶m, &b)) <= 0)
|
||||
|
|
@ -479,9 +465,6 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
break;
|
||||
|
||||
case SPA_PARAM_Meta:
|
||||
if (!port->have_format)
|
||||
return -EIO;
|
||||
|
||||
switch (result.index) {
|
||||
case 0:
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
|
|
@ -645,6 +628,14 @@ static int port_set_format(struct spa_node *node,
|
|||
|
||||
port->have_format = true;
|
||||
}
|
||||
if (port->have_format) {
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_READWRITE);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, SPA_PARAM_INFO_READ);
|
||||
} else {
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
|
||||
}
|
||||
emit_port_info(this, port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -993,13 +984,30 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
this->cpu_flags = spa_cpu_get_flags(this->cpu);
|
||||
|
||||
this->node = impl_node;
|
||||
this->info = SPA_NODE_INFO_INIT();
|
||||
this->info.max_input_ports = 1;
|
||||
this->info.max_output_ports = MAX_PORTS;
|
||||
this->info.change_mask |= SPA_NODE_CHANGE_MASK_FLAGS;
|
||||
this->info.flags = SPA_NODE_FLAG_RT;
|
||||
this->info.change_mask |= SPA_NODE_CHANGE_MASK_PARAMS;
|
||||
this->params[0] = SPA_PARAM_INFO(SPA_PARAM_Profile, SPA_PARAM_INFO_WRITE);
|
||||
this->info.params = this->params;
|
||||
this->info.n_params = 1;
|
||||
|
||||
port = GET_IN_PORT(this, 0);
|
||||
port->direction = SPA_DIRECTION_INPUT;
|
||||
port->id = 0;
|
||||
port->info = SPA_PORT_INFO_INIT();
|
||||
port->info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
port->info.flags = SPA_PORT_FLAG_CAN_USE_BUFFERS;
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
|
||||
port->params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
|
||||
port->params[1] = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
|
||||
port->params[2] = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
|
||||
port->info.params = port->params;
|
||||
port->info.n_params = 5;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ struct port {
|
|||
int32_t *io_mute;
|
||||
|
||||
struct spa_port_info info;
|
||||
struct spa_param_info params[5];
|
||||
|
||||
int valid:1;
|
||||
int have_format:1;
|
||||
|
|
@ -96,6 +97,9 @@ struct impl {
|
|||
|
||||
struct spa_audiomixer_ops ops;
|
||||
|
||||
struct spa_node_info info;
|
||||
struct spa_param_info params[8];
|
||||
|
||||
const struct spa_node_callbacks *callbacks;
|
||||
void *user_data;
|
||||
|
||||
|
|
@ -166,6 +170,14 @@ static int impl_node_send_command(struct spa_node *node, const struct spa_comman
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void emit_node_info(struct impl *this)
|
||||
{
|
||||
if (this->callbacks && this->callbacks->info && this->info.change_mask) {
|
||||
this->callbacks->info(this->user_data, &this->info);
|
||||
this->info.change_mask = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_port_info(struct impl *this, struct port *port)
|
||||
{
|
||||
if (this->callbacks && this->callbacks->port_info && port->info.change_mask) {
|
||||
|
|
@ -189,6 +201,7 @@ impl_node_set_callbacks(struct spa_node *node,
|
|||
this->callbacks = callbacks;
|
||||
this->user_data = user_data;
|
||||
|
||||
emit_node_info(this);
|
||||
emit_port_info(this, GET_OUT_PORT(this, 0));
|
||||
for (i = 0; i < this->last_port; i++) {
|
||||
if (this->in_ports[i].valid)
|
||||
|
|
@ -221,11 +234,19 @@ static int impl_node_add_port(struct spa_node *node, enum spa_direction directio
|
|||
|
||||
spa_list_init(&port->queue);
|
||||
port->info = SPA_PORT_INFO_INIT();
|
||||
port->info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
port->info.flags = SPA_PORT_FLAG_CAN_USE_BUFFERS |
|
||||
SPA_PORT_FLAG_REMOVABLE |
|
||||
SPA_PORT_FLAG_OPTIONAL |
|
||||
SPA_PORT_FLAG_IN_PLACE;
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
|
||||
port->params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
|
||||
port->params[1] = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
|
||||
port->params[2] = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
|
||||
port->info.params = port->params;
|
||||
port->info.n_params = 5;
|
||||
|
||||
this->port_count++;
|
||||
if (this->last_port <= port_id)
|
||||
|
|
@ -343,22 +364,6 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
|
||||
switch (id) {
|
||||
case SPA_PARAM_List:
|
||||
{
|
||||
uint32_t list[] = { SPA_PARAM_EnumFormat,
|
||||
SPA_PARAM_Format,
|
||||
SPA_PARAM_Buffers,
|
||||
SPA_PARAM_Meta,
|
||||
SPA_PARAM_IO, };
|
||||
|
||||
if (result.index < SPA_N_ELEMENTS(list))
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_ParamList, id,
|
||||
SPA_PARAM_LIST_id, SPA_POD_Id(list[result.index]));
|
||||
else
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
case SPA_PARAM_EnumFormat:
|
||||
if ((res = port_enum_formats(node, direction, port_id,
|
||||
result.index, ¶m, &b)) <= 0)
|
||||
|
|
@ -390,9 +395,6 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
SPA_PARAM_BUFFERS_align, SPA_POD_Int(16));
|
||||
break;
|
||||
case SPA_PARAM_Meta:
|
||||
if (!port->have_format)
|
||||
return -EIO;
|
||||
|
||||
switch (result.index) {
|
||||
case 0:
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
|
|
@ -518,6 +520,14 @@ static int port_set_format(struct spa_node *node,
|
|||
spa_log_info(this->log, NAME " %p: set format on port %d", this, port_id);
|
||||
}
|
||||
}
|
||||
if (port->have_format) {
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_READWRITE);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, SPA_PARAM_INFO_READ);
|
||||
} else {
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
|
||||
}
|
||||
emit_port_info(this, port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -928,13 +938,31 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
}
|
||||
|
||||
this->node = impl_node;
|
||||
this->info = SPA_NODE_INFO_INIT();
|
||||
this->info.max_input_ports = MAX_PORTS;
|
||||
this->info.max_output_ports = 1;
|
||||
this->info.change_mask |= SPA_NODE_CHANGE_MASK_FLAGS;
|
||||
this->info.flags = SPA_NODE_FLAG_DYNAMIC_INPUT_PORTS |
|
||||
SPA_NODE_FLAG_RT;
|
||||
this->info.params = this->params;
|
||||
|
||||
port = GET_OUT_PORT(this, 0);
|
||||
port->valid = true;
|
||||
port->direction = SPA_DIRECTION_OUTPUT;
|
||||
port->id = 0;
|
||||
port->info = SPA_PORT_INFO_INIT();
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
port->info.flags = SPA_PORT_FLAG_CAN_USE_BUFFERS |
|
||||
SPA_PORT_FLAG_NO_REF;
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
|
||||
port->params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
|
||||
port->params[1] = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
|
||||
port->params[2] = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
|
||||
port->info.params = port->params;
|
||||
port->info.n_params = 5;
|
||||
|
||||
spa_list_init(&port->queue);
|
||||
|
||||
spa_audiomixer_get_ops(&this->ops);
|
||||
|
|
|
|||
|
|
@ -41,8 +41,8 @@
|
|||
|
||||
#define NAME "audiotestsrc"
|
||||
|
||||
#define SAMPLES_TO_TIME(this,s) ((s) * SPA_NSEC_PER_SEC / (this)->current_format.info.raw.rate)
|
||||
#define BYTES_TO_SAMPLES(this,b) ((b)/(this)->bpf)
|
||||
#define SAMPLES_TO_TIME(this,s) ((s) * SPA_NSEC_PER_SEC / (port)->current_format.info.raw.rate)
|
||||
#define BYTES_TO_SAMPLES(this,b) ((b)/(port)->bpf)
|
||||
#define BYTES_TO_TIME(this,b) SAMPLES_TO_TIME(this, BYTES_TO_SAMPLES (this, b))
|
||||
|
||||
enum wave_type {
|
||||
|
|
@ -85,23 +85,10 @@ struct impl;
|
|||
|
||||
typedef int (*render_func_t) (struct impl *this, void *samples, size_t n_samples);
|
||||
|
||||
struct impl {
|
||||
struct spa_handle handle;
|
||||
struct spa_node node;
|
||||
|
||||
struct spa_log *log;
|
||||
struct spa_loop *data_loop;
|
||||
|
||||
struct props props;
|
||||
|
||||
const struct spa_node_callbacks *callbacks;
|
||||
void *callbacks_data;
|
||||
|
||||
bool async;
|
||||
struct spa_source timer_source;
|
||||
struct itimerspec timerspec;
|
||||
|
||||
struct port {
|
||||
struct spa_port_info info;
|
||||
struct spa_param_info params[5];
|
||||
|
||||
struct spa_io_buffers *io;
|
||||
struct spa_io_range *io_range;
|
||||
struct spa_io_sequence *io_control;
|
||||
|
|
@ -115,12 +102,34 @@ struct impl {
|
|||
struct buffer buffers[MAX_BUFFERS];
|
||||
uint32_t n_buffers;
|
||||
|
||||
struct spa_list empty;
|
||||
};
|
||||
|
||||
struct impl {
|
||||
struct spa_handle handle;
|
||||
struct spa_node node;
|
||||
|
||||
struct spa_log *log;
|
||||
struct spa_loop *data_loop;
|
||||
|
||||
struct spa_node_info info;
|
||||
struct spa_param_info params[2];
|
||||
struct props props;
|
||||
|
||||
const struct spa_node_callbacks *callbacks;
|
||||
void *callbacks_data;
|
||||
|
||||
bool async;
|
||||
struct spa_source timer_source;
|
||||
struct itimerspec timerspec;
|
||||
|
||||
bool started;
|
||||
uint64_t start_time;
|
||||
uint64_t elapsed_time;
|
||||
|
||||
uint64_t sample_count;
|
||||
struct spa_list empty;
|
||||
|
||||
struct port port;
|
||||
};
|
||||
|
||||
#define CHECK_PORT(this,d,p) ((d) == SPA_DIRECTION_OUTPUT && (p) < MAX_PORTS)
|
||||
|
|
@ -151,19 +160,6 @@ static int impl_node_enum_params(struct spa_node *node, int seq,
|
|||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
|
||||
switch (id) {
|
||||
case SPA_PARAM_List:
|
||||
{
|
||||
uint32_t list[] = { SPA_PARAM_PropInfo,
|
||||
SPA_PARAM_Props };
|
||||
|
||||
if (result.index < SPA_N_ELEMENTS(list))
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_ParamList, id,
|
||||
SPA_PARAM_LIST_id, SPA_POD_Id(list[result.index]));
|
||||
else
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
case SPA_PARAM_PropInfo:
|
||||
{
|
||||
struct props *p = &this->props;
|
||||
|
|
@ -320,8 +316,9 @@ static void read_timer(struct impl *this)
|
|||
static int make_buffer(struct impl *this)
|
||||
{
|
||||
struct buffer *b;
|
||||
struct spa_io_buffers *io = this->io;
|
||||
struct spa_io_range *range = this->io_range;
|
||||
struct port *port = &this->port;
|
||||
struct spa_io_buffers *io = port->io;
|
||||
struct spa_io_range *range = port->io_range;
|
||||
uint32_t n_bytes, n_samples, maxsize;
|
||||
void *data;
|
||||
struct spa_data *d;
|
||||
|
|
@ -330,12 +327,12 @@ static int make_buffer(struct impl *this)
|
|||
|
||||
read_timer(this);
|
||||
|
||||
if (spa_list_is_empty(&this->empty)) {
|
||||
if (spa_list_is_empty(&port->empty)) {
|
||||
set_timer(this, false);
|
||||
spa_log_error(this->log, NAME " %p: out of buffers", this);
|
||||
return -EPIPE;
|
||||
}
|
||||
b = spa_list_first(&this->empty, struct buffer, link);
|
||||
b = spa_list_first(&port->empty, struct buffer, link);
|
||||
spa_list_remove(&b->link);
|
||||
b->outstanding = true;
|
||||
|
||||
|
|
@ -360,18 +357,18 @@ static int make_buffer(struct impl *this)
|
|||
|
||||
offset = index % maxsize;
|
||||
|
||||
n_samples = n_bytes / this->bpf;
|
||||
n_samples = n_bytes / port->bpf;
|
||||
|
||||
l0 = SPA_MIN(n_bytes, maxsize - offset) / this->bpf;
|
||||
l0 = SPA_MIN(n_bytes, maxsize - offset) / port->bpf;
|
||||
l1 = n_samples - l0;
|
||||
|
||||
this->render_func(this, SPA_MEMBER(data, offset, void), l0);
|
||||
port->render_func(this, SPA_MEMBER(data, offset, void), l0);
|
||||
if (l1 > 0)
|
||||
this->render_func(this, data, l1);
|
||||
port->render_func(this, data, l1);
|
||||
|
||||
d[0].chunk->offset = index;
|
||||
d[0].chunk->size = n_bytes;
|
||||
d[0].chunk->stride = this->bpf;
|
||||
d[0].chunk->stride = port->bpf;
|
||||
|
||||
if (b->h) {
|
||||
b->h->seq = this->sample_count;
|
||||
|
|
@ -403,20 +400,22 @@ static void on_output(struct spa_source *source)
|
|||
static int impl_node_send_command(struct spa_node *node, const struct spa_command *command)
|
||||
{
|
||||
struct impl *this;
|
||||
struct port *port;
|
||||
|
||||
spa_return_val_if_fail(node != NULL, -EINVAL);
|
||||
spa_return_val_if_fail(command != NULL, -EINVAL);
|
||||
|
||||
this = SPA_CONTAINER_OF(node, struct impl, node);
|
||||
port = &this->port;
|
||||
|
||||
switch (SPA_NODE_COMMAND_ID(command)) {
|
||||
case SPA_NODE_COMMAND_Start:
|
||||
{
|
||||
struct timespec now;
|
||||
|
||||
if (!this->have_format)
|
||||
if (!port->have_format)
|
||||
return -EIO;
|
||||
if (this->n_buffers == 0)
|
||||
if (port->n_buffers == 0)
|
||||
return -EIO;
|
||||
|
||||
if (this->started)
|
||||
|
|
@ -435,9 +434,9 @@ static int impl_node_send_command(struct spa_node *node, const struct spa_comman
|
|||
break;
|
||||
}
|
||||
case SPA_NODE_COMMAND_Pause:
|
||||
if (!this->have_format)
|
||||
if (!port->have_format)
|
||||
return -EIO;
|
||||
if (this->n_buffers == 0)
|
||||
if (port->n_buffers == 0)
|
||||
return -EIO;
|
||||
|
||||
if (!this->started)
|
||||
|
|
@ -459,23 +458,18 @@ static const struct spa_dict_item node_info_items[] = {
|
|||
|
||||
static void emit_node_info(struct impl *this)
|
||||
{
|
||||
if (this->callbacks && this->callbacks->info) {
|
||||
struct spa_node_info info;
|
||||
|
||||
info = SPA_NODE_INFO_INIT();
|
||||
info.max_output_ports = 1;
|
||||
info.change_mask = SPA_NODE_CHANGE_MASK_PROPS;
|
||||
info.props = &SPA_DICT_INIT_ARRAY(node_info_items);
|
||||
|
||||
this->callbacks->info(this->callbacks_data, &info);
|
||||
if (this->callbacks && this->callbacks->info && this->info.change_mask) {
|
||||
this->info.props = &SPA_DICT_INIT_ARRAY(node_info_items);
|
||||
this->callbacks->info(this->callbacks_data, &this->info);
|
||||
this->info.change_mask = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_port_info(struct impl *this)
|
||||
static void emit_port_info(struct impl *this, struct port *port)
|
||||
{
|
||||
if (this->callbacks && this->callbacks->port_info && this->info.change_mask) {
|
||||
this->callbacks->port_info(this->callbacks_data, SPA_DIRECTION_OUTPUT, 0, &this->info);
|
||||
this->info.change_mask = 0;
|
||||
if (this->callbacks && this->callbacks->port_info && port->info.change_mask) {
|
||||
this->callbacks->port_info(this->callbacks_data, SPA_DIRECTION_OUTPUT, 0, &port->info);
|
||||
port->info.change_mask = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -494,7 +488,7 @@ impl_node_set_callbacks(struct spa_node *node,
|
|||
this->callbacks_data = data;
|
||||
|
||||
emit_node_info(this);
|
||||
emit_port_info(this);
|
||||
emit_port_info(this, &this->port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -546,6 +540,7 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
const struct spa_pod *filter)
|
||||
{
|
||||
struct impl *this;
|
||||
struct port *port;
|
||||
struct spa_pod_builder b = { 0 };
|
||||
uint8_t buffer[1024];
|
||||
struct spa_pod *param;
|
||||
|
|
@ -561,6 +556,8 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
|
||||
spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL);
|
||||
|
||||
port = &this->port;
|
||||
|
||||
result.id = id;
|
||||
result.next = start;
|
||||
next:
|
||||
|
|
@ -569,22 +566,6 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
|
||||
switch (id) {
|
||||
case SPA_PARAM_List:
|
||||
{
|
||||
uint32_t list[] = { SPA_PARAM_EnumFormat,
|
||||
SPA_PARAM_Format,
|
||||
SPA_PARAM_Buffers,
|
||||
SPA_PARAM_Meta,
|
||||
SPA_PARAM_IO, };
|
||||
|
||||
if (result.index < SPA_N_ELEMENTS(list))
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_ParamList, id,
|
||||
SPA_PARAM_LIST_id, SPA_POD_Id(list[result.index]));
|
||||
else
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
case SPA_PARAM_EnumFormat:
|
||||
if ((res = port_enum_formats(this, direction, port_id,
|
||||
result.index, ¶m, &b)) <= 0)
|
||||
|
|
@ -592,16 +573,16 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
break;
|
||||
|
||||
case SPA_PARAM_Format:
|
||||
if (!this->have_format)
|
||||
if (!port->have_format)
|
||||
return -EIO;
|
||||
if (result.index > 0)
|
||||
return 0;
|
||||
|
||||
param = spa_format_audio_raw_build(&b, id, &this->current_format.info.raw);
|
||||
param = spa_format_audio_raw_build(&b, id, &port->current_format.info.raw);
|
||||
break;
|
||||
|
||||
case SPA_PARAM_Buffers:
|
||||
if (!this->have_format)
|
||||
if (!port->have_format)
|
||||
return -EIO;
|
||||
if (result.index > 0)
|
||||
return 0;
|
||||
|
|
@ -611,16 +592,13 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(1, 1, MAX_BUFFERS),
|
||||
SPA_PARAM_BUFFERS_blocks, SPA_POD_Int(1),
|
||||
SPA_PARAM_BUFFERS_size, SPA_POD_CHOICE_RANGE_Int(
|
||||
1024 * this->bpf,
|
||||
16 * this->bpf,
|
||||
INT32_MAX / this->bpf),
|
||||
1024 * port->bpf,
|
||||
16 * port->bpf,
|
||||
INT32_MAX / port->bpf),
|
||||
SPA_PARAM_BUFFERS_stride, SPA_POD_Int(0),
|
||||
SPA_PARAM_BUFFERS_align, SPA_POD_Int(16));
|
||||
break;
|
||||
case SPA_PARAM_Meta:
|
||||
if (!this->have_format)
|
||||
return -EIO;
|
||||
|
||||
switch (result.index) {
|
||||
case 0:
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
|
|
@ -672,12 +650,12 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int clear_buffers(struct impl *this)
|
||||
static int clear_buffers(struct impl *this, struct port *port)
|
||||
{
|
||||
if (this->n_buffers > 0) {
|
||||
if (port->n_buffers > 0) {
|
||||
spa_log_info(this->log, NAME " %p: clear buffers", this);
|
||||
this->n_buffers = 0;
|
||||
spa_list_init(&this->empty);
|
||||
port->n_buffers = 0;
|
||||
spa_list_init(&port->empty);
|
||||
this->started = false;
|
||||
set_timer(this, false);
|
||||
}
|
||||
|
|
@ -692,10 +670,11 @@ port_set_format(struct impl *this,
|
|||
const struct spa_pod *format)
|
||||
{
|
||||
int res;
|
||||
struct port *port = &this->port;
|
||||
|
||||
if (format == NULL) {
|
||||
this->have_format = false;
|
||||
clear_buffers(this);
|
||||
port->have_format = false;
|
||||
clear_buffers(this, port);
|
||||
} else {
|
||||
struct spa_audio_info info = { 0 };
|
||||
int idx;
|
||||
|
|
@ -728,15 +707,25 @@ port_set_format(struct impl *this,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
this->bpf = sizes[idx] * info.info.raw.channels;
|
||||
this->current_format = info;
|
||||
this->have_format = true;
|
||||
this->render_func = sine_funcs[idx];
|
||||
port->bpf = sizes[idx] * info.info.raw.channels;
|
||||
port->current_format = info;
|
||||
port->have_format = true;
|
||||
port->render_func = sine_funcs[idx];
|
||||
}
|
||||
|
||||
if (this->have_format) {
|
||||
this->info.rate = this->current_format.info.raw.rate;
|
||||
if (port->have_format) {
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_RATE;
|
||||
port->info.rate = port->current_format.info.raw.rate;
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_READWRITE);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, SPA_PARAM_INFO_READ);
|
||||
} else {
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
|
||||
}
|
||||
emit_port_info(this, port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -768,6 +757,7 @@ impl_node_port_use_buffers(struct spa_node *node,
|
|||
uint32_t n_buffers)
|
||||
{
|
||||
struct impl *this;
|
||||
struct port *port;
|
||||
uint32_t i;
|
||||
|
||||
spa_return_val_if_fail(node != NULL, -EINVAL);
|
||||
|
|
@ -776,16 +766,18 @@ impl_node_port_use_buffers(struct spa_node *node,
|
|||
|
||||
spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL);
|
||||
|
||||
if (!this->have_format)
|
||||
port = &this->port;
|
||||
|
||||
if (!port->have_format)
|
||||
return -EIO;
|
||||
|
||||
clear_buffers(this);
|
||||
clear_buffers(this, port);
|
||||
|
||||
for (i = 0; i < n_buffers; i++) {
|
||||
struct buffer *b;
|
||||
struct spa_data *d = buffers[i]->datas;
|
||||
|
||||
b = &this->buffers[i];
|
||||
b = &port->buffers[i];
|
||||
b->id = i;
|
||||
b->outbuf = buffers[i];
|
||||
b->outstanding = false;
|
||||
|
|
@ -798,9 +790,9 @@ impl_node_port_use_buffers(struct spa_node *node,
|
|||
buffers[i]);
|
||||
return -EINVAL;
|
||||
}
|
||||
spa_list_append(&this->empty, &b->link);
|
||||
spa_list_append(&port->empty, &b->link);
|
||||
}
|
||||
this->n_buffers = n_buffers;
|
||||
port->n_buffers = n_buffers;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -815,6 +807,7 @@ impl_node_port_alloc_buffers(struct spa_node *node,
|
|||
uint32_t *n_buffers)
|
||||
{
|
||||
struct impl *this;
|
||||
struct port *port;
|
||||
|
||||
spa_return_val_if_fail(node != NULL, -EINVAL);
|
||||
|
||||
|
|
@ -822,7 +815,9 @@ impl_node_port_alloc_buffers(struct spa_node *node,
|
|||
|
||||
spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL);
|
||||
|
||||
if (!this->have_format)
|
||||
port = &this->port;
|
||||
|
||||
if (!port->have_format)
|
||||
return -EIO;
|
||||
|
||||
return -ENOTSUP;
|
||||
|
|
@ -836,6 +831,7 @@ impl_node_port_set_io(struct spa_node *node,
|
|||
void *data, size_t size)
|
||||
{
|
||||
struct impl *this;
|
||||
struct port *port;
|
||||
|
||||
spa_return_val_if_fail(node != NULL, -EINVAL);
|
||||
|
||||
|
|
@ -843,15 +839,17 @@ impl_node_port_set_io(struct spa_node *node,
|
|||
|
||||
spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL);
|
||||
|
||||
port = &this->port;
|
||||
|
||||
switch (id) {
|
||||
case SPA_IO_Buffers:
|
||||
this->io = data;
|
||||
port->io = data;
|
||||
break;
|
||||
case SPA_IO_Range:
|
||||
this->io_range = data;
|
||||
port->io_range = data;
|
||||
break;
|
||||
case SPA_IO_Control:
|
||||
this->io_control = data;
|
||||
port->io_control = data;
|
||||
break;
|
||||
default:
|
||||
return -ENOENT;
|
||||
|
|
@ -859,15 +857,15 @@ impl_node_port_set_io(struct spa_node *node,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline void reuse_buffer(struct impl *this, uint32_t id)
|
||||
static inline void reuse_buffer(struct impl *this, struct port *port, uint32_t id)
|
||||
{
|
||||
struct buffer *b = &this->buffers[id];
|
||||
struct buffer *b = &port->buffers[id];
|
||||
spa_return_if_fail(b->outstanding);
|
||||
|
||||
spa_log_trace(this->log, NAME " %p: reuse buffer %d", this, id);
|
||||
|
||||
b->outstanding = false;
|
||||
spa_list_append(&this->empty, &b->link);
|
||||
spa_list_append(&port->empty, &b->link);
|
||||
|
||||
if (!this->props.live)
|
||||
set_timer(this, true);
|
||||
|
|
@ -876,15 +874,17 @@ static inline void reuse_buffer(struct impl *this, uint32_t id)
|
|||
static int impl_node_port_reuse_buffer(struct spa_node *node, uint32_t port_id, uint32_t buffer_id)
|
||||
{
|
||||
struct impl *this;
|
||||
struct port *port;
|
||||
|
||||
spa_return_val_if_fail(node != NULL, -EINVAL);
|
||||
|
||||
this = SPA_CONTAINER_OF(node, struct impl, node);
|
||||
|
||||
spa_return_val_if_fail(port_id == 0, -EINVAL);
|
||||
spa_return_val_if_fail(buffer_id < this->n_buffers, -EINVAL);
|
||||
port = &this->port;
|
||||
spa_return_val_if_fail(buffer_id < port->n_buffers, -EINVAL);
|
||||
|
||||
reuse_buffer(this, buffer_id);
|
||||
reuse_buffer(this, port, buffer_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -914,23 +914,26 @@ static int process_control(struct impl *this, struct spa_pod_sequence *sequence)
|
|||
static int impl_node_process(struct spa_node *node)
|
||||
{
|
||||
struct impl *this;
|
||||
struct port *port;
|
||||
struct spa_io_buffers *io;
|
||||
|
||||
spa_return_val_if_fail(node != NULL, -EINVAL);
|
||||
|
||||
this = SPA_CONTAINER_OF(node, struct impl, node);
|
||||
io = this->io;
|
||||
port = &this->port;
|
||||
|
||||
io = port->io;
|
||||
spa_return_val_if_fail(io != NULL, -EIO);
|
||||
|
||||
if (this->io_control)
|
||||
process_control(this, &this->io_control->sequence);
|
||||
if (port->io_control)
|
||||
process_control(this, &port->io_control->sequence);
|
||||
|
||||
if (io->status == SPA_STATUS_HAVE_BUFFER)
|
||||
return SPA_STATUS_HAVE_BUFFER;
|
||||
|
||||
if (io->buffer_id < this->n_buffers) {
|
||||
reuse_buffer(this, this->io->buffer_id);
|
||||
this->io->buffer_id = SPA_ID_INVALID;
|
||||
if (io->buffer_id < port->n_buffers) {
|
||||
reuse_buffer(this, port, io->buffer_id);
|
||||
io->buffer_id = SPA_ID_INVALID;
|
||||
}
|
||||
|
||||
if (!this->props.live && (io->status == SPA_STATUS_NEED_BUFFER))
|
||||
|
|
@ -1004,6 +1007,7 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
uint32_t n_support)
|
||||
{
|
||||
struct impl *this;
|
||||
struct port *port;
|
||||
uint32_t i;
|
||||
|
||||
spa_return_val_if_fail(factory != NULL, -EINVAL);
|
||||
|
|
@ -1022,10 +1026,18 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
}
|
||||
|
||||
this->node = impl_node;
|
||||
this->info = SPA_NODE_INFO_INIT();
|
||||
this->info.max_output_ports = 1;
|
||||
this->info.change_mask |= SPA_NODE_CHANGE_MASK_FLAGS;
|
||||
this->info.flags = SPA_NODE_FLAG_RT;
|
||||
this->info.change_mask |= SPA_NODE_CHANGE_MASK_PROPS;
|
||||
this->info.change_mask |= SPA_NODE_CHANGE_MASK_PARAMS;
|
||||
this->params[0] = SPA_PARAM_INFO(SPA_PARAM_PropInfo, SPA_PARAM_INFO_READ);
|
||||
this->params[1] = SPA_PARAM_INFO(SPA_PARAM_Props, SPA_PARAM_INFO_READWRITE);
|
||||
this->info.params = this->params;
|
||||
this->info.n_params = 2;
|
||||
reset_props(&this->props);
|
||||
|
||||
spa_list_init(&this->empty);
|
||||
|
||||
this->timer_source.func = on_output;
|
||||
this->timer_source.data = this;
|
||||
this->timer_source.fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
|
||||
|
|
@ -1039,11 +1051,21 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
if (this->data_loop)
|
||||
spa_loop_add_source(this->data_loop, &this->timer_source);
|
||||
|
||||
this->info = SPA_PORT_INFO_INIT();
|
||||
this->info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
this->info.flags = SPA_PORT_FLAG_CAN_USE_BUFFERS | SPA_PORT_FLAG_NO_REF;
|
||||
port = &this->port;
|
||||
port->info = SPA_PORT_INFO_INIT();
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
port->info.flags = SPA_PORT_FLAG_CAN_USE_BUFFERS | SPA_PORT_FLAG_NO_REF;
|
||||
if (this->props.live)
|
||||
this->info.flags |= SPA_PORT_FLAG_LIVE;
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
|
||||
port->params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
|
||||
port->params[1] = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
|
||||
port->params[2] = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
|
||||
port->info.params = port->params;
|
||||
port->info.n_params = 5;
|
||||
spa_list_init(&port->empty);
|
||||
|
||||
spa_log_info(this->log, NAME " %p: initialized", this);
|
||||
|
||||
|
|
|
|||
|
|
@ -36,16 +36,16 @@ audio_test_src_create_sine_##type (struct impl *this, type *samples, size_t n_sa
|
|||
float freq = this->props.freq; \
|
||||
float volume = this->props.volume; \
|
||||
\
|
||||
channels = this->current_format.info.raw.channels; \
|
||||
step = M_PI_M2 * freq / this->current_format.info.raw.rate; \
|
||||
channels = this->port.current_format.info.raw.channels; \
|
||||
step = M_PI_M2 * freq / this->port.current_format.info.raw.rate; \
|
||||
amp = volume * scale; \
|
||||
\
|
||||
for (i = 0; i < n_samples; i++) { \
|
||||
type val; \
|
||||
this->accumulator += step; \
|
||||
if (this->accumulator >= M_PI_M2) \
|
||||
this->accumulator -= M_PI_M2; \
|
||||
val = (type) (sin (this->accumulator) * amp); \
|
||||
this->port.accumulator += step; \
|
||||
if (this->port.accumulator >= M_PI_M2) \
|
||||
this->port.accumulator -= M_PI_M2; \
|
||||
val = (type) (sin (this->port.accumulator) * amp); \
|
||||
for (c = 0; c < channels; ++c) \
|
||||
*samples++ = val; \
|
||||
} \
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Spa ALSA Sink
|
||||
/* Spa A2DP Sink
|
||||
*
|
||||
* Copyright © 2018 Wim Taymans
|
||||
*
|
||||
|
|
@ -63,6 +63,25 @@ struct buffer {
|
|||
struct spa_list link;
|
||||
};
|
||||
|
||||
struct port {
|
||||
bool have_format;
|
||||
struct spa_audio_info current_format;
|
||||
int frame_size;
|
||||
|
||||
struct spa_port_info info;
|
||||
struct spa_io_buffers *io;
|
||||
struct spa_io_range *range;
|
||||
struct spa_param_info params[8];
|
||||
|
||||
struct buffer buffers[MAX_BUFFERS];
|
||||
unsigned int n_buffers;
|
||||
|
||||
struct spa_list free;
|
||||
struct spa_list ready;
|
||||
|
||||
size_t ready_offset;
|
||||
};
|
||||
|
||||
struct impl {
|
||||
struct spa_handle handle;
|
||||
struct spa_node node;
|
||||
|
|
@ -76,28 +95,16 @@ struct impl {
|
|||
const struct spa_node_callbacks *callbacks;
|
||||
void *callbacks_data;
|
||||
|
||||
struct spa_node_info info;
|
||||
struct spa_param_info params[8];
|
||||
struct props props;
|
||||
|
||||
struct spa_bt_transport *transport;
|
||||
|
||||
struct port port;
|
||||
|
||||
bool opened;
|
||||
|
||||
bool have_format;
|
||||
struct spa_audio_info current_format;
|
||||
int frame_size;
|
||||
|
||||
struct spa_port_info info;
|
||||
struct spa_io_buffers *io;
|
||||
struct spa_io_range *range;
|
||||
|
||||
struct buffer buffers[MAX_BUFFERS];
|
||||
unsigned int n_buffers;
|
||||
|
||||
struct spa_list free;
|
||||
struct spa_list ready;
|
||||
|
||||
size_t ready_offset;
|
||||
|
||||
bool started;
|
||||
struct spa_source source;
|
||||
int timerfd;
|
||||
|
|
@ -171,19 +178,6 @@ static int impl_node_enum_params(struct spa_node *node, int seq,
|
|||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
|
||||
switch (id) {
|
||||
case SPA_PARAM_List:
|
||||
{
|
||||
uint32_t list[] = { SPA_PARAM_PropInfo,
|
||||
SPA_PARAM_Props };
|
||||
|
||||
if (result.index < SPA_N_ELEMENTS(list))
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_ParamList, id,
|
||||
SPA_PARAM_LIST_id, SPA_POD_Id(list[result.index]));
|
||||
else
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
case SPA_PARAM_PropInfo:
|
||||
{
|
||||
struct props *p = &this->props;
|
||||
|
|
@ -337,9 +331,10 @@ static int encode_buffer(struct impl *this, const void *data, int size)
|
|||
{
|
||||
int processed;
|
||||
ssize_t out_encoded;
|
||||
struct port *port = &this->port;
|
||||
|
||||
spa_log_trace(this->log, "a2dp-sink %p: encode %d used %d, %d %d",
|
||||
this, size, this->buffer_used, this->frame_size, this->write_size);
|
||||
this, size, this->buffer_used, port->frame_size, this->write_size);
|
||||
|
||||
if (this->frame_count > MAX_FRAME_COUNT)
|
||||
return -ENOSPC;
|
||||
|
|
@ -351,8 +346,8 @@ static int encode_buffer(struct impl *this, const void *data, int size)
|
|||
if (processed < 0)
|
||||
return processed;
|
||||
|
||||
this->sample_count += processed / this->frame_size;
|
||||
this->sample_time += processed / this->frame_size;
|
||||
this->sample_count += processed / port->frame_size;
|
||||
this->sample_time += processed / port->frame_size;
|
||||
this->frame_count += processed / this->codesize;
|
||||
this->buffer_used += out_encoded;
|
||||
|
||||
|
|
@ -428,6 +423,8 @@ static int add_data(struct impl *this, const void *data, int size)
|
|||
|
||||
static int set_bitpool(struct impl *this, int bitpool)
|
||||
{
|
||||
struct port *port = &this->port;
|
||||
|
||||
if (bitpool < this->min_bitpool)
|
||||
bitpool = this->min_bitpool;
|
||||
if (bitpool > this->max_bitpool)
|
||||
|
|
@ -447,7 +444,8 @@ static int set_bitpool(struct impl *this, int bitpool)
|
|||
- sizeof(struct rtp_header) - sizeof(struct rtp_payload) - 24;
|
||||
this->write_size = this->transport->write_mtu
|
||||
- sizeof(struct rtp_header) - sizeof(struct rtp_payload) - 24;
|
||||
this->write_samples = (this->write_size / this->frame_length) * (this->codesize / this->frame_size);
|
||||
this->write_samples = (this->write_size / this->frame_length) *
|
||||
(this->codesize / port->frame_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -469,27 +467,28 @@ static int flush_data(struct impl *this, uint64_t now_time)
|
|||
uint64_t elapsed;
|
||||
int64_t queued;
|
||||
struct itimerspec ts;
|
||||
struct port *port = &this->port;
|
||||
|
||||
total_frames = 0;
|
||||
while (!spa_list_is_empty(&this->ready)) {
|
||||
while (!spa_list_is_empty(&port->ready)) {
|
||||
uint8_t *src;
|
||||
uint32_t n_bytes, n_frames;
|
||||
struct buffer *b;
|
||||
struct spa_data *d;
|
||||
uint32_t index, offs, avail, l0, l1;
|
||||
|
||||
b = spa_list_first(&this->ready, struct buffer, link);
|
||||
b = spa_list_first(&port->ready, struct buffer, link);
|
||||
d = b->buf->datas;
|
||||
|
||||
src = d[0].data;
|
||||
|
||||
index = d[0].chunk->offset + this->ready_offset;
|
||||
avail = d[0].chunk->size - this->ready_offset;
|
||||
avail /= this->frame_size;
|
||||
index = d[0].chunk->offset + port->ready_offset;
|
||||
avail = d[0].chunk->size - port->ready_offset;
|
||||
avail /= port->frame_size;
|
||||
|
||||
offs = index % d[0].maxsize;
|
||||
n_frames = avail;
|
||||
n_bytes = n_frames * this->frame_size;
|
||||
n_bytes = n_frames * port->frame_size;
|
||||
|
||||
l0 = SPA_MIN(n_bytes, d[0].maxsize - offs);
|
||||
l1 = n_bytes - l0;
|
||||
|
|
@ -500,16 +499,16 @@ static int flush_data(struct impl *this, uint64_t now_time)
|
|||
if (n_bytes <= 0)
|
||||
break;
|
||||
|
||||
n_frames = n_bytes / this->frame_size;
|
||||
n_frames = n_bytes / port->frame_size;
|
||||
|
||||
this->ready_offset += n_bytes;
|
||||
port->ready_offset += n_bytes;
|
||||
|
||||
if (this->ready_offset >= d[0].chunk->size) {
|
||||
if (port->ready_offset >= d[0].chunk->size) {
|
||||
spa_list_remove(&b->link);
|
||||
b->outstanding = true;
|
||||
spa_log_trace(this->log, "a2dp-sink %p: reuse buffer %u", this, b->id);
|
||||
this->callbacks->reuse_buffer(this->callbacks_data, 0, b->id);
|
||||
this->ready_offset = 0;
|
||||
port->ready_offset = 0;
|
||||
}
|
||||
total_frames += n_frames;
|
||||
|
||||
|
|
@ -546,7 +545,7 @@ static int flush_data(struct impl *this, uint64_t now_time)
|
|||
else
|
||||
elapsed = 0;
|
||||
|
||||
elapsed = elapsed * this->current_format.info.raw.rate / SPA_NSEC_PER_SEC;
|
||||
elapsed = elapsed * port->current_format.info.raw.rate / SPA_NSEC_PER_SEC;
|
||||
|
||||
queued = this->sample_time - elapsed;
|
||||
|
||||
|
|
@ -559,7 +558,7 @@ static int flush_data(struct impl *this, uint64_t now_time)
|
|||
this->sample_time = queued;
|
||||
this->start_time = now_time;
|
||||
}
|
||||
if (!spa_list_is_empty(&this->ready) &&
|
||||
if (!spa_list_is_empty(&port->ready) &&
|
||||
now_time - this->last_error > SPA_NSEC_PER_SEC / 2) {
|
||||
reduce_bitpool(this);
|
||||
this->last_error = now_time;
|
||||
|
|
@ -568,7 +567,7 @@ static int flush_data(struct impl *this, uint64_t now_time)
|
|||
}
|
||||
calc_timeout(queued,
|
||||
FILL_FRAMES * this->write_samples,
|
||||
this->current_format.info.raw.rate,
|
||||
port->current_format.info.raw.rate,
|
||||
&this->now, &ts.it_value);
|
||||
ts.it_interval.tv_sec = 0;
|
||||
ts.it_interval.tv_nsec = 0;
|
||||
|
|
@ -605,9 +604,10 @@ static void a2dp_on_flush(struct spa_source *source)
|
|||
static void a2dp_on_timeout(struct spa_source *source)
|
||||
{
|
||||
struct impl *this = source->data;
|
||||
struct port *port = &this->port;
|
||||
int err;
|
||||
uint64_t exp, now_time;
|
||||
struct spa_io_buffers *io = this->io;
|
||||
struct spa_io_buffers *io = port->io;
|
||||
|
||||
if (this->started && read(this->timerfd, &exp, sizeof(uint64_t)) != sizeof(uint64_t))
|
||||
spa_log_warn(this->log, "error reading timerfd: %s", strerror(errno));
|
||||
|
|
@ -624,14 +624,14 @@ static void a2dp_on_timeout(struct spa_source *source)
|
|||
this->start_time = now_time;
|
||||
}
|
||||
|
||||
if (spa_list_is_empty(&this->ready)) {
|
||||
if (spa_list_is_empty(&port->ready)) {
|
||||
spa_log_trace(this->log, "a2dp-sink %p: %d", this, io->status);
|
||||
|
||||
io->status = SPA_STATUS_NEED_BUFFER;
|
||||
if (this->range) {
|
||||
this->range->offset = this->sample_count * this->frame_size;
|
||||
this->range->min_size = this->threshold * this->frame_size;
|
||||
this->range->max_size = this->write_samples * this->frame_size;
|
||||
if (port->range) {
|
||||
port->range->offset = this->sample_count * port->frame_size;
|
||||
port->range->min_size = this->threshold * port->frame_size;
|
||||
port->range->max_size = this->write_samples * port->frame_size;
|
||||
}
|
||||
this->callbacks->ready(this->callbacks_data, SPA_STATUS_NEED_BUFFER);
|
||||
}
|
||||
|
|
@ -823,18 +823,20 @@ static int do_stop(struct impl *this)
|
|||
static int impl_node_send_command(struct spa_node *node, const struct spa_command *command)
|
||||
{
|
||||
struct impl *this;
|
||||
struct port *port;
|
||||
int res;
|
||||
|
||||
spa_return_val_if_fail(node != NULL, -EINVAL);
|
||||
spa_return_val_if_fail(command != NULL, -EINVAL);
|
||||
|
||||
this = SPA_CONTAINER_OF(node, struct impl, node);
|
||||
port = &this->port;
|
||||
|
||||
switch (SPA_NODE_COMMAND_ID(command)) {
|
||||
case SPA_NODE_COMMAND_Start:
|
||||
if (!this->have_format)
|
||||
if (!port->have_format)
|
||||
return -EIO;
|
||||
if (this->n_buffers == 0)
|
||||
if (port->n_buffers == 0)
|
||||
return -EIO;
|
||||
|
||||
if ((res = do_start(this)) < 0)
|
||||
|
|
@ -857,23 +859,18 @@ static const struct spa_dict_item node_info_items[] = {
|
|||
|
||||
static void emit_node_info(struct impl *this)
|
||||
{
|
||||
if (this->callbacks && this->callbacks->info) {
|
||||
struct spa_node_info info;
|
||||
|
||||
info = SPA_NODE_INFO_INIT();
|
||||
info.max_input_ports = 1;
|
||||
info.change_mask = SPA_NODE_CHANGE_MASK_PROPS;
|
||||
info.props = &SPA_DICT_INIT_ARRAY(node_info_items);
|
||||
|
||||
this->callbacks->info(this->callbacks_data, &info);
|
||||
if (this->callbacks && this->callbacks->info && this->info.change_mask) {
|
||||
this->info.props = &SPA_DICT_INIT_ARRAY(node_info_items);
|
||||
this->callbacks->info(this->callbacks_data, &this->info);
|
||||
this->info.change_mask = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_port_info(struct impl *this)
|
||||
static void emit_port_info(struct impl *this, struct port *port)
|
||||
{
|
||||
if (this->callbacks && this->callbacks->port_info && this->info.change_mask) {
|
||||
this->callbacks->port_info(this->callbacks_data, SPA_DIRECTION_INPUT, 0, &this->info);
|
||||
this->info.change_mask = 0;
|
||||
if (this->callbacks && this->callbacks->port_info && port->info.change_mask) {
|
||||
this->callbacks->port_info(this->callbacks_data, SPA_DIRECTION_INPUT, 0, &port->info);
|
||||
port->info.change_mask = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -892,7 +889,7 @@ impl_node_set_callbacks(struct spa_node *node,
|
|||
this->callbacks_data = data;
|
||||
|
||||
emit_node_info(this);
|
||||
emit_port_info(this);
|
||||
emit_port_info(this, &this->port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -916,6 +913,7 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
{
|
||||
|
||||
struct impl *this;
|
||||
struct port *port;
|
||||
struct spa_pod *param;
|
||||
struct spa_pod_builder b = { 0 };
|
||||
uint8_t buffer[1024];
|
||||
|
|
@ -930,6 +928,7 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
spa_return_val_if_fail(this->callbacks && this->callbacks->result, -EIO);
|
||||
|
||||
spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL);
|
||||
port = &this->port;
|
||||
|
||||
result.id = id;
|
||||
result.next = start;
|
||||
|
|
@ -939,21 +938,6 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
|
||||
switch (id) {
|
||||
case SPA_PARAM_List:
|
||||
{
|
||||
uint32_t list[] = { SPA_PARAM_EnumFormat,
|
||||
SPA_PARAM_Format,
|
||||
SPA_PARAM_Buffers,
|
||||
SPA_PARAM_Meta };
|
||||
|
||||
if (result.index < SPA_N_ELEMENTS(list))
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_ParamList, id,
|
||||
SPA_PARAM_LIST_id, SPA_POD_Id(list[result.index]));
|
||||
else
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
case SPA_PARAM_EnumFormat:
|
||||
if (result.index > 0)
|
||||
return 0;
|
||||
|
|
@ -999,16 +983,16 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
break;
|
||||
|
||||
case SPA_PARAM_Format:
|
||||
if (!this->have_format)
|
||||
if (!port->have_format)
|
||||
return -EIO;
|
||||
if (result.index > 0)
|
||||
return 0;
|
||||
|
||||
param = spa_format_audio_raw_build(&b, id, &this->current_format.info.raw);
|
||||
param = spa_format_audio_raw_build(&b, id, &port->current_format.info.raw);
|
||||
break;
|
||||
|
||||
case SPA_PARAM_Buffers:
|
||||
if (!this->have_format)
|
||||
if (!port->have_format)
|
||||
return -EIO;
|
||||
if (result.index > 0)
|
||||
return 0;
|
||||
|
|
@ -1018,17 +1002,14 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(2, 2, MAX_BUFFERS),
|
||||
SPA_PARAM_BUFFERS_blocks, SPA_POD_Int(1),
|
||||
SPA_PARAM_BUFFERS_size, SPA_POD_CHOICE_RANGE_Int(
|
||||
this->props.min_latency * this->frame_size,
|
||||
this->props.min_latency * this->frame_size,
|
||||
INT32_MAX),
|
||||
this->props.min_latency * port->frame_size,
|
||||
this->props.min_latency * port->frame_size,
|
||||
INT32_MAX),
|
||||
SPA_PARAM_BUFFERS_stride, SPA_POD_Int(0),
|
||||
SPA_PARAM_BUFFERS_align, SPA_POD_Int(16));
|
||||
break;
|
||||
|
||||
case SPA_PARAM_Meta:
|
||||
if (!this->have_format)
|
||||
return -EIO;
|
||||
|
||||
switch (result.index) {
|
||||
case 0:
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
|
|
@ -1057,28 +1038,26 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int clear_buffers(struct impl *this)
|
||||
static int clear_buffers(struct impl *this, struct port *port)
|
||||
{
|
||||
do_stop(this);
|
||||
if (this->n_buffers > 0) {
|
||||
spa_list_init(&this->ready);
|
||||
this->n_buffers = 0;
|
||||
if (port->n_buffers > 0) {
|
||||
spa_list_init(&port->ready);
|
||||
port->n_buffers = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int port_set_format(struct spa_node *node,
|
||||
enum spa_direction direction, uint32_t port_id,
|
||||
static int port_set_format(struct impl *this, struct port *port,
|
||||
uint32_t flags,
|
||||
const struct spa_pod *format)
|
||||
{
|
||||
struct impl *this = SPA_CONTAINER_OF(node, struct impl, node);
|
||||
int err;
|
||||
|
||||
if (format == NULL) {
|
||||
spa_log_info(this->log, "clear format");
|
||||
clear_buffers(this);
|
||||
this->have_format = false;
|
||||
clear_buffers(this, port);
|
||||
port->have_format = false;
|
||||
} else {
|
||||
struct spa_audio_info info = { 0 };
|
||||
|
||||
|
|
@ -1092,16 +1071,26 @@ static int port_set_format(struct spa_node *node,
|
|||
if (spa_format_audio_raw_parse(format, &info.info.raw) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
this->frame_size = info.info.raw.channels * 2;
|
||||
port->frame_size = info.info.raw.channels * 2;
|
||||
port->current_format = info;
|
||||
port->have_format = true;
|
||||
this->threshold = this->props.min_latency;
|
||||
this->current_format = info;
|
||||
this->have_format = true;
|
||||
}
|
||||
|
||||
if (this->have_format) {
|
||||
this->info.flags = SPA_PORT_FLAG_CAN_USE_BUFFERS | SPA_PORT_FLAG_LIVE;
|
||||
this->info.rate = this->current_format.info.raw.rate;
|
||||
if (port->have_format) {
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
port->info.flags = SPA_PORT_FLAG_CAN_USE_BUFFERS | SPA_PORT_FLAG_LIVE;
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_RATE;
|
||||
port->info.rate = port->current_format.info.raw.rate;
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_READWRITE);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, SPA_PARAM_INFO_READ);
|
||||
} else {
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
|
||||
}
|
||||
emit_port_info(this, port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1112,12 +1101,17 @@ impl_node_port_set_param(struct spa_node *node,
|
|||
uint32_t id, uint32_t flags,
|
||||
const struct spa_pod *param)
|
||||
{
|
||||
struct impl *this;
|
||||
struct port *port;
|
||||
|
||||
spa_return_val_if_fail(node != NULL, -EINVAL);
|
||||
this = SPA_CONTAINER_OF(node, struct impl, node);
|
||||
|
||||
spa_return_val_if_fail(CHECK_PORT(node, direction, port_id), -EINVAL);
|
||||
port = &this->port;
|
||||
|
||||
if (id == SPA_PARAM_Format) {
|
||||
return port_set_format(node, direction, port_id, flags, param);
|
||||
return port_set_format(this, port, flags, param);
|
||||
}
|
||||
else
|
||||
return -ENOENT;
|
||||
|
|
@ -1129,23 +1123,24 @@ impl_node_port_use_buffers(struct spa_node *node,
|
|||
uint32_t port_id, struct spa_buffer **buffers, uint32_t n_buffers)
|
||||
{
|
||||
struct impl *this;
|
||||
struct port *port;
|
||||
uint32_t i;
|
||||
|
||||
spa_return_val_if_fail(node != NULL, -EINVAL);
|
||||
|
||||
this = SPA_CONTAINER_OF(node, struct impl, node);
|
||||
|
||||
spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL);
|
||||
port = &this->port;
|
||||
|
||||
spa_log_info(this->log, "use buffers %d", n_buffers);
|
||||
|
||||
if (!this->have_format)
|
||||
if (!port->have_format)
|
||||
return -EIO;
|
||||
|
||||
clear_buffers(this);
|
||||
clear_buffers(this, port);
|
||||
|
||||
for (i = 0; i < n_buffers; i++) {
|
||||
struct buffer *b = &this->buffers[i];
|
||||
struct buffer *b = &port->buffers[i];
|
||||
uint32_t type;
|
||||
|
||||
b->buf = buffers[i];
|
||||
|
|
@ -1161,9 +1156,9 @@ impl_node_port_use_buffers(struct spa_node *node,
|
|||
spa_log_error(this->log, NAME " %p: need mapped memory", this);
|
||||
return -EINVAL;
|
||||
}
|
||||
this->threshold = buffers[i]->datas[0].maxsize / this->frame_size;
|
||||
this->threshold = buffers[i]->datas[0].maxsize / port->frame_size;
|
||||
}
|
||||
this->n_buffers = n_buffers;
|
||||
port->n_buffers = n_buffers;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1178,6 +1173,7 @@ impl_node_port_alloc_buffers(struct spa_node *node,
|
|||
uint32_t *n_buffers)
|
||||
{
|
||||
struct impl *this;
|
||||
struct port *port;
|
||||
|
||||
spa_return_val_if_fail(node != NULL, -EINVAL);
|
||||
spa_return_val_if_fail(buffers != NULL, -EINVAL);
|
||||
|
|
@ -1185,8 +1181,9 @@ impl_node_port_alloc_buffers(struct spa_node *node,
|
|||
this = SPA_CONTAINER_OF(node, struct impl, node);
|
||||
|
||||
spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL);
|
||||
port = &this->port;
|
||||
|
||||
if (!this->have_format)
|
||||
if (!port->have_format)
|
||||
return -EIO;
|
||||
|
||||
return -ENOTSUP;
|
||||
|
|
@ -1200,19 +1197,21 @@ impl_node_port_set_io(struct spa_node *node,
|
|||
void *data, size_t size)
|
||||
{
|
||||
struct impl *this;
|
||||
struct port *port;
|
||||
|
||||
spa_return_val_if_fail(node != NULL, -EINVAL);
|
||||
|
||||
this = SPA_CONTAINER_OF(node, struct impl, node);
|
||||
|
||||
spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL);
|
||||
port = &this->port;
|
||||
|
||||
switch (id) {
|
||||
case SPA_IO_Buffers:
|
||||
this->io = data;
|
||||
port->io = data;
|
||||
break;
|
||||
case SPA_IO_Range:
|
||||
this->range = data;
|
||||
port->range = data;
|
||||
break;
|
||||
default:
|
||||
return -ENOENT;
|
||||
|
|
@ -1228,30 +1227,32 @@ static int impl_node_port_reuse_buffer(struct spa_node *node, uint32_t port_id,
|
|||
static int impl_node_process(struct spa_node *node)
|
||||
{
|
||||
struct impl *this;
|
||||
struct spa_io_buffers *input;
|
||||
struct port *port;
|
||||
struct spa_io_buffers *io;
|
||||
|
||||
spa_return_val_if_fail(node != NULL, -EINVAL);
|
||||
|
||||
this = SPA_CONTAINER_OF(node, struct impl, node);
|
||||
input = this->io;
|
||||
spa_return_val_if_fail(input != NULL, -EIO);
|
||||
port = &this->port;
|
||||
io = port->io;
|
||||
spa_return_val_if_fail(io != NULL, -EIO);
|
||||
|
||||
if (input->status == SPA_STATUS_HAVE_BUFFER && input->buffer_id < this->n_buffers) {
|
||||
struct buffer *b = &this->buffers[input->buffer_id];
|
||||
if (io->status == SPA_STATUS_HAVE_BUFFER && io->buffer_id < port->n_buffers) {
|
||||
struct buffer *b = &port->buffers[io->buffer_id];
|
||||
uint64_t now_time;
|
||||
|
||||
if (!b->outstanding) {
|
||||
spa_log_warn(this->log, NAME " %p: buffer %u in use", this, input->buffer_id);
|
||||
input->status = -EINVAL;
|
||||
spa_log_warn(this->log, NAME " %p: buffer %u in use", this, io->buffer_id);
|
||||
io->status = -EINVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spa_log_trace(this->log, NAME " %p: queue buffer %u", this, input->buffer_id);
|
||||
spa_log_trace(this->log, NAME " %p: queue buffer %u", this, io->buffer_id);
|
||||
|
||||
spa_list_append(&this->ready, &b->link);
|
||||
spa_list_append(&port->ready, &b->link);
|
||||
b->outstanding = false;
|
||||
|
||||
this->threshold = SPA_MIN(b->buf->datas[0].chunk->size / this->frame_size,
|
||||
this->threshold = SPA_MIN(b->buf->datas[0].chunk->size / port->frame_size,
|
||||
this->props.max_latency);
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &this->now);
|
||||
|
|
@ -1259,7 +1260,7 @@ static int impl_node_process(struct spa_node *node)
|
|||
|
||||
flush_data(this, now_time);
|
||||
|
||||
input->status = SPA_STATUS_OK;
|
||||
io->status = SPA_STATUS_OK;
|
||||
}
|
||||
return SPA_STATUS_HAVE_BUFFER;
|
||||
}
|
||||
|
|
@ -1319,6 +1320,7 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
uint32_t n_support)
|
||||
{
|
||||
struct impl *this;
|
||||
struct port *port;
|
||||
uint32_t i;
|
||||
|
||||
spa_return_val_if_fail(factory != NULL, -EINVAL);
|
||||
|
|
@ -1349,11 +1351,28 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
this->node = impl_node;
|
||||
reset_props(&this->props);
|
||||
|
||||
this->info = SPA_PORT_INFO_INIT();
|
||||
this->info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
this->info.flags = SPA_PORT_FLAG_CAN_USE_BUFFERS;
|
||||
this->info = SPA_NODE_INFO_INIT();
|
||||
this->info.change_mask |= SPA_NODE_CHANGE_MASK_FLAGS;
|
||||
this->info.flags = SPA_NODE_FLAG_RT;
|
||||
this->info.change_mask |= SPA_NODE_CHANGE_MASK_PARAMS;
|
||||
this->params[0] = SPA_PARAM_INFO(SPA_PARAM_PropInfo, SPA_PARAM_INFO_READ);
|
||||
this->params[1] = SPA_PARAM_INFO(SPA_PARAM_Props, SPA_PARAM_INFO_READWRITE);
|
||||
this->info.params = this->params;
|
||||
this->info.n_params = 2;
|
||||
|
||||
spa_list_init(&this->ready);
|
||||
port = &this->port;
|
||||
port->info = SPA_PORT_INFO_INIT();
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
port->info.flags = SPA_PORT_FLAG_CAN_USE_BUFFERS;
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
|
||||
port->params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
|
||||
port->params[1] = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
|
||||
port->params[2] = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
|
||||
port->info.params = port->params;
|
||||
port->info.n_params = 5;
|
||||
spa_list_init(&port->ready);
|
||||
|
||||
for (i = 0; info && i < info->n_items; i++) {
|
||||
if (strcmp(info->items[i].key, "bluez5.transport") == 0)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Spa ALSA Device
|
||||
/* Spa Bluez5 Device
|
||||
*
|
||||
* Copyright © 2018 Wim Taymans
|
||||
*
|
||||
|
|
@ -100,8 +100,8 @@ static int emit_nodes(struct impl *this)
|
|||
info = SPA_DEVICE_OBJECT_INFO_INIT();
|
||||
info.type = SPA_TYPE_INTERFACE_Node;
|
||||
info.factory = &spa_a2dp_sink_factory;
|
||||
info.change_mask = SPA_DEVICE_OBJECT_CHANGE_MASK_INFO;
|
||||
info.info = &SPA_DICT_INIT_ARRAY(items);
|
||||
info.change_mask = SPA_DEVICE_OBJECT_CHANGE_MASK_PROPS;
|
||||
info.props = &SPA_DICT_INIT_ARRAY(items);
|
||||
|
||||
this->callbacks->object_info(this->callbacks_data, 0, &info);
|
||||
break;
|
||||
|
|
@ -133,8 +133,11 @@ static int impl_set_callbacks(struct spa_device *device,
|
|||
struct spa_device_info info;
|
||||
|
||||
info = SPA_DEVICE_INFO_INIT();
|
||||
info.change_mask = SPA_DEVICE_CHANGE_MASK_INFO | SPA_DEVICE_CHANGE_MASK_PARAMS;
|
||||
info.info = &SPA_DICT_INIT_ARRAY(info_items);
|
||||
|
||||
info.change_mask = SPA_DEVICE_CHANGE_MASK_PROPS;
|
||||
info.props = &SPA_DICT_INIT_ARRAY(info_items);
|
||||
|
||||
info.change_mask |= SPA_DEVICE_CHANGE_MASK_PARAMS;
|
||||
info.n_params = 0;
|
||||
info.params = NULL;
|
||||
|
||||
|
|
|
|||
|
|
@ -43,18 +43,26 @@
|
|||
#define MAX_BUFFERS 32
|
||||
|
||||
struct buffer {
|
||||
uint32_t id;
|
||||
uint32_t flags;
|
||||
struct spa_buffer *outbuf;
|
||||
bool outstanding;
|
||||
struct buffer *next;
|
||||
struct spa_list link;
|
||||
};
|
||||
|
||||
struct port {
|
||||
bool have_format;
|
||||
struct spa_video_info current_format;
|
||||
bool have_buffers;
|
||||
struct buffer buffers[MAX_BUFFERS];
|
||||
struct spa_port_info info;
|
||||
struct spa_param_info params[8];
|
||||
|
||||
struct spa_video_info current_format;
|
||||
int have_format:1;
|
||||
|
||||
struct buffer buffers[MAX_BUFFERS];
|
||||
uint32_t n_buffers;
|
||||
|
||||
struct spa_io_buffers *io;
|
||||
|
||||
struct spa_list free;
|
||||
struct spa_list ready;
|
||||
};
|
||||
|
||||
struct impl {
|
||||
|
|
@ -63,6 +71,9 @@ struct impl {
|
|||
|
||||
struct spa_log *log;
|
||||
|
||||
struct spa_node_info info;
|
||||
struct spa_param_info params[2];
|
||||
|
||||
const struct spa_node_callbacks *callbacks;
|
||||
void *user_data;
|
||||
|
||||
|
|
@ -113,6 +124,14 @@ static int impl_node_send_command(struct spa_node *node, const struct spa_comman
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void emit_node_info(struct impl *this)
|
||||
{
|
||||
if (this->callbacks && this->callbacks->info && this->info.change_mask) {
|
||||
this->callbacks->info(this->user_data, &this->info);
|
||||
this->info.change_mask = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_port_info(struct impl *this, enum spa_direction direction, uint32_t id)
|
||||
{
|
||||
struct port *port = GET_PORT(this, direction, id);
|
||||
|
|
@ -138,6 +157,7 @@ impl_node_set_callbacks(struct spa_node *node,
|
|||
this->callbacks = callbacks;
|
||||
this->user_data = user_data;
|
||||
|
||||
emit_node_info(this);
|
||||
emit_port_info(this, SPA_DIRECTION_INPUT, 0);
|
||||
emit_port_info(this, SPA_DIRECTION_OUTPUT, 0);
|
||||
|
||||
|
|
@ -228,19 +248,6 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
|
||||
switch (id) {
|
||||
case SPA_PARAM_List:
|
||||
{
|
||||
uint32_t list[] = { SPA_PARAM_EnumFormat,
|
||||
SPA_PARAM_Format };
|
||||
|
||||
if (result.index < SPA_N_ELEMENTS(list))
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_ParamList, id,
|
||||
SPA_PARAM_LIST_id, SPA_POD_Id(list[result.index]));
|
||||
else
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
case SPA_PARAM_EnumFormat:
|
||||
if ((res = port_enum_formats(node, direction, port_id,
|
||||
result.index, filter, ¶m, &b)) <= 0)
|
||||
|
|
@ -290,7 +297,6 @@ static int port_set_format(struct spa_node *node,
|
|||
|
||||
if (format == NULL) {
|
||||
port->have_format = false;
|
||||
return 0;
|
||||
} else {
|
||||
struct spa_video_info info = { 0 };
|
||||
|
||||
|
|
@ -474,16 +480,32 @@ spa_ffmpeg_dec_init(struct spa_handle *handle,
|
|||
}
|
||||
|
||||
this->node = impl_node;
|
||||
this->info = SPA_NODE_INFO_INIT();
|
||||
this->info.max_input_ports = 1;
|
||||
this->info.max_output_ports = 1;
|
||||
this->info.change_mask |= SPA_NODE_CHANGE_MASK_FLAGS;
|
||||
this->info.flags = SPA_NODE_FLAG_RT;
|
||||
this->info.params = this->params;
|
||||
|
||||
port = GET_IN_PORT(this, 0);
|
||||
port->info = SPA_PORT_INFO_INIT();
|
||||
port->info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
port->info.flags = 0;
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
|
||||
port->params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
|
||||
port->params[1] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
port->info.params = port->params;
|
||||
port->info.n_params = 2;
|
||||
|
||||
port = GET_OUT_PORT(this, 0);
|
||||
port->info = SPA_PORT_INFO_INIT();
|
||||
port->info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
port->info.flags = 0;
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
|
||||
port->params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
|
||||
port->params[1] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
port->info.params = port->params;
|
||||
port->info.n_params = 2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,22 +42,26 @@
|
|||
#define MAX_BUFFERS 32
|
||||
|
||||
struct buffer {
|
||||
struct spa_buffer buffer;
|
||||
struct spa_meta metas[1];
|
||||
struct spa_meta_header header;
|
||||
struct spa_data datas[1];
|
||||
struct spa_buffer *imported;
|
||||
bool outstanding;
|
||||
struct buffer *next;
|
||||
uint32_t id;
|
||||
uint32_t flags;
|
||||
struct spa_buffer *outbuf;
|
||||
struct spa_list link;
|
||||
};
|
||||
|
||||
struct port {
|
||||
bool have_format;
|
||||
struct spa_video_info current_format;
|
||||
bool have_buffers;
|
||||
struct buffer buffers[MAX_BUFFERS];
|
||||
struct spa_port_info info;
|
||||
struct spa_param_info params[8];
|
||||
|
||||
struct spa_video_info current_format;
|
||||
int have_format:1;
|
||||
|
||||
struct buffer buffers[MAX_BUFFERS];
|
||||
uint32_t n_buffers;
|
||||
|
||||
struct spa_io_buffers *io;
|
||||
|
||||
struct spa_list free;
|
||||
struct spa_list ready;
|
||||
};
|
||||
|
||||
struct impl {
|
||||
|
|
@ -66,6 +70,9 @@ struct impl {
|
|||
|
||||
struct spa_log *log;
|
||||
|
||||
struct spa_node_info info;
|
||||
struct spa_param_info params[2];
|
||||
|
||||
const struct spa_node_callbacks *callbacks;
|
||||
void *user_data;
|
||||
|
||||
|
|
@ -115,6 +122,14 @@ static int impl_node_send_command(struct spa_node *node, const struct spa_comman
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void emit_node_info(struct impl *this)
|
||||
{
|
||||
if (this->callbacks && this->callbacks->info && this->info.change_mask) {
|
||||
this->callbacks->info(this->user_data, &this->info);
|
||||
this->info.change_mask = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_port_info(struct impl *this, enum spa_direction direction, uint32_t id)
|
||||
{
|
||||
struct port *port = GET_PORT(this, direction, id);
|
||||
|
|
@ -140,6 +155,7 @@ impl_node_set_callbacks(struct spa_node *node,
|
|||
this->callbacks = callbacks;
|
||||
this->user_data = user_data;
|
||||
|
||||
emit_node_info(this);
|
||||
emit_port_info(this, SPA_DIRECTION_INPUT, 0);
|
||||
emit_port_info(this, SPA_DIRECTION_OUTPUT, 0);
|
||||
|
||||
|
|
@ -217,19 +233,6 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
|
||||
switch (id) {
|
||||
case SPA_PARAM_List:
|
||||
{
|
||||
uint32_t list[] = { SPA_PARAM_EnumFormat,
|
||||
SPA_PARAM_Format };
|
||||
|
||||
if (result.index < SPA_N_ELEMENTS(list))
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_ParamList, id,
|
||||
SPA_PARAM_LIST_id, SPA_POD_Id(list[result.index]));
|
||||
else
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
case SPA_PARAM_EnumFormat:
|
||||
if ((res = port_enum_formats(node, direction, port_id,
|
||||
result.index, filter, ¶m, &b)) <= 0)
|
||||
|
|
@ -270,7 +273,6 @@ static int port_set_format(struct spa_node *node,
|
|||
|
||||
if (format == NULL) {
|
||||
port->have_format = false;
|
||||
return 0;
|
||||
} else {
|
||||
struct spa_video_info info = { 0 };
|
||||
|
||||
|
|
@ -452,16 +454,32 @@ spa_ffmpeg_enc_init(struct spa_handle *handle,
|
|||
}
|
||||
|
||||
this->node = impl_node;
|
||||
this->info = SPA_NODE_INFO_INIT();
|
||||
this->info.max_input_ports = 1;
|
||||
this->info.max_output_ports = 1;
|
||||
this->info.change_mask |= SPA_NODE_CHANGE_MASK_FLAGS;
|
||||
this->info.flags = SPA_NODE_FLAG_RT;
|
||||
this->info.params = this->params;
|
||||
|
||||
port = GET_IN_PORT(this, 0);
|
||||
port->info = SPA_PORT_INFO_INIT();
|
||||
port->info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
port->info.flags = 0;
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
|
||||
port->params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
|
||||
port->params[1] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
port->info.params = port->params;
|
||||
port->info.n_params = 2;
|
||||
|
||||
port = GET_OUT_PORT(this, 0);
|
||||
port->info = SPA_PORT_INFO_INIT();
|
||||
port->info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
port->info.flags = 0;
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
|
||||
port->params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
|
||||
port->params[1] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
port->info.params = port->params;
|
||||
port->info.n_params = 2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,22 +56,10 @@ struct buffer {
|
|||
struct spa_list link;
|
||||
};
|
||||
|
||||
struct impl {
|
||||
struct spa_handle handle;
|
||||
struct spa_node node;
|
||||
|
||||
struct spa_log *log;
|
||||
struct spa_loop *data_loop;
|
||||
|
||||
struct props props;
|
||||
|
||||
const struct spa_node_callbacks *callbacks;
|
||||
void *callbacks_data;
|
||||
|
||||
struct spa_source timer_source;
|
||||
struct itimerspec timerspec;
|
||||
|
||||
struct port {
|
||||
struct spa_port_info info;
|
||||
struct spa_param_info params[5];
|
||||
|
||||
struct spa_io_buffers *io;
|
||||
|
||||
bool have_format;
|
||||
|
|
@ -80,12 +68,33 @@ struct impl {
|
|||
struct buffer buffers[MAX_BUFFERS];
|
||||
uint32_t n_buffers;
|
||||
|
||||
struct spa_list ready;
|
||||
};
|
||||
|
||||
struct impl {
|
||||
struct spa_handle handle;
|
||||
struct spa_node node;
|
||||
|
||||
struct spa_log *log;
|
||||
struct spa_loop *data_loop;
|
||||
|
||||
struct spa_node_info info;
|
||||
struct spa_param_info params[1];
|
||||
struct props props;
|
||||
|
||||
const struct spa_node_callbacks *callbacks;
|
||||
void *callbacks_data;
|
||||
|
||||
struct spa_source timer_source;
|
||||
struct itimerspec timerspec;
|
||||
|
||||
bool started;
|
||||
uint64_t start_time;
|
||||
uint64_t elapsed_time;
|
||||
|
||||
uint64_t buffer_count;
|
||||
struct spa_list ready;
|
||||
|
||||
struct port port;
|
||||
};
|
||||
|
||||
#define CHECK_PORT(this,d,p) ((d) == SPA_DIRECTION_INPUT && (p) < MAX_PORTS)
|
||||
|
|
@ -123,14 +132,6 @@ static int impl_node_enum_params(struct spa_node *node, int seq,
|
|||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
|
||||
switch (id) {
|
||||
case SPA_PARAM_List:
|
||||
if (result.index > 0)
|
||||
return 0;
|
||||
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_ParamList, id,
|
||||
SPA_PARAM_LIST_id, SPA_POD_Id(SPA_PARAM_Props));
|
||||
break;
|
||||
case SPA_PARAM_Props:
|
||||
if (result.index > 0)
|
||||
return 0;
|
||||
|
|
@ -227,23 +228,24 @@ static void render_buffer(struct impl *this, struct buffer *b)
|
|||
|
||||
static int consume_buffer(struct impl *this)
|
||||
{
|
||||
struct port *port = &this->port;
|
||||
struct buffer *b;
|
||||
struct spa_io_buffers *io = this->io;
|
||||
struct spa_io_buffers *io = port->io;
|
||||
int n_bytes;
|
||||
|
||||
read_timer(this);
|
||||
|
||||
if (spa_list_is_empty(&this->ready)) {
|
||||
if (spa_list_is_empty(&port->ready)) {
|
||||
io->status = SPA_STATUS_NEED_BUFFER;
|
||||
if (this->callbacks->ready)
|
||||
this->callbacks->ready(this->callbacks_data, SPA_STATUS_NEED_BUFFER);
|
||||
}
|
||||
if (spa_list_is_empty(&this->ready)) {
|
||||
if (spa_list_is_empty(&port->ready)) {
|
||||
spa_log_error(this->log, NAME " %p: no buffers", this);
|
||||
return -EPIPE;
|
||||
}
|
||||
|
||||
b = spa_list_first(&this->ready, struct buffer, link);
|
||||
b = spa_list_first(&port->ready, struct buffer, link);
|
||||
spa_list_remove(&b->link);
|
||||
|
||||
n_bytes = b->outbuf->datas[0].maxsize;
|
||||
|
|
@ -283,20 +285,22 @@ static void on_input(struct spa_source *source)
|
|||
static int impl_node_send_command(struct spa_node *node, const struct spa_command *command)
|
||||
{
|
||||
struct impl *this;
|
||||
struct port *port;
|
||||
|
||||
spa_return_val_if_fail(node != NULL, -EINVAL);
|
||||
spa_return_val_if_fail(command != NULL, -EINVAL);
|
||||
|
||||
this = SPA_CONTAINER_OF(node, struct impl, node);
|
||||
port = &this->port;
|
||||
|
||||
switch (SPA_NODE_COMMAND_ID(command)) {
|
||||
case SPA_NODE_COMMAND_Start:
|
||||
{
|
||||
struct timespec now;
|
||||
|
||||
if (!this->have_format)
|
||||
if (!port->have_format)
|
||||
return -EIO;
|
||||
if (this->n_buffers == 0)
|
||||
if (port->n_buffers == 0)
|
||||
return -EIO;
|
||||
|
||||
if (this->started)
|
||||
|
|
@ -315,9 +319,9 @@ static int impl_node_send_command(struct spa_node *node, const struct spa_comman
|
|||
break;
|
||||
}
|
||||
case SPA_NODE_COMMAND_Pause:
|
||||
if (!this->have_format)
|
||||
if (!port->have_format)
|
||||
return -EIO;
|
||||
if (this->n_buffers == 0)
|
||||
if (port->n_buffers == 0)
|
||||
return -EIO;
|
||||
|
||||
if (!this->started)
|
||||
|
|
@ -333,14 +337,22 @@ static int impl_node_send_command(struct spa_node *node, const struct spa_comman
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void emit_port_info(struct impl *this)
|
||||
static void emit_node_info(struct impl *this)
|
||||
{
|
||||
if (this->callbacks && this->callbacks->port_info && this->info.change_mask) {
|
||||
this->callbacks->port_info(this->callbacks_data, SPA_DIRECTION_INPUT, 0, &this->info);
|
||||
if (this->callbacks && this->callbacks->info && this->info.change_mask) {
|
||||
this->callbacks->info(this->callbacks_data, &this->info);
|
||||
this->info.change_mask = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_port_info(struct impl *this, struct port *port)
|
||||
{
|
||||
if (this->callbacks && this->callbacks->port_info && port->info.change_mask) {
|
||||
this->callbacks->port_info(this->callbacks_data, SPA_DIRECTION_INPUT, 0, &port->info);
|
||||
port->info.change_mask = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
impl_node_set_callbacks(struct spa_node *node,
|
||||
const struct spa_node_callbacks *callbacks,
|
||||
|
|
@ -359,7 +371,8 @@ impl_node_set_callbacks(struct spa_node *node,
|
|||
this->callbacks = callbacks;
|
||||
this->callbacks_data = data;
|
||||
|
||||
emit_port_info(this);
|
||||
emit_node_info(this);
|
||||
emit_port_info(this, &this->port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -376,8 +389,7 @@ impl_node_remove_port(struct spa_node *node, enum spa_direction direction, uint3
|
|||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static int port_enum_formats(struct spa_node *node, int seq,
|
||||
enum spa_direction direction, uint32_t port_id,
|
||||
static int port_enum_formats(struct impl *this, int seq, struct port *port,
|
||||
uint32_t index,
|
||||
const struct spa_pod *filter,
|
||||
struct spa_pod **param,
|
||||
|
|
@ -386,22 +398,19 @@ static int port_enum_formats(struct spa_node *node, int seq,
|
|||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static int port_get_format(struct spa_node *node,
|
||||
enum spa_direction direction, uint32_t port_id,
|
||||
static int port_get_format(struct impl *this, struct port *port,
|
||||
uint32_t index,
|
||||
const struct spa_pod *filter,
|
||||
struct spa_pod **param,
|
||||
struct spa_pod_builder *builder)
|
||||
{
|
||||
struct impl *this = SPA_CONTAINER_OF(node, struct impl, node);
|
||||
|
||||
if (!this->have_format)
|
||||
if (!port->have_format)
|
||||
return -EIO;
|
||||
|
||||
if (index > 0)
|
||||
return 0;
|
||||
|
||||
*param = SPA_MEMBER(this->format_buffer, 0, struct spa_pod);
|
||||
*param = SPA_MEMBER(port->format_buffer, 0, struct spa_pod);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -413,6 +422,7 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
const struct spa_pod *filter)
|
||||
{
|
||||
struct impl *this;
|
||||
struct port *port;
|
||||
struct spa_pod_builder b = { 0 };
|
||||
uint8_t buffer[1024];
|
||||
struct spa_pod *param;
|
||||
|
|
@ -426,6 +436,7 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
this = SPA_CONTAINER_OF(node, struct impl, node);
|
||||
|
||||
spa_return_val_if_fail(CHECK_PORT(node, direction, port_id), -EINVAL);
|
||||
port = &this->port;
|
||||
|
||||
result.id = id;
|
||||
result.next = start;
|
||||
|
|
@ -435,29 +446,14 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
|
||||
switch (id) {
|
||||
case SPA_PARAM_List:
|
||||
{
|
||||
uint32_t list[] = { SPA_PARAM_EnumFormat,
|
||||
SPA_PARAM_Format,
|
||||
SPA_PARAM_Buffers,
|
||||
SPA_PARAM_Meta };
|
||||
|
||||
if (result.index < SPA_N_ELEMENTS(list))
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_ParamList, id,
|
||||
SPA_PARAM_LIST_id, SPA_POD_Id(list[result.index]));
|
||||
else
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
case SPA_PARAM_EnumFormat:
|
||||
if ((res = port_enum_formats(node, seq, direction, port_id,
|
||||
result.index, filter, ¶m, &b)) <= 0)
|
||||
if ((res = port_enum_formats(this, seq, port,
|
||||
result.index, filter, ¶m, &b)) <= 0)
|
||||
return res;
|
||||
break;
|
||||
case SPA_PARAM_Format:
|
||||
if ((res = port_get_format(node, direction, port_id,
|
||||
result.index, filter, ¶m, &b)) <= 0)
|
||||
if ((res = port_get_format(this, port,
|
||||
result.index, filter, ¶m, &b)) <= 0)
|
||||
return res;
|
||||
break;
|
||||
case SPA_PARAM_Buffers:
|
||||
|
|
@ -500,33 +496,29 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int clear_buffers(struct impl *this)
|
||||
static int clear_buffers(struct impl *this, struct port *port)
|
||||
{
|
||||
if (this->n_buffers > 0) {
|
||||
if (port->n_buffers > 0) {
|
||||
spa_log_info(this->log, NAME " %p: clear buffers", this);
|
||||
this->n_buffers = 0;
|
||||
spa_list_init(&this->ready);
|
||||
port->n_buffers = 0;
|
||||
spa_list_init(&port->ready);
|
||||
this->started = false;
|
||||
set_timer(this, false);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int port_set_format(struct spa_node *node,
|
||||
enum spa_direction direction, uint32_t port_id,
|
||||
uint32_t flags,
|
||||
const struct spa_pod *format)
|
||||
static int port_set_format(struct impl *this, struct port *port,
|
||||
uint32_t flags, const struct spa_pod *format)
|
||||
{
|
||||
struct impl *this = SPA_CONTAINER_OF(node, struct impl, node);
|
||||
|
||||
if (format == NULL) {
|
||||
this->have_format = false;
|
||||
clear_buffers(this);
|
||||
port->have_format = false;
|
||||
clear_buffers(this, port);
|
||||
} else {
|
||||
if (SPA_POD_SIZE(format) > sizeof(this->format_buffer))
|
||||
if (SPA_POD_SIZE(format) > sizeof(port->format_buffer))
|
||||
return -ENOSPC;
|
||||
memcpy(this->format_buffer, format, SPA_POD_SIZE(format));
|
||||
this->have_format = true;
|
||||
memcpy(port->format_buffer, format, SPA_POD_SIZE(format));
|
||||
port->have_format = true;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -537,12 +529,17 @@ impl_node_port_set_param(struct spa_node *node,
|
|||
uint32_t id, uint32_t flags,
|
||||
const struct spa_pod *param)
|
||||
{
|
||||
struct impl *this;
|
||||
struct port *port;
|
||||
|
||||
spa_return_val_if_fail(node != NULL, -EINVAL);
|
||||
this = SPA_CONTAINER_OF(node, struct impl, node);
|
||||
|
||||
spa_return_val_if_fail(CHECK_PORT(node, direction, port_id), -EINVAL);
|
||||
port = &this->port;
|
||||
|
||||
if (id == SPA_PARAM_Format) {
|
||||
return port_set_format(node, direction, port_id, flags, param);
|
||||
return port_set_format(this, port, flags, param);
|
||||
}
|
||||
else
|
||||
return -ENOENT;
|
||||
|
|
@ -556,6 +553,7 @@ impl_node_port_use_buffers(struct spa_node *node,
|
|||
uint32_t n_buffers)
|
||||
{
|
||||
struct impl *this;
|
||||
struct port *port;
|
||||
uint32_t i;
|
||||
|
||||
spa_return_val_if_fail(node != NULL, -EINVAL);
|
||||
|
|
@ -563,17 +561,18 @@ impl_node_port_use_buffers(struct spa_node *node,
|
|||
this = SPA_CONTAINER_OF(node, struct impl, node);
|
||||
|
||||
spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL);
|
||||
port = &this->port;
|
||||
|
||||
if (!this->have_format)
|
||||
if (!port->have_format)
|
||||
return -EIO;
|
||||
|
||||
clear_buffers(this);
|
||||
clear_buffers(this, port);
|
||||
|
||||
for (i = 0; i < n_buffers; i++) {
|
||||
struct buffer *b;
|
||||
struct spa_data *d = buffers[i]->datas;
|
||||
|
||||
b = &this->buffers[i];
|
||||
b = &port->buffers[i];
|
||||
b->id = i;
|
||||
b->outbuf = buffers[i];
|
||||
b->outstanding = true;
|
||||
|
|
@ -586,7 +585,7 @@ impl_node_port_use_buffers(struct spa_node *node,
|
|||
buffers[i]);
|
||||
}
|
||||
}
|
||||
this->n_buffers = n_buffers;
|
||||
port->n_buffers = n_buffers;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -601,14 +600,16 @@ impl_node_port_alloc_buffers(struct spa_node *node,
|
|||
uint32_t *n_buffers)
|
||||
{
|
||||
struct impl *this;
|
||||
struct port *port;
|
||||
|
||||
spa_return_val_if_fail(node != NULL, -EINVAL);
|
||||
|
||||
this = SPA_CONTAINER_OF(node, struct impl, node);
|
||||
|
||||
spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL);
|
||||
port = &this->port;
|
||||
|
||||
if (!this->have_format)
|
||||
if (!port->have_format)
|
||||
return -EIO;
|
||||
|
||||
return -ENOTSUP;
|
||||
|
|
@ -622,15 +623,17 @@ impl_node_port_set_io(struct spa_node *node,
|
|||
void *data, size_t size)
|
||||
{
|
||||
struct impl *this;
|
||||
struct port *port;
|
||||
|
||||
spa_return_val_if_fail(node != NULL, -EINVAL);
|
||||
|
||||
this = SPA_CONTAINER_OF(node, struct impl, node);
|
||||
|
||||
spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL);
|
||||
port = &this->port;
|
||||
|
||||
if (id == SPA_IO_Buffers)
|
||||
this->io = data;
|
||||
port->io = data;
|
||||
else
|
||||
return -ENOENT;
|
||||
|
||||
|
|
@ -645,31 +648,34 @@ static int impl_node_port_reuse_buffer(struct spa_node *node, uint32_t port_id,
|
|||
static int impl_node_process(struct spa_node *node)
|
||||
{
|
||||
struct impl *this;
|
||||
struct spa_io_buffers *input;
|
||||
struct port *port;
|
||||
struct spa_io_buffers *io;
|
||||
|
||||
spa_return_val_if_fail(node != NULL, -EINVAL);
|
||||
|
||||
this = SPA_CONTAINER_OF(node, struct impl, node);
|
||||
input = this->io;
|
||||
spa_return_val_if_fail(input != NULL, -EIO);
|
||||
port = &this->port;
|
||||
|
||||
if (input->status == SPA_STATUS_HAVE_BUFFER && input->buffer_id < this->n_buffers) {
|
||||
struct buffer *b = &this->buffers[input->buffer_id];
|
||||
io = port->io;
|
||||
spa_return_val_if_fail(io != NULL, -EIO);
|
||||
|
||||
if (io->status == SPA_STATUS_HAVE_BUFFER && io->buffer_id < port->n_buffers) {
|
||||
struct buffer *b = &port->buffers[io->buffer_id];
|
||||
|
||||
if (!b->outstanding) {
|
||||
spa_log_warn(this->log, NAME " %p: buffer %u in use", this,
|
||||
input->buffer_id);
|
||||
input->status = -EINVAL;
|
||||
io->buffer_id);
|
||||
io->status = -EINVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spa_log_trace(this->log, NAME " %p: queue buffer %u", this, input->buffer_id);
|
||||
spa_log_trace(this->log, NAME " %p: queue buffer %u", this, io->buffer_id);
|
||||
|
||||
spa_list_append(&this->ready, &b->link);
|
||||
spa_list_append(&port->ready, &b->link);
|
||||
b->outstanding = false;
|
||||
|
||||
input->buffer_id = SPA_ID_INVALID;
|
||||
input->status = SPA_STATUS_OK;
|
||||
io->buffer_id = SPA_ID_INVALID;
|
||||
io->status = SPA_STATUS_OK;
|
||||
}
|
||||
if (this->callbacks == NULL || this->callbacks->ready == NULL)
|
||||
return consume_buffer(this);
|
||||
|
|
@ -742,6 +748,7 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
uint32_t n_support)
|
||||
{
|
||||
struct impl *this;
|
||||
struct port *port;
|
||||
uint32_t i;
|
||||
|
||||
spa_return_val_if_fail(factory != NULL, -EINVAL);
|
||||
|
|
@ -760,9 +767,17 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
}
|
||||
|
||||
this->node = impl_node;
|
||||
this->info = SPA_NODE_INFO_INIT();
|
||||
this->info.max_input_ports = 1;
|
||||
this->info.max_output_ports = 0;
|
||||
this->info.change_mask |= SPA_NODE_CHANGE_MASK_FLAGS;
|
||||
this->info.flags = SPA_NODE_FLAG_RT;
|
||||
this->info.change_mask |= SPA_NODE_CHANGE_MASK_PARAMS;
|
||||
this->params[0] = SPA_PARAM_INFO(SPA_PARAM_Props, SPA_PARAM_INFO_READWRITE);
|
||||
this->info.params = this->params;
|
||||
this->info.n_params = 1;
|
||||
reset_props(this, &this->props);
|
||||
|
||||
spa_list_init(&this->ready);
|
||||
|
||||
this->timer_source.func = on_input;
|
||||
this->timer_source.data = this;
|
||||
|
|
@ -777,11 +792,22 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
if (this->data_loop)
|
||||
spa_loop_add_source(this->data_loop, &this->timer_source);
|
||||
|
||||
this->info = SPA_PORT_INFO_INIT();
|
||||
this->info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
this->info.flags = SPA_PORT_FLAG_CAN_USE_BUFFERS | SPA_PORT_FLAG_NO_REF;
|
||||
port = &this->port;
|
||||
port->info = SPA_PORT_INFO_INIT();
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
port->info.flags = SPA_PORT_FLAG_CAN_USE_BUFFERS | SPA_PORT_FLAG_NO_REF;
|
||||
if (this->props.live)
|
||||
this->info.flags |= SPA_PORT_FLAG_LIVE;
|
||||
port->info.flags |= SPA_PORT_FLAG_LIVE;
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
|
||||
port->params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
|
||||
port->params[1] = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
|
||||
port->params[2] = SPA_PARAM_INFO(SPA_PARAM_IO, 0);
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
|
||||
port->info.params = port->params;
|
||||
port->info.n_params = 5;
|
||||
|
||||
spa_list_init(&port->ready);
|
||||
|
||||
spa_log_info(this->log, NAME " %p: initialized", this);
|
||||
|
||||
|
|
|
|||
|
|
@ -57,22 +57,10 @@ struct buffer {
|
|||
struct spa_list link;
|
||||
};
|
||||
|
||||
struct impl {
|
||||
struct spa_handle handle;
|
||||
struct spa_node node;
|
||||
|
||||
struct spa_log *log;
|
||||
struct spa_loop *data_loop;
|
||||
|
||||
struct props props;
|
||||
|
||||
const struct spa_node_callbacks *callbacks;
|
||||
void *callbacks_data;
|
||||
|
||||
struct spa_source timer_source;
|
||||
struct itimerspec timerspec;
|
||||
|
||||
struct port {
|
||||
struct spa_port_info info;
|
||||
struct spa_param_info params[5];
|
||||
|
||||
struct spa_io_buffers *io;
|
||||
|
||||
bool have_format;
|
||||
|
|
@ -81,13 +69,34 @@ struct impl {
|
|||
struct buffer buffers[MAX_BUFFERS];
|
||||
uint32_t n_buffers;
|
||||
|
||||
struct spa_list empty;
|
||||
};
|
||||
|
||||
struct impl {
|
||||
struct spa_handle handle;
|
||||
struct spa_node node;
|
||||
|
||||
struct spa_log *log;
|
||||
struct spa_loop *data_loop;
|
||||
|
||||
struct spa_node_info info;
|
||||
struct spa_param_info params[1];
|
||||
struct props props;
|
||||
|
||||
const struct spa_node_callbacks *callbacks;
|
||||
void *callbacks_data;
|
||||
|
||||
struct spa_source timer_source;
|
||||
struct itimerspec timerspec;
|
||||
|
||||
bool started;
|
||||
uint64_t start_time;
|
||||
uint64_t elapsed_time;
|
||||
|
||||
uint64_t buffer_count;
|
||||
struct spa_list empty;
|
||||
bool underrun;
|
||||
|
||||
struct port port;
|
||||
};
|
||||
|
||||
#define CHECK_PORT(this,d,p) ((d) == SPA_DIRECTION_OUTPUT && (p) < MAX_PORTS)
|
||||
|
|
@ -127,15 +136,6 @@ static int impl_node_enum_params(struct spa_node *node, int seq,
|
|||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
|
||||
switch (id) {
|
||||
case SPA_PARAM_List:
|
||||
if (result.index > 0)
|
||||
return 0;
|
||||
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_ParamList, id,
|
||||
SPA_PARAM_LIST_id, SPA_POD_Id(SPA_PARAM_Props));
|
||||
break;
|
||||
|
||||
case SPA_PARAM_Props:
|
||||
{
|
||||
struct props *p = &this->props;
|
||||
|
|
@ -243,18 +243,19 @@ static inline void read_timer(struct impl *this)
|
|||
static int make_buffer(struct impl *this)
|
||||
{
|
||||
struct buffer *b;
|
||||
struct spa_io_buffers *io = this->io;
|
||||
struct port *port = &this->port;
|
||||
struct spa_io_buffers *io = port->io;
|
||||
int n_bytes;
|
||||
|
||||
read_timer(this);
|
||||
|
||||
if (spa_list_is_empty(&this->empty)) {
|
||||
if (spa_list_is_empty(&port->empty)) {
|
||||
set_timer(this, false);
|
||||
this->underrun = true;
|
||||
spa_log_error(this->log, NAME " %p: out of buffers", this);
|
||||
return -EPIPE;
|
||||
}
|
||||
b = spa_list_first(&this->empty, struct buffer, link);
|
||||
b = spa_list_first(&port->empty, struct buffer, link);
|
||||
spa_list_remove(&b->link);
|
||||
b->outstanding = true;
|
||||
|
||||
|
|
@ -298,21 +299,23 @@ static void on_output(struct spa_source *source)
|
|||
static int impl_node_send_command(struct spa_node *node, const struct spa_command *command)
|
||||
{
|
||||
struct impl *this;
|
||||
struct port *port;
|
||||
|
||||
spa_return_val_if_fail(node != NULL, -EINVAL);
|
||||
spa_return_val_if_fail(command != NULL, -EINVAL);
|
||||
|
||||
this = SPA_CONTAINER_OF(node, struct impl, node);
|
||||
port = &this->port;
|
||||
|
||||
switch (SPA_NODE_COMMAND_ID(command)) {
|
||||
case SPA_NODE_COMMAND_Start:
|
||||
{
|
||||
struct timespec now;
|
||||
|
||||
if (!this->have_format)
|
||||
if (!port->have_format)
|
||||
return -EIO;
|
||||
|
||||
if (this->n_buffers == 0)
|
||||
if (port->n_buffers == 0)
|
||||
return -EIO;
|
||||
|
||||
if (this->started)
|
||||
|
|
@ -331,9 +334,9 @@ static int impl_node_send_command(struct spa_node *node, const struct spa_comman
|
|||
break;
|
||||
}
|
||||
case SPA_NODE_COMMAND_Pause:
|
||||
if (!this->have_format)
|
||||
if (!port->have_format)
|
||||
return -EIO;
|
||||
if (this->n_buffers == 0)
|
||||
if (port->n_buffers == 0)
|
||||
return -EIO;
|
||||
|
||||
if (!this->started)
|
||||
|
|
@ -348,14 +351,22 @@ static int impl_node_send_command(struct spa_node *node, const struct spa_comman
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void emit_port_info(struct impl *this)
|
||||
static void emit_node_info(struct impl *this)
|
||||
{
|
||||
if (this->callbacks && this->callbacks->port_info && this->info.change_mask) {
|
||||
this->callbacks->port_info(this->callbacks_data, SPA_DIRECTION_OUTPUT, 0, &this->info);
|
||||
if (this->callbacks && this->callbacks->info && this->info.change_mask) {
|
||||
this->callbacks->info(this->callbacks_data, &this->info);
|
||||
this->info.change_mask = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_port_info(struct impl *this, struct port *port)
|
||||
{
|
||||
if (this->callbacks && this->callbacks->port_info && port->info.change_mask) {
|
||||
this->callbacks->port_info(this->callbacks_data, SPA_DIRECTION_OUTPUT, 0, &port->info);
|
||||
port->info.change_mask = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
impl_node_set_callbacks(struct spa_node *node,
|
||||
const struct spa_node_callbacks *callbacks,
|
||||
|
|
@ -374,7 +385,8 @@ impl_node_set_callbacks(struct spa_node *node,
|
|||
this->callbacks = callbacks;
|
||||
this->callbacks_data = data;
|
||||
|
||||
emit_port_info(this);
|
||||
emit_node_info(this);
|
||||
emit_port_info(this, &this->port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -391,8 +403,7 @@ impl_node_remove_port(struct spa_node *node, enum spa_direction direction, uint3
|
|||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static int port_enum_formats(struct spa_node *node,
|
||||
enum spa_direction direction, uint32_t port_id,
|
||||
static int port_enum_formats(struct impl *this, struct port *port,
|
||||
uint32_t index,
|
||||
const struct spa_pod *filter,
|
||||
struct spa_pod **param,
|
||||
|
|
@ -401,21 +412,18 @@ static int port_enum_formats(struct spa_node *node,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int port_get_format(struct spa_node *node,
|
||||
enum spa_direction direction, uint32_t port_id,
|
||||
static int port_get_format(struct impl *this, struct port *port,
|
||||
uint32_t index,
|
||||
const struct spa_pod *filter,
|
||||
struct spa_pod **param,
|
||||
struct spa_pod_builder *builder)
|
||||
{
|
||||
struct impl *this = SPA_CONTAINER_OF(node, struct impl, node);
|
||||
|
||||
if (!this->have_format)
|
||||
if (!port->have_format)
|
||||
return -EIO;
|
||||
if (index > 0)
|
||||
return 0;
|
||||
|
||||
*param = SPA_MEMBER(this->format_buffer, 0, struct spa_pod);
|
||||
*param = SPA_MEMBER(port->format_buffer, 0, struct spa_pod);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -427,6 +435,7 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
const struct spa_pod *filter)
|
||||
{
|
||||
struct impl *this;
|
||||
struct port *port;
|
||||
struct spa_pod_builder b = { 0 };
|
||||
uint8_t buffer[1024];
|
||||
struct spa_pod *param;
|
||||
|
|
@ -441,6 +450,7 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
spa_return_val_if_fail(this->callbacks && this->callbacks->result, -EIO);
|
||||
|
||||
spa_return_val_if_fail(CHECK_PORT(node, direction, port_id), -EINVAL);
|
||||
port = &this->port;
|
||||
|
||||
result.id = id;
|
||||
result.next = start;
|
||||
|
|
@ -450,29 +460,14 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
|
||||
switch (id) {
|
||||
case SPA_PARAM_List:
|
||||
{
|
||||
uint32_t list[] = { SPA_PARAM_EnumFormat,
|
||||
SPA_PARAM_Format,
|
||||
SPA_PARAM_Buffers,
|
||||
SPA_PARAM_Meta };
|
||||
|
||||
if (result.index < SPA_N_ELEMENTS(list))
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_ParamList, id,
|
||||
SPA_PARAM_LIST_id, SPA_POD_Id(list[result.index]));
|
||||
else
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
case SPA_PARAM_EnumFormat:
|
||||
if ((res = port_enum_formats(node, direction, port_id,
|
||||
result.index, filter, ¶m, &b)) <= 0)
|
||||
if ((res = port_enum_formats(this, port,
|
||||
result.index, filter, ¶m, &b)) <= 0)
|
||||
return res;
|
||||
break;
|
||||
case SPA_PARAM_Format:
|
||||
if ((res = port_get_format(node, direction, port_id,
|
||||
result.index, filter, ¶m, &b)) <= 0)
|
||||
if ((res = port_get_format(this, port,
|
||||
result.index, filter, ¶m, &b)) <= 0)
|
||||
return res;
|
||||
break;
|
||||
case SPA_PARAM_Buffers:
|
||||
|
|
@ -518,33 +513,30 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int clear_buffers(struct impl *this)
|
||||
static int clear_buffers(struct impl *this, struct port *port)
|
||||
{
|
||||
if (this->n_buffers > 0) {
|
||||
if (port->n_buffers > 0) {
|
||||
spa_log_info(this->log, NAME " %p: clear buffers", this);
|
||||
this->n_buffers = 0;
|
||||
spa_list_init(&this->empty);
|
||||
port->n_buffers = 0;
|
||||
spa_list_init(&port->empty);
|
||||
this->started = false;
|
||||
set_timer(this, false);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int port_set_format(struct spa_node *node,
|
||||
enum spa_direction direction, uint32_t port_id,
|
||||
static int port_set_format(struct impl *this, struct port *port,
|
||||
uint32_t flags,
|
||||
const struct spa_pod *format)
|
||||
{
|
||||
struct impl *this = SPA_CONTAINER_OF(node, struct impl, node);
|
||||
|
||||
if (format == NULL) {
|
||||
this->have_format = false;
|
||||
clear_buffers(this);
|
||||
port->have_format = false;
|
||||
clear_buffers(this, port);
|
||||
} else {
|
||||
if (SPA_POD_SIZE(format) > sizeof(this->format_buffer))
|
||||
if (SPA_POD_SIZE(format) > sizeof(port->format_buffer))
|
||||
return -ENOSPC;
|
||||
memcpy(this->format_buffer, format, SPA_POD_SIZE(format));
|
||||
this->have_format = true;
|
||||
memcpy(port->format_buffer, format, SPA_POD_SIZE(format));
|
||||
port->have_format = true;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -555,12 +547,17 @@ impl_node_port_set_param(struct spa_node *node,
|
|||
uint32_t id, uint32_t flags,
|
||||
const struct spa_pod *param)
|
||||
{
|
||||
struct impl *this;
|
||||
struct port *port;
|
||||
|
||||
spa_return_val_if_fail(node != NULL, -EINVAL);
|
||||
this = SPA_CONTAINER_OF(node, struct impl, node);
|
||||
|
||||
spa_return_val_if_fail(CHECK_PORT(node, direction, port_id), -EINVAL);
|
||||
port = &this->port;
|
||||
|
||||
if (id == SPA_PARAM_Format) {
|
||||
return port_set_format(node, direction, port_id, flags, param);
|
||||
return port_set_format(this, port, flags, param);
|
||||
}
|
||||
else
|
||||
return -ENOENT;
|
||||
|
|
@ -574,6 +571,7 @@ impl_node_port_use_buffers(struct spa_node *node,
|
|||
uint32_t n_buffers)
|
||||
{
|
||||
struct impl *this;
|
||||
struct port *port;
|
||||
uint32_t i;
|
||||
|
||||
spa_return_val_if_fail(node != NULL, -EINVAL);
|
||||
|
|
@ -581,17 +579,18 @@ impl_node_port_use_buffers(struct spa_node *node,
|
|||
this = SPA_CONTAINER_OF(node, struct impl, node);
|
||||
|
||||
spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL);
|
||||
port = &this->port;
|
||||
|
||||
if (!this->have_format)
|
||||
if (!port->have_format)
|
||||
return -EIO;
|
||||
|
||||
clear_buffers(this);
|
||||
clear_buffers(this, port);
|
||||
|
||||
for (i = 0; i < n_buffers; i++) {
|
||||
struct buffer *b;
|
||||
struct spa_data *d = buffers[i]->datas;
|
||||
|
||||
b = &this->buffers[i];
|
||||
b = &port->buffers[i];
|
||||
b->id = i;
|
||||
b->outbuf = buffers[i];
|
||||
b->outstanding = false;
|
||||
|
|
@ -603,9 +602,9 @@ impl_node_port_use_buffers(struct spa_node *node,
|
|||
spa_log_error(this->log, NAME " %p: invalid memory on buffer %p", this,
|
||||
buffers[i]);
|
||||
}
|
||||
spa_list_append(&this->empty, &b->link);
|
||||
spa_list_append(&port->empty, &b->link);
|
||||
}
|
||||
this->n_buffers = n_buffers;
|
||||
port->n_buffers = n_buffers;
|
||||
this->underrun = false;
|
||||
|
||||
return 0;
|
||||
|
|
@ -621,14 +620,16 @@ impl_node_port_alloc_buffers(struct spa_node *node,
|
|||
uint32_t *n_buffers)
|
||||
{
|
||||
struct impl *this;
|
||||
struct port *port;
|
||||
|
||||
spa_return_val_if_fail(node != NULL, -EINVAL);
|
||||
|
||||
this = SPA_CONTAINER_OF(node, struct impl, node);
|
||||
|
||||
spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL);
|
||||
port = &this->port;
|
||||
|
||||
if (!this->have_format)
|
||||
if (!port->have_format)
|
||||
return -EIO;
|
||||
|
||||
return -ENOTSUP;
|
||||
|
|
@ -642,30 +643,32 @@ impl_node_port_set_io(struct spa_node *node,
|
|||
void *data, size_t size)
|
||||
{
|
||||
struct impl *this;
|
||||
struct port *port;
|
||||
|
||||
spa_return_val_if_fail(node != NULL, -EINVAL);
|
||||
|
||||
this = SPA_CONTAINER_OF(node, struct impl, node);
|
||||
|
||||
spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL);
|
||||
port = &this->port;
|
||||
|
||||
if (id == SPA_IO_Buffers)
|
||||
this->io = data;
|
||||
port->io = data;
|
||||
else
|
||||
return -ENOENT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void reuse_buffer(struct impl *this, uint32_t id)
|
||||
static inline void reuse_buffer(struct impl *this, struct port *port, uint32_t id)
|
||||
{
|
||||
struct buffer *b = &this->buffers[id];
|
||||
struct buffer *b = &port->buffers[id];
|
||||
spa_return_if_fail(b->outstanding);
|
||||
|
||||
spa_log_trace(this->log, NAME " %p: reuse buffer %d", this, id);
|
||||
|
||||
b->outstanding = false;
|
||||
spa_list_append(&this->empty, &b->link);
|
||||
spa_list_append(&port->empty, &b->link);
|
||||
|
||||
if (this->underrun) {
|
||||
set_timer(this, true);
|
||||
|
|
@ -676,15 +679,18 @@ static inline void reuse_buffer(struct impl *this, uint32_t id)
|
|||
static int impl_node_port_reuse_buffer(struct spa_node *node, uint32_t port_id, uint32_t buffer_id)
|
||||
{
|
||||
struct impl *this;
|
||||
struct port *port;
|
||||
|
||||
spa_return_val_if_fail(node != NULL, -EINVAL);
|
||||
|
||||
this = SPA_CONTAINER_OF(node, struct impl, node);
|
||||
|
||||
spa_return_val_if_fail(port_id == 0, -EINVAL);
|
||||
spa_return_val_if_fail(buffer_id < this->n_buffers, -EINVAL);
|
||||
port = &this->port;
|
||||
|
||||
reuse_buffer(this, buffer_id);
|
||||
spa_return_val_if_fail(buffer_id < port->n_buffers, -EINVAL);
|
||||
|
||||
reuse_buffer(this, port, buffer_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -692,20 +698,22 @@ static int impl_node_port_reuse_buffer(struct spa_node *node, uint32_t port_id,
|
|||
static int impl_node_process(struct spa_node *node)
|
||||
{
|
||||
struct impl *this;
|
||||
struct port *port;
|
||||
struct spa_io_buffers *io;
|
||||
|
||||
spa_return_val_if_fail(node != NULL, -EINVAL);
|
||||
|
||||
this = SPA_CONTAINER_OF(node, struct impl, node);
|
||||
io = this->io;
|
||||
port = &this->port;
|
||||
io = port->io;
|
||||
spa_return_val_if_fail(io != NULL, -EIO);
|
||||
|
||||
if (io->status == SPA_STATUS_HAVE_BUFFER)
|
||||
return SPA_STATUS_HAVE_BUFFER;
|
||||
|
||||
if (io->buffer_id < this->n_buffers) {
|
||||
reuse_buffer(this, this->io->buffer_id);
|
||||
this->io->buffer_id = SPA_ID_INVALID;
|
||||
if (io->buffer_id < port->n_buffers) {
|
||||
reuse_buffer(this, port, io->buffer_id);
|
||||
io->buffer_id = SPA_ID_INVALID;
|
||||
}
|
||||
|
||||
if ((this->callbacks == NULL || this->callbacks->ready == NULL) &&
|
||||
|
|
@ -780,6 +788,7 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
uint32_t n_support)
|
||||
{
|
||||
struct impl *this;
|
||||
struct port *port;
|
||||
uint32_t i;
|
||||
|
||||
spa_return_val_if_fail(factory != NULL, -EINVAL);
|
||||
|
|
@ -798,10 +807,17 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
}
|
||||
|
||||
this->node = impl_node;
|
||||
this->info = SPA_NODE_INFO_INIT();
|
||||
this->info.max_input_ports = 0;
|
||||
this->info.max_output_ports = 1;
|
||||
this->info.change_mask |= SPA_NODE_CHANGE_MASK_FLAGS;
|
||||
this->info.flags = SPA_NODE_FLAG_RT;
|
||||
this->info.change_mask |= SPA_NODE_CHANGE_MASK_PARAMS;
|
||||
this->params[0] = SPA_PARAM_INFO(SPA_PARAM_Props, SPA_PARAM_INFO_READWRITE);
|
||||
this->info.params = this->params;
|
||||
this->info.n_params = 1;
|
||||
reset_props(this, &this->props);
|
||||
|
||||
spa_list_init(&this->empty);
|
||||
|
||||
this->timer_source.func = on_output;
|
||||
this->timer_source.data = this;
|
||||
this->timer_source.fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
|
||||
|
|
@ -815,11 +831,22 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
if (this->data_loop)
|
||||
spa_loop_add_source(this->data_loop, &this->timer_source);
|
||||
|
||||
this->info = SPA_PORT_INFO_INIT();
|
||||
this->info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
this->info.flags = SPA_PORT_FLAG_CAN_USE_BUFFERS | SPA_PORT_FLAG_NO_REF;
|
||||
port = &this->port;
|
||||
port->info = SPA_PORT_INFO_INIT();
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
port->info.flags = SPA_PORT_FLAG_CAN_USE_BUFFERS | SPA_PORT_FLAG_NO_REF;
|
||||
if (this->props.live)
|
||||
this->info.flags |= SPA_PORT_FLAG_LIVE;
|
||||
port->info.flags |= SPA_PORT_FLAG_LIVE;
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
|
||||
port->params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
|
||||
port->params[1] = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
|
||||
port->params[2] = SPA_PARAM_INFO(SPA_PARAM_IO, 0);
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
|
||||
port->info.params = port->params;
|
||||
port->info.n_params = 5;
|
||||
|
||||
spa_list_init(&port->empty);
|
||||
|
||||
spa_log_info(this->log, NAME " %p: initialized", this);
|
||||
|
||||
|
|
|
|||
|
|
@ -74,21 +74,25 @@ static int emit_info(struct impl *this)
|
|||
int res;
|
||||
struct spa_dict_item items[6];
|
||||
struct spa_device_info info;
|
||||
uint32_t params[] = { SPA_PARAM_EnumProfile, SPA_PARAM_Profile };
|
||||
struct spa_param_info params[2];
|
||||
|
||||
if ((res = spa_v4l2_open(&this->dev, this->props.device)) < 0)
|
||||
return res;
|
||||
|
||||
info = SPA_DEVICE_INFO_INIT();
|
||||
info.change_mask = SPA_DEVICE_CHANGE_MASK_INFO | SPA_DEVICE_CHANGE_MASK_PARAMS;
|
||||
|
||||
info.change_mask = SPA_DEVICE_CHANGE_MASK_PROPS;
|
||||
items[0] = SPA_DICT_ITEM_INIT("device.api", "v4l2");
|
||||
items[1] = SPA_DICT_ITEM_INIT("device.path", (char *)this->props.device);
|
||||
items[2] = SPA_DICT_ITEM_INIT("media.class", "Video/Device");
|
||||
items[3] = SPA_DICT_ITEM_INIT("v4l2.driver", (char *)this->dev.cap.driver);
|
||||
items[4] = SPA_DICT_ITEM_INIT("v4l2.card", (char *)this->dev.cap.card);
|
||||
items[5] = SPA_DICT_ITEM_INIT("v4l2.bus", (char *)this->dev.cap.bus_info);
|
||||
info.info = &SPA_DICT_INIT(items, 6);
|
||||
info.props = &SPA_DICT_INIT(items, 6);
|
||||
|
||||
info.change_mask |= SPA_DEVICE_CHANGE_MASK_PARAMS;
|
||||
params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumProfile, SPA_PARAM_INFO_READ);
|
||||
params[1] = SPA_PARAM_INFO(SPA_PARAM_Profile, SPA_PARAM_INFO_WRITE);
|
||||
info.n_params = SPA_N_ELEMENTS(params);
|
||||
info.params = params;
|
||||
|
||||
|
|
@ -103,8 +107,8 @@ static int emit_info(struct impl *this)
|
|||
oinfo = SPA_DEVICE_OBJECT_INFO_INIT();
|
||||
oinfo.type = SPA_TYPE_INTERFACE_Node;
|
||||
oinfo.factory = &spa_v4l2_source_factory;
|
||||
oinfo.change_mask = SPA_DEVICE_OBJECT_CHANGE_MASK_INFO;
|
||||
oinfo.info = &SPA_DICT_INIT(items, 6);
|
||||
oinfo.change_mask = SPA_DEVICE_OBJECT_CHANGE_MASK_PROPS;
|
||||
oinfo.props = &SPA_DICT_INIT(items, 6);
|
||||
|
||||
this->callbacks->object_info(this->callbacks_data, 0, &oinfo);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include <spa/utils/list.h>
|
||||
#include <spa/node/node.h>
|
||||
#include <spa/node/io.h>
|
||||
#include <spa/node/utils.h>
|
||||
#include <spa/param/video/format-utils.h>
|
||||
#include <spa/param/param.h>
|
||||
#include <spa/pod/filter.h>
|
||||
|
|
@ -115,6 +116,7 @@ struct port {
|
|||
struct spa_port_info info;
|
||||
struct spa_io_buffers *io;
|
||||
struct spa_io_sequence *control;
|
||||
struct spa_param_info params[8];
|
||||
};
|
||||
|
||||
struct impl {
|
||||
|
|
@ -125,11 +127,10 @@ struct impl {
|
|||
struct spa_loop *main_loop;
|
||||
struct spa_loop *data_loop;
|
||||
|
||||
uint32_t seq;
|
||||
|
||||
struct spa_node_info info;
|
||||
struct spa_param_info params[8];
|
||||
struct props props;
|
||||
|
||||
|
||||
const struct spa_node_callbacks *callbacks;
|
||||
void *callbacks_data;
|
||||
|
||||
|
|
@ -172,19 +173,6 @@ static int impl_node_enum_params(struct spa_node *node, int seq,
|
|||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
|
||||
switch (id) {
|
||||
case SPA_PARAM_List:
|
||||
{
|
||||
uint32_t list[] = { SPA_PARAM_PropInfo,
|
||||
SPA_PARAM_Props };
|
||||
|
||||
if (result.index < SPA_N_ELEMENTS(list))
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_ParamList, id,
|
||||
SPA_PARAM_LIST_id, SPA_POD_Id(list[result.index]));
|
||||
else
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
case SPA_PARAM_PropInfo:
|
||||
{
|
||||
struct props *p = &this->props;
|
||||
|
|
@ -343,22 +331,19 @@ static const struct spa_dict_item info_items[] = {
|
|||
|
||||
static void emit_node_info(struct impl *this)
|
||||
{
|
||||
if (this->callbacks && this->callbacks->info) {
|
||||
struct spa_node_info info;
|
||||
|
||||
info = SPA_NODE_INFO_INIT();
|
||||
info.max_output_ports = 1;
|
||||
info.change_mask = SPA_NODE_CHANGE_MASK_PROPS;
|
||||
info.props = &SPA_DICT_INIT_ARRAY(info_items);
|
||||
|
||||
this->callbacks->info(this->callbacks_data, &info);
|
||||
if (this->callbacks && this->callbacks->info && this->info.change_mask) {
|
||||
this->info.props = &SPA_DICT_INIT_ARRAY(info_items);
|
||||
this->callbacks->info(this->callbacks_data, &this->info);
|
||||
this->info.change_mask = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_port_info(struct impl *this, struct port *port)
|
||||
{
|
||||
if (this->callbacks && this->callbacks->port_info)
|
||||
if (this->callbacks && this->callbacks->port_info && port->info.change_mask) {
|
||||
this->callbacks->port_info(this->callbacks_data, SPA_DIRECTION_OUTPUT, 0, &port->info);
|
||||
port->info.change_mask = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int impl_node_set_callbacks(struct spa_node *node,
|
||||
|
|
@ -480,23 +465,6 @@ static int impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
|
||||
switch (id) {
|
||||
case SPA_PARAM_List:
|
||||
{
|
||||
uint32_t list[] = { SPA_PARAM_PropInfo,
|
||||
SPA_PARAM_EnumFormat,
|
||||
SPA_PARAM_Format,
|
||||
SPA_PARAM_Buffers,
|
||||
SPA_PARAM_Meta,
|
||||
SPA_PARAM_IO };
|
||||
|
||||
if (result.index < SPA_N_ELEMENTS(list))
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_ParamList, id,
|
||||
SPA_PARAM_LIST_id, SPA_POD_Id(list[result.index]));
|
||||
else
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
case SPA_PARAM_PropInfo:
|
||||
return spa_v4l2_enum_controls(this, seq, start, num, filter);
|
||||
|
||||
|
|
@ -586,11 +554,14 @@ static int port_set_format(struct spa_node *node,
|
|||
int res;
|
||||
|
||||
if (format == NULL) {
|
||||
if (!port->have_format)
|
||||
return 0;
|
||||
|
||||
spa_v4l2_stream_off(this);
|
||||
spa_v4l2_clear_buffers(this);
|
||||
port->have_format = false;
|
||||
spa_v4l2_close(&port->dev);
|
||||
return 0;
|
||||
goto done;
|
||||
} else {
|
||||
if ((res = spa_format_parse(format, &info.media_type, &info.media_subtype)) < 0)
|
||||
return res;
|
||||
|
|
@ -652,6 +623,16 @@ static int port_set_format(struct spa_node *node,
|
|||
port->have_format = true;
|
||||
}
|
||||
|
||||
done:
|
||||
if (port->have_format) {
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_READWRITE);
|
||||
port->params[5] = SPA_PARAM_INFO(SPA_PARAM_Buffers, SPA_PARAM_INFO_READ);
|
||||
} else {
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
port->params[5] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
|
||||
}
|
||||
emit_port_info(this, port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -983,6 +964,13 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
|
||||
this->node = impl_node;
|
||||
|
||||
this->info = SPA_NODE_INFO_INIT();
|
||||
this->info.max_output_ports = 1;
|
||||
this->info.change_mask = SPA_NODE_CHANGE_MASK_PROPS;
|
||||
this->params[0] = SPA_PARAM_INFO(SPA_PARAM_PropInfo, SPA_PARAM_INFO_READ);
|
||||
this->params[1] = SPA_PARAM_INFO(SPA_PARAM_Props, SPA_PARAM_INFO_READWRITE);
|
||||
this->info.params = this->params;
|
||||
this->info.n_params = 2;
|
||||
reset_props(&this->props);
|
||||
|
||||
port = GET_OUT_PORT(this, 0);
|
||||
|
|
@ -992,6 +980,14 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
port->info.flags = SPA_PORT_FLAG_LIVE |
|
||||
SPA_PORT_FLAG_PHYSICAL |
|
||||
SPA_PORT_FLAG_TERMINAL;
|
||||
port->params[0] = SPA_PARAM_INFO(SPA_PARAM_PropInfo, SPA_PARAM_INFO_READ);
|
||||
port->params[1] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
|
||||
port->params[2] = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
port->params[5] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
|
||||
port->info.params = port->params;
|
||||
port->info.n_params = 6;
|
||||
|
||||
port->export_buf = true;
|
||||
port->have_query_ext_ctrl = true;
|
||||
|
|
|
|||
|
|
@ -137,7 +137,8 @@ static void draw_pixel_uyvy(DrawingData * dd, int x, Pixel * color)
|
|||
|
||||
static int drawing_data_init(DrawingData * dd, struct impl *this, char *data)
|
||||
{
|
||||
struct spa_video_info *format = &this->current_format;
|
||||
struct port *port = &this->port;
|
||||
struct spa_video_info *format = &port->current_format;
|
||||
struct spa_rectangle *size = &format->info.raw.size;
|
||||
|
||||
if ((format->media_type != SPA_MEDIA_TYPE_video) ||
|
||||
|
|
@ -154,7 +155,7 @@ static int drawing_data_init(DrawingData * dd, struct impl *this, char *data)
|
|||
dd->line = data;
|
||||
dd->width = size->width;
|
||||
dd->height = size->height;
|
||||
dd->stride = this->stride;
|
||||
dd->stride = port->stride;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,8 +40,8 @@
|
|||
|
||||
#define NAME "videotestsrc"
|
||||
|
||||
#define FRAMES_TO_TIME(this,f) ((this->current_format.info.raw.framerate.denom * (f) * SPA_NSEC_PER_SEC) / \
|
||||
(this->current_format.info.raw.framerate.num))
|
||||
#define FRAMES_TO_TIME(port,f) ((port->current_format.info.raw.framerate.denom * (f) * SPA_NSEC_PER_SEC) / \
|
||||
(port->current_format.info.raw.framerate.num))
|
||||
|
||||
enum pattern {
|
||||
PATTERN_SMPTE_SNOW,
|
||||
|
|
@ -73,23 +73,10 @@ struct buffer {
|
|||
struct spa_list link;
|
||||
};
|
||||
|
||||
struct impl {
|
||||
struct spa_handle handle;
|
||||
struct spa_node node;
|
||||
|
||||
struct spa_log *log;
|
||||
struct spa_loop *data_loop;
|
||||
|
||||
struct props props;
|
||||
|
||||
const struct spa_node_callbacks *callbacks;
|
||||
void *callbacks_data;
|
||||
|
||||
bool async;
|
||||
struct spa_source timer_source;
|
||||
struct itimerspec timerspec;
|
||||
|
||||
struct port {
|
||||
struct spa_port_info info;
|
||||
struct spa_param_info params[5];
|
||||
|
||||
struct spa_io_buffers *io;
|
||||
|
||||
bool have_format;
|
||||
|
|
@ -100,12 +87,34 @@ struct impl {
|
|||
struct buffer buffers[MAX_BUFFERS];
|
||||
uint32_t n_buffers;
|
||||
|
||||
struct spa_list empty;
|
||||
};
|
||||
|
||||
struct impl {
|
||||
struct spa_handle handle;
|
||||
struct spa_node node;
|
||||
|
||||
struct spa_log *log;
|
||||
struct spa_loop *data_loop;
|
||||
|
||||
struct spa_node_info info;
|
||||
struct spa_param_info params[2];
|
||||
struct props props;
|
||||
|
||||
const struct spa_node_callbacks *callbacks;
|
||||
void *callbacks_data;
|
||||
|
||||
bool async;
|
||||
struct spa_source timer_source;
|
||||
struct itimerspec timerspec;
|
||||
|
||||
bool started;
|
||||
uint64_t start_time;
|
||||
uint64_t elapsed_time;
|
||||
|
||||
uint64_t frame_count;
|
||||
struct spa_list empty;
|
||||
|
||||
struct port port;
|
||||
};
|
||||
|
||||
#define CHECK_PORT(this,d,p) ((d) == SPA_DIRECTION_OUTPUT && (p) < MAX_PORTS)
|
||||
|
|
@ -136,19 +145,6 @@ static int impl_node_enum_params(struct spa_node *node, int seq,
|
|||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
|
||||
switch (id) {
|
||||
case SPA_PARAM_List:
|
||||
{
|
||||
uint32_t list[] = { SPA_PARAM_PropInfo,
|
||||
SPA_PARAM_Props };
|
||||
|
||||
if (result.index < SPA_N_ELEMENTS(list))
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_ParamList, id,
|
||||
SPA_PARAM_LIST_id, SPA_POD_Id(list[result.index]));
|
||||
else
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
case SPA_PARAM_PropInfo:
|
||||
{
|
||||
struct props *p = &this->props;
|
||||
|
|
@ -295,17 +291,18 @@ static void read_timer(struct impl *this)
|
|||
static int make_buffer(struct impl *this)
|
||||
{
|
||||
struct buffer *b;
|
||||
struct spa_io_buffers *io = this->io;
|
||||
struct port *port = &this->port;
|
||||
struct spa_io_buffers *io = port->io;
|
||||
uint32_t n_bytes;
|
||||
|
||||
read_timer(this);
|
||||
|
||||
if (spa_list_is_empty(&this->empty)) {
|
||||
if (spa_list_is_empty(&port->empty)) {
|
||||
set_timer(this, false);
|
||||
spa_log_error(this->log, NAME " %p: out of buffers", this);
|
||||
return -EPIPE;
|
||||
}
|
||||
b = spa_list_first(&this->empty, struct buffer, link);
|
||||
b = spa_list_first(&port->empty, struct buffer, link);
|
||||
spa_list_remove(&b->link);
|
||||
b->outstanding = true;
|
||||
|
||||
|
|
@ -317,7 +314,7 @@ static int make_buffer(struct impl *this)
|
|||
|
||||
b->outbuf->datas[0].chunk->offset = 0;
|
||||
b->outbuf->datas[0].chunk->size = n_bytes;
|
||||
b->outbuf->datas[0].chunk->stride = this->stride;
|
||||
b->outbuf->datas[0].chunk->stride = port->stride;
|
||||
|
||||
if (b->h) {
|
||||
b->h->seq = this->frame_count;
|
||||
|
|
@ -326,7 +323,7 @@ static int make_buffer(struct impl *this)
|
|||
}
|
||||
|
||||
this->frame_count++;
|
||||
this->elapsed_time = FRAMES_TO_TIME(this, this->frame_count);
|
||||
this->elapsed_time = FRAMES_TO_TIME(port, this->frame_count);
|
||||
set_timer(this, true);
|
||||
|
||||
io->buffer_id = b->id;
|
||||
|
|
@ -349,20 +346,22 @@ static void on_output(struct spa_source *source)
|
|||
static int impl_node_send_command(struct spa_node *node, const struct spa_command *command)
|
||||
{
|
||||
struct impl *this;
|
||||
struct port *port;
|
||||
|
||||
spa_return_val_if_fail(node != NULL, -EINVAL);
|
||||
spa_return_val_if_fail(command != NULL, -EINVAL);
|
||||
|
||||
this = SPA_CONTAINER_OF(node, struct impl, node);
|
||||
port = &this->port;
|
||||
|
||||
switch (SPA_NODE_COMMAND_ID(command)) {
|
||||
case SPA_NODE_COMMAND_Start:
|
||||
{
|
||||
struct timespec now;
|
||||
|
||||
if (!this->have_format)
|
||||
if (!port->have_format)
|
||||
return -EIO;
|
||||
if (this->n_buffers == 0)
|
||||
if (port->n_buffers == 0)
|
||||
return -EIO;
|
||||
|
||||
if (this->started)
|
||||
|
|
@ -381,9 +380,9 @@ static int impl_node_send_command(struct spa_node *node, const struct spa_comman
|
|||
break;
|
||||
}
|
||||
case SPA_NODE_COMMAND_Pause:
|
||||
if (!this->have_format)
|
||||
if (!port->have_format)
|
||||
return -EIO;
|
||||
if (this->n_buffers == 0)
|
||||
if (port->n_buffers == 0)
|
||||
return -EIO;
|
||||
|
||||
if (!this->started)
|
||||
|
|
@ -404,23 +403,18 @@ static const struct spa_dict_item node_info_items[] = {
|
|||
|
||||
static void emit_node_info(struct impl *this)
|
||||
{
|
||||
if (this->callbacks && this->callbacks->info) {
|
||||
struct spa_node_info info;
|
||||
|
||||
info = SPA_NODE_INFO_INIT();
|
||||
info.max_output_ports = 1;
|
||||
info.change_mask = SPA_NODE_CHANGE_MASK_PROPS;
|
||||
info.props = &SPA_DICT_INIT_ARRAY(node_info_items);
|
||||
|
||||
this->callbacks->info(this->callbacks_data, &info);
|
||||
if (this->callbacks && this->callbacks->info && this->info.change_mask) {
|
||||
this->info.props = &SPA_DICT_INIT_ARRAY(node_info_items);
|
||||
this->callbacks->info(this->callbacks_data, &this->info);
|
||||
this->info.change_mask = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_port_info(struct impl *this)
|
||||
static void emit_port_info(struct impl *this, struct port *port)
|
||||
{
|
||||
if (this->callbacks && this->callbacks->port_info && this->info.change_mask) {
|
||||
this->callbacks->port_info(this->callbacks_data, SPA_DIRECTION_OUTPUT, 0, &this->info);
|
||||
this->info.change_mask = 0;
|
||||
if (this->callbacks && this->callbacks->port_info && port->info.change_mask) {
|
||||
this->callbacks->port_info(this->callbacks_data, SPA_DIRECTION_OUTPUT, 0, &port->info);
|
||||
port->info.change_mask = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -439,7 +433,7 @@ impl_node_set_callbacks(struct spa_node *node,
|
|||
this->callbacks_data = data;
|
||||
|
||||
emit_node_info(this);
|
||||
emit_port_info(this);
|
||||
emit_port_info(this, &this->port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -495,6 +489,7 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
const struct spa_pod *filter)
|
||||
{
|
||||
struct impl *this;
|
||||
struct port *port;
|
||||
struct spa_pod_builder b = { 0 };
|
||||
uint8_t buffer[1024];
|
||||
struct spa_pod *param;
|
||||
|
|
@ -509,6 +504,7 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
spa_return_val_if_fail(this->callbacks && this->callbacks->result, -EIO);
|
||||
|
||||
spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL);
|
||||
port = &this->port;
|
||||
|
||||
result.id = id;
|
||||
result.next = start;
|
||||
|
|
@ -518,21 +514,6 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
|
||||
switch (id) {
|
||||
case SPA_PARAM_List:
|
||||
{
|
||||
uint32_t list[] = { SPA_PARAM_EnumFormat,
|
||||
SPA_PARAM_Format,
|
||||
SPA_PARAM_Buffers,
|
||||
SPA_PARAM_Meta };
|
||||
|
||||
if (result.index < SPA_N_ELEMENTS(list))
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_ParamList, id,
|
||||
SPA_PARAM_LIST_id, SPA_POD_Id(list[result.index]));
|
||||
else
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
case SPA_PARAM_EnumFormat:
|
||||
if ((res = port_enum_formats(node, direction, port_id,
|
||||
result.index, filter, ¶m, &b)) <= 0)
|
||||
|
|
@ -540,19 +521,19 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
break;
|
||||
|
||||
case SPA_PARAM_Format:
|
||||
if (!this->have_format)
|
||||
if (!port->have_format)
|
||||
return -EIO;
|
||||
if (result.index > 0)
|
||||
return 0;
|
||||
|
||||
param = spa_format_video_raw_build(&b, id, &this->current_format.info.raw);
|
||||
param = spa_format_video_raw_build(&b, id, &port->current_format.info.raw);
|
||||
break;
|
||||
|
||||
case SPA_PARAM_Buffers:
|
||||
{
|
||||
struct spa_video_info_raw *raw_info = &this->current_format.info.raw;
|
||||
struct spa_video_info_raw *raw_info = &port->current_format.info.raw;
|
||||
|
||||
if (!this->have_format)
|
||||
if (!port->have_format)
|
||||
return -EIO;
|
||||
if (result.index > 0)
|
||||
return 0;
|
||||
|
|
@ -561,15 +542,12 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
SPA_TYPE_OBJECT_ParamBuffers, id,
|
||||
SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(2, 1, MAX_BUFFERS),
|
||||
SPA_PARAM_BUFFERS_blocks, SPA_POD_Int(1),
|
||||
SPA_PARAM_BUFFERS_size, SPA_POD_Int(this->stride * raw_info->size.height),
|
||||
SPA_PARAM_BUFFERS_stride, SPA_POD_Int(this->stride),
|
||||
SPA_PARAM_BUFFERS_size, SPA_POD_Int(port->stride * raw_info->size.height),
|
||||
SPA_PARAM_BUFFERS_stride, SPA_POD_Int(port->stride),
|
||||
SPA_PARAM_BUFFERS_align, SPA_POD_Int(16));
|
||||
break;
|
||||
}
|
||||
case SPA_PARAM_Meta:
|
||||
if (!this->have_format)
|
||||
return -EIO;
|
||||
|
||||
switch (result.index) {
|
||||
case 0:
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
|
|
@ -598,29 +576,27 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int clear_buffers(struct impl *this)
|
||||
static int clear_buffers(struct impl *this, struct port *port)
|
||||
{
|
||||
if (this->n_buffers > 0) {
|
||||
if (port->n_buffers > 0) {
|
||||
spa_log_info(this->log, NAME " %p: clear buffers", this);
|
||||
this->n_buffers = 0;
|
||||
spa_list_init(&this->empty);
|
||||
port->n_buffers = 0;
|
||||
spa_list_init(&port->empty);
|
||||
this->started = false;
|
||||
set_timer(this, false);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int port_set_format(struct spa_node *node,
|
||||
enum spa_direction direction, uint32_t port_id,
|
||||
static int port_set_format(struct impl *this, struct port *port,
|
||||
uint32_t flags,
|
||||
const struct spa_pod *format)
|
||||
{
|
||||
struct impl *this = SPA_CONTAINER_OF(node, struct impl, node);
|
||||
int res;
|
||||
|
||||
if (format == NULL) {
|
||||
this->have_format = false;
|
||||
clear_buffers(this);
|
||||
port->have_format = false;
|
||||
clear_buffers(this, port);
|
||||
} else {
|
||||
struct spa_video_info info = { 0 };
|
||||
|
||||
|
|
@ -635,20 +611,27 @@ static int port_set_format(struct spa_node *node,
|
|||
return -EINVAL;
|
||||
|
||||
if (info.info.raw.format == SPA_VIDEO_FORMAT_RGB)
|
||||
this->bpp = 3;
|
||||
port->bpp = 3;
|
||||
else if (info.info.raw.format == SPA_VIDEO_FORMAT_UYVY)
|
||||
this->bpp = 2;
|
||||
port->bpp = 2;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
this->current_format = info;
|
||||
this->have_format = true;
|
||||
port->current_format = info;
|
||||
port->have_format = true;
|
||||
}
|
||||
|
||||
if (this->have_format) {
|
||||
struct spa_video_info_raw *raw_info = &this->current_format.info.raw;
|
||||
this->stride = SPA_ROUND_UP_N(this->bpp * raw_info->size.width, 4);
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
|
||||
if (port->have_format) {
|
||||
struct spa_video_info_raw *raw_info = &port->current_format.info.raw;
|
||||
port->stride = SPA_ROUND_UP_N(port->bpp * raw_info->size.width, 4);
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_READWRITE);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, SPA_PARAM_INFO_READ);
|
||||
} else {
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
|
||||
}
|
||||
emit_port_info(this, port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -659,12 +642,17 @@ impl_node_port_set_param(struct spa_node *node,
|
|||
uint32_t id, uint32_t flags,
|
||||
const struct spa_pod *param)
|
||||
{
|
||||
struct impl *this;
|
||||
struct port *port;
|
||||
|
||||
spa_return_val_if_fail(node != NULL, -EINVAL);
|
||||
this = SPA_CONTAINER_OF(node, struct impl, node);
|
||||
|
||||
spa_return_val_if_fail(CHECK_PORT(node, direction, port_id), -EINVAL);
|
||||
port = &this->port;
|
||||
|
||||
if (id == SPA_PARAM_Format) {
|
||||
return port_set_format(node, direction, port_id, flags, param);
|
||||
return port_set_format(this, port, flags, param);
|
||||
}
|
||||
else
|
||||
return -ENOENT;
|
||||
|
|
@ -678,6 +666,7 @@ impl_node_port_use_buffers(struct spa_node *node,
|
|||
uint32_t n_buffers)
|
||||
{
|
||||
struct impl *this;
|
||||
struct port *port;
|
||||
uint32_t i;
|
||||
|
||||
spa_return_val_if_fail(node != NULL, -EINVAL);
|
||||
|
|
@ -685,17 +674,18 @@ impl_node_port_use_buffers(struct spa_node *node,
|
|||
this = SPA_CONTAINER_OF(node, struct impl, node);
|
||||
|
||||
spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL);
|
||||
port = &this->port;
|
||||
|
||||
if (!this->have_format)
|
||||
if (!port->have_format)
|
||||
return -EIO;
|
||||
|
||||
clear_buffers(this);
|
||||
clear_buffers(this, port);
|
||||
|
||||
for (i = 0; i < n_buffers; i++) {
|
||||
struct buffer *b;
|
||||
struct spa_data *d = buffers[i]->datas;
|
||||
|
||||
b = &this->buffers[i];
|
||||
b = &port->buffers[i];
|
||||
b->id = i;
|
||||
b->outbuf = buffers[i];
|
||||
b->outstanding = false;
|
||||
|
|
@ -708,9 +698,9 @@ impl_node_port_use_buffers(struct spa_node *node,
|
|||
buffers[i]);
|
||||
return -EINVAL;
|
||||
}
|
||||
spa_list_append(&this->empty, &b->link);
|
||||
spa_list_append(&port->empty, &b->link);
|
||||
}
|
||||
this->n_buffers = n_buffers;
|
||||
port->n_buffers = n_buffers;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -725,14 +715,16 @@ impl_node_port_alloc_buffers(struct spa_node *node,
|
|||
uint32_t *n_buffers)
|
||||
{
|
||||
struct impl *this;
|
||||
struct port *port;
|
||||
|
||||
spa_return_val_if_fail(node != NULL, -EINVAL);
|
||||
|
||||
this = SPA_CONTAINER_OF(node, struct impl, node);
|
||||
|
||||
spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL);
|
||||
port = &this->port;
|
||||
|
||||
if (!this->have_format)
|
||||
if (!port->have_format)
|
||||
return -EIO;
|
||||
|
||||
return -ENOTSUP;
|
||||
|
|
@ -746,30 +738,32 @@ impl_node_port_set_io(struct spa_node *node,
|
|||
void *data, size_t size)
|
||||
{
|
||||
struct impl *this;
|
||||
struct port *port;
|
||||
|
||||
spa_return_val_if_fail(node != NULL, -EINVAL);
|
||||
|
||||
this = SPA_CONTAINER_OF(node, struct impl, node);
|
||||
|
||||
spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL);
|
||||
port = &this->port;
|
||||
|
||||
if (id == SPA_IO_Buffers)
|
||||
this->io = data;
|
||||
port->io = data;
|
||||
else
|
||||
return -ENOENT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void reuse_buffer(struct impl *this, uint32_t id)
|
||||
static inline void reuse_buffer(struct impl *this, struct port *port, uint32_t id)
|
||||
{
|
||||
struct buffer *b = &this->buffers[id];
|
||||
struct buffer *b = &port->buffers[id];
|
||||
spa_return_if_fail(b->outstanding);
|
||||
|
||||
spa_log_trace(this->log, NAME " %p: reuse buffer %d", this, id);
|
||||
|
||||
b->outstanding = false;
|
||||
spa_list_append(&this->empty, &b->link);
|
||||
spa_list_append(&port->empty, &b->link);
|
||||
|
||||
if (!this->props.live)
|
||||
set_timer(this, true);
|
||||
|
|
@ -778,15 +772,17 @@ static inline void reuse_buffer(struct impl *this, uint32_t id)
|
|||
static int impl_node_port_reuse_buffer(struct spa_node *node, uint32_t port_id, uint32_t buffer_id)
|
||||
{
|
||||
struct impl *this;
|
||||
struct port *port;
|
||||
|
||||
spa_return_val_if_fail(node != NULL, -EINVAL);
|
||||
|
||||
this = SPA_CONTAINER_OF(node, struct impl, node);
|
||||
|
||||
spa_return_val_if_fail(port_id == 0, -EINVAL);
|
||||
spa_return_val_if_fail(buffer_id < this->n_buffers, -EINVAL);
|
||||
port = &this->port;
|
||||
spa_return_val_if_fail(buffer_id < port->n_buffers, -EINVAL);
|
||||
|
||||
reuse_buffer(this, buffer_id);
|
||||
reuse_buffer(this, port, buffer_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -794,20 +790,22 @@ static int impl_node_port_reuse_buffer(struct spa_node *node, uint32_t port_id,
|
|||
static int impl_node_process(struct spa_node *node)
|
||||
{
|
||||
struct impl *this;
|
||||
struct port *port;
|
||||
struct spa_io_buffers *io;
|
||||
|
||||
spa_return_val_if_fail(node != NULL, -EINVAL);
|
||||
|
||||
this = SPA_CONTAINER_OF(node, struct impl, node);
|
||||
io = this->io;
|
||||
port = &this->port;
|
||||
io = port->io;
|
||||
spa_return_val_if_fail(io != NULL, -EIO);
|
||||
|
||||
if (io->status == SPA_STATUS_HAVE_BUFFER)
|
||||
return SPA_STATUS_HAVE_BUFFER;
|
||||
|
||||
if (io->buffer_id < this->n_buffers) {
|
||||
reuse_buffer(this, this->io->buffer_id);
|
||||
this->io->buffer_id = SPA_ID_INVALID;
|
||||
if (io->buffer_id < port->n_buffers) {
|
||||
reuse_buffer(this, port, io->buffer_id);
|
||||
io->buffer_id = SPA_ID_INVALID;
|
||||
}
|
||||
|
||||
if (!this->props.live && (io->status == SPA_STATUS_NEED_BUFFER))
|
||||
|
|
@ -881,6 +879,7 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
uint32_t n_support)
|
||||
{
|
||||
struct impl *this;
|
||||
struct port *port;
|
||||
uint32_t i;
|
||||
|
||||
spa_return_val_if_fail(factory != NULL, -EINVAL);
|
||||
|
|
@ -899,10 +898,18 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
}
|
||||
|
||||
this->node = impl_node;
|
||||
this->info = SPA_NODE_INFO_INIT();
|
||||
this->info.max_output_ports = 1;
|
||||
this->info.change_mask |= SPA_NODE_CHANGE_MASK_FLAGS;
|
||||
this->info.flags = SPA_NODE_FLAG_RT;
|
||||
this->info.change_mask |= SPA_NODE_CHANGE_MASK_PROPS;
|
||||
this->info.change_mask |= SPA_NODE_CHANGE_MASK_PARAMS;
|
||||
this->params[0] = SPA_PARAM_INFO(SPA_PARAM_PropInfo, SPA_PARAM_INFO_READ);
|
||||
this->params[1] = SPA_PARAM_INFO(SPA_PARAM_Props, SPA_PARAM_INFO_READWRITE);
|
||||
this->info.params = this->params;
|
||||
this->info.n_params = 2;
|
||||
reset_props(&this->props);
|
||||
|
||||
spa_list_init(&this->empty);
|
||||
|
||||
this->timer_source.func = on_output;
|
||||
this->timer_source.data = this;
|
||||
this->timer_source.fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
|
||||
|
|
@ -916,11 +923,21 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
if (this->data_loop)
|
||||
spa_loop_add_source(this->data_loop, &this->timer_source);
|
||||
|
||||
this->info = SPA_PORT_INFO_INIT();
|
||||
this->info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
this->info.flags = SPA_PORT_FLAG_CAN_USE_BUFFERS | SPA_PORT_FLAG_NO_REF;
|
||||
port = &this->port;
|
||||
port->info = SPA_PORT_INFO_INIT();
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
port->info.flags = SPA_PORT_FLAG_CAN_USE_BUFFERS | SPA_PORT_FLAG_NO_REF;
|
||||
if (this->props.live)
|
||||
this->info.flags |= SPA_PORT_FLAG_LIVE;
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
|
||||
port->params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
|
||||
port->params[1] = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
|
||||
port->params[2] = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
|
||||
port->info.params = port->params;
|
||||
port->info.n_params = 5;
|
||||
spa_list_init(&port->empty);
|
||||
|
||||
spa_log_info(this->log, NAME " %p: initialized", this);
|
||||
|
||||
|
|
|
|||
|
|
@ -54,8 +54,9 @@ static void reset_props(struct props *props)
|
|||
|
||||
struct buffer {
|
||||
uint32_t id;
|
||||
#define BUFFER_FLAG_OUT (1<<0)
|
||||
uint32_t flags;
|
||||
struct spa_buffer *outbuf;
|
||||
bool outstanding;
|
||||
struct spa_meta_header *h;
|
||||
void *ptr;
|
||||
size_t size;
|
||||
|
|
@ -63,12 +64,17 @@ struct buffer {
|
|||
};
|
||||
|
||||
struct port {
|
||||
enum spa_direction direction;
|
||||
uint32_t id;
|
||||
|
||||
bool have_format;
|
||||
|
||||
struct spa_port_info info;
|
||||
struct spa_param_info params[5];
|
||||
|
||||
struct buffer buffers[MAX_BUFFERS];
|
||||
uint32_t n_buffers;
|
||||
|
||||
struct spa_io_buffers *io;
|
||||
struct spa_io_range *range;
|
||||
|
||||
|
|
@ -81,6 +87,8 @@ struct impl {
|
|||
|
||||
struct spa_log *log;
|
||||
|
||||
struct spa_node_info info;
|
||||
struct spa_param_info params[5];
|
||||
struct props props;
|
||||
|
||||
const struct spa_node_callbacks *callbacks;
|
||||
|
|
@ -130,19 +138,6 @@ static int impl_node_enum_params(struct spa_node *node, int seq,
|
|||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
|
||||
switch (id) {
|
||||
case SPA_PARAM_List:
|
||||
{
|
||||
uint32_t list[] = { SPA_PARAM_PropInfo,
|
||||
SPA_PARAM_Props };
|
||||
|
||||
if (result.index < SPA_N_ELEMENTS(list))
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_ParamList, id,
|
||||
SPA_PARAM_LIST_id, SPA_POD_Id(list[result.index]));
|
||||
else
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
case SPA_PARAM_PropInfo:
|
||||
switch (result.index) {
|
||||
case 0:
|
||||
|
|
@ -249,11 +244,18 @@ static int impl_node_send_command(struct spa_node *node, const struct spa_comman
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void emit_port_info(struct impl *this, enum spa_direction direction, uint32_t id)
|
||||
static void emit_node_info(struct impl *this)
|
||||
{
|
||||
if (this->callbacks && this->callbacks->info && this->info.change_mask) {
|
||||
this->callbacks->info(this->callbacks_data, &this->info);
|
||||
this->info.change_mask = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_port_info(struct impl *this, struct port *port)
|
||||
{
|
||||
struct port *port = GET_PORT(this, direction, id);
|
||||
if (this->callbacks && this->callbacks->port_info && port->info.change_mask) {
|
||||
this->callbacks->port_info(this->callbacks_data, direction, id, &port->info);
|
||||
this->callbacks->port_info(this->callbacks_data, port->direction, port->id, &port->info);
|
||||
port->info.change_mask = 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -272,8 +274,9 @@ impl_node_set_callbacks(struct spa_node *node,
|
|||
this->callbacks = callbacks;
|
||||
this->callbacks_data = data;
|
||||
|
||||
emit_port_info(this, SPA_DIRECTION_INPUT, 0);
|
||||
emit_port_info(this, SPA_DIRECTION_OUTPUT, 0);
|
||||
emit_node_info(this);
|
||||
emit_port_info(this, GET_IN_PORT(this, 0));
|
||||
emit_port_info(this, GET_OUT_PORT(this, 0));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -349,22 +352,6 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
|
||||
switch (id) {
|
||||
case SPA_PARAM_List:
|
||||
{
|
||||
uint32_t list[] = { SPA_PARAM_EnumFormat,
|
||||
SPA_PARAM_Format,
|
||||
SPA_PARAM_Buffers,
|
||||
SPA_PARAM_Meta,
|
||||
SPA_PARAM_IO };
|
||||
|
||||
if (result.index < SPA_N_ELEMENTS(list))
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_ParamList, id,
|
||||
SPA_PARAM_LIST_id, SPA_POD_Id(list[result.index]));
|
||||
else
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
case SPA_PARAM_EnumFormat:
|
||||
if ((res = port_enum_formats(node, direction, port_id,
|
||||
result.index, filter, ¶m, &b)) <= 0)
|
||||
|
|
@ -485,6 +472,16 @@ static int port_set_format(struct spa_node *node,
|
|||
port->have_format = true;
|
||||
}
|
||||
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
|
||||
if (port->have_format) {
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_READWRITE);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, SPA_PARAM_INFO_READ);
|
||||
} else {
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
|
||||
}
|
||||
emit_port_info(this, port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -536,7 +533,7 @@ impl_node_port_use_buffers(struct spa_node *node,
|
|||
b = &port->buffers[i];
|
||||
b->id = i;
|
||||
b->outbuf = buffers[i];
|
||||
b->outstanding = direction == SPA_DIRECTION_INPUT;
|
||||
b->flags = direction == SPA_DIRECTION_INPUT ? BUFFER_FLAG_OUT : 0;
|
||||
b->h = spa_buffer_find_meta_data(buffers[i], SPA_META_Header, sizeof(*b->h));
|
||||
|
||||
if ((d[0].type == SPA_DATA_MemPtr ||
|
||||
|
|
@ -549,7 +546,7 @@ impl_node_port_use_buffers(struct spa_node *node,
|
|||
buffers[i]);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!b->outstanding)
|
||||
if (!SPA_FLAG_CHECK(b->flags, BUFFER_FLAG_OUT))
|
||||
spa_list_append(&port->empty, &b->link);
|
||||
}
|
||||
port->n_buffers = n_buffers;
|
||||
|
|
@ -605,13 +602,13 @@ static void recycle_buffer(struct impl *this, uint32_t id)
|
|||
struct port *port = GET_OUT_PORT(this, 0);
|
||||
struct buffer *b = &port->buffers[id];
|
||||
|
||||
if (!b->outstanding) {
|
||||
if (!SPA_FLAG_CHECK(b->flags, BUFFER_FLAG_OUT)) {
|
||||
spa_log_warn(this->log, NAME " %p: buffer %d not outstanding", this, id);
|
||||
return;
|
||||
}
|
||||
|
||||
spa_list_append(&port->empty, &b->link);
|
||||
b->outstanding = false;
|
||||
SPA_FLAG_UNSET(b->flags, BUFFER_FLAG_OUT);
|
||||
spa_log_trace(this->log, NAME " %p: recycle buffer %d", this, id);
|
||||
}
|
||||
|
||||
|
|
@ -646,7 +643,7 @@ static struct buffer *find_free_buffer(struct impl *this, struct port *port)
|
|||
|
||||
b = spa_list_first(&port->empty, struct buffer, link);
|
||||
spa_list_remove(&b->link);
|
||||
b->outstanding = true;
|
||||
SPA_FLAG_SET(b->flags, BUFFER_FLAG_OUT);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
|
@ -825,20 +822,48 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
}
|
||||
|
||||
this->node = impl_node;
|
||||
this->info = SPA_NODE_INFO_INIT();
|
||||
this->info.max_input_ports = 1;
|
||||
this->info.max_output_ports = 1;
|
||||
this->info.change_mask |= SPA_NODE_CHANGE_MASK_PARAMS;
|
||||
this->params[0] = SPA_PARAM_INFO(SPA_PARAM_PropInfo, SPA_PARAM_INFO_READ);
|
||||
this->params[1] = SPA_PARAM_INFO(SPA_PARAM_Props, SPA_PARAM_INFO_READWRITE);
|
||||
this->info.params = this->params;
|
||||
this->info.n_params = 2;
|
||||
reset_props(&this->props);
|
||||
|
||||
port = GET_IN_PORT(this, 0);
|
||||
port->direction = SPA_DIRECTION_INPUT;
|
||||
port->id = 0;
|
||||
port->info = SPA_PORT_INFO_INIT();
|
||||
port->info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
port->info.flags = SPA_PORT_FLAG_CAN_USE_BUFFERS |
|
||||
SPA_PORT_FLAG_IN_PLACE;
|
||||
port->info.change_mask |= SPA_NODE_CHANGE_MASK_PARAMS;
|
||||
port->params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
|
||||
port->params[1] = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
|
||||
port->params[2] = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
|
||||
port->info.params = port->params;
|
||||
port->info.n_params = 5;
|
||||
spa_list_init(&port->empty);
|
||||
|
||||
port = GET_OUT_PORT(this, 0);
|
||||
port->direction = SPA_DIRECTION_OUTPUT;
|
||||
port->id = 0;
|
||||
port->info = SPA_PORT_INFO_INIT();
|
||||
port->info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
port->info.flags = SPA_PORT_FLAG_CAN_USE_BUFFERS |
|
||||
SPA_PORT_FLAG_NO_REF;
|
||||
port->info.change_mask |= SPA_NODE_CHANGE_MASK_PARAMS;
|
||||
port->params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
|
||||
port->params[1] = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
|
||||
port->params[2] = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
|
||||
port->info.params = port->params;
|
||||
port->info.n_params = 5;
|
||||
spa_list_init(&port->empty);
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -112,15 +112,14 @@ static void test_abi(void)
|
|||
|
||||
spa_assert(SPA_TYPE_OBJECT_START == 0x50000);
|
||||
spa_assert(SPA_TYPE_OBJECT_MonitorItem == 0x50001);
|
||||
spa_assert(SPA_TYPE_OBJECT_ParamList == 0x50002);
|
||||
spa_assert(SPA_TYPE_OBJECT_PropInfo == 0x50003);
|
||||
spa_assert(SPA_TYPE_OBJECT_Props == 0x50004);
|
||||
spa_assert(SPA_TYPE_OBJECT_Format == 0x50005);
|
||||
spa_assert(SPA_TYPE_OBJECT_ParamBuffers == 0x50006);
|
||||
spa_assert(SPA_TYPE_OBJECT_ParamMeta == 0x50007);
|
||||
spa_assert(SPA_TYPE_OBJECT_ParamIO == 0x50008);
|
||||
spa_assert(SPA_TYPE_OBJECT_ParamProfile == 0x50009);
|
||||
spa_assert(SPA_TYPE_OBJECT_LAST == 0x5000a);
|
||||
spa_assert(SPA_TYPE_OBJECT_PropInfo == 0x50002);
|
||||
spa_assert(SPA_TYPE_OBJECT_Props == 0x50003);
|
||||
spa_assert(SPA_TYPE_OBJECT_Format == 0x50004);
|
||||
spa_assert(SPA_TYPE_OBJECT_ParamBuffers == 0x50005);
|
||||
spa_assert(SPA_TYPE_OBJECT_ParamMeta == 0x50006);
|
||||
spa_assert(SPA_TYPE_OBJECT_ParamIO == 0x50007);
|
||||
spa_assert(SPA_TYPE_OBJECT_ParamProfile == 0x50008);
|
||||
spa_assert(SPA_TYPE_OBJECT_LAST == 0x50009);
|
||||
|
||||
spa_assert(SPA_TYPE_VENDOR_PipeWire == 0x02000000);
|
||||
spa_assert(SPA_TYPE_VENDOR_Other == 0x7f000000);
|
||||
|
|
|
|||
|
|
@ -52,93 +52,72 @@ struct data {
|
|||
struct spa_pending_queue pending;
|
||||
};
|
||||
|
||||
static int print_param(struct spa_pending *pending, const void *result)
|
||||
{
|
||||
const struct spa_result_node_params *r = result;
|
||||
|
||||
if (spa_pod_is_object_type(r->param, SPA_TYPE_OBJECT_Format))
|
||||
spa_debug_format(16, NULL, r->param);
|
||||
else
|
||||
spa_debug_pod(16, NULL, r->param);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
inspect_node_params(struct data *data, struct spa_node *node)
|
||||
inspect_node_params(struct data *data, struct spa_node *node,
|
||||
uint32_t n_params, struct spa_param_info *params)
|
||||
{
|
||||
int res;
|
||||
uint32_t idx1, idx2;
|
||||
uint32_t i;
|
||||
struct spa_pending pending;
|
||||
|
||||
for (idx1 = 0;;) {
|
||||
uint32_t buffer[4096];
|
||||
struct spa_pod_builder b = { 0 };
|
||||
struct spa_pod *param;
|
||||
uint32_t id;
|
||||
for (i = 0; i < n_params; i++) {
|
||||
printf("enumerating: %s:\n", spa_debug_type_find_name(spa_type_param, params[i].id));
|
||||
|
||||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
if ((res = spa_node_enum_params_sync(node,
|
||||
SPA_PARAM_List, &idx1,
|
||||
NULL, ¶m, &b,
|
||||
&data->pending)) != 1) {
|
||||
if (res != 0)
|
||||
error(0, -res, "enum_params");
|
||||
if (!SPA_FLAG_CHECK(params[i].flags, SPA_PARAM_INFO_READ))
|
||||
continue;
|
||||
|
||||
spa_pending_queue_add(&data->pending, 0, &pending, print_param, data);
|
||||
res = spa_node_enum_params(node, 0, params[i].id, 0, UINT32_MAX, NULL);
|
||||
spa_pending_remove(&pending);
|
||||
|
||||
if (res != 0) {
|
||||
error(0, -res, "enum_params %d", params[i].id);
|
||||
break;
|
||||
}
|
||||
|
||||
spa_pod_parse_object(param,
|
||||
SPA_TYPE_OBJECT_ParamList, NULL,
|
||||
SPA_PARAM_LIST_id, SPA_POD_Id(&id));
|
||||
|
||||
printf("enumerating: %s:\n", spa_debug_type_find_name(spa_type_param, id));
|
||||
for (idx2 = 0;;) {
|
||||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
if ((res = spa_node_enum_params_sync(node,
|
||||
id, &idx2,
|
||||
NULL, ¶m, &b,
|
||||
&data->pending)) != 1) {
|
||||
if (res != 0)
|
||||
error(0, -res, "enum_params %d", id);
|
||||
break;
|
||||
}
|
||||
spa_debug_pod(0, NULL, param);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
inspect_port_params(struct data *data, struct spa_node *node,
|
||||
enum spa_direction direction, uint32_t port_id)
|
||||
enum spa_direction direction, uint32_t port_id,
|
||||
uint32_t n_params, struct spa_param_info *params)
|
||||
{
|
||||
int res;
|
||||
uint32_t idx1, idx2;
|
||||
uint32_t i;
|
||||
struct spa_pending pending;
|
||||
|
||||
for (idx1 = 0;;) {
|
||||
uint32_t buffer[4096];
|
||||
struct spa_pod_builder b = { 0 };
|
||||
struct spa_pod *param;
|
||||
uint32_t id;
|
||||
for (i = 0; i < n_params; i++) {
|
||||
printf("param: %s: flags %c%c\n",
|
||||
spa_debug_type_find_name(spa_type_param, params[i].id),
|
||||
params[i].flags & SPA_PARAM_INFO_READ ? 'r' : '-',
|
||||
params[i].flags & SPA_PARAM_INFO_WRITE ? 'w' : '-');
|
||||
|
||||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
if ((res = spa_node_port_enum_params_sync(node,
|
||||
direction, port_id,
|
||||
SPA_PARAM_List, &idx1,
|
||||
NULL, ¶m, &b,
|
||||
&data->pending)) != 1) {
|
||||
if (res != 0)
|
||||
error(0, -res, "port_enum_params");
|
||||
if (!SPA_FLAG_CHECK(params[i].flags, SPA_PARAM_INFO_READ))
|
||||
continue;
|
||||
|
||||
printf("values:\n");
|
||||
spa_pending_queue_add(&data->pending, 0, &pending, print_param, data);
|
||||
res = spa_node_port_enum_params(node, 0,
|
||||
direction, port_id,
|
||||
params[i].id, 0, UINT32_MAX,
|
||||
NULL);
|
||||
spa_pending_remove(&pending);
|
||||
|
||||
if (res != 0) {
|
||||
error(0, -res, "port_enum_params %d", params[i].id);
|
||||
break;
|
||||
}
|
||||
spa_pod_parse_object(param,
|
||||
SPA_TYPE_OBJECT_ParamList, NULL,
|
||||
SPA_PARAM_LIST_id, SPA_POD_Id(&id));
|
||||
|
||||
printf("enumerating: %s:\n", spa_debug_type_find_name(spa_type_param, id));
|
||||
for (idx2 = 0;;) {
|
||||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
if ((res = spa_node_port_enum_params_sync(node,
|
||||
direction, port_id,
|
||||
id, &idx2,
|
||||
NULL, ¶m, &b,
|
||||
&data->pending)) != 1) {
|
||||
if (res != 0)
|
||||
error(0, -res, "port_enum_params");
|
||||
break;
|
||||
}
|
||||
|
||||
if (spa_pod_is_object_type(param, SPA_TYPE_OBJECT_Format))
|
||||
spa_debug_format(0, NULL, param);
|
||||
else
|
||||
spa_debug_pod(0, NULL, param);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -146,6 +125,7 @@ static int node_info(void *_data, const struct spa_node_info *info)
|
|||
{
|
||||
struct data *data = _data;
|
||||
|
||||
printf("node info: %08lx\n", info->change_mask);
|
||||
printf("max input ports: %u\n", info->max_input_ports);
|
||||
printf("max output ports: %u\n", info->max_output_ports);
|
||||
|
||||
|
|
@ -153,7 +133,9 @@ static int node_info(void *_data, const struct spa_node_info *info)
|
|||
printf("node properties:\n");
|
||||
spa_debug_dict(2, info->props);
|
||||
}
|
||||
inspect_node_params(data, data->node);
|
||||
if (info->change_mask & SPA_NODE_CHANGE_MASK_PARAMS) {
|
||||
inspect_node_params(data, data->node, info->n_params, info->params);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -162,14 +144,23 @@ static int node_port_info(void *_data, enum spa_direction direction, uint32_t id
|
|||
{
|
||||
struct data *data = _data;
|
||||
|
||||
printf(" %s port: %08x",
|
||||
direction == SPA_DIRECTION_INPUT ? "input" : "output",
|
||||
id);
|
||||
|
||||
if (info == NULL) {
|
||||
printf("port %d removed", id);
|
||||
printf(" removed\n");
|
||||
}
|
||||
else {
|
||||
printf(" %s port: %08x\n",
|
||||
direction == SPA_DIRECTION_INPUT ? "input" : "output",
|
||||
id);
|
||||
inspect_port_params(data, data->node, direction, id);
|
||||
printf(" info:\n");
|
||||
if (info->change_mask & SPA_PORT_CHANGE_MASK_PROPS) {
|
||||
printf("port properties:\n");
|
||||
spa_debug_dict(2, info->props);
|
||||
}
|
||||
if (info->change_mask & SPA_PORT_CHANGE_MASK_PARAMS) {
|
||||
inspect_port_params(data, data->node, direction, id,
|
||||
info->n_params, info->params);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -190,7 +181,6 @@ static const struct spa_node_callbacks node_callbacks =
|
|||
|
||||
static void inspect_node(struct data *data, struct spa_node *node)
|
||||
{
|
||||
printf("node info:\n");
|
||||
data->node = node;
|
||||
spa_node_set_callbacks(node, &node_callbacks, data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,8 +73,6 @@ struct data {
|
|||
struct pw_remote *remote;
|
||||
struct spa_hook remote_listener;
|
||||
|
||||
struct spa_port_info port_info;
|
||||
|
||||
struct spa_node impl_node;
|
||||
const struct spa_node_callbacks *callbacks;
|
||||
void *callbacks_data;
|
||||
|
|
@ -144,10 +142,19 @@ static int impl_set_callbacks(struct spa_node *node,
|
|||
|
||||
if (d->callbacks && d->callbacks->port_info) {
|
||||
struct spa_port_info info;
|
||||
struct spa_param_info params[5];
|
||||
|
||||
info = SPA_PORT_INFO_INIT();
|
||||
info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
info.flags = SPA_PORT_FLAG_CAN_USE_BUFFERS;
|
||||
info.change_mask = SPA_PORT_CHANGE_MASK_PARAMS;
|
||||
params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
|
||||
params[1] = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
|
||||
params[2] = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
|
||||
params[3] = SPA_PARAM_INFO(SPA_PARAM_Buffers, SPA_PARAM_INFO_READ);
|
||||
params[4] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
info.params = params;
|
||||
info.n_params = 5;
|
||||
|
||||
d->callbacks->port_info(d->callbacks_data, SPA_DIRECTION_INPUT, 0, &info);
|
||||
}
|
||||
|
|
@ -201,22 +208,6 @@ static int impl_port_enum_params(struct spa_node *node, int seq,
|
|||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
|
||||
switch (id) {
|
||||
case SPA_PARAM_List:
|
||||
{
|
||||
uint32_t list[] = { SPA_PARAM_EnumFormat,
|
||||
SPA_PARAM_Format,
|
||||
SPA_PARAM_Buffers,
|
||||
SPA_PARAM_Meta,
|
||||
SPA_PARAM_IO };
|
||||
|
||||
if (result.index < SPA_N_ELEMENTS(list))
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_ParamList, id,
|
||||
SPA_PARAM_LIST_id, SPA_POD_Id(list[result.index]));
|
||||
else
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
case SPA_PARAM_EnumFormat:
|
||||
{
|
||||
SDL_RendererInfo info;
|
||||
|
|
|
|||
|
|
@ -110,13 +110,23 @@ static int impl_set_callbacks(struct spa_node *node,
|
|||
|
||||
if (d->callbacks && d->callbacks->port_info) {
|
||||
struct spa_port_info info;
|
||||
struct spa_dict_item port_items[1];
|
||||
struct spa_dict_item items[1];
|
||||
struct spa_param_info params[5];
|
||||
|
||||
info = SPA_PORT_INFO_INIT();
|
||||
info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS | SPA_PORT_CHANGE_MASK_PROPS;
|
||||
info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
info.flags = SPA_PORT_FLAG_CAN_USE_BUFFERS;
|
||||
port_items[0] = SPA_DICT_ITEM_INIT("port.dsp", "32 bit float mono audio");
|
||||
info.props = &SPA_DICT_INIT_ARRAY(port_items);
|
||||
info.change_mask |= SPA_PORT_CHANGE_MASK_PROPS;
|
||||
items[0] = SPA_DICT_ITEM_INIT("port.dsp", "32 bit float mono audio");
|
||||
info.props = &SPA_DICT_INIT_ARRAY(items);
|
||||
info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
|
||||
params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
|
||||
params[1] = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
|
||||
params[2] = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
|
||||
params[3] = SPA_PARAM_INFO(SPA_PARAM_Buffers, SPA_PARAM_INFO_READ);
|
||||
params[4] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
info.params = params;
|
||||
info.n_params = 5;
|
||||
|
||||
d->callbacks->port_info(d->callbacks_data, SPA_DIRECTION_OUTPUT, 0, &info);
|
||||
}
|
||||
|
|
@ -169,22 +179,6 @@ static int impl_port_enum_params(struct spa_node *node, int seq,
|
|||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
|
||||
switch (id) {
|
||||
case SPA_PARAM_List:
|
||||
{
|
||||
uint32_t list[] = { SPA_PARAM_EnumFormat,
|
||||
SPA_PARAM_Format,
|
||||
SPA_PARAM_Buffers,
|
||||
SPA_PARAM_Meta,
|
||||
SPA_PARAM_IO };
|
||||
|
||||
if (result.index < SPA_N_ELEMENTS(list))
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_ParamList, id,
|
||||
SPA_PARAM_LIST_id, SPA_POD_Id(list[result.index]));
|
||||
else
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
case SPA_PARAM_EnumFormat:
|
||||
if (result.index != 0)
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -75,10 +75,9 @@ struct port {
|
|||
|
||||
struct spa_io_buffers *io;
|
||||
struct spa_io_range *range;
|
||||
double *io_volume;
|
||||
int32_t *io_mute;
|
||||
|
||||
struct spa_port_info info;
|
||||
struct spa_param_info params[8];
|
||||
|
||||
int valid:1;
|
||||
int have_format:1;
|
||||
|
|
@ -96,6 +95,9 @@ struct impl {
|
|||
|
||||
struct spa_log *log;
|
||||
|
||||
struct spa_node_info info;
|
||||
struct spa_param_info params[8];
|
||||
|
||||
const struct spa_node_callbacks *callbacks;
|
||||
void *user_data;
|
||||
|
||||
|
|
@ -161,6 +163,14 @@ static int impl_node_send_command(struct spa_node *node, const struct spa_comman
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void emit_node_info(struct impl *this)
|
||||
{
|
||||
if (this->callbacks && this->callbacks->info && this->info.change_mask) {
|
||||
this->callbacks->info(this->user_data, &this->info);
|
||||
this->info.change_mask = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_port_info(struct impl *this, struct port *port)
|
||||
{
|
||||
if (this->callbacks && this->callbacks->port_info && port->info.change_mask) {
|
||||
|
|
@ -184,6 +194,7 @@ impl_node_set_callbacks(struct spa_node *node,
|
|||
this->callbacks = callbacks;
|
||||
this->user_data = user_data;
|
||||
|
||||
emit_node_info(this);
|
||||
emit_port_info(this, GET_OUT_PORT(this, 0));
|
||||
for (i = 0; i < this->last_port; i++) {
|
||||
if (this->in_ports[i].valid)
|
||||
|
|
@ -209,16 +220,22 @@ static int impl_node_add_port(struct spa_node *node, enum spa_direction directio
|
|||
port->id = port_id;
|
||||
|
||||
port_props_reset(&port->props);
|
||||
port->io_volume = &port->props.volume;
|
||||
port->io_mute = &port->props.mute;
|
||||
|
||||
spa_list_init(&port->queue);
|
||||
port->info = SPA_PORT_INFO_INIT();
|
||||
port->info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
port->info.flags = SPA_PORT_FLAG_CAN_USE_BUFFERS |
|
||||
SPA_PORT_FLAG_REMOVABLE |
|
||||
SPA_PORT_FLAG_OPTIONAL |
|
||||
SPA_PORT_FLAG_IN_PLACE;
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
|
||||
port->params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
|
||||
port->params[1] = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
|
||||
port->params[2] = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
|
||||
port->info.params = port->params;
|
||||
port->info.n_params = 5;
|
||||
|
||||
this->port_count++;
|
||||
if (this->last_port <= port_id)
|
||||
|
|
@ -332,22 +349,6 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
|
||||
switch (id) {
|
||||
case SPA_PARAM_List:
|
||||
{
|
||||
uint32_t list[] = { SPA_PARAM_EnumFormat,
|
||||
SPA_PARAM_Format,
|
||||
SPA_PARAM_Buffers,
|
||||
SPA_PARAM_Meta,
|
||||
SPA_PARAM_IO };
|
||||
|
||||
if (result.index < SPA_N_ELEMENTS(list))
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_ParamList, id,
|
||||
SPA_PARAM_LIST_id, SPA_POD_Id(list[result.index]));
|
||||
else
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
case SPA_PARAM_EnumFormat:
|
||||
if ((res = port_enum_formats(node, direction, port_id, result.index, ¶m, &b)) <= 0)
|
||||
return res;
|
||||
|
|
@ -381,9 +382,6 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
break;
|
||||
|
||||
case SPA_PARAM_Meta:
|
||||
if (!port->have_format)
|
||||
return -EIO;
|
||||
|
||||
switch (result.index) {
|
||||
case 0:
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
|
|
@ -523,6 +521,16 @@ static int port_set_format(struct spa_node *node,
|
|||
this, direction, port_id);
|
||||
}
|
||||
}
|
||||
if (port->have_format) {
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_READWRITE);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, SPA_PARAM_INFO_READ);
|
||||
} else {
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
|
||||
}
|
||||
emit_port_info(this, port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -892,14 +900,29 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
}
|
||||
|
||||
this->node = impl_node;
|
||||
this->info = SPA_NODE_INFO_INIT();
|
||||
this->info.max_input_ports = MAX_PORTS;
|
||||
this->info.max_output_ports = 1;
|
||||
this->info.change_mask |= SPA_NODE_CHANGE_MASK_FLAGS;
|
||||
this->info.flags = SPA_NODE_FLAG_RT | SPA_NODE_FLAG_DYNAMIC_INPUT_PORTS;
|
||||
|
||||
port = GET_OUT_PORT(this, 0);
|
||||
port->valid = true;
|
||||
port->direction = SPA_DIRECTION_OUTPUT;
|
||||
port->id = 0;
|
||||
port->info = SPA_PORT_INFO_INIT();
|
||||
port->info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
port->info.flags = SPA_PORT_FLAG_CAN_USE_BUFFERS |
|
||||
SPA_PORT_FLAG_NO_REF;
|
||||
SPA_PORT_FLAG_NO_REF;
|
||||
port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
|
||||
port->params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
|
||||
port->params[1] = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
|
||||
port->params[2] = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
|
||||
port->info.params = port->params;
|
||||
port->info.n_params = 5;
|
||||
|
||||
spa_list_init(&port->queue);
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -379,7 +379,7 @@ static int impl_node_enum_params(struct spa_node *node, int seq,
|
|||
|
||||
result.index = result.next++;
|
||||
if (result.index >= this->n_params)
|
||||
return 0;
|
||||
break;
|
||||
|
||||
param = this->params[result.index];
|
||||
|
||||
|
|
@ -390,10 +390,11 @@ static int impl_node_enum_params(struct spa_node *node, int seq,
|
|||
if (spa_pod_filter(&b, &result.param, param, filter) != 0)
|
||||
continue;
|
||||
|
||||
pw_log_debug("client-node %p: %d param %u", this, seq, result.index);
|
||||
if ((res = this->callbacks->result(this->callbacks_data, seq, 0, &result)) != 0)
|
||||
return res;
|
||||
|
||||
if (++count != num)
|
||||
if (++count == num)
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
|
|
@ -668,7 +669,7 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
|
||||
result.index = result.next++;
|
||||
if (result.index >= port->n_params)
|
||||
return 0;
|
||||
break;
|
||||
|
||||
param = port->params[result.index];
|
||||
|
||||
|
|
@ -683,7 +684,7 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
|
|||
if ((res = this->callbacks->result(this->callbacks_data, seq, 0, &result)) != 0)
|
||||
return res;
|
||||
|
||||
if (++count != num)
|
||||
if (++count == num)
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -137,20 +137,6 @@ static int impl_node_enum_params(struct spa_node *node, int seq,
|
|||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
|
||||
switch (id) {
|
||||
case SPA_PARAM_List:
|
||||
{
|
||||
uint32_t list[] = { SPA_PARAM_Props,
|
||||
SPA_PARAM_EnumFormat,
|
||||
SPA_PARAM_Format };
|
||||
|
||||
if (result.index < SPA_N_ELEMENTS(list))
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_ParamList, id,
|
||||
SPA_PARAM_LIST_id, SPA_POD_Id(list[result.index]));
|
||||
else
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
case SPA_PARAM_Props:
|
||||
if (impl->adapter == impl->cnode)
|
||||
return 0;
|
||||
|
|
@ -326,6 +312,26 @@ static const struct spa_node_callbacks adapter_node_callbacks = {
|
|||
.result = adapter_result,
|
||||
};
|
||||
|
||||
static void emit_node_info(struct node *this)
|
||||
{
|
||||
if (this->callbacks && this->callbacks->info) {
|
||||
struct spa_node_info info;
|
||||
struct spa_param_info params[4];
|
||||
|
||||
info = SPA_NODE_INFO_INIT();
|
||||
info.max_input_ports = 0;
|
||||
info.max_output_ports = 0;
|
||||
info.change_mask |= SPA_NODE_CHANGE_MASK_PARAMS;
|
||||
params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
|
||||
params[1] = SPA_PARAM_INFO(SPA_PARAM_Props, SPA_PARAM_INFO_READWRITE);
|
||||
params[2] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_READ);
|
||||
params[3] = SPA_PARAM_INFO(SPA_PARAM_Profile, SPA_PARAM_INFO_WRITE);
|
||||
info.params = params;
|
||||
info.n_params = 4;
|
||||
this->callbacks->info(this->callbacks_data, &info);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
impl_node_set_callbacks(struct spa_node *node,
|
||||
const struct spa_node_callbacks *callbacks,
|
||||
|
|
@ -342,6 +348,8 @@ impl_node_set_callbacks(struct spa_node *node,
|
|||
this->callbacks = callbacks;
|
||||
this->callbacks_data = data;
|
||||
|
||||
emit_node_info(this);
|
||||
|
||||
if (this->callbacks && impl->adapter && impl->adapter != impl->cnode)
|
||||
spa_node_set_callbacks(impl->adapter, &adapter_node_callbacks, impl);
|
||||
|
||||
|
|
|
|||
|
|
@ -107,10 +107,18 @@ client_node_marshal_port_update(void *object,
|
|||
SPA_POD_Pod(params[i]), NULL);
|
||||
|
||||
if (info) {
|
||||
uint64_t change_mask = info->change_mask;
|
||||
|
||||
n_items = info->props ? info->props->n_items : 0;
|
||||
|
||||
change_mask &= SPA_PORT_CHANGE_MASK_FLAGS |
|
||||
SPA_PORT_CHANGE_MASK_RATE |
|
||||
SPA_PORT_CHANGE_MASK_PROPS |
|
||||
SPA_PORT_CHANGE_MASK_PARAMS;
|
||||
|
||||
spa_pod_builder_push_struct(b, &f[1]);
|
||||
spa_pod_builder_add(b,
|
||||
SPA_POD_Long(change_mask),
|
||||
SPA_POD_Int(info->flags),
|
||||
SPA_POD_Int(info->rate),
|
||||
SPA_POD_Int(n_items), NULL);
|
||||
|
|
@ -119,7 +127,15 @@ client_node_marshal_port_update(void *object,
|
|||
SPA_POD_String(info->props->items[i].key),
|
||||
SPA_POD_String(info->props->items[i].value), NULL);
|
||||
}
|
||||
spa_pod_builder_add(b,
|
||||
SPA_POD_Int(info->n_params), NULL);
|
||||
for (i = 0; i < info->n_params; i++) {
|
||||
spa_pod_builder_add(b,
|
||||
SPA_POD_Id(info->params[i].id),
|
||||
SPA_POD_Int(info->params[i].flags), NULL);
|
||||
}
|
||||
spa_pod_builder_pop(b, &f[1]);
|
||||
|
||||
} else {
|
||||
spa_pod_builder_add(b,
|
||||
SPA_POD_Pod(NULL), NULL);
|
||||
|
|
@ -812,11 +828,17 @@ static int client_node_demarshal_port_update(void *object, void *data, size_t si
|
|||
spa_pod_parser_pod(&p2, ipod);
|
||||
if (spa_pod_parser_push_struct(&p2, &f2) < 0 ||
|
||||
spa_pod_parser_get(&p2,
|
||||
SPA_POD_Long(&info.change_mask),
|
||||
SPA_POD_Int(&info.flags),
|
||||
SPA_POD_Int(&info.rate),
|
||||
SPA_POD_Int(&props.n_items), NULL) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
info.change_mask &= SPA_PORT_CHANGE_MASK_FLAGS |
|
||||
SPA_PORT_CHANGE_MASK_RATE |
|
||||
SPA_PORT_CHANGE_MASK_PROPS |
|
||||
SPA_PORT_CHANGE_MASK_PARAMS;
|
||||
|
||||
if (props.n_items > 0) {
|
||||
info.props = &props;
|
||||
|
||||
|
|
@ -828,6 +850,19 @@ static int client_node_demarshal_port_update(void *object, void *data, size_t si
|
|||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
if (spa_pod_parser_get(&p2,
|
||||
SPA_POD_Int(&info.n_params), NULL) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (info.n_params > 0) {
|
||||
info.params = alloca(info.n_params * sizeof(struct spa_param_info));
|
||||
for (i = 0; i < info.n_params; i++) {
|
||||
if (spa_pod_parser_get(&p2,
|
||||
SPA_POD_Id(&info.params[i].id),
|
||||
SPA_POD_Int(&info.params[i].flags), NULL) < 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pw_resource_do(resource, struct pw_client_node_proxy_methods, port_update, 0, direction,
|
||||
|
|
|
|||
|
|
@ -406,27 +406,14 @@ static int add_port_update(struct pw_proxy *proxy, struct pw_port *port, uint32_
|
|||
int res;
|
||||
|
||||
if (change_mask & PW_CLIENT_NODE_PORT_UPDATE_PARAMS) {
|
||||
uint32_t idx1, idx2, id;
|
||||
uint32_t i, idx2, id;
|
||||
uint8_t buf[2048];
|
||||
struct spa_pod_builder b = { 0 };
|
||||
|
||||
for (idx1 = 0;;) {
|
||||
for (i = 0; i < port->info.n_params; i++) {
|
||||
struct spa_pod *param;
|
||||
|
||||
spa_pod_builder_init(&b, buf, sizeof(buf));
|
||||
if (spa_node_port_enum_params_sync(port->node->node,
|
||||
port->direction, port->port_id,
|
||||
SPA_PARAM_List, &idx1,
|
||||
NULL, ¶m, &b,
|
||||
port->node->pending) != 1)
|
||||
break;
|
||||
|
||||
spa_pod_parse_object(param,
|
||||
SPA_TYPE_OBJECT_ParamList, NULL,
|
||||
SPA_PARAM_LIST_id, SPA_POD_Id(&id));
|
||||
|
||||
params = realloc(params, sizeof(struct spa_pod *) * (n_params + 1));
|
||||
params[n_params++] = spa_pod_copy(param);
|
||||
id = port->info.params[i].id;
|
||||
|
||||
for (idx2 = 0;;) {
|
||||
spa_pod_builder_init(&b, buf, sizeof(buf));
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ static struct pw_port *get_port(struct pw_node *node, enum spa_direction directi
|
|||
if (port_id == SPA_ID_INVALID)
|
||||
return NULL;
|
||||
|
||||
p = pw_port_new(direction, port_id, 0, NULL, 0);
|
||||
p = pw_port_new(direction, port_id, NULL, 0);
|
||||
if (p == NULL)
|
||||
return NULL;
|
||||
|
||||
|
|
|
|||
|
|
@ -119,6 +119,21 @@ static void push_dict(struct spa_pod_builder *b, const struct spa_dict *dict)
|
|||
spa_pod_builder_pop(b, &f);
|
||||
}
|
||||
|
||||
static void push_params(struct spa_pod_builder *b, uint32_t n_params,
|
||||
const struct spa_param_info *params)
|
||||
{
|
||||
uint32_t i;
|
||||
struct spa_pod_frame f;
|
||||
|
||||
spa_pod_builder_push_struct(b, &f);
|
||||
spa_pod_builder_int(b, n_params);
|
||||
for (i = 0; i < n_params; i++) {
|
||||
spa_pod_builder_id(b, params[i].id);
|
||||
spa_pod_builder_int(b, params[i].flags);
|
||||
}
|
||||
spa_pod_builder_pop(b, &f);
|
||||
}
|
||||
|
||||
static int
|
||||
core_method_marshal_create_object(void *object,
|
||||
const char *factory_name,
|
||||
|
|
@ -612,6 +627,7 @@ static int device_marshal_info(void *object, const struct pw_device_info *info)
|
|||
SPA_POD_Long(info->change_mask),
|
||||
NULL);
|
||||
push_dict(b, info->props);
|
||||
push_params(b, info->n_params, info->params);
|
||||
spa_pod_builder_pop(b, &f);
|
||||
|
||||
return pw_protocol_native_end_resource(resource, b);
|
||||
|
|
@ -647,6 +663,22 @@ static int device_demarshal_info(void *object, void *data, size_t size)
|
|||
SPA_POD_String(&props.items[i].value), NULL) < 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
spa_pod_parser_pop(&prs, &f[1]);
|
||||
|
||||
if (spa_pod_parser_push_struct(&prs, &f[1]) < 0 ||
|
||||
spa_pod_parser_get(&prs,
|
||||
SPA_POD_Int(&info.n_params),
|
||||
NULL) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
info.params = alloca(info.n_params * sizeof(struct spa_param_info));
|
||||
for (i = 0; i < info.n_params; i++) {
|
||||
if (spa_pod_parser_get(&prs,
|
||||
SPA_POD_Id(&info.params[i].id),
|
||||
SPA_POD_Int(&info.params[i].flags), NULL) < 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return pw_proxy_notify(proxy, struct pw_device_proxy_events, info, 0, &info);
|
||||
}
|
||||
|
||||
|
|
@ -838,6 +870,7 @@ static int node_marshal_info(void *object, const struct pw_node_info *info)
|
|||
SPA_POD_String(info->error),
|
||||
NULL);
|
||||
push_dict(b, info->props);
|
||||
push_params(b, info->n_params, info->params);
|
||||
spa_pod_builder_pop(b, &f);
|
||||
|
||||
return pw_protocol_native_end_resource(resource, b);
|
||||
|
|
@ -879,6 +912,22 @@ static int node_demarshal_info(void *object, void *data, size_t size)
|
|||
SPA_POD_String(&props.items[i].value), NULL) < 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
spa_pod_parser_pop(&prs, &f[1]);
|
||||
|
||||
if (spa_pod_parser_push_struct(&prs, &f[1]) < 0 ||
|
||||
spa_pod_parser_get(&prs,
|
||||
SPA_POD_Int(&info.n_params),
|
||||
NULL) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
info.params = alloca(info.n_params * sizeof(struct spa_param_info));
|
||||
for (i = 0; i < info.n_params; i++) {
|
||||
if (spa_pod_parser_get(&prs,
|
||||
SPA_POD_Id(&info.params[i].id),
|
||||
SPA_POD_Int(&info.params[i].flags), NULL) < 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return pw_proxy_notify(proxy, struct pw_node_proxy_events, info, 0, &info);
|
||||
}
|
||||
|
||||
|
|
@ -1032,6 +1081,7 @@ static int port_marshal_info(void *object, const struct pw_port_info *info)
|
|||
SPA_POD_Long(info->change_mask),
|
||||
NULL);
|
||||
push_dict(b, info->props);
|
||||
push_params(b, info->n_params, info->params);
|
||||
spa_pod_builder_pop(b, &f);
|
||||
|
||||
return pw_protocol_native_end_resource(resource, b);
|
||||
|
|
@ -1067,6 +1117,21 @@ static int port_demarshal_info(void *object, void *data, size_t size)
|
|||
SPA_POD_String(&props.items[i].value), NULL) < 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
spa_pod_parser_pop(&prs, &f[1]);
|
||||
|
||||
if (spa_pod_parser_push_struct(&prs, &f[1]) < 0 ||
|
||||
spa_pod_parser_get(&prs,
|
||||
SPA_POD_Int(&info.n_params),
|
||||
NULL) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
info.params = alloca(info.n_params * sizeof(struct spa_param_info));
|
||||
for (i = 0; i < info.n_params; i++) {
|
||||
if (spa_pod_parser_get(&prs,
|
||||
SPA_POD_Id(&info.params[i].id),
|
||||
SPA_POD_Int(&info.params[i].flags), NULL) < 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
return pw_proxy_notify(proxy, struct pw_port_proxy_events, info, 0, &info);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ struct pw_device *pw_device_new(struct pw_core *core,
|
|||
|
||||
this->info.name = strdup(name);
|
||||
this->info.props = &properties->dict;
|
||||
this->info.params = this->params;
|
||||
spa_hook_list_init(&this->listener_list);
|
||||
|
||||
spa_list_init(&this->node_list);
|
||||
|
|
@ -242,7 +243,7 @@ global_bind(void *_data, struct pw_client *client, uint32_t permissions,
|
|||
|
||||
spa_list_append(&global->resource_list, &resource->link);
|
||||
|
||||
this->info.change_mask = ~0;
|
||||
this->info.change_mask = PW_DEVICE_CHANGE_MASK_ALL;
|
||||
pw_device_resource_info(resource, &this->info);
|
||||
this->info.change_mask = 0;
|
||||
|
||||
|
|
@ -314,12 +315,49 @@ static const struct pw_node_events node_events = {
|
|||
.destroy = node_destroy,
|
||||
};
|
||||
|
||||
static void emit_info_changed(struct pw_device *device)
|
||||
{
|
||||
struct pw_resource *resource;
|
||||
|
||||
pw_device_emit_info_changed(device, &device->info);
|
||||
|
||||
if (device->global)
|
||||
spa_list_for_each(resource, &device->global->resource_list, link)
|
||||
pw_device_resource_info(resource, &device->info);
|
||||
|
||||
device->info.change_mask = 0;
|
||||
}
|
||||
|
||||
static int update_properties(struct pw_device *device, const struct spa_dict *dict)
|
||||
{
|
||||
int changed;
|
||||
|
||||
changed = pw_properties_update(device->properties, dict);
|
||||
|
||||
pw_log_debug("device %p: updated %d properties", device, changed);
|
||||
|
||||
if (!changed)
|
||||
return 0;
|
||||
|
||||
device->info.props = &device->properties->dict;
|
||||
device->info.change_mask |= PW_DEVICE_CHANGE_MASK_PROPS;
|
||||
return changed;
|
||||
}
|
||||
|
||||
static int device_info(void *data, const struct spa_device_info *info)
|
||||
{
|
||||
struct pw_device *device = data;
|
||||
if (info->change_mask & SPA_DEVICE_CHANGE_MASK_INFO)
|
||||
pw_device_update_properties(device, info->info);
|
||||
if (info->change_mask & SPA_DEVICE_CHANGE_MASK_PROPS) {
|
||||
update_properties(device, info->props);
|
||||
}
|
||||
if (info->change_mask & SPA_DEVICE_CHANGE_MASK_PARAMS) {
|
||||
device->info.change_mask |= PW_DEVICE_CHANGE_MASK_PARAMS;
|
||||
device->info.n_params = SPA_MIN(info->n_params, SPA_N_ELEMENTS(device->params));
|
||||
memcpy(device->info.params, info->params,
|
||||
device->info.n_params * sizeof(struct spa_param_info));
|
||||
}
|
||||
emit_info_changed(device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -343,14 +381,14 @@ static void device_add(struct pw_device *device, uint32_t id,
|
|||
support = pw_core_get_support(device->core, &n_support);
|
||||
|
||||
props = pw_properties_copy(device->properties);
|
||||
if (info->info)
|
||||
pw_properties_update(props, info->info);
|
||||
if (info->props)
|
||||
pw_properties_update(props, info->props);
|
||||
|
||||
node = pw_node_new(device->core,
|
||||
device->info.name,
|
||||
props,
|
||||
sizeof(struct node_data) +
|
||||
spa_handle_factory_get_size(info->factory, info->info));
|
||||
spa_handle_factory_get_size(info->factory, info->props));
|
||||
|
||||
nd = pw_node_get_user_data(node);
|
||||
nd->id = id;
|
||||
|
|
@ -361,7 +399,7 @@ static void device_add(struct pw_device *device, uint32_t id,
|
|||
|
||||
if ((res = spa_handle_factory_init(info->factory,
|
||||
nd->handle,
|
||||
info->info,
|
||||
info->props,
|
||||
support,
|
||||
n_support)) < 0) {
|
||||
pw_log_error("can't make factory instance: %d", res);
|
||||
|
|
@ -412,8 +450,8 @@ static int device_object_info(void *data, uint32_t id,
|
|||
}
|
||||
}
|
||||
else if (nd != NULL) {
|
||||
if (info->change_mask & SPA_DEVICE_OBJECT_CHANGE_MASK_INFO)
|
||||
pw_node_update_properties(nd->node, info->info);
|
||||
if (info->change_mask & SPA_DEVICE_OBJECT_CHANGE_MASK_PROPS)
|
||||
pw_node_update_properties(nd->node, info->props);
|
||||
}
|
||||
else {
|
||||
device_add(device, id, info);
|
||||
|
|
@ -457,26 +495,8 @@ const struct pw_properties *pw_device_get_properties(struct pw_device *device)
|
|||
SPA_EXPORT
|
||||
int pw_device_update_properties(struct pw_device *device, const struct spa_dict *dict)
|
||||
{
|
||||
struct pw_resource *resource;
|
||||
int changed;
|
||||
|
||||
changed = pw_properties_update(device->properties, dict);
|
||||
|
||||
pw_log_debug("device %p: updated %d properties", device, changed);
|
||||
|
||||
if (!changed)
|
||||
return 0;
|
||||
|
||||
device->info.props = &device->properties->dict;
|
||||
device->info.change_mask |= PW_DEVICE_CHANGE_MASK_PROPS;
|
||||
pw_device_emit_info_changed(device, &device->info);
|
||||
|
||||
if (device->global)
|
||||
spa_list_for_each(resource, &device->global->resource_list, link)
|
||||
pw_device_resource_info(resource, &device->info);
|
||||
|
||||
device->info.change_mask = 0;
|
||||
|
||||
int changed = update_properties(device, dict);
|
||||
emit_info_changed(device);
|
||||
return changed;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -179,7 +179,6 @@ SPA_EXPORT
|
|||
struct pw_node_info *pw_node_info_update(struct pw_node_info *info,
|
||||
const struct pw_node_info *update)
|
||||
{
|
||||
|
||||
if (update == NULL)
|
||||
return info;
|
||||
|
||||
|
|
@ -214,6 +213,17 @@ struct pw_node_info *pw_node_info_update(struct pw_node_info *info,
|
|||
pw_spa_dict_destroy(info->props);
|
||||
info->props = pw_spa_dict_copy(update->props);
|
||||
}
|
||||
if (update->change_mask & PW_NODE_CHANGE_MASK_PARAMS) {
|
||||
info->n_params = update->n_params;
|
||||
free((void *) info->params);
|
||||
if (update->params) {
|
||||
size_t size = info->n_params * sizeof(struct spa_param_info);
|
||||
info->params = malloc(size);
|
||||
memcpy(info->params, update->params, size);
|
||||
}
|
||||
else
|
||||
info->params = NULL;
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
|
|
@ -225,6 +235,7 @@ void pw_node_info_free(struct pw_node_info *info)
|
|||
free((void *) info->error);
|
||||
if (info->props)
|
||||
pw_spa_dict_destroy(info->props);
|
||||
free((void *) info->params);
|
||||
free(info);
|
||||
}
|
||||
|
||||
|
|
@ -250,6 +261,17 @@ struct pw_port_info *pw_port_info_update(struct pw_port_info *info,
|
|||
pw_spa_dict_destroy(info->props);
|
||||
info->props = pw_spa_dict_copy(update->props);
|
||||
}
|
||||
if (update->change_mask & PW_PORT_CHANGE_MASK_PARAMS) {
|
||||
info->n_params = update->n_params;
|
||||
free((void *) info->params);
|
||||
if (update->params) {
|
||||
size_t size = info->n_params * sizeof(struct spa_param_info);
|
||||
info->params = malloc(size);
|
||||
memcpy(info->params, update->params, size);
|
||||
}
|
||||
else
|
||||
info->params = NULL;
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
|
|
@ -259,6 +281,7 @@ void pw_port_info_free(struct pw_port_info *info)
|
|||
|
||||
if (info->props)
|
||||
pw_spa_dict_destroy(info->props);
|
||||
free((void *) info->params);
|
||||
free(info);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -128,11 +128,15 @@ void pw_module_info_free(struct pw_module_info *info);
|
|||
|
||||
/** The device information. Extra information can be added in later versions \memberof pw_introspect */
|
||||
struct pw_device_info {
|
||||
uint32_t id; /**< id of the global */
|
||||
const char *name; /**< name the device */
|
||||
uint32_t id; /**< id of the global */
|
||||
const char *name; /**< name the device */
|
||||
#define PW_DEVICE_CHANGE_MASK_PROPS (1 << 0)
|
||||
uint64_t change_mask; /**< bitfield of changed fields since last call */
|
||||
struct spa_dict *props; /**< extra properties */
|
||||
#define PW_DEVICE_CHANGE_MASK_PARAMS (1 << 1)
|
||||
#define PW_DEVICE_CHANGE_MASK_ALL ((1 << 2)-1)
|
||||
uint64_t change_mask; /**< bitfield of changed fields since last call */
|
||||
struct spa_dict *props; /**< extra properties */
|
||||
struct spa_param_info *params; /**< parameters */
|
||||
uint32_t n_params; /**< number of items in \a params */
|
||||
};
|
||||
|
||||
/** Update and existing \ref pw_device_info with \a update \memberof pw_introspect */
|
||||
|
|
@ -168,6 +172,8 @@ struct pw_node_info {
|
|||
#define PW_NODE_CHANGE_MASK_OUTPUT_PORTS (1 << 2)
|
||||
#define PW_NODE_CHANGE_MASK_STATE (1 << 3)
|
||||
#define PW_NODE_CHANGE_MASK_PROPS (1 << 4)
|
||||
#define PW_NODE_CHANGE_MASK_PARAMS (1 << 5)
|
||||
#define PW_NODE_CHANGE_MASK_ALL ((1 << 6)-1)
|
||||
uint64_t change_mask; /**< bitfield of changed fields since last call */
|
||||
const char *name; /**< name the node, suitable for display */
|
||||
uint32_t max_input_ports; /**< maximum number of inputs */
|
||||
|
|
@ -177,6 +183,8 @@ struct pw_node_info {
|
|||
enum pw_node_state state; /**< the current state of the node */
|
||||
const char *error; /**< an error reason if \a state is error */
|
||||
struct spa_dict *props; /**< the properties of the node */
|
||||
struct spa_param_info *params; /**< parameters */
|
||||
uint32_t n_params; /**< number of items in \a params */
|
||||
};
|
||||
|
||||
struct pw_node_info *
|
||||
|
|
@ -190,8 +198,12 @@ struct pw_port_info {
|
|||
uint32_t id; /**< id of the global */
|
||||
enum pw_direction direction; /**< port direction */
|
||||
#define PW_PORT_CHANGE_MASK_PROPS (1 << 0)
|
||||
#define PW_PORT_CHANGE_MASK_PARAMS (1 << 1)
|
||||
#define PW_PORT_CHANGE_MASK_ALL ((1 << 2)-1)
|
||||
uint64_t change_mask; /**< bitfield of changed fields since last call */
|
||||
struct spa_dict *props; /**< the properties of the port */
|
||||
struct spa_param_info *params; /**< parameters */
|
||||
uint32_t n_params; /**< number of items in \a params */
|
||||
};
|
||||
|
||||
struct pw_port_info *
|
||||
|
|
|
|||
|
|
@ -166,10 +166,26 @@ static int start_node(struct pw_node *this)
|
|||
return res;
|
||||
}
|
||||
|
||||
static void emit_info_changed(struct pw_node *node)
|
||||
{
|
||||
struct pw_resource *resource;
|
||||
|
||||
if (node->info.change_mask == 0)
|
||||
return;
|
||||
|
||||
pw_node_emit_info_changed(node, &node->info);
|
||||
|
||||
if (node->global)
|
||||
spa_list_for_each(resource, &node->global->resource_list, link)
|
||||
pw_node_resource_info(resource, &node->info);
|
||||
|
||||
node->info.change_mask = 0;
|
||||
}
|
||||
|
||||
|
||||
static void node_update_state(struct pw_node *node, enum pw_node_state state, char *error)
|
||||
{
|
||||
enum pw_node_state old;
|
||||
struct pw_resource *resource;
|
||||
|
||||
old = node->info.state;
|
||||
if (old == state)
|
||||
|
|
@ -198,16 +214,9 @@ static void node_update_state(struct pw_node *node, enum pw_node_state state, ch
|
|||
pw_node_emit_state_changed(node, old, state, error);
|
||||
|
||||
node->info.change_mask |= PW_NODE_CHANGE_MASK_STATE;
|
||||
pw_node_emit_info_changed(node, &node->info);
|
||||
|
||||
if (node->global)
|
||||
spa_list_for_each(resource, &node->global->resource_list, link)
|
||||
pw_node_resource_info(resource, &node->info);
|
||||
|
||||
node->info.change_mask = 0;
|
||||
emit_info_changed(node);
|
||||
}
|
||||
|
||||
|
||||
static int suspend_node(struct pw_node *this)
|
||||
{
|
||||
int res = 0;
|
||||
|
|
@ -274,8 +283,10 @@ static int node_enum_params(void *object, int seq, uint32_t id,
|
|||
filter, reply_param, data)) < 0) {
|
||||
pw_log_error("resource %p: %d error %d (%s)", resource,
|
||||
resource->id, res, spa_strerror(res));
|
||||
pw_core_resource_error(client->core_resource,
|
||||
resource->id, seq, res, spa_strerror(res));
|
||||
pw_core_resource_errorf(client->core_resource,
|
||||
resource->id, seq, res,
|
||||
"enum params %s failed",
|
||||
spa_debug_type_find_name(spa_type_param, id));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -344,7 +355,7 @@ global_bind(void *_data, struct pw_client *client, uint32_t permissions,
|
|||
|
||||
spa_list_append(&global->resource_list, &resource->link);
|
||||
|
||||
this->info.change_mask = ~0;
|
||||
this->info.change_mask = PW_NODE_CHANGE_MASK_ALL;
|
||||
pw_node_resource_info(resource, &this->info);
|
||||
this->info.change_mask = 0;
|
||||
return 0;
|
||||
|
|
@ -694,6 +705,7 @@ struct pw_node *pw_node_new(struct pw_core *core,
|
|||
|
||||
this->info.state = PW_NODE_STATE_CREATING;
|
||||
this->info.props = &this->properties->dict;
|
||||
this->info.params = this->params;
|
||||
|
||||
spa_list_init(&this->input_ports);
|
||||
pw_map_init(&this->input_port_map, 64, 64);
|
||||
|
|
@ -767,41 +779,48 @@ const struct pw_properties *pw_node_get_properties(struct pw_node *node)
|
|||
return node->properties;
|
||||
}
|
||||
|
||||
SPA_EXPORT
|
||||
int pw_node_update_properties(struct pw_node *node, const struct spa_dict *dict)
|
||||
static int update_properties(struct pw_node *node, const struct spa_dict *dict)
|
||||
{
|
||||
struct pw_resource *resource;
|
||||
int changed;
|
||||
|
||||
changed = pw_properties_update(node->properties, dict);
|
||||
|
||||
pw_log_debug("node %p: updated %d properties", node, changed);
|
||||
|
||||
if (!changed)
|
||||
return 0;
|
||||
|
||||
check_properties(node);
|
||||
|
||||
node->info.props = &node->properties->dict;
|
||||
node->info.change_mask |= PW_NODE_CHANGE_MASK_PROPS;
|
||||
pw_node_emit_info_changed(node, &node->info);
|
||||
|
||||
if (node->global)
|
||||
spa_list_for_each(resource, &node->global->resource_list, link)
|
||||
pw_node_resource_info(resource, &node->info);
|
||||
|
||||
node->info.change_mask = 0;
|
||||
if (changed) {
|
||||
check_properties(node);
|
||||
node->info.props = &node->properties->dict;
|
||||
node->info.change_mask |= PW_NODE_CHANGE_MASK_PROPS;
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
SPA_EXPORT
|
||||
int pw_node_update_properties(struct pw_node *node, const struct spa_dict *dict)
|
||||
{
|
||||
int changed = update_properties(node, dict);
|
||||
emit_info_changed(node);
|
||||
return changed;
|
||||
}
|
||||
|
||||
static int node_info(void *data, const struct spa_node_info *info)
|
||||
{
|
||||
struct pw_node *node = data;
|
||||
|
||||
node->info.max_input_ports = info->max_input_ports;
|
||||
node->info.max_output_ports = info->max_output_ports;
|
||||
if (info->change_mask & SPA_NODE_CHANGE_MASK_PROPS)
|
||||
pw_node_update_properties(node, info->props);
|
||||
|
||||
if (info->change_mask & SPA_NODE_CHANGE_MASK_PROPS) {
|
||||
update_properties(node, info->props);
|
||||
}
|
||||
if (info->change_mask & SPA_NODE_CHANGE_MASK_PARAMS) {
|
||||
node->info.change_mask |= PW_NODE_CHANGE_MASK_PARAMS;
|
||||
node->info.n_params = SPA_MIN(info->n_params, SPA_N_ELEMENTS(node->params));
|
||||
memcpy(node->info.params, info->params,
|
||||
node->info.n_params * sizeof(struct spa_param_info));
|
||||
}
|
||||
emit_info_changed(node);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -821,22 +840,16 @@ static int node_port_info(void *data, enum spa_direction direction, uint32_t por
|
|||
pw_direction_as_string(direction), port_id);
|
||||
}
|
||||
} else if (port) {
|
||||
if (info->change_mask & SPA_PORT_CHANGE_MASK_FLAGS)
|
||||
port->spa_flags = info->flags;
|
||||
if (info->change_mask & SPA_PORT_CHANGE_MASK_PROPS)
|
||||
pw_port_update_properties(port, info->props);
|
||||
pw_log_debug("node %p: %s port %d changed", node,
|
||||
pw_direction_as_string(direction), port_id);
|
||||
pw_port_update_info(port, info);
|
||||
} else {
|
||||
int res;
|
||||
struct pw_properties *props;
|
||||
|
||||
pw_log_debug("node %p: %s port %d added", node,
|
||||
pw_direction_as_string(direction), port_id);
|
||||
|
||||
props = info->props ?
|
||||
pw_properties_new_dict(info->props) :
|
||||
pw_properties_new(NULL, NULL);
|
||||
|
||||
if ((port = pw_port_new(direction, port_id, info->flags, props,
|
||||
if ((port = pw_port_new(direction, port_id, info,
|
||||
node->port_user_data_size))) {
|
||||
if ((res = pw_port_add(port, node)) < 0) {
|
||||
pw_log_error("node %p: can't add port %p: %d, %s",
|
||||
|
|
|
|||
|
|
@ -79,6 +79,22 @@ void pw_port_mix_update_state(struct pw_port *port, struct pw_port_mix *mix, enu
|
|||
}
|
||||
}
|
||||
|
||||
static void emit_info_changed(struct pw_port *port)
|
||||
{
|
||||
struct pw_resource *resource;
|
||||
|
||||
if (port->info.change_mask == 0)
|
||||
return;
|
||||
|
||||
pw_port_emit_info_changed(port, &port->info);
|
||||
|
||||
if (port->global)
|
||||
spa_list_for_each(resource, &port->global->resource_list, link)
|
||||
pw_port_resource_info(resource, &port->info);
|
||||
|
||||
port->info.change_mask = 0;
|
||||
}
|
||||
|
||||
void pw_port_update_state(struct pw_port *port, enum pw_port_state state)
|
||||
{
|
||||
if (port->state != state) {
|
||||
|
|
@ -243,15 +259,46 @@ int pw_port_release_mix(struct pw_port *port, struct pw_port_mix *mix)
|
|||
return res;
|
||||
}
|
||||
|
||||
static int update_properties(struct pw_port *port, const struct spa_dict *dict)
|
||||
{
|
||||
int changed;
|
||||
|
||||
changed = pw_properties_update(port->properties, dict);
|
||||
|
||||
pw_log_debug("port %p: updated %d properties", port, changed);
|
||||
|
||||
if (changed) {
|
||||
port->info.props = &port->properties->dict;
|
||||
port->info.change_mask |= PW_PORT_CHANGE_MASK_PROPS;
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
static void update_info(struct pw_port *port, const struct spa_port_info *info)
|
||||
{
|
||||
if (info->change_mask & SPA_PORT_CHANGE_MASK_FLAGS) {
|
||||
port->spa_flags = info->flags;
|
||||
}
|
||||
if (info->change_mask & SPA_PORT_CHANGE_MASK_PROPS) {
|
||||
update_properties(port, info->props);
|
||||
}
|
||||
if (info->change_mask & SPA_PORT_CHANGE_MASK_PARAMS) {
|
||||
port->info.change_mask |= PW_PORT_CHANGE_MASK_PARAMS;
|
||||
port->info.n_params = SPA_MIN(info->n_params, SPA_N_ELEMENTS(port->params));
|
||||
memcpy(port->info.params, info->params,
|
||||
port->info.n_params * sizeof(struct spa_param_info));
|
||||
}
|
||||
}
|
||||
|
||||
SPA_EXPORT
|
||||
struct pw_port *pw_port_new(enum pw_direction direction,
|
||||
uint32_t port_id,
|
||||
uint32_t spa_flags,
|
||||
struct pw_properties *properties,
|
||||
const struct spa_port_info *info,
|
||||
size_t user_data_size)
|
||||
{
|
||||
struct impl *impl;
|
||||
struct pw_port *this;
|
||||
struct pw_properties *properties;
|
||||
|
||||
impl = calloc(1, sizeof(struct impl) + user_data_size);
|
||||
if (impl == NULL)
|
||||
|
|
@ -261,19 +308,22 @@ struct pw_port *pw_port_new(enum pw_direction direction,
|
|||
pw_log_debug("port %p: new %s %d", this,
|
||||
pw_direction_as_string(direction), port_id);
|
||||
|
||||
if (properties == NULL)
|
||||
if (info && info->change_mask & SPA_PORT_CHANGE_MASK_PROPS && info->props)
|
||||
properties = pw_properties_new_dict(info->props);
|
||||
else
|
||||
properties = pw_properties_new(NULL, NULL);
|
||||
|
||||
if (properties == NULL)
|
||||
goto no_mem;
|
||||
|
||||
if (SPA_FLAG_CHECK(spa_flags, SPA_PORT_FLAG_PHYSICAL))
|
||||
if (SPA_FLAG_CHECK(info->flags, SPA_PORT_FLAG_PHYSICAL))
|
||||
pw_properties_set(properties, "port.physical", "1");
|
||||
if (SPA_FLAG_CHECK(spa_flags, SPA_PORT_FLAG_TERMINAL))
|
||||
if (SPA_FLAG_CHECK(info->flags, SPA_PORT_FLAG_TERMINAL))
|
||||
pw_properties_set(properties, "port.terminal", "1");
|
||||
|
||||
this->direction = direction;
|
||||
this->port_id = port_id;
|
||||
this->spa_flags = spa_flags;
|
||||
this->spa_flags = info->flags;
|
||||
this->properties = properties;
|
||||
this->state = PW_PORT_STATE_INIT;
|
||||
this->rt.io = SPA_IO_BUFFERS_INIT;
|
||||
|
|
@ -282,6 +332,8 @@ struct pw_port *pw_port_new(enum pw_direction direction,
|
|||
this->user_data = SPA_MEMBER(impl, sizeof(struct impl), void);
|
||||
|
||||
this->info.direction = direction;
|
||||
this->info.params = this->params;
|
||||
this->info.change_mask = PW_PORT_CHANGE_MASK_PROPS;
|
||||
this->info.props = &this->properties->dict;
|
||||
|
||||
spa_list_init(&this->links);
|
||||
|
|
@ -308,6 +360,9 @@ struct pw_port *pw_port_new(enum pw_direction direction,
|
|||
0);
|
||||
this->rt.io.status = SPA_STATUS_NEED_BUFFER;
|
||||
|
||||
if (info)
|
||||
update_info(this, info);
|
||||
|
||||
return this;
|
||||
|
||||
no_mem:
|
||||
|
|
@ -354,29 +409,19 @@ const struct pw_properties *pw_port_get_properties(struct pw_port *port)
|
|||
SPA_EXPORT
|
||||
int pw_port_update_properties(struct pw_port *port, const struct spa_dict *dict)
|
||||
{
|
||||
struct pw_resource *resource;
|
||||
int changed;
|
||||
int changed = update_properties(port, dict);
|
||||
|
||||
changed = pw_properties_update(port->properties, dict);
|
||||
|
||||
pw_log_debug("port %p: updated %d properties", port, changed);
|
||||
|
||||
if (!changed)
|
||||
return 0;
|
||||
|
||||
port->info.props = &port->properties->dict;
|
||||
port->info.change_mask |= PW_PORT_CHANGE_MASK_PROPS;
|
||||
pw_port_emit_info_changed(port, &port->info);
|
||||
|
||||
if (port->global)
|
||||
spa_list_for_each(resource, &port->global->resource_list, link)
|
||||
pw_port_resource_info(resource, &port->info);
|
||||
|
||||
port->info.change_mask = 0;
|
||||
emit_info_changed(port);
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
void pw_port_update_info(struct pw_port *port, const struct spa_port_info *info)
|
||||
{
|
||||
update_info(port, info);
|
||||
emit_info_changed(port);
|
||||
}
|
||||
|
||||
SPA_EXPORT
|
||||
struct pw_node *pw_port_get_node(struct pw_port *port)
|
||||
{
|
||||
|
|
@ -431,11 +476,14 @@ static int check_param_io(void *data, int seq, uint32_t id,
|
|||
uint32_t pid, psize;
|
||||
|
||||
if (spa_pod_parse_object(param,
|
||||
SPA_TYPE_OBJECT_ParamIO, NULL,
|
||||
SPA_PARAM_IO_id, SPA_POD_Id(&pid),
|
||||
SPA_PARAM_IO_size, SPA_POD_Int(&psize)) < 0)
|
||||
SPA_TYPE_OBJECT_ParamIO, NULL,
|
||||
SPA_PARAM_IO_id, SPA_POD_Id(&pid),
|
||||
SPA_PARAM_IO_size, SPA_POD_Int(&psize)) < 0)
|
||||
return 0;
|
||||
|
||||
pw_log_debug("port %p: got control %s", port,
|
||||
spa_debug_type_find_name(spa_type_io, pid));
|
||||
|
||||
switch (pid) {
|
||||
case SPA_IO_Control:
|
||||
case SPA_IO_Notify:
|
||||
|
|
@ -518,7 +566,7 @@ global_bind(void *_data, struct pw_client *client, uint32_t permissions,
|
|||
|
||||
spa_list_append(&global->resource_list, &resource->link);
|
||||
|
||||
this->info.change_mask = ~0;
|
||||
this->info.change_mask = PW_PORT_CHANGE_MASK_ALL;
|
||||
pw_port_resource_info(resource, &this->info);
|
||||
this->info.change_mask = 0;
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -261,7 +261,8 @@ struct pw_device {
|
|||
struct spa_hook global_listener;
|
||||
|
||||
struct pw_properties *properties; /**< properties of the device */
|
||||
struct pw_device_info info; /**< introspectable device info */
|
||||
struct pw_device_info info; /**< introspectable device info */
|
||||
struct spa_param_info params[32];
|
||||
|
||||
struct spa_device *implementation; /**< implementation */
|
||||
struct spa_hook_list listener_list;
|
||||
|
|
@ -333,6 +334,7 @@ struct pw_node {
|
|||
struct pw_properties *properties; /**< properties of the node */
|
||||
|
||||
struct pw_node_info info; /**< introspectable node info */
|
||||
struct spa_param_info params[32];
|
||||
|
||||
int registered:1;
|
||||
int enabled:1; /**< if the node is enabled */
|
||||
|
|
@ -440,6 +442,7 @@ struct pw_port {
|
|||
|
||||
struct pw_properties *properties; /**< properties of the port */
|
||||
struct pw_port_info info;
|
||||
struct spa_param_info params[32];
|
||||
|
||||
struct allocation allocation;
|
||||
|
||||
|
|
@ -700,10 +703,11 @@ const struct pw_export_type *pw_core_find_export_type(struct pw_core *core, uint
|
|||
struct pw_port *
|
||||
pw_port_new(enum pw_direction direction,
|
||||
uint32_t port_id,
|
||||
uint32_t spa_flags,
|
||||
struct pw_properties *properties,
|
||||
const struct spa_port_info *info,
|
||||
size_t user_data_size);
|
||||
|
||||
void pw_port_update_info(struct pw_port *port, const struct spa_port_info *info);
|
||||
|
||||
int pw_port_register(struct pw_port *port,
|
||||
struct pw_client *owner,
|
||||
struct pw_global *parent,
|
||||
|
|
|
|||
|
|
@ -313,13 +313,40 @@ static int impl_send_command(struct spa_node *node, const struct spa_command *co
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void emit_node_info(struct stream *d)
|
||||
{
|
||||
if (d->callbacks && d->callbacks->info) {
|
||||
struct spa_node_info info;
|
||||
info = SPA_NODE_INFO_INIT();
|
||||
if (d->direction == SPA_DIRECTION_INPUT) {
|
||||
info.max_input_ports = 1;
|
||||
info.max_output_ports = 0;
|
||||
} else {
|
||||
info.max_input_ports = 0;
|
||||
info.max_output_ports = 1;
|
||||
}
|
||||
info.change_mask |= SPA_NODE_CHANGE_MASK_FLAGS;
|
||||
info.flags = SPA_NODE_FLAG_RT;
|
||||
d->callbacks->info(d->callbacks_data, &info);
|
||||
}
|
||||
}
|
||||
static void emit_port_info(struct stream *d)
|
||||
{
|
||||
if (d->callbacks && d->callbacks->port_info) {
|
||||
struct spa_port_info info;
|
||||
struct spa_param_info params[5];
|
||||
|
||||
info = SPA_PORT_INFO_INIT();
|
||||
info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS;
|
||||
info.flags = SPA_PORT_FLAG_CAN_USE_BUFFERS;
|
||||
info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
|
||||
params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
|
||||
params[1] = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
|
||||
params[2] = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
|
||||
params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
|
||||
info.params = params;
|
||||
info.n_params = 5;
|
||||
d->callbacks->port_info(d->callbacks_data, d->direction, 0, &info);
|
||||
}
|
||||
}
|
||||
|
|
@ -332,6 +359,7 @@ static int impl_set_callbacks(struct spa_node *node,
|
|||
d->callbacks = callbacks;
|
||||
d->callbacks_data = data;
|
||||
|
||||
emit_node_info(d);
|
||||
emit_port_info(d);
|
||||
|
||||
return 0;
|
||||
|
|
@ -382,8 +410,6 @@ static int impl_port_enum_params(struct spa_node *node, int seq,
|
|||
const struct spa_pod *filter)
|
||||
{
|
||||
struct stream *d = SPA_CONTAINER_OF(node, struct stream, impl_node);
|
||||
struct spa_pod *param;
|
||||
uint32_t last_id = SPA_ID_INVALID;
|
||||
uint32_t n_params = pw_array_get_len(&d->params, struct param);
|
||||
struct spa_result_node_params result;
|
||||
uint8_t buffer[1024];
|
||||
|
|
@ -391,52 +417,34 @@ static int impl_port_enum_params(struct spa_node *node, int seq,
|
|||
uint32_t count = 0;
|
||||
int res;
|
||||
|
||||
spa_return_val_if_fail(num != 0, -EINVAL);
|
||||
|
||||
result.id = id;
|
||||
result.next = start;
|
||||
next:
|
||||
result.index = result.next;
|
||||
|
||||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
|
||||
while (true) {
|
||||
if (result.next < n_params) {
|
||||
param = pw_array_get_unchecked(&d->params, result.next, struct param)->param;
|
||||
}
|
||||
else if (last_id != SPA_ID_INVALID)
|
||||
struct spa_pod *param;
|
||||
|
||||
result.index = result.next++;
|
||||
|
||||
if (result.index >= n_params)
|
||||
break;
|
||||
else
|
||||
return 0;
|
||||
|
||||
result.next++;
|
||||
param = pw_array_get_unchecked(&d->params, result.index, struct param)->param;
|
||||
|
||||
if (id == SPA_PARAM_List) {
|
||||
uint32_t new_id = ((struct spa_pod_object *) param)->body.id;
|
||||
if (param == NULL || !spa_pod_is_object_id(param, id))
|
||||
continue;
|
||||
|
||||
if (last_id == SPA_ID_INVALID){
|
||||
result.param = spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_ParamList, id,
|
||||
SPA_PARAM_LIST_id, SPA_POD_Id(new_id));
|
||||
last_id = new_id;
|
||||
}
|
||||
else if (last_id != new_id) {
|
||||
result.next--;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (param == NULL || !spa_pod_is_object_id(param, id))
|
||||
continue;
|
||||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
if (spa_pod_filter(&b, &result.param, param, filter) != 0)
|
||||
continue;
|
||||
|
||||
if (spa_pod_filter(&b, &result.param, param, filter) == 0)
|
||||
break;
|
||||
}
|
||||
if ((res = d->callbacks->result(d->callbacks_data, seq, 0, &result)) != 0)
|
||||
return res;
|
||||
|
||||
if (++count == num)
|
||||
break;
|
||||
}
|
||||
|
||||
if ((res = d->callbacks->result(d->callbacks_data, seq, 0, &result)) != 0)
|
||||
return res;
|
||||
|
||||
if (++count != num)
|
||||
goto next;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -553,6 +553,7 @@ static void info_module(struct proxy_data *pd)
|
|||
static void info_node(struct proxy_data *pd)
|
||||
{
|
||||
struct pw_node_info *info = pd->info;
|
||||
uint32_t i;
|
||||
|
||||
info_global(pd);
|
||||
fprintf(stdout, "%c\tname: \"%s\"\n", MARK_CHANGE(0), info->name);
|
||||
|
|
@ -566,17 +567,26 @@ static void info_node(struct proxy_data *pd)
|
|||
else
|
||||
fprintf(stdout, "\n");
|
||||
print_properties(info->props, MARK_CHANGE(4), true);
|
||||
fprintf(stdout, "%c\tenum_params\n", MARK_CHANGE(5));
|
||||
fprintf(stdout, "%c\tparams\n", MARK_CHANGE(5));
|
||||
for (i = 0; i < info->n_params; i++) {
|
||||
fprintf(stdout, "%c\t %d (%s)\n", MARK_CHANGE(5), info->params[i].id,
|
||||
spa_debug_type_find_name(spa_type_param, info->params[i].id));
|
||||
}
|
||||
info->change_mask = 0;
|
||||
}
|
||||
|
||||
static void info_port(struct proxy_data *pd)
|
||||
{
|
||||
struct pw_port_info *info = pd->info;
|
||||
uint32_t i;
|
||||
|
||||
info_global(pd);
|
||||
print_properties(info->props, MARK_CHANGE(0), true);
|
||||
fprintf(stdout, "%c\tenum_params\n", MARK_CHANGE(1));
|
||||
fprintf(stdout, "%c\tparams\n", MARK_CHANGE(1));
|
||||
for (i = 0; i < info->n_params; i++) {
|
||||
fprintf(stdout, "%c\t %d (%s)\n", MARK_CHANGE(1), info->params[i].id,
|
||||
spa_debug_type_find_name(spa_type_param, info->params[i].id));
|
||||
}
|
||||
info->change_mask = 0;
|
||||
}
|
||||
|
||||
|
|
@ -1182,16 +1192,14 @@ static bool do_node_params(struct data *data, const char *cmd, char *args, char
|
|||
struct global *global;
|
||||
|
||||
n = pw_split_ip(args, WHITESPACE, 2, a);
|
||||
if (n < 1) {
|
||||
asprintf(error, "%s <object-id> [<param-id-name>]", cmd);
|
||||
if (n < 2) {
|
||||
asprintf(error, "%s <object-id> <param-id>", cmd);
|
||||
return false;
|
||||
}
|
||||
if (n < 2)
|
||||
param_id = SPA_PARAM_List;
|
||||
else
|
||||
param_id = atoi(a[1]);
|
||||
|
||||
id = atoi(a[0]);
|
||||
param_id = atoi(a[1]);
|
||||
|
||||
global = pw_map_lookup(&rd->globals, id);
|
||||
if (global == NULL) {
|
||||
asprintf(error, "%s: unknown global %d", cmd, id);
|
||||
|
|
@ -1221,16 +1229,14 @@ static bool do_port_params(struct data *data, const char *cmd, char *args, char
|
|||
struct global *global;
|
||||
|
||||
n = pw_split_ip(args, WHITESPACE, 2, a);
|
||||
if (n < 1) {
|
||||
asprintf(error, "%s <object-id> [<param-id-name>]", cmd);
|
||||
if (n < 2) {
|
||||
asprintf(error, "%s <object-id> <param-id>", cmd);
|
||||
return false;
|
||||
}
|
||||
if (n < 2)
|
||||
param_id = SPA_PARAM_List;
|
||||
else
|
||||
param_id = atoi(a[1]);
|
||||
|
||||
id = atoi(a[0]);
|
||||
param_id = atoi(a[1]);
|
||||
|
||||
global = pw_map_lookup(&rd->globals, id);
|
||||
if (global == NULL) {
|
||||
asprintf(error, "%s: unknown global %d", cmd, id);
|
||||
|
|
|
|||
|
|
@ -39,6 +39,12 @@ struct proxy_data;
|
|||
|
||||
typedef void (*print_func_t) (struct proxy_data *data);
|
||||
|
||||
struct param {
|
||||
struct spa_list link;
|
||||
uint32_t id;
|
||||
struct spa_pod *param;
|
||||
};
|
||||
|
||||
struct data {
|
||||
struct pw_main_loop *loop;
|
||||
struct pw_core *core;
|
||||
|
|
@ -71,15 +77,16 @@ struct proxy_data {
|
|||
int pending_seq;
|
||||
struct spa_list pending_link;
|
||||
print_func_t print_func;
|
||||
uint32_t n_params;
|
||||
struct spa_pod **params;
|
||||
struct spa_list param_list;
|
||||
};
|
||||
|
||||
static void add_pending(struct proxy_data *pd)
|
||||
{
|
||||
struct data *d = pd->data;
|
||||
|
||||
spa_list_append(&d->pending_list, &pd->pending_link);
|
||||
if (pd->pending_seq == 0) {
|
||||
spa_list_append(&d->pending_list, &pd->pending_link);
|
||||
}
|
||||
pd->pending_seq = pw_core_proxy_sync(d->core_proxy, 0, pd->pending_seq);
|
||||
}
|
||||
|
||||
|
|
@ -107,27 +114,52 @@ static int on_core_done(void *data, uint32_t id, int seq)
|
|||
|
||||
static void clear_params(struct proxy_data *data)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < data->n_params; i++)
|
||||
free(data->params[i]);
|
||||
free(data->params);
|
||||
|
||||
data->n_params = 0;
|
||||
data->params = NULL;
|
||||
struct param *p;
|
||||
spa_list_consume(p, &data->param_list, link) {
|
||||
spa_list_remove(&p->link);
|
||||
free(p);
|
||||
}
|
||||
}
|
||||
|
||||
static int add_param(struct proxy_data *data, const struct spa_pod *param)
|
||||
static void remove_params(struct proxy_data *data, uint32_t id)
|
||||
{
|
||||
uint32_t idx = data->n_params++;
|
||||
struct param *p, *t;
|
||||
spa_list_for_each_safe(p, t, &data->param_list, link) {
|
||||
if (p->id == id) {
|
||||
spa_list_remove(&p->link);
|
||||
free(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data->params = realloc(data->params, sizeof(struct spa_pod *) * data->n_params);
|
||||
if (data->params == NULL)
|
||||
static int add_param(struct proxy_data *data, uint32_t id, const struct spa_pod *param)
|
||||
{
|
||||
struct param *p;
|
||||
|
||||
p = malloc(sizeof(struct param) + SPA_POD_SIZE(param));
|
||||
if (p == NULL)
|
||||
return -ENOMEM;
|
||||
data->params[idx] = spa_pod_copy(param);
|
||||
|
||||
p->id = id;
|
||||
p->param = SPA_MEMBER(p, sizeof(struct param), struct spa_pod);
|
||||
memcpy(p->param, param, SPA_POD_SIZE(param));
|
||||
spa_list_append(&data->param_list, &p->link);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void print_params(struct proxy_data *data, char mark)
|
||||
{
|
||||
struct param *p;
|
||||
|
||||
printf("%c\tparams:\n", mark);
|
||||
spa_list_for_each(p, &data->param_list, link) {
|
||||
if (spa_pod_is_object_type(p->param, SPA_TYPE_OBJECT_Format))
|
||||
spa_debug_format(10, NULL, p->param);
|
||||
else
|
||||
spa_debug_pod(10, NULL, p->param);
|
||||
}
|
||||
}
|
||||
|
||||
static void print_properties(const struct spa_dict *props, char mark)
|
||||
{
|
||||
const struct spa_dict_item *item;
|
||||
|
|
@ -226,16 +258,8 @@ static void print_node(struct proxy_data *data)
|
|||
printf("\ttype: %s (version %d)\n",
|
||||
spa_debug_type_find_name(pw_type_info(), data->type), data->version);
|
||||
if (print_all) {
|
||||
uint32_t i;
|
||||
|
||||
printf("%c\tname: \"%s\"\n", MARK_CHANGE(0), info->name);
|
||||
printf("%c\tparams:\n", MARK_CHANGE(5));
|
||||
for (i = 0; i < data->n_params; i++) {
|
||||
if (spa_pod_is_object_type(data->params[i], SPA_TYPE_OBJECT_Format))
|
||||
spa_debug_format(10, NULL, data->params[i]);
|
||||
else
|
||||
spa_debug_pod(10, NULL, data->params[i]);
|
||||
}
|
||||
print_params(data, MARK_CHANGE(5));
|
||||
printf("%c\tinput ports: %u/%u\n", MARK_CHANGE(1),
|
||||
info->n_input_ports, info->max_input_ports);
|
||||
printf("%c\toutput ports: %u/%u\n", MARK_CHANGE(2),
|
||||
|
|
@ -254,15 +278,23 @@ static void print_node(struct proxy_data *data)
|
|||
static int node_event_info(void *object, const struct pw_node_info *info)
|
||||
{
|
||||
struct proxy_data *data = object;
|
||||
bool is_new = data->info == NULL;
|
||||
struct pw_node_info *old = data->info;
|
||||
uint32_t i;
|
||||
|
||||
data->info = pw_node_info_update(data->info, info);
|
||||
|
||||
if (is_new) {
|
||||
pw_node_proxy_enum_params((struct pw_node_proxy*)data->proxy,
|
||||
0, SPA_PARAM_List, 0, 0, NULL);
|
||||
if (info->change_mask & PW_NODE_CHANGE_MASK_PARAMS) {
|
||||
for (i = 0; i < info->n_params; i++) {
|
||||
if (old != NULL && info->params[i].flags == old->params[i].flags)
|
||||
continue;
|
||||
remove_params(data, info->params[i].id);
|
||||
if (!SPA_FLAG_CHECK(info->params[i].flags, SPA_PARAM_INFO_READ))
|
||||
continue;
|
||||
pw_node_proxy_enum_params((struct pw_node_proxy*)data->proxy,
|
||||
0, info->params[i].id, 0, 0, NULL);
|
||||
}
|
||||
add_pending(data);
|
||||
}
|
||||
data->info = pw_node_info_update(data->info, info);
|
||||
|
||||
if (data->pending_seq == 0)
|
||||
data->print_func(data);
|
||||
return 0;
|
||||
|
|
@ -272,7 +304,7 @@ static int node_event_param(void *object, int seq, uint32_t id,
|
|||
uint32_t index, uint32_t next, const struct spa_pod *param)
|
||||
{
|
||||
struct proxy_data *data = object;
|
||||
return add_param(data, param);
|
||||
return add_param(data, id, param);
|
||||
}
|
||||
|
||||
static const struct pw_node_proxy_events node_events = {
|
||||
|
|
@ -305,16 +337,9 @@ static void print_port(struct proxy_data *data)
|
|||
printf("\ttype: %s (version %d)\n",
|
||||
spa_debug_type_find_name(pw_type_info(), data->type), data->version);
|
||||
if (print_all) {
|
||||
uint32_t i;
|
||||
printf(" \tdirection: \"%s\"\n", pw_direction_as_string(info->direction));
|
||||
printf("%c\tparams:\n", MARK_CHANGE(2));
|
||||
for (i = 0; i < data->n_params; i++) {
|
||||
if (spa_pod_is_object_type(data->params[i], SPA_TYPE_OBJECT_Format))
|
||||
spa_debug_format(12, NULL, data->params[i]);
|
||||
else
|
||||
spa_debug_pod(12, NULL, data->params[i]);
|
||||
}
|
||||
print_properties(info->props, MARK_CHANGE(1));
|
||||
print_params(data, MARK_CHANGE(1));
|
||||
print_properties(info->props, MARK_CHANGE(0));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -322,15 +347,23 @@ static int port_event_info(void *object, const struct pw_port_info *info)
|
|||
{
|
||||
|
||||
struct proxy_data *data = object;
|
||||
bool is_new = data->info == NULL;
|
||||
struct pw_port_info *old = data->info;
|
||||
uint32_t i;
|
||||
|
||||
data->info = pw_port_info_update(data->info, info);
|
||||
|
||||
if (is_new) {
|
||||
pw_port_proxy_enum_params((struct pw_port_proxy*)data->proxy,
|
||||
0, SPA_PARAM_EnumFormat, 0, 0, NULL);
|
||||
if (info->change_mask & PW_PORT_CHANGE_MASK_PARAMS) {
|
||||
for (i = 0; i < info->n_params; i++) {
|
||||
if (old != NULL && info->params[i].flags == old->params[i].flags)
|
||||
continue;
|
||||
remove_params(data, info->params[i].id);
|
||||
if (!SPA_FLAG_CHECK(info->params[i].flags, SPA_PARAM_INFO_READ))
|
||||
continue;
|
||||
pw_port_proxy_enum_params((struct pw_port_proxy*)data->proxy,
|
||||
0, info->params[i].id, 0, 0, NULL);
|
||||
}
|
||||
add_pending(data);
|
||||
}
|
||||
data->info = pw_port_info_update(data->info, info);
|
||||
|
||||
if (data->pending_seq == 0)
|
||||
data->print_func(data);
|
||||
return 0;
|
||||
|
|
@ -340,7 +373,7 @@ static int port_event_param(void *object, int seq, uint32_t id,
|
|||
uint32_t index, uint32_t next, const struct spa_pod *param)
|
||||
{
|
||||
struct proxy_data *data = object;
|
||||
return add_param(data, param);
|
||||
return add_param(data, id, param);
|
||||
}
|
||||
|
||||
static const struct pw_port_proxy_events port_events = {
|
||||
|
|
@ -606,6 +639,7 @@ static int registry_event_global(void *data, uint32_t id, uint32_t parent_id,
|
|||
pd->destroy = destroy;
|
||||
pd->pending_seq = 0;
|
||||
pd->print_func = print_func;
|
||||
spa_list_init(&pd->param_list);
|
||||
pw_proxy_add_proxy_listener(proxy, &pd->proxy_proxy_listener, events, pd);
|
||||
pw_proxy_add_listener(proxy, &pd->proxy_listener, &proxy_events, pd);
|
||||
return 0;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue