[PATCH] [RFC] alsaloop: add feedback frequency control support for UAC2 gadgets
Jerome Brunet
jbrunet at baylibre.com
Fri Nov 27 10:17:14 CET 2020
On Thu 12 Nov 2020 at 23:34, Ruslan Bilovol <ruslan.bilovol at gmail.com> wrote:
> Add support of special "PCM Feedback Frequency Hz"
> UAC2 Gadget mixer control that is designed to notify
> host about real sampling frequency of the gadget so
> it can adjust number of samples that hosts sends to
> the gadget.
>
> This is useful if both host and gadget has its own
> internal freerunning clock, so host can adjust
> number of samples sent, preventing overrun/underrun
> conditions.
>
> This patch reuses logic of the "PCM Rate Shift 100000"
> control used in case of in-kernel ALSA loopback
> driver. The only difference is alsaloop reports not
> rate shift but frequency in Hz
>
> Signed-off-by: Ruslan Bilovol <ruslan.bilovol at gmail.com>
> ---
> alsaloop/alsaloop.h | 1 +
> alsaloop/pcmjob.c | 35 +++++++++++++++++++++++++----------
> 2 files changed, 26 insertions(+), 10 deletions(-)
>
> diff --git a/alsaloop/alsaloop.h b/alsaloop/alsaloop.h
> index c4aa618..9a50a42 100644
> --- a/alsaloop/alsaloop.h
> +++ b/alsaloop/alsaloop.h
> @@ -122,6 +122,7 @@ struct loopback_handle {
> unsigned int ctl_pollfd_count;
> snd_ctl_elem_value_t *ctl_notify;
> snd_ctl_elem_value_t *ctl_rate_shift;
> + snd_ctl_elem_value_t *ctl_fback_freq;
> snd_ctl_elem_value_t *ctl_active;
> snd_ctl_elem_value_t *ctl_format;
> snd_ctl_elem_value_t *ctl_rate;
> diff --git a/alsaloop/pcmjob.c b/alsaloop/pcmjob.c
> index 6a9aff4..b3802a8 100644
> --- a/alsaloop/pcmjob.c
> +++ b/alsaloop/pcmjob.c
> @@ -1058,15 +1058,22 @@ static int set_notify(struct loopback_handle *lhandle, int enable)
>
> static int set_rate_shift(struct loopback_handle *lhandle, double pitch)
> {
> - int err;
> + int err = 0;
>
> - if (lhandle->ctl_rate_shift == NULL)
> - return 0;
> - snd_ctl_elem_value_set_integer(lhandle->ctl_rate_shift, 0, pitch * 100000);
> - err = snd_ctl_elem_write(lhandle->ctl, lhandle->ctl_rate_shift);
> - if (err < 0) {
> - logit(LOG_CRIT, "Cannot set PCM Rate Shift element for %s: %s\n", lhandle->id, snd_strerror(err));
> - return err;
> + if (lhandle->ctl_rate_shift) {
> + snd_ctl_elem_value_set_integer(lhandle->ctl_rate_shift, 0, pitch * 100000);
> + err = snd_ctl_elem_write(lhandle->ctl, lhandle->ctl_rate_shift);
> + if (err < 0) {
> + logit(LOG_CRIT, "Cannot set PCM Rate Shift element for %s: %s\n", lhandle->id, snd_strerror(err));
> + return err;
> + }
> + } else if (lhandle->ctl_fback_freq) {
> + snd_ctl_elem_value_set_integer(lhandle->ctl_fback_freq, 0, lhandle->rate * (2.0 - pitch));
> + err = snd_ctl_elem_write(lhandle->ctl, lhandle->ctl_fback_freq);
> + if (err < 0) {
> + logit(LOG_CRIT, "Cannot set PCM Feedback Frequency element for %s: %s\n", lhandle->id, snd_strerror(err));
> + return err;
> + }
Hi Ruslan,
I wonder why bother adding a control of another type for the audio
gadget ? Why not give the gadget a "Rate Shift" control, instead "Feedback
Frequency" and let the driver deal with shift as necessary ?
It would be easier for the applications to re-use the same logic.
> }
> return 0;
> }
> @@ -1195,6 +1202,7 @@ static int openctl(struct loopback_handle *lhandle, int device, int subdevice)
> int err;
>
> lhandle->ctl_rate_shift = NULL;
> + lhandle->ctl_fback_freq = NULL;
> if (lhandle->loopback->play == lhandle) {
> if (lhandle->loopback->controls)
> goto __events;
> @@ -1204,6 +1212,8 @@ static int openctl(struct loopback_handle *lhandle, int device, int subdevice)
> &lhandle->ctl_notify);
> openctl_elem(lhandle, device, subdevice, "PCM Rate Shift 100000",
> &lhandle->ctl_rate_shift);
> + openctl_elem(lhandle, device, subdevice, "PCM Feedback Frequency Hz",
> + &lhandle->ctl_fback_freq);
> set_rate_shift(lhandle, 1);
> openctl_elem(lhandle, device, subdevice, "PCM Slave Active",
> &lhandle->ctl_active);
> @@ -1289,6 +1299,9 @@ static int closeit(struct loopback_handle *lhandle)
> if (lhandle->ctl_rate_shift)
> snd_ctl_elem_value_free(lhandle->ctl_rate_shift);
> lhandle->ctl_rate_shift = NULL;
> + if (lhandle->ctl_fback_freq)
> + snd_ctl_elem_value_free(lhandle->ctl_fback_freq);
> + lhandle->ctl_fback_freq = NULL;
> if (lhandle->ctl)
> err = snd_ctl_close(lhandle->ctl);
> lhandle->ctl = NULL;
> @@ -1334,9 +1347,11 @@ int pcmjob_init(struct loopback *loop)
> snprintf(id, sizeof(id), "%s/%s", loop->play->id, loop->capt->id);
> id[sizeof(id)-1] = '\0';
> loop->id = strdup(id);
> - if (loop->sync == SYNC_TYPE_AUTO && loop->capt->ctl_rate_shift)
> + if (loop->sync == SYNC_TYPE_AUTO && (loop->capt->ctl_rate_shift ||
> + loop->capt->ctl_fback_freq))
> loop->sync = SYNC_TYPE_CAPTRATESHIFT;
> - if (loop->sync == SYNC_TYPE_AUTO && loop->play->ctl_rate_shift)
> + if (loop->sync == SYNC_TYPE_AUTO && (loop->play->ctl_rate_shift ||
> + loop->play->ctl_fback_freq))
> loop->sync = SYNC_TYPE_PLAYRATESHIFT;
> #ifdef USE_SAMPLERATE
> if (loop->sync == SYNC_TYPE_AUTO && loop->src_enable)
More information about the Alsa-devel
mailing list