upload tizen1.0 source
[framework/multimedia/gst-plugins-good0.10.git] / ext / jack / gstjackaudioclient.c
1 /* GStreamer
2  * Copyright (C) 2006 Wim Taymans <wim@fluendo.com>
3  *
4  * gstjackaudioclient.c: jack audio client implementation
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., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #include <string.h>
23
24 #include "gstjackaudioclient.h"
25
26 GST_DEBUG_CATEGORY_STATIC (gst_jack_audio_client_debug);
27 #define GST_CAT_DEFAULT gst_jack_audio_client_debug
28
29 void
30 gst_jack_audio_client_init (void)
31 {
32   GST_DEBUG_CATEGORY_INIT (gst_jack_audio_client_debug, "jackclient", 0,
33       "jackclient helpers");
34 }
35
36 /* a list of global connections indexed by id and server. */
37 G_LOCK_DEFINE_STATIC (connections_lock);
38 static GList *connections;
39
40 /* the connection to a server  */
41 typedef struct
42 {
43   gint refcount;
44   GMutex *lock;
45   GCond *flush_cond;
46
47   /* id/server pair and the connection */
48   gchar *id;
49   gchar *server;
50   jack_client_t *client;
51
52   /* lists of GstJackAudioClients */
53   gint n_clients;
54   GList *src_clients;
55   GList *sink_clients;
56 } GstJackAudioConnection;
57
58 /* an object sharing a jack_client_t connection. */
59 struct _GstJackAudioClient
60 {
61   GstJackAudioConnection *conn;
62
63   GstJackClientType type;
64   gboolean active;
65   gboolean deactivate;
66
67   void (*shutdown) (void *arg);
68   JackProcessCallback process;
69   JackBufferSizeCallback buffer_size;
70   JackSampleRateCallback sample_rate;
71   gpointer user_data;
72 };
73
74 typedef jack_default_audio_sample_t sample_t;
75
76 typedef struct
77 {
78   jack_nframes_t nframes;
79   gpointer user_data;
80 } JackCB;
81
82 static int
83 jack_process_cb (jack_nframes_t nframes, void *arg)
84 {
85   GstJackAudioConnection *conn = (GstJackAudioConnection *) arg;
86   GList *walk;
87   int res = 0;
88
89   g_mutex_lock (conn->lock);
90   /* call sources first, then sinks. Sources will either push data into the
91    * ringbuffer of the sinks, which will then pull the data out of it, or
92    * sinks will pull the data from the sources. */
93   for (walk = conn->src_clients; walk; walk = g_list_next (walk)) {
94     GstJackAudioClient *client = (GstJackAudioClient *) walk->data;
95
96     /* only call active clients */
97     if ((client->active || client->deactivate) && client->process) {
98       res = client->process (nframes, client->user_data);
99       if (client->deactivate) {
100         client->deactivate = FALSE;
101         g_cond_signal (conn->flush_cond);
102       }
103     }
104   }
105   for (walk = conn->sink_clients; walk; walk = g_list_next (walk)) {
106     GstJackAudioClient *client = (GstJackAudioClient *) walk->data;
107
108     /* only call active clients */
109     if ((client->active || client->deactivate) && client->process) {
110       res = client->process (nframes, client->user_data);
111       if (client->deactivate) {
112         client->deactivate = FALSE;
113         g_cond_signal (conn->flush_cond);
114       }
115     }
116   }
117   g_mutex_unlock (conn->lock);
118
119   return res;
120 }
121
122 /* we error out */
123 static int
124 jack_sample_rate_cb (jack_nframes_t nframes, void *arg)
125 {
126   return 0;
127 }
128
129 /* we error out */
130 static int
131 jack_buffer_size_cb (jack_nframes_t nframes, void *arg)
132 {
133   return 0;
134 }
135
136 static void
137 jack_shutdown_cb (void *arg)
138 {
139   GstJackAudioConnection *conn = (GstJackAudioConnection *) arg;
140   GList *walk;
141
142   GST_DEBUG ("disconnect client %s from server %s", conn->id,
143       GST_STR_NULL (conn->server));
144
145   g_mutex_lock (conn->lock);
146   for (walk = conn->src_clients; walk; walk = g_list_next (walk)) {
147     GstJackAudioClient *client = (GstJackAudioClient *) walk->data;
148
149     if (client->shutdown)
150       client->shutdown (client->user_data);
151   }
152   for (walk = conn->sink_clients; walk; walk = g_list_next (walk)) {
153     GstJackAudioClient *client = (GstJackAudioClient *) walk->data;
154
155     if (client->shutdown)
156       client->shutdown (client->user_data);
157   }
158   g_mutex_unlock (conn->lock);
159 }
160
161 typedef struct
162 {
163   const gchar *id;
164   const gchar *server;
165 } FindData;
166
167 static gint
168 connection_find (GstJackAudioConnection * conn, FindData * data)
169 {
170   /* id's must match */
171   if (strcmp (conn->id, data->id))
172     return 1;
173
174   /* both the same or NULL */
175   if (conn->server == data->server)
176     return 0;
177
178   /* we cannot compare NULL */
179   if (conn->server == NULL || data->server == NULL)
180     return 1;
181
182   if (strcmp (conn->server, data->server))
183     return 1;
184
185   return 0;
186 }
187
188 /* make a connection with @id and @server. Returns NULL on failure with the
189  * status set. */
190 static GstJackAudioConnection *
191 gst_jack_audio_make_connection (const gchar * id, const gchar * server,
192     jack_client_t * jclient, jack_status_t * status)
193 {
194   GstJackAudioConnection *conn;
195   jack_options_t options;
196   gint res;
197
198   *status = 0;
199
200   GST_DEBUG ("new client %s, connecting to server %s", id,
201       GST_STR_NULL (server));
202
203   /* never start a server */
204   options = JackNoStartServer;
205   /* if we have a servername, use it */
206   if (server != NULL)
207     options |= JackServerName;
208   /* open the client */
209   if (jclient == NULL)
210     jclient = jack_client_open (id, options, status, server);
211   if (jclient == NULL)
212     goto could_not_open;
213
214   /* now create object */
215   conn = g_new (GstJackAudioConnection, 1);
216   conn->refcount = 1;
217   conn->lock = g_mutex_new ();
218   conn->flush_cond = g_cond_new ();
219   conn->id = g_strdup (id);
220   conn->server = g_strdup (server);
221   conn->client = jclient;
222   conn->n_clients = 0;
223   conn->src_clients = NULL;
224   conn->sink_clients = NULL;
225
226   /* set our callbacks  */
227   jack_set_process_callback (jclient, jack_process_cb, conn);
228   /* these callbacks cause us to error */
229   jack_set_buffer_size_callback (jclient, jack_buffer_size_cb, conn);
230   jack_set_sample_rate_callback (jclient, jack_sample_rate_cb, conn);
231   jack_on_shutdown (jclient, jack_shutdown_cb, conn);
232
233   /* all callbacks are set, activate the client */
234   if ((res = jack_activate (jclient)))
235     goto could_not_activate;
236
237   GST_DEBUG ("opened connection %p", conn);
238
239   return conn;
240
241   /* ERRORS */
242 could_not_open:
243   {
244     GST_DEBUG ("failed to open jack client, %d", *status);
245     return NULL;
246   }
247 could_not_activate:
248   {
249     GST_ERROR ("Could not activate client (%d)", res);
250     *status = JackFailure;
251     g_mutex_free (conn->lock);
252     g_free (conn->id);
253     g_free (conn->server);
254     g_free (conn);
255     return NULL;
256   }
257 }
258
259 static GstJackAudioConnection *
260 gst_jack_audio_get_connection (const gchar * id, const gchar * server,
261     jack_client_t * jclient, jack_status_t * status)
262 {
263   GstJackAudioConnection *conn;
264   GList *found;
265   FindData data;
266
267   GST_DEBUG ("getting connection for id %s, server %s", id,
268       GST_STR_NULL (server));
269
270   data.id = id;
271   data.server = server;
272
273   G_LOCK (connections_lock);
274   found =
275       g_list_find_custom (connections, &data, (GCompareFunc) connection_find);
276   if (found != NULL && jclient != NULL) {
277     /* we found it, increase refcount and return it */
278     conn = (GstJackAudioConnection *) found->data;
279     conn->refcount++;
280
281     GST_DEBUG ("found connection %p", conn);
282   } else {
283     /* make new connection */
284     conn = gst_jack_audio_make_connection (id, server, jclient, status);
285     if (conn != NULL) {
286       GST_DEBUG ("created connection %p", conn);
287       /* add to list on success */
288       connections = g_list_prepend (connections, conn);
289     } else {
290       GST_WARNING ("could not create connection");
291     }
292   }
293   G_UNLOCK (connections_lock);
294
295   return conn;
296 }
297
298 static void
299 gst_jack_audio_unref_connection (GstJackAudioConnection * conn)
300 {
301   gint res;
302   gboolean zero;
303
304   GST_DEBUG ("unref connection %p refcnt %d", conn, conn->refcount);
305
306   G_LOCK (connections_lock);
307   conn->refcount--;
308   if ((zero = (conn->refcount == 0))) {
309     GST_DEBUG ("closing connection %p", conn);
310     /* remove from list, we can release the mutex after removing the connection
311      * from the list because after that, nobody can access the connection anymore. */
312     connections = g_list_remove (connections, conn);
313   }
314   G_UNLOCK (connections_lock);
315
316   /* if we are zero, close and cleanup the connection */
317   if (zero) {
318     /* don't use conn->lock here. two reasons:
319      *
320      *  1) its not necessary: jack_deactivate() will not return until the JACK thread
321      *      associated with this connection is cleaned up by a thread join, hence 
322      *      no more callbacks can occur or be in progress.
323      *
324      * 2) it would deadlock anyway, because jack_deactivate() will sleep
325      *      waiting for the JACK thread, and can thus cause deadlock in 
326      *      jack_process_cb()
327      */
328     if ((res = jack_deactivate (conn->client))) {
329       /* we only warn, this means the server is probably shut down and the client
330        * is gone anyway. */
331       GST_WARNING ("Could not deactivate Jack client (%d)", res);
332     }
333     /* close connection */
334     if ((res = jack_client_close (conn->client))) {
335       /* we assume the client is gone. */
336       GST_WARNING ("close failed (%d)", res);
337     }
338
339     /* free resources */
340     g_mutex_free (conn->lock);
341     g_cond_free (conn->flush_cond);
342     g_free (conn->id);
343     g_free (conn->server);
344     g_free (conn);
345   }
346 }
347
348 static void
349 gst_jack_audio_connection_add_client (GstJackAudioConnection * conn,
350     GstJackAudioClient * client)
351 {
352   g_mutex_lock (conn->lock);
353   switch (client->type) {
354     case GST_JACK_CLIENT_SOURCE:
355       conn->src_clients = g_list_append (conn->src_clients, client);
356       conn->n_clients++;
357       break;
358     case GST_JACK_CLIENT_SINK:
359       conn->sink_clients = g_list_append (conn->sink_clients, client);
360       conn->n_clients++;
361       break;
362     default:
363       g_warning ("trying to add unknown client type");
364       break;
365   }
366   g_mutex_unlock (conn->lock);
367 }
368
369 static void
370 gst_jack_audio_connection_remove_client (GstJackAudioConnection * conn,
371     GstJackAudioClient * client)
372 {
373   g_mutex_lock (conn->lock);
374   switch (client->type) {
375     case GST_JACK_CLIENT_SOURCE:
376       conn->src_clients = g_list_remove (conn->src_clients, client);
377       conn->n_clients--;
378       break;
379     case GST_JACK_CLIENT_SINK:
380       conn->sink_clients = g_list_remove (conn->sink_clients, client);
381       conn->n_clients--;
382       break;
383     default:
384       g_warning ("trying to remove unknown client type");
385       break;
386   }
387   g_mutex_unlock (conn->lock);
388 }
389
390 /**
391  * gst_jack_audio_client_get:
392  * @id: the client id
393  * @server: the server to connect to or NULL for the default server
394  * @type: the client type
395  * @shutdown: a callback when the jack server shuts down
396  * @process: a callback when samples are available
397  * @buffer_size: a callback when the buffer_size changes
398  * @sample_rate: a callback when the sample_rate changes
399  * @user_data: user data passed to the callbacks
400  * @status: pointer to hold the jack status code in case of errors
401  *
402  * Get the jack client connection for @id and @server. Connections to the same
403  * @id and @server will receive the same physical Jack client connection and
404  * will therefore be scheduled in the same process callback.
405  * 
406  * Returns: a #GstJackAudioClient.
407  */
408 GstJackAudioClient *
409 gst_jack_audio_client_new (const gchar * id, const gchar * server,
410     jack_client_t * jclient, GstJackClientType type,
411     void (*shutdown) (void *arg), JackProcessCallback process,
412     JackBufferSizeCallback buffer_size, JackSampleRateCallback sample_rate,
413     gpointer user_data, jack_status_t * status)
414 {
415   GstJackAudioClient *client;
416   GstJackAudioConnection *conn;
417
418   g_return_val_if_fail (id != NULL, NULL);
419   g_return_val_if_fail (status != NULL, NULL);
420
421   /* first get a connection for the id/server pair */
422   conn = gst_jack_audio_get_connection (id, server, jclient, status);
423   if (conn == NULL)
424     goto no_connection;
425
426   GST_INFO ("new client %s", id);
427
428   /* make new client using the connection */
429   client = g_new (GstJackAudioClient, 1);
430   client->active = client->deactivate = FALSE;
431   client->conn = conn;
432   client->type = type;
433   client->shutdown = shutdown;
434   client->process = process;
435   client->buffer_size = buffer_size;
436   client->sample_rate = sample_rate;
437   client->user_data = user_data;
438
439   /* add the client to the connection */
440   gst_jack_audio_connection_add_client (conn, client);
441
442   return client;
443
444   /* ERRORS */
445 no_connection:
446   {
447     GST_DEBUG ("Could not get server connection (%d)", *status);
448     return NULL;
449   }
450 }
451
452 /**
453  * gst_jack_audio_client_free:
454  * @client: a #GstJackAudioClient
455  *
456  * Free the resources used by @client.
457  */
458 void
459 gst_jack_audio_client_free (GstJackAudioClient * client)
460 {
461   GstJackAudioConnection *conn;
462
463   g_return_if_fail (client != NULL);
464
465   GST_INFO ("free client");
466
467   conn = client->conn;
468
469   /* remove from connection first so that it's not scheduled anymore after this
470    * call */
471   gst_jack_audio_connection_remove_client (conn, client);
472   gst_jack_audio_unref_connection (conn);
473
474   g_free (client);
475 }
476
477 /**
478  * gst_jack_audio_client_get_client:
479  * @client: a #GstJackAudioClient
480  *
481  * Get the jack audio client for @client. This function is used to perform
482  * operations on the jack server from this client.
483  *
484  * Returns: The jack audio client.
485  */
486 jack_client_t *
487 gst_jack_audio_client_get_client (GstJackAudioClient * client)
488 {
489   g_return_val_if_fail (client != NULL, NULL);
490
491   /* no lock needed, the connection and the client does not change 
492    * once the client is created. */
493   return client->conn->client;
494 }
495
496 /**
497  * gst_jack_audio_client_set_active:
498  * @client: a #GstJackAudioClient
499  * @active: new mode for the client
500  *
501  * Activate or deactive @client. When a client is activated it will receive
502  * callbacks when data should be processed.
503  *
504  * Returns: 0 if all ok.
505  */
506 gint
507 gst_jack_audio_client_set_active (GstJackAudioClient * client, gboolean active)
508 {
509   g_return_val_if_fail (client != NULL, -1);
510
511   /* make sure that we are not dispatching the client */
512   g_mutex_lock (client->conn->lock);
513   if (client->active && !active) {
514     /* we need to process once more to flush the port */
515     client->deactivate = TRUE;
516
517     /* need to wait for process_cb run once more */
518     while (client->deactivate)
519       g_cond_wait (client->conn->flush_cond, client->conn->lock);
520   }
521   client->active = active;
522   g_mutex_unlock (client->conn->lock);
523
524   return 0;
525 }