alsamidisrc: fix compiler warning with clang 10
[platform/upstream/gstreamer.git] / ext / alsa / gstalsamidisrc.c
1 /* GStreamer
2  * Copyright (C) 2014  Antonio Ospite <ao2@ao2.it>
3  *
4  * gstalsamidisrc.c: Source element for ALSA MIDI sequencer events
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21 /**
22  * SECTION:element-alsamidisrc
23  * @title: alsamidisrc
24  * @see_also: #GstPushSrc
25  *
26  * The alsamidisrc element is an element that fetches ALSA MIDI sequencer
27  * events and makes them available to elements understanding
28  * audio/x-midi-events in their sink pads.
29  *
30  * It can be used to generate notes from a MIDI input device.
31  *
32  * ## Example launch line
33  * |[
34  * gst-launch -v alsamidisrc ports=129:0 ! fluiddec ! audioconvert ! autoaudiosink
35  * ]|
36  *  This pipeline will listen for events from the sequencer device at port 129:0,
37  * and generate notes using the fluiddec element.
38  *
39  */
40
41 #ifdef HAVE_CONFIG_H
42 #  include "config.h"
43 #endif
44
45 #include "gstalsamidisrc.h"
46
47 GST_DEBUG_CATEGORY_STATIC (gst_alsa_midi_src_debug);
48 #define GST_CAT_DEFAULT gst_alsa_midi_src_debug
49
50 /*
51  * The MIDI specification declares some status bytes undefined:
52  *
53  *  - 0xF4 System common - Undefined (Reserved)
54  *  - 0xF5 System common - Undefined (Reserved)
55  *  - 0xF9 System real-time - Undefined (Reserved)
56  *  - 0xFD System real-time - Undefined (Reserved)
57  *
58  * See: http://www.midi.org/techspecs/midimessages.php#2
59  *
60  * Some other documents define status 0xf9 as a tick message with a period of
61  * 10ms:
62  *
63  *  - http://www.blitter.com/~russtopia/MIDI/~jglatt/tech/midispec/tick.htm
64  *  - http://www.sequencer.de/synth/index.php/MIDI_Format#0xf9_-_MIDI_Tick
65  *
66  * Even if non-standard it looks like this convention is quite widespread.
67  *
68  * For instance Fluidsynth uses 0xF9 as a "midi tick" message:
69  * http://sourceforge.net/p/fluidsynth/code-git/ci/master/tree/fluidsynth/src/midi/fluid_midi.h#l62
70  *
71  * And then so does the midiparse element in order to be compatible with
72  * Fluidsynth and the fluiddec element.
73  *
74  * Do the same to behave like midiparse.
75  */
76 #define MIDI_TICK 0xf9
77 #define MIDI_TICK_PERIOD_MS 10
78
79 /* Functions specific to the Alsa MIDI sequencer API */
80
81 #define DEFAULT_BUFSIZE 65536
82 #define DEFAULT_CLIENT_NAME "alsamidisrc"
83
84 static int
85 init_seq (GstAlsaMidiSrc * alsamidisrc)
86 {
87   int ret;
88
89   ret = snd_seq_open (&alsamidisrc->seq, "default", SND_SEQ_OPEN_DUPLEX, 0);
90   if (ret < 0) {
91     GST_ERROR_OBJECT (alsamidisrc, "Cannot open sequencer - %s",
92         snd_strerror (ret));
93     goto error;
94   }
95
96   /*
97    * Prevent Valgrind from reporting cached configuration as memory leaks, see:
98    * http://git.alsa-project.org/?p=alsa-lib.git;a=blob;f=MEMORY-LEAK;hb=HEAD
99    */
100   snd_config_update_free_global ();
101
102   ret = snd_seq_set_client_name (alsamidisrc->seq, DEFAULT_CLIENT_NAME);
103   if (ret < 0) {
104     GST_ERROR_OBJECT (alsamidisrc, "Cannot set client name - %s",
105         snd_strerror (ret));
106     goto error_seq_close;
107   }
108
109   return 0;
110
111 error_seq_close:
112   snd_seq_close (alsamidisrc->seq);
113 error:
114   return ret;
115 }
116
117 /* Parses one or more port addresses from the string */
118 static int
119 parse_ports (const char *arg, GstAlsaMidiSrc * alsamidisrc)
120 {
121   gchar **ports_list;
122   guint i;
123   int ret = 0;
124
125   GST_DEBUG_OBJECT (alsamidisrc, "ports: %s", arg);
126
127   /*
128    * Assume that ports are separated by commas.
129    *
130    * Commas are used instead of spaces because spaces are valid in client
131    * names.
132    */
133   ports_list = g_strsplit (arg, ",", 0);
134
135   alsamidisrc->port_count = g_strv_length (ports_list);
136   alsamidisrc->seq_ports = g_try_new (snd_seq_addr_t, alsamidisrc->port_count);
137   if (!alsamidisrc->seq_ports) {
138     GST_ERROR_OBJECT (alsamidisrc, "Out of memory");
139     ret = -ENOMEM;
140     goto out_free_ports_list;
141   }
142
143   for (i = 0; i < alsamidisrc->port_count; i++) {
144     gchar *port_name = ports_list[i];
145
146     ret = snd_seq_parse_address (alsamidisrc->seq, &alsamidisrc->seq_ports[i],
147         port_name);
148     if (ret < 0) {
149       GST_ERROR_OBJECT (alsamidisrc, "Invalid port %s - %s", port_name,
150           snd_strerror (ret));
151       goto error_free_seq_ports;
152     }
153   }
154
155   goto out_free_ports_list;
156
157 error_free_seq_ports:
158   g_free (alsamidisrc->seq_ports);
159 out_free_ports_list:
160   g_strfreev (ports_list);
161   return ret;
162 }
163
164 static int
165 start_queue_timer (GstAlsaMidiSrc * alsamidisrc)
166 {
167   int ret;
168
169   ret = snd_seq_start_queue (alsamidisrc->seq, alsamidisrc->queue, NULL);
170   if (ret < 0) {
171     GST_ERROR_OBJECT (alsamidisrc, "Timer event output error: %s",
172         snd_strerror (ret));
173     return ret;
174   }
175
176   ret = snd_seq_drain_output (alsamidisrc->seq);
177   if (ret < 0)
178     GST_ERROR_OBJECT (alsamidisrc, "Drain output error: %s",
179         snd_strerror (ret));
180
181   return ret;
182 }
183
184 static void
185 schedule_next_tick (GstAlsaMidiSrc * alsamidisrc)
186 {
187   snd_seq_event_t ev;
188   snd_seq_real_time_t time;
189   int ret;
190
191   snd_seq_ev_clear (&ev);
192   snd_seq_ev_set_source (&ev, 0);
193   snd_seq_ev_set_dest (&ev, snd_seq_client_id (alsamidisrc->seq), 0);
194
195   ev.type = SND_SEQ_EVENT_TICK;
196
197   alsamidisrc->tick += 1;
198   GST_TIME_TO_TIMESPEC (alsamidisrc->tick * MIDI_TICK_PERIOD_MS * GST_MSECOND,
199       time);
200
201   snd_seq_ev_schedule_real (&ev, alsamidisrc->queue, 0, &time);
202
203   ret = snd_seq_event_output (alsamidisrc->seq, &ev);
204   if (ret < 0)
205     GST_ERROR_OBJECT (alsamidisrc, "Event output error: %s",
206         snd_strerror (ret));
207
208   ret = snd_seq_drain_output (alsamidisrc->seq);
209   if (ret < 0)
210     GST_ERROR_OBJECT (alsamidisrc, "Event drain error: %s", snd_strerror (ret));
211 }
212
213 static int
214 create_port (GstAlsaMidiSrc * alsamidisrc)
215 {
216   snd_seq_port_info_t *pinfo;
217   int ret;
218
219   snd_seq_port_info_alloca (&pinfo);
220   snd_seq_port_info_set_name (pinfo, DEFAULT_CLIENT_NAME);
221   snd_seq_port_info_set_type (pinfo,
222       SND_SEQ_PORT_TYPE_MIDI_GENERIC | SND_SEQ_PORT_TYPE_APPLICATION);
223   snd_seq_port_info_set_capability (pinfo,
224       SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE);
225
226   ret = snd_seq_alloc_named_queue (alsamidisrc->seq, DEFAULT_CLIENT_NAME);
227   if (ret < 0) {
228     GST_ERROR_OBJECT (alsamidisrc, "Cannot allocate queue: %s",
229         snd_strerror (ret));
230     return ret;
231   }
232
233   /*
234    * Sequencer queues are "per-system" entities, so it's important to remember
235    * the queue id to make sure alsamidisrc refers to this very one in future
236    * operations, and not to some other port created by another sequencer user.
237    */
238   alsamidisrc->queue = ret;
239
240   snd_seq_port_info_set_timestamping (pinfo, 1);
241   snd_seq_port_info_set_timestamp_real (pinfo, 1);
242   snd_seq_port_info_set_timestamp_queue (pinfo, alsamidisrc->queue);
243
244   ret = snd_seq_create_port (alsamidisrc->seq, pinfo);
245   if (ret < 0) {
246     GST_ERROR_OBJECT (alsamidisrc, "Cannot create port - %s",
247         snd_strerror (ret));
248     return ret;
249   }
250
251   /*
252    * Conversely, it's not strictly necessary to remember the port id because
253    * ports are per-client and alsamidisrc is only creating one port (id = 0).
254    *
255    * If multiple ports were to be created, the ids could be retrieved with
256    * something like:
257    *
258    *   alsamidisrc->port = snd_seq_port_info_get_port(pinfo);
259    */
260
261   ret = start_queue_timer (alsamidisrc);
262   if (ret < 0)
263     GST_ERROR_OBJECT (alsamidisrc, "Cannot start timer for queue: %d - %s",
264         alsamidisrc->queue, snd_strerror (ret));
265
266   return ret;
267 }
268
269 static void
270 connect_ports (GstAlsaMidiSrc * alsamidisrc)
271 {
272   int i;
273   int ret;
274
275   for (i = 0; i < alsamidisrc->port_count; ++i) {
276     ret =
277         snd_seq_connect_from (alsamidisrc->seq, 0,
278         alsamidisrc->seq_ports[i].client, alsamidisrc->seq_ports[i].port);
279     if (ret < 0)
280       /* Issue a warning and try the other ports */
281       GST_WARNING_OBJECT (alsamidisrc, "Cannot connect from port %d:%d - %s",
282           alsamidisrc->seq_ports[i].client, alsamidisrc->seq_ports[i].port,
283           snd_strerror (ret));
284   }
285 }
286
287 /* GStreamer specific functions */
288
289 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
290     GST_PAD_SRC,
291     GST_PAD_ALWAYS,
292     GST_STATIC_CAPS ("audio/x-midi-event"));
293
294 #define DEFAULT_PORTS           NULL
295
296 enum
297 {
298   PROP_0,
299   PROP_PORTS,
300   PROP_LAST,
301 };
302
303 #define _do_init \
304     GST_DEBUG_CATEGORY_INIT (gst_alsa_midi_src_debug, "alsamidisrc", 0, "alsamidisrc element");
305 #define gst_alsa_midi_src_parent_class parent_class
306 G_DEFINE_TYPE_WITH_CODE (GstAlsaMidiSrc, gst_alsa_midi_src, GST_TYPE_PUSH_SRC,
307     _do_init);
308
309 static void gst_alsa_midi_src_set_property (GObject * object, guint prop_id,
310     const GValue * value, GParamSpec * pspec);
311 static void gst_alsa_midi_src_get_property (GObject * object, guint prop_id,
312     GValue * value, GParamSpec * pspec);
313
314 static gboolean gst_alsa_midi_src_start (GstBaseSrc * basesrc);
315 static gboolean gst_alsa_midi_src_stop (GstBaseSrc * basesrc);
316 static gboolean gst_alsa_midi_src_unlock (GstBaseSrc * basesrc);
317 static gboolean gst_alsa_midi_src_unlock_stop (GstBaseSrc * basesrc);
318 static void gst_alsa_midi_src_state_changed (GstElement * element,
319     GstState oldstate, GstState newstate, GstState pending);
320
321 static GstFlowReturn
322 gst_alsa_midi_src_create (GstPushSrc * src, GstBuffer ** buf);
323
324 static void
325 gst_alsa_midi_src_class_init (GstAlsaMidiSrcClass * klass)
326 {
327   GObjectClass *gobject_class;
328   GstElementClass *gstelement_class;
329   GstBaseSrcClass *gstbase_src_class;
330   GstPushSrcClass *gstpush_src_class;
331
332   gobject_class = G_OBJECT_CLASS (klass);
333   gstelement_class = GST_ELEMENT_CLASS (klass);
334   gstbase_src_class = GST_BASE_SRC_CLASS (klass);
335   gstpush_src_class = GST_PUSH_SRC_CLASS (klass);
336
337   gobject_class->set_property = gst_alsa_midi_src_set_property;
338   gobject_class->get_property = gst_alsa_midi_src_get_property;
339
340   g_object_class_install_property (gobject_class, PROP_PORTS,
341       g_param_spec_string ("ports", "Ports",
342           "Comma separated list of sequencer ports (e.g. client:port,...)",
343           DEFAULT_PORTS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
344
345   gst_element_class_set_static_metadata (gstelement_class,
346       "AlsaMidi Source",
347       "Source",
348       "Push ALSA MIDI sequencer events around", "Antonio Ospite <ao2@ao2.it>");
349   gst_element_class_add_static_pad_template (gstelement_class, &srctemplate);
350
351   gstbase_src_class->start = GST_DEBUG_FUNCPTR (gst_alsa_midi_src_start);
352   gstbase_src_class->stop = GST_DEBUG_FUNCPTR (gst_alsa_midi_src_stop);
353   gstbase_src_class->unlock = GST_DEBUG_FUNCPTR (gst_alsa_midi_src_unlock);
354   gstbase_src_class->unlock_stop =
355       GST_DEBUG_FUNCPTR (gst_alsa_midi_src_unlock_stop);
356   gstpush_src_class->create = GST_DEBUG_FUNCPTR (gst_alsa_midi_src_create);
357   gstelement_class->state_changed =
358       GST_DEBUG_FUNCPTR (gst_alsa_midi_src_state_changed);
359 }
360
361 static void
362 gst_alsa_midi_src_init (GstAlsaMidiSrc * alsamidisrc)
363 {
364   alsamidisrc->ports = DEFAULT_PORTS;
365
366   gst_base_src_set_format (GST_BASE_SRC (alsamidisrc), GST_FORMAT_TIME);
367   gst_base_src_set_live (GST_BASE_SRC (alsamidisrc), TRUE);
368 }
369
370 static void
371 gst_alsa_midi_src_set_property (GObject * object, guint prop_id,
372     const GValue * value, GParamSpec * pspec)
373 {
374   GstAlsaMidiSrc *src;
375
376   src = GST_ALSA_MIDI_SRC (object);
377
378   switch (prop_id) {
379     case PROP_PORTS:
380       g_free (src->ports);
381       src->ports = g_value_dup_string (value);
382       break;
383     default:
384       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
385       break;
386   }
387 }
388
389 static void
390 gst_alsa_midi_src_get_property (GObject * object, guint prop_id, GValue * value,
391     GParamSpec * pspec)
392 {
393   GstAlsaMidiSrc *src;
394
395   g_return_if_fail (GST_IS_ALSA_MIDI_SRC (object));
396
397   src = GST_ALSA_MIDI_SRC (object);
398
399   switch (prop_id) {
400     case PROP_PORTS:
401       g_value_set_string (value, src->ports);
402       break;
403     default:
404       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
405       break;
406   }
407 }
408
409 static void
410 push_buffer (GstAlsaMidiSrc * alsamidisrc, gpointer data, guint size,
411     GstClockTime time, GstBufferList * buffer_list)
412 {
413   gpointer local_data;
414   GstBuffer *buffer;
415
416   buffer = gst_buffer_new ();
417
418   GST_BUFFER_DTS (buffer) = time;
419   GST_BUFFER_PTS (buffer) = time;
420
421   local_data = g_memdup (data, size);
422
423   gst_buffer_append_memory (buffer,
424       gst_memory_new_wrapped (0, local_data, size, 0, size, local_data,
425           g_free));
426
427   GST_MEMDUMP_OBJECT (alsamidisrc, "MIDI data:", local_data, size);
428
429   gst_buffer_list_add (buffer_list, buffer);
430 }
431
432 static void
433 push_tick_buffer (GstAlsaMidiSrc * alsamidisrc, GstClockTime time,
434     GstBufferList * buffer_list)
435 {
436   alsamidisrc->buffer[0] = MIDI_TICK;
437   push_buffer (alsamidisrc, alsamidisrc->buffer, 1, time, buffer_list);
438 }
439
440 static GstFlowReturn
441 gst_alsa_midi_src_create (GstPushSrc * src, GstBuffer ** buf)
442 {
443   GstAlsaMidiSrc *alsamidisrc;
444   GstBufferList *buffer_list;
445   GstClockTime time;
446   long size_ev = 0;
447   int err;
448   int ret;
449   guint len;
450
451   alsamidisrc = GST_ALSA_MIDI_SRC (src);
452
453   buffer_list = gst_buffer_list_new ();
454
455 poll:
456   ret = gst_poll_wait (alsamidisrc->poll, GST_CLOCK_TIME_NONE);
457   if (ret <= 0) {
458     if (ret < 0 && errno == EBUSY) {
459       GST_INFO_OBJECT (alsamidisrc, "flushing");
460       gst_buffer_list_unref (buffer_list);
461       return GST_FLOW_FLUSHING;
462     }
463     GST_ERROR_OBJECT (alsamidisrc, "ERROR in poll: %s", strerror (errno));
464   } else {
465     /* There are events available */
466     do {
467       snd_seq_event_t *event;
468       err = snd_seq_event_input (alsamidisrc->seq, &event);
469       if (err < 0)
470         break;                  /* Processed all events */
471
472       if (event) {
473         time = GST_TIMESPEC_TO_TIME (event->time.time) - alsamidisrc->delay;
474
475         /*
476          * Special handling is needed because decoding SND_SEQ_EVENT_TICK is
477          * not supported by alsa-lib.
478          */
479         if (event->type == SND_SEQ_EVENT_TICK) {
480           push_tick_buffer (alsamidisrc, time, buffer_list);
481           schedule_next_tick (alsamidisrc);
482           continue;
483         }
484
485         size_ev =
486             snd_midi_event_decode (alsamidisrc->parser, alsamidisrc->buffer,
487             DEFAULT_BUFSIZE, event);
488         if (size_ev < 0) {
489           /* ENOENT indicates an event that is not a MIDI message, silently skip it */
490           if (-ENOENT == size_ev) {
491             GST_WARNING_OBJECT (alsamidisrc,
492                 "Warning: Received non-MIDI message");
493             goto poll;
494           } else {
495             GST_ERROR_OBJECT (alsamidisrc,
496                 "Error decoding event from ALSA to output: %s",
497                 strerror (-size_ev));
498             goto error;
499           }
500         } else {
501           push_buffer (alsamidisrc, alsamidisrc->buffer, size_ev, time,
502               buffer_list);
503         }
504       }
505     } while (err > 0);
506   }
507
508   len = gst_buffer_list_length (buffer_list);
509   if (len == 0)
510     goto error;
511
512   /* Pop the _last_ buffer in the list */
513   *buf = gst_buffer_copy (gst_buffer_list_get (buffer_list, len - 1));
514   gst_buffer_list_remove (buffer_list, len - 1, 1);
515   --len;
516
517   /*
518    * If there are no more buffers left, free the list, otherwise push all the
519    * _previous_ buffers left in the list.
520    *
521    * The one popped above will be pushed last when this function returns.
522    */
523   if (len == 0)
524     gst_buffer_list_unref (buffer_list);
525   else
526     gst_pad_push_list (GST_BASE_SRC (src)->srcpad, buffer_list);
527
528   return GST_FLOW_OK;
529
530 error:
531   gst_buffer_list_unref (buffer_list);
532   return GST_FLOW_ERROR;
533 }
534
535 static gboolean
536 gst_alsa_midi_src_start (GstBaseSrc * basesrc)
537 {
538   GstAlsaMidiSrc *alsamidisrc;
539   int ret;
540
541   alsamidisrc = GST_ALSA_MIDI_SRC (basesrc);
542
543   alsamidisrc->tick = 0;
544   alsamidisrc->port_count = 0;
545
546   ret = init_seq (alsamidisrc);
547   if (ret < 0)
548     goto err;
549
550   if (alsamidisrc->ports) {
551     ret = parse_ports (alsamidisrc->ports, alsamidisrc);
552     if (ret < 0)
553       goto error_seq_close;
554   }
555
556   ret = create_port (alsamidisrc);
557   if (ret < 0)
558     goto error_free_seq_ports;
559
560   connect_ports (alsamidisrc);
561
562   ret = snd_seq_nonblock (alsamidisrc->seq, 1);
563   if (ret < 0) {
564     GST_ERROR_OBJECT (alsamidisrc, "Cannot set nonblock mode - %s",
565         snd_strerror (ret));
566     goto error_free_seq_ports;
567   }
568
569   snd_midi_event_new (DEFAULT_BUFSIZE, &alsamidisrc->parser);
570   snd_midi_event_init (alsamidisrc->parser);
571   snd_midi_event_reset_decode (alsamidisrc->parser);
572
573   snd_midi_event_no_status (alsamidisrc->parser, 1);
574
575   alsamidisrc->buffer = g_try_malloc (DEFAULT_BUFSIZE);
576   if (alsamidisrc->buffer == NULL)
577     goto error_free_parser;
578
579   {
580     struct pollfd *pfds;
581     int npfds, i;
582
583     npfds = snd_seq_poll_descriptors_count (alsamidisrc->seq, POLLIN);
584     pfds = g_newa (struct pollfd, npfds);
585
586     snd_seq_poll_descriptors (alsamidisrc->seq, pfds, npfds, POLLIN);
587
588     alsamidisrc->poll = gst_poll_new (TRUE);
589     for (i = 0; i < npfds; ++i) {
590       GstPollFD fd = GST_POLL_FD_INIT;
591
592       fd.fd = pfds[i].fd;
593       gst_poll_add_fd (alsamidisrc->poll, &fd);
594       gst_poll_fd_ctl_read (alsamidisrc->poll, &fd, TRUE);
595       gst_poll_fd_ctl_write (alsamidisrc->poll, &fd, FALSE);
596     }
597   }
598
599   return TRUE;
600
601 error_free_parser:
602   snd_midi_event_free (alsamidisrc->parser);
603 error_free_seq_ports:
604   g_free (alsamidisrc->seq_ports);
605 error_seq_close:
606   snd_seq_close (alsamidisrc->seq);
607 err:
608   return FALSE;
609 }
610
611 static gboolean
612 gst_alsa_midi_src_stop (GstBaseSrc * basesrc)
613 {
614   GstAlsaMidiSrc *alsamidisrc;
615
616   alsamidisrc = GST_ALSA_MIDI_SRC (basesrc);
617
618   if (alsamidisrc->poll != NULL) {
619     gst_poll_free (alsamidisrc->poll);
620     alsamidisrc->poll = NULL;
621   }
622   g_free (alsamidisrc->ports);
623   g_free (alsamidisrc->buffer);
624   snd_midi_event_free (alsamidisrc->parser);
625   g_free (alsamidisrc->seq_ports);
626   snd_seq_close (alsamidisrc->seq);
627
628   return TRUE;
629 }
630
631 static gboolean
632 gst_alsa_midi_src_unlock (GstBaseSrc * basesrc)
633 {
634   GstAlsaMidiSrc *alsamidisrc = GST_ALSA_MIDI_SRC (basesrc);
635
636   gst_poll_set_flushing (alsamidisrc->poll, TRUE);
637   return TRUE;
638 }
639
640 static gboolean
641 gst_alsa_midi_src_unlock_stop (GstBaseSrc * basesrc)
642 {
643   GstAlsaMidiSrc *alsamidisrc = GST_ALSA_MIDI_SRC (basesrc);
644
645   gst_poll_set_flushing (alsamidisrc->poll, FALSE);
646   return TRUE;
647 }
648
649 static void
650 gst_alsa_midi_src_state_changed (GstElement * element, GstState oldstate,
651     GstState newstate, GstState pending)
652 {
653   GstAlsaMidiSrc *alsamidisrc;
654
655   alsamidisrc = GST_ALSA_MIDI_SRC (element);
656
657   if (newstate == GST_STATE_PLAYING) {
658     GstClockTime gst_time;
659     GstClockTime base_time;
660     GstClockTime running_time;
661     GstClockTime queue_time;
662     GstClock *clock;
663     snd_seq_queue_status_t *status;
664
665     clock = gst_element_get_clock (element);
666     if (clock == NULL) {
667       GST_WARNING_OBJECT (element, "No clock present");
668       return;
669     }
670     gst_time = gst_clock_get_time (clock);
671     gst_object_unref (clock);
672     base_time = gst_element_get_base_time (element);
673     running_time = gst_time - base_time;
674
675     snd_seq_queue_status_malloc (&status);
676     snd_seq_get_queue_status (alsamidisrc->seq, alsamidisrc->queue, status);
677     queue_time =
678         GST_TIMESPEC_TO_TIME (*snd_seq_queue_status_get_real_time (status));
679     snd_seq_queue_status_free (status);
680
681     /*
682      * The fact that the ALSA sequencer queue started before the pipeline
683      * transition to the PLAYING state ensures that the pipeline delay is
684      * always positive.
685      */
686     alsamidisrc->delay = queue_time - running_time;
687
688     if (alsamidisrc->tick == 0) {
689       schedule_next_tick (alsamidisrc);
690     }
691   }
692 }