1 /*****************************************************************
2  * gmerlin - a general purpose multimedia framework and applications
3  *
4  * Copyright (c) 2001 - 2011 Members of the Gmerlin project
5  * gmerlin-general@lists.sourceforge.net
6  * http://gmerlin.sourceforge.net
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  * *****************************************************************/
21 #include <string.h>
22 
23 #include "jack_common.h"
24 
25 #define LOG_DOMAIN "jack"
26 
27 
28 static const bg_parameter_info_t parameters[] =
29   {
30     {
31       .name = "connect_ports",
32       .long_name = TRS("Connect ports"),
33       .type = BG_PARAMETER_CHECKBUTTON,
34       .val_default = { .val_i = 1 },
35       .help_string = TRS("Autoconnect ports"),
36     },
37     { /* End */ },
38   };
39 
40 const bg_parameter_info_t *
bg_jack_get_parameters(void * p)41 bg_jack_get_parameters(void * p)
42   {
43   return parameters;
44   }
45 
46 /* Set parameter */
47 
48 void
bg_jack_set_parameter(void * p,const char * name,const bg_parameter_value_t * val)49 bg_jack_set_parameter(void * p, const char * name,
50                       const bg_parameter_value_t * val)
51   {
52   jack_t * priv = p;
53   if(!name)
54     return;
55 
56   if(!strcmp(name, "connect_ports"))
57     priv->connect_ports = val->val_i;
58   }
59 
bg_jack_create()60 void * bg_jack_create()
61   {
62   jack_t * ret = calloc(1, sizeof(*ret));
63 
64   pthread_mutex_init(&ret->running_mutex, NULL);
65   pthread_mutex_init(&ret->active_mutex, NULL);
66 
67   return ret;
68   }
69 
bg_jack_start(void * data)70 int bg_jack_start(void * data)
71   {
72   jack_t * priv = data;
73 
74   pthread_mutex_lock(&priv->active_mutex);
75   priv->active = 1;
76   pthread_mutex_unlock(&priv->active_mutex);
77 
78   return 1;
79   }
80 
bg_jack_stop(void * data)81 void bg_jack_stop(void * data)
82   {
83   jack_t * priv = data;
84   pthread_mutex_lock(&priv->active_mutex);
85   priv->active = 0;
86   pthread_mutex_unlock(&priv->active_mutex);
87   }
88 
create_channel_map(jack_t * priv,int output)89 static void create_channel_map(jack_t * priv, int output)
90   {
91   int i;
92 
93   int flags = JackPortIsPhysical;
94 
95   if(output)
96     flags |= JackPortIsInput;
97   else
98     flags |= JackPortIsOutput;
99 
100   priv->ext_ports =
101     jack_get_ports(priv->client, NULL, NULL, flags);
102 
103   /* Count ports */
104   priv->num_ports = 0;
105   while(priv->ext_ports[priv->num_ports])
106     priv->num_ports++;
107 
108   priv->ports = calloc(priv->num_ports, sizeof(*priv->ports));
109 
110   /* Set channel map */
111 
112   if(priv->num_ports == 1)
113     {
114     priv->ports[0].channel_id = GAVL_CHID_FRONT_CENTER;
115     }
116   if(priv->num_ports >= 2)
117     {
118     priv->ports[0].channel_id = GAVL_CHID_FRONT_LEFT;
119     priv->ports[1].channel_id = GAVL_CHID_FRONT_RIGHT;
120     }
121   if(priv->num_ports >= 4)
122     {
123     priv->ports[2].channel_id = GAVL_CHID_REAR_LEFT;
124     priv->ports[3].channel_id = GAVL_CHID_REAR_RIGHT;
125     }
126   if(priv->num_ports >= 5)
127     {
128     priv->ports[4].channel_id = GAVL_CHID_FRONT_CENTER;
129     }
130   if(priv->num_ports >= 6)
131     {
132     priv->ports[5].channel_id = GAVL_CHID_LFE;
133     }
134   if(priv->num_ports >= 8)
135     {
136     priv->ports[6].channel_id = GAVL_CHID_SIDE_LEFT;
137     priv->ports[7].channel_id = GAVL_CHID_SIDE_RIGHT;
138     }
139 
140   flags = JackPortIsTerminal;
141 
142   if(output)
143     flags |= JackPortIsOutput;
144   else
145     flags |= JackPortIsInput;
146 
147   /* Set ports and buffers */
148   for(i = 0; i < priv->num_ports; i++)
149     {
150     priv->ports[i].ext_name = priv->ext_ports[i];
151 
152     priv->ports[i].int_port =
153       jack_port_register(priv->client,
154                          gavl_channel_id_to_string(priv->ports[i].channel_id),
155                          JACK_DEFAULT_AUDIO_TYPE,
156                          flags, 0);
157     priv->ports[i].buffer =
158       jack_ringbuffer_create(sizeof(float)*priv->samples_per_frame*4);
159     }
160 
161   }
162 
connect_ports(jack_t * priv,int output)163 static void connect_ports(jack_t * priv, int output)
164   {
165   int i;
166   const char * src;
167   const char * dst;
168 
169   for(i = 0; i < priv->num_ports; i++)
170     {
171     if(output)
172       {
173       src = jack_port_name(priv->ports[i].int_port);
174       dst = priv->ports[i].ext_name;
175       }
176     else
177       {
178       src = priv->ports[i].ext_name;
179       dst = jack_port_name(priv->ports[i].int_port);
180       }
181 
182     if(jack_connect(priv->client, src, dst))
183       bg_log(BG_LOG_WARNING, LOG_DOMAIN,
184              "Connecting %s with %s failed", src, dst);
185     }
186   }
187 
jack_shutdown(void * arg)188 static void jack_shutdown (void *arg)
189   {
190   jack_t * priv = arg;
191   fprintf(stderr, "Jack shutdown\n");
192 
193   pthread_mutex_lock(&priv->running_mutex);
194   priv->running = 0;
195   pthread_mutex_unlock(&priv->running_mutex);
196 
197   //  exit (1);
198   }
199 
bg_jack_open_client(jack_t * priv,int output,int (* process)(jack_nframes_t,void *))200 int bg_jack_open_client(jack_t * priv, int output,
201                         int (*process)(jack_nframes_t, void *))
202   {
203   priv->client = jack_client_open((output ?
204                                    "gmerlin-output" : "gmerlin-input"),
205                                   0, NULL);
206 
207   if(!priv->client)
208     return 0;
209   /* Set callbacks */
210   jack_set_process_callback(priv->client, process, priv);
211   jack_on_shutdown(priv->client, jack_shutdown, priv);
212 
213   priv->samples_per_frame = jack_get_buffer_size(priv->client);
214   priv->samplerate = jack_get_sample_rate(priv->client);
215 
216   create_channel_map(priv, output);
217 
218   if(jack_activate(priv->client))
219     return 0;
220 
221   pthread_mutex_lock(&priv->running_mutex);
222   priv->running = 1;
223   pthread_mutex_unlock(&priv->running_mutex);
224 
225   if(priv->connect_ports)
226     {
227     connect_ports(priv, output);
228     }
229 
230   return 1;
231   }
232 
destroy_channel_map(jack_t * priv)233 static void destroy_channel_map(jack_t * priv)
234   {
235   int i;
236   for(i = 0; i < priv->num_ports; i++)
237     {
238     jack_port_unregister(priv->client,
239                          priv->ports[i].int_port);
240     jack_ringbuffer_free(priv->ports[i].buffer);
241     }
242 
243   if(priv->ports)
244     free(priv->ports);
245   if(priv->ext_ports)
246     free(priv->ext_ports);
247 
248   }
249 
250 
bg_jack_close_client(jack_t * priv)251 int bg_jack_close_client(jack_t * priv)
252   {
253   int running;
254   gavl_time_t delay_time;
255   delay_time = GAVL_TIME_SCALE / 100; /* 10 ms */
256 
257   jack_deactivate(priv->client);
258 
259   while(1)
260     {
261     pthread_mutex_lock(&priv->running_mutex);
262     running = priv->running;
263     pthread_mutex_unlock(&priv->running_mutex);
264 
265     if(running)
266       gavl_time_delay(&delay_time);
267     else
268       break;
269     }
270   destroy_channel_map(priv);
271   return 1;
272   }
273 
bg_jack_destroy(void * p)274 void bg_jack_destroy(void * p)
275   {
276   jack_t * priv = p;
277 
278   /* Stop thread and close client connection */
279   if(priv->client)
280     bg_jack_close_client(priv);
281 
282   pthread_mutex_destroy(&priv->running_mutex);
283   pthread_mutex_destroy(&priv->active_mutex);
284 
285   free(priv);
286   }
287