From: "Pavel Dovgaluk" <Pavel.Dovgaluk@ispras.ru>
To: 'QEMU Developers' <qemu-devel@nongnu.org>
Subject: [Qemu-devel] [RFC PATCH 04/22] Audo replay
Date: Tue, 1 Jul 2014 15:20:44 +0400 [thread overview]
Message-ID: <007801cf951e$80235370$8069fa50$@Dovgaluk@ispras.ru> (raw)
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;
}
reply other threads:[~2014-07-01 11:21 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='007801cf951e$80235370$8069fa50$@Dovgaluk@ispras.ru' \
--to=pavel.dovgaluk@ispras.ru \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.