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