1 /* Audio hardware handlers (OSS, ALSA, Sun, Windows, Mac OSX, Jack, HPUX, NetBSD, OpenBSD, pulseaudio, portaudio)
2  *
3  * In many cases, only callback driven transfers are supported, so ideally we'd have:
4  * int mus_audio_playback(caller_data, start_func, fill_func, end_func)
5  *   returns error indication or MUS_NO_ERROR
6  *   calls start_func at startup: void start(caller_data, ...)?
7  *   each times it needs a bufferfull, calls fill_func: bool fill(caller_data, void *buf, buf_size_in_samples, buf_data_type)
8  *     perhaps returns false to signal normal quit?
9  *   at end (either via fill or some interrupt), calls end(caller_data, ...)?
10  */
11 
12 /*
13  * layout of this file:
14  *    error handlers
15  *    OSS
16  *    ALSA
17  *    Sun
18  *    Windows 95/98
19  *    OSX
20  *    JACK
21  *    HPUX
22  *    OpenBSD
23  *    NetBSD
24  *    PulseAudio (in progress?)
25  *    PortAudio
26  */
27 
28 /*
29  * int mus_audio_open_output(int dev, int srate, int chans, mus_sample_t samp_type, int size)
30  * int mus_audio_open_input(int dev, int srate, int chans, mus_sample_t samp_type, int size)
31  * int mus_audio_write(int line, char *buf, int bytes)
32  * int mus_audio_close(int line)
33  * int mus_audio_read(int line, char *buf, int bytes)
34  * int mus_audio_initialize(void) does whatever is needed to get set up
35  * char *mus_audio_moniker(void) returns some brief description of the overall audio setup (don't free return string).
36  */
37 
38 #include "mus-config.h"
39 
40 #if USE_SND && __APPLE__ && USE_MOTIF
41   #undef USE_MOTIF
42   #define USE_NO_GUI 1
43   /* Xt's Boolean (/usr/include/X11/Intrinsic.h = char) collides with MacTypes.h Boolean, (actually,
44    *   unsigned char in /Developer/SDKs/MacOSX10.4u.sdk/System/Library/Frameworks/CoreFoundation.framework/Versions/A/Headers/CFBase.h)
45    *   but we want snd.h for other stuff, so, if Motif is in use, don't load its headers at this time
46    *   perhaps we could use the -funsigned-char switch in gcc
47    */
48 #endif
49 
50 #if USE_SND && __APPLE__ && HAVE_RUBY
51   /* if using Ruby, OpenTransport.h T_* definitions collide with Ruby's -- it isn't needed here, so... */
52   #define REDEFINE_HAVE_RUBY 1
53   #undef HAVE_RUBY
54 #endif
55 
56 #if USE_SND
57   #include "snd.h"
58 #else
59   #define PRINT_BUFFER_SIZE 512
60   #define LABEL_BUFFER_SIZE 64
61 #endif
62 
63 #if USE_SND && __APPLE__
64   #define USE_MOTIF 1
65   #undef USE_NO_GUI
66   #if REDEFINE_HAVE_RUBY
67     #define HAVE_RUBY 1
68   #endif
69 #endif
70 
71 #include <math.h>
72 #include <stdio.h>
73 #include <fcntl.h>
74 #include <errno.h>
75 #include <stdlib.h>
76 #ifndef _MSC_VER
77   #include <unistd.h>
78 #endif
79 #include <string.h>
80 
81 #ifdef __APPLE__
82 #include <CoreServices/CoreServices.h>
83 #include <CoreAudio/CoreAudio.h>
84 /* these pull in stdbool.h apparently, so they have to precede sndlib.h */
85 #endif
86 
87 /* #define HAVE_JACK_IN_LINUX (MUS_JACK && __linux__) */
88 /* using JACK on GNU/linux, GNU/kFreeBSD and GNU/Hurd is all the same */
89 #if ((defined __linux__) || ((defined __FreeBSD_kernel__) && (defined __GLIBC__)) || (defined __GNU__))
90   #define HAVE_JACK_IN_LINUX MUS_JACK
91 #else
92   #define HAVE_JACK_IN_LINUX 0
93 #endif
94 
95 #include "_sndlib.h"
96 #include "sndlib-strings.h"
97 
98 #if WITH_AUDIO
99 
100 enum {MUS_AUDIO_IGNORED, MUS_AUDIO_DUPLEX_DEFAULT, MUS_AUDIO_LINE_OUT,
101       MUS_AUDIO_LINE_IN, MUS_AUDIO_MICROPHONE, MUS_AUDIO_SPEAKERS, MUS_AUDIO_DIGITAL_OUT,
102       MUS_AUDIO_DAC_OUT, MUS_AUDIO_MIXER, MUS_AUDIO_AUX_OUTPUT
103 };
104 
105 
106 #define mus_standard_error(Error_Type, Error_Message) \
107   mus_print("%s\n  [%s[%d] %s]", Error_Message, __FILE__, __LINE__, __func__)
108 
109 #define mus_standard_io_error(Error_Type, IO_Func, IO_Name) \
110   mus_print("%s %s: %s\n  [%s[%d] %s]", IO_Func, IO_Name, strerror(errno), __FILE__, __LINE__, __func__)
111 
112 
113 static char *version_name = NULL;
114 static bool audio_initialized = false;
115 
116 
117 
118 
119 /* ------------------------------- OSS ----------------------------------------- */
120 
121 /* Thanks to Yair K. for OSS v4 changes.  22-Jan-08 */
122 
123 #if (HAVE_OSS || HAVE_ALSA || HAVE_JACK_IN_LINUX)
124 /* actually it's not impossible that someday we'll have ALSA but not OSS... */
125 #define AUDIO_OK 1
126 
127 #include <sys/ioctl.h>
128 #include <sys/soundcard.h>
129 
130 #if ((SOUND_VERSION > 360) && (defined(OSS_SYSINFO)))
131   #define NEW_OSS 1
132 #endif
133 
134 #define MUS_OSS_WRITE_RATE     SNDCTL_DSP_SPEED
135 #define MUS_OSS_WRITE_CHANNELS SNDCTL_DSP_CHANNELS
136 #define MUS_OSS_SET_FORMAT     SNDCTL_DSP_SETFMT
137 #define MUS_OSS_GET_FORMATS    SNDCTL_DSP_GETFMTS
138 
139 #define DAC_NAME "/dev/dsp"
140 #define MIXER_NAME "/dev/mixer"
141 /* some programs use /dev/audio */
142 
143 /* there can be more than one sound card installed, and a card can be handled through
144  * more than one /dev/dsp device, so we can't use a global dac device here.
145  * The caller has to keep track of the various cards (via AUDIO_SYSTEM) --
146  * I toyed with embedding all that in mus_audio_open_output and mus_audio_write, but
147  * decided it's better to keep them explicit -- the caller may want entirely
148  * different (non-synchronous) streams going to the various cards.  This same
149  * code (AUDIO_SYSTEM(n)->devn) should work in Windoze (see below), and
150  * might work on the Mac -- something for a rainy day...
151  */
152 
153 #define return_error_exit(Message_Type, Audio_Line, Ur_Message) \
154   do { \
155        char *Message; Message = Ur_Message; \
156        if (Audio_Line != -1) \
157           linux_audio_close(Audio_Line); \
158        if ((Message) && (strlen(Message) > 0)) \
159          { \
160            mus_print("%s\n  [%s[%d] %s]", \
161                      Message, \
162                      __FILE__, __LINE__, __func__); \
163            free(Message); \
164          } \
165        else mus_print("%s\n  [%s[%d] %s]", \
166                       mus_error_type_to_string(Message_Type), \
167                       __FILE__, __LINE__, __func__); \
168        return(MUS_ERROR); \
169      } while (false)
170 
171 static int FRAGMENTS = 4;
172 static int FRAGMENT_SIZE = 12;
173 static bool fragments_locked = false;
174 
175 /* defaults here are FRAGMENTS 16 and FRAGMENT_SIZE 12; these values however
176  * cause about a .5 second delay, which is not acceptable in "real-time" situations.
177  *
178  * this changed 22-May-01: these are causing more trouble than they're worth
179  */
180 
oss_mus_oss_set_buffers(int num,int size)181 static void oss_mus_oss_set_buffers(int num, int size) {FRAGMENTS = num; FRAGMENT_SIZE = size; fragments_locked = true;}
182 
183 #define MAX_SOUNDCARDS 8
184 #define MAX_DSPS 8
185 #define MAX_MIXERS 8
186 /* there can be (apparently) any number of mixers and dsps per soundcard, but 8 is enough! */
187 
188 static int *audio_fd = NULL;
189 static int *audio_open_ctr = NULL;
190 static int *audio_dsp = NULL;
191 static int *audio_mixer = NULL;
192 static int *audio_mode = NULL;
193 
194 static int sound_cards = 0;
195 #ifdef NEW_OSS
196   static int new_oss_running = 0;
197 #endif
198 static char *dev_name = NULL;
199 
oss_mus_audio_moniker(void)200 static char *oss_mus_audio_moniker(void)
201 {
202   if (!version_name) version_name = (char *)calloc(LABEL_BUFFER_SIZE, sizeof(char));
203   if (SOUND_VERSION < 361)
204     {
205       char version[LABEL_BUFFER_SIZE];
206       snprintf(version, LABEL_BUFFER_SIZE, "%d", SOUND_VERSION);
207       snprintf(version_name, LABEL_BUFFER_SIZE, "OSS %c.%c.%c", version[0], version[1], version[2]);
208     }
209   else
210     snprintf(version_name, LABEL_BUFFER_SIZE, "OSS %x.%x.%x",
211 		 (SOUND_VERSION >> 16) & 0xff,
212 		 (SOUND_VERSION >> 8) & 0xff,
213 		 SOUND_VERSION & 0xff);
214   return(version_name);
215 }
216 
dac_name(int sys,int offset)217 static char *dac_name(int sys, int offset)
218 {
219   if ((sys < sound_cards) && (audio_mixer[sys] >= -1))
220     {
221       snprintf(dev_name, LABEL_BUFFER_SIZE, "%s%d", DAC_NAME, audio_dsp[sys] + offset);
222       return(dev_name);
223     }
224   return((char *)DAC_NAME);
225 }
226 
227 #define MIXER_SIZE SOUND_MIXER_NRDEVICES
228 static int **mixer_state = NULL;
229 static int *init_srate = NULL, *init_chans = NULL, *init_format = NULL;
230 
oss_mus_audio_initialize(void)231 static int oss_mus_audio_initialize(void)
232 {
233   /* here we need to set up the map of /dev/dsp and /dev/mixer to a given system */
234   /* since this info is not passed to us by OSS, we have to work at it... */
235   /* for the time being, I'll ignore auxiliary dsp and mixer ports (each is a special case) */
236   int amp, old_mixer_amp, old_dsp_amp, new_mixer_amp;
237   int devmask;
238 #ifdef NEW_OSS
239   int status, ignored;
240   oss_sysinfo sysinfo;
241   static mixer_info mixinfo;
242   int sysinfo_ok = 0;
243 #endif
244   if (!audio_initialized)
245     {
246       int i, num_mixers, num_dsps, nmix, ndsp, err = 0, fd = -1, responsive_field;
247       audio_initialized = true;
248       audio_fd = (int *)calloc(MAX_SOUNDCARDS, sizeof(int));
249       audio_open_ctr = (int *)calloc(MAX_SOUNDCARDS, sizeof(int));
250       audio_dsp = (int *)calloc(MAX_SOUNDCARDS, sizeof(int));
251       audio_mixer = (int *)calloc(MAX_SOUNDCARDS, sizeof(int));
252       audio_mode = (int *)calloc(MAX_SOUNDCARDS, sizeof(int));
253       dev_name = (char *)calloc(LABEL_BUFFER_SIZE, sizeof(char));
254       init_srate = (int *)calloc(MAX_SOUNDCARDS, sizeof(int));
255       init_chans = (int *)calloc(MAX_SOUNDCARDS, sizeof(int));
256       init_format = (int *)calloc(MAX_SOUNDCARDS, sizeof(int));
257       mixer_state = (int **)calloc(MAX_SOUNDCARDS, sizeof(int *));
258       for (i = 0; i < MAX_SOUNDCARDS; i++) mixer_state[i] = (int *)calloc(MIXER_SIZE, sizeof(int));
259       for (i = 0; i < MAX_SOUNDCARDS; i++)
260 	{
261 	  audio_fd[i] = -1;
262 	  audio_open_ctr[i] = 0;
263 	  audio_dsp[i] = -1;
264 	  audio_mixer[i] = -1;
265 	}
266 
267       num_mixers = MAX_MIXERS;
268       num_dsps = MAX_DSPS;
269 #ifdef NEW_OSS
270       fd = open(DAC_NAME, O_WRONLY | O_NONBLOCK, 0);
271       if (fd == -1) fd = open(MIXER_NAME, O_RDONLY | O_NONBLOCK, 0);
272       if (fd != -1)
273 	{
274 	  status = ioctl(fd, OSS_GETVERSION, &ignored);
275 	  new_oss_running = (status == 0);
276 	  if (new_oss_running)
277 	    {
278 	      status = ioctl(fd, OSS_SYSINFO, &sysinfo);
279 	      sysinfo_ok = (status == 0);
280 	    }
281 	  if ((new_oss_running) && (sysinfo_ok))
282 	    {
283 	      num_mixers = sysinfo.nummixers;
284 	      num_dsps = sysinfo.numaudios;
285 	    }
286 	  close(fd);
287 	}
288 #endif
289 
290       /* need to get which /dev/dsp lines match which /dev/mixer lines,
291        *   find out how many separate systems (soundcards) are available,
292        *   fill the audio_dsp and audio_mixer arrays with the system-related numbers,
293        * since we have no way to tell from OSS info which mixers/dsps are the
294        *   main ones, we'll do some messing aound to try to deduce this info.
295        * for example, SB uses two dsp ports and two mixers per card, whereas
296        *  Ensoniq uses 2 dsps and 1 mixer.
297        *
298        * the data we are gathering here:
299        *   int audio_dsp[MAX_SOUNDCARDS] -> main_dsp_port[n] (-1 => no such system dsp)
300        *   int audio_mixer[MAX_SOUNDCARDS] -> main_mixer_port[n]
301        *   int sound_cards = 0 -> usable systems
302        * all auxiliary ports are currently ignored (SB equalizer, etc)
303        */
304       sound_cards = 0;
305       ndsp = 0;
306       nmix = 0;
307       while ((nmix < num_mixers) &&
308 	     (ndsp < num_dsps))
309 	{
310 	  char dname[LABEL_BUFFER_SIZE];
311 	  int md;
312 	  /* for each mixer, find associated main dsp (assumed to be first in /dev/dsp ordering) */
313 	  /*   if mixer's dsp overlaps or we run out of dsps first, ignore it (aux mixer) */
314 	  /* our by-guess-or-by-gosh method here is to try to open the mixer.
315 	   *   if that fails, quit (if very first, try at least to get the dsp setup)
316 	   *   find volume field, if none, go on, else read current volume
317 	   *   open next unchecked dsp, try to set volume, read current, if different we found a match -- set and go on.
318 	   *     if no change, move to next dsp and try again, if no more dsps, quit (checking for null case as before)
319 	   */
320 	  snprintf(dname, LABEL_BUFFER_SIZE, "%s%d", MIXER_NAME, nmix);
321 	  md = open(dname, O_RDWR, 0);
322 	  if (md == -1)
323 	    {
324 	      if (errno == EBUSY)
325 		{
326 		  mus_print("%s is busy: can't access it [%s[%d] %s]",
327 			    dname,
328 			    __FILE__, __LINE__, __func__);
329 		  nmix++;
330 		  continue;
331 		}
332 	      else break;
333 	    }
334 	  snprintf(dname, LABEL_BUFFER_SIZE, "%s%d", DAC_NAME, ndsp);
335 	  fd = open(dname, O_RDWR | O_NONBLOCK, 0);
336 	  if (fd == -1) fd = open(dname, O_RDONLY | O_NONBLOCK, 0);
337  	  if (fd == -1) fd = open(dname, O_WRONLY | O_NONBLOCK, 0); /* some output devices need this */
338 	  if (fd == -1)
339 	    {
340 	      close(md);
341 	      if (errno == EBUSY) /* in linux /usr/include/asm-generic/errno-base.h */
342 		{
343 		  fprintf(stderr, "%s is busy: can't access it\n", dname);
344 		  ndsp++;
345 		  continue;
346 		}
347 	      else
348 		{
349 		  if ((errno != ENXIO) && (errno != ENODEV) && (errno != ENOENT))
350 		    fprintf(stderr, "%s: %s! ", dname, strerror(errno));
351 		  break;
352 		}
353 	    }
354 #ifdef NEW_OSS
355 	  status = ioctl(md, SOUND_MIXER_INFO, &mixinfo);
356 #endif
357 	  err = ioctl(md, SOUND_MIXER_READ_DEVMASK, &devmask);
358 	  responsive_field = SOUND_MIXER_VOLUME;
359 	  for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
360 	    if ((1 << i) & devmask)
361 	      {
362 		responsive_field = i;
363 		break;
364 	      }
365 	  if (!err)
366 	    {
367 	      err = ioctl(md, MIXER_READ(responsive_field), &old_mixer_amp);
368 	      if (!err)
369 		{
370 		  err = ioctl(fd, MIXER_READ(responsive_field), &old_dsp_amp);
371 		  if ((!err) && (old_dsp_amp == old_mixer_amp))
372 		    {
373 		      if (old_mixer_amp == 0) amp = 50; else amp = 0; /* 0..100 */
374 		      err = ioctl(fd, MIXER_WRITE(responsive_field), &amp);
375 		      if (!err)
376 			{
377 			  err = ioctl(md, MIXER_READ(responsive_field), &new_mixer_amp);
378 			  if (!err)
379 			    {
380 			      if (new_mixer_amp == amp)
381 				{
382 				  /* found one! */
383 				  audio_dsp[sound_cards] = ndsp; ndsp++;
384 				  audio_mixer[sound_cards] = nmix; nmix++;
385 				  sound_cards++;
386 				}
387 			      else ndsp++;
388 			      err = ioctl(fd, MIXER_WRITE(responsive_field), &old_dsp_amp);
389 			    }
390 			  else nmix++;
391 			}
392 		      else ndsp++;
393 		    }
394 		  else ndsp++;
395 		}
396 	      else nmix++;
397 	    }
398 	  else nmix++;
399 	  close(fd);
400 	  close(md);
401 	}
402       if (sound_cards == 0)
403 	{
404  	  fd = open(DAC_NAME, O_WRONLY | O_NONBLOCK, 0);
405 	  if (fd != -1)
406 	    {
407 	      sound_cards = 1;
408 	      audio_dsp[0] = 0;
409 	      audio_mixer[0] = -2; /* hmmm -- need a way to see /dev/dsp as lonely outpost */
410 	      close(fd);
411  	      fd = open(MIXER_NAME, O_RDONLY | O_NONBLOCK, 0);
412 	      if (fd == -1)
413 		audio_mixer[0] = -3;
414 	      else close(fd);
415 	    }
416 	}
417     }
418   return(MUS_NO_ERROR);
419 }
420 
linux_audio_open(const char * pathname,int flags,mode_t mode,int system)421 static int linux_audio_open(const char *pathname, int flags, mode_t mode, int system)
422 {
423   /* sometimes this is simply searching for a device (so failure is not a mus_error) */
424   if (audio_fd[system] == -1)
425     {
426       audio_fd[system] = open(pathname, flags, mode);
427       audio_open_ctr[system] = 0;
428     }
429   else audio_open_ctr[system]++;
430   return(audio_fd[system]);
431 }
432 
linux_audio_open_with_error(const char * pathname,int flags,mode_t mode,int system)433 static int linux_audio_open_with_error(const char *pathname, int flags, mode_t mode, int system)
434 {
435   int fd;
436   static bool already_warned = false;
437   if ((system < 0) ||
438       (system >= MAX_SOUNDCARDS))
439     return(-1);
440 
441   fd = linux_audio_open(pathname, flags, mode, system);
442   if ((fd == -1) &&
443       (!already_warned))
444     {
445       already_warned = true;
446       mus_standard_io_error(MUS_AUDIO_CANT_OPEN,
447 			    ((mode == O_RDONLY) ? "open read" :
448 			     (mode == O_WRONLY) ? "open write" : "open read/write"),
449 			    pathname);
450     }
451   return(fd);
452 }
453 
find_system(int line)454 static int find_system(int line)
455 {
456   int i;
457   for (i = 0; i < sound_cards; i++)
458     if (line == audio_fd[i])
459       return(i);
460   return(MUS_ERROR);
461 }
462 
linux_audio_close(int fd)463 static int linux_audio_close(int fd)
464 {
465   if (fd != -1)
466     {
467       int err = 0, sys;
468       sys = find_system(fd);
469       if (sys != -1)
470 	{
471 	  if (audio_open_ctr[sys] > 0)
472 	    audio_open_ctr[sys]--;
473 	  else
474 	    {
475 	      err = close(fd);
476 	      audio_open_ctr[sys] = 0;
477 	      audio_fd[sys] = -1;
478 	    }
479 	}
480       else err = close(fd);
481       if (err) return_error_exit(MUS_AUDIO_CANT_CLOSE, -1,
482 				 mus_format("close %d failed: %s",
483 					    fd, strerror(errno)));
484     }
485   /* is this an error? */
486   return(MUS_NO_ERROR);
487 }
488 
to_oss_sample_type(mus_sample_t snd_format)489 static int to_oss_sample_type(mus_sample_t snd_format)
490 {
491   switch (snd_format)
492     {
493     case MUS_BYTE:    return(AFMT_S8);
494     case MUS_BSHORT:  return(AFMT_S16_BE);
495     case MUS_UBYTE:   return(AFMT_U8);
496     case MUS_MULAW:   return(AFMT_MU_LAW);
497     case MUS_ALAW:    return(AFMT_A_LAW);
498     case MUS_LSHORT:  return(AFMT_S16_LE);
499     case MUS_UBSHORT: return(AFMT_U16_BE);
500     case MUS_ULSHORT: return(AFMT_U16_LE);
501 #ifdef NEW_OSS
502     case MUS_LINT:    return(AFMT_S32_LE);
503     case MUS_BINT:    return(AFMT_S32_BE);
504 #endif
505     default: break;
506     }
507   return(MUS_ERROR);
508 }
509 
510 static bool fragment_set_failed = false;
511 
oss_mus_audio_open_output(int ur_dev,int srate,int chans,mus_sample_t samp_type,int size)512 static int oss_mus_audio_open_output(int ur_dev, int srate, int chans, mus_sample_t samp_type, int size)
513 {
514   int oss_sample_type, buffer_info, audio_out = -1, sys, dev;
515   char *dev_name;
516 #ifndef NEW_OSS
517   int stereo;
518 #endif
519   sys = MUS_AUDIO_SYSTEM(ur_dev);
520   dev = MUS_AUDIO_DEVICE(ur_dev);
521   oss_sample_type = to_oss_sample_type(samp_type);
522   if (oss_sample_type == MUS_ERROR)
523     return_error_exit(MUS_AUDIO_SAMPLE_TYPE_NOT_AVAILABLE, -1,
524 		      mus_format("sample type %d (%s) not available",
525 				 samp_type,
526 				 mus_sample_type_name(samp_type)));
527 
528   if (dev == MUS_AUDIO_DEFAULT)
529     audio_out = linux_audio_open_with_error(dev_name = dac_name(sys, 0),
530 					    O_WRONLY, 0, sys);
531   else audio_out = linux_audio_open_with_error(dev_name = dac_name(sys, (dev == MUS_AUDIO_AUX_OUTPUT) ? 1 : 0),
532 					       O_RDWR, 0, sys);
533   if (audio_out == -1) return(MUS_ERROR);
534 
535   /* ioctl(audio_out, SNDCTL_DSP_RESET, 0); */ /* causes clicks */
536   if ((fragments_locked) &&
537       (!(fragment_set_failed)) &&
538       ((dev == MUS_AUDIO_DUPLEX_DEFAULT) ||
539        (size != 0))) /* only set if user has previously called set_oss_buffers */
540     {
541       buffer_info = (FRAGMENTS << 16) | (FRAGMENT_SIZE);
542       if (ioctl(audio_out, SNDCTL_DSP_SETFRAGMENT, &buffer_info) == -1)
543         {
544           /* older Linuces (or OSS's?) refuse to handle the fragment reset if O_RDWR used --
545            * someone at OSS forgot to update the version number when this was fixed, so
546            * I have no way to get around this except to try and retry...
547            */
548           linux_audio_close(audio_out);
549           audio_out = linux_audio_open_with_error(dev_name = dac_name(sys, (dev == MUS_AUDIO_AUX_OUTPUT) ? 1 : 0),
550 						  O_WRONLY, 0, sys);
551 	  if (audio_out == -1) return(MUS_ERROR);
552           buffer_info = (FRAGMENTS << 16) | (FRAGMENT_SIZE);
553           if (ioctl(audio_out, SNDCTL_DSP_SETFRAGMENT, &buffer_info) == -1)
554 	    {
555 	      char *tmp;
556 	      tmp = mus_format("can't set %s fragments to: %d x %d",
557 			       dev_name, FRAGMENTS, FRAGMENT_SIZE); /* not an error if ALSA OSS-emulation */
558 	      fprintf(stderr, "%s\n", tmp);
559 	      fragment_set_failed = true;
560 	      free(tmp);
561 	    }
562         }
563     }
564   if ((ioctl(audio_out, MUS_OSS_SET_FORMAT, &oss_sample_type) == -1) ||
565       (oss_sample_type != to_oss_sample_type(samp_type)))
566     return_error_exit(MUS_AUDIO_SAMPLE_TYPE_NOT_AVAILABLE, audio_out,
567 		      mus_format("sample type %d (%s) not available on %s",
568 				 samp_type,
569 				 mus_sample_type_name(samp_type),
570 				 dev_name));
571 #ifdef NEW_OSS
572   if (ioctl(audio_out, MUS_OSS_WRITE_CHANNELS, &chans) == -1)
573     return_error_exit(MUS_AUDIO_CHANNELS_NOT_AVAILABLE, audio_out,
574 		      mus_format("can't get %d channels on %s",
575 				 chans, dev_name));
576 #else
577   if (chans == 2) stereo = 1; else stereo = 0;
578   if ((ioctl(audio_out, SNDCTL_DSP_STEREO, &stereo) == -1) ||
579       ((chans == 2) && (stereo == 0)))
580     return_error_exit(MUS_AUDIO_CHANNELS_NOT_AVAILABLE, audio_out,
581 		      mus_format("can't get %d channels on %s",
582 				 chans, dev_name));
583 #endif
584   if (ioctl(audio_out, MUS_OSS_WRITE_RATE, &srate) == -1)
585     return_error_exit(MUS_AUDIO_SRATE_NOT_AVAILABLE, audio_out,
586 		      mus_format("can't set srate of %s to %d",
587 				 dev_name, srate));
588   /* http://www.4front-tech.com/pguide/audio.html says this order has to be followed */
589   return(audio_out);
590 }
591 
oss_mus_audio_write(int line,char * buf,int bytes)592 static int oss_mus_audio_write(int line, char *buf, int bytes)
593 {
594   int err;
595   if (line < 0) return(-1);
596   errno = 0;
597   err = write(line, buf, bytes);
598   if (err != bytes)
599     {
600       if (errno != 0)
601 	return_error_exit(MUS_AUDIO_WRITE_ERROR, -1,
602 			  mus_format("write error: %s", strerror(errno)));
603       else return_error_exit(MUS_AUDIO_WRITE_ERROR, -1,
604 			     mus_format("wrote %d bytes of requested %d", err, bytes));
605     }
606   return(MUS_NO_ERROR);
607 }
608 
oss_mus_audio_close(int line)609 static int oss_mus_audio_close(int line)
610 {
611   return(linux_audio_close(line));
612 }
613 
oss_mus_audio_read(int line,char * buf,int bytes)614 static int oss_mus_audio_read(int line, char *buf, int bytes)
615 {
616   int err;
617   if (line < 0) return(-1);
618   errno = 0;
619   err = read(line, buf, bytes);
620   if (err != bytes)
621     {
622       if (errno != 0)
623 	return_error_exit(MUS_AUDIO_READ_ERROR, -1,
624 			  mus_format("read error: %s", strerror(errno)));
625       else return_error_exit(MUS_AUDIO_READ_ERROR, -1,
626 			     mus_format("read %d bytes of requested %d", err, bytes));
627     }
628   return(MUS_NO_ERROR);
629 }
630 
oss_unsrc(int srcbit)631 static char *oss_unsrc(int srcbit)
632 {
633   if (srcbit == 0)
634     return(mus_strdup("none"));
635   else
636     {
637       bool need_and = false;
638       char *buf;
639       buf = (char *)calloc(PRINT_BUFFER_SIZE, sizeof(char));
640       if (srcbit & SOUND_MASK_MIC) {need_and = true; strcat(buf, "mic");}
641       if (srcbit & SOUND_MASK_LINE) {if (need_and) strcat(buf, " and "); need_and = true; strcat(buf, "line in");}
642       if (srcbit & SOUND_MASK_CD) {if (need_and) strcat(buf, " and "); strcat(buf, "cd");}
643       return(buf);
644     }
645 }
646 
647 
oss_mus_audio_open_input(int ur_dev,int srate,int chans,mus_sample_t samp_type,int requested_size)648 static int oss_mus_audio_open_input(int ur_dev, int srate, int chans, mus_sample_t samp_type, int requested_size)
649 {
650   /* dev can be MUS_AUDIO_DEFAULT or MUS_AUDIO_DUPLEX_DEFAULT as well as the obvious others */
651   int audio_fd = -1, oss_sample_type, buffer_info, sys, dev, srcbit, cursrc, err;
652   char *dev_name;
653 #ifndef NEW_OSS
654   int stereo;
655 #endif
656   sys = MUS_AUDIO_SYSTEM(ur_dev);
657   dev = MUS_AUDIO_DEVICE(ur_dev);
658   oss_sample_type = to_oss_sample_type(samp_type);
659   if (oss_sample_type == MUS_ERROR)
660     return_error_exit(MUS_AUDIO_SAMPLE_TYPE_NOT_AVAILABLE, -1,
661 		      mus_format("sample type %d (%s) not available",
662 				 samp_type,
663 				 mus_sample_type_name(samp_type)));
664 
665   if (((dev == MUS_AUDIO_DEFAULT) || (dev == MUS_AUDIO_DUPLEX_DEFAULT)) && (sys == 0))
666     audio_fd = linux_audio_open(dev_name = dac_name(sys, 0),
667 				O_RDWR, 0, sys);
668   else audio_fd = linux_audio_open(dev_name = dac_name(sys, 0), O_RDONLY, 0, sys);
669   if (audio_fd == -1)
670     {
671       if (dev == MUS_AUDIO_DUPLEX_DEFAULT)
672 	return_error_exit(MUS_AUDIO_CONFIGURATION_NOT_AVAILABLE, -1,
673 		       mus_format("can't open %s: %s",
674 				  dev_name, strerror(errno)));
675       if ((audio_fd = linux_audio_open(dev_name = dac_name(sys, 0), O_RDONLY, 0, sys)) == -1)
676         {
677           if ((errno == EACCES) || (errno == ENOENT))
678 	    return_error_exit(MUS_AUDIO_NO_READ_PERMISSION, -1,
679 			      mus_format("can't open %s: %s\n  to get input in Linux, we need read permission on /dev/dsp",
680 					 dev_name,
681 					 strerror(errno)));
682           else return_error_exit(MUS_AUDIO_NO_INPUT_AVAILABLE, -1,
683 				 mus_format("can't open %s: %s",
684 					    dev_name,
685 					    strerror(errno)));
686         }
687     }
688 #ifdef SNDCTL_DSP_SETDUPLEX
689   else
690     ioctl(audio_fd, SNDCTL_DSP_SETDUPLEX, &err); /* not always a no-op! */
691 #endif
692   /* need to make sure the desired recording source is active -- does this actually have any effect? */
693   switch (dev)
694     {
695     case MUS_AUDIO_MICROPHONE: srcbit = SOUND_MASK_MIC;                   break;
696     case MUS_AUDIO_LINE_IN:    srcbit = SOUND_MASK_LINE;                  break;
697     case MUS_AUDIO_DUPLEX_DEFAULT:
698     case MUS_AUDIO_DEFAULT:    srcbit = SOUND_MASK_LINE | SOUND_MASK_MIC; break;
699     default:                   srcbit = 0;                                break;
700 
701     }
702   ioctl(audio_fd, MIXER_READ(SOUND_MIXER_RECSRC), &cursrc);
703   srcbit = (srcbit | cursrc);
704   ioctl(audio_fd, MIXER_WRITE(SOUND_MIXER_RECSRC), &srcbit);
705   ioctl(audio_fd, MIXER_READ(SOUND_MIXER_RECSRC), &cursrc);
706   if (cursrc != srcbit)
707     {
708       char *str1, *str2;
709       str1 = oss_unsrc(srcbit);
710       str2 = oss_unsrc(cursrc);
711       mus_print("weird: tried to set recorder source to %s, but got %s?", str1, str2);
712       free(str1);
713       free(str2);
714     }
715   if ((fragments_locked) && (requested_size != 0))
716     {
717       buffer_info = (FRAGMENTS << 16) | (FRAGMENT_SIZE);
718       ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &buffer_info);
719     }
720   if ((ioctl(audio_fd, MUS_OSS_SET_FORMAT, &oss_sample_type) == -1) ||
721       (oss_sample_type != to_oss_sample_type(samp_type)))
722     return_error_exit(MUS_AUDIO_SAMPLE_TYPE_NOT_AVAILABLE, audio_fd,
723 		      mus_format("can't set %s sample type to %d (%s)",
724 				 dev_name, samp_type,
725 				 mus_sample_type_name(samp_type)));
726 #ifdef NEW_OSS
727   if (ioctl(audio_fd, MUS_OSS_WRITE_CHANNELS, &chans) == -1)
728     return_error_exit(MUS_AUDIO_CHANNELS_NOT_AVAILABLE, audio_fd,
729 		      mus_format("can't get %d channels on %s",
730 				 chans, dev_name));
731 #else
732   if (chans == 2) stereo = 1; else stereo = 0;
733   if ((ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo) == -1) ||
734       ((chans == 2) && (stereo == 0)))
735     return_error_exit(MUS_AUDIO_CHANNELS_NOT_AVAILABLE, audio_fd,
736 		      mus_format("can't get %d channels on %s",
737 				 chans, dev_name));
738 #endif
739   if (ioctl(audio_fd, MUS_OSS_WRITE_RATE, &srate) == -1)
740     return_error_exit(MUS_AUDIO_SRATE_NOT_AVAILABLE, audio_fd,
741 		      mus_format("can't set srate to %d on %s",
742 				 srate, dev_name));
743   return(audio_fd);
744 }
745 
746 
747 #if (!HAVE_ALSA) && (!HAVE_JACK_IN_LINUX)
oss_sample_types(int ur_dev,mus_sample_t * val)748 static int oss_sample_types(int ur_dev, mus_sample_t *val)
749 {
750   int fd, samp_types = 0, sys, ind;
751 
752   sys = MUS_AUDIO_SYSTEM(ur_dev);
753   /* dev = MUS_AUDIO_DEVICE(ur_dev); */
754 
755   fd = open(dac_name(sys, 0), O_WRONLY, 0);
756   if (fd == -1) fd = open(DAC_NAME, O_WRONLY, 0);
757   if (fd == -1)
758     {
759       return_error_exit(MUS_AUDIO_CANT_OPEN, -1,
760 			mus_format("can't open %s: %s",
761 				   DAC_NAME, strerror(errno)));
762       return(MUS_ERROR);
763     }
764 
765   ioctl(fd, MUS_OSS_GET_FORMATS, &samp_types);
766   ind = 1;
767   if (samp_types & (to_oss_sample_type(MUS_BSHORT)))  val[ind++] = MUS_BSHORT;
768   if (samp_types & (to_oss_sample_type(MUS_LSHORT)))  val[ind++] = MUS_LSHORT;
769   if (samp_types & (to_oss_sample_type(MUS_MULAW)))   val[ind++] = MUS_MULAW;
770   if (samp_types & (to_oss_sample_type(MUS_ALAW)))    val[ind++] = MUS_ALAW;
771   if (samp_types & (to_oss_sample_type(MUS_BYTE)))    val[ind++] = MUS_BYTE;
772   if (samp_types & (to_oss_sample_type(MUS_UBYTE)))   val[ind++] = MUS_UBYTE;
773   if (samp_types & (to_oss_sample_type(MUS_UBSHORT))) val[ind++] = MUS_UBSHORT;
774   if (samp_types & (to_oss_sample_type(MUS_ULSHORT))) val[ind++] = MUS_ULSHORT;
775   val[0] = (mus_sample_t)(ind - 1);
776   return(MUS_NO_ERROR);
777 }
778 #endif
779 
780 
781 
782 
783 /* ------------------------------- ALSA, OSS, Jack-in-Linux ----------------------------------- */
784 
785 static int api = MUS_ALSA_API;
mus_audio_api(void)786 int mus_audio_api(void) {return(api);}
787 
788 /* hopefully first call to sndlib will be this... */
789 static int probe_api(void);
790 static int (*vect_mus_audio_initialize)(void);
791 
792 /* FIXME: add a suitable default for all other vectors
793    so that a call happening before mus_audio_initialize
794    can be detected */
795 /* I don't think this is necessary -- documentation discusses this
796  * (mus_sound_initialize calls mus_audio_initialize)
797  */
798 
799 /* vectors for the rest of the sndlib api */
800 static void  (*vect_mus_oss_set_buffers)(int num, int size);
801 static char* (*vect_mus_audio_moniker)(void);
802 static int   (*vect_mus_audio_open_output)(int ur_dev, int srate, int chans, mus_sample_t samp_type, int size);
803 static int   (*vect_mus_audio_open_input)(int ur_dev, int srate, int chans, mus_sample_t samp_type, int requested_size);
804 static int   (*vect_mus_audio_write)(int id, char *buf, int bytes);
805 static int   (*vect_mus_audio_read)(int id, char *buf, int bytes);
806 static int   (*vect_mus_audio_close)(int id);
807 
808 /* vectors for the rest of the sndlib api */
mus_audio_initialize(void)809 int mus_audio_initialize(void)
810 {
811   return(probe_api());
812 }
813 
mus_oss_set_buffers(int num,int size)814 void mus_oss_set_buffers(int num, int size)
815 {
816   vect_mus_oss_set_buffers(num, size);
817 }
818 
819 #if HAVE_ALSA
820 static char* alsa_mus_audio_moniker(void);
821 #endif
822 
mus_audio_moniker(void)823 char* mus_audio_moniker(void)
824 {
825 #if (HAVE_OSS && HAVE_ALSA)
826   char *both_names;
827   both_names = (char *)calloc(PRINT_BUFFER_SIZE, sizeof(char));
828   /* need to be careful here since these use the same constant buffer */
829   strcpy(both_names, oss_mus_audio_moniker());
830   strcat(both_names, ", ");
831   strcat(both_names, alsa_mus_audio_moniker());
832   return(both_names); /* tiny memory leak ... */
833 #else
834   return(vect_mus_audio_moniker());
835 #endif
836 }
837 
mus_audio_open_output(int ur_dev,int srate,int chans,mus_sample_t samp_type,int size)838 int mus_audio_open_output(int ur_dev, int srate, int chans, mus_sample_t samp_type, int size)
839 {
840   return(vect_mus_audio_open_output(ur_dev, srate, chans, samp_type, size));
841 }
842 
mus_audio_open_input(int ur_dev,int srate,int chans,mus_sample_t samp_type,int requested_size)843 int mus_audio_open_input(int ur_dev, int srate, int chans, mus_sample_t samp_type, int requested_size)
844 {
845   return(vect_mus_audio_open_input(ur_dev, srate, chans, samp_type, requested_size));
846 }
847 
mus_audio_write(int id,char * buf,int bytes)848 int mus_audio_write(int id, char *buf, int bytes)
849 {
850   return(vect_mus_audio_write(id, buf, bytes));
851 }
852 
mus_audio_read(int id,char * buf,int bytes)853 int mus_audio_read(int id, char *buf, int bytes)
854 {
855   return(vect_mus_audio_read(id, buf, bytes));
856 }
857 
mus_audio_close(int id)858 int mus_audio_close(int id)
859 {
860   return(vect_mus_audio_close(id));
861 }
862 
863 #if HAVE_JACK_IN_LINUX
864   static int jack_mus_audio_initialize(void);
865 #endif
866 
867 #if (!HAVE_ALSA)
probe_api(void)868 static int probe_api(void)
869 {
870 #if HAVE_JACK_IN_LINUX
871   {
872     int jackprobe = jack_mus_audio_initialize();
873     if (jackprobe == MUS_ERROR)
874       {
875 #endif
876   /* go for the oss api */
877   api = MUS_OSS_API;
878   vect_mus_audio_initialize = oss_mus_audio_initialize;
879   vect_mus_oss_set_buffers = oss_mus_oss_set_buffers;
880   vect_mus_audio_moniker = oss_mus_audio_moniker;
881   vect_mus_audio_open_output = oss_mus_audio_open_output;
882   vect_mus_audio_open_input = oss_mus_audio_open_input;
883   vect_mus_audio_write = oss_mus_audio_write;
884   vect_mus_audio_read = oss_mus_audio_read;
885   vect_mus_audio_close = oss_mus_audio_close;
886   return(vect_mus_audio_initialize());
887 #if HAVE_JACK_IN_LINUX
888       }
889     return(jackprobe);
890   }
891 #endif
892 }
893 #endif
894 
895 #endif
896 
897 
898 /* ------------------------------- ALSA ----------------------------------------- */
899 /*
900  * Changed the names of the environment variables to use MUS, not SNDLIB.
901  * reformatted and reorganized to be like the rest of the code
902  * changed default device to "default"
903  *    -- Bill 3-Feb-06
904  *
905  * error handling (mus_error) changed by Bill 14-Nov-02
906  * 0.5 support removed by Bill 24-Mar-02
907  *
908  * changed for 0.9.x api by Fernando Lopez-Lezcano <nando@ccrma.stanford.edu>
909  *
910  *  sndlib "exports" only one soundcard with two directions (if they are available),
911  *  and only deals with the alsa library pcm's. It does not scan for available
912  *  cards and devices at the hardware level. Which device it uses can be defined by:
913  *
914  *  - setting variables in the environment (searched for in the following order):
915  *    MUS_ALSA_PLAYBACK_DEVICE
916  *       defines the name of the playback device
917  *    MUS_ALSA_CAPTURE_DEVICE
918  *       defines the name of the capture device
919  *    MUS_ALSA_DEVICE
920  *       defines the name of the playback and capture device
921  *    use the first two if the playback and capture devices are different or the
922  *    third if they are the same.
923  *  - if no variables are found in the environment sndlib tries to probe for a
924  *    default device named "sndlib" (in alsa 0.9 devices are configured in
925  *    /usr/share/alsa/alsa.conf or in ~/.asoundrc)
926  *  - if "sndlib" is not a valid device "hw:0,0" was used [but now it looks for "default"] (which by default should
927  *    point to the first device of the first card
928  *
929  *  Some default settings are controllable through the environment as well:
930  *    MUS_ALSA_BUFFER_SIZE = size of each buffer in frames
931  *    MUS_ALSA_BUFFERS = number of buffers
932  *
933  * changed 18-Sep-00 by Bill: new error handling: old mus_audio_error folded into
934  *  mus_error; mus_error itself should be used only for "real" errors -- things
935  *  that can cause a throw (a kind of global jump elsewhere); use mus_print for informational
936  *  stuff -- in Snd, mus_print will also save everything printed in the error dialog.
937  *  In a few cases, I tried to fix the code to unwind before mus_error, and in others
938  *  I've changed mus_error to mus_print, but some of these may be mistaken.
939  *  Look for ?? below for areas where I'm not sure I rewrote code correctly.
940  *
941  * changed for 0.6.x api by Paul Barton-Davis, pbd@op.net
942  *
943  * changed for 0.5.x api by Fernando Lopez-Lezcano, nando@ccrma.stanford.edu
944  *   04-10-2000:
945  *     based on original 0.4.x code by Paul Barton-Davis (not much left of it :-)
946  *     also Bill's code and Jaroslav Kysela (aplay.c and friends)
947  *
948  * Changes:
949  * 04/25/2000: finished major rework, snd-dac now automatically decides which
950  *             device or devices it uses for playback. Multiple device use is
951  *             for now restricted to only two at most (more changes in Bill's
952  *             needed to be able to support more). Four channel playback in
953  *             Ensoniq AudioPCI and relatives possible (with proper settings
954  *             of the mixer) as well as using two separate cards.
955  * 04/11/2000: added reporting of alsa sound formats
956 */
957 
958 #if HAVE_ALSA
959 
960 #if (!HAVE_OSS)
961 #define AUDIO_OK 1
962 #endif
963 
964 #include <sys/ioctl.h>
965 
966 #if HAVE_ALSA
967   #include <alsa/asoundlib.h>
968 #else
969   #include <sys/asoundlib.h>
970 #endif
971 
972 #if SND_LIB_VERSION < ((0<<16)|(6<<8)|(0))
973   #error ALSA version is too old -- audio.c needs 0.9 or later
974 #endif
975 
976 /* prototypes for the alsa sndlib functions */
977 static int   alsa_mus_audio_initialize(void);
978 static void  alsa_mus_oss_set_buffers(int num, int size);
979 static int   alsa_mus_audio_open_output(int ur_dev, int srate, int chans, mus_sample_t samp_type, int size);
980 static int   alsa_mus_audio_open_input(int ur_dev, int srate, int chans, mus_sample_t samp_type, int requested_size);
981 static int   alsa_mus_audio_write(int id, char *buf, int bytes);
982 static int   alsa_mus_audio_read(int id, char *buf, int bytes);
983 static int   alsa_mus_audio_close(int id);
984 
985 /* decide which api to activate */
986 
probe_api(void)987 static int probe_api(void)
988 {
989 #if HAVE_JACK_IN_LINUX
990   int jackprobe;
991   jackprobe = jack_mus_audio_initialize();
992   if (jackprobe == MUS_ERROR)
993     {
994 #endif
995     int card = -1;
996     if ((snd_card_next(&card) >= 0) && (card >= 0))
997       {
998 	/* the alsa library has detected one or more cards */
999 	api = MUS_ALSA_API;
1000 	vect_mus_audio_initialize = alsa_mus_audio_initialize;
1001 	vect_mus_oss_set_buffers = alsa_mus_oss_set_buffers;
1002 	vect_mus_audio_moniker = alsa_mus_audio_moniker;
1003 	vect_mus_audio_open_output = alsa_mus_audio_open_output;
1004 	vect_mus_audio_open_input = alsa_mus_audio_open_input;
1005 	vect_mus_audio_write = alsa_mus_audio_write;
1006 	vect_mus_audio_read = alsa_mus_audio_read;
1007 	vect_mus_audio_close = alsa_mus_audio_close;
1008       }
1009     else
1010       {
1011 	/* go for the oss api */
1012         api = MUS_OSS_API;
1013 	vect_mus_audio_initialize = oss_mus_audio_initialize;
1014 	vect_mus_oss_set_buffers = oss_mus_oss_set_buffers;
1015 	vect_mus_audio_moniker = oss_mus_audio_moniker;
1016 	vect_mus_audio_open_output = oss_mus_audio_open_output;
1017 	vect_mus_audio_open_input = oss_mus_audio_open_input;
1018 	vect_mus_audio_write = oss_mus_audio_write;
1019 	vect_mus_audio_read = oss_mus_audio_read;
1020 	vect_mus_audio_close = oss_mus_audio_close;
1021       }
1022     /* will the _real_ mus_audio_initialize please stand up? */
1023     return(vect_mus_audio_initialize());
1024 #if HAVE_JACK_IN_LINUX
1025     }
1026   return(jackprobe);
1027 #endif
1028 }
1029 
1030 /* convert a sndlib sample type to an alsa sample type */
1031 
to_alsa_format(mus_sample_t snd_format)1032 static snd_pcm_format_t to_alsa_format(mus_sample_t snd_format)
1033 {
1034   switch (snd_format)
1035     {
1036     case MUS_BYTE:     return(SND_PCM_FORMAT_S8);
1037     case MUS_UBYTE:    return(SND_PCM_FORMAT_U8);
1038     case MUS_MULAW:    return(SND_PCM_FORMAT_MU_LAW);
1039     case MUS_ALAW:     return(SND_PCM_FORMAT_A_LAW);
1040     case MUS_BSHORT:   return(SND_PCM_FORMAT_S16_BE);
1041     case MUS_LSHORT:   return(SND_PCM_FORMAT_S16_LE);
1042     case MUS_UBSHORT:  return(SND_PCM_FORMAT_U16_BE);
1043     case MUS_ULSHORT:  return(SND_PCM_FORMAT_U16_LE);
1044     case MUS_B24INT:   return(SND_PCM_FORMAT_S24_BE);
1045     case MUS_L24INT:   return(SND_PCM_FORMAT_S24_LE);
1046     case MUS_BINT:     return(SND_PCM_FORMAT_S32_BE);
1047     case MUS_LINT:     return(SND_PCM_FORMAT_S32_LE);
1048     case MUS_BINTN:    return(SND_PCM_FORMAT_S32_BE);
1049     case MUS_LINTN:    return(SND_PCM_FORMAT_S32_LE);
1050     case MUS_BFLOAT:   return(SND_PCM_FORMAT_FLOAT_BE);
1051     case MUS_LFLOAT:   return(SND_PCM_FORMAT_FLOAT_LE);
1052     case MUS_BDOUBLE:  return(SND_PCM_FORMAT_FLOAT64_BE);
1053     case MUS_LDOUBLE:  return(SND_PCM_FORMAT_FLOAT64_LE);
1054     default: break;
1055     }
1056   return((snd_pcm_format_t)MUS_ERROR);
1057 }
1058 
1059 /* FIXME: this is not taking yet into account the
1060  * number of bits that a given alsa format is actually
1061  * using...
1062  */
1063 
to_mus_sample_type(int alsa_format)1064 static mus_sample_t to_mus_sample_type(int alsa_format)
1065 {
1066   /* alsa format definitions from asoundlib.h (0.9 cvs 6/27/2001) */
1067   switch (alsa_format)
1068     {
1069     case SND_PCM_FORMAT_S8:         return(MUS_BYTE);
1070     case SND_PCM_FORMAT_U8:         return(MUS_UBYTE);
1071     case SND_PCM_FORMAT_S16_LE:     return(MUS_LSHORT);
1072     case SND_PCM_FORMAT_S16_BE:     return(MUS_BSHORT);
1073     case SND_PCM_FORMAT_U16_LE:     return(MUS_ULSHORT);
1074     case SND_PCM_FORMAT_U16_BE:     return(MUS_UBSHORT);
1075     case SND_PCM_FORMAT_S24_LE:     return(MUS_L24INT);
1076     case SND_PCM_FORMAT_S24_BE:     return(MUS_B24INT);
1077     case SND_PCM_FORMAT_S32_LE:     return(MUS_LINTN); /* 32bit normalized plays 24bit and 16bit files with same amplitude bound (for 24 bit cards) */
1078     case SND_PCM_FORMAT_S32_BE:     return(MUS_BINTN);
1079     case SND_PCM_FORMAT_FLOAT_LE:   return(MUS_LFLOAT);
1080     case SND_PCM_FORMAT_FLOAT_BE:   return(MUS_BFLOAT);
1081     case SND_PCM_FORMAT_FLOAT64_LE: return(MUS_LDOUBLE);
1082     case SND_PCM_FORMAT_FLOAT64_BE: return(MUS_BDOUBLE);
1083     case SND_PCM_FORMAT_MU_LAW:     return(MUS_MULAW);
1084     case SND_PCM_FORMAT_A_LAW:      return(MUS_ALAW);
1085     /* formats with no translation in snd */
1086     case SND_PCM_FORMAT_U24_LE:
1087     case SND_PCM_FORMAT_U24_BE:
1088     case SND_PCM_FORMAT_U32_LE:
1089     case SND_PCM_FORMAT_U32_BE:
1090     case SND_PCM_FORMAT_IEC958_SUBFRAME_LE:
1091     case SND_PCM_FORMAT_IEC958_SUBFRAME_BE:
1092     case SND_PCM_FORMAT_IMA_ADPCM:
1093     case SND_PCM_FORMAT_MPEG:
1094     case SND_PCM_FORMAT_GSM:
1095     case SND_PCM_FORMAT_SPECIAL:
1096     default:
1097       return(MUS_UNKNOWN_SAMPLE);
1098     }
1099 }
1100 
1101 /* convert a sndlib device into an alsa device number and channel
1102  * [has to be coordinated with following function!]
1103  */
1104 
1105 /* very simplistic approach, device mapping should also depend
1106  * on which card we're dealing with, digital i/o devices should
1107  * be identified as such and so on
1108  */
1109 
1110 /* NOTE: in the Delta1010 digital i/o is just a pair of channels
1111  * in the 10 channel playback frame or 12 channel capture frame,
1112  * how do we specify that???
1113  */
1114 
to_alsa_device(int dev,int * adev,snd_pcm_stream_t * achan)1115 static int to_alsa_device(int dev, int *adev, snd_pcm_stream_t *achan)
1116 {
1117   switch (dev)
1118     {
1119       /* default values are a problem because the concept does
1120        * not imply a direction (playback or capture). This works
1121        * fine as long as both directions of a device are symmetric,
1122        * the Midiman 1010, for example, has 10 channel frames for
1123        * playback and 12 channel frames for capture and breaks
1124        * the recorder (probes the default, defaults to output,
1125        * uses the values for input).
1126        */
1127     case MUS_AUDIO_DEFAULT:
1128     case MUS_AUDIO_DUPLEX_DEFAULT:
1129     case MUS_AUDIO_LINE_OUT:
1130       /* analog output */
1131       (*adev) = 0;
1132       (*achan) = SND_PCM_STREAM_PLAYBACK;
1133       break;
1134 
1135     case MUS_AUDIO_AUX_OUTPUT:
1136       /* extra analog output */
1137       (*adev) = 1;
1138       (*achan) = SND_PCM_STREAM_PLAYBACK;
1139       break;
1140 
1141     case MUS_AUDIO_DAC_OUT:
1142       /* analog outputs */
1143       (*adev) = 2;
1144       (*achan) = SND_PCM_STREAM_PLAYBACK;
1145       break;
1146 
1147     case MUS_AUDIO_MICROPHONE:
1148     case MUS_AUDIO_LINE_IN:
1149       /* analog input */
1150       (*adev) = 0;
1151       (*achan) = SND_PCM_STREAM_CAPTURE;
1152       break;
1153 
1154     default:
1155       return(MUS_ERROR);
1156       break;
1157     }
1158   return(0);
1159 }
1160 
1161 /* convert an alsa device into a sndlib device
1162  * [has to be coordinated with previous function!]
1163  *
1164  * naming here is pretty much arbitrary. We have to have
1165  * a bidirectional mapping between sndlib devices and
1166  * alsa devices and that's just not possible (I think).
1167  * This stopgap mapping ignores digital input and output
1168  * devices - how to differentiate them in alsa?
1169  */
1170 
to_sndlib_device(int dev,int channel)1171 static int to_sndlib_device(int dev, int channel)
1172 {
1173   switch (channel)
1174     {
1175     case SND_PCM_STREAM_PLAYBACK:
1176       switch (dev)
1177 	{
1178 	  /* works only for the first three outputs */
1179 	case 0: return(MUS_AUDIO_LINE_OUT);
1180 	case 1: return(MUS_AUDIO_AUX_OUTPUT);
1181 	case 2: return(MUS_AUDIO_DAC_OUT);
1182 	default:
1183 	  return(MUS_ERROR);
1184 	}
1185     case SND_PCM_STREAM_CAPTURE:
1186       switch (dev)
1187 	{
1188 	case 0: return(MUS_AUDIO_LINE_IN);
1189 	default:
1190 	  return(MUS_ERROR);
1191 	}
1192       break;
1193     }
1194   return(MUS_ERROR);
1195 }
1196 
1197 
alsa_mus_error(int type,char * message)1198 static int alsa_mus_error(int type, char *message)
1199 {
1200   if (message)
1201     {
1202       mus_print("%s", message);
1203       free(message);
1204     }
1205   return(MUS_ERROR);
1206 }
1207 
1208 
1209 /* dump current hardware and software configuration */
1210 
alsa_dump_configuration(char * name,snd_pcm_hw_params_t * hw_params,snd_pcm_sw_params_t * sw_params)1211 static void alsa_dump_configuration(char *name, snd_pcm_hw_params_t *hw_params, snd_pcm_sw_params_t *sw_params)
1212 {
1213   int err;
1214   char *str;
1215   snd_output_t *buf;
1216 
1217 #if (SND_LIB_MAJOR == 0) || ((SND_LIB_MAJOR == 1) && (SND_LIB_MINOR == 0) && (SND_LIB_SUBMINOR < 8))
1218   return; /* avoid Alsa bug */
1219 #endif
1220 
1221   err = snd_output_buffer_open(&buf);
1222   if (err < 0)
1223     mus_print("could not open dump buffer: %s", snd_strerror(err));
1224   else
1225     {
1226       size_t len;
1227       if (hw_params)
1228 	{
1229 	  snd_output_puts(buf, "hw_params status of ");
1230 	  snd_output_puts(buf, name);
1231 	  snd_output_puts(buf, "\n");
1232 	  err = snd_pcm_hw_params_dump(hw_params, buf);
1233 	  if (err < 0)
1234 	    mus_print("snd_pcm_hw_params_dump: %s", snd_strerror(err));
1235 	}
1236       if (sw_params)
1237 	{
1238 	  snd_output_puts(buf, "sw_params status of ");
1239 	  snd_output_puts(buf, name);
1240 	  snd_output_puts(buf, "\n");
1241 	  err = snd_pcm_sw_params_dump(sw_params, buf);
1242 	  if (err < 0)
1243 	    mus_print("snd_pcm_hw_params_dump: %s", snd_strerror(err));
1244 	}
1245       snd_output_putc(buf, '\0');
1246       len = snd_output_buffer_string(buf, &str);
1247       if (len > 1)
1248 	mus_print("status of %s\n%s", name, str);
1249       snd_output_close(buf);
1250     }
1251 }
1252 
1253 /* get hardware params for a pcm */
1254 
alsa_get_hardware_params(const char * name,snd_pcm_stream_t stream,int mode)1255 static snd_pcm_hw_params_t *alsa_get_hardware_params(const char *name, snd_pcm_stream_t stream, int mode)
1256 {
1257   int err;
1258   snd_pcm_t *handle;
1259   if ((err = snd_pcm_open(&handle, name, stream, mode | SND_PCM_NONBLOCK)) != 0)
1260     {
1261       alsa_mus_error(MUS_AUDIO_CANT_OPEN,
1262 		     mus_format("open pcm %s for stream %d: %s",
1263 				name, stream, snd_strerror(err)));
1264       return(NULL);
1265     }
1266   else
1267     {
1268       snd_pcm_hw_params_t *params;
1269       params = (snd_pcm_hw_params_t *)calloc(1, snd_pcm_hw_params_sizeof());
1270       if (!params)
1271 	{
1272 	  snd_pcm_close(handle);
1273 	  alsa_mus_error(MUS_AUDIO_CONFIGURATION_NOT_AVAILABLE,
1274 			 mus_format("could not allocate memory for hardware params"));
1275 	}
1276       else
1277 	{
1278 	  err = snd_pcm_hw_params_any(handle, params);
1279 	  if (err < 0)
1280 	    {
1281 	      snd_pcm_close(handle);
1282 	      alsa_mus_error(MUS_AUDIO_CONFIGURATION_NOT_AVAILABLE,
1283 			     mus_format("snd_pcm_hw_params_any: pcm %s, stream %d, error: %s",
1284 					name, stream, snd_strerror(err)));
1285 	    }
1286 	  else
1287 	    {
1288 	      snd_pcm_close(handle);
1289 	      return(params);
1290 	    }
1291 	}
1292     }
1293   return(NULL);
1294 }
1295 
1296 /* allocate software params structure */
1297 
alsa_get_software_params(void)1298 static snd_pcm_sw_params_t *alsa_get_software_params(void)
1299 {
1300   snd_pcm_sw_params_t *params = NULL;
1301   params = (snd_pcm_sw_params_t *)calloc(1, snd_pcm_sw_params_sizeof());
1302   if (!params)
1303     {
1304       alsa_mus_error(MUS_AUDIO_CONFIGURATION_NOT_AVAILABLE,
1305 		     mus_format("could not allocate memory for software params"));
1306     }
1307   return(params);
1308 }
1309 
1310 /* probe a device name against the list of available pcm devices */
1311 
alsa_probe_device_name(const char * name)1312 static bool alsa_probe_device_name(const char *name)
1313 {
1314   snd_config_t *conf;
1315   snd_config_iterator_t pos, next;
1316   int err;
1317 
1318   err = snd_config_update();
1319   if (err < 0)
1320     {
1321       mus_print("snd_config_update: %s", snd_strerror(err));
1322       return(false);
1323     }
1324 
1325   err = snd_config_search(snd_config, "pcm", &conf);
1326   if (err < 0)
1327     {
1328       mus_print("snd_config_search: %s", snd_strerror(err));
1329       return(false);
1330     }
1331 
1332   snd_config_for_each(pos, next, conf)
1333     {
1334       snd_config_t *c = snd_config_iterator_entry(pos);
1335       const char *id;
1336       int err = snd_config_get_id(c, &id);
1337       if (err == 0) {
1338 	int result = strncmp(name, id, strlen(id));
1339 	if (result == 0 &&
1340 	    (name[strlen(id)] == '\0' || name[strlen(id)] == ':'))
1341 	  {
1342 	    return(true);
1343 	  }
1344       }
1345     }
1346   return(false);
1347 }
1348 
1349 /* check a device name against the list of available pcm devices */
1350 
alsa_check_device_name(const char * name)1351 static int alsa_check_device_name(const char *name)
1352 {
1353   if (!alsa_probe_device_name(name))
1354     {
1355       return(alsa_mus_error(MUS_AUDIO_CANT_READ,
1356 			    mus_format("alsa could not find device \"%s\" in configuration",
1357 				       name)));
1358     }
1359   return(MUS_NO_ERROR);
1360 }
1361 
1362 
1363 /* set scheduling priority to SCHED_FIFO
1364  * this will only work if the program that uses sndlib is run as root or is suid root
1365  */
1366 
1367 /* whether we want to trace calls
1368  *
1369  * set to "1" to print function trace information in the
1370  * snd error window
1371  */
1372 
1373 static int alsa_trace = 0;
1374 
1375 /* this should go away as it is oss specific */
1376 
1377 static int fragment_size = 512;
1378 static int fragments = 4;
1379 
alsa_mus_oss_set_buffers(int num,int size)1380 static void alsa_mus_oss_set_buffers(int num, int size)
1381 {
1382   fragments = num;
1383   fragment_size = size;
1384 }
1385 
1386 /* total number of soundcards in our setup, set by initialize_audio */
1387 
1388 /* static int sound_cards = 0; */
1389 
1390 /* return the number of cards that are available */
1391 
1392 /* return the type of driver we're dealing with */
1393 
alsa_mus_audio_moniker(void)1394 static char *alsa_mus_audio_moniker(void)
1395 {
1396   if (!version_name) version_name = (char *)calloc(LABEL_BUFFER_SIZE, sizeof(char));
1397   snprintf(version_name, LABEL_BUFFER_SIZE, "ALSA %s", SND_LIB_VERSION_STR);
1398   return(version_name);
1399 }
1400 
1401 /* handles for both directions of the virtual device */
1402 
1403 static snd_pcm_t *handles[2] = {NULL, NULL};
1404 
1405 /* hardware and software parameter sctructure pointers */
1406 
1407 static snd_pcm_hw_params_t *alsa_hw_params[2] = {NULL, NULL}; /* avoid bogus free */
1408 static snd_pcm_sw_params_t *alsa_sw_params[2] = {NULL, NULL};
1409 
1410 /* some defaults */
1411 
1412 static int alsa_open_mode = SND_PCM_ASYNC;
1413 static int alsa_buffers = 3;
1414 /* size of buffer in number of samples per channel,
1415  * at 44100 approximately 5.9mSecs
1416  */
1417 static int alsa_samples_per_channel = 1024;
1418 static snd_pcm_access_t alsa_interleave = SND_PCM_ACCESS_RW_INTERLEAVED;
1419 static int alsa_max_capture_channels = 32;
1420 
1421 /* first default name for pcm configuration */
1422 
1423 static char *alsa_sndlib_device_name = (char *)"sndlib";
1424 
1425 /* second default for playback and capture: hardware pcm, first card, first device */
1426 /* pcms used by sndlib, playback and capture */
1427 
1428 static char *alsa_playback_device_name = NULL;
1429 static char *alsa_capture_device_name = NULL;
1430 
1431 
1432 
1433 /* -------- tie these names into scheme/ruby -------- */
1434 
alsa_get_max_buffers(void)1435 static int alsa_get_max_buffers(void)
1436 {
1437   uint32_t max_periods = 0, max_rec_periods = 0;
1438   int dir = 0;
1439 
1440   if (alsa_hw_params[SND_PCM_STREAM_PLAYBACK])
1441     snd_pcm_hw_params_get_periods_max(alsa_hw_params[SND_PCM_STREAM_PLAYBACK], &max_periods, &dir);
1442 
1443   if (alsa_hw_params[SND_PCM_STREAM_CAPTURE])
1444     {
1445       snd_pcm_hw_params_get_periods_max(alsa_hw_params[SND_PCM_STREAM_CAPTURE], &max_rec_periods, &dir);
1446 
1447       if (max_periods > max_rec_periods)
1448 	max_periods = max_rec_periods;
1449     }
1450   return(max_periods);
1451 }
1452 
alsa_get_min_buffers(void)1453 static int alsa_get_min_buffers(void)
1454 {
1455   uint32_t min_periods = 0, min_rec_periods = 0;
1456   int dir = 0;
1457   if (alsa_hw_params[SND_PCM_STREAM_PLAYBACK])
1458     snd_pcm_hw_params_get_periods_min(alsa_hw_params[SND_PCM_STREAM_PLAYBACK], &min_periods, &dir);
1459 
1460   if (alsa_hw_params[SND_PCM_STREAM_CAPTURE])
1461     {
1462       snd_pcm_hw_params_get_periods_min(alsa_hw_params[SND_PCM_STREAM_CAPTURE], &min_rec_periods, &dir);
1463 
1464       if (min_periods < min_rec_periods)
1465 	min_periods = min_rec_periods;
1466     }
1467   return(min_periods);
1468 }
1469 
alsa_clamp_buffers(int bufs)1470 static int alsa_clamp_buffers(int bufs)
1471 {
1472   int minb, maxb;
1473   minb = alsa_get_min_buffers();
1474   maxb = alsa_get_max_buffers();
1475   if (bufs > maxb)
1476     bufs = maxb;
1477   if (bufs < minb)
1478     bufs = minb;
1479   return(bufs);
1480 }
1481 
alsa_get_min_buffer_size(void)1482 static snd_pcm_uframes_t alsa_get_min_buffer_size(void)
1483 {
1484   snd_pcm_uframes_t min_buffer_size = 0, min_rec_buffer_size = 0;
1485   if (alsa_hw_params[SND_PCM_STREAM_PLAYBACK])
1486     snd_pcm_hw_params_get_buffer_size_min(alsa_hw_params[SND_PCM_STREAM_PLAYBACK], &min_buffer_size);
1487 
1488   if (alsa_hw_params[SND_PCM_STREAM_CAPTURE])
1489     {
1490       snd_pcm_hw_params_get_buffer_size_min(alsa_hw_params[SND_PCM_STREAM_CAPTURE], &min_rec_buffer_size);
1491       if (min_buffer_size < min_rec_buffer_size)
1492 	min_buffer_size = min_rec_buffer_size;
1493     }
1494   return(min_buffer_size);
1495 }
1496 
alsa_get_max_buffer_size(void)1497 static snd_pcm_uframes_t alsa_get_max_buffer_size(void)
1498 {
1499   snd_pcm_uframes_t max_buffer_size = 0, max_rec_buffer_size = 0;
1500   if (alsa_hw_params[SND_PCM_STREAM_PLAYBACK])
1501     snd_pcm_hw_params_get_buffer_size_max(alsa_hw_params[SND_PCM_STREAM_PLAYBACK], &max_buffer_size);
1502 
1503   if (alsa_hw_params[SND_PCM_STREAM_CAPTURE])
1504     {
1505       snd_pcm_hw_params_get_buffer_size_max(alsa_hw_params[SND_PCM_STREAM_CAPTURE], &max_rec_buffer_size);
1506       if (max_buffer_size > max_rec_buffer_size)
1507 	max_buffer_size = max_rec_buffer_size;
1508     }
1509   return(max_buffer_size);
1510 }
1511 
alsa_clamp_buffer_size(snd_pcm_uframes_t buf_size)1512 static snd_pcm_uframes_t alsa_clamp_buffer_size(snd_pcm_uframes_t buf_size)
1513 {
1514   snd_pcm_uframes_t minb, maxb;
1515   minb = alsa_get_min_buffer_size();
1516   maxb = alsa_get_max_buffer_size();
1517   if (buf_size > maxb)
1518     buf_size = maxb;
1519   if (buf_size < minb)
1520     buf_size = minb;
1521   return(buf_size);
1522 }
1523 
alsa_set_playback_parameters(void)1524 static bool alsa_set_playback_parameters(void)
1525 {
1526   /* playback stream parameters */
1527   if (alsa_hw_params[SND_PCM_STREAM_PLAYBACK]) free(alsa_hw_params[SND_PCM_STREAM_PLAYBACK]);
1528   alsa_hw_params[SND_PCM_STREAM_PLAYBACK] = alsa_get_hardware_params(alsa_playback_device_name, SND_PCM_STREAM_PLAYBACK, alsa_open_mode);
1529   if (alsa_hw_params[SND_PCM_STREAM_PLAYBACK])
1530     {
1531       snd_pcm_uframes_t size;
1532       int old_buffers;
1533       old_buffers = alsa_buffers;
1534       if (alsa_sw_params[SND_PCM_STREAM_PLAYBACK]) free(alsa_sw_params[SND_PCM_STREAM_PLAYBACK]);
1535       alsa_sw_params[SND_PCM_STREAM_PLAYBACK] = alsa_get_software_params();
1536       sound_cards = 1;
1537       alsa_buffers = alsa_clamp_buffers(alsa_buffers);
1538       if (alsa_buffers <= 0)
1539 	{
1540 	  alsa_buffers = old_buffers;
1541 	  return(false);
1542 	}
1543       size = alsa_clamp_buffer_size((snd_pcm_uframes_t)(alsa_samples_per_channel * alsa_buffers));
1544       if (size <= 0) return(false);
1545       alsa_samples_per_channel = size / alsa_buffers;
1546     }
1547   return(alsa_hw_params[SND_PCM_STREAM_PLAYBACK] && alsa_sw_params[SND_PCM_STREAM_PLAYBACK]);
1548 }
1549 
alsa_set_capture_parameters(void)1550 static bool alsa_set_capture_parameters(void)
1551 {
1552   /* capture stream parameters */
1553   if (alsa_hw_params[SND_PCM_STREAM_CAPTURE]) free(alsa_hw_params[SND_PCM_STREAM_CAPTURE]);
1554   alsa_hw_params[SND_PCM_STREAM_CAPTURE] = alsa_get_hardware_params(alsa_capture_device_name, SND_PCM_STREAM_CAPTURE, alsa_open_mode);
1555   if (alsa_hw_params[SND_PCM_STREAM_CAPTURE])
1556     {
1557       snd_pcm_uframes_t size;
1558       int old_buffers;
1559       old_buffers = alsa_buffers;
1560       if (alsa_sw_params[SND_PCM_STREAM_CAPTURE]) free(alsa_sw_params[SND_PCM_STREAM_CAPTURE]);
1561       alsa_sw_params[SND_PCM_STREAM_CAPTURE] = alsa_get_software_params();
1562       sound_cards = 1;
1563       alsa_buffers = alsa_clamp_buffers(alsa_buffers);
1564       if (alsa_buffers <= 0)
1565 	{
1566 	  alsa_buffers = old_buffers;
1567 	  return(false);
1568 	}
1569       size = alsa_clamp_buffer_size((snd_pcm_uframes_t)(alsa_samples_per_channel * alsa_buffers));
1570       if (size <= 0) return(false);
1571       alsa_samples_per_channel = size / alsa_buffers;
1572     }
1573   return(alsa_hw_params[SND_PCM_STREAM_CAPTURE] && alsa_sw_params[SND_PCM_STREAM_CAPTURE]);
1574 }
1575 
1576 
mus_alsa_playback_device(void)1577 char *mus_alsa_playback_device(void) {return(alsa_playback_device_name);}
mus_alsa_set_playback_device(const char * name)1578 char *mus_alsa_set_playback_device(const char *name)
1579 {
1580   if (alsa_check_device_name(name) == MUS_NO_ERROR)
1581     {
1582       char *old_name = alsa_playback_device_name;
1583       alsa_playback_device_name = mus_strdup(name);
1584       if (!alsa_set_playback_parameters())
1585 	{
1586 	  alsa_playback_device_name = old_name; /* try to back out of the mistake */
1587 	  alsa_set_playback_parameters();
1588 	}
1589     }
1590   return(alsa_playback_device_name);
1591 }
1592 
mus_alsa_capture_device(void)1593 char *mus_alsa_capture_device(void) {return(alsa_capture_device_name);}
mus_alsa_set_capture_device(const char * name)1594 char *mus_alsa_set_capture_device(const char *name)
1595 {
1596   if (alsa_check_device_name(name) == MUS_NO_ERROR)
1597     {
1598       char *old_name = alsa_capture_device_name;
1599       alsa_capture_device_name = mus_strdup(name);
1600       if (!alsa_set_capture_parameters())
1601 	{
1602 	  alsa_capture_device_name = old_name;
1603 	  alsa_set_capture_parameters();
1604 	}
1605     }
1606   return(alsa_capture_device_name);
1607 }
1608 
mus_alsa_device(void)1609 char *mus_alsa_device(void) {return(alsa_sndlib_device_name);}
mus_alsa_set_device(const char * name)1610 char *mus_alsa_set_device(const char *name)
1611 {
1612   if (alsa_check_device_name(name) == MUS_NO_ERROR)
1613     {
1614       alsa_sndlib_device_name = mus_strdup(name);
1615       mus_alsa_set_playback_device(name);
1616       mus_alsa_set_capture_device(name);
1617     }
1618   return(alsa_sndlib_device_name);
1619 }
1620 
mus_alsa_buffer_size(void)1621 int mus_alsa_buffer_size(void) {return(alsa_samples_per_channel);}
mus_alsa_set_buffer_size(int size)1622 int mus_alsa_set_buffer_size(int size)
1623 {
1624   snd_pcm_uframes_t bsize;
1625   if (alsa_buffers == 0) alsa_buffers = 1;
1626   if (size > 0)
1627     {
1628       bsize = alsa_clamp_buffer_size((snd_pcm_uframes_t)(size * alsa_buffers));
1629       alsa_samples_per_channel = bsize / alsa_buffers;
1630     }
1631   return(alsa_samples_per_channel);
1632 }
1633 
mus_alsa_buffers(void)1634 int mus_alsa_buffers(void) {return(alsa_buffers);}
mus_alsa_set_buffers(int num)1635 int mus_alsa_set_buffers(int num)
1636 {
1637   snd_pcm_uframes_t size;
1638   if (num > 0)
1639     {
1640       alsa_buffers = alsa_clamp_buffers(num);
1641       if (alsa_buffers > 0)
1642 	{
1643 	  size = alsa_clamp_buffer_size((snd_pcm_uframes_t)(alsa_samples_per_channel * alsa_buffers));
1644 	  alsa_samples_per_channel = size / alsa_buffers;
1645 	}
1646     }
1647   return(alsa_buffers);
1648 }
1649 
1650 static bool alsa_squelch_warning = false;
mus_alsa_squelch_warning(void)1651 bool mus_alsa_squelch_warning(void) {return(alsa_squelch_warning);}
mus_alsa_set_squelch_warning(bool val)1652 bool mus_alsa_set_squelch_warning(bool val)
1653 {
1654   alsa_squelch_warning = val;
1655   return(val);
1656 }
1657 
1658 
1659 
1660 
1661 /* get a device name from the environment */
1662 
alsa_get_device_from_env(const char * name)1663 static char *alsa_get_device_from_env(const char *name)
1664 {
1665   char *string = getenv(name);
1666   if (string)
1667     if (alsa_check_device_name(string) == MUS_NO_ERROR)
1668       return(string);
1669   return(NULL);
1670 }
1671 
1672 /* get an integer from the environment */
1673 
alsa_get_int_from_env(const char * name,int * value,int min,int max)1674 static int alsa_get_int_from_env(const char *name, int *value, int min, int max)
1675 {
1676   char *string = getenv(name);
1677   if (string)
1678     {
1679       char *end;
1680       long int result = strtol(string, &end, 10);
1681       if (((min != -1) && (max != -1)) &&
1682 	  (result < min || result > max))
1683 	{
1684 	  return(alsa_mus_error(MUS_AUDIO_CANT_READ,
1685 				mus_format("%s ignored: out of range, value=%d, min=%d, max=%d",
1686 					   name, (int)result, min, max)));
1687 	}
1688       else
1689 	{
1690 	  if (errno == ERANGE)
1691 	    {
1692 	      return(alsa_mus_error(MUS_AUDIO_CANT_READ,
1693 				    mus_format("%s ignored: strlol conversion out of range",
1694 					       name)));
1695 	    }
1696 	  else
1697 	    {
1698 	      if ((*string != '\0') && (*end == '\0'))
1699 		{
1700 		  *value = (int)result;
1701 		  return(MUS_NO_ERROR);
1702 		}
1703 	      else
1704 		{
1705 		  return(alsa_mus_error(MUS_AUDIO_CANT_READ,
1706 					mus_format("%s ignored: value is \"%s\", not an integer",
1707 						   name, string)));
1708 		}
1709 	    }
1710 	}
1711     }
1712   return(MUS_ERROR);
1713 }
1714 
1715 /* initialize the audio subsystem */
1716 
1717 /* define environment variable names */
1718 #define MUS_ALSA_PLAYBACK_DEVICE_ENV_NAME "MUS_ALSA_PLAYBACK_DEVICE"
1719 #define MUS_ALSA_CAPTURE_DEVICE_ENV_NAME  "MUS_ALSA_CAPTURE_DEVICE"
1720 #define MUS_ALSA_DEVICE_ENV_NAME          "MUS_ALSA_DEVICE"
1721 #define MUS_ALSA_BUFFERS_ENV_NAME         "MUS_ALSA_BUFFERS"
1722 #define MUS_ALSA_BUFFER_SIZE_ENV_NAME     "MUS_ALSA_BUFFER_SIZE"
1723 #define MUS_ALSA_TRACE_ENV_NAME           "MUS_ALSA_TRACE"
1724 
alsa_mus_audio_initialize(void)1725 static int alsa_mus_audio_initialize(void)
1726 {
1727   char *name = NULL;
1728   char *pname;
1729   char *cname;
1730   int value = 0, alsa_buffer_size = 0;
1731 
1732   if (audio_initialized)
1733     return(0);
1734 
1735   sound_cards = 0;
1736 
1737   /* get trace flag from environment */
1738   if (alsa_get_int_from_env(MUS_ALSA_TRACE_ENV_NAME, &value, 0, 1) == MUS_NO_ERROR)
1739     alsa_trace = value;
1740 
1741   /* try to get device names from environment */
1742   pname = alsa_get_device_from_env(MUS_ALSA_PLAYBACK_DEVICE_ENV_NAME);
1743   if ((pname) && (alsa_probe_device_name(pname)))
1744     alsa_playback_device_name = pname;
1745 
1746   cname = alsa_get_device_from_env(MUS_ALSA_CAPTURE_DEVICE_ENV_NAME);
1747   if ((cname) && (alsa_probe_device_name(cname)))
1748     alsa_capture_device_name = cname;
1749 
1750   name = alsa_get_device_from_env(MUS_ALSA_DEVICE_ENV_NAME);
1751   if ((name) && (alsa_probe_device_name(name)))
1752     {
1753       if (!alsa_playback_device_name)
1754 	alsa_playback_device_name = name;
1755 
1756       if (!alsa_capture_device_name)
1757 	alsa_capture_device_name = name;
1758 
1759       alsa_sndlib_device_name = name;
1760     }
1761 
1762   /* now check that we have a plausible name */
1763   if (!alsa_probe_device_name(alsa_sndlib_device_name))
1764     {
1765       alsa_sndlib_device_name = (char *)"default";
1766       if (!alsa_probe_device_name(alsa_sndlib_device_name))
1767 	{
1768 	  alsa_sndlib_device_name = (char *)"plughw:0";
1769 	  if (!alsa_probe_device_name(alsa_sndlib_device_name))
1770 	    alsa_sndlib_device_name = (char *)"hw:0";
1771 	}
1772     }
1773 
1774   /* if no device name set yet, try for special sndlib name first */
1775   if (!alsa_playback_device_name)
1776     {
1777       if (alsa_probe_device_name(alsa_sndlib_device_name))
1778 	alsa_playback_device_name = alsa_sndlib_device_name;
1779       else alsa_playback_device_name = (char *)"hw:0";
1780     }
1781 
1782   if (!alsa_capture_device_name)
1783     {
1784       if (alsa_probe_device_name(alsa_sndlib_device_name))
1785 	alsa_capture_device_name = alsa_sndlib_device_name;
1786       else alsa_capture_device_name = (char *)"hw:0";
1787     }
1788 
1789   alsa_get_int_from_env(MUS_ALSA_BUFFERS_ENV_NAME, &alsa_buffers, -1, -1);
1790   alsa_get_int_from_env(MUS_ALSA_BUFFER_SIZE_ENV_NAME, &alsa_buffer_size, -1, -1);
1791 
1792   if ((alsa_buffer_size > 0) && (alsa_buffers > 0))
1793     alsa_samples_per_channel = alsa_buffer_size / alsa_buffers;
1794 
1795   if (!alsa_set_playback_parameters())
1796     {
1797       /* somehow we got a device that passed muster with alsa_probe_device_name, but doesn't return hw params! */
1798       alsa_playback_device_name = (char *)"plughw:0";
1799       if (!alsa_set_playback_parameters())
1800 	{
1801 	  alsa_playback_device_name = (char *)"hw:0";
1802 	  if (!alsa_set_playback_parameters())
1803 	    return(MUS_ERROR);
1804 	}
1805     }
1806 
1807   if (!alsa_set_capture_parameters())
1808     {
1809       alsa_capture_device_name = (char *)"plughw:0";
1810       if (!alsa_set_capture_parameters())
1811 	{
1812 	  alsa_capture_device_name = (char *)"hw:0";
1813 	  if (!alsa_set_capture_parameters())
1814 	    return(MUS_ERROR);
1815 	}
1816     }
1817 
1818   if ((!alsa_hw_params[SND_PCM_STREAM_CAPTURE]) ||
1819       (!alsa_hw_params[SND_PCM_STREAM_PLAYBACK]))
1820     return(MUS_ERROR);
1821 
1822   audio_initialized = true;
1823   return(0);
1824 }
1825 
1826 /* open an input or output stream */
1827 
alsa_audio_open(int ur_dev,int srate,int chans,mus_sample_t samp_type,int size)1828 static int alsa_audio_open(int ur_dev, int srate, int chans, mus_sample_t samp_type, int size)
1829 {
1830   int device, alsa_device;
1831   snd_pcm_format_t alsa_format;
1832   snd_pcm_stream_t alsa_stream;
1833   char *alsa_name;
1834   int frames, periods;
1835   int err;
1836   snd_pcm_t *handle;
1837   snd_pcm_hw_params_t *hw_params = NULL;
1838   snd_pcm_sw_params_t *sw_params = NULL;
1839 
1840   if ((!audio_initialized) &&
1841       (mus_audio_initialize() != MUS_NO_ERROR))
1842     return(MUS_ERROR);
1843   if (chans <= 0) return(MUS_ERROR);
1844 
1845   if (alsa_trace)
1846     mus_print("%s: %x rate=%d, chans=%d, format=%d:%s, size=%d",
1847 	      __func__, ur_dev, srate, chans, samp_type,
1848 	      mus_sample_type_to_string(samp_type), size);
1849 
1850   /* card = MUS_AUDIO_SYSTEM(ur_dev); */
1851   device = MUS_AUDIO_DEVICE(ur_dev);
1852 
1853   if ((err = to_alsa_device(device, &alsa_device, &alsa_stream)) < 0)
1854     {
1855       return(alsa_mus_error(MUS_AUDIO_DEVICE_NOT_AVAILABLE,
1856 			    mus_format("%s: cannot translate device %d to alsa",
1857 				       snd_strerror(err), device)));
1858     }
1859   if ((alsa_format = to_alsa_format(samp_type)) == (snd_pcm_format_t)MUS_ERROR)
1860     {
1861       return(alsa_mus_error(MUS_AUDIO_SAMPLE_TYPE_NOT_AVAILABLE,
1862 			    mus_format("could not change %s<%d> to alsa format",
1863 				       mus_sample_type_to_string(samp_type), samp_type)));
1864     }
1865 
1866   alsa_name = (alsa_stream == SND_PCM_STREAM_PLAYBACK) ? alsa_playback_device_name : alsa_capture_device_name;
1867   if ((err = snd_pcm_open(&handle, alsa_name, alsa_stream, alsa_open_mode)) != 0)
1868     {
1869       /* snd_pcm_close(handle); */
1870       /* this segfaults in some versions of ALSA */
1871       return(alsa_mus_error(MUS_AUDIO_CANT_OPEN,
1872 			    mus_format("open pcm %s stream %s: %s",
1873 				       alsa_name, snd_pcm_stream_name(alsa_stream),
1874 				       snd_strerror(err))));
1875     }
1876   handles[alsa_stream] = handle;
1877   hw_params = alsa_hw_params[alsa_stream];
1878   sw_params = alsa_sw_params[alsa_stream];
1879   if ((err = snd_pcm_hw_params_any(handle, hw_params)) < 0)
1880     {
1881       snd_pcm_close(handle);
1882       handles[alsa_stream] = NULL;
1883       alsa_dump_configuration(alsa_name, hw_params, sw_params);
1884       return(alsa_mus_error(MUS_AUDIO_CONFIGURATION_NOT_AVAILABLE,
1885 			    mus_format("%s: no parameter configurations available for %s",
1886 				       snd_strerror(err), alsa_name)));
1887     }
1888 
1889   err = snd_pcm_hw_params_set_access(handle, hw_params, alsa_interleave);
1890   if (err < 0)
1891     {
1892       snd_pcm_close(handle);
1893       handles[alsa_stream] = NULL;
1894       alsa_dump_configuration(alsa_name, hw_params, sw_params);
1895       return(alsa_mus_error(MUS_AUDIO_CONFIGURATION_NOT_AVAILABLE,
1896 			    mus_format("%s: %s: access type %s not available",
1897 				       snd_strerror(err), alsa_name, snd_pcm_access_name(alsa_interleave))));
1898     }
1899 
1900   periods = alsa_buffers;
1901   err = snd_pcm_hw_params_set_periods(handle, hw_params, periods, 0);
1902   if (err < 0)
1903     {
1904       uint32_t minp, maxp;
1905       int dir;
1906       snd_pcm_hw_params_get_periods_min(hw_params, &minp, &dir);
1907       snd_pcm_hw_params_get_periods_max(hw_params, &maxp, &dir);
1908       snd_pcm_close(handle);
1909       handles[alsa_stream] = NULL;
1910       alsa_dump_configuration(alsa_name, hw_params, sw_params);
1911       return(alsa_mus_error(MUS_AUDIO_CONFIGURATION_NOT_AVAILABLE,
1912 			    mus_format("%s: %s: cannot set number of periods to %d, min is %d, max is %d",
1913 				       snd_strerror(err), alsa_name, periods, (int)minp, (int)maxp)));
1914     }
1915 
1916   frames = size / chans / mus_bytes_per_sample(samp_type);
1917 
1918   err = snd_pcm_hw_params_set_buffer_size(handle, hw_params, frames * periods);
1919   if (err < 0)
1920     {
1921       snd_pcm_uframes_t minp, maxp;
1922       snd_pcm_hw_params_get_buffer_size_min(hw_params, &minp);
1923       snd_pcm_hw_params_get_buffer_size_max(hw_params, &maxp);
1924       snd_pcm_close(handle);
1925       handles[alsa_stream] = NULL;
1926       alsa_dump_configuration(alsa_name, hw_params, sw_params);
1927       return(alsa_mus_error(MUS_AUDIO_CONFIGURATION_NOT_AVAILABLE,
1928 			    mus_format("%s: %s: cannot set buffer size to %d periods of %d frames; \
1929 total requested buffer size is %d frames, minimum allowed is %d, maximum is %d",
1930 				       snd_strerror(err), alsa_name, periods, frames, periods * frames, (int)minp, (int)maxp)));
1931     }
1932 
1933   err = snd_pcm_hw_params_set_format(handle, hw_params, alsa_format);
1934   if (err < 0)
1935     {
1936       snd_pcm_close(handle);
1937       handles[alsa_stream] = NULL;
1938       alsa_dump_configuration(alsa_name, hw_params, sw_params);
1939       return(alsa_mus_error(MUS_AUDIO_CONFIGURATION_NOT_AVAILABLE,
1940 			    mus_format("%s: %s: cannot set format to %s",
1941 				       snd_strerror(err), alsa_name, snd_pcm_format_name(alsa_format))));
1942     }
1943 
1944   err = snd_pcm_hw_params_set_channels(handle, hw_params, chans);
1945   if (err < 0)
1946     {
1947       snd_pcm_close(handle);
1948       handles[alsa_stream] = NULL;
1949       alsa_dump_configuration(alsa_name, hw_params, sw_params);
1950       return(alsa_mus_error(MUS_AUDIO_CONFIGURATION_NOT_AVAILABLE,
1951 			    mus_format("%s: %s: cannot set channels to %d",
1952 				       snd_strerror(err), alsa_name, chans)));
1953     }
1954 
1955   {
1956     uint32_t new_rate;
1957     new_rate = srate;
1958     /* r is uint32_t so it can't be negative */
1959     err = snd_pcm_hw_params_set_rate_near(handle, hw_params, &new_rate, 0);
1960     if ((new_rate != (uint32_t)srate) && (!alsa_squelch_warning))
1961       {
1962 	mus_print("%s: could not set rate to exactly %d, set to %d instead",
1963 		  alsa_name, srate, new_rate);
1964       }
1965   }
1966 
1967   err = snd_pcm_hw_params(handle, hw_params);
1968   if (err < 0)
1969     {
1970       snd_pcm_close(handle);
1971       handles[alsa_stream] = NULL;
1972       alsa_dump_configuration(alsa_name, hw_params, sw_params);
1973       return(alsa_mus_error(MUS_AUDIO_CONFIGURATION_NOT_AVAILABLE,
1974 			    mus_format("%s: cannot set hardware parameters for %s",
1975 				       snd_strerror(err), alsa_name)));
1976     }
1977 
1978   snd_pcm_sw_params_current(handle, sw_params);
1979   err = snd_pcm_sw_params(handle, sw_params);
1980   if (err < 0)
1981     {
1982       snd_pcm_close(handle);
1983       handles[alsa_stream] = NULL;
1984       alsa_dump_configuration(alsa_name, hw_params, sw_params);
1985       return(alsa_mus_error(MUS_AUDIO_CONFIGURATION_NOT_AVAILABLE,
1986 			    mus_format("%s: cannot set software parameters for %s",
1987 				       snd_strerror(err), alsa_name)));
1988     }
1989 
1990   /* for now the id for the stream is the direction identifier, that is
1991      not a problem because we only advertise one card with two devices */
1992   return(alsa_stream);
1993 }
1994 
1995 /* sndlib support for opening output devices */
1996 
alsa_mus_audio_open_output(int ur_dev,int srate,int chans,mus_sample_t samp_type,int size)1997 static int alsa_mus_audio_open_output(int ur_dev, int srate, int chans, mus_sample_t samp_type, int size)
1998 {
1999   return(alsa_audio_open(ur_dev, srate, chans, samp_type, size));
2000 }
2001 
2002 /* sndlib support for opening input devices */
2003 
alsa_mus_audio_open_input(int ur_dev,int srate,int chans,mus_sample_t samp_type,int size)2004 static int alsa_mus_audio_open_input(int ur_dev, int srate, int chans, mus_sample_t samp_type, int size)
2005 {
2006   return(alsa_audio_open(ur_dev, srate, chans, samp_type, size));
2007 }
2008 
2009 /* sndlib support for closing a device */
2010 
2011 /* to force it to stop, snd_pcm_drop */
2012 
2013 static bool xrun_warned = false;
2014 
alsa_mus_audio_close(int id)2015 static int alsa_mus_audio_close(int id)
2016 {
2017   xrun_warned = false;
2018   if (id == MUS_ERROR) return(MUS_ERROR);
2019   if (alsa_trace) mus_print( "%s: %d", __func__, id);
2020   if (handles[id])
2021     {
2022       int err;
2023       err = snd_pcm_drain(handles[id]);
2024       if (err != 0)
2025 	mus_print("snd_pcm_drain: %s", snd_strerror(err));
2026 
2027       err = snd_pcm_close(handles[id]);
2028       if (err != 0)
2029 	return(alsa_mus_error(MUS_AUDIO_CANT_CLOSE,
2030 			      mus_format("snd_pcm_close: %s",
2031 					 snd_strerror(err))));
2032       handles[id] = NULL;
2033     }
2034   return(MUS_NO_ERROR);
2035 }
2036 
2037 /* recover from underruns or overruns */
2038 
recover_from_xrun(int id)2039 static int recover_from_xrun(int id)
2040 {
2041   int err;
2042   snd_pcm_status_t *status;
2043   snd_pcm_state_t state;
2044   snd_pcm_status_alloca(&status);
2045   err = snd_pcm_status(handles[id], status);
2046   if (err < 0)
2047     {
2048       mus_print("%s: snd_pcm_status: %s", __func__, snd_strerror(err));
2049       return(MUS_ERROR);
2050     }
2051   state = snd_pcm_status_get_state(status);
2052   if (state == SND_PCM_STATE_XRUN)
2053     {
2054       if (!xrun_warned)
2055 	{
2056 	  xrun_warned = true;
2057 	  mus_print("[under|over]run detected");
2058 	}
2059       err = snd_pcm_prepare(handles[id]);
2060       if (err < 0)
2061 	mus_print("snd_pcm_prepare: %s", snd_strerror(err));
2062       else return(MUS_NO_ERROR);
2063     }
2064   else mus_print("%s: error, current state is %s", __func__, snd_pcm_state_name(state));
2065   return(MUS_ERROR);
2066 }
2067 
2068 /* sndlib support for writing a buffer to an output device */
2069 
alsa_mus_audio_write(int id,char * buf,int bytes)2070 static int alsa_mus_audio_write(int id, char *buf, int bytes)
2071 {
2072   snd_pcm_sframes_t status;
2073   ssize_t frames;
2074   if (id == MUS_ERROR) return(MUS_ERROR);
2075   frames = snd_pcm_bytes_to_frames(handles[id], bytes);
2076   status = snd_pcm_writei(handles[id], buf, frames);
2077   if ((status == -EAGAIN) ||
2078       ((status >= 0) && (status < frames)))
2079     snd_pcm_wait(handles[id], 1000);
2080   else
2081     {
2082       if (status == -EPIPE)
2083 	return(recover_from_xrun(id));
2084       else
2085 	{
2086 	  if (status < 0)
2087 	    {
2088 	      mus_print("snd_pcm_writei: %s", snd_strerror(status));
2089 	      return(MUS_ERROR);
2090 	    }
2091 	}
2092     }
2093   return(MUS_NO_ERROR);
2094 }
2095 
2096 /* sndlib support for reading a buffer from an input device */
2097 
alsa_mus_audio_read(int id,char * buf,int bytes)2098 static int alsa_mus_audio_read(int id, char *buf, int bytes)
2099 {
2100   snd_pcm_sframes_t status;
2101   ssize_t frames;
2102   if (id == MUS_ERROR) return(MUS_ERROR);
2103   frames = snd_pcm_bytes_to_frames(handles[id], bytes);
2104   status = snd_pcm_readi(handles[id], buf, frames);
2105   if ((status == -EAGAIN) ||
2106       ((status >= 0) && (status < frames)))
2107     snd_pcm_wait(handles[id], 1000);
2108   else
2109     {
2110       if (status == -EPIPE)
2111 	return(recover_from_xrun(id));
2112       else
2113 	{
2114 	  if (status < 0)
2115 	    {
2116 	      mus_print("snd_pcm_readi: %s", snd_strerror(status));
2117 	      return(MUS_ERROR);
2118 	    }
2119 	}
2120     }
2121   return(MUS_NO_ERROR);
2122 }
2123 
2124 /* read state of the audio hardware */
2125 
alsa_chans(int ur_dev,int * info)2126 static int alsa_chans(int ur_dev, int *info)
2127 {
2128   int card;
2129   int device;
2130   int alsa_device = 0;
2131   snd_pcm_stream_t alsa_stream = SND_PCM_STREAM_PLAYBACK;
2132 
2133   if ((!audio_initialized) &&
2134       (mus_audio_initialize() != MUS_NO_ERROR))
2135     return(MUS_ERROR);
2136 
2137   card = MUS_AUDIO_SYSTEM(ur_dev);
2138   device = MUS_AUDIO_DEVICE(ur_dev);
2139   to_alsa_device(device, &alsa_device, &alsa_stream);
2140 
2141   if (card > 0 || alsa_device > 0)
2142     return(alsa_mus_error(MUS_AUDIO_CANT_READ, NULL));
2143 
2144   if ((alsa_stream == SND_PCM_STREAM_CAPTURE) &&
2145       (alsa_capture_device_name) &&
2146       (strcmp(alsa_capture_device_name, "default") == 0))
2147     {
2148       if (info)
2149 	info[0] = 2;
2150       else return(2);
2151     }
2152 
2153   {
2154     uint32_t max_channels = 0;
2155     snd_pcm_hw_params_get_channels_max(alsa_hw_params[alsa_stream], &max_channels);
2156 
2157     if ((alsa_stream == SND_PCM_STREAM_CAPTURE) &&
2158 	(max_channels > (uint32_t)alsa_max_capture_channels))
2159       {
2160 	/* limit number of capture channels to a reasonable maximum, if the user
2161 	   specifies a plug pcm as the capture pcm then the returned number of channels
2162 	   would be MAXINT (or whatever the name is for a really big number). At this
2163 	   point there is no support in the alsa api to distinguish between default
2164 	   parameters or those that have been set by a user on purpose, of for querying
2165 	   the hardware pcm device that is hidden by the plug device to see what is the
2166 	   real number of channels for the device we are dealing with. We could also try
2167 	   to flag this as an error to the user and exit the program */
2168 	max_channels = alsa_max_capture_channels;
2169       }
2170 
2171     if (info)
2172       {
2173 	uint32_t tmp = 0;
2174 	info[0] = max_channels;
2175 	snd_pcm_hw_params_get_channels_min(alsa_hw_params[alsa_stream], &tmp);
2176 	info[1] = tmp;
2177 	info[2] = max_channels;
2178       }
2179 
2180     return(max_channels);
2181   }
2182 }
2183 
2184 
alsa_sample_types(int ur_dev,int chan,mus_sample_t * val)2185 static int alsa_sample_types(int ur_dev, int chan, mus_sample_t *val)
2186 {
2187   int card;
2188   int device;
2189   int alsa_device = 0;
2190   snd_pcm_stream_t alsa_stream = SND_PCM_STREAM_PLAYBACK;
2191 
2192   if ((!audio_initialized) &&
2193       (mus_audio_initialize() != MUS_NO_ERROR))
2194     return(MUS_ERROR);
2195 
2196   card = MUS_AUDIO_SYSTEM(ur_dev);
2197   device = MUS_AUDIO_DEVICE(ur_dev);
2198   to_alsa_device(device, &alsa_device, &alsa_stream);
2199 
2200   if (card > 0 || alsa_device > 0)
2201     return(alsa_mus_error(MUS_AUDIO_CANT_READ, NULL));
2202 
2203   {
2204     int f, format;
2205     snd_pcm_format_mask_t *mask;
2206 
2207     snd_pcm_format_mask_alloca(&mask);
2208     snd_pcm_hw_params_get_format_mask(alsa_hw_params[alsa_stream], mask);
2209 
2210     for (format = 0, f = 1; format < SND_PCM_FORMAT_LAST; format++)
2211       {
2212 	int err;
2213 	err = snd_pcm_format_mask_test(mask, (snd_pcm_format_t)format);
2214 	if (err > 0)
2215 	  {
2216 	    if ((f < chan) &&
2217 		(to_mus_sample_type(format) != MUS_UNKNOWN_SAMPLE))
2218 	      val[f++] = to_mus_sample_type(format);
2219 	  }
2220       }
2221     val[0] = (mus_sample_t)(f - 1);
2222   }
2223 
2224   return(MUS_NO_ERROR);
2225 }
2226 
2227 #endif /* HAVE_ALSA */
2228 
2229 
2230 
2231 /* -------------------------------- SUN -------------------------------- */
2232 /*
2233  * Thanks to Seppo Ingalsuo for several bugfixes.
2234  * record case improved after perusal of Snack 1.6/src/jkAudio_sun.c
2235  */
2236 
2237 /* apparently input other than 8000 is 16-bit, 8000 is (?) mulaw */
2238 
2239 #if (defined(__sun) || defined(__SVR4)) && (!(defined(AUDIO_OK)))
2240 #define AUDIO_OK 1
2241 
2242 #include <sys/types.h>
2243 #ifdef SUNOS
2244   #include <stropts.h>
2245 #endif
2246 #include <sys/filio.h>
2247 
2248 #ifdef SUNOS
2249 #include <sun/audioio.h>
2250 #else
2251 #include <sys/audioio.h>
2252 #endif
2253 
2254 #include <sys/mixer.h>
2255 
mus_audio_initialize(void)2256 int mus_audio_initialize(void) {return(MUS_NO_ERROR);}
2257 
2258 #define DAC_NAME "/dev/audio"
2259 #define AUDIODEV_ENV "AUDIODEV"
2260 
2261 #define return_error_exit(Error_Type, Audio_Line, Ur_Error_Message) \
2262   do { char *Error_Message; Error_Message = Ur_Error_Message; \
2263     if (Audio_Line != -1) close(Audio_Line); \
2264     if (Error_Message) \
2265       {mus_standard_error(Error_Type, Error_Message); free(Error_Message);} \
2266     else mus_standard_error(Error_Type, mus_error_type_to_string(Error_Type)); \
2267     return(MUS_ERROR); \
2268   } while (false)
2269 
mus_audio_moniker(void)2270 char *mus_audio_moniker(void)
2271 {
2272 #ifndef AUDIO_DEV_AMD
2273   struct audio_device ad;
2274 #else
2275   int ad;
2276 #endif
2277   int audio_fd, err;
2278   char *dev_name;
2279   if (getenv(AUDIODEV_ENV))
2280     dev_name = getenv(AUDIODEV_ENV);
2281   else dev_name = (char *)DAC_NAME;
2282   audio_fd = open(dev_name, O_RDONLY | O_NONBLOCK, 0);
2283   if (audio_fd == -1)
2284     {
2285       audio_fd = open("/dev/audioctl", O_RDONLY | O_NONBLOCK, 0);
2286       if (audio_fd == -1) return("sun probably");
2287     }
2288   err = ioctl(audio_fd, AUDIO_GETDEV, &ad);
2289   if (err == -1)
2290     {
2291       close(audio_fd);
2292       return("sun?");
2293     }
2294   mus_audio_close(audio_fd);
2295 
2296   if (!version_name) version_name = (char *)calloc(PRINT_BUFFER_SIZE, sizeof(char));
2297 #ifndef AUDIO_DEV_AMD
2298   snprintf(version_name, LABEL_BUFFER_SIZE, "audio: %s (%s)", ad.name, ad.version);
2299 #else
2300   switch (ad)
2301     {
2302     case AUDIO_DEV_AMD:        snprintf(version_name, LABEL_BUFFER_SIZE, "audio: amd");        break;
2303   #ifdef AUDIO_DEV_CS4231
2304     case AUDIO_DEV_CS4231:     snprintf(version_name, LABEL_BUFFER_SIZE, "audio: cs4231");     break;
2305   #endif
2306     case AUDIO_DEV_SPEAKERBOX: snprintf(version_name, LABEL_BUFFER_SIZE, "audio: speakerbox"); break;
2307     case AUDIO_DEV_CODEC:      snprintf(version_name, LABEL_BUFFER_SIZE, "audio: codec");      break;
2308     default:                   snprintf(version_name, LABEL_BUFFER_SIZE, "audio: unknown");    break;
2309     }
2310 #endif
2311   return(version_name);
2312 }
2313 
to_sun_sample_type(mus_sample_t samp_type)2314 static int to_sun_sample_type(mus_sample_t samp_type)
2315 {
2316   switch (samp_type)
2317     {
2318 #if MUS_LITTLE_ENDIAN
2319     case MUS_LSHORT: /* Solaris on Intel? */
2320 #else
2321     case MUS_BSHORT:
2322 #endif
2323       return(AUDIO_ENCODING_LINEAR);
2324       break;
2325     case MUS_BYTE:
2326 #if defined(AUDIO_ENCODING_LINEAR8)
2327       return(AUDIO_ENCODING_LINEAR8); break;
2328 #else
2329       return(AUDIO_ENCODING_LINEAR);
2330       break;
2331 #endif
2332     case MUS_MULAW: return(AUDIO_ENCODING_ULAW); break;
2333     case MUS_ALAW:  return(AUDIO_ENCODING_ALAW); break;
2334       /* there's also AUDIO_ENCODING_DVI */
2335 
2336     default: break;
2337     }
2338   return(MUS_ERROR);
2339 }
2340 
mus_audio_open_output(int ur_dev,int srate,int chans,mus_sample_t samp_type,int size)2341 int mus_audio_open_output(int ur_dev, int srate, int chans, mus_sample_t samp_type, int size)
2342 {
2343   struct audio_info info;
2344   char *dev_name;
2345   int encode, bits, dev;
2346   int audio_fd, err;
2347   dev = MUS_AUDIO_DEVICE(ur_dev);
2348   encode = to_sun_sample_type(samp_type);
2349   if (encode == MUS_ERROR)
2350     return_error_exit(MUS_AUDIO_SAMPLE_TYPE_NOT_AVAILABLE, -1,
2351 		      mus_format("sample type %d (%s) not available",
2352 				 samp_type,
2353 				 mus_sample_type_name(samp_type)));
2354   if (getenv(AUDIODEV_ENV))
2355     dev_name = getenv(AUDIODEV_ENV);
2356   else dev_name = (char *)DAC_NAME;
2357   if (dev != MUS_AUDIO_DUPLEX_DEFAULT)
2358     audio_fd = open(dev_name, O_WRONLY, 0);
2359   else audio_fd = open(dev_name, O_RDWR, 0);
2360   if (audio_fd == -1)
2361     return_error_exit(MUS_AUDIO_CANT_OPEN, -1,
2362 		      mus_format("can't open output %s: %s",
2363 				 dev_name, strerror(errno)));
2364   AUDIO_INITINFO(&info);
2365   if (dev == MUS_AUDIO_LINE_OUT)
2366     info.play.port = AUDIO_LINE_OUT;
2367   else
2368     {
2369       if (dev == MUS_AUDIO_SPEAKERS)
2370 	/* OR may not be available */
2371 	info.play.port = AUDIO_SPEAKER | AUDIO_HEADPHONE;
2372       else
2373 	info.play.port = AUDIO_SPEAKER;
2374     }
2375   info.play.sample_rate = srate;
2376   info.play.channels = chans;
2377   bits = 8 * mus_bytes_per_sample(samp_type);
2378   info.play.precision = bits;
2379   info.play.encoding = encode;
2380   err = ioctl(audio_fd, AUDIO_SETINFO, &info);
2381   if (err == -1)
2382     {
2383       ioctl(audio_fd, AUDIO_GETINFO, &info);
2384 
2385       if ((int)info.play.channels != chans)
2386 	return_error_exit(MUS_AUDIO_CHANNELS_NOT_AVAILABLE, audio_fd,
2387 			  mus_format("can't set output %s channels to %d",
2388 				     dev_name, chans));
2389 
2390       if (((int)info.play.precision != bits) ||
2391 	  ((int)info.play.encoding != encode))
2392 	return_error_exit(MUS_AUDIO_SAMPLE_TYPE_NOT_AVAILABLE, audio_fd,
2393 			  mus_format("can't set output %s sample type to %d bits, %d encode (%s)",
2394 				     dev_name,
2395 				     bits, encode,
2396 				     mus_sample_type_name(samp_type)));
2397 
2398       if ((int)info.play.sample_rate != srate)
2399 	return_error_exit(MUS_AUDIO_CHANNELS_NOT_AVAILABLE, audio_fd,
2400 			  mus_format("can't set output %s srate to %d",
2401 				     dev_name, srate));
2402     }
2403   /* man audio sez the play.buffer_size field is not currently supported */
2404   /* but since the default buffer size is 8180! we need ioctl(audio_fd, I_SETSIG, ...) */
2405 #ifdef SUNOS
2406   ioctl(audio_fd, I_FLUSH, FLUSHR);
2407 #endif
2408   return(audio_fd);
2409 }
2410 
mus_audio_write(int line,char * buf,int bytes)2411 int mus_audio_write(int line, char *buf, int bytes)
2412 {
2413   if (write(line, buf, bytes) != bytes)
2414     return_error_exit(MUS_AUDIO_WRITE_ERROR, -1,
2415 		      mus_format("write error: %s", strerror(errno)));
2416   return(MUS_NO_ERROR);
2417 }
2418 
mus_audio_close(int line)2419 int mus_audio_close(int line)
2420 {
2421   write(line, (char *)NULL, 0);
2422   close(line);
2423   return(MUS_NO_ERROR);
2424 }
2425 
mus_audio_read(int line,char * buf,int bytes)2426 int mus_audio_read(int line, char *buf, int bytes)
2427 {
2428   int total = 0;
2429   char *curbuf;
2430   /* ioctl(line, AUDIO_DRAIN, NULL) */
2431   /* this seems to return 8-12 bytes fewer than requested -- perverse! */
2432   /* should I buffer data internally? */
2433 
2434   /* apparently we need to loop here ... */
2435   curbuf = buf;
2436   while (total < bytes)
2437     {
2438       int bytes_available;
2439       ioctl(line, FIONREAD, &bytes_available);
2440       if (bytes_available > 0)
2441 	{
2442 	  int bytes_read;
2443 	  if ((total + bytes_available) > bytes) bytes_available = bytes - total;
2444 	  bytes_read = read(line, curbuf, bytes_available);
2445 	  if (bytes_read > 0)
2446 	    {
2447 	      total += bytes_read;
2448 	      curbuf = (char *)(buf + total);
2449 	    }
2450 	  /* else return anyway?? */
2451 	}
2452     }
2453   return(MUS_NO_ERROR);
2454 }
2455 
mus_audio_open_input(int ur_dev,int srate,int chans,mus_sample_t samp_type,int size)2456 int mus_audio_open_input(int ur_dev, int srate, int chans, mus_sample_t samp_type, int size)
2457 {
2458   struct audio_info info;
2459   int indev, encode, bits, dev, audio_fd, err;
2460   char *dev_name;
2461   dev = MUS_AUDIO_DEVICE(ur_dev);
2462   encode = to_sun_sample_type(samp_type);
2463   bits = 8 * mus_bytes_per_sample(samp_type);
2464   if (encode == -1)
2465     return_error_exit(MUS_AUDIO_SAMPLE_TYPE_NOT_AVAILABLE, -1,
2466 		      mus_format("sample type %d bits, %d encode (%s) not available",
2467 				 bits, encode,
2468 				 mus_sample_type_name(samp_type)));
2469   if (getenv(AUDIODEV_ENV))
2470     dev_name = getenv(AUDIODEV_ENV);
2471   else dev_name = (char *)DAC_NAME;
2472   if (dev != MUS_AUDIO_DUPLEX_DEFAULT)
2473     audio_fd = open(dev_name, O_RDONLY, 0);
2474   else audio_fd = open(dev_name, O_RDWR, 0);
2475   if (audio_fd == -1)
2476     return_error_exit(MUS_AUDIO_CANT_OPEN, -1,
2477 		      mus_format("can't open input %s: %s",
2478 				 dev_name, strerror(errno)));
2479   AUDIO_INITINFO(&info);
2480   /*  ioctl(audio_fd, AUDIO_GETINFO, &info); */
2481   info.record.sample_rate = srate;
2482   info.record.channels = chans;
2483   err = ioctl(audio_fd, AUDIO_SETINFO, &info);
2484   if (err == -1)
2485     return_error_exit(MUS_AUDIO_CANT_OPEN, audio_fd,
2486 		      mus_format("can't set srate %d and chans %d for input %s",
2487 				 srate, chans,
2488 				 dev_name));
2489   ioctl(audio_fd, AUDIO_GETINFO, &info);
2490   if (info.record.sample_rate != (uint32_t)srate)
2491     mus_print("%s[%d]: sampling rate: %d != %d\n",
2492 	      __FILE__, __LINE__,
2493 	      info.record.sample_rate, srate);
2494   if (info.record.channels != (uint32_t)chans)
2495     mus_print("%s[%d]: channels: %d != %d\n",
2496 	      __FILE__, __LINE__,
2497 	      info.record.channels, chans);
2498 
2499   info.record.precision = bits; /* was play, changed 10-Jul-03 thanks to Jurgen Keil */
2500   info.record.encoding = encode;
2501   err = ioctl(audio_fd, AUDIO_SETINFO, &info);
2502   if (err == -1)
2503     return_error_exit(MUS_AUDIO_CANT_OPEN, audio_fd,
2504 		      mus_format("can't set bits %d, encode %d (sample type %s) for input %s",
2505 				 bits, encode, mus_sample_type_name(samp_type),
2506 				 dev_name));
2507   ioctl(audio_fd, AUDIO_GETINFO, &info);
2508 
2509   /* these cannot be OR'd */
2510   if (dev == MUS_AUDIO_LINE_IN)
2511     indev = AUDIO_LINE_IN;
2512   else indev = AUDIO_MICROPHONE;
2513   info.record.port = indev;
2514   err = ioctl(audio_fd, AUDIO_SETINFO, &info);
2515   if (err == -1)
2516     return_error_exit(MUS_AUDIO_CANT_WRITE, audio_fd,
2517 		      mus_format("can't set record.port to %d for %s",
2518 				 indev, dev_name));
2519   err = ioctl(audio_fd, AUDIO_GETINFO, &info);
2520   if (err == -1)
2521     return_error_exit(MUS_AUDIO_CANT_READ, audio_fd,
2522 		      mus_format("can't getinfo on input %s (line: %d)",
2523 				 dev_name,
2524 				 audio_fd));
2525   else
2526     {
2527       if ((int)info.record.port != indev)
2528 	return_error_exit(MUS_AUDIO_DEVICE_NOT_AVAILABLE, audio_fd,
2529 			  mus_format("confusion in record.port: %d != %d (%s)",
2530 				     (int)info.record.port, indev,
2531 				     dev_name));
2532       if ((int)info.record.channels != chans)
2533 	return_error_exit(MUS_AUDIO_CHANNELS_NOT_AVAILABLE, audio_fd,
2534 			  mus_format("confusion in record.channels: %d != %d (%s)",
2535 				     (int)info.record.channels, chans,
2536 				     dev_name));
2537       if (((int)info.record.precision != bits) ||
2538 	  ((int)info.record.encoding != encode))
2539 	return_error_exit(MUS_AUDIO_SAMPLE_TYPE_NOT_AVAILABLE, audio_fd,
2540 			  mus_format("confusion in record.precision|encoding: %d != %d or %d != %d (%s)",
2541 				     (int)info.record.precision, bits,
2542 				     (int)info.record.encoding, encode,
2543 				     dev_name));
2544     }
2545   /* this may be a bad idea */
2546   info.record.buffer_size = size;
2547   err = ioctl(audio_fd, AUDIO_SETINFO, &info);
2548   if (err == -1)
2549     return_error_exit(MUS_AUDIO_CANT_WRITE, audio_fd,
2550 		      mus_format("can't set buffer size to %d on input %s",
2551 				 size,
2552 				 dev_name));
2553   return(audio_fd);
2554 }
2555 
2556 #if 0
2557 /* pause can be implemented with play.pause and record.pause */
2558 
2559 static const char *sun_sample_type_name(mus_sample_t samp_type)
2560 {
2561   switch (samp_type)
2562     {
2563 #ifdef AUDIO_ENCODING_ALAW
2564     case AUDIO_ENCODING_ALAW: return("alaw"); break;
2565 #endif
2566 #ifdef AUDIO_ENCODING_ULAW
2567     case AUDIO_ENCODING_ULAW: return("ulaw"); break;
2568 #endif
2569 #ifdef AUDIO_ENCODING_DVI
2570     case AUDIO_ENCODING_DVI: return("dvi adpcm"); break;
2571 #endif
2572 #ifdef AUDIO_ENCODING_LINEAR8
2573     case AUDIO_ENCODING_LINEAR8: return("linear"); break;
2574 #else
2575   #ifdef AUDIO_ENCODING_PCM8
2576     case AUDIO_ENCODING_PCM8: return("linear"); break;
2577   #endif
2578 #endif
2579 #ifdef AUDIO_ENCODING_LINEAR
2580     case AUDIO_ENCODING_LINEAR: return("linear"); break;
2581 #else
2582   #ifdef AUDIO_ENCODING_PCM16
2583     case AUDIO_ENCODING_PCM16: return("linear"); break;
2584   #endif
2585 #endif
2586 #ifdef AUDIO_ENCODING_NONE
2587     case AUDIO_ENCODING_NONE: return("not audio"); break; /* dbri interface configured for something else */
2588 #endif
2589     }
2590   return("unknown");
2591 }
2592 
2593 static const char *sun_in_device_name(int dev)
2594 {
2595   if (dev == AUDIO_MICROPHONE) return("microphone");
2596   if (dev == AUDIO_LINE_IN) return("line in");
2597   if (dev == AUDIO_INTERNAL_CD_IN) return("cd");
2598   if (dev == (AUDIO_MICROPHONE | AUDIO_LINE_IN)) return("microphone + line in");
2599   if (dev == (AUDIO_MICROPHONE | AUDIO_LINE_IN | AUDIO_INTERNAL_CD_IN)) return("microphone + line in + cd");
2600   if (dev == (AUDIO_MICROPHONE | AUDIO_INTERNAL_CD_IN)) return("microphone + cd");
2601   if (dev == (AUDIO_LINE_IN | AUDIO_INTERNAL_CD_IN)) return("line in + cd");
2602   return("unknown");
2603 }
2604 
2605 static const char *sun_out_device_name(int dev)
2606 {
2607   if (dev == AUDIO_SPEAKER) return("speakers");
2608   if (dev == AUDIO_LINE_OUT) return("line out");
2609   if (dev == AUDIO_HEADPHONE) return("headphones");
2610   if (dev == (AUDIO_SPEAKER | AUDIO_LINE_OUT)) return("speakers + line out");
2611   if (dev == (AUDIO_SPEAKER | AUDIO_LINE_OUT | AUDIO_HEADPHONE)) return("speakers + line out + headphones");
2612   if (dev == (AUDIO_SPEAKER | AUDIO_HEADPHONE)) return("speakers + headphones");
2613   if (dev == (AUDIO_LINE_OUT | AUDIO_HEADPHONE)) return("line out + headphones");
2614   return("unknown");
2615 }
2616 
2617 
2618 static char *sun_vol_name = NULL;
2619 static char *sun_volume_name(float vol, int balance, int chans)
2620 {
2621   if (!sun_vol_name) sun_vol_name = (char *)calloc(LABEL_BUFFER_SIZE, sizeof(char));
2622   if (chans != 2)
2623     snprintf(sun_vol_name, LABEL_BUFFER_SIZE, "%.3f", vol);
2624   else
2625     {
2626       snprintf(sun_vol_name, LABEL_BUFFER_SIZE, "%.3f %.3f",
2627 		   vol * (float)(AUDIO_RIGHT_BALANCE - balance) / (float)AUDIO_RIGHT_BALANCE,
2628 		   vol * (float)balance / (float)AUDIO_RIGHT_BALANCE);
2629     }
2630   return(sun_vol_name);
2631 }
2632 
2633 #endif
2634 #endif
2635 
2636 
2637 
2638 /* ------------------------------- WINDOZE ----------------------------------------- */
2639 
2640 #if defined(_MSC_VER) && (!(defined(__CYGWIN__)))
2641 #define AUDIO_OK 1
2642 
2643 #include <windows.h>
2644 #include <mmsystem.h>
2645 
2646 #define BUFFER_FILLED 1
2647 #define BUFFER_EMPTY 2
2648 
2649 #define OUTPUT_LINE 1
2650 #define INPUT_LINE 2
2651 
2652 #define SOUND_UNREADY 0
2653 #define SOUND_INITIALIZED 1
2654 #define SOUND_RUNNING 2
2655 
2656 static int buffer_size = 1024;
2657 static int db_state[2];
2658 static int sound_state = 0;
2659 static int current_chans = 1;
2660 static int current_datum_size = 2;
2661 static int current_buf = 0;
2662 WAVEHDR wh[2];
2663 HWAVEOUT fd;
2664 HWAVEIN record_fd;
2665 WAVEHDR rec_wh;
2666 static int rec_state = SOUND_UNREADY;
2667 
2668 static MMRESULT win_in_err = 0, win_out_err = 0;
2669 static char errstr[128], getstr[128];
2670 
2671 static char *win_err_buf = NULL;
2672 static mus_print_handler_t *old_handler;
2673 
win_mus_print(char * msg)2674 static void win_mus_print(char *msg)
2675 {
2676   if ((win_in_err == 0) && (win_out_err == 0))
2677     (*old_handler)(msg);
2678   else
2679     {
2680       if (win_in_err)
2681 	waveInGetErrorText(win_in_err, getstr, PRINT_BUFFER_SIZE);
2682       else waveOutGetErrorText(win_out_err, getstr, PRINT_BUFFER_SIZE);
2683       snprintf(errstr, PRINT_BUFFER_SIZE, "%s [%s]", msg, getstr);
2684       (*old_handler)(errstr);
2685     }
2686 }
2687 
start_win_print(void)2688 static void start_win_print(void)
2689 {
2690   if (old_handler != win_mus_print)
2691     old_handler = mus_print_set_handler(win_mus_print);
2692 }
2693 
end_win_print(void)2694 static void end_win_print(void)
2695 {
2696   if (old_handler == win_mus_print)
2697     mus_print_set_handler(NULL);
2698   else mus_print_set_handler(old_handler);
2699 }
2700 
2701 #define return_error_exit(Error_Type, Ur_Error_Message) \
2702   do { char *Error_Message; Error_Message = Ur_Error_Message; \
2703     if (Error_Message) \
2704       {mus_standard_error(Error_Type, Error_Message); free(Error_Message);} \
2705     else mus_standard_error(Error_Type, mus_error_type_to_string(Error_Type)); \
2706     end_win_print(); \
2707     return(MUS_ERROR); \
2708   } while (false)
2709 
2710 
2711 
next_buffer(HWAVEOUT w,UINT msg,DWORD user_data,DWORD p1,DWORD p2)2712 DWORD CALLBACK next_buffer(HWAVEOUT w, UINT msg, DWORD user_data, DWORD p1, DWORD p2)
2713 {
2714   if (msg == WOM_DONE)
2715     {
2716       db_state[current_buf] = BUFFER_EMPTY;
2717     }
2718   return(0);
2719 }
2720 
mus_audio_open_output(int ur_dev,int srate,int chans,mus_sample_t samp_type,int size)2721 int mus_audio_open_output(int ur_dev, int srate, int chans, mus_sample_t samp_type, int size)
2722 {
2723   WAVEFORMATEX wf;
2724   int dev;
2725   start_win_print();
2726   dev = MUS_AUDIO_DEVICE(ur_dev);
2727   wf.nChannels = chans;
2728   current_chans = chans;
2729   wf.wFormatTag = WAVE_FORMAT_PCM;
2730   wf.cbSize = 0;
2731   if (samp_type == MUS_UBYTE)
2732     {
2733       wf.wBitsPerSample = 8;
2734       current_datum_size = 1;
2735     }
2736   else
2737     {
2738       wf.wBitsPerSample = 16;
2739       current_datum_size = 2;
2740     }
2741   wf.nSamplesPerSec = srate;
2742   wf.nBlockAlign = chans * current_datum_size;
2743   wf.nAvgBytesPerSec = wf.nBlockAlign * wf.nSamplesPerSec;
2744 #if _MSC_VER
2745   win_out_err = waveOutOpen(&fd, WAVE_MAPPER, &wf, (DWORD (*)(HWAVEOUT,UINT,DWORD,DWORD,DWORD))next_buffer, 0, CALLBACK_FUNCTION);
2746 #else
2747   win_out_err = waveOutOpen(&fd, WAVE_MAPPER, &wf, (DWORD)next_buffer, 0, CALLBACK_FUNCTION);
2748 #endif
2749   /* 0 here = user_data above, other case = WAVE_FORMAT_QUERY */
2750   if (win_out_err)
2751     return_error_exit(MUS_AUDIO_DEVICE_NOT_AVAILABLE,
2752 		      mus_format("can't open %d", dev));
2753   waveOutPause(fd);
2754   if (size <= 0)
2755     buffer_size = 1024;
2756   else buffer_size = size;
2757   wh[0].dwBufferLength = buffer_size * current_datum_size;
2758   wh[0].dwFlags = 0;
2759   wh[0].dwLoops = 0;
2760   wh[0].lpData = (char *)calloc(wh[0].dwBufferLength, sizeof(char));
2761   if ((wh[0].lpData) == 0)
2762     {
2763       waveOutClose(fd);
2764       return_error_exit(MUS_AUDIO_SIZE_NOT_AVAILABLE,
2765 			mus_format("can't allocate buffer size %d for output %d", buffer_size, dev));
2766     }
2767   win_out_err = waveOutPrepareHeader(fd, &(wh[0]), sizeof(WAVEHDR));
2768   if (win_out_err)
2769     {
2770       free(wh[0].lpData);
2771       waveOutClose(fd);
2772       return_error_exit(MUS_AUDIO_CONFIGURATION_NOT_AVAILABLE,
2773 			mus_format("can't setup output 'header' for %d", dev));
2774     }
2775   db_state[0] = BUFFER_EMPTY;
2776   wh[1].dwBufferLength = buffer_size * current_datum_size;
2777   wh[1].dwFlags = 0;
2778   wh[1].dwLoops = 0;
2779   wh[1].lpData = (char *)calloc(wh[0].dwBufferLength, sizeof(char));
2780   if ((wh[1].lpData) == 0)
2781     {
2782       free(wh[0].lpData);
2783       waveOutClose(fd);
2784       return_error_exit(MUS_AUDIO_SIZE_NOT_AVAILABLE,
2785 			mus_format("can't allocate buffer size %d for output %d", buffer_size, dev));
2786     }
2787   win_out_err = waveOutPrepareHeader(fd, &(wh[1]), sizeof(WAVEHDR));
2788   if (win_out_err)
2789     {
2790       waveOutUnprepareHeader(fd, &(wh[0]), sizeof(WAVEHDR));
2791       free(wh[0].lpData);
2792       free(wh[1].lpData);
2793       waveOutClose(fd);
2794       return_error_exit(MUS_AUDIO_CONFIGURATION_NOT_AVAILABLE,
2795 			mus_format("can't setup output 'header' for %d", dev));
2796     }
2797   db_state[1] = BUFFER_EMPTY;
2798   sound_state = SOUND_INITIALIZED;
2799   current_buf = 0;
2800   end_win_print();
2801   return(OUTPUT_LINE);
2802 }
2803 
fill_buffer(int dbi,char * inbuf,int instart,int bytes)2804 static MMRESULT fill_buffer(int dbi, char *inbuf, int instart, int bytes)
2805 {
2806   int i, j;
2807   win_out_err = 0;
2808   if (sound_state == SOUND_UNREADY) return(0);
2809   for (i = instart, j = 0; j < bytes; j++, i++)
2810     wh[dbi].lpData[j] = inbuf[i];
2811   wh[dbi].dwBufferLength = bytes;
2812   db_state[dbi] = BUFFER_FILLED;
2813   if ((sound_state == SOUND_INITIALIZED) &&
2814       (dbi == 1))
2815     {
2816       sound_state = SOUND_RUNNING;
2817       win_out_err = waveOutRestart(fd);
2818     }
2819   return(win_out_err);
2820 }
2821 
wait_for_empty_buffer(int buf)2822 static void wait_for_empty_buffer(int buf)
2823 {
2824   while (db_state[buf] != BUFFER_EMPTY)
2825     {
2826       Sleep(1);      /* in millisecs, so even this may be too much if buf = 256 bytes */
2827     }
2828 }
2829 
mus_audio_write(int line,char * buf,int bytes)2830 int mus_audio_write(int line, char *buf, int bytes)
2831 {
2832   int leftover, start;
2833   start_win_print();
2834   if (line != OUTPUT_LINE)
2835     return_error_exit(MUS_AUDIO_CANT_WRITE,
2836 		      mus_format("write error: line %d != %d?",
2837 				 line, OUTPUT_LINE));
2838   win_out_err = 0;
2839   leftover = bytes;
2840   start = 0;
2841   if (sound_state == SOUND_UNREADY)
2842     {
2843       end_win_print();
2844       return(MUS_NO_ERROR);
2845     }
2846   while (leftover > 0)
2847     {
2848       int lim;
2849       lim = leftover;
2850       if (lim > buffer_size) lim = buffer_size;
2851       leftover -= lim;
2852       wait_for_empty_buffer(current_buf);
2853       win_out_err = fill_buffer(current_buf, buf, start, lim);
2854       if (win_out_err)
2855 	return_error_exit(MUS_AUDIO_CANT_WRITE,
2856 			  mus_format("write error on %d",
2857 				     line));
2858       win_out_err = waveOutWrite(fd, &wh[current_buf], sizeof(WAVEHDR));
2859       if (win_out_err)
2860 	return_error_exit(MUS_AUDIO_CANT_WRITE,
2861 			  mus_format("write error on %d",
2862 				     line));
2863       start += lim;
2864       current_buf++;
2865       if (current_buf > 1) current_buf = 0;
2866     }
2867   return(MUS_NO_ERROR);
2868 }
2869 
unlog(unsigned short val)2870 static float unlog(unsigned short val)
2871 {
2872   /* 1.0 linear is 0xffff, rest is said to be "logarithmic", whatever that really means here */
2873   if (val == 0) return(0.0);
2874   return((float)val / 65536.0);
2875   /* return(pow(2.0, amp) - 1.0); */ /* doc seems to be bogus */
2876 }
2877 
mixer_status_name(int status)2878 static char *mixer_status_name(int status)
2879 {
2880   switch (status)
2881     {
2882     case MIXERLINE_LINEF_ACTIVE: return(", (active)"); break;
2883     case MIXERLINE_LINEF_DISCONNECTED: return(", (disconnected)"); break;
2884     case MIXERLINE_LINEF_SOURCE: return(", (source)"); break;
2885     default: return(""); break;
2886     }
2887 }
2888 
mixer_target_name(int type)2889 static char *mixer_target_name(int type)
2890 {
2891   switch (type)
2892     {
2893     case MIXERLINE_TARGETTYPE_UNDEFINED: return("undefined"); break;
2894     case MIXERLINE_TARGETTYPE_WAVEOUT: return("output"); break;
2895     case MIXERLINE_TARGETTYPE_WAVEIN: return("input"); break;
2896     case MIXERLINE_TARGETTYPE_MIDIOUT: return("midi output"); break;
2897     case MIXERLINE_TARGETTYPE_MIDIIN: return("midi input"); break;
2898     case MIXERLINE_TARGETTYPE_AUX: return("aux"); break;
2899     default: return(""); break;
2900     }
2901 }
2902 
mixer_component_name(int type)2903 static char *mixer_component_name(int type)
2904 {
2905   switch (type)
2906     {
2907     case MIXERLINE_COMPONENTTYPE_DST_UNDEFINED: return("undefined"); break;
2908     case MIXERLINE_COMPONENTTYPE_DST_DIGITAL: return("digital"); break;
2909     case MIXERLINE_COMPONENTTYPE_DST_LINE: return("line"); break;
2910     case MIXERLINE_COMPONENTTYPE_DST_MONITOR: return("monitor"); break;
2911     case MIXERLINE_COMPONENTTYPE_DST_SPEAKERS: return("speakers"); break;
2912     case MIXERLINE_COMPONENTTYPE_DST_HEADPHONES: return("headphones"); break;
2913     case MIXERLINE_COMPONENTTYPE_DST_TELEPHONE: return("telephone"); break;
2914     case MIXERLINE_COMPONENTTYPE_DST_WAVEIN: return("wave in"); break;
2915     case MIXERLINE_COMPONENTTYPE_DST_VOICEIN: return("voice in"); break;
2916     case MIXERLINE_COMPONENTTYPE_SRC_UNDEFINED: return("undefined"); break;
2917     case MIXERLINE_COMPONENTTYPE_SRC_DIGITAL: return("digital"); break;
2918     case MIXERLINE_COMPONENTTYPE_SRC_LINE: return("line"); break;
2919     case MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE: return("mic"); break;
2920     case MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER: return("synth"); break;
2921     case MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC: return("CD"); break;
2922     case MIXERLINE_COMPONENTTYPE_SRC_TELEPHONE: return("telephone"); break;
2923     case MIXERLINE_COMPONENTTYPE_SRC_PCSPEAKER: return("speaker"); break;
2924     case MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT: return("wave out"); break;
2925     case MIXERLINE_COMPONENTTYPE_SRC_AUXILIARY: return("aux"); break;
2926     case MIXERLINE_COMPONENTTYPE_SRC_ANALOG: return("analog"); break;
2927     default: return(""); break;
2928     }
2929 }
2930 
mus_audio_moniker(void)2931 char *mus_audio_moniker(void) {return("MS audio");} /* version number of some sort? */
2932 
mus_audio_initialize(void)2933 int mus_audio_initialize(void)
2934 {
2935   return(MUS_NO_ERROR);
2936 }
2937 
mus_audio_close(int line)2938 int mus_audio_close(int line)
2939 {
2940   win_out_err = 0;
2941   win_in_err = 0;
2942   if (line == OUTPUT_LINE)
2943     {
2944       /* fill with a few zeros, wait for empty flag */
2945       if (sound_state != SOUND_UNREADY)
2946         {
2947 	  int i;
2948           wait_for_empty_buffer(current_buf);
2949           for (i = 0; i < 128; i++) wh[current_buf].lpData[i] = 0;
2950           wait_for_empty_buffer(current_buf);
2951           win_out_err = waveOutClose(fd);
2952 	  i = 0;
2953           while (win_out_err == WAVERR_STILLPLAYING)
2954             {
2955 	      Sleep(1);
2956               win_out_err = waveOutClose(fd);
2957 	      i++;
2958 	      if (i > 1024) break;
2959             }
2960           db_state[0] = BUFFER_EMPTY;
2961           db_state[1] = BUFFER_EMPTY;
2962           sound_state = SOUND_UNREADY;
2963           waveOutUnprepareHeader(fd, &(wh[0]), sizeof(WAVEHDR));
2964           waveOutUnprepareHeader(fd, &(wh[1]), sizeof(WAVEHDR));
2965           free(wh[0].lpData);
2966           free(wh[1].lpData);
2967           if (win_out_err)
2968 	    return_error_exit(MUS_AUDIO_CANT_CLOSE,
2969 			      mus_format("close failed on %d",
2970 					 line));
2971         }
2972     }
2973   else
2974     {
2975       if (line == INPUT_LINE)
2976         {
2977           if (rec_state != SOUND_UNREADY)
2978             {
2979               waveInReset(record_fd);
2980               waveInClose(record_fd);
2981               waveInUnprepareHeader(record_fd, &rec_wh, sizeof(WAVEHDR));
2982               if (rec_wh.lpData)
2983 		{
2984 		  free(rec_wh.lpData);
2985 		  rec_wh.lpData = NULL;
2986 		}
2987               rec_state = SOUND_UNREADY;
2988             }
2989         }
2990       else
2991 	return_error_exit(MUS_AUDIO_CANT_CLOSE,
2992 			  mus_format("can't close unrecognized line %d",
2993 				     line));
2994     }
2995   return(MUS_NO_ERROR);
2996 }
2997 
2998   /*
2999    * waveInAddBuffer sends buffer to get data
3000    * MM_WIM_DATA lParam->WAVEHDR dwBytesRecorded =>how much data actually in buffer
3001    */
3002 
3003 static int current_record_chans = 0, current_record_datum_size = 0;
3004 
next_input_buffer(HWAVEIN w,UINT msg,DWORD user_data,DWORD p1,DWORD p2)3005 DWORD CALLBACK next_input_buffer(HWAVEIN w, UINT msg, DWORD user_data, DWORD p1, DWORD p2)
3006 {
3007   if (msg == WIM_DATA)
3008     {
3009       /* grab data */
3010       /* p1->dwBytesRecorded */
3011     }
3012   return(0);
3013 }
3014 
mus_audio_open_input(int ur_dev,int srate,int chans,mus_sample_t samp_type,int size)3015 int mus_audio_open_input(int ur_dev, int srate, int chans, mus_sample_t samp_type, int size)
3016 {
3017   WAVEFORMATEX wf;
3018   int dev;
3019   win_in_err = 0;
3020   dev = MUS_AUDIO_DEVICE(ur_dev);
3021   wf.nChannels = chans;
3022   current_record_chans = chans;
3023 
3024   wf.wFormatTag = WAVE_FORMAT_PCM;
3025   wf.cbSize = 0;
3026   if (samp_type == MUS_UBYTE)
3027     {
3028       wf.wBitsPerSample = 8;
3029       current_record_datum_size = 1;
3030     }
3031   else
3032     {
3033       wf.wBitsPerSample = 16;
3034       current_record_datum_size = 2;
3035     }
3036   wf.nSamplesPerSec = srate;
3037   wf.nBlockAlign = chans * current_datum_size;
3038   wf.nAvgBytesPerSec = wf.nBlockAlign * wf.nSamplesPerSec;
3039 
3040   rec_wh.dwBufferLength = size * current_record_datum_size;
3041   rec_wh.dwFlags = 0;
3042   rec_wh.dwLoops = 0;
3043   rec_wh.lpData = (char *)calloc(rec_wh.dwBufferLength, sizeof(char));
3044   if ((rec_wh.lpData) == 0)
3045     return_error_exit(MUS_AUDIO_SIZE_NOT_AVAILABLE,
3046 		      mus_format("can't allocated %d bytes for input buffer of %d", size, dev));
3047 #if _MSC_VER
3048   win_in_err = waveInOpen(&record_fd, WAVE_MAPPER, &wf, (DWORD (*)(HWAVEIN,UINT,DWORD,DWORD,DWORD))next_input_buffer, 0, CALLBACK_FUNCTION);
3049   /* why isn't the simple cast (DWORD) correct here as below? -- the docs say the 4th arg's type is DWORD */
3050 #else
3051   win_in_err = waveInOpen(&record_fd, WAVE_MAPPER, &wf, (DWORD)next_input_buffer, 0, CALLBACK_FUNCTION);
3052 #endif
3053   if (win_in_err)
3054     {
3055       free(rec_wh.lpData);
3056       return_error_exit(MUS_AUDIO_DEVICE_NOT_AVAILABLE,
3057 			mus_format("can't open input device %d", dev));
3058     }
3059   win_in_err = waveInPrepareHeader(record_fd, &(rec_wh), sizeof(WAVEHDR));
3060   if (win_in_err)
3061     {
3062       free(rec_wh.lpData);
3063       waveInClose(record_fd);
3064       return_error_exit(MUS_AUDIO_CONFIGURATION_NOT_AVAILABLE,
3065 			mus_format("can't prepare input 'header' for %d", dev));
3066     }
3067   return(MUS_NO_ERROR);
3068 }
3069 
mus_audio_read(int line,char * buf,int bytes)3070 int mus_audio_read(int line, char *buf, int bytes)
3071 {
3072   win_in_err = 0;
3073   return(MUS_ERROR);
3074 }
3075 
3076 #endif
3077 
3078 
3079 
3080 /* ------------------------------- Mac OSX ----------------------------------------- */
3081 
3082 /* this code based primarily on the CoreAudio headers and portaudio pa_mac_core.c,
3083  *   and to a much lesser extent, coreaudio.pdf and the HAL/Daisy examples.
3084  */
3085 
3086 #ifdef __APPLE__
3087 #define AUDIO_OK 1
3088 
3089 #include <AvailabilityMacros.h>
3090 
3091 /*
3092 #include <CoreServices/CoreServices.h>
3093 #include <CoreAudio/CoreAudio.h>
3094 */
3095 /* ./System/Library/Frameworks/CoreAudio.framework/Headers/CoreAudio.h */
3096 
osx_error(OSStatus err)3097 static const char* osx_error(OSStatus err)
3098 {
3099   if (err == noErr) return("no error");
3100   switch (err)
3101     {
3102     case kAudioHardwareNoError:               return("no error");
3103     case kAudioHardwareUnspecifiedError:      return("unspecified audio hardware error");
3104     case kAudioHardwareNotRunningError:       return("audio hardware not running");
3105     case kAudioHardwareUnknownPropertyError:  return("unknown property");
3106     case kAudioHardwareBadPropertySizeError:  return("bad property");
3107     case kAudioHardwareBadDeviceError:        return("bad device");
3108     case kAudioHardwareBadStreamError:        return("bad stream");
3109     case kAudioHardwareIllegalOperationError: return("illegal operation");
3110     case kAudioDeviceUnsupportedFormatError:  return("unsupported sample type");
3111     case kAudioDevicePermissionsError:        return("device permissions error");
3112     }
3113   return("unknown error");
3114 }
3115 
3116 #define MAX_BUFS 4
3117 static char **bufs = NULL;
3118 static uint32_t in_buf = 0, out_buf = 0;
3119 
writer(AudioDeviceID inDevice,const AudioTimeStamp * inNow,const AudioBufferList * InputData,const AudioTimeStamp * InputTime,AudioBufferList * OutputData,const AudioTimeStamp * OutputTime,void * appGlobals)3120 static OSStatus writer(AudioDeviceID inDevice,
3121 		       const AudioTimeStamp *inNow,
3122 		       const AudioBufferList *InputData, const AudioTimeStamp *InputTime,
3123 		       AudioBufferList *OutputData, const AudioTimeStamp *OutputTime,
3124 		       void *appGlobals)
3125 {
3126   AudioBuffer abuf;
3127   char *aplbuf, *sndbuf;
3128   abuf = OutputData->mBuffers[0];
3129   aplbuf = (char *)(abuf.mData);
3130   sndbuf = bufs[out_buf];
3131   memmove((void *)aplbuf, (void *)sndbuf, abuf.mDataByteSize);
3132   out_buf++;
3133   if (out_buf >= MAX_BUFS) out_buf = 0;
3134   return(noErr);
3135 }
3136 
reader(AudioDeviceID inDevice,const AudioTimeStamp * inNow,const AudioBufferList * InputData,const AudioTimeStamp * InputTime,AudioBufferList * OutputData,const AudioTimeStamp * OutputTime,void * appGlobals)3137 static OSStatus reader(AudioDeviceID inDevice,
3138 		       const AudioTimeStamp *inNow,
3139 		       const AudioBufferList *InputData, const AudioTimeStamp *InputTime,
3140 		       AudioBufferList *OutputData, const AudioTimeStamp *OutputTime,
3141 		       void *appGlobals)
3142 {
3143   AudioBuffer abuf;
3144   char *aplbuf, *sndbuf;
3145   abuf = InputData->mBuffers[0];
3146   aplbuf = (char *)(abuf.mData);
3147   sndbuf = bufs[out_buf];
3148   memmove((void *)sndbuf, (void *)aplbuf, abuf.mDataByteSize);
3149   out_buf++;
3150   if (out_buf >= MAX_BUFS) out_buf = 0;
3151   return(noErr);
3152 }
3153 
3154 
3155 static AudioDeviceID device = kAudioDeviceUnknown;
3156 static bool writing = false, open_for_input = false;
3157 
3158 #ifdef MAC_OS_X_VERSION_10_5
3159   #define HAVE_OSX_10_5 1
3160 #else
3161   #define HAVE_OSX_10_5 0
3162 #endif
3163 
3164 #if HAVE_OSX_10_5
3165   static AudioDeviceIOProcID read_procId, write_procId;
3166 #endif
3167 
mus_audio_close(int line)3168 int mus_audio_close(int line)
3169 {
3170   OSStatus err = noErr;
3171   UInt32 sizeof_running;
3172   UInt32 running;
3173   if (open_for_input)
3174     {
3175       in_buf = 0;
3176       err = AudioDeviceStop(device, (AudioDeviceIOProc)reader);
3177       if (err == noErr)
3178 #if HAVE_OSX_10_5
3179 	err = AudioDeviceDestroyIOProcID(device, read_procId);
3180 #else
3181         err = AudioDeviceRemoveIOProc(device, (AudioDeviceIOProc)reader);
3182 #endif
3183     }
3184   else
3185     {
3186       if ((in_buf > 0) && (!writing))
3187 	{
3188 	  /* short enough sound that we never got started? */
3189 #if HAVE_OSX_10_5
3190 	  err = AudioDeviceCreateIOProcID(device, (AudioDeviceIOProc)writer, NULL, &write_procId);
3191 #else
3192 	  err = AudioDeviceAddIOProc(device, (AudioDeviceIOProc)writer, NULL);
3193 #endif
3194 	  if (err == noErr)
3195 	    err = AudioDeviceStart(device, (AudioDeviceIOProc)writer); /* writer will be called right away */
3196 	  if (err == noErr)
3197 	    writing = true;
3198 	}
3199       if (writing)
3200 	{
3201 	  /* send out waiting buffers */
3202 	  sizeof_running = sizeof(UInt32);
3203 	  while (in_buf == out_buf)
3204 	    {
3205 	      /* err = AudioDeviceGetProperty(device, 0, false, kAudioDevicePropertyDeviceIsRunning, &sizeof_running, &running); */
3206 	      {
3207 		AudioObjectPropertyAddress device_address = { kAudioDevicePropertyDeviceIsRunning,
3208 							      kAudioDevicePropertyScopeOutput,
3209 							      kAudioObjectPropertyElementMaster };
3210 		err = AudioObjectGetPropertyData(device, &device_address, 0, NULL, &sizeof_running, &running);
3211 	      }
3212 	    }
3213 	  while (in_buf != out_buf)
3214 	    {
3215 	      /* err = AudioDeviceGetProperty(device, 0, false, kAudioDevicePropertyDeviceIsRunning, &sizeof_running, &running); */
3216 	      {
3217 		AudioObjectPropertyAddress device_address = { kAudioDevicePropertyDeviceIsRunning,
3218 							      kAudioDevicePropertyScopeOutput,
3219 							      kAudioObjectPropertyElementMaster };
3220 		err = AudioObjectGetPropertyData(device, &device_address, 0, NULL, &sizeof_running, &running);
3221 	      }
3222 	    }
3223 	  in_buf = 0;
3224 	  err = AudioDeviceStop(device, (AudioDeviceIOProc)writer);
3225 	  if (err == noErr)
3226 #if HAVE_OSX_10_5
3227 	    err = AudioDeviceDestroyIOProcID(device, write_procId);
3228 #else
3229 	    err = AudioDeviceRemoveIOProc(device, (AudioDeviceIOProc)writer);
3230 #endif
3231 	  writing = false;
3232 	}
3233     }
3234   device = kAudioDeviceUnknown;
3235   if (err == noErr)
3236     return(MUS_NO_ERROR);
3237   return(MUS_ERROR);
3238 }
3239 
3240 typedef enum {CONVERT_NOT, CONVERT_COPY, CONVERT_SKIP, CONVERT_COPY_AND_SKIP, CONVERT_SKIP_N, CONVERT_COPY_AND_SKIP_N} audio_convert_t;
3241 static audio_convert_t conversion_choice = CONVERT_NOT;
3242 static float conversion_multiplier = 1.0;
3243 static int dac_out_chans, dac_out_srate;
3244 static int incoming_out_chans = 1, incoming_out_srate = 44100;
3245 static uint32_t fill_point = 0;
3246 static uint32_t bufsize = 0, current_bufsize = 0;
3247 static bool match_dac_to_sound = true;
3248 
3249 
mus_audio_output_properties_mutable(bool mut)3250 bool mus_audio_output_properties_mutable(bool mut)
3251 {
3252   match_dac_to_sound = mut;
3253   return(mut);
3254 }
3255 
3256 
3257 /* I'm getting bogus buffer sizes from the audio conversion stuff from Apple,
3258  *   and I think AudioConvert doesn't handle cases like 4->6 chans correctly
3259  *   so, I'll just do the conversions myself -- there is little need here
3260  *   for non-integer srate conversion anyway, and the rest is trivial.
3261  */
3262 
mus_audio_open_output(int dev,int srate,int chans,mus_sample_t samp_type,int size)3263 int mus_audio_open_output(int dev, int srate, int chans, mus_sample_t samp_type, int size)
3264 {
3265   OSStatus err = noErr;
3266   UInt32 sizeof_device, sizeof_format, sizeof_bufsize;
3267   AudioStreamBasicDescription device_desc;
3268 
3269   device = 0;
3270   sizeof_device = sizeof(AudioDeviceID);
3271   sizeof_bufsize = sizeof(uint32_t);
3272 
3273   /* err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &sizeof_device, (void *)(&device)); */
3274   {
3275     AudioObjectPropertyAddress device_address = { kAudioHardwarePropertyDefaultOutputDevice,
3276 						  kAudioObjectPropertyScopeGlobal,
3277 						  kAudioObjectPropertyElementMaster };
3278     err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &device_address, 0, NULL, &sizeof_device, &device);
3279   }
3280 
3281   bufsize = 4096;
3282   if (err == noErr)
3283     {
3284       /* err = AudioDeviceGetProperty(device, 0, false, kAudioDevicePropertyBufferSize, &sizeof_bufsize, &bufsize); */
3285       {
3286 	AudioObjectPropertyAddress device_address = { kAudioDevicePropertyBufferSize,
3287 						      kAudioDevicePropertyScopeOutput,
3288 						      kAudioObjectPropertyElementMaster };
3289 	err = AudioObjectGetPropertyData(device, &device_address, 0, NULL, &sizeof_bufsize, &bufsize);
3290       }
3291     }
3292   if (err != noErr)
3293     {
3294       fprintf(stderr, "open audio output err: %d %s\n", (int)err, osx_error(err));
3295       return(MUS_ERROR);
3296     }
3297 
3298   sizeof_format = sizeof(AudioStreamBasicDescription);
3299   /* err = AudioDeviceGetProperty(device, 0, false, kAudioDevicePropertyStreamFormat, &sizeof_format, &device_desc); */
3300   {
3301     AudioObjectPropertyAddress device_address = { kAudioDevicePropertyStreamFormat,
3302 						  kAudioDevicePropertyScopeOutput,
3303 						  kAudioObjectPropertyElementMaster };
3304     err = AudioObjectGetPropertyData(device, &device_address, 0, NULL, &sizeof_format, &device_desc);
3305   }
3306 
3307   if (err != noErr)
3308     {
3309       fprintf(stderr, "open audio output (get device format) err: %d %s\n", (int)err, osx_error(err));
3310       return(MUS_ERROR);
3311     }
3312 
3313   if (match_dac_to_sound)
3314     {
3315       /* now check for srate/chan mismatches and so on */
3316 
3317       /* current DAC state: device_desc.mChannelsPerFrame, (int)(device_desc.mSampleRate) */
3318       /* apparently get stream format can return noErr but chans == 0?? */
3319 
3320       if (((int)device_desc.mChannelsPerFrame != chans) ||
3321 	  ((int)(device_desc.mSampleRate) != srate))
3322 	{
3323 	  /* try to match DAC settings to current sound */
3324 	  device_desc.mChannelsPerFrame = chans;
3325 	  device_desc.mSampleRate = srate;
3326 	  device_desc.mBytesPerPacket = chans * 4; /* assume 1 frame/packet and float32 data */
3327 	  device_desc.mBytesPerFrame = chans * 4;
3328 	  sizeof_format = sizeof(AudioStreamBasicDescription);
3329 	  /* err = AudioDeviceSetProperty(device, 0, 0, false, kAudioDevicePropertyStreamFormat, sizeof_format, &device_desc); */
3330 	  {
3331 	    AudioObjectPropertyAddress device_address = { kAudioDevicePropertyStreamFormat,
3332 							  kAudioDevicePropertyScopeOutput,
3333 							  kAudioObjectPropertyElementMaster };
3334 	    err = AudioObjectSetPropertyData(device, &device_address, 0, NULL, sizeof_format, &device_desc);
3335 	  }
3336 
3337 	  /* this error is bogus in some cases -- other audio systems just ignore it,
3338 	   *   but in my case (a standard MacIntel with no special audio hardware), if I leave
3339 	   *   this block out, the sound is played back at the wrong rate, and the volume
3340 	   *   of outa is set to 0.0??
3341 	   */
3342 
3343 	  if (err != noErr)
3344 	    {
3345 	      /* it must have failed for some reason -- look for closest match available */
3346 	      /* if srate = 22050 try 44100, if chans = 1 try 2 */
3347 	      /* the "get closest match" business appears to be completely bogus... */
3348 
3349 	      device_desc.mChannelsPerFrame = (chans == 1) ? 2 : chans;
3350 	      device_desc.mSampleRate = (srate == 22050) ? 44100 : srate;
3351 	      device_desc.mBytesPerPacket = device_desc.mChannelsPerFrame * 4; /* assume 1 frame/packet and float32 data */
3352 	      device_desc.mBytesPerFrame = device_desc.mChannelsPerFrame * 4;
3353 	      sizeof_format = sizeof(AudioStreamBasicDescription);
3354 	      /* err = AudioDeviceSetProperty(device, 0, 0, false, kAudioDevicePropertyStreamFormat, sizeof_format, &device_desc); */
3355 	      {
3356 		AudioObjectPropertyAddress device_address = { kAudioDevicePropertyStreamFormat,
3357 							      kAudioDevicePropertyScopeOutput,
3358 							      kAudioObjectPropertyElementMaster };
3359 		err = AudioObjectSetPropertyData(device, &device_address, 0, NULL, sizeof_format, &device_desc);
3360 	      }
3361 	      if (err != noErr)
3362 		{
3363 		  sizeof_format = sizeof(AudioStreamBasicDescription);
3364 		  /* err = AudioDeviceGetProperty(device, 0, false, kAudioDevicePropertyStreamFormatMatch, &sizeof_format, &device_desc); */
3365 		  {
3366 		    AudioObjectPropertyAddress device_address = { kAudioDevicePropertyStreamFormatMatch,
3367 								  kAudioDevicePropertyScopeOutput,
3368 								  kAudioObjectPropertyElementMaster };
3369 		    err = AudioObjectGetPropertyData(device, &device_address, 0, NULL, &sizeof_format, &device_desc);
3370 		  }
3371 
3372 		  if (err == noErr)
3373 		    {
3374 		      /* match suggests: device_desc.mChannelsPerFrame, (int)(device_desc.mSampleRate) */
3375 		      /* try to set DAC to reflect that match */
3376 		      /* a bug here in emagic 2|6 -- we can get 6 channel match, but then can't set it?? */
3377 
3378 		      sizeof_format = sizeof(AudioStreamBasicDescription);
3379 		      /* err = AudioDeviceSetProperty(device, 0, 0, false, kAudioDevicePropertyStreamFormat, sizeof_format, &device_desc); */
3380 		      {
3381 			AudioObjectPropertyAddress device_address = { kAudioDevicePropertyStreamFormat,
3382 								      kAudioDevicePropertyScopeOutput,
3383 								      kAudioObjectPropertyElementMaster };
3384 			err = AudioObjectSetPropertyData(device, &device_address, 0, NULL, sizeof_format, &device_desc);
3385 		      }
3386 		      if (err != noErr)
3387 			{
3388 			  /* no luck -- get current DAC settings at least */
3389 			  sizeof_format = sizeof(AudioStreamBasicDescription);
3390 			  /* AudioDeviceGetProperty(device, 0, false, kAudioDevicePropertyStreamFormat, &sizeof_format, &device_desc); */
3391 			  {
3392 			    AudioObjectPropertyAddress device_address = { kAudioDevicePropertyStreamFormat,
3393 									  kAudioDevicePropertyScopeOutput,
3394 									  kAudioObjectPropertyElementMaster };
3395 			    err = AudioObjectGetPropertyData(device, &device_address, 0, NULL, &sizeof_format, &device_desc);
3396 			  }
3397 			}
3398 		    }
3399 		}
3400 	      else
3401 		{
3402 		  /* nothing matches? -- get current DAC settings */
3403 		  sizeof_format = sizeof(AudioStreamBasicDescription);
3404 		  /* AudioDeviceGetProperty(device, 0, false, kAudioDevicePropertyStreamFormat, &sizeof_format, &device_desc); */
3405 		  {
3406 		    AudioObjectPropertyAddress device_address = { kAudioDevicePropertyStreamFormat,
3407 								  kAudioDevicePropertyScopeOutput,
3408 								  kAudioObjectPropertyElementMaster };
3409 		    err = AudioObjectGetPropertyData(device, &device_address, 0, NULL, &sizeof_format, &device_desc);
3410 		  }
3411 		}
3412 	    }
3413 	}
3414     } /* end mismatch check */
3415 
3416   /* now DAC claims it is ready for device_desc.mChannelsPerFrame, (int)(device_desc.mSampleRate) */
3417   dac_out_chans = device_desc.mChannelsPerFrame; /* use better variable names */
3418   dac_out_srate = (int)(device_desc.mSampleRate);
3419 
3420   open_for_input = false;
3421   if ((!bufs) || (bufsize > current_bufsize))
3422     {
3423       int i;
3424       if (bufs)
3425 	{
3426 	  for (i = 0; i < MAX_BUFS; i++) free(bufs[i]);
3427 	  free(bufs);
3428 	}
3429       bufs = (char **)calloc(MAX_BUFS, sizeof(char *));
3430       for (i = 0; i < MAX_BUFS; i++)
3431 	bufs[i] = (char *)calloc(bufsize, sizeof(char));
3432       current_bufsize = bufsize;
3433     }
3434 
3435   in_buf = 0;
3436   out_buf = 0;
3437   fill_point = 0;
3438 
3439   if (!match_dac_to_sound)
3440     {
3441       incoming_out_srate = dac_out_srate;
3442       incoming_out_chans = dac_out_chans;
3443       conversion_choice = CONVERT_NOT;
3444       conversion_multiplier = 1.0;
3445       return(MUS_NO_ERROR);
3446     }
3447 
3448   incoming_out_srate = srate;
3449   incoming_out_chans = chans;
3450 
3451   if (incoming_out_chans == dac_out_chans)
3452     {
3453       if (incoming_out_srate == dac_out_srate)
3454 	{
3455 	  conversion_choice = CONVERT_NOT;
3456 	  conversion_multiplier = 1.0;
3457 	}
3458       else
3459 	{
3460 	  /* here we don't get very fancy -- assume dac/2=in */
3461 	  conversion_choice = CONVERT_COPY;
3462 	  conversion_multiplier = 2.0;
3463 	}
3464     }
3465   else
3466     {
3467       if (incoming_out_srate == dac_out_srate)
3468 	{
3469 	  if ((dac_out_chans == 2) && (incoming_out_chans == 1)) /* the usual case */
3470 	    {
3471 	      conversion_choice = CONVERT_SKIP;
3472 	      conversion_multiplier = 2.0;
3473 	    }
3474 	  else
3475 	    {
3476 	      conversion_choice = CONVERT_SKIP_N;
3477 	      conversion_multiplier = ((float)dac_out_chans / (float)incoming_out_chans);
3478 	    }
3479 	}
3480       else
3481 	{
3482 	  if ((dac_out_chans == 2) && (incoming_out_chans == 1)) /* the usual case */
3483 	    {
3484 	      conversion_choice = CONVERT_COPY_AND_SKIP;
3485 	      conversion_multiplier = 4.0;
3486 	    }
3487 	  else
3488 	    {
3489 	      conversion_choice = CONVERT_COPY_AND_SKIP_N;
3490 	      conversion_multiplier = ((float)dac_out_chans / (float)incoming_out_chans) * 2;
3491 	    }
3492 	}
3493     }
3494   return(MUS_NO_ERROR);
3495 }
3496 
3497 
convert_incoming(char * to_buf,int fill_point,int lim,char * buf)3498 static void convert_incoming(char *to_buf, int fill_point, int lim, char *buf)
3499 {
3500   int i, j, k, jc, kc, ic;
3501   switch (conversion_choice)
3502     {
3503     case CONVERT_NOT:
3504       /* no conversion needed */
3505       for (i = 0; i < lim; i++)
3506 	to_buf[i + fill_point] = buf[i];
3507       break;
3508 
3509     case CONVERT_COPY:
3510       /* copy sample to mimic lower srate */
3511       for (i = 0, j = fill_point; i < lim; i += 8, j += 16)
3512 	for (k = 0; k < 8; k++)
3513 	  {
3514 	    to_buf[j + k] = buf[i + k];
3515 	    to_buf[j + k + 8] = buf[i + k];
3516 	  }
3517       break;
3518 
3519     case CONVERT_SKIP:
3520       /* skip sample for empty chan */
3521       for (i = 0, j = fill_point; i < lim; i += 4, j += 8)
3522 	for (k = 0; k < 4; k++)
3523 	  {
3524 	    to_buf[j + k] = buf[i + k];
3525 	    to_buf[j + k + 4] = 0;
3526 	  }
3527       break;
3528 
3529     case CONVERT_SKIP_N:
3530       /* copy incoming_out_chans then skip up to dac_out_chans */
3531       jc = dac_out_chans * 4;
3532       ic = incoming_out_chans * 4;
3533       for (i = 0, j = fill_point; i < lim; i += ic, j += jc)
3534 	{
3535 	  for (k = 0; k < ic; k++) to_buf[j + k] = buf[i + k];
3536 	  for (k = ic; k < jc; k++) to_buf[j + k] = 0;
3537 	}
3538       break;
3539 
3540     case CONVERT_COPY_AND_SKIP:
3541       for (i = 0, j = fill_point; i < lim; i += 4, j += 16)
3542 	for (k = 0; k < 4; k++)
3543 	  {
3544 	    to_buf[j + k] = buf[i + k];
3545 	    to_buf[j + k + 4] = 0;
3546 	    to_buf[j + k + 8] = buf[i + k];
3547 	    to_buf[j + k + 12] = 0;
3548 	  }
3549       break;
3550 
3551     case CONVERT_COPY_AND_SKIP_N:
3552       /* copy for each active chan, skip rest */
3553       jc = dac_out_chans * 8;
3554       ic = incoming_out_chans * 4;
3555       kc = dac_out_chans * 4;
3556       for (i = 0, j = fill_point; i < lim; i += ic, j += jc)
3557 	{
3558 	  for (k = 0; k < ic; k++)
3559 	    {
3560 	      to_buf[j + k] = buf[i + k];
3561 	      to_buf[j + k + kc] = buf[i + k];
3562 	    }
3563 	  for (k = ic; k < kc; k++)
3564 	    {
3565 	      to_buf[j + k] = 0;
3566 	      to_buf[j + k + kc] = 0;
3567 	    }
3568 	}
3569       break;
3570     }
3571 }
3572 
3573 
mus_audio_write(int line,char * buf,int bytes)3574 int mus_audio_write(int line, char *buf, int bytes)
3575 {
3576   OSStatus err = noErr;
3577   uint32_t lim, out_bytes;
3578   UInt32 sizeof_running;
3579   UInt32 running;
3580   char *to_buf;
3581 
3582   to_buf = bufs[in_buf];
3583   out_bytes = (uint32_t)(bytes * conversion_multiplier);
3584   if ((fill_point + out_bytes) > bufsize)
3585     out_bytes = bufsize - fill_point;
3586   lim = (uint32_t)(out_bytes / conversion_multiplier);
3587 
3588   if (!writing)
3589     {
3590       convert_incoming(to_buf, fill_point, lim, buf);
3591       fill_point += out_bytes;
3592       if (fill_point >= bufsize)
3593 	{
3594 	  in_buf++;
3595 	  fill_point = 0;
3596 	  if (in_buf == MAX_BUFS)
3597 	    {
3598 	      in_buf = 0;
3599 #if HAVE_OSX_10_5
3600 	      err = AudioDeviceCreateIOProcID(device, (AudioDeviceIOProc)writer, NULL, &write_procId);
3601 #else
3602 	      err = AudioDeviceAddIOProc(device, (AudioDeviceIOProc)writer, NULL);
3603 #endif
3604 	      if (err == noErr)
3605 		err = AudioDeviceStart(device, (AudioDeviceIOProc)writer); /* writer will be called right away */
3606 	      if (err == noErr)
3607 		{
3608 		  writing = true;
3609 		  return(MUS_NO_ERROR);
3610 		}
3611 	      else return(MUS_ERROR);
3612 	    }
3613 	}
3614       return(MUS_NO_ERROR);
3615     }
3616   if ((fill_point == 0) && (in_buf == out_buf))
3617     {
3618       uint32_t bp;
3619       bp = out_buf;
3620       sizeof_running = sizeof(UInt32);
3621       while (bp == out_buf)
3622 	{
3623 	  /* i.e. just kill time without hanging */
3624 	  /* err = AudioDeviceGetProperty(device, 0, false, kAudioDevicePropertyDeviceIsRunning, &sizeof_running, &running); */
3625 	  {
3626 	    AudioObjectPropertyAddress device_address = { kAudioDevicePropertyDeviceIsRunning,
3627 							  kAudioDevicePropertyScopeOutput,
3628 							  kAudioObjectPropertyElementMaster };
3629 	    err = AudioObjectGetPropertyData(device, &device_address, 0, NULL, &sizeof_running, &running);
3630 	  }
3631 	  /* usleep(10); */
3632 	}
3633     }
3634   to_buf = bufs[in_buf];
3635   if (fill_point == 0) memset((void *)to_buf, 0, bufsize);
3636   convert_incoming(to_buf, fill_point, lim, buf);
3637   fill_point += out_bytes;
3638   if (fill_point >= bufsize)
3639     {
3640       in_buf++;
3641       fill_point = 0;
3642       if (in_buf >= MAX_BUFS) in_buf = 0;
3643     }
3644   return(MUS_NO_ERROR);
3645 }
3646 
mus_audio_open_input(int dev,int srate,int chans,mus_sample_t samp_type,int size)3647 int mus_audio_open_input(int dev, int srate, int chans, mus_sample_t samp_type, int size)
3648 {
3649   OSStatus err = noErr;
3650   UInt32 sizeof_device;
3651   UInt32 sizeof_bufsize;
3652 
3653   sizeof_device = sizeof(AudioDeviceID);
3654   sizeof_bufsize = sizeof(uint32_t);
3655 
3656   device = 0;
3657   /* err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &sizeof_device, (void *)(&device)); */
3658   {
3659     AudioObjectPropertyAddress device_address = { kAudioHardwarePropertyDefaultInputDevice,
3660 						  kAudioObjectPropertyScopeGlobal,
3661 						  kAudioObjectPropertyElementMaster };
3662     err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &device_address, 0, NULL, &sizeof_device, &device);
3663   }
3664 
3665   bufsize = 4096;
3666   if (err == noErr)
3667     {
3668       /* err = AudioDeviceGetProperty(device, 0, true, kAudioDevicePropertyBufferSize, &sizeof_bufsize, &bufsize); */
3669       {
3670 	AudioObjectPropertyAddress device_address = { kAudioDevicePropertyBufferSize,
3671 						      kAudioDevicePropertyScopeInput,
3672 						      kAudioObjectPropertyElementMaster };
3673 	err = AudioObjectGetPropertyData(device, &device_address, 0, NULL, &sizeof_bufsize, &bufsize);
3674       }
3675     }
3676   if (err != noErr)
3677     {
3678       fprintf(stderr, "open audio input err: %d %s\n", (int)err, osx_error(err));
3679       return(MUS_ERROR);
3680     }
3681   open_for_input = true;
3682   /* assume for now that recorder (higher level) will enforce match */
3683   if ((!bufs) || (bufsize > current_bufsize))
3684     {
3685       int i;
3686       if (bufs)
3687 	{
3688 	  for (i = 0; i < MAX_BUFS; i++) free(bufs[i]);
3689 	  free(bufs);
3690 	}
3691       bufs = (char **)calloc(MAX_BUFS, sizeof(char *));
3692       for (i = 0; i < MAX_BUFS; i++)
3693 	bufs[i] = (char *)calloc(bufsize, sizeof(char));
3694       current_bufsize = bufsize;
3695     }
3696   in_buf = 0;
3697   out_buf = 0;
3698   fill_point = 0;
3699   incoming_out_srate = srate;
3700   incoming_out_chans = chans;
3701 
3702 #if HAVE_OSX_10_5
3703   err = AudioDeviceCreateIOProcID(device, (AudioDeviceIOProc)reader, NULL, &read_procId);
3704 #else
3705   err = AudioDeviceAddIOProc(device, (AudioDeviceIOProc)reader, NULL);
3706 #endif
3707 
3708   if (err == noErr)
3709     err = AudioDeviceStart(device, (AudioDeviceIOProc)reader);
3710   if (err != noErr)
3711     {
3712       fprintf(stderr, "add open audio input err: %d %s\n", (int)err, osx_error(err));
3713       return(MUS_ERROR);
3714     }
3715   return(MUS_NO_ERROR);
3716 }
3717 
mus_audio_read(int line,char * buf,int bytes)3718 int mus_audio_read(int line, char *buf, int bytes)
3719 {
3720   OSStatus err = noErr;
3721   UInt32 sizeof_running;
3722   UInt32 running;
3723   char *to_buf;
3724 
3725   if (in_buf == out_buf)
3726     {
3727       uint32_t bp;
3728       bp = out_buf;
3729       sizeof_running = sizeof(UInt32);
3730       while (bp == out_buf)
3731 	{
3732 	  /* err = AudioDeviceGetProperty(device, 0, true, kAudioDevicePropertyDeviceIsRunning, &sizeof_running, &running); */
3733 	  {
3734 	    AudioObjectPropertyAddress device_address = { kAudioDevicePropertyDeviceIsRunning,
3735 							  kAudioDevicePropertyScopeInput,
3736 							  kAudioObjectPropertyElementMaster };
3737 	    err = AudioObjectGetPropertyData(device, &device_address, 0, NULL, &sizeof_running, &running);
3738 	  }
3739 	  if (err != noErr)
3740 	    fprintf(stderr, "wait err: %s ", osx_error(err));
3741 	}
3742     }
3743   to_buf = bufs[in_buf];
3744   if (bytes <= (int)bufsize)
3745     memmove((void *)buf, (void *)to_buf, bytes);
3746   else memmove((void *)buf, (void *)to_buf, bufsize);
3747   in_buf++;
3748   if (in_buf >= MAX_BUFS) in_buf = 0;
3749   return(MUS_ERROR);
3750 }
3751 
mus_audio_initialize(void)3752 int mus_audio_initialize(void) {return(MUS_NO_ERROR);}
3753 
mus_audio_moniker(void)3754 char *mus_audio_moniker(void) {return((char *)"Mac OSX audio");}
3755 #endif
3756 
3757 
3758 
3759 
3760 /* ------------------------------- JACK ----------------------------------------- */
3761 
3762 /* Kjetil S. Matheussen. k.s.matheussen@notam02.no */
3763 /* Based on code from ceres. */
3764 
3765 #if MUS_JACK
3766 #define AUDIO_OK 1
3767 #include <pthread.h>
3768 #include <jack/jack.h>
3769 #include <samplerate.h>
3770 #include <sys/mman.h>
3771 #include <signal.h>
3772 
3773 #if MUS_LITTLE_ENDIAN
3774 #  define MUS_COMP_SHORT MUS_LSHORT
3775 #  define MUS_COMP_FLOAT MUS_LFLOAT
3776 #else
3777 #  define MUS_COMP_SHORT MUS_BSHORT
3778 #  define MUS_COMP_FLOAT MUS_BFLOAT
3779 #endif
3780 
3781 #define SRC_QUALITY SRC_SINC_BEST_QUALITY
3782 
atomic_add(int * mem,int how_much)3783 static inline void atomic_add(int *mem, int how_much){
3784   __atomic_fetch_add(mem, how_much, __ATOMIC_SEQ_CST);
3785 }
3786 
3787 
3788 /*************/
3789 /* Jack Part */
3790 /*************/
3791 
3792 #define SNDJACK_BUFFERSIZE 32768
3793 
3794 typedef jack_default_audio_sample_t sample_t;
3795 typedef jack_nframes_t nframes_t;
3796 
3797 struct SndjackChannel{
3798   jack_port_t *port;
3799   sample_t *buffer;
3800 };
3801 
3802 static jack_client_t *sndjack_client = NULL;
3803 
3804 
3805 /*************************/
3806 /* Variables for reading */
3807 /*************************/
3808 static int sndjack_num_read_channels_allocated=0;
3809 static int sndjack_num_read_channels_inuse=0;
3810 static struct SndjackChannel *sndjack_read_channels=NULL;
3811 static pthread_cond_t sndjack_read_cond= PTHREAD_COND_INITIALIZER;
3812 static pthread_mutex_t sndjack_read_mutex= PTHREAD_MUTEX_INITIALIZER;
3813 static int sj_r_buffersize=0;
3814 static int sj_r_writeplace=0;
3815 static int sj_r_readplace=0;
3816 static int sj_r_unread=0;
3817 static int sj_r_xrun=0;
3818 static int sj_r_totalxrun=0;
3819 
3820 /*************************/
3821 /* Variables for writing */
3822 /*************************/
3823 static pthread_cond_t sndjack_cond= PTHREAD_COND_INITIALIZER;
3824 static pthread_mutex_t sndjack_mutex=  PTHREAD_MUTEX_INITIALIZER;
3825 
3826 enum{SJ_STOPPED,SJ_RUNNING,SJ_ABOUTTOSTOP};
3827 
3828 // Variables for the ringbuffer:
3829 static  int sj_writeplace=0;
3830 static  int sj_readplace=0;
3831 static  int sj_unread=0;
3832 static  int sj_buffersize;
3833 static int sj_jackbuffersize; // number of frames sent to sndjack_process.
3834 static int sj_totalxrun=0;
3835 static int sj_xrun=0;
3836 static int sj_status=SJ_STOPPED;
3837 
3838 static int sndjack_num_channels_allocated=0;
3839 static int sndjack_num_channels_inuse=0;
3840 static struct SndjackChannel *sndjack_channels=NULL;
3841 static int sndjack_read_format;
3842 
3843 static SRC_STATE **sndjack_srcstates;
3844 static double sndjack_srcratio=1.0;
3845 
3846 static int jack_mus_watchdog_counter=0;
3847 
3848 
3849 #define SJ_MAX(a,b) (((a)>(b))?(a):(b))
3850 
sndjack_read_process(jack_nframes_t nframes)3851 static void sndjack_read_process(jack_nframes_t nframes){
3852   int i,ch;
3853   sample_t *out[sndjack_num_channels_allocated];
3854 
3855   if (sndjack_num_read_channels_inuse==0) return;
3856 
3857   for (ch=0;ch<sndjack_num_read_channels_allocated;ch++){
3858     out[ch]=(sample_t*)jack_port_get_buffer(sndjack_read_channels[ch].port,nframes);
3859   }
3860 
3861   for (i=0;i<(int)nframes;i++){
3862     if (sj_r_unread==sj_buffersize){
3863       sj_r_xrun+=nframes-i;
3864       goto exit;
3865     }
3866     for (ch=0;ch<sndjack_num_read_channels_inuse;ch++)
3867       sndjack_read_channels[ch].buffer[sj_r_writeplace]=out[ch][i];
3868     atomic_add(&sj_r_unread,1);
3869     sj_r_writeplace++;
3870     if (sj_r_writeplace==sj_r_buffersize)
3871       sj_r_writeplace=0;
3872   }
3873  exit:
3874   pthread_cond_broadcast(&sndjack_read_cond);
3875 }
3876 
3877 
sndjack_write_process(jack_nframes_t nframes)3878 static void sndjack_write_process(jack_nframes_t nframes){
3879   int ch,i;
3880   sample_t *out[sndjack_num_channels_allocated];
3881 
3882   for (ch=0;ch<sndjack_num_channels_allocated;ch++){
3883     out[ch]=(sample_t*)jack_port_get_buffer(sndjack_channels[ch].port,nframes);
3884   }
3885 
3886   if (sj_status==SJ_STOPPED){
3887     for (ch=0;ch<sndjack_num_channels_allocated;ch++){
3888       memset(out[ch],0,nframes*sizeof(sample_t));
3889     }
3890   }else{
3891 
3892     // First null out unused channels, if any.
3893     if (sndjack_num_channels_inuse==1 && sndjack_num_channels_allocated>=2){
3894       for (ch=2;ch<sndjack_num_channels_allocated;ch++){
3895 	memset(out[ch],0,nframes*sizeof(sample_t));
3896       }
3897     }else{
3898       for (ch=sndjack_num_channels_inuse;ch<sndjack_num_channels_allocated;ch++){
3899 	memset(out[ch],0,nframes*sizeof(sample_t));
3900       }
3901     }
3902 
3903     for (i=0;i<(int)nframes;i++){
3904       if (sj_unread==0){
3905 	if (sj_status==SJ_RUNNING)
3906 	  sj_xrun+=nframes-i;
3907 	for (;i<(int)nframes;i++){
3908 	  for (ch=0;ch<sndjack_num_channels_inuse;ch++){
3909 	    out[ch][i]=0.0f;
3910 	  }
3911 	}
3912 	break;
3913       }
3914 
3915       if (sndjack_num_channels_inuse==1 && sndjack_num_channels_allocated>=2){
3916 	for (ch=0;ch<2;ch++){
3917 	  out[ch][i]=sndjack_channels[0].buffer[sj_readplace];
3918 	}
3919       }else{
3920 	for (ch=0;ch<sndjack_num_channels_inuse;ch++){
3921 	  out[ch][i]=sndjack_channels[ch].buffer[sj_readplace];
3922 	}
3923       }
3924       atomic_add(&sj_unread,-1);
3925       sj_readplace++;
3926       if (sj_readplace==sj_buffersize)
3927 	sj_readplace=0;
3928     }
3929 
3930     pthread_cond_broadcast(&sndjack_cond);
3931 
3932     if (sj_status==SJ_ABOUTTOSTOP && sj_unread==0)
3933       sj_status=SJ_STOPPED;
3934   }
3935 
3936 }
3937 
3938 
3939 
sndjack_process(jack_nframes_t nframes,void * arg)3940 static int sndjack_process(jack_nframes_t nframes, void *arg){
3941   sndjack_read_process(nframes);
3942   sndjack_write_process(nframes);
3943   return 0;
3944 }
3945 
3946 
sndjack_read(void * buf,int bytes,int chs)3947 static int sndjack_read(void *buf,int bytes,int chs){
3948   int i,ch;
3949   int nframes=bytes /
3950     sndjack_read_format==MUS_COMP_FLOAT ? sizeof(float) :
3951     sndjack_read_format==MUS_COMP_SHORT ? sizeof(short) :
3952     1;
3953   float *buf_f=(float *)buf;
3954   short *buf_s=(short *)buf;
3955   char *buf_c=(char *)buf;
3956 
3957   for (i=0;i<nframes;i++){
3958     while(sj_r_unread==0){
3959       pthread_cond_wait(&sndjack_read_cond,&sndjack_read_mutex);
3960       jack_mus_watchdog_counter++;
3961     }
3962 
3963     if (sj_r_xrun>0){
3964       sj_r_totalxrun+=sj_r_xrun;
3965       sj_r_xrun=0;
3966       return -1;
3967     }
3968     for (ch=0;ch<chs;ch++){
3969       switch (sndjack_read_format){
3970       case MUS_BYTE:
3971 	buf_c[i*chs+ch]=sndjack_read_channels[ch].buffer[sj_r_readplace] * 127.9f;
3972 	break;
3973       case MUS_COMP_SHORT:
3974 	buf_s[i*chs+ch]=sndjack_read_channels[ch].buffer[sj_r_readplace] * 32767.9f;
3975 	break;
3976       case MUS_COMP_FLOAT:
3977 	buf_f[i*chs+ch]=sndjack_read_channels[ch].buffer[sj_r_readplace];
3978 	break;
3979       }}
3980     atomic_add(&sj_r_unread,-1);
3981     sj_r_readplace++;
3982     if (sj_r_readplace==sj_r_buffersize)
3983       sj_r_readplace=0;
3984   }
3985   return 0;
3986 }
3987 
sndjack_write(sample_t ** buf,int nframes,int latencyframes,int chs)3988 static void sndjack_write(sample_t **buf,int nframes,int latencyframes,int chs){
3989   int ch;
3990   int i;
3991 
3992   if (sj_xrun>0){
3993     if (sj_status==SJ_RUNNING){
3994       printf("Warning. %d frames delayed.\n",sj_xrun);
3995       sj_totalxrun+=sj_xrun;
3996     }
3997     sj_xrun=0;
3998   }
3999 
4000   for (i=0;i<nframes;i++){
4001     while(
4002 	  sj_status==SJ_RUNNING
4003 	  && (sj_unread==sj_buffersize
4004 	      || sj_unread >= SJ_MAX(sj_jackbuffersize*2, latencyframes))
4005 	  )
4006       {
4007 	jack_mus_watchdog_counter++;
4008 	pthread_cond_wait(&sndjack_cond,&sndjack_mutex);
4009       }
4010 
4011     for (ch=0;ch<chs;ch++)
4012       sndjack_channels[ch].buffer[sj_writeplace]=buf[ch][i];
4013 
4014     atomic_add(&sj_unread,1);
4015     sj_writeplace++;
4016     if (sj_writeplace==sj_buffersize)
4017       sj_writeplace=0;
4018   }
4019 
4020   if (sj_status==SJ_STOPPED)
4021     if (sj_unread>=sj_jackbuffersize)
4022       sj_status=SJ_RUNNING;
4023 }
4024 
sndjack_buffersizecallback(jack_nframes_t nframes,void * arg)4025 static int sndjack_buffersizecallback(jack_nframes_t nframes, void *arg){
4026   sj_jackbuffersize=nframes;
4027   return 0;
4028 }
4029 
sndjack_getnumoutchannels(void)4030 static int sndjack_getnumoutchannels(void){
4031   char *a=getenv("SNDLIB_NUM_JACK_CHANNELS");
4032   if (a!=NULL){
4033     int num_ch=atoi(a);
4034     return
4035       (num_ch<=0 || num_ch > 100000)
4036       ? 2
4037       : num_ch;
4038   }else{
4039     int lokke=0;
4040     const char **ports=jack_get_ports(sndjack_client,NULL,NULL,JackPortIsPhysical|JackPortIsInput);
4041     while(ports!=NULL && ports[lokke]!=NULL){
4042       lokke++;
4043     }
4044 
4045     if (lokke<2) return 2;
4046     return lokke;
4047   }
4048 }
4049 
sndjack_getnuminchannels(void)4050 static int sndjack_getnuminchannels(void){
4051   char *a=getenv("SNDLIB_NUM_JACK_CHANNELS");
4052   if (a!=NULL){
4053     int num_ch=atoi(a);
4054     return
4055       (num_ch<=0 || num_ch > 100000)
4056       ? 2
4057       : num_ch;
4058   }else{
4059     int lokke=0;
4060     const char **ports=jack_get_ports(sndjack_client,NULL,NULL,JackPortIsPhysical|JackPortIsOutput);
4061     while(ports!=NULL && ports[lokke]!=NULL){
4062       lokke++;
4063     }
4064     if (lokke<2) return 2;
4065     return lokke;
4066   }
4067 }
4068 
4069 
sndjack_init(void)4070 static int sndjack_init(void){
4071   int ch;
4072   int numch;
4073 
4074   {
4075     jack_status_t status;
4076     sndjack_client=jack_client_open("sndlib",JackNoStartServer,&status,NULL);
4077     if (!sndjack_client) {
4078 #if 0
4079       fprintf (stderr, "jack_client_open() failed, "
4080 	       "status = 0x%2.0x\n", status);
4081       if (status & JackServerFailed) {
4082 	fprintf (stderr, "Unable to connect to JACK server\n");
4083       }
4084 #endif
4085       return -1;
4086     }
4087   }
4088 
4089   pthread_mutex_init(&sndjack_mutex,NULL);
4090   pthread_cond_init(&sndjack_cond,NULL);
4091   pthread_mutex_init(&sndjack_read_mutex,NULL);
4092   pthread_cond_init(&sndjack_read_cond,NULL);
4093 
4094   jack_set_process_callback(sndjack_client,sndjack_process,NULL);
4095 
4096   sndjack_num_channels_allocated = numch = sndjack_getnumoutchannels();
4097   sndjack_num_read_channels_allocated    = sndjack_getnuminchannels();
4098 
4099   sndjack_channels=(struct SndjackChannel *)calloc(sizeof(struct SndjackChannel),numch);
4100   sndjack_read_channels=(struct SndjackChannel *)calloc(sizeof(struct SndjackChannel),sndjack_num_read_channels_allocated);
4101 
4102   for (ch=0;ch<numch;ch++){
4103     sndjack_channels[ch].buffer=(sample_t *)calloc(sizeof(sample_t),SNDJACK_BUFFERSIZE);
4104   }
4105   for (ch=0;ch<sndjack_num_read_channels_allocated;ch++){
4106     sndjack_read_channels[ch].buffer=(sample_t *)calloc(sizeof(sample_t),SNDJACK_BUFFERSIZE);
4107   }
4108   sj_buffersize=SNDJACK_BUFFERSIZE;
4109 
4110   for (ch=0;ch<numch;ch++){
4111     char temp[500];
4112     snprintf(temp, 500, "out_%d",ch+1);
4113     if ((sndjack_channels[ch].port=jack_port_register(
4114 						     sndjack_client,
4115 						     mus_strdup(temp),
4116 						     JACK_DEFAULT_AUDIO_TYPE,
4117 						     JackPortIsOutput,
4118 						     0
4119 						     ))==NULL)
4120       {
4121 	fprintf(stderr, "Error. Could not register jack port.\n");
4122 	goto failed_register;
4123       }
4124   }
4125 
4126   for (ch=0;ch<sndjack_num_read_channels_allocated;ch++){
4127     char temp[500];
4128     snprintf(temp, 500, "in_%d",ch+1);
4129     if ((sndjack_read_channels[ch].port=jack_port_register(
4130 							  sndjack_client,
4131 							  mus_strdup(temp),
4132 							  JACK_DEFAULT_AUDIO_TYPE,
4133 							  JackPortIsInput,
4134 							  0
4135 							  ))==NULL)
4136       {
4137 	fprintf(stderr, "Error. Could not register jack port.\n");
4138 	goto failed_register;
4139       }
4140   }
4141 
4142 
4143 
4144 
4145   sj_jackbuffersize=jack_get_buffer_size(sndjack_client);
4146   jack_set_buffer_size_callback(sndjack_client,sndjack_buffersizecallback,NULL);
4147 
4148   if (jack_activate (sndjack_client)) {
4149     fprintf (stderr, "Error. Cannot activate jack client.\n");
4150     goto failed_activate;
4151   }
4152 
4153   if (getenv("SNDLIB_JACK_DONT_AUTOCONNECT")==NULL){
4154 
4155     const char **outportnames=jack_get_ports(sndjack_client,NULL,NULL,JackPortIsPhysical|JackPortIsInput);
4156     for (ch=0;outportnames && outportnames[ch]!=NULL && ch<numch;ch++){
4157       if (
4158 	  jack_connect(
4159 		       sndjack_client,
4160 		       jack_port_name(sndjack_channels[ch].port),
4161 		       outportnames[ch]
4162 		       )
4163 	  )
4164 	{
4165 	  printf ("Warning. Cannot connect jack output port %d: \"%s\".\n",ch,outportnames[ch]);
4166 	}
4167     }
4168 
4169     const char **inportnames=jack_get_ports(sndjack_client,NULL,NULL,JackPortIsPhysical|JackPortIsOutput);
4170     for (ch=0;inportnames && inportnames[ch]!=NULL && ch<numch;ch++){
4171     if (
4172 	jack_connect(
4173 		     sndjack_client,
4174 		     inportnames[ch],
4175 		     jack_port_name(sndjack_read_channels[ch].port)
4176 		     )
4177 	)
4178       {
4179 	printf ("Warning. Cannot connect jack input port %d: \"%s\".\n",ch,inportnames[ch]);
4180       }
4181     }
4182   }
4183 
4184   return 0;
4185 
4186   // failed_connect:
4187  failed_activate:
4188   jack_deactivate(sndjack_client);
4189 
4190  failed_register:
4191   jack_client_close(sndjack_client);
4192   sndjack_client=NULL;
4193 
4194   return -1;
4195 }
sndjack_cleanup(void)4196 static void sndjack_cleanup(void){
4197   int ch;
4198   for (ch=0;ch<sndjack_num_channels_allocated;ch++){
4199     src_delete(sndjack_srcstates[ch]);
4200   }
4201   jack_deactivate(sndjack_client);
4202   jack_client_close(sndjack_client);
4203 
4204 }
4205 
4206 
4207 /***************/
4208 /* Sndlib Part */
4209 /***************/
4210 
4211 static int sndjack_format;
4212 static sample_t **sndjack_buffer;
4213 static sample_t *sndjack_srcbuffer;
4214 
4215 static int sndjack_dev;
4216 static int sndjack_read_dev;
4217 
4218 /* prototypes for the jack sndlib functions */
4219 static int   jack_mus_audio_initialize(void);
4220 static void  jack_mus_oss_set_buffers(int num, int size);
4221 static char* jack_mus_audio_moniker(void);
4222 static int   jack_mus_audio_open_output(int ur_dev, int srate, int chans, mus_sample_t samp_type, int size);
4223 static int   jack_mus_audio_open_input(int ur_dev, int srate, int chans, mus_sample_t samp_type, int requested_size);
4224 static int   jack_mus_audio_write(int id, char *buf, int bytes);
4225 static int   jack_mus_audio_read(int id, char *buf, int bytes);
4226 static int   jack_mus_audio_close(int id);
4227 
4228 #if (!HAVE_JACK_IN_LINUX) // Ie. Not using Linux.
mus_audio_open_output(int ur_dev,int srate,int chans,mus_sample_t samp_type,int size)4229 int mus_audio_open_output(int ur_dev, int srate, int chans, mus_sample_t samp_type, int size)
4230 {
4231   return(jack_mus_audio_open_output(ur_dev, srate, chans, samp_type, size));
4232 }
4233 
mus_audio_open_input(int ur_dev,int srate,int chans,mus_sample_t samp_type,int requested_size)4234 int mus_audio_open_input(int ur_dev, int srate, int chans, mus_sample_t samp_type, int requested_size)
4235 {
4236   return(jack_mus_audio_open_input(ur_dev, srate, chans, samp_type, requested_size));
4237 }
4238 
mus_audio_write(int id,char * buf,int bytes)4239 int mus_audio_write(int id, char *buf, int bytes)
4240 {
4241   return(jack_mus_audio_write(id, buf, bytes));
4242 }
4243 
mus_audio_read(int id,char * buf,int bytes)4244 int mus_audio_read(int id, char *buf, int bytes)
4245 {
4246   return(jack_mus_audio_read(id, buf, bytes));
4247 }
4248 
mus_audio_close(int id)4249 int mus_audio_close(int id)
4250 {
4251   return(jack_mus_audio_close(id));
4252 }
4253 
mus_audio_initialize(void)4254 int mus_audio_initialize(void){
4255   return jack_mus_audio_initialize();
4256 }
4257 
mus_audio_moniker(void)4258 char* mus_audio_moniker(void)
4259 {
4260   return(jack_mus_audio_moniker());
4261 }
4262 #endif
4263 
4264 
jack_mus_audio_initialize(void)4265 static int jack_mus_audio_initialize(void) {
4266   int ch;
4267 
4268   if (audio_initialized){
4269     return MUS_NO_ERROR;
4270   }
4271 
4272   if (sndjack_init()!=0)
4273     return MUS_ERROR;
4274 
4275   sndjack_buffer=(sample_t **)calloc(sizeof(sample_t*),sndjack_num_channels_allocated);
4276   for (ch=0;ch<sndjack_num_channels_allocated;ch++)
4277     sndjack_buffer[ch]=(sample_t *)calloc(sizeof(sample_t),SNDJACK_BUFFERSIZE);
4278   sndjack_srcbuffer=(sample_t *)calloc(sizeof(sample_t),SNDJACK_BUFFERSIZE);
4279 
4280   sndjack_srcstates=(SRC_STATE **)calloc(sizeof(SRC_STATE*),sndjack_num_channels_allocated);
4281   for (ch=0;ch<sndjack_num_channels_allocated;ch++){
4282     sndjack_srcstates[ch]=src_new(SRC_QUALITY,1,NULL);
4283   }
4284 
4285   atexit(sndjack_cleanup);
4286 
4287   api = MUS_JACK_API;
4288   vect_mus_audio_initialize = jack_mus_audio_initialize;
4289   vect_mus_oss_set_buffers = jack_mus_oss_set_buffers;
4290   vect_mus_audio_moniker = jack_mus_audio_moniker;
4291   vect_mus_audio_open_output = jack_mus_audio_open_output;
4292   vect_mus_audio_open_input = jack_mus_audio_open_input;
4293   vect_mus_audio_write = jack_mus_audio_write;
4294   vect_mus_audio_read = jack_mus_audio_read;
4295   vect_mus_audio_close = jack_mus_audio_close;
4296 
4297   audio_initialized = true;
4298 
4299 #if 0
4300 
4301   /* Locking all future memory shouldn't be that necessary, and might even freeze the machine in certain situations. */
4302   /* So remove MCL_FUTURE from the mlockall call. (No. We can't do that. It can screw up code using the realtime extension. -Kjetil.*/
4303   munlockall();
4304   //mlockall(MCL_CURRENT);
4305 
4306   // Instead we just do this: (which is not enough, but maybe better than nothing)
4307   {
4308     mlock(sndjack_channels,sizeof(struct SndjackChannel)*sndjack_num_channels_allocated);
4309     mlock(sndjack_read_channels,sizeof(struct SndjackChannel)*sndjack_num_read_channels_allocated);
4310 
4311     for (ch=0;ch<numch;ch++){
4312       mlock(sndjack_channels[ch].buffer,sizeof(sample_t)*SNDJACK_BUFFERSIZE);
4313     }
4314     for (ch=0;ch<sndjack_num_read_channels_allocated;ch++){
4315       mlock(sndjack_read_channels[ch].buffer,sizeof(sample_t)*SNDJACK_BUFFERSIZE);
4316     }
4317   }
4318 #endif
4319 
4320   return MUS_NO_ERROR;
4321 }
4322 
4323 // ??
jack_mus_oss_set_buffers(int num,int size)4324 static void  jack_mus_oss_set_buffers(int num, int size){
4325 }
4326 
4327 static int jack_mus_isrunning=0;
4328 static pid_t jack_mus_player_pid;
4329 static pthread_t jack_mus_watchdog_thread;
4330 
jack_mus_audio_watchdog(void * arg)4331 static void *jack_mus_audio_watchdog(void *arg){
4332 #if MUS_JACK
4333   struct sched_param par;
4334 
4335   par.sched_priority = sched_get_priority_max(SCHED_RR);
4336   if (sched_setscheduler(0,SCHED_RR,&par)==-1){
4337     fprintf(stderr, "SNDLIB: Unable to set SCHED_RR realtime priority for the watchdog thread. No watchdog.\n");
4338     goto exit;
4339   }
4340 
4341   for (;;){
4342     int last=jack_mus_watchdog_counter;
4343     sleep(1);
4344 
4345     if (jack_mus_isrunning && jack_mus_watchdog_counter<last+10){
4346       struct sched_param par;
4347       fprintf(stderr, "SNDLIB: Setting player to non-realtime for 2 seconds.\n");
4348 
4349       par.sched_priority = 0;
4350       if (sched_setscheduler(jack_mus_player_pid,SCHED_OTHER,&par)==-1){
4351 	fprintf(stderr, "SNDLIB: Unable to set non-realtime priority. Must kill player thread. Sorry!\n");
4352 	while(1){
4353 	  kill(jack_mus_player_pid,SIGKILL);
4354 	  sleep(2);
4355 	}
4356       }
4357 
4358       sleep(2);
4359 
4360       if (jack_mus_isrunning){
4361 	par.sched_priority = sched_get_priority_min(SCHED_RR)+1;
4362 	if (sched_setscheduler(jack_mus_player_pid,SCHED_RR,&par)==-1){
4363 	  fprintf(stderr, "SNDLIB: Could not set back to realtime priority...\n");
4364 	}else
4365 	  fprintf(stderr, "SNDLIB: Play thread set back to realtime priority.\n");
4366       }
4367 
4368     }
4369   }
4370  exit:
4371   fprintf(stderr, "SNDLIB: Watchdog exiting\n");
4372 #endif
4373   return NULL;
4374 }
4375 
4376 
jack_mus_audio_set_realtime(void)4377 static void jack_mus_audio_set_realtime(void){
4378 #if HAVE_JACK_IN_LINUX
4379   struct sched_param par;
4380   static int watchdog_started=0;
4381 
4382   jack_mus_player_pid=getpid();
4383 
4384   if (watchdog_started==0){
4385     if (pthread_create(&jack_mus_watchdog_thread,NULL,jack_mus_audio_watchdog,NULL)!=0){
4386       fprintf(stderr, "Could not create watchdog. Not running realtime\n");
4387       return;
4388     }
4389     watchdog_started=1;
4390   }
4391 
4392   jack_mus_isrunning=1;
4393 
4394   par.sched_priority = sched_get_priority_min(SCHED_RR)+1;
4395   if (sched_setscheduler(0,SCHED_RR,&par)==-1){
4396     fprintf(stderr, "SNDLIB: Unable to set SCHED_RR realtime priority for the player thread.\n");
4397   }{
4398     //fprintf(stderr, "Set realtime priority\n");
4399   }
4400 #endif
4401 }
4402 
jack_mus_audio_set_non_realtime(void)4403 static void jack_mus_audio_set_non_realtime(void){
4404 #if HAVE_JACK_IN_LINUX
4405   struct sched_param par;
4406   par.sched_priority = 0;
4407   sched_setscheduler(0,SCHED_OTHER,&par);
4408   //fprintf(stderr, "Set non-realtime priority\n");
4409   jack_mus_isrunning=0;
4410 #endif
4411 }
4412 
4413 #ifndef JACK_AUTO_SRC
4414   #define JACK_AUTO_SRC 1
4415 #endif
4416 
jack_mus_audio_open_output(int dev,int srate,int chans,mus_sample_t samp_type,int size)4417 int jack_mus_audio_open_output(int dev, int srate, int chans, mus_sample_t samp_type, int size){
4418   if (sndjack_client==NULL){
4419     if (jack_mus_audio_initialize()==MUS_ERROR)
4420       return MUS_ERROR;
4421   }
4422 
4423   if (sndjack_num_channels_allocated<chans){
4424     printf("Error. Can not play back %d channels. (Only %d)\n",chans,sndjack_num_channels_allocated);
4425     return MUS_ERROR;
4426   }
4427 
4428   if (samp_type!=MUS_BYTE && samp_type!=MUS_COMP_SHORT && samp_type!=MUS_COMP_FLOAT){
4429     printf("Error, unable to handle sample type %s.\n",mus_sample_type_to_string(samp_type));
4430     return MUS_ERROR;
4431   }
4432 
4433   while(sj_status!=SJ_STOPPED) usleep(5);
4434 
4435   sj_unread=0;
4436   sj_writeplace=0;
4437   sj_readplace=0;
4438 
4439 #if JACK_AUTO_SRC
4440   if (srate!=(int)jack_get_sample_rate(sndjack_client)){
4441     int lokke;
4442     //printf("Warning, sample-rate differs between snd and jack. Sound will not be played correctly! %d/%d\n",srate,jack_get_sample_rate(sndjack_client));
4443     sndjack_srcratio=(double)jack_get_sample_rate(sndjack_client)/(double)srate;
4444     for (lokke=0;lokke<chans;lokke++){
4445       src_reset(sndjack_srcstates[lokke]);
4446     }
4447   }else{
4448     sndjack_srcratio=1.0;
4449   }
4450 #else
4451   sndjack_srcratio=1.0;
4452 #endif
4453 
4454   sndjack_format=samp_type;
4455   sndjack_num_channels_inuse=chans;
4456   sndjack_dev=dev;
4457 
4458   jack_mus_audio_set_realtime();
4459 
4460   return(MUS_NO_ERROR);
4461 }
4462 
4463 
4464 #define MUS_BYTE_TO_SAMPLE(n) (((mus_float_t)(n) / (mus_float_t)(1 << 7)))
4465 
sndjack_from_byte(int ch,int chs,char * buf,float * out,int bytes)4466 static int sndjack_from_byte(int ch,int chs,char *buf,float *out,int bytes){
4467   int i;
4468   int len=bytes/chs;
4469   if (len>SNDJACK_BUFFERSIZE) return -1;
4470 
4471   for (i=0;i<len;i++){
4472     out[i]=MUS_BYTE_TO_SAMPLE(buf[i*chs+ch]);
4473   }
4474   return len;
4475 }
4476 
sndjack_from_short(int ch,int chs,short * buf,float * out,int bytes)4477 static int sndjack_from_short(int ch,int chs,short *buf,float *out,int bytes){
4478   int i;
4479   int len=bytes/(sizeof(short)*chs);
4480   if (len>SNDJACK_BUFFERSIZE) return -1;
4481 
4482   for (i=0;i<len;i++){
4483     out[i]=(float)buf[i*chs+ch]/32768.1f;
4484   }
4485   return len;
4486 }
4487 
sndjack_from_float(int ch,int chs,float * buf,float * out,int bytes)4488 static int sndjack_from_float(int ch,int chs,float *buf,float *out,int bytes){
4489   int i;
4490   int len=bytes/(sizeof(float)*chs);
4491   if (len>SNDJACK_BUFFERSIZE) return -1;
4492 
4493   for (i=0;i<len;i++){
4494     out[i]=buf[i*chs+ch];
4495   }
4496   return len;
4497 }
4498 
4499 
jack_mus_audio_write(int line,char * buf,int bytes)4500 int jack_mus_audio_write(int line, char *buf, int bytes){
4501   int ch;
4502   int outlen=0;
4503 
4504   for (ch=0;ch<sndjack_num_channels_inuse;ch++){
4505     int len = 0;
4506     float *buf2=sndjack_srcratio==1.0?sndjack_buffer[ch]:sndjack_srcbuffer;
4507 
4508     switch (sndjack_format){
4509     case MUS_BYTE:
4510       len=sndjack_from_byte(ch,sndjack_num_channels_inuse,buf,buf2,bytes);
4511       break;
4512     case MUS_COMP_SHORT:
4513       len=sndjack_from_short(ch,sndjack_num_channels_inuse,(short *)buf,buf2,bytes);
4514       break;
4515     case MUS_COMP_FLOAT:
4516       len=sndjack_from_float(ch,sndjack_num_channels_inuse,(float *)buf,buf2,bytes);
4517       break;
4518     }
4519     if (len<0){
4520       printf("Errur. Input buffer to large for mus_audio_write.\n");
4521       return MUS_ERROR;
4522     }
4523 
4524     if (sndjack_srcratio!=1.0){
4525       SRC_DATA src_data={
4526 	buf2,sndjack_buffer[ch],
4527 	len,SNDJACK_BUFFERSIZE,
4528 	0,0,
4529 	0,
4530 	sndjack_srcratio
4531       };
4532       int res=src_process(sndjack_srcstates[ch],&src_data);
4533       if (res!=0){
4534 	printf("Error while resampling. (%s)\n",src_strerror(res));
4535 	return MUS_ERROR;
4536       }
4537       if (src_data.input_frames!=len){
4538 	printf("Unsuccessful resampling: Should have used %d bytes, used %ld.",len,(long int)(src_data.input_frames));
4539 	return MUS_ERROR;
4540       }
4541       if (ch>0 && src_data.output_frames_gen!=outlen){
4542 	printf("Error, src_process did not output the same number of frames as previous resampled channel (%ld/%d).\n"
4543 	       "Please report this problem to k.s.matheussen@notam02.no. Thanks!\n",(long int)(src_data.output_frames_gen),outlen);
4544 	return MUS_ERROR;
4545       }
4546       outlen=src_data.output_frames_gen;
4547     }else{
4548       outlen=len;
4549     }
4550   }
4551 
4552 
4553   sndjack_write(sndjack_buffer,outlen,outlen*2,sndjack_num_channels_inuse);
4554 
4555   return MUS_NO_ERROR;
4556 }
4557 
jack_mus_audio_close(int line)4558 int jack_mus_audio_close(int line)
4559 {
4560   jack_mus_audio_set_non_realtime();
4561   if (line==sndjack_dev){
4562     sj_status=SJ_ABOUTTOSTOP;
4563     sndjack_num_channels_inuse=0;
4564   }
4565   return MUS_NO_ERROR;
4566  }
4567 
jack_mus_audio_open_input(int dev,int srate,int chans,mus_sample_t samp_type,int size)4568 int jack_mus_audio_open_input(int dev, int srate, int chans, mus_sample_t samp_type, int size){
4569   if (sndjack_client==NULL){
4570     if (jack_mus_audio_initialize()==MUS_ERROR)
4571       return MUS_ERROR;
4572   }
4573 
4574   if (sndjack_num_read_channels_allocated<chans){
4575     printf("Error. Can not record %d channels. (Only %d)\n",chans,sndjack_num_read_channels_allocated);
4576     return MUS_ERROR;
4577   }
4578 
4579   printf("dev: %d\n" ,dev);
4580   if (samp_type!=MUS_BYTE && samp_type!=MUS_COMP_SHORT && samp_type!=MUS_COMP_FLOAT){
4581     printf("Error, unable to handle format %s.\n",mus_sample_type_to_string(samp_type));
4582     return MUS_ERROR;
4583   }
4584 
4585   if (srate!=(int)jack_get_sample_rate(sndjack_client)){
4586     printf("Warning, jacks samplerate is %d (and not %d), and the recording will use this samplerate too.\n",jack_get_sample_rate(sndjack_client),srate);
4587   }
4588 
4589   sndjack_read_format=samp_type;
4590   sndjack_num_read_channels_inuse=chans;
4591   sndjack_read_dev=dev;
4592 
4593   return(MUS_NO_ERROR);
4594 }
4595 
4596 
jack_mus_audio_read(int line,char * buf,int bytes)4597 int jack_mus_audio_read(int line, char *buf, int bytes){
4598   if (sndjack_read(buf,bytes,sndjack_num_read_channels_inuse)==-1)
4599     return(MUS_ERROR);
4600   return MUS_NO_ERROR;
4601 }
4602 
4603 
jack_mus_audio_moniker(void)4604 char *jack_mus_audio_moniker(void)
4605 {
4606   return((char *)"Jack");
4607 }
4608 #endif
4609 
4610 
4611 
4612 /* ------------------------------- HPUX ----------------------------------------- */
4613 
4614 /* if this is basically the same as the Sun case with different macro names,
4615  * then it could perhaps be updated to match the new Sun version above --
4616  * Sun version changed 28-Jan-99
4617  */
4618 
4619 #if defined(__hpux) && (!(defined(AUDIO_OK)))
4620 #define AUDIO_OK 1
4621 #include <sys/audio.h>
4622 
4623 
4624 #define return_error_exit(Error_Type, Audio_Line, Ur_Error_Message) \
4625   do { char *Error_Message; Error_Message = Ur_Error_Message; \
4626     if (Audio_Line != -1) close(Audio_Line); \
4627     if (Error_Message) \
4628       {mus_standard_error(Error_Type, Error_Message); free(Error_Message);} \
4629     else mus_standard_error(Error_Type, mus_error_type_to_string(Error_Type)); \
4630     return(MUS_ERROR); \
4631   } while (false)
4632 
4633 
mus_audio_moniker(void)4634 char *mus_audio_moniker(void)
4635 {
4636   return("HPUX audio");
4637 }
4638 
4639 
mus_audio_open_output(int ur_dev,int srate,int chans,mus_sample_t samp_type,int size)4640 int mus_audio_open_output(int ur_dev, int srate, int chans, mus_sample_t samp_type, int size)
4641 {
4642   int fd, i, dev;
4643   struct audio_describe desc;
4644 
4645   dev = MUS_AUDIO_DEVICE(ur_dev);
4646   fd = open("/dev/audio", O_RDWR);
4647   if (fd == -1)
4648     return_error_exit(MUS_AUDIO_CANT_OPEN, -1,
4649 		      mus_format("can't open /dev/audio for output: %s",
4650 				 strerror(errno)));
4651 
4652   ioctl(fd, AUDIO_SET_CHANNELS, chans);
4653   if (dev == MUS_AUDIO_SPEAKERS)
4654     ioctl(fd, AUDIO_SET_OUTPUT, AUDIO_OUT_SPEAKER);
4655   else
4656     if (dev == MUS_AUDIO_LINE_OUT)
4657       ioctl(fd, AUDIO_SET_OUTPUT, AUDIO_OUT_LINE);
4658     else ioctl(fd, AUDIO_SET_OUTPUT, AUDIO_OUT_HEADPHONE);
4659 
4660   if (samp_type == MUS_BSHORT)
4661     ioctl(fd, AUDIO_SET_SAMPLE_TYPE, AUDIO_FORMAT_LINEAR16BIT);
4662   else
4663     {
4664       if (samp_type == MUS_MULAW)
4665 	ioctl(fd, AUDIO_SET_SAMPLE_TYPE, AUDIO_FORMAT_ULAW);
4666       else
4667 	{
4668 	  if (samp_type == MUS_ALAW)
4669 	    ioctl(fd, AUDIO_SET_SAMPLE_TYPE, AUDIO_FORMAT_ALAW);
4670 	  else
4671 	    return_error_exit(MUS_AUDIO_SAMPLE_TYPE_NOT_AVAILABLE, fd,
4672 			      mus_format("can't set output sample type to %d (%s) for %d",
4673 					 samp_type, mus_sample_type_to_string(samp_type),
4674 					 dev));
4675 	}
4676     }
4677 
4678   ioctl(fd, AUDIO_DESCRIBE, &desc);
4679   for (i = 0; i < desc.nrates; i++)
4680     if (srate == desc.sample_rate[i])
4681       break;
4682 
4683   if (i == desc.nrates)
4684     return_error_exit(SRATE_NOT_AVAILABLE, fd,
4685 		      mus_format("can't set srate to %d on %d",
4686 				 srate, dev));
4687 
4688   ioctl(fd, AUDIO_SET_SAMPLE_RATE, srate);
4689   return(fd);
4690 }
4691 
4692 
mus_audio_write(int line,char * buf,int bytes)4693 int mus_audio_write(int line, char *buf, int bytes)
4694 {
4695   write(line, buf, bytes);
4696   return(MUS_NO_ERROR);
4697 }
4698 
4699 
mus_audio_close(int line)4700 int mus_audio_close(int line)
4701 {
4702   close(line);
4703   return(MUS_NO_ERROR);
4704 }
4705 
4706 
mus_audio_initialize(void)4707 int mus_audio_initialize(void)
4708 {
4709   return(MUS_NO_ERROR);
4710 }
4711 
4712 
4713 /* struct audio_status status_b;
4714  * ioctl(devAudio, AUDIO_GET_STATUS, &status_b)
4715  * not_busy = (status_b.transmit_status == AUDIO_DONE);
4716 */
4717 
mus_audio_open_input(int ur_dev,int srate,int chans,mus_sample_t samp_type,int size)4718 int mus_audio_open_input(int ur_dev, int srate, int chans, mus_sample_t samp_type, int size)
4719 {
4720   int fd, i, dev;
4721   struct audio_describe desc;
4722 
4723   dev = MUS_AUDIO_DEVICE(ur_dev);
4724   fd = open("/dev/audio", O_RDWR);
4725   if (fd == -1)
4726     return_error_exit(MUS_AUDIO_CANT_OPEN, NULL,
4727 		      mus_format("can't open /dev/audio for input: %s",
4728 				 strerror(errno)));
4729 
4730   ioctl(fd, AUDIO_SET_CHANNELS, chans);
4731   if (dev == MUS_AUDIO_MICROPHONE)
4732     ioctl(fd, AUDIO_SET_INPUT, AUDIO_IN_MIKE);
4733   else ioctl(fd, AUDIO_SET_INPUT, AUDIO_IN_LINE);
4734 
4735   if (samp_type == MUS_BSHORT)
4736     ioctl(fd, AUDIO_SET_SAMPLE_TYPE, AUDIO_FORMAT_LINEAR16BIT);
4737   else
4738     {
4739       if (samp_type == MUS_MULAW)
4740 	ioctl(fd, AUDIO_SET_SAMPLE_TYPE, AUDIO_FORMAT_ULAW);
4741       else
4742 	{
4743 	  if (samp_type == MUS_ALAW)
4744 	    ioctl(fd, AUDIO_SET_SAMPLE_TYPE, AUDIO_FORMAT_ALAW);
4745 	  else
4746 	    return_error_exit(MUS_AUDIO_SAMPLE_TYPE_NOT_AVAILABLE, fd,
4747 			      mus_format("can't set input sample type to %d (%s) on %d",
4748 					 samp_type, mus_sample_type_to_string(samp_type),
4749 					 dev));
4750 	}
4751     }
4752 
4753   ioctl(fd, AUDIO_DESCRIBE, &desc);
4754   for (i = 0; i < desc.nrates; i++)
4755     if (srate == desc.sample_rate[i])
4756       break;
4757 
4758   if (i == desc.nrates)
4759     return_error_exit(MUS_AUDIO_SRATE_NOT_AVAILABLE, fd,
4760 		      mus_format("can't set srate to %d on %d",
4761 				 srate, dev));
4762 
4763   ioctl(fd, AUDIO_SET_SAMPLE_RATE, srate);
4764   return(fd);
4765 }
4766 
4767 
mus_audio_read(int line,char * buf,int bytes)4768 int mus_audio_read(int line, char *buf, int bytes)
4769 {
4770   read(line, buf, bytes);
4771   return(MUS_NO_ERROR);
4772 }
4773 
4774 #endif
4775 
4776 /* ------------------------------- OpenBSD ----------------------------------------- */
4777 #if (__OpenBSD__) && (!(defined(AUDIO_OK)))
4778 #define AUDIO_OK 1
4779 #include <sndio.h>
4780 /* this code thanks to Koen De Turck May-18 */
4781 
4782 static struct sio_hdl *in_hdl = NULL;
4783 static struct sio_hdl *out_hdl = NULL;
4784 
4785 #define SNDIO_OUT 0
4786 #define SNDIO_IN 1
4787 
mus_audio_initialize(void)4788 int mus_audio_initialize(void)
4789 {
4790   return(MUS_NO_ERROR);
4791 }
4792 
mus_audio_moniker(void)4793 char *mus_audio_moniker(void)
4794 {
4795   return((char *)"OpenBSD audio (sndio)");
4796 }
4797 
mus_sndio_open(int mode,int srate,int chans,mus_sample_t samp_type,int size)4798 static int mus_sndio_open(int mode, int srate, int chans, mus_sample_t samp_type, int size)
4799 {
4800   struct sio_hdl *hdl;
4801   struct sio_par par, par2;
4802   hdl = sio_open(SIO_DEVANY, mode, 0 /*non-blocking io=0 -> we choose blocking*/);
4803   sio_initpar(&par);
4804   switch (samp_type)
4805     {
4806     case MUS_BYTE:    par.bits=8;par.bps=1;par.sig=1;break;
4807     case MUS_UBYTE:   par.bits=8;par.bps=1;par.sig=0;break;
4808     case MUS_LSHORT:  par.bits=16;par.bps=2;par.sig=1;par.le=1;break;
4809     case MUS_BSHORT:  par.bits=16;par.bps=2;par.sig=1;par.le=0;break;
4810     case MUS_ULSHORT: par.bits=16;par.bps=2;par.sig=0;par.le=1;break;
4811     case MUS_UBSHORT: par.bits=16;par.bps=2;par.sig=0;par.le=0;break;
4812     /* actually, all linear integer formats are accepted by sndio */
4813     default:
4814 	return(mus_error(MUS_AUDIO_CANT_OPEN, NULL));
4815     }
4816   if(mode==SIO_PLAY)
4817     par.pchan=chans;
4818   else
4819     par.rchan=chans;
4820   par.rate=srate;
4821   par.appbufsz=size;
4822   /* set params */
4823   if (!sio_setpar(hdl, &par))
4824 	return(mus_error(MUS_AUDIO_CANT_OPEN, NULL));
4825   /* then see what sndio thinks of it */
4826   if (!sio_getpar(hdl, &par2))
4827 	return(mus_error(MUS_AUDIO_CANT_OPEN, NULL));
4828 
4829   if (par2.bits!=par.bits || par2.bps!=par.bps ||
4830       par2.sig!=par.sig   || par2.le!=par.le ||
4831       par2.rate!=par.rate ||par2.bufsz<size)
4832 	return(mus_error(MUS_AUDIO_CANT_OPEN, NULL));
4833   if (mode==SIO_PLAY && par2.pchan != par.pchan)
4834 	return(mus_error(MUS_AUDIO_CANT_OPEN, NULL));
4835   if (mode==SIO_REC && par2.rchan != par.rchan)
4836 	return(mus_error(MUS_AUDIO_CANT_OPEN, NULL));
4837 
4838   sio_start(hdl);
4839 
4840   if (mode==SIO_PLAY) out_hdl=hdl;
4841   if (mode==SIO_REC) in_hdl=hdl;
4842   return(MUS_NO_ERROR);
4843 }
4844 
mus_audio_open_output(int dev,int srate,int chans,mus_sample_t samp_type,int size)4845 int mus_audio_open_output(int dev, int srate, int chans, mus_sample_t samp_type, int size)
4846 {
4847   if (out_hdl!=NULL) return(mus_error(MUS_AUDIO_CANT_OPEN, NULL));
4848   mus_sndio_open(SIO_PLAY, srate, chans, samp_type, size);
4849   return(SNDIO_OUT);
4850 }
4851 
mus_audio_open_input(int ur_dev,int srate,int chans,mus_sample_t samp_type,int size)4852 int mus_audio_open_input(int ur_dev, int srate, int chans, mus_sample_t samp_type, int size)
4853 {
4854   if (in_hdl!=NULL) return(mus_error(MUS_AUDIO_CANT_OPEN, NULL));
4855   mus_sndio_open(SIO_REC, srate, chans, samp_type, size);
4856   return(SNDIO_IN);
4857 }
4858 
mus_audio_read(int line,char * buf,int bytes)4859 int mus_audio_read(int line, char *buf, int bytes)
4860 {
4861   if(bytes==sio_read(in_hdl, buf, bytes))
4862 	  return(MUS_NO_ERROR);
4863   else return MUS_ERROR;
4864 }
4865 
4866 
mus_audio_write(int line,char * buf,int bytes)4867 int mus_audio_write(int line, char *buf, int bytes)
4868 {
4869   if(bytes==sio_write(out_hdl, buf, bytes))
4870 	  return(MUS_NO_ERROR);
4871   else return MUS_ERROR;
4872 }
4873 
mus_audio_close(int line)4874 int mus_audio_close(int line)
4875 {
4876   if (line==SNDIO_IN && in_hdl!=NULL) {
4877     sio_stop(in_hdl);
4878     sio_close(in_hdl);
4879     in_hdl=NULL;
4880   }
4881   if (line==SNDIO_OUT && out_hdl!=NULL) {
4882     sio_stop(out_hdl);
4883     sio_close(out_hdl);
4884     out_hdl=NULL;
4885   }
4886   return(MUS_NO_ERROR);
4887 }
4888 
4889 #endif
4890 
4891 /* ------------------------------- NETBSD ----------------------------------------- */
4892 
4893 #if (__NetBSD__) && (!(defined(AUDIO_OK)))
4894 #define AUDIO_OK 1
4895 
4896 /* started from Xanim a long time ago..., bugfixes from Thomas Klausner 30-Jul-05, worked into better shape Aug-05 */
4897 #include <fcntl.h>
4898 #include <sys/audioio.h>
4899 #include <sys/ioctl.h>
4900 #include <sys/param.h>
4901 
4902 #define return_error_exit(Error_Type, Audio_Line, Ur_Error_Message) \
4903   do { char *Error_Message; Error_Message = Ur_Error_Message; \
4904     if (Audio_Line != -1) close(Audio_Line); \
4905     if (Error_Message) \
4906       {mus_standard_error(Error_Type, Error_Message); free(Error_Message);} \
4907     else mus_standard_error(Error_Type, mus_error_type_to_string(Error_Type)); \
4908     return(MUS_ERROR); \
4909   } while (false)
4910 
4911 
bsd_format_to_sndlib(int encoding)4912 static mus_sample_t bsd_format_to_sndlib(int encoding)
4913 {
4914   switch (encoding)
4915     {
4916     case AUDIO_ENCODING_ULAW:       return(MUS_MULAW);
4917     case AUDIO_ENCODING_ALAW:       return(MUS_ALAW);
4918     case AUDIO_ENCODING_LINEAR:     return(MUS_BSHORT);  /* "sun compatible" so probably big-endian? */
4919     case AUDIO_ENCODING_SLINEAR:
4920     case AUDIO_ENCODING_LINEAR8:    return(MUS_BYTE);
4921     case AUDIO_ENCODING_SLINEAR_LE: return(MUS_LSHORT);
4922     case AUDIO_ENCODING_SLINEAR_BE: return(MUS_BSHORT);
4923     case AUDIO_ENCODING_ULINEAR_LE: return(MUS_ULSHORT);
4924     case AUDIO_ENCODING_ULINEAR_BE: return(MUS_UBSHORT);
4925     case AUDIO_ENCODING_ULINEAR:    return(MUS_UBYTE);
4926     case AUDIO_ENCODING_NONE:
4927     case AUDIO_ENCODING_ADPCM:
4928     default:                        return(MUS_UNKNOWN_SAMPLE);
4929     }
4930   return(MUS_UNKNOWN_SAMPLE);
4931 }
4932 
4933 
sndlib_format_to_bsd(mus_sample_t encoding)4934 static int sndlib_format_to_bsd(mus_sample_t encoding)
4935 {
4936   switch (encoding)
4937     {
4938     case MUS_MULAW:   return(AUDIO_ENCODING_ULAW);
4939     case MUS_ALAW:    return(AUDIO_ENCODING_ALAW);
4940     case MUS_BYTE:    return(AUDIO_ENCODING_SLINEAR);
4941     case MUS_LSHORT:  return(AUDIO_ENCODING_SLINEAR_LE);
4942     case MUS_BSHORT:  return(AUDIO_ENCODING_SLINEAR_BE);
4943     case MUS_ULSHORT: return(AUDIO_ENCODING_ULINEAR_LE);
4944     case MUS_UBSHORT: return(AUDIO_ENCODING_ULINEAR_BE);
4945     case MUS_UBYTE:   return(AUDIO_ENCODING_ULINEAR);
4946     default: break;
4947     }
4948   return(AUDIO_ENCODING_NONE);
4949 }
4950 
4951 
mus_audio_initialize(void)4952 int mus_audio_initialize(void)
4953 {
4954   return(MUS_NO_ERROR);
4955 }
4956 
4957 
mus_audio_moniker(void)4958 char *mus_audio_moniker(void)
4959 {
4960 #if __NetBSD__
4961   return((char *)"NetBSD audio");
4962 #else
4963   return((char *)"OpenBSD audio");
4964 #endif
4965 }
4966 
4967 
4968 static int cur_chans = 1, cur_srate = 22050;
4969 
mus_audio_write(int line,char * buf,int bytes)4970 int mus_audio_write(int line, char *buf, int bytes)
4971 {
4972 #if defined(__NetBSD__) && (__NetBSD_Version__ >= 700000000)
4973   if (write(line, buf, bytes) != bytes)
4974     return_error_exit(MUS_AUDIO_WRITE_ERROR, line,
4975 		      mus_format("write error: %s", strerror(errno)));
4976 #else
4977   /* trouble... AUDIO_WSEEK always returns 0, no way to tell that I'm about to
4978    *   hit "hiwat", but when I do, it hangs.  Can't use AUDIO_DRAIN --
4979    *   it introduces interruptions.  Not sure what to do...
4980    */
4981   int b = 0;
4982 
4983   b = write(line, buf, bytes);
4984   usleep(10000);
4985 
4986   if ((b != bytes) && (b > 0)) /* b <= 0 presumably some sort of error, and we want to avoid infinite recursion below */
4987     {
4988       /* hangs at close if we don't handle this somehow */
4989       if ((cur_chans == 1) || (cur_srate == 22050))
4990 	sleep(1);
4991       else usleep(10000);
4992       mus_audio_write(line, (char *)(buf + b), bytes - b);
4993     }
4994 #endif
4995   return(MUS_NO_ERROR);
4996 }
4997 
4998 /* from Mike Scholz, 11-Feb-16 (edited):
4999  *   On Netbsd sound output with Snd and Sndplay stops before the sound is really at the end.
5000  *   [In audioplay] after the read-write loop they call ioctl(fd, AUDIO_DRAIN, NULL).
5001  *   Before closing sound output they call ioctl(fd, AUDIO_FLUSH, NULL) (like in audio.c),
5002  *   and in addition ioctl(fd, AUDIO_SETINFO, &info).  The latter requires that
5003  *   audio_info_t a_info be a global variable.  The AUDIO_DRAIN call has been in their
5004  *   sources since version 1.1 of /usr/src/usr.bin/audio/play/play.c from March 1999.
5005  */
5006 
5007 static audio_info_t a_info;
5008 
mus_audio_close(int line)5009 int mus_audio_close(int line)
5010 {
5011   ioctl(line, AUDIO_DRAIN, NULL);
5012   ioctl(line, AUDIO_FLUSH, NULL);
5013   ioctl(line, AUDIO_SETINFO, &a_info);
5014   close(line);
5015   return(MUS_NO_ERROR);
5016 }
5017 
5018 #if defined(__NetBSD__) && (__NetBSD_Version__ < 900000000)
5019   static int netbsd_default_outputs = (AUDIO_HEADPHONE | AUDIO_LINE_OUT | AUDIO_SPEAKER);
5020 #else
5021   static int netbsd_default_outputs = 0;
5022 #endif
5023 
mus_audio_open_output(int dev,int srate,int chans,mus_sample_t samp_type,int size)5024 int mus_audio_open_output(int dev, int srate, int chans, mus_sample_t samp_type, int size)
5025 {
5026   int line, encode;
5027 
5028   line = open("/dev/sound", O_WRONLY); /* /dev/audio assumes mono 8-bit mulaw */
5029   if (line == -1)
5030     {
5031       if (errno == EBUSY)
5032 	return(mus_error(MUS_AUDIO_CANT_OPEN, NULL));
5033       else return(mus_error(MUS_AUDIO_DEVICE_NOT_AVAILABLE, NULL));
5034     }
5035   AUDIO_INITINFO(&a_info);
5036 
5037   /* a_info.blocksize = size; */
5038   encode = sndlib_format_to_bsd(samp_type);
5039   if (encode == AUDIO_ENCODING_NONE)
5040     return_error_exit(MUS_AUDIO_SAMPLE_TYPE_NOT_AVAILABLE, -1,
5041 		      mus_format("sample type %d (%s) not available",
5042 				 samp_type,
5043 				 mus_sample_type_name(samp_type)));
5044 
5045   a_info.play.encoding = encode;
5046   a_info.mode = AUMODE_PLAY | AUMODE_PLAY_ALL;
5047   a_info.play.precision = mus_bytes_per_sample(samp_type) * 8;
5048   a_info.play.sample_rate = srate;
5049 
5050   if (dev == MUS_AUDIO_LINE_OUT)
5051     a_info.play.port = AUDIO_LINE_OUT;
5052   else
5053     {
5054       if (dev == MUS_AUDIO_SPEAKERS)
5055 	a_info.play.port = AUDIO_SPEAKER | (netbsd_default_outputs & AUDIO_HEADPHONE);
5056       else a_info.play.port = netbsd_default_outputs;
5057     }
5058 
5059   a_info.play.channels = chans;
5060   ioctl(line, AUDIO_SETINFO, &a_info);
5061   /* actually doesn't set the "ports" field -- always 0 */
5062 
5063   ioctl(line, AUDIO_GETINFO, &a_info);
5064 
5065   if ((int)(a_info.play.sample_rate) != srate)
5066     mus_print("srate: %d -> %d\n", srate, a_info.play.sample_rate);
5067   if ((int)(a_info.play.encoding) != sndlib_format_to_bsd(samp_type))
5068     mus_print("encoding: %d -> %d\n", sndlib_format_to_bsd(samp_type), a_info.play.encoding);
5069   if ((int)(a_info.play.channels) != chans)
5070     mus_print("chans: %d -> %d\n", chans, a_info.play.channels);
5071 
5072   cur_chans = chans;
5073   cur_srate = srate;
5074 
5075   return(line);
5076 }
5077 
5078 
mus_audio_read(int line,char * buf,int bytes)5079 int mus_audio_read(int line, char *buf, int bytes)
5080 {
5081   read(line, buf, bytes);
5082   return(MUS_NO_ERROR);
5083 }
5084 
5085 
netbsd_sample_types(int ur_dev,mus_sample_t * val)5086 static int netbsd_sample_types(int ur_dev, mus_sample_t *val)
5087 {
5088   int i, audio_fd, err, dev;
5089   audio_info_t info;
5090   audio_encoding_t e_info;
5091 
5092   dev = MUS_AUDIO_DEVICE(ur_dev);
5093   AUDIO_INITINFO(&info);
5094 
5095   audio_fd = open("/dev/sound", O_RDONLY | O_NONBLOCK, 0);
5096   if (audio_fd == -1)
5097     return_error_exit(MUS_AUDIO_CANT_READ, -1, mus_format("can't open /dev/sound: %s", strerror(errno)));
5098   err = ioctl(audio_fd, AUDIO_GETINFO, &info);
5099   if (err == -1)
5100     {
5101       close(audio_fd);
5102       return_error_exit(MUS_AUDIO_CANT_READ, audio_fd, mus_format("can't get dac info"));
5103     }
5104 
5105   for (i = 0; ; i++)
5106     {
5107       e_info.index = i;
5108       err = ioctl(audio_fd, AUDIO_GETENC, &e_info);
5109       if (err != 0) break;
5110       val[i + 1] = bsd_format_to_sndlib(e_info.encoding);
5111     }
5112   val[0] = (mus_sample_t)i;
5113   close(audio_fd);
5114   return(MUS_NO_ERROR);
5115 }
5116 
5117 
5118 
mus_audio_open_input(int ur_dev,int srate,int chans,mus_sample_t samp_type,int size)5119 int mus_audio_open_input(int ur_dev, int srate, int chans, mus_sample_t samp_type, int size)
5120 {
5121   audio_info_t info;
5122   int encode, bits, dev, audio_fd, err;
5123 
5124   dev = MUS_AUDIO_DEVICE(ur_dev);
5125   encode = sndlib_format_to_bsd(samp_type);
5126   bits = 8 * mus_bytes_per_sample(samp_type);
5127   if (encode == AUDIO_ENCODING_NONE)
5128     return_error_exit(MUS_AUDIO_SAMPLE_TYPE_NOT_AVAILABLE, -1,
5129 		      mus_format("sample type %s not available for recording",
5130 				 mus_sample_type_name(samp_type)));
5131 
5132   if (dev != MUS_AUDIO_DUPLEX_DEFAULT)
5133     audio_fd = open("/dev/sound", O_RDONLY, 0);
5134   else audio_fd = open("/dev/sound", O_RDWR, 0);
5135   if (audio_fd == -1)
5136     return_error_exit(MUS_AUDIO_CANT_OPEN, -1,
5137 		      mus_format("can't open /dev/sound: %s",
5138 				 strerror(errno)));
5139 
5140   AUDIO_INITINFO(&info);
5141   info.record.sample_rate = srate;
5142   info.record.channels = chans;
5143   info.record.precision = bits;
5144   info.record.encoding = encode;
5145   info.record.port = AUDIO_MICROPHONE;
5146   err = ioctl(audio_fd, AUDIO_SETINFO, &info);
5147   if (err == -1)
5148     return_error_exit(MUS_AUDIO_CANT_WRITE, audio_fd,
5149 		      mus_format("can't set up for recording"));
5150   return(audio_fd);
5151 }
5152 
5153 #endif
5154 
5155 
5156 
5157 /* -------------------------------- PULSEAUDIO -------------------------------- */
5158 
5159 #if defined(MUS_PULSEAUDIO) && (!(defined(AUDIO_OK)))
5160 #define AUDIO_OK 1
5161 
5162 
5163 /* this code compiles/loads, but I don't know if it works -- paplay itself
5164  *   doesn't work on my machine due to either a libtool/dlopen mismatch
5165  *   or some problem with "pulse-rt".
5166  */
5167 
5168 
5169 #include <pulse/simple.h>
5170 #include <pulse/error.h>
5171 #include <pulse/gccmacro.h>
5172 
5173 
sndlib_to_pa_format(mus_sample_t samp_type)5174 static int sndlib_to_pa_format(mus_sample_t samp_type)
5175 {
5176   switch (samp_type)
5177     {
5178     case MUS_BYTE:   return(PA_SAMPLE_U8);
5179     case MUS_LSHORT: return(PA_SAMPLE_S16LE);
5180     case MUS_BSHORT: return(PA_SAMPLE_S16BE);
5181     case MUS_LINT:   return(PA_SAMPLE_S32LE);
5182     case MUS_BINT:   return(PA_SAMPLE_S32BE);
5183     case MUS_LFLOAT: return(PA_SAMPLE_FLOAT32LE);
5184     case MUS_BFLOAT: return(PA_SAMPLE_FLOAT32BE);
5185     case MUS_ALAW:   return(PA_SAMPLE_ALAW);
5186     case MUS_MULAW:  return(PA_SAMPLE_ULAW);
5187 
5188     default:
5189       fprintf(stderr, "unsupported sample type: %d\n", samp_type);
5190       return(0);
5191       break;
5192     }
5193 }
5194 
5195 
5196 static pa_simple *pa_out = NULL, *pa_in = NULL;
5197 
mus_audio_open_output(int dev,int srate,int chans,mus_sample_t samp_type,int size)5198 int mus_audio_open_output(int dev, int srate, int chans, mus_sample_t samp_type, int size)
5199 {
5200   pa_sample_spec spec = {0};
5201   int error;
5202 
5203   spec.format = sndlib_to_pa_format(samp_type);
5204   spec.rate = srate;
5205   spec.channels = chans;
5206 
5207   pa_out = pa_simple_new(NULL, "snd", PA_STREAM_PLAYBACK, NULL, "playback", &spec, NULL, NULL, &error);
5208   if (!pa_out)
5209     {
5210       fprintf(stderr, "can't play: %s\n", pa_strerror(error));
5211       return(MUS_ERROR);
5212     }
5213   return(0);
5214 }
5215 
5216 
mus_audio_open_input(int dev,int srate,int chans,mus_sample_t samp_type,int size)5217 int mus_audio_open_input(int dev, int srate, int chans, mus_sample_t samp_type, int size)
5218 {
5219   return(MUS_ERROR);
5220 }
5221 
5222 
mus_audio_write(int line,char * buf,int bytes)5223 int mus_audio_write(int line, char *buf, int bytes)
5224 {
5225   int error;
5226   pa_simple_write(pa_out, (unsigned char *)buf, (size_t)bytes, &error);
5227   return(error);
5228 }
5229 
5230 
mus_audio_close(int line)5231 int mus_audio_close(int line)
5232 {
5233   int error;
5234   pa_simple_drain(pa_out, &error);
5235   pa_simple_free(pa_out);
5236   pa_out = NULL;
5237   return(error);
5238 }
5239 
5240 
mus_audio_read(int line,char * buf,int bytes)5241 int mus_audio_read(int line, char *buf, int bytes)
5242 {
5243   return(MUS_ERROR);
5244 }
5245 
5246 
mus_audio_initialize(void)5247 int mus_audio_initialize(void)
5248 {
5249   return(MUS_ERROR);
5250 }
5251 
5252 
mus_audio_moniker(void)5253 char *mus_audio_moniker(void)
5254 {
5255   return(mus_format("pulseaudio %s", pa_get_library_version()));
5256 }
5257 
5258 
5259 #endif
5260 
5261 
5262 
5263 /* -------------------------------- PORTAUDIO -------------------------------- */
5264 
5265 #if defined(MUS_PORTAUDIO) && (!(defined(AUDIO_OK)))
5266 #define AUDIO_OK 1
5267 
5268 #include <portaudio.h>
5269 
5270 #define PA_OUT_STREAM 0
5271 #define PA_IN_STREAM 1
5272 
sndlib_to_portaudio_format(mus_sample_t samp_type)5273 static unsigned long sndlib_to_portaudio_format(mus_sample_t samp_type)
5274 {
5275   switch (samp_type)
5276     {
5277     case MUS_BYTE:   return(paInt8);
5278     case MUS_LSHORT: return(paInt16);
5279     case MUS_BSHORT: return(paInt16);
5280     case MUS_LINT:   return(paInt32);
5281     case MUS_BINT:   return(paInt32);
5282     case MUS_LFLOAT: return(paFloat32);
5283     case MUS_BFLOAT: return(paFloat32);
5284     default: break;
5285     }
5286   return(paInt16);
5287 }
5288 
5289 static PaStream *out_stream = NULL;
5290 
mus_audio_open_output(int dev,int srate,int chans,mus_sample_t samp_type,int size)5291 int mus_audio_open_output(int dev, int srate, int chans, mus_sample_t samp_type, int size)
5292 {
5293   PaStreamParameters output_pars;
5294   PaError err;
5295 
5296   output_pars.device = Pa_GetDefaultOutputDevice();
5297   output_pars.channelCount = chans;
5298   output_pars.sampleFormat = sndlib_to_portaudio_format(samp_type);
5299   output_pars.suggestedLatency = Pa_GetDeviceInfo(output_pars.device)->defaultHighOutputLatency;
5300   output_pars.hostApiSpecificStreamInfo = NULL;
5301 
5302   err = Pa_OpenStream(&out_stream, NULL, &output_pars, srate, 1024, paClipOff, NULL, NULL); /* 1024 = frames [dac_size] but can we use "size"? */
5303   if (err == paNoError)
5304     err = Pa_StartStream(out_stream);
5305 
5306   if (err != paNoError)
5307     {
5308       fprintf(stderr, "portaudio open output: %s\n", Pa_GetErrorText(err));
5309       return(MUS_ERROR);
5310     }
5311   return(PA_OUT_STREAM);
5312 }
5313 
5314 
5315 static PaStream *in_stream = NULL;
5316 
mus_audio_open_input(int dev,int srate,int chans,mus_sample_t samp_type,int size)5317 int mus_audio_open_input(int dev, int srate, int chans, mus_sample_t samp_type, int size)
5318 {
5319   PaStreamParameters input_pars;
5320   PaError err;
5321 
5322   input_pars.device = Pa_GetDefaultInputDevice();
5323   input_pars.channelCount = chans;
5324   input_pars.sampleFormat = sndlib_to_portaudio_format(samp_type);
5325   input_pars.suggestedLatency = Pa_GetDeviceInfo(input_pars.device)->defaultHighInputLatency;
5326   input_pars.hostApiSpecificStreamInfo = NULL;
5327 
5328   err = Pa_OpenStream(&in_stream, &input_pars, NULL, srate, 1024, paClipOff, NULL, NULL);
5329   if (err == paNoError)
5330     err = Pa_StartStream(in_stream);
5331 
5332   if (err != paNoError)
5333     {
5334       fprintf(stderr, "portaudio open input: %s\n", Pa_GetErrorText(err));
5335       return(MUS_ERROR);
5336     }
5337   return(MUS_NO_ERROR);
5338 
5339 }
5340 
5341 
mus_audio_write(int line,char * buf,int bytes)5342 int mus_audio_write(int line, char *buf, int bytes)
5343 {
5344   PaError err;
5345   err = Pa_WriteStream(out_stream, buf, 1024);
5346 
5347   if (err != paNoError)
5348     {
5349       fprintf(stderr, "portaudio write: %s\n", Pa_GetErrorText(err));
5350       return(MUS_ERROR);
5351     }
5352   return(MUS_NO_ERROR);
5353 }
5354 
5355 
mus_audio_close(int line)5356 int mus_audio_close(int line)
5357 {
5358   PaError err;
5359   if (line == PA_IN_STREAM)
5360     err = Pa_CloseStream(in_stream);
5361   else err = Pa_CloseStream(out_stream);
5362 
5363   if (err != paNoError)
5364     {
5365       fprintf(stderr, "portaudio close: %s\n", Pa_GetErrorText(err));
5366       return(MUS_ERROR);
5367     }
5368   return(MUS_NO_ERROR);
5369 }
5370 
5371 
mus_audio_read(int line,char * buf,int bytes)5372 int mus_audio_read(int line, char *buf, int bytes)
5373 {
5374   PaError err;
5375   err = Pa_ReadStream(in_stream, buf, 1024);
5376 
5377   if (err != paNoError)
5378     {
5379       fprintf(stderr, "portaudio read: %s\n", Pa_GetErrorText(err));
5380       return(MUS_ERROR);
5381     }
5382   return(MUS_NO_ERROR);
5383 }
5384 
5385 
5386 static bool portaudio_initialized = false;
5387 
mus_audio_initialize(void)5388 int mus_audio_initialize(void)
5389 {
5390   PaError err;
5391 
5392   if (portaudio_initialized) return(MUS_NO_ERROR);
5393   portaudio_initialized = true;
5394 
5395   err = Pa_Initialize();
5396   if (err == paNoError)
5397     return(MUS_NO_ERROR);
5398 
5399   fprintf(stderr, "portaudio initialize: %s\n", Pa_GetErrorText(err));
5400   return(MUS_ERROR);
5401 }
5402 
5403 
mus_audio_moniker(void)5404 char *mus_audio_moniker(void)
5405 {
5406   return((char *)Pa_GetVersionText());
5407 }
5408 #endif
5409 
5410 
5411 
5412 
5413 /* ------------------------------- STUBS ----------------------------------------- */
5414 
5415 #ifndef AUDIO_OK
mus_audio_open_output(int dev,int srate,int chans,mus_sample_t samp_type,int size)5416 int mus_audio_open_output(int dev, int srate, int chans, mus_sample_t samp_type, int size) {return(MUS_ERROR);}
mus_audio_open_input(int dev,int srate,int chans,mus_sample_t samp_type,int size)5417 int mus_audio_open_input(int dev, int srate, int chans, mus_sample_t samp_type, int size) {return(MUS_ERROR);}
mus_audio_write(int line,char * buf,int bytes)5418 int mus_audio_write(int line, char *buf, int bytes) {return(MUS_ERROR);}
mus_audio_close(int line)5419 int mus_audio_close(int line) {return(MUS_ERROR);}
mus_audio_read(int line,char * buf,int bytes)5420 int mus_audio_read(int line, char *buf, int bytes) {return(MUS_ERROR);}
mus_audio_initialize(void)5421 int mus_audio_initialize(void) {return(MUS_ERROR);}
mus_audio_moniker(void)5422 char *mus_audio_moniker(void) {return((char *)"no audio support");}
5423 #endif
5424 
5425 
5426 
5427 /* for CLM */
mus_reset_audio_c(void)5428 void mus_reset_audio_c(void)
5429 {
5430   audio_initialized = false;
5431   version_name = NULL;
5432 }
5433 
5434 
5435 #if HAVE_ALSA || HAVE_OSS
5436 
5437 void mus_audio_alsa_channel_info(int dev, int *info);
mus_audio_alsa_channel_info(int dev,int * info)5438 void mus_audio_alsa_channel_info(int dev, int *info)
5439 {
5440 #if MUS_JACK
5441   if (api == MUS_JACK_API)
5442     {
5443       info[0] = sndjack_num_channels_allocated;
5444       return;
5445     }
5446 #endif
5447 
5448 #if HAVE_ALSA
5449   if (api == MUS_ALSA_API)
5450     {
5451       alsa_chans(dev, info);
5452       return;
5453     }
5454 #endif
5455 
5456 #if HAVE_OSS
5457   info[0] = 2;
5458 #endif
5459 
5460 }
5461 
5462 
5463 int mus_audio_alsa_samples_per_channel(int dev);
mus_audio_alsa_samples_per_channel(int dev)5464 int mus_audio_alsa_samples_per_channel(int dev)
5465 {
5466 #if HAVE_ALSA
5467   return(alsa_samples_per_channel);
5468 #else
5469   return(1024);
5470 #endif
5471 }
5472 
5473 
5474 void mus_audio_alsa_device_list(int ur_dev, int chan, int *val);
mus_audio_alsa_device_list(int ur_dev,int chan,int * val)5475 void mus_audio_alsa_device_list(int ur_dev, int chan, int *val)
5476 {
5477 #if HAVE_ALSA
5478   int i = 1;
5479 
5480   if (!audio_initialized) mus_audio_initialize();
5481 
5482   if (alsa_hw_params[SND_PCM_STREAM_PLAYBACK])
5483     val[i++] = to_sndlib_device(0, SND_PCM_STREAM_PLAYBACK);
5484 
5485   if (alsa_hw_params[SND_PCM_STREAM_CAPTURE])
5486     val[i++] = to_sndlib_device(0, SND_PCM_STREAM_CAPTURE);
5487 
5488   val[0] = (i - 1);
5489 #endif
5490 }
5491 
5492 #define MUS_AUDIO_DIRECTION_PLAYBACK 0
5493 #define MUS_AUDIO_DIRECTION_RECORD 1
5494 
5495 int mus_audio_alsa_device_direction(int dev);
mus_audio_alsa_device_direction(int dev)5496 int mus_audio_alsa_device_direction(int dev)
5497 {
5498 #if HAVE_OSS
5499   switch (MUS_AUDIO_DEVICE(dev))
5500     {
5501     case MUS_AUDIO_DIGITAL_OUT: case MUS_AUDIO_LINE_OUT: case MUS_AUDIO_DEFAULT:
5502     case MUS_AUDIO_SPEAKERS: case MUS_AUDIO_MIXER:
5503     case MUS_AUDIO_AUX_OUTPUT: case MUS_AUDIO_DAC_OUT:
5504       return(MUS_AUDIO_DIRECTION_PLAYBACK);
5505 
5506     default:
5507       return(MUS_AUDIO_DIRECTION_RECORD);
5508     }
5509 #else
5510   {
5511     int card, device, alsa_device = 0;
5512     snd_pcm_stream_t alsa_stream = SND_PCM_STREAM_PLAYBACK;
5513 
5514     if ((!audio_initialized) &&
5515 	(mus_audio_initialize() != MUS_NO_ERROR))
5516       return(MUS_ERROR);
5517 
5518     card = MUS_AUDIO_SYSTEM(dev);
5519     device = MUS_AUDIO_DEVICE(dev);
5520     to_alsa_device(device, &alsa_device, &alsa_stream);
5521 
5522     if (card > 0 || alsa_device > 0)
5523       return(alsa_mus_error(MUS_AUDIO_CANT_READ, NULL));
5524     return(alsa_stream);
5525   }
5526 #endif
5527 }
5528 #endif
5529 
5530 
mus_audio_device_channels(int dev)5531 int mus_audio_device_channels(int dev)
5532 {
5533 #if MUS_JACK
5534   if (api == MUS_JACK_API)
5535     {
5536       return(sndjack_num_channels_allocated);
5537     }
5538 #endif
5539 
5540 #if HAVE_ALSA
5541   if (api == MUS_ALSA_API)
5542     {
5543       return(alsa_chans(dev, NULL));
5544     }
5545 #endif
5546 
5547   return(2); /* netbsd hpux sun mac and oss with quibbles */
5548 }
5549 
5550 
mus_audio_compatible_sample_type(int dev)5551 mus_sample_t mus_audio_compatible_sample_type(int dev) /* snd-dac and sndplay */
5552 {
5553 #if HAVE_ALSA
5554   if (api == MUS_ALSA_API)
5555     {
5556       int err;
5557       mus_sample_t ival[32];
5558       err = alsa_sample_types(dev, 32, ival);
5559       if (err != MUS_ERROR)
5560 	{
5561 	  int i;
5562 	  for (i = 1; i <= (int)(ival[0]); i++)
5563 	    if (ival[i] == MUS_AUDIO_COMPATIBLE_SAMPLE_TYPE)
5564 	      return(MUS_AUDIO_COMPATIBLE_SAMPLE_TYPE);
5565 
5566 	  for (i = 1; i <= (int)(ival[0]); i++)
5567 	    if ((ival[i] == MUS_BINT) || (ival[i] == MUS_LINT) ||
5568 	        (ival[i] == MUS_BFLOAT) || (ival[i] == MUS_LFLOAT) ||
5569 		(ival[i] == MUS_BSHORT) || (ival[i] == MUS_LSHORT))
5570 	      return(ival[i]);
5571 
5572 	  for (i = 1; i <= (int)(ival[0]); i++)
5573 	    if ((ival[i] == MUS_MULAW) || (ival[i] == MUS_ALAW) ||
5574 	        (ival[i] == MUS_UBYTE) || (ival[i] == MUS_BYTE))
5575 	      return(ival[i]);
5576 
5577 	  return(ival[1]);
5578 	}
5579     }
5580 #endif
5581 
5582 #if MUS_JACK
5583   if (api == MUS_JACK_API)
5584     return(MUS_COMP_FLOAT);
5585 #endif
5586   return(MUS_AUDIO_COMPATIBLE_SAMPLE_TYPE);
5587 }
5588 
5589 
look_for_sample_type(mus_sample_t * mixer_vals,mus_sample_t samp_type)5590 static mus_sample_t look_for_sample_type (mus_sample_t *mixer_vals, mus_sample_t samp_type)
5591 {
5592   int i, lim;
5593   lim = mixer_vals[0];
5594   for (i = 1; i <= lim; i++)
5595     if (mixer_vals[i] == samp_type)
5596       return(samp_type);
5597   return(MUS_UNKNOWN_SAMPLE);
5598 }
5599 
5600 
mus_audio_device_sample_type(int dev)5601 mus_sample_t mus_audio_device_sample_type(int dev) /* snd-dac */
5602 {
5603   mus_sample_t mixer_vals[16];
5604   mus_sample_t samp_type;
5605   int i;
5606   /* we return the new sample type, so mixer_vals is just a local collector of possible sample types */
5607   for (i = 0; i < 16; i++) mixer_vals[i] = MUS_UNKNOWN_SAMPLE;
5608 
5609 #if (!WITH_AUDIO)
5610   return(MUS_AUDIO_COMPATIBLE_SAMPLE_TYPE);
5611 #endif
5612 
5613 #if HAVE_OSS
5614   if (api == MUS_OSS_API)
5615     oss_sample_types(dev, mixer_vals);
5616 #endif
5617 
5618 #if HAVE_ALSA
5619   if (api == MUS_ALSA_API)
5620     alsa_sample_types(dev, 16, mixer_vals);
5621 #endif
5622 
5623 #if MUS_JACK
5624   if (api == MUS_JACK_API)
5625     {
5626       mixer_vals[0] = (mus_sample_t)1;
5627       mixer_vals[1] = MUS_COMP_FLOAT;
5628     }
5629 #endif
5630 
5631 #if HAVE_SUN
5632   mixer_vals[0] = (mus_sample_t)2;
5633   mixer_vals[1] = MUS_LSHORT;
5634   mixer_vals[2] = MUS_MULAW;
5635 #endif
5636 
5637 #if __APPLE__
5638   mixer_vals[0] = (mus_sample_t)1;
5639 #if MUS_LITTLE_ENDIAN
5640   mixer_vals[1] = MUS_LFLOAT;
5641 #else
5642   mixer_vals[1] = MUS_BFLOAT;
5643 #endif
5644 #endif
5645 
5646 #if __NetBSD__
5647   netbsd_sample_types(dev, mixer_vals);
5648 #endif
5649 
5650 #if __OpenBSD__
5651   mixer_vals[0] = (mus_sample_t)1;
5652 #if MUS_LITTLE_ENDIAN
5653   mixer_vals[1] = MUS_LSHORT;
5654 #else
5655   mixer_vals[1] = MUS_BSHORT;
5656 #endif
5657 #endif
5658 
5659   samp_type = look_for_sample_type(mixer_vals, MUS_AUDIO_COMPATIBLE_SAMPLE_TYPE);
5660   if (samp_type != MUS_UNKNOWN_SAMPLE)
5661     return(samp_type);
5662 
5663 #if MUS_LITTLE_ENDIAN
5664   samp_type = look_for_sample_type(mixer_vals, MUS_LFLOAT);
5665   if (samp_type == MUS_UNKNOWN_SAMPLE)
5666     {
5667       samp_type = look_for_sample_type(mixer_vals, MUS_LSHORT);
5668       if (samp_type == MUS_UNKNOWN_SAMPLE)
5669 	samp_type = mixer_vals[1];
5670     }
5671 #else
5672   samp_type = look_for_sample_type(mixer_vals, MUS_BFLOAT);
5673   if (samp_type == MUS_UNKNOWN_SAMPLE)
5674     {
5675       samp_type = look_for_sample_type(mixer_vals, MUS_BSHORT);
5676       if (samp_type == MUS_UNKNOWN_SAMPLE)
5677 	samp_type = mixer_vals[1];
5678     }
5679 #endif
5680   return(samp_type);
5681 }
5682 
5683 
5684 #else
5685 /* not WITH_AUDIO */
5686 
mus_audio_open_output(int dev,int srate,int chans,mus_sample_t samp_type,int size)5687 int mus_audio_open_output(int dev, int srate, int chans, mus_sample_t samp_type, int size) {return(-1);}
mus_audio_open_input(int dev,int srate,int chans,mus_sample_t samp_type,int size)5688 int mus_audio_open_input(int dev, int srate, int chans, mus_sample_t samp_type, int size) {return(-1);}
mus_audio_write(int line,char * buf,int bytes)5689 int mus_audio_write(int line, char *buf, int bytes) {return(-1);}
mus_audio_close(int line)5690 int mus_audio_close(int line) {return(-1);}
mus_audio_read(int line,char * buf,int bytes)5691 int mus_audio_read(int line, char *buf, int bytes) {return(-1);}
mus_audio_initialize(void)5692 int mus_audio_initialize(void) {return(-1);}
mus_audio_moniker(void)5693 char *mus_audio_moniker(void) {return((char *)"no audio support");}
5694 
mus_reset_audio_c(void)5695 void mus_reset_audio_c(void) {}
5696 
mus_audio_device_channels(int dev)5697 int mus_audio_device_channels(int dev) {return(0);}
mus_audio_compatible_sample_type(int dev)5698 mus_sample_t mus_audio_compatible_sample_type(int dev) {return(MUS_UNKNOWN_SAMPLE);}
mus_audio_device_sample_type(int dev)5699 mus_sample_t mus_audio_device_sample_type(int dev) {return(MUS_UNKNOWN_SAMPLE);}
5700 
5701 #if __APPLE__
mus_audio_output_properties_mutable(bool mut)5702 bool mus_audio_output_properties_mutable(bool mut) {return(false);}
5703 #endif
5704 #endif
5705