summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWim Taymans <wtaymans@redhat.com>2016-10-25 11:15:15 +0200
committerWim Taymans <wtaymans@redhat.com>2016-10-25 11:21:53 +0200
commit4148e0ff78ee108b14c6041fb44c75cd26b7d3a7 (patch)
tree35eef8427a9c155fa890e11dadea7de1d088a7f2
parent73e627248885419bfb7ef0cc2052ba3daaef6036 (diff)
cleanups:
Keep lock while doing recycle_buffer Pass context to main loop Recycle WorkItems in a free list Push and pull from the node data loop Do async start/pause in alsa Add alsa fds right after open.
-rw-r--r--pinos/client/connection.c2
-rw-r--r--pinos/gst/gstpinossrc.c2
-rw-r--r--pinos/server/daemon.c3
-rw-r--r--pinos/server/data-loop.c20
-rw-r--r--pinos/server/data-loop.h2
-rw-r--r--pinos/server/main-loop.c105
-rw-r--r--pinos/server/main-loop.h5
-rw-r--r--pinos/server/node.c51
-rw-r--r--spa/plugins/alsa/alsa-sink.c2
-rw-r--r--spa/plugins/alsa/alsa-source.c126
-rw-r--r--spa/plugins/alsa/alsa-utils.c73
-rw-r--r--spa/plugins/alsa/alsa-utils.h10
12 files changed, 313 insertions, 88 deletions
diff --git a/pinos/client/connection.c b/pinos/client/connection.c
index eb92d315..3411cf6b 100644
--- a/pinos/client/connection.c
+++ b/pinos/client/connection.c
@@ -156,8 +156,8 @@ connection_ensure_size (PinosConnection *conn, ConnectionBuffer *buf, size_t siz
{
if (buf->buffer_size + size > buf->buffer_maxsize) {
buf->buffer_maxsize = buf->buffer_size + MAX_BUFFER_SIZE * ((size + MAX_BUFFER_SIZE-1) / MAX_BUFFER_SIZE);
- buf->buffer_data = realloc (buf->buffer_data, buf->buffer_maxsize);
g_debug ("connection %p: resize buffer to %zd", conn, buf->buffer_maxsize);
+ buf->buffer_data = realloc (buf->buffer_data, buf->buffer_maxsize);
}
return (uint8_t *) buf->buffer_data + buf->buffer_size;
}
diff --git a/pinos/gst/gstpinossrc.c b/pinos/gst/gstpinossrc.c
index b033b5a0..1e6d17c3 100644
--- a/pinos/gst/gstpinossrc.c
+++ b/pinos/gst/gstpinossrc.c
@@ -354,7 +354,9 @@ buffer_recycle (GstMiniObject *obj)
src = data->src;
GST_LOG_OBJECT (obj, "recycle buffer");
+ pinos_thread_main_loop_lock (src->loop);
pinos_stream_recycle_buffer (src->stream, data->id);
+ pinos_thread_main_loop_unlock (src->loop);
return FALSE;
}
diff --git a/pinos/server/daemon.c b/pinos/server/daemon.c
index bd72f80e..0d4901ec 100644
--- a/pinos/server/daemon.c
+++ b/pinos/server/daemon.c
@@ -990,7 +990,8 @@ pinos_daemon_init (PinosDaemon * daemon)
g_str_equal,
g_free,
g_object_unref);
- daemon->main_loop = pinos_main_loop_new();
+
+ daemon->main_loop = pinos_main_loop_new (g_main_context_get_thread_default ());
priv->data_loop = pinos_data_loop_new();
diff --git a/pinos/server/data-loop.c b/pinos/server/data-loop.c
index dabf627f..59fae193 100644
--- a/pinos/server/data-loop.c
+++ b/pinos/server/data-loop.c
@@ -106,7 +106,6 @@ loop (void *user_data)
/* rebuild */
if (priv->rebuild_fds) {
- g_debug ("data-loop %p: rebuild fds", this);
priv->n_fds = 1;
for (i = 0; i < priv->n_poll; i++) {
SpaPollItem *p = &priv->poll[i];
@@ -142,7 +141,7 @@ loop (void *user_data)
break;
}
if (r == 0) {
- g_debug ("data-loop %p: select timeout should not happen", this);
+ g_warning ("data-loop %p: select timeout should not happen", this);
continue;
}
@@ -226,10 +225,8 @@ do_add_item (SpaPoll *poll,
PinosDataLoop *this = SPA_CONTAINER_OF (poll, PinosDataLoop, poll);
PinosDataLoopPrivate *priv = this->priv;
gboolean in_thread = pthread_equal (priv->thread, pthread_self());
- unsigned int i;
item->id = ++priv->counter;
- g_debug ("data-loop %p: %d: add pollid %d, n_poll %d, n_fds %d", this, in_thread, item->id, priv->n_poll, item->n_fds);
priv->poll[priv->n_poll] = *item;
priv->n_poll++;
if (item->n_fds)
@@ -239,10 +236,6 @@ do_add_item (SpaPoll *poll,
wakeup_thread (this);
start_thread (this);
}
- for (i = 0; i < priv->n_poll; i++) {
- if (priv->poll[i].n_fds > 0)
- g_debug ("poll %d: %d %d", i, priv->poll[i].id, priv->poll[i].fds[0].fd);
- }
return SPA_RESULT_OK;
}
@@ -278,7 +271,6 @@ do_remove_item (SpaPoll *poll,
gboolean in_thread = pthread_equal (priv->thread, pthread_self());
unsigned int i;
- g_debug ("data-loop %p: %d: remove poll %d %d", this, item->id, item->n_fds, priv->n_poll);
for (i = 0; i < priv->n_poll; i++) {
if (priv->poll[i].id == item->id) {
priv->n_poll--;
@@ -295,10 +287,6 @@ do_remove_item (SpaPoll *poll,
if (priv->n_poll == 0) {
stop_thread (this, in_thread);
}
- for (i = 0; i < priv->n_poll; i++) {
- if (priv->poll[i].n_fds > 0)
- g_debug ("poll %d: %d %d", i, priv->poll[i].id, priv->poll[i].fds[0].fd);
- }
return SPA_RESULT_OK;
}
@@ -432,3 +420,9 @@ pinos_data_loop_new (void)
{
return g_object_new (PINOS_TYPE_DATA_LOOP, NULL);
}
+
+gboolean
+pinos_data_loop_in_thread (PinosDataLoop *loop)
+{
+ return pthread_equal (loop->priv->thread, pthread_self());
+}
diff --git a/pinos/server/data-loop.h b/pinos/server/data-loop.h
index f70c0cd3..3f3a26f0 100644
--- a/pinos/server/data-loop.h
+++ b/pinos/server/data-loop.h
@@ -67,6 +67,8 @@ GType pinos_data_loop_get_type (void);
PinosDataLoop * pinos_data_loop_new (void);
+gboolean pinos_data_loop_in_thread (PinosDataLoop *loop);
+
G_END_DECLS
#endif /* __PINOS_DATA_LOOP_H__ */
diff --git a/pinos/server/main-loop.c b/pinos/server/main-loop.c
index c0abed2b..daa7122c 100644
--- a/pinos/server/main-loop.c
+++ b/pinos/server/main-loop.c
@@ -58,6 +58,9 @@ struct _WorkItem {
struct _PinosMainLoopPrivate
{
+ GMainContext *context;
+ GMainLoop *loop;
+
gulong counter;
SpaRingbuffer buffer;
@@ -77,6 +80,7 @@ G_DEFINE_TYPE (PinosMainLoop, pinos_main_loop, G_TYPE_OBJECT);
enum
{
PROP_0,
+ PROP_MAIN_CONTEXT,
};
enum
@@ -226,12 +230,54 @@ do_invoke (SpaPoll *poll,
}
static void
+pinos_main_loop_get_property (GObject *_object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ PinosMainLoop *loop = PINOS_MAIN_LOOP (_object);
+ PinosMainLoopPrivate *priv = loop->priv;
+
+ switch (prop_id) {
+ case PROP_MAIN_CONTEXT:
+ g_value_set_boxed (value, priv->context);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (loop, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+pinos_main_loop_set_property (GObject *_object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ PinosMainLoop *loop = PINOS_MAIN_LOOP (_object);
+ PinosMainLoopPrivate *priv = loop->priv;
+
+ switch (prop_id) {
+ case PROP_MAIN_CONTEXT:
+ priv->context = g_value_dup_boxed (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (loop, prop_id, pspec);
+ break;
+ }
+}
+
+
+static void
pinos_main_loop_constructed (GObject * obj)
{
PinosMainLoop *this = PINOS_MAIN_LOOP (obj);
PinosMainLoopPrivate *priv = this->priv;
g_debug ("main-loop %p: constructed", this);
+ priv->loop = g_main_loop_new (priv->context, FALSE);
priv->fds[0].fd = eventfd (0, 0);
priv->fds[0].events = POLLIN | POLLPRI | POLLERR;
@@ -264,9 +310,12 @@ static void
pinos_main_loop_finalize (GObject * obj)
{
PinosMainLoop *this = PINOS_MAIN_LOOP (obj);
+ PinosMainLoopPrivate *priv = this->priv;
g_debug ("main-loop %p: finalize", this);
+ g_slice_free_chain (WorkItem, priv->free_list, next);
+
G_OBJECT_CLASS (pinos_main_loop_parent_class)->finalize (obj);
}
@@ -280,6 +329,19 @@ pinos_main_loop_class_init (PinosMainLoopClass * klass)
gobject_class->constructed = pinos_main_loop_constructed;
gobject_class->dispose = pinos_main_loop_dispose;
gobject_class->finalize = pinos_main_loop_finalize;
+ gobject_class->set_property = pinos_main_loop_set_property;
+ gobject_class->get_property = pinos_main_loop_get_property;
+
+ g_object_class_install_property (gobject_class,
+ PROP_MAIN_CONTEXT,
+ g_param_spec_boxed ("main-context",
+ "Main Context",
+ "The main context to use",
+ G_TYPE_MAIN_CONTEXT,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
}
static void
@@ -302,15 +364,18 @@ pinos_main_loop_init (PinosMainLoop * this)
/**
* pinos_main_loop_new:
+ * @context: a #GMainContext or %NULL to use the default context
*
* Create a new #PinosMainLoop.
*
* Returns: a new #PinosMainLoop
*/
PinosMainLoop *
-pinos_main_loop_new (void)
+pinos_main_loop_new (GMainContext *context)
{
- return g_object_new (PINOS_TYPE_MAIN_LOOP, NULL);
+ return g_object_new (PINOS_TYPE_MAIN_LOOP,
+ "main-context", context,
+ NULL);
}
static gboolean
@@ -340,7 +405,10 @@ process_work_queue (PinosMainLoop *this)
item->func (item->obj, item->data, item->res, item->id);
if (item->notify)
item->notify (item->data);
- g_slice_free (WorkItem, item);
+
+ item->next = priv->free_list;
+ priv->free_list = item;
+
item = prev;
}
return FALSE;
@@ -361,7 +429,12 @@ pinos_main_loop_defer (PinosMainLoop *loop,
g_return_val_if_fail (PINOS_IS_MAIN_LOOP (loop), 0);
priv = loop->priv;
- item = g_slice_new (WorkItem);
+ if (priv->free_list) {
+ item = priv->free_list;
+ priv->free_list = item->next;
+ } else {
+ item = g_slice_new (WorkItem);
+ }
item->id = ++priv->counter;
item->obj = obj;
item->func = func;
@@ -440,3 +513,27 @@ pinos_main_loop_defer_complete (PinosMainLoop *loop,
if (priv->work_id == 0 && have_work)
priv->work_id = g_idle_add ((GSourceFunc) process_work_queue, loop);
}
+
+GMainLoop *
+pinos_main_loop_get_impl (PinosMainLoop *loop)
+{
+ g_return_val_if_fail (PINOS_IS_MAIN_LOOP (loop), NULL);
+
+ return loop->priv->loop;
+}
+
+void
+pinos_main_loop_quit (PinosMainLoop *loop)
+{
+ g_return_if_fail (PINOS_IS_MAIN_LOOP (loop));
+
+ g_main_loop_quit (loop->priv->loop);
+}
+
+void
+pinos_main_loop_run (PinosMainLoop *loop)
+{
+ g_return_if_fail (PINOS_IS_MAIN_LOOP (loop));
+
+ g_main_loop_run (loop->priv->loop);
+}
diff --git a/pinos/server/main-loop.h b/pinos/server/main-loop.h
index 65d6b624..b480fc83 100644
--- a/pinos/server/main-loop.h
+++ b/pinos/server/main-loop.h
@@ -70,8 +70,11 @@ typedef void (*PinosDeferFunc) (gpointer obj,
/* normal GObject stuff */
GType pinos_main_loop_get_type (void);
-PinosMainLoop * pinos_main_loop_new (void);
+PinosMainLoop * pinos_main_loop_new (GMainContext *context);
+GMainLoop * pinos_main_loop_get_impl (PinosMainLoop *loop);
+void pinos_main_loop_run (PinosMainLoop *loop);
+void pinos_main_loop_quit (PinosMainLoop *loop);
gulong pinos_main_loop_defer (PinosMainLoop *loop,
gpointer obj,
diff --git a/pinos/server/node.c b/pinos/server/node.c
index 34313ade..981a2271 100644
--- a/pinos/server/node.c
+++ b/pinos/server/node.c
@@ -327,37 +327,40 @@ send_clock_update (PinosNode *this)
g_debug ("got error %d", res);
}
-static gboolean
-do_read_link (PinosNode *this, PinosLink *link)
+static SpaResult
+do_read_link (SpaPoll *poll,
+ bool async,
+ uint32_t seq,
+ size_t size,
+ void *data,
+ void *user_data)
{
- SpaRingbufferArea areas[2];
+ PinosNode *this = user_data;
+ PinosLink *link = ((PinosLink**)data)[0];
+ size_t offset;
SpaResult res;
- gboolean pushed = FALSE;
- spa_ringbuffer_get_read_areas (&link->ringbuffer, areas);
-
- if (areas[0].len > 0) {
+ if (spa_ringbuffer_get_read_offset (&link->ringbuffer, &offset) > 0) {
SpaPortInputInfo iinfo[1];
if (link->in_ready <= 0 || link->input == NULL)
- return FALSE;
+ return SPA_RESULT_OK;
link->in_ready--;
iinfo[0].port_id = link->input->port;
- iinfo[0].buffer_id = link->queue[areas[0].offset];
+ iinfo[0].buffer_id = link->queue[offset];
iinfo[0].flags = SPA_PORT_INPUT_FLAG_NONE;
if ((res = spa_node_port_push_input (link->input->node->node, 1, iinfo)) < 0)
g_warning ("node %p: error pushing buffer: %d, %d", this, res, iinfo[0].status);
- else
- pushed = TRUE;
spa_ringbuffer_read_advance (&link->ringbuffer, 1);
}
- return pushed;
+ return SPA_RESULT_OK;
}
+
static void
on_node_event (SpaNode *node, SpaNodeEvent *event, void *user_data)
{
@@ -393,7 +396,12 @@ on_node_event (SpaNode *node, SpaNodeEvent *event, void *user_data)
continue;
link->in_ready++;
- do_read_link (this, link);
+ spa_poll_invoke (&link->input->node->priv->data_loop->poll,
+ do_read_link,
+ SPA_ID_INVALID,
+ sizeof (PinosLink *),
+ &link,
+ link->input->node);
}
break;
}
@@ -414,17 +422,22 @@ on_node_event (SpaNode *node, SpaNodeEvent *event, void *user_data)
for (i = 0; i < priv->rt.links->len; i++) {
PinosLink *link = g_ptr_array_index (priv->rt.links, i);
- SpaRingbufferArea areas[2];
+ size_t offset;
if (link->output == NULL || link->output->port != ho->port_id)
continue;
- spa_ringbuffer_get_write_areas (&link->ringbuffer, areas);
- if (areas[0].len > 0) {
- link->queue[areas[0].offset] = oinfo[0].buffer_id;
+ if (spa_ringbuffer_get_write_offset (&link->ringbuffer, &offset) > 0) {
+ link->queue[offset] = oinfo[0].buffer_id;
spa_ringbuffer_write_advance (&link->ringbuffer, 1);
- pushed = do_read_link (this, link);
+ spa_poll_invoke (&link->input->node->priv->data_loop->poll,
+ do_read_link,
+ SPA_ID_INVALID,
+ sizeof (PinosLink *),
+ &link,
+ link->input->node);
+ pushed = TRUE;
}
}
if (!pushed) {
@@ -443,7 +456,7 @@ on_node_event (SpaNode *node, SpaNodeEvent *event, void *user_data)
for (i = 0; i < priv->rt.links->len; i++) {
PinosLink *link = g_ptr_array_index (priv->rt.links, i);
- if (link->output == NULL || link->output->port != rb->port_id)
+ if (link->input == NULL || link->input->port != rb->port_id)
continue;
if ((res = spa_node_port_reuse_buffer (link->output->node->node,
diff --git a/spa/plugins/alsa/alsa-sink.c b/spa/plugins/alsa/alsa-sink.c
index c4324864..4274e444 100644
--- a/spa/plugins/alsa/alsa-sink.c
+++ b/spa/plugins/alsa/alsa-sink.c
@@ -170,7 +170,7 @@ spa_alsa_sink_node_send_command (SpaNode *node,
update_state (this, SPA_NODE_STATE_STREAMING);
break;
case SPA_NODE_COMMAND_PAUSE:
- spa_alsa_stop (this);
+ spa_alsa_pause (this);
update_state (this, SPA_NODE_STATE_PAUSED);
break;
diff --git a/spa/plugins/alsa/alsa-source.c b/spa/plugins/alsa/alsa-source.c
index 63b89d46..7fdc025b 100644
--- a/spa/plugins/alsa/alsa-source.c
+++ b/spa/plugins/alsa/alsa-source.c
@@ -38,8 +38,8 @@ update_state (SpaALSASource *this, SpaNodeState state)
}
static const char default_device[] = "hw:0";
-static const uint32_t default_buffer_time = 100000;
-static const uint32_t default_period_time = 10000;
+static const uint32_t default_buffer_time = 1000;
+static const uint32_t default_period_time = 100;
static const bool default_period_event = 0;
static void
@@ -152,8 +152,85 @@ spa_alsa_source_node_set_props (SpaNode *node,
}
static SpaResult
+do_send_event (SpaPoll *poll,
+ bool async,
+ uint32_t seq,
+ size_t size,
+ void *data,
+ void *user_data)
+{
+ SpaALSASource *this = user_data;
+
+ this->event_cb (&this->node, data, this->user_data);
+
+ return SPA_RESULT_OK;
+}
+
+static SpaResult
+do_start (SpaPoll *poll,
+ bool async,
+ uint32_t seq,
+ size_t size,
+ void *data,
+ void *user_data)
+{
+ SpaALSASource *this = user_data;
+ SpaResult res;
+ SpaNodeEventAsyncComplete ac;
+
+ if (SPA_RESULT_IS_OK (res = spa_alsa_start (this))) {
+ update_state (this, SPA_NODE_STATE_STREAMING);
+ }
+
+ if (async) {
+ ac.event.type = SPA_NODE_EVENT_TYPE_ASYNC_COMPLETE;
+ ac.event.size = sizeof (SpaNodeEventAsyncComplete);
+ ac.seq = seq;
+ ac.res = res;
+ spa_poll_invoke (this->main_loop,
+ do_send_event,
+ SPA_ID_INVALID,
+ sizeof (ac),
+ &ac,
+ this);
+ }
+ return res;
+}
+
+static SpaResult
+do_pause (SpaPoll *poll,
+ bool async,
+ uint32_t seq,
+ size_t size,
+ void *data,
+ void *user_data)
+{
+ SpaALSASource *this = user_data;
+ SpaResult res;
+ SpaNodeEventAsyncComplete ac;
+
+ if (SPA_RESULT_IS_OK (res = spa_alsa_pause (this))) {
+ update_state (this, SPA_NODE_STATE_PAUSED);
+ }
+
+ if (async) {
+ ac.event.type = SPA_NODE_EVENT_TYPE_ASYNC_COMPLETE;
+ ac.event.size = sizeof (SpaNodeEventAsyncComplete);
+ ac.seq = seq;
+ ac.res = res;
+ spa_poll_invoke (this->main_loop,
+ do_send_event,
+ SPA_ID_INVALID,
+ sizeof (ac),
+ &ac,
+ this);
+ }
+ return res;
+}
+
+static SpaResult
spa_alsa_source_node_send_command (SpaNode *node,
- SpaNodeCommand *command)
+ SpaNodeCommand *command)
{
SpaALSASource *this;
@@ -167,17 +244,36 @@ spa_alsa_source_node_send_command (SpaNode *node,
return SPA_RESULT_INVALID_COMMAND;
case SPA_NODE_COMMAND_START:
- if (spa_alsa_start (this) < 0)
- return SPA_RESULT_ERROR;
+ {
+ if (!this->have_format)
+ return SPA_RESULT_NO_FORMAT;
- update_state (this, SPA_NODE_STATE_STREAMING);
- break;
- case SPA_NODE_COMMAND_PAUSE:
- if (spa_alsa_stop (this) < 0)
- return SPA_RESULT_ERROR;
+ if (this->n_buffers == 0)
+ return SPA_RESULT_NO_BUFFERS;
- update_state (this, SPA_NODE_STATE_PAUSED);
- break;
+ return spa_poll_invoke (this->data_loop,
+ do_start,
+ ++this->seq,
+ 0,
+ NULL,
+ this);
+
+ }
+ case SPA_NODE_COMMAND_PAUSE:
+ {
+ if (!this->have_format)
+ return SPA_RESULT_NO_FORMAT;
+
+ if (this->n_buffers == 0)
+ return SPA_RESULT_NO_BUFFERS;
+
+ return spa_poll_invoke (this->data_loop,
+ do_pause,
+ ++this->seq,
+ 0,
+ NULL,
+ this);
+ }
case SPA_NODE_COMMAND_FLUSH:
case SPA_NODE_COMMAND_DRAIN:
case SPA_NODE_COMMAND_MARKER:
@@ -345,8 +441,10 @@ spa_alsa_source_node_port_set_format (SpaNode *node,
return SPA_RESULT_INVALID_PORT;
if (format == NULL) {
- this->have_format = false;
+ spa_alsa_pause (this);
spa_alsa_clear_buffers (this);
+ spa_alsa_close (this);
+ this->have_format = false;
update_state (this, SPA_NODE_STATE_CONFIGURE);
return SPA_RESULT_OK;
}
@@ -768,6 +866,8 @@ alsa_source_init (const SpaHandleFactory *factory,
this->log = support[i].data;
else if (strcmp (support[i].uri, SPA_POLL__DataLoop) == 0)
this->data_loop = support[i].data;
+ else if (strcmp (support[i].uri, SPA_POLL__MainLoop) == 0)
+ this->main_loop = support[i].data;
}
if (this->map == NULL) {
spa_log_error (this->log, "an id-map is needed");
diff --git a/spa/plugins/alsa/alsa-utils.c b/spa/plugins/alsa/alsa-utils.c
index 258e6d01..1f3446e3 100644
--- a/spa/plugins/alsa/alsa-utils.c
+++ b/spa/plugins/alsa/alsa-utils.c
@@ -11,6 +11,8 @@
#define CHECK(s,msg) if ((err = (s)) < 0) { spa_log_error (state->log, msg ": %s\n", snd_strerror(err)); return err; }
+static int alsa_on_fd_events (SpaPollNotifyData *data);
+
static int
spa_alsa_open (SpaALSAState *state)
{
@@ -31,12 +33,30 @@ spa_alsa_open (SpaALSAState *state)
SND_PCM_NO_AUTO_CHANNELS |
SND_PCM_NO_AUTO_FORMAT), "open failed");
+ if ((state->poll.n_fds = snd_pcm_poll_descriptors_count (state->hndl)) <= 0) {
+ spa_log_error (state->log, "Invalid poll descriptors count %d\n", state->poll.n_fds);
+ return SPA_RESULT_ERROR;
+ }
+ if ((err = snd_pcm_poll_descriptors (state->hndl, (struct pollfd *)state->fds, state->poll.n_fds)) < 0) {
+ spa_log_error (state->log, "Unable to obtain poll descriptors for playback: %s\n", snd_strerror(err));
+ return SPA_RESULT_ERROR;
+ }
+
+ state->poll.id = 0;
+ state->poll.enabled = false;
+ state->poll.fds = state->fds;
+ state->poll.idle_cb = NULL;
+ state->poll.before_cb = NULL;
+ state->poll.after_cb = alsa_on_fd_events;
+ state->poll.user_data = state;
+ spa_poll_add_item (state->data_loop, &state->poll);
+
state->opened = true;
return 0;
}
-static int
+int
spa_alsa_close (SpaALSAState *state)
{
int err = 0;
@@ -44,7 +64,9 @@ spa_alsa_close (SpaALSAState *state)
if (!state->opened)
return 0;
- spa_log_info (state->log, "Playback device closing\n");
+ spa_poll_remove_item (state->data_loop, &state->poll);
+
+ spa_log_info (state->log, "Device closing\n");
CHECK (snd_pcm_close (state->hndl), "close failed");
state->opened = false;
@@ -426,54 +448,41 @@ alsa_on_fd_events (SpaPollNotifyData *data)
return 0;
}
-int
+SpaResult
spa_alsa_start (SpaALSAState *state)
{
int err;
- if (spa_alsa_open (state) < 0)
- return -1;
-
- if (state->n_buffers == 0)
- return -1;
+ if (state->started)
+ return SPA_RESULT_OK;
CHECK (set_swparams (state), "swparams");
-
snd_pcm_dump (state->hndl, state->output);
- if ((state->poll.n_fds = snd_pcm_poll_descriptors_count (state->hndl)) <= 0) {
- spa_log_error (state->log, "Invalid poll descriptors count\n");
- return state->poll.n_fds;
- }
- if ((err = snd_pcm_poll_descriptors (state->hndl, (struct pollfd *)state->fds, state->poll.n_fds)) < 0) {
- spa_log_error (state->log, "Unable to obtain poll descriptors for playback: %s\n", snd_strerror(err));
- return err;
+ if (state->stream == SND_PCM_STREAM_PLAYBACK) {
+ mmap_write (state);
}
- state->poll.id = 0;
state->poll.enabled = true;
- state->poll.fds = state->fds;
- state->poll.idle_cb = NULL;
- state->poll.before_cb = NULL;
- state->poll.after_cb = alsa_on_fd_events;
- state->poll.user_data = state;
- spa_poll_add_item (state->data_loop, &state->poll);
+ spa_poll_update_item (state->data_loop, &state->poll);
- mmap_write (state);
err = snd_pcm_start (state->hndl);
+ state->started = true;
- return err;
+ return SPA_RESULT_OK;
}
-int
-spa_alsa_stop (SpaALSAState *state)
+SpaResult
+spa_alsa_pause (SpaALSAState *state)
{
- if (!state->opened)
- return 0;
+ if (!state->started)
+ return SPA_RESULT_OK;
+
+ state->poll.enabled = false;
+ spa_poll_update_item (state->data_loop, &state->poll);
- spa_poll_remove_item (state->data_loop, &state->poll);
snd_pcm_drop (state->hndl);
- spa_alsa_close (state);
+ state->started = false;
- return 0;
+ return SPA_RESULT_OK;
}
diff --git a/spa/plugins/alsa/alsa-utils.h b/spa/plugins/alsa/alsa-utils.h
index d98077a2..26d0a9bd 100644
--- a/spa/plugins/alsa/alsa-utils.h
+++ b/spa/plugins/alsa/alsa-utils.h
@@ -66,9 +66,12 @@ struct _SpaALSAState {
SpaNode node;
SpaClock clock;
+ uint32_t seq;
+
URI uri;
SpaIDMap *map;
SpaLog *log;
+ SpaPoll *main_loop;
SpaPoll *data_loop;
snd_pcm_stream_t stream;
@@ -104,7 +107,7 @@ struct _SpaALSAState {
SpaQueue free;
SpaQueue ready;
- bool running;
+ bool started;
SpaPollFd fds[16];
SpaPollItem poll;
@@ -117,8 +120,9 @@ int spa_alsa_set_format (SpaALSAState *state,
SpaFormatAudio *fmt,
SpaPortFormatFlags flags);
-int spa_alsa_start (SpaALSAState *state);
-int spa_alsa_stop (SpaALSAState *state);
+SpaResult spa_alsa_start (SpaALSAState *state);
+SpaResult spa_alsa_pause (SpaALSAState *state);
+SpaResult spa_alsa_close (SpaALSAState *state);
#ifdef __cplusplus
} /* extern "C" */