cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

SDL_sndioaudio.c (9010B)


      1/*
      2  Simple DirectMedia Layer
      3  Copyright (C) 1997-2014 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
     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 <unistd.h>
     37
     38#include "SDL_audio.h"
     39#include "../SDL_audiomem.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
     47static struct sio_hdl * (*SNDIO_sio_open)(const char *, unsigned int, int);
     48static void (*SNDIO_sio_close)(struct sio_hdl *);
     49static int (*SNDIO_sio_setpar)(struct sio_hdl *, struct sio_par *);
     50static int (*SNDIO_sio_getpar)(struct sio_hdl *, struct sio_par *);
     51static int (*SNDIO_sio_start)(struct sio_hdl *);
     52static int (*SNDIO_sio_stop)(struct sio_hdl *);
     53static size_t (*SNDIO_sio_read)(struct sio_hdl *, void *, size_t);
     54static size_t (*SNDIO_sio_write)(struct sio_hdl *, const void *, size_t);
     55static void (*SNDIO_sio_initpar)(struct sio_par *);
     56
     57#ifdef SDL_AUDIO_DRIVER_SNDIO_DYNAMIC
     58static const char *sndio_library = SDL_AUDIO_DRIVER_SNDIO_DYNAMIC;
     59static void *sndio_handle = NULL;
     60
     61static int
     62load_sndio_sym(const char *fn, void **addr)
     63{
     64    *addr = SDL_LoadFunction(sndio_handle, fn);
     65    if (*addr == NULL) {
     66        /* Don't call SDL_SetError(): SDL_LoadFunction already did. */
     67        return 0;
     68    }
     69
     70    return 1;
     71}
     72
     73/* cast funcs to char* first, to please GCC's strict aliasing rules. */
     74#define SDL_SNDIO_SYM(x) \
     75    if (!load_sndio_sym(#x, (void **) (char *) &SNDIO_##x)) return -1
     76#else
     77#define SDL_SNDIO_SYM(x) SNDIO_##x = x
     78#endif
     79
     80static int
     81load_sndio_syms(void)
     82{
     83    SDL_SNDIO_SYM(sio_open);
     84    SDL_SNDIO_SYM(sio_close);
     85    SDL_SNDIO_SYM(sio_setpar);
     86    SDL_SNDIO_SYM(sio_getpar);
     87    SDL_SNDIO_SYM(sio_start);
     88    SDL_SNDIO_SYM(sio_stop);
     89    SDL_SNDIO_SYM(sio_read);
     90    SDL_SNDIO_SYM(sio_write);
     91    SDL_SNDIO_SYM(sio_initpar);
     92    return 0;
     93}
     94
     95#undef SDL_SNDIO_SYM
     96
     97#ifdef SDL_AUDIO_DRIVER_SNDIO_DYNAMIC
     98
     99static void
    100UnloadSNDIOLibrary(void)
    101{
    102    if (sndio_handle != NULL) {
    103        SDL_UnloadObject(sndio_handle);
    104        sndio_handle = NULL;
    105    }
    106}
    107
    108static int
    109LoadSNDIOLibrary(void)
    110{
    111    int retval = 0;
    112    if (sndio_handle == NULL) {
    113        sndio_handle = SDL_LoadObject(sndio_library);
    114        if (sndio_handle == NULL) {
    115            retval = -1;
    116            /* Don't call SDL_SetError(): SDL_LoadObject already did. */
    117        } else {
    118            retval = load_sndio_syms();
    119            if (retval < 0) {
    120                UnloadSNDIOLibrary();
    121            }
    122        }
    123    }
    124    return retval;
    125}
    126
    127#else
    128
    129static void
    130UnloadSNDIOLibrary(void)
    131{
    132}
    133
    134static int
    135LoadSNDIOLibrary(void)
    136{
    137    load_sndio_syms();
    138    return 0;
    139}
    140
    141#endif /* SDL_AUDIO_DRIVER_SNDIO_DYNAMIC */
    142
    143
    144
    145
    146static void
    147SNDIO_WaitDevice(_THIS)
    148{
    149    /* no-op; SNDIO_sio_write() blocks if necessary. */
    150}
    151
    152static void
    153SNDIO_PlayDevice(_THIS)
    154{
    155    const int written = SNDIO_sio_write(this->hidden->dev,
    156                                        this->hidden->mixbuf,
    157                                        this->hidden->mixlen);
    158
    159    /* If we couldn't write, assume fatal error for now */
    160    if ( written == 0 ) {
    161        this->enabled = 0;
    162    }
    163#ifdef DEBUG_AUDIO
    164    fprintf(stderr, "Wrote %d bytes of audio data\n", written);
    165#endif
    166}
    167
    168static Uint8 *
    169SNDIO_GetDeviceBuf(_THIS)
    170{
    171    return this->hidden->mixbuf;
    172}
    173
    174static void
    175SNDIO_WaitDone(_THIS)
    176{
    177    SNDIO_sio_stop(this->hidden->dev);
    178}
    179
    180static void
    181SNDIO_CloseDevice(_THIS)
    182{
    183    if (this->hidden != NULL) {
    184        SDL_FreeAudioMem(this->hidden->mixbuf);
    185        this->hidden->mixbuf = NULL;
    186        if ( this->hidden->dev != NULL ) {
    187            SNDIO_sio_close(this->hidden->dev);
    188            this->hidden->dev = NULL;
    189        }
    190        SDL_free(this->hidden);
    191        this->hidden = NULL;
    192    }
    193}
    194
    195static int
    196SNDIO_OpenDevice(_THIS, const char *devname, int iscapture)
    197{
    198    SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
    199    struct sio_par par;
    200    int status;
    201
    202    this->hidden = (struct SDL_PrivateAudioData *)
    203        SDL_malloc(sizeof(*this->hidden));
    204    if (this->hidden == NULL) {
    205        return SDL_OutOfMemory();
    206    }
    207    SDL_memset(this->hidden, 0, sizeof(*this->hidden));
    208
    209    this->hidden->mixlen = this->spec.size;
    210
    211    /* !!! FIXME: SIO_DEVANY can be a specific device... */
    212    if ((this->hidden->dev = SNDIO_sio_open(SIO_DEVANY, SIO_PLAY, 0)) == NULL) {
    213        SNDIO_CloseDevice(this);
    214        return SDL_SetError("sio_open() failed");
    215    }
    216
    217    SNDIO_sio_initpar(&par);
    218
    219    par.rate = this->spec.freq;
    220    par.pchan = this->spec.channels;
    221    par.round = this->spec.samples;
    222    par.appbufsz = par.round * 2;
    223
    224    /* Try for a closest match on audio format */
    225    status = -1;
    226    while (test_format && (status < 0)) {
    227        if (!SDL_AUDIO_ISFLOAT(test_format)) {
    228            par.le = SDL_AUDIO_ISLITTLEENDIAN(test_format) ? 1 : 0;
    229            par.sig = SDL_AUDIO_ISSIGNED(test_format) ? 1 : 0;
    230            par.bits = SDL_AUDIO_BITSIZE(test_format);
    231
    232            if (SNDIO_sio_setpar(this->hidden->dev, &par) == 0) {
    233                continue;
    234            }
    235            if (SNDIO_sio_getpar(this->hidden->dev, &par) == 0) {
    236                SNDIO_CloseDevice(this);
    237                return SDL_SetError("sio_getpar() failed");
    238            }
    239            if (par.bps != SIO_BPS(par.bits)) {
    240                continue;
    241            }
    242            if ((par.bits == 8 * par.bps) || (par.msb)) {
    243                status = 0;
    244                break;
    245            }
    246        }
    247        test_format = SDL_NextAudioFormat();
    248    }
    249
    250    if (status < 0) {
    251        SNDIO_CloseDevice(this);
    252        return SDL_SetError("sndio: Couldn't find any hardware audio formats");
    253    }
    254
    255    if ((par.bps == 4) && (par.sig) && (par.le))
    256        this->spec.format = AUDIO_S32LSB;
    257    else if ((par.bps == 4) && (par.sig) && (!par.le))
    258        this->spec.format = AUDIO_S32MSB;
    259    else if ((par.bps == 2) && (par.sig) && (par.le))
    260        this->spec.format = AUDIO_S16LSB;
    261    else if ((par.bps == 2) && (par.sig) && (!par.le))
    262        this->spec.format = AUDIO_S16MSB;
    263    else if ((par.bps == 2) && (!par.sig) && (par.le))
    264        this->spec.format = AUDIO_U16LSB;
    265    else if ((par.bps == 2) && (!par.sig) && (!par.le))
    266        this->spec.format = AUDIO_U16MSB;
    267    else if ((par.bps == 1) && (par.sig))
    268        this->spec.format = AUDIO_S8;
    269    else if ((par.bps == 1) && (!par.sig))
    270        this->spec.format = AUDIO_U8;
    271    else {
    272        SNDIO_CloseDevice(this);
    273        return SDL_SetError("sndio: Got unsupported hardware audio format.");
    274    }
    275
    276    this->spec.freq = par.rate;
    277    this->spec.channels = par.pchan;
    278    this->spec.samples = par.round;
    279
    280    /* Calculate the final parameters for this audio specification */
    281    SDL_CalculateAudioSpec(&this->spec);
    282
    283    /* Allocate mixing buffer */
    284    this->hidden->mixlen = this->spec.size;
    285    this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
    286    if (this->hidden->mixbuf == NULL) {
    287        SNDIO_CloseDevice(this);
    288        return SDL_OutOfMemory();
    289    }
    290    SDL_memset(this->hidden->mixbuf, this->spec.silence, this->hidden->mixlen);
    291
    292    if (!SNDIO_sio_start(this->hidden->dev)) {
    293        return SDL_SetError("sio_start() failed");
    294    }
    295
    296    /* We're ready to rock and roll. :-) */
    297    return 0;
    298}
    299
    300static void
    301SNDIO_Deinitialize(void)
    302{
    303    UnloadSNDIOLibrary();
    304}
    305
    306static int
    307SNDIO_Init(SDL_AudioDriverImpl * impl)
    308{
    309    if (LoadSNDIOLibrary() < 0) {
    310        return 0;
    311    }
    312
    313    /* Set the function pointers */
    314    impl->OpenDevice = SNDIO_OpenDevice;
    315    impl->WaitDevice = SNDIO_WaitDevice;
    316    impl->PlayDevice = SNDIO_PlayDevice;
    317    impl->GetDeviceBuf = SNDIO_GetDeviceBuf;
    318    impl->WaitDone = SNDIO_WaitDone;
    319    impl->CloseDevice = SNDIO_CloseDevice;
    320    impl->Deinitialize = SNDIO_Deinitialize;
    321    impl->OnlyHasDefaultOutputDevice = 1;  /* !!! FIXME: sndio can handle multiple devices. */
    322
    323    return 1;   /* this audio target is available. */
    324}
    325
    326AudioBootStrap SNDIO_bootstrap = {
    327    "sndio", "OpenBSD sndio", SNDIO_Init, 0
    328};
    329
    330#endif /* SDL_AUDIO_DRIVER_SNDIO */
    331
    332/* vi: set ts=4 sw=4 expandtab: */