X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/a126050a103c924b03388a9a64ce9af8c96b0969..48e56d503e18bd1e8a75463fd7cc1580bf7e7650:/audio/audio.c diff --git a/audio/audio.c b/audio/audio.c index b3db67979d..7658d2af66 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -21,16 +21,18 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +#include "qemu/osdep.h" #include "hw/hw.h" #include "audio.h" #include "monitor/monitor.h" #include "qemu/timer.h" #include "sysemu/sysemu.h" +#include "qemu/cutils.h" +#include "sysemu/replay.h" #define AUDIO_CAP "audio" #include "audio_int.h" -/* #define DEBUG_PLIVE */ /* #define DEBUG_LIVE */ /* #define DEBUG_OUT */ /* #define DEBUG_CAPTURE */ @@ -66,8 +68,6 @@ static struct { int hertz; int64_t ticks; } period; - int plive; - int log_to_monitor; int try_poll_in; int try_poll_out; } conf = { @@ -95,9 +95,7 @@ static struct { } }, - .period = { .hertz = 250 }, - .plive = 0, - .log_to_monitor = 0, + .period = { .hertz = 100 }, .try_poll_in = 1, .try_poll_out = 1, }; @@ -331,20 +329,11 @@ static const char *audio_get_conf_str (const char *key, void AUD_vlog (const char *cap, const char *fmt, va_list ap) { - if (conf.log_to_monitor) { - if (cap) { - monitor_printf(default_mon, "%s: ", cap); - } - - monitor_vprintf(default_mon, fmt, ap); + if (cap) { + fprintf(stderr, "%s: ", cap); } - else { - if (cap) { - fprintf (stderr, "%s: ", cap); - } - vfprintf (stderr, fmt, ap); - } + vfprintf(stderr, fmt, ap); } void AUD_log (const char *cap, const char *fmt, ...) @@ -435,12 +424,12 @@ static void audio_process_options (const char *prefix, const char qemu_prefix[] = "QEMU_"; size_t preflen, optlen; - if (audio_bug (AUDIO_FUNC, !prefix)) { + if (audio_bug(__func__, !prefix)) { dolog ("prefix = NULL\n"); return; } - if (audio_bug (AUDIO_FUNC, !opt)) { + if (audio_bug(__func__, !opt)) { dolog ("opt = NULL\n"); return; } @@ -803,7 +792,7 @@ static int audio_attach_capture (HWVoiceOut *hw) SWVoiceOut *sw; HWVoiceOut *hw_cap = &cap->hw; - sc = audio_calloc (AUDIO_FUNC, 1, sizeof (*sc)); + sc = audio_calloc(__func__, 1, sizeof(*sc)); if (!sc) { dolog ("Could not allocate soft capture voice (%zu bytes)\n", sizeof (*sc)); @@ -859,7 +848,7 @@ static int audio_pcm_hw_find_min_in (HWVoiceIn *hw) int audio_pcm_hw_get_live_in (HWVoiceIn *hw) { int live = hw->total_samples_captured - audio_pcm_hw_find_min_in (hw); - if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) { + if (audio_bug(__func__, live < 0 || live > hw->samples)) { dolog ("live=%d hw->samples=%d\n", live, hw->samples); return 0; } @@ -897,7 +886,7 @@ static int audio_pcm_sw_get_rpos_in (SWVoiceIn *sw) int live = hw->total_samples_captured - sw->total_hw_samples_acquired; int rpos; - if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) { + if (audio_bug(__func__, live < 0 || live > hw->samples)) { dolog ("live=%d hw->samples=%d\n", live, hw->samples); return 0; } @@ -920,7 +909,7 @@ int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size) rpos = audio_pcm_sw_get_rpos_in (sw) % hw->samples; live = hw->total_samples_captured - sw->total_hw_samples_acquired; - if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) { + if (audio_bug(__func__, live < 0 || live > hw->samples)) { dolog ("live_in=%d hw->samples=%d\n", live, hw->samples); return 0; } @@ -946,7 +935,7 @@ int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size) } osamp = swlim; - if (audio_bug (AUDIO_FUNC, osamp < 0)) { + if (audio_bug(__func__, osamp < 0)) { dolog ("osamp=%d\n", osamp); return 0; } @@ -1001,7 +990,7 @@ static int audio_pcm_hw_get_live_out (HWVoiceOut *hw, int *nb_live) if (nb_live1) { int live = smin; - if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) { + if (audio_bug(__func__, live < 0 || live > hw->samples)) { dolog ("live=%d hw->samples=%d\n", live, hw->samples); return 0; } @@ -1025,7 +1014,7 @@ int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size) hwsamples = sw->hw->samples; live = sw->total_hw_samples_mixed; - if (audio_bug (AUDIO_FUNC, live < 0 || live > hwsamples)){ + if (audio_bug(__func__, live < 0 || live > hwsamples)) { dolog ("live=%d hw->samples=%d\n", live, hwsamples); return 0; } @@ -1124,7 +1113,7 @@ static int audio_is_timer_needed (void) static void audio_reset_timer (AudioState *s) { 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); } else { @@ -1143,8 +1132,6 @@ static void audio_timer (void *opaque) */ int AUD_write (SWVoiceOut *sw, void *buf, int size) { - int bytes; - if (!sw) { /* XXX: Consider options */ return size; @@ -1155,14 +1142,11 @@ int AUD_write (SWVoiceOut *sw, void *buf, int size) return 0; } - bytes = sw->hw->pcm_ops->write (sw, buf, size); - return bytes; + return sw->hw->pcm_ops->write(sw, buf, size); } int AUD_read (SWVoiceIn *sw, void *buf, int size) { - int bytes; - if (!sw) { /* XXX: Consider options */ return size; @@ -1173,8 +1157,7 @@ int AUD_read (SWVoiceIn *sw, void *buf, int size) return 0; } - bytes = sw->hw->pcm_ops->read (sw, buf, size); - return bytes; + return sw->hw->pcm_ops->read(sw, buf, size); } int AUD_get_buffer_size_out (SWVoiceOut *sw) @@ -1280,7 +1263,7 @@ static int audio_get_avail (SWVoiceIn *sw) } live = sw->hw->total_samples_captured - sw->total_hw_samples_acquired; - if (audio_bug (AUDIO_FUNC, live < 0 || live > sw->hw->samples)) { + if (audio_bug(__func__, live < 0 || live > sw->hw->samples)) { dolog ("live=%d sw->hw->samples=%d\n", live, sw->hw->samples); return 0; } @@ -1304,7 +1287,7 @@ static int audio_get_free (SWVoiceOut *sw) live = sw->total_hw_samples_mixed; - if (audio_bug (AUDIO_FUNC, live < 0 || live > sw->hw->samples)) { + if (audio_bug(__func__, live < 0 || live > sw->hw->samples)) { dolog ("live=%d sw->hw->samples=%d\n", live, sw->hw->samples); return 0; } @@ -1371,7 +1354,7 @@ static void audio_run_out (AudioState *s) live = 0; } - if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) { + if (audio_bug(__func__, live < 0 || live > hw->samples)) { dolog ("live=%d hw->samples=%d\n", live, hw->samples); continue; } @@ -1405,7 +1388,8 @@ static void audio_run_out (AudioState *s) prev_rpos = hw->rpos; played = hw->pcm_ops->run_out (hw, live); - if (audio_bug (AUDIO_FUNC, hw->rpos >= hw->samples)) { + replay_audio_out(&played); + if (audio_bug(__func__, hw->rpos >= hw->samples)) { dolog ("hw->rpos=%d hw->samples=%d played=%d\n", hw->rpos, hw->samples, played); hw->rpos = 0; @@ -1426,7 +1410,7 @@ static void audio_run_out (AudioState *s) continue; } - if (audio_bug (AUDIO_FUNC, played > sw->total_hw_samples_mixed)) { + if (audio_bug(__func__, played > sw->total_hw_samples_mixed)) { dolog ("played=%d sw->total_hw_samples_mixed=%d\n", played, sw->total_hw_samples_mixed); played = sw->total_hw_samples_mixed; @@ -1454,9 +1438,6 @@ static void audio_run_out (AudioState *s) while (sw) { sw1 = sw->entries.le_next; if (!sw->active && !sw->callback.fn) { -#ifdef DEBUG_PLIVE - dolog ("Finishing with old voice\n"); -#endif audio_close_out (sw); } sw = sw1; @@ -1471,9 +1452,12 @@ static void audio_run_in (AudioState *s) while ((hw = audio_pcm_hw_find_any_enabled_in (hw))) { 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); hw->total_samples_captured += captured - min; @@ -1529,7 +1513,7 @@ static void audio_run_capture (AudioState *s) continue; } - if (audio_bug (AUDIO_FUNC, captured > sw->total_hw_samples_mixed)) { + if (audio_bug(__func__, captured > sw->total_hw_samples_mixed)) { dolog ("captured=%d sw->total_hw_samples_mixed=%d\n", captured, sw->total_hw_samples_mixed); captured = sw->total_hw_samples_mixed; @@ -1648,18 +1632,6 @@ static struct audio_option audio_options[] = { .valp = &conf.period.hertz, .descr = "Timer period in HZ (0 - use lowest possible)" }, - { - .name = "PLIVE", - .tag = AUD_OPT_BOOL, - .valp = &conf.plive, - .descr = "(undocumented)" - }, - { - .name = "LOG_TO_MONITOR", - .tag = AUD_OPT_BOOL, - .valp = &conf.log_to_monitor, - .descr = "Print logging messages to monitor instead of stderr" - }, { /* End of list */ } }; @@ -1772,13 +1744,21 @@ static void audio_vm_change_state_handler (void *opaque, int running, audio_reset_timer (s); } -static void audio_atexit (void) +static bool is_cleaning_up; + +bool audio_is_cleaning_up(void) +{ + return is_cleaning_up; +} + +void audio_cleanup(void) { AudioState *s = &glob_audio_state; - HWVoiceOut *hwo = NULL; - HWVoiceIn *hwi = NULL; + HWVoiceOut *hwo, *hwon; + HWVoiceIn *hwi, *hwin; - while ((hwo = audio_pcm_hw_find_any_out (hwo))) { + is_cleaning_up = true; + QLIST_FOREACH_SAFE(hwo, &glob_audio_state.hw_head_out, entries, hwon) { SWVoiceCap *sc; if (hwo->enabled) { @@ -1794,17 +1774,20 @@ static void audio_atexit (void) cb->ops.destroy (cb->opaque); } } + QLIST_REMOVE(hwo, entries); } - while ((hwi = audio_pcm_hw_find_any_in (hwi))) { + QLIST_FOREACH_SAFE(hwi, &glob_audio_state.hw_head_in, entries, hwin) { if (hwi->enabled) { hwi->pcm_ops->ctl_in (hwi, VOICE_DISABLE); } hwi->pcm_ops->fini_in (hwi); + QLIST_REMOVE(hwi, entries); } if (s->drv) { s->drv->fini (s->drv_opaque); + s->drv = NULL; } } @@ -1812,8 +1795,7 @@ static const VMStateDescription vmstate_audio = { .name = "audio", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_END_OF_LIST() } }; @@ -1833,12 +1815,9 @@ static void audio_init (void) QLIST_INIT (&s->hw_head_out); QLIST_INIT (&s->hw_head_in); QLIST_INIT (&s->cap_head); - atexit (audio_atexit); + atexit(audio_cleanup); s->ts = timer_new_ns(QEMU_CLOCK_VIRTUAL, audio_timer, s); - if (!s->ts) { - hw_error("Could not create audio timer\n"); - } audio_process_options ("AUDIO", audio_options); @@ -1889,12 +1868,8 @@ static void audio_init (void) if (!done) { done = !audio_driver_init (s, &no_audio_driver); - if (!done) { - hw_error("Could not initialize audio subsystem\n"); - } - else { - dolog ("warning: Using timer based audio emulation\n"); - } + assert(done); + dolog("warning: Using timer based audio emulation\n"); } if (conf.period.hertz <= 0) { @@ -1905,8 +1880,7 @@ static void audio_init (void) } conf.period.ticks = 1; } else { - conf.period.ticks = - muldiv64 (1, get_ticks_per_sec (), conf.period.hertz); + conf.period.ticks = NANOSECONDS_PER_SECOND / conf.period.hertz; } e = qemu_add_vm_change_state_handler (audio_vm_change_state_handler, s); @@ -1950,7 +1924,7 @@ CaptureVoiceOut *AUD_add_capture ( goto err0; } - cb = audio_calloc (AUDIO_FUNC, 1, sizeof (*cb)); + cb = audio_calloc(__func__, 1, sizeof(*cb)); if (!cb) { dolog ("Could not allocate capture callback information, size %zu\n", sizeof (*cb)); @@ -1968,7 +1942,7 @@ CaptureVoiceOut *AUD_add_capture ( HWVoiceOut *hw; CaptureVoiceOut *cap; - cap = audio_calloc (AUDIO_FUNC, 1, sizeof (*cap)); + cap = audio_calloc(__func__, 1, sizeof(*cap)); if (!cap) { dolog ("Could not allocate capture voice, size %zu\n", sizeof (*cap)); @@ -1981,8 +1955,8 @@ CaptureVoiceOut *AUD_add_capture ( /* XXX find a more elegant way */ hw->samples = 4096 * 4; - hw->mix_buf = audio_calloc (AUDIO_FUNC, hw->samples, - sizeof (struct st_sample)); + hw->mix_buf = audio_calloc(__func__, hw->samples, + sizeof(struct st_sample)); if (!hw->mix_buf) { dolog ("Could not allocate capture mix buffer (%d samples)\n", hw->samples); @@ -1991,7 +1965,7 @@ CaptureVoiceOut *AUD_add_capture ( audio_pcm_init_info (&hw->info, as); - cap->buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); + cap->buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift); if (!cap->buf) { dolog ("Could not allocate capture buffer " "(%d samples, each %d bytes)\n", @@ -2008,8 +1982,7 @@ CaptureVoiceOut *AUD_add_capture ( QLIST_INSERT_HEAD (&s->cap_head, cap, entries); QLIST_INSERT_HEAD (&cap->cb_head, cb, entries); - hw = NULL; - while ((hw = audio_pcm_hw_find_any_out (hw))) { + QLIST_FOREACH(hw, &glob_audio_state.hw_head_out, entries) { audio_attach_capture (hw); } return cap; @@ -2055,6 +2028,8 @@ void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque) sw = sw1; } QLIST_REMOVE (cap, entries); + g_free (cap->hw.mix_buf); + g_free (cap->buf); g_free (cap); } return;