SDL  2.0
SDL_paudio.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2018 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 "../../core/unix/SDL_poll.h"
40 #include "SDL_paudio.h"
41 
42 /* #define DEBUG_AUDIO */
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  int timeoutMS;
142  audio_buffer paud_bufinfo;
143 
144  if (ioctl(this->hidden->audio_fd, AUDIO_BUFFER, &paud_bufinfo) < 0) {
145 #ifdef DEBUG_AUDIO
146  fprintf(stderr, "Couldn't get audio buffer information\n");
147 #endif
148  timeoutMS = 10 * 1000;
149  } else {
150  timeoutMS = paud_bufinfo.write_buf_time;
151 #ifdef DEBUG_AUDIO
152  fprintf(stderr, "Waiting for write_buf_time=%d ms\n", timeoutMS);
153 #endif
154  }
155 
156 #ifdef DEBUG_AUDIO
157  fprintf(stderr, "Waiting for audio to get ready\n");
158 #endif
159  if (SDL_IOReady(this->hidden->audio_fd, SDL_TRUE, timeoutMS) <= 0) {
160  /*
161  * In general we should never print to the screen,
162  * but in this case we have no other way of letting
163  * the user know what happened.
164  */
165  fprintf(stderr, "SDL: %s - Audio timeout - buggy audio driver? (disabled)\n", strerror(errno));
167  /* Don't try to close - may hang */
168  this->hidden->audio_fd = -1;
169 #ifdef DEBUG_AUDIO
170  fprintf(stderr, "Done disabling audio\n");
171 #endif
172  }
173 #ifdef DEBUG_AUDIO
174  fprintf(stderr, "Ready!\n");
175 #endif
176  }
177 }
178 
179 static void
180 PAUDIO_PlayDevice(_THIS)
181 {
182  int written = 0;
183  const Uint8 *mixbuf = this->hidden->mixbuf;
184  const size_t mixlen = this->hidden->mixlen;
185 
186  /* Write the audio data, checking for EAGAIN on broken audio drivers */
187  do {
188  written = write(this->hidden->audio_fd, mixbuf, mixlen);
189  if ((written < 0) && ((errno == 0) || (errno == EAGAIN))) {
190  SDL_Delay(1); /* Let a little CPU time go by */
191  }
192  } while ((written < 0) &&
193  ((errno == 0) || (errno == EAGAIN) || (errno == EINTR)));
194 
195  /* If timer synchronization is enabled, set the next write frame */
196  if (this->hidden->frame_ticks) {
197  this->hidden->next_frame += this->hidden->frame_ticks;
198  }
199 
200  /* If we couldn't write, assume fatal error for now */
201  if (written < 0) {
203  }
204 #ifdef DEBUG_AUDIO
205  fprintf(stderr, "Wrote %d bytes of audio data\n", written);
206 #endif
207 }
208 
209 static Uint8 *
210 PAUDIO_GetDeviceBuf(_THIS)
211 {
212  return this->hidden->mixbuf;
213 }
214 
215 static void
216 PAUDIO_CloseDevice(_THIS)
217 {
218  if (this->hidden->audio_fd >= 0) {
219  close(this->hidden->audio_fd);
220  }
221  SDL_free(this->hidden->mixbuf);
222  SDL_free(this->hidden);
223 }
224 
225 static int
226 PAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
227 {
228  const char *workaround = SDL_getenv("SDL_DSP_NOSELECT");
229  char audiodev[1024];
230  const char *err = NULL;
231  int format;
232  int bytes_per_sample;
233  SDL_AudioFormat test_format;
234  audio_init paud_init;
235  audio_buffer paud_bufinfo;
236  audio_control paud_control;
237  audio_change paud_change;
238  int fd = -1;
239 
240  /* Initialize all variables that we clean on shutdown */
241  this->hidden = (struct SDL_PrivateAudioData *)
242  SDL_malloc((sizeof *this->hidden));
243  if (this->hidden == NULL) {
244  return SDL_OutOfMemory();
245  }
246  SDL_zerop(this->hidden);
247 
248  /* Open the audio device */
249  fd = OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0);
250  this->hidden->audio_fd = fd;
251  if (fd < 0) {
252  return SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno));
253  }
254 
255  /*
256  * We can't set the buffer size - just ask the device for the maximum
257  * that we can have.
258  */
259  if (ioctl(fd, AUDIO_BUFFER, &paud_bufinfo) < 0) {
260  return SDL_SetError("Couldn't get audio buffer information");
261  }
262 
263  if (this->spec.channels > 1)
264  this->spec.channels = 2;
265  else
266  this->spec.channels = 1;
267 
268  /*
269  * Fields in the audio_init structure:
270  *
271  * Ignored by us:
272  *
273  * paud.loadpath[LOAD_PATH]; * DSP code to load, MWave chip only?
274  * paud.slot_number; * slot number of the adapter
275  * paud.device_id; * adapter identification number
276  *
277  * Input:
278  *
279  * paud.srate; * the sampling rate in Hz
280  * paud.bits_per_sample; * 8, 16, 32, ...
281  * paud.bsize; * block size for this rate
282  * paud.mode; * ADPCM, PCM, MU_LAW, A_LAW, SOURCE_MIX
283  * paud.channels; * 1=mono, 2=stereo
284  * paud.flags; * FIXED - fixed length data
285  * * LEFT_ALIGNED, RIGHT_ALIGNED (var len only)
286  * * TWOS_COMPLEMENT - 2's complement data
287  * * SIGNED - signed? comment seems wrong in sys/audio.h
288  * * BIG_ENDIAN
289  * paud.operation; * PLAY, RECORD
290  *
291  * Output:
292  *
293  * paud.flags; * PITCH - pitch is supported
294  * * INPUT - input is supported
295  * * OUTPUT - output is supported
296  * * MONITOR - monitor is supported
297  * * VOLUME - volume is supported
298  * * VOLUME_DELAY - volume delay is supported
299  * * BALANCE - balance is supported
300  * * BALANCE_DELAY - balance delay is supported
301  * * TREBLE - treble control is supported
302  * * BASS - bass control is supported
303  * * BESTFIT_PROVIDED - best fit returned
304  * * LOAD_CODE - DSP load needed
305  * paud.rc; * NO_PLAY - DSP code can't do play requests
306  * * NO_RECORD - DSP code can't do record requests
307  * * INVALID_REQUEST - request was invalid
308  * * CONFLICT - conflict with open's flags
309  * * OVERLOADED - out of DSP MIPS or memory
310  * paud.position_resolution; * smallest increment for position
311  */
312 
313  paud_init.srate = this->spec.freq;
314  paud_init.mode = PCM;
315  paud_init.operation = PLAY;
316  paud_init.channels = this->spec.channels;
317 
318  /* Try for a closest match on audio format */
319  format = 0;
320  for (test_format = SDL_FirstAudioFormat(this->spec.format);
321  !format && test_format;) {
322 #ifdef DEBUG_AUDIO
323  fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
324 #endif
325  switch (test_format) {
326  case AUDIO_U8:
327  bytes_per_sample = 1;
328  paud_init.bits_per_sample = 8;
329  paud_init.flags = TWOS_COMPLEMENT | FIXED;
330  format = 1;
331  break;
332  case AUDIO_S8:
333  bytes_per_sample = 1;
334  paud_init.bits_per_sample = 8;
335  paud_init.flags = SIGNED | TWOS_COMPLEMENT | FIXED;
336  format = 1;
337  break;
338  case AUDIO_S16LSB:
339  bytes_per_sample = 2;
340  paud_init.bits_per_sample = 16;
341  paud_init.flags = SIGNED | TWOS_COMPLEMENT | FIXED;
342  format = 1;
343  break;
344  case AUDIO_S16MSB:
345  bytes_per_sample = 2;
346  paud_init.bits_per_sample = 16;
347  paud_init.flags = BIG_ENDIAN | SIGNED | TWOS_COMPLEMENT | FIXED;
348  format = 1;
349  break;
350  case AUDIO_U16LSB:
351  bytes_per_sample = 2;
352  paud_init.bits_per_sample = 16;
353  paud_init.flags = TWOS_COMPLEMENT | FIXED;
354  format = 1;
355  break;
356  case AUDIO_U16MSB:
357  bytes_per_sample = 2;
358  paud_init.bits_per_sample = 16;
359  paud_init.flags = BIG_ENDIAN | TWOS_COMPLEMENT | FIXED;
360  format = 1;
361  break;
362  default:
363  break;
364  }
365  if (!format) {
366  test_format = SDL_NextAudioFormat();
367  }
368  }
369  if (format == 0) {
370 #ifdef DEBUG_AUDIO
371  fprintf(stderr, "Couldn't find any hardware audio formats\n");
372 #endif
373  return SDL_SetError("Couldn't find any hardware audio formats");
374  }
375  this->spec.format = test_format;
376 
377  /*
378  * We know the buffer size and the max number of subsequent writes
379  * that can be pending. If more than one can pend, allow the application
380  * to do something like double buffering between our write buffer and
381  * the device's own buffer that we are filling with write() anyway.
382  *
383  * We calculate this->spec.samples like this because
384  * SDL_CalculateAudioSpec() will give put paud_bufinfo.write_buf_cap
385  * (or paud_bufinfo.write_buf_cap/2) into this->spec.size in return.
386  */
387  if (paud_bufinfo.request_buf_cap == 1) {
388  this->spec.samples = paud_bufinfo.write_buf_cap
389  / bytes_per_sample / this->spec.channels;
390  } else {
391  this->spec.samples = paud_bufinfo.write_buf_cap
392  / bytes_per_sample / this->spec.channels / 2;
393  }
394  paud_init.bsize = bytes_per_sample * this->spec.channels;
395 
397 
398  /*
399  * The AIX paud device init can't modify the values of the audio_init
400  * structure that we pass to it. So we don't need any recalculation
401  * of this stuff and no reinit call as in linux dsp code.
402  *
403  * /dev/paud supports all of the encoding formats, so we don't need
404  * to do anything like reopening the device, either.
405  */
406  if (ioctl(fd, AUDIO_INIT, &paud_init) < 0) {
407  switch (paud_init.rc) {
408  case 1:
409  err = "Couldn't set audio format: DSP can't do play requests";
410  break;
411  case 2:
412  err = "Couldn't set audio format: DSP can't do record requests";
413  break;
414  case 4:
415  err = "Couldn't set audio format: request was invalid";
416  break;
417  case 5:
418  err = "Couldn't set audio format: conflict with open's flags";
419  break;
420  case 6:
421  err = "Couldn't set audio format: out of DSP MIPS or memory";
422  break;
423  default:
424  err = "Couldn't set audio format: not documented in sys/audio.h";
425  break;
426  }
427  }
428 
429  if (err != NULL) {
430  return SDL_SetError("Paudio: %s", err);
431  }
432 
433  /* Allocate mixing buffer */
434  this->hidden->mixlen = this->spec.size;
435  this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen);
436  if (this->hidden->mixbuf == NULL) {
437  return SDL_OutOfMemory();
438  }
439  SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
440 
441  /*
442  * Set some paramters: full volume, first speaker that we can find.
443  * Ignore the other settings for now.
444  */
445  paud_change.input = AUDIO_IGNORE; /* the new input source */
446  paud_change.output = OUTPUT_1; /* EXTERNAL_SPEAKER,INTERNAL_SPEAKER,OUTPUT_1 */
447  paud_change.monitor = AUDIO_IGNORE; /* the new monitor state */
448  paud_change.volume = 0x7fffffff; /* volume level [0-0x7fffffff] */
449  paud_change.volume_delay = AUDIO_IGNORE; /* the new volume delay */
450  paud_change.balance = 0x3fffffff; /* the new balance */
451  paud_change.balance_delay = AUDIO_IGNORE; /* the new balance delay */
452  paud_change.treble = AUDIO_IGNORE; /* the new treble state */
453  paud_change.bass = AUDIO_IGNORE; /* the new bass state */
454  paud_change.pitch = AUDIO_IGNORE; /* the new pitch state */
455 
456  paud_control.ioctl_request = AUDIO_CHANGE;
457  paud_control.request_info = (char *) &paud_change;
458  if (ioctl(fd, AUDIO_CONTROL, &paud_control) < 0) {
459 #ifdef DEBUG_AUDIO
460  fprintf(stderr, "Can't change audio display settings\n");
461 #endif
462  }
463 
464  /*
465  * Tell the device to expect data. Actual start will wait for
466  * the first write() call.
467  */
468  paud_control.ioctl_request = AUDIO_START;
469  paud_control.position = 0;
470  if (ioctl(fd, AUDIO_CONTROL, &paud_control) < 0) {
471 #ifdef DEBUG_AUDIO
472  fprintf(stderr, "Can't start audio play\n");
473 #endif
474  return SDL_SetError("Can't start audio play");
475  }
476 
477  /* Check to see if we need to use SDL_IOReady() workaround */
478  if (workaround != NULL) {
479  this->hidden->frame_ticks = (float) (this->spec.samples * 1000) /
480  this->spec.freq;
481  this->hidden->next_frame = SDL_GetTicks() + this->hidden->frame_ticks;
482  }
483 
484  /* We're ready to rock and roll. :-) */
485  return 0;
486 }
487 
488 static int
489 PAUDIO_Init(SDL_AudioDriverImpl * impl)
490 {
491  /* !!! FIXME: not right for device enum? */
492  int fd = OpenAudioPath(NULL, 0, OPEN_FLAGS, 0);
493  if (fd < 0) {
494  SDL_SetError("PAUDIO: Couldn't open audio device");
495  return 0;
496  }
497  close(fd);
498 
499  /* Set the function pointers */
500  impl->OpenDevice = PAUDIO_OpenDevice;
501  impl->PlayDevice = PAUDIO_PlayDevice;
502  impl->PlayDevice = PAUDIO_WaitDevice;
503  impl->GetDeviceBuf = PAUDIO_GetDeviceBuf;
504  impl->CloseDevice = PAUDIO_CloseDevice;
505  impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: add device enum! */
506 
507  return 1; /* this audio target is available. */
508 }
509 
511  "paud", "AIX Paudio", PAUDIO_Init, 0
512 };
513 
514 #endif /* SDL_AUDIO_DRIVER_PAUDIO */
515 
516 /* vi: set ts=4 sw=4 expandtab: */
#define SDL_strlcpy
SDL_AudioFormat SDL_FirstAudioFormat(SDL_AudioFormat format)
Definition: SDL_audio.c:1584
int SDL_IOReady(int fd, SDL_bool forWrite, int timeoutMS)
Definition: SDL_poll.c:38
#define AUDIO_U16LSB
Definition: SDL_audio.h:91
static int ticks
Definition: testtimer.c:24
void(* PlayDevice)(_THIS)
Definition: SDL_sysaudio.h:73
Uint16 samples
Definition: SDL_audio.h:183
void SDL_OpenedAudioDeviceDisconnected(SDL_AudioDevice *device)
Definition: SDL_audio.c:449
Uint16 SDL_AudioFormat
Audio format flags.
Definition: SDL_audio.h:64
#define SDL_zerop(x)
Definition: SDL_stdinc.h:417
SDL_AudioFormat SDL_NextAudioFormat(void)
Definition: SDL_audio.c:1596
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: SDL_opengl.h:1572
SDL_AudioSpec spec
Definition: loopwave.c:31
#define AUDIO_U8
Definition: SDL_audio.h:89
EGLImageKHR EGLint EGLint * handle
Definition: eglext.h:937
Uint32 SDL_GetTicks(void)
Get the number of milliseconds since the SDL library initialization.
Uint8 channels
Definition: SDL_audio.h:181
#define _THIS
uint8_t Uint8
Definition: SDL_stdinc.h:157
#define SDL_free
void SDL_CalculateAudioSpec(SDL_AudioSpec *spec)
Definition: SDL_audio.c:1605
int32_t Sint32
Definition: SDL_stdinc.h:175
#define FUDGE_TICKS
Definition: SDL_artsaudio.h:49
#define SDL_Delay
#define SDL_getenv
Uint32 size
Definition: SDL_audio.h:185
int(* OpenDevice)(_THIS, void *handle, const char *devname, int iscapture)
Definition: SDL_sysaudio.h:68
#define NULL
Definition: begin_code.h:164
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
#define SDL_SetError
GLbitfield flags
void(* CloseDevice)(_THIS)
Definition: SDL_sysaudio.h:79
#define AUDIO_S16MSB
Definition: SDL_audio.h:94
SDL_AudioFormat format
Definition: SDL_audio.h:180
AudioBootStrap PAUDIO_bootstrap
#define AUDIO_S16LSB
Definition: SDL_audio.h:92
Uint8 *(* GetDeviceBuf)(_THIS)
Definition: SDL_sysaudio.h:75
#define SDL_snprintf
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:93
#define SDL_malloc
GLsizei const GLchar *const * path
#define AUDIO_S8
Definition: SDL_audio.h:90
GLuint64 GLenum GLint fd
Definition: gl2ext.h:1508
#define SDL_memset
#define AUDIO_U16MSB
Definition: SDL_audio.h:93