All of lore.kernel.org
 help / color / mirror / Atom feed
* Alsaloop: sync mode PLAYSHIFT + Loopback on playback side
@ 2021-10-01  8:35 Pavel Hofman
  2021-10-04  9:24 ` Jaroslav Kysela
  0 siblings, 1 reply; 7+ messages in thread
From: Pavel Hofman @ 2021-10-01  8:35 UTC (permalink / raw)
  To: alsa-devel

Hi,

I added support for "Playback Pitch 1000000" ctl elem to UAC2 gadget 
(not submitted to USB yet) and now I am working on alsaloop support for 
this ctl elem. The changes are simple (tested to work perfectly, patch 
to follow), but during the work I hit the following issue with playback 
Loopback "PCM Rate Shift 100000".

If the snd-aloop device is on playback side (i.e. capture from soundcard 
-> Loopback), the required sync mode is PLAYSHIFT. That means Loopback 
ctl elem "PCM Rate Shift 100000" should be controlled (by a reciprocal). 
That is simple by a patch like this:

diff --git a/alsaloop/pcmjob.c b/alsaloop/pcmjob.c
index 845ab82..619bf35 100644
--- a/alsaloop/pcmjob.c
+++ b/alsaloop/pcmjob.c
@@ -1061,7 +1061,13 @@ static int set_rate_shift(struct loopback_handle 
*lhandle, double pitch)
         int err;

         if (lhandle->ctl_rate_shift) {
-               snd_ctl_elem_value_set_integer(lhandle->ctl_rate_shift, 
0, pitch * 100000);
+               long value;
+               if (lhandle->loopback->play == lhandle)
+                       // playback => reciprocal
+                       value = 1/(pitch) * 100000;
+               else
+                       value = pitch * 100000;
+               snd_ctl_elem_value_set_integer(lhandle->ctl_rate_shift, 
0, value);
                 err = snd_ctl_elem_write(lhandle->ctl, 
lhandle->ctl_rate_shift);
         } else if (lhandle->capt_pitch) {
                 snd_ctl_elem_value_set_integer(lhandle->capt_pitch, 0, 
(1 / pitch) * 1000000);
@@ -1205,15 +1211,18 @@ static int openctl(struct loopback_handle 
*lhandle, int device, int subdevice)
         int err;

         lhandle->ctl_rate_shift = NULL;
+       // both play and capture
+       openctl_elem(lhandle, device, subdevice, "PCM Notify",
+                       &lhandle->ctl_notify);
+       openctl_elem(lhandle, device, subdevice, "PCM Rate Shift 100000",
+                       &lhandle->ctl_rate_shift);
         if (lhandle->loopback->play == lhandle) {
+               // play only
                 if (lhandle->loopback->controls)
                         goto __events;
                 return 0;
         }
-       openctl_elem(lhandle, device, subdevice, "PCM Notify",
-                       &lhandle->ctl_notify);
-       openctl_elem(lhandle, device, subdevice, "PCM Rate Shift 100000",
-                       &lhandle->ctl_rate_shift);
+       // capture only
         openctl_elem(lhandle, device, subdevice, "Capture Pitch 1000000",
                         &lhandle->capt_pitch);
         set_rate_shift(lhandle, 1);


However, IIUC how the Loopback device works, the "PCM Rate Shift 100000" 
ctl elem applicable to device=0 on playback side is that of the capture 
side, i.e. for device=1. The patch above would pick the playback-side 
device=0 ctl elem in pcmjob.c:openctl_elem. Hard-coding the device=0 -> 
device=1 is possible, but Loopback supports more devices.

Please what solution for picking the correct "PCM Rate Shift 100000" ctl 
elem for the PLAYSHIFT sync mode would you recommend?

Thanks a lot,

Pavel.

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: Alsaloop: sync mode PLAYSHIFT + Loopback on playback side
  2021-10-01  8:35 Alsaloop: sync mode PLAYSHIFT + Loopback on playback side Pavel Hofman
@ 2021-10-04  9:24 ` Jaroslav Kysela
  2021-10-04 11:24   ` Pavel Hofman
  0 siblings, 1 reply; 7+ messages in thread
From: Jaroslav Kysela @ 2021-10-04  9:24 UTC (permalink / raw)
  To: Pavel Hofman; +Cc: ALSA development

On 01. 10. 21 10:35, Pavel Hofman wrote:
> Hi,
> 
> I added support for "Playback Pitch 1000000" ctl elem to UAC2 gadget
> (not submitted to USB yet) and now I am working on alsaloop support for
> this ctl elem. The changes are simple (tested to work perfectly, patch
> to follow), but during the work I hit the following issue with playback
> Loopback "PCM Rate Shift 100000".
> 
> If the snd-aloop device is on playback side (i.e. capture from soundcard
> -> Loopback), the required sync mode is PLAYSHIFT. That means Loopback
> ctl elem "PCM Rate Shift 100000" should be controlled (by a reciprocal).
> That is simple by a patch like this:
> 
> diff --git a/alsaloop/pcmjob.c b/alsaloop/pcmjob.c
> index 845ab82..619bf35 100644
> --- a/alsaloop/pcmjob.c
> +++ b/alsaloop/pcmjob.c
> @@ -1061,7 +1061,13 @@ static int set_rate_shift(struct loopback_handle
> *lhandle, double pitch)
>           int err;
> 
>           if (lhandle->ctl_rate_shift) {
> -               snd_ctl_elem_value_set_integer(lhandle->ctl_rate_shift,
> 0, pitch * 100000);
> +               long value;
> +               if (lhandle->loopback->play == lhandle)
> +                       // playback => reciprocal
> +                       value = 1/(pitch) * 100000;
> +               else
> +                       value = pitch * 100000;
> +               snd_ctl_elem_value_set_integer(lhandle->ctl_rate_shift,
> 0, value);
>                   err = snd_ctl_elem_write(lhandle->ctl,
> lhandle->ctl_rate_shift);
>           } else if (lhandle->capt_pitch) {
>                   snd_ctl_elem_value_set_integer(lhandle->capt_pitch, 0,
> (1 / pitch) * 1000000);
> @@ -1205,15 +1211,18 @@ static int openctl(struct loopback_handle
> *lhandle, int device, int subdevice)
>           int err;
> 
>           lhandle->ctl_rate_shift = NULL;
> +       // both play and capture
> +       openctl_elem(lhandle, device, subdevice, "PCM Notify",
> +                       &lhandle->ctl_notify);
> +       openctl_elem(lhandle, device, subdevice, "PCM Rate Shift 100000",
> +                       &lhandle->ctl_rate_shift);
>           if (lhandle->loopback->play == lhandle) {
> +               // play only
>                   if (lhandle->loopback->controls)
>                           goto __events;
>                   return 0;
>           }
> -       openctl_elem(lhandle, device, subdevice, "PCM Notify",
> -                       &lhandle->ctl_notify);
> -       openctl_elem(lhandle, device, subdevice, "PCM Rate Shift 100000",
> -                       &lhandle->ctl_rate_shift);
> +       // capture only
>           openctl_elem(lhandle, device, subdevice, "Capture Pitch 1000000",
>                           &lhandle->capt_pitch);
>           set_rate_shift(lhandle, 1);
> 
> 
> However, IIUC how the Loopback device works, the "PCM Rate Shift 100000"
> ctl elem applicable to device=0 on playback side is that of the capture
> side, i.e. for device=1. The patch above would pick the playback-side
> device=0 ctl elem in pcmjob.c:openctl_elem. Hard-coding the device=0 ->
> device=1 is possible, but Loopback supports more devices.
> 
> Please what solution for picking the correct "PCM Rate Shift 100000" ctl
> elem for the PLAYSHIFT sync mode would you recommend?

Hi,

I would not touch the controls associated to the capture PCM by default. It 
would be possible to add another alsaloop option and code to configure the 
rate shift control identifier separately for this use case. The user should 
avoid the double pitch control (playback + capture) for the loopback devices.

					Jaroslav

-- 
Jaroslav Kysela <perex@perex.cz>
Linux Sound Maintainer; ALSA Project; Red Hat, Inc.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Alsaloop: sync mode PLAYSHIFT + Loopback on playback side
  2021-10-04  9:24 ` Jaroslav Kysela
@ 2021-10-04 11:24   ` Pavel Hofman
  2021-10-04 11:55     ` Jaroslav Kysela
  0 siblings, 1 reply; 7+ messages in thread
From: Pavel Hofman @ 2021-10-04 11:24 UTC (permalink / raw)
  To: Jaroslav Kysela; +Cc: ALSA development


Dne 04. 10. 21 v 11:24 Jaroslav Kysela napsal(a):
> On 01. 10. 21 10:35, Pavel Hofman wrote:
>> Hi,
>>
>> I added support for "Playback Pitch 1000000" ctl elem to UAC2 gadget
>> (not submitted to USB yet) and now I am working on alsaloop support for
>> this ctl elem. The changes are simple (tested to work perfectly, patch
>> to follow), but during the work I hit the following issue with playback
>> Loopback "PCM Rate Shift 100000".
>>
>> If the snd-aloop device is on playback side (i.e. capture from soundcard
>> -> Loopback), the required sync mode is PLAYSHIFT. That means Loopback
>> ctl elem "PCM Rate Shift 100000" should be controlled (by a reciprocal).
>> That is simple by a patch like this:
>>
>> diff --git a/alsaloop/pcmjob.c b/alsaloop/pcmjob.c
>> index 845ab82..619bf35 100644
>> --- a/alsaloop/pcmjob.c
>> +++ b/alsaloop/pcmjob.c
>> @@ -1061,7 +1061,13 @@ static int set_rate_shift(struct loopback_handle
>> *lhandle, double pitch)
>>           int err;
>>
>>           if (lhandle->ctl_rate_shift) {
>> -               snd_ctl_elem_value_set_integer(lhandle->ctl_rate_shift,
>> 0, pitch * 100000);
>> +               long value;
>> +               if (lhandle->loopback->play == lhandle)
>> +                       // playback => reciprocal
>> +                       value = 1/(pitch) * 100000;
>> +               else
>> +                       value = pitch * 100000;
>> +               snd_ctl_elem_value_set_integer(lhandle->ctl_rate_shift,
>> 0, value);
>>                   err = snd_ctl_elem_write(lhandle->ctl,
>> lhandle->ctl_rate_shift);
>>           } else if (lhandle->capt_pitch) {
>>                   snd_ctl_elem_value_set_integer(lhandle->capt_pitch, 0,
>> (1 / pitch) * 1000000);
>> @@ -1205,15 +1211,18 @@ static int openctl(struct loopback_handle
>> *lhandle, int device, int subdevice)
>>           int err;
>>
>>           lhandle->ctl_rate_shift = NULL;
>> +       // both play and capture
>> +       openctl_elem(lhandle, device, subdevice, "PCM Notify",
>> +                       &lhandle->ctl_notify);
>> +       openctl_elem(lhandle, device, subdevice, "PCM Rate Shift 100000",
>> +                       &lhandle->ctl_rate_shift);
>>           if (lhandle->loopback->play == lhandle) {
>> +               // play only
>>                   if (lhandle->loopback->controls)
>>                           goto __events;
>>                   return 0;
>>           }
>> -       openctl_elem(lhandle, device, subdevice, "PCM Notify",
>> -                       &lhandle->ctl_notify);
>> -       openctl_elem(lhandle, device, subdevice, "PCM Rate Shift 100000",
>> -                       &lhandle->ctl_rate_shift);
>> +       // capture only
>>           openctl_elem(lhandle, device, subdevice, "Capture Pitch 
>> 1000000",
>>                           &lhandle->capt_pitch);
>>           set_rate_shift(lhandle, 1);
>>
>>
>> However, IIUC how the Loopback device works, the "PCM Rate Shift 100000"
>> ctl elem applicable to device=0 on playback side is that of the capture
>> side, i.e. for device=1. The patch above would pick the playback-side
>> device=0 ctl elem in pcmjob.c:openctl_elem. Hard-coding the device=0 ->
>> device=1 is possible, but Loopback supports more devices.
>>
>> Please what solution for picking the correct "PCM Rate Shift 100000" ctl
>> elem for the PLAYSHIFT sync mode would you recommend?
> 
> Hi,
> 
> I would not touch the controls associated to the capture PCM by default. 
> It would be possible to add another alsaloop option and code to 
> configure the rate shift control identifier separately for this use 
> case. The user should avoid the double pitch control (playback + 
> capture) for the loopback devices.

Thanks for your input. I am not sure I understand correctly your intention.

The current code already avoids running playback and capture pitch 
control concurrently by one alsaloop as the loop->sync is either 
SYNC_TYPE_CAPTRATESHIFT or SYNC_TYPE_PLAYRATESHIFT. IMO the current code 
ignores SYNC_TYPE_PLAYRATESHIFT because the code jumps to 
set_rate_shift(loop->play, pitch) 
https://github.com/alsa-project/alsa-utils/blob/master/alsaloop/pcmjob.c#L1103 
but the lhandle->ctl_rate_shift elem is never set for playback side in 
pcmjob.c:openctl 
https://github.com/alsa-project/alsa-utils/blob/master/alsaloop/pcmjob.c#L1208 
(lhandle->loopback->play == lhandle). I confirmed it using the debug 
patch you accepted today (thanks! :-)).

Therefore my patch of the openctl moves the "PCM Notify" and "PCM Rate 
Shift 100000" setup before the playback check, so that lhandles of both 
directions can have the two elems configured.

But the loopback->play lhandle should configure elements for the capture 
side of the snd-aloop pipe which I do not know how to locate nicely. I 
can always use some hack "if device==0 then use device = 1" for the 
playback side etc. but that does not look nice.

Thanks a lot,

Pavel.


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Alsaloop: sync mode PLAYSHIFT + Loopback on playback side
  2021-10-04 11:24   ` Pavel Hofman
@ 2021-10-04 11:55     ` Jaroslav Kysela
  2021-10-04 14:32       ` Pavel Hofman
  0 siblings, 1 reply; 7+ messages in thread
From: Jaroslav Kysela @ 2021-10-04 11:55 UTC (permalink / raw)
  To: Pavel Hofman; +Cc: ALSA development

On 04. 10. 21 13:24, Pavel Hofman wrote:
> 
> Dne 04. 10. 21 v 11:24 Jaroslav Kysela napsal(a):
>> On 01. 10. 21 10:35, Pavel Hofman wrote:
>>> Hi,
>>>
>>> I added support for "Playback Pitch 1000000" ctl elem to UAC2 gadget
>>> (not submitted to USB yet) and now I am working on alsaloop support for
>>> this ctl elem. The changes are simple (tested to work perfectly, patch
>>> to follow), but during the work I hit the following issue with playback
>>> Loopback "PCM Rate Shift 100000".
>>>
>>> If the snd-aloop device is on playback side (i.e. capture from soundcard
>>> -> Loopback), the required sync mode is PLAYSHIFT. That means Loopback
>>> ctl elem "PCM Rate Shift 100000" should be controlled (by a reciprocal).
>>> That is simple by a patch like this:
>>>
>>> diff --git a/alsaloop/pcmjob.c b/alsaloop/pcmjob.c
>>> index 845ab82..619bf35 100644
>>> --- a/alsaloop/pcmjob.c
>>> +++ b/alsaloop/pcmjob.c
>>> @@ -1061,7 +1061,13 @@ static int set_rate_shift(struct loopback_handle
>>> *lhandle, double pitch)
>>>            int err;
>>>
>>>            if (lhandle->ctl_rate_shift) {
>>> -               snd_ctl_elem_value_set_integer(lhandle->ctl_rate_shift,
>>> 0, pitch * 100000);
>>> +               long value;
>>> +               if (lhandle->loopback->play == lhandle)
>>> +                       // playback => reciprocal
>>> +                       value = 1/(pitch) * 100000;
>>> +               else
>>> +                       value = pitch * 100000;
>>> +               snd_ctl_elem_value_set_integer(lhandle->ctl_rate_shift,
>>> 0, value);
>>>                    err = snd_ctl_elem_write(lhandle->ctl,
>>> lhandle->ctl_rate_shift);
>>>            } else if (lhandle->capt_pitch) {
>>>                    snd_ctl_elem_value_set_integer(lhandle->capt_pitch, 0,
>>> (1 / pitch) * 1000000);
>>> @@ -1205,15 +1211,18 @@ static int openctl(struct loopback_handle
>>> *lhandle, int device, int subdevice)
>>>            int err;
>>>
>>>            lhandle->ctl_rate_shift = NULL;
>>> +       // both play and capture
>>> +       openctl_elem(lhandle, device, subdevice, "PCM Notify",
>>> +                       &lhandle->ctl_notify);
>>> +       openctl_elem(lhandle, device, subdevice, "PCM Rate Shift 100000",
>>> +                       &lhandle->ctl_rate_shift);
>>>            if (lhandle->loopback->play == lhandle) {
>>> +               // play only
>>>                    if (lhandle->loopback->controls)
>>>                            goto __events;
>>>                    return 0;
>>>            }
>>> -       openctl_elem(lhandle, device, subdevice, "PCM Notify",
>>> -                       &lhandle->ctl_notify);
>>> -       openctl_elem(lhandle, device, subdevice, "PCM Rate Shift 100000",
>>> -                       &lhandle->ctl_rate_shift);
>>> +       // capture only
>>>            openctl_elem(lhandle, device, subdevice, "Capture Pitch
>>> 1000000",
>>>                            &lhandle->capt_pitch);
>>>            set_rate_shift(lhandle, 1);
>>>
>>>
>>> However, IIUC how the Loopback device works, the "PCM Rate Shift 100000"
>>> ctl elem applicable to device=0 on playback side is that of the capture
>>> side, i.e. for device=1. The patch above would pick the playback-side
>>> device=0 ctl elem in pcmjob.c:openctl_elem. Hard-coding the device=0 ->
>>> device=1 is possible, but Loopback supports more devices.
>>>
>>> Please what solution for picking the correct "PCM Rate Shift 100000" ctl
>>> elem for the PLAYSHIFT sync mode would you recommend?
>>
>> Hi,
>>
>> I would not touch the controls associated to the capture PCM by default.
>> It would be possible to add another alsaloop option and code to
>> configure the rate shift control identifier separately for this use
>> case. The user should avoid the double pitch control (playback +
>> capture) for the loopback devices.
> 
> Thanks for your input. I am not sure I understand correctly your intention.
> 
> The current code already avoids running playback and capture pitch
> control concurrently by one alsaloop as the loop->sync is either
> SYNC_TYPE_CAPTRATESHIFT or SYNC_TYPE_PLAYRATESHIFT. IMO the current code
> ignores SYNC_TYPE_PLAYRATESHIFT because the code jumps to
> set_rate_shift(loop->play, pitch)
> https://github.com/alsa-project/alsa-utils/blob/master/alsaloop/pcmjob.c#L1103
> but the lhandle->ctl_rate_shift elem is never set for playback side in
> pcmjob.c:openctl
> https://github.com/alsa-project/alsa-utils/blob/master/alsaloop/pcmjob.c#L1208
> (lhandle->loopback->play == lhandle). I confirmed it using the debug
> patch you accepted today (thanks! :-)).
> 
> Therefore my patch of the openctl moves the "PCM Notify" and "PCM Rate
> Shift 100000" setup before the playback check, so that lhandles of both
> directions can have the two elems configured.
> 
> But the loopback->play lhandle should configure elements for the capture
> side of the snd-aloop pipe which I do not know how to locate nicely. I
> can always use some hack "if device==0 then use device = 1" for the
> playback side etc. but that does not look nice.

Please, assume that the 'PCM Rate Shift 100000' control is for the capture PCM 
only by default. The applications should not handle those driver specific mapping.

If the user wants to use this control for the playback side, a new command 
line option may be added to cope with the alternate playback rate shift 
control indentifier (it may be parsed using snd_ctl_ascii_elem_id_parse() for 
example). So the user may specify the correct (different) device number there.

					Jaroslav

-- 
Jaroslav Kysela <perex@perex.cz>
Linux Sound Maintainer; ALSA Project; Red Hat, Inc.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Alsaloop: sync mode PLAYSHIFT + Loopback on playback side
  2021-10-04 11:55     ` Jaroslav Kysela
@ 2021-10-04 14:32       ` Pavel Hofman
  2021-10-05  8:58         ` Jaroslav Kysela
  0 siblings, 1 reply; 7+ messages in thread
From: Pavel Hofman @ 2021-10-04 14:32 UTC (permalink / raw)
  To: Jaroslav Kysela; +Cc: ALSA development

Dne 04. 10. 21 v 13:55 Jaroslav Kysela napsal(a):
>>> Hi,
>>>
>>> I would not touch the controls associated to the capture PCM by default.
>>> It would be possible to add another alsaloop option and code to
>>> configure the rate shift control identifier separately for this use
>>> case. The user should avoid the double pitch control (playback +
>>> capture) for the loopback devices.
>>
>> Thanks for your input. I am not sure I understand correctly your 
>> intention.
>>
>> The current code already avoids running playback and capture pitch
>> control concurrently by one alsaloop as the loop->sync is either
>> SYNC_TYPE_CAPTRATESHIFT or SYNC_TYPE_PLAYRATESHIFT. IMO the current code
>> ignores SYNC_TYPE_PLAYRATESHIFT because the code jumps to
>> set_rate_shift(loop->play, pitch)
>> https://github.com/alsa-project/alsa-utils/blob/master/alsaloop/pcmjob.c#L1103 
>>
>> but the lhandle->ctl_rate_shift elem is never set for playback side in
>> pcmjob.c:openctl
>> https://github.com/alsa-project/alsa-utils/blob/master/alsaloop/pcmjob.c#L1208 
>>
>> (lhandle->loopback->play == lhandle). I confirmed it using the debug
>> patch you accepted today (thanks! :-)).
>>
>> Therefore my patch of the openctl moves the "PCM Notify" and "PCM Rate
>> Shift 100000" setup before the playback check, so that lhandles of both
>> directions can have the two elems configured.
>>
>> But the loopback->play lhandle should configure elements for the capture
>> side of the snd-aloop pipe which I do not know how to locate nicely. I
>> can always use some hack "if device==0 then use device = 1" for the
>> playback side etc. but that does not look nice.
> 
> Please, assume that the 'PCM Rate Shift 100000' control is for the 
> capture PCM only by default. The applications should not handle those 
> driver specific mapping.
> 
> If the user wants to use this control for the playback side, a new 
> command line option may be added to cope with the alternate playback 
> rate shift control indentifier (it may be parsed using 
> snd_ctl_ascii_elem_id_parse() for example). So the user may specify the 
> correct (different) device number there.

Thanks, please can you comment on this patch? alsaloop.1 not updated 
yet. Tested to work OK, while checking via amixer that the elem 'PCM 
Rate Shift 100000',device=1 gets controlled:

pavel@precision:~/work/rpi-gadget/alsa-utils/alsaloop$ ./alsaloop -vv -l 
10000 v -c 2 -r 48000 -f S32_LE -C hw:Quartet -P hw:Loopback -S 
playshift -x iface=PCM,name='PCM Rate Shift 100000',device=1

!!!Scheduler set to Round Robin with priority 99 FAILED!
Opened PCM element 'iface=PCM,name=PCM Rate Shift 100000,device=1' for 
playback rate adjust of hw:10
Hardware PCM card 10 'Loopback' device 0 subdevice 0
Its setup is:
   stream       : PLAYBACK
   access       : RW_INTERLEAVED
   format       : S32_LE
   subformat    : STD
   channels     : 2
   rate         : 48000
   exact rate   : 48000 (48000/1)
   msbits       : 32
   buffer_size  : 39992
   period_size  : 4999
   period_time  : 104145
   tstamp_mode  : NONE
   tstamp_type  : MONOTONIC
   period_step  : 1
   avail_min    : 32494
   period_event : 0
   start_threshold  : 2147483647
   stop_threshold   : 39992
   silence_threshold: 0
   silence_size : 0
   boundary     : 5628373634306277376
   appl_ptr     : 0
   hw_ptr       : 0
Hardware PCM card 0 'Infrasonic Quartet' device 0 subdevice 0
Its setup is:
   stream       : CAPTURE
   access       : RW_INTERLEAVED
   format       : S32_LE
   subformat    : STD
   channels     : 2
   rate         : 48000
   exact rate   : 48000 (48000/1)
   msbits       : 24
   buffer_size  : 32768
   period_size  : 4096
   period_time  : 85333
   tstamp_mode  : NONE
   tstamp_type  : MONOTONIC
   period_step  : 1
   avail_min    : 4096
   period_event : 0
   start_threshold  : 2147483647
   stop_threshold   : 32768
   silence_threshold: 0
   silence_size : 0
   boundary     : 4611686018427387904
   appl_ptr     : 0
   hw_ptr       : 0
Latency 9999 frames, 208312.500us, 208.312500ms (4.8005Hz)
shared buffer!!!
playback hw:Loopback/capture hw:Quartet sync type: PLAYRATESHIFT
New pitch for playback hw:Loopback/capture hw:Quartet: 1.00000000 
(min/max samples = 0/0)
New pitch for playback hw:Loopback/capture hw:Quartet: 1.00001042 
(min/max samples = 0/35)
New pitch for playback hw:Loopback/capture hw:Quartet: 1.00001042 
(min/max samples = 0/35)
New pitch for playback hw:Loopback/capture hw:Quartet: 1.00001042 
(min/max samples = 0/35)
New pitch for playback hw:Loopback/capture hw:Quartet: 1.00002083 
(min/max samples = 0/39)
New pitch for playback hw:Loopback/capture hw:Quartet: 1.00002083 
(min/max samples = 0/39)
New pitch for playback hw:Loopback/capture hw:Quartet: 1.00002083 
(min/max samples = 0/39)
New pitch for playback hw:Loopback/capture hw:Quartet: 1.00001042 
(min/max samples = -14/39)
New pitch for playback hw:Loopback/capture hw:Quartet: 1.00000000 
(min/max samples = -29/39)
New pitch for playback hw:Loopback/capture hw:Quartet: 0.99998958 
(min/max samples = -32/39)
New pitch for playback hw:Loopback/capture hw:Quartet: 0.99998958 
(min/max samples = -32/39)
New pitch for playback hw:Loopback/capture hw:Quartet: 0.99998958 
(min/max samples = -32/39)
New pitch for playback hw:Loopback/capture hw:Quartet: 0.99998958 
(min/max samples = -32/39)
New pitch for playback hw:Loopback/capture hw:Quartet: 1.00000000 
(min/max samples = -32/39)
New pitch for playback hw:Loopback/capture hw:Quartet: 1.00001042 
(min/max samples = -32/39)
New pitch for playback hw:Loopback/capture hw:Quartet: 1.00002083 
(min/max samples = -32/39)
New pitch for playback hw:Loopback/capture hw:Quartet: 1.00003125 
(min/max samples = -32/39)
New pitch for playback hw:Loopback/capture hw:Quartet: 1.00002083 
(min/max samples = -32/39)
New pitch for playback hw:Loopback/capture hw:Quartet: 1.00001042 
(min/max samples = -32/39)
New pitch for playback hw:Loopback/capture hw:Quartet: 1.00000000 
(min/max samples = -38/39)
New pitch for playback hw:Loopback/capture hw:Quartet: 0.99998958 
(min/max samples = -41/39)
New pitch for playback hw:Loopback/capture hw:Quartet: 0.99998958 
(min/max samples = -41/39)
New pitch for playback hw:Loopback/capture hw:Quartet: 0.99998958 
(min/max samples = -41/39)
New pitch for playback hw:Loopback/capture hw:Quartet: 0.99998958 
(min/max samples = -41/39)
New pitch for playback hw:Loopback/capture hw:Quartet: 0.99998958 
(min/max samples = -41/39)
New pitch for playback hw:Loopback/capture hw:Quartet: 1.00000000 
(min/max samples = -41/39)
New pitch for playback hw:Loopback/capture hw:Quartet: 1.00001042 
(min/max samples = -41/39)
New pitch for playback hw:Loopback/capture hw:Quartet: 1.00002083 
(min/max samples = -41/39)
New pitch for playback hw:Loopback/capture hw:Quartet: 1.00002083 
(min/max samples = -41/39)


Without specifying the -x CONTROL_NAME param (no rate control applied) 
the pitch starts diverging:

New pitch for playback hw:Loopback/capture hw:Quartet: 1.00000000 
(min/max samples = 0/0)
New pitch for playback hw:Loopback/capture hw:Quartet: 1.00001042 
(min/max samples = 0/14)
New pitch for playback hw:Loopback/capture hw:Quartet: 1.00002083 
(min/max samples = 0/16)
New pitch for playback hw:Loopback/capture hw:Quartet: 1.00003125 
(min/max samples = 0/17)
New pitch for playback hw:Loopback/capture hw:Quartet: 1.00004167 
(min/max samples = 0/21)
New pitch for playback hw:Loopback/capture hw:Quartet: 1.00005208 
(min/max samples = 0/23)
New pitch for playback hw:Loopback/capture hw:Quartet: 1.00006250 
(min/max samples = 0/27)
New pitch for playback hw:Loopback/capture hw:Quartet: 1.00007292 
(min/max samples = 0/29)
New pitch for playback hw:Loopback/capture hw:Quartet: 1.00008333 
(min/max samples = 0/33)
New pitch for playback hw:Loopback/capture hw:Quartet: 1.00009375 
(min/max samples = 0/34)

Thanks a lot,

Pavel.


=============================================================
diff --git a/alsaloop/alsaloop.c b/alsaloop/alsaloop.c
index 06ffadf..4358db0 100644
--- a/alsaloop/alsaloop.c
+++ b/alsaloop/alsaloop.c
@@ -175,6 +175,7 @@ void help(void)
  "-C,--cdevice   capture device\n"
  "-X,--pctl      playback ctl device\n"
  "-Y,--cctl      capture ctl device\n"
+"-x,--prateshift playback 'PCM Rate Shift 100000' ascii ctl name\n"
  "-l,--latency   requested latency in frames\n"
  "-t,--tlatency  requested latency in usec (1/1000000sec)\n"
  "-f,--format    sample format\n"
@@ -362,6 +363,7 @@ static int parse_config(int argc, char *argv[], 
snd_output_t *output,
  		{"cdevice", 1, NULL, 'C'},
  		{"pctl", 1, NULL, 'X'},
  		{"cctl", 1, NULL, 'Y'},
+		{"prateshift", 1, NULL, 'x'},
  		{"latency", 1, NULL, 'l'},
  		{"tlatency", 1, NULL, 't'},
  		{"format", 1, NULL, 'f'},
@@ -391,6 +393,7 @@ static int parse_config(int argc, char *argv[], 
snd_output_t *output,
  	char *arg_cdevice = NULL;
  	char *arg_pctl = NULL;
  	char *arg_cctl = NULL;
+	char *arg_prateshift = NULL;
  	unsigned int arg_latency_req = 0;
  	unsigned int arg_latency_reqtime = 10000;
  	snd_pcm_format_t arg_format = SND_PCM_FORMAT_S16_LE;
@@ -420,7 +423,7 @@ static int parse_config(int argc, char *argv[], 
snd_output_t *output,
  	while (1) {
  		int c;
  		if ((c = getopt_long(argc, argv,
-				"hdg:P:C:X:Y:l:t:F:f:c:r:s:benvA:S:a:m:T:O:w:UW:z",
+				"hdg:P:C:X:Y:x:l:t:F:f:c:r:s:benvA:S:a:m:T:O:w:UW:z",
  				long_option, NULL)) < 0)
  			break;
  		switch (c) {
@@ -446,6 +449,9 @@ static int parse_config(int argc, char *argv[], 
snd_output_t *output,
  		case 'Y':
  			arg_cctl = strdup(optarg);
  			break;
+		case 'x':
+			arg_prateshift = strdup(optarg);
+			break;
  		case 'l':
  			err = atoi(optarg);
  			arg_latency_req = err >= 4 ? err : 4;
@@ -627,6 +633,10 @@ static int parse_config(int argc, char *argv[], 
snd_output_t *output,
  			logit(LOG_CRIT, "Unable to add ossmixer controls.\n");
  			exit(EXIT_FAILURE);
  		}
+		if (arg_prateshift) {
+			play->prateshift_name = arg_prateshift;
+		}
+
  #ifdef USE_SAMPLERATE
  		loop->src_enable = arg_samplerate > 0;
  		if (loop->src_enable)
diff --git a/alsaloop/alsaloop.h b/alsaloop/alsaloop.h
index 1dbcefe..7a98ef3 100644
--- a/alsaloop/alsaloop.h
+++ b/alsaloop/alsaloop.h
@@ -127,6 +127,7 @@ struct loopback_handle {
  	snd_ctl_elem_value_t *ctl_format;
  	snd_ctl_elem_value_t *ctl_rate;
  	snd_ctl_elem_value_t *ctl_channels;
+	char *prateshift_name; /* ascii name for the playback rate shift ctl 
elem */
  };

  struct loopback {
diff --git a/alsaloop/pcmjob.c b/alsaloop/pcmjob.c
index 845ab82..a4b28e3 100644
--- a/alsaloop/pcmjob.c
+++ b/alsaloop/pcmjob.c
@@ -1101,7 +1101,8 @@ void update_pitch(struct loopback *loop)
  #endif
  	}
  	else if (loop->sync == SYNC_TYPE_PLAYRATESHIFT) {
-		set_rate_shift(loop->play, pitch);
+		// pitch is capture-based, playback side requires reciprocal
+		set_rate_shift(loop->play, 1 / pitch);
  #ifdef USE_SAMPLERATE
  		if (loop->use_samplerate) {
  			loop->src_data.src_ratio =
@@ -1200,16 +1201,66 @@ static void openctl_elem(struct loopback_handle 
*lhandle,
  	}
  }

+static int openctl_play_rateshift(struct loopback_handle *lhandle,
+			char *ascii_name) {
+	int err;
+	snd_ctl_elem_id_t *id;
+	snd_ctl_elem_value_t **elem;
+
+	elem = &lhandle->ctl_rate_shift;
+
+	if (snd_ctl_elem_value_malloc(elem) < 0) {
+		return -ENOMEM;
+	}
+
+	if (snd_ctl_elem_id_malloc(&id)) {
+		snd_ctl_elem_value_free(*elem);
+		return -ENOMEM;
+	}
+
+	if (snd_ctl_ascii_elem_id_parse(id, ascii_name)) {
+		snd_ctl_elem_id_free(id);
+		snd_ctl_elem_value_free(*elem);
+		fprintf(stderr, "Wrong control identifier: %s\n", ascii_name);
+		return -EINVAL;
+	}
+
+	snd_ctl_elem_value_set_id(*elem, id);
+	err = snd_ctl_elem_read(lhandle->ctl, *elem);
+	if (err < 0) {
+		snd_ctl_elem_id_free(id);
+		snd_ctl_elem_value_free(*elem);
+		return err;
+	} else {
+		snd_output_printf(lhandle->loopback->output,
+				"Opened PCM element '%s' for playback rate adjust of %s\n",
+				ascii_name, snd_ctl_name(lhandle->ctl));
+	}
+	return 0;
+}
+
+
  static int openctl(struct loopback_handle *lhandle, int device, int 
subdevice)
  {
  	int err;

-	lhandle->ctl_rate_shift = NULL;
  	if (lhandle->loopback->play == lhandle) {
+		// play only
+		if (lhandle->prateshift_name) {
+			err = openctl_play_rateshift(lhandle, lhandle->prateshift_name);
+			if (err < 0) {
+				logit(LOG_CRIT, "Unable to open playback PCM Rate Shift elem '%s'.\n",
+						lhandle->prateshift_name);
+				exit(EXIT_FAILURE);
+			}
+		}
+
  		if (lhandle->loopback->controls)
  			goto __events;
  		return 0;
  	}
+	// capture only
+	lhandle->ctl_rate_shift = NULL;
  	openctl_elem(lhandle, device, subdevice, "PCM Notify",
  			&lhandle->ctl_notify);
  	openctl_elem(lhandle, device, subdevice, "PCM Rate Shift 100000",

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: Alsaloop: sync mode PLAYSHIFT + Loopback on playback side
  2021-10-04 14:32       ` Pavel Hofman
@ 2021-10-05  8:58         ` Jaroslav Kysela
  2021-10-13  6:38           ` Pavel Hofman
  0 siblings, 1 reply; 7+ messages in thread
From: Jaroslav Kysela @ 2021-10-05  8:58 UTC (permalink / raw)
  To: Pavel Hofman; +Cc: ALSA development

On 04. 10. 21 16:32, Pavel Hofman wrote:

> 
> +static int openctl_play_rateshift(struct loopback_handle *lhandle,
> +			char *ascii_name) {

I would create 'openctl_elem_ascii' function which will accept the ascii id 
and the snd_ctl_elem_value_t pointer like 'openctl_elem' does. The the common 
code may be moved to the 'openctl_elem_id' function from the 'openctl_elem' 
function.

But it's just nitpicking, the rest of patch looks fine and follows my 
suggestion. Thank you.

						Jaroslav

-- 
Jaroslav Kysela <perex@perex.cz>
Linux Sound Maintainer; ALSA Project; Red Hat, Inc.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Alsaloop: sync mode PLAYSHIFT + Loopback on playback side
  2021-10-05  8:58         ` Jaroslav Kysela
@ 2021-10-13  6:38           ` Pavel Hofman
  0 siblings, 0 replies; 7+ messages in thread
From: Pavel Hofman @ 2021-10-13  6:38 UTC (permalink / raw)
  To: Jaroslav Kysela; +Cc: ALSA development

Hi Jaroslav,

Dne 05. 10. 21 v 10:58 Jaroslav Kysela napsal(a):
> On 04. 10. 21 16:32, Pavel Hofman wrote:
> 
>>
>> +static int openctl_play_rateshift(struct loopback_handle *lhandle,
>> +            char *ascii_name) {
> 
> I would create 'openctl_elem_ascii' function which will accept the ascii 
> id and the snd_ctl_elem_value_t pointer like 'openctl_elem' does. The 
> the common code may be moved to the 'openctl_elem_id' function from the 
> 'openctl_elem' function.
> 
> But it's just nitpicking, the rest of patch looks fine and follows my 
> suggestion. Thank you.
> 

Thanks for your recommendations. I sent the v2 patch in 
https://patchwork.kernel.org/project/alsa-devel/patch/20211005194903.7957-1-pavel.hofman@ivitera.com/ 
. Please is it OK now or should I make some more changes?

Thanks a lot,

Pavel.

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2021-10-13  6:39 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-10-01  8:35 Alsaloop: sync mode PLAYSHIFT + Loopback on playback side Pavel Hofman
2021-10-04  9:24 ` Jaroslav Kysela
2021-10-04 11:24   ` Pavel Hofman
2021-10-04 11:55     ` Jaroslav Kysela
2021-10-04 14:32       ` Pavel Hofman
2021-10-05  8:58         ` Jaroslav Kysela
2021-10-13  6:38           ` Pavel Hofman

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.