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

Latest commit

 

History

History
354 lines (308 loc) · 9.67 KB

SDL_dspaudio.c

File metadata and controls

354 lines (308 loc) · 9.67 KB
 
Apr 26, 2001
Apr 26, 2001
1
2
/*
SDL - Simple DirectMedia Layer
Feb 1, 2006
Feb 1, 2006
3
Copyright (C) 1997-2006 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
58
59
60
#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 */
#define OPEN_FLAGS (O_WRONLY|O_NONBLOCK)
/* Audio driver functions */
Oct 4, 2006
Oct 4, 2006
61
62
63
64
65
66
67
static int DSP_DetectDevices(int iscapture);
static const char *DSP_GetDeviceName(int index, int iscapture);
static int DSP_OpenDevice(_THIS, const char *devname, int iscapture);
static void DSP_WaitDevice(_THIS);
static void DSP_PlayDevice(_THIS);
static Uint8 *DSP_GetDeviceBuf(_THIS);
static void DSP_CloseDevice(_THIS);
Apr 26, 2001
Apr 26, 2001
68
69
70
/* Audio driver bootstrap functions */
Jul 10, 2006
Jul 10, 2006
71
static int
Oct 4, 2006
Oct 4, 2006
72
DSP_Available(void)
Apr 26, 2001
Apr 26, 2001
73
{
Oct 4, 2006
Oct 4, 2006
74
75
76
77
78
79
/*
* !!! FIXME: maybe change this to always available, and move this to
* !!! FIXME: to device enumeration and opening?
*/
int fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 0);
int available = 0;
Jul 10, 2006
Jul 10, 2006
80
81
82
83
84
if (fd >= 0) {
available = 1;
close(fd);
}
return (available);
Apr 26, 2001
Apr 26, 2001
85
86
87
}
Oct 4, 2006
Oct 4, 2006
88
89
static int
DSP_Init(SDL_AudioDriverImpl *impl)
Apr 26, 2001
Apr 26, 2001
90
{
Jul 10, 2006
Jul 10, 2006
91
/* Set the function pointers */
Oct 4, 2006
Oct 4, 2006
92
93
94
95
96
97
98
99
100
impl->DetectDevices = DSP_DetectDevices;
impl->GetDeviceName = DSP_GetDeviceName;
impl->OpenDevice = DSP_OpenDevice;
impl->WaitDevice = DSP_WaitDevice;
impl->PlayDevice = DSP_PlayDevice;
impl->GetDeviceBuf = DSP_GetDeviceBuf;
impl->CloseDevice = DSP_CloseDevice;
return 1;
Apr 26, 2001
Apr 26, 2001
101
102
}
Oct 4, 2006
Oct 4, 2006
103
Apr 26, 2001
Apr 26, 2001
104
AudioBootStrap DSP_bootstrap = {
Jul 10, 2006
Jul 10, 2006
105
DSP_DRIVER_NAME, "OSS /dev/dsp standard audio",
Oct 4, 2006
Oct 4, 2006
106
DSP_Available, DSP_Init
Apr 26, 2001
Apr 26, 2001
107
108
109
};
Oct 4, 2006
Oct 4, 2006
110
111
static int
DSP_DetectDevices(int iscapture)
Apr 26, 2001
Apr 26, 2001
112
{
Oct 4, 2006
Oct 4, 2006
113
return -1; /* !!! FIXME */
Apr 26, 2001
Apr 26, 2001
114
115
116
}
Oct 4, 2006
Oct 4, 2006
117
118
static const char *
DSP_GetDeviceName(int index, int iscapture)
Apr 26, 2001
Apr 26, 2001
119
{
Oct 4, 2006
Oct 4, 2006
120
121
SDL_SetError("No such device"); /* !!! FIXME */
return NULL;
Apr 26, 2001
Apr 26, 2001
122
123
}
Oct 4, 2006
Oct 4, 2006
124
Jul 10, 2006
Jul 10, 2006
125
static int
Oct 4, 2006
Oct 4, 2006
126
DSP_OpenDevice(_THIS, const char *devname, int iscapture)
Apr 26, 2001
Apr 26, 2001
127
{
Oct 4, 2006
Oct 4, 2006
128
char dev[1024];
Jul 10, 2006
Jul 10, 2006
129
130
131
int format;
int value;
int frag_spec;
Aug 24, 2006
Aug 24, 2006
132
SDL_AudioFormat test_format;
Jul 10, 2006
Jul 10, 2006
133
Oct 4, 2006
Oct 4, 2006
134
135
136
137
138
139
140
141
142
143
144
145
146
/* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
if (this->hidden == NULL) {
SDL_OutOfMemory();
return 0;
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
this->hidden->audio_fd = -1;
/* !!! FIXME: handle devname */
/* !!! FIXME: handle iscapture */
Jul 10, 2006
Jul 10, 2006
147
/* Open the audio device */
Oct 4, 2006
Oct 4, 2006
148
149
150
151
this->hidden->audio_fd = SDL_OpenAudioPath(dev, sizeof(dev), OPEN_FLAGS, 0);
if (this->hidden->audio_fd < 0) {
SDL_SetError("Couldn't open %s: %s", dev, strerror(errno));
return 0;
Jul 10, 2006
Jul 10, 2006
152
}
Oct 4, 2006
Oct 4, 2006
153
this->hidden->mixbuf = NULL;
Jul 10, 2006
Jul 10, 2006
154
155
156
157
/* Make the file descriptor use blocking writes with fcntl() */
{
long flags;
Oct 4, 2006
Oct 4, 2006
158
flags = fcntl(this->hidden->audio_fd, F_GETFL);
Jul 10, 2006
Jul 10, 2006
159
flags &= ~O_NONBLOCK;
Oct 4, 2006
Oct 4, 2006
160
if (fcntl(this->hidden->audio_fd, F_SETFL, flags) < 0) {
Jul 10, 2006
Jul 10, 2006
161
SDL_SetError("Couldn't set audio blocking mode");
Oct 4, 2006
Oct 4, 2006
162
163
DSP_CloseDevice(this);
return 0;
Jul 10, 2006
Jul 10, 2006
164
165
166
167
}
}
/* Get a list of supported hardware formats */
Oct 4, 2006
Oct 4, 2006
168
if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_GETFMTS, &value) < 0) {
Jul 10, 2006
Jul 10, 2006
169
170
perror("SNDCTL_DSP_GETFMTS");
SDL_SetError("Couldn't get audio format list");
Oct 4, 2006
Oct 4, 2006
171
172
DSP_CloseDevice(this);
return 0;
Jul 10, 2006
Jul 10, 2006
173
174
175
176
}
/* Try for a closest match on audio format */
format = 0;
Oct 4, 2006
Oct 4, 2006
177
for (test_format = SDL_FirstAudioFormat(this->spec.format);
Jul 10, 2006
Jul 10, 2006
178
!format && test_format;) {
Apr 26, 2001
Apr 26, 2001
179
#ifdef DEBUG_AUDIO
Jul 10, 2006
Jul 10, 2006
180
fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
Apr 26, 2001
Apr 26, 2001
181
#endif
Jul 10, 2006
Jul 10, 2006
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
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
198
199
200
201
202
#if 0
/*
* These formats are not used by any real life systems so they are not
* needed here.
*/
Jul 10, 2006
Jul 10, 2006
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
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
218
#endif
Jul 10, 2006
Jul 10, 2006
219
220
221
222
223
224
225
226
227
228
default:
format = 0;
break;
}
if (!format) {
test_format = SDL_NextAudioFormat();
}
}
if (format == 0) {
SDL_SetError("Couldn't find any hardware audio formats");
Oct 4, 2006
Oct 4, 2006
229
230
DSP_CloseDevice(this);
return 0;
Jul 10, 2006
Jul 10, 2006
231
}
Oct 4, 2006
Oct 4, 2006
232
this->spec.format = test_format;
Jul 10, 2006
Jul 10, 2006
233
234
235
/* Set the audio format */
value = format;
Oct 4, 2006
Oct 4, 2006
236
237
if ( (ioctl(this->hidden->audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) ||
(value != format) ) {
Jul 10, 2006
Jul 10, 2006
238
239
perror("SNDCTL_DSP_SETFMT");
SDL_SetError("Couldn't set audio format");
Oct 4, 2006
Oct 4, 2006
240
241
DSP_CloseDevice(this);
return 0;
Jul 10, 2006
Jul 10, 2006
242
243
244
}
/* Set the number of channels of output */
Oct 4, 2006
Oct 4, 2006
245
246
value = this->spec.channels;
if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_CHANNELS, &value) < 0) {
Jul 10, 2006
Jul 10, 2006
247
248
perror("SNDCTL_DSP_CHANNELS");
SDL_SetError("Cannot set the number of channels");
Oct 4, 2006
Oct 4, 2006
249
250
DSP_CloseDevice(this);
return 0;
Jul 10, 2006
Jul 10, 2006
251
}
Oct 4, 2006
Oct 4, 2006
252
this->spec.channels = value;
Jul 10, 2006
Jul 10, 2006
253
254
/* Set the DSP frequency */
Oct 4, 2006
Oct 4, 2006
255
256
value = this->spec.freq;
if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_SPEED, &value) < 0) {
Jul 10, 2006
Jul 10, 2006
257
258
perror("SNDCTL_DSP_SPEED");
SDL_SetError("Couldn't set audio frequency");
Oct 4, 2006
Oct 4, 2006
259
260
DSP_CloseDevice(this);
return 0;
Jul 10, 2006
Jul 10, 2006
261
}
Oct 4, 2006
Oct 4, 2006
262
this->spec.freq = value;
Jul 10, 2006
Jul 10, 2006
263
264
/* Calculate the final parameters for this audio specification */
Oct 4, 2006
Oct 4, 2006
265
SDL_CalculateAudioSpec(&this->spec);
Jul 10, 2006
Jul 10, 2006
266
267
/* Determine the power of two of the fragment size */
Oct 4, 2006
Oct 4, 2006
268
269
for (frag_spec = 0; (0x01U << frag_spec) < this->spec.size; ++frag_spec);
if ((0x01U << frag_spec) != this->spec.size) {
Jul 10, 2006
Jul 10, 2006
270
SDL_SetError("Fragment size must be a power of two");
Oct 4, 2006
Oct 4, 2006
271
272
DSP_CloseDevice(this);
return 0;
Jul 10, 2006
Jul 10, 2006
273
274
275
276
}
frag_spec |= 0x00020000; /* two fragments, for low latency */
/* Set the audio buffering parameters */
Nov 12, 2004
Nov 12, 2004
277
#ifdef DEBUG_AUDIO
Jul 10, 2006
Jul 10, 2006
278
279
fprintf(stderr, "Requesting %d fragments of size %d\n",
(frag_spec >> 16), 1 << (frag_spec & 0xFFFF));
Nov 12, 2004
Nov 12, 2004
280
#endif
Oct 4, 2006
Oct 4, 2006
281
if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag_spec) < 0) {
Jul 10, 2006
Jul 10, 2006
282
283
perror("SNDCTL_DSP_SETFRAGMENT");
}
Nov 12, 2004
Nov 12, 2004
284
#ifdef DEBUG_AUDIO
Jul 10, 2006
Jul 10, 2006
285
286
{
audio_buf_info info;
Oct 4, 2006
Oct 4, 2006
287
ioctl(this->hidden->audio_fd, SNDCTL_DSP_GETOSPACE, &info);
Jul 10, 2006
Jul 10, 2006
288
289
290
291
292
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
293
#endif
Apr 26, 2001
Apr 26, 2001
294
Jul 10, 2006
Jul 10, 2006
295
/* Allocate mixing buffer */
Oct 4, 2006
Oct 4, 2006
296
297
298
299
300
this->hidden->mixlen = this->spec.size;
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
DSP_CloseDevice(this);
return 0;
Jul 10, 2006
Jul 10, 2006
301
}
Oct 4, 2006
Oct 4, 2006
302
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
Apr 26, 2001
Apr 26, 2001
303
Jul 10, 2006
Jul 10, 2006
304
/* We're ready to rock and roll. :-) */
Oct 4, 2006
Oct 4, 2006
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
return 1;
}
/* This function waits until it is possible to write a full sound buffer */
static void
DSP_WaitDevice(_THIS)
{
/* Not needed at all since OSS handles waiting automagically */
}
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
}
static Uint8 *
DSP_GetDeviceBuf(_THIS)
{
return (this->hidden->mixbuf);
}
static void
DSP_CloseDevice(_THIS)
{
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;
}
Apr 26, 2001
Apr 26, 2001
352
}
Jul 10, 2006
Jul 10, 2006
353
354
/* vi: set ts=4 sw=4 expandtab: */