Atlas - SDL_sndioaudio.c
Home / ext / SDL2 / src / audio / sndio Lines: 2 | Size: 10426 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2018 Sam Lantinga <[email protected]> 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 22#include "../../SDL_internal.h" 23 24#if SDL_AUDIO_DRIVER_SNDIO 25 26/* OpenBSD sndio target */ 27 28#if HAVE_STDIO_H 29#include <stdio.h> 30#endif 31 32#ifdef HAVE_SIGNAL_H 33#include <signal.h> 34#endif 35 36#include <poll.h> 37#include <unistd.h> 38 39#include "SDL_audio.h" 40#include "../SDL_audio_c.h" 41#include "SDL_sndioaudio.h" 42 43#ifdef SDL_AUDIO_DRIVER_SNDIO_DYNAMIC 44#include "SDL_loadso.h" 45#endif 46 47#ifndef INFTIM 48#define INFTIM -1 49#endif 50 51#ifndef SIO_DEVANY 52#define SIO_DEVANY "default" 53#endif 54 55static struct sio_hdl * (*SNDIO_sio_open)(const char *, unsigned int, int); 56static void (*SNDIO_sio_close)(struct sio_hdl *); 57static int (*SNDIO_sio_setpar)(struct sio_hdl *, struct sio_par *); 58static int (*SNDIO_sio_getpar)(struct sio_hdl *, struct sio_par *); 59static int (*SNDIO_sio_start)(struct sio_hdl *); 60static int (*SNDIO_sio_stop)(struct sio_hdl *); 61static size_t (*SNDIO_sio_read)(struct sio_hdl *, void *, size_t); 62static size_t (*SNDIO_sio_write)(struct sio_hdl *, const void *, size_t); 63static int (*SNDIO_sio_nfds)(struct sio_hdl *); 64static int (*SNDIO_sio_pollfd)(struct sio_hdl *, struct pollfd *, int); 65static int (*SNDIO_sio_revents)(struct sio_hdl *, struct pollfd *); 66static int (*SNDIO_sio_eof)(struct sio_hdl *); 67static void (*SNDIO_sio_initpar)(struct sio_par *); 68 69#ifdef SDL_AUDIO_DRIVER_SNDIO_DYNAMIC 70static const char *sndio_library = SDL_AUDIO_DRIVER_SNDIO_DYNAMIC; 71static void *sndio_handle = NULL; 72 73static int 74load_sndio_sym(const char *fn, void **addr) 75{ 76 *addr = SDL_LoadFunction(sndio_handle, fn); 77 if (*addr == NULL) { 78 /* Don't call SDL_SetError(): SDL_LoadFunction already did. */ 79 return 0; 80 } 81 82 return 1; 83} 84 85/* cast funcs to char* first, to please GCC's strict aliasing rules. */ 86#define SDL_SNDIO_SYM(x) \ 87 if (!load_sndio_sym(#x, (void **) (char *) &SNDIO_##x)) return -1 88#else 89#define SDL_SNDIO_SYM(x) SNDIO_##x = x 90#endif 91 92static int 93load_sndio_syms(void) 94{ 95 SDL_SNDIO_SYM(sio_open); 96 SDL_SNDIO_SYM(sio_close); 97 SDL_SNDIO_SYM(sio_setpar); 98 SDL_SNDIO_SYM(sio_getpar); 99 SDL_SNDIO_SYM(sio_start); 100 SDL_SNDIO_SYM(sio_stop); 101 SDL_SNDIO_SYM(sio_read); 102 SDL_SNDIO_SYM(sio_write); 103 SDL_SNDIO_SYM(sio_nfds); 104 SDL_SNDIO_SYM(sio_pollfd); 105 SDL_SNDIO_SYM(sio_revents); 106 SDL_SNDIO_SYM(sio_eof); 107 SDL_SNDIO_SYM(sio_initpar); 108 return 0; 109} 110 111#undef SDL_SNDIO_SYM 112 113#ifdef SDL_AUDIO_DRIVER_SNDIO_DYNAMIC 114 115static void 116UnloadSNDIOLibrary(void) 117{ 118 if (sndio_handle != NULL) { 119 SDL_UnloadObject(sndio_handle); 120 sndio_handle = NULL; 121 } 122} 123 124static int 125LoadSNDIOLibrary(void) 126{ 127 int retval = 0; 128 if (sndio_handle == NULL) { 129 sndio_handle = SDL_LoadObject(sndio_library); 130 if (sndio_handle == NULL) { 131 retval = -1; 132 /* Don't call SDL_SetError(): SDL_LoadObject already did. */ 133 } else { 134 retval = load_sndio_syms(); 135 if (retval < 0) { 136 UnloadSNDIOLibrary(); 137 } 138 } 139 } 140 return retval; 141} 142 143#else 144 145static void 146UnloadSNDIOLibrary(void) 147{ 148} 149 150static int 151LoadSNDIOLibrary(void) 152{ 153 load_sndio_syms(); 154 return 0; 155} 156 157#endif /* SDL_AUDIO_DRIVER_SNDIO_DYNAMIC */ 158 159 160 161 162static void 163SNDIO_WaitDevice(_THIS) 164{ 165 /* no-op; SNDIO_sio_write() blocks if necessary. */ 166} 167 168static void 169SNDIO_PlayDevice(_THIS) 170{ 171 const int written = SNDIO_sio_write(this->hidden->dev, 172 this->hidden->mixbuf, 173 this->hidden->mixlen); 174 175 /* If we couldn't write, assume fatal error for now */ 176 if ( written == 0 ) { 177 SDL_OpenedAudioDeviceDisconnected(this); 178 } 179#ifdef DEBUG_AUDIO 180 fprintf(stderr, "Wrote %d bytes of audio data\n", written); 181#endif 182} 183 184static int 185SNDIO_CaptureFromDevice(_THIS, void *buffer, int buflen) 186{ 187 size_t r; 188 int revents; 189 int nfds; 190 191 /* Emulate a blocking read */ 192 r = SNDIO_sio_read(this->hidden->dev, buffer, buflen); 193 while (r == 0 && !SNDIO_sio_eof(this->hidden->dev)) { 194 if ((nfds = SNDIO_sio_pollfd(this->hidden->dev, this->hidden->pfd, POLLIN)) <= 0 195 || poll(this->hidden->pfd, nfds, INFTIM) < 0) { 196 return -1; 197 } 198 revents = SNDIO_sio_revents(this->hidden->dev, this->hidden->pfd); 199 if (revents & POLLIN) { 200 r = SNDIO_sio_read(this->hidden->dev, buffer, buflen); 201 } 202 if (revents & POLLHUP) { 203 break; 204 } 205 } 206 return (int) r; 207} 208 209static void 210SNDIO_FlushCapture(_THIS) 211{ 212 char buf[512]; 213 214 while (SNDIO_sio_read(this->hidden->dev, buf, sizeof(buf)) != 0) { 215 /* do nothing */; 216 } 217} 218 219static Uint8 * 220SNDIO_GetDeviceBuf(_THIS) 221{ 222 return this->hidden->mixbuf; 223} 224 225static void 226SNDIO_CloseDevice(_THIS) 227{ 228 if ( this->hidden->pfd != NULL ) { 229 SDL_free(this->hidden->pfd); 230 } 231 if ( this->hidden->dev != NULL ) { 232 SNDIO_sio_stop(this->hidden->dev); 233 SNDIO_sio_close(this->hidden->dev); 234 } 235 SDL_free(this->hidden->mixbuf); 236 SDL_free(this->hidden); 237} 238 239static int 240SNDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) 241{ 242 SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format); 243 struct sio_par par; 244 int status; 245 246 this->hidden = (struct SDL_PrivateAudioData *) 247 SDL_malloc(sizeof(*this->hidden)); 248 if (this->hidden == NULL) { 249 return SDL_OutOfMemory(); 250 } 251 SDL_zerop(this->hidden); 252 253 this->hidden->mixlen = this->spec.size; 254 255 /* Capture devices must be non-blocking for SNDIO_FlushCapture */ 256 if ((this->hidden->dev = 257 SNDIO_sio_open(devname != NULL ? devname : SIO_DEVANY, 258 iscapture ? SIO_REC : SIO_PLAY, iscapture)) == NULL) { 259 return SDL_SetError("sio_open() failed"); 260 } 261 262 /* Allocate the pollfd array for capture devices */ 263 if (iscapture && (this->hidden->pfd = 264 SDL_malloc(sizeof(struct pollfd) * SNDIO_sio_nfds(this->hidden->dev))) == NULL) { 265 return SDL_OutOfMemory(); 266 } 267 268 SNDIO_sio_initpar(&par); 269 270 par.rate = this->spec.freq; 271 par.pchan = this->spec.channels; 272 par.round = this->spec.samples; 273 par.appbufsz = par.round * 2; 274 275 /* Try for a closest match on audio format */ 276 status = -1; 277 while (test_format && (status < 0)) { 278 if (!SDL_AUDIO_ISFLOAT(test_format)) { 279 par.le = SDL_AUDIO_ISLITTLEENDIAN(test_format) ? 1 : 0; 280 par.sig = SDL_AUDIO_ISSIGNED(test_format) ? 1 : 0; 281 par.bits = SDL_AUDIO_BITSIZE(test_format); 282 283 if (SNDIO_sio_setpar(this->hidden->dev, &par) == 0) { 284 continue; 285 } 286 if (SNDIO_sio_getpar(this->hidden->dev, &par) == 0) { 287 return SDL_SetError("sio_getpar() failed"); 288 } 289 if (par.bps != SIO_BPS(par.bits)) { 290 continue; 291 } 292 if ((par.bits == 8 * par.bps) || (par.msb)) { 293 status = 0; 294 break; 295 } 296 } 297 test_format = SDL_NextAudioFormat(); 298 } 299 300 if (status < 0) { 301 return SDL_SetError("sndio: Couldn't find any hardware audio formats"); 302 } 303 304 if ((par.bps == 4) && (par.sig) && (par.le)) 305 this->spec.format = AUDIO_S32LSB; 306 else if ((par.bps == 4) && (par.sig) && (!par.le)) 307 this->spec.format = AUDIO_S32MSB; 308 else if ((par.bps == 2) && (par.sig) && (par.le)) 309 this->spec.format = AUDIO_S16LSB; 310 else if ((par.bps == 2) && (par.sig) && (!par.le)) 311 this->spec.format = AUDIO_S16MSB; 312 else if ((par.bps == 2) && (!par.sig) && (par.le)) 313 this->spec.format = AUDIO_U16LSB; 314 else if ((par.bps == 2) && (!par.sig) && (!par.le)) 315 this->spec.format = AUDIO_U16MSB; 316 else if ((par.bps == 1) && (par.sig)) 317 this->spec.format = AUDIO_S8; 318 else if ((par.bps == 1) && (!par.sig)) 319 this->spec.format = AUDIO_U8; 320 else { 321 return SDL_SetError("sndio: Got unsupported hardware audio format."); 322 } 323 324 this->spec.freq = par.rate; 325 this->spec.channels = par.pchan; 326 this->spec.samples = par.round; 327 328 /* Calculate the final parameters for this audio specification */ 329 SDL_CalculateAudioSpec(&this->spec); 330 331 /* Allocate mixing buffer */ 332 this->hidden->mixlen = this->spec.size; 333 this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen); 334 if (this->hidden->mixbuf == NULL) { 335 return SDL_OutOfMemory(); 336 } 337 SDL_memset(this->hidden->mixbuf, this->spec.silence, this->hidden->mixlen); 338 339 if (!SNDIO_sio_start(this->hidden->dev)) { 340 return SDL_SetError("sio_start() failed"); 341 } 342 343 /* We're ready to rock and roll. :-) */ 344 return 0; 345} 346 347static void 348SNDIO_Deinitialize(void) 349{ 350 UnloadSNDIOLibrary(); 351} 352 353static int 354SNDIO_Init(SDL_AudioDriverImpl * impl) 355{ 356 if (LoadSNDIOLibrary() < 0) { 357 return 0; 358 } 359 360 /* Set the function pointers */ 361 impl->OpenDevice = SNDIO_OpenDevice; 362 impl->WaitDevice = SNDIO_WaitDevice; 363 impl->PlayDevice = SNDIO_PlayDevice; 364 impl->GetDeviceBuf = SNDIO_GetDeviceBuf; 365 impl->CloseDevice = SNDIO_CloseDevice; 366 impl->CaptureFromDevice = SNDIO_CaptureFromDevice; 367 impl->FlushCapture = SNDIO_FlushCapture; 368 impl->Deinitialize = SNDIO_Deinitialize; 369 370 impl->AllowsArbitraryDeviceNames = 1; 371 impl->HasCaptureSupport = SDL_TRUE; 372 373 return 1; /* this audio target is available. */ 374} 375 376AudioBootStrap SNDIO_bootstrap = { 377 "sndio", "OpenBSD sndio", SNDIO_Init, 0 378}; 379 380#endif /* SDL_AUDIO_DRIVER_SNDIO */ 381 382/* vi: set ts=4 sw=4 expandtab: */ 383[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.