Re: Alsaloop: sync mode PLAYSHIFT + Loopback on playback side

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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",



[Index of Archives]     [ALSA User]     [Linux Audio Users]     [Pulse Audio]     [Kernel Archive]     [Asterisk PBX]     [Photo Sharing]     [Linux Sound]     [Video 4 Linux]     [Gimp]     [Yosemite News]

  Powered by Linux