1 /* Jack plugin for moc by Alex Norman <alex@neisis.net> 2005
2 * moc by Copyright (C) 2004 Damian Pietras <daper@daper.net>
3 * use at your own risk
4 */
5
6 #ifdef HAVE_CONFIG_H
7 # include "config.h"
8 #endif
9
10 #include <unistd.h>
11
12 #define DEBUG
13
14 #include <stdio.h>
15 #include <jack/jack.h>
16 #include <jack/types.h>
17 #include <jack/ringbuffer.h>
18 #include <string.h>
19 #include <assert.h>
20 #include <math.h>
21
22 #include "common.h"
23 #include "audio.h"
24 #include "log.h"
25 #include "options.h"
26
27 #define RINGBUF_SZ 32768
28
29 /* the client */
30 static jack_client_t *client;
31 /* an array of output ports */
32 static jack_port_t **output_port;
33 /* the ring buffer, used to store the sound data before jack takes it */
34 static jack_ringbuffer_t *ringbuffer[2];
35 /* volume */
36 static jack_default_audio_sample_t volume = 1.0;
37 /* volume as an integer - needed to avoid cast errors on set/read */
38 static int volume_integer = 100;
39 /* indicates if we should be playing or not */
40 static int play;
41 /* current sample rate */
42 static int rate;
43 /* flag set if xrun occurred that was our fault (the ringbuffer doesn't
44 * contain enough data in the process callback) */
45 static volatile int our_xrun = 0;
46 /* set to 1 if jack client thread exits */
47 static volatile int jack_shutdown = 0;
48
49 /* this is the function that jack calls to get audio samples from us */
moc_jack_process(jack_nframes_t nframes,void * arg ATTR_UNUSED)50 static int moc_jack_process(jack_nframes_t nframes, void *arg ATTR_UNUSED)
51 {
52 jack_default_audio_sample_t *out[2];
53
54 if (nframes <= 0)
55 return 0;
56
57 /* get the jack output ports */
58 out[0] = (jack_default_audio_sample_t *) jack_port_get_buffer (
59 output_port[0], nframes);
60 out[1] = (jack_default_audio_sample_t *) jack_port_get_buffer (
61 output_port[1], nframes);
62
63 if (play) {
64 size_t i;
65
66 /* ringbuffer[1] is filled later, so we only need to check
67 * it's space. */
68 size_t avail_data = jack_ringbuffer_read_space(ringbuffer[1]);
69 size_t avail_frames = avail_data
70 / sizeof(jack_default_audio_sample_t);
71
72 if (avail_frames > nframes) {
73 avail_frames = nframes;
74 avail_data = nframes
75 * sizeof(jack_default_audio_sample_t);
76 }
77
78 jack_ringbuffer_read (ringbuffer[0], (char *)out[0],
79 avail_data);
80 jack_ringbuffer_read (ringbuffer[1], (char *)out[1],
81 avail_data);
82
83
84 /* we must provide nframes data, so fill with silence
85 * the remaining space. */
86 if (avail_frames < nframes) {
87 our_xrun = 1;
88
89 for (i = avail_frames; i < nframes; i++)
90 out[0][i] = out[1][i] = 0.0;
91 }
92 }
93 else {
94 size_t i;
95 size_t size;
96
97 /* consume the input */
98 size = jack_ringbuffer_read_space(ringbuffer[1]);
99 jack_ringbuffer_read_advance (ringbuffer[0], size);
100 jack_ringbuffer_read_advance (ringbuffer[1], size);
101
102 for (i = 0; i < nframes; i++) {
103 out[0][i] = 0.0;
104 out[1][i] = 0.0;
105 }
106 }
107
108 return 0;
109 }
110
111 /* this is called if jack changes its sample rate */
moc_jack_update_sample_rate(jack_nframes_t new_rate,void * arg ATTR_UNUSED)112 static int moc_jack_update_sample_rate(jack_nframes_t new_rate,
113 void *arg ATTR_UNUSED)
114 {
115 rate = new_rate;
116 return 0;
117 }
118
119 /* callback for jack's error messages */
error_callback(const char * msg)120 static void error_callback (const char *msg)
121 {
122 error ("JACK: %s", msg);
123 }
124
shutdown_callback(void * arg ATTR_UNUSED)125 static void shutdown_callback (void *arg ATTR_UNUSED)
126 {
127 jack_shutdown = 1;
128 }
129
moc_jack_init(struct output_driver_caps * caps)130 static int moc_jack_init (struct output_driver_caps *caps)
131 {
132 const char *client_name;
133
134 client_name = options_get_str ("JackClientName");
135
136 jack_set_error_function (error_callback);
137
138 #ifdef HAVE_JACK_CLIENT_OPEN
139
140 jack_status_t status;
141 jack_options_t options;
142
143 /* open a client connection to the JACK server */
144 options = JackNullOption;
145 if (!options_get_bool ("JackStartServer"))
146 options |= JackNoStartServer;
147 client = jack_client_open (client_name, options, &status, NULL);
148 if (client == NULL) {
149 error ("jack_client_open() failed, status = 0x%2.0x", status);
150 if (status & JackServerFailed)
151 error ("Unable to connect to JACK server");
152 return 0;
153 }
154
155 if (status & JackServerStarted)
156 printf ("JACK server started\n");
157
158 #else
159
160 /* try to become a client of the JACK server */
161 client = jack_client_new (client_name);
162 if (client == NULL) {
163 error ("Cannot create client; JACK server not running?");
164 return 0;
165 }
166
167 #endif
168
169 jack_shutdown = 0;
170 jack_on_shutdown (client, shutdown_callback, NULL);
171
172 /* allocate memory for an array of 2 output ports */
173 output_port = xmalloc(2 * sizeof(jack_port_t *));
174 output_port[0] = jack_port_register (client, "output0", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
175 output_port[1] = jack_port_register (client, "output1", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
176
177 /* create the ring buffers */
178 ringbuffer[0] = jack_ringbuffer_create(RINGBUF_SZ);
179 ringbuffer[1] = jack_ringbuffer_create(RINGBUF_SZ);
180
181 /* set the call back functions, activate the client */
182 jack_set_process_callback (client, moc_jack_process, NULL);
183 jack_set_sample_rate_callback(client, moc_jack_update_sample_rate, NULL);
184 if (jack_activate (client)) {
185 error ("cannot activate client");
186 return 0;
187 }
188
189 /* connect ports
190 * a value of NULL in JackOut* gives no connection
191 * */
192 if(strcmp(options_get_str("JackOutLeft"),"NULL")){
193 if(jack_connect(client,"moc:output0", options_get_str("JackOutLeft")))
194 fprintf(stderr,"%s is not a valid Jack Client / Port", options_get_str("JackOutLeft"));
195 }
196 if(strcmp(options_get_str("JackOutRight"),"NULL")){
197 if(jack_connect(client,"moc:output1", options_get_str("JackOutRight")))
198 fprintf(stderr,"%s is not a valid Jack Client / Port", options_get_str("JackOutRight"));
199 }
200
201 caps->formats = SFMT_FLOAT;
202 rate = jack_get_sample_rate (client);
203 caps->max_channels = caps->min_channels = 2;
204
205 logit ("jack init");
206
207 return 1;
208 }
209
moc_jack_open(struct sound_params * sound_params)210 static int moc_jack_open (struct sound_params *sound_params)
211 {
212 if (sound_params->fmt != SFMT_FLOAT) {
213 char fmt_name[SFMT_STR_MAX];
214
215 error ("Unsupported sound format: %s.",
216 sfmt_str(sound_params->fmt, fmt_name, sizeof(fmt_name)));
217 return 0;
218 }
219 if (sound_params->channels != 2) {
220 error ("Unsupported number of channels");
221 return 0;
222 }
223
224 logit ("jack open");
225 play = 1;
226
227 return 1;
228 }
229
moc_jack_close()230 static void moc_jack_close ()
231 {
232 logit ("jack close");
233 play = 0;
234 }
235
moc_jack_play(const char * buff,const size_t size)236 static int moc_jack_play (const char *buff, const size_t size)
237 {
238 size_t remain = size;
239 size_t pos = 0;
240
241 if (jack_shutdown) {
242 logit ("Refusing to play, because there is no client thread.");
243 return -1;
244 }
245
246 debug ("Playing %zu bytes", size);
247
248 if (our_xrun) {
249 logit ("xrun");
250 our_xrun = 0;
251 }
252
253 while (remain && !jack_shutdown) {
254 size_t space;
255
256 /* check if some space is available only in the second
257 * ringbuffer, because it is read later than the first. */
258 if ((space = jack_ringbuffer_write_space(ringbuffer[1]))
259 > sizeof(jack_default_audio_sample_t)) {
260 size_t to_write;
261
262 space *= 2; /* we have 2 channels */
263 debug ("Space in the ringbuffer: %zu bytes", space);
264
265 to_write = MIN (space, remain);
266
267 to_write /= sizeof(jack_default_audio_sample_t) * 2;
268 remain -= to_write * sizeof(float) * 2;
269 while (to_write--) {
270 jack_default_audio_sample_t sample;
271
272 sample = *(jack_default_audio_sample_t *)
273 (buff + pos) * volume;
274 pos += sizeof (jack_default_audio_sample_t);
275 jack_ringbuffer_write (ringbuffer[0],
276 (char *)&sample,
277 sizeof(sample));
278
279 sample = *(jack_default_audio_sample_t *)
280 (buff + pos) * volume;
281 pos += sizeof (jack_default_audio_sample_t);
282 jack_ringbuffer_write (ringbuffer[1],
283 (char *)&sample,
284 sizeof(sample));
285 }
286 }
287 else {
288 debug ("Sleeping for %uus", (unsigned)(RINGBUF_SZ
289 / (float)(audio_get_bps()) * 100000.0));
290 usleep (RINGBUF_SZ / (float)(audio_get_bps())
291 * 100000.0);
292 }
293 }
294
295 if (jack_shutdown)
296 return -1;
297
298 return size;
299 }
300
moc_jack_read_mixer()301 static int moc_jack_read_mixer ()
302 {
303 return volume_integer;
304 }
305
moc_jack_set_mixer(int vol)306 static void moc_jack_set_mixer (int vol)
307 {
308 volume_integer = vol;
309 volume = (jack_default_audio_sample_t)((exp((double)vol / 100.0) - 1)
310 / (M_E - 1));
311 }
312
moc_jack_get_buff_fill()313 static int moc_jack_get_buff_fill ()
314 {
315 /* FIXME: should we also use jack_port_get_latency() here? */
316 return sizeof(float) * (jack_ringbuffer_read_space(ringbuffer[0])
317 + jack_ringbuffer_read_space(ringbuffer[1]))
318 / sizeof(jack_default_audio_sample_t);
319 }
320
moc_jack_reset()321 static int moc_jack_reset ()
322 {
323 //jack_ringbuffer_reset(ringbuffer); /*this is not threadsafe!*/
324 return 1;
325 }
326
327 /* do any cleanup that needs to be done */
moc_jack_shutdown()328 static void moc_jack_shutdown(){
329 jack_port_unregister(client,output_port[0]);
330 jack_port_unregister(client,output_port[1]);
331 free(output_port);
332 jack_client_close(client);
333 jack_ringbuffer_free(ringbuffer[0]);
334 jack_ringbuffer_free(ringbuffer[1]);
335 }
336
moc_jack_get_rate()337 static int moc_jack_get_rate ()
338 {
339 return rate;
340 }
341
moc_jack_get_mixer_channel_name()342 static char *moc_jack_get_mixer_channel_name ()
343 {
344 return xstrdup ("soft mixer");
345 }
346
moc_jack_toggle_mixer_channel()347 static void moc_jack_toggle_mixer_channel ()
348 {
349 }
350
moc_jack_funcs(struct hw_funcs * funcs)351 void moc_jack_funcs (struct hw_funcs *funcs)
352 {
353 funcs->init = moc_jack_init;
354 funcs->open = moc_jack_open;
355 funcs->close = moc_jack_close;
356 funcs->play = moc_jack_play;
357 funcs->read_mixer = moc_jack_read_mixer;
358 funcs->set_mixer = moc_jack_set_mixer;
359 funcs->get_buff_fill = moc_jack_get_buff_fill;
360 funcs->reset = moc_jack_reset;
361 funcs->shutdown = moc_jack_shutdown;
362 funcs->get_rate = moc_jack_get_rate;
363 funcs->get_mixer_channel_name = moc_jack_get_mixer_channel_name;
364 funcs->toggle_mixer_channel = moc_jack_toggle_mixer_channel;
365 }
366