audio: make recording packet length calculation exact
Introduce the new function st_rate_frames_out() to calculate the exact number of audio output frames the resampling code can generate from a given number of audio input frames. When upsampling, this function returns the maximum number of output frames. This new function replaces the audio_frontend_frames_in() function, which calculated the average number of output frames rounded down to the nearest integer. The audio_frontend_frames_in() function was additionally used to limit the number of output frames to the resample buffer size. In audio_pcm_sw_read() the variable resample_buf.size replaces the open coded audio_frontend_frames_in() function. In audio_run_in() an additional MIN() function is necessary. After this patch the audio packet length calculation for audio recording is exact. Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> Signed-off-by: Volker Rümelin <vr_qemu@t-online.de> Message-Id: <20230224190555.7409-12-vr_qemu@t-online.de>
This commit is contained in:
parent
fbde1edf06
commit
a9ea567873
@ -579,7 +579,7 @@ static void audio_pcm_sw_resample_in(SWVoiceIn *sw,
|
||||
static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t buf_len)
|
||||
{
|
||||
HWVoiceIn *hw = sw->hw;
|
||||
size_t live, frames_out_max, swlim, total_in, total_out;
|
||||
size_t live, frames_out_max, total_in, total_out;
|
||||
|
||||
live = hw->total_samples_captured - sw->total_hw_samples_acquired;
|
||||
if (!live) {
|
||||
@ -590,12 +590,10 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t buf_len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
frames_out_max = buf_len / sw->info.bytes_per_frame;
|
||||
frames_out_max = MIN(buf_len / sw->info.bytes_per_frame,
|
||||
sw->resample_buf.size);
|
||||
|
||||
swlim = (live * sw->ratio) >> 32;
|
||||
swlim = MIN(swlim, frames_out_max);
|
||||
|
||||
audio_pcm_sw_resample_in(sw, live, swlim, &total_in, &total_out);
|
||||
audio_pcm_sw_resample_in(sw, live, frames_out_max, &total_in, &total_out);
|
||||
|
||||
if (!hw->pcm_ops->volume_in) {
|
||||
mixeng_volume(sw->resample_buf.buffer, total_out, &sw->vol);
|
||||
@ -979,18 +977,6 @@ 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;
|
||||
@ -1007,9 +993,9 @@ static size_t audio_get_avail (SWVoiceIn *sw)
|
||||
}
|
||||
|
||||
ldebug (
|
||||
"%s: get_avail live %zu frontend frames %zu\n",
|
||||
"%s: get_avail live %zu frontend frames %u\n",
|
||||
SW_NAME (sw),
|
||||
live, audio_frontend_frames_in(sw, live)
|
||||
live, st_rate_frames_out(sw->rate, live)
|
||||
);
|
||||
|
||||
return live;
|
||||
@ -1314,8 +1300,9 @@ static void audio_run_in (AudioState *s)
|
||||
size_t sw_avail = audio_get_avail(sw);
|
||||
size_t avail;
|
||||
|
||||
avail = audio_frontend_frames_in(sw, sw_avail);
|
||||
avail = st_rate_frames_out(sw->rate, sw_avail);
|
||||
if (avail > 0) {
|
||||
avail = MIN(avail, sw->resample_buf.size);
|
||||
sw->callback.fn(sw->callback.opaque,
|
||||
avail * sw->info.bytes_per_frame);
|
||||
}
|
||||
|
@ -440,6 +440,47 @@ void st_rate_stop (void *opaque)
|
||||
g_free (opaque);
|
||||
}
|
||||
|
||||
/**
|
||||
* st_rate_frames_out() - returns the number of frames the resampling code
|
||||
* generates from frames_in frames
|
||||
*
|
||||
* @opaque: pointer to struct rate
|
||||
* @frames_in: number of frames
|
||||
*
|
||||
* When upsampling, there may be more than one correct result. In this case,
|
||||
* the function returns the maximum number of output frames the resampling
|
||||
* code can generate.
|
||||
*/
|
||||
uint32_t st_rate_frames_out(void *opaque, uint32_t frames_in)
|
||||
{
|
||||
struct rate *rate = opaque;
|
||||
uint64_t opos_end, opos_delta;
|
||||
uint32_t ipos_end;
|
||||
uint32_t frames_out;
|
||||
|
||||
if (rate->opos_inc == 1ULL << 32) {
|
||||
return frames_in;
|
||||
}
|
||||
|
||||
/* no output frame without at least one input frame */
|
||||
if (!frames_in) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* last frame read was at rate->ipos - 1 */
|
||||
ipos_end = rate->ipos - 1 + frames_in;
|
||||
opos_end = (uint64_t)ipos_end << 32;
|
||||
|
||||
/* last frame written was at rate->opos - rate->opos_inc */
|
||||
if (opos_end + rate->opos_inc <= rate->opos) {
|
||||
return 0;
|
||||
}
|
||||
opos_delta = opos_end - rate->opos + rate->opos_inc;
|
||||
frames_out = opos_delta / rate->opos_inc;
|
||||
|
||||
return opos_delta % rate->opos_inc ? frames_out : frames_out - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* st_rate_frames_in() - returns the number of frames needed to
|
||||
* get frames_out frames after resampling
|
||||
|
@ -52,6 +52,7 @@ void st_rate_flow(void *opaque, st_sample *ibuf, st_sample *obuf,
|
||||
void st_rate_flow_mix(void *opaque, st_sample *ibuf, st_sample *obuf,
|
||||
size_t *isamp, size_t *osamp);
|
||||
void st_rate_stop (void *opaque);
|
||||
uint32_t st_rate_frames_out(void *opaque, uint32_t frames_in);
|
||||
uint32_t st_rate_frames_in(void *opaque, uint32_t frames_out);
|
||||
void mixeng_clear (struct st_sample *buf, int len);
|
||||
void mixeng_volume (struct st_sample *buf, int len, struct mixeng_volume *vol);
|
||||
|
Loading…
Reference in New Issue
Block a user