zenilib  0.5.3.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
SDL_dspaudio.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_OSS
24 
25 /* Allow access to a raw mixing buffer */
26 
27 #include <stdio.h> /* For perror() */
28 #include <string.h> /* For strerror() */
29 #include <errno.h>
30 #include <unistd.h>
31 #include <fcntl.h>
32 #include <signal.h>
33 #include <sys/time.h>
34 #include <sys/ioctl.h>
35 #include <sys/stat.h>
36 
37 #if SDL_AUDIO_DRIVER_OSS_SOUNDCARD_H
38 /* This is installed on some systems */
39 #include <soundcard.h>
40 #else
41 /* This is recommended by OSS */
42 #include <sys/soundcard.h>
43 #endif
44 
45 #include "SDL_timer.h"
46 #include "SDL_audio.h"
47 #include "../SDL_audiomem.h"
48 #include "../SDL_audio_c.h"
49 #include "../SDL_audiodev_c.h"
50 #include "SDL_dspaudio.h"
51 
52 
53 static void
54 DSP_DetectDevices(int iscapture, SDL_AddAudioDevice addfn)
55 {
56  SDL_EnumUnixAudioDevices(iscapture, 0, NULL, addfn);
57 }
58 
59 
60 static void
61 DSP_CloseDevice(_THIS)
62 {
63  if (this->hidden != NULL) {
64  SDL_FreeAudioMem(this->hidden->mixbuf);
65  this->hidden->mixbuf = NULL;
66  if (this->hidden->audio_fd >= 0) {
67  close(this->hidden->audio_fd);
68  this->hidden->audio_fd = -1;
69  }
70  SDL_free(this->hidden);
71  this->hidden = NULL;
72  }
73 }
74 
75 
76 static int
77 DSP_OpenDevice(_THIS, const char *devname, int iscapture)
78 {
79  const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
80  int format;
81  int value;
82  int frag_spec;
83  SDL_AudioFormat test_format;
84 
85  /* We don't care what the devname is...we'll try to open anything. */
86  /* ...but default to first name in the list... */
87  if (devname == NULL) {
88  devname = SDL_GetAudioDeviceName(0, iscapture);
89  if (devname == NULL) {
90  return SDL_SetError("No such audio device");
91  }
92  }
93 
94  /* Make sure fragment size stays a power of 2, or OSS fails. */
95  /* I don't know which of these are actually legal values, though... */
96  if (this->spec.channels > 8)
97  this->spec.channels = 8;
98  else if (this->spec.channels > 4)
99  this->spec.channels = 4;
100  else if (this->spec.channels > 2)
101  this->spec.channels = 2;
102 
103  /* Initialize all variables that we clean on shutdown */
104  this->hidden = (struct SDL_PrivateAudioData *)
105  SDL_malloc((sizeof *this->hidden));
106  if (this->hidden == NULL) {
107  return SDL_OutOfMemory();
108  }
109  SDL_memset(this->hidden, 0, (sizeof *this->hidden));
110 
111  /* Open the audio device */
112  this->hidden->audio_fd = open(devname, flags, 0);
113  if (this->hidden->audio_fd < 0) {
114  DSP_CloseDevice(this);
115  return SDL_SetError("Couldn't open %s: %s", devname, strerror(errno));
116  }
117  this->hidden->mixbuf = NULL;
118 
119  /* Make the file descriptor use blocking writes with fcntl() */
120  {
121  long ctlflags;
122  ctlflags = fcntl(this->hidden->audio_fd, F_GETFL);
123  ctlflags &= ~O_NONBLOCK;
124  if (fcntl(this->hidden->audio_fd, F_SETFL, ctlflags) < 0) {
125  DSP_CloseDevice(this);
126  return SDL_SetError("Couldn't set audio blocking mode");
127  }
128  }
129 
130  /* Get a list of supported hardware formats */
131  if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_GETFMTS, &value) < 0) {
132  perror("SNDCTL_DSP_GETFMTS");
133  DSP_CloseDevice(this);
134  return SDL_SetError("Couldn't get audio format list");
135  }
136 
137  /* Try for a closest match on audio format */
138  format = 0;
139  for (test_format = SDL_FirstAudioFormat(this->spec.format);
140  !format && test_format;) {
141 #ifdef DEBUG_AUDIO
142  fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
143 #endif
144  switch (test_format) {
145  case AUDIO_U8:
146  if (value & AFMT_U8) {
147  format = AFMT_U8;
148  }
149  break;
150  case AUDIO_S16LSB:
151  if (value & AFMT_S16_LE) {
152  format = AFMT_S16_LE;
153  }
154  break;
155  case AUDIO_S16MSB:
156  if (value & AFMT_S16_BE) {
157  format = AFMT_S16_BE;
158  }
159  break;
160 #if 0
161 /*
162  * These formats are not used by any real life systems so they are not
163  * needed here.
164  */
165  case AUDIO_S8:
166  if (value & AFMT_S8) {
167  format = AFMT_S8;
168  }
169  break;
170  case AUDIO_U16LSB:
171  if (value & AFMT_U16_LE) {
172  format = AFMT_U16_LE;
173  }
174  break;
175  case AUDIO_U16MSB:
176  if (value & AFMT_U16_BE) {
177  format = AFMT_U16_BE;
178  }
179  break;
180 #endif
181  default:
182  format = 0;
183  break;
184  }
185  if (!format) {
186  test_format = SDL_NextAudioFormat();
187  }
188  }
189  if (format == 0) {
190  DSP_CloseDevice(this);
191  return SDL_SetError("Couldn't find any hardware audio formats");
192  }
193  this->spec.format = test_format;
194 
195  /* Set the audio format */
196  value = format;
197  if ((ioctl(this->hidden->audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) ||
198  (value != format)) {
199  perror("SNDCTL_DSP_SETFMT");
200  DSP_CloseDevice(this);
201  return SDL_SetError("Couldn't set audio format");
202  }
203 
204  /* Set the number of channels of output */
205  value = this->spec.channels;
206  if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_CHANNELS, &value) < 0) {
207  perror("SNDCTL_DSP_CHANNELS");
208  DSP_CloseDevice(this);
209  return SDL_SetError("Cannot set the number of channels");
210  }
211  this->spec.channels = value;
212 
213  /* Set the DSP frequency */
214  value = this->spec.freq;
215  if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_SPEED, &value) < 0) {
216  perror("SNDCTL_DSP_SPEED");
217  DSP_CloseDevice(this);
218  return SDL_SetError("Couldn't set audio frequency");
219  }
220  this->spec.freq = value;
221 
222  /* Calculate the final parameters for this audio specification */
223  SDL_CalculateAudioSpec(&this->spec);
224 
225  /* Determine the power of two of the fragment size */
226  for (frag_spec = 0; (0x01U << frag_spec) < this->spec.size; ++frag_spec);
227  if ((0x01U << frag_spec) != this->spec.size) {
228  DSP_CloseDevice(this);
229  return SDL_SetError("Fragment size must be a power of two");
230  }
231  frag_spec |= 0x00020000; /* two fragments, for low latency */
232 
233  /* Set the audio buffering parameters */
234 #ifdef DEBUG_AUDIO
235  fprintf(stderr, "Requesting %d fragments of size %d\n",
236  (frag_spec >> 16), 1 << (frag_spec & 0xFFFF));
237 #endif
238  if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag_spec) < 0) {
239  perror("SNDCTL_DSP_SETFRAGMENT");
240  }
241 #ifdef DEBUG_AUDIO
242  {
243  audio_buf_info info;
244  ioctl(this->hidden->audio_fd, SNDCTL_DSP_GETOSPACE, &info);
245  fprintf(stderr, "fragments = %d\n", info.fragments);
246  fprintf(stderr, "fragstotal = %d\n", info.fragstotal);
247  fprintf(stderr, "fragsize = %d\n", info.fragsize);
248  fprintf(stderr, "bytes = %d\n", info.bytes);
249  }
250 #endif
251 
252  /* Allocate mixing buffer */
253  this->hidden->mixlen = this->spec.size;
254  this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
255  if (this->hidden->mixbuf == NULL) {
256  DSP_CloseDevice(this);
257  return SDL_OutOfMemory();
258  }
259  SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
260 
261  /* We're ready to rock and roll. :-) */
262  return 0;
263 }
264 
265 
266 static void
267 DSP_PlayDevice(_THIS)
268 {
269  const Uint8 *mixbuf = this->hidden->mixbuf;
270  const int mixlen = this->hidden->mixlen;
271  if (write(this->hidden->audio_fd, mixbuf, mixlen) == -1) {
272  perror("Audio write");
273  this->enabled = 0;
274  }
275 #ifdef DEBUG_AUDIO
276  fprintf(stderr, "Wrote %d bytes of audio data\n", mixlen);
277 #endif
278 }
279 
280 static Uint8 *
281 DSP_GetDeviceBuf(_THIS)
282 {
283  return (this->hidden->mixbuf);
284 }
285 
286 static int
287 DSP_Init(SDL_AudioDriverImpl * impl)
288 {
289  /* Set the function pointers */
290  impl->DetectDevices = DSP_DetectDevices;
291  impl->OpenDevice = DSP_OpenDevice;
292  impl->PlayDevice = DSP_PlayDevice;
293  impl->GetDeviceBuf = DSP_GetDeviceBuf;
294  impl->CloseDevice = DSP_CloseDevice;
295 
296  return 1; /* this audio target is available. */
297 }
298 
299 
301  "dsp", "OSS /dev/dsp standard audio", DSP_Init, 0
302 };
303 
304 #endif /* SDL_AUDIO_DRIVER_OSS */
305 
306 /* 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
void(* SDL_AddAudioDevice)(const char *name)
Definition: SDL_sysaudio.h:34
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
SDL_AudioFormat SDL_NextAudioFormat(void)
Definition: SDL_audio.c:1238
void(* PlayDevice)(_THIS)
Definition: SDL_sysaudio.h:42
#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
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
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
AudioBootStrap DSP_bootstrap
EGLSurface EGLint void ** value
Definition: eglext.h:301
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