aboutsummaryrefslogtreecommitdiff
path: root/audio/audio.c
diff options
context:
space:
mode:
Diffstat (limited to 'audio/audio.c')
-rw-r--r--audio/audio.c111
1 files changed, 73 insertions, 38 deletions
diff --git a/audio/audio.c b/audio/audio.c
index df6818ed55..cc664271eb 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -986,6 +986,18 @@ void AUD_set_active_in (SWVoiceIn *sw, int on)
}
}
+/**
+ * audio_frontend_frames_in() - returns the number of frames the resampling
+ * code generates from frames_in frames
+ *
+ * @sw: audio recording frontend
+ * @frames_in: number of frames
+ */
+static size_t audio_frontend_frames_in(SWVoiceIn *sw, size_t frames_in)
+{
+ return (int64_t)frames_in * sw->ratio >> 32;
+}
+
static size_t audio_get_avail (SWVoiceIn *sw)
{
size_t live;
@@ -1002,17 +1014,24 @@ static size_t audio_get_avail (SWVoiceIn *sw)
}
ldebug (
- "%s: get_avail live %zu ret %" PRId64 "\n",
+ "%s: get_avail live %zu frontend frames %zu\n",
SW_NAME (sw),
- live, (((int64_t) live << 32) / sw->ratio) * sw->info.bytes_per_frame
+ live, audio_frontend_frames_in(sw, live)
);
- return (((int64_t) live << 32) / sw->ratio) * sw->info.bytes_per_frame;
+ return live;
}
-static size_t audio_sw_bytes_free(SWVoiceOut *sw, size_t free)
+/**
+ * audio_frontend_frames_out() - returns the number of frames needed to
+ * get frames_out frames after resampling
+ *
+ * @sw: audio playback frontend
+ * @frames_out: number of frames
+ */
+static size_t audio_frontend_frames_out(SWVoiceOut *sw, size_t frames_out)
{
- return (((int64_t)free << 32) / sw->ratio) * sw->info.bytes_per_frame;
+ return ((int64_t)frames_out << 32) / sw->ratio;
}
static size_t audio_get_free(SWVoiceOut *sw)
@@ -1034,8 +1053,8 @@ static size_t audio_get_free(SWVoiceOut *sw)
dead = sw->hw->mix_buf->size - live;
#ifdef DEBUG_OUT
- dolog("%s: get_free live %zu dead %zu sw_bytes %zu\n",
- SW_NAME(sw), live, dead, audio_sw_bytes_free(sw, dead));
+ dolog("%s: get_free live %zu dead %zu frontend frames %zu\n",
+ SW_NAME(sw), live, dead, audio_frontend_frames_out(sw, dead));
#endif
return dead;
@@ -1121,8 +1140,12 @@ static void audio_run_out (AudioState *s)
HWVoiceOut *hw = NULL;
SWVoiceOut *sw;
- if (!audio_get_pdo_out(s->dev)->mixing_engine) {
- while ((hw = audio_pcm_hw_find_any_enabled_out(s, hw))) {
+ while ((hw = audio_pcm_hw_find_any_enabled_out(s, hw))) {
+ size_t played, live, prev_rpos;
+ size_t hw_free = audio_pcm_hw_get_free(hw);
+ int nb_live;
+
+ if (!audio_get_pdo_out(s->dev)->mixing_engine) {
/* there is exactly 1 sw for each hw with no mixeng */
sw = hw->sw_head.lh_first;
@@ -1135,16 +1158,16 @@ static void audio_run_out (AudioState *s)
}
if (sw->active) {
- sw->callback.fn(sw->callback.opaque, INT_MAX);
+ sw->callback.fn(sw->callback.opaque,
+ hw_free * sw->info.bytes_per_frame);
}
- }
- return;
- }
- while ((hw = audio_pcm_hw_find_any_enabled_out(s, hw))) {
- size_t played, live, prev_rpos;
- size_t hw_free = audio_pcm_hw_get_free(hw);
- int nb_live;
+ if (hw->pcm_ops->run_buffer_out) {
+ hw->pcm_ops->run_buffer_out(hw);
+ }
+
+ continue;
+ }
for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
if (sw->active) {
@@ -1152,13 +1175,14 @@ static void audio_run_out (AudioState *s)
size_t free;
if (hw_free > sw->total_hw_samples_mixed) {
- free = audio_sw_bytes_free(sw,
+ free = audio_frontend_frames_out(sw,
MIN(sw_free, hw_free - sw->total_hw_samples_mixed));
} else {
free = 0;
}
if (free > 0) {
- sw->callback.fn(sw->callback.opaque, free);
+ sw->callback.fn(sw->callback.opaque,
+ free * sw->info.bytes_per_frame);
}
}
}
@@ -1297,11 +1321,13 @@ static void audio_run_in (AudioState *s)
sw->total_hw_samples_acquired -= min;
if (sw->active) {
+ size_t sw_avail = audio_get_avail(sw);
size_t avail;
- avail = audio_get_avail (sw);
+ avail = audio_frontend_frames_in(sw, sw_avail);
if (avail > 0) {
- sw->callback.fn (sw->callback.opaque, avail);
+ sw->callback.fn(sw->callback.opaque,
+ avail * sw->info.bytes_per_frame);
}
}
}
@@ -1501,10 +1527,6 @@ size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size)
}
}
- if (hw->pcm_ops->run_buffer_out) {
- hw->pcm_ops->run_buffer_out(hw);
- }
-
return total;
}
@@ -1750,13 +1772,13 @@ static AudioState *audio_init(Audiodev *dev, const char *name)
s->nb_hw_voices_out = audio_get_pdo_out(dev)->voices;
s->nb_hw_voices_in = audio_get_pdo_in(dev)->voices;
- if (s->nb_hw_voices_out <= 0) {
+ if (s->nb_hw_voices_out < 1) {
dolog ("Bogus number of playback voices %d, setting to 1\n",
s->nb_hw_voices_out);
s->nb_hw_voices_out = 1;
}
- if (s->nb_hw_voices_in <= 0) {
+ if (s->nb_hw_voices_in < 0) {
dolog ("Bogus number of capture voices %d, setting to 0\n",
s->nb_hw_voices_in);
s->nb_hw_voices_in = 0;
@@ -2251,26 +2273,39 @@ void audio_rate_start(RateCtl *rate)
rate->start_ticks = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
}
-size_t audio_rate_get_bytes(struct audio_pcm_info *info, RateCtl *rate,
- size_t bytes_avail)
+size_t audio_rate_peek_bytes(RateCtl *rate, struct audio_pcm_info *info)
{
int64_t now;
int64_t ticks;
int64_t bytes;
- int64_t samples;
- size_t ret;
+ int64_t frames;
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
ticks = now - rate->start_ticks;
bytes = muldiv64(ticks, info->bytes_per_second, NANOSECONDS_PER_SECOND);
- samples = (bytes - rate->bytes_sent) / info->bytes_per_frame;
- if (samples < 0 || samples > 65536) {
- AUD_log(NULL, "Resetting rate control (%" PRId64 " samples)\n", samples);
+ frames = (bytes - rate->bytes_sent) / info->bytes_per_frame;
+ if (frames < 0 || frames > 65536) {
+ AUD_log(NULL, "Resetting rate control (%" PRId64 " frames)\n", frames);
audio_rate_start(rate);
- samples = 0;
+ frames = 0;
}
- ret = MIN(samples * info->bytes_per_frame, bytes_avail);
- rate->bytes_sent += ret;
- return ret;
+ return frames * info->bytes_per_frame;
+}
+
+void audio_rate_add_bytes(RateCtl *rate, size_t bytes_used)
+{
+ rate->bytes_sent += bytes_used;
+}
+
+size_t audio_rate_get_bytes(RateCtl *rate, struct audio_pcm_info *info,
+ size_t bytes_avail)
+{
+ size_t bytes;
+
+ bytes = audio_rate_peek_bytes(rate, info);
+ bytes = MIN(bytes, bytes_avail);
+ audio_rate_add_bytes(rate, bytes);
+
+ return bytes;
}