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