Commit cfc3fef6 authored by Peter Maydell's avatar Peter Maydell
Browse files

Merge remote-tracking branch 'remotes/kraxel/tags/audio-20190312-pull-request' into staging



audio: introduce -audiodev

# gpg: Signature made Tue 12 Mar 2019 07:12:19 GMT
# gpg:                using RSA key 4CB6D8EED3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>" [full]
# gpg:                 aka "Gerd Hoffmann <gerd@kraxel.org>" [full]
# gpg:                 aka "Gerd Hoffmann (private) <kraxel@gmail.com>" [full]
# Primary key fingerprint: A032 8CFF B93A 17A7 9901  FE7D 4CB6 D8EE D3E8 7138

* remotes/kraxel/tags/audio-20190312-pull-request:
  audio: -audiodev command line option: cleanup
  wavaudio: port to -audiodev config
  spiceaudio: port to -audiodev config
  sdlaudio: port to -audiodev config
  paaudio: port to -audiodev config
  ossaudio: port to -audiodev config
  noaudio: port to -audiodev config
  dsoundaudio: port to -audiodev config
  coreaudio: port to -audiodev config
  alsaaudio: port to -audiodev config
  audio: -audiodev command line option basic implementation
  audio: -audiodev command line option: documentation
  audio: use qapi AudioFormat instead of audfmt_e
  qapi: qapi for audio backends

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>

# Conflicts:
#	qemu-deprecated.texi
parents 2cb73afa 05d2f2a6
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
common-obj-y = audio.o noaudio.o wavaudio.o mixeng.o
common-obj-y = audio.o audio_legacy.o noaudio.o wavaudio.o mixeng.o
common-obj-$(CONFIG_SPICE) += spiceaudio.o
common-obj-$(CONFIG_AUDIO_COREAUDIO) += coreaudio.o
common-obj-$(CONFIG_AUDIO_DSOUND) += dsoundaudio.o
+120 −250
Original line number Diff line number Diff line
@@ -33,28 +33,9 @@
#define AUDIO_CAP "alsa"
#include "audio_int.h"

typedef struct ALSAConf {
    int size_in_usec_in;
    int size_in_usec_out;
    const char *pcm_name_in;
    const char *pcm_name_out;
    unsigned int buffer_size_in;
    unsigned int period_size_in;
    unsigned int buffer_size_out;
    unsigned int period_size_out;
    unsigned int threshold;

    int buffer_size_in_overridden;
    int period_size_in_overridden;

    int buffer_size_out_overridden;
    int period_size_out_overridden;
} ALSAConf;

struct pollhlp {
    snd_pcm_t *handle;
    struct pollfd *pfds;
    ALSAConf *conf;
    int count;
    int mask;
};
@@ -66,6 +47,7 @@ typedef struct ALSAVoiceOut {
    void *pcm_buf;
    snd_pcm_t *handle;
    struct pollhlp pollhlp;
    Audiodev *dev;
} ALSAVoiceOut;

typedef struct ALSAVoiceIn {
@@ -73,21 +55,18 @@ typedef struct ALSAVoiceIn {
    snd_pcm_t *handle;
    void *pcm_buf;
    struct pollhlp pollhlp;
    Audiodev *dev;
} ALSAVoiceIn;

struct alsa_params_req {
    int freq;
    snd_pcm_format_t fmt;
    int nchannels;
    int size_in_usec;
    int override_mask;
    unsigned int buffer_size;
    unsigned int period_size;
};

struct alsa_params_obt {
    int freq;
    audfmt_e fmt;
    AudioFormat fmt;
    int endianness;
    int nchannels;
    snd_pcm_uframes_t samples;
@@ -294,16 +273,16 @@ static int alsa_write (SWVoiceOut *sw, void *buf, int len)
    return audio_pcm_sw_write (sw, buf, len);
}

static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt, int endianness)
static snd_pcm_format_t aud_to_alsafmt (AudioFormat fmt, int endianness)
{
    switch (fmt) {
    case AUD_FMT_S8:
    case AUDIO_FORMAT_S8:
        return SND_PCM_FORMAT_S8;

    case AUD_FMT_U8:
    case AUDIO_FORMAT_U8:
        return SND_PCM_FORMAT_U8;

    case AUD_FMT_S16:
    case AUDIO_FORMAT_S16:
        if (endianness) {
            return SND_PCM_FORMAT_S16_BE;
        }
@@ -311,7 +290,7 @@ static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt, int endianness)
            return SND_PCM_FORMAT_S16_LE;
        }

    case AUD_FMT_U16:
    case AUDIO_FORMAT_U16:
        if (endianness) {
            return SND_PCM_FORMAT_U16_BE;
        }
@@ -319,7 +298,7 @@ static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt, int endianness)
            return SND_PCM_FORMAT_U16_LE;
        }

    case AUD_FMT_S32:
    case AUDIO_FORMAT_S32:
        if (endianness) {
            return SND_PCM_FORMAT_S32_BE;
        }
@@ -327,7 +306,7 @@ static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt, int endianness)
            return SND_PCM_FORMAT_S32_LE;
        }

    case AUD_FMT_U32:
    case AUDIO_FORMAT_U32:
        if (endianness) {
            return SND_PCM_FORMAT_U32_BE;
        }
@@ -344,58 +323,58 @@ static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt, int endianness)
    }
}

static int alsa_to_audfmt (snd_pcm_format_t alsafmt, audfmt_e *fmt,
static int alsa_to_audfmt (snd_pcm_format_t alsafmt, AudioFormat *fmt,
                           int *endianness)
{
    switch (alsafmt) {
    case SND_PCM_FORMAT_S8:
        *endianness = 0;
        *fmt = AUD_FMT_S8;
        *fmt = AUDIO_FORMAT_S8;
        break;

    case SND_PCM_FORMAT_U8:
        *endianness = 0;
        *fmt = AUD_FMT_U8;
        *fmt = AUDIO_FORMAT_U8;
        break;

    case SND_PCM_FORMAT_S16_LE:
        *endianness = 0;
        *fmt = AUD_FMT_S16;
        *fmt = AUDIO_FORMAT_S16;
        break;

    case SND_PCM_FORMAT_U16_LE:
        *endianness = 0;
        *fmt = AUD_FMT_U16;
        *fmt = AUDIO_FORMAT_U16;
        break;

    case SND_PCM_FORMAT_S16_BE:
        *endianness = 1;
        *fmt = AUD_FMT_S16;
        *fmt = AUDIO_FORMAT_S16;
        break;

    case SND_PCM_FORMAT_U16_BE:
        *endianness = 1;
        *fmt = AUD_FMT_U16;
        *fmt = AUDIO_FORMAT_U16;
        break;

    case SND_PCM_FORMAT_S32_LE:
        *endianness = 0;
        *fmt = AUD_FMT_S32;
        *fmt = AUDIO_FORMAT_S32;
        break;

    case SND_PCM_FORMAT_U32_LE:
        *endianness = 0;
        *fmt = AUD_FMT_U32;
        *fmt = AUDIO_FORMAT_U32;
        break;

    case SND_PCM_FORMAT_S32_BE:
        *endianness = 1;
        *fmt = AUD_FMT_S32;
        *fmt = AUDIO_FORMAT_S32;
        break;

    case SND_PCM_FORMAT_U32_BE:
        *endianness = 1;
        *fmt = AUD_FMT_U32;
        *fmt = AUDIO_FORMAT_U32;
        break;

    default:
@@ -408,7 +387,8 @@ static int alsa_to_audfmt (snd_pcm_format_t alsafmt, audfmt_e *fmt,

static void alsa_dump_info (struct alsa_params_req *req,
                            struct alsa_params_obt *obt,
                            snd_pcm_format_t obtfmt)
                            snd_pcm_format_t obtfmt,
                            AudiodevAlsaPerDirectionOptions *apdo)
{
    dolog("parameter | requested value | obtained value\n");
    dolog("format    |      %10d |     %10d\n", req->fmt, obtfmt);
@@ -416,8 +396,8 @@ static void alsa_dump_info (struct alsa_params_req *req,
          req->nchannels, obt->nchannels);
    dolog("frequency |      %10d |     %10d\n", req->freq, obt->freq);
    dolog("============================================\n");
    dolog ("requested: buffer size %d period size %d\n",
           req->buffer_size, req->period_size);
    dolog("requested: buffer len %" PRId32 " period len %" PRId32 "\n",
          apdo->buffer_length, apdo->period_length);
    dolog("obtained: samples %ld\n", obt->samples);
}

@@ -451,23 +431,23 @@ static void alsa_set_threshold (snd_pcm_t *handle, snd_pcm_uframes_t threshold)
    }
}

static int alsa_open (int in, struct alsa_params_req *req,
static int alsa_open(bool in, struct alsa_params_req *req,
                     struct alsa_params_obt *obt, snd_pcm_t **handlep,
                      ALSAConf *conf)
                     Audiodev *dev)
{
    AudiodevAlsaOptions *aopts = &dev->u.alsa;
    AudiodevAlsaPerDirectionOptions *apdo = in ? aopts->in : aopts->out;
    snd_pcm_t *handle;
    snd_pcm_hw_params_t *hw_params;
    int err;
    int size_in_usec;
    unsigned int freq, nchannels;
    const char *pcm_name = in ? conf->pcm_name_in : conf->pcm_name_out;
    const char *pcm_name = apdo->has_dev ? apdo->dev : "default";
    snd_pcm_uframes_t obt_buffer_size;
    const char *typ = in ? "ADC" : "DAC";
    snd_pcm_format_t obtfmt;

    freq = req->freq;
    nchannels = req->nchannels;
    size_in_usec = req->size_in_usec;

    snd_pcm_hw_params_alloca (&hw_params);

@@ -527,79 +507,42 @@ static int alsa_open (int in, struct alsa_params_req *req,
        goto err;
    }

    if (req->buffer_size) {
        unsigned long obt;

        if (size_in_usec) {
    if (apdo->buffer_length) {
        int dir = 0;
            unsigned int btime = req->buffer_size;
        unsigned int btime = apdo->buffer_length;

        err = snd_pcm_hw_params_set_buffer_time_near(
                handle,
                hw_params,
                &btime,
                &dir
                );
            obt = btime;
        }
        else {
            snd_pcm_uframes_t bsize = req->buffer_size;
            handle, hw_params, &btime, &dir);

            err = snd_pcm_hw_params_set_buffer_size_near (
                handle,
                hw_params,
                &bsize
                );
            obt = bsize;
        }
        if (err < 0) {
            alsa_logerr2 (err, typ, "Failed to set buffer %s to %d\n",
                          size_in_usec ? "time" : "size", req->buffer_size);
            alsa_logerr2(err, typ, "Failed to set buffer time to %" PRId32 "\n",
                         apdo->buffer_length);
            goto err;
        }

        if ((req->override_mask & 2) && (obt - req->buffer_size))
            dolog ("Requested buffer %s %u was rejected, using %lu\n",
                   size_in_usec ? "time" : "size", req->buffer_size, obt);
        if (apdo->has_buffer_length && btime != apdo->buffer_length) {
            dolog("Requested buffer time %" PRId32
                  " was rejected, using %u\n", apdo->buffer_length, btime);
        }

    if (req->period_size) {
        unsigned long obt;

        if (size_in_usec) {
            int dir = 0;
            unsigned int ptime = req->period_size;

            err = snd_pcm_hw_params_set_period_time_near (
                handle,
                hw_params,
                &ptime,
                &dir
                );
            obt = ptime;
    }
        else {

    if (apdo->period_length) {
        int dir = 0;
            snd_pcm_uframes_t psize = req->period_size;
        unsigned int ptime = apdo->period_length;

            err = snd_pcm_hw_params_set_period_size_near (
                handle,
                hw_params,
                &psize,
                &dir
                );
            obt = psize;
        }
        err = snd_pcm_hw_params_set_period_time_near(handle, hw_params, &ptime,
                                                     &dir);

        if (err < 0) {
            alsa_logerr2 (err, typ, "Failed to set period %s to %d\n",
                          size_in_usec ? "time" : "size", req->period_size);
            alsa_logerr2(err, typ, "Failed to set period time to %" PRId32 "\n",
                         apdo->period_length);
            goto err;
        }

        if (((req->override_mask & 1) && (obt - req->period_size)))
            dolog ("Requested period %s %u was rejected, using %lu\n",
                   size_in_usec ? "time" : "size", req->period_size, obt);
        if (apdo->has_period_length && ptime != apdo->period_length) {
            dolog("Requested period time %" PRId32 " was rejected, using %d\n",
                  apdo->period_length, ptime);
        }
    }

    err = snd_pcm_hw_params (handle, hw_params);
@@ -631,30 +574,12 @@ static int alsa_open (int in, struct alsa_params_req *req,
        goto err;
    }

    if (!in && conf->threshold) {
        snd_pcm_uframes_t threshold;
        int bytes_per_sec;

        bytes_per_sec = freq << (nchannels == 2);

        switch (obt->fmt) {
        case AUD_FMT_S8:
        case AUD_FMT_U8:
            break;

        case AUD_FMT_S16:
        case AUD_FMT_U16:
            bytes_per_sec <<= 1;
            break;

        case AUD_FMT_S32:
        case AUD_FMT_U32:
            bytes_per_sec <<= 2;
            break;
        }

        threshold = (conf->threshold * bytes_per_sec) / 1000;
        alsa_set_threshold (handle, threshold);
    if (!in && aopts->has_threshold && aopts->threshold) {
        struct audsettings as = { .freq = freq };
        alsa_set_threshold(
            handle,
            audio_buffer_frames(qapi_AudiodevAlsaPerDirectionOptions_base(apdo),
                                &as, aopts->threshold));
    }

    obt->nchannels = nchannels;
@@ -667,11 +592,11 @@ static int alsa_open (int in, struct alsa_params_req *req,
         obt->nchannels != req->nchannels ||
         obt->freq != req->freq) {
        dolog ("Audio parameters for %s\n", typ);
        alsa_dump_info (req, obt, obtfmt);
        alsa_dump_info(req, obt, obtfmt, apdo);
    }

#ifdef DEBUG
    alsa_dump_info (req, obt, obtfmt);
    alsa_dump_info(req, obt, obtfmt, pdo);
#endif
    return 0;

@@ -797,19 +722,13 @@ static int alsa_init_out(HWVoiceOut *hw, struct audsettings *as,
    struct alsa_params_obt obt;
    snd_pcm_t *handle;
    struct audsettings obt_as;
    ALSAConf *conf = drv_opaque;
    Audiodev *dev = drv_opaque;

    req.fmt = aud_to_alsafmt (as->fmt, as->endianness);
    req.freq = as->freq;
    req.nchannels = as->nchannels;
    req.period_size = conf->period_size_out;
    req.buffer_size = conf->buffer_size_out;
    req.size_in_usec = conf->size_in_usec_out;
    req.override_mask =
        (conf->period_size_out_overridden ? 1 : 0) |
        (conf->buffer_size_out_overridden ? 2 : 0);

    if (alsa_open (0, &req, &obt, &handle, conf)) {

    if (alsa_open(0, &req, &obt, &handle, dev)) {
        return -1;
    }

@@ -830,7 +749,7 @@ static int alsa_init_out(HWVoiceOut *hw, struct audsettings *as,
    }

    alsa->handle = handle;
    alsa->pollhlp.conf = conf;
    alsa->dev = dev;
    return 0;
}

@@ -870,16 +789,12 @@ static int alsa_voice_ctl (snd_pcm_t *handle, const char *typ, int ctl)
static int alsa_ctl_out (HWVoiceOut *hw, int cmd, ...)
{
    ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
    AudiodevAlsaPerDirectionOptions *apdo = alsa->dev->u.alsa.out;

    switch (cmd) {
    case VOICE_ENABLE:
        {
            va_list ap;
            int poll_mode;

            va_start (ap, cmd);
            poll_mode = va_arg (ap, int);
            va_end (ap);
            bool poll_mode = apdo->try_poll;

            ldebug ("enabling voice\n");
            if (poll_mode && alsa_poll_out (hw)) {
@@ -908,19 +823,13 @@ static int alsa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
    struct alsa_params_obt obt;
    snd_pcm_t *handle;
    struct audsettings obt_as;
    ALSAConf *conf = drv_opaque;
    Audiodev *dev = drv_opaque;

    req.fmt = aud_to_alsafmt (as->fmt, as->endianness);
    req.freq = as->freq;
    req.nchannels = as->nchannels;
    req.period_size = conf->period_size_in;
    req.buffer_size = conf->buffer_size_in;
    req.size_in_usec = conf->size_in_usec_in;
    req.override_mask =
        (conf->period_size_in_overridden ? 1 : 0) |
        (conf->buffer_size_in_overridden ? 2 : 0);

    if (alsa_open (1, &req, &obt, &handle, conf)) {

    if (alsa_open(1, &req, &obt, &handle, dev)) {
        return -1;
    }

@@ -941,7 +850,7 @@ static int alsa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
    }

    alsa->handle = handle;
    alsa->pollhlp.conf = conf;
    alsa->dev = dev;
    return 0;
}

@@ -1083,16 +992,12 @@ static int alsa_read (SWVoiceIn *sw, void *buf, int size)
static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...)
{
    ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
    AudiodevAlsaPerDirectionOptions *apdo = alsa->dev->u.alsa.in;

    switch (cmd) {
    case VOICE_ENABLE:
        {
            va_list ap;
            int poll_mode;

            va_start (ap, cmd);
            poll_mode = va_arg (ap, int);
            va_end (ap);
            bool poll_mode = apdo->try_poll;

            ldebug ("enabling voice\n");
            if (poll_mode && alsa_poll_in (hw)) {
@@ -1115,87 +1020,53 @@ static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...)
    return -1;
}

static ALSAConf glob_conf = {
    .buffer_size_out = 4096,
    .period_size_out = 1024,
    .pcm_name_out = "default",
    .pcm_name_in = "default",
};

static void *alsa_audio_init (void)
static void alsa_init_per_direction(AudiodevAlsaPerDirectionOptions *apdo)
{
    ALSAConf *conf = g_malloc(sizeof(ALSAConf));
    *conf = glob_conf;
    return conf;
    if (!apdo->has_try_poll) {
        apdo->try_poll = true;
        apdo->has_try_poll = true;
    }
}

static void alsa_audio_fini (void *opaque)
static void *alsa_audio_init(Audiodev *dev)
{
    g_free(opaque);
    AudiodevAlsaOptions *aopts;
    assert(dev->driver == AUDIODEV_DRIVER_ALSA);

    aopts = &dev->u.alsa;
    alsa_init_per_direction(aopts->in);
    alsa_init_per_direction(aopts->out);

    /*
     * need to define them, as otherwise alsa produces no sound
     * doesn't set has_* so alsa_open can identify it wasn't set by the user
     */
    if (!dev->u.alsa.out->has_period_length) {
        /* 1024 frames assuming 44100Hz */
        dev->u.alsa.out->period_length = 1024 * 1000000 / 44100;
    }
    if (!dev->u.alsa.out->has_buffer_length) {
        /* 4096 frames assuming 44100Hz */
        dev->u.alsa.out->buffer_length = 4096ll * 1000000 / 44100;
    }

static struct audio_option alsa_options[] = {
    {
        .name        = "DAC_SIZE_IN_USEC",
        .tag         = AUD_OPT_BOOL,
        .valp        = &glob_conf.size_in_usec_out,
        .descr       = "DAC period/buffer size in microseconds (otherwise in frames)"
    },
    {
        .name        = "DAC_PERIOD_SIZE",
        .tag         = AUD_OPT_INT,
        .valp        = &glob_conf.period_size_out,
        .descr       = "DAC period size (0 to go with system default)",
        .overriddenp = &glob_conf.period_size_out_overridden
    },
    {
        .name        = "DAC_BUFFER_SIZE",
        .tag         = AUD_OPT_INT,
        .valp        = &glob_conf.buffer_size_out,
        .descr       = "DAC buffer size (0 to go with system default)",
        .overriddenp = &glob_conf.buffer_size_out_overridden
    },
    {
        .name        = "ADC_SIZE_IN_USEC",
        .tag         = AUD_OPT_BOOL,
        .valp        = &glob_conf.size_in_usec_in,
        .descr       =
        "ADC period/buffer size in microseconds (otherwise in frames)"
    },
    {
        .name        = "ADC_PERIOD_SIZE",
        .tag         = AUD_OPT_INT,
        .valp        = &glob_conf.period_size_in,
        .descr       = "ADC period size (0 to go with system default)",
        .overriddenp = &glob_conf.period_size_in_overridden
    },
    {
        .name        = "ADC_BUFFER_SIZE",
        .tag         = AUD_OPT_INT,
        .valp        = &glob_conf.buffer_size_in,
        .descr       = "ADC buffer size (0 to go with system default)",
        .overriddenp = &glob_conf.buffer_size_in_overridden
    },
    {
        .name        = "THRESHOLD",
        .tag         = AUD_OPT_INT,
        .valp        = &glob_conf.threshold,
        .descr       = "(undocumented)"
    },
    {
        .name        = "DAC_DEV",
        .tag         = AUD_OPT_STR,
        .valp        = &glob_conf.pcm_name_out,
        .descr       = "DAC device name (for instance dmix)"
    },
    /*
     * OptsVisitor sets unspecified optional fields to zero, but do not depend
     * on it...
     */
    if (!dev->u.alsa.in->has_period_length) {
        dev->u.alsa.in->period_length = 0;
    }
    if (!dev->u.alsa.in->has_buffer_length) {
        dev->u.alsa.in->buffer_length = 0;
    }

    return dev;
}

static void alsa_audio_fini (void *opaque)
{
        .name        = "ADC_DEV",
        .tag         = AUD_OPT_STR,
        .valp        = &glob_conf.pcm_name_in,
        .descr       = "ADC device name"
    },
    { /* End of list */ }
};
}

static struct audio_pcm_ops alsa_pcm_ops = {
    .init_out = alsa_init_out,
@@ -1214,7 +1085,6 @@ static struct audio_pcm_ops alsa_pcm_ops = {
static struct audio_driver alsa_audio_driver = {
    .name           = "alsa",
    .descr          = "ALSA http://www.alsa-project.org",
    .options        = alsa_options,
    .init           = alsa_audio_init,
    .fini           = alsa_audio_fini,
    .pcm_ops        = &alsa_pcm_ops,
+299 −560

File changed.

Preview size limit exceeded, changes collapsed.

+17 −13
Original line number Diff line number Diff line
@@ -26,30 +26,31 @@
#define QEMU_AUDIO_H

#include "qemu/queue.h"
#include "qapi/qapi-types-audio.h"

typedef void (*audio_callback_fn) (void *opaque, int avail);

typedef enum {
    AUD_FMT_U8,
    AUD_FMT_S8,
    AUD_FMT_U16,
    AUD_FMT_S16,
    AUD_FMT_U32,
    AUD_FMT_S32
} audfmt_e;

#ifdef HOST_WORDS_BIGENDIAN
#define AUDIO_HOST_ENDIANNESS 1
#else
#define AUDIO_HOST_ENDIANNESS 0
#endif

struct audsettings {
typedef struct audsettings {
    int freq;
    int nchannels;
    audfmt_e fmt;
    AudioFormat fmt;
    int endianness;
};
} audsettings;

audsettings audiodev_to_audsettings(AudiodevPerDirectionOptions *pdo);
int audioformat_bytes_per_sample(AudioFormat fmt);
int audio_buffer_frames(AudiodevPerDirectionOptions *pdo,
                        audsettings *as, int def_usecs);
int audio_buffer_samples(AudiodevPerDirectionOptions *pdo,
                         audsettings *as, int def_usecs);
int audio_buffer_bytes(AudiodevPerDirectionOptions *pdo,
                       audsettings *as, int def_usecs);

typedef enum {
    AUD_CNOTIFY_ENABLE,
@@ -89,7 +90,6 @@ typedef struct QEMUAudioTimeStamp {
void AUD_vlog (const char *cap, const char *fmt, va_list ap) GCC_FMT_ATTR(2, 0);
void AUD_log (const char *cap, const char *fmt, ...) GCC_FMT_ATTR(2, 3);

void AUD_help (void);
void AUD_register_card (const char *name, QEMUSoundCard *card);
void AUD_remove_card (QEMUSoundCard *card);
CaptureVoiceOut *AUD_add_capture (
@@ -171,4 +171,8 @@ void audio_sample_to_uint64(void *samples, int pos,
void audio_sample_from_uint64(void *samples, int pos,
                            uint64_t left, uint64_t right);

void audio_parse_option(const char *opt);
void audio_init_audiodevs(void);
void audio_legacy_help(void);

#endif /* QEMU_AUDIO_H */
+19 −18
Original line number Diff line number Diff line
@@ -33,22 +33,6 @@

struct audio_pcm_ops;

typedef enum {
    AUD_OPT_INT,
    AUD_OPT_FMT,
    AUD_OPT_STR,
    AUD_OPT_BOOL
} audio_option_tag_e;

struct audio_option {
    const char *name;
    audio_option_tag_e tag;
    void *valp;
    const char *descr;
    int *overriddenp;
    int overridden;
};

struct audio_callback {
    void *opaque;
    audio_callback_fn fn;
@@ -145,8 +129,7 @@ typedef struct audio_driver audio_driver;
struct audio_driver {
    const char *name;
    const char *descr;
    struct audio_option *options;
    void *(*init) (void);
    void *(*init) (Audiodev *);
    void (*fini) (void *);
    struct audio_pcm_ops *pcm_ops;
    int can_be_default;
@@ -193,6 +176,7 @@ struct SWVoiceCap {

typedef struct AudioState {
    struct audio_driver *drv;
    Audiodev *dev;
    void *drv_opaque;

    QEMUTimer *ts;
@@ -203,10 +187,13 @@ typedef struct AudioState {
    int nb_hw_voices_out;
    int nb_hw_voices_in;
    int vm_running;
    int64_t period_ticks;
} AudioState;

extern const struct mixeng_volume nominal_volume;

extern const char *audio_prio_list[];

void audio_driver_register(audio_driver *drv);
audio_driver *audio_driver_lookup(const char *name);

@@ -248,4 +235,18 @@ static inline int audio_ring_dist (int dst, int src, int len)
#define AUDIO_STRINGIFY_(n) #n
#define AUDIO_STRINGIFY(n) AUDIO_STRINGIFY_(n)

typedef struct AudiodevListEntry {
    Audiodev *dev;
    QSIMPLEQ_ENTRY(AudiodevListEntry) next;
} AudiodevListEntry;

typedef QSIMPLEQ_HEAD(, AudiodevListEntry) AudiodevListHead;
AudiodevListHead audio_handle_legacy_opts(void);

void audio_free_audiodev_list(AudiodevListHead *head);

void audio_create_pdos(Audiodev *dev);
AudiodevPerDirectionOptions *audio_get_pdo_in(Audiodev *dev);
AudiodevPerDirectionOptions *audio_get_pdo_out(Audiodev *dev);

#endif /* QEMU_AUDIO_INT_H */
Loading