X-Git-Url: https://git.ao2.it/gst-aseq-appsrc.git/blobdiff_plain/d579e6473dc66a60b98ac3ebbbdccaca22b033ee..e01610203967b299c3dcb06c957657d4f8430df9:/gst-aseq-appsrc.c diff --git a/gst-aseq-appsrc.c b/gst-aseq-appsrc.c index b6d38d0..1577ebf 100644 --- a/gst-aseq-appsrc.c +++ b/gst-aseq-appsrc.c @@ -38,8 +38,8 @@ #define DEFAULT_TICK_PERIOD_MS 10 #define DEFAULT_POLL_TIMEOUT_MS (DEFAULT_TICK_PERIOD_MS / 2) -GST_DEBUG_CATEGORY (mysrc_debug); -#define GST_CAT_DEFAULT mysrc_debug +GST_DEBUG_CATEGORY (mysource_debug); +#define GST_CAT_DEFAULT mysource_debug typedef struct _App App; @@ -51,6 +51,7 @@ struct _App GMainLoop *loop; snd_seq_t *seq; + int queue; int port_count; snd_seq_addr_t *seq_ports; snd_midi_event_t *parser; @@ -62,7 +63,7 @@ struct _App guint64 tick; }; -App s_app; +static App s_app; static int init_seq (App * app) @@ -75,6 +76,12 @@ init_seq (App * app) goto error; } + /* + * Prevent Valgrind from reporting cached configuration as memory leaks, see: + * http://git.alsa-project.org/?p=alsa-lib.git;a=blob;f=MEMORY-LEAK;hb=HEAD + */ + snd_config_update_free_global(); + ret = snd_seq_set_client_name (app->seq, DEFAULT_CLIENT_NAME); if (ret < 0) { GST_ERROR ("Cannot set client name - %s", snd_strerror (ret)); @@ -137,17 +144,52 @@ out_free_ports_list: } static int +start_queue_timer (snd_seq_t *seq, int queue) +{ + int ret; + + ret = snd_seq_start_queue (seq, queue, NULL); + if (ret < 0) { + GST_ERROR ("Timer event output error: %s\n", snd_strerror (ret)); + return ret; + } + + ret = snd_seq_drain_output (seq); + if (ret < 0) + GST_ERROR ("Drain output error: %s\n", snd_strerror (ret)); + + return ret; +} + +static int create_port (App * app) { + snd_seq_port_info_t *pinfo; int ret; - ret = snd_seq_create_simple_port (app->seq, DEFAULT_CLIENT_NAME, - SND_SEQ_PORT_CAP_WRITE | - SND_SEQ_PORT_CAP_SUBS_WRITE, - SND_SEQ_PORT_TYPE_MIDI_GENERIC | SND_SEQ_PORT_TYPE_APPLICATION); + snd_seq_port_info_alloca (&pinfo); + snd_seq_port_info_set_name (pinfo, DEFAULT_CLIENT_NAME); + snd_seq_port_info_set_type (pinfo, SND_SEQ_PORT_TYPE_MIDI_GENERIC | SND_SEQ_PORT_TYPE_APPLICATION); + snd_seq_port_info_set_capability (pinfo, SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE); + + ret = snd_seq_alloc_queue (app->seq); + if (ret < 0) { + GST_ERROR ("Cannot allocate queue: %s\n", snd_strerror (ret)); + return ret; + } + + app->queue = ret; + + snd_seq_port_info_set_timestamping (pinfo, 1); + snd_seq_port_info_set_timestamp_real (pinfo, 1); + snd_seq_port_info_set_timestamp_queue (pinfo, app->queue); + + ret = snd_seq_create_port (app->seq, pinfo); if (ret < 0) GST_ERROR ("Cannot create port - %s", snd_strerror (ret)); + ret = start_queue_timer (app->seq, app->queue); + return ret; } @@ -171,20 +213,17 @@ connect_ports (App * app) static void push_buffer (App * app, gpointer data, guint size) { - GstBuffer *buffer; GstClockTime time; - int ret; gpointer local_data; + GstBuffer *buffer; + int ret; - /* read the next chunk */ buffer = gst_buffer_new (); time = app->tick * DEFAULT_TICK_PERIOD_MS * GST_MSECOND; GST_BUFFER_DTS (buffer) = time; GST_BUFFER_PTS (buffer) = time; - GST_BUFFER_OFFSET (buffer) = time; - GST_BUFFER_DURATION (buffer) = DEFAULT_TICK_PERIOD_MS * GST_MSECOND; local_data = g_memdup (data, size); @@ -192,6 +231,8 @@ push_buffer (App * app, gpointer data, guint size) gst_memory_new_wrapped (0, local_data, size, 0, size, local_data, g_free)); + GST_MEMDUMP ("MIDI data:", local_data, size); + GST_DEBUG ("feed buffer %p, tick %" G_GUINT64_FORMAT " size: %u", (gpointer) buffer, app->tick, size); g_signal_emit_by_name (app->appsrc, "push-buffer", buffer, &ret); @@ -221,14 +262,18 @@ feed_data (GstElement * appsrc, guint size, App * app) ret = poll (app->pfds, app->npfds, DEFAULT_POLL_TIMEOUT_MS); if (ret < 0) { GST_ERROR ("ERROR in poll: %s", strerror (errno)); + gst_app_src_end_of_stream (GST_APP_SRC (appsrc)); } else if (ret == 0) { push_tick_buffer (app); } else { do { snd_seq_event_t *event; err = snd_seq_event_input (app->seq, &event); - if (err < 0) + if (err < 0 && err != -EAGAIN) { + GST_ERROR ("Error in snd_seq_event_input: %s", snd_strerror (err)); + gst_app_src_end_of_stream (GST_APP_SRC (appsrc)); break; + } if (event) { size_ev = snd_midi_event_decode (app->parser, app->buffer, DEFAULT_BUFSIZE, @@ -241,6 +286,7 @@ feed_data (GstElement * appsrc, guint size, App * app) } else { GST_ERROR ("Error decoding event from ALSA to output: %s", strerror (-size_ev)); + gst_app_src_end_of_stream (GST_APP_SRC (appsrc)); break; } } else { @@ -392,9 +438,12 @@ main (int argc, char *argv[]) GOptionContext *ctx; GError *err = NULL; gchar *ports = NULL; + gboolean verbose = FALSE; GOptionEntry options[] = { {"ports", 'p', 0, G_OPTION_ARG_STRING, &ports, "Comma separated list of sequencer ports", "client:port,..."}, + {"verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, + "Output status information and property notifications", NULL}, {NULL} }; @@ -412,7 +461,7 @@ main (int argc, char *argv[]) gst_init (&argc, &argv); - GST_DEBUG_CATEGORY_INIT (mysrc_debug, "mysrc", 0, + GST_DEBUG_CATEGORY_INIT (mysource_debug, "mysource", 0, "ALSA MIDI sequencer appsrc pipeline"); ret = app_init (app, ports); @@ -433,6 +482,9 @@ main (int argc, char *argv[]) ("appsrc name=mysource ! fluiddec ! audioconvert ! autoaudiosink", NULL); g_assert (app->pipeline); + if (verbose) + g_signal_connect (app->pipeline, "deep-notify", G_CALLBACK (gst_object_default_deep_notify), NULL); + bus = gst_pipeline_get_bus (GST_PIPELINE (app->pipeline)); g_assert (bus);