185571bc7Sbellard /* 21d14ffa9Sbellard * QEMU SDL audio driver 385571bc7Sbellard * 41d14ffa9Sbellard * Copyright (c) 2004-2005 Vassili Karpov (malc) 585571bc7Sbellard * 685571bc7Sbellard * Permission is hereby granted, free of charge, to any person obtaining a copy 785571bc7Sbellard * of this software and associated documentation files (the "Software"), to deal 885571bc7Sbellard * in the Software without restriction, including without limitation the rights 985571bc7Sbellard * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 1085571bc7Sbellard * copies of the Software, and to permit persons to whom the Software is 1185571bc7Sbellard * furnished to do so, subject to the following conditions: 1285571bc7Sbellard * 1385571bc7Sbellard * The above copyright notice and this permission notice shall be included in 1485571bc7Sbellard * all copies or substantial portions of the Software. 1585571bc7Sbellard * 1685571bc7Sbellard * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1785571bc7Sbellard * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1885571bc7Sbellard * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1985571bc7Sbellard * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2085571bc7Sbellard * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 2185571bc7Sbellard * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 2285571bc7Sbellard * THE SOFTWARE. 2385571bc7Sbellard */ 249f059ecaSbellard #include <SDL.h> 259f059ecaSbellard #include <SDL_thread.h> 2685571bc7Sbellard #include "vl.h" 2785571bc7Sbellard 28*e784ba70Sths #ifndef _WIN32 29*e784ba70Sths #ifdef __sun__ 30*e784ba70Sths #define _POSIX_PTHREAD_SEMANTICS 1 31*e784ba70Sths #endif 32*e784ba70Sths #include <signal.h> 33*e784ba70Sths #endif 34*e784ba70Sths 351d14ffa9Sbellard #define AUDIO_CAP "sdl" 361d14ffa9Sbellard #include "audio_int.h" 37fb065187Sbellard 381d14ffa9Sbellard typedef struct SDLVoiceOut { 391d14ffa9Sbellard HWVoiceOut hw; 401d14ffa9Sbellard int live; 411d14ffa9Sbellard int rpos; 421d14ffa9Sbellard int decr; 431d14ffa9Sbellard } SDLVoiceOut; 4485571bc7Sbellard 4585571bc7Sbellard static struct { 4685571bc7Sbellard int nb_samples; 4785571bc7Sbellard } conf = { 4885571bc7Sbellard 1024 4985571bc7Sbellard }; 5085571bc7Sbellard 5185571bc7Sbellard struct SDLAudioState { 5285571bc7Sbellard int exit; 5385571bc7Sbellard SDL_mutex *mutex; 5485571bc7Sbellard SDL_sem *sem; 5585571bc7Sbellard int initialized; 5685571bc7Sbellard } glob_sdl; 5785571bc7Sbellard typedef struct SDLAudioState SDLAudioState; 5885571bc7Sbellard 591d14ffa9Sbellard static void GCC_FMT_ATTR (1, 2) sdl_logerr (const char *fmt, ...) 6085571bc7Sbellard { 611d14ffa9Sbellard va_list ap; 621d14ffa9Sbellard 631d14ffa9Sbellard va_start (ap, fmt); 641d14ffa9Sbellard AUD_vlog (AUDIO_CAP, fmt, ap); 651d14ffa9Sbellard va_end (ap); 661d14ffa9Sbellard 671d14ffa9Sbellard AUD_log (AUDIO_CAP, "Reason: %s\n", SDL_GetError ()); 6885571bc7Sbellard } 6985571bc7Sbellard 701d14ffa9Sbellard static int sdl_lock (SDLAudioState *s, const char *forfn) 7185571bc7Sbellard { 7285571bc7Sbellard if (SDL_LockMutex (s->mutex)) { 731d14ffa9Sbellard sdl_logerr ("SDL_LockMutex for %s failed\n", forfn); 7485571bc7Sbellard return -1; 7585571bc7Sbellard } 7685571bc7Sbellard return 0; 7785571bc7Sbellard } 7885571bc7Sbellard 791d14ffa9Sbellard static int sdl_unlock (SDLAudioState *s, const char *forfn) 8085571bc7Sbellard { 8185571bc7Sbellard if (SDL_UnlockMutex (s->mutex)) { 821d14ffa9Sbellard sdl_logerr ("SDL_UnlockMutex for %s failed\n", forfn); 8385571bc7Sbellard return -1; 8485571bc7Sbellard } 8585571bc7Sbellard return 0; 8685571bc7Sbellard } 8785571bc7Sbellard 881d14ffa9Sbellard static int sdl_post (SDLAudioState *s, const char *forfn) 8985571bc7Sbellard { 9085571bc7Sbellard if (SDL_SemPost (s->sem)) { 911d14ffa9Sbellard sdl_logerr ("SDL_SemPost for %s failed\n", forfn); 9285571bc7Sbellard return -1; 9385571bc7Sbellard } 9485571bc7Sbellard return 0; 9585571bc7Sbellard } 9685571bc7Sbellard 971d14ffa9Sbellard static int sdl_wait (SDLAudioState *s, const char *forfn) 9885571bc7Sbellard { 9985571bc7Sbellard if (SDL_SemWait (s->sem)) { 1001d14ffa9Sbellard sdl_logerr ("SDL_SemWait for %s failed\n", forfn); 10185571bc7Sbellard return -1; 10285571bc7Sbellard } 10385571bc7Sbellard return 0; 10485571bc7Sbellard } 10585571bc7Sbellard 1061d14ffa9Sbellard static int sdl_unlock_and_post (SDLAudioState *s, const char *forfn) 10785571bc7Sbellard { 1081d14ffa9Sbellard if (sdl_unlock (s, forfn)) { 10985571bc7Sbellard return -1; 11085571bc7Sbellard } 11185571bc7Sbellard 1121d14ffa9Sbellard return sdl_post (s, forfn); 11385571bc7Sbellard } 11485571bc7Sbellard 1151d14ffa9Sbellard static int aud_to_sdlfmt (audfmt_e fmt, int *shift) 11685571bc7Sbellard { 1171d14ffa9Sbellard switch (fmt) { 1181d14ffa9Sbellard case AUD_FMT_S8: 11985571bc7Sbellard *shift = 0; 1201d14ffa9Sbellard return AUDIO_S8; 1211d14ffa9Sbellard 1221d14ffa9Sbellard case AUD_FMT_U8: 1231d14ffa9Sbellard *shift = 0; 1241d14ffa9Sbellard return AUDIO_U8; 1251d14ffa9Sbellard 1261d14ffa9Sbellard case AUD_FMT_S16: 1271d14ffa9Sbellard *shift = 1; 1281d14ffa9Sbellard return AUDIO_S16LSB; 1291d14ffa9Sbellard 1301d14ffa9Sbellard case AUD_FMT_U16: 1311d14ffa9Sbellard *shift = 1; 1321d14ffa9Sbellard return AUDIO_U16LSB; 1331d14ffa9Sbellard 13485571bc7Sbellard default: 1351d14ffa9Sbellard dolog ("Internal logic error: Bad audio format %d\n", fmt); 1361d14ffa9Sbellard #ifdef DEBUG_AUDIO 1371d14ffa9Sbellard abort (); 1381d14ffa9Sbellard #endif 1391d14ffa9Sbellard return AUDIO_U8; 14085571bc7Sbellard } 14185571bc7Sbellard } 14285571bc7Sbellard 1431d14ffa9Sbellard static int sdl_to_audfmt (int sdlfmt, audfmt_e *fmt, int *endianess) 14485571bc7Sbellard { 1451d14ffa9Sbellard switch (sdlfmt) { 1461d14ffa9Sbellard case AUDIO_S8: 1471d14ffa9Sbellard *endianess = 0; 1481d14ffa9Sbellard *fmt = AUD_FMT_S8; 1491d14ffa9Sbellard break; 1501d14ffa9Sbellard 1511d14ffa9Sbellard case AUDIO_U8: 1521d14ffa9Sbellard *endianess = 0; 1531d14ffa9Sbellard *fmt = AUD_FMT_U8; 1541d14ffa9Sbellard break; 1551d14ffa9Sbellard 1561d14ffa9Sbellard case AUDIO_S16LSB: 1571d14ffa9Sbellard *endianess = 0; 1581d14ffa9Sbellard *fmt = AUD_FMT_S16; 1591d14ffa9Sbellard break; 1601d14ffa9Sbellard 1611d14ffa9Sbellard case AUDIO_U16LSB: 1621d14ffa9Sbellard *endianess = 0; 1631d14ffa9Sbellard *fmt = AUD_FMT_U16; 1641d14ffa9Sbellard break; 1651d14ffa9Sbellard 1661d14ffa9Sbellard case AUDIO_S16MSB: 1671d14ffa9Sbellard *endianess = 1; 1681d14ffa9Sbellard *fmt = AUD_FMT_S16; 1691d14ffa9Sbellard break; 1701d14ffa9Sbellard 1711d14ffa9Sbellard case AUDIO_U16MSB: 1721d14ffa9Sbellard *endianess = 1; 1731d14ffa9Sbellard *fmt = AUD_FMT_U16; 1741d14ffa9Sbellard break; 1751d14ffa9Sbellard 17685571bc7Sbellard default: 1771d14ffa9Sbellard dolog ("Unrecognized SDL audio format %d\n", sdlfmt); 1781d14ffa9Sbellard return -1; 17985571bc7Sbellard } 1801d14ffa9Sbellard 1811d14ffa9Sbellard return 0; 18285571bc7Sbellard } 18385571bc7Sbellard 18485571bc7Sbellard static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt) 18585571bc7Sbellard { 18685571bc7Sbellard int status; 187*e784ba70Sths #ifndef _WIN32 188*e784ba70Sths sigset_t new, old; 189*e784ba70Sths 190*e784ba70Sths /* Make sure potential threads created by SDL don't hog signals. */ 191*e784ba70Sths sigfillset (&new); 192*e784ba70Sths pthread_sigmask (SIG_BLOCK, &new, &old); 193*e784ba70Sths #endif 19485571bc7Sbellard 19585571bc7Sbellard status = SDL_OpenAudio (req, obt); 19685571bc7Sbellard if (status) { 1971d14ffa9Sbellard sdl_logerr ("SDL_OpenAudio failed\n"); 19885571bc7Sbellard } 199*e784ba70Sths 200*e784ba70Sths #ifndef _WIN32 201*e784ba70Sths pthread_sigmask (SIG_SETMASK, &old, 0); 202*e784ba70Sths #endif 20385571bc7Sbellard return status; 20485571bc7Sbellard } 20585571bc7Sbellard 20685571bc7Sbellard static void sdl_close (SDLAudioState *s) 20785571bc7Sbellard { 20885571bc7Sbellard if (s->initialized) { 2091d14ffa9Sbellard sdl_lock (s, "sdl_close"); 21085571bc7Sbellard s->exit = 1; 2111d14ffa9Sbellard sdl_unlock_and_post (s, "sdl_close"); 21285571bc7Sbellard SDL_PauseAudio (1); 21385571bc7Sbellard SDL_CloseAudio (); 21485571bc7Sbellard s->initialized = 0; 21585571bc7Sbellard } 21685571bc7Sbellard } 21785571bc7Sbellard 21885571bc7Sbellard static void sdl_callback (void *opaque, Uint8 *buf, int len) 21985571bc7Sbellard { 2201d14ffa9Sbellard SDLVoiceOut *sdl = opaque; 22185571bc7Sbellard SDLAudioState *s = &glob_sdl; 2221d14ffa9Sbellard HWVoiceOut *hw = &sdl->hw; 2231d14ffa9Sbellard int samples = len >> hw->info.shift; 22485571bc7Sbellard 22585571bc7Sbellard if (s->exit) { 22685571bc7Sbellard return; 22785571bc7Sbellard } 22885571bc7Sbellard 22985571bc7Sbellard while (samples) { 2301d14ffa9Sbellard int to_mix, decr; 23185571bc7Sbellard 23285571bc7Sbellard /* dolog ("in callback samples=%d\n", samples); */ 2331d14ffa9Sbellard sdl_wait (s, "sdl_callback"); 23485571bc7Sbellard if (s->exit) { 23585571bc7Sbellard return; 23685571bc7Sbellard } 23785571bc7Sbellard 2381d14ffa9Sbellard if (sdl_lock (s, "sdl_callback")) { 2391d14ffa9Sbellard return; 2401d14ffa9Sbellard } 2411d14ffa9Sbellard 2421d14ffa9Sbellard if (audio_bug (AUDIO_FUNC, sdl->live < 0 || sdl->live > hw->samples)) { 2431d14ffa9Sbellard dolog ("sdl->live=%d hw->samples=%d\n", 2441d14ffa9Sbellard sdl->live, hw->samples); 2451d14ffa9Sbellard return; 2461d14ffa9Sbellard } 2471d14ffa9Sbellard 2481d14ffa9Sbellard if (!sdl->live) { 24985571bc7Sbellard goto again; 2501d14ffa9Sbellard } 25185571bc7Sbellard 25285571bc7Sbellard /* dolog ("in callback live=%d\n", live); */ 2531d14ffa9Sbellard to_mix = audio_MIN (samples, sdl->live); 25485571bc7Sbellard decr = to_mix; 25585571bc7Sbellard while (to_mix) { 25685571bc7Sbellard int chunk = audio_MIN (to_mix, hw->samples - hw->rpos); 25785571bc7Sbellard st_sample_t *src = hw->mix_buf + hw->rpos; 25885571bc7Sbellard 25985571bc7Sbellard /* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */ 26085571bc7Sbellard hw->clip (buf, src, chunk); 2611d14ffa9Sbellard sdl->rpos = (sdl->rpos + chunk) % hw->samples; 26285571bc7Sbellard to_mix -= chunk; 2631d14ffa9Sbellard buf += chunk << hw->info.shift; 26485571bc7Sbellard } 26585571bc7Sbellard samples -= decr; 2661d14ffa9Sbellard sdl->live -= decr; 2671d14ffa9Sbellard sdl->decr += decr; 26885571bc7Sbellard 26985571bc7Sbellard again: 2701d14ffa9Sbellard if (sdl_unlock (s, "sdl_callback")) { 2711d14ffa9Sbellard return; 2721d14ffa9Sbellard } 27385571bc7Sbellard } 27485571bc7Sbellard /* dolog ("done len=%d\n", len); */ 27585571bc7Sbellard } 27685571bc7Sbellard 2771d14ffa9Sbellard static int sdl_write_out (SWVoiceOut *sw, void *buf, int len) 27885571bc7Sbellard { 2791d14ffa9Sbellard return audio_pcm_sw_write (sw, buf, len); 2801d14ffa9Sbellard } 2811d14ffa9Sbellard 2821d14ffa9Sbellard static int sdl_run_out (HWVoiceOut *hw) 2831d14ffa9Sbellard { 2841d14ffa9Sbellard int decr, live; 2851d14ffa9Sbellard SDLVoiceOut *sdl = (SDLVoiceOut *) hw; 2861d14ffa9Sbellard SDLAudioState *s = &glob_sdl; 2871d14ffa9Sbellard 2881d14ffa9Sbellard if (sdl_lock (s, "sdl_callback")) { 2891d14ffa9Sbellard return 0; 2901d14ffa9Sbellard } 2911d14ffa9Sbellard 2921d14ffa9Sbellard live = audio_pcm_hw_get_live_out (hw); 2931d14ffa9Sbellard 2941d14ffa9Sbellard if (sdl->decr > live) { 2951d14ffa9Sbellard ldebug ("sdl->decr %d live %d sdl->live %d\n", 2961d14ffa9Sbellard sdl->decr, 2971d14ffa9Sbellard live, 2981d14ffa9Sbellard sdl->live); 2991d14ffa9Sbellard } 3001d14ffa9Sbellard 3011d14ffa9Sbellard decr = audio_MIN (sdl->decr, live); 3021d14ffa9Sbellard sdl->decr -= decr; 3031d14ffa9Sbellard 3041d14ffa9Sbellard sdl->live = live - decr; 3051d14ffa9Sbellard hw->rpos = sdl->rpos; 3061d14ffa9Sbellard 3071d14ffa9Sbellard if (sdl->live > 0) { 3081d14ffa9Sbellard sdl_unlock_and_post (s, "sdl_callback"); 3091d14ffa9Sbellard } 3101d14ffa9Sbellard else { 3111d14ffa9Sbellard sdl_unlock (s, "sdl_callback"); 3121d14ffa9Sbellard } 3131d14ffa9Sbellard return decr; 3141d14ffa9Sbellard } 3151d14ffa9Sbellard 3161d14ffa9Sbellard static void sdl_fini_out (HWVoiceOut *hw) 3171d14ffa9Sbellard { 3181d14ffa9Sbellard (void) hw; 3191d14ffa9Sbellard 32085571bc7Sbellard sdl_close (&glob_sdl); 32185571bc7Sbellard } 32285571bc7Sbellard 323c0fe3827Sbellard static int sdl_init_out (HWVoiceOut *hw, audsettings_t *as) 32485571bc7Sbellard { 3251d14ffa9Sbellard SDLVoiceOut *sdl = (SDLVoiceOut *) hw; 32685571bc7Sbellard SDLAudioState *s = &glob_sdl; 32785571bc7Sbellard SDL_AudioSpec req, obt; 32885571bc7Sbellard int shift; 3291d14ffa9Sbellard int endianess; 3301d14ffa9Sbellard int err; 3311d14ffa9Sbellard audfmt_e effective_fmt; 332c0fe3827Sbellard audsettings_t obt_as; 33385571bc7Sbellard 334c0fe3827Sbellard shift <<= as->nchannels == 2; 33585571bc7Sbellard 336c0fe3827Sbellard req.freq = as->freq; 337c0fe3827Sbellard req.format = aud_to_sdlfmt (as->fmt, &shift); 338c0fe3827Sbellard req.channels = as->nchannels; 33985571bc7Sbellard req.samples = conf.nb_samples; 34085571bc7Sbellard req.callback = sdl_callback; 34185571bc7Sbellard req.userdata = sdl; 34285571bc7Sbellard 3431d14ffa9Sbellard if (sdl_open (&req, &obt)) { 34485571bc7Sbellard return -1; 3451d14ffa9Sbellard } 34685571bc7Sbellard 3471d14ffa9Sbellard err = sdl_to_audfmt (obt.format, &effective_fmt, &endianess); 3481d14ffa9Sbellard if (err) { 3491d14ffa9Sbellard sdl_close (s); 3501d14ffa9Sbellard return -1; 3511d14ffa9Sbellard } 3521d14ffa9Sbellard 353c0fe3827Sbellard obt_as.freq = obt.freq; 354c0fe3827Sbellard obt_as.nchannels = obt.channels; 355c0fe3827Sbellard obt_as.fmt = effective_fmt; 356d929eba5Sbellard obt_as.endianness = endianess; 357c0fe3827Sbellard 358d929eba5Sbellard audio_pcm_init_info (&hw->info, &obt_as); 359c0fe3827Sbellard hw->samples = obt.samples; 36085571bc7Sbellard 36185571bc7Sbellard s->initialized = 1; 36285571bc7Sbellard s->exit = 0; 36385571bc7Sbellard SDL_PauseAudio (0); 36485571bc7Sbellard return 0; 36585571bc7Sbellard } 36685571bc7Sbellard 3671d14ffa9Sbellard static int sdl_ctl_out (HWVoiceOut *hw, int cmd, ...) 36885571bc7Sbellard { 36985571bc7Sbellard (void) hw; 37085571bc7Sbellard 37185571bc7Sbellard switch (cmd) { 37285571bc7Sbellard case VOICE_ENABLE: 37385571bc7Sbellard SDL_PauseAudio (0); 37485571bc7Sbellard break; 37585571bc7Sbellard 37685571bc7Sbellard case VOICE_DISABLE: 37785571bc7Sbellard SDL_PauseAudio (1); 37885571bc7Sbellard break; 37985571bc7Sbellard } 38085571bc7Sbellard return 0; 38185571bc7Sbellard } 38285571bc7Sbellard 38385571bc7Sbellard static void *sdl_audio_init (void) 38485571bc7Sbellard { 38585571bc7Sbellard SDLAudioState *s = &glob_sdl; 38685571bc7Sbellard 38785571bc7Sbellard if (SDL_InitSubSystem (SDL_INIT_AUDIO)) { 3881d14ffa9Sbellard sdl_logerr ("SDL failed to initialize audio subsystem\n"); 38985571bc7Sbellard return NULL; 39085571bc7Sbellard } 39185571bc7Sbellard 39285571bc7Sbellard s->mutex = SDL_CreateMutex (); 39385571bc7Sbellard if (!s->mutex) { 3941d14ffa9Sbellard sdl_logerr ("Failed to create SDL mutex\n"); 39585571bc7Sbellard SDL_QuitSubSystem (SDL_INIT_AUDIO); 39685571bc7Sbellard return NULL; 39785571bc7Sbellard } 39885571bc7Sbellard 39985571bc7Sbellard s->sem = SDL_CreateSemaphore (0); 40085571bc7Sbellard if (!s->sem) { 4011d14ffa9Sbellard sdl_logerr ("Failed to create SDL semaphore\n"); 40285571bc7Sbellard SDL_DestroyMutex (s->mutex); 40385571bc7Sbellard SDL_QuitSubSystem (SDL_INIT_AUDIO); 40485571bc7Sbellard return NULL; 40585571bc7Sbellard } 40685571bc7Sbellard 40785571bc7Sbellard return s; 40885571bc7Sbellard } 40985571bc7Sbellard 41085571bc7Sbellard static void sdl_audio_fini (void *opaque) 41185571bc7Sbellard { 41285571bc7Sbellard SDLAudioState *s = opaque; 41385571bc7Sbellard sdl_close (s); 41485571bc7Sbellard SDL_DestroySemaphore (s->sem); 41585571bc7Sbellard SDL_DestroyMutex (s->mutex); 41685571bc7Sbellard SDL_QuitSubSystem (SDL_INIT_AUDIO); 41785571bc7Sbellard } 41885571bc7Sbellard 4191d14ffa9Sbellard static struct audio_option sdl_options[] = { 4201d14ffa9Sbellard {"SAMPLES", AUD_OPT_INT, &conf.nb_samples, 4211d14ffa9Sbellard "Size of SDL buffer in samples", NULL, 0}, 4221d14ffa9Sbellard {NULL, 0, NULL, NULL, NULL, 0} 42385571bc7Sbellard }; 42485571bc7Sbellard 4251d14ffa9Sbellard static struct audio_pcm_ops sdl_pcm_ops = { 4261d14ffa9Sbellard sdl_init_out, 4271d14ffa9Sbellard sdl_fini_out, 4281d14ffa9Sbellard sdl_run_out, 4291d14ffa9Sbellard sdl_write_out, 4301d14ffa9Sbellard sdl_ctl_out, 4311d14ffa9Sbellard 4321d14ffa9Sbellard NULL, 4331d14ffa9Sbellard NULL, 4341d14ffa9Sbellard NULL, 4351d14ffa9Sbellard NULL, 4361d14ffa9Sbellard NULL 4371d14ffa9Sbellard }; 4381d14ffa9Sbellard 4391d14ffa9Sbellard struct audio_driver sdl_audio_driver = { 4401d14ffa9Sbellard INIT_FIELD (name = ) "sdl", 4411d14ffa9Sbellard INIT_FIELD (descr = ) "SDL http://www.libsdl.org", 4421d14ffa9Sbellard INIT_FIELD (options = ) sdl_options, 4431d14ffa9Sbellard INIT_FIELD (init = ) sdl_audio_init, 4441d14ffa9Sbellard INIT_FIELD (fini = ) sdl_audio_fini, 4451d14ffa9Sbellard INIT_FIELD (pcm_ops = ) &sdl_pcm_ops, 4461d14ffa9Sbellard INIT_FIELD (can_be_default = ) 1, 4471d14ffa9Sbellard INIT_FIELD (max_voices_out = ) 1, 4481d14ffa9Sbellard INIT_FIELD (max_voices_in = ) 0, 4491d14ffa9Sbellard INIT_FIELD (voice_size_out = ) sizeof (SDLVoiceOut), 4501d14ffa9Sbellard INIT_FIELD (voice_size_in = ) 0 45185571bc7Sbellard }; 452