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