1 /* 2 * Copyright (c) 2008 Jacob Meuser <jakemsr@sdf.lonestar.org> 3 * 4 * Permission to use, copy, modify, and distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 #include "SDL_config.h" 18 19 /* Allow access to a raw mixing buffer */ 20 21 #ifdef HAVE_SIGNAL_H 22 #include <signal.h> 23 #endif 24 #include <unistd.h> 25 26 #include "SDL_timer.h" 27 #include "SDL_audio.h" 28 #include "../SDL_audiomem.h" 29 #include "../SDL_audio_c.h" 30 #include "../SDL_audiodev_c.h" 31 #include "SDL_sndioaudio.h" 32 33 /* The tag name used by sndio audio */ 34 #define SNDIO_DRIVER_NAME "sndio" 35 36 /* Audio driver functions */ 37 static int SNDIO_OpenAudio(_THIS, SDL_AudioSpec *spec); 38 static void SNDIO_WaitAudio(_THIS); 39 static void SNDIO_PlayAudio(_THIS); 40 static Uint8 *SNDIO_GetAudioBuf(_THIS); 41 static void SNDIO_CloseAudio(_THIS); 42 43 /* Audio driver bootstrap functions */ 44 45 static int Audio_Available(void) 46 { 47 struct sio_hdl *this_hdl; 48 int available = 0; 49 50 if ( (this_hdl = sio_open(SIO_DEVANY, SIO_PLAY, 0)) != NULL ) { 51 sio_close(this_hdl); 52 available = 1; 53 } 54 55 return available; 56 } 57 58 static void Audio_DeleteDevice(SDL_AudioDevice *device) 59 { 60 SDL_free(device->hidden); 61 SDL_free(device); 62 } 63 64 static SDL_AudioDevice *Audio_CreateDevice(int devindex) 65 { 66 SDL_AudioDevice *this; 67 68 /* Initialize all variables that we clean on shutdown */ 69 this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice)); 70 if ( this ) { 71 SDL_memset(this, 0, (sizeof *this)); 72 this->hidden = (struct SDL_PrivateAudioData *) 73 SDL_malloc((sizeof *this->hidden)); 74 } 75 if ( (this == NULL) || (this->hidden == NULL) ) { 76 SDL_OutOfMemory(); 77 if ( this ) { 78 SDL_free(this); 79 } 80 return(0); 81 } 82 SDL_memset(this->hidden, 0, (sizeof *this->hidden)); 83 84 /* Set the function pointers */ 85 this->OpenAudio = SNDIO_OpenAudio; 86 this->WaitAudio = SNDIO_WaitAudio; 87 this->PlayAudio = SNDIO_PlayAudio; 88 this->GetAudioBuf = SNDIO_GetAudioBuf; 89 this->CloseAudio = SNDIO_CloseAudio; 90 91 this->free = Audio_DeleteDevice; 92 93 hdl = NULL; 94 95 return this; 96 } 97 98 AudioBootStrap SNDIO_bootstrap = { 99 SNDIO_DRIVER_NAME, "sndio", 100 Audio_Available, Audio_CreateDevice 101 }; 102 103 104 105 /* This function waits until it is possible to write a full sound buffer */ 106 static void SNDIO_WaitAudio(_THIS) 107 { 108 /* nothing, we're using the blocking api */ 109 } 110 111 static void SNDIO_PlayAudio(_THIS) 112 { 113 int written; 114 115 /* Write the audio data */ 116 written = sio_write(hdl, mixbuf, mixlen); 117 118 /* If we couldn't write, assume fatal error for now */ 119 if ( written == 0 ) { 120 this->enabled = 0; 121 } 122 #ifdef DEBUG_AUDIO 123 fprintf(stderr, "Wrote %d bytes of audio data\n", written); 124 #endif 125 } 126 127 static Uint8 *SNDIO_GetAudioBuf(_THIS) 128 { 129 return(mixbuf); 130 } 131 132 static void SNDIO_CloseAudio(_THIS) 133 { 134 if ( mixbuf != NULL ) { 135 SDL_FreeAudioMem(mixbuf); 136 mixbuf = NULL; 137 } 138 if ( hdl != NULL ) { 139 sio_close(hdl); 140 hdl = NULL; 141 } 142 } 143 144 static int SNDIO_OpenAudio(_THIS, SDL_AudioSpec *spec) 145 { 146 struct sio_par par; 147 148 mixbuf = NULL; 149 150 if ((hdl = sio_open(NULL, SIO_PLAY, 0)) == NULL) { 151 SDL_SetError("sio_open() failed"); 152 return(-1); 153 } 154 155 sio_initpar(&par); 156 157 switch (spec->format) { 158 case AUDIO_S16LSB: 159 par.bits = 16; 160 par.sig = 1; 161 par.le = 1; 162 break; 163 case AUDIO_S16MSB: 164 par.bits = 16; 165 par.sig = 1; 166 par.le = 0; 167 break; 168 case AUDIO_S8: 169 par.bits = 8; 170 par.sig = 1; 171 break; 172 case AUDIO_U16LSB: 173 par.bits = 16; 174 par.sig = 0; 175 par.le = 1; 176 break; 177 case AUDIO_U16MSB: 178 par.bits = 16; 179 par.sig = 0; 180 par.le = 0; 181 break; 182 case AUDIO_U8: 183 par.bits = 8; 184 par.sig = 0; 185 break; 186 default: 187 SDL_SetError("SNDIO unknown format"); 188 return(-1); 189 } 190 191 par.rate = spec->freq; 192 par.pchan = spec->channels; 193 par.round = spec->samples; 194 par.appbufsz = par.round * 2; 195 196 if (sio_setpar(hdl, &par) == 0) { 197 SDL_SetError("sio_setpar() failed"); 198 return(-1); 199 } 200 201 if (sio_getpar(hdl, &par) == 0) { 202 SDL_SetError("sio_getpar() failed"); 203 return(-1); 204 } 205 206 if (par.bits == 16) { 207 if (par.sig && par.le) { 208 spec->format = AUDIO_S16LSB; 209 } else if (par.sig && !par.le) { 210 spec->format = AUDIO_S16MSB; 211 } else if (!par.sig && par.le) { 212 spec->format = AUDIO_U16LSB; 213 } else 214 spec->format = AUDIO_U16MSB; 215 } else if (par.bits == 8) { 216 spec->format = par.sig ? AUDIO_S8 : AUDIO_U8; 217 } else { 218 SDL_SetError("SNDIO couldn't configure a suitable format"); 219 return(-1); 220 } 221 222 spec->freq = par.rate; 223 spec->channels = par.pchan; 224 spec->samples = par.round; 225 226 SDL_CalculateAudioSpec(spec); 227 228 /* Allocate mixing buffer */ 229 mixlen = spec->size; 230 mixbuf = (Uint8 *)SDL_AllocAudioMem(mixlen); 231 if ( mixbuf == NULL ) { 232 return(-1); 233 } 234 SDL_memset(mixbuf, spec->silence, spec->size); 235 236 if ( sio_start(hdl) == 0 ) { 237 SDL_SetError("sio_start() failed"); 238 return(-1); 239 } 240 241 /* We're ready to rock and roll. :-) */ 242 return(0); 243 } 244