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

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



audio: bugfixes, mostly audio backend rewrite fallout

# gpg: Signature made Fri 07 Feb 2020 07:45:44 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-20200207-pull-request:
  audio: proper support for float samples in mixeng
  coreaudio: fix coreaudio playback
  audio/dsound: fix invalid parameters error
  audio: audio_generic_get_buffer_in should honor *size
  ossaudio: disable poll mode can't be reached
  ossaudio: prevent SIGSEGV in oss_enable_out
  audio: fix bug 1858488
  audio: prevent SIGSEGV in AUD_get_buffer_size_out
  paaudio: remove unused variables
  audio: fix audio_generic_read
  audio: fix audio_generic_write
  audio/oss: fix buffer pos calculation

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents 346ed315 ed2a4a79
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -307,6 +307,13 @@ static snd_pcm_format_t aud_to_alsafmt (AudioFormat fmt, int endianness)
            return SND_PCM_FORMAT_U32_LE;
        }

    case AUDIO_FORMAT_F32:
        if (endianness) {
            return SND_PCM_FORMAT_FLOAT_BE;
        } else {
            return SND_PCM_FORMAT_FLOAT_LE;
        }

    default:
        dolog ("Internal logic error: Bad audio format %d\n", fmt);
#ifdef DEBUG_AUDIO
@@ -370,6 +377,16 @@ static int alsa_to_audfmt (snd_pcm_format_t alsafmt, AudioFormat *fmt,
        *fmt = AUDIO_FORMAT_U32;
        break;

    case SND_PCM_FORMAT_FLOAT_LE:
        *endianness = 0;
        *fmt = AUDIO_FORMAT_F32;
        break;

    case SND_PCM_FORMAT_FLOAT_BE:
        *endianness = 1;
        *fmt = AUDIO_FORMAT_F32;
        break;

    default:
        dolog ("Unrecognized audio format %d\n", alsafmt);
        return -1;
@@ -906,6 +923,7 @@ static struct audio_pcm_ops alsa_pcm_ops = {
    .init_out = alsa_init_out,
    .fini_out = alsa_fini_out,
    .write    = alsa_write,
    .run_buffer_out = audio_generic_run_buffer_out,
    .enable_out = alsa_enable_out,

    .init_in  = alsa_init_in,
+77 −62
Original line number Diff line number Diff line
@@ -218,6 +218,9 @@ static void audio_print_settings (struct audsettings *as)
    case AUDIO_FORMAT_U32:
        AUD_log (NULL, "U32");
        break;
    case AUDIO_FORMAT_F32:
        AUD_log (NULL, "F32");
        break;
    default:
        AUD_log (NULL, "invalid(%d)", as->fmt);
        break;
@@ -252,6 +255,7 @@ static int audio_validate_settings (struct audsettings *as)
    case AUDIO_FORMAT_U16:
    case AUDIO_FORMAT_S32:
    case AUDIO_FORMAT_U32:
    case AUDIO_FORMAT_F32:
        break;
    default:
        invalid = 1;
@@ -264,24 +268,28 @@ static int audio_validate_settings (struct audsettings *as)

static int audio_pcm_info_eq (struct audio_pcm_info *info, struct audsettings *as)
{
    int bits = 8, sign = 0;
    int bits = 8;
    bool is_signed = false, is_float = false;

    switch (as->fmt) {
    case AUDIO_FORMAT_S8:
        sign = 1;
        is_signed = true;
        /* fall through */
    case AUDIO_FORMAT_U8:
        break;

    case AUDIO_FORMAT_S16:
        sign = 1;
        is_signed = true;
        /* fall through */
    case AUDIO_FORMAT_U16:
        bits = 16;
        break;

    case AUDIO_FORMAT_F32:
        is_float = true;
        /* fall through */
    case AUDIO_FORMAT_S32:
        sign = 1;
        is_signed = true;
        /* fall through */
    case AUDIO_FORMAT_U32:
        bits = 32;
@@ -292,33 +300,38 @@ static int audio_pcm_info_eq (struct audio_pcm_info *info, struct audsettings *a
    }
    return info->freq == as->freq
        && info->nchannels == as->nchannels
        && info->sign == sign
        && info->is_signed == is_signed
        && info->is_float == is_float
        && info->bits == bits
        && info->swap_endianness == (as->endianness != AUDIO_HOST_ENDIANNESS);
}

void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as)
{
    int bits = 8, sign = 0, mul;
    int bits = 8, mul;
    bool is_signed = false, is_float = false;

    switch (as->fmt) {
    case AUDIO_FORMAT_S8:
        sign = 1;
        is_signed = true;
        /* fall through */
    case AUDIO_FORMAT_U8:
        mul = 1;
        break;

    case AUDIO_FORMAT_S16:
        sign = 1;
        is_signed = true;
        /* fall through */
    case AUDIO_FORMAT_U16:
        bits = 16;
        mul = 2;
        break;

    case AUDIO_FORMAT_F32:
        is_float = true;
        /* fall through */
    case AUDIO_FORMAT_S32:
        sign = 1;
        is_signed = true;
        /* fall through */
    case AUDIO_FORMAT_U32:
        bits = 32;
@@ -331,7 +344,8 @@ void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as)

    info->freq = as->freq;
    info->bits = bits;
    info->sign = sign;
    info->is_signed = is_signed;
    info->is_float = is_float;
    info->nchannels = as->nchannels;
    info->bytes_per_frame = as->nchannels * mul;
    info->bytes_per_second = info->freq * info->bytes_per_frame;
@@ -344,7 +358,7 @@ void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len)
        return;
    }

    if (info->sign) {
    if (info->is_signed || info->is_float) {
        memset(buf, 0x00, len * info->bytes_per_frame);
    }
    else {
@@ -770,8 +784,9 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
#ifdef DEBUG_AUDIO
static void audio_pcm_print_info (const char *cap, struct audio_pcm_info *info)
{
    dolog ("%s: bits %d, sign %d, freq %d, nchan %d\n",
           cap, info->bits, info->sign, info->freq, info->nchannels);
    dolog("%s: bits %d, sign %d, float %d, freq %d, nchan %d\n",
          cap, info->bits, info->is_signed, info->is_float, info->freq,
          info->nchannels);
}
#endif

@@ -881,7 +896,7 @@ size_t AUD_read(SWVoiceIn *sw, void *buf, size_t size)

int AUD_get_buffer_size_out(SWVoiceOut *sw)
{
    return sw->hw->mix_buf->size * sw->hw->info.bytes_per_frame;
    return sw->hw->samples * sw->hw->info.bytes_per_frame;
}

void AUD_set_active_out (SWVoiceOut *sw, int on)
@@ -1076,10 +1091,8 @@ static size_t audio_pcm_hw_run_out(HWVoiceOut *hw, size_t live)
    while (live) {
        size_t size, decr, proc;
        void *buf = hw->pcm_ops->get_buffer_out(hw, &size);
        if (!buf) {
            /* retrying will likely won't help, drop everything. */
            hw->mix_buf->pos = (hw->mix_buf->pos + live) % hw->mix_buf->size;
            return clipped + live;
        if (!buf || size == 0) {
            break;
        }

        decr = MIN(size / hw->info.bytes_per_frame, live);
@@ -1097,6 +1110,10 @@ static size_t audio_pcm_hw_run_out(HWVoiceOut *hw, size_t live)
        }
    }

    if (hw->pcm_ops->run_buffer_out) {
        hw->pcm_ops->run_buffer_out(hw);
    }

    return clipped;
}

@@ -1403,7 +1420,8 @@ void *audio_generic_get_buffer_in(HWVoiceIn *hw, size_t *size)
    }
    assert(start >= 0 && start < hw->size_emul);

    *size = MIN(hw->pending_emul, hw->size_emul - start);
    *size = MIN(*size, hw->pending_emul);
    *size = MIN(*size, hw->size_emul - start);
    return hw->buf_emul + start;
}

@@ -1413,6 +1431,28 @@ void audio_generic_put_buffer_in(HWVoiceIn *hw, void *buf, size_t size)
    hw->pending_emul -= size;
}

void audio_generic_run_buffer_out(HWVoiceOut *hw)
{
    while (hw->pending_emul) {
        size_t write_len, written;
        ssize_t start = ((ssize_t) hw->pos_emul) - hw->pending_emul;

        if (start < 0) {
            start += hw->size_emul;
        }
        assert(start >= 0 && start < hw->size_emul);

        write_len = MIN(hw->pending_emul, hw->size_emul - start);

        written = hw->pcm_ops->write(hw, hw->buf_emul + start, write_len);
        hw->pending_emul -= written;

        if (written < write_len) {
            break;
        }
    }
}

void *audio_generic_get_buffer_out(HWVoiceOut *hw, size_t *size)
{
    if (unlikely(!hw->buf_emul)) {
@@ -1428,8 +1468,7 @@ void *audio_generic_get_buffer_out(HWVoiceOut *hw, size_t *size)
    return hw->buf_emul + hw->pos_emul;
}

size_t audio_generic_put_buffer_out_nowrite(HWVoiceOut *hw, void *buf,
                                            size_t size)
size_t audio_generic_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size)
{
    assert(buf == hw->buf_emul + hw->pos_emul &&
           size + hw->pending_emul <= hw->size_emul);
@@ -1440,35 +1479,6 @@ size_t audio_generic_put_buffer_out_nowrite(HWVoiceOut *hw, void *buf,
    return size;
}

size_t audio_generic_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size)
{
    audio_generic_put_buffer_out_nowrite(hw, buf, size);

    while (hw->pending_emul) {
        size_t write_len, written;
        ssize_t start = ((ssize_t) hw->pos_emul) - hw->pending_emul;
        if (start < 0) {
            start += hw->size_emul;
        }
        assert(start >= 0 && start < hw->size_emul);

        write_len = MIN(hw->pending_emul, hw->size_emul - start);

        written = hw->pcm_ops->write(hw, hw->buf_emul + start, write_len);
        hw->pending_emul -= written;

        if (written < write_len) {
            break;
        }
    }

    /*
     * fake we have written everything. non-written data remain in pending_emul,
     * so we do not have to clip them multiple times
     */
    return size;
}

size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size)
{
    size_t dst_size, copy_size;
@@ -1476,17 +1486,17 @@ size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size)
    copy_size = MIN(size, dst_size);

    memcpy(dst, buf, copy_size);
    return hw->pcm_ops->put_buffer_out(hw, buf, copy_size);
    return hw->pcm_ops->put_buffer_out(hw, dst, copy_size);
}

size_t audio_generic_read(HWVoiceIn *hw, void *buf, size_t size)
{
    size_t dst_size, copy_size;
    void *dst = hw->pcm_ops->get_buffer_in(hw, &dst_size);
    copy_size = MIN(size, dst_size);
    size_t src_size, copy_size;
    void *src = hw->pcm_ops->get_buffer_in(hw, &src_size);
    copy_size = MIN(size, src_size);

    memcpy(dst, buf, copy_size);
    hw->pcm_ops->put_buffer_in(hw, buf, copy_size);
    memcpy(buf, src, copy_size);
    hw->pcm_ops->put_buffer_in(hw, src, copy_size);
    return copy_size;
}

@@ -1837,11 +1847,15 @@ CaptureVoiceOut *AUD_add_capture(

        cap->buf = g_malloc0_n(hw->mix_buf->size, hw->info.bytes_per_frame);

        if (hw->info.is_float) {
            hw->clip = mixeng_clip_float[hw->info.nchannels == 2];
        } else {
            hw->clip = mixeng_clip
                [hw->info.nchannels == 2]
            [hw->info.sign]
                [hw->info.is_signed]
                [hw->info.swap_endianness]
                [audio_bits_to_index(hw->info.bits)];
        }

        QLIST_INSERT_HEAD (&s->cap_head, cap, entries);
        QLIST_INSERT_HEAD (&cap->cb_head, cb, entries);
@@ -2080,6 +2094,7 @@ int audioformat_bytes_per_sample(AudioFormat fmt)

    case AUDIO_FORMAT_U32:
    case AUDIO_FORMAT_S32:
    case AUDIO_FORMAT_F32:
        return 4;

    case AUDIO_FORMAT__MAX:
+4 −3
Original line number Diff line number Diff line
@@ -40,7 +40,8 @@ struct audio_callback {

struct audio_pcm_info {
    int bits;
    int sign;
    bool is_signed;
    bool is_float;
    int freq;
    int nchannels;
    int bytes_per_frame;
@@ -152,6 +153,7 @@ struct audio_pcm_ops {
    int    (*init_out)(HWVoiceOut *hw, audsettings *as, void *drv_opaque);
    void   (*fini_out)(HWVoiceOut *hw);
    size_t (*write)   (HWVoiceOut *hw, void *buf, size_t size);
    void   (*run_buffer_out)(HWVoiceOut *hw);
    /*
     * get a buffer that after later can be passed to put_buffer_out; optional
     * returns the buffer, and writes it's size to size (in bytes)
@@ -178,10 +180,9 @@ struct audio_pcm_ops {

void *audio_generic_get_buffer_in(HWVoiceIn *hw, size_t *size);
void audio_generic_put_buffer_in(HWVoiceIn *hw, void *buf, size_t size);
void audio_generic_run_buffer_out(HWVoiceOut *hw);
void *audio_generic_get_buffer_out(HWVoiceOut *hw, size_t *size);
size_t audio_generic_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size);
size_t audio_generic_put_buffer_out_nowrite(HWVoiceOut *hw, void *buf,
                                            size_t size);
size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size);
size_t audio_generic_read(HWVoiceIn *hw, void *buf, size_t size);

+28 −12
Original line number Diff line number Diff line
@@ -153,15 +153,23 @@ static int glue (audio_pcm_sw_init_, TYPE) (
    sw->ratio = ((int64_t) sw->info.freq << 32) / sw->hw->info.freq;
#endif

    if (sw->info.is_float) {
#ifdef DAC
        sw->conv = mixeng_conv_float[sw->info.nchannels == 2];
#else
        sw->clip = mixeng_clip_float[sw->info.nchannels == 2];
#endif
    } else {
#ifdef DAC
        sw->conv = mixeng_conv
#else
        sw->clip = mixeng_clip
#endif
            [sw->info.nchannels == 2]
        [sw->info.sign]
            [sw->info.is_signed]
            [sw->info.swap_endianness]
            [audio_bits_to_index(sw->info.bits)];
    }

    sw->name = g_strdup (name);
    err = glue (audio_pcm_sw_alloc_resources_, TYPE) (sw);
@@ -276,15 +284,23 @@ static HW *glue(audio_pcm_hw_add_new_, TYPE)(AudioState *s,
        goto err1;
    }

    if (hw->info.is_float) {
#ifdef DAC
        hw->clip = mixeng_clip_float[hw->info.nchannels == 2];
#else
        hw->conv = mixeng_conv_float[hw->info.nchannels == 2];
#endif
    } else {
#ifdef DAC
        hw->clip = mixeng_clip
#else
        hw->conv = mixeng_conv
#endif
            [hw->info.nchannels == 2]
        [hw->info.sign]
            [hw->info.is_signed]
            [hw->info.swap_endianness]
            [audio_bits_to_index(hw->info.bits)];
    }

    glue(audio_pcm_hw_alloc_resources_, TYPE)(hw);

+9 −25
Original line number Diff line number Diff line
@@ -411,7 +411,7 @@ static int coreaudio_unlock (coreaudioVoiceOut *core, const char *fn_name)
    }
COREAUDIO_WRAPPER_FUNC(get_buffer_out, void *, (HWVoiceOut *hw, size_t *size),
                       (hw, size))
COREAUDIO_WRAPPER_FUNC(put_buffer_out_nowrite, size_t,
COREAUDIO_WRAPPER_FUNC(put_buffer_out, size_t,
                       (HWVoiceOut *hw, void *buf, size_t size),
                       (hw, buf, size))
COREAUDIO_WRAPPER_FUNC(write, size_t, (HWVoiceOut *hw, void *buf, size_t size),
@@ -471,20 +471,6 @@ static OSStatus audioDeviceIOProc(
    return 0;
}

static UInt32 coreaudio_get_flags(struct audio_pcm_info *info,
                                  struct audsettings *as)
{
    UInt32 flags = info->sign ? kAudioFormatFlagIsSignedInteger : 0;
    if (as->endianness) { /* 0 = little, 1 = big */
        flags |= kAudioFormatFlagIsBigEndian;
    }

    if (flags == 0) { /* must not be 0 */
        flags = kAudioFormatFlagsAreAllClear;
    }
    return flags;
}

static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
                              void *drv_opaque)
{
@@ -496,6 +482,7 @@ static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
    Audiodev *dev = drv_opaque;
    AudiodevCoreaudioPerDirectionOptions *cpdo = dev->u.coreaudio.out;
    int frames;
    struct audsettings fake_as;

    /* create mutex */
    err = pthread_mutex_init(&core->mutex, NULL);
@@ -504,6 +491,9 @@ static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
        return -1;
    }

    fake_as = *as;
    as = &fake_as;
    as->fmt = AUDIO_FORMAT_F32;
    audio_pcm_init_info (&hw->info, as);

    status = coreaudio_get_voice(&core->outputDeviceID);
@@ -572,15 +562,6 @@ static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,

    /* set Samplerate */
    core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq;
    core->outputStreamBasicDescription.mFormatID = kAudioFormatLinearPCM;
    core->outputStreamBasicDescription.mFormatFlags =
        coreaudio_get_flags(&hw->info, as);
    core->outputStreamBasicDescription.mBytesPerPacket =
        core->outputStreamBasicDescription.mBytesPerFrame =
        hw->info.nchannels * hw->info.bits / 8;
    core->outputStreamBasicDescription.mFramesPerPacket = 1;
    core->outputStreamBasicDescription.mChannelsPerFrame = hw->info.nchannels;
    core->outputStreamBasicDescription.mBitsPerChannel = hw->info.bits;

    status = coreaudio_set_streamformat(core->outputDeviceID,
                                        &core->outputStreamBasicDescription);
@@ -687,9 +668,12 @@ static void coreaudio_audio_fini (void *opaque)
static struct audio_pcm_ops coreaudio_pcm_ops = {
    .init_out = coreaudio_init_out,
    .fini_out = coreaudio_fini_out,
  /* wrapper for audio_generic_write */
    .write    = coreaudio_write,
  /* wrapper for audio_generic_get_buffer_out */
    .get_buffer_out = coreaudio_get_buffer_out,
    .put_buffer_out = coreaudio_put_buffer_out_nowrite,
  /* wrapper for audio_generic_put_buffer_out */
    .put_buffer_out = coreaudio_put_buffer_out,
    .enable_out = coreaudio_enable_out
};

Loading