Annotation of qemu/audio/sdlaudio.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * QEMU SDL audio output driver
                      3:  * 
                      4:  * Copyright (c) 2004 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 "vl.h"
                     27: 
                     28: #include "audio/audio_int.h"
                     29: 
                     30: typedef struct SDLVoice {
                     31:     HWVoice hw;
                     32: } SDLVoice;
                     33: 
                     34: #define dolog(...) AUD_log ("sdl", __VA_ARGS__)
                     35: #ifdef DEBUG
                     36: #define ldebug(...) dolog (__VA_ARGS__)
                     37: #else
                     38: #define ldebug(...)
                     39: #endif
                     40: 
                     41: #define QC_SDL_SAMPLES "QEMU_SDL_SAMPLES"
                     42: 
                     43: #define errstr() SDL_GetError ()
                     44: 
                     45: static struct {
                     46:     int nb_samples;
                     47: } conf = {
                     48:     1024
                     49: };
                     50: 
                     51: struct SDLAudioState {
                     52:     int exit;
                     53:     SDL_mutex *mutex;
                     54:     SDL_sem *sem;
                     55:     int initialized;
                     56: } glob_sdl;
                     57: typedef struct SDLAudioState SDLAudioState;
                     58: 
                     59: static void sdl_hw_run (HWVoice *hw)
                     60: {
                     61:     (void) hw;
                     62: }
                     63: 
                     64: static int sdl_lock (SDLAudioState *s)
                     65: {
                     66:     if (SDL_LockMutex (s->mutex)) {
                     67:         dolog ("SDL_LockMutex failed\nReason: %s\n", errstr ());
                     68:         return -1;
                     69:     }
                     70:     return 0;
                     71: }
                     72: 
                     73: static int sdl_unlock (SDLAudioState *s)
                     74: {
                     75:     if (SDL_UnlockMutex (s->mutex)) {
                     76:         dolog ("SDL_UnlockMutex failed\nReason: %s\n", errstr ());
                     77:         return -1;
                     78:     }
                     79:     return 0;
                     80: }
                     81: 
                     82: static int sdl_post (SDLAudioState *s)
                     83: {
                     84:     if (SDL_SemPost (s->sem)) {
                     85:         dolog ("SDL_SemPost failed\nReason: %s\n", errstr ());
                     86:         return -1;
                     87:     }
                     88:     return 0;
                     89: }
                     90: 
                     91: static int sdl_wait (SDLAudioState *s)
                     92: {
                     93:     if (SDL_SemWait (s->sem)) {
                     94:         dolog ("SDL_SemWait failed\nReason: %s\n", errstr ());
                     95:         return -1;
                     96:     }
                     97:     return 0;
                     98: }
                     99: 
                    100: static int sdl_unlock_and_post (SDLAudioState *s)
                    101: {
                    102:     if (sdl_unlock (s))
                    103:         return -1;
                    104: 
                    105:     return sdl_post (s);
                    106: }
                    107: 
                    108: static int sdl_hw_write (SWVoice *sw, void *buf, int len)
                    109: {
                    110:     int ret;
                    111:     SDLAudioState *s = &glob_sdl;
                    112:     sdl_lock (s);
                    113:     ret = pcm_hw_write (sw, buf, len);
                    114:     sdl_unlock_and_post (s);
                    115:     return ret;
                    116: }
                    117: 
                    118: static int AUD_to_sdlfmt (audfmt_e fmt, int *shift)
                    119: {
                    120:     *shift = 0;
                    121:     switch (fmt) {
                    122:     case AUD_FMT_S8: return AUDIO_S8;
                    123:     case AUD_FMT_U8: return AUDIO_U8;
                    124:     case AUD_FMT_S16: *shift = 1; return AUDIO_S16LSB;
                    125:     case AUD_FMT_U16: *shift = 1; return AUDIO_U16LSB;
                    126:     default:
                    127:         dolog ("Internal logic error: Bad audio format %d\nAborting\n", fmt);
                    128:         exit (EXIT_FAILURE);
                    129:     }
                    130: }
                    131: 
                    132: static int sdl_to_audfmt (int fmt)
                    133: {
                    134:     switch (fmt) {
                    135:     case AUDIO_S8: return AUD_FMT_S8;
                    136:     case AUDIO_U8: return AUD_FMT_U8;
                    137:     case AUDIO_S16LSB: return AUD_FMT_S16;
                    138:     case AUDIO_U16LSB: return AUD_FMT_U16;
                    139:     default:
                    140:         dolog ("Internal logic error: Unrecognized SDL audio format %d\n"
                    141:                "Aborting\n", fmt);
                    142:         exit (EXIT_FAILURE);
                    143:     }
                    144: }
                    145: 
                    146: static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt)
                    147: {
                    148:     int status;
                    149: 
                    150:     status = SDL_OpenAudio (req, obt);
                    151:     if (status) {
                    152:         dolog ("SDL_OpenAudio failed\nReason: %s\n", errstr ());
                    153:     }
                    154:     return status;
                    155: }
                    156: 
                    157: static void sdl_close (SDLAudioState *s)
                    158: {
                    159:     if (s->initialized) {
                    160:         sdl_lock (s);
                    161:         s->exit = 1;
                    162:         sdl_unlock_and_post (s);
                    163:         SDL_PauseAudio (1);
                    164:         SDL_CloseAudio ();
                    165:         s->initialized = 0;
                    166:     }
                    167: }
                    168: 
                    169: static void sdl_callback (void *opaque, Uint8 *buf, int len)
                    170: {
                    171:     SDLVoice *sdl = opaque;
                    172:     SDLAudioState *s = &glob_sdl;
                    173:     HWVoice *hw = &sdl->hw;
                    174:     int samples = len >> hw->shift;
                    175: 
                    176:     if (s->exit) {
                    177:         return;
                    178:     }
                    179: 
                    180:     while (samples) {
                    181:         int to_mix, live, decr;
                    182: 
                    183:         /* dolog ("in callback samples=%d\n", samples); */
                    184:         sdl_wait (s);
                    185:         if (s->exit) {
                    186:             return;
                    187:         }
                    188: 
                    189:         sdl_lock (s);
                    190:         live = pcm_hw_get_live (hw);
                    191:         if (live <= 0)
                    192:             goto again;
                    193: 
                    194:         /* dolog ("in callback live=%d\n", live); */
                    195:         to_mix = audio_MIN (samples, live);
                    196:         decr = to_mix;
                    197:         while (to_mix) {
                    198:             int chunk = audio_MIN (to_mix, hw->samples - hw->rpos);
                    199:             st_sample_t *src = hw->mix_buf + hw->rpos;
                    200: 
                    201:             /* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */
                    202:             hw->clip (buf, src, chunk);
                    203:             memset (src, 0, chunk * sizeof (st_sample_t));
                    204:             hw->rpos = (hw->rpos + chunk) % hw->samples;
                    205:             to_mix -= chunk;
                    206:             buf += chunk << hw->shift;
                    207:         }
                    208:         samples -= decr;
                    209:         pcm_hw_dec_live (hw, decr);
                    210: 
                    211:     again:
                    212:         sdl_unlock (s);
                    213:     }
                    214:     /* dolog ("done len=%d\n", len); */
                    215: }
                    216: 
                    217: static void sdl_hw_fini (HWVoice *hw)
                    218: {
                    219:     ldebug ("sdl_hw_fini %d fixed=%d\n",
                    220:              glob_sdl.initialized, audio_state.fixed_format);
                    221:     sdl_close (&glob_sdl);
                    222: }
                    223: 
                    224: static int sdl_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
                    225: {
                    226:     SDLVoice *sdl = (SDLVoice *) hw;
                    227:     SDLAudioState *s = &glob_sdl;
                    228:     SDL_AudioSpec req, obt;
                    229:     int shift;
                    230: 
                    231:     ldebug ("sdl_hw_init %d freq=%d fixed=%d\n",
                    232:             s->initialized, freq, audio_state.fixed_format);
                    233: 
                    234:     if (nchannels != 2) {
                    235:         dolog ("Bogus channel count %d\n", nchannels);
                    236:         return -1;
                    237:     }
                    238: 
                    239:     req.freq = freq;
                    240:     req.format = AUD_to_sdlfmt (fmt, &shift);
                    241:     req.channels = nchannels;
                    242:     req.samples = conf.nb_samples;
                    243:     shift <<= nchannels == 2;
                    244: 
                    245:     req.callback = sdl_callback;
                    246:     req.userdata = sdl;
                    247: 
                    248:     if (sdl_open (&req, &obt))
                    249:         return -1;
                    250: 
                    251:     hw->freq = obt.freq;
                    252:     hw->fmt = sdl_to_audfmt (obt.format);
                    253:     hw->nchannels = obt.channels;
                    254:     hw->bufsize = obt.samples << shift;
                    255: 
                    256:     s->initialized = 1;
                    257:     s->exit = 0;
                    258:     SDL_PauseAudio (0);
                    259:     return 0;
                    260: }
                    261: 
                    262: static int sdl_hw_ctl (HWVoice *hw, int cmd, ...)
                    263: {
                    264:     (void) hw;
                    265: 
                    266:     switch (cmd) {
                    267:     case VOICE_ENABLE:
                    268:         SDL_PauseAudio (0);
                    269:         break;
                    270: 
                    271:     case VOICE_DISABLE:
                    272:         SDL_PauseAudio (1);
                    273:         break;
                    274:     }
                    275:     return 0;
                    276: }
                    277: 
                    278: static void *sdl_audio_init (void)
                    279: {
                    280:     SDLAudioState *s = &glob_sdl;
                    281:     conf.nb_samples = audio_get_conf_int (QC_SDL_SAMPLES, conf.nb_samples);
                    282: 
                    283:     if (SDL_InitSubSystem (SDL_INIT_AUDIO)) {
                    284:         dolog ("SDL failed to initialize audio subsystem\nReason: %s\n",
                    285:                errstr ());
                    286:         return NULL;
                    287:     }
                    288: 
                    289:     s->mutex = SDL_CreateMutex ();
                    290:     if (!s->mutex) {
                    291:         dolog ("Failed to create SDL mutex\nReason: %s\n", errstr ());
                    292:         SDL_QuitSubSystem (SDL_INIT_AUDIO);
                    293:         return NULL;
                    294:     }
                    295: 
                    296:     s->sem = SDL_CreateSemaphore (0);
                    297:     if (!s->sem) {
                    298:         dolog ("Failed to create SDL semaphore\nReason: %s\n", errstr ());
                    299:         SDL_DestroyMutex (s->mutex);
                    300:         SDL_QuitSubSystem (SDL_INIT_AUDIO);
                    301:         return NULL;
                    302:     }
                    303: 
                    304:     return s;
                    305: }
                    306: 
                    307: static void sdl_audio_fini (void *opaque)
                    308: {
                    309:     SDLAudioState *s = opaque;
                    310:     sdl_close (s);
                    311:     SDL_DestroySemaphore (s->sem);
                    312:     SDL_DestroyMutex (s->mutex);
                    313:     SDL_QuitSubSystem (SDL_INIT_AUDIO);
                    314: }
                    315: 
                    316: struct pcm_ops sdl_pcm_ops = {
                    317:     sdl_hw_init,
                    318:     sdl_hw_fini,
                    319:     sdl_hw_run,
                    320:     sdl_hw_write,
                    321:     sdl_hw_ctl
                    322: };
                    323: 
                    324: struct audio_output_driver sdl_output_driver = {
                    325:     "sdl",
                    326:     sdl_audio_init,
                    327:     sdl_audio_fini,
                    328:     &sdl_pcm_ops,
                    329:     1,
                    330:     1,
                    331:     sizeof (SDLVoice)
                    332: };

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.