Commit 7a24c800 authored by malc's avatar malc
Browse files

Rework period/buffer size setting

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4768 c046a42c-6fe2-441c-8c8c-71466251a162
parent 5b5ef0db
Loading
Loading
Loading
Loading
+52 −138
Original line number Diff line number Diff line
@@ -58,37 +58,15 @@ static struct {
    int period_size_out_overridden;
    int verbose;
} conf = {
#define DEFAULT_BUFFER_SIZE 1024
#define DEFAULT_PERIOD_SIZE 256
#ifdef HIGH_LATENCY
    .size_in_usec_in = 1,
    .size_in_usec_out = 1,
#endif
    .pcm_name_out = "default",
    .pcm_name_in = "default",
#ifdef HIGH_LATENCY
    .buffer_size_in = 400000,
    .period_size_in = 400000 / 4,
    .buffer_size_out = 400000,
    .period_size_out = 400000 / 4,
#else
    .buffer_size_in = DEFAULT_BUFFER_SIZE * 4,
    .period_size_in = DEFAULT_PERIOD_SIZE * 4,
    .buffer_size_out = DEFAULT_BUFFER_SIZE,
    .period_size_out = DEFAULT_PERIOD_SIZE,
    .buffer_size_in_overridden = 0,
    .buffer_size_out_overridden = 0,
    .period_size_in_overridden = 0,
    .period_size_out_overridden = 0,
#endif
    .threshold = 0,
    .verbose = 0
};

struct alsa_params_req {
    int freq;
    snd_pcm_format_t fmt;
    int nchannels;
    int size_in_usec;
    unsigned int buffer_size;
    unsigned int period_size;
};
@@ -286,17 +264,16 @@ static int alsa_open (int in, struct alsa_params_req *req,
    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;
    unsigned int period_size, buffer_size;
    snd_pcm_uframes_t obt_buffer_size;
    const char *typ = in ? "ADC" : "DAC";
    snd_pcm_format_t obtfmt;

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

    snd_pcm_hw_params_alloca (&hw_params);

@@ -356,131 +333,62 @@ static int alsa_open (int in, struct alsa_params_req *req,
        goto err;
    }

    if (!((in && conf.size_in_usec_in) || (!in && conf.size_in_usec_out))) {
        if (!buffer_size) {
            buffer_size = DEFAULT_BUFFER_SIZE;
            period_size= DEFAULT_PERIOD_SIZE;
        }
    }
    if (req->buffer_size) {
        if (size_in_usec) {
            int dir = 0;
            unsigned int btime = req->buffer_size;

    if (buffer_size) {
        if ((in && conf.size_in_usec_in) || (!in && conf.size_in_usec_out)) {
            if (period_size) {
                err = snd_pcm_hw_params_set_period_time_near (
            err = snd_pcm_hw_params_set_buffer_time_near (
                handle,
                hw_params,
                    &period_size,
                    0
                &btime,
                &dir
                );
                if (err < 0) {
                    alsa_logerr2 (err, typ,
                                  "Failed to set period time %d\n",
                                  req->period_size);
                    goto err;
                }
        }
        else {
            snd_pcm_uframes_t bsize = req->buffer_size;

            err = snd_pcm_hw_params_set_buffer_time_near (
            err = snd_pcm_hw_params_set_buffer_size_near (
                handle,
                hw_params,
                &buffer_size,
                0
                &bsize
                );

        }
        if (err < 0) {
                alsa_logerr2 (err, typ,
                              "Failed to set buffer time %d\n",
                              req->buffer_size);
            alsa_logerr2 (err, typ, "Failed to set buffer %s to %d\n",
                          size_in_usec ? "time" : "size", req->buffer_size);
            goto err;
        }
    }
        else {
            int dir;
            snd_pcm_uframes_t minval;

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

                err = snd_pcm_hw_params_get_period_size_min (
            err = snd_pcm_hw_params_set_period_time_near (
                handle,
                hw_params,
                    &minval,
                &ptime,
                &dir
                );
                if (err < 0) {
                    alsa_logerr (
                        err,
                        "Could not get minmal period size for %s\n",
                        typ
                        );
        }
        else {
                    if (period_size < minval) {
                        if ((in && conf.period_size_in_overridden)
                            || (!in && conf.period_size_out_overridden)) {
                            dolog ("%s period size(%d) is less "
                                   "than minmal period size(%ld)\n",
                                   typ,
                                   period_size,
                                   minval);
                        }
                        period_size = minval;
                    }
                }
            snd_pcm_uframes_t psize = req->period_size;

                err = snd_pcm_hw_params_set_period_size (
            err = snd_pcm_hw_params_set_buffer_size_near (
                handle,
                hw_params,
                    period_size,
                    0
                    );
                if (err < 0) {
                    alsa_logerr2 (err, typ, "Failed to set period size %d\n",
                                  req->period_size);
                    goto err;
                }
            }

            minval = buffer_size;
            err = snd_pcm_hw_params_get_buffer_size_min (
                hw_params,
                &minval
                );
            if (err < 0) {
                alsa_logerr (err, "Could not get minmal buffer size for %s\n",
                             typ);
            }
            else {
                if (buffer_size < minval) {
                    if ((in && conf.buffer_size_in_overridden)
                        || (!in && conf.buffer_size_out_overridden)) {
                        dolog (
                            "%s buffer size(%d) is less "
                            "than minimal buffer size(%ld)\n",
                            typ,
                            buffer_size,
                            minval
                &psize
                );
        }
                    buffer_size = minval;
                }
            }

            err = snd_pcm_hw_params_set_buffer_size (
                handle,
                hw_params,
                buffer_size
                );
        if (err < 0) {
                alsa_logerr2 (err, typ, "Failed to set buffer size %d\n",
                              req->buffer_size);
            alsa_logerr2 (err, typ, "Failed to set period %s to %d\n",
                          size_in_usec ? "time" : "size", req->period_size);
            goto err;
        }
    }
    }
    else {
        dolog ("warning: Buffer size is not set\n");
    }

    err = snd_pcm_hw_params (handle, hw_params);
    if (err < 0) {
@@ -697,6 +605,7 @@ static int alsa_init_out (HWVoiceOut *hw, audsettings_t *as)
    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_in;

    if (alsa_open (0, &req, &obt, &handle)) {
        return -1;
@@ -774,6 +683,7 @@ static int alsa_init_in (HWVoiceIn *hw, audsettings_t *as)
    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;

    if (alsa_open (1, &req, &obt, &handle)) {
        return -1;
@@ -953,16 +863,20 @@ 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_overridden, 0},
     "DAC period size (0 to go with system default)",
     &conf.period_size_out_overridden, 0},
    {"DAC_BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_size_out,
     "DAC buffer size", &conf.buffer_size_out_overridden, 0},
     "DAC buffer size (0 to go with system default)",
     &conf.buffer_size_out_overridden, 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_overridden, 0},
     "ADC period size (0 to go with system default)",
     &conf.period_size_in_overridden, 0},
    {"ADC_BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_size_in,
     "ADC buffer size", &conf.buffer_size_in_overridden, 0},
     "ADC buffer size (0 to go with system default)",
     &conf.buffer_size_in_overridden, 0},

    {"THRESHOLD", AUD_OPT_INT, &conf.threshold,
     "(undocumented)", NULL, 0},