zenilib  0.5.3.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
SDL_bsdaudio.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2013 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_config.h"
22 
23 #if SDL_AUDIO_DRIVER_BSD
24 
25 /*
26  * Driver for native OpenBSD/NetBSD audio(4).
27  * vedge@vedge.com.ar.
28  */
29 
30 #include <errno.h>
31 #include <unistd.h>
32 #include <fcntl.h>
33 #include <sys/time.h>
34 #include <sys/ioctl.h>
35 #include <sys/stat.h>
36 #include <sys/types.h>
37 #include <sys/audioio.h>
38 
39 #include "SDL_timer.h"
40 #include "SDL_audio.h"
41 #include "../SDL_audiomem.h"
42 #include "../SDL_audio_c.h"
43 #include "../SDL_audiodev_c.h"
44 #include "SDL_bsdaudio.h"
45 
46 /* Use timer for synchronization */
47 /* #define USE_TIMER_SYNC */
48 
49 /* #define DEBUG_AUDIO */
50 /* #define DEBUG_AUDIO_STREAM */
51 
52 
53 static void
54 BSDAUDIO_DetectDevices(int iscapture, SDL_AddAudioDevice addfn)
55 {
56  SDL_EnumUnixAudioDevices(iscapture, 0, NULL, addfn);
57 }
58 
59 
60 static void
61 BSDAUDIO_Status(_THIS)
62 {
63 #ifdef DEBUG_AUDIO
64  /* *INDENT-OFF* */
65  audio_info_t info;
66 
67  if (ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info) < 0) {
68  fprintf(stderr, "AUDIO_GETINFO failed.\n");
69  return;
70  }
71  fprintf(stderr, "\n"
72  "[play/record info]\n"
73  "buffer size : %d bytes\n"
74  "sample rate : %i Hz\n"
75  "channels : %i\n"
76  "precision : %i-bit\n"
77  "encoding : 0x%x\n"
78  "seek : %i\n"
79  "sample count : %i\n"
80  "EOF count : %i\n"
81  "paused : %s\n"
82  "error occured : %s\n"
83  "waiting : %s\n"
84  "active : %s\n"
85  "",
86  info.play.buffer_size,
87  info.play.sample_rate,
88  info.play.channels,
89  info.play.precision,
90  info.play.encoding,
91  info.play.seek,
92  info.play.samples,
93  info.play.eof,
94  info.play.pause ? "yes" : "no",
95  info.play.error ? "yes" : "no",
96  info.play.waiting ? "yes" : "no",
97  info.play.active ? "yes" : "no");
98 
99  fprintf(stderr, "\n"
100  "[audio info]\n"
101  "monitor_gain : %i\n"
102  "hw block size : %d bytes\n"
103  "hi watermark : %i\n"
104  "lo watermark : %i\n"
105  "audio mode : %s\n"
106  "",
107  info.monitor_gain,
108  info.blocksize,
109  info.hiwat, info.lowat,
110  (info.mode == AUMODE_PLAY) ? "PLAY"
111  : (info.mode = AUMODE_RECORD) ? "RECORD"
112  : (info.mode == AUMODE_PLAY_ALL ? "PLAY_ALL" : "?"));
113  /* *INDENT-ON* */
114 #endif /* DEBUG_AUDIO */
115 }
116 
117 
118 /* This function waits until it is possible to write a full sound buffer */
119 static void
120 BSDAUDIO_WaitDevice(_THIS)
121 {
122 #ifndef USE_BLOCKING_WRITES /* Not necessary when using blocking writes */
123  /* See if we need to use timed audio synchronization */
124  if (this->hidden->frame_ticks) {
125  /* Use timer for general audio synchronization */
126  Sint32 ticks;
127 
128  ticks =
129  ((Sint32) (this->hidden->next_frame - SDL_GetTicks())) -
130  FUDGE_TICKS;
131  if (ticks > 0) {
132  SDL_Delay(ticks);
133  }
134  } else {
135  /* Use select() for audio synchronization */
136  fd_set fdset;
137  struct timeval timeout;
138 
139  FD_ZERO(&fdset);
140  FD_SET(this->hidden->audio_fd, &fdset);
141  timeout.tv_sec = 10;
142  timeout.tv_usec = 0;
143 #ifdef DEBUG_AUDIO
144  fprintf(stderr, "Waiting for audio to get ready\n");
145 #endif
146  if (select(this->hidden->audio_fd + 1, NULL, &fdset, NULL, &timeout)
147  <= 0) {
148  const char *message =
149  "Audio timeout - buggy audio driver? (disabled)";
150  /* In general we should never print to the screen,
151  but in this case we have no other way of letting
152  the user know what happened.
153  */
154  fprintf(stderr, "SDL: %s\n", message);
155  this->enabled = 0;
156  /* Don't try to close - may hang */
157  this->hidden->audio_fd = -1;
158 #ifdef DEBUG_AUDIO
159  fprintf(stderr, "Done disabling audio\n");
160 #endif
161  }
162 #ifdef DEBUG_AUDIO
163  fprintf(stderr, "Ready!\n");
164 #endif
165  }
166 #endif /* !USE_BLOCKING_WRITES */
167 }
168 
169 static void
170 BSDAUDIO_PlayDevice(_THIS)
171 {
172  int written, p = 0;
173 
174  /* Write the audio data, checking for EAGAIN on broken audio drivers */
175  do {
176  written = write(this->hidden->audio_fd,
177  &this->hidden->mixbuf[p], this->hidden->mixlen - p);
178 
179  if (written > 0)
180  p += written;
181  if (written == -1 && errno != 0 && errno != EAGAIN && errno != EINTR) {
182  /* Non recoverable error has occurred. It should be reported!!! */
183  perror("audio");
184  break;
185  }
186 
187  if (p < written
188  || ((written < 0) && ((errno == 0) || (errno == EAGAIN)))) {
189  SDL_Delay(1); /* Let a little CPU time go by */
190  }
191  } while (p < written);
192 
193  /* If timer synchronization is enabled, set the next write frame */
194  if (this->hidden->frame_ticks) {
195  this->hidden->next_frame += this->hidden->frame_ticks;
196  }
197 
198  /* If we couldn't write, assume fatal error for now */
199  if (written < 0) {
200  this->enabled = 0;
201  }
202 #ifdef DEBUG_AUDIO
203  fprintf(stderr, "Wrote %d bytes of audio data\n", written);
204 #endif
205 }
206 
207 static Uint8 *
208 BSDAUDIO_GetDeviceBuf(_THIS)
209 {
210  return (this->hidden->mixbuf);
211 }
212 
213 static void
214 BSDAUDIO_CloseDevice(_THIS)
215 {
216  if (this->hidden != NULL) {
217  SDL_FreeAudioMem(this->hidden->mixbuf);
218  this->hidden->mixbuf = NULL;
219  if (this->hidden->audio_fd >= 0) {
220  close(this->hidden->audio_fd);
221  this->hidden->audio_fd = -1;
222  }
223  SDL_free(this->hidden);
224  this->hidden = NULL;
225  }
226 }
227 
228 static int
229 BSDAUDIO_OpenDevice(_THIS, const char *devname, int iscapture)
230 {
231  const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
233  audio_info_t info;
234 
235  /* We don't care what the devname is...we'll try to open anything. */
236  /* ...but default to first name in the list... */
237  if (devname == NULL) {
238  devname = SDL_GetAudioDeviceName(0, iscapture);
239  if (devname == NULL) {
240  return SDL_SetError("No such audio device");
241  }
242  }
243 
244  /* Initialize all variables that we clean on shutdown */
245  this->hidden = (struct SDL_PrivateAudioData *)
246  SDL_malloc((sizeof *this->hidden));
247  if (this->hidden == NULL) {
248  return SDL_OutOfMemory();
249  }
250  SDL_memset(this->hidden, 0, (sizeof *this->hidden));
251 
252  /* Open the audio device */
253  this->hidden->audio_fd = open(devname, flags, 0);
254  if (this->hidden->audio_fd < 0) {
255  return SDL_SetError("Couldn't open %s: %s", devname, strerror(errno));
256  }
257 
258  AUDIO_INITINFO(&info);
259 
260  /* Calculate the final parameters for this audio specification */
261  SDL_CalculateAudioSpec(&this->spec);
262 
263  /* Set to play mode */
264  info.mode = AUMODE_PLAY;
265  if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) < 0) {
266  BSDAUDIO_CloseDevice(this);
267  return SDL_SetError("Couldn't put device into play mode");
268  }
269 
270  AUDIO_INITINFO(&info);
271  for (format = SDL_FirstAudioFormat(this->spec.format);
272  format; format = SDL_NextAudioFormat()) {
273  switch (format) {
274  case AUDIO_U8:
275  info.play.encoding = AUDIO_ENCODING_ULINEAR;
276  info.play.precision = 8;
277  break;
278  case AUDIO_S8:
279  info.play.encoding = AUDIO_ENCODING_SLINEAR;
280  info.play.precision = 8;
281  break;
282  case AUDIO_S16LSB:
283  info.play.encoding = AUDIO_ENCODING_SLINEAR_LE;
284  info.play.precision = 16;
285  break;
286  case AUDIO_S16MSB:
287  info.play.encoding = AUDIO_ENCODING_SLINEAR_BE;
288  info.play.precision = 16;
289  break;
290  case AUDIO_U16LSB:
291  info.play.encoding = AUDIO_ENCODING_ULINEAR_LE;
292  info.play.precision = 16;
293  break;
294  case AUDIO_U16MSB:
295  info.play.encoding = AUDIO_ENCODING_ULINEAR_BE;
296  info.play.precision = 16;
297  break;
298  default:
299  continue;
300  }
301 
302  if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) == 0) {
303  break;
304  }
305  }
306 
307  if (!format) {
308  BSDAUDIO_CloseDevice(this);
309  return SDL_SetError("No supported encoding for 0x%x", this->spec.format);
310  }
311 
312  this->spec.format = format;
313 
314  AUDIO_INITINFO(&info);
315  info.play.channels = this->spec.channels;
316  if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) == -1) {
317  this->spec.channels = 1;
318  }
319  AUDIO_INITINFO(&info);
320  info.play.sample_rate = this->spec.freq;
321  info.blocksize = this->spec.size;
322  info.hiwat = 5;
323  info.lowat = 3;
324  (void) ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info);
325  (void) ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info);
326  this->spec.freq = info.play.sample_rate;
327  /* Allocate mixing buffer */
328  this->hidden->mixlen = this->spec.size;
329  this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
330  if (this->hidden->mixbuf == NULL) {
331  BSDAUDIO_CloseDevice(this);
332  return SDL_OutOfMemory();
333  }
334  SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
335 
336  BSDAUDIO_Status(this);
337 
338  /* We're ready to rock and roll. :-) */
339  return 0;
340 }
341 
342 static int
343 BSDAUDIO_Init(SDL_AudioDriverImpl * impl)
344 {
345  /* Set the function pointers */
346  impl->DetectDevices = BSDAUDIO_DetectDevices;
347  impl->OpenDevice = BSDAUDIO_OpenDevice;
348  impl->PlayDevice = BSDAUDIO_PlayDevice;
349  impl->WaitDevice = BSDAUDIO_WaitDevice;
350  impl->GetDeviceBuf = BSDAUDIO_GetDeviceBuf;
351  impl->CloseDevice = BSDAUDIO_CloseDevice;
352 
353  return 1; /* this audio target is available. */
354 }
355 
356 
358  "bsd", "BSD audio", BSDAUDIO_Init, 0
359 };
360 
361 #endif /* SDL_AUDIO_DRIVER_BSD */
362 
363 /* vi: set ts=4 sw=4 expandtab: */
void(* CloseDevice)(_THIS)
Definition: SDL_sysaudio.h:45
#define OPEN_FLAGS_INPUT
SDL_AudioFormat SDL_FirstAudioFormat(SDL_AudioFormat format)
Definition: SDL_audio.c:1226
int32_t Sint32
A signed 32-bit integer type.
Definition: SDL_stdinc.h:141
GLvoid **typedef void(GLAPIENTRY *PFNGLGETVERTEXATTRIBDVPROC)(GLuint
Definition: glew.h:1824
GLsizei GLenum GLuint GLuint GLsizei GLchar * message
Definition: glew.h:2540
void(* SDL_AddAudioDevice)(const char *name)
Definition: SDL_sysaudio.h:34
void(* WaitDevice)(_THIS)
Definition: SDL_sysaudio.h:41
void SDL_EnumUnixAudioDevices(int iscapture, int classic, int(*test)(int fd), SDL_AddAudioDevice addfn)
#define NULL
Definition: ftobjs.h:61
#define AUDIO_U16LSB
Definition: SDL_audio.h:91
GLenum GLsizei const GLuint GLboolean enabled
Definition: glew.h:2538
Uint8 *(* GetDeviceBuf)(_THIS)
Definition: SDL_sysaudio.h:43
#define SDL_FreeAudioMem
Definition: SDL_audiomem.h:24
DECLSPEC void SDLCALL SDL_free(void *mem)
Uint16 SDL_AudioFormat
Audio format flags.
Definition: SDL_audio.h:64
int(* OpenDevice)(_THIS, const char *devname, int iscapture)
Definition: SDL_sysaudio.h:39
AudioBootStrap BSD_AUDIO_bootstrap
SDL_AudioFormat SDL_NextAudioFormat(void)
Definition: SDL_audio.c:1238
void(* PlayDevice)(_THIS)
Definition: SDL_sysaudio.h:42
DECLSPEC Uint32 SDLCALL SDL_GetTicks(void)
Get the number of milliseconds since the SDL library initialization.
Definition: SDL_systimer.c:44
#define AUDIO_U8
Definition: SDL_audio.h:89
void(* DetectDevices)(int iscapture, SDL_AddAudioDevice addfn)
Definition: SDL_sysaudio.h:38
DECLSPEC const char *SDLCALL SDL_GetAudioDeviceName(int index, int iscapture)
Definition: SDL_audio.c:708
#define OPEN_FLAGS_OUTPUT
#define _THIS
GLfloat GLfloat p
Definition: glew.h:14938
DECLSPEC void SDLCALL SDL_Delay(Uint32 ms)
Wait a specified number of milliseconds before returning.
Definition: SDL_systimer.c:70
DECLSPEC void *SDLCALL SDL_memset(void *dst, int c, size_t len)
Definition: SDL_string.c:261
GLint GLenum GLsizei GLsizei GLsizei GLint GLenum format
Definition: gl2ext.h:845
DECLSPEC int SDLCALL SDL_SetError(const char *fmt,...)
Definition: SDL_error.c:53
DECLSPEC void *SDLCALL SDL_malloc(size_t size)
void SDL_CalculateAudioSpec(SDL_AudioSpec *spec)
Definition: SDL_audio.c:1247
#define SDL_AllocAudioMem
Definition: SDL_audiomem.h:23
GLbitfield GLuint64 timeout
Definition: glew.h:5938
#define FUDGE_TICKS
Definition: SDL_artsaudio.h:49
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
GLenum GLsizei GLsizei GLsizei GLsizei GLbitfield flags
Definition: glew.h:2767
#define AUDIO_S16MSB
Definition: SDL_audio.h:94
uint8_t Uint8
An unsigned 8-bit integer type.
Definition: SDL_stdinc.h:129
#define AUDIO_S16LSB
Definition: SDL_audio.h:92
#define AUDIO_S8
Definition: SDL_audio.h:90
#define AUDIO_U16MSB
Definition: SDL_audio.h:93