summaryrefslogtreecommitdiff
path: root/contrib/SDL-3.2.8/src/audio/netbsd
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2025-12-27 12:03:39 -0800
committer3gg <3gg@shellblade.net>2025-12-27 12:03:39 -0800
commit5a079a2d114f96d4847d1ee305d5b7c16eeec50e (patch)
tree8926ab44f168acf787d8e19608857b3af0f82758 /contrib/SDL-3.2.8/src/audio/netbsd
Initial commit
Diffstat (limited to 'contrib/SDL-3.2.8/src/audio/netbsd')
-rw-r--r--contrib/SDL-3.2.8/src/audio/netbsd/SDL_netbsdaudio.c328
-rw-r--r--contrib/SDL-3.2.8/src/audio/netbsd/SDL_netbsdaudio.h44
2 files changed, 372 insertions, 0 deletions
diff --git a/contrib/SDL-3.2.8/src/audio/netbsd/SDL_netbsdaudio.c b/contrib/SDL-3.2.8/src/audio/netbsd/SDL_netbsdaudio.c
new file mode 100644
index 0000000..26060d3
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/audio/netbsd/SDL_netbsdaudio.c
@@ -0,0 +1,328 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 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_internal.h"
22
23#ifdef SDL_AUDIO_DRIVER_NETBSD
24
25// Driver for native NetBSD audio(4).
26
27#include <errno.h>
28#include <unistd.h>
29#include <fcntl.h>
30#include <sys/time.h>
31#include <sys/ioctl.h>
32#include <sys/stat.h>
33#include <sys/types.h>
34#include <sys/audioio.h>
35
36#include "../../core/unix/SDL_poll.h"
37#include "../SDL_audiodev_c.h"
38#include "SDL_netbsdaudio.h"
39
40//#define DEBUG_AUDIO
41
42static void NETBSDAUDIO_DetectDevices(SDL_AudioDevice **default_playback, SDL_AudioDevice **default_recording)
43{
44 SDL_EnumUnixAudioDevices(false, NULL);
45}
46
47static void NETBSDAUDIO_Status(SDL_AudioDevice *device)
48{
49#ifdef DEBUG_AUDIO
50 /* *INDENT-OFF* */ // clang-format off
51 audio_info_t info;
52 const struct audio_prinfo *prinfo;
53
54 if (ioctl(device->hidden->audio_fd, AUDIO_GETINFO, &info) < 0) {
55 fprintf(stderr, "AUDIO_GETINFO failed.\n");
56 return;
57 }
58
59 prinfo = device->recording ? &info.record : &info.play;
60
61 fprintf(stderr, "\n"
62 "[%s info]\n"
63 "buffer size : %d bytes\n"
64 "sample rate : %i Hz\n"
65 "channels : %i\n"
66 "precision : %i-bit\n"
67 "encoding : 0x%x\n"
68 "seek : %i\n"
69 "sample count : %i\n"
70 "EOF count : %i\n"
71 "paused : %s\n"
72 "error occurred : %s\n"
73 "waiting : %s\n"
74 "active : %s\n"
75 "",
76 device->recording ? "record" : "play",
77 prinfo->buffer_size,
78 prinfo->sample_rate,
79 prinfo->channels,
80 prinfo->precision,
81 prinfo->encoding,
82 prinfo->seek,
83 prinfo->samples,
84 prinfo->eof,
85 prinfo->pause ? "yes" : "no",
86 prinfo->error ? "yes" : "no",
87 prinfo->waiting ? "yes" : "no",
88 prinfo->active ? "yes" : "no");
89
90 fprintf(stderr, "\n"
91 "[audio info]\n"
92 "monitor_gain : %i\n"
93 "hw block size : %d bytes\n"
94 "hi watermark : %i\n"
95 "lo watermark : %i\n"
96 "audio mode : %s\n"
97 "",
98 info.monitor_gain,
99 info.blocksize,
100 info.hiwat, info.lowat,
101 (info.mode == AUMODE_PLAY) ? "PLAY"
102 : (info.mode == AUMODE_RECORD) ? "RECORD"
103 : (info.mode == AUMODE_PLAY_ALL ? "PLAY_ALL" : "?"));
104
105 fprintf(stderr, "\n"
106 "[audio spec]\n"
107 "format : 0x%x\n"
108 "size : %u\n"
109 "",
110 device->spec.format,
111 device->buffer_size);
112 /* *INDENT-ON* */ // clang-format on
113
114#endif // DEBUG_AUDIO
115}
116
117static bool NETBSDAUDIO_WaitDevice(SDL_AudioDevice *device)
118{
119 const bool recording = device->recording;
120 while (!SDL_GetAtomicInt(&device->shutdown)) {
121 audio_info_t info;
122 const int rc = ioctl(device->hidden->audio_fd, AUDIO_GETINFO, &info);
123 if (rc < 0) {
124 if (errno == EAGAIN) {
125 continue;
126 }
127 // Hmm, not much we can do - abort
128 fprintf(stderr, "netbsdaudio WaitDevice ioctl failed (unrecoverable): %s\n", strerror(errno));
129 return false;
130 }
131 const size_t remain = (size_t)((recording ? info.record.seek : info.play.seek) * SDL_AUDIO_BYTESIZE(device->spec.format));
132 if (!recording && (remain >= device->buffer_size)) {
133 SDL_Delay(10);
134 } else if (recording && (remain < device->buffer_size)) {
135 SDL_Delay(10);
136 } else {
137 break; // ready to go!
138 }
139 }
140
141 return true;
142}
143
144static bool NETBSDAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
145{
146 struct SDL_PrivateAudioData *h = device->hidden;
147 const int written = write(h->audio_fd, buffer, buflen);
148 if (written != buflen) { // Treat even partial writes as fatal errors.
149 return false;
150 }
151
152#ifdef DEBUG_AUDIO
153 fprintf(stderr, "Wrote %d bytes of audio data\n", written);
154#endif
155 return true;
156}
157
158static Uint8 *NETBSDAUDIO_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
159{
160 return device->hidden->mixbuf;
161}
162
163static int NETBSDAUDIO_RecordDevice(SDL_AudioDevice *device, void *vbuffer, int buflen)
164{
165 Uint8 *buffer = (Uint8 *)vbuffer;
166 const int br = read(device->hidden->audio_fd, buffer, buflen);
167 if (br == -1) {
168 // Non recoverable error has occurred. It should be reported!!!
169 perror("audio");
170 return -1;
171 }
172
173#ifdef DEBUG_AUDIO
174 fprintf(stderr, "Recorded %d bytes of audio data\n", br);
175#endif
176 return br;
177}
178
179static void NETBSDAUDIO_FlushRecording(SDL_AudioDevice *device)
180{
181 struct SDL_PrivateAudioData *h = device->hidden;
182 audio_info_t info;
183 if (ioctl(device->hidden->audio_fd, AUDIO_GETINFO, &info) == 0) {
184 size_t remain = (size_t)(info.record.seek * SDL_AUDIO_BYTESIZE(device->spec.format));
185 while (remain > 0) {
186 char buf[512];
187 const size_t len = SDL_min(sizeof(buf), remain);
188 const ssize_t br = read(h->audio_fd, buf, len);
189 if (br <= 0) {
190 break;
191 }
192 remain -= br;
193 }
194 }
195}
196
197static void NETBSDAUDIO_CloseDevice(SDL_AudioDevice *device)
198{
199 if (device->hidden) {
200 if (device->hidden->audio_fd >= 0) {
201 close(device->hidden->audio_fd);
202 }
203 SDL_free(device->hidden->mixbuf);
204 SDL_free(device->hidden);
205 device->hidden = NULL;
206 }
207}
208
209static bool NETBSDAUDIO_OpenDevice(SDL_AudioDevice *device)
210{
211 const bool recording = device->recording;
212 int encoding = AUDIO_ENCODING_NONE;
213 audio_info_t info, hwinfo;
214 struct audio_prinfo *prinfo = recording ? &info.record : &info.play;
215
216 // Initialize all variables that we clean on shutdown
217 device->hidden = (struct SDL_PrivateAudioData *) SDL_calloc(1, sizeof(*device->hidden));
218 if (!device->hidden) {
219 return false;
220 }
221
222 // Open the audio device; we hardcode the device path in `device->name` for lack of better info, so use that.
223 const int flags = ((device->recording) ? O_RDONLY : O_WRONLY);
224 device->hidden->audio_fd = open(device->name, flags | O_CLOEXEC);
225 if (device->hidden->audio_fd < 0) {
226 return SDL_SetError("Couldn't open %s: %s", device->name, strerror(errno));
227 }
228
229 AUDIO_INITINFO(&info);
230
231#ifdef AUDIO_GETFORMAT // Introduced in NetBSD 9.0
232 if (ioctl(device->hidden->audio_fd, AUDIO_GETFORMAT, &hwinfo) != -1) {
233 // Use the device's native sample rate so the kernel doesn't have to resample.
234 device->spec.freq = recording ? hwinfo.record.sample_rate : hwinfo.play.sample_rate;
235 }
236#endif
237
238 prinfo->sample_rate = device->spec.freq;
239 prinfo->channels = device->spec.channels;
240
241 SDL_AudioFormat test_format;
242 const SDL_AudioFormat *closefmts = SDL_ClosestAudioFormats(device->spec.format);
243 while ((test_format = *(closefmts++)) != 0) {
244 switch (test_format) {
245 case SDL_AUDIO_U8:
246 encoding = AUDIO_ENCODING_ULINEAR;
247 break;
248 case SDL_AUDIO_S8:
249 encoding = AUDIO_ENCODING_SLINEAR;
250 break;
251 case SDL_AUDIO_S16LE:
252 encoding = AUDIO_ENCODING_SLINEAR_LE;
253 break;
254 case SDL_AUDIO_S16BE:
255 encoding = AUDIO_ENCODING_SLINEAR_BE;
256 break;
257 case SDL_AUDIO_S32LE:
258 encoding = AUDIO_ENCODING_SLINEAR_LE;
259 break;
260 case SDL_AUDIO_S32BE:
261 encoding = AUDIO_ENCODING_SLINEAR_BE;
262 break;
263 default:
264 continue;
265 }
266 break;
267 }
268
269 if (!test_format) {
270 return SDL_SetError("%s: Unsupported audio format", "netbsd");
271 }
272 prinfo->encoding = encoding;
273 prinfo->precision = SDL_AUDIO_BITSIZE(test_format);
274
275 info.hiwat = 5;
276 info.lowat = 3;
277 if (ioctl(device->hidden->audio_fd, AUDIO_SETINFO, &info) < 0) {
278 return SDL_SetError("AUDIO_SETINFO failed for %s: %s", device->name, strerror(errno));
279 }
280
281 if (ioctl(device->hidden->audio_fd, AUDIO_GETINFO, &info) < 0) {
282 return SDL_SetError("AUDIO_GETINFO failed for %s: %s", device->name, strerror(errno));
283 }
284
285 // Final spec used for the device.
286 device->spec.format = test_format;
287 device->spec.freq = prinfo->sample_rate;
288 device->spec.channels = prinfo->channels;
289
290 SDL_UpdatedAudioDeviceFormat(device);
291
292 if (!recording) {
293 // Allocate mixing buffer
294 device->hidden->mixlen = device->buffer_size;
295 device->hidden->mixbuf = (Uint8 *)SDL_malloc(device->hidden->mixlen);
296 if (!device->hidden->mixbuf) {
297 return false;
298 }
299 SDL_memset(device->hidden->mixbuf, device->silence_value, device->buffer_size);
300 }
301
302 NETBSDAUDIO_Status(device);
303
304 return true; // We're ready to rock and roll. :-)
305}
306
307static bool NETBSDAUDIO_Init(SDL_AudioDriverImpl *impl)
308{
309 impl->DetectDevices = NETBSDAUDIO_DetectDevices;
310 impl->OpenDevice = NETBSDAUDIO_OpenDevice;
311 impl->WaitDevice = NETBSDAUDIO_WaitDevice;
312 impl->PlayDevice = NETBSDAUDIO_PlayDevice;
313 impl->GetDeviceBuf = NETBSDAUDIO_GetDeviceBuf;
314 impl->CloseDevice = NETBSDAUDIO_CloseDevice;
315 impl->WaitRecordingDevice = NETBSDAUDIO_WaitDevice;
316 impl->RecordDevice = NETBSDAUDIO_RecordDevice;
317 impl->FlushRecording = NETBSDAUDIO_FlushRecording;
318
319 impl->HasRecordingSupport = true;
320
321 return true;
322}
323
324AudioBootStrap NETBSDAUDIO_bootstrap = {
325 "netbsd", "NetBSD audio", NETBSDAUDIO_Init, false, false
326};
327
328#endif // SDL_AUDIO_DRIVER_NETBSD
diff --git a/contrib/SDL-3.2.8/src/audio/netbsd/SDL_netbsdaudio.h b/contrib/SDL-3.2.8/src/audio/netbsd/SDL_netbsdaudio.h
new file mode 100644
index 0000000..dcdc6f4
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/audio/netbsd/SDL_netbsdaudio.h
@@ -0,0 +1,44 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 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_internal.h"
22
23#ifndef SDL_netbsdaudio_h_
24#define SDL_netbsdaudio_h_
25
26#include "../SDL_sysaudio.h"
27
28struct SDL_PrivateAudioData
29{
30 // The file descriptor for the audio device
31 int audio_fd;
32
33 // Raw mixing buffer
34 Uint8 *mixbuf;
35 int mixlen;
36
37 // Support for audio timing using a timer, in addition to SDL_IOReady()
38 float frame_ticks;
39 float next_frame;
40};
41
42#define FUDGE_TICKS 10 // The scheduler overhead ticks per frame
43
44#endif // SDL_netbsdaudio_h_