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
22 #include <stdio.h>
23 #include <string.h>
24
25 #include <unistd.h>
26 #include <stdlib.h>
27
28 #include "jack_common.h"
29
30 #include <gmerlin/utils.h>
31
32
33 #define LOG_DOMAIN "oa_jack"
34
mute_port(jack_t * priv,jack_nframes_t nframes,int port)35 static void mute_port(jack_t * priv, jack_nframes_t nframes, int port)
36 {
37 char *out;
38 out = jack_port_get_buffer(priv->ports[port].int_port, nframes);
39 memset(out, 0, nframes * sizeof(float));
40 }
41
find_port(jack_t * priv,gavl_channel_id_t id)42 static int find_port(jack_t * priv, gavl_channel_id_t id)
43 {
44 int i;
45 for(i = 0; i < priv->num_ports; i++)
46 {
47 if(priv->ports[i].channel_id == id)
48 return i;
49 }
50 return -1;
51 }
52
jack_process(jack_nframes_t nframes,void * arg)53 static int jack_process(jack_nframes_t nframes, void *arg)
54 {
55 int i;
56 jack_t * priv = arg;
57 char *out;
58 int bytes_read, bytes_to_read, result;
59 gavl_time_t delay_time;
60
61 // fprintf(stderr, "jack_process %d\n", nframes);
62
63 bytes_to_read = nframes * sizeof(float);
64
65 pthread_mutex_lock(&priv->active_mutex);
66
67 if(!priv->active)
68 {
69 for(i = 0; i < priv->num_ports; i++)
70 mute_port(priv, nframes, i);
71 pthread_mutex_unlock(&priv->active_mutex);
72 return 0;
73 }
74
75 pthread_mutex_unlock(&priv->active_mutex);
76
77 for(i = 0; i < priv->num_ports; i++)
78 {
79 if(priv->ports[i].active)
80 {
81 bytes_read = 0;
82 out = jack_port_get_buffer(priv->ports[i].int_port, nframes);
83
84 while(bytes_read < bytes_to_read)
85 {
86 result = jack_ringbuffer_read(priv->ports[i].buffer, out + bytes_read,
87 bytes_to_read - bytes_read);
88
89 if(result < bytes_to_read - bytes_read)
90 {
91 fprintf(stderr, "Underflow\n");
92
93 delay_time = gavl_time_unscale(priv->format.samplerate,
94 bytes_to_read - bytes_read - result) / 2;
95 gavl_time_delay(&delay_time);
96 }
97 bytes_read += result;
98 }
99 }
100 else
101 {
102 mute_port(priv, nframes, i);
103 }
104 }
105
106 return 0;
107 }
108
109
setup_channel(jack_t * priv,gavl_channel_id_t id)110 static void setup_channel(jack_t * priv, gavl_channel_id_t id)
111 {
112 int index;
113
114 index = find_port(priv, id);
115 if(index < 0)
116 return;
117
118 priv->ports[index].index = priv->format.num_channels;
119 priv->format.channel_locations[priv->format.num_channels] = id;
120 priv->ports[index].active = 1;
121 priv->format.num_channels++;
122
123 jack_ringbuffer_reset(priv->ports[index].buffer);
124
125 }
126
open_jack(void * data,gavl_audio_format_t * format)127 static int open_jack(void * data, gavl_audio_format_t * format)
128 {
129 int i;
130 int num_front_channels;
131 int num_rear_channels;
132 int num_lfe_channels;
133
134 jack_t * priv = data;
135
136 if(!priv->client)
137 bg_jack_open_client(priv, 1, jack_process);
138
139 /* Copy format */
140 gavl_audio_format_copy(&priv->format, format);
141
142 priv->format.samplerate = priv->samplerate;
143 priv->format.sample_format = GAVL_SAMPLE_FLOAT;
144 priv->format.interleave_mode = GAVL_INTERLEAVE_NONE;
145 priv->format.samples_per_frame = priv->samples_per_frame;
146
147 /* Clear ports */
148 for(i = 0; i < priv->num_ports; i++)
149 priv->ports[i].active = 0;
150
151 /* Setup ports */
152
153 num_front_channels = gavl_front_channels(format);
154 num_rear_channels = gavl_rear_channels(format);
155 num_lfe_channels = gavl_lfe_channels(format);
156
157 priv->format.num_channels = 0;
158
159 switch(num_front_channels)
160 {
161 case 2:
162 setup_channel(priv, GAVL_CHID_FRONT_LEFT);
163 setup_channel(priv, GAVL_CHID_FRONT_RIGHT);
164 break;
165 case 1:
166 case 3:
167 setup_channel(priv, GAVL_CHID_FRONT_CENTER);
168 setup_channel(priv, GAVL_CHID_FRONT_LEFT);
169 setup_channel(priv, GAVL_CHID_FRONT_RIGHT);
170 break;
171 }
172
173 if(num_rear_channels)
174 {
175 setup_channel(priv, GAVL_CHID_REAR_LEFT);
176 setup_channel(priv, GAVL_CHID_REAR_RIGHT);
177 }
178 if(num_lfe_channels)
179 setup_channel(priv, GAVL_CHID_LFE);
180
181 gavl_audio_format_copy(format, &priv->format);
182
183 return 1;
184 }
185
close_jack(void * p)186 static void close_jack(void * p)
187 {
188 }
189
write_frame_jack(void * p,gavl_audio_frame_t * f)190 static void write_frame_jack(void * p, gavl_audio_frame_t * f)
191 {
192 int i;
193 int samples_written, result;
194 gavl_time_t delay_time;
195 jack_t * priv = p;
196 int write_space;
197
198 // fprintf(stderr, "Write jack %d\n", f->valid_samples);
199
200 for(i = 0; i < priv->num_ports; i++)
201 {
202 if(!priv->ports[i].active)
203 continue;
204
205 samples_written = 0;
206
207 while(1)
208 {
209 write_space = jack_ringbuffer_write_space(priv->ports[i].buffer);
210 if(write_space >= f->valid_samples * sizeof(float))
211 break;
212
213 delay_time = gavl_time_unscale(priv->format.samplerate,
214 f->valid_samples - write_space / sizeof(float)) / 2;
215 gavl_time_delay(&delay_time);
216 }
217
218 while(samples_written < f->valid_samples)
219 {
220 result =
221 jack_ringbuffer_write(priv->ports[i].buffer,
222 (const char*)(f->channels.f[priv->ports[i].index] +
223 samples_written),
224 (f->valid_samples - samples_written) *
225 sizeof(float));
226 #if 0
227 if(i)
228 fprintf(stderr, "Write %d %d %ld\n", samples_written,
229 f->valid_samples - samples_written, result);
230
231 #endif
232 result /= sizeof(float);
233
234 samples_written += result;
235
236 }
237
238 }
239
240 }
241
get_delay_jack(void * p)242 static int get_delay_jack(void * p)
243 {
244 jack_t * priv;
245 priv = p;
246
247 return jack_port_get_latency(priv->ports[0].int_port);
248 }
249
250 const bg_oa_plugin_t the_plugin =
251 {
252 .common =
253 {
254 BG_LOCALE,
255 .name = "oa_jack",
256 .long_name = TRS("Jack"),
257 .description = TRS("Jack output plugin"),
258 .type = BG_PLUGIN_OUTPUT_AUDIO,
259 .flags = BG_PLUGIN_PLAYBACK,
260 .priority = BG_PLUGIN_PRIORITY_MAX-1,
261 .create = bg_jack_create,
262 .destroy = bg_jack_destroy,
263
264 .get_parameters = bg_jack_get_parameters,
265 .set_parameter = bg_jack_set_parameter,
266 },
267
268 .open = open_jack,
269 .start = bg_jack_start,
270 .write_audio = write_frame_jack,
271 .stop = bg_jack_stop,
272 .close = close_jack,
273 .get_delay = get_delay_jack,
274 };
275
276 /* Include this into all plugin modules exactly once
277 to let the plugin loader obtain the API version */
278 BG_GET_PLUGIN_API_VERSION;
279