diff --git a/doc/design.txt b/doc/design.txt index f7c3b8e8b..26ed958e9 100644 --- a/doc/design.txt +++ b/doc/design.txt @@ -395,7 +395,7 @@ communication channel node-update port-update - state-configure + state change CONFIGURE 2) Set formats S->C CONFIGURE @@ -409,7 +409,7 @@ communication channel 3) Buffer requirements update C->S Update port status - state-ready if enough formats are set + state change READY if enough formats are set 4) Start S->C READY @@ -418,43 +418,39 @@ communication channel remove_mem add_buffer remove_buffer - start->streaming + command START/PAUSE -5) Pause S->C STREAMING +5) Pause S->C PAUSED - stop-streaming + state change STREAMING + set-format to NULL -> state change to CONFIGURE -5) data transfer C->S +5) data transfer C->S STREAMING need-input have-output - add_mem - add_buffer process_buffer reuse_buffer - remove_buffer - remove_mem + state change PAUSED 6) data transfer S->C - add_mem - add_buffer process_buffer reuse_buffer - remove_buffer - remove_mem 7) format change C->S port-update - state-configure + state change CONFIGURE 8) format change S->C Send set-format change on ports -> READY if new memory requirements - -> RUNNING if all ok + -> PAUSED/STREAMING if all ok -9) format-change to NULL -> CONFIGURE +9) format-change to NULL + + state change CONFIGURE 10) ERROR diff --git a/pinos/client/introspect.h b/pinos/client/introspect.h index 42fad9863..70fdde2ce 100644 --- a/pinos/client/introspect.h +++ b/pinos/client/introspect.h @@ -57,9 +57,9 @@ const gchar * pinos_node_state_as_string (PinosNodeState state); * The direction of a port */ typedef enum { - PINOS_DIRECTION_INVALID = -1, - PINOS_DIRECTION_INPUT = 0, - PINOS_DIRECTION_OUTPUT = 1 + PINOS_DIRECTION_INVALID = 0, + PINOS_DIRECTION_INPUT = 1, + PINOS_DIRECTION_OUTPUT = 2 } PinosDirection; const gchar * pinos_direction_as_string (PinosDirection direction); diff --git a/pinos/client/stream.c b/pinos/client/stream.c index 54f9204ab..fd48efc7c 100644 --- a/pinos/client/stream.c +++ b/pinos/client/stream.c @@ -58,7 +58,7 @@ typedef struct { static void clear_buffer_id (BufferId *id) { - spa_buffer_unref (id->buf); + free (id->buf); id->buf = NULL; } @@ -519,21 +519,31 @@ pinos_stream_get_error (PinosStream *stream) } static void -send_need_input (PinosStream *stream, uint32_t port) +send_need_input (PinosStream *stream, uint32_t port_id, uint32_t buffer_id) { PinosStreamPrivate *priv = stream->priv; SpaControlBuilder builder; SpaControl control; guint8 buffer[64]; SpaControlCmdNeedInput ni; + SpaControlCmdReuseBuffer rb; spa_control_builder_init_into (&builder, buffer, 64, NULL, 0); - ni.port = port; + if (buffer_id != SPA_ID_INVALID) { + rb.port_id = port_id; + rb.buffer_id = buffer_id; + rb.offset = 0; + rb.size = -1; + spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_REUSE_BUFFER, &rb); + } + ni.port_id = port_id; spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_NEED_INPUT, &ni); spa_control_builder_end (&builder, &control); if (spa_control_write (&control, priv->fd) < 0) g_warning ("stream %p: error writing control", stream); + + spa_control_clear (&control); } static BufferId * @@ -577,9 +587,8 @@ parse_control (PinosStream *stream, case SPA_CONTROL_CMD_NODE_UPDATE: case SPA_CONTROL_CMD_PORT_UPDATE: case SPA_CONTROL_CMD_PORT_REMOVED: - case SPA_CONTROL_CMD_START_CONFIGURE: + case SPA_CONTROL_CMD_STATE_CHANGE: case SPA_CONTROL_CMD_PORT_STATUS_CHANGE: - case SPA_CONTROL_CMD_START_ALLOC: case SPA_CONTROL_CMD_NEED_INPUT: case SPA_CONTROL_CMD_HAVE_OUTPUT: g_warning ("got unexpected control %d", cmd); @@ -593,30 +602,31 @@ parse_control (PinosStream *stream, case SPA_CONTROL_CMD_SET_FORMAT: { SpaControlCmdSetFormat p; + SpaControlBuilder builder; + SpaControl control; + SpaControlCmdStateChange sc; + guint8 buffer[1024]; + const gchar *str; if (spa_control_iter_parse_cmd (&it, &p) < 0) break; if (priv->format) g_bytes_unref (priv->format); - priv->format = g_bytes_new (p.str, strlen (p.str) + 1); + str = "video/x-raw," + " format=(string)YUY2," + " width=(int)320," + " height=(int)240," + " framerate=(fraction)30/1"; + priv->format = g_bytes_new_static (str, strlen (str)+1); g_object_notify (G_OBJECT (stream), "format"); - break; - } - case SPA_CONTROL_CMD_SET_PROPERTY: - g_warning ("set property not implemented"); - break; - - case SPA_CONTROL_CMD_END_CONFIGURE: - { - SpaControlBuilder builder; - SpaControl control; - guint8 buffer[1024]; /* FIXME send update port status */ - /* send start-alloc */ + + /* send state-change */ spa_control_builder_init_into (&builder, buffer, 1024, NULL, 0); - spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_START_ALLOC, NULL); + sc.state = SPA_NODE_STATE_READY; + spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_STATE_CHANGE, &sc); spa_control_builder_end (&builder, &control); if (spa_control_write (&control, priv->fd) < 0) @@ -624,19 +634,23 @@ parse_control (PinosStream *stream, break; } - - case SPA_CONTROL_CMD_PAUSE: + case SPA_CONTROL_CMD_SET_PROPERTY: + g_warning ("set property not implemented"); break; + case SPA_CONTROL_CMD_START: { + g_debug ("stream %p: start", stream); + if (priv->direction == PINOS_DIRECTION_INPUT) - send_need_input (stream, 0); + send_need_input (stream, 0, SPA_ID_INVALID); stream_set_state (stream, PINOS_STREAM_STATE_STREAMING, NULL); break; } case SPA_CONTROL_CMD_STOP: { + g_debug ("stream %p: stop", stream); stream_set_state (stream, PINOS_STREAM_STATE_READY, NULL); break; } @@ -654,8 +668,9 @@ parse_control (PinosStream *stream, if (fd == -1) break; + g_debug ("add mem %d, %d", p.mem_id, fd); mid.cleanup = false; - mid.id = p.id; + mid.id = p.mem_id; mid.fd = fd; g_array_append_val (priv->mem_ids, mid); break; @@ -668,7 +683,8 @@ parse_control (PinosStream *stream, if (spa_control_iter_parse_cmd (&it, &p) < 0) break; - if ((mid = find_mem (stream, p.id))) + g_debug ("stream %p: stop", stream); + if ((mid = find_mem (stream, p.mem_id))) mid->cleanup = true; break; } @@ -680,6 +696,7 @@ parse_control (PinosStream *stream, if (spa_control_iter_parse_cmd (&it, &p) < 0) break; + g_debug ("add buffer %d", p.buffer->id); bid.cleanup = false; bid.id = p.buffer->id; bid.buf = p.buffer; @@ -694,7 +711,8 @@ parse_control (PinosStream *stream, if (spa_control_iter_parse_cmd (&it, &p) < 0) break; - if ((bid = find_buffer (stream, p.id))) + g_debug ("remove buffer %d", p.buffer_id); + if ((bid = find_buffer (stream, p.buffer_id))) bid->cleanup = true; break; } @@ -707,7 +725,8 @@ parse_control (PinosStream *stream, if (spa_control_iter_parse_cmd (&it, &p) < 0) break; - if ((bid = find_buffer (stream, p.id))) { + g_debug ("process buffer %d", p.buffer_id); + if ((bid = find_buffer (stream, p.buffer_id))) { SpaBuffer *b = bid->buf; for (i = 0; i < b->n_datas; i++) { @@ -728,7 +747,15 @@ parse_control (PinosStream *stream, break; } case SPA_CONTROL_CMD_REUSE_BUFFER: + { + SpaControlCmdReuseBuffer p; + + if (spa_control_iter_parse_cmd (&it, &p) < 0) + break; + + g_debug ("reuse buffer %d", p.buffer_id); break; + } case SPA_CONTROL_CMD_INVALID: g_warning ("unhandled command %d", cmd); @@ -768,8 +795,8 @@ on_socket_condition (GSocket *socket, if (priv->buffer) { g_signal_emit (stream, signals[SIGNAL_NEW_BUFFER], 0, NULL); + send_need_input (stream, 0, priv->buffer->id); priv->buffer = NULL; - send_need_input (stream, 0); } for (i = 0; i < priv->mem_ids->len; i++) { MemId *mid = &g_array_index (priv->mem_ids, MemId, i); @@ -1051,16 +1078,18 @@ do_start (PinosStream *stream) PinosStreamPrivate *priv = stream->priv; SpaControlBuilder builder; SpaControlCmdPortUpdate pu; + SpaControlCmdStateChange sc; SpaControl control; handle_socket (stream, priv->fd); control_builder_init (stream, &builder); - pu.port = 0; + pu.port_id = 0; pu.change_mask = 0; spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_PORT_UPDATE, &pu); - spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_START_CONFIGURE, NULL); + sc.state = SPA_NODE_STATE_CONFIGURE; + spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_STATE_CHANGE, &sc); spa_control_builder_end (&builder, &control); if (spa_control_write (&control, priv->fd) < 0) @@ -1250,7 +1279,7 @@ pinos_stream_peek_buffer (PinosStream *stream) g_return_val_if_fail (PINOS_IS_STREAM (stream), NULL); priv = stream->priv; - return spa_buffer_ref (priv->buffer); + return priv->buffer; } /** diff --git a/pinos/gst/gstpinossink.c b/pinos/gst/gstpinossink.c index 37e501d85..c21b8ef51 100644 --- a/pinos/gst/gstpinossink.c +++ b/pinos/gst/gstpinossink.c @@ -525,8 +525,6 @@ gst_pinos_sink_render (GstBaseSink * bsink, GstBuffer * buffer) size = gst_buffer_get_size (buffer); b = g_slice_new (SinkBuffer); - b->buffer.refcount = 0; - b->buffer.notify = sink_buffer_free; b->buffer.id = pinos_fd_manager_get_id (pinossink->fdmanager); b->buffer.size = size; b->buffer.n_metas = 1; diff --git a/pinos/gst/gstpinossrc.c b/pinos/gst/gstpinossrc.c index 694d69ff5..aede1f91d 100644 --- a/pinos/gst/gstpinossrc.c +++ b/pinos/gst/gstpinossrc.c @@ -332,7 +332,6 @@ process_mem_data_destroy (gpointer user_data) { ProcessMemData *data = user_data; - spa_buffer_unref (data->buffer); gst_object_unref (data->src); g_slice_free (ProcessMemData, data); } diff --git a/pinos/modules/spa/spa-alsa-sink.c b/pinos/modules/spa/spa-alsa-sink.c index bb2730297..93e427ca6 100644 --- a/pinos/modules/spa/spa-alsa-sink.c +++ b/pinos/modules/spa/spa-alsa-sink.c @@ -161,11 +161,11 @@ on_sink_event (SpaNode *node, SpaEvent *event, void *user_data) iinfo.port_id = event->port_id; iinfo.flags = SPA_INPUT_FLAG_NONE; - iinfo.id = 0; + iinfo.buffer_id = 0; iinfo.offset = 0; iinfo.size = total; - g_debug ("push sink %d", iinfo.id); + g_debug ("push sink %d", iinfo.buffer_id); if ((res = spa_node_port_push_input (priv->sink, 1, &iinfo)) < 0) g_debug ("got error %d", res); break; @@ -427,13 +427,14 @@ free_mem_block (MemBlock *b) static gboolean on_received_buffer (PinosPort *port, - SpaBuffer *buffer, + uint32_t buffer_id, GError **error, gpointer user_data) { PinosSpaAlsaSink *this = user_data; PinosSpaAlsaSinkPrivate *priv = this->priv; unsigned int i; + SpaBuffer *buffer = NULL; for (i = 0; i < buffer->n_datas; i++) { SpaData *d = &buffer->datas[i]; @@ -460,11 +461,19 @@ on_received_buffer (PinosPort *port, pinos_ringbuffer_write_advance (priv->ringbuffer, total); } - spa_buffer_unref (buffer); return TRUE; } +static gboolean +on_received_event (PinosPort *port, + SpaEvent *event, + GError **error, + gpointer user_data) +{ + return TRUE; +} + static void on_format_change (GObject *obj, GParamSpec *pspec, @@ -499,7 +508,7 @@ add_port (PinosNode *node, data->port = PINOS_NODE_CLASS (pinos_spa_alsa_sink_parent_class) ->add_port (node, direction, id, error); - pinos_port_set_received_buffer_cb (data->port, on_received_buffer, sink, NULL); + 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); diff --git a/pinos/modules/spa/spa-v4l2-source.c b/pinos/modules/spa/spa-v4l2-source.c index 9c61b0742..e806c23ee 100644 --- a/pinos/modules/spa/spa-v4l2-source.c +++ b/pinos/modules/spa/spa-v4l2-source.c @@ -48,8 +48,6 @@ typedef struct { struct _PinosSpaV4l2SourcePrivate { - SpaNode *source; - SpaPollFd fds[16]; unsigned int n_fds; SpaPollItem poll; @@ -112,143 +110,6 @@ make_node (SpaNode **node, const char *lib, const char *name) return SPA_RESULT_ERROR; } -static void -on_source_event (SpaNode *node, SpaEvent *event, void *user_data) -{ - PinosSpaV4l2Source *source = user_data; - PinosSpaV4l2SourcePrivate *priv = source->priv; - - switch (event->type) { - case SPA_EVENT_TYPE_CAN_PULL_OUTPUT: - { - SpaOutputInfo info[1] = { 0, }; - SpaResult res; - SpaBuffer *b; - GList *walk; - - if ((res = spa_node_port_pull_output (priv->source, 1, info)) < 0) - g_debug ("spa-v4l2-source %p: got pull error %d", source, res); - - b = NULL; /* info[0].id; */ - - for (walk = priv->ports; walk; walk = g_list_next (walk)) { - SourcePortData *data = walk->data; - GError *error = NULL; - - if (!data->have_format) { - g_object_set (data->port, "format", priv->format, NULL); - data->have_format = TRUE; - } - - if (!pinos_port_send_buffer (data->port, b, &error)) { - g_debug ("send failed: %s", error->message); - g_clear_error (&error); - } - } - spa_buffer_unref (b); - break; - } - - case SPA_EVENT_TYPE_ADD_POLL: - { - SpaPollItem *poll = event->data; - - priv->poll = *poll; - priv->fds[0] = poll->fds[0]; - priv->n_fds = 1; - priv->poll.fds = priv->fds; - break; - } - default: - g_debug ("got event %d", event->type); - break; - } -} - -static void -create_pipeline (PinosSpaV4l2Source *this) -{ - PinosSpaV4l2SourcePrivate *priv = this->priv; - SpaResult res; - SpaProps *props; - SpaPropValue value; - - if ((res = make_node (&priv->source, - "spa/build/plugins/v4l2/libspa-v4l2.so", - "v4l2-source")) < 0) { - g_error ("can't create v4l2-source: %d", res); - return; - } - spa_node_set_event_callback (priv->source, on_source_event, this); - - if ((res = spa_node_get_props (priv->source, &props)) < 0) - g_debug ("got get_props error %d", res); - - value.type = SPA_PROP_TYPE_STRING; - value.value = "/dev/video1"; - 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->source, props)) < 0) - g_debug ("got set_props error %d", res); -} - -static SpaResult -negotiate_formats (PinosSpaV4l2Source *this) -{ - PinosSpaV4l2SourcePrivate *priv = this->priv; - SpaResult res; - SpaFormat *format; - SpaProps *props; - uint32_t val; - SpaPropValue value; - void *state = NULL; - SpaFraction frac; - SpaRectangle rect; - const gchar *str; - - if ((res = spa_node_port_enum_formats (priv->source, 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_VIDEO_FORMAT_YUY2; - if ((res = spa_props_set_prop (props, spa_props_index_for_id (props, SPA_PROP_ID_VIDEO_FORMAT), &value)) < 0) - return res; - - value.type = SPA_PROP_TYPE_RECTANGLE; - value.size = sizeof (SpaRectangle); - value.value = ▭ - rect.width = 320; - rect.height = 240; - if ((res = spa_props_set_prop (props, spa_props_index_for_id (props, SPA_PROP_ID_VIDEO_SIZE), &value)) < 0) - return res; - - value.type = SPA_PROP_TYPE_FRACTION; - value.size = sizeof (SpaFraction); - value.value = &frac; - frac.num = 25; - frac.denom = 1; - if ((res = spa_props_set_prop (props, spa_props_index_for_id (props, SPA_PROP_ID_VIDEO_FRAMERATE), &value)) < 0) - return res; - - if ((res = spa_node_port_set_format (priv->source, 0, 0, format)) < 0) - return res; - - str = "video/x-raw," - " format=(string)YUY2," - " width=(int)320," - " height=(int)240," - " framerate=(fraction)30/1"; - priv->format = g_bytes_new_static (str, strlen (str)+1); - - return SPA_RESULT_OK; -} - static void * loop (void *user_data) { @@ -282,35 +143,186 @@ loop (void *user_data) } static void -start_pipeline (PinosSpaV4l2Source *source) +on_source_event (SpaNode *node, SpaEvent *event, void *user_data) { - PinosSpaV4l2SourcePrivate *priv = source->priv; - SpaResult res; - SpaCommand cmd; - int err; + PinosSpaV4l2Source *this = user_data; + PinosSpaV4l2SourcePrivate *priv = this->priv; - g_debug ("spa-v4l2-source %p: starting pipeline", source); - negotiate_formats (source); + switch (event->type) { + case SPA_EVENT_TYPE_CAN_PULL_OUTPUT: + { + SpaOutputInfo info[1] = { 0, }; + SpaResult res; + GList *walk; - cmd.type = SPA_COMMAND_START; - if ((res = spa_node_send_command (priv->source, &cmd)) < 0) - g_debug ("got error %d", res); + if ((res = spa_node_port_pull_output (node, 1, info)) < 0) + g_debug ("spa-v4l2-source %p: got pull error %d, %d", this, res, info[0].status); - priv->running = true; - if ((err = pthread_create (&priv->thread, NULL, loop, source)) != 0) { - g_debug ("spa-v4l2-source %p: can't create thread", strerror (err)); - priv->running = false; + for (walk = priv->ports; walk; walk = g_list_next (walk)) { + SourcePortData *data = walk->data; + GError *error = NULL; + + if (!pinos_port_send_buffer (data->port, info[0].buffer_id, &error)) { + g_debug ("send failed: %s", error->message); + g_clear_error (&error); + } + } + break; + } + + case SPA_EVENT_TYPE_ADD_POLL: + { + SpaPollItem *poll = event->data; + int err; + + 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: %s", this, strerror (err)); + priv->running = false; + } + } + break; + } + case SPA_EVENT_TYPE_REMOVE_POLL: + { + if (priv->running) { + priv->running = false; + pthread_join (priv->thread, NULL); + } + break; + } + default: + g_debug ("got event %d", event->type); + break; } } static void -stop_pipeline (PinosSpaV4l2Source *source) +setup_node (PinosSpaV4l2Source *this) { - PinosSpaV4l2SourcePrivate *priv = source->priv; + PinosNode *node = PINOS_NODE (this); + PinosSpaV4l2SourcePrivate *priv = this->priv; + SpaResult res; + SpaProps *props; + SpaPropValue value; + + spa_node_set_event_callback (node->node, on_source_event, this); + + if ((res = spa_node_get_props (node->node, &props)) < 0) + g_debug ("got get_props error %d", res); + + value.type = SPA_PROP_TYPE_STRING; + value.value = "/dev/video1"; + 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 (node->node, props)) < 0) + g_debug ("got set_props error %d", res); +} + +#if 0 +static SpaResult +negotiate_formats (PinosSpaV4l2Source *this) +{ + PinosNode *node = PINOS_NODE (this); + PinosSpaV4l2SourcePrivate *priv = this->priv; + SpaResult res; + SpaFormat *format; + SpaProps *props; + uint32_t val; + SpaPropValue value; + void *state = NULL; + SpaFraction frac; + SpaRectangle rect; + const gchar *str; + + if ((res = spa_node_port_enum_formats (node->node, 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_VIDEO_FORMAT_YUY2; + if ((res = spa_props_set_prop (props, spa_props_index_for_id (props, SPA_PROP_ID_VIDEO_FORMAT), &value)) < 0) + return res; + + value.type = SPA_PROP_TYPE_RECTANGLE; + value.size = sizeof (SpaRectangle); + value.value = ▭ + rect.width = 320; + rect.height = 240; + if ((res = spa_props_set_prop (props, spa_props_index_for_id (props, SPA_PROP_ID_VIDEO_SIZE), &value)) < 0) + return res; + + value.type = SPA_PROP_TYPE_FRACTION; + value.size = sizeof (SpaFraction); + value.value = &frac; + frac.num = 25; + frac.denom = 1; + if ((res = spa_props_set_prop (props, spa_props_index_for_id (props, SPA_PROP_ID_VIDEO_FRAMERATE), &value)) < 0) + return res; + + if ((res = spa_node_port_set_format (node->node, 0, 0, format)) < 0) + return res; + + str = "video/x-raw," + " format=(string)YUY2," + " width=(int)320," + " height=(int)240," + " framerate=(fraction)30/1"; + priv->format = g_bytes_new_static (str, strlen (str)+1); + + priv->n_buffers = 16; + if ((res = spa_node_port_alloc_buffers (node->node, 0, NULL, 0, priv->buffers, &priv->n_buffers)) < 0) + return res; + + return SPA_RESULT_OK; +} +#endif + +static void +start_pipeline (PinosSpaV4l2Source *this) +{ +#if 0 + PinosSpaV4l2SourcePrivate *priv = this->priv; + PinosNode *node = PINOS_NODE (this); + SpaResult res; + SpaCommand cmd; + int err; + + g_debug ("spa-v4l2-source %p: starting pipeline", this); + negotiate_formats (this); + + cmd.type = SPA_COMMAND_START; + if ((res = spa_node_send_command (node->node, &cmd)) < 0) + g_debug ("got error %d", res); + + 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; + } +#endif +} + +static void +stop_pipeline (PinosSpaV4l2Source *this) +{ + PinosSpaV4l2SourcePrivate *priv = this->priv; + PinosNode *node = PINOS_NODE (this); SpaResult res; SpaCommand cmd; - g_debug ("spa-v4l2-source %p: stopping pipeline", source); + g_debug ("spa-v4l2-source %p: stopping pipeline", this); if (priv->running) { priv->running = false; @@ -318,14 +330,14 @@ stop_pipeline (PinosSpaV4l2Source *source) } cmd.type = SPA_COMMAND_STOP; - if ((res = spa_node_send_command (priv->source, &cmd)) < 0) + if ((res = spa_node_send_command (node->node, &cmd)) < 0) g_debug ("got error %d", res); } static void -destroy_pipeline (PinosSpaV4l2Source *source) +destroy_pipeline (PinosSpaV4l2Source *this) { - g_debug ("spa-v4l2-source %p: destroy pipeline", source); + g_debug ("spa-v4l2-source %p: destroy pipeline", this); } static gboolean @@ -440,7 +452,7 @@ source_constructed (GObject * object) G_OBJECT_CLASS (pinos_spa_v4l2_source_parent_class)->constructed (object); - create_pipeline (source); + setup_node (source); } static void @@ -454,6 +466,42 @@ source_finalize (GObject * object) G_OBJECT_CLASS (pinos_spa_v4l2_source_parent_class)->finalize (object); } +static gboolean +on_received_buffer (PinosPort *port, uint32_t buffer_id, GError **error, gpointer user_data) +{ + return FALSE; +} + +static gboolean +on_received_event (PinosPort *port, SpaEvent *event, GError **error, gpointer user_data) +{ + PinosNode *node = user_data; + PinosSpaV4l2Source *source = PINOS_SPA_V4L2_SOURCE (node); + PinosSpaV4l2SourcePrivate *priv = source->priv; + SpaResult res; + + switch (event->type) { + case SPA_EVENT_TYPE_REUSE_BUFFER: + { + SpaEventReuseBuffer *rb = event->data; + + if ((res = spa_node_port_reuse_buffer (node->node, + event->port_id, + rb->buffer_id, + rb->offset, + rb->size)) < 0) + g_warning ("client-node %p: error reuse buffer: %d", node, res); + break; + } + default: + if ((res = spa_node_port_push_event (node->node, port->id, event)) < 0) + g_warning ("client-node %p: error pushing event: %d", node, res); + break; + } + return TRUE; +} + + static PinosPort * add_port (PinosNode *node, PinosDirection direction, @@ -472,6 +520,8 @@ add_port (PinosNode *node, data->port = PINOS_NODE_CLASS (pinos_spa_v4l2_source_parent_class) ->add_port (node, direction, id, error); + pinos_port_set_received_cb (data->port, on_received_buffer, on_received_event, node, 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); @@ -511,11 +561,21 @@ pinos_spa_v4l2_source_new (PinosDaemon *daemon, PinosProperties *properties) { PinosNode *node; + SpaNode *n; + SpaResult res; + + if ((res = make_node (&n, + "spa/build/plugins/v4l2/libspa-v4l2.so", + "v4l2-source")) < 0) { + g_error ("can't create v4l2-source: %d", res); + return NULL; + } node = g_object_new (PINOS_TYPE_SPA_V4L2_SOURCE, "daemon", daemon, "name", name, "properties", properties, + "node", n, NULL); return node; diff --git a/pinos/server/client-node.c b/pinos/server/client-node.c index 0e933e2bc..79c726fc1 100644 --- a/pinos/server/client-node.c +++ b/pinos/server/client-node.c @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include @@ -42,24 +44,17 @@ #include "spa/include/spa/control.h" -#define MAX_BUFFER_SIZE 1024 -#define MAX_FDS 16 - struct _PinosClientNodePrivate { int fd; - GSource *socket_source; GSocket *sockets[2]; - SpaControl recv_control; + SpaPollFd fds[16]; + unsigned int n_fds; + SpaPollItem poll; - guint8 recv_data[MAX_BUFFER_SIZE]; - int recv_fds[MAX_FDS]; - - guint8 send_data[MAX_BUFFER_SIZE]; - int send_fds[MAX_FDS]; - - GHashTable *mem_ids; + gboolean running; + pthread_t thread; }; #define PINOS_CLIENT_NODE_GET_PRIVATE(obj) \ @@ -110,193 +105,6 @@ pinos_client_node_set_property (GObject *_object, } } -static gboolean -parse_control (PinosClientNode *cnode, - SpaControl *ctrl) -{ - PinosNode *node = PINOS_NODE (cnode); - PinosClientNodePrivate *priv = cnode->priv; - SpaControlIter it; - - spa_control_iter_init (&it, ctrl); - while (spa_control_iter_next (&it) == SPA_RESULT_OK) { - SpaControlCmd cmd = spa_control_iter_get_cmd (&it); - - switch (cmd) { - case SPA_CONTROL_CMD_ADD_PORT: - case SPA_CONTROL_CMD_REMOVE_PORT: - case SPA_CONTROL_CMD_SET_FORMAT: - case SPA_CONTROL_CMD_SET_PROPERTY: - case SPA_CONTROL_CMD_END_CONFIGURE: - case SPA_CONTROL_CMD_PAUSE: - case SPA_CONTROL_CMD_START: - case SPA_CONTROL_CMD_STOP: - g_warning ("client-node %p: got unexpected control %d", node, cmd); - break; - - case SPA_CONTROL_CMD_NODE_UPDATE: - case SPA_CONTROL_CMD_PORT_UPDATE: - case SPA_CONTROL_CMD_PORT_REMOVED: - g_warning ("client-node %p: command not implemented %d", node, cmd); - break; - - case SPA_CONTROL_CMD_START_CONFIGURE: - { - SpaControlBuilder builder; - SpaControl control; - guint8 buffer[1024]; - - /* set port format */ - - /* send end-configure */ - spa_control_builder_init_into (&builder, buffer, 1024, NULL, 0); - spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_END_CONFIGURE, NULL); - spa_control_builder_end (&builder, &control); - - if (spa_control_write (&control, priv->fd) < 0) - g_warning ("client-node %p: error writing control", node); - - break; - } - case SPA_CONTROL_CMD_PORT_STATUS_CHANGE: - { - g_warning ("client-node %p: command not implemented %d", node, cmd); - break; - } - case SPA_CONTROL_CMD_START_ALLOC: - { - SpaControlBuilder builder; - SpaControl control; - guint8 buffer[1024]; - GList *ports, *walk; - - /* FIXME read port memory requirements */ - /* FIXME add_mem */ - - /* send start */ - spa_control_builder_init_into (&builder, buffer, 1024, NULL, 0); - spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_START, NULL); - spa_control_builder_end (&builder, &control); - - if (spa_control_write (&control, priv->fd) < 0) - g_warning ("client-node %p: error writing control", node); - - ports = pinos_node_get_ports (node); - for (walk = ports; walk; walk = g_list_next (walk)) { - PinosPort *port = walk->data; - - pinos_port_activate (port); - } - break; - } - case SPA_CONTROL_CMD_NEED_INPUT: - { - break; - } - case SPA_CONTROL_CMD_HAVE_OUTPUT: - { - break; - } - - case SPA_CONTROL_CMD_ADD_MEM: - break; - case SPA_CONTROL_CMD_REMOVE_MEM: - break; - case SPA_CONTROL_CMD_ADD_BUFFER: - break; - case SPA_CONTROL_CMD_REMOVE_BUFFER: - break; - - case SPA_CONTROL_CMD_PROCESS_BUFFER: - { - break; - } - case SPA_CONTROL_CMD_REUSE_BUFFER: - { - break; - } - - default: - g_warning ("client-node %p: command unhandled %d", node, cmd); - break; - } - } - spa_control_iter_end (&it); - - return TRUE; -} - -static gboolean -on_socket_condition (GSocket *socket, - GIOCondition condition, - gpointer user_data) -{ - PinosClientNode *node = user_data; - PinosClientNodePrivate *priv = node->priv; - - switch (condition) { - case G_IO_IN: - { - SpaControl *control = &priv->recv_control; - - if (spa_control_read (control, - priv->fd, - priv->recv_data, - MAX_BUFFER_SIZE, - priv->recv_fds, - MAX_FDS) < 0) { - g_warning ("client-node %p: failed to read buffer", node); - return TRUE; - } - - parse_control (node, control); - -#if 0 - if (!pinos_port_receive_buffer (priv->port, buffer, &error)) { - g_warning ("client-node %p: port %p failed to receive buffer: %s", node, priv->port, error->message); - g_clear_error (&error); - } -#endif - spa_control_clear (control); - break; - } - - case G_IO_OUT: - g_warning ("can do IO OUT\n"); - break; - - default: - break; - } - return TRUE; -} - -static void -handle_socket (PinosClientNode *node, GSocket *socket) -{ - PinosClientNodePrivate *priv = node->priv; - GMainContext *context = g_main_context_get_thread_default(); - - g_debug ("client-node %p: handle socket in context %p", node, context); - priv->fd = g_socket_get_fd (socket); - priv->socket_source = g_socket_create_source (socket, G_IO_IN, NULL); - g_source_set_callback (priv->socket_source, (GSourceFunc) on_socket_condition, node, NULL); - g_source_attach (priv->socket_source, context); -} - -static void -unhandle_socket (PinosClientNode *node) -{ - PinosClientNodePrivate *priv = node->priv; - - g_debug ("client-node %p: unhandle socket", node); - if (priv->socket_source) { - g_source_destroy (priv->socket_source); - g_clear_pointer (&priv->socket_source, g_source_unref); - priv->fd = -1; - } -} - /** * pinos_client_node_get_socket_pair: * @node: a #PinosClientNode @@ -308,15 +116,19 @@ unhandle_socket (PinosClientNode *node) * Returns: a #GSocket that can be used to send/receive buffers to node. */ GSocket * -pinos_client_node_get_socket_pair (PinosClientNode *node, - GError **error) +pinos_client_node_get_socket_pair (PinosClientNode *this, + GError **error) { + PinosNode *node; PinosClientNodePrivate *priv; - g_return_val_if_fail (PINOS_IS_CLIENT_NODE (node), FALSE); - priv = node->priv; + g_return_val_if_fail (PINOS_IS_CLIENT_NODE (this), FALSE); + node = PINOS_NODE (this); + priv = this->priv; if (priv->sockets[1] == NULL) { + SpaProps *props; + SpaPropValue value; int fd[2]; if (socketpair (AF_UNIX, SOCK_STREAM, 0, fd) != 0) @@ -330,7 +142,14 @@ pinos_client_node_get_socket_pair (PinosClientNode *node, if (priv->sockets[1] == NULL) goto create_failed; - handle_socket (node, priv->sockets[0]); + priv->fd = g_socket_get_fd (priv->sockets[0]); + + spa_node_get_props (node->node, &props); + value.type = SPA_PROP_TYPE_INT; + value.value = &priv->fd; + value.size = sizeof (int); + spa_props_set_prop (props, spa_props_index_for_name (props, "socket"), &value); + spa_node_set_props (node->node, props); } return g_object_ref (priv->sockets[1]); @@ -351,156 +170,169 @@ create_failed: } } -static void -on_format_change (GObject *obj, - GParamSpec *pspec, - gpointer user_data) -{ - PinosClientNode *node = user_data; - PinosClientNodePrivate *priv = node->priv; - GBytes *format; - SpaControl control; - SpaControlBuilder builder; - SpaControlCmdSetFormat sf; - guint8 buf[1024]; - - g_object_get (obj, "format", &format, NULL); - if (format == NULL) - return ; - - g_debug ("port %p: format change %s", obj, (gchar*)g_bytes_get_data (format, NULL)); - - spa_control_builder_init_into (&builder, buf, 1024, NULL, 0); - sf.port = 0; - sf.format = NULL; - sf.str = g_bytes_get_data (format, NULL); - spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_SET_FORMAT, &sf); - spa_control_builder_end (&builder, &control); - - if (spa_control_write (&control, priv->fd)) - g_warning ("client-node %p: error writing control", node); -} - - -static int -tmpfile_create (void *data, gsize size) -{ - char filename[] = "/dev/shm/tmpfilepay.XXXXXX"; - int fd; - - fd = mkostemp (filename, O_CLOEXEC); - if (fd == -1) { - g_debug ("Failed to create temporary file: %s", strerror (errno)); - return -1; - } - unlink (filename); - - if (write (fd, data, size) != (gssize) size) - g_debug ("Failed to write data: %s", strerror (errno)); - - return fd; -} - -typedef struct { - SpaBuffer buffer; - SpaData datas[16]; - int idx[16]; - SpaBuffer *orig; -} MyBuffer; - static gboolean -on_received_buffer (PinosPort *port, SpaBuffer *buffer, GError **error, gpointer user_data) +on_received_buffer (PinosPort *port, uint32_t buffer_id, GError **error, gpointer user_data) { - PinosClientNode *node = user_data; - PinosClientNodePrivate *priv = node->priv; - SpaControl control; - SpaControlBuilder builder; - guint8 buf[1024]; - int fds[16]; - SpaControlCmdAddBuffer ab; - SpaControlCmdProcessBuffer pb; - SpaControlCmdRemoveBuffer rb; - bool tmpfile = false; + PinosNode *node = user_data; + PinosClientNode *this = PINOS_CLIENT_NODE (node); + PinosClientNodePrivate *priv = this->priv; + SpaResult res; + SpaInputInfo info[1]; - if (pinos_port_get_direction (port) == PINOS_DIRECTION_OUTPUT) { - /* FIXME, does not happen */ - spa_control_builder_init_into (&builder, buf, 1024, NULL, 0); - spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_HAVE_OUTPUT, NULL); - spa_control_builder_end (&builder, &control); + info[0].port_id = port->id; + info[0].buffer_id = buffer_id; + info[0].flags = SPA_INPUT_FLAG_NONE; + info[0].offset = 0; + info[0].size = -1; - if (spa_control_write (&control, priv->fd)) { - g_warning ("client-node %p: error writing control", node); - return FALSE; - } - } else { - unsigned int i; - MyBuffer b; - - spa_control_builder_init_into (&builder, buf, 1024, fds, 16); - - b.buffer.refcount = 1; - b.buffer.notify = NULL; - b.buffer.id = buffer->id; - b.buffer.size = buffer->size; - b.buffer.n_metas = buffer->n_metas; - b.buffer.metas = buffer->metas; - b.buffer.n_datas = buffer->n_datas; - b.buffer.datas = b.datas; - - for (i = 0; i < buffer->n_datas; i++) { - SpaData *d = &buffer->datas[i]; - int fd; - SpaControlCmdAddMem am; - - if (d->type == SPA_DATA_TYPE_FD) { - fd = *((int *)d->ptr); - } else { - fd = tmpfile_create (d->ptr, d->size + d->offset); - tmpfile = true; - } - am.port = 0; - am.id = i; - am.type = 0; - am.fd_index = spa_control_builder_add_fd (&builder, fd, tmpfile ? true : false); - am.offset = 0; - am.size = d->offset + d->size; - spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_ADD_MEM, &am); - - b.idx[i] = i; - b.datas[i].type = SPA_DATA_TYPE_MEMID; - b.datas[i].ptr_type = NULL; - b.datas[i].ptr = &b.idx[i]; - b.datas[i].offset = d->offset; - b.datas[i].size = d->size; - b.datas[i].stride = d->stride; - } - ab.port = 0; - ab.buffer = &b.buffer; - spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_ADD_BUFFER, &ab); - pb.port = 0; - pb.id = b.buffer.id; - spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_PROCESS_BUFFER, &pb); - rb.port = 0; - rb.id = b.buffer.id; - spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_REMOVE_BUFFER, &rb); - - for (i = 0; i < buffer->n_datas; i++) { - SpaControlCmdRemoveMem rm; - rm.port = 0; - rm.id = i; - spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_REMOVE_MEM, &rm); - } - spa_control_builder_end (&builder, &control); - - if (spa_control_write (&control, priv->fd)) - g_warning ("client-node %p: error writing control", node); - - spa_control_clear (&control); - } + if ((res = spa_node_port_push_input (node->node, 1, info)) < 0) + g_warning ("client-node %p: error pushing buffer: %d, %d", node, res, info[0].status); return TRUE; } +static gboolean +on_received_event (PinosPort *port, SpaEvent *event, GError **error, gpointer user_data) +{ + PinosNode *node = user_data; + PinosClientNode *this = PINOS_CLIENT_NODE (node); + PinosClientNodePrivate *priv = this->priv; + SpaResult res; + + if ((res = spa_node_port_push_event (node->node, port->id, event)) < 0) + g_warning ("client-node %p: error pushing event: %d", node, res); + + return TRUE; +} + +static void * +loop (void *user_data) +{ + PinosClientNode *this = user_data; + PinosClientNodePrivate *priv = this->priv; + int r; + + g_debug ("client-node %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 ("client-node %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 ("client-node %p: leave thread", this); + + return NULL; +} + +static void +start_thread (PinosClientNode *this) +{ + PinosClientNodePrivate *priv = this->priv; + int err; + + if (!priv->running) { + priv->running = true; + if ((err = pthread_create (&priv->thread, NULL, loop, this)) != 0) { + g_debug ("client-node %p: can't create thread", strerror (err)); + priv->running = false; + } + } +} + +static void +stop_thread (PinosClientNode *this) +{ + PinosClientNodePrivate *priv = this->priv; + + if (priv->running) { + priv->running = false; + pthread_join (priv->thread, NULL); + } +} + +static void +on_node_event (SpaNode *node, SpaEvent *event, void *user_data) +{ + PinosClientNode *this = user_data; + PinosClientNodePrivate *priv = this->priv; + + switch (event->type) { + case SPA_EVENT_TYPE_STATE_CHANGE: + { + SpaEventStateChange *sc = event->data; + + switch (sc->state) { + case SPA_NODE_STATE_CONFIGURE: + { + GList *ports, *walk; + + ports = pinos_node_get_ports (PINOS_NODE (this)); + for (walk = ports; walk; walk = g_list_next (walk)) { + PinosPort *port = walk->data; + pinos_port_activate (port); + } + } + default: + break; + } + break; + } + case SPA_EVENT_TYPE_ADD_POLL: + { + SpaPollItem *poll = event->data; + + priv->poll = *poll; + priv->fds[0] = poll->fds[0]; + priv->n_fds = 1; + priv->poll.fds = priv->fds; + + start_thread (this); + break; + } + case SPA_EVENT_TYPE_REMOVE_POLL: + { + stop_thread (this); + break; + } + case SPA_EVENT_TYPE_REUSE_BUFFER: + { + PinosPort *port; + GError *error = NULL; + + port = pinos_node_find_port (PINOS_NODE (this), event->port_id); + pinos_port_send_event (port, event, &error); + break; + } + default: + g_debug ("client-node %p: got event %d", this, event->type); + break; + } +} + +static void +setup_node (PinosClientNode *this) +{ + PinosNode *node = PINOS_NODE (this); + SpaResult res; + + if ((res = spa_node_set_event_callback (node->node, on_node_event, this)) < 0) + g_warning ("client-node %p: error setting callback", this); +} + static PinosPort * add_port (PinosNode *node, PinosDirection direction, @@ -509,12 +341,13 @@ add_port (PinosNode *node, { PinosPort *port; + if (spa_node_add_port (node->node, direction, id) < 0) + g_warning ("client-node %p: error adding port", node); + port = PINOS_NODE_CLASS (pinos_client_node_parent_class)->add_port (node, direction, id, error); if (port) { - pinos_port_set_received_buffer_cb (port, on_received_buffer, node, NULL); - - g_signal_connect (port, "notify::format", (GCallback) on_format_change, node); + pinos_port_set_received_cb (port, on_received_buffer, on_received_event, node, NULL); } return port; } @@ -523,16 +356,18 @@ static gboolean remove_port (PinosNode *node, guint id) { + if (spa_node_remove_port (node->node, id) < 0) + g_warning ("client-node %p: error removing port", node); + return PINOS_NODE_CLASS (pinos_client_node_parent_class)->remove_port (node, id); } static void pinos_client_node_dispose (GObject * object) { - PinosClientNode *node = PINOS_CLIENT_NODE (object); + PinosClientNode *this = PINOS_CLIENT_NODE (object); - g_debug ("client-node %p: dispose", node); - unhandle_socket (node); + g_debug ("client-node %p: dispose", this); G_OBJECT_CLASS (pinos_client_node_parent_class)->dispose (object); } @@ -540,11 +375,9 @@ pinos_client_node_dispose (GObject * object) static void pinos_client_node_finalize (GObject * object) { - PinosClientNode *node = PINOS_CLIENT_NODE (object); - PinosClientNodePrivate *priv = node->priv; + PinosClientNode *this = PINOS_CLIENT_NODE (object); - g_debug ("client-node %p: finalize", node); - g_hash_table_unref (priv->mem_ids); + g_debug ("client-node %p: finalize", this); G_OBJECT_CLASS (pinos_client_node_parent_class)->finalize (object); } @@ -552,11 +385,13 @@ pinos_client_node_finalize (GObject * object) static void pinos_client_node_constructed (GObject * object) { - PinosClientNode *node = PINOS_CLIENT_NODE (object); + PinosClientNode *this = PINOS_CLIENT_NODE (object); - g_debug ("client-node %p: constructed", node); + g_debug ("client-node %p: constructed", this); G_OBJECT_CLASS (pinos_client_node_parent_class)->constructed (object); + + setup_node (this); } static void @@ -584,3 +419,85 @@ pinos_client_node_init (PinosClientNode * node) g_debug ("client-node %p: new", node); } + +static SpaResult +make_node (SpaNode **node, const char *lib, const char *name) +{ + SpaHandle *handle; + SpaResult res; + void *hnd, *state = NULL; + SpaEnumHandleFactoryFunc enum_func; + + if ((hnd = dlopen (lib, RTLD_NOW)) == NULL) { + g_error ("can't load %s: %s", lib, dlerror()); + return SPA_RESULT_ERROR; + } + if ((enum_func = dlsym (hnd, "spa_enum_handle_factory")) == NULL) { + g_error ("can't find enum function"); + return SPA_RESULT_ERROR; + } + + while (true) { + const SpaHandleFactory *factory; + void *iface; + + if ((res = enum_func (&factory, &state)) < 0) { + if (res != SPA_RESULT_ENUM_END) + g_error ("can't enumerate factories: %d", res); + break; + } + if (strcmp (factory->name, name)) + continue; + + handle = calloc (1, factory->size); + if ((res = factory->init (factory, handle)) < 0) { + g_error ("can't make factory instance: %d", res); + return res; + } + if ((res = handle->get_interface (handle, SPA_INTERFACE_ID_NODE, &iface)) < 0) { + g_error ("can't get interface %d", res); + return res; + } + *node = iface; + return SPA_RESULT_OK; + } + return SPA_RESULT_ERROR; +} + +/** + * pinos_client_node_new: + * @daemon: a #PinosDaemon + * @sender: the path of the owner + * @name: a name + * @properties: extra properties + * + * Create a new #PinosNode. + * + * Returns: a new #PinosNode + */ +PinosNode * +pinos_client_node_new (PinosDaemon *daemon, + const gchar *sender, + const gchar *name, + PinosProperties *properties) +{ + SpaNode *n; + SpaResult res; + + g_return_val_if_fail (PINOS_IS_DAEMON (daemon), NULL); + + if ((res = make_node (&n, + "spa/build/plugins/remote/libspa-remote.so", + "proxy")) < 0) { + g_error ("can't create proxy: %d", res); + return NULL; + } + + return g_object_new (PINOS_TYPE_CLIENT_NODE, + "daemon", daemon, + "sender", sender, + "name", name, + "properties", properties, + "node", n, + NULL); +} diff --git a/pinos/server/client-node.h b/pinos/server/client-node.h index 53b653759..b546430dc 100644 --- a/pinos/server/client-node.h +++ b/pinos/server/client-node.h @@ -62,6 +62,11 @@ struct _PinosClientNodeClass { /* normal GObject stuff */ GType pinos_client_node_get_type (void); +PinosNode * pinos_client_node_new (PinosDaemon *daemon, + const gchar *sender, + const gchar *name, + PinosProperties *properties); + GSocket * pinos_client_node_get_socket_pair (PinosClientNode *node, GError **error); diff --git a/pinos/server/daemon.c b/pinos/server/daemon.c index a56c22881..367b581a6 100644 --- a/pinos/server/daemon.c +++ b/pinos/server/daemon.c @@ -148,7 +148,8 @@ handle_create_node (PinosDaemon1 *interface, node = pinos_node_new (daemon, sender, arg_name, - props); + props, + NULL); } pinos_properties_free (props); @@ -204,12 +205,10 @@ handle_create_client_node (PinosDaemon1 *interface, g_debug ("daemon %p: create client-node: %s", daemon, sender); props = pinos_properties_from_variant (arg_properties); - node = g_object_new (PINOS_TYPE_CLIENT_NODE, - "daemon", daemon, - "sender", sender, - "name", arg_name, - "properties", props, - NULL); + node = pinos_client_node_new (daemon, + sender, + arg_name, + props); client = sender_get_client (daemon, sender); diff --git a/pinos/server/link.c b/pinos/server/link.c index 3af9272aa..f24ade9d2 100644 --- a/pinos/server/link.c +++ b/pinos/server/link.c @@ -21,6 +21,8 @@ #include +#include + #include "pinos/client/pinos.h" #include "pinos/client/enumtypes.h" @@ -40,11 +42,24 @@ struct _PinosLinkPrivate gchar *object_path; gulong input_id, output_id; + gboolean active; + gboolean negotiated; + gboolean allocated; + PinosPort *output; PinosPort *input; + + SpaNode *output_node; + uint32_t output_port; + SpaNode *input_node; + uint32_t input_port; + GBytes *possible_formats; GBytes *format; + + SpaBuffer *buffers[16]; + unsigned int n_buffers; }; G_DEFINE_TYPE (PinosLink, pinos_link, G_TYPE_OBJECT); @@ -69,21 +84,39 @@ enum static guint signals[LAST_SIGNAL] = { 0 }; static gboolean -on_output_send (PinosPort *port, SpaBuffer *buffer, GError **error, gpointer user_data) +on_output_buffer (PinosPort *port, uint32_t buffer_id, GError **error, gpointer user_data) { PinosLink *link = user_data; PinosLinkPrivate *priv = link->priv; - return pinos_port_receive_buffer (priv->input, buffer, error); + return pinos_port_receive_buffer (priv->input, buffer_id, error); } static gboolean -on_input_send (PinosPort *port, SpaBuffer *buffer, GError **error, gpointer user_data) +on_output_event (PinosPort *port, SpaEvent *event, GError **error, gpointer user_data) { PinosLink *link = user_data; PinosLinkPrivate *priv = link->priv; - return pinos_port_receive_buffer (priv->output, buffer, error); + return pinos_port_receive_event (priv->input, event, error); +} + +static gboolean +on_input_buffer (PinosPort *port, uint32_t buffer_id, GError **error, gpointer user_data) +{ + PinosLink *link = user_data; + PinosLinkPrivate *priv = link->priv; + + return pinos_port_receive_buffer (priv->output, buffer_id, error); +} + +static gboolean +on_input_event (PinosPort *port, SpaEvent *event, GError **error, gpointer user_data) +{ + PinosLink *link = user_data; + PinosLinkPrivate *priv = link->priv; + + return pinos_port_receive_event (priv->output, event, error); } static void @@ -142,10 +175,14 @@ pinos_link_set_property (GObject *_object, case PROP_OUTPUT: priv->output = g_value_dup_object (value); + priv->output_node = priv->output->node->node; + priv->output_port = priv->output->id; break; case PROP_INPUT: priv->input = g_value_dup_object (value); + priv->input_node = priv->input->node->node; + priv->input_port = priv->input->id; break; case PROP_OBJECT_PATH: @@ -199,11 +236,101 @@ link_unregister_object (PinosLink *link) pinos_daemon_unexport (priv->daemon, priv->object_path); } +static SpaResult +do_negotiate (PinosLink *this) +{ + PinosLinkPrivate *priv = this->priv; + SpaResult res; + SpaFormat *format; + SpaProps *props; + uint32_t val; + SpaPropValue value; + void *state = NULL; + SpaFraction frac; + SpaRectangle rect; + + g_debug ("link %p: doing set format", this); + + if ((res = spa_node_port_enum_formats (priv->output_node, priv->output_port, &format, NULL, &state)) < 0) { + g_warning ("error enum formats: %d", res); + return res; + } + + props = &format->props; + + value.type = SPA_PROP_TYPE_UINT32; + value.size = sizeof (uint32_t); + value.value = &val; + + val = SPA_VIDEO_FORMAT_YUY2; + if ((res = spa_props_set_prop (props, spa_props_index_for_id (props, SPA_PROP_ID_VIDEO_FORMAT), &value)) < 0) + return res; + + value.type = SPA_PROP_TYPE_RECTANGLE; + value.size = sizeof (SpaRectangle); + value.value = ▭ + rect.width = 320; + rect.height = 240; + if ((res = spa_props_set_prop (props, spa_props_index_for_id (props, SPA_PROP_ID_VIDEO_SIZE), &value)) < 0) + return res; + + value.type = SPA_PROP_TYPE_FRACTION; + value.size = sizeof (SpaFraction); + value.value = &frac; + frac.num = 25; + frac.denom = 1; + if ((res = spa_props_set_prop (props, spa_props_index_for_id (props, SPA_PROP_ID_VIDEO_FRAMERATE), &value)) < 0) + return res; + + if ((res = spa_node_port_set_format (priv->output_node, priv->output_port, 0, format)) < 0) { + g_warning ("error set format output: %d", res); + return res; + } + + if ((res = spa_node_port_set_format (priv->input_node, priv->input_port, 0, format)) < 0) { + g_warning ("error set format input: %d", res); + return res; + } + + priv->negotiated = TRUE; + + return SPA_RESULT_OK; +} + +static SpaResult +do_allocation (PinosLink *this) +{ + PinosLinkPrivate *priv = this->priv; + SpaResult res; + + g_debug ("link %p: doing alloc buffers", this); + + priv->n_buffers = 16; + if ((res = spa_node_port_alloc_buffers (priv->output_node, priv->output_port, + NULL, 0, + priv->buffers, &priv->n_buffers)) < 0) { + g_warning ("error alloc buffers: %d", res); + return res; + } + + if ((res = spa_node_port_use_buffers (priv->input_node, priv->input_port, + priv->buffers, priv->n_buffers)) < 0) { + g_warning ("error alloc buffers: %d", res); + return res; + } + + priv->allocated = TRUE; + + return SPA_RESULT_OK; +} + static gboolean on_activate (PinosPort *port, gpointer user_data) { - PinosLink *link = user_data; - PinosLinkPrivate *priv = link->priv; + PinosLink *this = user_data; + PinosLinkPrivate *priv = this->priv; + SpaCommand cmd; + SpaResult res; if (priv->active) return TRUE; @@ -214,6 +341,19 @@ on_activate (PinosPort *port, gpointer user_data) pinos_port_activate (priv->input); priv->active = TRUE; + if (!priv->negotiated) + do_negotiate (this); + + /* negotiate allocation */ + if (!priv->allocated) + do_allocation (this); + + cmd.type = SPA_COMMAND_START; + if ((res = spa_node_send_command (priv->input_node, &cmd)) < 0) + g_warning ("got error %d", res); + if ((res = spa_node_send_command (priv->output_node, &cmd)) < 0) + g_warning ("got error %d", res); + return TRUE; } @@ -222,6 +362,8 @@ on_deactivate (PinosPort *port, gpointer user_data) { PinosLink *link = user_data; PinosLinkPrivate *priv = link->priv; + SpaCommand cmd; + SpaResult res; if (!priv->active) return TRUE; @@ -232,46 +374,32 @@ on_deactivate (PinosPort *port, gpointer user_data) pinos_port_deactivate (priv->input); priv->active = FALSE; + cmd.type = SPA_COMMAND_STOP; + if ((res = spa_node_send_command (priv->input_node, &cmd)) < 0) + g_warning ("got error %d", res); + if ((res = spa_node_send_command (priv->output_node, &cmd)) < 0) + g_warning ("got error %d", res); + return TRUE; } -static void -on_format_change (GObject *obj, - GParamSpec *pspec, - gpointer user_data) -{ - PinosLink *link = user_data; - PinosLinkPrivate *priv = link->priv; - GBytes *formats; - - g_object_get (priv->output, "format", &formats, NULL); - g_debug ("port %p: format change %s", priv->output, (gchar*)g_bytes_get_data (formats, NULL)); - g_object_set (priv->input, "format", formats, NULL); -} - static void pinos_link_constructed (GObject * object) { PinosLink *link = PINOS_LINK (object); PinosLinkPrivate *priv = link->priv; - GBytes *formats; - priv->output_id = pinos_port_add_send_buffer_cb (priv->output, - on_output_send, + priv->output_id = pinos_port_add_send_cb (priv->output, + on_output_buffer, + on_output_event, link, NULL); - priv->input_id = pinos_port_add_send_buffer_cb (priv->input, - on_input_send, + priv->input_id = pinos_port_add_send_cb (priv->input, + on_input_buffer, + on_input_event, link, NULL); - g_object_get (priv->input, "possible-formats", &formats, NULL); - g_object_set (priv->output, "possible-formats", formats, NULL); - g_object_get (priv->output, "format", &formats, NULL); - g_object_set (priv->input, "format", formats, NULL); - - g_signal_connect (priv->output, "notify::format", (GCallback) on_format_change, link); - g_signal_connect (priv->input, "activate", (GCallback) on_activate, link); g_signal_connect (priv->input, "deactivate", (GCallback) on_deactivate, link); g_signal_connect (priv->output, "activate", (GCallback) on_activate, link); @@ -291,8 +419,8 @@ pinos_link_dispose (GObject * object) g_debug ("link %p: dispose", link); - pinos_port_remove_send_buffer_cb (priv->input, priv->input_id); - pinos_port_remove_send_buffer_cb (priv->output, priv->output_id); + pinos_port_remove_send_cb (priv->input, priv->input_id); + pinos_port_remove_send_cb (priv->output, priv->output_id); if (priv->active) { priv->active = FALSE; pinos_port_deactivate (priv->input); @@ -415,7 +543,7 @@ pinos_link_new (PinosDaemon *daemon, PinosLink *link; PinosPort *tmp; - if (pinos_port_get_direction (output) != PINOS_DIRECTION_OUTPUT) { + if (output->direction != PINOS_DIRECTION_OUTPUT) { tmp = output; output = input; input = tmp; diff --git a/pinos/server/node.c b/pinos/server/node.c index 541d4823d..61086919d 100644 --- a/pinos/server/node.c +++ b/pinos/server/node.c @@ -63,6 +63,7 @@ enum PROP_NAME, PROP_STATE, PROP_PROPERTIES, + PROP_NODE, }; enum @@ -239,6 +240,10 @@ pinos_node_get_property (GObject *_object, g_value_set_boxed (value, priv->properties); break; + case PROP_NODE: + g_value_set_pointer (value, node->node); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (node, prop_id, pspec); break; @@ -273,6 +278,10 @@ pinos_node_set_property (GObject *_object, priv->properties = g_value_dup_boxed (value); break; + case PROP_NODE: + node->node = g_value_get_pointer (value); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (node, prop_id, pspec); break; @@ -456,6 +465,15 @@ pinos_node_class_init (PinosNodeClass * klass) G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, + PROP_NODE, + g_param_spec_pointer ("node", + "Node", + "The SPA node", + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + signals[SIGNAL_REMOVE] = g_signal_new ("remove", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, @@ -509,7 +527,8 @@ PinosNode * pinos_node_new (PinosDaemon *daemon, const gchar *sender, const gchar *name, - PinosProperties *properties) + PinosProperties *properties, + SpaNode *node) { g_return_val_if_fail (PINOS_IS_DAEMON (daemon), NULL); @@ -518,6 +537,7 @@ pinos_node_new (PinosDaemon *daemon, "sender", sender, "name", name, "properties", properties, + "node", node, NULL); } @@ -653,7 +673,7 @@ pinos_node_remove (PinosNode *node) static void do_remove_port (PinosPort *port, PinosNode *node) { - pinos_node_remove_port (node, pinos_port_get_id (port)); + pinos_node_remove_port (node, port->id); } /** diff --git a/pinos/server/node.h b/pinos/server/node.h index 6b030db91..51c0a11e3 100644 --- a/pinos/server/node.h +++ b/pinos/server/node.h @@ -28,6 +28,8 @@ typedef struct _PinosNode PinosNode; typedef struct _PinosNodeClass PinosNodeClass; typedef struct _PinosNodePrivate PinosNodePrivate; +#include + #include #include #include @@ -49,6 +51,8 @@ typedef struct _PinosNodePrivate PinosNodePrivate; struct _PinosNode { GObject object; + SpaNode *node; + PinosNodePrivate *priv; }; @@ -78,7 +82,8 @@ GType pinos_node_get_type (void); PinosNode * pinos_node_new (PinosDaemon *daemon, const gchar *sender, const gchar *name, - PinosProperties *properties); + PinosProperties *properties, + SpaNode *node); void pinos_node_remove (PinosNode *node); const gchar * pinos_node_get_name (PinosNode *node); diff --git a/pinos/server/port.c b/pinos/server/port.c index ad95350dd..be405e121 100644 --- a/pinos/server/port.c +++ b/pinos/server/port.c @@ -40,25 +40,25 @@ typedef struct { gulong id; PinosBufferCallback send_buffer_cb; - gpointer send_buffer_data; - GDestroyNotify send_buffer_notify; + PinosEventCallback send_event_cb; + gpointer send_data; + GDestroyNotify send_notify; } SendData; struct _PinosPortPrivate { PinosDaemon *daemon; - guint id; + gulong data_id; - PinosNode *node; - PinosDirection direction; GBytes *possible_formats; GBytes *format; PinosProperties *properties; PinosBufferCallback received_buffer_cb; - gpointer received_buffer_data; - GDestroyNotify received_buffer_notify; + PinosEventCallback received_event_cb; + gpointer received_data; + GDestroyNotify received_notify; gint active_count; @@ -92,10 +92,11 @@ static guint signals[LAST_SIGNAL] = { 0 }; void -pinos_port_set_received_buffer_cb (PinosPort *port, - PinosBufferCallback cb, - gpointer user_data, - GDestroyNotify notify) +pinos_port_set_received_cb (PinosPort *port, + PinosBufferCallback buffer_cb, + PinosEventCallback event_cb, + gpointer user_data, + GDestroyNotify notify) { PinosPortPrivate *priv; @@ -104,41 +105,45 @@ pinos_port_set_received_buffer_cb (PinosPort *port, g_debug ("port %p: set receive callback", port); - if (priv->received_buffer_notify) - priv->received_buffer_notify (priv->received_buffer_data);; - priv->received_buffer_cb = cb; - priv->received_buffer_data = user_data; - priv->received_buffer_notify = notify; + if (priv->received_notify) + priv->received_notify (priv->received_data);; + priv->received_buffer_cb = buffer_cb; + priv->received_event_cb = event_cb; + priv->received_data = user_data; + priv->received_notify = notify; } gulong -pinos_port_add_send_buffer_cb (PinosPort *port, - PinosBufferCallback cb, - gpointer user_data, - GDestroyNotify notify) +pinos_port_add_send_cb (PinosPort *port, + PinosBufferCallback buffer_cb, + PinosEventCallback event_cb, + gpointer user_data, + GDestroyNotify notify) { PinosPortPrivate *priv; SendData *data; g_return_val_if_fail (PINOS_IS_PORT (port), -1); - g_return_val_if_fail (cb != NULL, -1); + g_return_val_if_fail (buffer_cb != NULL, -1); + g_return_val_if_fail (event_cb != NULL, -1); priv = port->priv; g_debug ("port %p: add send callback", port); data = g_slice_new (SendData); - data->id = priv->id++; - data->send_buffer_cb = cb; - data->send_buffer_data = user_data; - data->send_buffer_notify = notify; + data->id = priv->data_id++; + data->send_buffer_cb = buffer_cb; + data->send_event_cb = event_cb; + data->send_data = user_data; + data->send_notify = notify; priv->send_datas = g_list_prepend (priv->send_datas, data); return data->id; } void -pinos_port_remove_send_buffer_cb (PinosPort *port, - gulong id) +pinos_port_remove_send_cb (PinosPort *port, + gulong id) { PinosPortPrivate *priv; GList *walk; @@ -151,8 +156,8 @@ pinos_port_remove_send_buffer_cb (PinosPort *port, SendData *data = walk->data; if (data->id == id) { - if (data->send_buffer_notify) - data->send_buffer_notify (data->send_buffer_data);; + if (data->send_notify) + data->send_notify (data->send_data);; g_slice_free (SendData, data); priv->send_datas = g_list_delete_link (priv->send_datas, walk); break; @@ -175,15 +180,15 @@ pinos_port_get_property (GObject *_object, break; case PROP_NODE: - g_value_set_object (value, priv->node); + g_value_set_object (value, port->node); break; case PROP_DIRECTION: - g_value_set_enum (value, priv->direction); + g_value_set_enum (value, port->direction); break; case PROP_ID: - g_value_set_uint (value, priv->id); + g_value_set_uint (value, port->id); break; case PROP_POSSIBLE_FORMATS: @@ -219,15 +224,15 @@ pinos_port_set_property (GObject *_object, break; case PROP_NODE: - priv->node = g_value_get_object (value); + port->node = g_value_get_object (value); break; case PROP_DIRECTION: - priv->direction = g_value_get_enum (value); + port->direction = g_value_get_enum (value); break; case PROP_ID: - priv->id = g_value_get_uint (value); + port->id = g_value_get_uint (value); break; case PROP_POSSIBLE_FORMATS: @@ -285,12 +290,12 @@ pinos_port_finalize (GObject * object) g_clear_pointer (&priv->possible_formats, g_bytes_unref); g_clear_pointer (&priv->format, g_bytes_unref); g_clear_pointer (&priv->properties, pinos_properties_free); - if (priv->received_buffer_notify) - priv->received_buffer_notify (priv->received_buffer_data); + if (priv->received_notify) + priv->received_notify (priv->received_data); for (walk = priv->send_datas; walk; walk = g_list_next (walk)) { SendData *data = walk->data; - if (data->send_buffer_notify) - data->send_buffer_notify (data->send_buffer_data); + if (data->send_notify) + data->send_notify (data->send_data); g_slice_free (SendData, data); } g_list_free (priv->send_datas); @@ -435,7 +440,7 @@ pinos_port_init (PinosPort * port) PinosPortPrivate *priv = port->priv = PINOS_PORT_GET_PRIVATE (port); g_debug ("port %p: new", port); - priv->direction = PINOS_DIRECTION_INVALID; + port->direction = PINOS_DIRECTION_INVALID; } /** @@ -453,63 +458,6 @@ pinos_port_remove (PinosPort *port) g_signal_emit (port, signals[SIGNAL_REMOVE], 0, NULL); } -/** - * pinos_port_get_node: - * @port: a #PinosPort - * - * Get the parent #PinosNode of @port - * - * Returns: the parent node or %NULL - */ -PinosNode * -pinos_port_get_node (PinosPort *port) -{ - PinosPortPrivate *priv; - - g_return_val_if_fail (PINOS_IS_PORT (port), NULL); - priv = port->priv; - - return priv->node; -} - -/** - * pinos_port_get_direction: - * @port: a #PinosPort - * - * Get the direction of @port - * - * Returns: the direction or %NULL - */ -PinosDirection -pinos_port_get_direction (PinosPort *port) -{ - PinosPortPrivate *priv; - - g_return_val_if_fail (PINOS_IS_PORT (port), PINOS_DIRECTION_INVALID); - priv = port->priv; - - return priv->direction; -} - -/** - * pinos_port_get_id: - * @port: a #PinosPort - * - * Get the id of @port - * - * Returns: the id or %NULL - */ -guint -pinos_port_get_id (PinosPort *port) -{ - PinosPortPrivate *priv; - - g_return_val_if_fail (PINOS_IS_PORT (port), -1); - priv = port->priv; - - return priv->id; -} - /** * pinos_port_get_possible_formats: * @port: a #PinosPort @@ -625,11 +573,10 @@ pinos_port_deactivate (PinosPort *port) g_signal_emit (port, signals[SIGNAL_DEACTIVATE], 0, NULL); } - /** * pinos_port_receive_buffer: * @port: a #PinosPort - * @buffer: a #PinosBuffer + * @buffer_id: a buffer id * @error: a #GError or %NULL * * Receive @buffer on @port @@ -638,16 +585,42 @@ pinos_port_deactivate (PinosPort *port) */ gboolean pinos_port_receive_buffer (PinosPort *port, - SpaBuffer *buffer, + uint32_t buffer_id, GError **error) { gboolean res = TRUE; PinosPortPrivate *priv = port->priv; - PINOS_DEBUG_TRANSPORT ("port %p: receive buffer %p", port, buffer); + PINOS_DEBUG_TRANSPORT ("port %p: receive buffer %d", port, buffer_id); if (priv->received_buffer_cb) - res = priv->received_buffer_cb (port, buffer, error, priv->received_buffer_data); + res = priv->received_buffer_cb (port, buffer_id, error, priv->received_data); + + return res; +} + +/** + * pinos_port_receive_event: + * @port: a #PinosPort + * @event: a #SpaEvent + * @error: a #GError or %NULL + * + * Receive @event on @port + * + * Returns: %TRUE on success. @error is set when %FALSE is returned. + */ +gboolean +pinos_port_receive_event (PinosPort *port, + SpaEvent *event, + GError **error) +{ + gboolean res = TRUE; + PinosPortPrivate *priv = port->priv; + + PINOS_DEBUG_TRANSPORT ("port %p: receive event %p", port, event); + + if (priv->received_event_cb) + res = priv->received_event_cb (port, event, error, priv->received_data); return res; } @@ -655,7 +628,7 @@ pinos_port_receive_buffer (PinosPort *port, /** * pinos_port_send_buffer: * @port: a #PinosPort - * @buffer: a #SpaBuffer + * @buffer_id: a buffer id * @error: a #GError or %NULL * * Send @buffer out on @port. @@ -664,7 +637,7 @@ pinos_port_receive_buffer (PinosPort *port, */ gboolean pinos_port_send_buffer (PinosPort *port, - SpaBuffer *buffer, + uint32_t buffer_id, GError **error) { gboolean res = TRUE; @@ -673,13 +646,45 @@ pinos_port_send_buffer (PinosPort *port, g_return_val_if_fail (PINOS_IS_PORT (port), FALSE); - PINOS_DEBUG_TRANSPORT ("port %p: send buffer %p", port, buffer); + PINOS_DEBUG_TRANSPORT ("port %p: send buffer %d", port, buffer_id); priv = port->priv; for (walk = priv->send_datas; walk; walk = g_list_next (walk)) { SendData *data = walk->data; - data->send_buffer_cb (port, buffer, error, data->send_buffer_data); + data->send_buffer_cb (port, buffer_id, error, data->send_data); + } + return res; +} + +/** + * pinos_port_send_event: + * @port: a #PinosPort + * @event: a #SpaEvent + * @error: a #GError or %NULL + * + * Send @event out on @port. + * + * Returns: %TRUE on success. @error is set when %FALSE is returned. + */ +gboolean +pinos_port_send_event (PinosPort *port, + SpaEvent *event, + GError **error) +{ + gboolean res = TRUE; + PinosPortPrivate *priv; + GList *walk; + + g_return_val_if_fail (PINOS_IS_PORT (port), FALSE); + + PINOS_DEBUG_TRANSPORT ("port %p: send event %p", port, event); + + priv = port->priv; + + for (walk = priv->send_datas; walk; walk = g_list_next (walk)) { + SendData *data = walk->data; + data->send_event_cb (port, event, error, data->send_data); } return res; } diff --git a/pinos/server/port.h b/pinos/server/port.h index ca31b7490..09e27f124 100644 --- a/pinos/server/port.h +++ b/pinos/server/port.h @@ -51,6 +51,10 @@ typedef struct _PinosPortPrivate PinosPortPrivate; struct _PinosPort { GObject object; + PinosDirection direction; + uint32_t id; + PinosNode *node; + PinosPortPrivate *priv; }; @@ -67,28 +71,28 @@ struct _PinosPortClass { GTask *task); }; -typedef gboolean (*PinosBufferCallback) (PinosPort *port, SpaBuffer *buffer, GError **error, gpointer user_data); +typedef gboolean (*PinosBufferCallback) (PinosPort *port, uint32_t buffer_id, GError **error, gpointer user_data); +typedef gboolean (*PinosEventCallback) (PinosPort *port, SpaEvent *event, GError **error, gpointer user_data); /* normal GObject stuff */ GType pinos_port_get_type (void); -void pinos_port_set_received_buffer_cb (PinosPort *port, - PinosBufferCallback cb, +void pinos_port_set_received_cb (PinosPort *port, + PinosBufferCallback buffer_cb, + PinosEventCallback event_cb, gpointer user_data, GDestroyNotify notify); -gulong pinos_port_add_send_buffer_cb (PinosPort *port, - PinosBufferCallback cb, +gulong pinos_port_add_send_cb (PinosPort *port, + PinosBufferCallback buffer_cb, + PinosEventCallback event_cb, gpointer user_data, GDestroyNotify notify); -void pinos_port_remove_send_buffer_cb (PinosPort *port, +void pinos_port_remove_send_cb (PinosPort *port, gulong id); void pinos_port_remove (PinosPort *port); -PinosNode * pinos_port_get_node (PinosPort *port); const gchar * pinos_port_get_name (PinosPort *port); -PinosDirection pinos_port_get_direction (PinosPort *port); -guint pinos_port_get_id (PinosPort *port); PinosProperties * pinos_port_get_properties (PinosPort *port); GBytes * pinos_port_get_possible_formats (PinosPort *port); @@ -97,14 +101,21 @@ GBytes * pinos_port_filter_formats (PinosPort *port, GError **error); GBytes * pinos_port_get_format (PinosPort *port); + void pinos_port_activate (PinosPort *port); void pinos_port_deactivate (PinosPort *port); gboolean pinos_port_send_buffer (PinosPort *port, - SpaBuffer *buffer, + uint32_t buffer_id, + GError **error); +gboolean pinos_port_send_event (PinosPort *port, + SpaEvent *event, GError **error); gboolean pinos_port_receive_buffer (PinosPort *port, - SpaBuffer *buffer, + uint32_t buffer_id, + GError **error); +gboolean pinos_port_receive_event (PinosPort *port, + SpaEvent *event, GError **error); G_END_DECLS diff --git a/spa/include/spa/buffer.h b/spa/include/spa/buffer.h index e0b231362..59e8ad752 100644 --- a/spa/include/spa/buffer.h +++ b/spa/include/spa/buffer.h @@ -138,9 +138,6 @@ typedef struct { /** * SpaBuffer: - * @refcount: reference counter - * @notify: called when the refcount reaches 0 - * @user_data: extra user data * @id: buffer id * @size: total size of the buffer data * @n_metas: number of metadata @@ -149,9 +146,6 @@ typedef struct { * @datas: array of @n_datas data pointers */ struct _SpaBuffer { - volatile int refcount; - SpaNotify notify; - void *user_data; uint32_t id; size_t size; unsigned int n_metas; @@ -160,44 +154,6 @@ struct _SpaBuffer { SpaData *datas; }; -/** - * spa_buffer_ref: - * @buffer: a #SpaBuffer - * - * Increase the refcount on @buffer - * - * Returns: @buffer - */ -static inline SpaBuffer * -spa_buffer_ref (SpaBuffer *buffer) -{ - if (buffer != NULL) - buffer->refcount++; - return buffer; -} - -/** - * spa_buffer_unref: - * @buffer: a #SpaBuffer - * - * Decrease the refcount on buffer. when the refcount is 0, the notify, - * if any, of the buffer will be called. - * - * Returns: @buffer or %NULL when the refcount is 0 - */ -static inline SpaBuffer * -spa_buffer_unref (SpaBuffer *buffer) -{ - if (buffer != NULL) { - if (--buffer->refcount == 0) { - if (buffer->notify) - buffer->notify (buffer); - return NULL; - } - } - return buffer; -} - #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/spa/include/spa/command.h b/spa/include/spa/command.h index e61fd24eb..18aa04eca 100644 --- a/spa/include/spa/command.h +++ b/spa/include/spa/command.h @@ -38,8 +38,6 @@ typedef enum { } SpaCommandType; struct _SpaCommand { - volatile int refcount; - SpaNotify notify; SpaCommandType type; uint32_t port_id; void *data; diff --git a/spa/include/spa/control.h b/spa/include/spa/control.h index eb547bba8..ebd4ca312 100644 --- a/spa/include/spa/control.h +++ b/spa/include/spa/control.h @@ -34,6 +34,7 @@ typedef struct _SpaControlBuilder SpaControlBuilder; #include #include #include +#include struct _SpaControl { size_t x[16]; @@ -59,13 +60,12 @@ typedef enum { SPA_CONTROL_CMD_PORT_UPDATE = 2, SPA_CONTROL_CMD_PORT_REMOVED = 3, - SPA_CONTROL_CMD_START_CONFIGURE = 4, + SPA_CONTROL_CMD_STATE_CHANGE = 4, SPA_CONTROL_CMD_PORT_STATUS_CHANGE = 5, - SPA_CONTROL_CMD_START_ALLOC = 6, - SPA_CONTROL_CMD_NEED_INPUT = 7, - SPA_CONTROL_CMD_HAVE_OUTPUT = 8, + SPA_CONTROL_CMD_NEED_INPUT = 6, + SPA_CONTROL_CMD_HAVE_OUTPUT = 7, /* server to client */ SPA_CONTROL_CMD_ADD_PORT = 32, @@ -73,11 +73,9 @@ typedef enum { SPA_CONTROL_CMD_SET_FORMAT = 34, SPA_CONTROL_CMD_SET_PROPERTY = 35, - SPA_CONTROL_CMD_END_CONFIGURE = 36, - SPA_CONTROL_CMD_PAUSE = 37, - SPA_CONTROL_CMD_START = 38, - SPA_CONTROL_CMD_STOP = 39, + SPA_CONTROL_CMD_START = 36, + SPA_CONTROL_CMD_STOP = 37, /* both */ SPA_CONTROL_CMD_ADD_MEM = 64, @@ -100,7 +98,7 @@ typedef struct { /* SPA_CONTROL_CMD_PORT_UPDATE */ typedef struct { - uint32_t port; + uint32_t port_id; uint32_t change_mask; uint32_t direction; uint32_t n_possible_formats; @@ -111,65 +109,61 @@ typedef struct { /* SPA_CONTROL_CMD_PORT_REMOVED */ typedef struct { - uint32_t port; + uint32_t port_id; } SpaControlCmdPortRemoved; -/* SPA_CONTROL_CMD_START_CONFIGURE */ +/* SPA_CONTROL_CMD_STATE_CHANGE */ +typedef struct { + SpaNodeState state; +} SpaControlCmdStateChange; /* SPA_CONTROL_CMD_PORT_STATUS_CHANGE */ -/* SPA_CONTROL_CMD_START_ALLOC */ - /* SPA_CONTROL_CMD_NEED_INPUT */ typedef struct { - uint32_t port; + uint32_t port_id; } SpaControlCmdNeedInput; /* SPA_CONTROL_CMD_HAVE_OUTPUT */ typedef struct { - uint32_t port; + uint32_t port_id; } SpaControlCmdHaveOutput; /* SPA_CONTROL_CMD_ADD_PORT */ typedef struct { - uint32_t port; + uint32_t port_id; uint32_t direction; } SpaControlCmdAddPort; /* SPA_CONTROL_CMD_REMOVE_PORT */ typedef struct { - uint32_t port; + uint32_t port_id; } SpaControlCmdRemovePort; /* SPA_CONTROL_CMD_SET_FORMAT */ typedef struct { - uint32_t port; + uint32_t port_id; const SpaFormat *format; - const char *str; } SpaControlCmdSetFormat; /* SPA_CONTROL_CMD_SET_PROPERTY */ typedef struct { - uint32_t port; + uint32_t port_id; uint32_t id; uint32_t size; void *value; } SpaControlCmdSetProperty; -/* SPA_CONTROL_CMD_END_CONFIGURE */ - /* SPA_CONTROL_CMD_PAUSE */ /* SPA_CONTROL_CMD_START */ -/* SPA_CONTROL_CMD_STOP */ - /* SPA_CONTROL_CMD_ADD_MEM */ typedef struct { - uint32_t port; - uint32_t id; - uint32_t type; + uint32_t port_id; + uint32_t mem_id; + uint32_t mem_type; uint32_t fd_index; uint64_t offset; uint64_t size; @@ -177,32 +171,36 @@ typedef struct { /* SPA_CONTROL_CMD_REMOVE_MEM */ typedef struct { - uint32_t port; - uint32_t id; + uint32_t port_id; + uint32_t mem_id; } SpaControlCmdRemoveMem; /* SPA_CONTROL_CMD_ADD_BUFFER */ typedef struct { - uint32_t port; + uint32_t port_id; SpaBuffer *buffer; } SpaControlCmdAddBuffer; /* SPA_CONTROL_CMD_REMOVE_BUFFER */ typedef struct { - uint32_t port; - uint32_t id; + uint32_t port_id; + uint32_t buffer_id; } SpaControlCmdRemoveBuffer; /* SPA_CONTROL_CMD_PROCESS_BUFFER */ typedef struct { - uint32_t port; - uint32_t id; + uint32_t port_id; + uint32_t buffer_id; + uint64_t offset; + uint64_t size; } SpaControlCmdProcessBuffer; /* SPA_CONTROL_CMD_REUSE_BUFFER */ typedef struct { - uint32_t port; - uint32_t id; + uint32_t port_id; + uint32_t buffer_id; + uint64_t offset; + uint64_t size; } SpaControlCmdReuseBuffer; diff --git a/spa/include/spa/defs.h b/spa/include/spa/defs.h index c1eecfefb..439784c84 100644 --- a/spa/include/spa/defs.h +++ b/spa/include/spa/defs.h @@ -55,6 +55,8 @@ typedef enum { SPA_RESULT_TOO_MANY_PORTS = -24, SPA_RESULT_INVALID_PROPERTY_ACCESS = -25, SPA_RESULT_UNEXPECTED = -26, + SPA_RESULT_NO_BUFFERS = -27, + SPA_RESULT_INVALID_BUFFER_ID = -28, } SpaResult; typedef enum { @@ -69,6 +71,9 @@ typedef void (*SpaNotify) (void *data); #define SPA_MIN(a,b) ((a)<(b) ? (a) : (b)) #define SPA_MAX(a,b) ((a)>(b) ? (a) : (b)) +#define SPA_ID_INVALID ((uint32_t)0xffffffff) + + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/spa/include/spa/event.h b/spa/include/spa/event.h index 80038e28a..985b9143a 100644 --- a/spa/include/spa/event.h +++ b/spa/include/spa/event.h @@ -28,17 +28,17 @@ typedef struct _SpaEvent SpaEvent; #include #include +#include /** * SpaEventType: * @SPA_EVENT_TYPE_INVALID: invalid event, should be ignored - * @SPA_EVENT_TYPE_STARTED: emited when the START command completes - * @SPA_EVENT_TYPE_STOPPED: emited when the STOP command completes + * @SPA_EVENT_TYPE_STATE_CHANGE: emited when the state changes * @SPA_EVENT_TYPE_CAN_PULL_OUTPUT: emited when an async node has output that can be pulled * @SPA_EVENT_TYPE_CAN_PUSH_INPUT: emited when more data can be pushed to an async node * @SPA_EVENT_TYPE_PULL_INPUT: emited when data needs to be provided on an input. data points to - * buffer to fill. - * @SPA_EVENT_TYPE_ALLOC_OUTPUT: emited when an output buffer needs to be allocated + * SpaEventPullInput + * @SPA_EVENT_TYPE_REUSE_BUFFER: emited when a buffer can be reused * @SPA_EVENT_TYPE_ADD_POLL: emited when a pollfd should be added. data points to #SpaPollItem * @SPA_EVENT_TYPE_REMOVE_POLL: emited when a pollfd should be removed. data points to #SpaPollItem * @SPA_EVENT_TYPE_DRAINED: emited when DRAIN command completed @@ -49,12 +49,11 @@ typedef struct _SpaEvent SpaEvent; */ typedef enum { SPA_EVENT_TYPE_INVALID = 0, - SPA_EVENT_TYPE_STARTED, - SPA_EVENT_TYPE_STOPPED, + SPA_EVENT_TYPE_STATE_CHANGE, SPA_EVENT_TYPE_CAN_PULL_OUTPUT, SPA_EVENT_TYPE_CAN_PUSH_INPUT, SPA_EVENT_TYPE_PULL_INPUT, - SPA_EVENT_TYPE_ALLOC_OUTPUT, + SPA_EVENT_TYPE_REUSE_BUFFER, SPA_EVENT_TYPE_ADD_POLL, SPA_EVENT_TYPE_REMOVE_POLL, SPA_EVENT_TYPE_DRAINED, @@ -65,8 +64,6 @@ typedef enum { } SpaEventType; struct _SpaEvent { - volatile int refcount; - SpaNotify notify; SpaEventType type; uint32_t port_id; void *data; @@ -74,10 +71,21 @@ struct _SpaEvent { }; typedef struct { + uint32_t buffer_id; off_t offset; size_t size; } SpaEventPullInput; +typedef struct { + SpaNodeState state; +} SpaEventStateChange; + +typedef struct { + uint32_t buffer_id; + off_t offset; + size_t size; +} SpaEventReuseBuffer; + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/spa/include/spa/node.h b/spa/include/spa/node.h index b68f2560e..65da279ec 100644 --- a/spa/include/spa/node.h +++ b/spa/include/spa/node.h @@ -26,6 +26,24 @@ extern "C" { typedef struct _SpaNode SpaNode; +/** + * SpaNodeState: + * @SPA_NODE_STATE_INIT: the node is initializing + * @SPA_NODE_STATE_CONFIGURE: the node needs at least one port format + * @SPA_NODE_STATE_READY: the node is ready for memory allocation + * @SPA_NODE_STATE_STREAMING: the node is streaming + * @SPA_NODE_STATE_ERROR: the node is in error + */ +typedef enum { + SPA_NODE_STATE_INIT, + SPA_NODE_STATE_CONFIGURE, + SPA_NODE_STATE_READY, + SPA_NODE_STATE_PAUSED, + SPA_NODE_STATE_STREAMING, + SPA_NODE_STATE_ERROR +} SpaNodeState; + + #include #include #include @@ -62,18 +80,19 @@ typedef enum { * SpaInputInfo: * @port_id: the port id * @flags: extra flags + * @buffer_id: a buffer id * @offset: offset of data in @id * @size: size of data in @id - * @id: a buffer id + * @status: status * * Input information for a node. */ typedef struct { uint32_t port_id; SpaInputFlags flags; + uint32_t buffer_id; off_t offset; size_t size; - uint32_t id; SpaResult status; } SpaInputInfo; @@ -96,36 +115,22 @@ typedef enum { * SpaOutputInfo: * @port_id: the port id * @flags: extra flags + * @buffer_id: a buffer id will be set * @offset: offset to get * @size: size to get - * @id: a buffer id will be set - * @event: an event + * @status: a status * * Output information for a node. */ typedef struct { uint32_t port_id; SpaOutputFlags flags; + uint32_t buffer_id; off_t offset; size_t size; - uint32_t id; SpaResult status; } SpaOutputInfo; -/** - * SpaNodeState: - * @SPA_NODE_STATE_INIT: the node is initializing - * @SPA_NODE_STATE_CONFIGURE: the node needs at least one port format - * @SPA_NODE_STATE_READY: the node is ready for memory allocation - * @SPA_NODE_STREAMING: the node is streaming - */ -typedef enum { - SPA_NODE_STATE_INIT, - SPA_NODE_STATE_CONFIGURE, - SPA_NODE_STATE_READY, - SPA_NODE_STATE_STREAMING -} SpaNodeState; - /** * SpaEventCallback: * @node: a #SpaNode emiting the event @@ -371,6 +376,9 @@ struct _SpaNode { * will be set by @node so that buffers will be reused when the refcount * reaches 0. * + * Passing %NULL as @buffers will remove the reference that the port has + * on the buffers. + * * Returns: #SPA_RESULT_OK on success */ SpaResult (*port_use_buffers) (SpaNode *node, @@ -404,6 +412,12 @@ struct _SpaNode { SpaBuffer **buffers, unsigned int *n_buffers); + SpaResult (*port_reuse_buffer) (SpaNode *node, + uint32_t port_id, + uint32_t buffer_id, + off_t offset, + size_t size); + SpaResult (*port_get_status) (SpaNode *node, uint32_t port_id, const SpaPortStatus **status); @@ -473,6 +487,7 @@ struct _SpaNode { #define spa_node_port_set_props(n,...) (n)->port_set_props((n),__VA_ARGS__) #define spa_node_port_use_buffers(n,...) (n)->port_use_buffers((n),__VA_ARGS__) #define spa_node_port_alloc_buffers(n,...) (n)->port_alloc_buffers((n),__VA_ARGS__) +#define spa_node_port_reuse_buffer(n,...) (n)->port_reuse_buffer((n),__VA_ARGS__) #define spa_node_port_get_status(n,...) (n)->port_get_status((n),__VA_ARGS__) #define spa_node_port_push_input(n,...) (n)->port_push_input((n),__VA_ARGS__) #define spa_node_port_pull_output(n,...) (n)->port_pull_output((n),__VA_ARGS__) diff --git a/spa/include/spa/port.h b/spa/include/spa/port.h index 139b25b5f..997318e7c 100644 --- a/spa/include/spa/port.h +++ b/spa/include/spa/port.h @@ -30,6 +30,7 @@ extern "C" { /** * SpaAllocParamType: * @SPA_ALLOC_PARAM_TYPE_INVALID: invalid type, should be ignored + * @SPA_ALLOC_PARAM_TYPE_BUFFER: buffer requirements * @SPA_ALLOC_PARAM_TYPE_META_ENABLE: enable a certain metadata on buffers * @SPA_ALLOC_PARAM_TYPE_VIDEO_PADDING: do specialized video padding */ @@ -92,11 +93,6 @@ typedef enum { /** * SpaPortInfo * @flags: extra port flags - * @minsize: minimum size of the buffers or 0 when not specified - * @stride: suggested stride or 0 when not specified - * @min_buffers: minimum number of buffers - * @max_buffers: maximum number of buffers - * @align: required alignment of the data * @maxbuffering: the maximum amount of bytes that the element will keep * around internally * @latency: latency on this port in nanoseconds diff --git a/spa/lib/control.c b/spa/lib/control.c index db31963bb..3f0b90df6 100644 --- a/spa/lib/control.c +++ b/spa/lib/control.c @@ -355,10 +355,8 @@ parse_add_buffer (struct stack_iter *si, uint32_t *p = si->data; unsigned int i; - command->port = *p++; + command->port_id = *p++; b = malloc (sizeof (MyBuffer)); - b->buffer.refcount = 1; - b->buffer.notify = free; b->buffer.id = *(uint32_t *)p++; b->buffer.size = *(uint32_t *)p++; b->buffer.n_metas = *(uint32_t *)p++; @@ -411,9 +409,14 @@ spa_control_iter_parse_cmd (SpaControlIter *iter, memcpy (command, si->data, sizeof (SpaControlCmdPortRemoved)); break; - case SPA_CONTROL_CMD_START_CONFIGURE: + case SPA_CONTROL_CMD_STATE_CHANGE: + if (si->size < sizeof (SpaControlCmdStateChange)) + return SPA_RESULT_ERROR; + memcpy (command, si->data, sizeof (SpaControlCmdStateChange)); + break; + case SPA_CONTROL_CMD_PORT_STATUS_CHANGE: - case SPA_CONTROL_CMD_START_ALLOC: + fprintf (stderr, "implement iter of %d\n", si->cmd); break; case SPA_CONTROL_CMD_NEED_INPUT: @@ -447,8 +450,8 @@ spa_control_iter_parse_cmd (SpaControlIter *iter, uint32_t *p = si->data; cmd = command; - cmd->port = *p++; - cmd->str = (char *)p; + cmd->port_id = *p++; + cmd->format = (const SpaFormat *)p; break; } @@ -456,8 +459,6 @@ spa_control_iter_parse_cmd (SpaControlIter *iter, fprintf (stderr, "implement iter of %d\n", si->cmd); break; - case SPA_CONTROL_CMD_END_CONFIGURE: - case SPA_CONTROL_CMD_PAUSE: case SPA_CONTROL_CMD_START: case SPA_CONTROL_CMD_STOP: break; @@ -636,8 +637,6 @@ spa_control_builder_end (SpaControlBuilder *builder, sc->max_fds = sb->control.max_fds; sc->free_fds = sb->control.free_fds; - SPA_DEBUG_CONTROL ("builder %p: control %p init", builder, control); - return SPA_RESULT_OK; } @@ -743,7 +742,7 @@ build_add_buffer (struct stack_builder *sb, } p = builder_add_cmd (sb, SPA_CONTROL_CMD_ADD_BUFFER, size); - *p++ = command->port; + *p++ = command->port_id; *p++ = b->id; *p++ = b->size; *p++ = b->n_metas; @@ -803,12 +802,12 @@ spa_control_builder_add_cmd (SpaControlBuilder *builder, memcpy (p, command, sizeof (SpaControlCmdPortRemoved)); break; - case SPA_CONTROL_CMD_START_CONFIGURE: - p = builder_add_cmd (sb, cmd, 0); + case SPA_CONTROL_CMD_STATE_CHANGE: + p = builder_add_cmd (sb, cmd, sizeof (SpaControlCmdStateChange)); + memcpy (p, command, sizeof (SpaControlCmdStateChange)); break; case SPA_CONTROL_CMD_PORT_STATUS_CHANGE: - case SPA_CONTROL_CMD_START_ALLOC: p = builder_add_cmd (sb, cmd, 0); break; @@ -839,13 +838,13 @@ spa_control_builder_add_cmd (SpaControlBuilder *builder, SpaControlCmdSetFormat *sf = command; uint32_t *p; - slen = strlen (sf->str)+1; + slen = strlen ("")+1; /* port + string */ len = 4 + slen; p = builder_add_cmd (sb, cmd, len); - *p++ = sf->port; - memcpy ((char*)p, sf->str, slen); + *p++ = sf->port_id; + memcpy ((char*)p, sf->format, slen); break; } @@ -853,11 +852,6 @@ spa_control_builder_add_cmd (SpaControlBuilder *builder, fprintf (stderr, "implement builder of %d\n", cmd); break; - case SPA_CONTROL_CMD_END_CONFIGURE: - p = builder_add_cmd (sb, cmd, 0); - break; - - case SPA_CONTROL_CMD_PAUSE: case SPA_CONTROL_CMD_START: case SPA_CONTROL_CMD_STOP: p = builder_add_cmd (sb, cmd, 0); @@ -986,6 +980,8 @@ spa_control_read (SpaControl *control, } sc->magic = SSC_MAGIC; + SPA_DEBUG_CONTROL ("read %zd bytes and %d fds\n", len, sc->n_fds); + return SPA_RESULT_OK; /* ERRORS */ @@ -1037,6 +1033,8 @@ spa_control_write (SpaControl *control, if (len != (ssize_t) sc->size) return SPA_RESULT_ERROR; + SPA_DEBUG_CONTROL ("written %zd bytes\n", len); + return SPA_RESULT_OK; /* ERRORS */ diff --git a/spa/plugins/alsa/alsa-sink.c b/spa/plugins/alsa/alsa-sink.c index ab2bbed42..0492b2053 100644 --- a/spa/plugins/alsa/alsa-sink.c +++ b/spa/plugins/alsa/alsa-sink.c @@ -89,7 +89,9 @@ struct _SpaALSASink { SpaPortInfo info; SpaPortStatus status; - SpaBuffer *input_buffer; + SpaBuffer *buffers; + unsigned int n_buffers; + uint32_t input_buffer; ALSABuffer buffer; }; @@ -233,13 +235,13 @@ spa_alsa_sink_node_send_command (SpaNode *node, if (this->event_cb) { SpaEvent event; + SpaEventStateChange sc; - event.refcount = 1; - event.notify = NULL; - event.type = SPA_EVENT_TYPE_STARTED; + event.type = SPA_EVENT_TYPE_STATE_CHANGE; event.port_id = -1; - event.data = NULL; - event.size = 0; + event.data = ≻ + event.size = sizeof (sc); + sc.state = SPA_NODE_STATE_STREAMING; this->event_cb (node, &event, this->user_data); } @@ -249,13 +251,13 @@ spa_alsa_sink_node_send_command (SpaNode *node, if (this->event_cb) { SpaEvent event; + SpaEventStateChange sc; - event.refcount = 1; - event.notify = NULL; - event.type = SPA_EVENT_TYPE_STOPPED; + event.type = SPA_EVENT_TYPE_STATE_CHANGE; event.port_id = -1; - event.data = NULL; - event.size = 0; + event.data = ≻ + event.size = sizeof (sc); + sc.state = SPA_NODE_STATE_STREAMING; this->event_cb (node, &event, this->user_data); } @@ -465,6 +467,36 @@ spa_alsa_sink_node_port_set_props (SpaNode *node, return SPA_RESULT_NOT_IMPLEMENTED; } +static SpaResult +spa_alsa_sink_node_port_use_buffers (SpaNode *node, + uint32_t port_id, + SpaBuffer **buffers, + uint32_t n_buffers) +{ + return SPA_RESULT_NOT_IMPLEMENTED; +} + +static SpaResult +spa_alsa_sink_node_port_alloc_buffers (SpaNode *node, + uint32_t port_id, + SpaAllocParam **params, + uint32_t n_params, + SpaBuffer **buffers, + uint32_t *n_buffers) +{ + return SPA_RESULT_NOT_IMPLEMENTED; +} + +static SpaResult +spa_alsa_sink_node_port_reuse_buffer (SpaNode *node, + uint32_t port_id, + uint32_t buffer_id, + off_t offset, + size_t size) +{ + return SPA_RESULT_NOT_IMPLEMENTED; +} + static SpaResult spa_alsa_sink_node_port_get_status (SpaNode *node, uint32_t port_id, @@ -485,32 +517,6 @@ spa_alsa_sink_node_port_get_status (SpaNode *node, return SPA_RESULT_OK; } -static SpaResult -spa_alsa_sink_node_port_use_buffers (SpaNode *node, - uint32_t port_id, - SpaBuffer **buffers, - uint32_t n_buffers) -{ - return SPA_RESULT_NOT_IMPLEMENTED; -} - -static SpaResult -spa_alsa_sink_node_port_alloc_buffers (SpaNode *node, - uint32_t port_id, - SpaAllocParam **params, - uint32_t n_params, - SpaBuffer **buffers, - uint32_t *n_buffers) -{ - return SPA_RESULT_NOT_IMPLEMENTED; -} - -static SpaBuffer * -find_buffer (SpaALSASink *this, uint32_t id) -{ - return NULL; -} - static SpaResult spa_alsa_sink_node_port_push_input (SpaNode *node, unsigned int n_info, @@ -526,29 +532,25 @@ spa_alsa_sink_node_port_push_input (SpaNode *node, this = (SpaALSASink *) node->handle; for (i = 0; i < n_info; i++) { - SpaBuffer *buffer; - if (info[i].port_id != 0) { info[i].status = SPA_RESULT_INVALID_PORT; have_error = true; continue; } - buffer = find_buffer (this, info[i].id); - - if (buffer != NULL) { + if (info[i].buffer_id != SPA_ID_INVALID) { if (!this->have_format) { info[i].status = SPA_RESULT_NO_FORMAT; have_error = true; continue; } - if (this->input_buffer != NULL) { + if (this->input_buffer != -1) { info[i].status = SPA_RESULT_HAVE_ENOUGH_INPUT; have_enough = true; continue; } - this->input_buffer = spa_buffer_ref (buffer); + this->input_buffer = info[i].buffer_id; } info[i].status = SPA_RESULT_OK; } @@ -587,6 +589,7 @@ static const SpaNode alsasink_node = { spa_alsa_sink_node_port_set_props, spa_alsa_sink_node_port_use_buffers, spa_alsa_sink_node_port_alloc_buffers, + spa_alsa_sink_node_port_reuse_buffer, spa_alsa_sink_node_port_get_status, spa_alsa_sink_node_port_push_input, spa_alsa_sink_node_port_pull_output, diff --git a/spa/plugins/alsa/alsa-utils.c b/spa/plugins/alsa/alsa-utils.c index d6fef1586..520f92846 100644 --- a/spa/plugins/alsa/alsa-utils.c +++ b/spa/plugins/alsa/alsa-utils.c @@ -205,40 +205,18 @@ static void pull_input (SpaALSASink *this, void *data, snd_pcm_uframes_t frames) { SpaEvent event; - ALSABuffer *buffer = &this->buffer; + SpaEventPullInput pi; - event.refcount = 1; - event.notify = NULL; event.type = SPA_EVENT_TYPE_PULL_INPUT; event.port_id = 0; event.size = frames * sizeof (uint16_t) * 2; - event.data = buffer; + event.data = π - buffer->buffer.refcount = 1; - buffer->buffer.notify = NULL; - buffer->buffer.size = frames * sizeof (uint16_t) * 2; - buffer->buffer.n_metas = 1; - buffer->buffer.metas = buffer->meta; - buffer->buffer.n_datas = 1; - buffer->buffer.datas = buffer->data; + pi.buffer_id = this->buffer.buffer.id; + pi.offset = 0; + pi.size = frames * sizeof (uint16_t) * 2; - buffer->header.flags = 0; - buffer->header.seq = 0; - buffer->header.pts = 0; - buffer->header.dts_offset = 0; - - buffer->meta[0].type = SPA_META_TYPE_HEADER; - buffer->meta[0].data = &buffer->header; - buffer->meta[0].size = sizeof (buffer->header); - - buffer->data[0].type = SPA_DATA_TYPE_MEMPTR; - buffer->data[0].ptr = data; - buffer->data[0].ptr_type = "sysmem"; - buffer->data[0].size = frames * sizeof (uint16_t) * 2; - - this->event_cb (&this->node, &event,this->user_data); - - spa_buffer_unref ((SpaBuffer *)event.data); + this->event_cb (&this->node, &event, this->user_data); } static int @@ -273,11 +251,10 @@ mmap_write (SpaALSASink *this) frames); if (this->input_buffer) { - if (this->input_buffer != &this->buffer.buffer) { + if (this->input_buffer != this->buffer.buffer.id) { /* FIXME, copy input */ } - spa_buffer_unref (this->input_buffer); - this->input_buffer = NULL; + this->input_buffer = -1; } commitres = snd_pcm_mmap_commit (handle, offset, frames); @@ -366,8 +343,6 @@ spa_alsa_start (SpaALSASink *this) return err; } - event.refcount = 1; - event.notify = NULL; event.type = SPA_EVENT_TYPE_ADD_POLL; event.port_id = 0; event.data = &state->poll; @@ -394,8 +369,6 @@ spa_alsa_stop (SpaALSASink *this) snd_pcm_drop (state->handle); - event.refcount = 1; - event.notify = NULL; event.type = SPA_EVENT_TYPE_REMOVE_POLL; event.port_id = 0; event.data = &state->poll; diff --git a/spa/plugins/audiomixer/audiomixer.c b/spa/plugins/audiomixer/audiomixer.c index e5d946279..cc382f1d1 100644 --- a/spa/plugins/audiomixer/audiomixer.c +++ b/spa/plugins/audiomixer/audiomixer.c @@ -148,13 +148,13 @@ spa_audiomixer_node_send_command (SpaNode *node, case SPA_COMMAND_START: if (this->event_cb) { SpaEvent event; + SpaEventStateChange sc; - event.refcount = 1; - event.notify = NULL; - event.type = SPA_EVENT_TYPE_STARTED; + event.type = SPA_EVENT_TYPE_STATE_CHANGE; event.port_id = -1; - event.data = NULL; - event.size = 0; + event.data = ≻ + event.size = sizeof (sc); + sc.state = SPA_NODE_STATE_STREAMING; this->event_cb (node, &event, this->user_data); } @@ -163,13 +163,13 @@ spa_audiomixer_node_send_command (SpaNode *node, case SPA_COMMAND_STOP: if (this->event_cb) { SpaEvent event; + SpaEventStateChange sc; - event.refcount = 1; - event.notify = NULL; - event.type = SPA_EVENT_TYPE_STOPPED; + event.type = SPA_EVENT_TYPE_STATE_CHANGE; event.port_id = -1; - event.data = NULL; - event.size = 0; + event.data = ≻ + event.size = sizeof (sc); + sc.state = SPA_NODE_STATE_PAUSED; this->event_cb (node, &event, this->user_data); } @@ -302,7 +302,6 @@ spa_audiomixer_node_remove_port (SpaNode *node, this->ports[port_id].valid = false; this->port_count--; if (this->ports[port_id].buffer) { - spa_buffer_unref (this->ports[port_id].buffer); this->ports[port_id].buffer = NULL; this->port_queued--; } @@ -446,6 +445,36 @@ spa_audiomixer_node_port_set_props (SpaNode *node, return SPA_RESULT_NOT_IMPLEMENTED; } +static SpaResult +spa_audiomixer_node_port_use_buffers (SpaNode *node, + uint32_t port_id, + SpaBuffer **buffers, + uint32_t n_buffers) +{ + return SPA_RESULT_NOT_IMPLEMENTED; +} + +static SpaResult +spa_audiomixer_node_port_alloc_buffers (SpaNode *node, + uint32_t port_id, + SpaAllocParam **params, + uint32_t n_params, + SpaBuffer **buffers, + uint32_t *n_buffers) +{ + return SPA_RESULT_NOT_IMPLEMENTED; +} + +static SpaResult +spa_audiomixer_node_port_reuse_buffer (SpaNode *node, + uint32_t port_id, + uint32_t buffer_id, + off_t offset, + size_t size) +{ + return SPA_RESULT_NOT_IMPLEMENTED; +} + static SpaResult spa_audiomixer_node_port_get_status (SpaNode *node, uint32_t port_id, @@ -471,26 +500,6 @@ spa_audiomixer_node_port_get_status (SpaNode *node, return SPA_RESULT_OK; } -static SpaResult -spa_audiomixer_node_port_use_buffers (SpaNode *node, - uint32_t port_id, - SpaBuffer **buffers, - uint32_t n_buffers) -{ - return SPA_RESULT_NOT_IMPLEMENTED; -} - -static SpaResult -spa_audiomixer_node_port_alloc_buffers (SpaNode *node, - uint32_t port_id, - SpaAllocParam **params, - uint32_t n_params, - SpaBuffer **buffers, - uint32_t *n_buffers) -{ - return SPA_RESULT_NOT_IMPLEMENTED; -} - static SpaResult spa_audiomixer_node_port_push_input (SpaNode *node, unsigned int n_info, @@ -519,7 +528,7 @@ spa_audiomixer_node_port_push_input (SpaNode *node, continue; } port = &this->ports[idx]; - buffer = port->buffers[info[i].id]; + buffer = port->buffers[info[i].buffer_id]; if (buffer == NULL) { info[i].status = SPA_RESULT_INVALID_ARGUMENTS; @@ -539,7 +548,7 @@ spa_audiomixer_node_port_push_input (SpaNode *node, have_error = true; continue; } - this->ports[idx].buffer = spa_buffer_ref (buffer); + this->ports[idx].buffer = buffer; this->ports[idx].buffer_queued = buffer->size; this->ports[idx].buffer_index = 0; this->ports[idx].buffer_offset = 0; @@ -562,35 +571,14 @@ pull_port (SpaAudioMixer *this, uint32_t port_id, SpaOutputInfo *info, size_t pu { SpaEvent event; MixerBuffer *buffer = &this->ports[port_id].mix; + SpaEventPullInput pi; - event.refcount = 1; - event.notify = NULL; event.type = SPA_EVENT_TYPE_PULL_INPUT; event.port_id = port_id; - event.data = buffer; - - buffer->buffer.refcount = 1; - buffer->buffer.notify = NULL; - buffer->buffer.size = pull_size; - buffer->buffer.n_metas = 1; - buffer->buffer.metas = buffer->meta; - buffer->buffer.n_datas = 1; - buffer->buffer.datas = buffer->data; - - buffer->header.flags = 0; - buffer->header.seq = 0; - buffer->header.pts = 0; - buffer->header.dts_offset = 0; - - buffer->meta[0].type = SPA_META_TYPE_HEADER; - buffer->meta[0].data = &buffer->header; - buffer->meta[0].size = sizeof (buffer->header); - - buffer->data[0].type = SPA_DATA_TYPE_MEMPTR; - buffer->data[0].ptr = buffer->samples; - buffer->data[0].ptr_type = "sysmem"; - buffer->data[0].size = pull_size; - + event.data = π + pi.buffer_id = buffer->buffer.id; + pi.offset = 0; + pi.size = pull_size; this->event_cb (&this->node, &event, this->user_data); } @@ -622,7 +610,6 @@ add_port_data (SpaAudioMixer *this, SpaBuffer *out, SpaAudioMixerPort *port) if ((is -= chunk) == 0) { if (++port->buffer_index == port->buffer->n_datas) { - spa_buffer_unref (port->buffer); port->buffer = NULL; port->status.flags = SPA_PORT_STATUS_FLAG_NEED_INPUT; this->ports[0].status.flags &= ~SPA_PORT_STATUS_FLAG_HAVE_OUTPUT; @@ -677,7 +664,7 @@ mix_data (SpaAudioMixer *this, SpaOutputInfo *info) return SPA_RESULT_NEED_MORE_INPUT; buf = this->ports[min_port].buffer; - info->id = buf->id; + info->buffer_id = buf->id; this->ports[min_port].buffer = NULL; this->ports[min_port].status.flags = SPA_PORT_STATUS_FLAG_NEED_INPUT; this->ports[0].status.flags &= ~SPA_PORT_STATUS_FLAG_HAVE_OUTPUT; @@ -757,6 +744,7 @@ static const SpaNode audiomixer_node = { spa_audiomixer_node_port_set_props, spa_audiomixer_node_port_use_buffers, spa_audiomixer_node_port_alloc_buffers, + spa_audiomixer_node_port_reuse_buffer, spa_audiomixer_node_port_get_status, spa_audiomixer_node_port_push_input, spa_audiomixer_node_port_pull_output, diff --git a/spa/plugins/audiotestsrc/audiotestsrc.c b/spa/plugins/audiotestsrc/audiotestsrc.c index 509608007..401a48493 100644 --- a/spa/plugins/audiotestsrc/audiotestsrc.c +++ b/spa/plugins/audiotestsrc/audiotestsrc.c @@ -179,13 +179,13 @@ spa_audiotestsrc_node_send_command (SpaNode *node, case SPA_COMMAND_START: if (this->event_cb) { SpaEvent event; + SpaEventStateChange sc; - event.refcount = 1; - event.notify = NULL; - event.type = SPA_EVENT_TYPE_STARTED; + event.type = SPA_EVENT_TYPE_STATE_CHANGE; event.port_id = -1; - event.data = NULL; - event.size = 0; + event.data = ≻ + event.size = sizeof (sc); + sc.state = SPA_NODE_STATE_STREAMING; this->event_cb (node, &event, this->user_data); } @@ -194,13 +194,13 @@ spa_audiotestsrc_node_send_command (SpaNode *node, case SPA_COMMAND_STOP: if (this->event_cb) { SpaEvent event; + SpaEventStateChange sc; - event.refcount = 1; - event.notify = NULL; - event.type = SPA_EVENT_TYPE_STOPPED; + event.type = SPA_EVENT_TYPE_STATE_CHANGE; event.port_id = -1; - event.data = NULL; - event.size = 0; + event.data = ≻ + event.size = sizeof (sc); + sc.state = SPA_NODE_STATE_PAUSED; this->event_cb (node, &event, this->user_data); } @@ -407,6 +407,36 @@ spa_audiotestsrc_node_port_set_props (SpaNode *node, return SPA_RESULT_NOT_IMPLEMENTED; } +static SpaResult +spa_audiotestsrc_node_port_use_buffers (SpaNode *node, + uint32_t port_id, + SpaBuffer **buffers, + uint32_t n_buffers) +{ + return SPA_RESULT_NOT_IMPLEMENTED; +} + +static SpaResult +spa_audiotestsrc_node_port_alloc_buffers (SpaNode *node, + uint32_t port_id, + SpaAllocParam **params, + uint32_t n_params, + SpaBuffer **buffers, + uint32_t *n_buffers) +{ + return SPA_RESULT_NOT_IMPLEMENTED; +} + +static SpaResult +spa_audiotestsrc_node_port_reuse_buffer (SpaNode *node, + uint32_t port_id, + uint32_t buffer_id, + off_t offset, + size_t size) +{ + return SPA_RESULT_NOT_IMPLEMENTED; +} + static SpaResult spa_audiotestsrc_node_port_get_status (SpaNode *node, uint32_t port_id, @@ -430,26 +460,6 @@ spa_audiotestsrc_node_port_get_status (SpaNode *node, return SPA_RESULT_OK; } -static SpaResult -spa_audiotestsrc_node_port_use_buffers (SpaNode *node, - uint32_t port_id, - SpaBuffer **buffers, - uint32_t n_buffers) -{ - return SPA_RESULT_NOT_IMPLEMENTED; -} - -static SpaResult -spa_audiotestsrc_node_port_alloc_buffers (SpaNode *node, - uint32_t port_id, - SpaAllocParam **params, - uint32_t n_params, - SpaBuffer **buffers, - uint32_t *n_buffers) -{ - return SPA_RESULT_NOT_IMPLEMENTED; -} - static SpaResult spa_audiotestsrc_node_port_push_input (SpaNode *node, @@ -528,6 +538,7 @@ static const SpaNode audiotestsrc_node = { spa_audiotestsrc_node_port_set_props, spa_audiotestsrc_node_port_use_buffers, spa_audiotestsrc_node_port_alloc_buffers, + spa_audiotestsrc_node_port_reuse_buffer, spa_audiotestsrc_node_port_get_status, spa_audiotestsrc_node_port_push_input, spa_audiotestsrc_node_port_pull_output, diff --git a/spa/plugins/ffmpeg/ffmpeg-dec.c b/spa/plugins/ffmpeg/ffmpeg-dec.c index 682c0107d..9fe05a353 100644 --- a/spa/plugins/ffmpeg/ffmpeg-dec.c +++ b/spa/plugins/ffmpeg/ffmpeg-dec.c @@ -145,13 +145,13 @@ spa_ffmpeg_dec_node_send_command (SpaNode *node, case SPA_COMMAND_START: if (this->event_cb) { SpaEvent event; + SpaEventStateChange sc; - event.refcount = 1; - event.notify = NULL; - event.type = SPA_EVENT_TYPE_STARTED; + event.type = SPA_EVENT_TYPE_STATE_CHANGE; event.port_id = -1; - event.data = NULL; - event.size = 0; + event.data = ≻ + event.size = sizeof (sc); + sc.state = SPA_NODE_STATE_STREAMING; this->event_cb (node, &event, this->user_data); } @@ -159,13 +159,13 @@ spa_ffmpeg_dec_node_send_command (SpaNode *node, case SPA_COMMAND_STOP: if (this->event_cb) { SpaEvent event; + SpaEventStateChange sc; - event.refcount = 1; - event.notify = NULL; - event.type = SPA_EVENT_TYPE_STOPPED; + event.type = SPA_EVENT_TYPE_STATE_CHANGE; event.port_id = -1; - event.data = NULL; - event.size = 0; + event.data = ≻ + event.size = sizeof (sc); + sc.state = SPA_NODE_STATE_PAUSED; this->event_cb (node, &event, this->user_data); } @@ -399,6 +399,48 @@ spa_ffmpeg_dec_node_port_set_props (SpaNode *node, return SPA_RESULT_NOT_IMPLEMENTED; } +static SpaResult +spa_ffmpeg_dec_node_port_use_buffers (SpaNode *node, + uint32_t port_id, + SpaBuffer **buffers, + uint32_t n_buffers) +{ + if (node == NULL || node->handle == NULL) + return SPA_RESULT_INVALID_ARGUMENTS; + + if (!IS_VALID_PORT (port_id)) + return SPA_RESULT_INVALID_PORT; + + return SPA_RESULT_NOT_IMPLEMENTED; +} + +static SpaResult +spa_ffmpeg_dec_node_port_alloc_buffers (SpaNode *node, + uint32_t port_id, + SpaAllocParam **params, + uint32_t n_params, + SpaBuffer **buffers, + uint32_t *n_buffers) +{ + return SPA_RESULT_NOT_IMPLEMENTED; +} + +static SpaResult +spa_ffmpeg_dec_node_port_reuse_buffer (SpaNode *node, + uint32_t port_id, + uint32_t buffer_id, + off_t offse, + size_t size) +{ + if (node == NULL || node->handle == NULL) + return SPA_RESULT_INVALID_ARGUMENTS; + + if (!IS_VALID_PORT (port_id)) + return SPA_RESULT_INVALID_PORT; + + return SPA_RESULT_NOT_IMPLEMENTED; +} + static SpaResult spa_ffmpeg_dec_node_port_get_status (SpaNode *node, uint32_t port_id, @@ -419,33 +461,6 @@ spa_ffmpeg_dec_node_port_get_status (SpaNode *node, return SPA_RESULT_OK; } -static SpaResult -spa_ffmpeg_dec_node_port_use_buffers (SpaNode *node, - uint32_t port_id, - SpaBuffer **buffers, - uint32_t n_buffers) -{ - if (node == NULL || node->handle == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - if (!IS_VALID_PORT (port_id)) - return SPA_RESULT_INVALID_PORT; - - return SPA_RESULT_OK; -} - -static SpaResult -spa_ffmpeg_dec_node_port_alloc_buffers (SpaNode *node, - uint32_t port_id, - SpaAllocParam **params, - uint32_t n_params, - SpaBuffer **buffers, - uint32_t *n_buffers) -{ - return SPA_RESULT_NOT_IMPLEMENTED; -} - - static SpaResult spa_ffmpeg_dec_node_port_push_input (SpaNode *node, unsigned int n_info, @@ -518,6 +533,7 @@ static const SpaNode ffmpeg_dec_node = { spa_ffmpeg_dec_node_port_set_props, spa_ffmpeg_dec_node_port_use_buffers, spa_ffmpeg_dec_node_port_alloc_buffers, + spa_ffmpeg_dec_node_port_reuse_buffer, spa_ffmpeg_dec_node_port_get_status, spa_ffmpeg_dec_node_port_push_input, spa_ffmpeg_dec_node_port_pull_output, diff --git a/spa/plugins/ffmpeg/ffmpeg-enc.c b/spa/plugins/ffmpeg/ffmpeg-enc.c index ea6b316a3..0a153a585 100644 --- a/spa/plugins/ffmpeg/ffmpeg-enc.c +++ b/spa/plugins/ffmpeg/ffmpeg-enc.c @@ -145,13 +145,13 @@ spa_ffmpeg_enc_node_send_command (SpaNode *node, case SPA_COMMAND_START: if (this->event_cb) { SpaEvent event; + SpaEventStateChange sc; - event.refcount = 1; - event.notify = NULL; - event.type = SPA_EVENT_TYPE_STARTED; + event.type = SPA_EVENT_TYPE_STATE_CHANGE; event.port_id = -1; - event.data = NULL; - event.size = 0; + event.data = ≻ + event.size = sizeof (sc); + sc.state = SPA_NODE_STATE_STREAMING; this->event_cb (node, &event, this->user_data); } @@ -159,13 +159,13 @@ spa_ffmpeg_enc_node_send_command (SpaNode *node, case SPA_COMMAND_STOP: if (this->event_cb) { SpaEvent event; + SpaEventStateChange sc; - event.refcount = 1; - event.notify = NULL; - event.type = SPA_EVENT_TYPE_STOPPED; + event.type = SPA_EVENT_TYPE_STATE_CHANGE; event.port_id = -1; - event.data = NULL; - event.size = 0; + event.data = ≻ + event.size = sizeof (sc); + sc.state = SPA_NODE_STATE_PAUSED; this->event_cb (node, &event, this->user_data); } @@ -399,6 +399,48 @@ spa_ffmpeg_enc_node_port_set_props (SpaNode *node, return SPA_RESULT_NOT_IMPLEMENTED; } +static SpaResult +spa_ffmpeg_enc_node_port_use_buffers (SpaNode *node, + uint32_t port_id, + SpaBuffer **buffers, + uint32_t n_buffers) +{ + if (node == NULL || node->handle == NULL) + return SPA_RESULT_INVALID_ARGUMENTS; + + if (!IS_VALID_PORT (port_id)) + return SPA_RESULT_INVALID_PORT; + + return SPA_RESULT_NOT_IMPLEMENTED; +} + +static SpaResult +spa_ffmpeg_enc_node_port_alloc_buffers (SpaNode *node, + uint32_t port_id, + SpaAllocParam **params, + uint32_t n_params, + SpaBuffer **buffers, + uint32_t *n_buffers) +{ + return SPA_RESULT_NOT_IMPLEMENTED; +} + +static SpaResult +spa_ffmpeg_enc_node_port_reuse_buffer (SpaNode *node, + uint32_t port_id, + uint32_t buffer_id, + off_t offset, + size_t size) +{ + if (node == NULL || node->handle == NULL) + return SPA_RESULT_INVALID_ARGUMENTS; + + if (!IS_VALID_PORT (port_id)) + return SPA_RESULT_INVALID_PORT; + + return SPA_RESULT_NOT_IMPLEMENTED; +} + static SpaResult spa_ffmpeg_enc_node_port_get_status (SpaNode *node, uint32_t port_id, @@ -419,33 +461,6 @@ spa_ffmpeg_enc_node_port_get_status (SpaNode *node, return SPA_RESULT_OK; } -static SpaResult -spa_ffmpeg_enc_node_port_use_buffers (SpaNode *node, - uint32_t port_id, - SpaBuffer **buffers, - uint32_t n_buffers) -{ - if (node == NULL || node->handle == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - if (!IS_VALID_PORT (port_id)) - return SPA_RESULT_INVALID_PORT; - - return SPA_RESULT_OK; -} - -static SpaResult -spa_ffmpeg_enc_node_port_alloc_buffers (SpaNode *node, - uint32_t port_id, - SpaAllocParam **params, - uint32_t n_params, - SpaBuffer **buffers, - uint32_t *n_buffers) -{ - return SPA_RESULT_NOT_IMPLEMENTED; -} - - static SpaResult spa_ffmpeg_enc_node_port_push_input (SpaNode *node, unsigned int n_info, @@ -518,6 +533,7 @@ static const SpaNode ffmpeg_enc_node = { spa_ffmpeg_enc_node_port_set_props, spa_ffmpeg_enc_node_port_use_buffers, spa_ffmpeg_enc_node_port_alloc_buffers, + spa_ffmpeg_enc_node_port_reuse_buffer, spa_ffmpeg_enc_node_port_get_status, spa_ffmpeg_enc_node_port_push_input, spa_ffmpeg_enc_node_port_pull_output, diff --git a/spa/plugins/remote/proxy.c b/spa/plugins/remote/proxy.c index af988c563..2aec6bcca 100644 --- a/spa/plugins/remote/proxy.c +++ b/spa/plugins/remote/proxy.c @@ -37,7 +37,8 @@ #define MAX_OUTPUTS 64 #define MAX_PORTS (MAX_INPUTS + MAX_OUTPUTS) -#define CHECK_PORT_ID(this,id) ((id) < MAX_PORTS && (this)->ports[id].valid) +#define CHECK_FREE_PORT_ID(this,id) ((id) < MAX_PORTS && !(this)->ports[id].valid) +#define CHECK_PORT_ID(this,id) ((id) < MAX_PORTS && (this)->ports[id].valid) #define CHECK_PORT_ID_DIR(this,id,dir) (CHECK_PORT_ID(this,id) && (this)->ports[i].direction == (dir)) typedef struct _SpaProxy SpaProxy; @@ -61,6 +62,7 @@ typedef struct { struct _SpaProxy { SpaHandle handle; SpaNode node; + SpaNodeState state; SpaProxyProps props[2]; @@ -108,8 +110,6 @@ update_poll (SpaProxy *this, int socketfd) p = &this->props[1]; if (p->socketfd != -1) { - event.refcount = 1; - event.notify = NULL; event.type = SPA_EVENT_TYPE_REMOVE_POLL; event.port_id = 0; event.data = &this->poll; @@ -120,8 +120,6 @@ update_poll (SpaProxy *this, int socketfd) if (p->socketfd != -1) { this->fds[0].fd = p->socketfd; - event.refcount = 1; - event.notify = NULL; event.type = SPA_EVENT_TYPE_ADD_POLL; event.port_id = 0; event.data = &this->poll; @@ -130,6 +128,25 @@ update_poll (SpaProxy *this, int socketfd) } } +static SpaResult +update_state (SpaProxy *this, SpaNodeState state) +{ + if (this->state != state) { + SpaEvent event; + SpaEventStateChange sc; + + this->state = state; + + event.type = SPA_EVENT_TYPE_STATE_CHANGE; + event.port_id = -1; + event.data = ≻ + event.size = sizeof (sc); + sc.state = state; + this->event_cb (&this->node, &event, this->user_data); + } + return SPA_RESULT_OK; +} + static SpaResult spa_proxy_node_get_props (SpaNode *node, SpaProps **props) @@ -186,6 +203,7 @@ spa_proxy_node_send_command (SpaNode *node, SpaCommand *command) { SpaProxy *this; + SpaResult res; if (node == NULL || node->handle == NULL || command == NULL) return SPA_RESULT_INVALID_ARGUMENTS; @@ -197,34 +215,40 @@ spa_proxy_node_send_command (SpaNode *node, return SPA_RESULT_INVALID_COMMAND; case SPA_COMMAND_START: - if (this->event_cb) { - SpaEvent event; + { + SpaControlBuilder builder; + SpaControl control; + uint8_t buf[128]; - event.refcount = 1; - event.notify = NULL; - event.type = SPA_EVENT_TYPE_STARTED; - event.port_id = -1; - event.data = NULL; - event.size = 0; + /* send start */ + spa_control_builder_init_into (&builder, buf, sizeof (buf), NULL, 0); + spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_START, NULL); + spa_control_builder_end (&builder, &control); - this->event_cb (&this->node, &event, this->user_data); - } + if ((res = spa_control_write (&control, this->fds[0].fd)) < 0) + fprintf (stderr, "proxy %p: error writing control %d\n", this, res); + + spa_control_clear (&control); break; + } case SPA_COMMAND_STOP: - if (this->event_cb) { - SpaEvent event; + { + SpaControlBuilder builder; + SpaControl control; + uint8_t buf[128]; - event.refcount = 1; - event.notify = NULL; - event.type = SPA_EVENT_TYPE_STOPPED; - event.port_id = -1; - event.data = NULL; - event.size = 0; + /* send start */ + spa_control_builder_init_into (&builder, buf, sizeof (buf), NULL, 0); + spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_STOP, NULL); + spa_control_builder_end (&builder, &control); - this->event_cb (&this->node, &event, this->user_data); - } + if ((res = spa_control_write (&control, this->fds[0].fd)) < 0) + fprintf (stderr, "proxy %p: error writing control %d\n", this, res); + + spa_control_clear (&control); break; + } case SPA_COMMAND_FLUSH: case SPA_COMMAND_DRAIN: @@ -315,14 +339,46 @@ spa_proxy_node_add_port (SpaNode *node, SpaDirection direction, uint32_t port_id) { - return SPA_RESULT_NOT_IMPLEMENTED; + SpaProxy *this; + SpaProxyPort *port; + + if (node == NULL || node->handle == NULL) + return SPA_RESULT_INVALID_ARGUMENTS; + + this = (SpaProxy *) node->handle; + + if (!CHECK_FREE_PORT_ID (this, port_id)) + return SPA_RESULT_INVALID_PORT; + + fprintf (stderr, "%p: adding port %d, %d\n", node, port_id, direction); + port = &this->ports[port_id]; + + port->direction = direction; + port->valid = true; + port->have_format = false; + + return SPA_RESULT_OK; } static SpaResult spa_proxy_node_remove_port (SpaNode *node, uint32_t port_id) { - return SPA_RESULT_NOT_IMPLEMENTED; + SpaProxy *this; + SpaProxyPort *port; + + if (node == NULL || node->handle == NULL) + return SPA_RESULT_INVALID_ARGUMENTS; + + this = (SpaProxy *) node->handle; + + if (!CHECK_PORT_ID (this, port_id)) + return SPA_RESULT_INVALID_PORT; + + port = &this->ports[port_id]; + port->valid = false; + + return SPA_RESULT_OK; } static SpaResult @@ -385,13 +441,15 @@ spa_proxy_node_port_set_format (SpaNode *node, port = &this->ports[port_id]; spa_control_builder_init_into (&builder, buf, sizeof (buf), NULL, 0); - sf.port = port_id; + sf.port_id = port_id; sf.format = format; spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_SET_FORMAT, &sf); spa_control_builder_end (&builder, &control); if ((res = spa_control_write (&control, this->fds[0].fd)) < 0) - fprintf (stderr, "proxy %p: error writing control", this); + fprintf (stderr, "proxy %p: error writing control\n", this); + + spa_control_clear (&control); port->have_format = format != NULL; @@ -489,6 +547,127 @@ spa_proxy_node_port_get_status (SpaNode *node, return SPA_RESULT_OK; } +static int +tmpfile_create (void *data, size_t size) +{ + char filename[] = "/dev/shm/tmpfilepay.XXXXXX"; + int fd; + + fd = mkostemp (filename, O_CLOEXEC); + if (fd == -1) { + fprintf (stderr, "Failed to create temporary file: %s\n", strerror (errno)); + return -1; + } + unlink (filename); + + if (write (fd, data, size) != (ssize_t) size) + fprintf (stderr, "Failed to write data: %s\n", strerror (errno)); + + return fd; +} + +typedef struct { + SpaBuffer buffer; + SpaData datas[16]; + int idx[16]; + SpaBuffer *orig; +} MyBuffer; + +static SpaResult +add_buffer (SpaProxy *this, uint32_t port_id, SpaBuffer *buffer) +{ + SpaControl control; + SpaControlBuilder builder; + uint8_t buf[1024]; + int fds[16]; + SpaControlCmdAddBuffer ab; + bool tmpfile = false; + unsigned int i; + MyBuffer b; + SpaResult res; + + spa_control_builder_init_into (&builder, buf, sizeof (buf), fds, sizeof (fds)); + + b.buffer.id = buffer->id; + b.buffer.size = buffer->size; + b.buffer.n_metas = buffer->n_metas; + b.buffer.metas = buffer->metas; + b.buffer.n_datas = buffer->n_datas; + b.buffer.datas = b.datas; + + for (i = 0; i < buffer->n_datas; i++) { + SpaData *d = &buffer->datas[i]; + int fd; + SpaControlCmdAddMem am; + + if (d->type == SPA_DATA_TYPE_FD) { + fd = *((int *)d->ptr); + } else { + fd = tmpfile_create (d->ptr, d->size + d->offset); + tmpfile = true; + } + am.port_id = port_id; + am.mem_id = buffer->id * 64 + i; + am.mem_type = 0; + am.fd_index = spa_control_builder_add_fd (&builder, fd, tmpfile ? true : false); + am.offset = 0; + am.size = d->offset + d->size; + spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_ADD_MEM, &am); + + b.idx[i] = am.mem_id; + b.datas[i].type = SPA_DATA_TYPE_MEMID; + b.datas[i].ptr_type = NULL; + b.datas[i].ptr = &b.idx[i]; + b.datas[i].offset = d->offset; + b.datas[i].size = d->size; + b.datas[i].stride = d->stride; + } + ab.port_id = port_id; + ab.buffer = &b.buffer; + fprintf (stderr, "proxy %p: add buffer %d\n", this, b.buffer.id); + spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_ADD_BUFFER, &ab); + spa_control_builder_end (&builder, &control); + + if ((res = spa_control_write (&control, this->fds[0].fd)) < 0) + fprintf (stderr, "proxy %p: error writing control\n", this); + + spa_control_clear (&control); + + return SPA_RESULT_OK; +} + +static SpaResult +remove_buffer (SpaProxy *this, uint32_t port_id, SpaBuffer *buffer) +{ + SpaControl control; + SpaControlBuilder builder; + uint8_t buf[1024]; + SpaControlCmdRemoveBuffer rb; + unsigned int i; + SpaResult res; + + spa_control_builder_init_into (&builder, buf, sizeof (buf), NULL, 0); + rb.port_id = port_id; + rb.buffer_id = buffer->id; + spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_REMOVE_BUFFER, &rb); + + for (i = 0; i < buffer->n_datas; i++) { + SpaControlCmdRemoveMem rm; + rm.port_id = port_id; + rm.mem_id = i; + spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_REMOVE_MEM, &rm); + } + spa_control_builder_end (&builder, &control); + + if ((res = spa_control_write (&control, this->fds[0].fd)) < 0) + fprintf (stderr, "proxy %p: error writing control\n", this); + + spa_control_clear (&control); + + return SPA_RESULT_OK; +} + + static SpaResult spa_proxy_node_port_use_buffers (SpaNode *node, uint32_t port_id, @@ -497,11 +676,13 @@ spa_proxy_node_port_use_buffers (SpaNode *node, { SpaProxy *this; SpaProxyPort *port; + unsigned int i; - if (node == NULL || node->handle == NULL || buffers == NULL) + if (node == NULL || node->handle == NULL) return SPA_RESULT_INVALID_ARGUMENTS; this = (SpaProxy *) node->handle; + fprintf (stderr, "proxy %p: use buffers %p %u\n", this, buffers, n_buffers); if (!CHECK_PORT_ID (this, port_id)) return SPA_RESULT_INVALID_PORT; @@ -511,8 +692,18 @@ spa_proxy_node_port_use_buffers (SpaNode *node, if (!port->have_format) return SPA_RESULT_NO_FORMAT; - port->buffers = buffers; - port->n_buffers = n_buffers; + for (i = 0; i < port->n_buffers; i++) + remove_buffer (this, port_id, port->buffers[i]); + + if (buffers == NULL || n_buffers == 0) { + port->buffers = NULL; + port->n_buffers = 0; + } else { + port->buffers = buffers; + port->n_buffers = n_buffers; + } + for (i = 0; i < port->n_buffers; i++) + add_buffer (this, port_id, port->buffers[i]); return SPA_RESULT_OK; } @@ -541,112 +732,17 @@ spa_proxy_node_port_alloc_buffers (SpaNode *node, if (!port->have_format) return SPA_RESULT_NO_FORMAT; - return SPA_RESULT_OK; + return SPA_RESULT_NOT_IMPLEMENTED; } -static int -tmpfile_create (void *data, size_t size) -{ - char filename[] = "/dev/shm/tmpfilepay.XXXXXX"; - int fd; - - fd = mkostemp (filename, O_CLOEXEC); - if (fd == -1) { - fprintf (stderr, "Failed to create temporary file: %s", strerror (errno)); - return -1; - } - unlink (filename); - - if (write (fd, data, size) != (ssize_t) size) - fprintf (stderr, "Failed to write data: %s", strerror (errno)); - - return fd; -} - -typedef struct { - SpaBuffer buffer; - SpaData datas[16]; - int idx[16]; - SpaBuffer *orig; -} MyBuffer; - static SpaResult -send_buffer (SpaProxy *this, SpaBuffer *buffer) +spa_proxy_node_port_reuse_buffer (SpaNode *node, + uint32_t port_id, + uint32_t buffer_id, + off_t offset, + size_t size) { - SpaControl control; - SpaControlBuilder builder; - uint8_t buf[1024]; - int fds[16]; - SpaControlCmdAddBuffer ab; - SpaControlCmdProcessBuffer pb; - SpaControlCmdRemoveBuffer rb; - bool tmpfile = false; - unsigned int i; - MyBuffer b; - SpaResult res; - - spa_control_builder_init_into (&builder, buf, 1024, fds, 16); - - b.buffer.refcount = 1; - b.buffer.notify = NULL; - b.buffer.id = buffer->id; - b.buffer.size = buffer->size; - b.buffer.n_metas = buffer->n_metas; - b.buffer.metas = buffer->metas; - b.buffer.n_datas = buffer->n_datas; - b.buffer.datas = b.datas; - - for (i = 0; i < buffer->n_datas; i++) { - SpaData *d = &buffer->datas[i]; - int fd; - SpaControlCmdAddMem am; - - if (d->type == SPA_DATA_TYPE_FD) { - fd = *((int *)d->ptr); - } else { - fd = tmpfile_create (d->ptr, d->size + d->offset); - tmpfile = true; - } - am.port = 0; - am.id = i; - am.type = 0; - am.fd_index = spa_control_builder_add_fd (&builder, fd, tmpfile ? true : false); - am.offset = 0; - am.size = d->offset + d->size; - spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_ADD_MEM, &am); - - b.idx[i] = i; - b.datas[i].type = SPA_DATA_TYPE_MEMID; - b.datas[i].ptr_type = NULL; - b.datas[i].ptr = &b.idx[i]; - b.datas[i].offset = d->offset; - b.datas[i].size = d->size; - b.datas[i].stride = d->stride; - } - ab.port = 0; - ab.buffer = &b.buffer; - spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_ADD_BUFFER, &ab); - pb.port = 0; - pb.id = b.buffer.id; - spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_PROCESS_BUFFER, &pb); - rb.port = 0; - rb.id = b.buffer.id; - spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_REMOVE_BUFFER, &rb); - - for (i = 0; i < buffer->n_datas; i++) { - SpaControlCmdRemoveMem rm; - rm.port = 0; - rm.id = i; - spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_REMOVE_MEM, &rm); - } - spa_control_builder_end (&builder, &control); - - if ((res = spa_control_write (&control, this->fds[0].fd)) < 0) - fprintf (stderr, "proxy %p: error writing control", this); - - spa_control_clear (&control); - - return SPA_RESULT_OK; + return SPA_RESULT_NOT_IMPLEMENTED; } static SpaResult @@ -659,12 +755,19 @@ spa_proxy_node_port_push_input (SpaNode *node, unsigned int i; bool have_error = false; bool have_enough = false; + SpaControl control; + SpaControlBuilder builder; + SpaControlCmdProcessBuffer pb; + uint8_t buf[64]; + SpaResult res; if (node == NULL || node->handle == NULL || n_info == 0 || info == NULL) return SPA_RESULT_INVALID_ARGUMENTS; this = (SpaProxy *) node->handle; + spa_control_builder_init_into (&builder, buf, sizeof(buf), NULL, 0); + for (i = 0; i < n_info; i++) { if (!CHECK_PORT_ID_DIR (this, info[i].port_id, SPA_DIRECTION_INPUT)) { info[i].status = SPA_RESULT_INVALID_PORT; @@ -678,14 +781,33 @@ spa_proxy_node_port_push_input (SpaNode *node, have_error = true; continue; } + if (info[i].buffer_id >= port->n_buffers) { + if (port->n_buffers == 0) + info[i].status = SPA_RESULT_NO_BUFFERS; + else + info[i].status = SPA_RESULT_INVALID_BUFFER_ID; + have_error = true; + continue; + } + + pb.port_id = info[i].port_id; + pb.buffer_id = info[i].buffer_id; + spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_PROCESS_BUFFER, &pb); info[i].status = SPA_RESULT_OK; } + spa_control_builder_end (&builder, &control); + if (have_error) return SPA_RESULT_ERROR; if (have_enough) return SPA_RESULT_HAVE_ENOUGH_INPUT; + if ((res = spa_control_write (&control, this->fds[0].fd)) < 0) + fprintf (stderr, "proxy %p: error writing control\n", this); + + spa_control_clear (&control); + return SPA_RESULT_OK; } @@ -728,73 +850,56 @@ spa_proxy_node_port_pull_output (SpaNode *node, return SPA_RESULT_OK; } +static SpaResult +spa_proxy_node_port_push_event (SpaNode *node, + uint32_t port_id, + SpaEvent *event) +{ + return SPA_RESULT_NOT_IMPLEMENTED; +} + static SpaResult parse_control (SpaProxy *this, SpaControl *ctrl) { SpaControlIter it; - SpaResult res; spa_control_iter_init (&it, ctrl); while (spa_control_iter_next (&it) == SPA_RESULT_OK) { SpaControlCmd cmd = spa_control_iter_get_cmd (&it); + fprintf (stderr, "proxy %p: got control %d\n", this, cmd); + switch (cmd) { case SPA_CONTROL_CMD_ADD_PORT: case SPA_CONTROL_CMD_REMOVE_PORT: case SPA_CONTROL_CMD_SET_FORMAT: case SPA_CONTROL_CMD_SET_PROPERTY: - case SPA_CONTROL_CMD_END_CONFIGURE: - case SPA_CONTROL_CMD_PAUSE: case SPA_CONTROL_CMD_START: case SPA_CONTROL_CMD_STOP: - fprintf (stderr, "proxy %p: got unexpected control %d", this, cmd); + fprintf (stderr, "proxy %p: got unexpected control %d\n", this, cmd); break; case SPA_CONTROL_CMD_NODE_UPDATE: case SPA_CONTROL_CMD_PORT_UPDATE: case SPA_CONTROL_CMD_PORT_REMOVED: - fprintf (stderr, "proxy %p: command not implemented %d", this, cmd); + fprintf (stderr, "proxy %p: command not implemented %d\n", this, cmd); break; - case SPA_CONTROL_CMD_START_CONFIGURE: + case SPA_CONTROL_CMD_STATE_CHANGE: { - SpaControlBuilder builder; - SpaControl control; - uint8_t buf[128]; + SpaControlCmdStateChange sc; - /* set port format */ + if (spa_control_iter_parse_cmd (&it, &sc) < 0) + break; - /* send end-configure */ - spa_control_builder_init_into (&builder, buf, sizeof (buf), NULL, 0); - spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_END_CONFIGURE, NULL); - spa_control_builder_end (&builder, &control); - - if ((res = spa_control_write (&control, this->fds[0].fd)) < 0) - fprintf (stderr, "proxy %p: error writing control: %d", this, res); + fprintf (stderr, "proxy %p: got state-change to %d\n", this, sc.state); + update_state (this, sc.state); break; } case SPA_CONTROL_CMD_PORT_STATUS_CHANGE: { - fprintf (stderr, "proxy %p: command not implemented %d", this, cmd); - break; - } - case SPA_CONTROL_CMD_START_ALLOC: - { - SpaControlBuilder builder; - SpaControl control; - uint8_t buf[128]; - - /* FIXME read port memory requirements */ - /* FIXME add_mem */ - - /* send start */ - spa_control_builder_init_into (&builder, buf, sizeof (buf), NULL, 0); - spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_START, NULL); - spa_control_builder_end (&builder, &control); - - if ((res = spa_control_write (&control, this->fds[0].fd)) < 0) - fprintf (stderr, "proxy %p: error writing control %d", this, res); + fprintf (stderr, "proxy %p: command not implemented %d\n", this, cmd); break; } case SPA_CONTROL_CMD_NEED_INPUT: @@ -821,10 +926,26 @@ parse_control (SpaProxy *this, } case SPA_CONTROL_CMD_REUSE_BUFFER: { + SpaEvent event; + SpaEventReuseBuffer rb; + SpaControlCmdReuseBuffer crb; + + if (spa_control_iter_parse_cmd (&it, &crb) < 0) + break; + + event.type = SPA_EVENT_TYPE_REUSE_BUFFER; + event.port_id = crb.port_id; + event.data = &rb; + event.size = sizeof (rb); + rb.buffer_id = crb.buffer_id; + rb.offset = crb.offset; + rb.size = crb.size; + this->event_cb (&this->node, &event, this->user_data); + break; } default: - fprintf (stderr, "proxy %p: command unhandled %d", this, cmd); + fprintf (stderr, "proxy %p: command unhandled %d\n", this, cmd); break; } } @@ -845,7 +966,7 @@ proxy_on_fd_events (SpaPollNotifyData *data) int fds[16]; if ((res = spa_control_read (&control, data->fds[0].fd, buf, 1024, fds, 16)) < 0) { - fprintf (stderr, "proxy %p: failed to read control: %d", this, res); + fprintf (stderr, "proxy %p: failed to read control: %d\n", this, res); return 0; } parse_control (this, &control); @@ -873,9 +994,11 @@ static const SpaNode proxy_node = { spa_proxy_node_port_set_props, spa_proxy_node_port_use_buffers, spa_proxy_node_port_alloc_buffers, + spa_proxy_node_port_reuse_buffer, spa_proxy_node_port_get_status, spa_proxy_node_port_push_input, spa_proxy_node_port_pull_output, + spa_proxy_node_port_push_event, }; static SpaResult diff --git a/spa/plugins/v4l2/v4l2-source.c b/spa/plugins/v4l2/v4l2-source.c index 1b5293f6e..69d64ebb4 100644 --- a/spa/plugins/v4l2/v4l2-source.c +++ b/spa/plugins/v4l2/v4l2-source.c @@ -228,13 +228,13 @@ spa_v4l2_source_node_send_command (SpaNode *node, if (this->event_cb) { SpaEvent event; + SpaEventStateChange sc; - event.refcount = 1; - event.notify = NULL; - event.type = SPA_EVENT_TYPE_STARTED; + event.type = SPA_EVENT_TYPE_STATE_CHANGE; event.port_id = -1; - event.data = NULL; - event.size = 0; + event.data = ≻ + event.size = sizeof (sc); + sc.state = SPA_NODE_STATE_STREAMING; this->event_cb (node, &event, this->user_data); } @@ -244,13 +244,13 @@ spa_v4l2_source_node_send_command (SpaNode *node, if (this->event_cb) { SpaEvent event; + SpaEventStateChange sc; - event.refcount = 1; - event.notify = NULL; - event.type = SPA_EVENT_TYPE_STOPPED; + event.type = SPA_EVENT_TYPE_STATE_CHANGE; event.port_id = -1; - event.data = NULL; - event.size = 0; + event.data = ≻ + event.size = sizeof (sc); + sc.state = SPA_NODE_STATE_PAUSED; this->event_cb (node, &event, this->user_data); } @@ -496,26 +496,6 @@ spa_v4l2_source_node_port_set_props (SpaNode *node, return SPA_RESULT_NOT_IMPLEMENTED; } -static SpaResult -spa_v4l2_source_node_port_get_status (SpaNode *node, - uint32_t port_id, - const SpaPortStatus **status) -{ - SpaV4l2Source *this; - - if (node == NULL || node->handle == NULL || status == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - this = (SpaV4l2Source *) node->handle; - - if (port_id != 0) - return SPA_RESULT_INVALID_PORT; - - *status = &this->state[port_id].status; - - return SPA_RESULT_OK; -} - static SpaResult spa_v4l2_source_node_port_use_buffers (SpaNode *node, uint32_t port_id, @@ -560,6 +540,47 @@ spa_v4l2_source_node_port_alloc_buffers (SpaNode *node, return SPA_RESULT_OK; } +static SpaResult +spa_v4l2_source_node_port_reuse_buffer (SpaNode *node, + uint32_t port_id, + uint32_t buffer_id, + off_t offset, + size_t size) +{ + SpaV4l2Source *this; + + if (node == NULL || node->handle == NULL) + return SPA_RESULT_INVALID_ARGUMENTS; + + this = (SpaV4l2Source *) node->handle; + + if (port_id != 0) + return SPA_RESULT_INVALID_PORT; + + spa_v4l2_buffer_recycle (this, buffer_id); + + return SPA_RESULT_OK; +} + +static SpaResult +spa_v4l2_source_node_port_get_status (SpaNode *node, + uint32_t port_id, + const SpaPortStatus **status) +{ + SpaV4l2Source *this; + + if (node == NULL || node->handle == NULL || status == NULL) + return SPA_RESULT_INVALID_ARGUMENTS; + + this = (SpaV4l2Source *) node->handle; + + if (port_id != 0) + return SPA_RESULT_INVALID_PORT; + + *status = &this->state[port_id].status; + + return SPA_RESULT_OK; +} static SpaResult spa_v4l2_source_node_port_push_input (SpaNode *node, @@ -584,7 +605,6 @@ spa_v4l2_source_node_port_pull_output (SpaNode *node, this = (SpaV4l2Source *) node->handle; - for (i = 0; i < n_info; i++) { V4l2Buffer *b; @@ -612,7 +632,7 @@ spa_v4l2_source_node_port_pull_output (SpaNode *node, b->outstanding = true; - info[i].id = b->buffer.id; + info[i].buffer_id = b->buffer.id; info[i].status = SPA_RESULT_OK; } if (have_error) @@ -649,6 +669,7 @@ static const SpaNode v4l2source_node = { spa_v4l2_source_node_port_set_props, spa_v4l2_source_node_port_use_buffers, spa_v4l2_source_node_port_alloc_buffers, + spa_v4l2_source_node_port_reuse_buffer, spa_v4l2_source_node_port_get_status, spa_v4l2_source_node_port_push_input, spa_v4l2_source_node_port_pull_output, diff --git a/spa/plugins/v4l2/v4l2-utils.c b/spa/plugins/v4l2/v4l2-utils.c index 290170f53..05aabaed6 100644 --- a/spa/plugins/v4l2/v4l2-utils.c +++ b/spa/plugins/v4l2/v4l2-utils.c @@ -437,7 +437,7 @@ spa_v4l2_close (SpaV4l2Source *this) return 0; } -static int +static SpaResult mmap_read (SpaV4l2Source *this) { SpaV4l2State *state = &this->state[0]; @@ -455,7 +455,7 @@ mmap_read (SpaV4l2Source *this) case EIO: default: perror ("VIDIOC_DQBUF"); - return -1; + return SPA_RESULT_ERROR; } } @@ -464,7 +464,7 @@ mmap_read (SpaV4l2Source *this) state->ready = b; state->ready_count++; - return 0; + return SPA_RESULT_OK; } static int @@ -473,10 +473,9 @@ v4l2_on_fd_events (SpaPollNotifyData *data) SpaV4l2Source *this = data->user_data; SpaEvent event; - mmap_read (this); + if (mmap_read (this) < 0) + return 0; - event.refcount = 1; - event.notify = NULL; event.type = SPA_EVENT_TYPE_CAN_PULL_OUTPUT; event.port_id = 0; event.size = 0; @@ -487,14 +486,11 @@ v4l2_on_fd_events (SpaPollNotifyData *data) } static void -v4l2_buffer_recycle (void *data) +spa_v4l2_buffer_recycle (SpaV4l2Source *this, uint32_t buffer_id) { - SpaBuffer *buf = data; - SpaV4l2Source *this = buf->user_data; SpaV4l2State *state = &this->state[0]; - V4l2Buffer *b = &state->buffers[buf->id]; + V4l2Buffer *b = &state->buffers[buffer_id]; - b->imported->refcount = 1; b->outstanding = false; if (xioctl (state->fd, VIDIOC_QBUF, &b->v4l2_buffer) < 0) { @@ -502,7 +498,7 @@ v4l2_buffer_recycle (void *data) } } -static int +static SpaResult spa_v4l2_import_buffers (SpaV4l2Source *this, SpaBuffer **buffers, uint32_t n_buffers) { SpaV4l2State *state = &this->state[0]; @@ -518,12 +514,12 @@ spa_v4l2_import_buffers (SpaV4l2Source *this, SpaBuffer **buffers, uint32_t n_bu if (xioctl (state->fd, VIDIOC_REQBUFS, &reqbuf) < 0) { perror ("VIDIOC_REQBUFS"); - return -1; + return SPA_RESULT_ERROR; } fprintf (stderr, "got %d buffers\n", reqbuf.count); if (reqbuf.count < 2) { fprintf (stderr, "can't allocate enough buffers\n"); - return -1; + return SPA_RESULT_ERROR; } state->reqbuf = reqbuf; @@ -532,14 +528,9 @@ spa_v4l2_import_buffers (SpaV4l2Source *this, SpaBuffer **buffers, uint32_t n_bu b = &state->buffers[i]; - buffers[i]->notify = v4l2_buffer_recycle; - buffers[i]->user_data = this; - fprintf (stderr, "import buffer %p\n", buffers[i]); b->source = this; - b->buffer.refcount = 0; - b->buffer.notify = v4l2_buffer_recycle; b->buffer.id = buffers[i]->id; b->buffer.size = buffers[i]->size; b->buffer.n_metas = buffers[i]->n_metas; @@ -556,14 +547,14 @@ spa_v4l2_import_buffers (SpaV4l2Source *this, SpaBuffer **buffers, uint32_t n_bu b->v4l2_buffer.m.userptr = (unsigned long) b->buffer.datas[0].ptr; b->v4l2_buffer.length = b->buffer.datas[0].size; - v4l2_buffer_recycle (buffers[i]); + spa_v4l2_buffer_recycle (this, buffers[i]->id); } state->have_buffers = true; - return 0; + return SPA_RESULT_OK; } -static int +static SpaResult mmap_init (SpaV4l2Source *this, SpaAllocParam **params, unsigned int n_params, @@ -583,7 +574,7 @@ mmap_init (SpaV4l2Source *this, if (xioctl (state->fd, VIDIOC_REQBUFS, &reqbuf) < 0) { perror ("VIDIOC_REQBUFS"); - return -1; + return SPA_RESULT_ERROR; } fprintf (stderr, "got %d buffers\n", reqbuf.count); @@ -591,7 +582,7 @@ mmap_init (SpaV4l2Source *this, if (reqbuf.count < 2) { fprintf (stderr, "can't allocate enough buffers\n"); - return -1; + return SPA_RESULT_ERROR; } if (state->export_buf) fprintf (stderr, "using EXPBUF\n"); @@ -609,7 +600,7 @@ mmap_init (SpaV4l2Source *this, if (xioctl (state->fd, VIDIOC_QUERYBUF, &buf) < 0) { perror ("VIDIOC_QUERYBUF"); - return -1; + return SPA_RESULT_ERROR; } b = &state->buffers[i]; @@ -617,9 +608,6 @@ mmap_init (SpaV4l2Source *this, buffers[i] = &b->buffer; b->source = this; - b->buffer.refcount = 0; - b->buffer.notify = v4l2_buffer_recycle; - b->buffer.user_data = this; b->buffer.id = i; b->buffer.size = buf.length; b->buffer.n_metas = 1; @@ -679,47 +667,49 @@ mmap_init (SpaV4l2Source *this, b->v4l2_buffer.memory = state->memtype; b->v4l2_buffer.index = i; - v4l2_buffer_recycle (b); + spa_v4l2_buffer_recycle (this, i); } state->have_buffers = true; - return 0; + return SPA_RESULT_OK; } -static int +static SpaResult userptr_init (SpaV4l2Source *this) { - return -1; + return SPA_RESULT_NOT_IMPLEMENTED; } -static int +static SpaResult read_init (SpaV4l2Source *this) { - return -1; + return SPA_RESULT_NOT_IMPLEMENTED; } -static int +static SpaResult spa_v4l2_alloc_buffers (SpaV4l2Source *this, SpaAllocParam **params, unsigned int n_params, SpaBuffer **buffers, unsigned int *n_buffers) { + SpaResult res; SpaV4l2State *state = &this->state[0]; if (state->cap.capabilities & V4L2_CAP_STREAMING) { - if (mmap_init (this, params, n_params, buffers, n_buffers) < 0) - if (userptr_init (this) < 0) - return -1; + if ((res = mmap_init (this, params, n_params, buffers, n_buffers)) < 0) + if ((res = userptr_init (this)) < 0) + return res; } else if (state->cap.capabilities & V4L2_CAP_READWRITE) { - if (read_init (this) < 0) - return -1; + if ((res = read_init (this)) < 0) + return res; } else - return -1; - return 0; + return SPA_RESULT_ERROR; + + return SPA_RESULT_OK; } -static int +static SpaResult spa_v4l2_start (SpaV4l2Source *this) { SpaV4l2State *state = &this->state[0]; @@ -727,14 +717,11 @@ spa_v4l2_start (SpaV4l2Source *this) SpaEvent event; if (spa_v4l2_open (this) < 0) - return -1; + return SPA_RESULT_ERROR; if (!state->have_buffers) - return -1; + return SPA_RESULT_NO_BUFFERS; - - event.refcount = 1; - event.notify = NULL; event.type = SPA_EVENT_TYPE_ADD_POLL; event.port_id = 0; event.data = &state->poll; @@ -756,12 +743,12 @@ spa_v4l2_start (SpaV4l2Source *this) type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (xioctl (state->fd, VIDIOC_STREAMON, &type) < 0) { perror ("VIDIOC_STREAMON"); - return -1; + return SPA_RESULT_ERROR; } - return 0; + return SPA_RESULT_OK; } -static int +static SpaResult spa_v4l2_stop (SpaV4l2Source *this) { SpaV4l2State *state = &this->state[0]; @@ -769,10 +756,13 @@ spa_v4l2_stop (SpaV4l2Source *this) SpaEvent event; int i; + if (!state->opened) + return SPA_RESULT_OK; + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (xioctl (state->fd, VIDIOC_STREAMOFF, &type) < 0) { perror ("VIDIOC_STREAMOFF"); - return -1; + return SPA_RESULT_ERROR; } for (i = 0; i < state->reqbuf.count; i++) { @@ -781,7 +771,7 @@ spa_v4l2_stop (SpaV4l2Source *this) b = &state->buffers[i]; if (b->outstanding) { fprintf (stderr, "queueing outstanding buffer %p\n", b); - v4l2_buffer_recycle (b); + spa_v4l2_buffer_recycle (this, i); } if (state->export_buf) { close (b->dmafd); @@ -791,8 +781,6 @@ spa_v4l2_stop (SpaV4l2Source *this) } state->have_buffers = false; - event.refcount = 1; - event.notify = NULL; event.type = SPA_EVENT_TYPE_REMOVE_POLL; event.port_id = 0; event.data = &state->poll; @@ -801,5 +789,5 @@ spa_v4l2_stop (SpaV4l2Source *this) spa_v4l2_close (this); - return 0; + return SPA_RESULT_OK; } diff --git a/spa/plugins/volume/volume.c b/spa/plugins/volume/volume.c index e5afc217e..ec8eb9b3a 100644 --- a/spa/plugins/volume/volume.c +++ b/spa/plugins/volume/volume.c @@ -159,13 +159,13 @@ spa_volume_node_send_command (SpaNode *node, case SPA_COMMAND_START: if (this->event_cb) { SpaEvent event; + SpaEventStateChange sc; - event.refcount = 1; - event.notify = NULL; - event.type = SPA_EVENT_TYPE_STARTED; + event.type = SPA_EVENT_TYPE_STATE_CHANGE; event.port_id = -1; - event.data = NULL; - event.size = 0; + event.data = ≻ + event.size = sizeof (sc); + sc.state = SPA_NODE_STATE_STREAMING; this->event_cb (node, &event, this->user_data); } @@ -174,13 +174,13 @@ spa_volume_node_send_command (SpaNode *node, case SPA_COMMAND_STOP: if (this->event_cb) { SpaEvent event; + SpaEventStateChange sc; - event.refcount = 1; - event.notify = NULL; - event.type = SPA_EVENT_TYPE_STOPPED; + event.type = SPA_EVENT_TYPE_STATE_CHANGE; event.port_id = -1; - event.data = NULL; - event.size = 0; + event.data = ≻ + event.size = sizeof (sc); + sc.state = SPA_NODE_STATE_PAUSED; this->event_cb (node, &event, this->user_data); } @@ -398,6 +398,36 @@ spa_volume_node_port_set_props (SpaNode *node, return SPA_RESULT_NOT_IMPLEMENTED; } +static SpaResult +spa_volume_node_port_use_buffers (SpaNode *node, + uint32_t port_id, + SpaBuffer **buffers, + uint32_t n_buffers) +{ + return SPA_RESULT_NOT_IMPLEMENTED; +} + +static SpaResult +spa_volume_node_port_alloc_buffers (SpaNode *node, + uint32_t port_id, + SpaAllocParam **params, + uint32_t n_params, + SpaBuffer **buffers, + uint32_t *n_buffers) +{ + return SPA_RESULT_NOT_IMPLEMENTED; +} + +static SpaResult +spa_volume_node_port_reuse_buffer (SpaNode *node, + uint32_t port_id, + uint32_t buffer_id, + off_t offset, + size_t size) +{ + return SPA_RESULT_NOT_IMPLEMENTED; +} + static SpaResult spa_volume_node_port_get_status (SpaNode *node, uint32_t port_id, @@ -424,26 +454,6 @@ spa_volume_node_port_get_status (SpaNode *node, return SPA_RESULT_OK; } -static SpaResult -spa_volume_node_port_use_buffers (SpaNode *node, - uint32_t port_id, - SpaBuffer **buffers, - uint32_t n_buffers) -{ - return SPA_RESULT_NOT_IMPLEMENTED; -} - -static SpaResult -spa_volume_node_port_alloc_buffers (SpaNode *node, - uint32_t port_id, - SpaAllocParam **params, - uint32_t n_params, - SpaBuffer **buffers, - uint32_t *n_buffers) -{ - return SPA_RESULT_NOT_IMPLEMENTED; -} - static SpaResult spa_volume_node_port_push_input (SpaNode *node, @@ -471,7 +481,7 @@ spa_volume_node_port_push_input (SpaNode *node, } port = &this->ports[info[i].port_id]; - buffer = port->buffers[info[i].id]; + buffer = port->buffers[info[i].buffer_id]; if (buffer == NULL) { info[i].status = SPA_RESULT_INVALID_ARGUMENTS; @@ -491,7 +501,7 @@ spa_volume_node_port_push_input (SpaNode *node, have_enough = true; continue; } - port->buffer = spa_buffer_ref (buffer); + port->buffer = buffer; this->ports[0].status.flags &= ~SPA_PORT_STATUS_FLAG_NEED_INPUT; this->ports[1].status.flags |= SPA_PORT_STATUS_FLAG_HAVE_OUTPUT; @@ -512,6 +522,22 @@ find_free_buffer (SpaVolume *this, SpaVolumePort *port) return NULL; } +static void +release_buffer (SpaVolume *this, SpaBuffer *buffer) +{ + SpaEvent event; + SpaEventReuseBuffer rb; + + event.type = SPA_EVENT_TYPE_REUSE_BUFFER; + event.port_id = 0; + event.data = &rb; + event.size = sizeof (rb); + rb.buffer_id = buffer->id; + rb.offset = 0; + rb.size = -1; + this->event_cb (&this->node, &event, this->user_data); +} + static SpaResult spa_volume_node_port_pull_output (SpaNode *node, unsigned int n_info, @@ -586,10 +612,10 @@ spa_volume_node_port_pull_output (SpaNode *node, } if (sbuf != dbuf) - spa_buffer_unref (sbuf); + release_buffer (this, sbuf); this->ports[0].buffer = NULL; - info->id = dbuf->id; + info->buffer_id = dbuf->id; this->ports[0].status.flags |= SPA_PORT_STATUS_FLAG_NEED_INPUT; this->ports[1].status.flags &= ~SPA_PORT_STATUS_FLAG_HAVE_OUTPUT; @@ -624,6 +650,7 @@ static const SpaNode volume_node = { spa_volume_node_port_set_props, spa_volume_node_port_use_buffers, spa_volume_node_port_alloc_buffers, + spa_volume_node_port_reuse_buffer, spa_volume_node_port_get_status, spa_volume_node_port_push_input, spa_volume_node_port_pull_output, diff --git a/spa/plugins/xv/xv-sink.c b/spa/plugins/xv/xv-sink.c index 75350a0c3..4cbca631c 100644 --- a/spa/plugins/xv/xv-sink.c +++ b/spa/plugins/xv/xv-sink.c @@ -187,13 +187,13 @@ spa_xv_sink_node_send_command (SpaNode *node, if (this->event_cb) { SpaEvent event; + SpaEventStateChange sc; - event.refcount = 1; - event.notify = NULL; - event.type = SPA_EVENT_TYPE_STARTED; + event.type = SPA_EVENT_TYPE_STATE_CHANGE; event.port_id = -1; - event.data = NULL; - event.size = 0; + event.data = ≻ + event.size = sizeof (sc); + sc.state = SPA_NODE_STATE_STREAMING; this->event_cb (node, &event, this->user_data); } @@ -203,13 +203,13 @@ spa_xv_sink_node_send_command (SpaNode *node, if (this->event_cb) { SpaEvent event; + SpaEventStateChange sc; - event.refcount = 1; - event.notify = NULL; - event.type = SPA_EVENT_TYPE_STOPPED; + event.type = SPA_EVENT_TYPE_STATE_CHANGE; event.port_id = -1; - event.data = NULL; - event.size = 0; + event.data = ≻ + event.size = sizeof (sc); + sc.state = SPA_NODE_STATE_PAUSED; this->event_cb (node, &event, this->user_data); } @@ -435,26 +435,6 @@ spa_xv_sink_node_port_set_props (SpaNode *node, return SPA_RESULT_NOT_IMPLEMENTED; } -static SpaResult -spa_xv_sink_node_port_get_status (SpaNode *node, - uint32_t port_id, - const SpaPortStatus **status) -{ - SpaXvSink *this; - - if (node == NULL || node->handle == NULL || status == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - this = (SpaXvSink *) node->handle; - - if (port_id != 0) - return SPA_RESULT_INVALID_PORT; - - *status = &this->status; - - return SPA_RESULT_OK; -} - static SpaResult spa_xv_sink_node_port_use_buffers (SpaNode *node, uint32_t port_id, @@ -475,6 +455,36 @@ spa_xv_sink_node_port_alloc_buffers (SpaNode *node, return SPA_RESULT_NOT_IMPLEMENTED; } +static SpaResult +spa_xv_sink_node_port_reuse_buffer (SpaNode *node, + uint32_t port_id, + uint32_t buffer_id, + off_t offset, + size_t size) +{ + return SPA_RESULT_NOT_IMPLEMENTED; +} + +static SpaResult +spa_xv_sink_node_port_get_status (SpaNode *node, + uint32_t port_id, + const SpaPortStatus **status) +{ + SpaXvSink *this; + + if (node == NULL || node->handle == NULL || status == NULL) + return SPA_RESULT_INVALID_ARGUMENTS; + + this = (SpaXvSink *) node->handle; + + if (port_id != 0) + return SPA_RESULT_INVALID_PORT; + + *status = &this->status; + + return SPA_RESULT_OK; +} + static SpaResult spa_xv_sink_node_port_push_input (SpaNode *node, unsigned int n_info, @@ -518,6 +528,7 @@ static const SpaNode xvsink_node = { spa_xv_sink_node_port_set_props, spa_xv_sink_node_port_use_buffers, spa_xv_sink_node_port_alloc_buffers, + spa_xv_sink_node_port_reuse_buffer, spa_xv_sink_node_port_get_status, spa_xv_sink_node_port_push_input, spa_xv_sink_node_port_pull_output, diff --git a/spa/tests/test-mixer.c b/spa/tests/test-mixer.c index 2bf34b3dd..bfdeb2461 100644 --- a/spa/tests/test-mixer.c +++ b/spa/tests/test-mixer.c @@ -118,7 +118,7 @@ on_mix_event (SpaNode *node, SpaEvent *event, void *user_data) iinfo.port_id = event->port_id; iinfo.flags = SPA_INPUT_FLAG_NONE; - iinfo.id = oinfo.id; + iinfo.buffer_id = oinfo.buffer_id; if ((res = spa_node_port_push_input (data->mix, 1, &iinfo)) < 0) printf ("got error from mixer %d\n", res); @@ -155,7 +155,7 @@ on_sink_event (SpaNode *node, SpaEvent *event, void *user_data) iinfo.port_id = event->port_id; iinfo.flags = SPA_INPUT_FLAG_NONE; - iinfo.id = oinfo.id; + iinfo.buffer_id = oinfo.buffer_id; if ((res = spa_node_port_push_input (data->sink, 1, &iinfo)) < 0) printf ("got error %d\n", res); diff --git a/spa/tests/test-v4l2.c b/spa/tests/test-v4l2.c index e8a5695a9..a8436b82b 100644 --- a/spa/tests/test-v4l2.c +++ b/spa/tests/test-v4l2.c @@ -125,7 +125,7 @@ on_source_event (SpaNode *node, SpaEvent *event, void *user_data) if ((res = spa_node_port_pull_output (data->source, 1, info)) < 0) printf ("got pull error %d\n", res); - b = data->bp[info->id]; + b = data->bp[info->buffer_id]; if (b->metas[1].type == SPA_META_TYPE_POINTER && strcmp (((SpaMetaPointer*)b->metas[1].data)->ptr_type, "SDL_Texture") == 0) { @@ -165,7 +165,7 @@ on_source_event (SpaNode *node, SpaEvent *event, void *user_data) SDL_RenderCopy (data->renderer, data->texture, NULL, NULL); SDL_RenderPresent (data->renderer); } - spa_buffer_unref (b); + spa_node_port_reuse_buffer (data->source, 0, info->buffer_id, info->offset, info->size); break; } case SPA_EVENT_TYPE_ADD_POLL: @@ -237,8 +237,6 @@ alloc_buffers (AppData *data) return; } - b->buffer.refcount = 1; - b->buffer.notify = NULL; b->buffer.id = i; b->buffer.size = stride * 240; b->buffer.n_metas = 2;