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

Merge remote-tracking branch 'remotes/kraxel/tags/pull-audio-20170301-1' into staging



audio: replay support, sdl2 fix.

# gpg: Signature made Wed 01 Mar 2017 15:38:09 GMT
# gpg:                using RSA key 0x4CB6D8EED3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>"
# gpg:                 aka "Gerd Hoffmann <gerd@kraxel.org>"
# gpg:                 aka "Gerd Hoffmann (private) <kraxel@gmail.com>"
# Primary key fingerprint: A032 8CFF B93A 17A7 9901  FE7D 4CB6 D8EE D3E8 7138

* remotes/kraxel/tags/pull-audio-20170301-1:
  audio/sdlaudio: Allow audio playback with SDL2
  audio: make audio poll timer deterministic
  replay: add record/replay for audio passthrough

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents b49d31a0 bcf19777
Loading
Loading
Loading
Loading
+8 −3
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@
#include "qemu/timer.h"
#include "sysemu/sysemu.h"
#include "qemu/cutils.h"
#include "sysemu/replay.h"

#define AUDIO_CAP "audio"
#include "audio_int.h"
@@ -1112,7 +1113,7 @@ static int audio_is_timer_needed (void)
static void audio_reset_timer (AudioState *s)
{
    if (audio_is_timer_needed ()) {
        timer_mod (s->ts,
        timer_mod_anticipate_ns(s->ts,
            qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + conf.period.ticks);
    }
    else {
@@ -1387,6 +1388,7 @@ static void audio_run_out (AudioState *s)

        prev_rpos = hw->rpos;
        played = hw->pcm_ops->run_out (hw, live);
        replay_audio_out(&played);
        if (audio_bug (AUDIO_FUNC, hw->rpos >= hw->samples)) {
            dolog ("hw->rpos=%d hw->samples=%d played=%d\n",
                   hw->rpos, hw->samples, played);
@@ -1450,9 +1452,12 @@ static void audio_run_in (AudioState *s)

    while ((hw = audio_pcm_hw_find_any_enabled_in (hw))) {
        SWVoiceIn *sw;
        int captured, min;
        int captured = 0, min;

        if (replay_mode != REPLAY_MODE_PLAY) {
            captured = hw->pcm_ops->run_in(hw);
        }
        replay_audio_in(&captured, hw->conv_buf, &hw->wpos, hw->samples);

        min = audio_pcm_hw_find_min_in (hw);
        hw->total_samples_captured += captured - min;
+5 −0
Original line number Diff line number Diff line
@@ -166,4 +166,9 @@ int wav_start_capture (CaptureState *s, const char *path, int freq,
bool audio_is_cleaning_up(void);
void audio_cleanup(void);

void audio_sample_to_uint64(void *samples, int pos,
                            uint64_t *left, uint64_t *right);
void audio_sample_from_uint64(void *samples, int pos,
                            uint64_t left, uint64_t right);

#endif /* QEMU_AUDIO_H */
+32 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "qemu/bswap.h"
#include "qemu/error-report.h"
#include "audio.h"

#define AUDIO_CAP "mixeng"
@@ -267,6 +268,37 @@ f_sample *mixeng_clip[2][2][2][3] = {
    }
};


void audio_sample_to_uint64(void *samples, int pos,
                            uint64_t *left, uint64_t *right)
{
    struct st_sample *sample = samples;
    sample += pos;
#ifdef FLOAT_MIXENG
    error_report(
        "Coreaudio and floating point samples are not supported by replay yet");
    abort();
#else
    *left = sample->l;
    *right = sample->r;
#endif
}

void audio_sample_from_uint64(void *samples, int pos,
                            uint64_t left, uint64_t right)
{
    struct st_sample *sample = samples;
    sample += pos;
#ifdef FLOAT_MIXENG
    error_report(
        "Coreaudio and floating point samples are not supported by replay yet");
    abort();
#else
    sample->l = left;
    sample->r = right;
#endif
}

/*
 * August 21, 1998
 * Copyright 1998 Fabrice Bellard.
+48 −0
Original line number Diff line number Diff line
@@ -38,10 +38,14 @@
#define AUDIO_CAP "sdl"
#include "audio_int.h"

#define USE_SEMAPHORE (SDL_MAJOR_VERSION < 2)

typedef struct SDLVoiceOut {
    HWVoiceOut hw;
    int live;
#if USE_SEMAPHORE
    int rpos;
#endif
    int decr;
} SDLVoiceOut;

@@ -53,8 +57,10 @@ static struct {

static struct SDLAudioState {
    int exit;
#if USE_SEMAPHORE
    SDL_mutex *mutex;
    SDL_sem *sem;
#endif
    int initialized;
    bool driver_created;
} glob_sdl;
@@ -73,31 +79,45 @@ static void GCC_FMT_ATTR (1, 2) sdl_logerr (const char *fmt, ...)

static int sdl_lock (SDLAudioState *s, const char *forfn)
{
#if USE_SEMAPHORE
    if (SDL_LockMutex (s->mutex)) {
        sdl_logerr ("SDL_LockMutex for %s failed\n", forfn);
        return -1;
    }
#else
    SDL_LockAudio();
#endif

    return 0;
}

static int sdl_unlock (SDLAudioState *s, const char *forfn)
{
#if USE_SEMAPHORE
    if (SDL_UnlockMutex (s->mutex)) {
        sdl_logerr ("SDL_UnlockMutex for %s failed\n", forfn);
        return -1;
    }
#else
    SDL_UnlockAudio();
#endif

    return 0;
}

static int sdl_post (SDLAudioState *s, const char *forfn)
{
#if USE_SEMAPHORE
    if (SDL_SemPost (s->sem)) {
        sdl_logerr ("SDL_SemPost for %s failed\n", forfn);
        return -1;
    }
#endif

    return 0;
}

#if USE_SEMAPHORE
static int sdl_wait (SDLAudioState *s, const char *forfn)
{
    if (SDL_SemWait (s->sem)) {
@@ -106,6 +126,7 @@ static int sdl_wait (SDLAudioState *s, const char *forfn)
    }
    return 0;
}
#endif

static int sdl_unlock_and_post (SDLAudioState *s, const char *forfn)
{
@@ -246,6 +267,7 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
        int to_mix, decr;

        /* dolog ("in callback samples=%d\n", samples); */
#if USE_SEMAPHORE
        sdl_wait (s, "sdl_callback");
        if (s->exit) {
            return;
@@ -264,6 +286,11 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
        if (!sdl->live) {
            goto again;
        }
#else
        if (s->exit || !sdl->live) {
            break;
        }
#endif

        /* dolog ("in callback live=%d\n", live); */
        to_mix = audio_MIN (samples, sdl->live);
@@ -274,7 +301,11 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)

            /* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */
            hw->clip (buf, src, chunk);
#if USE_SEMAPHORE
            sdl->rpos = (sdl->rpos + chunk) % hw->samples;
#else
            hw->rpos = (hw->rpos + chunk) % hw->samples;
#endif
            to_mix -= chunk;
            buf += chunk << hw->info.shift;
        }
@@ -282,12 +313,21 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
        sdl->live -= decr;
        sdl->decr += decr;

#if USE_SEMAPHORE
    again:
        if (sdl_unlock (s, "sdl_callback")) {
            return;
        }
#endif
    }
    /* dolog ("done len=%d\n", len); */

#if (SDL_MAJOR_VERSION >= 2)
    /* SDL2 does not clear the remaining buffer for us, so do it on our own */
    if (samples) {
        memset(buf, 0, samples << hw->info.shift);
    }
#endif
}

static int sdl_write_out (SWVoiceOut *sw, void *buf, int len)
@@ -315,8 +355,12 @@ static int sdl_run_out (HWVoiceOut *hw, int live)
    decr = audio_MIN (sdl->decr, live);
    sdl->decr -= decr;

#if USE_SEMAPHORE
    sdl->live = live - decr;
    hw->rpos = sdl->rpos;
#else
    sdl->live = live;
#endif

    if (sdl->live > 0) {
        sdl_unlock_and_post (s, "sdl_run_out");
@@ -405,6 +449,7 @@ static void *sdl_audio_init (void)
        return NULL;
    }

#if USE_SEMAPHORE
    s->mutex = SDL_CreateMutex ();
    if (!s->mutex) {
        sdl_logerr ("Failed to create SDL mutex\n");
@@ -419,6 +464,7 @@ static void *sdl_audio_init (void)
        SDL_QuitSubSystem (SDL_INIT_AUDIO);
        return NULL;
    }
#endif

    s->driver_created = true;
    return s;
@@ -428,8 +474,10 @@ static void sdl_audio_fini (void *opaque)
{
    SDLAudioState *s = opaque;
    sdl_close (s);
#if USE_SEMAPHORE
    SDL_DestroySemaphore (s->sem);
    SDL_DestroyMutex (s->mutex);
#endif
    SDL_QuitSubSystem (SDL_INIT_AUDIO);
    s->driver_created = false;
}
+7 −0
Original line number Diff line number Diff line
@@ -225,3 +225,10 @@ recording the virtual machine this filter puts all packets coming from
the outer world into the log. In replay mode packets from the log are
injected into the network device. All interactions with network backend
in replay mode are disabled.

Audio devices
-------------

Audio data is recorded and replay automatically. The command line for recording
and replaying must contain identical specifications of audio hardware, e.g.:
 -soundhw ac97
Loading