📄 audio.c
字号:
live = sw->total_hw_samples_mixed; if (audio_bug (AUDIO_FUNC, live < 0 || live > hwsamples)){ dolog ("live=%d hw->samples=%d\n", live, hwsamples); return 0; } if (live == hwsamples) {#ifdef DEBUG_OUT dolog ("%s is full %d\n", sw->name, live);#endif return 0; } wpos = (sw->hw->rpos + live) % hwsamples; samples = size >> sw->info.shift; dead = hwsamples - live; swlim = ((int64_t) dead << 32) / sw->ratio; swlim = audio_MIN (swlim, samples); if (swlim) { sw->conv (sw->buf, buf, swlim, &sw->vol); } while (swlim) { dead = hwsamples - live; left = hwsamples - wpos; blck = audio_MIN (dead, left); if (!blck) { break; } isamp = swlim; osamp = blck; st_rate_flow_mix ( sw->rate, sw->buf + pos, sw->hw->mix_buf + wpos, &isamp, &osamp ); ret += isamp; swlim -= isamp; pos += isamp; live += osamp; wpos = (wpos + osamp) % hwsamples; total += osamp; } sw->total_hw_samples_mixed += total; sw->empty = sw->total_hw_samples_mixed == 0;#ifdef DEBUG_OUT dolog ( "%s: write size %d ret %d total sw %d\n", SW_NAME (sw), size >> sw->info.shift, ret, sw->total_hw_samples_mixed );#endif return ret << sw->info.shift;}#ifdef DEBUG_AUDIOstatic void audio_pcm_print_info (const char *cap, struct audio_pcm_info *info){ dolog ("%s: bits %d, sign %d, freq %d, nchan %d\n", cap, info->bits, info->sign, info->freq, info->nchannels);}#endif#define DAC#include "audio_template.h"#undef DAC#include "audio_template.h"int AUD_write (SWVoiceOut *sw, void *buf, int size){ int bytes; if (!sw) { /* XXX: Consider options */ return size; } if (!sw->hw->enabled) { dolog ("Writing to disabled voice %s\n", SW_NAME (sw)); return 0; } bytes = sw->hw->pcm_ops->write (sw, buf, size); return bytes;}int AUD_read (SWVoiceIn *sw, void *buf, int size){ int bytes; if (!sw) { /* XXX: Consider options */ return size; } if (!sw->hw->enabled) { dolog ("Reading from disabled voice %s\n", SW_NAME (sw)); return 0; } bytes = sw->hw->pcm_ops->read (sw, buf, size); return bytes;}int AUD_get_buffer_size_out (SWVoiceOut *sw){ return sw->hw->samples << sw->hw->info.shift;}void AUD_set_active_out (SWVoiceOut *sw, int on){ HWVoiceOut *hw; if (!sw) { return; } hw = sw->hw; if (sw->active != on) { SWVoiceOut *temp_sw; SWVoiceCap *sc; if (on) { hw->pending_disable = 0; if (!hw->enabled) { hw->enabled = 1; hw->pcm_ops->ctl_out (hw, VOICE_ENABLE); } } else { if (hw->enabled) { int nb_active = 0; for (temp_sw = hw->sw_head.lh_first; temp_sw; temp_sw = temp_sw->entries.le_next) { nb_active += temp_sw->active != 0; } hw->pending_disable = nb_active == 1; } } for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) { sc->sw.active = hw->enabled; if (hw->enabled) { audio_capture_maybe_changed (sc->cap, 1); } } sw->active = on; }}void AUD_set_active_in (SWVoiceIn *sw, int on){ HWVoiceIn *hw; if (!sw) { return; } hw = sw->hw; if (sw->active != on) { SWVoiceIn *temp_sw; if (on) { if (!hw->enabled) { hw->enabled = 1; hw->pcm_ops->ctl_in (hw, VOICE_ENABLE); } sw->total_hw_samples_acquired = hw->total_samples_captured; } else { if (hw->enabled) { int nb_active = 0; for (temp_sw = hw->sw_head.lh_first; temp_sw; temp_sw = temp_sw->entries.le_next) { nb_active += temp_sw->active != 0; } if (nb_active == 1) { hw->enabled = 0; hw->pcm_ops->ctl_in (hw, VOICE_DISABLE); } } } sw->active = on; }}static int audio_get_avail (SWVoiceIn *sw){ int live; if (!sw) { return 0; } live = sw->hw->total_samples_captured - sw->total_hw_samples_acquired; if (audio_bug (AUDIO_FUNC, live < 0 || live > sw->hw->samples)) { dolog ("live=%d sw->hw->samples=%d\n", live, sw->hw->samples); return 0; } ldebug ( "%s: get_avail live %d ret %" PRId64 "\n", SW_NAME (sw), live, (((int64_t) live << 32) / sw->ratio) << sw->info.shift ); return (((int64_t) live << 32) / sw->ratio) << sw->info.shift;}static int audio_get_free (SWVoiceOut *sw){ int live, dead; if (!sw) { return 0; } live = sw->total_hw_samples_mixed; if (audio_bug (AUDIO_FUNC, live < 0 || live > sw->hw->samples)) { dolog ("live=%d sw->hw->samples=%d\n", live, sw->hw->samples); return 0; } dead = sw->hw->samples - live;#ifdef DEBUG_OUT dolog ("%s: get_free live %d dead %d ret %" PRId64 "\n", SW_NAME (sw), live, dead, (((int64_t) dead << 32) / sw->ratio) << sw->info.shift);#endif return (((int64_t) dead << 32) / sw->ratio) << sw->info.shift;}static void audio_capture_mix_and_clear (HWVoiceOut *hw, int rpos, int samples){ int n; if (hw->enabled) { SWVoiceCap *sc; for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) { SWVoiceOut *sw = &sc->sw; int rpos2 = rpos; n = samples; while (n) { int till_end_of_hw = hw->samples - rpos2; int to_write = audio_MIN (till_end_of_hw, n); int bytes = to_write << hw->info.shift; int written; sw->buf = hw->mix_buf + rpos2; written = audio_pcm_sw_write (sw, NULL, bytes); if (written - bytes) { dolog ("Could not mix %d bytes into a capture " "buffer, mixed %d\n", bytes, written); break; } n -= to_write; rpos2 = (rpos2 + to_write) % hw->samples; } } } n = audio_MIN (samples, hw->samples - rpos); mixeng_clear (hw->mix_buf + rpos, n); mixeng_clear (hw->mix_buf, samples - n);}static void audio_run_out (AudioState *s){ HWVoiceOut *hw = NULL; SWVoiceOut *sw; while ((hw = audio_pcm_hw_find_any_enabled_out (s, hw))) { int played; int live, free, nb_live, cleanup_required, prev_rpos; live = audio_pcm_hw_get_live_out2 (hw, &nb_live); if (!nb_live) { live = 0; } if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) { dolog ("live=%d hw->samples=%d\n", live, hw->samples); continue; } if (hw->pending_disable && !nb_live) { SWVoiceCap *sc;#ifdef DEBUG_OUT dolog ("Disabling voice\n");#endif hw->enabled = 0; hw->pending_disable = 0; hw->pcm_ops->ctl_out (hw, VOICE_DISABLE); for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) { sc->sw.active = 0; audio_recalc_and_notify_capture (sc->cap); } continue; } if (!live) { for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) { if (sw->active) { free = audio_get_free (sw); if (free > 0) { sw->callback.fn (sw->callback.opaque, free); } } } continue; } prev_rpos = hw->rpos; played = hw->pcm_ops->run_out (hw); if (audio_bug (AUDIO_FUNC, hw->rpos >= hw->samples)) { dolog ("hw->rpos=%d hw->samples=%d played=%d\n", hw->rpos, hw->samples, played); hw->rpos = 0; }#ifdef DEBUG_OUT dolog ("played=%d\n", played);#endif if (played) { hw->ts_helper += played; audio_capture_mix_and_clear (hw, prev_rpos, played); } cleanup_required = 0; for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) { if (!sw->active && sw->empty) { continue; } if (audio_bug (AUDIO_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; } sw->total_hw_samples_mixed -= played; if (!sw->total_hw_samples_mixed) { sw->empty = 1; cleanup_required |= !sw->active && !sw->callback.fn; } if (sw->active) { free = audio_get_free (sw); if (free > 0) { sw->callback.fn (sw->callback.opaque, free); } } } if (cleanup_required) { SWVoiceOut *sw1; sw = hw->sw_head.lh_first; 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 (s, sw); } sw = sw1; } } }}static void audio_run_in (AudioState *s){ HWVoiceIn *hw = NULL; while ((hw = audio_pcm_hw_find_any_enabled_in (s, hw))) { SWVoiceIn *sw; int captured, min; captured = hw->pcm_ops->run_in (hw); min = audio_pcm_hw_find_min_in (hw); hw->total_samples_captured += captured - min; hw->ts_helper += captured; for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) { sw->total_hw_samples_acquired -= min; if (sw->active) { int avail; avail = audio_get_avail (sw); if (avail > 0) { sw->callback.fn (sw->callback.opaque, avail); } } } }}static void audio_run_capture (AudioState *s){ CaptureVoiceOut *cap; for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) { int live, rpos, captured; HWVoiceOut *hw = &cap->hw; SWVoiceOut *sw; captured = live = audio_pcm_hw_get_live_out (hw); rpos = hw->rpos; while (live) { int left = hw->samples - rpos; int to_capture = audio_MIN (live, left); st_sample_t *src; struct capture_callback *cb; src = hw->mix_buf + rpos; hw->clip (cap->buf, src, to_capture); mixeng_clear (src, to_capture); for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) { cb->ops.capture (cb->opaque, cap->buf, to_capture << hw->info.shift); } rpos = (rpos + to_capture) % hw->samples; live -= to_capture; } hw->rpos = rpos; for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) { if (!sw->active && sw->empty) { continue; } if (audio_bug (AUDIO_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; } sw->total_hw_samples_mixed -= captured; sw->empty = sw->total_hw_samples_mixed == 0; } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -