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