@@ -731,16 +731,21 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t buf_len)
hw_free = hw_free > live ? hw_free - live : 0;
frames_out_max = MIN(dead, hw_free);
sw_max = st_rate_frames_in(sw->rate, frames_out_max);
- fe_max = MIN(buf_len / sw->info.bytes_per_frame, sw->resample_buf.size);
+ fe_max = MIN(buf_len / sw->info.bytes_per_frame + sw->resample_buf.pos,
+ sw->resample_buf.size);
frames_in_max = MIN(sw_max, fe_max);
if (!frames_in_max) {
return 0;
}
- sw->conv(sw->resample_buf.buffer, buf, frames_in_max);
- if (!sw->hw->pcm_ops->volume_out) {
- mixeng_volume(sw->resample_buf.buffer, frames_in_max, &sw->vol);
+ if (frames_in_max > sw->resample_buf.pos) {
+ sw->conv(sw->resample_buf.buffer + sw->resample_buf.pos,
+ buf, frames_in_max - sw->resample_buf.pos);
+ if (!sw->hw->pcm_ops->volume_out) {
+ mixeng_volume(sw->resample_buf.buffer + sw->resample_buf.pos,
+ frames_in_max - sw->resample_buf.pos, &sw->vol);
+ }
}
audio_pcm_sw_resample_out(sw, frames_in_max, frames_out_max,
@@ -749,6 +754,22 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t buf_len)
sw->total_hw_samples_mixed += total_out;
sw->empty = sw->total_hw_samples_mixed == 0;
+ /*
+ * Upsampling may leave one audio frame in the resample buffer. Decrement
+ * total_in by one if there was a leftover frame from the previous resample
+ * pass in the resample buffer. Increment total_in by one if the current
+ * resample pass left one frame in the resample buffer.
+ */
+ if (frames_in_max - total_in == 1) {
+ /* copy one leftover audio frame to the beginning of the buffer */
+ *sw->resample_buf.buffer = *(sw->resample_buf.buffer + total_in);
+ total_in += 1 - sw->resample_buf.pos;
+ sw->resample_buf.pos = 1;
+ } else if (total_in >= sw->resample_buf.pos) {
+ total_in -= sw->resample_buf.pos;
+ sw->resample_buf.pos = 0;
+ }
+
#ifdef DEBUG_OUT
dolog (
"%s: write size %zu written %zu total mixed %zu\n",
@@ -1155,8 +1176,9 @@ static void audio_run_out (AudioState *s)
} else {
free = 0;
}
- if (free > 0) {
- free = MIN(free, sw->resample_buf.size);
+ if (free > sw->resample_buf.pos) {
+ free = MIN(free, sw->resample_buf.size)
+ - sw->resample_buf.pos;
sw->callback.fn(sw->callback.opaque,
free * sw->info.bytes_per_frame);
}
@@ -138,6 +138,12 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
return -1;
}
+ /*
+ * Allocate one additional audio frame that is needed for upsampling
+ * if the resample buffer size is small. For large buffer sizes take
+ * care of overflows.
+ */
+ samples = samples < INT_MAX ? samples + 1 : INT_MAX;
sw->resample_buf.buffer = g_new0(st_sample, samples);
sw->resample_buf.size = samples;
sw->resample_buf.pos = 0;