audio: replay support, sdl2 fix.
-----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABAgAGBQJYturhAAoJEEy22O7T6HE4wGoP/Rvg4gkUff5Ze9Wt4kk4JyJq qI9rv+gypzkHHVmSB8eEM3JTxcbAacPsbldxXL6BhWdUz7M3ppJDWC3U6wwkNVIT uY3e8Ojg22bzthZccHSfdTtq5AWzgrzaydm16VtUffzv6tJ73bd+f4wFwSAO4kI8 teAYc5b+33clN98T2aJtXI6sxnmRHKhG9Pp6C9Co1vdix4/caZ3qvKP1QEGbFIOh i0rp7Zyas6hXm0YzUkoVFltvdgJSFQ+LBMAQZGWqWu9ndu2M82rad5c3E6W49VJk 7bf4qcaSu12KnZy7etaWN3d8jp9Zw2Re3nEUayr/A7f6uliRwMIi2vS3oOUnlbV5 NV/AwYOxx+m6iMNNQOi86xgpThhfPI9118HyYVnh6WtL3RdmRHPKrHvAQ9KH+693 XYyRcjjlaK7Bm9TTl7AqUv2xaDKivhuO5LAbMbTbuEWy/9i+RWYh3clp3mMmM571 gidzoo5oAywgZzmSVg6q8K03gi0DNEX62+MHfw6OYL9b5j5hgsVTY8fbHoG1UxAs f+0VpO4KaRYOHbZwKvxdVWs/++cz/PRfQUwz3ApLgLC+0PSgZNtJIHZbDLvt89tI SZECHsHpMzMP6h4zRLtPyfyeoe/gvaHS6q9l/0LsnAYoW3uHORhxLiBd9kjxygLO 7+tXPSRcik9kMugC1VI8 =+nSM -----END PGP SIGNATURE----- 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: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
6835504887
|
@ -28,6 +28,7 @@
|
||||||
#include "qemu/timer.h"
|
#include "qemu/timer.h"
|
||||||
#include "sysemu/sysemu.h"
|
#include "sysemu/sysemu.h"
|
||||||
#include "qemu/cutils.h"
|
#include "qemu/cutils.h"
|
||||||
|
#include "sysemu/replay.h"
|
||||||
|
|
||||||
#define AUDIO_CAP "audio"
|
#define AUDIO_CAP "audio"
|
||||||
#include "audio_int.h"
|
#include "audio_int.h"
|
||||||
|
@ -1112,7 +1113,7 @@ static int audio_is_timer_needed (void)
|
||||||
static void audio_reset_timer (AudioState *s)
|
static void audio_reset_timer (AudioState *s)
|
||||||
{
|
{
|
||||||
if (audio_is_timer_needed ()) {
|
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);
|
qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + conf.period.ticks);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -1387,6 +1388,7 @@ static void audio_run_out (AudioState *s)
|
||||||
|
|
||||||
prev_rpos = hw->rpos;
|
prev_rpos = hw->rpos;
|
||||||
played = hw->pcm_ops->run_out (hw, live);
|
played = hw->pcm_ops->run_out (hw, live);
|
||||||
|
replay_audio_out(&played);
|
||||||
if (audio_bug (AUDIO_FUNC, hw->rpos >= hw->samples)) {
|
if (audio_bug (AUDIO_FUNC, hw->rpos >= hw->samples)) {
|
||||||
dolog ("hw->rpos=%d hw->samples=%d played=%d\n",
|
dolog ("hw->rpos=%d hw->samples=%d played=%d\n",
|
||||||
hw->rpos, hw->samples, played);
|
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))) {
|
while ((hw = audio_pcm_hw_find_any_enabled_in (hw))) {
|
||||||
SWVoiceIn *sw;
|
SWVoiceIn *sw;
|
||||||
int captured, min;
|
int captured = 0, min;
|
||||||
|
|
||||||
captured = hw->pcm_ops->run_in (hw);
|
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);
|
min = audio_pcm_hw_find_min_in (hw);
|
||||||
hw->total_samples_captured += captured - min;
|
hw->total_samples_captured += captured - min;
|
||||||
|
|
|
@ -166,4 +166,9 @@ int wav_start_capture (CaptureState *s, const char *path, int freq,
|
||||||
bool audio_is_cleaning_up(void);
|
bool audio_is_cleaning_up(void);
|
||||||
void audio_cleanup(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 */
|
#endif /* QEMU_AUDIO_H */
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "qemu-common.h"
|
#include "qemu-common.h"
|
||||||
#include "qemu/bswap.h"
|
#include "qemu/bswap.h"
|
||||||
|
#include "qemu/error-report.h"
|
||||||
#include "audio.h"
|
#include "audio.h"
|
||||||
|
|
||||||
#define AUDIO_CAP "mixeng"
|
#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
|
* August 21, 1998
|
||||||
* Copyright 1998 Fabrice Bellard.
|
* Copyright 1998 Fabrice Bellard.
|
||||||
|
|
|
@ -38,10 +38,14 @@
|
||||||
#define AUDIO_CAP "sdl"
|
#define AUDIO_CAP "sdl"
|
||||||
#include "audio_int.h"
|
#include "audio_int.h"
|
||||||
|
|
||||||
|
#define USE_SEMAPHORE (SDL_MAJOR_VERSION < 2)
|
||||||
|
|
||||||
typedef struct SDLVoiceOut {
|
typedef struct SDLVoiceOut {
|
||||||
HWVoiceOut hw;
|
HWVoiceOut hw;
|
||||||
int live;
|
int live;
|
||||||
|
#if USE_SEMAPHORE
|
||||||
int rpos;
|
int rpos;
|
||||||
|
#endif
|
||||||
int decr;
|
int decr;
|
||||||
} SDLVoiceOut;
|
} SDLVoiceOut;
|
||||||
|
|
||||||
|
@ -53,8 +57,10 @@ static struct {
|
||||||
|
|
||||||
static struct SDLAudioState {
|
static struct SDLAudioState {
|
||||||
int exit;
|
int exit;
|
||||||
|
#if USE_SEMAPHORE
|
||||||
SDL_mutex *mutex;
|
SDL_mutex *mutex;
|
||||||
SDL_sem *sem;
|
SDL_sem *sem;
|
||||||
|
#endif
|
||||||
int initialized;
|
int initialized;
|
||||||
bool driver_created;
|
bool driver_created;
|
||||||
} glob_sdl;
|
} 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)
|
static int sdl_lock (SDLAudioState *s, const char *forfn)
|
||||||
{
|
{
|
||||||
|
#if USE_SEMAPHORE
|
||||||
if (SDL_LockMutex (s->mutex)) {
|
if (SDL_LockMutex (s->mutex)) {
|
||||||
sdl_logerr ("SDL_LockMutex for %s failed\n", forfn);
|
sdl_logerr ("SDL_LockMutex for %s failed\n", forfn);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
SDL_LockAudio();
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sdl_unlock (SDLAudioState *s, const char *forfn)
|
static int sdl_unlock (SDLAudioState *s, const char *forfn)
|
||||||
{
|
{
|
||||||
|
#if USE_SEMAPHORE
|
||||||
if (SDL_UnlockMutex (s->mutex)) {
|
if (SDL_UnlockMutex (s->mutex)) {
|
||||||
sdl_logerr ("SDL_UnlockMutex for %s failed\n", forfn);
|
sdl_logerr ("SDL_UnlockMutex for %s failed\n", forfn);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
SDL_UnlockAudio();
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sdl_post (SDLAudioState *s, const char *forfn)
|
static int sdl_post (SDLAudioState *s, const char *forfn)
|
||||||
{
|
{
|
||||||
|
#if USE_SEMAPHORE
|
||||||
if (SDL_SemPost (s->sem)) {
|
if (SDL_SemPost (s->sem)) {
|
||||||
sdl_logerr ("SDL_SemPost for %s failed\n", forfn);
|
sdl_logerr ("SDL_SemPost for %s failed\n", forfn);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if USE_SEMAPHORE
|
||||||
static int sdl_wait (SDLAudioState *s, const char *forfn)
|
static int sdl_wait (SDLAudioState *s, const char *forfn)
|
||||||
{
|
{
|
||||||
if (SDL_SemWait (s->sem)) {
|
if (SDL_SemWait (s->sem)) {
|
||||||
|
@ -106,6 +126,7 @@ static int sdl_wait (SDLAudioState *s, const char *forfn)
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static int sdl_unlock_and_post (SDLAudioState *s, const char *forfn)
|
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;
|
int to_mix, decr;
|
||||||
|
|
||||||
/* dolog ("in callback samples=%d\n", samples); */
|
/* dolog ("in callback samples=%d\n", samples); */
|
||||||
|
#if USE_SEMAPHORE
|
||||||
sdl_wait (s, "sdl_callback");
|
sdl_wait (s, "sdl_callback");
|
||||||
if (s->exit) {
|
if (s->exit) {
|
||||||
return;
|
return;
|
||||||
|
@ -264,6 +286,11 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
|
||||||
if (!sdl->live) {
|
if (!sdl->live) {
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
if (s->exit || !sdl->live) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* dolog ("in callback live=%d\n", live); */
|
/* dolog ("in callback live=%d\n", live); */
|
||||||
to_mix = audio_MIN (samples, sdl->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); */
|
/* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */
|
||||||
hw->clip (buf, src, chunk);
|
hw->clip (buf, src, chunk);
|
||||||
|
#if USE_SEMAPHORE
|
||||||
sdl->rpos = (sdl->rpos + chunk) % hw->samples;
|
sdl->rpos = (sdl->rpos + chunk) % hw->samples;
|
||||||
|
#else
|
||||||
|
hw->rpos = (hw->rpos + chunk) % hw->samples;
|
||||||
|
#endif
|
||||||
to_mix -= chunk;
|
to_mix -= chunk;
|
||||||
buf += chunk << hw->info.shift;
|
buf += chunk << hw->info.shift;
|
||||||
}
|
}
|
||||||
|
@ -282,12 +313,21 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
|
||||||
sdl->live -= decr;
|
sdl->live -= decr;
|
||||||
sdl->decr += decr;
|
sdl->decr += decr;
|
||||||
|
|
||||||
|
#if USE_SEMAPHORE
|
||||||
again:
|
again:
|
||||||
if (sdl_unlock (s, "sdl_callback")) {
|
if (sdl_unlock (s, "sdl_callback")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
/* dolog ("done len=%d\n", len); */
|
/* 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)
|
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);
|
decr = audio_MIN (sdl->decr, live);
|
||||||
sdl->decr -= decr;
|
sdl->decr -= decr;
|
||||||
|
|
||||||
|
#if USE_SEMAPHORE
|
||||||
sdl->live = live - decr;
|
sdl->live = live - decr;
|
||||||
hw->rpos = sdl->rpos;
|
hw->rpos = sdl->rpos;
|
||||||
|
#else
|
||||||
|
sdl->live = live;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (sdl->live > 0) {
|
if (sdl->live > 0) {
|
||||||
sdl_unlock_and_post (s, "sdl_run_out");
|
sdl_unlock_and_post (s, "sdl_run_out");
|
||||||
|
@ -405,6 +449,7 @@ static void *sdl_audio_init (void)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if USE_SEMAPHORE
|
||||||
s->mutex = SDL_CreateMutex ();
|
s->mutex = SDL_CreateMutex ();
|
||||||
if (!s->mutex) {
|
if (!s->mutex) {
|
||||||
sdl_logerr ("Failed to create SDL mutex\n");
|
sdl_logerr ("Failed to create SDL mutex\n");
|
||||||
|
@ -419,6 +464,7 @@ static void *sdl_audio_init (void)
|
||||||
SDL_QuitSubSystem (SDL_INIT_AUDIO);
|
SDL_QuitSubSystem (SDL_INIT_AUDIO);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
s->driver_created = true;
|
s->driver_created = true;
|
||||||
return s;
|
return s;
|
||||||
|
@ -428,8 +474,10 @@ static void sdl_audio_fini (void *opaque)
|
||||||
{
|
{
|
||||||
SDLAudioState *s = opaque;
|
SDLAudioState *s = opaque;
|
||||||
sdl_close (s);
|
sdl_close (s);
|
||||||
|
#if USE_SEMAPHORE
|
||||||
SDL_DestroySemaphore (s->sem);
|
SDL_DestroySemaphore (s->sem);
|
||||||
SDL_DestroyMutex (s->mutex);
|
SDL_DestroyMutex (s->mutex);
|
||||||
|
#endif
|
||||||
SDL_QuitSubSystem (SDL_INIT_AUDIO);
|
SDL_QuitSubSystem (SDL_INIT_AUDIO);
|
||||||
s->driver_created = false;
|
s->driver_created = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
the outer world into the log. In replay mode packets from the log are
|
||||||
injected into the network device. All interactions with network backend
|
injected into the network device. All interactions with network backend
|
||||||
in replay mode are disabled.
|
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
|
||||||
|
|
|
@ -152,6 +152,13 @@ void replay_unregister_net(ReplayNetState *rns);
|
||||||
void replay_net_packet_event(ReplayNetState *rns, unsigned flags,
|
void replay_net_packet_event(ReplayNetState *rns, unsigned flags,
|
||||||
const struct iovec *iov, int iovcnt);
|
const struct iovec *iov, int iovcnt);
|
||||||
|
|
||||||
|
/* Audio */
|
||||||
|
|
||||||
|
/*! Saves/restores number of played samples of audio out operation. */
|
||||||
|
void replay_audio_out(int *played);
|
||||||
|
/*! Saves/restores recorded samples of audio in operation. */
|
||||||
|
void replay_audio_in(int *recorded, void *samples, int *wpos, int size);
|
||||||
|
|
||||||
/* VM state operations */
|
/* VM state operations */
|
||||||
|
|
||||||
/*! Called at the start of execution.
|
/*! Called at the start of execution.
|
||||||
|
|
|
@ -6,3 +6,4 @@ common-obj-y += replay-input.o
|
||||||
common-obj-y += replay-char.o
|
common-obj-y += replay-char.o
|
||||||
common-obj-y += replay-snapshot.o
|
common-obj-y += replay-snapshot.o
|
||||||
common-obj-y += replay-net.o
|
common-obj-y += replay-net.o
|
||||||
|
common-obj-y += replay-audio.o
|
79
replay/replay-audio.c
Normal file
79
replay/replay-audio.c
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* replay-audio.c
|
||||||
|
*
|
||||||
|
* Copyright (c) 2010-2017 Institute for System Programming
|
||||||
|
* of the Russian Academy of Sciences.
|
||||||
|
*
|
||||||
|
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||||
|
* See the COPYING file in the top-level directory.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "qemu/error-report.h"
|
||||||
|
#include "sysemu/replay.h"
|
||||||
|
#include "replay-internal.h"
|
||||||
|
#include "sysemu/sysemu.h"
|
||||||
|
#include "audio/audio.h"
|
||||||
|
|
||||||
|
void replay_audio_out(int *played)
|
||||||
|
{
|
||||||
|
if (replay_mode == REPLAY_MODE_RECORD) {
|
||||||
|
replay_save_instructions();
|
||||||
|
replay_mutex_lock();
|
||||||
|
replay_put_event(EVENT_AUDIO_OUT);
|
||||||
|
replay_put_dword(*played);
|
||||||
|
replay_mutex_unlock();
|
||||||
|
} else if (replay_mode == REPLAY_MODE_PLAY) {
|
||||||
|
replay_account_executed_instructions();
|
||||||
|
replay_mutex_lock();
|
||||||
|
if (replay_next_event_is(EVENT_AUDIO_OUT)) {
|
||||||
|
*played = replay_get_dword();
|
||||||
|
replay_finish_event();
|
||||||
|
replay_mutex_unlock();
|
||||||
|
} else {
|
||||||
|
replay_mutex_unlock();
|
||||||
|
error_report("Missing audio out event in the replay log");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void replay_audio_in(int *recorded, void *samples, int *wpos, int size)
|
||||||
|
{
|
||||||
|
int pos;
|
||||||
|
uint64_t left, right;
|
||||||
|
if (replay_mode == REPLAY_MODE_RECORD) {
|
||||||
|
replay_save_instructions();
|
||||||
|
replay_mutex_lock();
|
||||||
|
replay_put_event(EVENT_AUDIO_IN);
|
||||||
|
replay_put_dword(*recorded);
|
||||||
|
replay_put_dword(*wpos);
|
||||||
|
for (pos = (*wpos - *recorded + size) % size ; pos != *wpos
|
||||||
|
; pos = (pos + 1) % size) {
|
||||||
|
audio_sample_to_uint64(samples, pos, &left, &right);
|
||||||
|
replay_put_qword(left);
|
||||||
|
replay_put_qword(right);
|
||||||
|
}
|
||||||
|
replay_mutex_unlock();
|
||||||
|
} else if (replay_mode == REPLAY_MODE_PLAY) {
|
||||||
|
replay_account_executed_instructions();
|
||||||
|
replay_mutex_lock();
|
||||||
|
if (replay_next_event_is(EVENT_AUDIO_IN)) {
|
||||||
|
*recorded = replay_get_dword();
|
||||||
|
*wpos = replay_get_dword();
|
||||||
|
for (pos = (*wpos - *recorded + size) % size ; pos != *wpos
|
||||||
|
; pos = (pos + 1) % size) {
|
||||||
|
left = replay_get_qword();
|
||||||
|
right = replay_get_qword();
|
||||||
|
audio_sample_from_uint64(samples, pos, left, right);
|
||||||
|
}
|
||||||
|
replay_finish_event();
|
||||||
|
replay_mutex_unlock();
|
||||||
|
} else {
|
||||||
|
replay_mutex_unlock();
|
||||||
|
error_report("Missing audio in event in the replay log");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -29,6 +29,10 @@ enum ReplayEvents {
|
||||||
/* for character device read all event */
|
/* for character device read all event */
|
||||||
EVENT_CHAR_READ_ALL,
|
EVENT_CHAR_READ_ALL,
|
||||||
EVENT_CHAR_READ_ALL_ERROR,
|
EVENT_CHAR_READ_ALL_ERROR,
|
||||||
|
/* for audio out event */
|
||||||
|
EVENT_AUDIO_OUT,
|
||||||
|
/* for audio in event */
|
||||||
|
EVENT_AUDIO_IN,
|
||||||
/* for clock read/writes */
|
/* for clock read/writes */
|
||||||
/* some of greater codes are reserved for clocks */
|
/* some of greater codes are reserved for clocks */
|
||||||
EVENT_CLOCK,
|
EVENT_CLOCK,
|
||||||
|
|
Loading…
Reference in a new issue