* [Qemu-devel] [RFC PATCH 04/22] Audo replay
@ 2014-07-01 11:20 Pavel Dovgaluk
0 siblings, 0 replies; only message in thread
From: Pavel Dovgaluk @ 2014-07-01 11:20 UTC (permalink / raw)
To: 'QEMU Developers'
These patches add deterministic replay for audio adapter. Support of audio
record and replay is implemented only for Win32.
Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@gmail.com>
---
diff --git a/audio/audio.c b/audio/audio.c
index 9d018e9..475211c
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -26,6 +26,7 @@
#include "monitor/monitor.h"
#include "qemu/timer.h"
#include "sysemu/sysemu.h"
+#include "replay/replay.h"
#define AUDIO_CAP "audio"
#include "audio_int.h"
@@ -1201,7 +1202,7 @@ void AUD_set_active_out (SWVoiceOut *sw, int on)
if (!hw->enabled) {
hw->enabled = 1;
if (s->vm_running) {
- hw->pcm_ops->ctl_out (hw, VOICE_ENABLE, conf.try_poll_out);
+ hw->pcm_ops->ctl_out (hw, VOICE_ENABLE, replay_mode == REPLAY_NONE ?
conf.try_poll_out : 0);
audio_reset_timer (s);
}
}
@@ -1763,11 +1764,11 @@ static void audio_vm_change_state_handler (void *opaque, int running,
s->vm_running = running;
while ((hwo = audio_pcm_hw_find_any_enabled_out (hwo))) {
- hwo->pcm_ops->ctl_out (hwo, op, conf.try_poll_out);
+ hwo->pcm_ops->ctl_out (hwo, op, replay_mode == REPLAY_NONE ? conf.try_poll_out : 0);
}
while ((hwi = audio_pcm_hw_find_any_enabled_in (hwi))) {
- hwi->pcm_ops->ctl_in (hwi, op, conf.try_poll_in);
+ hwi->pcm_ops->ctl_in (hwi, op, replay_mode == REPLAY_NONE ? conf.try_poll_in : 0);
}
audio_reset_timer (s);
}
@@ -1810,9 +1811,10 @@ static void audio_atexit (void)
static const VMStateDescription vmstate_audio = {
.name = "audio",
- .version_id = 1,
+ .version_id = 2,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
+ VMSTATE_TIMER_V(ts, AudioState, 2),
VMSTATE_END_OF_LIST()
}
};
diff --git a/audio/winwaveaudio.c b/audio/winwaveaudio.c
index 8dbd145..8fee218 100644
--- a/audio/winwaveaudio.c
+++ b/audio/winwaveaudio.c
@@ -2,11 +2,14 @@
#include "qemu-common.h"
#include "sysemu/sysemu.h"
+#include "migration/vmstate.h"
#include "audio.h"
#define AUDIO_CAP "winwave"
#include "audio_int.h"
+#include "replay/replay.h"
+
#include <windows.h>
#include <mmsystem.h>
@@ -47,6 +50,7 @@ typedef struct {
int paused;
int rpos;
int avail;
+ int non_added;
CRITICAL_SECTION crit_sect;
} WaveVoiceIn;
@@ -124,6 +128,24 @@ static void winwave_anal_close_out (WaveVoiceOut *wave)
wave->hwo = NULL;
}
+void winwave_callback_out_impl(void *dwInstance, WAVEHDR *h)
+{
+ WaveVoiceOut *wave = (WaveVoiceOut *) dwInstance;
+ if (!h->dwUser) {
+ h->dwUser = 1;
+ EnterCriticalSection (&wave->crit_sect);
+ {
+ wave->avail += conf.dac_samples;
+ }
+ LeaveCriticalSection (&wave->crit_sect);
+ if (wave->hw.poll_mode) {
+ if (!SetEvent (wave->event)) {
+ dolog ("DAC SetEvent failed %lx\n", GetLastError ());
+ }
+ }
+ }
+}
+
static void CALLBACK winwave_callback_out (
HWAVEOUT hwo,
UINT msg,
@@ -132,24 +154,18 @@ static void CALLBACK winwave_callback_out (
DWORD_PTR dwParam2
)
{
- WaveVoiceOut *wave = (WaveVoiceOut *) dwInstance;
-
switch (msg) {
case WOM_DONE:
{
- WAVEHDR *h = (WAVEHDR *) dwParam1;
- if (!h->dwUser) {
- h->dwUser = 1;
- EnterCriticalSection (&wave->crit_sect);
- {
- wave->avail += conf.dac_samples;
- }
- LeaveCriticalSection (&wave->crit_sect);
- if (wave->hw.poll_mode) {
- if (!SetEvent (wave->event)) {
- dolog ("DAC SetEvent failed %lx\n", GetLastError ());
- }
- }
+ if (replay_mode == REPLAY_SAVE) {
+ replay_sound_out_event((WAVEHDR *) dwParam1);
+ }
+ else if (replay_mode == REPLAY_PLAY
+ && replay_get_play_submode() != REPLAY_PLAY_CHANGED) {
+ /* Do nothing */
+ }
+ else {
+ winwave_callback_out_impl((void*)dwInstance, (WAVEHDR *) dwParam1);
}
}
break;
@@ -163,6 +179,21 @@ static void CALLBACK winwave_callback_out (
}
}
+static const VMStateDescription vmstate_audio_out = {
+ .name = "audio_out",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_INT32(enabled, HWVoiceOut),
+ VMSTATE_INT32(poll_mode, HWVoiceOut),
+ VMSTATE_INT32(pending_disable, HWVoiceOut),
+ VMSTATE_INT32(rpos, HWVoiceOut),
+ VMSTATE_UINT64(ts_helper, HWVoiceOut),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static int winwave_init_out (HWVoiceOut *hw, struct audsettings *as)
{
int i;
@@ -173,6 +204,8 @@ static int winwave_init_out (HWVoiceOut *hw, struct audsettings *as)
wave = (WaveVoiceOut *) hw;
+ vmstate_register(NULL, 0, &vmstate_audio_out, hw);
+
InitializeCriticalSection (&wave->crit_sect);
err = waveformat_from_audio_settings (&wfx, as);
@@ -219,6 +252,10 @@ static int winwave_init_out (HWVoiceOut *hw, struct audsettings *as)
}
}
+ if (replay_mode != REPLAY_NONE) {
+ replay_init_sound_out(wave, wave->hdrs, conf.dac_headers);
+ }
+
return 0;
err4:
@@ -262,10 +299,20 @@ static int winwave_run_out (HWVoiceOut *hw, int live)
WAVEHDR *h = &wave->hdrs[wave->curhdr];
h->dwUser = 0;
- mr = waveOutWrite (wave->hwo, h, sizeof (*h));
- if (mr != MMSYSERR_NOERROR) {
- winwave_logerr (mr, "waveOutWrite(%d)", wave->curhdr);
- break;
+ /* Only events will be simulated in REPLAY_PLAY mode. Without sound */
+ if (replay_mode != REPLAY_PLAY
+ || replay_get_play_submode() == REPLAY_PLAY_CHANGED) {
+ mr = waveOutWrite (wave->hwo, h, sizeof (*h));
+ if (mr != MMSYSERR_NOERROR) {
+ winwave_logerr (mr, "waveOutWrite(%d)", wave->curhdr);
+ break;
+ }
+ } else {
+ /* This header will be passed to callback function,
+ when event will be read in the log */
+ if (replay_sound_out_event(h)) {
+ break;
+ }
}
wave->pending -= conf.dac_samples;
@@ -382,6 +429,26 @@ static void winwave_anal_close_in (WaveVoiceIn *wave)
wave->hwi = NULL;
}
+void winwave_callback_in_impl(void *dwInstance, WAVEHDR *h)
+{
+ WaveVoiceIn *wave = (WaveVoiceIn *) dwInstance;
+
+ if (!h->dwUser) {
+ h->dwUser = 1;
+ EnterCriticalSection (&wave->crit_sect);
+ {
+ wave->avail += conf.adc_samples;
+ }
+ LeaveCriticalSection (&wave->crit_sect);
+
+ if (wave->hw.poll_mode) {
+ if (!SetEvent (wave->event)) {
+ dolog ("ADC SetEvent failed %lx\n", GetLastError ());
+ }
+ }
+ }
+}
+
static void CALLBACK winwave_callback_in (
HWAVEIN *hwi,
UINT msg,
@@ -390,24 +457,16 @@ static void CALLBACK winwave_callback_in (
DWORD_PTR dwParam2
)
{
- WaveVoiceIn *wave = (WaveVoiceIn *) dwInstance;
-
switch (msg) {
case WIM_DATA:
{
- WAVEHDR *h = (WAVEHDR *) dwParam1;
- if (!h->dwUser) {
- h->dwUser = 1;
- EnterCriticalSection (&wave->crit_sect);
- {
- wave->avail += conf.adc_samples;
- }
- LeaveCriticalSection (&wave->crit_sect);
- if (wave->hw.poll_mode) {
- if (!SetEvent (wave->event)) {
- dolog ("ADC SetEvent failed %lx\n", GetLastError ());
- }
- }
+ if (replay_mode == REPLAY_SAVE) {
+ replay_sound_in_event((WAVEHDR *) dwParam1);
+ } else if (replay_mode == REPLAY_PLAY
+ && replay_get_play_submode() != REPLAY_PLAY_CHANGED) {
+ /* Do nothing */
+ } else {
+ winwave_callback_in_impl((void*)dwInstance, (WAVEHDR *) dwParam1);
}
}
break;
@@ -421,9 +480,10 @@ static void CALLBACK winwave_callback_in (
}
}
-static void winwave_add_buffers (WaveVoiceIn *wave, int samples)
+static int winwave_add_buffers (WaveVoiceIn *wave, int samples)
{
int doreset;
+ int added = 0;
doreset = wave->hw.poll_mode && (samples >= conf.adc_samples);
if (doreset && !ResetEvent (wave->event)) {
@@ -435,15 +495,40 @@ static void winwave_add_buffers (WaveVoiceIn *wave, int samples)
WAVEHDR *h = &wave->hdrs[wave->curhdr];
h->dwUser = 0;
- mr = waveInAddBuffer (wave->hwi, h, sizeof (*h));
- if (mr != MMSYSERR_NOERROR) {
- winwave_logerr (mr, "waveInAddBuffer(%d)", wave->curhdr);
+ /* Add buffer to replay in PLAY mode - it will be
+ loaded from log file. */
+ if (replay_mode != REPLAY_PLAY
+ || replay_get_play_submode() != REPLAY_PLAY_CHANGED) {
+ mr = waveInAddBuffer (wave->hwi, h, sizeof (*h));
+ if (mr != MMSYSERR_NOERROR) {
+ winwave_logerr (mr, "waveInAddBuffer(%d)", wave->curhdr);
+ }
+ } else {
+ replay_sound_in_event(h);
}
wave->curhdr = (wave->curhdr + 1) % conf.adc_headers;
samples -= conf.adc_samples;
+ added += conf.adc_samples;
}
+
+ return added;
}
+static const VMStateDescription vmstate_audio_in = {
+ .name = "audio_in",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_INT32(enabled, HWVoiceIn),
+ VMSTATE_INT32(poll_mode, HWVoiceIn),
+ VMSTATE_INT32(wpos, HWVoiceIn),
+ VMSTATE_INT32(total_samples_captured, HWVoiceIn),
+ VMSTATE_UINT64(ts_helper, HWVoiceIn),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static int winwave_init_in (HWVoiceIn *hw, struct audsettings *as)
{
int i;
@@ -454,6 +539,8 @@ static int winwave_init_in (HWVoiceIn *hw, struct audsettings *as)
wave = (WaveVoiceIn *) hw;
+ vmstate_register(NULL, 0, &vmstate_audio_in, hw);
+
InitializeCriticalSection (&wave->crit_sect);
err = waveformat_from_audio_settings (&wfx, as);
@@ -478,6 +565,7 @@ static int winwave_init_in (HWVoiceIn *hw, struct audsettings *as)
audio_pcm_init_info (&hw->info, as);
hw->samples = conf.adc_samples * conf.adc_headers;
wave->avail = 0;
+ wave->non_added = 0;
wave->pcm_buf = audio_calloc (AUDIO_FUNC, conf.adc_samples,
conf.adc_headers << hw->info.shift);
@@ -500,6 +588,10 @@ static int winwave_init_in (HWVoiceIn *hw, struct audsettings *as)
}
}
+ if (replay_mode != REPLAY_NONE) {
+ replay_init_sound_in(wave, wave->hdrs, conf.adc_headers);
+ }
+
wave->paused = 1;
winwave_add_buffers (wave, hw->samples);
return 0;
@@ -570,6 +662,7 @@ static int winwave_run_in (HWVoiceIn *hw)
LeaveCriticalSection (&wave->crit_sect);
ret = decr;
+ wave->non_added += ret;
while (decr) {
int left = hw->samples - hw->wpos;
int conv = audio_MIN (left, decr);
@@ -582,7 +675,7 @@ static int winwave_run_in (HWVoiceIn *hw)
decr -= conv;
}
- winwave_add_buffers (wave, ret);
+ wave->non_added -= winwave_add_buffers (wave, wave->non_added);
return ret;
}
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2014-07-01 11:21 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-07-01 11:20 [Qemu-devel] [RFC PATCH 04/22] Audo replay Pavel Dovgaluk
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.