Annotation of uae/src/sd-alsa/sound.c, revision 1.1.1.5

1.1.1.2   root        1:  /*
1.1       root        2:   * UAE - The Un*x Amiga Emulator
1.1.1.2   root        3:   *
1.1       root        4:   * Support for Linux/ALSA sound
1.1.1.2   root        5:   *
1.1       root        6:   * Copyright 1997 Bernd Schmidt
                      7:   * Copyright 2004 Heikki Orsila
1.1.1.4   root        8:   * Copyright 2006-2007 Richard Drummond
1.1       root        9:   *
                     10:   * BUGS: certainly
                     11:   * TODO:
                     12:   * - if setup_sound() fails, there may still be hope to get the
                     13:   *   sound device, but we totally give up.. see sd-uss.
                     14:   */
                     15: 
                     16: #include "sysconfig.h"
                     17: #include "sysdeps.h"
                     18: 
                     19: #include "options.h"
1.1.1.4   root       20: #include "gensound.h"
1.1       root       21: #include "memory.h"
                     22: #include "events.h"
                     23: #include "custom.h"
1.1.1.4   root       24: #include "newcpu.h"
1.1       root       25: #include "sounddep/sound.h"
1.1.1.4   root       26: #include "threaddep/thread.h"
1.1       root       27: 
                     28: #include <alsa/asoundlib.h>
                     29: 
1.1.1.4   root       30: static smp_comm_pipe to_sound_pipe;
                     31: static uae_sem_t sound_comm_sem;
                     32: 
                     33: static char alsa_device[256] = "default";
                     34: static int alsa_verbose = 0;
                     35: 
                     36: static int have_sound = 0, have_thread = 0;
                     37: static int dont_block;
1.1       root       38: 
1.1.1.4   root       39: static int which_buffer;
                     40: static uae_u16 sndbuffer[2][44100];
                     41: uae_u16 *sndbufpt, *sndbuf_base;
1.1       root       42: int sndbufsize;
                     43: 
1.1.1.4   root       44: static snd_pcm_t *alsa_playback_handle = 0;
                     45: static int alsa_to_frames_divisor;
                     46: static snd_pcm_uframes_t period_frames;
                     47: 
                     48: /* alsa_xrun_recovery() function is copied from ALSA manual. why the hell did
                     49:  * they make ALSA this hard?! i bet 95% of ALSA programmers would like a
                     50:  * simpler way to do error handling.. let the 5% use tricky APIs.  */
                     51: static int alsa_xrun_recovery (snd_pcm_t *handle, int err)
                     52: {
                     53:     if (err == -EPIPE) {
                     54:        /* under-run */
                     55:        err = snd_pcm_prepare (handle);
                     56:        if (err < 0)
                     57:            fprintf (stderr, "uae: no recovery with alsa from underrun, prepare failed: %s\n", snd_strerror (err));
                     58:        return 0;
                     59:     } else if (err == -ESTRPIPE) {
                     60:        while ((err = snd_pcm_resume (handle)) == -EAGAIN) {
                     61:            /* wait until the suspend flag is released */
                     62:            fprintf (stderr, "uae: sleeping for alsa.\n");
                     63:            sleep (1);
                     64:        }
                     65:        if (err < 0) {
                     66:            err = snd_pcm_prepare (handle);
                     67:            if (err < 0)
                     68:                fprintf (stderr, "uae: no recovery with alsa from suspend, prepare failed: %s\n", snd_strerror (err));
                     69:        }
                     70:        return 0;
                     71:     }
                     72:     return err;
                     73: }
                     74: 
                     75: static void write_sound_frames (uae_u16 *bufbase)
                     76: {
                     77:     char *buf = (char *) bufbase;
                     78:     int ret;
                     79: 
                     80:     int frames = period_frames;
                     81:     while (frames > 0) {
                     82:        ret = snd_pcm_writei (alsa_playback_handle, buf, frames);
                     83:        if (ret < 0) {
                     84:            if (ret == -EAGAIN || ret == -EINTR)
                     85:                continue;
                     86:            if (alsa_xrun_recovery (alsa_playback_handle, ret) < 0) {
                     87:                fprintf (stderr, "uae: write error with alsa: %s\n", snd_strerror (ret));
                     88:                exit (-1);
                     89:            }
                     90:            continue;
                     91:        }
                     92:        frames -= ret;
                     93:        buf += ret * alsa_to_frames_divisor;
                     94:     }
                     95: }
                     96: 
                     97: void finish_sound_buffers ()
                     98: {
                     99:     dont_block = currprefs.m68k_speed == -1 && (!regs.stopped || active_fs_packets > 0);
                    100:     if (!dont_block) {
                    101:        write_sound_frames (sndbuf_base);
                    102:     } else {
                    103:        write_comm_pipe_int (&to_sound_pipe, 2, 1);
                    104:        uae_sem_wait (&sound_comm_sem);
                    105:     }
                    106: 
                    107:     sndbufpt = sndbuf_base = sndbuffer[which_buffer ^ 1];
                    108: }
1.1       root      109: 
                    110: void close_sound (void)
                    111: {
1.1.1.4   root      112:     sync_with_sound = 0;
                    113:     if (alsa_playback_handle) {
                    114:        snd_pcm_close (alsa_playback_handle);
                    115:        alsa_playback_handle = 0;
                    116:     }
                    117:     if (have_thread) {
                    118:        write_comm_pipe_int (&to_sound_pipe, 1, 1);
                    119:        uae_sem_wait (&sound_comm_sem);
                    120:        uae_sem_destroy (&sound_comm_sem);
                    121:        have_thread = 0;
                    122:     }
1.1       root      123: }
                    124: 
1.1.1.4   root      125: static int open_sound_device (void)
1.1       root      126: {
1.1.1.4   root      127:     return snd_pcm_open (&alsa_playback_handle, alsa_device, SND_PCM_STREAM_PLAYBACK, 0);
1.1       root      128: }
                    129: 
                    130: /* Try to determine whether sound is available.  This is only for GUI purposes.  */
                    131: int setup_sound (void)
                    132: {
1.1.1.4   root      133:     int err;
                    134:     sound_available = 0;
                    135:     if ((err = open_sound_device ()) < 0) {
                    136:        /* TODO: if the pcm was busy, we should the same as sd-uss does.
                    137:           tell the caller that sound is available. in any other
                    138:           condition we should just return 0. */
                    139:        write_log ("Cannot open audio device: %s.\n", snd_strerror (err));
                    140:        return 0;
                    141:     }
                    142:     snd_pcm_close (alsa_playback_handle);
                    143:     alsa_playback_handle = 0;
                    144:     sound_available = 1;
                    145:     return 1;
                    146: }
                    147: 
                    148: static int set_hw_params (snd_pcm_t *pcm, snd_pcm_hw_params_t *hw_params,
                    149:                          unsigned int *rate, unsigned int channels,
                    150:                          snd_pcm_format_t format, unsigned int *buffer_time,
                    151:                          snd_pcm_uframes_t *buffer_frames,
                    152:                          snd_pcm_uframes_t *per_frames)
                    153: {
                    154:     int err;
                    155:     unsigned int periods = 2;
                    156: 
                    157:     err = snd_pcm_hw_params_any (pcm, hw_params);
                    158:     if (err < 0)
                    159:        return err;
                    160:     err = snd_pcm_hw_params_set_access (pcm, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
                    161:     if (err < 0)
                    162:        return err;
                    163:     err = snd_pcm_hw_params_set_format (pcm, hw_params, format);
                    164:     if (err < 0)
                    165:        return err;
                    166:     err = snd_pcm_hw_params_set_channels (pcm, hw_params, channels);
                    167:     if (err < 0)
                    168:        return err;
                    169:     err = snd_pcm_hw_params_set_rate_near (pcm, hw_params, rate, 0);
                    170:     if (err < 0)
                    171:        return err;
                    172:     err = snd_pcm_hw_params_set_buffer_time_near (pcm, hw_params, buffer_time, NULL);
                    173:     if (err < 0)
                    174:        return err;
                    175:     snd_pcm_hw_params_get_buffer_size (hw_params, buffer_frames);
                    176:     err = snd_pcm_hw_params_set_periods_near (pcm, hw_params, &periods, NULL);
                    177:     if (err < 0)
                    178:        return err;
                    179:     if (periods == 1)
                    180:        return -EINVAL;
                    181:     err = snd_pcm_hw_params (pcm, hw_params);
                    182: 
                    183:     snd_pcm_hw_params_get_period_size (hw_params, per_frames, NULL);
                    184:     return 0;
                    185: }
                    186: 
                    187: static int set_sw_params (snd_pcm_t * pcm,
                    188:                          snd_pcm_sw_params_t * sw_params, snd_pcm_uframes_t buffer_frames, snd_pcm_uframes_t period_frames)
                    189: {
                    190:     int err;
                    191: 
                    192:     err = snd_pcm_sw_params_current (pcm, sw_params);
                    193:     if (err < 0)
                    194:        return err;
                    195:     err = snd_pcm_sw_params_set_start_threshold (pcm, sw_params, (buffer_frames / period_frames) * period_frames);
                    196:     if (err < 0)
                    197:        return err;
                    198:     err = snd_pcm_sw_params_set_avail_min (pcm, sw_params, period_frames);
                    199:     if (err < 0)
                    200:        return err;
                    201:     err = snd_pcm_sw_params_set_stop_threshold (pcm, sw_params, buffer_frames);
                    202:     if (err < 0)
                    203:        return err;
                    204:     err = snd_pcm_sw_params_set_xfer_align (pcm, sw_params, 1);
                    205:     if (err < 0)
                    206:        return err;
                    207:     err = snd_pcm_sw_params (pcm, sw_params);
                    208:     if (err < 0)
                    209:        return err;
1.1       root      210:     return 0;
1.1.1.4   root      211: }
                    212: 
                    213: static void open_sound (void)
                    214: {
                    215:     unsigned int rate;
                    216:     snd_pcm_format_t format;
                    217:     unsigned int channels;
                    218: 
                    219:     snd_pcm_hw_params_t *hw_params = 0;
                    220:     snd_pcm_sw_params_t *sw_params = 0;
                    221:     snd_pcm_uframes_t buffer_frames;
                    222:     unsigned int buffer_time;
                    223: 
                    224:     snd_output_t *alsa_out;
                    225: 
                    226:     int err;
                    227: 
                    228:     sync_with_sound = 0;
                    229: 
                    230:     snd_output_stdio_attach (&alsa_out, stderr, 0);
                    231: 
1.1.1.5 ! root      232:     channels = 2;
1.1.1.4   root      233:     rate = currprefs.sound_freq;
                    234: 
                    235:     have_sound = 0;
                    236:     alsa_playback_handle = 0;
                    237:     if ((err = open_sound_device ()) < 0) {
                    238:        write_log ("Cannot open audio device: %s\n", snd_strerror (err));
                    239:        goto nosound;
                    240:     }
                    241: 
                    242:     buffer_time = currprefs.sound_maxbsiz * 1000;
                    243: 
                    244:     while (buffer_time / (rate * 2 * channels) < 6)
                    245:        buffer_time *= 2;
                    246:     if (buffer_time != currprefs.sound_maxbsiz * 1000) {
                    247:        fprintf (stderr, "Increasing sound buffer size to sane minimum of %d bytes.\n",
                    248:                 buffer_time / 1000);
                    249:     }
                    250:     if (buffer_time < 1000 || buffer_time > 500000)
                    251:        buffer_time = 100000;
                    252: 
                    253: 
                    254:     if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) {
                    255:        write_log ("Cannot allocate hardware parameter structure: %s.\n", snd_strerror (err));
                    256:        goto nosound;
                    257:     }
                    258:     if ((err = snd_pcm_sw_params_malloc (&sw_params)) < 0) {
                    259:        write_log ("Cannot allocate software parameter structure: %s.\n", snd_strerror (err));
                    260:        goto nosound;
                    261:     }
                    262: 
                    263:     format = SND_PCM_FORMAT_S16;
                    264: 
                    265:     alsa_to_frames_divisor = 2 * channels;
                    266: 
                    267:     if ((err =
                    268:         set_hw_params (alsa_playback_handle, hw_params, &rate, channels, format, &buffer_time, &buffer_frames,
                    269:                        &period_frames)) < 0) {
                    270:        write_log ("Cannot set hw parameters: %s.\n", snd_strerror (err));
                    271:        goto nosound;
                    272:     }
                    273: 
                    274:     if ((err = set_sw_params (alsa_playback_handle, sw_params, buffer_frames, period_frames)) < 0) {
                    275:        write_log ("Cannot set sw parameters: %s.\n", snd_strerror (err));
                    276:        goto nosound;
                    277:     }
                    278: 
                    279:     sndbufsize = period_frames * alsa_to_frames_divisor;
                    280:     snd_pcm_hw_params_free (hw_params);
                    281:     snd_pcm_sw_params_free (sw_params);
                    282: 
                    283:     if ((err = snd_pcm_prepare (alsa_playback_handle)) < 0) {
                    284:        write_log ("Cannot prepare audio interface for use: %s.\n", snd_strerror (err));
                    285:        goto nosound;
                    286:     }
                    287: 
                    288:     obtainedfreq = rate;
                    289: 
                    290:     init_sound_table16 ();
1.1.1.5 ! root      291:     sample_handler = sample16s_handler;
1.1.1.4   root      292: 
                    293:     have_sound = 1;
                    294:     sound_available = 1;
                    295: 
                    296:     write_log ("ALSA: Using device '%s'.\n", alsa_device);
                    297:     write_log ("ALSA: Sound configured for %d Hz. Buffer length is %u us, period size %d bytes.\n",
                    298:               rate, buffer_time, period_frames * alsa_to_frames_divisor);
                    299: 
                    300:     if (alsa_verbose)
                    301:        snd_pcm_dump (alsa_playback_handle, alsa_out);
                    302: 
                    303:     sndbufpt = sndbuf_base = sndbuffer[which_buffer = 0];
                    304: 
                    305:     sync_with_sound = 1;
                    306:     return;
                    307: 
                    308:   nosound:
                    309:     have_sound = 0;
                    310:     if (hw_params)
                    311:        snd_pcm_hw_params_free (hw_params);
                    312:     if (sw_params)
                    313:        snd_pcm_sw_params_free (sw_params);
                    314: 
                    315:     close_sound ();
                    316: }
                    317: 
                    318: #if 0
                    319: /*
                    320:  * Handle audio specific cfgfile options
                    321:  */
                    322: void audio_default_options (struct uae_prefs *p)
                    323: {
                    324:     strncpy (alsa_device, "default", 256);
                    325:     alsa_verbose = 1;
                    326: }
                    327: 
                    328: void audio_save_options (FILE * f, const struct uae_prefs *p)
                    329: {
                    330:     cfgfile_write (f, "alsa.device=%s\n", alsa_device);
                    331:     cfgfile_write (f, "alsa.verbose=%s\n", alsa_verbose ? "true" : "false");
                    332: }
                    333: 
                    334: int audio_parse_option (struct uae_prefs *p, const char *option, const char *value)
                    335: {
                    336:     return (cfgfile_string (option, value, "device", alsa_device, 256)
                    337:            || cfgfile_yesno (option, value, "verbose", &alsa_verbose));
                    338: }
                    339: #endif
                    340: 
                    341: static void *sound_thread (void *dummy)
                    342: {
                    343:     for (;;) {
                    344:        int cmd = read_comm_pipe_int_blocking (&to_sound_pipe);
                    345:        int n;
                    346: 
                    347:        switch (cmd) {
                    348:        case 0:
                    349:            open_sound ();
                    350:            uae_sem_post (&sound_comm_sem);
                    351:            break;
                    352:        case 1:
                    353:            uae_sem_post (&sound_comm_sem);
                    354:            return 0;
                    355:        case 2:
                    356:            /* If trying for maximum CPU speed, don't block the main
                    357:               thread, instead set the delaying_for_sound variable.  If
                    358:               not trying for maximum CPU speed, synchronize here by
                    359:               delaying the sem_post until after the write.  */
                    360:            delaying_for_sound = dont_block;
                    361:            if (dont_block)
                    362:                uae_sem_post (&sound_comm_sem);
                    363: 
                    364:            write_sound_frames (sndbuf_base);
                    365:            if (!dont_block)
                    366:                uae_sem_post (&sound_comm_sem);
                    367: 
                    368:            delaying_for_sound = 0;
                    369:            break;
                    370:        }
                    371:     }
                    372: }
                    373: 
                    374: /* We use a thread so that we can use the time spent waiting for the sound
                    375:    driver for executing m68k instructions, rather than just blocking.  */
                    376: static void init_sound_thread (void)
                    377: {
                    378:     uae_thread_id tid;
                    379: 
                    380:     init_comm_pipe (&to_sound_pipe, 20, 1);
                    381:     uae_sem_init (&sound_comm_sem, 0, 0);
                    382:     uae_start_thread (sound_thread, NULL, &tid);
                    383:     have_thread = 1;
1.1       root      384: }
                    385: 
                    386: int init_sound (void)
                    387: {
1.1.1.4   root      388:     init_sound_thread ();
                    389:     write_comm_pipe_int (&to_sound_pipe, 0, 1);
                    390:     uae_sem_wait (&sound_comm_sem);
                    391: 
                    392:     return have_sound;
1.1       root      393: }

unix.superglobalmegacorp.com

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