renamed GST_FLAGS macros to GST_OBJECT_FLAGS moved bitshift from macro to enum definition
[platform/upstream/gst-plugins-good.git] / ext / jack / gstjackbin.c
1 /* -*- Mode: C; c-basic-offset: 4 -*- */
2 /*
3     Copyright (C) 2002, 2003 Andy Wingo <wingo@pobox.com>
4
5     This library is free software; you can redistribute it and/or
6     modify it under the terms of the GNU General Public
7     License as published by the Free Software Foundation; either
8     version 2 of the License, or (at your option) any later version.
9
10     This library is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13     General Public License for more details.
14
15     You should have received a copy of the GNU General Public
16     License along with this library; if not, write to the Free
17     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <stdlib.h>
25 #include <string.h>
26 #include <signal.h>
27 #include "gstjack.h"
28
29
30 static GstBinClass *parent_class = NULL;
31
32 static void gst_jack_bin_init (GstJackBin * this);
33 static void gst_jack_bin_class_init (GstJackBinClass * klass);
34
35 static GstStateChangeReturn gst_jack_bin_change_state (GstElement * element,
36     GstStateChange transition);
37
38 /* jack callbacks */
39 static int process (jack_nframes_t nframes, void *arg);
40 static int sample_rate (jack_nframes_t nframes, void *arg);
41 static int buffer_size (jack_nframes_t nframes, void *arg);
42 static void shutdown (void *arg);
43
44 static void sighup_handler (int sig);
45 static GstJackBin *_jackbin = NULL;
46 static gboolean watchdog_please_set_the_jackbin_to_ready = FALSE;
47
48 /* fixme: we need a watchdog thread to see if we have received a SIGHUP, and if
49  * so set the state of the bin to READY. */
50
51 GType
52 gst_jack_bin_get_type (void)
53 {
54   static GType jack_bin_type = 0;
55
56   if (!jack_bin_type) {
57     static const GTypeInfo jack_bin_info = {
58       sizeof (GstJackBinClass),
59       NULL,
60       NULL,
61       (GClassInitFunc) gst_jack_bin_class_init,
62       NULL,
63       NULL,
64       sizeof (GstJackBin),
65       0,
66       (GInstanceInitFunc) gst_jack_bin_init,
67     };
68
69     jack_bin_type =
70         g_type_register_static (GST_TYPE_BIN, "GstJackBin", &jack_bin_info, 0);
71   }
72   return jack_bin_type;
73 }
74
75 static void
76 gst_jack_bin_class_init (GstJackBinClass * klass)
77 {
78   GObjectClass *object_class;
79   GstElementClass *element_class;
80
81   object_class = (GObjectClass *) klass;
82   element_class = (GstElementClass *) klass;
83
84   parent_class = g_type_class_ref (GST_TYPE_BIN);
85
86   element_class->change_state = gst_jack_bin_change_state;
87 }
88
89 static void
90 gst_jack_bin_init (GstJackBin * this)
91 {
92   GST_DEBUG ("initializing jack bin");
93
94   /* jack bins are managing bins and iterate themselves */
95   GST_OBJECT_FLAG_SET (this, GST_BIN_FLAG_MANAGER);
96   GST_OBJECT_FLAG_SET (this, GST_BIN_SELF_SCHEDULABLE);
97
98   /* make a new scheduler and associate it with the bin */
99   gst_scheduler_factory_make (NULL, GST_ELEMENT (this));
100 }
101
102 static GstStateChangeReturn
103 gst_jack_bin_change_state (GstElement * element, GstStateChange transition)
104 {
105   GstJackBin *this;
106   GList *l = NULL;
107   GstJackPad *pad;
108
109   g_return_val_if_fail (element != NULL, FALSE);
110   this = GST_JACK_BIN (element);
111
112   switch (GST_STATE_PENDING (element)) {
113     case GST_STATE_NULL:
114       JACK_DEBUG ("jackbin: NULL state");
115       if (this->client) {
116         JACK_DEBUG ("jackbin: closing client");
117         jack_client_close (this->client);
118         this->client = NULL;
119       }
120
121       if (_jackbin)
122         signal (SIGHUP, SIG_DFL);
123       _jackbin = NULL;
124
125       if (GST_ELEMENT_CLASS (parent_class)->change_state)
126         return GST_ELEMENT_CLASS (parent_class)->change_state (element,
127             transition);
128       break;
129
130     case GST_STATE_READY:
131       JACK_DEBUG ("jackbin: READY");
132
133       _jackbin = this;
134       signal (SIGHUP, sighup_handler);
135
136       if (!this->client) {
137         if (!(this->client = jack_client_new ("gst-jack"))) {
138           g_warning ("jack server not running?");
139           return GST_STATE_CHANGE_FAILURE;
140         }
141
142         gst_scheduler_setup (GST_ELEMENT_SCHED (this));
143
144         jack_set_process_callback (this->client, process, this);
145         jack_set_sample_rate_callback (this->client, sample_rate, this);
146         jack_set_buffer_size_callback (this->client, buffer_size, this);
147         this->nframes = jack_get_buffer_size (this->client);
148         jack_on_shutdown (this->client, shutdown, this);
149       }
150
151       if (GST_OBJECT_FLAG_IS_SET (GST_OBJECT (this), GST_JACK_OPEN)) {
152         l = this->src_pads;
153         while (l) {
154           JACK_DEBUG ("jackbin: unregistering pad %s:%s",
155               GST_JACK_PAD (l)->name, GST_JACK_PAD (l)->peer_name);
156           jack_port_unregister (this->client, GST_JACK_PAD (l)->port);
157           l = g_list_next (l);
158         }
159         l = this->sink_pads;
160         while (l) {
161           JACK_DEBUG ("jackbin: unregistering pad %s:%s",
162               GST_JACK_PAD (l)->name, GST_JACK_PAD (l)->peer_name);
163           jack_port_unregister (this->client, GST_JACK_PAD (l)->port);
164           l = g_list_next (l);
165         }
166         GST_OBJECT_FLAG_UNSET (GST_OBJECT (this), GST_JACK_OPEN);
167
168         if (GST_OBJECT_FLAG_IS_SET (GST_OBJECT (this), GST_JACK_ACTIVE)) {
169           JACK_DEBUG ("jackbin: deactivating client");
170           jack_deactivate (this->client);
171           GST_OBJECT_FLAG_UNSET (GST_OBJECT (this), GST_JACK_ACTIVE);
172         }
173       }
174
175       if (GST_ELEMENT_CLASS (parent_class)->change_state)
176         return GST_ELEMENT_CLASS (parent_class)->change_state (element,
177             transition);
178       break;
179
180     case GST_STATE_PAUSED:
181       JACK_DEBUG ("jackbin: PAUSED");
182
183       if (!GST_OBJECT_FLAG_IS_SET (GST_OBJECT (this), GST_JACK_OPEN)) {
184         l = this->src_pads;
185         while (l) {
186           pad = GST_JACK_PAD (l);
187           JACK_DEBUG ("jackbin: registering input port %s (peer %s)", pad->name,
188               pad->peer_name);
189           pad->port =
190               jack_port_register (this->client, pad->name,
191               JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput | JackPortIsTerminal, 0);
192           l = g_list_next (l);
193         }
194         l = this->sink_pads;
195         while (l) {
196           pad = GST_JACK_PAD (l);
197           JACK_DEBUG ("jackbin: registering output port %s (peer %s)",
198               pad->name, pad->peer_name);
199           pad->port =
200               jack_port_register (this->client, pad->name,
201               JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput | JackPortIsTerminal,
202               0);
203           l = g_list_next (l);
204         }
205
206         /* must activate before connecting */
207         if (!GST_OBJECT_FLAG_IS_SET (GST_OBJECT (this), GST_JACK_ACTIVE)) {
208           JACK_DEBUG ("jackbin: activating client");
209           jack_activate (this->client);
210           GST_OBJECT_FLAG_SET (GST_OBJECT (this), GST_JACK_ACTIVE);
211         }
212
213         l = this->src_pads;
214         while (l) {
215           pad = GST_JACK_PAD (l);
216           JACK_DEBUG ("connecting jack port %s to gst jack port %s",
217               pad->peer_name, jack_port_name (pad->port));
218           if (jack_connect (this->client, pad->peer_name,
219                   jack_port_name (pad->port))) {
220             g_warning ("jackbin: could not connect %s and %s", pad->peer_name,
221                 jack_port_name (pad->port));
222             return GST_STATE_CHANGE_FAILURE;
223           }
224           l = g_list_next (l);
225         }
226         l = this->sink_pads;
227         while (l) {
228           pad = GST_JACK_PAD (l);
229           JACK_DEBUG ("connecting gst jack port %s to jack port %s",
230               jack_port_name (pad->port), pad->peer_name);
231           if (jack_connect (this->client, jack_port_name (pad->port),
232                   pad->peer_name)) {
233             g_warning ("jackbin: could not connect %s and %s", pad->peer_name,
234                 jack_port_name (pad->port));
235             return GST_STATE_CHANGE_FAILURE;
236           }
237           l = g_list_next (l);
238         }
239
240         JACK_DEBUG ("jackbin: setting OPEN flag");
241         GST_OBJECT_FLAG_SET (GST_OBJECT (this), GST_JACK_OPEN);
242
243         if (GST_ELEMENT_CLASS (parent_class)->change_state)
244           return GST_ELEMENT_CLASS (parent_class)->change_state (element,
245               transition);
246       } else {
247         if (GST_ELEMENT_CLASS (parent_class)->change_state)
248           return GST_ELEMENT_CLASS (parent_class)->change_state (element,
249               transition);
250       }
251
252       break;
253     case GST_STATE_PLAYING:
254       JACK_DEBUG ("jackbin: PLAYING");
255
256       if (GST_ELEMENT_CLASS (parent_class)->change_state)
257         return GST_ELEMENT_CLASS (parent_class)->change_state (element,
258             transition);
259       break;
260   }
261
262   JACK_DEBUG ("jackbin: state change finished");
263
264   return GST_STATE_CHANGE_SUCCESS;
265 }
266
267 /* jack callbacks */
268
269 /* keep in mind that these run in another thread, mm-kay? */
270
271 static int
272 process (jack_nframes_t nframes, void *arg)
273 {
274   GstJackBin *bin = (GstJackBin *) arg;
275   GstJackPad *pad;
276   GList *l;
277
278   g_assert (bin);
279
280   JACK_DEBUG ("jackbin: process()");
281
282   if (GST_STATE (bin) != GST_STATE_PLAYING) {
283     JACK_DEBUG ("jackbin: bin is not PLAYING yet, returning");
284     return 0;
285   } else {
286     JACK_DEBUG ("jackbin: we are PLAYING, let's process()");
287   }
288
289   l = bin->src_pads;
290   while (l) {
291     pad = GST_JACK_PAD (l);
292     pad->data = jack_port_get_buffer (pad->port, nframes);
293     l = g_list_next (l);
294   }
295
296   l = bin->sink_pads;
297   while (l) {
298     pad = GST_JACK_PAD (l);
299     pad->data = jack_port_get_buffer (pad->port, nframes);
300     l = g_list_next (l);
301   }
302
303   bin->nframes = nframes;
304
305   JACK_DEBUG ("jackbin: iterating to process %ld frames of audio...", nframes);
306   if (!gst_bin_iterate (GST_BIN (bin))) {
307     g_warning ("bin failed to iterate");
308     return -1;
309   }
310
311   /* that's all folks */
312
313   return 0;
314 }
315
316 static int
317 sample_rate (jack_nframes_t nframes, void *arg)
318 {
319   GstJackBin *bin = (GstJackBin *) arg;
320
321   JACK_DEBUG ("the sample rate is now %lu/sec\n", nframes);
322   bin->rate = nframes;
323   return 0;
324 }
325
326 static int
327 buffer_size (jack_nframes_t nframes, void *arg)
328 {
329   GstJackBin *bin = (GstJackBin *) arg;
330
331   JACK_DEBUG ("the buffer size is now %lu\n", nframes);
332   bin->nframes = nframes;
333   return 0;
334 }
335
336 static void
337 shutdown (void *arg)
338 {
339 /*    GstJackClient *client = (GstJackClient*) arg; */
340   printf ("shutdown %p\n", arg);
341 /*    gst_element_set_state (GST_ELEMENT (client->manager), GST_STATE_READY); */
342 }
343
344 static void
345 sighup_handler (int sig)
346 {
347   g_message ("got sighup, setting state to READY");
348   watchdog_please_set_the_jackbin_to_ready = TRUE;
349 }