⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 alsaaudio.c

📁 qemu虚拟机代码
💻 C
📖 第 1 页 / 共 2 页
字号:
#if defined DEBUG_MISMATCHES || defined DEBUG    if (obt->fmt != req->fmt ||        obt->nchannels != req->nchannels ||        obt->freq != req->freq) {        dolog ("Audio paramters mismatch for %s\n", typ);        alsa_dump_info (req, obt);    }#endif#ifdef DEBUG    alsa_dump_info (req, obt);#endif    return 0; err:    alsa_anal_close (&handle);    return -1;}static int alsa_recover (snd_pcm_t *handle){    int err = snd_pcm_prepare (handle);    if (err < 0) {        alsa_logerr (err, "Failed to prepare handle %p\n", handle);        return -1;    }    return 0;}static snd_pcm_sframes_t alsa_get_avail (snd_pcm_t *handle){    snd_pcm_sframes_t avail;    avail = snd_pcm_avail_update (handle);    if (avail < 0) {        if (avail == -EPIPE) {            if (!alsa_recover (handle)) {                avail = snd_pcm_avail_update (handle);            }        }        if (avail < 0) {            alsa_logerr (avail,                         "Could not obtain number of available frames\n");            return -1;        }    }    return avail;}static int alsa_run_out (HWVoiceOut *hw){    ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;    int rpos, live, decr;    int samples;    uint8_t *dst;    st_sample_t *src;    snd_pcm_sframes_t avail;    live = audio_pcm_hw_get_live_out (hw);    if (!live) {        return 0;    }    avail = alsa_get_avail (alsa->handle);    if (avail < 0) {        dolog ("Could not get number of available playback frames\n");        return 0;    }    decr = audio_MIN (live, avail);    samples = decr;    rpos = hw->rpos;    while (samples) {        int left_till_end_samples = hw->samples - rpos;        int len = audio_MIN (samples, left_till_end_samples);        snd_pcm_sframes_t written;        src = hw->mix_buf + rpos;        dst = advance (alsa->pcm_buf, rpos << hw->info.shift);        hw->clip (dst, src, len);        while (len) {            written = snd_pcm_writei (alsa->handle, dst, len);            if (written <= 0) {                switch (written) {                case 0:                    if (conf.verbose) {                        dolog ("Failed to write %d frames (wrote zero)\n", len);                    }                    goto exit;                case -EPIPE:                    if (alsa_recover (alsa->handle)) {                        alsa_logerr (written, "Failed to write %d frames\n",                                     len);                        goto exit;                    }                    if (conf.verbose) {                        dolog ("Recovering from playback xrun\n");                    }                    continue;                case -EAGAIN:                    goto exit;                default:                    alsa_logerr (written, "Failed to write %d frames to %p\n",                                 len, dst);                    goto exit;                }            }            mixeng_clear (src, written);            rpos = (rpos + written) % hw->samples;            samples -= written;            len -= written;            dst = advance (dst, written << hw->info.shift);            src += written;        }    } exit:    hw->rpos = rpos;    return decr;}static void alsa_fini_out (HWVoiceOut *hw){    ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;    ldebug ("alsa_fini\n");    alsa_anal_close (&alsa->handle);    if (alsa->pcm_buf) {        qemu_free (alsa->pcm_buf);        alsa->pcm_buf = NULL;    }}static int alsa_init_out (HWVoiceOut *hw, audsettings_t *as){    ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;    struct alsa_params_req req;    struct alsa_params_obt obt;    audfmt_e effective_fmt;    int endianness;    int err;    snd_pcm_t *handle;    audsettings_t obt_as;    req.fmt = aud_to_alsafmt (as->fmt);    req.freq = as->freq;    req.nchannels = as->nchannels;    req.period_size = conf.period_size_out;    req.buffer_size = conf.buffer_size_out;    if (alsa_open (0, &req, &obt, &handle)) {        return -1;    }    err = alsa_to_audfmt (obt.fmt, &effective_fmt, &endianness);    if (err) {        alsa_anal_close (&handle);        return -1;    }    obt_as.freq = obt.freq;    obt_as.nchannels = obt.nchannels;    obt_as.fmt = effective_fmt;    audio_pcm_init_info (        &hw->info,        &obt_as,        audio_need_to_swap_endian (endianness)        );    hw->samples = obt.samples;    alsa->pcm_buf = audio_calloc (AUDIO_FUNC, obt.samples, 1 << hw->info.shift);    if (!alsa->pcm_buf) {        dolog ("Could not allocate DAC buffer (%d samples, each %d bytes)\n",               hw->samples, 1 << hw->info.shift);        alsa_anal_close (&handle);        return -1;    }    alsa->handle = handle;    return 0;}static int alsa_voice_ctl (snd_pcm_t *handle, const char *typ, int pause){    int err;    if (pause) {        err = snd_pcm_drop (handle);        if (err < 0) {            alsa_logerr (err, "Could not stop %s\n", typ);            return -1;        }    }    else {        err = snd_pcm_prepare (handle);        if (err < 0) {            alsa_logerr (err, "Could not prepare handle for %s\n", typ);            return -1;        }    }    return 0;}static int alsa_ctl_out (HWVoiceOut *hw, int cmd, ...){    ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;    switch (cmd) {    case VOICE_ENABLE:        ldebug ("enabling voice\n");        return alsa_voice_ctl (alsa->handle, "playback", 0);    case VOICE_DISABLE:        ldebug ("disabling voice\n");        return alsa_voice_ctl (alsa->handle, "playback", 1);    }    return -1;}static int alsa_init_in (HWVoiceIn *hw, audsettings_t *as){    ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;    struct alsa_params_req req;    struct alsa_params_obt obt;    int endianness;    int err;    audfmt_e effective_fmt;    snd_pcm_t *handle;    audsettings_t obt_as;    req.fmt = aud_to_alsafmt (as->fmt);    req.freq = as->freq;    req.nchannels = as->nchannels;    req.period_size = conf.period_size_in;    req.buffer_size = conf.buffer_size_in;    if (alsa_open (1, &req, &obt, &handle)) {        return -1;    }    err = alsa_to_audfmt (obt.fmt, &effective_fmt, &endianness);    if (err) {        alsa_anal_close (&handle);        return -1;    }    obt_as.freq = obt.freq;    obt_as.nchannels = obt.nchannels;    obt_as.fmt = effective_fmt;    audio_pcm_init_info (        &hw->info,        &obt_as,        audio_need_to_swap_endian (endianness)        );    hw->samples = obt.samples;    alsa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);    if (!alsa->pcm_buf) {        dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n",               hw->samples, 1 << hw->info.shift);        alsa_anal_close (&handle);        return -1;    }    alsa->handle = handle;    return 0;}static void alsa_fini_in (HWVoiceIn *hw){    ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;    alsa_anal_close (&alsa->handle);    if (alsa->pcm_buf) {        qemu_free (alsa->pcm_buf);        alsa->pcm_buf = NULL;    }}static int alsa_run_in (HWVoiceIn *hw){    ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;    int hwshift = hw->info.shift;    int i;    int live = audio_pcm_hw_get_live_in (hw);    int dead = hw->samples - live;    int decr;    struct {        int add;        int len;    } bufs[2] = {        { hw->wpos, 0 },        { 0, 0 }    };    snd_pcm_sframes_t avail;    snd_pcm_uframes_t read_samples = 0;    if (!dead) {        return 0;    }    avail = alsa_get_avail (alsa->handle);    if (avail < 0) {        dolog ("Could not get number of captured frames\n");        return 0;    }    if (!avail && (snd_pcm_state (alsa->handle) == SND_PCM_STATE_PREPARED)) {        avail = hw->samples;    }    decr = audio_MIN (dead, avail);    if (!decr) {        return 0;    }    if (hw->wpos + decr > hw->samples) {        bufs[0].len = (hw->samples - hw->wpos);        bufs[1].len = (decr - (hw->samples - hw->wpos));    }    else {        bufs[0].len = decr;    }    for (i = 0; i < 2; ++i) {        void *src;        st_sample_t *dst;        snd_pcm_sframes_t nread;        snd_pcm_uframes_t len;        len = bufs[i].len;        src = advance (alsa->pcm_buf, bufs[i].add << hwshift);        dst = hw->conv_buf + bufs[i].add;        while (len) {            nread = snd_pcm_readi (alsa->handle, src, len);            if (nread <= 0) {                switch (nread) {                case 0:                    if (conf.verbose) {                        dolog ("Failed to read %ld frames (read zero)\n", len);                    }                    goto exit;                case -EPIPE:                    if (alsa_recover (alsa->handle)) {                        alsa_logerr (nread, "Failed to read %ld frames\n", len);                        goto exit;                    }                    if (conf.verbose) {                        dolog ("Recovering from capture xrun\n");                    }                    continue;                case -EAGAIN:                    goto exit;                default:                    alsa_logerr (                        nread,                        "Failed to read %ld frames from %p\n",                        len,                        src                        );                    goto exit;                }            }            hw->conv (dst, src, nread, &nominal_volume);            src = advance (src, nread << hwshift);            dst += nread;            read_samples += nread;            len -= nread;        }    } exit:    hw->wpos = (hw->wpos + read_samples) % hw->samples;    return read_samples;}static int alsa_read (SWVoiceIn *sw, void *buf, int size){    return audio_pcm_sw_read (sw, buf, size);}static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...){    ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;    switch (cmd) {    case VOICE_ENABLE:        ldebug ("enabling voice\n");        return alsa_voice_ctl (alsa->handle, "capture", 0);    case VOICE_DISABLE:        ldebug ("disabling voice\n");        return alsa_voice_ctl (alsa->handle, "capture", 1);    }    return -1;}static void *alsa_audio_init (void){    return &conf;}static void alsa_audio_fini (void *opaque){    (void) opaque;}static struct audio_option alsa_options[] = {    {"DAC_SIZE_IN_USEC", AUD_OPT_BOOL, &conf.size_in_usec_out,     "DAC period/buffer size in microseconds (otherwise in frames)", NULL, 0},    {"DAC_PERIOD_SIZE", AUD_OPT_INT, &conf.period_size_out,     "DAC period size", &conf.period_size_out_overriden, 0},    {"DAC_BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_size_out,     "DAC buffer size", &conf.buffer_size_out_overriden, 0},    {"ADC_SIZE_IN_USEC", AUD_OPT_BOOL, &conf.size_in_usec_in,     "ADC period/buffer size in microseconds (otherwise in frames)", NULL, 0},    {"ADC_PERIOD_SIZE", AUD_OPT_INT, &conf.period_size_in,     "ADC period size", &conf.period_size_in_overriden, 0},    {"ADC_BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_size_in,     "ADC buffer size", &conf.buffer_size_in_overriden, 0},    {"THRESHOLD", AUD_OPT_INT, &conf.threshold,     "(undocumented)", NULL, 0},    {"DAC_DEV", AUD_OPT_STR, &conf.pcm_name_out,     "DAC device name (for instance dmix)", NULL, 0},    {"ADC_DEV", AUD_OPT_STR, &conf.pcm_name_in,     "ADC device name", NULL, 0},    {"VERBOSE", AUD_OPT_BOOL, &conf.verbose,     "Behave in a more verbose way", NULL, 0},    {NULL, 0, NULL, NULL, NULL, 0}};static struct audio_pcm_ops alsa_pcm_ops = {    alsa_init_out,    alsa_fini_out,    alsa_run_out,    alsa_write,    alsa_ctl_out,    alsa_init_in,    alsa_fini_in,    alsa_run_in,    alsa_read,    alsa_ctl_in};struct audio_driver alsa_audio_driver = {    INIT_FIELD (name           = ) "alsa",    INIT_FIELD (descr          = ) "ALSA http://www.alsa-project.org",    INIT_FIELD (options        = ) alsa_options,    INIT_FIELD (init           = ) alsa_audio_init,    INIT_FIELD (fini           = ) alsa_audio_fini,    INIT_FIELD (pcm_ops        = ) &alsa_pcm_ops,    INIT_FIELD (can_be_default = ) 1,    INIT_FIELD (max_voices_out = ) INT_MAX,    INIT_FIELD (max_voices_in  = ) INT_MAX,    INIT_FIELD (voice_size_out = ) sizeof (ALSAVoiceOut),    INIT_FIELD (voice_size_in  = ) sizeof (ALSAVoiceIn)};

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -