Skip to content
This repository has been archived by the owner on Feb 11, 2021. It is now read-only.

Latest commit

 

History

History
393 lines (341 loc) · 10.9 KB

SDL_dspaudio.c

File metadata and controls

393 lines (341 loc) · 10.9 KB
 
Apr 26, 2001
Apr 26, 2001
1
2
/*
SDL - Simple DirectMedia Layer
Jan 24, 2010
Jan 24, 2010
3
Copyright (C) 1997-2010 Sam Lantinga
Apr 26, 2001
Apr 26, 2001
4
5
This library is free software; you can redistribute it and/or
Feb 1, 2006
Feb 1, 2006
6
modify it under the terms of the GNU Lesser General Public
Apr 26, 2001
Apr 26, 2001
7
License as published by the Free Software Foundation; either
Feb 1, 2006
Feb 1, 2006
8
version 2.1 of the License, or (at your option) any later version.
Apr 26, 2001
Apr 26, 2001
9
10
11
12
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Feb 1, 2006
Feb 1, 2006
13
Lesser General Public License for more details.
Apr 26, 2001
Apr 26, 2001
14
Feb 1, 2006
Feb 1, 2006
15
16
17
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Apr 26, 2001
Apr 26, 2001
18
19
Sam Lantinga
Dec 14, 2001
Dec 14, 2001
20
slouken@libsdl.org
Nov 12, 2004
Nov 12, 2004
21
22
23
Modified in Oct 2004 by Hannu Savolainen
hannu@opensound.com
Apr 26, 2001
Apr 26, 2001
24
*/
Feb 21, 2006
Feb 21, 2006
25
#include "SDL_config.h"
Apr 26, 2001
Apr 26, 2001
26
27
28
/* Allow access to a raw mixing buffer */
Jul 10, 2006
Jul 10, 2006
29
30
#include <stdio.h> /* For perror() */
#include <string.h> /* For strerror() */
Apr 26, 2001
Apr 26, 2001
31
32
33
34
35
36
37
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
Feb 16, 2006
Feb 16, 2006
38
39
#if SDL_AUDIO_DRIVER_OSS_SOUNDCARD_H
Jul 8, 2001
Jul 8, 2001
40
41
42
43
/* This is installed on some systems */
#include <soundcard.h>
#else
/* This is recommended by OSS */
Apr 26, 2001
Apr 26, 2001
44
#include <sys/soundcard.h>
Jul 8, 2001
Jul 8, 2001
45
#endif
Apr 26, 2001
Apr 26, 2001
46
Feb 10, 2006
Feb 10, 2006
47
#include "SDL_timer.h"
Apr 26, 2001
Apr 26, 2001
48
#include "SDL_audio.h"
Feb 16, 2006
Feb 16, 2006
49
50
51
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
Apr 26, 2001
Apr 26, 2001
52
53
54
55
56
57
#include "SDL_dspaudio.h"
/* The tag name used by DSP audio */
#define DSP_DRIVER_NAME "dsp"
/* Open the audio device for playback, and don't block if busy */
Oct 17, 2006
Oct 17, 2006
58
59
#define OPEN_FLAGS_OUTPUT (O_WRONLY|O_NONBLOCK)
#define OPEN_FLAGS_INPUT (O_RDONLY|O_NONBLOCK)
Apr 26, 2001
Apr 26, 2001
60
Oct 17, 2006
Oct 17, 2006
61
62
63
64
static char **outputDevices = NULL;
static int outputDeviceCount = 0;
static char **inputDevices = NULL;
static int inputDeviceCount = 0;
Apr 26, 2001
Apr 26, 2001
65
Oct 17, 2006
Oct 17, 2006
66
67
static inline void
free_device_list(char ***devs, int *count)
Apr 26, 2001
Apr 26, 2001
68
{
Oct 17, 2006
Oct 17, 2006
69
SDL_FreeUnixAudioDevices(devs, count);
Apr 26, 2001
Apr 26, 2001
70
71
}
Oct 17, 2006
Oct 17, 2006
72
73
static inline void
build_device_list(int iscapture, char ***devs, int *count)
Apr 26, 2001
Apr 26, 2001
74
{
Oct 17, 2006
Oct 17, 2006
75
76
77
const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
free_device_list(devs, count);
SDL_EnumUnixAudioDevices(flags, 0, NULL, devs, count);
Apr 26, 2001
Apr 26, 2001
78
79
}
Oct 17, 2006
Oct 17, 2006
80
81
static inline void
build_device_lists(void)
Apr 26, 2001
Apr 26, 2001
82
{
Oct 17, 2006
Oct 17, 2006
83
84
85
build_device_list(0, &outputDevices, &outputDeviceCount);
build_device_list(1, &inputDevices, &inputDeviceCount);
}
Jul 10, 2006
Jul 10, 2006
86
87
Oct 17, 2006
Oct 17, 2006
88
89
90
91
92
static inline void
free_device_lists(void)
{
free_device_list(&outputDevices, &outputDeviceCount);
free_device_list(&inputDevices, &inputDeviceCount);
Apr 26, 2001
Apr 26, 2001
93
94
95
}
Jul 10, 2006
Jul 10, 2006
96
static void
Oct 17, 2006
Oct 17, 2006
97
DSP_Deinitialize(void)
Apr 26, 2001
Apr 26, 2001
98
{
Oct 17, 2006
Oct 17, 2006
99
free_device_lists();
Apr 26, 2001
Apr 26, 2001
100
101
}
Oct 17, 2006
Oct 17, 2006
102
103
104
static int
DSP_DetectDevices(int iscapture)
Apr 26, 2001
Apr 26, 2001
105
{
Oct 17, 2006
Oct 17, 2006
106
107
108
109
110
111
if (iscapture) {
build_device_list(1, &inputDevices, &inputDeviceCount);
return inputDeviceCount;
} else {
build_device_list(0, &outputDevices, &outputDeviceCount);
return outputDeviceCount;
Jul 10, 2006
Jul 10, 2006
112
}
Oct 17, 2006
Oct 17, 2006
113
Oct 28, 2006
Oct 28, 2006
114
return 0; /* shouldn't ever hit this. */
Apr 26, 2001
Apr 26, 2001
115
116
}
Oct 17, 2006
Oct 17, 2006
117
118
static const char *
DSP_GetDeviceName(int index, int iscapture)
Apr 26, 2001
Apr 26, 2001
119
{
Oct 17, 2006
Oct 17, 2006
120
121
122
123
124
125
126
127
if ((iscapture) && (index < inputDeviceCount)) {
return inputDevices[index];
} else if ((!iscapture) && (index < outputDeviceCount)) {
return outputDevices[index];
}
SDL_SetError("No such device");
return NULL;
Apr 26, 2001
Apr 26, 2001
128
129
}
Oct 17, 2006
Oct 17, 2006
130
Jul 10, 2006
Jul 10, 2006
131
static void
Oct 17, 2006
Oct 17, 2006
132
DSP_CloseDevice(_THIS)
Apr 26, 2001
Apr 26, 2001
133
{
Oct 17, 2006
Oct 17, 2006
134
135
136
137
138
139
140
141
142
143
144
if (this->hidden != NULL) {
if (this->hidden->mixbuf != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
}
if (this->hidden->audio_fd >= 0) {
close(this->hidden->audio_fd);
this->hidden->audio_fd = -1;
}
SDL_free(this->hidden);
this->hidden = NULL;
Jul 10, 2006
Jul 10, 2006
145
}
Apr 26, 2001
Apr 26, 2001
146
147
}
Oct 17, 2006
Oct 17, 2006
148
Jul 10, 2006
Jul 10, 2006
149
static int
Oct 17, 2006
Oct 17, 2006
150
DSP_OpenDevice(_THIS, const char *devname, int iscapture)
Apr 26, 2001
Apr 26, 2001
151
{
Oct 17, 2006
Oct 17, 2006
152
const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
Jul 10, 2006
Jul 10, 2006
153
154
155
int format;
int value;
int frag_spec;
Aug 24, 2006
Aug 24, 2006
156
SDL_AudioFormat test_format;
Jul 10, 2006
Jul 10, 2006
157
Oct 17, 2006
Oct 17, 2006
158
159
160
/* We don't care what the devname is...we'll try to open anything. */
/* ...but default to first name in the list... */
if (devname == NULL) {
Oct 28, 2006
Oct 28, 2006
161
162
if (((iscapture) && (inputDeviceCount == 0)) ||
((!iscapture) && (outputDeviceCount == 0))) {
Oct 17, 2006
Oct 17, 2006
163
164
165
166
167
168
SDL_SetError("No such audio device");
return 0;
}
devname = ((iscapture) ? inputDevices[0] : outputDevices[0]);
}
Nov 13, 2006
Nov 13, 2006
169
170
171
172
173
174
175
176
177
/* Make sure fragment size stays a power of 2, or OSS fails. */
/* I don't know which of these are actually legal values, though... */
if (this->spec.channels > 8)
this->spec.channels = 8;
else if (this->spec.channels > 4)
this->spec.channels = 4;
else if (this->spec.channels > 2)
this->spec.channels = 2;
Oct 17, 2006
Oct 17, 2006
178
179
/* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *)
Oct 28, 2006
Oct 28, 2006
180
SDL_malloc((sizeof *this->hidden));
Oct 17, 2006
Oct 17, 2006
181
182
183
184
185
186
if (this->hidden == NULL) {
SDL_OutOfMemory();
return 0;
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
Jul 10, 2006
Jul 10, 2006
187
/* Open the audio device */
Oct 17, 2006
Oct 17, 2006
188
189
190
191
192
this->hidden->audio_fd = open(devname, flags, 0);
if (this->hidden->audio_fd < 0) {
DSP_CloseDevice(this);
SDL_SetError("Couldn't open %s: %s", devname, strerror(errno));
return 0;
Jul 10, 2006
Jul 10, 2006
193
}
Oct 17, 2006
Oct 17, 2006
194
this->hidden->mixbuf = NULL;
Jul 10, 2006
Jul 10, 2006
195
196
197
/* Make the file descriptor use blocking writes with fcntl() */
{
Oct 17, 2006
Oct 17, 2006
198
199
200
201
202
long ctlflags;
ctlflags = fcntl(this->hidden->audio_fd, F_GETFL);
ctlflags &= ~O_NONBLOCK;
if (fcntl(this->hidden->audio_fd, F_SETFL, ctlflags) < 0) {
DSP_CloseDevice(this);
Jul 10, 2006
Jul 10, 2006
203
SDL_SetError("Couldn't set audio blocking mode");
Oct 17, 2006
Oct 17, 2006
204
return 0;
Jul 10, 2006
Jul 10, 2006
205
206
207
208
}
}
/* Get a list of supported hardware formats */
Oct 17, 2006
Oct 17, 2006
209
if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_GETFMTS, &value) < 0) {
Jul 10, 2006
Jul 10, 2006
210
perror("SNDCTL_DSP_GETFMTS");
Oct 17, 2006
Oct 17, 2006
211
DSP_CloseDevice(this);
Jul 10, 2006
Jul 10, 2006
212
SDL_SetError("Couldn't get audio format list");
Oct 17, 2006
Oct 17, 2006
213
return 0;
Jul 10, 2006
Jul 10, 2006
214
215
216
217
}
/* Try for a closest match on audio format */
format = 0;
Oct 17, 2006
Oct 17, 2006
218
for (test_format = SDL_FirstAudioFormat(this->spec.format);
Jul 10, 2006
Jul 10, 2006
219
!format && test_format;) {
Apr 26, 2001
Apr 26, 2001
220
#ifdef DEBUG_AUDIO
Jul 10, 2006
Jul 10, 2006
221
fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
Apr 26, 2001
Apr 26, 2001
222
#endif
Jul 10, 2006
Jul 10, 2006
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
switch (test_format) {
case AUDIO_U8:
if (value & AFMT_U8) {
format = AFMT_U8;
}
break;
case AUDIO_S16LSB:
if (value & AFMT_S16_LE) {
format = AFMT_S16_LE;
}
break;
case AUDIO_S16MSB:
if (value & AFMT_S16_BE) {
format = AFMT_S16_BE;
}
break;
Nov 12, 2004
Nov 12, 2004
239
240
241
242
243
#if 0
/*
* These formats are not used by any real life systems so they are not
* needed here.
*/
Jul 10, 2006
Jul 10, 2006
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
case AUDIO_S8:
if (value & AFMT_S8) {
format = AFMT_S8;
}
break;
case AUDIO_U16LSB:
if (value & AFMT_U16_LE) {
format = AFMT_U16_LE;
}
break;
case AUDIO_U16MSB:
if (value & AFMT_U16_BE) {
format = AFMT_U16_BE;
}
break;
Nov 12, 2004
Nov 12, 2004
259
#endif
Jul 10, 2006
Jul 10, 2006
260
261
262
263
264
265
266
267
268
default:
format = 0;
break;
}
if (!format) {
test_format = SDL_NextAudioFormat();
}
}
if (format == 0) {
Oct 17, 2006
Oct 17, 2006
269
DSP_CloseDevice(this);
Jul 10, 2006
Jul 10, 2006
270
SDL_SetError("Couldn't find any hardware audio formats");
Oct 17, 2006
Oct 17, 2006
271
return 0;
Jul 10, 2006
Jul 10, 2006
272
}
Oct 17, 2006
Oct 17, 2006
273
this->spec.format = test_format;
Jul 10, 2006
Jul 10, 2006
274
275
276
/* Set the audio format */
value = format;
Oct 28, 2006
Oct 28, 2006
277
278
if ((ioctl(this->hidden->audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) ||
(value != format)) {
Jul 10, 2006
Jul 10, 2006
279
perror("SNDCTL_DSP_SETFMT");
Oct 17, 2006
Oct 17, 2006
280
DSP_CloseDevice(this);
Jul 10, 2006
Jul 10, 2006
281
SDL_SetError("Couldn't set audio format");
Oct 17, 2006
Oct 17, 2006
282
return 0;
Jul 10, 2006
Jul 10, 2006
283
284
285
}
/* Set the number of channels of output */
Oct 17, 2006
Oct 17, 2006
286
287
value = this->spec.channels;
if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_CHANNELS, &value) < 0) {
Jul 10, 2006
Jul 10, 2006
288
perror("SNDCTL_DSP_CHANNELS");
Oct 17, 2006
Oct 17, 2006
289
DSP_CloseDevice(this);
Jul 10, 2006
Jul 10, 2006
290
SDL_SetError("Cannot set the number of channels");
Oct 17, 2006
Oct 17, 2006
291
return 0;
Jul 10, 2006
Jul 10, 2006
292
}
Oct 17, 2006
Oct 17, 2006
293
this->spec.channels = value;
Jul 10, 2006
Jul 10, 2006
294
295
/* Set the DSP frequency */
Oct 17, 2006
Oct 17, 2006
296
297
value = this->spec.freq;
if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_SPEED, &value) < 0) {
Jul 10, 2006
Jul 10, 2006
298
perror("SNDCTL_DSP_SPEED");
Oct 17, 2006
Oct 17, 2006
299
DSP_CloseDevice(this);
Jul 10, 2006
Jul 10, 2006
300
SDL_SetError("Couldn't set audio frequency");
Oct 17, 2006
Oct 17, 2006
301
return 0;
Jul 10, 2006
Jul 10, 2006
302
}
Oct 17, 2006
Oct 17, 2006
303
this->spec.freq = value;
Jul 10, 2006
Jul 10, 2006
304
305
/* Calculate the final parameters for this audio specification */
Oct 17, 2006
Oct 17, 2006
306
SDL_CalculateAudioSpec(&this->spec);
Jul 10, 2006
Jul 10, 2006
307
308
/* Determine the power of two of the fragment size */
Oct 17, 2006
Oct 17, 2006
309
310
311
for (frag_spec = 0; (0x01U << frag_spec) < this->spec.size; ++frag_spec);
if ((0x01U << frag_spec) != this->spec.size) {
DSP_CloseDevice(this);
Jul 10, 2006
Jul 10, 2006
312
SDL_SetError("Fragment size must be a power of two");
Oct 17, 2006
Oct 17, 2006
313
return 0;
Jul 10, 2006
Jul 10, 2006
314
315
316
317
}
frag_spec |= 0x00020000; /* two fragments, for low latency */
/* Set the audio buffering parameters */
Nov 12, 2004
Nov 12, 2004
318
#ifdef DEBUG_AUDIO
Jul 10, 2006
Jul 10, 2006
319
320
fprintf(stderr, "Requesting %d fragments of size %d\n",
(frag_spec >> 16), 1 << (frag_spec & 0xFFFF));
Nov 12, 2004
Nov 12, 2004
321
#endif
Oct 17, 2006
Oct 17, 2006
322
if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag_spec) < 0) {
Jul 10, 2006
Jul 10, 2006
323
324
perror("SNDCTL_DSP_SETFRAGMENT");
}
Nov 12, 2004
Nov 12, 2004
325
#ifdef DEBUG_AUDIO
Jul 10, 2006
Jul 10, 2006
326
327
{
audio_buf_info info;
Oct 17, 2006
Oct 17, 2006
328
ioctl(this->hidden->audio_fd, SNDCTL_DSP_GETOSPACE, &info);
Jul 10, 2006
Jul 10, 2006
329
330
331
332
333
fprintf(stderr, "fragments = %d\n", info.fragments);
fprintf(stderr, "fragstotal = %d\n", info.fragstotal);
fprintf(stderr, "fragsize = %d\n", info.fragsize);
fprintf(stderr, "bytes = %d\n", info.bytes);
}
Nov 12, 2004
Nov 12, 2004
334
#endif
Apr 26, 2001
Apr 26, 2001
335
Jul 10, 2006
Jul 10, 2006
336
/* Allocate mixing buffer */
Oct 17, 2006
Oct 17, 2006
337
338
339
340
341
342
this->hidden->mixlen = this->spec.size;
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
DSP_CloseDevice(this);
SDL_OutOfMemory();
return 0;
Jul 10, 2006
Jul 10, 2006
343
}
Oct 17, 2006
Oct 17, 2006
344
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
Apr 26, 2001
Apr 26, 2001
345
Jul 10, 2006
Jul 10, 2006
346
/* We're ready to rock and roll. :-) */
Oct 17, 2006
Oct 17, 2006
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
return 1;
}
static void
DSP_PlayDevice(_THIS)
{
const Uint8 *mixbuf = this->hidden->mixbuf;
const int mixlen = this->hidden->mixlen;
if (write(this->hidden->audio_fd, mixbuf, mixlen) == -1) {
perror("Audio write");
this->enabled = 0;
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", mixlen);
#endif
Apr 26, 2001
Apr 26, 2001
363
}
Jul 10, 2006
Jul 10, 2006
364
Oct 17, 2006
Oct 17, 2006
365
366
367
368
369
370
371
static Uint8 *
DSP_GetDeviceBuf(_THIS)
{
return (this->hidden->mixbuf);
}
static int
Oct 28, 2006
Oct 28, 2006
372
DSP_Init(SDL_AudioDriverImpl * impl)
Oct 17, 2006
Oct 17, 2006
373
374
375
376
377
378
379
380
381
382
383
{
/* Set the function pointers */
impl->DetectDevices = DSP_DetectDevices;
impl->GetDeviceName = DSP_GetDeviceName;
impl->OpenDevice = DSP_OpenDevice;
impl->PlayDevice = DSP_PlayDevice;
impl->GetDeviceBuf = DSP_GetDeviceBuf;
impl->CloseDevice = DSP_CloseDevice;
impl->Deinitialize = DSP_Deinitialize;
build_device_lists();
Jan 26, 2010
Jan 26, 2010
384
385
return 1; /* this audio target is available. */
Oct 17, 2006
Oct 17, 2006
386
387
388
389
390
391
392
}
AudioBootStrap DSP_bootstrap = {
DSP_DRIVER_NAME, "OSS /dev/dsp standard audio", DSP_Init, 0
};
Jul 10, 2006
Jul 10, 2006
393
/* vi: set ts=4 sw=4 expandtab: */