(linenum→info "unix/slp.c:2238")

qemu/0.9.1/audio/sdlaudio.c

    1: /*
    2:  * QEMU SDL audio driver
    3:  *
    4:  * Copyright (c) 2004-2005 Vassili Karpov (malc)
    5:  *
    6:  * Permission is hereby granted, free of charge, to any person obtaining a copy
    7:  * of this software and associated documentation files (the "Software"), to deal
    8:  * in the Software without restriction, including without limitation the rights
    9:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   10:  * copies of the Software, and to permit persons to whom the Software is
   11:  * furnished to do so, subject to the following conditions:
   12:  *
   13:  * The above copyright notice and this permission notice shall be included in
   14:  * all copies or substantial portions of the Software.
   15:  *
   16:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   17:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   18:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   19:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   20:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   21:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   22:  * THE SOFTWARE.
   23:  */
   24: #include <SDL.h>
   25: #include <SDL_thread.h>
   26: #include "qemu-common.h"
   27: #include "audio.h"
   28: 
   29: #ifndef _WIN32
   30: #ifdef __sun__
   31: #define _POSIX_PTHREAD_SEMANTICS 1
   32: #endif
   33: #include <signal.h>
   34: #endif
   35: 
   36: #define AUDIO_CAP "sdl"
   37: #include "audio_int.h"
   38: 
   39: typedef struct SDLVoiceOut {
   40:     HWVoiceOut hw;
   41:     int live;
   42:     int rpos;
   43:     int decr;
   44: } SDLVoiceOut;
   45: 
   46: static struct {
   47:     int nb_samples;
   48: } conf = {
   49:     1024
   50: };
   51: 
   52: struct SDLAudioState {
   53:     int exit;
   54:     SDL_mutex *mutex;
   55:     SDL_sem *sem;
   56:     int initialized;
   57: } glob_sdl;
   58: typedef struct SDLAudioState SDLAudioState;
   59: 
   60: static void GCC_FMT_ATTR (1, 2) sdl_logerr (const char *fmt, ...)
   61: {
   62:     va_list ap;
   63: 
   64:     va_start (ap, fmt);
   65:     AUD_vlog (AUDIO_CAP, fmt, ap);
   66:     va_end (ap);
   67: 
   68:     AUD_log (AUDIO_CAP, "Reason: %s\n", SDL_GetError ());
   69: }
   70: 
   71: static int sdl_lock (SDLAudioState *s, const char *forfn)
   72: {
   73:     if (SDL_LockMutex (s->mutex)) {
   74:         sdl_logerr ("SDL_LockMutex for %s failed\n", forfn);
   75:         return -1;
   76:     }
   77:     return 0;
   78: }
   79: 
   80: static int sdl_unlock (SDLAudioState *s, const char *forfn)
   81: {
   82:     if (SDL_UnlockMutex (s->mutex)) {
   83:         sdl_logerr ("SDL_UnlockMutex for %s failed\n", forfn);
   84:         return -1;
   85:     }
   86:     return 0;
   87: }
   88: 
   89: static int sdl_post (SDLAudioState *s, const char *forfn)
   90: {
   91:     if (SDL_SemPost (s->sem)) {
   92:         sdl_logerr ("SDL_SemPost for %s failed\n", forfn);
   93:         return -1;
   94:     }
   95:     return 0;
   96: }
   97: 
   98: static int sdl_wait (SDLAudioState *s, const char *forfn)
   99: {
  100:     if (SDL_SemWait (s->sem)) {
  101:         sdl_logerr ("SDL_SemWait for %s failed\n", forfn);
  102:         return -1;
  103:     }
  104:     return 0;
  105: }
  106: 
  107: static int sdl_unlock_and_post (SDLAudioState *s, const char *forfn)
  108: {
  109:     if (sdl_unlock (s, forfn)) {
  110:         return -1;
  111:     }
  112: 
  113:     return sdl_post (s, forfn);
  114: }
  115: 
  116: static int aud_to_sdlfmt (audfmt_e fmt, int *shift)
  117: {
  118:     switch (fmt) {
  119:     case AUD_FMT_S8:
  120:         *shift = 0;
  121:         return AUDIO_S8;
  122: 
  123:     case AUD_FMT_U8:
  124:         *shift = 0;
  125:         return AUDIO_U8;
  126: 
  127:     case AUD_FMT_S16:
  128:         *shift = 1;
  129:         return AUDIO_S16LSB;
  130: 
  131:     case AUD_FMT_U16:
  132:         *shift = 1;
  133:         return AUDIO_U16LSB;
  134: 
  135:     default:
  136:         dolog ("Internal logic error: Bad audio format %d\n", fmt);
  137: #ifdef DEBUG_AUDIO
  138:         abort ();
  139: #endif
  140:         return AUDIO_U8;
  141:     }
  142: }
  143: 
  144: static int sdl_to_audfmt (int sdlfmt, audfmt_e *fmt, int *endianess)
  145: {
  146:     switch (sdlfmt) {
  147:     case AUDIO_S8:
  148:         *endianess = 0;
  149:         *fmt = AUD_FMT_S8;
  150:         break;
  151: 
  152:     case AUDIO_U8:
  153:         *endianess = 0;
  154:         *fmt = AUD_FMT_U8;
  155:         break;
  156: 
  157:     case AUDIO_S16LSB:
  158:         *endianess = 0;
  159:         *fmt = AUD_FMT_S16;
  160:         break;
  161: 
  162:     case AUDIO_U16LSB:
  163:         *endianess = 0;
  164:         *fmt = AUD_FMT_U16;
  165:         break;
  166: 
  167:     case AUDIO_S16MSB:
  168:         *endianess = 1;
  169:         *fmt = AUD_FMT_S16;
  170:         break;
  171: 
  172:     case AUDIO_U16MSB:
  173:         *endianess = 1;
  174:         *fmt = AUD_FMT_U16;
  175:         break;
  176: 
  177:     default:
  178:         dolog ("Unrecognized SDL audio format %d\n", sdlfmt);
  179:         return -1;
  180:     }
  181: 
  182:     return 0;
  183: }
  184: 
  185: static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt)
  186: {
  187:     int status;
  188: #ifndef _WIN32
  189:     sigset_t new, old;
  190: 
  191:     /* Make sure potential threads created by SDL don't hog signals.  */
  192:     sigfillset (&new);
  193:     pthread_sigmask (SIG_BLOCK, &new, &old);
  194: #endif
  195: 
  196:     status = SDL_OpenAudio (req, obt);
  197:     if (status) {
  198:         sdl_logerr ("SDL_OpenAudio failed\n");
  199:     }
  200: 
  201: #ifndef _WIN32
  202:     pthread_sigmask (SIG_SETMASK, &old, 0);
  203: #endif
  204:     return status;
  205: }
  206: 
  207: static void sdl_close (SDLAudioState *s)
  208: {
  209:     if (s->initialized) {
  210:         sdl_lock (s, "sdl_close");
  211:         s->exit = 1;
  212:         sdl_unlock_and_post (s, "sdl_close");
  213:         SDL_PauseAudio (1);
  214:         SDL_CloseAudio ();
  215:         s->initialized = 0;
  216:     }
  217: }
  218: 
  219: static void sdl_callback (void *opaque, Uint8 *buf, int len)
  220: {
  221:     SDLVoiceOut *sdl = opaque;
  222:     SDLAudioState *s = &glob_sdl;
  223:     HWVoiceOut *hw = &sdl->hw;
  224:     int samples = len >> hw->info.shift;
  225: 
  226:     if (s->exit) {
  227:         return;
  228:     }
  229: 
  230:     while (samples) {
  231:         int to_mix, decr;
  232: 
  233:         /* dolog ("in callback samples=%d\n", samples); */
  234:         sdl_wait (s, "sdl_callback");
  235:         if (s->exit) {
  236:             return;
  237:         }
  238: 
  239:         if (sdl_lock (s, "sdl_callback")) {
  240:             return;
  241:         }
  242: 
  243:         if (audio_bug (AUDIO_FUNC, sdl->live < 0 || sdl->live > hw->samples)) {
  244:             dolog ("sdl->live=%d hw->samples=%d\n",
  245:                    sdl->live, hw->samples);
  246:             return;
  247:         }
  248: 
  249:         if (!sdl->live) {
  250:             goto again;
  251:         }
  252: 
  253:         /* dolog ("in callback live=%d\n", live); */
  254:         to_mix = audio_MIN (samples, sdl->live);
  255:         decr = to_mix;
  256:         while (to_mix) {
  257:             int chunk = audio_MIN (to_mix, hw->samples - hw->rpos);
  258:             st_sample_t *src = hw->mix_buf + hw->rpos;
  259: 
  260:             /* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */
  261:             hw->clip (buf, src, chunk);
  262:             sdl->rpos = (sdl->rpos + chunk) % hw->samples;
  263:             to_mix -= chunk;
  264:             buf += chunk << hw->info.shift;
  265:         }
  266:         samples -= decr;
  267:         sdl->live -= decr;
  268:         sdl->decr += decr;
  269: 
  270:     again:
  271:         if (sdl_unlock (s, "sdl_callback")) {
  272:             return;
  273:         }
  274:     }
  275:     /* dolog ("done len=%d\n", len); */
  276: }
  277: 
  278: static int sdl_write_out (SWVoiceOut *sw, void *buf, int len)
  279: {
  280:     return audio_pcm_sw_write (sw, buf, len);
  281: }
  282: 
  283: static int sdl_run_out (HWVoiceOut *hw)
  284: {
  285:     int decr, live;
  286:     SDLVoiceOut *sdl = (SDLVoiceOut *) hw;
  287:     SDLAudioState *s = &glob_sdl;
  288: 
  289:     if (sdl_lock (s, "sdl_callback")) {
  290:         return 0;
  291:     }
  292: 
  293:     live = audio_pcm_hw_get_live_out (hw);
  294: 
  295:     if (sdl->decr > live) {
  296:         ldebug ("sdl->decr %d live %d sdl->live %d\n",
  297:                 sdl->decr,
  298:                 live,
  299:                 sdl->live);
  300:     }
  301: 
  302:     decr = audio_MIN (sdl->decr, live);
  303:     sdl->decr -= decr;
  304: 
  305:     sdl->live = live - decr;
  306:     hw->rpos = sdl->rpos;
  307: 
  308:     if (sdl->live > 0) {
  309:         sdl_unlock_and_post (s, "sdl_callback");
  310:     }
  311:     else {
  312:         sdl_unlock (s, "sdl_callback");
  313:     }
  314:     return decr;
  315: }
  316: 
  317: static void sdl_fini_out (HWVoiceOut *hw)
  318: {
  319:     (void) hw;
  320: 
  321:     sdl_close (&glob_sdl);
  322: }
  323: 
  324: static int sdl_init_out (HWVoiceOut *hw, audsettings_t *as)
  325: {
  326:     SDLVoiceOut *sdl = (SDLVoiceOut *) hw;
  327:     SDLAudioState *s = &glob_sdl;
  328:     SDL_AudioSpec req, obt;
  329:     int shift;
  330:     int endianess;
  331:     int err;
  332:     audfmt_e effective_fmt;
  333:     audsettings_t obt_as;
  334: 
  335:     shift <<= as->nchannels == 2;
  336: 
  337:     req.freq = as->freq;
  338:     req.format = aud_to_sdlfmt (as->fmt, &shift);
  339:     req.channels = as->nchannels;
  340:     req.samples = conf.nb_samples;
  341:     req.callback = sdl_callback;
  342:     req.userdata = sdl;
  343: 
  344:     if (sdl_open (&req, &obt)) {
  345:         return -1;
  346:     }
  347: 
  348:     err = sdl_to_audfmt (obt.format, &effective_fmt, &endianess);
  349:     if (err) {
  350:         sdl_close (s);
  351:         return -1;
  352:     }
  353: 
  354:     obt_as.freq = obt.freq;
  355:     obt_as.nchannels = obt.channels;
  356:     obt_as.fmt = effective_fmt;
  357:     obt_as.endianness = endianess;
  358: 
  359:     audio_pcm_init_info (&hw->info, &obt_as);
  360:     hw->samples = obt.samples;
  361: 
  362:     s->initialized = 1;
  363:     s->exit = 0;
  364:     SDL_PauseAudio (0);
  365:     return 0;
  366: }
  367: 
  368: static int sdl_ctl_out (HWVoiceOut *hw, int cmd, ...)
  369: {
  370:     (void) hw;
  371: 
  372:     switch (cmd) {
  373:     case VOICE_ENABLE:
  374:         SDL_PauseAudio (0);
  375:         break;
  376: 
  377:     case VOICE_DISABLE:
  378:         SDL_PauseAudio (1);
  379:         break;
  380:     }
  381:     return 0;
  382: }
  383: 
  384: static void *sdl_audio_init (void)
  385: {
  386:     SDLAudioState *s = &glob_sdl;
  387: 
  388:     if (SDL_InitSubSystem (SDL_INIT_AUDIO)) {
  389:         sdl_logerr ("SDL failed to initialize audio subsystem\n");
  390:         return NULL;
  391:     }
  392: 
  393:     s->mutex = SDL_CreateMutex ();
  394:     if (!s->mutex) {
  395:         sdl_logerr ("Failed to create SDL mutex\n");
  396:         SDL_QuitSubSystem (SDL_INIT_AUDIO);
  397:         return NULL;
  398:     }
  399: 
  400:     s->sem = SDL_CreateSemaphore (0);
  401:     if (!s->sem) {
  402:         sdl_logerr ("Failed to create SDL semaphore\n");
  403:         SDL_DestroyMutex (s->mutex);
  404:         SDL_QuitSubSystem (SDL_INIT_AUDIO);
  405:         return NULL;
  406:     }
  407: 
  408:     return s;
  409: }
  410: 
  411: static void sdl_audio_fini (void *opaque)
  412: {
  413:     SDLAudioState *s = opaque;
  414:     sdl_close (s);
  415:     SDL_DestroySemaphore (s->sem);
  416:     SDL_DestroyMutex (s->mutex);
  417:     SDL_QuitSubSystem (SDL_INIT_AUDIO);
  418: }
  419: 
  420: static struct audio_option sdl_options[] = {
  421:     {"SAMPLES", AUD_OPT_INT, &conf.nb_samples,
  422:      "Size of SDL buffer in samples", NULL, 0},
  423:     {NULL, 0, NULL, NULL, NULL, 0}
  424: };
  425: 
  426: static struct audio_pcm_ops sdl_pcm_ops = {
  427:     sdl_init_out,
  428:     sdl_fini_out,
  429:     sdl_run_out,
  430:     sdl_write_out,
  431:     sdl_ctl_out,
  432: 
  433:     NULL,
  434:     NULL,
  435:     NULL,
  436:     NULL,
  437:     NULL
  438: };
  439: 
  440: struct audio_driver sdl_audio_driver = {
  441:     INIT_FIELD (name           = ) "sdl",
  442:     INIT_FIELD (descr          = ) "SDL http://www.libsdl.org",
  443:     INIT_FIELD (options        = ) sdl_options,
  444:     INIT_FIELD (init           = ) sdl_audio_init,
  445:     INIT_FIELD (fini           = ) sdl_audio_fini,
  446:     INIT_FIELD (pcm_ops        = ) &sdl_pcm_ops,
  447:     INIT_FIELD (can_be_default = ) 1,
  448:     INIT_FIELD (max_voices_out = ) 1,
  449:     INIT_FIELD (max_voices_in  = ) 0,
  450:     INIT_FIELD (voice_size_out = ) sizeof (SDLVoiceOut),
  451:     INIT_FIELD (voice_size_in  = ) 0
  452: };
Syntax (Markdown)