work on sink

This commit is contained in:
Wim Taymans 2016-08-18 12:43:25 +02:00
parent bdbddaf75b
commit a03352353f
9 changed files with 180 additions and 306 deletions

View file

@ -53,8 +53,6 @@ typedef struct {
struct _PinosSpaAlsaSinkPrivate
{
SpaNode *sink;
PinosProperties *props;
PinosRingbuffer *ringbuffer;
@ -121,6 +119,39 @@ make_node (SpaNode **node, const char *lib, const char *name)
return SPA_RESULT_ERROR;
}
static void *
loop (void *user_data)
{
PinosSpaAlsaSink *this = user_data;
PinosSpaAlsaSinkPrivate *priv = this->priv;
int r;
g_debug ("spa-alsa-sink %p: enter thread", this);
while (priv->running) {
SpaPollNotifyData ndata;
r = poll ((struct pollfd *) priv->fds, priv->n_fds, -1);
if (r < 0) {
if (errno == EINTR)
continue;
break;
}
if (r == 0) {
g_debug ("spa-alsa-sink %p: select timeout", this);
break;
}
if (priv->poll.after_cb) {
ndata.fds = priv->poll.fds;
ndata.n_fds = priv->poll.n_fds;
ndata.user_data = priv->poll.user_data;
priv->poll.after_cb (&ndata);
}
}
g_debug ("spa-alsa-sink %p: leave thread", this);
return NULL;
}
static void
on_sink_event (SpaNode *node, SpaEvent *event, void *user_data)
{
@ -167,7 +198,7 @@ on_sink_event (SpaNode *node, SpaEvent *event, void *user_data)
iinfo.size = total;
g_debug ("push sink %d", iinfo.buffer_id);
if ((res = spa_node_port_push_input (priv->sink, 1, &iinfo)) < 0)
if ((res = spa_node_port_push_input (node, 1, &iinfo)) < 0)
g_debug ("got error %d", res);
break;
}
@ -175,12 +206,21 @@ on_sink_event (SpaNode *node, SpaEvent *event, void *user_data)
case SPA_EVENT_TYPE_ADD_POLL:
{
SpaPollItem *poll = event->data;
int err;
g_debug ("add poll");
priv->poll = *poll;
priv->fds[0] = poll->fds[0];
priv->n_fds = 1;
priv->poll.fds = priv->fds;
if (!priv->running) {
priv->running = true;
if ((err = pthread_create (&priv->thread, NULL, loop, this)) != 0) {
g_debug ("spa-v4l2-source %p: can't create thread", strerror (err));
priv->running = false;
}
}
break;
}
@ -191,20 +231,16 @@ on_sink_event (SpaNode *node, SpaEvent *event, void *user_data)
}
static void
create_pipeline (PinosSpaAlsaSink *this)
setup_node (PinosSpaAlsaSink *this)
{
PinosSpaAlsaSinkPrivate *priv = this->priv;
PinosNode *node = PINOS_NODE (this);
SpaResult res;
SpaProps *props;
SpaPropValue value;
if ((res = make_node (&priv->sink, "spa/build/plugins/alsa/libspa-alsa.so", "alsa-sink")) < 0) {
g_error ("can't create alsa-sink: %d", res);
return;
}
spa_node_set_event_callback (priv->sink, on_sink_event, this);
spa_node_set_event_callback (node->node, on_sink_event, this);
if ((res = spa_node_get_props (priv->sink, &props)) < 0)
if ((res = spa_node_get_props (node->node, &props)) < 0)
g_debug ("got get_props error %d", res);
value.type = SPA_PROP_TYPE_STRING;
@ -212,67 +248,14 @@ create_pipeline (PinosSpaAlsaSink *this)
value.size = strlen (value.value)+1;
spa_props_set_prop (props, spa_props_index_for_name (props, "device"), &value);
if ((res = spa_node_set_props (priv->sink, props)) < 0)
if ((res = spa_node_set_props (node->node, props)) < 0)
g_debug ("got set_props error %d", res);
}
static void *
loop (void *user_data)
{
PinosSpaAlsaSink *this = user_data;
PinosSpaAlsaSinkPrivate *priv = this->priv;
int r;
g_debug ("spa-alsa-sink %p: enter thread", this);
while (priv->running) {
SpaPollNotifyData ndata;
r = poll ((struct pollfd *) priv->fds, priv->n_fds, -1);
if (r < 0) {
if (errno == EINTR)
continue;
break;
}
if (r == 0) {
g_debug ("spa-alsa-sink %p: select timeout", this);
break;
}
if (priv->poll.after_cb) {
ndata.fds = priv->poll.fds;
ndata.n_fds = priv->poll.n_fds;
ndata.user_data = priv->poll.user_data;
priv->poll.after_cb (&ndata);
}
}
g_debug ("spa-alsa-sink %p: leave thread", this);
return NULL;
}
static void
start_pipeline (PinosSpaAlsaSink *sink)
{
PinosSpaAlsaSinkPrivate *priv = sink->priv;
SpaResult res;
SpaCommand cmd;
int err;
g_debug ("spa-alsa-sink %p: starting pipeline", sink);
cmd.type = SPA_COMMAND_START;
if ((res = spa_node_send_command (priv->sink, &cmd)) < 0)
g_debug ("got error %d", res);
priv->running = true;
if ((err = pthread_create (&priv->thread, NULL, loop, sink)) != 0) {
g_debug ("spa-v4l2-source %p: can't create thread", strerror (err));
priv->running = false;
}
}
static void
stop_pipeline (PinosSpaAlsaSink *sink)
{
PinosNode *node = PINOS_NODE (sink);
PinosSpaAlsaSinkPrivate *priv = sink->priv;
SpaResult res;
SpaCommand cmd;
@ -285,7 +268,7 @@ stop_pipeline (PinosSpaAlsaSink *sink)
}
cmd.type = SPA_COMMAND_STOP;
if ((res = spa_node_send_command (priv->sink, &cmd)) < 0)
if ((res = spa_node_send_command (node->node, &cmd)) < 0)
g_debug ("got error %d", res);
}
@ -315,7 +298,6 @@ set_state (PinosNode *node,
break;
case PINOS_NODE_STATE_RUNNING:
start_pipeline (this);
break;
case PINOS_NODE_STATE_ERROR:
@ -378,47 +360,6 @@ free_sink_port_data (SinkPortData *data)
g_slice_free (SinkPortData, data);
}
static SpaResult
negotiate_formats (PinosSpaAlsaSink *this)
{
PinosSpaAlsaSinkPrivate *priv = this->priv;
SpaResult res;
SpaFormat *format;
SpaProps *props;
uint32_t val;
SpaPropValue value;
void *state = NULL;
if ((res = spa_node_port_enum_formats (priv->sink, 0, &format, NULL, &state)) < 0)
return res;
props = &format->props;
value.type = SPA_PROP_TYPE_UINT32;
value.size = sizeof (uint32_t);
value.value = &val;
val = SPA_AUDIO_FORMAT_S16LE;
if ((res = spa_props_set_prop (props, spa_props_index_for_id (props, SPA_PROP_ID_AUDIO_FORMAT), &value)) < 0)
return res;
val = SPA_AUDIO_LAYOUT_INTERLEAVED;
if ((res = spa_props_set_prop (props, spa_props_index_for_id (props, SPA_PROP_ID_AUDIO_LAYOUT), &value)) < 0)
return res;
val = 44100;
if ((res = spa_props_set_prop (props, spa_props_index_for_id (props, SPA_PROP_ID_AUDIO_RATE), &value)) < 0)
return res;
val = 2;
if ((res = spa_props_set_prop (props, spa_props_index_for_id (props, SPA_PROP_ID_AUDIO_CHANNELS), &value)) < 0)
return res;
if ((res = spa_node_port_set_format (priv->sink, 0, 0, format)) < 0)
return res;
priv->ringbuffer = pinos_ringbuffer_new (PINOS_RINGBUFFER_MODE_READ, 64 * 1024);
return SPA_RESULT_OK;
}
static void
free_mem_block (MemBlock *b)
{
@ -475,23 +416,6 @@ on_received_event (PinosPort *port,
return TRUE;
}
static void
on_format_change (GObject *obj,
GParamSpec *pspec,
gpointer user_data)
{
SinkPortData *data = user_data;
PinosNode *node = PINOS_NODE (data->sink);
PinosSpaAlsaSink *sink = PINOS_SPA_ALSA_SINK (node);
GBytes *formats;
g_object_get (obj, "format", &formats, NULL);
if (formats) {
g_debug ("port %p: format change %s", obj, (gchar*) g_bytes_get_data (formats, NULL));
negotiate_formats (sink);
}
}
static PinosPort *
add_port (PinosNode *node,
PinosDirection direction,
@ -501,7 +425,6 @@ add_port (PinosNode *node,
PinosSpaAlsaSink *sink = PINOS_SPA_ALSA_SINK (node);
PinosSpaAlsaSinkPrivate *priv = sink->priv;
SinkPortData *data;
GBytes *formats;
data = g_slice_new0 (SinkPortData);
data->sink = sink;
@ -511,15 +434,10 @@ add_port (PinosNode *node,
pinos_port_set_received_cb (data->port, on_received_buffer, on_received_event, sink, NULL);
formats = g_bytes_new ("ANY", strlen ("ANY") + 1);
g_object_set (data->port, "possible-formats", formats, NULL);
g_debug ("connecting signals");
g_signal_connect (data->port, "activate", (GCallback) on_activate, data);
g_signal_connect (data->port, "deactivate", (GCallback) on_deactivate, data);
g_signal_connect (data->port, "notify::format", (GCallback) on_format_change, data);
priv->ports = g_list_append (priv->ports, data);
return data->port;
@ -553,7 +471,7 @@ sink_constructed (GObject * object)
{
PinosSpaAlsaSink *sink = PINOS_SPA_ALSA_SINK (object);
create_pipeline (sink);
setup_node (sink);
G_OBJECT_CLASS (pinos_spa_alsa_sink_parent_class)->constructed (object);
}
@ -605,11 +523,21 @@ pinos_spa_alsa_sink_new (PinosDaemon *daemon,
PinosProperties *properties)
{
PinosNode *node;
SpaNode *n;
SpaResult res;
if ((res = make_node (&n,
"spa/build/plugins/alsa/libspa-alsa.so",
"alsa-sink")) < 0) {
g_error ("can't create v4l2-source: %d", res);
return NULL;
}
node = g_object_new (PINOS_TYPE_SPA_ALSA_SINK,
"daemon", daemon,
"name", name,
"properties", properties,
"node", n,
NULL);
return node;