[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [RFC PATCH 04/22] Audo replay
From: |
Pavel Dovgaluk |
Subject: |
[Qemu-devel] [RFC PATCH 04/22] Audo replay |
Date: |
Tue, 1 Jul 2014 15:20:44 +0400 |
These patches add deterministic replay for audio adapter. Support of audio
record and replay is implemented only for Win32.
Signed-off-by: Pavel Dovgalyuk <address@hidden>
---
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;
}
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Qemu-devel] [RFC PATCH 04/22] Audo replay,
Pavel Dovgaluk <=