mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
work on sink
This commit is contained in:
parent
bdbddaf75b
commit
a03352353f
9 changed files with 180 additions and 306 deletions
|
|
@ -123,8 +123,6 @@ enum
|
|||
|
||||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
static void unhandle_socket (PinosStream *stream);
|
||||
|
||||
static void
|
||||
pinos_stream_get_property (GObject *_object,
|
||||
guint prop_id,
|
||||
|
|
@ -674,15 +672,12 @@ parse_control (PinosStream *stream,
|
|||
case SPA_CONTROL_CMD_REMOVE_MEM:
|
||||
{
|
||||
SpaControlCmdRemoveMem p;
|
||||
SpaMemory *mem;
|
||||
|
||||
if (spa_control_iter_parse_cmd (&it, &p) < 0)
|
||||
break;
|
||||
|
||||
g_debug ("stream %p: stop", stream);
|
||||
mem = spa_memory_find (&p.mem);
|
||||
if (--mem->refcount == 0)
|
||||
mem->notify (mem);
|
||||
g_debug ("stream %p: remove mem", stream);
|
||||
spa_memory_unref (&p.mem);
|
||||
break;
|
||||
}
|
||||
case SPA_CONTROL_CMD_ADD_BUFFER:
|
||||
|
|
@ -813,23 +808,11 @@ handle_socket (PinosStream *stream, gint fd)
|
|||
if (priv->socket == NULL)
|
||||
goto socket_failed;
|
||||
|
||||
switch (priv->mode) {
|
||||
case PINOS_STREAM_MODE_SOCKET:
|
||||
g_object_notify (G_OBJECT (stream), "socket");
|
||||
break;
|
||||
priv->fd = g_socket_get_fd (priv->socket);
|
||||
priv->socket_source = g_socket_create_source (priv->socket, G_IO_IN, NULL);
|
||||
g_source_set_callback (priv->socket_source, (GSourceFunc) on_socket_condition, stream, NULL);
|
||||
g_source_attach (priv->socket_source, priv->context->priv->context);
|
||||
|
||||
case PINOS_STREAM_MODE_BUFFER:
|
||||
{
|
||||
priv->fd = g_socket_get_fd (priv->socket);
|
||||
priv->socket_source = g_socket_create_source (priv->socket, G_IO_IN, NULL);
|
||||
g_source_set_callback (priv->socket_source, (GSourceFunc) on_socket_condition, stream, NULL);
|
||||
g_source_attach (priv->socket_source, priv->context->priv->context);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return;
|
||||
|
||||
/* ERRORS */
|
||||
|
|
@ -846,21 +829,9 @@ unhandle_socket (PinosStream *stream)
|
|||
{
|
||||
PinosStreamPrivate *priv = stream->priv;
|
||||
|
||||
switch (priv->mode) {
|
||||
case PINOS_STREAM_MODE_SOCKET:
|
||||
g_clear_object (&priv->socket);
|
||||
g_object_notify (G_OBJECT (stream), "socket");
|
||||
break;
|
||||
|
||||
case PINOS_STREAM_MODE_BUFFER:
|
||||
if (priv->socket_source) {
|
||||
g_source_destroy (priv->socket_source);
|
||||
g_clear_pointer (&priv->socket_source, g_source_unref);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
if (priv->socket_source) {
|
||||
g_source_destroy (priv->socket_source);
|
||||
g_clear_pointer (&priv->socket_source, g_source_unref);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -876,8 +847,8 @@ do_node_init (PinosStream *stream)
|
|||
control_builder_init (stream, &builder);
|
||||
nu.change_mask = SPA_CONTROL_CMD_NODE_UPDATE_MAX_INPUTS |
|
||||
SPA_CONTROL_CMD_NODE_UPDATE_MAX_OUTPUTS;
|
||||
nu.max_input_ports = 1;
|
||||
nu.max_output_ports = 0;
|
||||
nu.max_input_ports = priv->direction == PINOS_DIRECTION_INPUT ? 1 : 0;
|
||||
nu.max_output_ports = priv->direction == PINOS_DIRECTION_OUTPUT ? 1 : 0;
|
||||
nu.props = NULL;
|
||||
spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_NODE_UPDATE, &nu);
|
||||
|
||||
|
|
@ -964,9 +935,10 @@ on_node_created (GObject *source_object,
|
|||
goto fd_failed;
|
||||
|
||||
priv->fd = fd;
|
||||
|
||||
g_object_unref (fd_list);
|
||||
|
||||
handle_socket (stream, priv->fd);
|
||||
|
||||
pinos_subscribe_get_proxy (context->priv->subscribe,
|
||||
PINOS_DBUS_SERVICE,
|
||||
node_path,
|
||||
|
|
@ -1026,17 +998,23 @@ do_connect (PinosStream *stream)
|
|||
* pinos_stream_connect:
|
||||
* @stream: a #PinosStream
|
||||
* @direction: the stream direction
|
||||
* @mode: a #PinosStreamMode
|
||||
* @port_path: the port path to connect to or %NULL to get the default port
|
||||
* @flags: a #PinosStreamFlags
|
||||
* @possible_formats: (transfer full): a #GPtrArray with possible accepted formats
|
||||
*
|
||||
* Connect @stream for input or output on @port_path.
|
||||
*
|
||||
* When @mode is #PINOS_STREAM_MODE_BUFFER, you should connect to the new-buffer
|
||||
* signal and use pinos_stream_capture_buffer() to get the latest metadata and
|
||||
* data.
|
||||
*
|
||||
* Returns: %TRUE on success.
|
||||
*/
|
||||
gboolean
|
||||
pinos_stream_connect (PinosStream *stream,
|
||||
PinosDirection direction,
|
||||
PinosStreamMode mode,
|
||||
const gchar *port_path,
|
||||
PinosStreamFlags flags,
|
||||
GPtrArray *possible_formats)
|
||||
|
|
@ -1053,6 +1031,7 @@ pinos_stream_connect (PinosStream *stream,
|
|||
g_return_val_if_fail (pinos_stream_get_state (stream) == PINOS_STREAM_STATE_UNCONNECTED, FALSE);
|
||||
|
||||
priv->direction = direction;
|
||||
priv->mode = mode;
|
||||
g_free (priv->path);
|
||||
priv->path = g_strdup (port_path);
|
||||
priv->flags = flags;
|
||||
|
|
@ -1077,8 +1056,6 @@ do_start (PinosStream *stream)
|
|||
SpaControlCmdStateChange sc;
|
||||
SpaControl control;
|
||||
|
||||
handle_socket (stream, priv->fd);
|
||||
|
||||
control_builder_init (stream, &builder);
|
||||
sc.state = SPA_NODE_STATE_CONFIGURE;
|
||||
spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_STATE_CHANGE, &sc);
|
||||
|
|
@ -1097,24 +1074,14 @@ do_start (PinosStream *stream)
|
|||
/**
|
||||
* pinos_stream_start:
|
||||
* @stream: a #PinosStream
|
||||
* @format: (transfer full): a #SpaFormat with format
|
||||
* @mode: a #PinosStreamMode
|
||||
*
|
||||
* Start capturing from @stream in @format.
|
||||
* Start capturing from @stream.
|
||||
*
|
||||
* When @mode is #PINOS_STREAM_MODE_SOCKET, you should connect to the notify::socket
|
||||
* signal to obtain a readable socket with metadata and data.
|
||||
*
|
||||
* When @mode is #PINOS_STREAM_MODE_BUFFER, you should connect to the new-buffer
|
||||
* signal and use pinos_stream_capture_buffer() to get the latest metadata and
|
||||
* data.
|
||||
*
|
||||
* Returns: %TRUE on success.
|
||||
*/
|
||||
gboolean
|
||||
pinos_stream_start (PinosStream *stream,
|
||||
SpaFormat *format,
|
||||
PinosStreamMode mode)
|
||||
pinos_stream_start (PinosStream *stream)
|
||||
{
|
||||
PinosStreamPrivate *priv;
|
||||
|
||||
|
|
@ -1123,9 +1090,6 @@ pinos_stream_start (PinosStream *stream,
|
|||
priv = stream->priv;
|
||||
g_return_val_if_fail (priv->state == PINOS_STREAM_STATE_READY, FALSE);
|
||||
|
||||
priv->mode = mode;
|
||||
priv->format = format;
|
||||
|
||||
stream_set_state (stream, PINOS_STREAM_STATE_STARTING, NULL);
|
||||
|
||||
g_main_context_invoke (priv->context->priv->context,
|
||||
|
|
@ -1193,6 +1157,8 @@ on_node_removed (GObject *source_object,
|
|||
|
||||
g_variant_unref (ret);
|
||||
|
||||
unhandle_socket (stream);
|
||||
|
||||
stream_set_state (stream, PINOS_STREAM_STATE_UNCONNECTED, NULL);
|
||||
g_object_unref (stream);
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -60,9 +60,8 @@ typedef enum {
|
|||
} PinosStreamFlags;
|
||||
|
||||
typedef enum {
|
||||
PINOS_STREAM_MODE_SOCKET = 0,
|
||||
PINOS_STREAM_MODE_BUFFER = 1,
|
||||
PINOS_STREAM_MODE_RINGBUFFER = 2,
|
||||
PINOS_STREAM_MODE_BUFFER = 0,
|
||||
PINOS_STREAM_MODE_RINGBUFFER = 1,
|
||||
} PinosStreamMode;
|
||||
|
||||
/**
|
||||
|
|
@ -98,14 +97,13 @@ const GError * pinos_stream_get_error (PinosStream *stream);
|
|||
|
||||
gboolean pinos_stream_connect (PinosStream *stream,
|
||||
PinosDirection direction,
|
||||
PinosStreamMode mode,
|
||||
const gchar *port_path,
|
||||
PinosStreamFlags flags,
|
||||
GPtrArray *possible_formats);
|
||||
gboolean pinos_stream_disconnect (PinosStream *stream);
|
||||
|
||||
gboolean pinos_stream_start (PinosStream *stream,
|
||||
SpaFormat *format,
|
||||
PinosStreamMode mode);
|
||||
gboolean pinos_stream_start (PinosStream *stream);
|
||||
gboolean pinos_stream_stop (PinosStream *stream);
|
||||
|
||||
SpaBuffer * pinos_stream_peek_buffer (PinosStream *stream);
|
||||
|
|
|
|||
|
|
@ -414,16 +414,12 @@ gst_pinos_sink_setcaps (GstBaseSink * bsink, GstCaps * caps)
|
|||
{
|
||||
GstPinosSink *pinossink;
|
||||
GPtrArray *possible;
|
||||
SpaFormat *format;
|
||||
PinosStreamState state;
|
||||
gboolean res = FALSE;
|
||||
|
||||
pinossink = GST_PINOS_SINK (bsink);
|
||||
|
||||
format = gst_caps_to_format (caps, 0);
|
||||
possible = g_ptr_array_new ();
|
||||
spa_format_ref (format);
|
||||
g_ptr_array_insert (possible, -1, format);
|
||||
possible = gst_caps_to_format_all (caps);
|
||||
|
||||
pinos_main_loop_lock (pinossink->loop);
|
||||
state = pinos_stream_get_state (pinossink->stream);
|
||||
|
|
@ -439,6 +435,7 @@ gst_pinos_sink_setcaps (GstBaseSink * bsink, GstCaps * caps)
|
|||
|
||||
pinos_stream_connect (pinossink->stream,
|
||||
PINOS_DIRECTION_OUTPUT,
|
||||
PINOS_STREAM_MODE_BUFFER,
|
||||
pinossink->path,
|
||||
flags,
|
||||
possible);
|
||||
|
|
@ -457,9 +454,7 @@ gst_pinos_sink_setcaps (GstBaseSink * bsink, GstCaps * caps)
|
|||
}
|
||||
|
||||
if (state != PINOS_STREAM_STATE_STREAMING) {
|
||||
res = pinos_stream_start (pinossink->stream,
|
||||
format,
|
||||
PINOS_STREAM_MODE_BUFFER);
|
||||
res = pinos_stream_start (pinossink->stream);
|
||||
|
||||
while (TRUE) {
|
||||
state = pinos_stream_get_state (pinossink->stream);
|
||||
|
|
@ -483,7 +478,7 @@ start_error:
|
|||
{
|
||||
GST_ERROR ("could not start stream");
|
||||
pinos_main_loop_unlock (pinossink->loop);
|
||||
spa_format_unref (format);
|
||||
g_ptr_array_unref (possible);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -484,19 +484,14 @@ parse_stream_properties (GstPinosSrc *pinossrc, PinosProperties *props)
|
|||
|
||||
|
||||
static gboolean
|
||||
gst_pinos_src_stream_start (GstPinosSrc *pinossrc, GstCaps * caps)
|
||||
gst_pinos_src_stream_start (GstPinosSrc *pinossrc)
|
||||
{
|
||||
SpaFormat *format;
|
||||
gboolean res;
|
||||
PinosProperties *props;
|
||||
|
||||
if (caps)
|
||||
format = gst_caps_to_format (caps, 0);
|
||||
else
|
||||
format = NULL;
|
||||
|
||||
pinos_main_loop_lock (pinossrc->loop);
|
||||
res = pinos_stream_start (pinossrc->stream, format, PINOS_STREAM_MODE_BUFFER);
|
||||
res = pinos_stream_start (pinossrc->stream);
|
||||
while (TRUE) {
|
||||
PinosStreamState state = pinos_stream_get_state (pinossrc->stream);
|
||||
|
||||
|
|
@ -515,8 +510,9 @@ gst_pinos_src_stream_start (GstPinosSrc *pinossrc, GstCaps * caps)
|
|||
pinos_main_loop_unlock (pinossrc->loop);
|
||||
|
||||
if (format) {
|
||||
caps = gst_caps_from_format (format);
|
||||
GstCaps *caps = gst_caps_from_format (format);
|
||||
gst_base_src_set_caps (GST_BASE_SRC (pinossrc), caps);
|
||||
gst_caps_unref (caps);
|
||||
spa_format_unref (format);
|
||||
}
|
||||
|
||||
|
|
@ -609,6 +605,7 @@ gst_pinos_src_negotiate (GstBaseSrc * basesrc)
|
|||
GST_DEBUG_OBJECT (basesrc, "connect capture with path %s", pinossrc->path);
|
||||
pinos_stream_connect (pinossrc->stream,
|
||||
PINOS_DIRECTION_INPUT,
|
||||
PINOS_STREAM_MODE_BUFFER,
|
||||
pinossrc->path,
|
||||
PINOS_STREAM_FLAG_AUTOCONNECT,
|
||||
possible);
|
||||
|
|
@ -626,7 +623,7 @@ gst_pinos_src_negotiate (GstBaseSrc * basesrc)
|
|||
}
|
||||
pinos_main_loop_unlock (pinossrc->loop);
|
||||
|
||||
result = gst_pinos_src_stream_start (pinossrc, NULL);
|
||||
result = gst_pinos_src_stream_start (pinossrc);
|
||||
|
||||
pinossrc->negotiated = result;
|
||||
|
||||
|
|
|
|||
|
|
@ -53,8 +53,6 @@ typedef struct {
|
|||
|
||||
struct _PinosSpaAlsaSinkPrivate
|
||||
{
|
||||
SpaNode *sink;
|
||||
|
||||
PinosProperties *props;
|
||||
PinosRingbuffer *ringbuffer;
|
||||
|
||||
|
|
@ -121,6 +119,39 @@ make_node (SpaNode **node, const char *lib, const char *name)
|
|||
return SPA_RESULT_ERROR;
|
||||
}
|
||||
|
||||
static void *
|
||||
loop (void *user_data)
|
||||
{
|
||||
PinosSpaAlsaSink *this = user_data;
|
||||
PinosSpaAlsaSinkPrivate *priv = this->priv;
|
||||
int r;
|
||||
|
||||
g_debug ("spa-alsa-sink %p: enter thread", this);
|
||||
while (priv->running) {
|
||||
SpaPollNotifyData ndata;
|
||||
|
||||
r = poll ((struct pollfd *) priv->fds, priv->n_fds, -1);
|
||||
if (r < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
if (r == 0) {
|
||||
g_debug ("spa-alsa-sink %p: select timeout", this);
|
||||
break;
|
||||
}
|
||||
if (priv->poll.after_cb) {
|
||||
ndata.fds = priv->poll.fds;
|
||||
ndata.n_fds = priv->poll.n_fds;
|
||||
ndata.user_data = priv->poll.user_data;
|
||||
priv->poll.after_cb (&ndata);
|
||||
}
|
||||
}
|
||||
g_debug ("spa-alsa-sink %p: leave thread", this);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
on_sink_event (SpaNode *node, SpaEvent *event, void *user_data)
|
||||
{
|
||||
|
|
@ -167,7 +198,7 @@ on_sink_event (SpaNode *node, SpaEvent *event, void *user_data)
|
|||
iinfo.size = total;
|
||||
|
||||
g_debug ("push sink %d", iinfo.buffer_id);
|
||||
if ((res = spa_node_port_push_input (priv->sink, 1, &iinfo)) < 0)
|
||||
if ((res = spa_node_port_push_input (node, 1, &iinfo)) < 0)
|
||||
g_debug ("got error %d", res);
|
||||
break;
|
||||
}
|
||||
|
|
@ -175,12 +206,21 @@ on_sink_event (SpaNode *node, SpaEvent *event, void *user_data)
|
|||
case SPA_EVENT_TYPE_ADD_POLL:
|
||||
{
|
||||
SpaPollItem *poll = event->data;
|
||||
int err;
|
||||
|
||||
g_debug ("add poll");
|
||||
priv->poll = *poll;
|
||||
priv->fds[0] = poll->fds[0];
|
||||
priv->n_fds = 1;
|
||||
priv->poll.fds = priv->fds;
|
||||
|
||||
if (!priv->running) {
|
||||
priv->running = true;
|
||||
if ((err = pthread_create (&priv->thread, NULL, loop, this)) != 0) {
|
||||
g_debug ("spa-v4l2-source %p: can't create thread", strerror (err));
|
||||
priv->running = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -191,20 +231,16 @@ on_sink_event (SpaNode *node, SpaEvent *event, void *user_data)
|
|||
}
|
||||
|
||||
static void
|
||||
create_pipeline (PinosSpaAlsaSink *this)
|
||||
setup_node (PinosSpaAlsaSink *this)
|
||||
{
|
||||
PinosSpaAlsaSinkPrivate *priv = this->priv;
|
||||
PinosNode *node = PINOS_NODE (this);
|
||||
SpaResult res;
|
||||
SpaProps *props;
|
||||
SpaPropValue value;
|
||||
|
||||
if ((res = make_node (&priv->sink, "spa/build/plugins/alsa/libspa-alsa.so", "alsa-sink")) < 0) {
|
||||
g_error ("can't create alsa-sink: %d", res);
|
||||
return;
|
||||
}
|
||||
spa_node_set_event_callback (priv->sink, on_sink_event, this);
|
||||
spa_node_set_event_callback (node->node, on_sink_event, this);
|
||||
|
||||
if ((res = spa_node_get_props (priv->sink, &props)) < 0)
|
||||
if ((res = spa_node_get_props (node->node, &props)) < 0)
|
||||
g_debug ("got get_props error %d", res);
|
||||
|
||||
value.type = SPA_PROP_TYPE_STRING;
|
||||
|
|
@ -212,67 +248,14 @@ create_pipeline (PinosSpaAlsaSink *this)
|
|||
value.size = strlen (value.value)+1;
|
||||
spa_props_set_prop (props, spa_props_index_for_name (props, "device"), &value);
|
||||
|
||||
if ((res = spa_node_set_props (priv->sink, props)) < 0)
|
||||
if ((res = spa_node_set_props (node->node, props)) < 0)
|
||||
g_debug ("got set_props error %d", res);
|
||||
}
|
||||
|
||||
static void *
|
||||
loop (void *user_data)
|
||||
{
|
||||
PinosSpaAlsaSink *this = user_data;
|
||||
PinosSpaAlsaSinkPrivate *priv = this->priv;
|
||||
int r;
|
||||
|
||||
g_debug ("spa-alsa-sink %p: enter thread", this);
|
||||
while (priv->running) {
|
||||
SpaPollNotifyData ndata;
|
||||
|
||||
r = poll ((struct pollfd *) priv->fds, priv->n_fds, -1);
|
||||
if (r < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
if (r == 0) {
|
||||
g_debug ("spa-alsa-sink %p: select timeout", this);
|
||||
break;
|
||||
}
|
||||
if (priv->poll.after_cb) {
|
||||
ndata.fds = priv->poll.fds;
|
||||
ndata.n_fds = priv->poll.n_fds;
|
||||
ndata.user_data = priv->poll.user_data;
|
||||
priv->poll.after_cb (&ndata);
|
||||
}
|
||||
}
|
||||
g_debug ("spa-alsa-sink %p: leave thread", this);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
start_pipeline (PinosSpaAlsaSink *sink)
|
||||
{
|
||||
PinosSpaAlsaSinkPrivate *priv = sink->priv;
|
||||
SpaResult res;
|
||||
SpaCommand cmd;
|
||||
int err;
|
||||
|
||||
g_debug ("spa-alsa-sink %p: starting pipeline", sink);
|
||||
|
||||
cmd.type = SPA_COMMAND_START;
|
||||
if ((res = spa_node_send_command (priv->sink, &cmd)) < 0)
|
||||
g_debug ("got error %d", res);
|
||||
|
||||
priv->running = true;
|
||||
if ((err = pthread_create (&priv->thread, NULL, loop, sink)) != 0) {
|
||||
g_debug ("spa-v4l2-source %p: can't create thread", strerror (err));
|
||||
priv->running = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
stop_pipeline (PinosSpaAlsaSink *sink)
|
||||
{
|
||||
PinosNode *node = PINOS_NODE (sink);
|
||||
PinosSpaAlsaSinkPrivate *priv = sink->priv;
|
||||
SpaResult res;
|
||||
SpaCommand cmd;
|
||||
|
|
@ -285,7 +268,7 @@ stop_pipeline (PinosSpaAlsaSink *sink)
|
|||
}
|
||||
|
||||
cmd.type = SPA_COMMAND_STOP;
|
||||
if ((res = spa_node_send_command (priv->sink, &cmd)) < 0)
|
||||
if ((res = spa_node_send_command (node->node, &cmd)) < 0)
|
||||
g_debug ("got error %d", res);
|
||||
}
|
||||
|
||||
|
|
@ -315,7 +298,6 @@ set_state (PinosNode *node,
|
|||
break;
|
||||
|
||||
case PINOS_NODE_STATE_RUNNING:
|
||||
start_pipeline (this);
|
||||
break;
|
||||
|
||||
case PINOS_NODE_STATE_ERROR:
|
||||
|
|
@ -378,47 +360,6 @@ free_sink_port_data (SinkPortData *data)
|
|||
g_slice_free (SinkPortData, data);
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
negotiate_formats (PinosSpaAlsaSink *this)
|
||||
{
|
||||
PinosSpaAlsaSinkPrivate *priv = this->priv;
|
||||
SpaResult res;
|
||||
SpaFormat *format;
|
||||
SpaProps *props;
|
||||
uint32_t val;
|
||||
SpaPropValue value;
|
||||
void *state = NULL;
|
||||
|
||||
if ((res = spa_node_port_enum_formats (priv->sink, 0, &format, NULL, &state)) < 0)
|
||||
return res;
|
||||
|
||||
props = &format->props;
|
||||
|
||||
value.type = SPA_PROP_TYPE_UINT32;
|
||||
value.size = sizeof (uint32_t);
|
||||
value.value = &val;
|
||||
|
||||
val = SPA_AUDIO_FORMAT_S16LE;
|
||||
if ((res = spa_props_set_prop (props, spa_props_index_for_id (props, SPA_PROP_ID_AUDIO_FORMAT), &value)) < 0)
|
||||
return res;
|
||||
val = SPA_AUDIO_LAYOUT_INTERLEAVED;
|
||||
if ((res = spa_props_set_prop (props, spa_props_index_for_id (props, SPA_PROP_ID_AUDIO_LAYOUT), &value)) < 0)
|
||||
return res;
|
||||
val = 44100;
|
||||
if ((res = spa_props_set_prop (props, spa_props_index_for_id (props, SPA_PROP_ID_AUDIO_RATE), &value)) < 0)
|
||||
return res;
|
||||
val = 2;
|
||||
if ((res = spa_props_set_prop (props, spa_props_index_for_id (props, SPA_PROP_ID_AUDIO_CHANNELS), &value)) < 0)
|
||||
return res;
|
||||
|
||||
if ((res = spa_node_port_set_format (priv->sink, 0, 0, format)) < 0)
|
||||
return res;
|
||||
|
||||
priv->ringbuffer = pinos_ringbuffer_new (PINOS_RINGBUFFER_MODE_READ, 64 * 1024);
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
free_mem_block (MemBlock *b)
|
||||
{
|
||||
|
|
@ -475,23 +416,6 @@ on_received_event (PinosPort *port,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
on_format_change (GObject *obj,
|
||||
GParamSpec *pspec,
|
||||
gpointer user_data)
|
||||
{
|
||||
SinkPortData *data = user_data;
|
||||
PinosNode *node = PINOS_NODE (data->sink);
|
||||
PinosSpaAlsaSink *sink = PINOS_SPA_ALSA_SINK (node);
|
||||
GBytes *formats;
|
||||
|
||||
g_object_get (obj, "format", &formats, NULL);
|
||||
if (formats) {
|
||||
g_debug ("port %p: format change %s", obj, (gchar*) g_bytes_get_data (formats, NULL));
|
||||
negotiate_formats (sink);
|
||||
}
|
||||
}
|
||||
|
||||
static PinosPort *
|
||||
add_port (PinosNode *node,
|
||||
PinosDirection direction,
|
||||
|
|
@ -501,7 +425,6 @@ add_port (PinosNode *node,
|
|||
PinosSpaAlsaSink *sink = PINOS_SPA_ALSA_SINK (node);
|
||||
PinosSpaAlsaSinkPrivate *priv = sink->priv;
|
||||
SinkPortData *data;
|
||||
GBytes *formats;
|
||||
|
||||
data = g_slice_new0 (SinkPortData);
|
||||
data->sink = sink;
|
||||
|
|
@ -511,15 +434,10 @@ add_port (PinosNode *node,
|
|||
|
||||
pinos_port_set_received_cb (data->port, on_received_buffer, on_received_event, sink, NULL);
|
||||
|
||||
formats = g_bytes_new ("ANY", strlen ("ANY") + 1);
|
||||
g_object_set (data->port, "possible-formats", formats, NULL);
|
||||
|
||||
g_debug ("connecting signals");
|
||||
g_signal_connect (data->port, "activate", (GCallback) on_activate, data);
|
||||
g_signal_connect (data->port, "deactivate", (GCallback) on_deactivate, data);
|
||||
|
||||
g_signal_connect (data->port, "notify::format", (GCallback) on_format_change, data);
|
||||
|
||||
priv->ports = g_list_append (priv->ports, data);
|
||||
|
||||
return data->port;
|
||||
|
|
@ -553,7 +471,7 @@ sink_constructed (GObject * object)
|
|||
{
|
||||
PinosSpaAlsaSink *sink = PINOS_SPA_ALSA_SINK (object);
|
||||
|
||||
create_pipeline (sink);
|
||||
setup_node (sink);
|
||||
|
||||
G_OBJECT_CLASS (pinos_spa_alsa_sink_parent_class)->constructed (object);
|
||||
}
|
||||
|
|
@ -605,11 +523,21 @@ pinos_spa_alsa_sink_new (PinosDaemon *daemon,
|
|||
PinosProperties *properties)
|
||||
{
|
||||
PinosNode *node;
|
||||
SpaNode *n;
|
||||
SpaResult res;
|
||||
|
||||
if ((res = make_node (&n,
|
||||
"spa/build/plugins/alsa/libspa-alsa.so",
|
||||
"alsa-sink")) < 0) {
|
||||
g_error ("can't create v4l2-source: %d", res);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node = g_object_new (PINOS_TYPE_SPA_ALSA_SINK,
|
||||
"daemon", daemon,
|
||||
"name", name,
|
||||
"properties", properties,
|
||||
"node", n,
|
||||
NULL);
|
||||
|
||||
return node;
|
||||
|
|
|
|||
|
|
@ -80,33 +80,8 @@ on_stream_notify (GObject *gobject,
|
|||
break;
|
||||
|
||||
case PINOS_STREAM_STATE_READY:
|
||||
{
|
||||
GPtrArray *possible;
|
||||
SpaFormat *format;
|
||||
|
||||
g_object_get (s, "possible-formats", &possible, NULL);
|
||||
|
||||
format = g_ptr_array_index (possible, 0);
|
||||
|
||||
#if 0
|
||||
/* set some reasonable defaults */
|
||||
if (gst_structure_has_field (structure, "width"))
|
||||
gst_structure_fixate_field_nearest_int (structure, "width", 320);
|
||||
if (gst_structure_has_field (structure, "height"))
|
||||
gst_structure_fixate_field_nearest_int (structure, "height", 240);
|
||||
if (gst_structure_has_field (structure, "framerate"))
|
||||
gst_structure_fixate_field_nearest_fraction (structure, "framerate", 30, 1);
|
||||
|
||||
/* use random fixation otherwise */
|
||||
caps = gst_caps_fixate (caps);
|
||||
str = gst_caps_to_string (caps);
|
||||
gst_caps_unref (caps);
|
||||
format = g_bytes_new_static (str, strlen (str) + 1);
|
||||
#endif
|
||||
|
||||
pinos_stream_start (s, format, PINOS_STREAM_MODE_SOCKET);
|
||||
pinos_stream_start (s);
|
||||
break;
|
||||
}
|
||||
|
||||
case PINOS_STREAM_STATE_STREAMING:
|
||||
break;
|
||||
|
|
@ -141,7 +116,12 @@ on_state_notify (GObject *gobject,
|
|||
g_signal_connect (stream, "notify::socket", (GCallback) on_socket_notify, stream);
|
||||
|
||||
possible = NULL;
|
||||
pinos_stream_connect (stream, PINOS_DIRECTION_OUTPUT, NULL, 0, possible);
|
||||
pinos_stream_connect (stream,
|
||||
PINOS_DIRECTION_OUTPUT,
|
||||
PINOS_STREAM_MODE_BUFFER,
|
||||
NULL,
|
||||
0,
|
||||
possible);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ reset_alsa_sink_props (SpaALSASinkProps *props)
|
|||
|
||||
typedef struct {
|
||||
bool opened;
|
||||
bool have_buffers;
|
||||
snd_pcm_t *handle;
|
||||
snd_output_t *output;
|
||||
snd_pcm_sframes_t buffer_size;
|
||||
|
|
@ -391,6 +392,9 @@ spa_alsa_sink_node_port_set_format (SpaNode *node,
|
|||
if ((res = spa_audio_raw_format_parse (format, &this->current_format)) < 0)
|
||||
return res;
|
||||
|
||||
if (alsa_set_format (this, &this->current_format, false) < 0)
|
||||
return SPA_RESULT_ERROR;
|
||||
|
||||
this->have_format = true;
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
|
|
|
|||
|
|
@ -11,6 +11,48 @@ static int verbose = 0; /* verbose flag */
|
|||
|
||||
#define CHECK(s,msg) if ((err = (s)) < 0) { printf (msg ": %s\n", snd_strerror(err)); return err; }
|
||||
|
||||
static int
|
||||
spa_alsa_open (SpaALSASink *this)
|
||||
{
|
||||
SpaALSAState *state = &this->state;
|
||||
int err;
|
||||
SpaALSASinkProps *props = &this->props[1];
|
||||
|
||||
if (state->opened)
|
||||
return 0;
|
||||
|
||||
CHECK (snd_output_stdio_attach (&state->output, stdout, 0), "attach failed");
|
||||
|
||||
printf ("Playback device is '%s'\n", props->device);
|
||||
CHECK (snd_pcm_open (&state->handle,
|
||||
props->device,
|
||||
SND_PCM_STREAM_PLAYBACK,
|
||||
SND_PCM_NONBLOCK |
|
||||
SND_PCM_NO_AUTO_RESAMPLE |
|
||||
SND_PCM_NO_AUTO_CHANNELS |
|
||||
SND_PCM_NO_AUTO_FORMAT), "open failed");
|
||||
|
||||
state->opened = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
spa_alsa_close (SpaALSASink *this)
|
||||
{
|
||||
SpaALSAState *state = &this->state;
|
||||
int err = 0;
|
||||
|
||||
if (!state->opened)
|
||||
return 0;
|
||||
|
||||
CHECK (snd_pcm_close (state->handle), "close failed");
|
||||
|
||||
state->opened = false;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static snd_pcm_format_t
|
||||
spa_alsa_format_to_alsa (SpaAudioFormat format)
|
||||
{
|
||||
|
|
@ -63,7 +105,7 @@ spa_alsa_format_to_alsa (SpaAudioFormat format)
|
|||
}
|
||||
|
||||
static int
|
||||
set_hwparams (SpaALSASink *this)
|
||||
alsa_set_format (SpaALSASink *this, SpaAudioRawFormat *fmt, bool try_only)
|
||||
{
|
||||
unsigned int rrate;
|
||||
snd_pcm_uframes_t size;
|
||||
|
|
@ -71,13 +113,17 @@ set_hwparams (SpaALSASink *this)
|
|||
snd_pcm_hw_params_t *params;
|
||||
snd_pcm_format_t format;
|
||||
SpaALSAState *state = &this->state;
|
||||
SpaAudioRawFormat *fmt = &this->current_format;
|
||||
SpaAudioRawInfo *info = &fmt->info;
|
||||
snd_pcm_t *handle = state->handle;
|
||||
snd_pcm_t *handle;
|
||||
unsigned int buffer_time;
|
||||
unsigned int period_time;
|
||||
SpaALSASinkProps *props = &this->props[1];
|
||||
|
||||
if ((err = spa_alsa_open (this)) < 0)
|
||||
return err;
|
||||
|
||||
handle = state->handle;
|
||||
|
||||
snd_pcm_hw_params_alloca (¶ms);
|
||||
/* choose all parameters */
|
||||
CHECK (snd_pcm_hw_params_any (handle, params), "Broken configuration for playback: no configurations available");
|
||||
|
|
@ -175,32 +221,6 @@ xrun_recovery (snd_pcm_t *handle, int err)
|
|||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
spa_alsa_open (SpaALSASink *this)
|
||||
{
|
||||
SpaALSAState *state = &this->state;
|
||||
int err;
|
||||
SpaALSASinkProps *props = &this->props[1];
|
||||
|
||||
if (state->opened)
|
||||
return 0;
|
||||
|
||||
CHECK (snd_output_stdio_attach (&state->output, stdout, 0), "attach failed");
|
||||
|
||||
printf ("Playback device is '%s'\n", props->device);
|
||||
CHECK (snd_pcm_open (&state->handle,
|
||||
props->device,
|
||||
SND_PCM_STREAM_PLAYBACK,
|
||||
SND_PCM_NONBLOCK |
|
||||
SND_PCM_NO_AUTO_RESAMPLE |
|
||||
SND_PCM_NO_AUTO_CHANNELS |
|
||||
SND_PCM_NO_AUTO_FORMAT), "open failed");
|
||||
|
||||
state->opened = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
pull_input (SpaALSASink *this, void *data, snd_pcm_uframes_t frames)
|
||||
{
|
||||
|
|
@ -303,22 +323,6 @@ alsa_on_fd_events (SpaPollNotifyData *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
spa_alsa_close (SpaALSASink *this)
|
||||
{
|
||||
SpaALSAState *state = &this->state;
|
||||
int err = 0;
|
||||
|
||||
if (!state->opened)
|
||||
return 0;
|
||||
|
||||
CHECK (snd_pcm_close (state->handle), "close failed");
|
||||
|
||||
state->opened = false;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
spa_alsa_start (SpaALSASink *this)
|
||||
{
|
||||
|
|
@ -329,7 +333,9 @@ spa_alsa_start (SpaALSASink *this)
|
|||
if (spa_alsa_open (this) < 0)
|
||||
return -1;
|
||||
|
||||
CHECK (set_hwparams (this), "hwparams");
|
||||
if (!state->have_buffers)
|
||||
return -1;
|
||||
|
||||
CHECK (set_swparams (this), "swparams");
|
||||
|
||||
snd_pcm_dump (state->handle, state->output);
|
||||
|
|
|
|||
|
|
@ -66,6 +66,24 @@ spa_v4l2_open (SpaV4l2Source *this)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
spa_v4l2_close (SpaV4l2Source *this)
|
||||
{
|
||||
SpaV4l2State *state = &this->state[0];
|
||||
|
||||
if (!state->opened)
|
||||
return 0;
|
||||
|
||||
fprintf (stderr, "close\n");
|
||||
if (close(state->fd))
|
||||
perror ("close");
|
||||
|
||||
state->fd = -1;
|
||||
state->opened = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
uint32_t fourcc;
|
||||
SpaVideoFormat format;
|
||||
|
|
@ -418,24 +436,6 @@ spa_v4l2_set_format (SpaV4l2Source *this, V4l2Format *f, bool try_only)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
spa_v4l2_close (SpaV4l2Source *this)
|
||||
{
|
||||
SpaV4l2State *state = &this->state[0];
|
||||
|
||||
if (!state->opened)
|
||||
return 0;
|
||||
|
||||
fprintf (stderr, "close\n");
|
||||
if (close(state->fd))
|
||||
perror ("close");
|
||||
|
||||
state->fd = -1;
|
||||
state->opened = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
mmap_read (SpaV4l2Source *this)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue