SDL  2.0
SDL_paudio.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
4 
5  This software is provided 'as-is', without any express or implied
6  warranty. In no event will the authors be held liable for any damages
7  arising from the use of this software.
8 
9  Permission is granted to anyone to use this software for any purpose,
10  including commercial applications, and to alter it and redistribute it
11  freely, subject to the following restrictions:
12 
13  1. The origin of this software must not be misrepresented; you must not
14  claim that you wrote the original software. If you use this software
15  in a product, an acknowledgment in the product documentation would be
16  appreciated but is not required.
17  2. Altered source versions must be plainly marked as such, and must not be
18  misrepresented as being the original software.
19  3. This notice may not be removed or altered from any source distribution.
20 */
21 #include "../../SDL_internal.h"
22 
23 #if SDL_AUDIO_DRIVER_PAUDIO
24 
25 /* Allow access to a raw mixing buffer */
26 
27 #include <errno.h>
28 #include <unistd.h>
29 #include <fcntl.h>
30 #include <sys/time.h>
31 #include <sys/ioctl.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 
35 #include "SDL_timer.h"
36 #include "SDL_audio.h"
37 #include "SDL_stdinc.h"
38 #include "../SDL_audiomem.h"
39 #include "../SDL_audio_c.h"
40 #include "SDL_paudio.h"
41 
42 #define DEBUG_AUDIO 0
43 
44 /* A conflict within AIX 4.3.3 <sys/> headers and probably others as well.
45  * I guess nobody ever uses audio... Shame over AIX header files. */
46 #include <sys/machine.h>
47 #undef BIG_ENDIAN
48 #include <sys/audio.h>
49 
50 /* Open the audio device for playback, and don't block if busy */
51 /* #define OPEN_FLAGS (O_WRONLY|O_NONBLOCK) */
52 #define OPEN_FLAGS O_WRONLY
53 
54 /* Get the name of the audio device we use for output */
55 
56 #ifndef _PATH_DEV_DSP
57 #define _PATH_DEV_DSP "/dev/%caud%c/%c"
58 #endif
59 
60 static char devsettings[][3] = {
61  {'p', '0', '1'}, {'p', '0', '2'}, {'p', '0', '3'}, {'p', '0', '4'},
62  {'p', '1', '1'}, {'p', '1', '2'}, {'p', '1', '3'}, {'p', '1', '4'},
63  {'p', '2', '1'}, {'p', '2', '2'}, {'p', '2', '3'}, {'p', '2', '4'},
64  {'p', '3', '1'}, {'p', '3', '2'}, {'p', '3', '3'}, {'p', '3', '4'},
65  {'b', '0', '1'}, {'b', '0', '2'}, {'b', '0', '3'}, {'b', '0', '4'},
66  {'b', '1', '1'}, {'b', '1', '2'}, {'b', '1', '3'}, {'b', '1', '4'},
67  {'b', '2', '1'}, {'b', '2', '2'}, {'b', '2', '3'}, {'b', '2', '4'},
68  {'b', '3', '1'}, {'b', '3', '2'}, {'b', '3', '3'}, {'b', '3', '4'},
69  {'\0', '\0', '\0'}
70 };
71 
72 static int
73 OpenUserDefinedDevice(char *path, int maxlen, int flags)
74 {
75  const char *audiodev;
76  int fd;
77 
78  /* Figure out what our audio device is */
79  if ((audiodev = SDL_getenv("SDL_PATH_DSP")) == NULL) {
80  audiodev = SDL_getenv("AUDIODEV");
81  }
82  if (audiodev == NULL) {
83  return -1;
84  }
85  fd = open(audiodev, flags, 0);
86  if (path != NULL) {
87  SDL_strlcpy(path, audiodev, maxlen);
88  path[maxlen - 1] = '\0';
89  }
90  return fd;
91 }
92 
93 static int
94 OpenAudioPath(char *path, int maxlen, int flags, int classic)
95 {
96  struct stat sb;
97  int cycle = 0;
98  int fd = OpenUserDefinedDevice(path, maxlen, flags);
99 
100  if (fd != -1) {
101  return fd;
102  }
103 
104  /* !!! FIXME: do we really need a table here? */
105  while (devsettings[cycle][0] != '\0') {
106  char audiopath[1024];
107  SDL_snprintf(audiopath, SDL_arraysize(audiopath),
108  _PATH_DEV_DSP,
109  devsettings[cycle][0],
110  devsettings[cycle][1], devsettings[cycle][2]);
111 
112  if (stat(audiopath, &sb) == 0) {
113  fd = open(audiopath, flags, 0);
114  if (fd >= 0) {
115  if (path != NULL) {
116  SDL_strlcpy(path, audiopath, maxlen);
117  }
118  return fd;
119  }
120  }
121  }
122  return -1;
123 }
124 
125 /* This function waits until it is possible to write a full sound buffer */
126 static void
127 PAUDIO_WaitDevice(_THIS)
128 {
129  fd_set fdset;
130 
131  /* See if we need to use timed audio synchronization */
132  if (this->hidden->frame_ticks) {
133  /* Use timer for general audio synchronization */
134  Sint32 ticks;
135 
136  ticks = ((Sint32) (this->hidden->next_frame - SDL_GetTicks())) - FUDGE_TICKS;
137  if (ticks > 0) {
138  SDL_Delay(ticks);
139  }
140  } else {
141  audio_buffer paud_bufinfo;
142 
143  /* Use select() for audio synchronization */
144  struct timeval timeout;
145  FD_ZERO(&fdset);
146  FD_SET(this->hidden->audio_fd, &fdset);
147 
148  if (ioctl(this->hidden->audio_fd, AUDIO_BUFFER, &paud_bufinfo) < 0) {
149 #ifdef DEBUG_AUDIO
150  fprintf(stderr, "Couldn't get audio buffer information\n");
151 #endif
152  timeout.tv_sec = 10;
153  timeout.tv_usec = 0;
154  } else {
155  long ms_in_buf = paud_bufinfo.write_buf_time;
156  timeout.tv_sec = ms_in_buf / 1000;
157  ms_in_buf = ms_in_buf - timeout.tv_sec * 1000;
158  timeout.tv_usec = ms_in_buf * 1000;
159 #ifdef DEBUG_AUDIO
160  fprintf(stderr,
161  "Waiting for write_buf_time=%ld,%ld\n",
162  timeout.tv_sec, timeout.tv_usec);
163 #endif
164  }
165 
166 #ifdef DEBUG_AUDIO
167  fprintf(stderr, "Waiting for audio to get ready\n");
168 #endif
169  if (select(this->hidden->audio_fd + 1, NULL, &fdset, NULL, &timeout)
170  <= 0) {
171  const char *message =
172  "Audio timeout - buggy audio driver? (disabled)";
173  /*
174  * In general we should never print to the screen,
175  * but in this case we have no other way of letting
176  * the user know what happened.
177  */
178  fprintf(stderr, "SDL: %s - %s\n", strerror(errno), message);
180  /* Don't try to close - may hang */
181  this->hidden->audio_fd = -1;
182 #ifdef DEBUG_AUDIO
183  fprintf(stderr, "Done disabling audio\n");
184 #endif
185  }
186 #ifdef DEBUG_AUDIO
187  fprintf(stderr, "Ready!\n");
188 #endif
189  }
190 }
191 
192 static void
193 PAUDIO_PlayDevice(_THIS)
194 {
195  int written = 0;
196  const Uint8 *mixbuf = this->hidden->mixbuf;
197  const size_t mixlen = this->hidden->mixlen;
198 
199  /* Write the audio data, checking for EAGAIN on broken audio drivers */
200  do {
201  written = write(this->hidden->audio_fd, mixbuf, mixlen);
202  if ((written < 0) && ((errno == 0) || (errno == EAGAIN))) {
203  SDL_Delay(1); /* Let a little CPU time go by */
204  }
205  } while ((written < 0) &&
206  ((errno == 0) || (errno == EAGAIN) || (errno == EINTR)));
207 
208  /* If timer synchronization is enabled, set the next write frame */
209  if (this->hidden->frame_ticks) {
210  this->hidden->next_frame += this->hidden->frame_ticks;
211  }
212 
213  /* If we couldn't write, assume fatal error for now */
214  if (written < 0) {
216  }
217 #ifdef DEBUG_AUDIO
218  fprintf(stderr, "Wrote %d bytes of audio data\n", written);
219 #endif
220 }
221 
222 static Uint8 *
223 PAUDIO_GetDeviceBuf(_THIS)
224 {
225  return this->hidden->mixbuf;
226 }
227 
228 static void
229 PAUDIO_CloseDevice(_THIS)
230 {
231  if (this->hidden != NULL) {
232  SDL_FreeAudioMem(this->hidden->mixbuf);
233  this->hidden->mixbuf = NULL;
234  if (this->hidden->audio_fd >= 0) {
235  close(this->hidden->audio_fd);
236  this->hidden->audio_fd = -1;
237  }
238  SDL_free(this->hidden);
239  this->hidden = NULL;
240  }
241 }
242 
243 static int
244 PAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
245 {
246  const char *workaround = SDL_getenv("SDL_DSP_NOSELECT");
247  char audiodev[1024];
248  const char *err = NULL;
249  int format;
250  int bytes_per_sample;
251  SDL_AudioFormat test_format;
252  audio_init paud_init;
253  audio_buffer paud_bufinfo;
254  audio_status paud_status;
255  audio_control paud_control;
256  audio_change paud_change;
257  int fd = -1;
258 
259  /* Initialize all variables that we clean on shutdown */
260  this->hidden = (struct SDL_PrivateAudioData *)
261  SDL_malloc((sizeof *this->hidden));
262  if (this->hidden == NULL) {
263  return SDL_OutOfMemory();
264  }
265  SDL_memset(this->hidden, 0, (sizeof *this->hidden));
266 
267  /* Open the audio device */
268  fd = OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0);
269  this->hidden->audio_fd = fd;
270  if (fd < 0) {
271  PAUDIO_CloseDevice(this);
272  return SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno));
273  }
274 
275  /*
276  * We can't set the buffer size - just ask the device for the maximum
277  * that we can have.
278  */
279  if (ioctl(fd, AUDIO_BUFFER, &paud_bufinfo) < 0) {
280  PAUDIO_CloseDevice(this);
281  return SDL_SetError("Couldn't get audio buffer information");
282  }
283 
284  if (this->spec.channels > 1)
285  this->spec.channels = 2;
286  else
287  this->spec.channels = 1;
288 
289  /*
290  * Fields in the audio_init structure:
291  *
292  * Ignored by us:
293  *
294  * paud.loadpath[LOAD_PATH]; * DSP code to load, MWave chip only?
295  * paud.slot_number; * slot number of the adapter
296  * paud.device_id; * adapter identification number
297  *
298  * Input:
299  *
300  * paud.srate; * the sampling rate in Hz
301  * paud.bits_per_sample; * 8, 16, 32, ...
302  * paud.bsize; * block size for this rate
303  * paud.mode; * ADPCM, PCM, MU_LAW, A_LAW, SOURCE_MIX
304  * paud.channels; * 1=mono, 2=stereo
305  * paud.flags; * FIXED - fixed length data
306  * * LEFT_ALIGNED, RIGHT_ALIGNED (var len only)
307  * * TWOS_COMPLEMENT - 2's complement data
308  * * SIGNED - signed? comment seems wrong in sys/audio.h
309  * * BIG_ENDIAN
310  * paud.operation; * PLAY, RECORD
311  *
312  * Output:
313  *
314  * paud.flags; * PITCH - pitch is supported
315  * * INPUT - input is supported
316  * * OUTPUT - output is supported
317  * * MONITOR - monitor is supported
318  * * VOLUME - volume is supported
319  * * VOLUME_DELAY - volume delay is supported
320  * * BALANCE - balance is supported
321  * * BALANCE_DELAY - balance delay is supported
322  * * TREBLE - treble control is supported
323  * * BASS - bass control is supported
324  * * BESTFIT_PROVIDED - best fit returned
325  * * LOAD_CODE - DSP load needed
326  * paud.rc; * NO_PLAY - DSP code can't do play requests
327  * * NO_RECORD - DSP code can't do record requests
328  * * INVALID_REQUEST - request was invalid
329  * * CONFLICT - conflict with open's flags
330  * * OVERLOADED - out of DSP MIPS or memory
331  * paud.position_resolution; * smallest increment for position
332  */
333 
334  paud_init.srate = this->spec.freq;
335  paud_init.mode = PCM;
336  paud_init.operation = PLAY;
337  paud_init.channels = this->spec.channels;
338 
339  /* Try for a closest match on audio format */
340  format = 0;
341  for (test_format = SDL_FirstAudioFormat(this->spec.format);
342  !format && test_format;) {
343 #ifdef DEBUG_AUDIO
344  fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
345 #endif
346  switch (test_format) {
347  case AUDIO_U8:
348  bytes_per_sample = 1;
349  paud_init.bits_per_sample = 8;
350  paud_init.flags = TWOS_COMPLEMENT | FIXED;
351  format = 1;
352  break;
353  case AUDIO_S8:
354  bytes_per_sample = 1;
355  paud_init.bits_per_sample = 8;
356  paud_init.flags = SIGNED | TWOS_COMPLEMENT | FIXED;
357  format = 1;
358  break;
359  case AUDIO_S16LSB:
360  bytes_per_sample = 2;
361  paud_init.bits_per_sample = 16;
362  paud_init.flags = SIGNED | TWOS_COMPLEMENT | FIXED;
363  format = 1;
364  break;
365  case AUDIO_S16MSB:
366  bytes_per_sample = 2;
367  paud_init.bits_per_sample = 16;
368  paud_init.flags = BIG_ENDIAN | SIGNED | TWOS_COMPLEMENT | FIXED;
369  format = 1;
370  break;
371  case AUDIO_U16LSB:
372  bytes_per_sample = 2;
373  paud_init.bits_per_sample = 16;
374  paud_init.flags = TWOS_COMPLEMENT | FIXED;
375  format = 1;
376  break;
377  case AUDIO_U16MSB:
378  bytes_per_sample = 2;
379  paud_init.bits_per_sample = 16;
380  paud_init.flags = BIG_ENDIAN | TWOS_COMPLEMENT | FIXED;
381  format = 1;
382  break;
383  default:
384  break;
385  }
386  if (!format) {
387  test_format = SDL_NextAudioFormat();
388  }
389  }
390  if (format == 0) {
391 #ifdef DEBUG_AUDIO
392  fprintf(stderr, "Couldn't find any hardware audio formats\n");
393 #endif
394  PAUDIO_CloseDevice(this);
395  return SDL_SetError("Couldn't find any hardware audio formats");
396  }
397  this->spec.format = test_format;
398 
399  /*
400  * We know the buffer size and the max number of subsequent writes
401  * that can be pending. If more than one can pend, allow the application
402  * to do something like double buffering between our write buffer and
403  * the device's own buffer that we are filling with write() anyway.
404  *
405  * We calculate this->spec.samples like this because
406  * SDL_CalculateAudioSpec() will give put paud_bufinfo.write_buf_cap
407  * (or paud_bufinfo.write_buf_cap/2) into this->spec.size in return.
408  */
409  if (paud_bufinfo.request_buf_cap == 1) {
410  this->spec.samples = paud_bufinfo.write_buf_cap
411  / bytes_per_sample / this->spec.channels;
412  } else {
413  this->spec.samples = paud_bufinfo.write_buf_cap
414  / bytes_per_sample / this->spec.channels / 2;
415  }
416  paud_init.bsize = bytes_per_sample * this->spec.channels;
417 
419 
420  /*
421  * The AIX paud device init can't modify the values of the audio_init
422  * structure that we pass to it. So we don't need any recalculation
423  * of this stuff and no reinit call as in linux dsp code.
424  *
425  * /dev/paud supports all of the encoding formats, so we don't need
426  * to do anything like reopening the device, either.
427  */
428  if (ioctl(fd, AUDIO_INIT, &paud_init) < 0) {
429  switch (paud_init.rc) {
430  case 1:
431  err = "Couldn't set audio format: DSP can't do play requests";
432  break;
433  case 2:
434  err = "Couldn't set audio format: DSP can't do record requests";
435  break;
436  case 4:
437  err = "Couldn't set audio format: request was invalid";
438  break;
439  case 5:
440  err = "Couldn't set audio format: conflict with open's flags";
441  break;
442  case 6:
443  err = "Couldn't set audio format: out of DSP MIPS or memory";
444  break;
445  default:
446  err = "Couldn't set audio format: not documented in sys/audio.h";
447  break;
448  }
449  }
450 
451  if (err != NULL) {
452  PAUDIO_CloseDevice(this);
453  return SDL_SetError("Paudio: %s", err);
454  }
455 
456  /* Allocate mixing buffer */
457  this->hidden->mixlen = this->spec.size;
458  this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
459  if (this->hidden->mixbuf == NULL) {
460  PAUDIO_CloseDevice(this);
461  return SDL_OutOfMemory();
462  }
463  SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
464 
465  /*
466  * Set some paramters: full volume, first speaker that we can find.
467  * Ignore the other settings for now.
468  */
469  paud_change.input = AUDIO_IGNORE; /* the new input source */
470  paud_change.output = OUTPUT_1; /* EXTERNAL_SPEAKER,INTERNAL_SPEAKER,OUTPUT_1 */
471  paud_change.monitor = AUDIO_IGNORE; /* the new monitor state */
472  paud_change.volume = 0x7fffffff; /* volume level [0-0x7fffffff] */
473  paud_change.volume_delay = AUDIO_IGNORE; /* the new volume delay */
474  paud_change.balance = 0x3fffffff; /* the new balance */
475  paud_change.balance_delay = AUDIO_IGNORE; /* the new balance delay */
476  paud_change.treble = AUDIO_IGNORE; /* the new treble state */
477  paud_change.bass = AUDIO_IGNORE; /* the new bass state */
478  paud_change.pitch = AUDIO_IGNORE; /* the new pitch state */
479 
480  paud_control.ioctl_request = AUDIO_CHANGE;
481  paud_control.request_info = (char *) &paud_change;
482  if (ioctl(fd, AUDIO_CONTROL, &paud_control) < 0) {
483 #ifdef DEBUG_AUDIO
484  fprintf(stderr, "Can't change audio display settings\n");
485 #endif
486  }
487 
488  /*
489  * Tell the device to expect data. Actual start will wait for
490  * the first write() call.
491  */
492  paud_control.ioctl_request = AUDIO_START;
493  paud_control.position = 0;
494  if (ioctl(fd, AUDIO_CONTROL, &paud_control) < 0) {
495  PAUDIO_CloseDevice(this);
496 #ifdef DEBUG_AUDIO
497  fprintf(stderr, "Can't start audio play\n");
498 #endif
499  return SDL_SetError("Can't start audio play");
500  }
501 
502  /* Check to see if we need to use select() workaround */
503  if (workaround != NULL) {
504  this->hidden->frame_ticks = (float) (this->spec.samples * 1000) /
505  this->spec.freq;
506  this->hidden->next_frame = SDL_GetTicks() + this->hidden->frame_ticks;
507  }
508 
509  /* We're ready to rock and roll. :-) */
510  return 0;
511 }
512 
513 static int
514 PAUDIO_Init(SDL_AudioDriverImpl * impl)
515 {
516  /* !!! FIXME: not right for device enum? */
517  int fd = OpenAudioPath(NULL, 0, OPEN_FLAGS, 0);
518  if (fd < 0) {
519  SDL_SetError("PAUDIO: Couldn't open audio device");
520  return 0;
521  }
522  close(fd);
523 
524  /* Set the function pointers */
525  impl->OpenDevice = DSP_OpenDevice;
526  impl->PlayDevice = DSP_PlayDevice;
527  impl->PlayDevice = DSP_WaitDevice;
528  impl->GetDeviceBuf = DSP_GetDeviceBuf;
529  impl->CloseDevice = DSP_CloseDevice;
530  impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: add device enum! */
531 
532  return 1; /* this audio target is available. */
533 }
534 
536  "paud", "AIX Paudio", PAUDIO_Init, 0
537 };
538 
539 #endif /* SDL_AUDIO_DRIVER_PAUDIO */
540 
541 /* vi: set ts=4 sw=4 expandtab: */
#define SDL_strlcpy
SDL_AudioFormat SDL_FirstAudioFormat(SDL_AudioFormat format)
Definition: SDL_audio.c:1398
GLuint GLsizei const GLchar * message
#define AUDIO_U16LSB
Definition: SDL_audio.h:91
static int ticks
Definition: testtimer.c:24
#define SDL_FreeAudioMem
Definition: SDL_audiomem.h:24
void(* PlayDevice)(_THIS)
Definition: SDL_sysaudio.h:75
Uint16 samples
Definition: SDL_audio.h:174
void SDL_OpenedAudioDeviceDisconnected(SDL_AudioDevice *device)
Definition: SDL_audio.c:364
Uint16 SDL_AudioFormat
Audio format flags.
Definition: SDL_audio.h:64
SDL_AudioFormat SDL_NextAudioFormat(void)
Definition: SDL_audio.c:1410
SDL_AudioSpec spec
Definition: loopwave.c:35
#define AUDIO_U8
Definition: SDL_audio.h:89
Uint32 SDL_GetTicks(void)
Get the number of milliseconds since the SDL library initialization.
Uint8 channels
Definition: SDL_audio.h:172
#define _THIS
uint8_t Uint8
An unsigned 8-bit integer type.
Definition: SDL_stdinc.h:139
void SDL_free(void *mem)
AudioBootStrap PAUDIO_bootstrap
void SDL_CalculateAudioSpec(SDL_AudioSpec *spec)
Definition: SDL_audio.c:1419
#define SDL_AllocAudioMem
Definition: SDL_audiomem.h:23
int32_t Sint32
A signed 32-bit integer type.
Definition: SDL_stdinc.h:151
#define FUDGE_TICKS
Definition: SDL_artsaudio.h:49
#define SDL_Delay
#define SDL_getenv
Uint32 size
Definition: SDL_audio.h:176
int(* OpenDevice)(_THIS, void *handle, const char *devname, int iscapture)
Definition: SDL_sysaudio.h:72
#define NULL
Definition: begin_code.h:143
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
#define SDL_SetError
void(* CloseDevice)(_THIS)
Definition: SDL_sysaudio.h:79
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: SDL_opengl.h:1565
#define AUDIO_S16MSB
Definition: SDL_audio.h:94
SDL_AudioFormat format
Definition: SDL_audio.h:171
GLbitfield GLuint64 timeout
#define AUDIO_S16LSB
Definition: SDL_audio.h:92
Uint8 *(* GetDeviceBuf)(_THIS)
Definition: SDL_sysaudio.h:77
#define SDL_snprintf
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:93
GLbitfield flags
#define SDL_malloc
GLsizei const GLchar *const * path
#define AUDIO_S8
Definition: SDL_audio.h:90
#define SDL_memset
#define AUDIO_U16MSB
Definition: SDL_audio.h:93