1 /*
2 * Copyright (C) 2002 2003 2004 2005 2008 2009 2010, Magnus Hjorth
3 *
4 * This file is part of mhWaveEdit.
5 *
6 * mhWaveEdit is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * mhWaveEdit is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with mhWaveEdit; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21
22 #include <config.h>
23
24 #include "sound.h"
25 #include "inifile.h"
26 #include "main.h"
27 #include "um.h"
28 #include "gettext.h"
29 #include "mainloop.h"
30
31 gboolean output_byteswap_flag;
32 static gchar *output_byteswap_buffer=NULL;
33 static guint output_byteswap_bufsize=0;
34 gboolean sound_lock_driver;
35 static gboolean sound_delayed_quit=FALSE;
36 static Dataformat playing_format;
37 gboolean output_stereo_flag;
38 static GVoidFunc output_ready_func=NULL,input_ready_func=NULL;
39 static char zerobuf[1024];
40 static int output_play_count;
41 static gboolean output_want_data_cached;
42
43 #ifdef HAVE_ALSALIB
44 #include "sound-alsalib.c"
45 #endif
46
47 #ifdef HAVE_OSS
48 #include "sound-oss.c"
49 #endif
50
51 #ifdef HAVE_JACK
52 #include "sound-jack.c"
53 #endif
54
55 #ifdef HAVE_SUN
56 #include "sound-sun.c"
57 #endif
58
59 #if defined (HAVE_PORTAUDIO)
60 #include "sound-portaudio.c"
61 #endif
62
63 #if defined (HAVE_SDL)
64 #include "sound-sdl.c"
65 #endif
66
67 #ifdef HAVE_ESOUND
68 #include "sound-esound.c"
69 #endif
70
71 #ifdef HAVE_ARTSC
72 #include "sound-artsc.c"
73 #endif
74
75 #ifdef HAVE_PULSEAUDIO
76 #include "sound-pulse.c"
77 #endif
78
79 #include "sound-dummy.c"
80
input_supported_true(gboolean * complete)81 static GList *input_supported_true(gboolean *complete)
82 {
83 *complete = FALSE;
84 return NULL;
85 }
86
87 struct sound_driver {
88 gchar *name, *id;
89
90 void (*preferences)(void);
91
92 gboolean (*init)(gboolean silent);
93 void (*quit)(void);
94
95 gint (*output_select_format)(Dataformat *format, gboolean silent,
96 GVoidFunc ready_func);
97 gboolean (*output_want_data)(void);
98 guint (*output_play)(gchar *buffer, guint bufsize);
99 gboolean (*output_stop)(gboolean);
100 void (*output_clear_buffers)(void);
101 gboolean (*output_suggest_format)(Dataformat *format, Dataformat *result);
102 gboolean (*driver_needs_polling)(void);
103
104 GList *(*input_supported_formats)(gboolean *complete);
105 gint (*input_select_format)(Dataformat *format, gboolean silent,
106 GVoidFunc ready_func);
107 void (*input_store)(Ringbuf *buffer);
108 void (*input_stop)(void);
109 void (*input_stop_hint)(void);
110 int (*input_overrun_count)(void);
111 };
112
113 static struct sound_driver drivers[] = {
114
115 #ifdef HAVE_OSS
116 { "Open Sound System", "oss", oss_preferences, oss_init, oss_quit,
117 oss_output_select_format,
118 oss_output_want_data, oss_output_play, oss_output_stop,
119 oss_output_clear_buffers,NULL,NULL,
120 input_supported_true, oss_input_select_format,
121 oss_input_store, oss_input_stop },
122 #endif
123
124 #ifdef HAVE_ALSALIB
125 { "ALSA", "alsa", alsa_show_preferences, alsa_init, alsa_quit,
126 alsa_output_select_format,
127 alsa_output_want_data, alsa_output_play, alsa_output_stop,
128 alsa_output_clear_buffers,NULL,alsa_needs_polling,
129 input_supported_true,
130 alsa_input_select_format, alsa_input_store, alsa_input_stop,
131 alsa_input_stop_hint,alsa_input_overrun_count },
132 #endif
133
134 #ifdef HAVE_JACK
135 { "JACK", "jack", mhjack_preferences, mhjack_init, mhjack_quit,
136 mhjack_output_select_format,
137 mhjack_output_want_data, mhjack_output_play, mhjack_output_stop,
138 mhjack_clear_buffers, mhjack_output_suggest_format,NULL,
139 mhjack_input_supported_formats,
140 mhjack_input_select_format, mhjack_input_store, mhjack_input_stop,
141 mhjack_input_stop, mhjack_get_xrun_count },
142 #endif
143
144 #ifdef HAVE_SUN
145 { "Sun audio", "sun", NULL, sunaud_init, sunaud_quit,
146 sunaud_output_select_format, sunaud_output_want_data,
147 sunaud_output_play, sunaud_output_stop,
148 sunaud_output_clear_buffers,
149 sunaud_output_suggest_format, NULL,
150 input_supported_true,sunaud_input_select_format,sunaud_input_store,
151 sunaud_input_stop,NULL,sunaud_input_overrun_count },
152 #endif
153
154 #if defined (HAVE_PORTAUDIO)
155 { "PortAudio", "pa", NULL, portaudio_init, portaudio_quit,
156 portaudio_output_select_format,
157 portaudio_output_want_data, portaudio_output_play,
158 portaudio_output_stop,
159 portaudio_output_clear_buffers,
160 NULL, NULL,
161 portaudio_input_supported_formats,
162 portaudio_input_select_format, portaudio_input_store,
163 portaudio_input_stop, NULL, portaudio_input_overrun_count },
164 #endif
165
166 #if defined (HAVE_SDL)
167 { N_("SDL (output only)"), "sdl", NULL, sdl_init, sdl_quit,
168 sdl_output_select_format,
169 sdl_output_want_data, sdl_output_play, sdl_output_stop,
170 sdl_output_clear_buffers, NULL, NULL,
171 NULL, NULL, NULL, NULL, NULL },
172 #endif
173
174 #ifdef HAVE_ESOUND
175
176 { "ESound", "esound", esound_preferences, esound_init, esound_quit,
177 esound_output_select_format,
178 esound_output_want_data, esound_output_play, esound_output_stop,
179 esound_output_clear_buffers, NULL, NULL,
180 input_supported_true,
181 esound_input_select_format, esound_input_store, esound_input_stop },
182
183 #endif
184
185 #ifdef HAVE_ARTSC
186
187 { "aRts", "arts", NULL, mharts_init, mharts_quit,
188 mharts_output_select_format,
189 mharts_output_want_data, mharts_output_play, mharts_output_stop,
190 mharts_output_clear_buffers, mharts_output_suggest_format, NULL,
191 input_supported_true,
192 mharts_input_select_format, mharts_input_store, mharts_input_stop },
193
194 #endif
195
196 #ifdef HAVE_PULSEAUDIO
197
198 { "PulseAudio", "pulse", pulse_preferences, pulse_init, pulse_quit,
199 pulse_output_select_format, pulse_output_want_data, pulse_output_play,
200 pulse_output_stop, pulse_output_clear_buffers, NULL,
201 pulse_needs_polling,
202 pulse_input_supported_formats,
203 pulse_input_select_format,pulse_input_store,pulse_input_stop,NULL,
204 pulse_input_overrun_count
205 },
206
207 #endif
208
209 { N_("Dummy (no sound)"), "dummy", NULL, dummy_init, dummy_quit,
210 dummy_output_select_format,
211 dummy_output_want_data, dummy_output_play, dummy_output_stop,
212 dummy_output_clear_buffers, NULL, NULL,
213 dummy_input_supported_formats,
214 dummy_input_select_format, dummy_input_store, dummy_input_stop }
215
216 };
217
218 static guint current_driver = 0;
219
220 /* Auto-detection order. */
221
222 static gchar *autodetect_order[] = {
223 /* Sound servers. These must auto-detect properly */
224 "jack", "pulse", "esound", "arts",
225 /* "Direct" API:s that don't auto-detect properly.
226 * If compiled in they probably work. */
227 "alsa", "sun",
228 /* "Direct" API:s that may or may not work and doesn't autodetect
229 * properly */
230 "oss",
231 /* Drivers that shouldn't be used unless everything else fails */
232 "pa", "sdl", "dummy",
233 };
234
sound_driver_name(void)235 gchar *sound_driver_name(void)
236 {
237 return _(drivers[current_driver].name);
238 }
239
sound_driver_id(void)240 gchar *sound_driver_id(void)
241 {
242 return drivers[current_driver].id;
243 }
244
sound_driver_index(void)245 int sound_driver_index(void)
246 {
247 return current_driver;
248 }
249
sound_driver_valid_names(void)250 GList *sound_driver_valid_names(void)
251 {
252 GList *l = NULL;
253 int i;
254 for (i=0; i<ARRAY_LENGTH(drivers); i++)
255 l = g_list_append(l, _(drivers[i].name));
256 return l;
257 }
258
sound_driver_id_from_name(gchar * name)259 gchar *sound_driver_id_from_name(gchar *name)
260 {
261 int i;
262 for (i=0; i<ARRAY_LENGTH(drivers); i++)
263 if (!strcmp(_(drivers[i].name),name))
264 return drivers[i].id;
265 return NULL;
266 }
267
sound_driver_id_from_index(int index)268 gchar *sound_driver_id_from_index(int index)
269 {
270 return drivers[index].id;
271 }
272
sound_driver_name_from_id(gchar * id)273 gchar *sound_driver_name_from_id(gchar *id)
274 {
275 int i;
276 for (i=0; i<ARRAY_LENGTH(drivers); i++)
277 if (!strcmp(drivers[i].id,id))
278 return _(drivers[i].name);
279 return NULL;
280 }
281
sound_driver_has_preferences(gchar * id)282 gboolean sound_driver_has_preferences(gchar *id)
283 {
284 int i;
285
286 if (!id) return (drivers[current_driver].preferences != NULL);
287
288 for (i=0; i<ARRAY_LENGTH(drivers); i++)
289 if (!strcmp(drivers[i].id,id))
290 return (drivers[i].preferences != NULL);
291 g_assert_not_reached();
292 return FALSE;
293 }
294
sound_driver_show_preferences(gchar * id)295 void sound_driver_show_preferences(gchar *id)
296 {
297 int i;
298
299 if ((!id) && sound_driver_has_preferences(id))
300 drivers[current_driver].preferences();
301
302 for (i=0; i<ARRAY_LENGTH(drivers); i++)
303 if (!strcmp(drivers[i].id,id))
304 drivers[i].preferences();
305 }
306
sound_init_driver(char * name)307 static void sound_init_driver(char *name)
308 {
309 gchar *d,**p;
310 int i;
311
312 /* Handle auto-detection */
313 if (!strcmp(name,"auto")) {
314 for (p=autodetect_order; ; p++) {
315 for (i=0; i<ARRAY_LENGTH(drivers) &&
316 strcmp(drivers[i].id,*p); i++) { }
317 if (i == ARRAY_LENGTH(drivers)) continue;
318 if (drivers[i].init(TRUE)) {
319 current_driver = i;
320 return;
321 }
322 }
323 g_assert_not_reached();
324 }
325
326 /* Set current_driver */
327 for (i=0; i<ARRAY_LENGTH(drivers); i++) {
328 if (!strcmp(drivers[i].id,name)) {
329 current_driver = i;
330 break;
331 }
332 }
333 if (i == ARRAY_LENGTH(drivers)) {
334 d = g_strdup_printf(_("Invalid driver name: %s\nUsing '%s' driver "
335 "instead"),name,drivers[0].name);
336 user_error(d);
337 current_driver = 0;
338 }
339
340 drivers[current_driver].init(FALSE);
341 }
342
sound_init(void)343 void sound_init(void)
344 {
345 gchar *c;
346 sound_lock_driver = inifile_get_gboolean("soundLock",FALSE);
347 output_byteswap_flag = inifile_get_gboolean("outputByteswap",FALSE);
348 output_stereo_flag = inifile_get_gboolean("outputStereo",FALSE);
349 if (driver_option != NULL)
350 c = driver_option;
351 else {
352 c = inifile_get(INI_SETTING_SOUNDDRIVER, DEFAULT_DRIVER);
353 if (!strcmp(c,"default")) c = drivers[0].id;
354 }
355
356 sound_init_driver(c);
357
358 /* Add sound_poll to main loop */
359 mainloop_constant_source_add((constsource_cb)sound_poll,NULL,FALSE);
360
361 }
362
delayed_output_stop(void)363 static void delayed_output_stop(void)
364 {
365 drivers[current_driver].output_stop(FALSE);
366 sound_delayed_quit=FALSE;
367 }
368
sound_quit(void)369 void sound_quit(void)
370 {
371 if (sound_delayed_quit) delayed_output_stop();
372 drivers[current_driver].quit();
373 }
374
375 static void sound_output_ready_func(void);
376 static gboolean sound_select_in_progress = FALSE;
377
sound_poll(void)378 gboolean sound_poll(void)
379 {
380 int i=0;
381 static int last_playcount;
382
383 if (sound_select_in_progress) return -1;
384
385 if (drivers[current_driver].driver_needs_polling!=NULL &&
386 !drivers[current_driver].driver_needs_polling() )
387 return -1;
388
389 if (output_ready_func==NULL && input_ready_func==NULL)
390 return -1;
391
392 if ((output_ready_func!=NULL || sound_delayed_quit) &&
393 output_want_data() && last_playcount != output_play_count) {
394 last_playcount = output_play_count;
395 sound_output_ready_func();
396 i=1;
397 }
398 if (input_ready_func != NULL) {
399 input_ready_func();
400 i=0;
401 }
402
403 return i;
404 }
405
406 /* We need to filter the output ready event if delayed stop mode is enabled */
sound_output_ready_func(void)407 static void sound_output_ready_func(void)
408 {
409 output_want_data_cached = TRUE;
410 if (sound_delayed_quit) {
411 while (output_want_data()) {
412 output_play(zerobuf,
413 sizeof(zerobuf)-
414 (sizeof(zerobuf)%playing_format.samplebytes));
415 }
416 } else if (output_ready_func != NULL && output_want_data()) {
417 output_ready_func();
418 } else if (output_ready_func != NULL) {
419 puts("output_ready_func called but !output_want_data");
420 }
421 }
422
output_select_format(Dataformat * format,gboolean silent,GVoidFunc ready_func)423 gint output_select_format(Dataformat *format, gboolean silent,
424 GVoidFunc ready_func)
425 {
426 gint i;
427
428 if (output_stereo_flag && format->channels==1) return -1;
429
430 if (sound_delayed_quit) {
431 if (dataformat_equal(format,&playing_format)) {
432 sound_delayed_quit = FALSE;
433 output_ready_func = ready_func;
434 return FALSE;
435 }
436 else delayed_output_stop();
437 }
438
439 /* We "guard" using this flag to protect against recursive calls
440 * to sound_poll (happens if driver calls user_error, for example) */
441 sound_select_in_progress = TRUE;
442
443 /* Set up the variables before calling output_select_format, in
444 * case the ready callback is called immediately */
445 memcpy(&playing_format,format,sizeof(Dataformat));
446 output_ready_func = ready_func;
447 i = drivers[current_driver].output_select_format(format,silent,
448 sound_output_ready_func);
449 if (i != 0) output_ready_func = NULL;
450
451 sound_select_in_progress = FALSE;
452 output_play_count++;
453 return i;
454 }
455
input_supported_formats(gboolean * complete)456 GList *input_supported_formats(gboolean *complete)
457 {
458 if (drivers[current_driver].input_supported_formats != NULL)
459 return drivers[current_driver].input_supported_formats(complete);
460 else {
461 *complete = TRUE;
462 return NULL;
463 }
464 }
465
input_supported(void)466 gboolean input_supported(void)
467 {
468 gboolean b;
469 GList *l;
470 l = input_supported_formats(&b);
471 if (l != NULL) {
472 g_list_foreach(l,(GFunc)g_free,NULL);
473 g_list_free(l);
474 return TRUE;
475 } else
476 return !b;
477 }
478
input_select_format(Dataformat * format,gboolean silent,GVoidFunc ready_func)479 gint input_select_format(Dataformat *format, gboolean silent,
480 GVoidFunc ready_func)
481 {
482 gint i;
483 if (sound_delayed_quit) delayed_output_stop();
484 i = drivers[current_driver].input_select_format(format,silent,ready_func);
485 if (i == 0)
486 input_ready_func = ready_func;
487 return i;
488 }
489
output_stop(gboolean must_flush)490 gboolean output_stop(gboolean must_flush)
491 {
492 output_ready_func = NULL;
493 if (sound_lock_driver) {
494 if (must_flush)
495 while (output_play(NULL,0) > 0) { }
496 else
497 output_clear_buffers();
498 sound_delayed_quit=TRUE;
499 return must_flush;
500 } else {
501 return drivers[current_driver].output_stop(must_flush);
502 }
503 }
504
output_want_data(void)505 gboolean output_want_data(void)
506 {
507 if (!output_want_data_cached)
508 output_want_data_cached = drivers[current_driver].output_want_data();
509 return output_want_data_cached;
510 }
511
output_play(gchar * buffer,guint bufsize)512 guint output_play(gchar *buffer, guint bufsize)
513 {
514 if (bufsize > 0)
515 output_want_data_cached = FALSE;
516 if (output_byteswap_flag) {
517 if (output_byteswap_bufsize < bufsize) {
518 g_free(output_byteswap_buffer);
519 output_byteswap_buffer = g_malloc(bufsize);
520 output_byteswap_bufsize = bufsize;
521 }
522 memcpy(output_byteswap_buffer,buffer,bufsize);
523 byteswap(output_byteswap_buffer,playing_format.samplesize,bufsize);
524 buffer = output_byteswap_buffer;
525 }
526 if (bufsize > 0) output_play_count++;
527 return drivers[current_driver].output_play(buffer,bufsize);
528 }
529
output_suggest_format(Dataformat * format,Dataformat * result)530 gboolean output_suggest_format(Dataformat *format, Dataformat *result)
531 {
532 if (output_stereo_flag && format->channels==1) {
533 memcpy(result,format,sizeof(Dataformat));
534 result->channels = 2;
535 return TRUE;
536 }
537
538 if (drivers[current_driver].output_suggest_format)
539 return drivers[current_driver].output_suggest_format(format,result);
540 else
541 return FALSE;
542 }
543
input_stop(void)544 void input_stop(void)
545 {
546 if (!sound_delayed_quit)
547 drivers[current_driver].input_stop();
548 input_ready_func = NULL;
549 }
550
input_store(Ringbuf * buffer)551 void input_store(Ringbuf *buffer)
552 {
553 drivers[current_driver].input_store(buffer);
554 }
555
output_clear_buffers(void)556 void output_clear_buffers(void)
557 {
558 drivers[current_driver].output_clear_buffers();
559 }
560
input_stop_hint(void)561 void input_stop_hint(void)
562 {
563 if (drivers[current_driver].input_stop_hint)
564 drivers[current_driver].input_stop_hint();
565 }
566
input_overrun_count(void)567 int input_overrun_count(void)
568 {
569 if (drivers[current_driver].input_overrun_count)
570 return drivers[current_driver].input_overrun_count();
571 else
572 return -1;
573 }
574