/
SDL_netbsdaudio.c
333 lines (282 loc) · 9.21 KB
1
2
/*
Simple DirectMedia Layer
3
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../../SDL_internal.h"
23
#if SDL_AUDIO_DRIVER_NETBSD
24
25
/*
26
* Driver for native NetBSD audio(4).
27
28
29
30
31
32
33
34
35
36
37
38
39
40
* vedge@vedge.com.ar.
*/
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/audioio.h>
#include "SDL_timer.h"
#include "SDL_audio.h"
41
#include "../../core/unix/SDL_poll.h"
42
43
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
44
#include "SDL_netbsdaudio.h"
45
46
47
48
/* #define DEBUG_AUDIO */
static void
49
NETBSDAUDIO_DetectDevices(void)
50
51
52
53
54
55
{
SDL_EnumUnixAudioDevices(0, NULL);
}
static void
56
NETBSDAUDIO_Status(_THIS)
57
58
59
60
{
#ifdef DEBUG_AUDIO
/* *INDENT-OFF* */
audio_info_t info;
61
const struct audio_prinfo *prinfo;
62
63
64
65
66
if (ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info) < 0) {
fprintf(stderr, "AUDIO_GETINFO failed.\n");
return;
}
67
68
prinfo = this->iscapture ? &info.record : &info.play;
69
70
fprintf(stderr, "\n"
71
"[%s info]\n"
72
73
74
75
76
77
78
79
80
81
82
83
84
"buffer size : %d bytes\n"
"sample rate : %i Hz\n"
"channels : %i\n"
"precision : %i-bit\n"
"encoding : 0x%x\n"
"seek : %i\n"
"sample count : %i\n"
"EOF count : %i\n"
"paused : %s\n"
"error occured : %s\n"
"waiting : %s\n"
"active : %s\n"
"",
85
86
87
88
89
90
91
92
93
94
95
96
97
this->iscapture ? "record" : "play",
prinfo->buffer_size,
prinfo->sample_rate,
prinfo->channels,
prinfo->precision,
prinfo->encoding,
prinfo->seek,
prinfo->samples,
prinfo->eof,
prinfo->pause ? "yes" : "no",
prinfo->error ? "yes" : "no",
prinfo->waiting ? "yes" : "no",
prinfo->active ? "yes" : "no");
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
fprintf(stderr, "\n"
"[audio info]\n"
"monitor_gain : %i\n"
"hw block size : %d bytes\n"
"hi watermark : %i\n"
"lo watermark : %i\n"
"audio mode : %s\n"
"",
info.monitor_gain,
info.blocksize,
info.hiwat, info.lowat,
(info.mode == AUMODE_PLAY) ? "PLAY"
: (info.mode = AUMODE_RECORD) ? "RECORD"
: (info.mode == AUMODE_PLAY_ALL ? "PLAY_ALL" : "?"));
113
114
115
116
117
118
119
120
fprintf(stderr, "\n"
"[audio spec]\n"
"format : 0x%x\n"
"size : %u\n"
"",
this->spec.format,
this->spec.size);
121
122
123
124
125
126
/* *INDENT-ON* */
#endif /* DEBUG_AUDIO */
}
static void
127
NETBSDAUDIO_PlayDevice(_THIS)
128
{
129
130
struct SDL_PrivateAudioData *h = this->hidden;
int written;
131
132
133
134
135
/* Write the audio data */
written = write(h->audio_fd, h->mixbuf, h->mixlen);
if (written == -1) {
/* Non recoverable error has occurred. It should be reported!!! */
136
SDL_OpenedAudioDeviceDisconnected(this);
137
138
perror("audio");
return;
139
}
140
141
142
143
#ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", written);
#endif
144
145
146
}
static Uint8 *
147
NETBSDAUDIO_GetDeviceBuf(_THIS)
148
149
150
151
{
return (this->hidden->mixbuf);
}
152
153
static int
154
NETBSDAUDIO_CaptureFromDevice(_THIS, void *_buffer, int buflen)
155
156
{
Uint8 *buffer = (Uint8 *) _buffer;
157
158
159
160
161
162
163
164
int br;
br = read(this->hidden->audio_fd, buffer, buflen);
if (br == -1) {
/* Non recoverable error has occurred. It should be reported!!! */
perror("audio");
return -1;
}
165
166
#ifdef DEBUG_AUDIO
167
fprintf(stderr, "Captured %d bytes of audio data\n", br);
168
#endif
169
return 0;
170
171
172
}
static void
173
NETBSDAUDIO_FlushCapture(_THIS)
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
{
audio_info_t info;
size_t remain;
Uint8 buf[512];
if (ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info) < 0) {
return; /* oh well. */
}
remain = (size_t) (info.record.samples * (SDL_AUDIO_BITSIZE(this->spec.format) / 8));
while (remain > 0) {
const size_t len = SDL_min(sizeof (buf), remain);
const int br = read(this->hidden->audio_fd, buf, len);
if (br <= 0) {
return; /* oh well. */
}
remain -= br;
}
}
194
static void
195
NETBSDAUDIO_CloseDevice(_THIS)
196
{
197
198
if (this->hidden->audio_fd >= 0) {
close(this->hidden->audio_fd);
199
}
200
SDL_free(this->hidden->mixbuf);
201
SDL_free(this->hidden);
202
203
204
}
static int
205
NETBSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
206
207
208
{
SDL_AudioFormat format = 0;
audio_info_t info;
209
struct audio_prinfo *prinfo = iscapture ? &info.record : &info.play;
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
/* 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) {
devname = SDL_GetAudioDeviceName(0, iscapture);
if (devname == NULL) {
return SDL_SetError("No such audio device");
}
}
/* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
if (this->hidden == NULL) {
return SDL_OutOfMemory();
}
226
SDL_zerop(this->hidden);
227
228
/* Open the audio device */
229
this->hidden->audio_fd = open(devname, iscapture ? O_RDONLY : O_WRONLY);
230
231
232
233
234
235
if (this->hidden->audio_fd < 0) {
return SDL_SetError("Couldn't open %s: %s", devname, strerror(errno));
}
AUDIO_INITINFO(&info);
236
prinfo->encoding = AUDIO_ENCODING_NONE;
237
238
for (format = SDL_FirstAudioFormat(this->spec.format); format;) {
239
240
switch (format) {
case AUDIO_U8:
241
242
prinfo->encoding = AUDIO_ENCODING_ULINEAR;
prinfo->precision = 8;
243
244
break;
case AUDIO_S8:
245
246
prinfo->encoding = AUDIO_ENCODING_SLINEAR;
prinfo->precision = 8;
247
248
break;
case AUDIO_S16LSB:
249
250
prinfo->encoding = AUDIO_ENCODING_SLINEAR_LE;
prinfo->precision = 16;
251
252
break;
case AUDIO_S16MSB:
253
254
prinfo->encoding = AUDIO_ENCODING_SLINEAR_BE;
prinfo->precision = 16;
255
256
break;
case AUDIO_U16LSB:
257
258
prinfo->encoding = AUDIO_ENCODING_ULINEAR_LE;
prinfo->precision = 16;
259
260
break;
case AUDIO_U16MSB:
261
262
prinfo->encoding = AUDIO_ENCODING_ULINEAR_BE;
prinfo->precision = 16;
263
264
break;
}
265
if (prinfo->encoding != AUDIO_ENCODING_NONE) {
266
267
break;
}
268
format = SDL_NextAudioFormat();
269
270
}
271
if (prinfo->encoding == AUDIO_ENCODING_NONE) {
272
273
274
275
276
return SDL_SetError("No supported encoding for 0x%x", this->spec.format);
}
this->spec.format = format;
277
278
279
280
/* Calculate spec parameters based on our chosen format */
SDL_CalculateAudioSpec(&this->spec);
info.mode = iscapture ? AUMODE_RECORD : AUMODE_PLAY;
281
282
283
info.blocksize = this->spec.size;
info.hiwat = 5;
info.lowat = 3;
284
285
prinfo->sample_rate = this->spec.freq;
prinfo->channels = this->spec.channels;
286
(void) ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info);
287
288
(void) ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info);
289
this->spec.freq = prinfo->sample_rate;
290
this->spec.channels = prinfo->channels;
291
292
293
294
if (!iscapture) {
/* Allocate mixing buffer */
this->hidden->mixlen = this->spec.size;
295
this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen);
296
297
298
299
if (this->hidden->mixbuf == NULL) {
return SDL_OutOfMemory();
}
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
300
301
}
302
NETBSDAUDIO_Status(this);
303
304
305
306
307
308
/* We're ready to rock and roll. :-) */
return 0;
}
static int
309
NETBSDAUDIO_Init(SDL_AudioDriverImpl * impl)
310
311
{
/* Set the function pointers */
312
313
314
315
316
317
318
impl->DetectDevices = NETBSDAUDIO_DetectDevices;
impl->OpenDevice = NETBSDAUDIO_OpenDevice;
impl->PlayDevice = NETBSDAUDIO_PlayDevice;
impl->GetDeviceBuf = NETBSDAUDIO_GetDeviceBuf;
impl->CloseDevice = NETBSDAUDIO_CloseDevice;
impl->CaptureFromDevice = NETBSDAUDIO_CaptureFromDevice;
impl->FlushCapture = NETBSDAUDIO_FlushCapture;
319
320
impl->HasCaptureSupport = SDL_TRUE;
321
322
323
324
325
326
impl->AllowsArbitraryDeviceNames = 1;
return 1; /* this audio target is available. */
}
327
328
AudioBootStrap NETBSDAUDIO_bootstrap = {
"netbsd", "NetBSD audio", NETBSDAUDIO_Init, 0
329
330
};
331
#endif /* SDL_AUDIO_DRIVER_NETBSD */
332
333
/* vi: set ts=4 sw=4 expandtab: */