From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:56941) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1X1w7J-0005Vc-4f for qemu-devel@nongnu.org; Tue, 01 Jul 2014 07:21:00 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1X1w7A-0008Kn-B9 for qemu-devel@nongnu.org; Tue, 01 Jul 2014 07:20:52 -0400 Received: from mail.ispras.ru ([83.149.199.45]:33120) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1X1w79-0008Ke-Or for qemu-devel@nongnu.org; Tue, 01 Jul 2014 07:20:44 -0400 Received: from PASHAISP (unknown [80.250.189.177]) by mail.ispras.ru (Postfix) with ESMTPSA id 139E2540157 for ; Tue, 1 Jul 2014 15:20:43 +0400 (MSK) From: "Pavel Dovgaluk" Date: Tue, 1 Jul 2014 15:20:44 +0400 Message-ID: <007801cf951e$80235370$8069fa50$@Dovgaluk@ispras.ru> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Language: ru Subject: [Qemu-devel] [RFC PATCH 04/22] Audo replay List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , 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 --- 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 #include @@ -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; }