mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-02 09:01:50 -05: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
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue