forked from pool/alsa-utils
- backport GIT PATCHES:
* A few alsactl init fix patches: * amixer control-id parse fix * new aloop utility * robusitfy speaker-test * misc clean up, translation updates - Use systemd for openSUSE 11.4 - Put udev rules into this package instead of alsa.rpm OBS-URL: https://build.opensuse.org/package/show/multimedia:libs/alsa-utils?expand=0&rev=23
This commit is contained in:
parent
00b6532313
commit
3331bcfb82
@ -0,0 +1,35 @@
|
|||||||
|
From 52bd2f8acedaacce32ca8e89cb1f21683658648e Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jaroslav Kysela <perex@perex.cz>
|
||||||
|
Date: Tue, 7 Sep 2010 17:07:12 +0200
|
||||||
|
Subject: [PATCH 14/38] alsactl init: Handle "Capture Source" and "Mic Boost" in the default script
|
||||||
|
|
||||||
|
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
|
||||||
|
---
|
||||||
|
alsactl/init/default | 6 ++++++
|
||||||
|
1 files changed, 6 insertions(+), 0 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/alsactl/init/default b/alsactl/init/default
|
||||||
|
index 35acfc3..9fd7972 100644
|
||||||
|
--- a/alsactl/init/default
|
||||||
|
+++ b/alsactl/init/default
|
||||||
|
@@ -185,6 +185,11 @@ CTL{name}="Capture Volume",CTL{do_search}=="1", \
|
||||||
|
CTL{name}="Capture Switch",CTL{do_search}=="1", \
|
||||||
|
CTL{values}="on"
|
||||||
|
|
||||||
|
+CTL{name}="Capture Source",PROGRAM!="__ctl_search", GOTO=""
|
||||||
|
+CTL{enums}=="*|Internal Mic|*",CTL{values}="Internal Mic", GOTO=""
|
||||||
|
+CTL{enums}=="*|Mic|*",CTL{values}="Mic"
|
||||||
|
+LABEL=""
|
||||||
|
+
|
||||||
|
CTL{name}="Input Source",PROGRAM!="__ctl_search", GOTO=""
|
||||||
|
CTL{enums}=="*|Internal Mic|*",CTL{values}="Internal Mic", GOTO=""
|
||||||
|
CTL{enums}=="*|Mic|*",CTL{values}="Mic"
|
||||||
|
@@ -195,4 +200,5 @@ CTL{enums}=="*|Digital Mic 1|*",CTL{values}="Digital Mic 1", GOTO=""
|
||||||
|
CTL{enums}=="*|Mic|*",CTL{values}="Mic"
|
||||||
|
LABEL=""
|
||||||
|
|
||||||
|
+CTL{name}="Mic Boost",CTL{do_search}=="1", CTL{values}="on"
|
||||||
|
CTL{name}="Internal Mic Boost",CTL{do_search}=="1", CTL{values}="on"
|
||||||
|
--
|
||||||
|
1.7.3.1
|
||||||
|
|
@ -0,0 +1,31 @@
|
|||||||
|
From ef919a4724169f4c0dc14168dec32c168b2471e4 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jaroslav Kysela <perex@perex.cz>
|
||||||
|
Date: Tue, 7 Sep 2010 17:33:14 +0200
|
||||||
|
Subject: [PATCH 15/38] alsactl init: Initialize also "Master Front Playback Volume" & "Switch"
|
||||||
|
|
||||||
|
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
|
||||||
|
---
|
||||||
|
alsactl/init/default | 7 +++++++
|
||||||
|
1 files changed, 7 insertions(+), 0 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/alsactl/init/default b/alsactl/init/default
|
||||||
|
index 9fd7972..7f8ec4c 100644
|
||||||
|
--- a/alsactl/init/default
|
||||||
|
+++ b/alsactl/init/default
|
||||||
|
@@ -30,6 +30,13 @@ CTL{name}="Master Playback Switch",CTL{do_search}=="1", \
|
||||||
|
CTL{values}="on"
|
||||||
|
|
||||||
|
CTL{reset}="mixer"
|
||||||
|
+CTL{name}="Master Front Playback Volume",CTL{do_search}=="1", \
|
||||||
|
+ ENV{has_pmaster_vol}:="true", \
|
||||||
|
+ CTL{write}!="$env{pvolume}",CTL{values}="$env{ppercent}"
|
||||||
|
+CTL{name}="Master Front Playback Switch",CTL{do_search}=="1", \
|
||||||
|
+ CTL{values}="on"
|
||||||
|
+
|
||||||
|
+CTL{reset}="mixer"
|
||||||
|
CTL{name}="Master Digital Playback Volume",CTL{do_search}=="1", \
|
||||||
|
CTL{write}!="$env{pvolume}",CTL{values}="$env{ppercent}"
|
||||||
|
CTL{name}="Master Digital Playback Switch",CTL{do_search}=="1", \
|
||||||
|
--
|
||||||
|
1.7.3.1
|
||||||
|
|
27
0016-amixer-fix-parsing-of-control-ID-name.patch
Normal file
27
0016-amixer-fix-parsing-of-control-ID-name.patch
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
From 87c58b59b5c443fe3244bd06417c451581d1f635 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jaroslav Kysela <perex@perex.cz>
|
||||||
|
Date: Tue, 5 Oct 2010 10:02:45 +0200
|
||||||
|
Subject: [PATCH 16/38] amixer: fix parsing of control ID name
|
||||||
|
|
||||||
|
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
|
||||||
|
---
|
||||||
|
amixer/amixer.c | 2 +-
|
||||||
|
1 files changed, 1 insertions(+), 1 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/amixer/amixer.c b/amixer/amixer.c
|
||||||
|
index c9ea572..a177288 100644
|
||||||
|
--- a/amixer/amixer.c
|
||||||
|
+++ b/amixer/amixer.c
|
||||||
|
@@ -1120,8 +1120,8 @@ static int parse_control_id(const char *str, snd_ctl_elem_id_t *id)
|
||||||
|
}
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
- *ptr = '\0';
|
||||||
|
}
|
||||||
|
+ *ptr = '\0';
|
||||||
|
snd_ctl_elem_id_set_name(id, buf);
|
||||||
|
} else if (!strncasecmp(str, "index=", 6)) {
|
||||||
|
str += 6;
|
||||||
|
--
|
||||||
|
1.7.3.1
|
||||||
|
|
3313
0017-Introduce-alsaloop-utility.patch
Normal file
3313
0017-Introduce-alsaloop-utility.patch
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,45 @@
|
|||||||
|
From ad0e562373af1de5e911cf1d5def598a7b6523f2 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jaroslav Kysela <perex@perex.cz>
|
||||||
|
Date: Wed, 6 Oct 2010 18:30:18 +0200
|
||||||
|
Subject: [PATCH 18/38] alsaloop: Fix loopbacks pointer initialization and allocation, fix -T option
|
||||||
|
|
||||||
|
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
|
||||||
|
---
|
||||||
|
alsaloop/alsaloop.c | 7 ++++---
|
||||||
|
1 files changed, 4 insertions(+), 3 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/alsaloop/alsaloop.c b/alsaloop/alsaloop.c
|
||||||
|
index 4ba5203..0001358 100644
|
||||||
|
--- a/alsaloop/alsaloop.c
|
||||||
|
+++ b/alsaloop/alsaloop.c
|
||||||
|
@@ -45,7 +45,7 @@ struct loopback_thread {
|
||||||
|
int verbose = 0;
|
||||||
|
int daemonize = 0;
|
||||||
|
int use_syslog = 0;
|
||||||
|
-struct loopback **loopbacks;
|
||||||
|
+struct loopback **loopbacks = NULL;
|
||||||
|
int loopbacks_count = 0;
|
||||||
|
|
||||||
|
static void my_exit(struct loopback_thread *thread, int exitcode)
|
||||||
|
@@ -199,7 +199,8 @@ static long timediff(struct timeval t1, struct timeval t2)
|
||||||
|
|
||||||
|
static void add_loop(struct loopback *loop)
|
||||||
|
{
|
||||||
|
- loopbacks = realloc(loopbacks, loopbacks_count * sizeof(struct loopback *));
|
||||||
|
+ loopbacks = realloc(loopbacks, (loopbacks_count + 1) *
|
||||||
|
+ sizeof(struct loopback *));
|
||||||
|
if (loopbacks == NULL) {
|
||||||
|
logit(LOG_CRIT, "No enough memory\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
@@ -321,7 +322,7 @@ static int parse_config(int argc, char *argv[], snd_output_t *output)
|
||||||
|
morehelp = 0;
|
||||||
|
while (1) {
|
||||||
|
int c;
|
||||||
|
- if ((c = getopt_long(argc, argv, "hdg:P:C:l:t:F:f:c:r:s:benvA:S:a:m:", long_option, NULL)) < 0)
|
||||||
|
+ if ((c = getopt_long(argc, argv, "hdg:P:C:l:t:F:f:c:r:s:benvA:S:a:m:T:", long_option, NULL)) < 0)
|
||||||
|
break;
|
||||||
|
switch (c) {
|
||||||
|
case 'h':
|
||||||
|
--
|
||||||
|
1.7.3.1
|
||||||
|
|
80
0019-alsaloop-Fix-thread-handling.patch
Normal file
80
0019-alsaloop-Fix-thread-handling.patch
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
From 4fe4d22b73dd205521348583f8105de1c155f4a6 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jaroslav Kysela <perex@perex.cz>
|
||||||
|
Date: Wed, 6 Oct 2010 18:51:29 +0200
|
||||||
|
Subject: [PATCH 19/38] alsaloop: Fix thread handling
|
||||||
|
|
||||||
|
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
|
||||||
|
---
|
||||||
|
alsaloop/alsaloop.c | 5 ++---
|
||||||
|
alsaloop/test.sh | 19 +++++++++++++++++++
|
||||||
|
2 files changed, 21 insertions(+), 3 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/alsaloop/alsaloop.c b/alsaloop/alsaloop.c
|
||||||
|
index 0001358..743e0ef 100644
|
||||||
|
--- a/alsaloop/alsaloop.c
|
||||||
|
+++ b/alsaloop/alsaloop.c
|
||||||
|
@@ -687,7 +687,7 @@ int main(int argc, char *argv[])
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we must sort thread IDs */
|
||||||
|
- j = 0;
|
||||||
|
+ j = -1;
|
||||||
|
do {
|
||||||
|
k = 0x7fffffff;
|
||||||
|
for (i = 0; i < loopbacks_count; i++) {
|
||||||
|
@@ -695,11 +695,11 @@ int main(int argc, char *argv[])
|
||||||
|
loopbacks[i]->thread > j)
|
||||||
|
k = loopbacks[i]->thread;
|
||||||
|
}
|
||||||
|
+ j++;
|
||||||
|
for (i = 0; i < loopbacks_count; i++) {
|
||||||
|
if (loopbacks[i]->thread == k)
|
||||||
|
loopbacks[i]->thread = j;
|
||||||
|
}
|
||||||
|
- j++;
|
||||||
|
} while (k != 0x7fffffff);
|
||||||
|
/* fix maximum thread id */
|
||||||
|
for (i = 0, j = -1; i < loopbacks_count; i++) {
|
||||||
|
@@ -729,7 +729,6 @@ int main(int argc, char *argv[])
|
||||||
|
for (k = 0; k < j; k++)
|
||||||
|
thread_job(&threads[k]);
|
||||||
|
|
||||||
|
- logit(LOG_CRIT, "threads = %i %i\n", j, loopbacks_count);
|
||||||
|
if (j > 1) {
|
||||||
|
for (k = 0; k < j; k++)
|
||||||
|
pthread_join(threads[k].thread, NULL);
|
||||||
|
diff --git a/alsaloop/test.sh b/alsaloop/test.sh
|
||||||
|
index 2033add..bc42480 100755
|
||||||
|
--- a/alsaloop/test.sh
|
||||||
|
+++ b/alsaloop/test.sh
|
||||||
|
@@ -27,8 +27,27 @@ EOF
|
||||||
|
$DBG ./alsaloop -d --config $CFGFILE
|
||||||
|
}
|
||||||
|
|
||||||
|
+test3() {
|
||||||
|
+ echo "TEST2"
|
||||||
|
+cat > $CFGFILE <<EOF
|
||||||
|
+-C hw:1,0,0 -P dmix:0 --tlatency 50000 --thread 0 \
|
||||||
|
+ --mixer "name='Master Playback Volume'@name='Master Playback Volume'" \
|
||||||
|
+ --mixer "name='Master Playback Switch'@name='Master Playback Switch'" \
|
||||||
|
+ --mixer "name='PCM Playback Volume'"
|
||||||
|
+-C hw:1,0,1 -P dmix:0 --tlatency 50000 --thread 1
|
||||||
|
+-C hw:1,0,2 -P dmix:0 --tlatency 50000 --thread 2
|
||||||
|
+-C hw:1,0,3 -P dmix:0 --tlatency 50000 --thread 3
|
||||||
|
+-C hw:1,0,4 -P dmix:0 --tlatency 50000 --thread 4
|
||||||
|
+-C hw:1,0,5 -P dmix:0 --tlatency 50000 --thread 5
|
||||||
|
+-C hw:1,0,6 -P dmix:0 --tlatency 50000 --thread 6
|
||||||
|
+-C hw:1,0,7 -P dmix:0 --tlatency 50000 --thread 7
|
||||||
|
+EOF
|
||||||
|
+ $DBG ./alsaloop --config $CFGFILE
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
case "$1" in
|
||||||
|
test1) test1 ;;
|
||||||
|
test2) test2 ;;
|
||||||
|
+test3) test3 ;;
|
||||||
|
*) test1 ;;
|
||||||
|
esac
|
||||||
|
--
|
||||||
|
1.7.3.1
|
||||||
|
|
85
0020-alsaloop-fix-a-option-and-slave-mode-processing.patch
Normal file
85
0020-alsaloop-fix-a-option-and-slave-mode-processing.patch
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
From 5ad13c4825085ac28ed12afb0daf73c315fe0ed6 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jaroslav Kysela <perex@perex.cz>
|
||||||
|
Date: Wed, 6 Oct 2010 20:34:03 +0200
|
||||||
|
Subject: [PATCH 20/38] alsaloop: fix -a option and slave mode processing
|
||||||
|
|
||||||
|
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
|
||||||
|
---
|
||||||
|
alsaloop/alsaloop.c | 4 ++--
|
||||||
|
alsaloop/pcmjob.c | 3 +++
|
||||||
|
alsaloop/test.sh | 18 +++++++++---------
|
||||||
|
3 files changed, 14 insertions(+), 11 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/alsaloop/alsaloop.c b/alsaloop/alsaloop.c
|
||||||
|
index 743e0ef..48bd21a 100644
|
||||||
|
--- a/alsaloop/alsaloop.c
|
||||||
|
+++ b/alsaloop/alsaloop.c
|
||||||
|
@@ -424,9 +424,9 @@ static int parse_config(int argc, char *argv[], snd_output_t *output)
|
||||||
|
case 'a':
|
||||||
|
if (optarg[0] == 'a')
|
||||||
|
arg_slave = SLAVE_TYPE_AUTO;
|
||||||
|
- else if (strcasecmp(optarg, "off"))
|
||||||
|
+ else if (strcasecmp(optarg, "on") == 0)
|
||||||
|
arg_slave = SLAVE_TYPE_ON;
|
||||||
|
- else if (strcasecmp(optarg, "on"))
|
||||||
|
+ else if (strcasecmp(optarg, "off") == 0)
|
||||||
|
arg_slave = SLAVE_TYPE_OFF;
|
||||||
|
else
|
||||||
|
arg_slave = atoi(optarg);
|
||||||
|
diff --git a/alsaloop/pcmjob.c b/alsaloop/pcmjob.c
|
||||||
|
index 47256e0..51d9ea6 100644
|
||||||
|
--- a/alsaloop/pcmjob.c
|
||||||
|
+++ b/alsaloop/pcmjob.c
|
||||||
|
@@ -1432,6 +1432,8 @@ int pcmjob_pollfds_handle(struct loopback *loop, struct pollfd *fds)
|
||||||
|
}
|
||||||
|
if (verbose > 9)
|
||||||
|
snd_output_printf(loop->output, "%s: prevents = 0x%x, crevents = 0x%x\n", loop->id, prevents, crevents);
|
||||||
|
+ if (prevents == 0 && crevents == 0)
|
||||||
|
+ goto __pcm_end;
|
||||||
|
do {
|
||||||
|
ccount = readit(capt);
|
||||||
|
buf_add(loop, ccount);
|
||||||
|
@@ -1520,6 +1522,7 @@ int pcmjob_pollfds_handle(struct loopback *loop, struct pollfd *fds)
|
||||||
|
else
|
||||||
|
snd_output_printf(loop->output, "%s: end delay %li\n", capt->id, cdelay);
|
||||||
|
}
|
||||||
|
+ __pcm_end:
|
||||||
|
if (verbose > 13) {
|
||||||
|
getcurtimestamp(&loop->tstamp_end);
|
||||||
|
snd_output_printf(loop->output, "%s: processing time %lius\n", capt->id, timediff(loop->tstamp_end, loop->tstamp_start));
|
||||||
|
diff --git a/alsaloop/test.sh b/alsaloop/test.sh
|
||||||
|
index bc42480..a1d4dbe 100755
|
||||||
|
--- a/alsaloop/test.sh
|
||||||
|
+++ b/alsaloop/test.sh
|
||||||
|
@@ -28,19 +28,19 @@ EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
test3() {
|
||||||
|
- echo "TEST2"
|
||||||
|
+ echo "TEST3"
|
||||||
|
cat > $CFGFILE <<EOF
|
||||||
|
--C hw:1,0,0 -P dmix:0 --tlatency 50000 --thread 0 \
|
||||||
|
+-C hw:1,0,0 -P plug:dmix:0 --tlatency 50000 --thread 0 \
|
||||||
|
--mixer "name='Master Playback Volume'@name='Master Playback Volume'" \
|
||||||
|
--mixer "name='Master Playback Switch'@name='Master Playback Switch'" \
|
||||||
|
--mixer "name='PCM Playback Volume'"
|
||||||
|
--C hw:1,0,1 -P dmix:0 --tlatency 50000 --thread 1
|
||||||
|
--C hw:1,0,2 -P dmix:0 --tlatency 50000 --thread 2
|
||||||
|
--C hw:1,0,3 -P dmix:0 --tlatency 50000 --thread 3
|
||||||
|
--C hw:1,0,4 -P dmix:0 --tlatency 50000 --thread 4
|
||||||
|
--C hw:1,0,5 -P dmix:0 --tlatency 50000 --thread 5
|
||||||
|
--C hw:1,0,6 -P dmix:0 --tlatency 50000 --thread 6
|
||||||
|
--C hw:1,0,7 -P dmix:0 --tlatency 50000 --thread 7
|
||||||
|
+-C hw:1,0,1 -P plug:dmix:0 --tlatency 50000 --thread 1
|
||||||
|
+-C hw:1,0,2 -P plug:dmix:0 --tlatency 50000 --thread 2
|
||||||
|
+-C hw:1,0,3 -P plug:dmix:0 --tlatency 50000 --thread 3
|
||||||
|
+-C hw:1,0,4 -P plug:dmix:0 --tlatency 50000 --thread 4
|
||||||
|
+-C hw:1,0,5 -P plug:dmix:0 --tlatency 50000 --thread 5
|
||||||
|
+-C hw:1,0,6 -P plug:dmix:0 --tlatency 50000 --thread 6
|
||||||
|
+-C hw:1,0,7 -P plug:dmix:0 --tlatency 50000 --thread 7
|
||||||
|
EOF
|
||||||
|
$DBG ./alsaloop --config $CFGFILE
|
||||||
|
}
|
||||||
|
--
|
||||||
|
1.7.3.1
|
||||||
|
|
49
0021-alsaloop-fix-resample-argument-parsing.patch
Normal file
49
0021-alsaloop-fix-resample-argument-parsing.patch
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
From f956c329aa1271c89cf13a01d1bcea8fae6b03f8 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jaroslav Kysela <perex@perex.cz>
|
||||||
|
Date: Thu, 7 Oct 2010 00:12:38 +0200
|
||||||
|
Subject: [PATCH 21/38] alsaloop: fix resample argument parsing
|
||||||
|
|
||||||
|
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
|
||||||
|
---
|
||||||
|
alsaloop/alsaloop.c | 4 ++--
|
||||||
|
alsaloop/pcmjob.c | 2 +-
|
||||||
|
2 files changed, 3 insertions(+), 3 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/alsaloop/alsaloop.c b/alsaloop/alsaloop.c
|
||||||
|
index 48bd21a..6fb9c2a 100644
|
||||||
|
--- a/alsaloop/alsaloop.c
|
||||||
|
+++ b/alsaloop/alsaloop.c
|
||||||
|
@@ -81,7 +81,7 @@ static int create_loopback_handle(struct loopback_handle **_handle,
|
||||||
|
handle->format = SND_PCM_FORMAT_S16_LE;
|
||||||
|
handle->rate = 48000;
|
||||||
|
handle->channels = 2;
|
||||||
|
- handle->resample = 1;
|
||||||
|
+ handle->resample = 0;
|
||||||
|
*_handle = handle;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@@ -384,7 +384,7 @@ static int parse_config(int argc, char *argv[], snd_output_t *output)
|
||||||
|
arg_effect = 1;
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
- arg_resample = 0;
|
||||||
|
+ arg_resample = 1;
|
||||||
|
break;
|
||||||
|
case 'A':
|
||||||
|
if (strcasecmp(optarg, "sincbest") == 0)
|
||||||
|
diff --git a/alsaloop/pcmjob.c b/alsaloop/pcmjob.c
|
||||||
|
index 51d9ea6..4ad752d 100644
|
||||||
|
--- a/alsaloop/pcmjob.c
|
||||||
|
+++ b/alsaloop/pcmjob.c
|
||||||
|
@@ -108,7 +108,7 @@ static int setparams_stream(struct loopback_handle *lhandle,
|
||||||
|
rrate = 0;
|
||||||
|
snd_pcm_hw_params_get_rate(params, &rrate, 0);
|
||||||
|
if ((int)rrate != lhandle->rate) {
|
||||||
|
- logit(LOG_CRIT, "Rate does not match (requested %iHz, get %iHz)\n", lhandle->rate, err);
|
||||||
|
+ logit(LOG_CRIT, "Rate does not match (requested %iHz, got %iHz, resample %i)\n", lhandle->rate, rrate, lhandle->resample);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
--
|
||||||
|
1.7.3.1
|
||||||
|
|
618
0022-alsaloop-added-resampling-for-unsupported-soundcard-.patch
Normal file
618
0022-alsaloop-added-resampling-for-unsupported-soundcard-.patch
Normal file
@ -0,0 +1,618 @@
|
|||||||
|
From 058357f04239e1c61d60c29f40409f91d6a6e413 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jaroslav Kysela <perex@perex.cz>
|
||||||
|
Date: Thu, 7 Oct 2010 20:38:36 +0200
|
||||||
|
Subject: [PATCH 22/38] alsaloop: added resampling for unsupported soundcard rates
|
||||||
|
|
||||||
|
- improve also xrun synchronization
|
||||||
|
|
||||||
|
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
|
||||||
|
---
|
||||||
|
alsaloop/alsaloop.c | 6 +-
|
||||||
|
alsaloop/alsaloop.h | 7 +-
|
||||||
|
alsaloop/pcmjob.c | 279 +++++++++++++++++++++++++++++++++++++--------------
|
||||||
|
alsaloop/test.sh | 12 ++-
|
||||||
|
4 files changed, 223 insertions(+), 81 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/alsaloop/alsaloop.c b/alsaloop/alsaloop.c
|
||||||
|
index 6fb9c2a..bbf570e 100644
|
||||||
|
--- a/alsaloop/alsaloop.c
|
||||||
|
+++ b/alsaloop/alsaloop.c
|
||||||
|
@@ -79,7 +79,7 @@ static int create_loopback_handle(struct loopback_handle **_handle,
|
||||||
|
handle->id = strdup(idbuf);
|
||||||
|
handle->access = SND_PCM_ACCESS_RW_INTERLEAVED;
|
||||||
|
handle->format = SND_PCM_FORMAT_S16_LE;
|
||||||
|
- handle->rate = 48000;
|
||||||
|
+ handle->rate = handle->rate_req = 48000;
|
||||||
|
handle->channels = 2;
|
||||||
|
handle->resample = 0;
|
||||||
|
*_handle = handle;
|
||||||
|
@@ -311,7 +311,7 @@ static int parse_config(int argc, char *argv[], snd_output_t *output)
|
||||||
|
int arg_nblock = 0;
|
||||||
|
int arg_effect = 0;
|
||||||
|
int arg_resample = 0;
|
||||||
|
- int arg_samplerate = 0;
|
||||||
|
+ int arg_samplerate = SRC_SINC_FASTEST + 1;
|
||||||
|
int arg_sync = SYNC_TYPE_AUTO;
|
||||||
|
int arg_slave = SLAVE_TYPE_AUTO;
|
||||||
|
int arg_thread = 0;
|
||||||
|
@@ -474,7 +474,7 @@ static int parse_config(int argc, char *argv[], snd_output_t *output)
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
play->format = capt->format = arg_format;
|
||||||
|
- play->rate = capt->rate = arg_rate;
|
||||||
|
+ play->rate = play->rate_req = capt->rate = capt->rate_req = arg_rate;
|
||||||
|
play->channels = capt->channels = arg_channels;
|
||||||
|
play->buffer_size_req = capt->buffer_size_req = arg_buffer_size;
|
||||||
|
play->period_size_req = capt->period_size_req = arg_period_size;
|
||||||
|
diff --git a/alsaloop/alsaloop.h b/alsaloop/alsaloop.h
|
||||||
|
index 4b357de..9753c41 100644
|
||||||
|
--- a/alsaloop/alsaloop.h
|
||||||
|
+++ b/alsaloop/alsaloop.h
|
||||||
|
@@ -79,6 +79,7 @@ struct loopback_handle {
|
||||||
|
snd_pcm_access_t access;
|
||||||
|
snd_pcm_format_t format;
|
||||||
|
unsigned int rate;
|
||||||
|
+ unsigned int rate_req;
|
||||||
|
unsigned int channels;
|
||||||
|
unsigned int buffer_size;
|
||||||
|
unsigned int period_size;
|
||||||
|
@@ -100,6 +101,8 @@ struct loopback_handle {
|
||||||
|
unsigned long long counter;
|
||||||
|
unsigned long sync_point; /* in samples */
|
||||||
|
snd_pcm_sframes_t last_delay;
|
||||||
|
+ double pitch;
|
||||||
|
+ snd_pcm_uframes_t total_queued;
|
||||||
|
/* control */
|
||||||
|
snd_ctl_t *ctl;
|
||||||
|
unsigned int ctl_pollfd_count;
|
||||||
|
@@ -135,15 +138,15 @@ struct loopback {
|
||||||
|
snd_pcm_sframes_t pitch_diff;
|
||||||
|
snd_pcm_sframes_t pitch_diff_min;
|
||||||
|
snd_pcm_sframes_t pitch_diff_max;
|
||||||
|
- snd_pcm_uframes_t total_queued;
|
||||||
|
unsigned int total_queued_count;
|
||||||
|
snd_timestamp_t tstamp_start;
|
||||||
|
snd_timestamp_t tstamp_end;
|
||||||
|
/* control mixer */
|
||||||
|
struct loopback_mixer *controls;
|
||||||
|
/* sample rate */
|
||||||
|
+ unsigned int use_samplerate:1;
|
||||||
|
#ifdef USE_SAMPLERATE
|
||||||
|
- unsigned int src_enable: 1;
|
||||||
|
+ unsigned int src_enable:1;
|
||||||
|
int src_converter_type;
|
||||||
|
SRC_STATE *src_state;
|
||||||
|
SRC_DATA src_data;
|
||||||
|
diff --git a/alsaloop/pcmjob.c b/alsaloop/pcmjob.c
|
||||||
|
index 4ad752d..86917ef 100644
|
||||||
|
--- a/alsaloop/pcmjob.c
|
||||||
|
+++ b/alsaloop/pcmjob.c
|
||||||
|
@@ -99,18 +99,20 @@ static int setparams_stream(struct loopback_handle *lhandle,
|
||||||
|
logit(LOG_CRIT, "Channels count (%i) not available for %s: %s\n", lhandle->channels, lhandle->id, snd_strerror(err));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
- rrate = lhandle->rate;
|
||||||
|
+ rrate = lhandle->rate_req;
|
||||||
|
err = snd_pcm_hw_params_set_rate_near(handle, params, &rrate, 0);
|
||||||
|
if (err < 0) {
|
||||||
|
- logit(LOG_CRIT, "Rate %iHz not available for %s: %s\n", lhandle->rate, lhandle->id, snd_strerror(err));
|
||||||
|
+ logit(LOG_CRIT, "Rate %iHz not available for %s: %s\n", lhandle->rate_req, lhandle->id, snd_strerror(err));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
rrate = 0;
|
||||||
|
snd_pcm_hw_params_get_rate(params, &rrate, 0);
|
||||||
|
- if ((int)rrate != lhandle->rate) {
|
||||||
|
+ lhandle->rate = rrate;
|
||||||
|
+ if (!lhandle->loopback->src_enable && (int)rrate != lhandle->rate) {
|
||||||
|
logit(LOG_CRIT, "Rate does not match (requested %iHz, got %iHz, resample %i)\n", lhandle->rate, rrate, lhandle->resample);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
+ lhandle->pitch = (double)lhandle->rate_req / (double)lhandle->rate;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -245,11 +247,11 @@ static int setparams(struct loopback *loop, snd_pcm_uframes_t bufsize)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
- if ((err = setparams_bufsize(loop->play, p_params, pt_params, bufsize)) < 0) {
|
||||||
|
+ if ((err = setparams_bufsize(loop->play, p_params, pt_params, bufsize / loop->play->pitch)) < 0) {
|
||||||
|
logit(LOG_CRIT, "Unable to set buffer parameters for %s stream: %s\n", loop->play->id, snd_strerror(err));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
- if ((err = setparams_bufsize(loop->capt, c_params, ct_params, bufsize)) < 0) {
|
||||||
|
+ if ((err = setparams_bufsize(loop->capt, c_params, ct_params, bufsize / loop->capt->pitch)) < 0) {
|
||||||
|
logit(LOG_CRIT, "Unable to set buffer parameters for %s stream: %s\n", loop->capt->id, snd_strerror(err));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
@@ -618,6 +620,7 @@ static snd_pcm_sframes_t remove_samples(struct loopback *loop,
|
||||||
|
} else {
|
||||||
|
if (count > play->buf_count)
|
||||||
|
count = play->buf_count;
|
||||||
|
+ play->buf_count -= count;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
@@ -627,7 +630,7 @@ static int xrun_sync(struct loopback *loop)
|
||||||
|
struct loopback_handle *play = loop->play;
|
||||||
|
struct loopback_handle *capt = loop->capt;
|
||||||
|
snd_pcm_uframes_t fill = get_whole_latency(loop);
|
||||||
|
- snd_pcm_sframes_t delay, delayi, pdelay, cdelay, diff;
|
||||||
|
+ snd_pcm_sframes_t pdelay, cdelay, delay1, pdelay1, cdelay1, diff;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
__again:
|
||||||
|
@@ -681,45 +684,82 @@ static int xrun_sync(struct loopback *loop)
|
||||||
|
}
|
||||||
|
capt->counter = cdelay;
|
||||||
|
play->counter = pdelay;
|
||||||
|
- loop->total_queued = 0;
|
||||||
|
- loop->total_queued_count = 0;
|
||||||
|
- loop->pitch_diff = loop->pitch_diff_min = loop->pitch_diff_max = 0;
|
||||||
|
- delay = delayi = pdelay + cdelay;
|
||||||
|
if (play->buf != capt->buf)
|
||||||
|
- delay += capt->buf_count;
|
||||||
|
- delay += play->buf_count;
|
||||||
|
+ cdelay += capt->buf_count;
|
||||||
|
+ pdelay += play->buf_count;
|
||||||
|
#ifdef USE_SAMPLERATE
|
||||||
|
- delay += loop->src_out_frames;
|
||||||
|
- delayi += loop->src_out_frames;
|
||||||
|
+ pdelay += loop->src_out_frames;
|
||||||
|
#endif
|
||||||
|
-#if 0
|
||||||
|
- printf("s: cdelay = %li, pdelay = %li, delay = %li, delayi = %li, fill = %li, src_out = %li\n",
|
||||||
|
- (long)cdelay, (long)pdelay, (long)delay,
|
||||||
|
- (long)delayi, (long)fill, (long)loop->src_out_frames);
|
||||||
|
- printf("s: cbufcount = %li, pbufcount = %li\n", (long)capt->buf_count, (long)play->buf_count);
|
||||||
|
-#endif
|
||||||
|
- if (delayi > fill) {
|
||||||
|
+ cdelay1 = cdelay * capt->pitch;
|
||||||
|
+ pdelay1 = pdelay * play->pitch;
|
||||||
|
+ delay1 = cdelay1 + pdelay1;
|
||||||
|
+ capt->total_queued = 0;
|
||||||
|
+ play->total_queued = 0;
|
||||||
|
+ loop->total_queued_count = 0;
|
||||||
|
+ loop->pitch_diff = loop->pitch_diff_min = loop->pitch_diff_max = 0;
|
||||||
|
+ if (verbose > 6) {
|
||||||
|
+ snd_output_printf(loop->output,
|
||||||
|
+ "sync: cdelay=%li(%li), pdelay=%li(%li), fill=%li (delay=%li), src_out=%li\n",
|
||||||
|
+ (long)cdelay, (long)cdelay1, (long)pdelay, (long)pdelay1,
|
||||||
|
+ (long)fill, (long)delay1, (long)loop->src_out_frames);
|
||||||
|
+ snd_output_printf(loop->output,
|
||||||
|
+ "sync: cbufcount=%li, pbufcount=%li\n",
|
||||||
|
+ (long)capt->buf_count, (long)play->buf_count);
|
||||||
|
+ }
|
||||||
|
+ if (delay1 > fill && capt->counter > 0) {
|
||||||
|
if ((err = snd_pcm_drop(capt->handle)) < 0)
|
||||||
|
return err;
|
||||||
|
if ((err = snd_pcm_prepare(capt->handle)) < 0)
|
||||||
|
return err;
|
||||||
|
if ((err = snd_pcm_start(capt->handle)) < 0)
|
||||||
|
return err;
|
||||||
|
- remove_samples(loop, 1, delayi - fill);
|
||||||
|
+ diff = remove_samples(loop, 1, (delay1 - fill) / capt->pitch);
|
||||||
|
+ if (verbose > 6)
|
||||||
|
+ snd_output_printf(loop->output,
|
||||||
|
+ "sync: capt stop removed %li samples\n", (long)diff);
|
||||||
|
goto __again;
|
||||||
|
}
|
||||||
|
- if (delay > fill) {
|
||||||
|
- diff = fill > delayi ? play->buf_count - (fill - delayi) : 0;
|
||||||
|
- delay -= remove_samples(loop, 0, diff);
|
||||||
|
+ if (delay1 > fill) {
|
||||||
|
+ diff = (delay1 - fill) / play->pitch;
|
||||||
|
+ if (diff > play->buf_count)
|
||||||
|
+ diff = play->buf_count;
|
||||||
|
+ if (verbose > 6)
|
||||||
|
+ snd_output_printf(loop->output,
|
||||||
|
+ "sync: removing %li playback samples, delay1=%li\n", (long)diff, (long)delay1);
|
||||||
|
+ diff = remove_samples(loop, 0, diff);
|
||||||
|
+ pdelay -= diff;
|
||||||
|
+ pdelay1 = pdelay * play->pitch;
|
||||||
|
+ delay1 = cdelay1 + pdelay1;
|
||||||
|
+ if (verbose > 6)
|
||||||
|
+ snd_output_printf(loop->output,
|
||||||
|
+ "sync: removed %li playback samples, delay1=%li\n", (long)diff, (long)delay1);
|
||||||
|
}
|
||||||
|
- if (delay > fill) {
|
||||||
|
- diff = fill > delayi ? capt->buf_count - (fill - delayi) : 0;
|
||||||
|
- delay -= remove_samples(loop, 1, diff);
|
||||||
|
+ if (delay1 > fill) {
|
||||||
|
+ diff = (delay1 - fill) / capt->pitch;
|
||||||
|
+ if (diff > capt->buf_count)
|
||||||
|
+ diff = capt->buf_count;
|
||||||
|
+ if (verbose > 6)
|
||||||
|
+ snd_output_printf(loop->output,
|
||||||
|
+ "sync: removing %li captured samples, delay1=%li\n", (long)diff, (long)delay1);
|
||||||
|
+ diff -= remove_samples(loop, 1, diff);
|
||||||
|
+ cdelay -= diff;
|
||||||
|
+ cdelay1 = cdelay * capt->pitch;
|
||||||
|
+ delay1 = cdelay1 + pdelay1;
|
||||||
|
+ if (verbose > 6)
|
||||||
|
+ snd_output_printf(loop->output,
|
||||||
|
+ "sync: removed %li captured samples, delay1=%li\n", (long)diff, (long)delay1);
|
||||||
|
}
|
||||||
|
if (play->xrun_pending) {
|
||||||
|
play->xrun_pending = 0;
|
||||||
|
- if (fill > delay && play->buf_count < fill - delay) {
|
||||||
|
- diff = fill - delay - play->buf_count;
|
||||||
|
+ diff = (fill - delay1) / play->pitch;
|
||||||
|
+ if (verbose > 6)
|
||||||
|
+ snd_output_printf(loop->output,
|
||||||
|
+ "sync: xrun_pending, silence filling %li / buf_count=%li\n", (long)diff, play->buf_count);
|
||||||
|
+ if (fill > delay1 && play->buf_count < diff) {
|
||||||
|
+ diff = diff - play->buf_count;
|
||||||
|
+ if (verbose > 6)
|
||||||
|
+ snd_output_printf(loop->output,
|
||||||
|
+ "sync: playback silence added %li samples\n", (long)diff);
|
||||||
|
play->buf_pos -= diff;
|
||||||
|
play->buf_pos %= play->buf_size;
|
||||||
|
if ((err = snd_pcm_format_set_silence(play->format, play->buf + play->buf_pos * play->channels, diff)) < 0)
|
||||||
|
@@ -728,18 +768,43 @@ static int xrun_sync(struct loopback *loop)
|
||||||
|
}
|
||||||
|
if ((err = snd_pcm_prepare(play->handle)) < 0) {
|
||||||
|
logit(LOG_CRIT, "%s prepare failed: %s\n", play->id, snd_strerror(err));
|
||||||
|
+
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
- delayi = writeit(play);
|
||||||
|
- if (delayi > diff)
|
||||||
|
- buf_remove(loop, delayi - diff);
|
||||||
|
+ delay1 = writeit(play);
|
||||||
|
+ if (verbose > 6)
|
||||||
|
+ snd_output_printf(loop->output,
|
||||||
|
+ "sync: playback wrote %li samples\n", (long)delay1);
|
||||||
|
+ if (delay1 > diff) {
|
||||||
|
+ buf_remove(loop, delay1 - diff);
|
||||||
|
+ if (verbose > 6)
|
||||||
|
+ snd_output_printf(loop->output,
|
||||||
|
+ "sync: playback buf_remove %li samples\n", (long)(delay1 - diff));
|
||||||
|
+ }
|
||||||
|
if ((err = snd_pcm_start(play->handle)) < 0) {
|
||||||
|
logit(LOG_CRIT, "%s start failed: %s\n", play->id, snd_strerror(err));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- if (verbose > 5)
|
||||||
|
+ if (verbose > 5) {
|
||||||
|
snd_output_printf(loop->output, "%s: xrun sync ok\n", loop->id);
|
||||||
|
+ if (verbose > 6) {
|
||||||
|
+ if (snd_pcm_delay(capt->handle, &cdelay) < 0)
|
||||||
|
+ cdelay = -1;
|
||||||
|
+ if (snd_pcm_delay(play->handle, &pdelay) < 0)
|
||||||
|
+ pdelay = -1;
|
||||||
|
+ if (play->buf != capt->buf)
|
||||||
|
+ cdelay += capt->buf_count;
|
||||||
|
+ pdelay += play->buf_count;
|
||||||
|
+#ifdef USE_SAMPLERATE
|
||||||
|
+ pdelay += loop->src_out_frames;
|
||||||
|
+#endif
|
||||||
|
+ cdelay1 = cdelay * capt->pitch;
|
||||||
|
+ pdelay1 = pdelay * play->pitch;
|
||||||
|
+ delay1 = cdelay1 + pdelay1;
|
||||||
|
+ snd_output_printf(loop->output, "%s: sync verify: %li\n", loop->id, delay1);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -778,6 +843,46 @@ static int set_rate_shift(struct loopback_handle *lhandle, double pitch)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
+void update_pitch(struct loopback *loop)
|
||||||
|
+{
|
||||||
|
+ double pitch = loop->pitch;
|
||||||
|
+
|
||||||
|
+#ifdef USE_SAMPLERATE
|
||||||
|
+ if (loop->sync == SYNC_TYPE_SAMPLERATE) {
|
||||||
|
+ loop->src_data.src_ratio = (double)1.0 / (pitch *
|
||||||
|
+ loop->play->pitch * loop->capt->pitch);
|
||||||
|
+ if (verbose > 2)
|
||||||
|
+ snd_output_printf(loop->output, "%s: Samplerate src_ratio update1: %.8f\n", loop->id, loop->src_data.src_ratio);
|
||||||
|
+ } else
|
||||||
|
+#endif
|
||||||
|
+ if (loop->sync == SYNC_TYPE_CAPTRATESHIFT) {
|
||||||
|
+ set_rate_shift(loop->capt, pitch);
|
||||||
|
+#ifdef USE_SAMPLERATE
|
||||||
|
+ if (loop->use_samplerate) {
|
||||||
|
+ loop->src_data.src_ratio =
|
||||||
|
+ (double)1.0 /
|
||||||
|
+ (loop->play->pitch * loop->capt->pitch);
|
||||||
|
+ if (verbose > 2)
|
||||||
|
+ snd_output_printf(loop->output, "%s: Samplerate src_ratio update2: %.8f\n", loop->id, loop->src_data.src_ratio);
|
||||||
|
+ }
|
||||||
|
+#endif
|
||||||
|
+ }
|
||||||
|
+ else if (loop->sync == SYNC_TYPE_PLAYRATESHIFT) {
|
||||||
|
+ set_rate_shift(loop->play, pitch);
|
||||||
|
+#ifdef USE_SAMPLERATE
|
||||||
|
+ if (loop->use_samplerate) {
|
||||||
|
+ loop->src_data.src_ratio =
|
||||||
|
+ (double)1.0 /
|
||||||
|
+ (loop->play->pitch * loop->capt->pitch);
|
||||||
|
+ if (verbose > 2)
|
||||||
|
+ snd_output_printf(loop->output, "%s: Samplerate src_ratio update3: %.8f\n", loop->id, loop->src_data.src_ratio);
|
||||||
|
+ }
|
||||||
|
+#endif
|
||||||
|
+ }
|
||||||
|
+ if (verbose)
|
||||||
|
+ snd_output_printf(loop->output, "New pitch for %s: %.8f (min/max samples = %li/%li)\n", loop->id, pitch, loop->pitch_diff_min, loop->pitch_diff_max);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int get_active(struct loopback_handle *lhandle)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
@@ -1002,6 +1107,8 @@ int pcmjob_init(struct loopback *loop)
|
||||||
|
#ifdef USE_SAMPLERATE
|
||||||
|
if (loop->sync == SYNC_TYPE_AUTO && loop->src_enable)
|
||||||
|
loop->sync = SYNC_TYPE_SAMPLERATE;
|
||||||
|
+#else
|
||||||
|
+ loop->src_enable = 0;
|
||||||
|
#endif
|
||||||
|
if (loop->sync == SYNC_TYPE_AUTO)
|
||||||
|
loop->sync = SYNC_TYPE_SIMPLE;
|
||||||
|
@@ -1035,8 +1142,9 @@ int pcmjob_init(struct loopback *loop)
|
||||||
|
static void freeloop(struct loopback *loop)
|
||||||
|
{
|
||||||
|
#ifdef USE_SAMPLERATE
|
||||||
|
- if (loop->src_enable) {
|
||||||
|
- src_delete(loop->src_state);
|
||||||
|
+ if (loop->use_samplerate) {
|
||||||
|
+ if (loop->src_state)
|
||||||
|
+ src_delete(loop->src_state);
|
||||||
|
loop->src_state = NULL;
|
||||||
|
free(loop->src_data.data_in);
|
||||||
|
loop->src_data.data_in = NULL;
|
||||||
|
@@ -1078,6 +1186,7 @@ static void lhandle_start(struct loopback_handle *lhandle)
|
||||||
|
lhandle->buf_pos = 0;
|
||||||
|
lhandle->buf_count = 0;
|
||||||
|
lhandle->counter = 0;
|
||||||
|
+ lhandle->total_queued = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pcmjob_start(struct loopback *loop)
|
||||||
|
@@ -1098,7 +1207,7 @@ int pcmjob_start(struct loopback *loop)
|
||||||
|
err = get_rate(loop->capt);
|
||||||
|
if (err < 0)
|
||||||
|
goto __error;
|
||||||
|
- loop->play->rate = loop->capt->rate = err;
|
||||||
|
+ loop->play->rate_req = loop->capt->rate_req = err;
|
||||||
|
err = get_channels(loop->capt);
|
||||||
|
if (err < 0)
|
||||||
|
goto __error;
|
||||||
|
@@ -1107,6 +1216,7 @@ int pcmjob_start(struct loopback *loop)
|
||||||
|
loop->pollfd_count = loop->play->ctl_pollfd_count +
|
||||||
|
loop->capt->ctl_pollfd_count;
|
||||||
|
loop->reinit = 0;
|
||||||
|
+ loop->use_samplerate = 0;
|
||||||
|
loop->latency = loop->latency_req;
|
||||||
|
if (loop->latency == 0)
|
||||||
|
loop->latency = time_to_frames(loop->play,
|
||||||
|
@@ -1114,7 +1224,7 @@ int pcmjob_start(struct loopback *loop)
|
||||||
|
if ((err = setparams(loop, loop->latency/2)) < 0)
|
||||||
|
goto __error;
|
||||||
|
if (verbose)
|
||||||
|
- showlatency(loop, loop->latency, loop->play->rate);
|
||||||
|
+ showlatency(loop, loop->latency, loop->play->rate_req);
|
||||||
|
if (loop->play->access == loop->capt->access &&
|
||||||
|
loop->play->format == loop->capt->format &&
|
||||||
|
loop->play->rate == loop->capt->rate &&
|
||||||
|
@@ -1142,6 +1252,10 @@ int pcmjob_start(struct loopback *loop)
|
||||||
|
goto __error;
|
||||||
|
if ((err = init_handle(loop->capt, 1)) < 0)
|
||||||
|
goto __error;
|
||||||
|
+ if (loop->play->rate_req != loop->play->rate)
|
||||||
|
+ loop->use_samplerate = 1;
|
||||||
|
+ if (loop->capt->rate_req != loop->capt->rate)
|
||||||
|
+ loop->use_samplerate = 1;
|
||||||
|
}
|
||||||
|
if ((err = snd_pcm_poll_descriptors_count(loop->play->handle)) < 0)
|
||||||
|
goto __error;
|
||||||
|
@@ -1152,7 +1266,22 @@ int pcmjob_start(struct loopback *loop)
|
||||||
|
loop->capt->pollfd_count = err;
|
||||||
|
loop->pollfd_count += err;
|
||||||
|
#ifdef USE_SAMPLERATE
|
||||||
|
- if (loop->sync == SYNC_TYPE_SAMPLERATE) {
|
||||||
|
+ if (loop->sync == SYNC_TYPE_SAMPLERATE)
|
||||||
|
+ loop->use_samplerate = 1;
|
||||||
|
+ if (loop->use_samplerate && !loop->src_enable) {
|
||||||
|
+ logit(LOG_CRIT, "samplerate conversion required but disabled\n");
|
||||||
|
+ loop->use_samplerate = 0;
|
||||||
|
+ err = -EIO;
|
||||||
|
+ goto __error;
|
||||||
|
+ }
|
||||||
|
+ if (loop->use_samplerate) {
|
||||||
|
+ if (loop->capt->format != SND_PCM_FORMAT_S16 ||
|
||||||
|
+ loop->play->format != SND_PCM_FORMAT_S16) {
|
||||||
|
+ logit(LOG_CRIT, "samplerate conversion supports only S16_LE format (%i, %i)\n", loop->play->format, loop->capt->format);
|
||||||
|
+ loop->use_samplerate = 0;
|
||||||
|
+ err = -EIO;
|
||||||
|
+ goto __error;
|
||||||
|
+ }
|
||||||
|
loop->src_state = src_new(loop->src_converter_type,
|
||||||
|
loop->play->channels, &err);
|
||||||
|
loop->src_data.data_in = calloc(1, sizeof(float)*loop->capt->channels*loop->capt->buf_size);
|
||||||
|
@@ -1173,7 +1302,7 @@ int pcmjob_start(struct loopback *loop)
|
||||||
|
loop->src_state = NULL;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
- if (loop->sync == SYNC_TYPE_SAMPLERATE) {
|
||||||
|
+ if (loop->sync == SYNC_TYPE_SAMPLERATE || loop->use_samplerate) {
|
||||||
|
logit(LOG_CRIT, "alsaloop is compiled without libsamplerate support\n");
|
||||||
|
err = -EIO;
|
||||||
|
goto __error;
|
||||||
|
@@ -1195,12 +1324,12 @@ int pcmjob_start(struct loopback *loop)
|
||||||
|
logit(LOG_CRIT, "%s: silence error\n", loop->id);
|
||||||
|
goto __error;
|
||||||
|
}
|
||||||
|
- loop->pitch = 1;
|
||||||
|
+ loop->pitch = 1.0;
|
||||||
|
+ update_pitch(loop);
|
||||||
|
loop->pitch_delta = 1.0 / ((double)loop->capt->rate * 4);
|
||||||
|
- loop->total_queued = 0;
|
||||||
|
loop->total_queued_count = 0;
|
||||||
|
loop->pitch_diff = 0;
|
||||||
|
- count = get_whole_latency(loop);
|
||||||
|
+ count = get_whole_latency(loop) / loop->play->pitch;
|
||||||
|
loop->play->buf_count = count;
|
||||||
|
if (loop->play->buf == loop->capt->buf)
|
||||||
|
loop->capt->buf_pos = count;
|
||||||
|
@@ -1277,19 +1406,14 @@ int pcmjob_pollfds_init(struct loopback *loop, struct pollfd *fds)
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
-static snd_pcm_sframes_t get_queued_samples(struct loopback *loop)
|
||||||
|
+static snd_pcm_sframes_t get_queued_playback_samples(struct loopback *loop)
|
||||||
|
{
|
||||||
|
- snd_pcm_sframes_t pdelay, cdelay, delay;
|
||||||
|
+ snd_pcm_sframes_t delay;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
- if ((err = snd_pcm_delay(loop->play->handle, &pdelay)) < 0)
|
||||||
|
- return 0;
|
||||||
|
- if ((err = snd_pcm_delay(loop->capt->handle, &cdelay)) < 0)
|
||||||
|
+ if ((err = snd_pcm_delay(loop->play->handle, &delay)) < 0)
|
||||||
|
return 0;
|
||||||
|
- loop->play->last_delay = pdelay;
|
||||||
|
- loop->capt->last_delay = cdelay;
|
||||||
|
- delay = pdelay + cdelay;
|
||||||
|
- delay += loop->capt->buf_count;
|
||||||
|
+ loop->play->last_delay = delay;
|
||||||
|
delay += loop->play->buf_count;
|
||||||
|
#ifdef USE_SAMPLERATE
|
||||||
|
delay += loop->src_out_frames;
|
||||||
|
@@ -1297,6 +1421,18 @@ static snd_pcm_sframes_t get_queued_samples(struct loopback *loop)
|
||||||
|
return delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static snd_pcm_sframes_t get_queued_capture_samples(struct loopback *loop)
|
||||||
|
+{
|
||||||
|
+ snd_pcm_sframes_t delay;
|
||||||
|
+ int err;
|
||||||
|
+
|
||||||
|
+ if ((err = snd_pcm_delay(loop->capt->handle, &delay)) < 0)
|
||||||
|
+ return 0;
|
||||||
|
+ loop->capt->last_delay = delay;
|
||||||
|
+ delay += loop->capt->buf_count;
|
||||||
|
+ return delay;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int ctl_event_check(snd_ctl_elem_value_t *val, snd_ctl_event_t *ev)
|
||||||
|
{
|
||||||
|
snd_ctl_elem_id_t *id1, *id2;
|
||||||
|
@@ -1363,7 +1499,6 @@ int pcmjob_pollfds_handle(struct loopback *loop, struct pollfd *fds)
|
||||||
|
struct loopback_handle *capt = loop->capt;
|
||||||
|
unsigned short prevents, crevents, events;
|
||||||
|
snd_pcm_uframes_t ccount, pcount;
|
||||||
|
- snd_pcm_sframes_t queued;
|
||||||
|
int err, loopcount = 10, idx;
|
||||||
|
|
||||||
|
if (verbose > 11)
|
||||||
|
@@ -1463,8 +1598,8 @@ int pcmjob_pollfds_handle(struct loopback *loop, struct pollfd *fds)
|
||||||
|
play->counter >= play->sync_point &&
|
||||||
|
capt->counter >= play->sync_point) {
|
||||||
|
snd_pcm_sframes_t diff, lat = get_whole_latency(loop);
|
||||||
|
- double pitch;
|
||||||
|
- diff = ((double)loop->total_queued /
|
||||||
|
+ diff = ((double)(((double)play->total_queued * play->pitch) +
|
||||||
|
+ ((double)capt->total_queued * capt->pitch)) /
|
||||||
|
(double)loop->total_queued_count) - lat;
|
||||||
|
/* FIXME: this algorithm may be slightly better */
|
||||||
|
if (verbose > 3)
|
||||||
|
@@ -1472,12 +1607,12 @@ int pcmjob_pollfds_handle(struct loopback *loop, struct pollfd *fds)
|
||||||
|
if (diff > 0) {
|
||||||
|
if (diff == loop->pitch_diff)
|
||||||
|
loop->pitch += loop->pitch_delta;
|
||||||
|
- if (diff > loop->pitch_diff)
|
||||||
|
+ else if (diff > loop->pitch_diff)
|
||||||
|
loop->pitch += loop->pitch_delta*2;
|
||||||
|
} else if (diff < 0) {
|
||||||
|
if (diff == loop->pitch_diff)
|
||||||
|
loop->pitch -= loop->pitch_delta;
|
||||||
|
- if (diff < loop->pitch_diff)
|
||||||
|
+ else if (diff < loop->pitch_diff)
|
||||||
|
loop->pitch -= loop->pitch_delta*2;
|
||||||
|
}
|
||||||
|
loop->pitch_diff = diff;
|
||||||
|
@@ -1485,31 +1620,25 @@ int pcmjob_pollfds_handle(struct loopback *loop, struct pollfd *fds)
|
||||||
|
loop->pitch_diff_min = diff;
|
||||||
|
if (loop->pitch_diff_max < diff)
|
||||||
|
loop->pitch_diff_max = diff;
|
||||||
|
- pitch = loop->pitch;
|
||||||
|
-#ifdef USE_SAMPLERATE
|
||||||
|
- if (loop->sync == SYNC_TYPE_SAMPLERATE)
|
||||||
|
- loop->src_data.src_ratio = (double)1.0 / pitch;
|
||||||
|
- else
|
||||||
|
-#endif
|
||||||
|
- if (loop->sync == SYNC_TYPE_CAPTRATESHIFT)
|
||||||
|
- set_rate_shift(capt, pitch);
|
||||||
|
- if (loop->sync == SYNC_TYPE_PLAYRATESHIFT)
|
||||||
|
- set_rate_shift(play, pitch);
|
||||||
|
- if (verbose)
|
||||||
|
- snd_output_printf(loop->output, "New pitch for %s: %.8f (min/max samples = %li/%li)\n", loop->id, pitch, loop->pitch_diff_min, loop->pitch_diff_max);
|
||||||
|
+ update_pitch(loop);
|
||||||
|
play->counter -= play->sync_point;
|
||||||
|
capt->counter -= play->sync_point;
|
||||||
|
- loop->total_queued = 0;
|
||||||
|
+ play->total_queued = 0;
|
||||||
|
+ capt->total_queued = 0;
|
||||||
|
loop->total_queued_count = 0;
|
||||||
|
}
|
||||||
|
if (loop->sync != SYNC_TYPE_NONE) {
|
||||||
|
- queued = get_queued_samples(loop);
|
||||||
|
+ snd_pcm_sframes_t pqueued, cqueued;
|
||||||
|
+ pqueued = get_queued_playback_samples(loop);
|
||||||
|
+ cqueued = get_queued_capture_samples(loop);
|
||||||
|
if (verbose > 4)
|
||||||
|
- snd_output_printf(loop->output, "%s: queued %li samples\n", loop->id, queued);
|
||||||
|
- if (queued > 0) {
|
||||||
|
- loop->total_queued += queued;
|
||||||
|
+ snd_output_printf(loop->output, "%s: queued %li/%li samples\n", loop->id, pqueued, cqueued);
|
||||||
|
+ if (pqueued > 0)
|
||||||
|
+ loop->play->total_queued += pqueued;
|
||||||
|
+ if (cqueued > 0)
|
||||||
|
+ loop->capt->total_queued += cqueued;
|
||||||
|
+ if (pqueued > 0 || cqueued > 0)
|
||||||
|
loop->total_queued_count += 1;
|
||||||
|
- }
|
||||||
|
}
|
||||||
|
if (verbose > 12) {
|
||||||
|
snd_pcm_sframes_t pdelay, cdelay;
|
||||||
|
diff --git a/alsaloop/test.sh b/alsaloop/test.sh
|
||||||
|
index a1d4dbe..fbd40c0 100755
|
||||||
|
--- a/alsaloop/test.sh
|
||||||
|
+++ b/alsaloop/test.sh
|
||||||
|
@@ -6,7 +6,7 @@ CFGFILE="/tmp/alsaloop.test.cfg"
|
||||||
|
|
||||||
|
test1() {
|
||||||
|
echo "TEST1"
|
||||||
|
- $DBG ./alsaloop -C hw:1,0 -P hw:0,0 \
|
||||||
|
+ $DBG ./alsaloop -C hw:1,0 -P plughw:0,0 \
|
||||||
|
--tlatency 50000 \
|
||||||
|
--mixer "name='Master Playback Volume'@name='Master Playback Volume'" \
|
||||||
|
--mixer "name='Master Playback Switch'@name='Master Playback Switch'" \
|
||||||
|
@@ -45,9 +45,19 @@ EOF
|
||||||
|
$DBG ./alsaloop --config $CFGFILE
|
||||||
|
}
|
||||||
|
|
||||||
|
+test4() {
|
||||||
|
+ echo "TEST4"
|
||||||
|
+ $DBG ./alsaloop -C hw:1,0 -P plughw:0,0 -a off -r 11025 \
|
||||||
|
+ --tlatency 50000 \
|
||||||
|
+ --mixer "name='Master Playback Volume'@name='Master Playback Volume'" \
|
||||||
|
+ --mixer "name='Master Playback Switch'@name='Master Playback Switch'" \
|
||||||
|
+ --mixer "name='PCM Playback Volume'"
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
case "$1" in
|
||||||
|
test1) test1 ;;
|
||||||
|
test2) test2 ;;
|
||||||
|
test3) test3 ;;
|
||||||
|
+test4) test4 ;;
|
||||||
|
*) test1 ;;
|
||||||
|
esac
|
||||||
|
--
|
||||||
|
1.7.3.1
|
||||||
|
|
317
0023-alsaloop-Add-OSS-mixer-redirection-support.patch
Normal file
317
0023-alsaloop-Add-OSS-mixer-redirection-support.patch
Normal file
@ -0,0 +1,317 @@
|
|||||||
|
From 147a1cc75cf6002eb5ea2983a374d2e84eee8e1d Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jaroslav Kysela <perex@perex.cz>
|
||||||
|
Date: Fri, 8 Oct 2010 15:10:23 +0200
|
||||||
|
Subject: [PATCH 23/38] alsaloop: Add OSS mixer redirection support
|
||||||
|
|
||||||
|
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
|
||||||
|
---
|
||||||
|
alsaloop/alsaloop.1 | 16 +++++++++++++
|
||||||
|
alsaloop/alsaloop.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++-
|
||||||
|
alsaloop/alsaloop.h | 12 +++++++++-
|
||||||
|
alsaloop/control.c | 48 +++++++++++++++++++++++++++++++++++++-
|
||||||
|
alsaloop/pcmjob.c | 1 +
|
||||||
|
alsaloop/test.sh | 4 ++-
|
||||||
|
6 files changed, 138 insertions(+), 6 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/alsaloop/alsaloop.1 b/alsaloop/alsaloop.1
|
||||||
|
index 66be499..1554b6e 100644
|
||||||
|
--- a/alsaloop/alsaloop.1
|
||||||
|
+++ b/alsaloop/alsaloop.1
|
||||||
|
@@ -153,6 +153,22 @@ Known attributes:
|
||||||
|
numid - control ID numid
|
||||||
|
|
||||||
|
.TP
|
||||||
|
+\fI\-O <ossmixid>\fP | \fI\-\-ossmixer=<midid>\fP
|
||||||
|
+
|
||||||
|
+Redirect mixer control from the OSS Mixer emulation layer (capture card)
|
||||||
|
+to the ALSA layer (capture card). Format of \fIossmixid\fP is
|
||||||
|
+ALSAID[,INDEX]@OSSID:
|
||||||
|
+
|
||||||
|
+ "Master@VOLUME"
|
||||||
|
+ "PCM,1@ALTPCM"
|
||||||
|
+
|
||||||
|
+Known OSS attributes:
|
||||||
|
+
|
||||||
|
+ VOLUME, BASS, TREBLE, SYNTH, PCM, SPEAKER, LINE, MIC, CD, IMIX, ALTPCM,
|
||||||
|
+ RECLEV, IGAIN, OGAIN, LINE1, LINE2, LINE3, DIGITAL1, DIGITAL2, DIGITAL3,
|
||||||
|
+ PHONEIN, PHONEOUT, VIDEO, RADIO, MONITOR
|
||||||
|
+
|
||||||
|
+.TP
|
||||||
|
\fI\-v\fP | \fI\-\-verbose\fP
|
||||||
|
|
||||||
|
Verbose mode. Use multiple times to increase verbosity.
|
||||||
|
diff --git a/alsaloop/alsaloop.c b/alsaloop/alsaloop.c
|
||||||
|
index bbf570e..effa073 100644
|
||||||
|
--- a/alsaloop/alsaloop.c
|
||||||
|
+++ b/alsaloop/alsaloop.c
|
||||||
|
@@ -164,7 +164,9 @@ void help(void)
|
||||||
|
"-a,--slave stream parameters slave mode (0=auto, 1=on, 2=off)\n"
|
||||||
|
"-T,--thread thread number (-1 = create unique)\n"
|
||||||
|
"-m,--mixer redirect mixer, argument is:\n"
|
||||||
|
-" SRC_SLAVE_ID(PLAYBACK)@DST_SLAVE_ID(CAPTURE)\n"
|
||||||
|
+" SRC_SLAVE_ID(PLAYBACK)[@DST_SLAVE_ID(CAPTURE)]\n"
|
||||||
|
+"-O,--ossmixer rescan and redirect oss mixer, argument is:\n"
|
||||||
|
+" ALSA_ID@OSS_ID (for example: \"Master@VOLUME\")\n"
|
||||||
|
"-e,--effect apply an effect (bandpass filter sweep)\n"
|
||||||
|
"-v,--verbose verbose mode (more -v means more verbose)\n"
|
||||||
|
);
|
||||||
|
@@ -266,6 +268,46 @@ static int add_mixers(struct loopback *loop,
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int add_oss_mixers(struct loopback *loop,
|
||||||
|
+ char **mixers,
|
||||||
|
+ int mixers_count)
|
||||||
|
+{
|
||||||
|
+ struct loopback_ossmixer *mixer, *last = NULL;
|
||||||
|
+ char *str1, *str2;
|
||||||
|
+
|
||||||
|
+ while (mixers_count > 0) {
|
||||||
|
+ mixer = calloc(1, sizeof(*mixer));
|
||||||
|
+ if (mixer == NULL)
|
||||||
|
+ return -ENOMEM;
|
||||||
|
+ if (last)
|
||||||
|
+ last->next = mixer;
|
||||||
|
+ else
|
||||||
|
+ loop->oss_controls = mixer;
|
||||||
|
+ last = mixer;
|
||||||
|
+ str1 = strchr(*mixers, ',');
|
||||||
|
+ if (str1)
|
||||||
|
+ *str1 = '\0';
|
||||||
|
+ str2 = strchr(str1 ? str1 + 1 : *mixers, '@');
|
||||||
|
+ if (str2)
|
||||||
|
+ *str2 = '\0';
|
||||||
|
+ mixer->alsa_id = strdup(*mixers);
|
||||||
|
+ if (str1)
|
||||||
|
+ mixer->alsa_index = atoi(str1);
|
||||||
|
+ mixer->oss_id = strdup(str2 ? str2 + 1 : *mixers);
|
||||||
|
+ if (mixer->alsa_id == NULL || mixer->oss_id == NULL) {
|
||||||
|
+ logit(LOG_CRIT, "Not enough memory");
|
||||||
|
+ return -ENOMEM;
|
||||||
|
+ }
|
||||||
|
+ if (str1)
|
||||||
|
+ *str1 = ',';
|
||||||
|
+ if (str2)
|
||||||
|
+ *str2 = ',';
|
||||||
|
+ mixers++;
|
||||||
|
+ mixers_count--;
|
||||||
|
+ }
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int parse_config_file(const char *file, snd_output_t *output);
|
||||||
|
|
||||||
|
static int parse_config(int argc, char *argv[], snd_output_t *output)
|
||||||
|
@@ -294,6 +336,7 @@ static int parse_config(int argc, char *argv[], snd_output_t *output)
|
||||||
|
{"slave", 1, NULL, 'a'},
|
||||||
|
{"thread", 1, NULL, 'T'},
|
||||||
|
{"mixer", 1, NULL, 'm'},
|
||||||
|
+ {"ossmixer", 1, NULL, 'O'},
|
||||||
|
{NULL, 0, NULL, 0},
|
||||||
|
};
|
||||||
|
int err, morehelp;
|
||||||
|
@@ -318,11 +361,15 @@ static int parse_config(int argc, char *argv[], snd_output_t *output)
|
||||||
|
struct loopback *loop = NULL;
|
||||||
|
char *arg_mixers[MAX_MIXERS];
|
||||||
|
int arg_mixers_count = 0;
|
||||||
|
+ char *arg_ossmixers[MAX_MIXERS];
|
||||||
|
+ int arg_ossmixers_count = 0;
|
||||||
|
|
||||||
|
morehelp = 0;
|
||||||
|
while (1) {
|
||||||
|
int c;
|
||||||
|
- if ((c = getopt_long(argc, argv, "hdg:P:C:l:t:F:f:c:r:s:benvA:S:a:m:T:", long_option, NULL)) < 0)
|
||||||
|
+ if ((c = getopt_long(argc, argv,
|
||||||
|
+ "hdg:P:C:l:t:F:f:c:r:s:benvA:S:a:m:T:O:",
|
||||||
|
+ long_option, NULL)) < 0)
|
||||||
|
break;
|
||||||
|
switch (c) {
|
||||||
|
case 'h':
|
||||||
|
@@ -445,6 +492,13 @@ static int parse_config(int argc, char *argv[], snd_output_t *output)
|
||||||
|
}
|
||||||
|
arg_mixers[arg_mixers_count++] = optarg;
|
||||||
|
break;
|
||||||
|
+ case 'O':
|
||||||
|
+ if (arg_ossmixers_count >= MAX_MIXERS) {
|
||||||
|
+ logit(LOG_CRIT, "Maximum redirected mixer controls reached (max %i)\n", (int)MAX_MIXERS);
|
||||||
|
+ exit(EXIT_FAILURE);
|
||||||
|
+ }
|
||||||
|
+ arg_ossmixers[arg_ossmixers_count++] = optarg;
|
||||||
|
+ break;
|
||||||
|
case 'v':
|
||||||
|
verbose++;
|
||||||
|
break;
|
||||||
|
@@ -490,6 +544,11 @@ static int parse_config(int argc, char *argv[], snd_output_t *output)
|
||||||
|
logit(LOG_CRIT, "Unable to add mixer controls.\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
+ err = add_oss_mixers(loop, arg_ossmixers, arg_ossmixers_count);
|
||||||
|
+ if (err < 0) {
|
||||||
|
+ logit(LOG_CRIT, "Unable to add ossmixer controls.\n");
|
||||||
|
+ exit(EXIT_FAILURE);
|
||||||
|
+ }
|
||||||
|
#ifdef USE_SAMPLERATE
|
||||||
|
loop->src_enable = arg_samplerate > 0;
|
||||||
|
if (loop->src_enable)
|
||||||
|
diff --git a/alsaloop/alsaloop.h b/alsaloop/alsaloop.h
|
||||||
|
index 9753c41..366a296 100644
|
||||||
|
--- a/alsaloop/alsaloop.h
|
||||||
|
+++ b/alsaloop/alsaloop.h
|
||||||
|
@@ -65,16 +65,25 @@ struct loopback_control {
|
||||||
|
};
|
||||||
|
|
||||||
|
struct loopback_mixer {
|
||||||
|
- unsigned int skip: 1;
|
||||||
|
+ unsigned int skip:1;
|
||||||
|
struct loopback_control src;
|
||||||
|
struct loopback_control dst;
|
||||||
|
struct loopback_mixer *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
+struct loopback_ossmixer {
|
||||||
|
+ unsigned int skip:1;
|
||||||
|
+ const char *alsa_id;
|
||||||
|
+ int alsa_index;
|
||||||
|
+ const char *oss_id;
|
||||||
|
+ struct loopback_ossmixer *next;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
struct loopback_handle {
|
||||||
|
struct loopback *loopback;
|
||||||
|
char *device;
|
||||||
|
char *id;
|
||||||
|
+ int card_number;
|
||||||
|
snd_pcm_t *handle;
|
||||||
|
snd_pcm_access_t access;
|
||||||
|
snd_pcm_format_t format;
|
||||||
|
@@ -143,6 +152,7 @@ struct loopback {
|
||||||
|
snd_timestamp_t tstamp_end;
|
||||||
|
/* control mixer */
|
||||||
|
struct loopback_mixer *controls;
|
||||||
|
+ struct loopback_ossmixer *oss_controls;
|
||||||
|
/* sample rate */
|
||||||
|
unsigned int use_samplerate:1;
|
||||||
|
#ifdef USE_SAMPLERATE
|
||||||
|
diff --git a/alsaloop/control.c b/alsaloop/control.c
|
||||||
|
index ade7733..967f1e9 100644
|
||||||
|
--- a/alsaloop/control.c
|
||||||
|
+++ b/alsaloop/control.c
|
||||||
|
@@ -205,6 +205,34 @@ static int copy_value(struct loopback_control *dst,
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int oss_set(struct loopback *loop,
|
||||||
|
+ struct loopback_ossmixer *ossmix,
|
||||||
|
+ int enable)
|
||||||
|
+{
|
||||||
|
+ char buf[128], file[128];
|
||||||
|
+ int fd;
|
||||||
|
+
|
||||||
|
+ if (loop->capt->card_number < 0)
|
||||||
|
+ return 0;
|
||||||
|
+ if (!enable) {
|
||||||
|
+ sprintf(buf, "%s \"\" 0\n", ossmix->oss_id);
|
||||||
|
+ } else {
|
||||||
|
+ sprintf(buf, "%s \"%s\" %i\n", ossmix->oss_id, ossmix->alsa_id, ossmix->alsa_index);
|
||||||
|
+ }
|
||||||
|
+ sprintf(file, "/proc/asound/card%i/oss_mixer", loop->capt->card_number);
|
||||||
|
+ if (verbose)
|
||||||
|
+ snd_output_printf(loop->output, "%s: Initialize OSS volume %s: %s", loop->id, file, buf);
|
||||||
|
+ fd = open(file, O_WRONLY);
|
||||||
|
+ if (fd >= 0 && write(fd, buf, strlen(buf)) == strlen(buf)) {
|
||||||
|
+ close(fd);
|
||||||
|
+ return 0;
|
||||||
|
+ }
|
||||||
|
+ if (fd >= 0)
|
||||||
|
+ close(fd);
|
||||||
|
+ logit(LOG_INFO, "%s: Unable to initialize OSS Mixer ID '%s'\n", loop->id, ossmix->oss_id);
|
||||||
|
+ return -1;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int control_init2(struct loopback *loop,
|
||||||
|
struct loopback_mixer *mix)
|
||||||
|
{
|
||||||
|
@@ -280,12 +308,15 @@ static int control_init2(struct loopback *loop,
|
||||||
|
int control_init(struct loopback *loop)
|
||||||
|
{
|
||||||
|
struct loopback_mixer *mix;
|
||||||
|
+ struct loopback_ossmixer *ossmix;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
+ for (ossmix = loop->oss_controls; ossmix; ossmix = ossmix->next)
|
||||||
|
+ oss_set(loop, ossmix, 0);
|
||||||
|
for (mix = loop->controls; mix; mix = mix->next) {
|
||||||
|
err = control_init1(loop->play, &mix->src);
|
||||||
|
if (err < 0) {
|
||||||
|
- logit(LOG_WARNING, "Disabling playback control '%s'\n", id_str(mix->src.id));
|
||||||
|
+ logit(LOG_WARNING, "%s: Disabling playback control '%s'\n", loop->id, id_str(mix->src.id));
|
||||||
|
mix->skip = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
@@ -293,22 +324,35 @@ int control_init(struct loopback *loop)
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
+ for (ossmix = loop->oss_controls; ossmix; ossmix = ossmix->next) {
|
||||||
|
+ err = oss_set(loop, ossmix, 1);
|
||||||
|
+ if (err < 0) {
|
||||||
|
+ ossmix->skip = 1;
|
||||||
|
+ logit(LOG_WARNING, "%s: Disabling OSS mixer ID '%s'\n", loop->id, ossmix->oss_id);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int control_done(struct loopback *loop)
|
||||||
|
{
|
||||||
|
struct loopback_mixer *mix;
|
||||||
|
+ struct loopback_ossmixer *ossmix;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (loop->capt->ctl == NULL)
|
||||||
|
return 0;
|
||||||
|
+ for (ossmix = loop->oss_controls; ossmix; ossmix = ossmix->next) {
|
||||||
|
+ err = oss_set(loop, ossmix, 0);
|
||||||
|
+ if (err < 0)
|
||||||
|
+ logit(LOG_WARNING, "%s: Unable to remove OSS control '%s'\n", loop->id, ossmix->oss_id);
|
||||||
|
+ }
|
||||||
|
for (mix = loop->controls; mix; mix = mix->next) {
|
||||||
|
if (mix->skip)
|
||||||
|
continue;
|
||||||
|
err = snd_ctl_elem_remove(loop->capt->ctl, mix->dst.id);
|
||||||
|
if (err < 0)
|
||||||
|
- logit(LOG_WARNING, "Unable to remove control '%s': %s\n", id_str(mix->dst.id), snd_strerror(err));
|
||||||
|
+ logit(LOG_WARNING, "%s: Unable to remove control '%s': %s\n", loop->id, id_str(mix->dst.id), snd_strerror(err));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
diff --git a/alsaloop/pcmjob.c b/alsaloop/pcmjob.c
|
||||||
|
index 86917ef..5c2fed0 100644
|
||||||
|
--- a/alsaloop/pcmjob.c
|
||||||
|
+++ b/alsaloop/pcmjob.c
|
||||||
|
@@ -1022,6 +1022,7 @@ static int openit(struct loopback_handle *lhandle)
|
||||||
|
device = snd_pcm_info_get_device(info);
|
||||||
|
subdevice = snd_pcm_info_get_subdevice(info);
|
||||||
|
snd_pcm_info_free(info);
|
||||||
|
+ lhandle->card_number = card;
|
||||||
|
lhandle->ctl = NULL;
|
||||||
|
if (card >= 0) {
|
||||||
|
char name[16];
|
||||||
|
diff --git a/alsaloop/test.sh b/alsaloop/test.sh
|
||||||
|
index fbd40c0..13a5ba7 100755
|
||||||
|
--- a/alsaloop/test.sh
|
||||||
|
+++ b/alsaloop/test.sh
|
||||||
|
@@ -10,7 +10,9 @@ test1() {
|
||||||
|
--tlatency 50000 \
|
||||||
|
--mixer "name='Master Playback Volume'@name='Master Playback Volume'" \
|
||||||
|
--mixer "name='Master Playback Switch'@name='Master Playback Switch'" \
|
||||||
|
- --mixer "name='PCM Playback Volume'"
|
||||||
|
+ --mixer "name='PCM Playback Volume'" \
|
||||||
|
+ --ossmixer "Master@VOLUME" \
|
||||||
|
+ --ossmixer "PCM@PCM"
|
||||||
|
}
|
||||||
|
|
||||||
|
test2() {
|
||||||
|
--
|
||||||
|
1.7.3.1
|
||||||
|
|
227
0024-alsaloop-Fix-command-line-parsing-and-pollfd-initial.patch
Normal file
227
0024-alsaloop-Fix-command-line-parsing-and-pollfd-initial.patch
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
From e77983d3c55a7822e2151dfd60d9a20ec2023c9f Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jaroslav Kysela <perex@perex.cz>
|
||||||
|
Date: Fri, 8 Oct 2010 22:23:05 +0200
|
||||||
|
Subject: [PATCH 24/38] alsaloop: Fix command-line parsing and pollfd initialization
|
||||||
|
|
||||||
|
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
|
||||||
|
---
|
||||||
|
alsaloop/alsaloop.c | 28 ++++++++++++++++++++--------
|
||||||
|
alsaloop/control.c | 4 ++++
|
||||||
|
alsaloop/pcmjob.c | 24 +++++++++++++-----------
|
||||||
|
alsaloop/test.sh | 18 +++++++++++++++++-
|
||||||
|
4 files changed, 54 insertions(+), 20 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/alsaloop/alsaloop.c b/alsaloop/alsaloop.c
|
||||||
|
index effa073..97b00d5 100644
|
||||||
|
--- a/alsaloop/alsaloop.c
|
||||||
|
+++ b/alsaloop/alsaloop.c
|
||||||
|
@@ -47,6 +47,8 @@ int daemonize = 0;
|
||||||
|
int use_syslog = 0;
|
||||||
|
struct loopback **loopbacks = NULL;
|
||||||
|
int loopbacks_count = 0;
|
||||||
|
+char **my_argv = NULL;
|
||||||
|
+int my_argc = 0;
|
||||||
|
|
||||||
|
static void my_exit(struct loopback_thread *thread, int exitcode)
|
||||||
|
{
|
||||||
|
@@ -575,9 +577,6 @@ static int parse_config_file(const char *file, snd_output_t *output)
|
||||||
|
int argc, c, err = 0;
|
||||||
|
char **argv;
|
||||||
|
|
||||||
|
- argv = malloc(sizeof(char *) * MAX_ARGS);
|
||||||
|
- if (argv == NULL)
|
||||||
|
- return -ENOMEM;
|
||||||
|
fp = fopen(file, "r");
|
||||||
|
if (fp == NULL) {
|
||||||
|
logit(LOG_CRIT, "Unable to open file '%s': %s\n", file, strerror(errno));
|
||||||
|
@@ -587,8 +586,13 @@ static int parse_config_file(const char *file, snd_output_t *output)
|
||||||
|
if (fgets(line, sizeof(line)-1, fp) == NULL)
|
||||||
|
break;
|
||||||
|
line[sizeof(line)-1] = '\0';
|
||||||
|
+ my_argv = realloc(my_argv, my_argc + MAX_ARGS * sizeof(char *));
|
||||||
|
+ if (my_argv == NULL)
|
||||||
|
+ return -ENOMEM;
|
||||||
|
+ argv = my_argv + my_argc;
|
||||||
|
argc = 0;
|
||||||
|
argv[argc++] = strdup("<prog>");
|
||||||
|
+ my_argc++;
|
||||||
|
str = line;
|
||||||
|
while (*str) {
|
||||||
|
ptr = word;
|
||||||
|
@@ -607,25 +611,30 @@ static int parse_config_file(const char *file, snd_output_t *output)
|
||||||
|
*ptr++ = *str++;
|
||||||
|
}
|
||||||
|
if (ptr != word) {
|
||||||
|
+ if (*(ptr-1) == '\n')
|
||||||
|
+ ptr--;
|
||||||
|
*ptr = '\0';
|
||||||
|
+ if (argc >= MAX_ARGS) {
|
||||||
|
+ logit(LOG_CRIT, "Too many arguments.");
|
||||||
|
+ goto __error;
|
||||||
|
+ }
|
||||||
|
argv[argc++] = strdup(word);
|
||||||
|
+ my_argc++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* erase runtime variables for getopt */
|
||||||
|
optarg = NULL;
|
||||||
|
optind = opterr = 1;
|
||||||
|
- optopt = 63;
|
||||||
|
+ optopt = '?';
|
||||||
|
|
||||||
|
err = parse_config(argc, argv, output);
|
||||||
|
__next:
|
||||||
|
- while (argc > 0)
|
||||||
|
- free(argv[--argc]);
|
||||||
|
if (err < 0)
|
||||||
|
break;
|
||||||
|
err = 0;
|
||||||
|
}
|
||||||
|
+ __error:
|
||||||
|
fclose(fp);
|
||||||
|
- free(argv);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
@@ -656,7 +665,7 @@ static void thread_job1(void *_data)
|
||||||
|
pfds_count += thread->loopbacks[i]->pollfd_count;
|
||||||
|
}
|
||||||
|
pfds = calloc(pfds_count, sizeof(struct pollfd));
|
||||||
|
- if (pfds == NULL) {
|
||||||
|
+ if (pfds == NULL || pfds_count <= 0) {
|
||||||
|
logit(LOG_CRIT, "Poll FDs allocation failed.\n");
|
||||||
|
my_exit(thread, EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
@@ -723,6 +732,9 @@ int main(int argc, char *argv[])
|
||||||
|
logit(LOG_CRIT, "Unable to parse arguments or configuration...\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
+ while (my_argc > 0)
|
||||||
|
+ free(my_argv[--my_argc]);
|
||||||
|
+ free(my_argv);
|
||||||
|
|
||||||
|
if (loopbacks_count <= 0) {
|
||||||
|
logit(LOG_CRIT, "No loopback defined...\n");
|
||||||
|
diff --git a/alsaloop/control.c b/alsaloop/control.c
|
||||||
|
index 967f1e9..8383d79 100644
|
||||||
|
--- a/alsaloop/control.c
|
||||||
|
+++ b/alsaloop/control.c
|
||||||
|
@@ -164,6 +164,10 @@ static int control_init1(struct loopback_handle *lhandle,
|
||||||
|
|
||||||
|
snd_ctl_elem_info_set_id(ctl->info, ctl->id);
|
||||||
|
snd_ctl_elem_value_set_id(ctl->value, ctl->id);
|
||||||
|
+ if (lhandle->ctl == NULL) {
|
||||||
|
+ logit(LOG_WARNING, "Unable to read control info for '%s'\n", id_str(ctl->id));
|
||||||
|
+ return -EIO;
|
||||||
|
+ }
|
||||||
|
err = snd_ctl_elem_info(lhandle->ctl, ctl->info);
|
||||||
|
if (err < 0) {
|
||||||
|
logit(LOG_WARNING, "Unable to read control info '%s': %s\n", id_str(ctl->id), snd_strerror(err));
|
||||||
|
diff --git a/alsaloop/pcmjob.c b/alsaloop/pcmjob.c
|
||||||
|
index 5c2fed0..df835f0 100644
|
||||||
|
--- a/alsaloop/pcmjob.c
|
||||||
|
+++ b/alsaloop/pcmjob.c
|
||||||
|
@@ -1195,6 +1195,16 @@ int pcmjob_start(struct loopback *loop)
|
||||||
|
snd_pcm_uframes_t count;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
+ loop->pollfd_count = loop->play->ctl_pollfd_count +
|
||||||
|
+ loop->capt->ctl_pollfd_count;
|
||||||
|
+ if ((err = snd_pcm_poll_descriptors_count(loop->play->handle)) < 0)
|
||||||
|
+ goto __error;
|
||||||
|
+ loop->play->pollfd_count = err;
|
||||||
|
+ loop->pollfd_count += err;
|
||||||
|
+ if ((err = snd_pcm_poll_descriptors_count(loop->capt->handle)) < 0)
|
||||||
|
+ goto __error;
|
||||||
|
+ loop->capt->pollfd_count = err;
|
||||||
|
+ loop->pollfd_count += err;
|
||||||
|
if (loop->slave == SLAVE_TYPE_ON) {
|
||||||
|
err = get_active(loop->capt);
|
||||||
|
if (err < 0)
|
||||||
|
@@ -1214,8 +1224,6 @@ int pcmjob_start(struct loopback *loop)
|
||||||
|
goto __error;
|
||||||
|
loop->play->channels = loop->capt->channels = err;
|
||||||
|
}
|
||||||
|
- loop->pollfd_count = loop->play->ctl_pollfd_count +
|
||||||
|
- loop->capt->ctl_pollfd_count;
|
||||||
|
loop->reinit = 0;
|
||||||
|
loop->use_samplerate = 0;
|
||||||
|
loop->latency = loop->latency_req;
|
||||||
|
@@ -1258,14 +1266,6 @@ int pcmjob_start(struct loopback *loop)
|
||||||
|
if (loop->capt->rate_req != loop->capt->rate)
|
||||||
|
loop->use_samplerate = 1;
|
||||||
|
}
|
||||||
|
- if ((err = snd_pcm_poll_descriptors_count(loop->play->handle)) < 0)
|
||||||
|
- goto __error;
|
||||||
|
- loop->play->pollfd_count = err;
|
||||||
|
- loop->pollfd_count += err;
|
||||||
|
- if ((err = snd_pcm_poll_descriptors_count(loop->capt->handle)) < 0)
|
||||||
|
- goto __error;
|
||||||
|
- loop->capt->pollfd_count = err;
|
||||||
|
- loop->pollfd_count += err;
|
||||||
|
#ifdef USE_SAMPLERATE
|
||||||
|
if (loop->sync == SYNC_TYPE_SAMPLERATE)
|
||||||
|
loop->use_samplerate = 1;
|
||||||
|
@@ -1463,9 +1463,11 @@ static int handle_ctl_events(struct loopback_handle *lhandle,
|
||||||
|
if (lhandle == lhandle->loopback->play)
|
||||||
|
goto __ctl_check;
|
||||||
|
if (verbose > 6)
|
||||||
|
- snd_output_printf(lhandle->loopback->output, "ctl event!!!! %s\n", snd_ctl_event_elem_get_name(ev));
|
||||||
|
+ snd_output_printf(lhandle->loopback->output, "%s: ctl event!!!! %s\n", lhandle->id, snd_ctl_event_elem_get_name(ev));
|
||||||
|
if (ctl_event_check(lhandle->ctl_active, ev)) {
|
||||||
|
err = get_active(lhandle);
|
||||||
|
+ if (verbose > 7)
|
||||||
|
+ snd_output_printf(lhandle->loopback->output, "%s: ctl event active %i\n", lhandle->id, err);
|
||||||
|
if (err != lhandle->loopback->running)
|
||||||
|
goto __restart;
|
||||||
|
} else if (ctl_event_check(lhandle->ctl_format, ev)) {
|
||||||
|
diff --git a/alsaloop/test.sh b/alsaloop/test.sh
|
||||||
|
index 13a5ba7..91f4cbc 100755
|
||||||
|
--- a/alsaloop/test.sh
|
||||||
|
+++ b/alsaloop/test.sh
|
||||||
|
@@ -2,6 +2,7 @@
|
||||||
|
|
||||||
|
#DBG="gdb --args "
|
||||||
|
#DBG="strace"
|
||||||
|
+#DBG="valgrind --leak-check=full"
|
||||||
|
CFGFILE="/tmp/alsaloop.test.cfg"
|
||||||
|
|
||||||
|
test1() {
|
||||||
|
@@ -35,7 +36,8 @@ cat > $CFGFILE <<EOF
|
||||||
|
-C hw:1,0,0 -P plug:dmix:0 --tlatency 50000 --thread 0 \
|
||||||
|
--mixer "name='Master Playback Volume'@name='Master Playback Volume'" \
|
||||||
|
--mixer "name='Master Playback Switch'@name='Master Playback Switch'" \
|
||||||
|
- --mixer "name='PCM Playback Volume'"
|
||||||
|
+ --mixer "name='PCM Playback Volume'" \
|
||||||
|
+ --ossmixer "name=Master@VOLUME"
|
||||||
|
-C hw:1,0,1 -P plug:dmix:0 --tlatency 50000 --thread 1
|
||||||
|
-C hw:1,0,2 -P plug:dmix:0 --tlatency 50000 --thread 2
|
||||||
|
-C hw:1,0,3 -P plug:dmix:0 --tlatency 50000 --thread 3
|
||||||
|
@@ -56,10 +58,24 @@ test4() {
|
||||||
|
--mixer "name='PCM Playback Volume'"
|
||||||
|
}
|
||||||
|
|
||||||
|
+test5() {
|
||||||
|
+ echo "TEST5"
|
||||||
|
+cat > $CFGFILE <<EOF
|
||||||
|
+-C hw:1,0,0 -P plughw:0,0 --tlatency 50000 --thread 1 \
|
||||||
|
+ --mixer "name='Master Playback Volume'@name='Master Playback Volume'" \
|
||||||
|
+ --mixer "name='Master Playback Switch'@name='Master Playback Switch'" \
|
||||||
|
+ --mixer "name='PCM Playback Volume'" \
|
||||||
|
+ --ossmixer "name=Master@VOLUME"
|
||||||
|
+-C hw:1,0,1 -P plughw:0,1 --tlatency 50000 --thread 2
|
||||||
|
+EOF
|
||||||
|
+ $DBG ./alsaloop --config $CFGFILE
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
case "$1" in
|
||||||
|
test1) test1 ;;
|
||||||
|
test2) test2 ;;
|
||||||
|
test3) test3 ;;
|
||||||
|
test4) test4 ;;
|
||||||
|
+test5) test5 ;;
|
||||||
|
*) test1 ;;
|
||||||
|
esac
|
||||||
|
--
|
||||||
|
1.7.3.1
|
||||||
|
|
449
0025-alsaloop-Fixes-and-added-workaround-option.patch
Normal file
449
0025-alsaloop-Fixes-and-added-workaround-option.patch
Normal file
@ -0,0 +1,449 @@
|
|||||||
|
From bee994f509e6829647aa68fd276f5e8821d15445 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jaroslav Kysela <perex@perex.cz>
|
||||||
|
Date: Mon, 11 Oct 2010 10:24:14 +0200
|
||||||
|
Subject: [PATCH 25/38] alsaloop: Fixes and added --workaround option
|
||||||
|
|
||||||
|
- added workaround for alsa-lib (pthread configuration parsing issue) -
|
||||||
|
the workaround must be activated manually using ('--workaround serialopen')
|
||||||
|
- fixed avail_min initialization (caused high CPU usage or xruns)
|
||||||
|
- fixed shared buffer initialization (both capture and playback buffers
|
||||||
|
must have equal number of samples in this config)
|
||||||
|
|
||||||
|
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
|
||||||
|
---
|
||||||
|
alsaloop/Makefile.am | 1 +
|
||||||
|
alsaloop/alsaloop.c | 9 ++++-
|
||||||
|
alsaloop/alsaloop.h | 3 +
|
||||||
|
alsaloop/pcmjob.c | 111 ++++++++++++++++++++++++++++++++++++++------------
|
||||||
|
alsaloop/test.sh | 26 +++++++-----
|
||||||
|
5 files changed, 112 insertions(+), 38 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/alsaloop/Makefile.am b/alsaloop/Makefile.am
|
||||||
|
index 97d2e6f..f76eafd 100644
|
||||||
|
--- a/alsaloop/Makefile.am
|
||||||
|
+++ b/alsaloop/Makefile.am
|
||||||
|
@@ -1,5 +1,6 @@
|
||||||
|
INCLUDES = -I$(top_srcdir)/include
|
||||||
|
LDADD = -lm
|
||||||
|
+CFLAGS += -D_GNU_SOURCE
|
||||||
|
if HAVE_SAMPLERATE
|
||||||
|
LDADD += -lsamplerate
|
||||||
|
endif
|
||||||
|
diff --git a/alsaloop/alsaloop.c b/alsaloop/alsaloop.c
|
||||||
|
index 97b00d5..3af3dd7 100644
|
||||||
|
--- a/alsaloop/alsaloop.c
|
||||||
|
+++ b/alsaloop/alsaloop.c
|
||||||
|
@@ -43,6 +43,7 @@ struct loopback_thread {
|
||||||
|
};
|
||||||
|
|
||||||
|
int verbose = 0;
|
||||||
|
+int workarounds = 0;
|
||||||
|
int daemonize = 0;
|
||||||
|
int use_syslog = 0;
|
||||||
|
struct loopback **loopbacks = NULL;
|
||||||
|
@@ -171,6 +172,7 @@ void help(void)
|
||||||
|
" ALSA_ID@OSS_ID (for example: \"Master@VOLUME\")\n"
|
||||||
|
"-e,--effect apply an effect (bandpass filter sweep)\n"
|
||||||
|
"-v,--verbose verbose mode (more -v means more verbose)\n"
|
||||||
|
+"-w,--workaround use workaround (serialopen)\n"
|
||||||
|
);
|
||||||
|
printf("\nRecognized sample formats are:");
|
||||||
|
for (k = 0; k < SND_PCM_FORMAT_LAST; ++k) {
|
||||||
|
@@ -339,6 +341,7 @@ static int parse_config(int argc, char *argv[], snd_output_t *output)
|
||||||
|
{"thread", 1, NULL, 'T'},
|
||||||
|
{"mixer", 1, NULL, 'm'},
|
||||||
|
{"ossmixer", 1, NULL, 'O'},
|
||||||
|
+ {"workaround", 1, NULL, 'w'},
|
||||||
|
{NULL, 0, NULL, 0},
|
||||||
|
};
|
||||||
|
int err, morehelp;
|
||||||
|
@@ -370,7 +373,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:l:t:F:f:c:r:s:benvA:S:a:m:T:O:",
|
||||||
|
+ "hdg:P:C:l:t:F:f:c:r:s:benvA:S:a:m:T:O:w:",
|
||||||
|
long_option, NULL)) < 0)
|
||||||
|
break;
|
||||||
|
switch (c) {
|
||||||
|
@@ -504,6 +507,10 @@ static int parse_config(int argc, char *argv[], snd_output_t *output)
|
||||||
|
case 'v':
|
||||||
|
verbose++;
|
||||||
|
break;
|
||||||
|
+ case 'w':
|
||||||
|
+ if (strcasecmp(optarg, "serialopen") == 0)
|
||||||
|
+ workarounds |= WORKAROUND_SERIALOPEN;
|
||||||
|
+ break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/alsaloop/alsaloop.h b/alsaloop/alsaloop.h
|
||||||
|
index 366a296..6c4f40a 100644
|
||||||
|
--- a/alsaloop/alsaloop.h
|
||||||
|
+++ b/alsaloop/alsaloop.h
|
||||||
|
@@ -40,6 +40,8 @@ enum {
|
||||||
|
#define FILE_CWRITE "/tmp/alsaloop.craw"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
+#define WORKAROUND_SERIALOPEN (1<<0)
|
||||||
|
+
|
||||||
|
typedef enum _sync_type {
|
||||||
|
SYNC_TYPE_NONE = 0,
|
||||||
|
SYNC_TYPE_SIMPLE, /* add or remove samples */
|
||||||
|
@@ -171,6 +173,7 @@ struct loopback {
|
||||||
|
};
|
||||||
|
|
||||||
|
extern int verbose;
|
||||||
|
+extern int workarounds;
|
||||||
|
extern int use_syslog;
|
||||||
|
|
||||||
|
#define logit(priority, fmt, args...) do { \
|
||||||
|
diff --git a/alsaloop/pcmjob.c b/alsaloop/pcmjob.c
|
||||||
|
index df835f0..8b3e568 100644
|
||||||
|
--- a/alsaloop/pcmjob.c
|
||||||
|
+++ b/alsaloop/pcmjob.c
|
||||||
|
@@ -31,9 +31,11 @@
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
+#include <pthread.h>
|
||||||
|
#include "alsaloop.h"
|
||||||
|
|
||||||
|
static int set_rate_shift(struct loopback_handle *lhandle, double pitch);
|
||||||
|
+static int get_rate(struct loopback_handle *lhandle);
|
||||||
|
|
||||||
|
#define SYNCTYPE(v) [SYNC_TYPE_##v] = #v
|
||||||
|
|
||||||
|
@@ -56,6 +58,21 @@ static const char *src_types[] = {
|
||||||
|
SRCTYPE(LINEAR)
|
||||||
|
};
|
||||||
|
|
||||||
|
+static pthread_mutex_t pcm_open_mutex =
|
||||||
|
+ PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
|
||||||
|
+
|
||||||
|
+static inline void pcm_open_lock(void)
|
||||||
|
+{
|
||||||
|
+ if (workarounds & WORKAROUND_SERIALOPEN)
|
||||||
|
+ pthread_mutex_lock(&pcm_open_mutex);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void pcm_open_unlock(void)
|
||||||
|
+{
|
||||||
|
+ if (workarounds & WORKAROUND_SERIALOPEN)
|
||||||
|
+ pthread_mutex_unlock(&pcm_open_mutex);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static inline snd_pcm_uframes_t get_whole_latency(struct loopback *loop)
|
||||||
|
{
|
||||||
|
return loop->latency;
|
||||||
|
@@ -76,7 +93,7 @@ static int setparams_stream(struct loopback_handle *lhandle,
|
||||||
|
|
||||||
|
err = snd_pcm_hw_params_any(handle, params);
|
||||||
|
if (err < 0) {
|
||||||
|
- logit(LOG_CRIT, "Broken configuration for %s PCM: no configurations available: %s\n", snd_strerror(err), lhandle->id);
|
||||||
|
+ logit(LOG_CRIT, "Broken configuration for %s PCM: no configurations available: %s\n", lhandle->id, snd_strerror(err));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
err = snd_pcm_hw_params_set_rate_resample(handle, params, lhandle->resample);
|
||||||
|
@@ -153,6 +170,8 @@ static int setparams_bufsize(struct loopback_handle *lhandle,
|
||||||
|
goto __again;
|
||||||
|
}
|
||||||
|
snd_pcm_hw_params_get_buffer_size(params, &periodsize);
|
||||||
|
+ if (verbose > 6)
|
||||||
|
+ snd_output_printf(lhandle->loopback->output, "%s: buffer_size=%li\n", lhandle->id, periodsize);
|
||||||
|
if (lhandle->period_size_req > 0)
|
||||||
|
periodsize = lhandle->period_size_req;
|
||||||
|
else
|
||||||
|
@@ -163,6 +182,8 @@ static int setparams_bufsize(struct loopback_handle *lhandle,
|
||||||
|
goto __again;
|
||||||
|
}
|
||||||
|
snd_pcm_hw_params_get_period_size(params, &periodsize, NULL);
|
||||||
|
+ if (verbose > 6)
|
||||||
|
+ snd_output_printf(lhandle->loopback->output, "%s: period_size=%li\n", lhandle->id, periodsize);
|
||||||
|
if (periodsize != bufsize)
|
||||||
|
bufsize = periodsize;
|
||||||
|
snd_pcm_hw_params_get_buffer_size(params, &buffersize);
|
||||||
|
@@ -175,11 +196,12 @@ static int setparams_bufsize(struct loopback_handle *lhandle,
|
||||||
|
|
||||||
|
static int setparams_set(struct loopback_handle *lhandle,
|
||||||
|
snd_pcm_hw_params_t *params,
|
||||||
|
- snd_pcm_sw_params_t *swparams)
|
||||||
|
+ snd_pcm_sw_params_t *swparams,
|
||||||
|
+ snd_pcm_uframes_t bufsize)
|
||||||
|
{
|
||||||
|
snd_pcm_t *handle = lhandle->handle;
|
||||||
|
int err;
|
||||||
|
- snd_pcm_uframes_t val, val1;
|
||||||
|
+ snd_pcm_uframes_t val, period_size, buffer_size;
|
||||||
|
|
||||||
|
err = snd_pcm_hw_params(handle, params);
|
||||||
|
if (err < 0) {
|
||||||
|
@@ -196,21 +218,29 @@ static int setparams_set(struct loopback_handle *lhandle,
|
||||||
|
logit(LOG_CRIT, "Unable to set start threshold mode for %s: %s\n", lhandle->id, snd_strerror(err));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
- snd_pcm_hw_params_get_period_size(params, &val, NULL);
|
||||||
|
- snd_pcm_hw_params_get_buffer_size(params, &val1);
|
||||||
|
+ snd_pcm_hw_params_get_period_size(params, &period_size, NULL);
|
||||||
|
+ snd_pcm_hw_params_get_buffer_size(params, &buffer_size);
|
||||||
|
if (lhandle->nblock) {
|
||||||
|
if (lhandle == lhandle->loopback->play) {
|
||||||
|
- val = val1 - (2 * val - 4);
|
||||||
|
+ val = buffer_size - (2 * period_size - 4);
|
||||||
|
} else {
|
||||||
|
val = 4;
|
||||||
|
}
|
||||||
|
+ if (verbose > 6)
|
||||||
|
+ snd_output_printf(lhandle->loopback->output, "%s: avail_min1=%li\n", lhandle->id, val);
|
||||||
|
} else {
|
||||||
|
if (lhandle == lhandle->loopback->play) {
|
||||||
|
- snd_pcm_hw_params_get_buffer_size(params, &val1);
|
||||||
|
- val = val1 - val - val / 2;
|
||||||
|
+ val = bufsize / 2 + bufsize / 4 + bufsize / 8;
|
||||||
|
+ if (val > buffer_size / 4)
|
||||||
|
+ val = buffer_size / 4;
|
||||||
|
+ val = buffer_size - val;
|
||||||
|
} else {
|
||||||
|
- val /= 2;
|
||||||
|
+ val = bufsize / 2;
|
||||||
|
+ if (val > buffer_size / 4)
|
||||||
|
+ val = buffer_size / 4;
|
||||||
|
}
|
||||||
|
+ if (verbose > 6)
|
||||||
|
+ snd_output_printf(lhandle->loopback->output, "%s: avail_min2=%li\n", lhandle->id, val);
|
||||||
|
}
|
||||||
|
err = snd_pcm_sw_params_set_avail_min(handle, swparams, val);
|
||||||
|
if (err < 0) {
|
||||||
|
@@ -256,11 +286,11 @@ static int setparams(struct loopback *loop, snd_pcm_uframes_t bufsize)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
- if ((err = setparams_set(loop->play, p_params, p_swparams)) < 0) {
|
||||||
|
+ if ((err = setparams_set(loop->play, p_params, p_swparams, bufsize / loop->play->pitch)) < 0) {
|
||||||
|
logit(LOG_CRIT, "Unable to set sw parameters for %s stream: %s\n", loop->play->id, snd_strerror(err));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
- if ((err = setparams_set(loop->capt, c_params, c_swparams)) < 0) {
|
||||||
|
+ if ((err = setparams_set(loop->capt, c_params, c_swparams, bufsize / loop->capt->pitch)) < 0) {
|
||||||
|
logit(LOG_CRIT, "Unable to set sw parameters for %s stream: %s\n", loop->capt->id, snd_strerror(err));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
@@ -495,6 +525,12 @@ static int readit(struct loopback_handle *lhandle)
|
||||||
|
int err;
|
||||||
|
|
||||||
|
avail = snd_pcm_avail_update(lhandle->handle);
|
||||||
|
+ if (avail == -EPIPE) {
|
||||||
|
+ return xrun(lhandle);
|
||||||
|
+ } else if (avail == -ESTRPIPE) {
|
||||||
|
+ if ((err = suspend(lhandle)) < 0)
|
||||||
|
+ return err;
|
||||||
|
+ }
|
||||||
|
if (avail > buf_avail(lhandle)) {
|
||||||
|
lhandle->buf_over += avail - buf_avail(lhandle);
|
||||||
|
avail = buf_avail(lhandle);
|
||||||
|
@@ -1008,7 +1044,10 @@ static int openit(struct loopback_handle *lhandle)
|
||||||
|
SND_PCM_STREAM_PLAYBACK :
|
||||||
|
SND_PCM_STREAM_CAPTURE;
|
||||||
|
int err, card, device, subdevice;
|
||||||
|
- if ((err = snd_pcm_open(&lhandle->handle, lhandle->device, stream, SND_PCM_NONBLOCK)) < 0) {
|
||||||
|
+ pcm_open_lock();
|
||||||
|
+ err = snd_pcm_open(&lhandle->handle, lhandle->device, stream, SND_PCM_NONBLOCK);
|
||||||
|
+ pcm_open_unlock();
|
||||||
|
+ if (err < 0) {
|
||||||
|
logit(LOG_CRIT, "%s open error: %s\n", lhandle->id, snd_strerror(err));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
@@ -1027,7 +1066,9 @@ static int openit(struct loopback_handle *lhandle)
|
||||||
|
if (card >= 0) {
|
||||||
|
char name[16];
|
||||||
|
sprintf(name, "hw:%i", card);
|
||||||
|
+ pcm_open_lock();
|
||||||
|
err = snd_ctl_open(&lhandle->ctl, name, SND_CTL_NONBLOCK);
|
||||||
|
+ pcm_open_unlock();
|
||||||
|
if (err < 0) {
|
||||||
|
logit(LOG_CRIT, "%s [%s] ctl open error: %s\n", lhandle->id, name, snd_strerror(err));
|
||||||
|
lhandle->ctl = NULL;
|
||||||
|
@@ -1254,6 +1295,17 @@ int pcmjob_start(struct loopback *loop)
|
||||||
|
goto __error;
|
||||||
|
}
|
||||||
|
loop->play->buf = nbuf;
|
||||||
|
+ loop->play->buf_size = loop->capt->buf_size;
|
||||||
|
+ } else if (loop->capt->buf_size < loop->play->buf_size) {
|
||||||
|
+ char *nbuf = realloc(loop->capt->buf,
|
||||||
|
+ loop->play->buf_size *
|
||||||
|
+ loop->play->frame_size);
|
||||||
|
+ if (nbuf == NULL) {
|
||||||
|
+ err = -ENOMEM;
|
||||||
|
+ goto __error;
|
||||||
|
+ }
|
||||||
|
+ loop->capt->buf = nbuf;
|
||||||
|
+ loop->capt->buf_size = loop->play->buf_size;
|
||||||
|
}
|
||||||
|
loop->capt->buf = loop->play->buf;
|
||||||
|
} else {
|
||||||
|
@@ -1278,7 +1330,7 @@ int pcmjob_start(struct loopback *loop)
|
||||||
|
if (loop->use_samplerate) {
|
||||||
|
if (loop->capt->format != SND_PCM_FORMAT_S16 ||
|
||||||
|
loop->play->format != SND_PCM_FORMAT_S16) {
|
||||||
|
- logit(LOG_CRIT, "samplerate conversion supports only S16_LE format (%i, %i)\n", loop->play->format, loop->capt->format);
|
||||||
|
+ logit(LOG_CRIT, "samplerate conversion supports only %s format (play=%s, capt=%s)\n", snd_pcm_format_name(SND_PCM_FORMAT_S16), snd_pcm_format_name(loop->play->format), snd_pcm_format_name(loop->capt->format));
|
||||||
|
loop->use_samplerate = 0;
|
||||||
|
err = -EIO;
|
||||||
|
goto __error;
|
||||||
|
@@ -1325,6 +1377,8 @@ int pcmjob_start(struct loopback *loop)
|
||||||
|
logit(LOG_CRIT, "%s: silence error\n", loop->id);
|
||||||
|
goto __error;
|
||||||
|
}
|
||||||
|
+ if (verbose > 4)
|
||||||
|
+ snd_output_printf(loop->output, "%s: capt->buffer_size = %li, play->buffer_size = %li\n", loop->id, loop->capt->buf_size, loop->play->buf_size);
|
||||||
|
loop->pitch = 1.0;
|
||||||
|
update_pitch(loop);
|
||||||
|
loop->pitch_delta = 1.0 / ((double)loop->capt->rate * 4);
|
||||||
|
@@ -1334,8 +1388,13 @@ int pcmjob_start(struct loopback *loop)
|
||||||
|
loop->play->buf_count = count;
|
||||||
|
if (loop->play->buf == loop->capt->buf)
|
||||||
|
loop->capt->buf_pos = count;
|
||||||
|
- if (writeit(loop->play) != count) {
|
||||||
|
- logit(LOG_CRIT, "%s: initial playback fill error\n", loop->id);
|
||||||
|
+ err = writeit(loop->play);
|
||||||
|
+ if (verbose > 4)
|
||||||
|
+ snd_output_printf(loop->output, "%s: silence queued %i samples\n", loop->id, err);
|
||||||
|
+ if (count > loop->play->buffer_size)
|
||||||
|
+ count = loop->play->buffer_size;
|
||||||
|
+ if (err != count) {
|
||||||
|
+ logit(LOG_CRIT, "%s: initial playback fill error (%i/%i/%i)\n", loop->id, err, (int)count, loop->play->buffer_size);
|
||||||
|
err = -EIO;
|
||||||
|
goto __error;
|
||||||
|
}
|
||||||
|
@@ -1511,13 +1570,13 @@ int pcmjob_pollfds_handle(struct loopback *loop, struct pollfd *fds)
|
||||||
|
if (verbose > 12) {
|
||||||
|
snd_pcm_sframes_t pdelay, cdelay;
|
||||||
|
if ((err = snd_pcm_delay(play->handle, &pdelay)) < 0)
|
||||||
|
- snd_output_printf(loop->output, "%s: delay error: %s\n", play->id, snd_strerror(err));
|
||||||
|
+ snd_output_printf(loop->output, "%s: delay error: %s / %li / %li\n", play->id, snd_strerror(err), play->buf_size, play->buf_count);
|
||||||
|
else
|
||||||
|
- snd_output_printf(loop->output, "%s: delay %li\n", play->id, pdelay);
|
||||||
|
+ snd_output_printf(loop->output, "%s: delay %li / %li / %li\n", play->id, pdelay, play->buf_size, play->buf_count);
|
||||||
|
if ((err = snd_pcm_delay(capt->handle, &cdelay)) < 0)
|
||||||
|
- snd_output_printf(loop->output, "%s: delay error: %s\n", capt->id, snd_strerror(err));
|
||||||
|
+ snd_output_printf(loop->output, "%s: delay error: %s / %li / %li\n", capt->id, snd_strerror(err), capt->buf_size, capt->buf_count);
|
||||||
|
else
|
||||||
|
- snd_output_printf(loop->output, "%s: delay %li\n", capt->id, cdelay);
|
||||||
|
+ snd_output_printf(loop->output, "%s: delay %li / %li / %li\n", capt->id, cdelay, capt->buf_size, capt->buf_count);
|
||||||
|
}
|
||||||
|
idx = 0;
|
||||||
|
if (loop->running) {
|
||||||
|
@@ -1570,7 +1629,7 @@ int pcmjob_pollfds_handle(struct loopback *loop, struct pollfd *fds)
|
||||||
|
}
|
||||||
|
if (verbose > 9)
|
||||||
|
snd_output_printf(loop->output, "%s: prevents = 0x%x, crevents = 0x%x\n", loop->id, prevents, crevents);
|
||||||
|
- if (prevents == 0 && crevents == 0)
|
||||||
|
+ if (!loop->running)
|
||||||
|
goto __pcm_end;
|
||||||
|
do {
|
||||||
|
ccount = readit(capt);
|
||||||
|
@@ -1637,22 +1696,22 @@ int pcmjob_pollfds_handle(struct loopback *loop, struct pollfd *fds)
|
||||||
|
if (verbose > 4)
|
||||||
|
snd_output_printf(loop->output, "%s: queued %li/%li samples\n", loop->id, pqueued, cqueued);
|
||||||
|
if (pqueued > 0)
|
||||||
|
- loop->play->total_queued += pqueued;
|
||||||
|
+ play->total_queued += pqueued;
|
||||||
|
if (cqueued > 0)
|
||||||
|
- loop->capt->total_queued += cqueued;
|
||||||
|
+ capt->total_queued += cqueued;
|
||||||
|
if (pqueued > 0 || cqueued > 0)
|
||||||
|
loop->total_queued_count += 1;
|
||||||
|
}
|
||||||
|
if (verbose > 12) {
|
||||||
|
snd_pcm_sframes_t pdelay, cdelay;
|
||||||
|
if ((err = snd_pcm_delay(play->handle, &pdelay)) < 0)
|
||||||
|
- snd_output_printf(loop->output, "%s: end delay error: %s\n", play->id, snd_strerror(err));
|
||||||
|
+ snd_output_printf(loop->output, "%s: end delay error: %s / %li / %li\n", play->id, snd_strerror(err), play->buf_size, play->buf_count);
|
||||||
|
else
|
||||||
|
- snd_output_printf(loop->output, "%s: end delay %li\n", play->id, pdelay);
|
||||||
|
+ snd_output_printf(loop->output, "%s: end delay %li / %li / %li\n", play->id, pdelay, play->buf_size, play->buf_count);
|
||||||
|
if ((err = snd_pcm_delay(capt->handle, &cdelay)) < 0)
|
||||||
|
- snd_output_printf(loop->output, "%s: end delay error: %s\n", capt->id, snd_strerror(err));
|
||||||
|
+ snd_output_printf(loop->output, "%s: end delay error: %s / %li / %li\n", capt->id, snd_strerror(err), capt->buf_size, capt->buf_count);
|
||||||
|
else
|
||||||
|
- snd_output_printf(loop->output, "%s: end delay %li\n", capt->id, cdelay);
|
||||||
|
+ snd_output_printf(loop->output, "%s: end delay %li / %li / %li\n", capt->id, cdelay, capt->buf_size, capt->buf_count);
|
||||||
|
}
|
||||||
|
__pcm_end:
|
||||||
|
if (verbose > 13) {
|
||||||
|
diff --git a/alsaloop/test.sh b/alsaloop/test.sh
|
||||||
|
index 91f4cbc..e3d81b1 100755
|
||||||
|
--- a/alsaloop/test.sh
|
||||||
|
+++ b/alsaloop/test.sh
|
||||||
|
@@ -3,6 +3,7 @@
|
||||||
|
#DBG="gdb --args "
|
||||||
|
#DBG="strace"
|
||||||
|
#DBG="valgrind --leak-check=full"
|
||||||
|
+ARGS=
|
||||||
|
CFGFILE="/tmp/alsaloop.test.cfg"
|
||||||
|
|
||||||
|
test1() {
|
||||||
|
@@ -13,7 +14,8 @@ test1() {
|
||||||
|
--mixer "name='Master Playback Switch'@name='Master Playback Switch'" \
|
||||||
|
--mixer "name='PCM Playback Volume'" \
|
||||||
|
--ossmixer "Master@VOLUME" \
|
||||||
|
- --ossmixer "PCM@PCM"
|
||||||
|
+ --ossmixer "PCM@PCM" \
|
||||||
|
+ $ARGS
|
||||||
|
}
|
||||||
|
|
||||||
|
test2() {
|
||||||
|
@@ -27,7 +29,7 @@ cat > $CFGFILE <<EOF
|
||||||
|
# next line - second job
|
||||||
|
-C hw:1,0,1 -P hw:0,1,0 --tlatency 50000 --thread 2
|
||||||
|
EOF
|
||||||
|
- $DBG ./alsaloop -d --config $CFGFILE
|
||||||
|
+ $DBG ./alsaloop -d --config $CFGFILE $ARGS
|
||||||
|
}
|
||||||
|
|
||||||
|
test3() {
|
||||||
|
@@ -46,7 +48,8 @@ cat > $CFGFILE <<EOF
|
||||||
|
-C hw:1,0,6 -P plug:dmix:0 --tlatency 50000 --thread 6
|
||||||
|
-C hw:1,0,7 -P plug:dmix:0 --tlatency 50000 --thread 7
|
||||||
|
EOF
|
||||||
|
- $DBG ./alsaloop --config $CFGFILE
|
||||||
|
+ LD_PRELOAD="/home/perex/alsa/alsa-lib/src/.libs/libasound.so" \
|
||||||
|
+ $DBG ./alsaloop --config $CFGFILE $ARGS
|
||||||
|
}
|
||||||
|
|
||||||
|
test4() {
|
||||||
|
@@ -55,7 +58,8 @@ test4() {
|
||||||
|
--tlatency 50000 \
|
||||||
|
--mixer "name='Master Playback Volume'@name='Master Playback Volume'" \
|
||||||
|
--mixer "name='Master Playback Switch'@name='Master Playback Switch'" \
|
||||||
|
- --mixer "name='PCM Playback Volume'"
|
||||||
|
+ --mixer "name='PCM Playback Volume'" \
|
||||||
|
+ $ARGS
|
||||||
|
}
|
||||||
|
|
||||||
|
test5() {
|
||||||
|
@@ -68,14 +72,14 @@ cat > $CFGFILE <<EOF
|
||||||
|
--ossmixer "name=Master@VOLUME"
|
||||||
|
-C hw:1,0,1 -P plughw:0,1 --tlatency 50000 --thread 2
|
||||||
|
EOF
|
||||||
|
- $DBG ./alsaloop --config $CFGFILE
|
||||||
|
+ $DBG ./alsaloop --config $CFGFILE $ARGS
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
-test1) test1 ;;
|
||||||
|
-test2) test2 ;;
|
||||||
|
-test3) test3 ;;
|
||||||
|
-test4) test4 ;;
|
||||||
|
-test5) test5 ;;
|
||||||
|
-*) test1 ;;
|
||||||
|
+test1) shift; ARGS="$@"; test1 ;;
|
||||||
|
+test2) shift; ARGS="$@"; test2 ;;
|
||||||
|
+test3) shift; ARGS="$@"; test3 ;;
|
||||||
|
+test4) shift; ARGS="$@"; test4 ;;
|
||||||
|
+test5) shift; ARGS="$@"; test5 ;;
|
||||||
|
+*) ARGS="$@"; test1 ;;
|
||||||
|
esac
|
||||||
|
--
|
||||||
|
1.7.3.1
|
||||||
|
|
149
0026-alsaloop-add-pctl-and-cctl-options.patch
Normal file
149
0026-alsaloop-add-pctl-and-cctl-options.patch
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
From 38c2ef96b78d8733957f03b74799d953b83e045d Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jaroslav Kysela <perex@perex.cz>
|
||||||
|
Date: Mon, 11 Oct 2010 11:53:50 +0200
|
||||||
|
Subject: [PATCH 26/38] alsaloop: add --pctl and --cctl options
|
||||||
|
|
||||||
|
In some cases it might be usefull to specify another CTL device names.
|
||||||
|
Add -X/--pctl and -Y/--cctl options.
|
||||||
|
|
||||||
|
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
|
||||||
|
---
|
||||||
|
alsaloop/alsaloop.c | 28 +++++++++++++++++++++++++---
|
||||||
|
alsaloop/alsaloop.h | 1 +
|
||||||
|
alsaloop/pcmjob.c | 13 ++++++++-----
|
||||||
|
3 files changed, 34 insertions(+), 8 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/alsaloop/alsaloop.c b/alsaloop/alsaloop.c
|
||||||
|
index 3af3dd7..1b3505e 100644
|
||||||
|
--- a/alsaloop/alsaloop.c
|
||||||
|
+++ b/alsaloop/alsaloop.c
|
||||||
|
@@ -66,6 +66,7 @@ static void my_exit(struct loopback_thread *thread, int exitcode)
|
||||||
|
|
||||||
|
static int create_loopback_handle(struct loopback_handle **_handle,
|
||||||
|
const char *device,
|
||||||
|
+ const char *ctldev,
|
||||||
|
const char *id)
|
||||||
|
{
|
||||||
|
char idbuf[1024];
|
||||||
|
@@ -77,6 +78,15 @@ static int create_loopback_handle(struct loopback_handle **_handle,
|
||||||
|
if (device == NULL)
|
||||||
|
device = "hw:0,0";
|
||||||
|
handle->device = strdup(device);
|
||||||
|
+ if (handle->device == NULL)
|
||||||
|
+ return -ENOMEM;
|
||||||
|
+ if (ctldev) {
|
||||||
|
+ handle->ctldev = strdup(ctldev);
|
||||||
|
+ if (handle->ctldev == NULL)
|
||||||
|
+ return -ENOMEM;
|
||||||
|
+ } else {
|
||||||
|
+ handle->ctldev = NULL;
|
||||||
|
+ }
|
||||||
|
snprintf(idbuf, sizeof(idbuf)-1, "%s %s", id, device);
|
||||||
|
idbuf[sizeof(idbuf)-1] = '\0';
|
||||||
|
handle->id = strdup(idbuf);
|
||||||
|
@@ -150,6 +160,8 @@ void help(void)
|
||||||
|
"-d,--daemonize daemonize the main process and use syslog for errors\n"
|
||||||
|
"-P,--pdevice playback device\n"
|
||||||
|
"-C,--cdevice capture device\n"
|
||||||
|
+"-X,--pctl playback ctl device\n"
|
||||||
|
+"-Y,--cctl capture ctl device\n"
|
||||||
|
"-l,--latency requested latency in frames\n"
|
||||||
|
"-t,--tlatency requested latency in usec (1/1000000sec)\n"
|
||||||
|
"-f,--format sample format\n"
|
||||||
|
@@ -323,6 +335,8 @@ static int parse_config(int argc, char *argv[], snd_output_t *output)
|
||||||
|
{"daemonize", 0, NULL, 'd'},
|
||||||
|
{"pdevice", 1, NULL, 'P'},
|
||||||
|
{"cdevice", 1, NULL, 'C'},
|
||||||
|
+ {"pctl", 1, NULL, 'X'},
|
||||||
|
+ {"cctl", 1, NULL, 'Y'},
|
||||||
|
{"latency", 1, NULL, 'l'},
|
||||||
|
{"tlatency", 1, NULL, 't'},
|
||||||
|
{"format", 1, NULL, 'f'},
|
||||||
|
@@ -348,6 +362,8 @@ static int parse_config(int argc, char *argv[], snd_output_t *output)
|
||||||
|
char *arg_config = NULL;
|
||||||
|
char *arg_pdevice = NULL;
|
||||||
|
char *arg_cdevice = NULL;
|
||||||
|
+ char *arg_pctl = NULL;
|
||||||
|
+ char *arg_cctl = NULL;
|
||||||
|
unsigned int arg_latency_req = 0;
|
||||||
|
unsigned int arg_latency_reqtime = 10000;
|
||||||
|
snd_pcm_format_t arg_format = SND_PCM_FORMAT_S16_LE;
|
||||||
|
@@ -373,7 +389,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:l:t:F:f:c:r:s:benvA:S:a:m:T:O:w:",
|
||||||
|
+ "hdg:P:C:X:Y:l:t:F:f:c:r:s:benvA:S:a:m:T:O:w:",
|
||||||
|
long_option, NULL)) < 0)
|
||||||
|
break;
|
||||||
|
switch (c) {
|
||||||
|
@@ -394,6 +410,12 @@ static int parse_config(int argc, char *argv[], snd_output_t *output)
|
||||||
|
case 'C':
|
||||||
|
arg_cdevice = strdup(optarg);
|
||||||
|
break;
|
||||||
|
+ case 'X':
|
||||||
|
+ arg_pctl = strdup(optarg);
|
||||||
|
+ break;
|
||||||
|
+ case 'Y':
|
||||||
|
+ arg_cctl = strdup(optarg);
|
||||||
|
+ break;
|
||||||
|
case 'l':
|
||||||
|
err = atoi(optarg);
|
||||||
|
arg_latency_req = err >= 4 ? err : 4;
|
||||||
|
@@ -521,12 +543,12 @@ static int parse_config(int argc, char *argv[], snd_output_t *output)
|
||||||
|
if (arg_config == NULL) {
|
||||||
|
struct loopback_handle *play;
|
||||||
|
struct loopback_handle *capt;
|
||||||
|
- err = create_loopback_handle(&play, arg_pdevice, "playback");
|
||||||
|
+ err = create_loopback_handle(&play, arg_pdevice, arg_pctl, "playback");
|
||||||
|
if (err < 0) {
|
||||||
|
logit(LOG_CRIT, "Unable to create playback handle.\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
- err = create_loopback_handle(&capt, arg_cdevice, "capture");
|
||||||
|
+ err = create_loopback_handle(&capt, arg_cdevice, arg_cctl, "capture");
|
||||||
|
if (err < 0) {
|
||||||
|
logit(LOG_CRIT, "Unable to create capture handle.\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
diff --git a/alsaloop/alsaloop.h b/alsaloop/alsaloop.h
|
||||||
|
index 6c4f40a..7516807 100644
|
||||||
|
--- a/alsaloop/alsaloop.h
|
||||||
|
+++ b/alsaloop/alsaloop.h
|
||||||
|
@@ -84,6 +84,7 @@ struct loopback_ossmixer {
|
||||||
|
struct loopback_handle {
|
||||||
|
struct loopback *loopback;
|
||||||
|
char *device;
|
||||||
|
+ char *ctldev;
|
||||||
|
char *id;
|
||||||
|
int card_number;
|
||||||
|
snd_pcm_t *handle;
|
||||||
|
diff --git a/alsaloop/pcmjob.c b/alsaloop/pcmjob.c
|
||||||
|
index 8b3e568..9d1bb01 100644
|
||||||
|
--- a/alsaloop/pcmjob.c
|
||||||
|
+++ b/alsaloop/pcmjob.c
|
||||||
|
@@ -1063,14 +1063,17 @@ static int openit(struct loopback_handle *lhandle)
|
||||||
|
snd_pcm_info_free(info);
|
||||||
|
lhandle->card_number = card;
|
||||||
|
lhandle->ctl = NULL;
|
||||||
|
- if (card >= 0) {
|
||||||
|
- char name[16];
|
||||||
|
- sprintf(name, "hw:%i", card);
|
||||||
|
+ if (card >= 0 || lhandle->ctldev) {
|
||||||
|
+ char name[16], *dev = lhandle->ctldev;
|
||||||
|
+ if (dev == NULL) {
|
||||||
|
+ sprintf(name, "hw:%i", card);
|
||||||
|
+ dev = name;
|
||||||
|
+ }
|
||||||
|
pcm_open_lock();
|
||||||
|
- err = snd_ctl_open(&lhandle->ctl, name, SND_CTL_NONBLOCK);
|
||||||
|
+ err = snd_ctl_open(&lhandle->ctl, dev, SND_CTL_NONBLOCK);
|
||||||
|
pcm_open_unlock();
|
||||||
|
if (err < 0) {
|
||||||
|
- logit(LOG_CRIT, "%s [%s] ctl open error: %s\n", lhandle->id, name, snd_strerror(err));
|
||||||
|
+ logit(LOG_CRIT, "%s [%s] ctl open error: %s\n", lhandle->id, dev, snd_strerror(err));
|
||||||
|
lhandle->ctl = NULL;
|
||||||
|
}
|
||||||
|
if (lhandle->ctl)
|
||||||
|
--
|
||||||
|
1.7.3.1
|
||||||
|
|
34
0027-alsaloop-add-pctl-and-cctl-options-to-man-page.patch
Normal file
34
0027-alsaloop-add-pctl-and-cctl-options-to-man-page.patch
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
From af61ea60cfabb6b59b29a1e26769a7068a5742e1 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jaroslav Kysela <perex@perex.cz>
|
||||||
|
Date: Mon, 11 Oct 2010 11:56:16 +0200
|
||||||
|
Subject: [PATCH 27/38] alsaloop: add --pctl and --cctl options to man page
|
||||||
|
|
||||||
|
Signed-off-by: Jaroslav Kysela <perex@perex.cz># Please enter the commit message for your changes. Lines starting
|
||||||
|
---
|
||||||
|
alsaloop/alsaloop.1 | 10 ++++++++++
|
||||||
|
1 files changed, 10 insertions(+), 0 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/alsaloop/alsaloop.1 b/alsaloop/alsaloop.1
|
||||||
|
index 1554b6e..0b57b59 100644
|
||||||
|
--- a/alsaloop/alsaloop.1
|
||||||
|
+++ b/alsaloop/alsaloop.1
|
||||||
|
@@ -48,6 +48,16 @@ Use given playback device.
|
||||||
|
Use given capture device.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
+\fI\-X <device>\fP | \fI\-\-pctl=<device>\fP
|
||||||
|
+
|
||||||
|
+Use given CTL device for playback.
|
||||||
|
+
|
||||||
|
+.TP
|
||||||
|
+\fI\-Y <device>\fP | \fI\-\-cctl=<device>\fP
|
||||||
|
+
|
||||||
|
+Use given CTL device for capture.
|
||||||
|
+
|
||||||
|
+.TP
|
||||||
|
\fI\-l <latency>\fP | \fI\-\-latency=<frames>\fP
|
||||||
|
|
||||||
|
Requested latency in frames.
|
||||||
|
--
|
||||||
|
1.7.3.1
|
||||||
|
|
677
0028-alsaloop-added-xrun-profiling-support-U-xrun-added-S.patch
Normal file
677
0028-alsaloop-added-xrun-profiling-support-U-xrun-added-S.patch
Normal file
@ -0,0 +1,677 @@
|
|||||||
|
From 1a35bdf7c6c3a4727662d093963141dddc376072 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jaroslav Kysela <perex@perex.cz>
|
||||||
|
Date: Wed, 13 Oct 2010 23:39:36 +0200
|
||||||
|
Subject: [PATCH 28/38] alsaloop: added xrun profiling support (-U,--xrun), added SIGUSR1 state dump
|
||||||
|
|
||||||
|
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
|
||||||
|
---
|
||||||
|
alsaloop/alsaloop.c | 89 ++++++++++++++++++++++---
|
||||||
|
alsaloop/alsaloop.h | 20 +++++-
|
||||||
|
alsaloop/pcmjob.c | 180 ++++++++++++++++++++++++++++++++++++++++++++-------
|
||||||
|
alsaloop/test.sh | 26 +++++---
|
||||||
|
4 files changed, 270 insertions(+), 45 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/alsaloop/alsaloop.c b/alsaloop/alsaloop.c
|
||||||
|
index 1b3505e..561fdd7 100644
|
||||||
|
--- a/alsaloop/alsaloop.c
|
||||||
|
+++ b/alsaloop/alsaloop.c
|
||||||
|
@@ -31,6 +31,7 @@
|
||||||
|
#include <math.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
+#include <sys/signal.h>
|
||||||
|
#include "alsaloop.h"
|
||||||
|
|
||||||
|
struct loopback_thread {
|
||||||
|
@@ -42,6 +43,7 @@ struct loopback_thread {
|
||||||
|
snd_output_t *output;
|
||||||
|
};
|
||||||
|
|
||||||
|
+int quit = 0;
|
||||||
|
int verbose = 0;
|
||||||
|
int workarounds = 0;
|
||||||
|
int daemonize = 0;
|
||||||
|
@@ -50,6 +52,10 @@ struct loopback **loopbacks = NULL;
|
||||||
|
int loopbacks_count = 0;
|
||||||
|
char **my_argv = NULL;
|
||||||
|
int my_argc = 0;
|
||||||
|
+struct loopback_thread *threads;
|
||||||
|
+int threads_count = 0;
|
||||||
|
+pthread_t main_job;
|
||||||
|
+int arg_default_xrun = 0;
|
||||||
|
|
||||||
|
static void my_exit(struct loopback_thread *thread, int exitcode)
|
||||||
|
{
|
||||||
|
@@ -118,6 +124,7 @@ static int create_loopback(struct loopback **_handle,
|
||||||
|
handle->loop_time = ~0UL;
|
||||||
|
handle->loop_limit = ~0ULL;
|
||||||
|
handle->output = output;
|
||||||
|
+ handle->state = output;
|
||||||
|
#ifdef USE_SAMPLERATE
|
||||||
|
handle->src_enable = 1;
|
||||||
|
handle->src_converter_type = SRC_SINC_BEST_QUALITY;
|
||||||
|
@@ -185,6 +192,7 @@ void help(void)
|
||||||
|
"-e,--effect apply an effect (bandpass filter sweep)\n"
|
||||||
|
"-v,--verbose verbose mode (more -v means more verbose)\n"
|
||||||
|
"-w,--workaround use workaround (serialopen)\n"
|
||||||
|
+"-U,--xrun xrun profiling\n"
|
||||||
|
);
|
||||||
|
printf("\nRecognized sample formats are:");
|
||||||
|
for (k = 0; k < SND_PCM_FORMAT_LAST; ++k) {
|
||||||
|
@@ -326,7 +334,8 @@ static int add_oss_mixers(struct loopback *loop,
|
||||||
|
|
||||||
|
static int parse_config_file(const char *file, snd_output_t *output);
|
||||||
|
|
||||||
|
-static int parse_config(int argc, char *argv[], snd_output_t *output)
|
||||||
|
+static int parse_config(int argc, char *argv[], snd_output_t *output,
|
||||||
|
+ int cmdline)
|
||||||
|
{
|
||||||
|
struct option long_option[] =
|
||||||
|
{
|
||||||
|
@@ -356,6 +365,7 @@ static int parse_config(int argc, char *argv[], snd_output_t *output)
|
||||||
|
{"mixer", 1, NULL, 'm'},
|
||||||
|
{"ossmixer", 1, NULL, 'O'},
|
||||||
|
{"workaround", 1, NULL, 'w'},
|
||||||
|
+ {"xrun", 0, NULL, 'U'},
|
||||||
|
{NULL, 0, NULL, 0},
|
||||||
|
};
|
||||||
|
int err, morehelp;
|
||||||
|
@@ -384,12 +394,13 @@ static int parse_config(int argc, char *argv[], snd_output_t *output)
|
||||||
|
int arg_mixers_count = 0;
|
||||||
|
char *arg_ossmixers[MAX_MIXERS];
|
||||||
|
int arg_ossmixers_count = 0;
|
||||||
|
+ int arg_xrun = arg_default_xrun;
|
||||||
|
|
||||||
|
morehelp = 0;
|
||||||
|
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:",
|
||||||
|
+ "hdg:P:C:X:Y:l:t:F:f:c:r:s:benvA:S:a:m:T:O:w:U",
|
||||||
|
long_option, NULL)) < 0)
|
||||||
|
break;
|
||||||
|
switch (c) {
|
||||||
|
@@ -533,6 +544,11 @@ static int parse_config(int argc, char *argv[], snd_output_t *output)
|
||||||
|
if (strcasecmp(optarg, "serialopen") == 0)
|
||||||
|
workarounds |= WORKAROUND_SERIALOPEN;
|
||||||
|
break;
|
||||||
|
+ case 'U':
|
||||||
|
+ arg_xrun = 1;
|
||||||
|
+ if (cmdline)
|
||||||
|
+ arg_default_xrun = 1;
|
||||||
|
+ break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -570,6 +586,7 @@ static int parse_config(int argc, char *argv[], snd_output_t *output)
|
||||||
|
loop->sync = arg_sync;
|
||||||
|
loop->slave = arg_slave;
|
||||||
|
loop->thread = arg_thread;
|
||||||
|
+ loop->xrun = arg_xrun;
|
||||||
|
err = add_mixers(loop, arg_mixers, arg_mixers_count);
|
||||||
|
if (err < 0) {
|
||||||
|
logit(LOG_CRIT, "Unable to add mixer controls.\n");
|
||||||
|
@@ -656,7 +673,7 @@ static int parse_config_file(const char *file, snd_output_t *output)
|
||||||
|
optind = opterr = 1;
|
||||||
|
optopt = '?';
|
||||||
|
|
||||||
|
- err = parse_config(argc, argv, output);
|
||||||
|
+ err = parse_config(argc, argv, output, 0);
|
||||||
|
__next:
|
||||||
|
if (err < 0)
|
||||||
|
break;
|
||||||
|
@@ -698,7 +715,7 @@ static void thread_job1(void *_data)
|
||||||
|
logit(LOG_CRIT, "Poll FDs allocation failed.\n");
|
||||||
|
my_exit(thread, EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
- while (1) {
|
||||||
|
+ while (!quit) {
|
||||||
|
struct timeval tv1, tv2;
|
||||||
|
for (i = j = 0; i < thread->loopbacks_count; i++) {
|
||||||
|
err = pcmjob_pollfds_init(thread->loopbacks[i], &pfds[j]);
|
||||||
|
@@ -711,12 +728,16 @@ static void thread_job1(void *_data)
|
||||||
|
if (verbose > 10)
|
||||||
|
gettimeofday(&tv1, NULL);
|
||||||
|
err = poll(pfds, j, -1);
|
||||||
|
+ if (err < 0)
|
||||||
|
+ err = -errno;
|
||||||
|
if (verbose > 10) {
|
||||||
|
gettimeofday(&tv2, NULL);
|
||||||
|
snd_output_printf(output, "pool took %lius\n", timediff(tv2, tv1));
|
||||||
|
}
|
||||||
|
if (err < 0) {
|
||||||
|
- logit(LOG_CRIT, "Poll failed.\n");
|
||||||
|
+ if (err == -EINTR || err == -ERESTART)
|
||||||
|
+ continue;
|
||||||
|
+ logit(LOG_CRIT, "Poll failed: %s\n", strerror(-err));
|
||||||
|
my_exit(thread, EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
for (i = j = 0; i < thread->loopbacks_count; i++) {
|
||||||
|
@@ -745,18 +766,58 @@ static void thread_job(struct loopback_thread *thread)
|
||||||
|
(void *) thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
+static void send_to_all(int sig)
|
||||||
|
+{
|
||||||
|
+ struct loopback_thread *thread;
|
||||||
|
+ int i;
|
||||||
|
+
|
||||||
|
+ for (i = 0; i < threads_count; i++) {
|
||||||
|
+ thread = &threads[i];
|
||||||
|
+ if (thread->threaded)
|
||||||
|
+ pthread_kill(thread->thread, sig);
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void signal_handler(int sig)
|
||||||
|
+{
|
||||||
|
+ quit = 1;
|
||||||
|
+ send_to_all(SIGUSR2);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void signal_handler_state(int sig)
|
||||||
|
+{
|
||||||
|
+ pthread_t self = pthread_self();
|
||||||
|
+ struct loopback_thread *thread;
|
||||||
|
+ int i, j;
|
||||||
|
+
|
||||||
|
+ if (pthread_equal(main_job, self))
|
||||||
|
+ send_to_all(SIGUSR1);
|
||||||
|
+ for (i = 0; i < threads_count; i++) {
|
||||||
|
+ thread = &threads[i];
|
||||||
|
+ if (thread->thread == self) {
|
||||||
|
+ for (j = 0; j < thread->loopbacks_count; j++)
|
||||||
|
+ pcmjob_state(thread->loopbacks[j]);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ signal(sig, signal_handler_state);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void signal_handler_ignore(int sig)
|
||||||
|
+{
|
||||||
|
+ signal(sig, signal_handler_ignore);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
snd_output_t *output;
|
||||||
|
int i, j, k, l, err;
|
||||||
|
- struct loopback_thread *threads;
|
||||||
|
|
||||||
|
err = snd_output_stdio_attach(&output, stdout, 0);
|
||||||
|
if (err < 0) {
|
||||||
|
logit(LOG_CRIT, "Output failed: %s\n", snd_strerror(err));
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
- err = parse_config(argc, argv, output);
|
||||||
|
+ err = parse_config(argc, argv, output, 1);
|
||||||
|
if (err < 0) {
|
||||||
|
logit(LOG_CRIT, "Unable to parse arguments or configuration...\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
@@ -825,12 +886,20 @@ int main(int argc, char *argv[])
|
||||||
|
if (loopbacks[i]->thread == k)
|
||||||
|
threads[k].loopbacks[l++] = loopbacks[i];
|
||||||
|
}
|
||||||
|
-
|
||||||
|
- for (k = 0; k < j; k++)
|
||||||
|
+ threads_count = j;
|
||||||
|
+ main_job = pthread_self();
|
||||||
|
+
|
||||||
|
+ signal(SIGINT, signal_handler);
|
||||||
|
+ signal(SIGTERM, signal_handler);
|
||||||
|
+ signal(SIGABRT, signal_handler);
|
||||||
|
+ signal(SIGUSR1, signal_handler_state);
|
||||||
|
+ signal(SIGUSR2, signal_handler_ignore);
|
||||||
|
+
|
||||||
|
+ for (k = 0; k < threads_count; k++)
|
||||||
|
thread_job(&threads[k]);
|
||||||
|
|
||||||
|
if (j > 1) {
|
||||||
|
- for (k = 0; k < j; k++)
|
||||||
|
+ for (k = 0; k < threads_count; k++)
|
||||||
|
pthread_join(threads[k].thread, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/alsaloop/alsaloop.h b/alsaloop/alsaloop.h
|
||||||
|
index 7516807..839fc6d 100644
|
||||||
|
--- a/alsaloop/alsaloop.h
|
||||||
|
+++ b/alsaloop/alsaloop.h
|
||||||
|
@@ -95,6 +95,7 @@ struct loopback_handle {
|
||||||
|
unsigned int channels;
|
||||||
|
unsigned int buffer_size;
|
||||||
|
unsigned int period_size;
|
||||||
|
+ snd_pcm_uframes_t avail_min;
|
||||||
|
unsigned int buffer_size_req;
|
||||||
|
unsigned int period_size_req;
|
||||||
|
unsigned int frame_size;
|
||||||
|
@@ -130,12 +131,13 @@ struct loopback {
|
||||||
|
char *id;
|
||||||
|
struct loopback_handle *capt;
|
||||||
|
struct loopback_handle *play;
|
||||||
|
- snd_pcm_uframes_t latency; /* final latency */
|
||||||
|
- unsigned int latency_req; /* in frames / 2 */
|
||||||
|
- unsigned int latency_reqtime; /* in us / 2 */
|
||||||
|
+ snd_pcm_uframes_t latency; /* final latency in frames */
|
||||||
|
+ unsigned int latency_req; /* in frames */
|
||||||
|
+ unsigned int latency_reqtime; /* in us */
|
||||||
|
unsigned long loop_time; /* ~0 = unlimited (in seconds) */
|
||||||
|
unsigned long long loop_limit; /* ~0 = unlimited (in frames) */
|
||||||
|
snd_output_t *output;
|
||||||
|
+ snd_output_t *state;
|
||||||
|
int pollfd_count;
|
||||||
|
int active_pollfd_count;
|
||||||
|
unsigned int linked:1; /* linked streams */
|
||||||
|
@@ -153,6 +155,17 @@ struct loopback {
|
||||||
|
unsigned int total_queued_count;
|
||||||
|
snd_timestamp_t tstamp_start;
|
||||||
|
snd_timestamp_t tstamp_end;
|
||||||
|
+ /* xrun profiling */
|
||||||
|
+ unsigned int xrun:1; /* xrun profiling */
|
||||||
|
+ snd_timestamp_t xrun_last_update;
|
||||||
|
+ snd_timestamp_t xrun_last_wake0;
|
||||||
|
+ snd_timestamp_t xrun_last_wake;
|
||||||
|
+ snd_timestamp_t xrun_last_check0;
|
||||||
|
+ snd_timestamp_t xrun_last_check;
|
||||||
|
+ snd_pcm_sframes_t xrun_last_pdelay;
|
||||||
|
+ snd_pcm_sframes_t xrun_last_cdelay;
|
||||||
|
+ long xrun_max_proctime;
|
||||||
|
+ double xrun_max_missing;
|
||||||
|
/* control mixer */
|
||||||
|
struct loopback_mixer *controls;
|
||||||
|
struct loopback_ossmixer *oss_controls;
|
||||||
|
@@ -190,6 +203,7 @@ int pcmjob_start(struct loopback *loop);
|
||||||
|
int pcmjob_stop(struct loopback *loop);
|
||||||
|
int pcmjob_pollfds_init(struct loopback *loop, struct pollfd *fds);
|
||||||
|
int pcmjob_pollfds_handle(struct loopback *loop, struct pollfd *fds);
|
||||||
|
+void pcmjob_state(struct loopback *loop);
|
||||||
|
|
||||||
|
int control_parse_id(const char *str, snd_ctl_elem_id_t *id);
|
||||||
|
int control_id_match(snd_ctl_elem_id_t *id1, snd_ctl_elem_id_t *id2);
|
||||||
|
diff --git a/alsaloop/pcmjob.c b/alsaloop/pcmjob.c
|
||||||
|
index 9d1bb01..0f1a853 100644
|
||||||
|
--- a/alsaloop/pcmjob.c
|
||||||
|
+++ b/alsaloop/pcmjob.c
|
||||||
|
@@ -34,6 +34,8 @@
|
||||||
|
#include <pthread.h>
|
||||||
|
#include "alsaloop.h"
|
||||||
|
|
||||||
|
+#define XRUN_PROFILE_UNKNOWN (-10000000)
|
||||||
|
+
|
||||||
|
static int set_rate_shift(struct loopback_handle *lhandle, double pitch);
|
||||||
|
static int get_rate(struct loopback_handle *lhandle);
|
||||||
|
|
||||||
|
@@ -50,6 +52,7 @@ static const char *sync_types[] = {
|
||||||
|
|
||||||
|
#define SRCTYPE(v) [SRC_##v] = "SRC_" #v
|
||||||
|
|
||||||
|
+#ifdef USE_SAMPLERATE
|
||||||
|
static const char *src_types[] = {
|
||||||
|
SRCTYPE(SINC_BEST_QUALITY),
|
||||||
|
SRCTYPE(SINC_MEDIUM_QUALITY),
|
||||||
|
@@ -57,6 +60,7 @@ static const char *src_types[] = {
|
||||||
|
SRCTYPE(ZERO_ORDER_HOLD),
|
||||||
|
SRCTYPE(LINEAR)
|
||||||
|
};
|
||||||
|
+#endif
|
||||||
|
|
||||||
|
static pthread_mutex_t pcm_open_mutex =
|
||||||
|
PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
|
||||||
|
@@ -78,6 +82,13 @@ static inline snd_pcm_uframes_t get_whole_latency(struct loopback *loop)
|
||||||
|
return loop->latency;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static inline unsigned long long
|
||||||
|
+ frames_to_time(struct loopback_handle *lhandle,
|
||||||
|
+ snd_pcm_uframes_t frames)
|
||||||
|
+{
|
||||||
|
+ return (frames * 1000000ULL) / lhandle->rate;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static inline snd_pcm_uframes_t time_to_frames(struct loopback_handle *lhandle,
|
||||||
|
unsigned long long time)
|
||||||
|
{
|
||||||
|
@@ -125,7 +136,11 @@ static int setparams_stream(struct loopback_handle *lhandle,
|
||||||
|
rrate = 0;
|
||||||
|
snd_pcm_hw_params_get_rate(params, &rrate, 0);
|
||||||
|
lhandle->rate = rrate;
|
||||||
|
- if (!lhandle->loopback->src_enable && (int)rrate != lhandle->rate) {
|
||||||
|
+ if (
|
||||||
|
+#ifdef USE_SAMPLERATE
|
||||||
|
+ !lhandle->loopback->src_enable &&
|
||||||
|
+#endif
|
||||||
|
+ (int)rrate != lhandle->rate) {
|
||||||
|
logit(LOG_CRIT, "Rate does not match (requested %iHz, got %iHz, resample %i)\n", lhandle->rate, rrate, lhandle->resample);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
@@ -247,6 +262,7 @@ static int setparams_set(struct loopback_handle *lhandle,
|
||||||
|
logit(LOG_CRIT, "Unable to set avail min for %s: %s\n", lhandle->id, snd_strerror(err));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
+ snd_pcm_sw_params_get_avail_min(swparams, &lhandle->avail_min);
|
||||||
|
err = snd_pcm_sw_params(handle, swparams);
|
||||||
|
if (err < 0) {
|
||||||
|
logit(LOG_CRIT, "Unable to set sw params for %s: %s\n", lhandle->id, snd_strerror(err));
|
||||||
|
@@ -316,11 +332,12 @@ static int setparams(struct loopback *loop, snd_pcm_uframes_t bufsize)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
-static void showlatency(struct loopback *loop, size_t latency, unsigned int rate)
|
||||||
|
+static void showlatency(snd_output_t *out, size_t latency, unsigned int rate,
|
||||||
|
+ char *prefix)
|
||||||
|
{
|
||||||
|
double d;
|
||||||
|
d = (double)latency / (double)rate;
|
||||||
|
- snd_output_printf(loop->output, "Latency %li frames, %.3fus, %.6fms (%.4fHz)\n", (long)latency, d * 1000000, d * 1000, (double)1 / d);
|
||||||
|
+ snd_output_printf(out, "%s %li frames, %.3fus, %.6fms (%.4fHz)\n", prefix, (long)latency, d * 1000000, d * 1000, (double)1 / d);
|
||||||
|
}
|
||||||
|
|
||||||
|
static long timediff(snd_timestamp_t t1, snd_timestamp_t t2)
|
||||||
|
@@ -328,11 +345,11 @@ static long timediff(snd_timestamp_t t1, snd_timestamp_t t2)
|
||||||
|
signed long l;
|
||||||
|
|
||||||
|
t1.tv_sec -= t2.tv_sec;
|
||||||
|
- l = (signed long) t1.tv_usec - (signed long) t2.tv_usec;
|
||||||
|
- if (l < 0) {
|
||||||
|
+ if (t1.tv_usec < t2.tv_usec) {
|
||||||
|
+ l = ((t1.tv_usec + 1000000) - t2.tv_usec) % 1000000;
|
||||||
|
t1.tv_sec--;
|
||||||
|
- l = -l;
|
||||||
|
- l %= 1000000;
|
||||||
|
+ } else {
|
||||||
|
+ l = t1.tv_usec - t2.tv_usec;
|
||||||
|
}
|
||||||
|
return (t1.tv_sec * 1000000) + l;
|
||||||
|
}
|
||||||
|
@@ -346,6 +363,56 @@ static int getcurtimestamp(snd_timestamp_t *ts)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static void xrun_profile0(struct loopback *loop)
|
||||||
|
+{
|
||||||
|
+ snd_pcm_sframes_t pdelay, cdelay;
|
||||||
|
+
|
||||||
|
+ if (snd_pcm_delay(loop->play->handle, &pdelay) >= 0 &&
|
||||||
|
+ snd_pcm_delay(loop->capt->handle, &cdelay) >= 0) {
|
||||||
|
+ getcurtimestamp(&loop->xrun_last_update);
|
||||||
|
+ loop->xrun_last_pdelay = pdelay;
|
||||||
|
+ loop->xrun_last_cdelay = cdelay;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void xrun_profile(struct loopback *loop)
|
||||||
|
+{
|
||||||
|
+ if (loop->xrun)
|
||||||
|
+ xrun_profile0(loop);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void xrun_stats0(struct loopback *loop)
|
||||||
|
+{
|
||||||
|
+ snd_timestamp_t t;
|
||||||
|
+ double expected, last, wake, check, queued = -1, proc, missing;
|
||||||
|
+
|
||||||
|
+ expected = ((double)loop->latency /
|
||||||
|
+ (double)loop->play->rate) * 1000;
|
||||||
|
+ getcurtimestamp(&t);
|
||||||
|
+ last = (double)timediff(t, loop->xrun_last_update) / 1000;
|
||||||
|
+ wake = (double)timediff(t, loop->xrun_last_wake) / 1000;
|
||||||
|
+ check = (double)timediff(t, loop->xrun_last_check) / 1000;
|
||||||
|
+ if (loop->xrun_last_pdelay != XRUN_PROFILE_UNKNOWN)
|
||||||
|
+ queued = (((double)loop->xrun_last_pdelay *
|
||||||
|
+ loop->play->pitch) /
|
||||||
|
+ (double)loop->play->rate) * 1000;
|
||||||
|
+ proc = (double)loop->xrun_max_proctime / 1000;
|
||||||
|
+ missing = last - queued;
|
||||||
|
+ if (loop->xrun_max_missing < missing)
|
||||||
|
+ loop->xrun_max_missing = missing;
|
||||||
|
+ loop->xrun_max_proctime = 0;
|
||||||
|
+ getcurtimestamp(&t);
|
||||||
|
+ logit(LOG_INFO, " last write before %.4fms, queued %.4fms -> missing %.4fms\n", last, queued, missing);
|
||||||
|
+ logit(LOG_INFO, " expected %.4fms, processing %.4fms, max missing %.4fms\n", expected, proc, loop->xrun_max_missing);
|
||||||
|
+ logit(LOG_INFO, " last wake before %.4fms, last check before %.4fms\n", wake, check);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void xrun_stats(struct loopback *loop)
|
||||||
|
+{
|
||||||
|
+ if (loop->xrun)
|
||||||
|
+ xrun_stats0(loop);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static inline snd_pcm_uframes_t buf_avail(struct loopback_handle *lhandle)
|
||||||
|
{
|
||||||
|
return lhandle->buf_size - lhandle->buf_count;
|
||||||
|
@@ -495,11 +562,13 @@ static int xrun(struct loopback_handle *lhandle)
|
||||||
|
|
||||||
|
if (lhandle == lhandle->loopback->play) {
|
||||||
|
logit(LOG_DEBUG, "underrun for %s\n", lhandle->id);
|
||||||
|
+ xrun_stats(lhandle->loopback);
|
||||||
|
if ((err = snd_pcm_prepare(lhandle->handle)) < 0)
|
||||||
|
return err;
|
||||||
|
lhandle->xrun_pending = 1;
|
||||||
|
} else {
|
||||||
|
logit(LOG_DEBUG, "overrun for %s\n", lhandle->id);
|
||||||
|
+ xrun_stats(lhandle->loopback);
|
||||||
|
if ((err = snd_pcm_prepare(lhandle->handle)) < 0)
|
||||||
|
return err;
|
||||||
|
lhandle->xrun_pending = 1;
|
||||||
|
@@ -622,6 +691,7 @@ static int writeit(struct loopback_handle *lhandle)
|
||||||
|
fwrite(lhandle->buf + lhandle->buf_pos * lhandle->frame_size,
|
||||||
|
r, lhandle->frame_size, lhandle->loopback->pfile);
|
||||||
|
#endif
|
||||||
|
+ xrun_profile(lhandle->loopback);
|
||||||
|
res += r;
|
||||||
|
lhandle->counter += r;
|
||||||
|
lhandle->buf_count -= r;
|
||||||
|
@@ -735,9 +805,17 @@ static int xrun_sync(struct loopback *loop)
|
||||||
|
loop->pitch_diff = loop->pitch_diff_min = loop->pitch_diff_max = 0;
|
||||||
|
if (verbose > 6) {
|
||||||
|
snd_output_printf(loop->output,
|
||||||
|
- "sync: cdelay=%li(%li), pdelay=%li(%li), fill=%li (delay=%li), src_out=%li\n",
|
||||||
|
+ "sync: cdelay=%li(%li), pdelay=%li(%li), fill=%li (delay=%li)"
|
||||||
|
+#ifdef USE_SAMPLERATE
|
||||||
|
+ ", src_out=%li"
|
||||||
|
+#endif
|
||||||
|
+ "\n",
|
||||||
|
(long)cdelay, (long)cdelay1, (long)pdelay, (long)pdelay1,
|
||||||
|
- (long)fill, (long)delay1, (long)loop->src_out_frames);
|
||||||
|
+ (long)fill, (long)delay1
|
||||||
|
+#ifdef USE_SAMPLERATE
|
||||||
|
+ , (long)loop->src_out_frames
|
||||||
|
+#endif
|
||||||
|
+ );
|
||||||
|
snd_output_printf(loop->output,
|
||||||
|
"sync: cbufcount=%li, pbufcount=%li\n",
|
||||||
|
(long)capt->buf_count, (long)play->buf_count);
|
||||||
|
@@ -1112,10 +1190,7 @@ static int init_handle(struct loopback_handle *lhandle, int alloc)
|
||||||
|
lhandle->frame_size = (snd_pcm_format_width(lhandle->format) / 8) *
|
||||||
|
lhandle->channels;
|
||||||
|
lhandle->sync_point = lhandle->rate * 15; /* every 15 seconds */
|
||||||
|
- lat = lhandle->loopback->latency_req;
|
||||||
|
- if (lat == 0)
|
||||||
|
- lat = time_to_frames(lhandle,
|
||||||
|
- lhandle->loopback->latency_reqtime);
|
||||||
|
+ lat = lhandle->loopback->latency;
|
||||||
|
if (lhandle->buffer_size > lat)
|
||||||
|
lat = lhandle->buffer_size;
|
||||||
|
lhandle->buf_size = lat * 2;
|
||||||
|
@@ -1152,8 +1227,6 @@ int pcmjob_init(struct loopback *loop)
|
||||||
|
#ifdef USE_SAMPLERATE
|
||||||
|
if (loop->sync == SYNC_TYPE_AUTO && loop->src_enable)
|
||||||
|
loop->sync = SYNC_TYPE_SAMPLERATE;
|
||||||
|
-#else
|
||||||
|
- loop->src_enable = 0;
|
||||||
|
#endif
|
||||||
|
if (loop->sync == SYNC_TYPE_AUTO)
|
||||||
|
loop->sync = SYNC_TYPE_SIMPLE;
|
||||||
|
@@ -1270,14 +1343,16 @@ int pcmjob_start(struct loopback *loop)
|
||||||
|
}
|
||||||
|
loop->reinit = 0;
|
||||||
|
loop->use_samplerate = 0;
|
||||||
|
- loop->latency = loop->latency_req;
|
||||||
|
- if (loop->latency == 0)
|
||||||
|
- loop->latency = time_to_frames(loop->play,
|
||||||
|
- loop->latency_reqtime);
|
||||||
|
+ if (loop->latency_req) {
|
||||||
|
+ loop->latency_reqtime = frames_to_time(loop->play,
|
||||||
|
+ loop->latency_req);
|
||||||
|
+ loop->latency_req = 0;
|
||||||
|
+ }
|
||||||
|
+ loop->latency = time_to_frames(loop->play, loop->latency_reqtime);
|
||||||
|
if ((err = setparams(loop, loop->latency/2)) < 0)
|
||||||
|
goto __error;
|
||||||
|
if (verbose)
|
||||||
|
- showlatency(loop, loop->latency, loop->play->rate_req);
|
||||||
|
+ showlatency(loop->output, loop->latency, loop->play->rate, "Latency");
|
||||||
|
if (loop->play->access == loop->capt->access &&
|
||||||
|
loop->play->format == loop->capt->format &&
|
||||||
|
loop->play->rate == loop->capt->rate &&
|
||||||
|
@@ -1402,6 +1477,12 @@ int pcmjob_start(struct loopback *loop)
|
||||||
|
goto __error;
|
||||||
|
}
|
||||||
|
loop->running = 1;
|
||||||
|
+ if (loop->xrun) {
|
||||||
|
+ getcurtimestamp(&loop->xrun_last_update);
|
||||||
|
+ loop->xrun_last_pdelay = XRUN_PROFILE_UNKNOWN;
|
||||||
|
+ loop->xrun_last_cdelay = XRUN_PROFILE_UNKNOWN;
|
||||||
|
+ loop->xrun_max_proctime = 0;
|
||||||
|
+ }
|
||||||
|
if ((err = snd_pcm_start(loop->capt->handle)) < 0) {
|
||||||
|
logit(LOG_CRIT, "pcm start %s error: %s\n", loop->capt->id, snd_strerror(err));
|
||||||
|
goto __error;
|
||||||
|
@@ -1568,7 +1649,7 @@ int pcmjob_pollfds_handle(struct loopback *loop, struct pollfd *fds)
|
||||||
|
|
||||||
|
if (verbose > 11)
|
||||||
|
snd_output_printf(loop->output, "%s: pollfds handle\n", loop->id);
|
||||||
|
- if (verbose > 13)
|
||||||
|
+ if (verbose > 13 || loop->xrun)
|
||||||
|
getcurtimestamp(&loop->tstamp_start);
|
||||||
|
if (verbose > 12) {
|
||||||
|
snd_pcm_sframes_t pdelay, cdelay;
|
||||||
|
@@ -1595,6 +1676,14 @@ int pcmjob_pollfds_handle(struct loopback *loop, struct pollfd *fds)
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
idx += capt->pollfd_count;
|
||||||
|
+ if (loop->xrun) {
|
||||||
|
+ if (prevents || crevents) {
|
||||||
|
+ loop->xrun_last_wake = loop->xrun_last_wake0;
|
||||||
|
+ loop->xrun_last_wake0 = loop->tstamp_start;
|
||||||
|
+ }
|
||||||
|
+ loop->xrun_last_check = loop->xrun_last_check0;
|
||||||
|
+ loop->xrun_last_check0 = loop->tstamp_start;
|
||||||
|
+ }
|
||||||
|
} else {
|
||||||
|
prevents = crevents = 0;
|
||||||
|
}
|
||||||
|
@@ -1717,9 +1806,54 @@ int pcmjob_pollfds_handle(struct loopback *loop, struct pollfd *fds)
|
||||||
|
snd_output_printf(loop->output, "%s: end delay %li / %li / %li\n", capt->id, cdelay, capt->buf_size, capt->buf_count);
|
||||||
|
}
|
||||||
|
__pcm_end:
|
||||||
|
- if (verbose > 13) {
|
||||||
|
+ if (verbose > 13 || loop->xrun) {
|
||||||
|
+ long diff;
|
||||||
|
getcurtimestamp(&loop->tstamp_end);
|
||||||
|
- snd_output_printf(loop->output, "%s: processing time %lius\n", capt->id, timediff(loop->tstamp_end, loop->tstamp_start));
|
||||||
|
+ diff = timediff(loop->tstamp_end, loop->tstamp_start);
|
||||||
|
+ if (verbose > 13)
|
||||||
|
+ snd_output_printf(loop->output, "%s: processing time %lius\n", loop->id, diff);
|
||||||
|
+ if (loop->xrun && loop->xrun_max_proctime < diff)
|
||||||
|
+ loop->xrun_max_proctime = diff;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+#define OUT(args...) \
|
||||||
|
+ snd_output_printf(loop->state, ##args)
|
||||||
|
+
|
||||||
|
+static pthread_mutex_t state_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
+
|
||||||
|
+static void show_handle(struct loopback_handle *lhandle, const char *id)
|
||||||
|
+{
|
||||||
|
+ struct loopback *loop = lhandle->loopback;
|
||||||
|
+
|
||||||
|
+ OUT(" %s: %s:\n", id, lhandle->id);
|
||||||
|
+ OUT(" device = '%s', ctldev '%s'\n", lhandle->device, lhandle->ctldev);
|
||||||
|
+ OUT(" card_number = %i\n", lhandle->card_number);
|
||||||
|
+ if (!loop->running)
|
||||||
|
+ return;
|
||||||
|
+ OUT(" access = %s, format = %s, rate = %u, channels = %u\n", snd_pcm_access_name(lhandle->access), snd_pcm_format_name(lhandle->format), lhandle->rate, lhandle->channels);
|
||||||
|
+ OUT(" buffer_size = %u, period_size = %u, avail_min = %li\n", lhandle->buffer_size, lhandle->period_size, lhandle->avail_min);
|
||||||
|
+ OUT(" xrun_pending = %i\n", lhandle->xrun_pending);
|
||||||
|
+ OUT(" buf_size = %li, buf_pos = %li, buf_count = %li, buf_over = %li\n", lhandle->buf_size, lhandle->buf_pos, lhandle->buf_count, lhandle->buf_over);
|
||||||
|
+ OUT(" pitch = %.8f\n", lhandle->pitch);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void pcmjob_state(struct loopback *loop)
|
||||||
|
+{
|
||||||
|
+ pthread_t self = pthread_self();
|
||||||
|
+ pthread_mutex_lock(&state_mutex);
|
||||||
|
+ OUT("State dump for thread %p job %i: %s:\n", (void *)self, loop->thread, loop->id);
|
||||||
|
+ OUT(" running = %i\n", loop->running);
|
||||||
|
+ OUT(" sync = %i\n", loop->sync);
|
||||||
|
+ OUT(" slave = %i\n", loop->slave);
|
||||||
|
+ if (!loop->running)
|
||||||
|
+ goto __skip;
|
||||||
|
+ OUT(" pollfd_count = %i\n", loop->pollfd_count);
|
||||||
|
+ OUT(" pitch = %.8f, delta = %.8f, diff = %li, min = %li, max = %li\n", loop->pitch, loop->pitch_delta, loop->pitch_diff, loop->pitch_diff_min, loop->pitch_diff_max);
|
||||||
|
+ OUT(" use_samplerate = %i\n", loop->use_samplerate);
|
||||||
|
+ __skip:
|
||||||
|
+ show_handle(loop->play, "playback");
|
||||||
|
+ show_handle(loop->capt, "capture");
|
||||||
|
+ pthread_mutex_unlock(&state_mutex);
|
||||||
|
+}
|
||||||
|
diff --git a/alsaloop/test.sh b/alsaloop/test.sh
|
||||||
|
index e3d81b1..ff9aa4e 100755
|
||||||
|
--- a/alsaloop/test.sh
|
||||||
|
+++ b/alsaloop/test.sh
|
||||||
|
@@ -35,20 +35,19 @@ EOF
|
||||||
|
test3() {
|
||||||
|
echo "TEST3"
|
||||||
|
cat > $CFGFILE <<EOF
|
||||||
|
--C hw:1,0,0 -P plug:dmix:0 --tlatency 50000 --thread 0 \
|
||||||
|
+-C hw:1,0,0 -P plug:dmix:0 --tlatency 30000 --thread 0 \
|
||||||
|
--mixer "name='Master Playback Volume'@name='Master Playback Volume'" \
|
||||||
|
--mixer "name='Master Playback Switch'@name='Master Playback Switch'" \
|
||||||
|
--mixer "name='PCM Playback Volume'" \
|
||||||
|
--ossmixer "name=Master@VOLUME"
|
||||||
|
--C hw:1,0,1 -P plug:dmix:0 --tlatency 50000 --thread 1
|
||||||
|
--C hw:1,0,2 -P plug:dmix:0 --tlatency 50000 --thread 2
|
||||||
|
--C hw:1,0,3 -P plug:dmix:0 --tlatency 50000 --thread 3
|
||||||
|
--C hw:1,0,4 -P plug:dmix:0 --tlatency 50000 --thread 4
|
||||||
|
--C hw:1,0,5 -P plug:dmix:0 --tlatency 50000 --thread 5
|
||||||
|
--C hw:1,0,6 -P plug:dmix:0 --tlatency 50000 --thread 6
|
||||||
|
--C hw:1,0,7 -P plug:dmix:0 --tlatency 50000 --thread 7
|
||||||
|
+-C hw:1,0,1 -P plug:dmix:0 --tlatency 30000 --thread 1
|
||||||
|
+-C hw:1,0,2 -P plug:dmix:0 --tlatency 30000 --thread 2
|
||||||
|
+-C hw:1,0,3 -P plug:dmix:0 --tlatency 30000 --thread 3
|
||||||
|
+-C hw:1,0,4 -P plug:dmix:0 --tlatency 30000 --thread 4
|
||||||
|
+-C hw:1,0,5 -P plug:dmix:0 --tlatency 30000 --thread 5
|
||||||
|
+-C hw:1,0,6 -P plug:dmix:0 --tlatency 30000 --thread 6
|
||||||
|
+-C hw:1,0,7 -P plug:dmix:0 --tlatency 30000 --thread 7
|
||||||
|
EOF
|
||||||
|
- LD_PRELOAD="/home/perex/alsa/alsa-lib/src/.libs/libasound.so" \
|
||||||
|
$DBG ./alsaloop --config $CFGFILE $ARGS
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -75,11 +74,20 @@ EOF
|
||||||
|
$DBG ./alsaloop --config $CFGFILE $ARGS
|
||||||
|
}
|
||||||
|
|
||||||
|
+sigusr1() {
|
||||||
|
+ pid=$(ps ax | grep alsaloop | grep -v grep | colrm 7 255)
|
||||||
|
+ if test -n "$pid"; then
|
||||||
|
+ echo "Killing alsaloop $pid..."
|
||||||
|
+ kill -SIGUSR1 $pid
|
||||||
|
+ fi
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
case "$1" in
|
||||||
|
test1) shift; ARGS="$@"; test1 ;;
|
||||||
|
test2) shift; ARGS="$@"; test2 ;;
|
||||||
|
test3) shift; ARGS="$@"; test3 ;;
|
||||||
|
test4) shift; ARGS="$@"; test4 ;;
|
||||||
|
test5) shift; ARGS="$@"; test5 ;;
|
||||||
|
+usr|sig*) sigusr1 ;;
|
||||||
|
*) ARGS="$@"; test1 ;;
|
||||||
|
esac
|
||||||
|
--
|
||||||
|
1.7.3.1
|
||||||
|
|
30
0029-alsaloop-add-U-xrun-to-alsaloop.1-man-page.patch
Normal file
30
0029-alsaloop-add-U-xrun-to-alsaloop.1-man-page.patch
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
From b68986fb4a946ef736295d3b2f24f1e6fab1e77d Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jaroslav Kysela <perex@perex.cz>
|
||||||
|
Date: Wed, 13 Oct 2010 23:41:29 +0200
|
||||||
|
Subject: [PATCH 29/38] alsaloop: add -U/--xrun to alsaloop.1 man page
|
||||||
|
|
||||||
|
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
|
||||||
|
---
|
||||||
|
alsaloop/alsaloop.1 | 6 ++++++
|
||||||
|
1 files changed, 6 insertions(+), 0 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/alsaloop/alsaloop.1 b/alsaloop/alsaloop.1
|
||||||
|
index 0b57b59..65edba1 100644
|
||||||
|
--- a/alsaloop/alsaloop.1
|
||||||
|
+++ b/alsaloop/alsaloop.1
|
||||||
|
@@ -184,6 +184,12 @@ Known OSS attributes:
|
||||||
|
Verbose mode. Use multiple times to increase verbosity.
|
||||||
|
|
||||||
|
|
||||||
|
+.TP
|
||||||
|
+\fI\-U\fP | \fI\-\-xrun\fP
|
||||||
|
+
|
||||||
|
+Verbose xrun profiling.
|
||||||
|
+
|
||||||
|
+
|
||||||
|
.SH EXAMPLES
|
||||||
|
|
||||||
|
.TP
|
||||||
|
--
|
||||||
|
1.7.3.1
|
||||||
|
|
371
0030-alsaloop-fixes-added-W-wake-option.patch
Normal file
371
0030-alsaloop-fixes-added-W-wake-option.patch
Normal file
@ -0,0 +1,371 @@
|
|||||||
|
From 513a9c7ad179e9786a7d2ff0aa651d42f9674697 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jaroslav Kysela <perex@perex.cz>
|
||||||
|
Date: Thu, 14 Oct 2010 11:17:25 +0200
|
||||||
|
Subject: [PATCH 30/38] alsaloop: fixes, added -W/--wake option
|
||||||
|
|
||||||
|
- added -W/--wake option to reduce poll time
|
||||||
|
- another try to fix the avail_min parameter for playback
|
||||||
|
- fixed initial silence fill
|
||||||
|
|
||||||
|
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
|
||||||
|
---
|
||||||
|
alsaloop/alsaloop.1 | 4 ++
|
||||||
|
alsaloop/alsaloop.c | 20 +++++++++--
|
||||||
|
alsaloop/alsaloop.h | 4 ++
|
||||||
|
alsaloop/pcmjob.c | 90 ++++++++++++++++++++++++++++++++++++++-------------
|
||||||
|
alsaloop/test.sh | 17 +++++----
|
||||||
|
5 files changed, 101 insertions(+), 34 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/alsaloop/alsaloop.1 b/alsaloop/alsaloop.1
|
||||||
|
index 65edba1..048d1e0 100644
|
||||||
|
--- a/alsaloop/alsaloop.1
|
||||||
|
+++ b/alsaloop/alsaloop.1
|
||||||
|
@@ -189,6 +189,10 @@ Verbose mode. Use multiple times to increase verbosity.
|
||||||
|
|
||||||
|
Verbose xrun profiling.
|
||||||
|
|
||||||
|
+.TP
|
||||||
|
+\fI\-W <timeout>\fP | \fI\-\-wake=<timeout>\fP
|
||||||
|
+
|
||||||
|
+Set process wake timeout.
|
||||||
|
|
||||||
|
.SH EXAMPLES
|
||||||
|
|
||||||
|
diff --git a/alsaloop/alsaloop.c b/alsaloop/alsaloop.c
|
||||||
|
index 561fdd7..8710dd1 100644
|
||||||
|
--- a/alsaloop/alsaloop.c
|
||||||
|
+++ b/alsaloop/alsaloop.c
|
||||||
|
@@ -56,6 +56,7 @@ struct loopback_thread *threads;
|
||||||
|
int threads_count = 0;
|
||||||
|
pthread_t main_job;
|
||||||
|
int arg_default_xrun = 0;
|
||||||
|
+int arg_default_wake = 0;
|
||||||
|
|
||||||
|
static void my_exit(struct loopback_thread *thread, int exitcode)
|
||||||
|
{
|
||||||
|
@@ -193,6 +194,7 @@ void help(void)
|
||||||
|
"-v,--verbose verbose mode (more -v means more verbose)\n"
|
||||||
|
"-w,--workaround use workaround (serialopen)\n"
|
||||||
|
"-U,--xrun xrun profiling\n"
|
||||||
|
+"-W,--wake process wake timeout in ms\n"
|
||||||
|
);
|
||||||
|
printf("\nRecognized sample formats are:");
|
||||||
|
for (k = 0; k < SND_PCM_FORMAT_LAST; ++k) {
|
||||||
|
@@ -395,12 +397,13 @@ static int parse_config(int argc, char *argv[], snd_output_t *output,
|
||||||
|
char *arg_ossmixers[MAX_MIXERS];
|
||||||
|
int arg_ossmixers_count = 0;
|
||||||
|
int arg_xrun = arg_default_xrun;
|
||||||
|
+ int arg_wake = arg_default_wake;
|
||||||
|
|
||||||
|
morehelp = 0;
|
||||||
|
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:U",
|
||||||
|
+ "hdg:P:C:X:Y:l:t:F:f:c:r:s:benvA:S:a:m:T:O:w:UW:",
|
||||||
|
long_option, NULL)) < 0)
|
||||||
|
break;
|
||||||
|
switch (c) {
|
||||||
|
@@ -549,6 +552,11 @@ static int parse_config(int argc, char *argv[], snd_output_t *output,
|
||||||
|
if (cmdline)
|
||||||
|
arg_default_xrun = 1;
|
||||||
|
break;
|
||||||
|
+ case 'W':
|
||||||
|
+ arg_wake = atoi(optarg);
|
||||||
|
+ if (cmdline)
|
||||||
|
+ arg_default_wake = arg_wake;
|
||||||
|
+ break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -587,6 +595,7 @@ static int parse_config(int argc, char *argv[], snd_output_t *output,
|
||||||
|
loop->slave = arg_slave;
|
||||||
|
loop->thread = arg_thread;
|
||||||
|
loop->xrun = arg_xrun;
|
||||||
|
+ loop->wake = arg_wake;
|
||||||
|
err = add_mixers(loop, arg_mixers, arg_mixers_count);
|
||||||
|
if (err < 0) {
|
||||||
|
logit(LOG_CRIT, "Unable to add mixer controls.\n");
|
||||||
|
@@ -691,7 +700,7 @@ static void thread_job1(void *_data)
|
||||||
|
snd_output_t *output = thread->output;
|
||||||
|
struct pollfd *pfds = NULL;
|
||||||
|
int pfds_count = 0;
|
||||||
|
- int i, j, err;
|
||||||
|
+ int i, j, err, wake = 1000000;
|
||||||
|
|
||||||
|
setscheduler();
|
||||||
|
|
||||||
|
@@ -709,7 +718,12 @@ static void thread_job1(void *_data)
|
||||||
|
my_exit(thread, EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
pfds_count += thread->loopbacks[i]->pollfd_count;
|
||||||
|
+ j = thread->loopbacks[i]->wake;
|
||||||
|
+ if (j > 0 && j < wake)
|
||||||
|
+ wake = j;
|
||||||
|
}
|
||||||
|
+ if (wake >= 1000000)
|
||||||
|
+ wake = -1;
|
||||||
|
pfds = calloc(pfds_count, sizeof(struct pollfd));
|
||||||
|
if (pfds == NULL || pfds_count <= 0) {
|
||||||
|
logit(LOG_CRIT, "Poll FDs allocation failed.\n");
|
||||||
|
@@ -727,7 +741,7 @@ static void thread_job1(void *_data)
|
||||||
|
}
|
||||||
|
if (verbose > 10)
|
||||||
|
gettimeofday(&tv1, NULL);
|
||||||
|
- err = poll(pfds, j, -1);
|
||||||
|
+ err = poll(pfds, j, wake);
|
||||||
|
if (err < 0)
|
||||||
|
err = -errno;
|
||||||
|
if (verbose > 10) {
|
||||||
|
diff --git a/alsaloop/alsaloop.h b/alsaloop/alsaloop.h
|
||||||
|
index 839fc6d..e506427 100644
|
||||||
|
--- a/alsaloop/alsaloop.h
|
||||||
|
+++ b/alsaloop/alsaloop.h
|
||||||
|
@@ -146,6 +146,7 @@ struct loopback {
|
||||||
|
sync_type_t sync; /* type of sync */
|
||||||
|
slave_type_t slave;
|
||||||
|
int thread; /* thread number */
|
||||||
|
+ unsigned int wake;
|
||||||
|
/* statistics */
|
||||||
|
double pitch;
|
||||||
|
double pitch_delta;
|
||||||
|
@@ -164,6 +165,9 @@ struct loopback {
|
||||||
|
snd_timestamp_t xrun_last_check;
|
||||||
|
snd_pcm_sframes_t xrun_last_pdelay;
|
||||||
|
snd_pcm_sframes_t xrun_last_cdelay;
|
||||||
|
+ snd_pcm_uframes_t xrun_buf_pcount;
|
||||||
|
+ snd_pcm_uframes_t xrun_buf_ccount;
|
||||||
|
+ unsigned int xrun_out_frames;
|
||||||
|
long xrun_max_proctime;
|
||||||
|
double xrun_max_missing;
|
||||||
|
/* control mixer */
|
||||||
|
diff --git a/alsaloop/pcmjob.c b/alsaloop/pcmjob.c
|
||||||
|
index 0f1a853..6aa8bfe 100644
|
||||||
|
--- a/alsaloop/pcmjob.c
|
||||||
|
+++ b/alsaloop/pcmjob.c
|
||||||
|
@@ -83,16 +83,16 @@ static inline snd_pcm_uframes_t get_whole_latency(struct loopback *loop)
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned long long
|
||||||
|
- frames_to_time(struct loopback_handle *lhandle,
|
||||||
|
+ frames_to_time(unsigned int rate,
|
||||||
|
snd_pcm_uframes_t frames)
|
||||||
|
{
|
||||||
|
- return (frames * 1000000ULL) / lhandle->rate;
|
||||||
|
+ return (frames * 1000000ULL) / rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
-static inline snd_pcm_uframes_t time_to_frames(struct loopback_handle *lhandle,
|
||||||
|
+static inline snd_pcm_uframes_t time_to_frames(unsigned int rate,
|
||||||
|
unsigned long long time)
|
||||||
|
{
|
||||||
|
- return (time * lhandle->rate) / 1000000ULL;
|
||||||
|
+ return (time * rate) / 1000000ULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int setparams_stream(struct loopback_handle *lhandle,
|
||||||
|
@@ -245,12 +245,16 @@ static int setparams_set(struct loopback_handle *lhandle,
|
||||||
|
snd_output_printf(lhandle->loopback->output, "%s: avail_min1=%li\n", lhandle->id, val);
|
||||||
|
} else {
|
||||||
|
if (lhandle == lhandle->loopback->play) {
|
||||||
|
- val = bufsize / 2 + bufsize / 4 + bufsize / 8;
|
||||||
|
- if (val > buffer_size / 4)
|
||||||
|
- val = buffer_size / 4;
|
||||||
|
+ val = bufsize + bufsize / 2;
|
||||||
|
+ if (val < (period_size * 3) / 4)
|
||||||
|
+ val = (period_size * 3) / 4;
|
||||||
|
+ if (val > (buffer_size * 3) / 4)
|
||||||
|
+ val = (buffer_size * 3) / 4;
|
||||||
|
val = buffer_size - val;
|
||||||
|
} else {
|
||||||
|
val = bufsize / 2;
|
||||||
|
+ if (val < period_size / 2)
|
||||||
|
+ val = period_size / 2;
|
||||||
|
if (val > buffer_size / 4)
|
||||||
|
val = buffer_size / 4;
|
||||||
|
}
|
||||||
|
@@ -372,6 +376,11 @@ static void xrun_profile0(struct loopback *loop)
|
||||||
|
getcurtimestamp(&loop->xrun_last_update);
|
||||||
|
loop->xrun_last_pdelay = pdelay;
|
||||||
|
loop->xrun_last_cdelay = cdelay;
|
||||||
|
+ loop->xrun_buf_pcount = loop->play->buf_count;
|
||||||
|
+ loop->xrun_buf_ccount = loop->capt->buf_count;
|
||||||
|
+#ifdef USE_SAMPLERATE
|
||||||
|
+ loop->xrun_out_frames = loop->src_out_frames;
|
||||||
|
+#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -384,27 +393,45 @@ static inline void xrun_profile(struct loopback *loop)
|
||||||
|
static void xrun_stats0(struct loopback *loop)
|
||||||
|
{
|
||||||
|
snd_timestamp_t t;
|
||||||
|
- double expected, last, wake, check, queued = -1, proc, missing;
|
||||||
|
+ double expected, last, wake, check, queued = -1, proc, missing = -1;
|
||||||
|
+ double maxbuf, pfilled, cfilled, cqueued = -1, avail_min;
|
||||||
|
+ double sincejob;
|
||||||
|
|
||||||
|
expected = ((double)loop->latency /
|
||||||
|
- (double)loop->play->rate) * 1000;
|
||||||
|
+ (double)loop->play->rate_req) * 1000;
|
||||||
|
getcurtimestamp(&t);
|
||||||
|
last = (double)timediff(t, loop->xrun_last_update) / 1000;
|
||||||
|
wake = (double)timediff(t, loop->xrun_last_wake) / 1000;
|
||||||
|
check = (double)timediff(t, loop->xrun_last_check) / 1000;
|
||||||
|
+ sincejob = (double)timediff(t, loop->tstamp_start) / 1000;
|
||||||
|
if (loop->xrun_last_pdelay != XRUN_PROFILE_UNKNOWN)
|
||||||
|
- queued = (((double)loop->xrun_last_pdelay *
|
||||||
|
- loop->play->pitch) /
|
||||||
|
+ queued = ((double)loop->xrun_last_pdelay /
|
||||||
|
+ (double)loop->play->rate) * 1000;
|
||||||
|
+ if (loop->xrun_last_cdelay != XRUN_PROFILE_UNKNOWN)
|
||||||
|
+ cqueued = ((double)loop->xrun_last_cdelay /
|
||||||
|
+ (double)loop->capt->rate) * 1000;
|
||||||
|
+ maxbuf = ((double)loop->play->buffer_size /
|
||||||
|
(double)loop->play->rate) * 1000;
|
||||||
|
proc = (double)loop->xrun_max_proctime / 1000;
|
||||||
|
- missing = last - queued;
|
||||||
|
- if (loop->xrun_max_missing < missing)
|
||||||
|
+ pfilled = ((double)(loop->xrun_buf_pcount + loop->xrun_out_frames) /
|
||||||
|
+ (double)loop->play->rate) * 1000;
|
||||||
|
+ cfilled = ((double)loop->xrun_buf_ccount /
|
||||||
|
+ (double)loop->capt->rate) * 1000;
|
||||||
|
+ avail_min = (((double)loop->play->buffer_size -
|
||||||
|
+ (double)loop->play->avail_min ) /
|
||||||
|
+ (double)loop->play->rate) * 1000;
|
||||||
|
+ avail_min = expected - avail_min;
|
||||||
|
+ if (queued >= 0)
|
||||||
|
+ missing = last - queued;
|
||||||
|
+ if (missing >= 0 && loop->xrun_max_missing < missing)
|
||||||
|
loop->xrun_max_missing = missing;
|
||||||
|
loop->xrun_max_proctime = 0;
|
||||||
|
getcurtimestamp(&t);
|
||||||
|
- logit(LOG_INFO, " last write before %.4fms, queued %.4fms -> missing %.4fms\n", last, queued, missing);
|
||||||
|
+ logit(LOG_INFO, " last write before %.4fms, queued %.4fms/%.4fms -> missing %.4fms\n", last, queued, cqueued, missing);
|
||||||
|
logit(LOG_INFO, " expected %.4fms, processing %.4fms, max missing %.4fms\n", expected, proc, loop->xrun_max_missing);
|
||||||
|
- logit(LOG_INFO, " last wake before %.4fms, last check before %.4fms\n", wake, check);
|
||||||
|
+ logit(LOG_INFO, " last wake %.4fms, last check %.4fms, avail_min %.4fms\n", wake, check, avail_min);
|
||||||
|
+ logit(LOG_INFO, " max buf %.4fms, pfilled %.4fms, cfilled %.4fms\n", maxbuf, pfilled, cfilled);
|
||||||
|
+ logit(LOG_INFO, " job started before %.4fms\n", sincejob);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void xrun_stats(struct loopback *loop)
|
||||||
|
@@ -483,7 +510,14 @@ static void buf_add_src(struct loopback *loop)
|
||||||
|
count1 = count;
|
||||||
|
if (count1 + pos1 > capt->buf_size)
|
||||||
|
count1 = capt->buf_size - pos1;
|
||||||
|
- src_short_to_float_array((short *)(capt->buf +
|
||||||
|
+ if (capt->format == SND_PCM_FORMAT_S32)
|
||||||
|
+ src_int_to_float_array((int *)(capt->buf +
|
||||||
|
+ pos1 * capt->frame_size),
|
||||||
|
+ loop->src_data.data_in +
|
||||||
|
+ pos * capt->channels,
|
||||||
|
+ count1 * capt->channels);
|
||||||
|
+ else
|
||||||
|
+ src_short_to_float_array((short *)(capt->buf +
|
||||||
|
pos1 * capt->frame_size),
|
||||||
|
loop->src_data.data_in +
|
||||||
|
pos * capt->channels,
|
||||||
|
@@ -514,7 +548,14 @@ static void buf_add_src(struct loopback *loop)
|
||||||
|
count1 = buf_avail(play);
|
||||||
|
if (count1 == 0)
|
||||||
|
break;
|
||||||
|
- src_float_to_short_array(loop->src_data.data_out +
|
||||||
|
+ if (capt->format == SND_PCM_FORMAT_S32)
|
||||||
|
+ src_float_to_int_array(loop->src_data.data_out +
|
||||||
|
+ pos * play->channels,
|
||||||
|
+ (int *)(play->buf +
|
||||||
|
+ pos1 * play->frame_size),
|
||||||
|
+ count1 * play->channels);
|
||||||
|
+ else
|
||||||
|
+ src_float_to_short_array(loop->src_data.data_out +
|
||||||
|
pos * play->channels,
|
||||||
|
(short *)(play->buf +
|
||||||
|
pos1 * play->frame_size),
|
||||||
|
@@ -691,12 +732,12 @@ static int writeit(struct loopback_handle *lhandle)
|
||||||
|
fwrite(lhandle->buf + lhandle->buf_pos * lhandle->frame_size,
|
||||||
|
r, lhandle->frame_size, lhandle->loopback->pfile);
|
||||||
|
#endif
|
||||||
|
- xrun_profile(lhandle->loopback);
|
||||||
|
res += r;
|
||||||
|
lhandle->counter += r;
|
||||||
|
lhandle->buf_count -= r;
|
||||||
|
lhandle->buf_pos += r;
|
||||||
|
lhandle->buf_pos %= lhandle->buf_size;
|
||||||
|
+ xrun_profile(lhandle->loopback);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
@@ -919,6 +960,7 @@ static int xrun_sync(struct loopback *loop)
|
||||||
|
snd_output_printf(loop->output, "%s: sync verify: %li\n", loop->id, delay1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+ loop->xrun_max_proctime = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -1344,11 +1386,11 @@ int pcmjob_start(struct loopback *loop)
|
||||||
|
loop->reinit = 0;
|
||||||
|
loop->use_samplerate = 0;
|
||||||
|
if (loop->latency_req) {
|
||||||
|
- loop->latency_reqtime = frames_to_time(loop->play,
|
||||||
|
+ loop->latency_reqtime = frames_to_time(loop->play->rate_req,
|
||||||
|
loop->latency_req);
|
||||||
|
loop->latency_req = 0;
|
||||||
|
}
|
||||||
|
- loop->latency = time_to_frames(loop->play, loop->latency_reqtime);
|
||||||
|
+ loop->latency = time_to_frames(loop->play->rate_req, loop->latency_reqtime);
|
||||||
|
if ((err = setparams(loop, loop->latency/2)) < 0)
|
||||||
|
goto __error;
|
||||||
|
if (verbose)
|
||||||
|
@@ -1406,9 +1448,11 @@ int pcmjob_start(struct loopback *loop)
|
||||||
|
goto __error;
|
||||||
|
}
|
||||||
|
if (loop->use_samplerate) {
|
||||||
|
- if (loop->capt->format != SND_PCM_FORMAT_S16 ||
|
||||||
|
- loop->play->format != SND_PCM_FORMAT_S16) {
|
||||||
|
- logit(LOG_CRIT, "samplerate conversion supports only %s format (play=%s, capt=%s)\n", snd_pcm_format_name(SND_PCM_FORMAT_S16), snd_pcm_format_name(loop->play->format), snd_pcm_format_name(loop->capt->format));
|
||||||
|
+ if ((loop->capt->format != SND_PCM_FORMAT_S16 ||
|
||||||
|
+ loop->play->format != SND_PCM_FORMAT_S16) &&
|
||||||
|
+ (loop->capt->format != SND_PCM_FORMAT_S32 ||
|
||||||
|
+ loop->play->format != SND_PCM_FORMAT_S32)) {
|
||||||
|
+ logit(LOG_CRIT, "samplerate conversion supports only %s or %s formats (play=%s, capt=%s)\n", snd_pcm_format_name(SND_PCM_FORMAT_S16), snd_pcm_format_name(SND_PCM_FORMAT_S32), snd_pcm_format_name(loop->play->format), snd_pcm_format_name(loop->capt->format));
|
||||||
|
loop->use_samplerate = 0;
|
||||||
|
err = -EIO;
|
||||||
|
goto __error;
|
||||||
|
diff --git a/alsaloop/test.sh b/alsaloop/test.sh
|
||||||
|
index ff9aa4e..fac72b9 100755
|
||||||
|
--- a/alsaloop/test.sh
|
||||||
|
+++ b/alsaloop/test.sh
|
||||||
|
@@ -34,19 +34,20 @@ EOF
|
||||||
|
|
||||||
|
test3() {
|
||||||
|
echo "TEST3"
|
||||||
|
+ LATENCY=180000
|
||||||
|
cat > $CFGFILE <<EOF
|
||||||
|
--C hw:1,0,0 -P plug:dmix:0 --tlatency 30000 --thread 0 \
|
||||||
|
+-C hw:1,0,0 -P plug:dmix:0 --tlatency $LATENCY --thread 0 \
|
||||||
|
--mixer "name='Master Playback Volume'@name='Master Playback Volume'" \
|
||||||
|
--mixer "name='Master Playback Switch'@name='Master Playback Switch'" \
|
||||||
|
--mixer "name='PCM Playback Volume'" \
|
||||||
|
--ossmixer "name=Master@VOLUME"
|
||||||
|
--C hw:1,0,1 -P plug:dmix:0 --tlatency 30000 --thread 1
|
||||||
|
--C hw:1,0,2 -P plug:dmix:0 --tlatency 30000 --thread 2
|
||||||
|
--C hw:1,0,3 -P plug:dmix:0 --tlatency 30000 --thread 3
|
||||||
|
--C hw:1,0,4 -P plug:dmix:0 --tlatency 30000 --thread 4
|
||||||
|
--C hw:1,0,5 -P plug:dmix:0 --tlatency 30000 --thread 5
|
||||||
|
--C hw:1,0,6 -P plug:dmix:0 --tlatency 30000 --thread 6
|
||||||
|
--C hw:1,0,7 -P plug:dmix:0 --tlatency 30000 --thread 7
|
||||||
|
+-C hw:1,0,1 -P plug:dmix:0 --tlatency $LATENCY --thread 1
|
||||||
|
+-C hw:1,0,2 -P plug:dmix:0 --tlatency $LATENCY --thread 2
|
||||||
|
+-C hw:1,0,3 -P plug:dmix:0 --tlatency $LATENCY --thread 3
|
||||||
|
+-C hw:1,0,4 -P plug:dmix:0 --tlatency $LATENCY --thread 4
|
||||||
|
+-C hw:1,0,5 -P plug:dmix:0 --tlatency $LATENCY --thread 5
|
||||||
|
+-C hw:1,0,6 -P plug:dmix:0 --tlatency $LATENCY --thread 6
|
||||||
|
+-C hw:1,0,7 -P plug:dmix:0 --tlatency $LATENCY --thread 7
|
||||||
|
EOF
|
||||||
|
$DBG ./alsaloop --config $CFGFILE $ARGS
|
||||||
|
}
|
||||||
|
--
|
||||||
|
1.7.3.1
|
||||||
|
|
26
0031-alsaloop-Fix-latency-print.patch
Normal file
26
0031-alsaloop-Fix-latency-print.patch
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
From 1ae28cae89a12ed39532bc2a3596e4efa0189e4c Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jaroslav Kysela <perex@perex.cz>
|
||||||
|
Date: Thu, 14 Oct 2010 15:39:28 +0200
|
||||||
|
Subject: [PATCH 31/38] alsaloop: Fix latency print
|
||||||
|
|
||||||
|
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
|
||||||
|
---
|
||||||
|
alsaloop/pcmjob.c | 2 +-
|
||||||
|
1 files changed, 1 insertions(+), 1 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/alsaloop/pcmjob.c b/alsaloop/pcmjob.c
|
||||||
|
index 6aa8bfe..925380c 100644
|
||||||
|
--- a/alsaloop/pcmjob.c
|
||||||
|
+++ b/alsaloop/pcmjob.c
|
||||||
|
@@ -1394,7 +1394,7 @@ int pcmjob_start(struct loopback *loop)
|
||||||
|
if ((err = setparams(loop, loop->latency/2)) < 0)
|
||||||
|
goto __error;
|
||||||
|
if (verbose)
|
||||||
|
- showlatency(loop->output, loop->latency, loop->play->rate, "Latency");
|
||||||
|
+ showlatency(loop->output, loop->latency, loop->play->rate_req, "Latency");
|
||||||
|
if (loop->play->access == loop->capt->access &&
|
||||||
|
loop->play->format == loop->capt->format &&
|
||||||
|
loop->play->rate == loop->capt->rate &&
|
||||||
|
--
|
||||||
|
1.7.3.1
|
||||||
|
|
32
0032-speaker-test-Don-t-retry-after-fatal-errors.patch
Normal file
32
0032-speaker-test-Don-t-retry-after-fatal-errors.patch
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
From b67d215d20bcf546617de962dec60cc29b238e4e Mon Sep 17 00:00:00 2001
|
||||||
|
From: David Henningsson <david.henningsson@canonical.com>
|
||||||
|
Date: Fri, 15 Oct 2010 12:30:44 +0200
|
||||||
|
Subject: [PATCH 32/38] speaker-test: Don't retry after fatal errors
|
||||||
|
|
||||||
|
Fixup commit 9b1a2566: Remove error loop
|
||||||
|
|
||||||
|
Signed-off-by: David Henningsson <david.henningsson@canonical.com>
|
||||||
|
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
||||||
|
---
|
||||||
|
speaker-test/speaker-test.c | 4 ++--
|
||||||
|
1 files changed, 2 insertions(+), 2 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/speaker-test/speaker-test.c b/speaker-test/speaker-test.c
|
||||||
|
index 458a8d7..3029110 100644
|
||||||
|
--- a/speaker-test/speaker-test.c
|
||||||
|
+++ b/speaker-test/speaker-test.c
|
||||||
|
@@ -993,9 +993,9 @@ int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
- while ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
|
||||||
|
+ if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
|
||||||
|
printf(_("Playback open error: %d,%s\n"), err,snd_strerror(err));
|
||||||
|
- sleep(1);
|
||||||
|
+ exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((err = set_hwparams(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
|
||||||
|
--
|
||||||
|
1.7.3.1
|
||||||
|
|
104
0033-alsaloop-Delay-the-restart-a-bit-to-handle-snd-aloop.patch
Normal file
104
0033-alsaloop-Delay-the-restart-a-bit-to-handle-snd-aloop.patch
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
From d53eb0309df34f058b33c18210c8949c8a2d8b8e Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jaroslav Kysela <perex@perex.cz>
|
||||||
|
Date: Wed, 20 Oct 2010 09:26:24 +0200
|
||||||
|
Subject: [PATCH 33/38] alsaloop: Delay the restart a bit (to handle snd-aloop playback xruns better)
|
||||||
|
|
||||||
|
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
|
||||||
|
---
|
||||||
|
alsaloop/alsaloop.h | 2 ++
|
||||||
|
alsaloop/pcmjob.c | 33 ++++++++++++++++++++++++++-------
|
||||||
|
2 files changed, 28 insertions(+), 7 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/alsaloop/alsaloop.h b/alsaloop/alsaloop.h
|
||||||
|
index e506427..8dc445a 100644
|
||||||
|
--- a/alsaloop/alsaloop.h
|
||||||
|
+++ b/alsaloop/alsaloop.h
|
||||||
|
@@ -143,6 +143,8 @@ struct loopback {
|
||||||
|
unsigned int linked:1; /* linked streams */
|
||||||
|
unsigned int reinit:1;
|
||||||
|
unsigned int running:1;
|
||||||
|
+ unsigned int stop_pending:1;
|
||||||
|
+ snd_pcm_uframes_t stop_count;
|
||||||
|
sync_type_t sync; /* type of sync */
|
||||||
|
slave_type_t slave;
|
||||||
|
int thread; /* thread number */
|
||||||
|
diff --git a/alsaloop/pcmjob.c b/alsaloop/pcmjob.c
|
||||||
|
index 925380c..23270a0 100644
|
||||||
|
--- a/alsaloop/pcmjob.c
|
||||||
|
+++ b/alsaloop/pcmjob.c
|
||||||
|
@@ -738,6 +738,15 @@ static int writeit(struct loopback_handle *lhandle)
|
||||||
|
lhandle->buf_pos += r;
|
||||||
|
lhandle->buf_pos %= lhandle->buf_size;
|
||||||
|
xrun_profile(lhandle->loopback);
|
||||||
|
+ if (lhandle->loopback->stop_pending) {
|
||||||
|
+ lhandle->loopback->stop_count += r;
|
||||||
|
+ if (lhandle->loopback->stop_count * lhandle->pitch >
|
||||||
|
+ lhandle->loopback->latency * 3) {
|
||||||
|
+ lhandle->loopback->stop_pending = 0;
|
||||||
|
+ lhandle->loopback->reinit = 1;
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
@@ -1521,6 +1530,7 @@ int pcmjob_start(struct loopback *loop)
|
||||||
|
goto __error;
|
||||||
|
}
|
||||||
|
loop->running = 1;
|
||||||
|
+ loop->stop_pending = 0;
|
||||||
|
if (loop->xrun) {
|
||||||
|
getcurtimestamp(&loop->xrun_last_update);
|
||||||
|
loop->xrun_last_pdelay = XRUN_PROFILE_UNKNOWN;
|
||||||
|
@@ -1638,6 +1648,7 @@ static int ctl_event_check(snd_ctl_elem_value_t *val, snd_ctl_event_t *ev)
|
||||||
|
static int handle_ctl_events(struct loopback_handle *lhandle,
|
||||||
|
unsigned short events)
|
||||||
|
{
|
||||||
|
+ struct loopback *loop = lhandle->loopback;
|
||||||
|
snd_ctl_event_t *ev;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
@@ -1647,16 +1658,24 @@ static int handle_ctl_events(struct loopback_handle *lhandle,
|
||||||
|
break;
|
||||||
|
if (snd_ctl_event_get_type(ev) != SND_CTL_EVENT_ELEM)
|
||||||
|
continue;
|
||||||
|
- if (lhandle == lhandle->loopback->play)
|
||||||
|
+ if (lhandle == loop->play)
|
||||||
|
goto __ctl_check;
|
||||||
|
if (verbose > 6)
|
||||||
|
- snd_output_printf(lhandle->loopback->output, "%s: ctl event!!!! %s\n", lhandle->id, snd_ctl_event_elem_get_name(ev));
|
||||||
|
+ snd_output_printf(loop->output, "%s: ctl event!!!! %s\n", lhandle->id, snd_ctl_event_elem_get_name(ev));
|
||||||
|
if (ctl_event_check(lhandle->ctl_active, ev)) {
|
||||||
|
err = get_active(lhandle);
|
||||||
|
if (verbose > 7)
|
||||||
|
- snd_output_printf(lhandle->loopback->output, "%s: ctl event active %i\n", lhandle->id, err);
|
||||||
|
- if (err != lhandle->loopback->running)
|
||||||
|
- goto __restart;
|
||||||
|
+ snd_output_printf(loop->output, "%s: ctl event active %i\n", lhandle->id, err);
|
||||||
|
+ if (!err) {
|
||||||
|
+ if (lhandle->loopback->running) {
|
||||||
|
+ loop->stop_pending = 1;
|
||||||
|
+ loop->stop_count = 0;
|
||||||
|
+ }
|
||||||
|
+ } else {
|
||||||
|
+ loop->stop_pending = 0;
|
||||||
|
+ if (loop->running == 0)
|
||||||
|
+ goto __restart;
|
||||||
|
+ }
|
||||||
|
} else if (ctl_event_check(lhandle->ctl_format, ev)) {
|
||||||
|
err = get_format(lhandle);
|
||||||
|
if (lhandle->format != err)
|
||||||
|
@@ -1676,8 +1695,8 @@ static int handle_ctl_events(struct loopback_handle *lhandle,
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
__restart:
|
||||||
|
- pcmjob_stop(lhandle->loopback);
|
||||||
|
- err = pcmjob_start(lhandle->loopback);
|
||||||
|
+ pcmjob_stop(loop);
|
||||||
|
+ err = pcmjob_start(loop);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
return 1;
|
||||||
|
--
|
||||||
|
1.7.3.1
|
||||||
|
|
95
0034-alsaloop-rework-the-ctl-event-handling-routine.patch
Normal file
95
0034-alsaloop-rework-the-ctl-event-handling-routine.patch
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
From 7a11a2b5464e86573f01af6cf4637ffdc0351478 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jaroslav Kysela <perex@perex.cz>
|
||||||
|
Date: Thu, 21 Oct 2010 20:38:06 +0200
|
||||||
|
Subject: [PATCH 34/38] alsaloop: rework the ctl event handling routine
|
||||||
|
|
||||||
|
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
|
||||||
|
---
|
||||||
|
alsaloop/pcmjob.c | 51 +++++++++++++++++++++++++++------------------------
|
||||||
|
1 files changed, 27 insertions(+), 24 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/alsaloop/pcmjob.c b/alsaloop/pcmjob.c
|
||||||
|
index 23270a0..0b84803 100644
|
||||||
|
--- a/alsaloop/pcmjob.c
|
||||||
|
+++ b/alsaloop/pcmjob.c
|
||||||
|
@@ -1650,7 +1650,7 @@ static int handle_ctl_events(struct loopback_handle *lhandle,
|
||||||
|
{
|
||||||
|
struct loopback *loop = lhandle->loopback;
|
||||||
|
snd_ctl_event_t *ev;
|
||||||
|
- int err;
|
||||||
|
+ int err, restart = 0;
|
||||||
|
|
||||||
|
snd_ctl_event_alloca(&ev);
|
||||||
|
while ((err = snd_ctl_read(lhandle->ctl, ev)) != 0 && err != -EAGAIN) {
|
||||||
|
@@ -1663,42 +1663,45 @@ static int handle_ctl_events(struct loopback_handle *lhandle,
|
||||||
|
if (verbose > 6)
|
||||||
|
snd_output_printf(loop->output, "%s: ctl event!!!! %s\n", lhandle->id, snd_ctl_event_elem_get_name(ev));
|
||||||
|
if (ctl_event_check(lhandle->ctl_active, ev)) {
|
||||||
|
- err = get_active(lhandle);
|
||||||
|
- if (verbose > 7)
|
||||||
|
- snd_output_printf(loop->output, "%s: ctl event active %i\n", lhandle->id, err);
|
||||||
|
- if (!err) {
|
||||||
|
- if (lhandle->loopback->running) {
|
||||||
|
- loop->stop_pending = 1;
|
||||||
|
- loop->stop_count = 0;
|
||||||
|
- }
|
||||||
|
- } else {
|
||||||
|
- loop->stop_pending = 0;
|
||||||
|
- if (loop->running == 0)
|
||||||
|
- goto __restart;
|
||||||
|
- }
|
||||||
|
+ continue;
|
||||||
|
} else if (ctl_event_check(lhandle->ctl_format, ev)) {
|
||||||
|
err = get_format(lhandle);
|
||||||
|
if (lhandle->format != err)
|
||||||
|
- goto __restart;
|
||||||
|
+ restart = 1;
|
||||||
|
+ continue;
|
||||||
|
} else if (ctl_event_check(lhandle->ctl_rate, ev)) {
|
||||||
|
err = get_rate(lhandle);
|
||||||
|
if (lhandle->rate != err)
|
||||||
|
- goto __restart;
|
||||||
|
+ restart = 1;
|
||||||
|
+ continue;
|
||||||
|
} else if (ctl_event_check(lhandle->ctl_channels, ev)) {
|
||||||
|
err = get_channels(lhandle);
|
||||||
|
if (lhandle->channels != err)
|
||||||
|
- goto __restart;
|
||||||
|
+ restart = 1;
|
||||||
|
+ continue;
|
||||||
|
}
|
||||||
|
__ctl_check:
|
||||||
|
control_event(lhandle, ev);
|
||||||
|
}
|
||||||
|
- return 0;
|
||||||
|
-
|
||||||
|
- __restart:
|
||||||
|
- pcmjob_stop(loop);
|
||||||
|
- err = pcmjob_start(loop);
|
||||||
|
- if (err < 0)
|
||||||
|
- return err;
|
||||||
|
+ err = get_active(lhandle);
|
||||||
|
+ if (verbose > 7)
|
||||||
|
+ snd_output_printf(loop->output, "%s: ctl event active %i\n", lhandle->id, err);
|
||||||
|
+ if (!err) {
|
||||||
|
+ if (lhandle->loopback->running) {
|
||||||
|
+ loop->stop_pending = 1;
|
||||||
|
+ loop->stop_count = 0;
|
||||||
|
+ }
|
||||||
|
+ } else {
|
||||||
|
+ loop->stop_pending = 0;
|
||||||
|
+ if (loop->running == 0)
|
||||||
|
+ restart = 1;
|
||||||
|
+ }
|
||||||
|
+ if (restart) {
|
||||||
|
+ pcmjob_stop(loop);
|
||||||
|
+ err = pcmjob_start(loop);
|
||||||
|
+ if (err < 0)
|
||||||
|
+ return err;
|
||||||
|
+ }
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
--
|
||||||
|
1.7.3.1
|
||||||
|
|
88
0035-alsamixer-remove-obsolete-e-mail.patch
Normal file
88
0035-alsamixer-remove-obsolete-e-mail.patch
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
From f2e9e9a5b017a3834941256da52e1d608f9c4c7b Mon Sep 17 00:00:00 2001
|
||||||
|
From: Clemens Ladisch <clemens@ladisch.de>
|
||||||
|
Date: Wed, 10 Nov 2010 10:14:53 +0100
|
||||||
|
Subject: [PATCH 35/38] alsamixer: remove obsolete e-mail
|
||||||
|
|
||||||
|
Tim Janik's e-mail address is no longer valid.
|
||||||
|
|
||||||
|
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
|
||||||
|
---
|
||||||
|
alsamixer/cli.c | 2 +-
|
||||||
|
alsamixer/colors.c | 2 +-
|
||||||
|
alsamixer/mixer_controls.c | 2 +-
|
||||||
|
alsamixer/mixer_widget.c | 4 ++--
|
||||||
|
alsamixer/textbox.c | 2 +-
|
||||||
|
5 files changed, 6 insertions(+), 6 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/alsamixer/cli.c b/alsamixer/cli.c
|
||||||
|
index ab6255f..3898196 100644
|
||||||
|
--- a/alsamixer/cli.c
|
||||||
|
+++ b/alsamixer/cli.c
|
||||||
|
@@ -1,6 +1,6 @@
|
||||||
|
/*
|
||||||
|
* alsamixer - curses mixer for the ALSA project
|
||||||
|
- * Copyright (c) 1998,1999 Tim Janik <timj@gtk.org>
|
||||||
|
+ * Copyright (c) 1998,1999 Tim Janik
|
||||||
|
* Jaroslav Kysela <perex@perex.cz>
|
||||||
|
* Copyright (c) 2009 Clemens Ladisch <clemens@ladisch.de>
|
||||||
|
*
|
||||||
|
diff --git a/alsamixer/colors.c b/alsamixer/colors.c
|
||||||
|
index fcceb16..b4b98e5 100644
|
||||||
|
--- a/alsamixer/colors.c
|
||||||
|
+++ b/alsamixer/colors.c
|
||||||
|
@@ -1,6 +1,6 @@
|
||||||
|
/*
|
||||||
|
* colors.c - color and attribute definitions
|
||||||
|
- * Copyright (c) 1998,1999 Tim Janik <timj@gtk.org>
|
||||||
|
+ * Copyright (c) 1998,1999 Tim Janik
|
||||||
|
* Jaroslav Kysela <perex@perex.cz>
|
||||||
|
* Copyright (c) 2009 Clemens Ladisch <clemens@ladisch.de>
|
||||||
|
*
|
||||||
|
diff --git a/alsamixer/mixer_controls.c b/alsamixer/mixer_controls.c
|
||||||
|
index 796df7b..cc98b64 100644
|
||||||
|
--- a/alsamixer/mixer_controls.c
|
||||||
|
+++ b/alsamixer/mixer_controls.c
|
||||||
|
@@ -1,6 +1,6 @@
|
||||||
|
/*
|
||||||
|
* mixer_controls.c - handles mixer controls and mapping from selems
|
||||||
|
- * Copyright (c) 1998,1999 Tim Janik <timj@gtk.org>
|
||||||
|
+ * Copyright (c) 1998,1999 Tim Janik
|
||||||
|
* Jaroslav Kysela <perex@perex.cz>
|
||||||
|
* Copyright (c) 2009 Clemens Ladisch <clemens@ladisch.de>
|
||||||
|
*
|
||||||
|
diff --git a/alsamixer/mixer_widget.c b/alsamixer/mixer_widget.c
|
||||||
|
index 796ea1d..c8ca156 100644
|
||||||
|
--- a/alsamixer/mixer_widget.c
|
||||||
|
+++ b/alsamixer/mixer_widget.c
|
||||||
|
@@ -1,6 +1,6 @@
|
||||||
|
/*
|
||||||
|
* mixer_widget.c - mixer widget and keys handling
|
||||||
|
- * Copyright (c) 1998,1999 Tim Janik <timj@gtk.org>
|
||||||
|
+ * Copyright (c) 1998,1999 Tim Janik
|
||||||
|
* Jaroslav Kysela <perex@perex.cz>
|
||||||
|
* Copyright (c) 2009 Clemens Ladisch <clemens@ladisch.de>
|
||||||
|
*
|
||||||
|
@@ -211,7 +211,7 @@ static void show_help(void)
|
||||||
|
_("; ' Toggle left/right capture"),
|
||||||
|
"",
|
||||||
|
_("Authors:"),
|
||||||
|
- _(" Tim Janik <timj@gtk.org>"),
|
||||||
|
+ _(" Tim Janik"),
|
||||||
|
_(" Jaroslav Kysela <perex@perex.cz>"),
|
||||||
|
_(" Clemens Ladisch <clemens@ladisch.de>"),
|
||||||
|
};
|
||||||
|
diff --git a/alsamixer/textbox.c b/alsamixer/textbox.c
|
||||||
|
index d743a14..a979d3c 100644
|
||||||
|
--- a/alsamixer/textbox.c
|
||||||
|
+++ b/alsamixer/textbox.c
|
||||||
|
@@ -1,6 +1,6 @@
|
||||||
|
/*
|
||||||
|
* textbox.c - show a text box for messages, files or help
|
||||||
|
- * Copyright (c) 1998,1999 Tim Janik <timj@gtk.org>
|
||||||
|
+ * Copyright (c) 1998,1999 Tim Janik
|
||||||
|
* Jaroslav Kysela <perex@perex.cz>
|
||||||
|
* Copyright (c) 2009 Clemens Ladisch <clemens@ladisch.de>
|
||||||
|
*
|
||||||
|
--
|
||||||
|
1.7.3.1
|
||||||
|
|
1170
0036-update-German-translations.patch
Normal file
1170
0036-update-German-translations.patch
Normal file
File diff suppressed because it is too large
Load Diff
211
0037-alsactl-systemd-and-udev-hookup.patch
Normal file
211
0037-alsactl-systemd-and-udev-hookup.patch
Normal file
@ -0,0 +1,211 @@
|
|||||||
|
From de7c3eff0e371ce155403bbcdcf81ee79266fa0f Mon Sep 17 00:00:00 2001
|
||||||
|
From: Lennart Poettering <lennart@poettering.net>
|
||||||
|
Date: Tue, 23 Nov 2010 01:45:08 +0100
|
||||||
|
Subject: [PATCH 37/38] alsactl: systemd and udev hookup
|
||||||
|
|
||||||
|
Add minimal systemd and udev support to alsactl so that mixer settings
|
||||||
|
are restored at boot, when sound cards are plugged in and saved on
|
||||||
|
shutdown.
|
||||||
|
|
||||||
|
This is similar to existing udev/init script solutions in various
|
||||||
|
distributions.
|
||||||
|
|
||||||
|
Note that alsactl is called both synchronously from the udev rules as
|
||||||
|
well as asynchronously at boot. This is intended, and to ensure two
|
||||||
|
things:
|
||||||
|
|
||||||
|
- At boot the asound.state file might not be readable, since it resides
|
||||||
|
on a different file system. That means exclusively restoring sound card
|
||||||
|
settings from udev rules will no suffice, since if the rule is
|
||||||
|
executed at early boot (for example within udev settle) then the file
|
||||||
|
will no be readable and cannot be restored.
|
||||||
|
|
||||||
|
- We need to ensure that applications monitoring sound cards coming and
|
||||||
|
going (such as PA) must not get these events before the mixer settings
|
||||||
|
have been restored. That means the mixer settings must be restored
|
||||||
|
synchronously withing the udev rules, before the events are passed on
|
||||||
|
to the apps.
|
||||||
|
|
||||||
|
That basically means we need to restore the settings once in udev, to
|
||||||
|
deal with sound cards becoming available during runtime. And once in
|
||||||
|
early boot to deal with coldplugged soundcards whose data files might
|
||||||
|
not have been available at time of plugging. Hence we call alsactl
|
||||||
|
twice: one from the udev rule, and once from he systemd unit file.
|
||||||
|
|
||||||
|
Signed-off-by: Lennart Poettering <mznyfn@0pointer.de>
|
||||||
|
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
|
||||||
|
---
|
||||||
|
Makefile.am | 3 ++
|
||||||
|
alsactl/90-alsa-restore.rules.in | 2 +
|
||||||
|
alsactl/Makefile.am | 46 ++++++++++++++++++++++++++++++++++++++
|
||||||
|
alsactl/alsa-restore.service.in | 11 +++++++++
|
||||||
|
alsactl/alsa-store.service.in | 9 +++++++
|
||||||
|
configure.in | 17 +++++++++++--
|
||||||
|
7 files changed, 88 insertions(+), 3 deletions(-)
|
||||||
|
create mode 100644 alsactl/90-alsa-restore.rules.in
|
||||||
|
create mode 100644 alsactl/alsa-restore.service.in
|
||||||
|
create mode 100644 alsactl/alsa-store.service.in
|
||||||
|
|
||||||
|
diff --git a/Makefile.am b/Makefile.am
|
||||||
|
index 9951c46..62e1ba6 100644
|
||||||
|
--- a/Makefile.am
|
||||||
|
+++ b/Makefile.am
|
||||||
|
@@ -37,3 +37,6 @@ dist-hook:
|
||||||
|
else \
|
||||||
|
$(TAR) --create --verbose --file=- $(distdir) | bzip2 -c -9 > $(distdir).tar.bz2 ; \
|
||||||
|
fi
|
||||||
|
+
|
||||||
|
+DISTCHECK_CONFIGURE_FLAGS = \
|
||||||
|
+ --with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir)
|
||||||
|
diff --git a/alsactl/90-alsa-restore.rules.in b/alsactl/90-alsa-restore.rules.in
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000..0bcee5b
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/alsactl/90-alsa-restore.rules.in
|
||||||
|
@@ -0,0 +1,2 @@
|
||||||
|
+ACTION=="add", SUBSYSTEM=="sound", KERNEL=="controlC*", KERNELS=="card*", \
|
||||||
|
+ RUN+="@sbindir@/alsactl restore $attr{number}"
|
||||||
|
diff --git a/alsactl/Makefile.am b/alsactl/Makefile.am
|
||||||
|
index 359f73a..9a2d30e 100644
|
||||||
|
--- a/alsactl/Makefile.am
|
||||||
|
+++ b/alsactl/Makefile.am
|
||||||
|
@@ -10,5 +10,51 @@ EXTRA_DIST=alsactl.1 alsactl_init.xml
|
||||||
|
alsactl_SOURCES=alsactl.c state.c utils.c init_parse.c
|
||||||
|
noinst_HEADERS=alsactl.h list.h init_sysdeps.c init_utils_string.c init_utils_run.c init_sysfs.c
|
||||||
|
|
||||||
|
+udevrulesdir=/lib/udev/rules.d
|
||||||
|
+
|
||||||
|
+dist_udevrules_DATA = \
|
||||||
|
+ 90-alsa-restore.rules
|
||||||
|
+
|
||||||
|
+if HAVE_SYSTEMD
|
||||||
|
+
|
||||||
|
+systemdsystemunit_DATA = \
|
||||||
|
+ alsa-store.service \
|
||||||
|
+ alsa-restore.service
|
||||||
|
+
|
||||||
|
+install-data-hook:
|
||||||
|
+ $(MKDIR_P) -m 0755 \
|
||||||
|
+ $(DESTDIR)$(systemdsystemunitdir)/basic.target.wants \
|
||||||
|
+ $(DESTDIR)$(systemdsystemunitdir)/shutdown.target.wants
|
||||||
|
+ ( cd $(DESTDIR)$(systemdsystemunitdir)/basic.target.wants && \
|
||||||
|
+ rm -f alsa-restore.service && \
|
||||||
|
+ $(LN_S) ../alsa-restore.service alsa-restore.service )
|
||||||
|
+ ( cd $(DESTDIR)$(systemdsystemunitdir)/shutdown.target.wants && \
|
||||||
|
+ rm -f alsa-store.service && \
|
||||||
|
+ $(LN_S) ../alsa-store.service alsa-store.service )
|
||||||
|
+
|
||||||
|
+endif
|
||||||
|
+
|
||||||
|
+edit = \
|
||||||
|
+ sed $(SED) -r 's,@sbindir\@,$(sbindir),g' < $< > $@ || rm $@
|
||||||
|
+
|
||||||
|
+alsa-store.service: alsa-store.service.in
|
||||||
|
+ $(edit)
|
||||||
|
+
|
||||||
|
+alsa-restore.service: alsa-restore.service.in
|
||||||
|
+ $(edit)
|
||||||
|
+
|
||||||
|
+90-alsa-restore.rules: 90-alsa-restore.rules.in
|
||||||
|
+ $(edit)
|
||||||
|
+
|
||||||
|
+EXTRA_DIST += \
|
||||||
|
+ alsa-store.service.in \
|
||||||
|
+ alsa-restore.service.in \
|
||||||
|
+ 90-alsa-restore.rules.in
|
||||||
|
+
|
||||||
|
+CLEANFILES = \
|
||||||
|
+ alsa-store.service \
|
||||||
|
+ alsa-restore.service \
|
||||||
|
+ 90-alsa-restore.rules
|
||||||
|
+
|
||||||
|
%.7: %.xml
|
||||||
|
xmlto man $?
|
||||||
|
diff --git a/alsactl/alsa-restore.service.in b/alsactl/alsa-restore.service.in
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000..e97d196
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/alsactl/alsa-restore.service.in
|
||||||
|
@@ -0,0 +1,11 @@
|
||||||
|
+[Unit]
|
||||||
|
+Description=Restore Sound Card State
|
||||||
|
+DefaultDependencies=no
|
||||||
|
+After=sysinit.target
|
||||||
|
+Before=shutdown.target
|
||||||
|
+Conflicts=shutdown.target
|
||||||
|
+
|
||||||
|
+[Service]
|
||||||
|
+Type=oneshot
|
||||||
|
+ExecStart=-@sbindir@/alsactl restore
|
||||||
|
+StandardOutput=syslog
|
||||||
|
diff --git a/alsactl/alsa-store.service.in b/alsactl/alsa-store.service.in
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000..0e2823c
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/alsactl/alsa-store.service.in
|
||||||
|
@@ -0,0 +1,9 @@
|
||||||
|
+[Unit]
|
||||||
|
+Description=Store Sound Card State
|
||||||
|
+DefaultDependencies=no
|
||||||
|
+Before=shutdown.target
|
||||||
|
+
|
||||||
|
+[Service]
|
||||||
|
+Type=oneshot
|
||||||
|
+ExecStart=@sbindir@/alsactl store
|
||||||
|
+StandardOutput=syslog
|
||||||
|
diff --git a/configure.in b/configure.in
|
||||||
|
index 31fd581..54ea74c 100644
|
||||||
|
--- a/configure.in
|
||||||
|
+++ b/configure.in
|
||||||
|
@@ -26,6 +26,7 @@ fi
|
||||||
|
AC_PROG_CC
|
||||||
|
dnl AC_PROG_CXX
|
||||||
|
AC_PROG_INSTALL
|
||||||
|
+AC_PROG_MKDIR_P
|
||||||
|
AC_PROG_LN_S
|
||||||
|
AM_PATH_ALSA(1.0.16)
|
||||||
|
|
||||||
|
@@ -130,7 +131,7 @@ if test x$alsamixer = xtrue; then
|
||||||
|
CURSES_CFLAGS=`ncursesw5-config --cflags`
|
||||||
|
curseslib="ncursesw"
|
||||||
|
else
|
||||||
|
- AC_CHECK_LIB(ncursesw, initscr,
|
||||||
|
+ AC_CHECK_LIB(ncursesw, initscr,
|
||||||
|
[ CURSESINC='<ncurses.h>'; CURSESLIB='-lncursesw'; curseslib="ncursesw"])
|
||||||
|
fi
|
||||||
|
if test -n "$CURSESINC"; then
|
||||||
|
@@ -147,12 +148,12 @@ if test x$alsamixer = xtrue; then
|
||||||
|
CURSES_CFLAGS=`ncurses5-config --cflags`
|
||||||
|
curseslib="ncurses"
|
||||||
|
else
|
||||||
|
- AC_CHECK_LIB(ncurses, initscr,
|
||||||
|
+ AC_CHECK_LIB(ncurses, initscr,
|
||||||
|
[ CURSESINC='<ncurses.h>'; CURSESLIB='-lncurses'; curseslib="ncurses"])
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if test "$curseslib" = "curses" -o "$curseslib" = "auto"; then
|
||||||
|
- AC_CHECK_LIB(curses, initscr,
|
||||||
|
+ AC_CHECK_LIB(curses, initscr,
|
||||||
|
[ CURSESINC='<curses.h>'; CURSESLIB='-lcurses'; curseslib="curses"])
|
||||||
|
fi
|
||||||
|
if test -z "$CURSESINC"; then
|
||||||
|
@@ -278,6 +279,16 @@ SAVE_UTIL_VERSION
|
||||||
|
|
||||||
|
AC_SUBST(LIBRT)
|
||||||
|
|
||||||
|
+dnl Check for systemd
|
||||||
|
+PKG_PROG_PKG_CONFIG
|
||||||
|
+AC_ARG_WITH([systemdsystemunitdir],
|
||||||
|
+ AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files]),
|
||||||
|
+ [], [with_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)])
|
||||||
|
+if test "x$with_systemdsystemunitdir" != xno; then
|
||||||
|
+ AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir])
|
||||||
|
+fi
|
||||||
|
+AM_CONDITIONAL(HAVE_SYSTEMD, [test -n "$with_systemdsystemunitdir" -a "x$with_systemdsystemunitdir" != xno ])
|
||||||
|
+
|
||||||
|
AC_OUTPUT(Makefile alsactl/Makefile alsactl/init/Makefile \
|
||||||
|
alsamixer/Makefile amidi/Makefile amixer/Makefile \
|
||||||
|
m4/Makefile po/Makefile.in \
|
||||||
|
--
|
||||||
|
1.7.3.1
|
||||||
|
|
123
0038-alsactl-Move-asound.state-location-to-var-lib-alsa.patch
Normal file
123
0038-alsactl-Move-asound.state-location-to-var-lib-alsa.patch
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
From 81f015f5abdd8e6cfa75e37bd97eb22781019eec Mon Sep 17 00:00:00 2001
|
||||||
|
From: Lennart Poettering <lennart@poettering.net>
|
||||||
|
Date: Tue, 23 Nov 2010 02:59:18 +0100
|
||||||
|
Subject: [PATCH 38/38] alsactl: Move asound.state location to /var/lib/alsa
|
||||||
|
|
||||||
|
.... and add configure switch for it.
|
||||||
|
|
||||||
|
/etc might be on a read-only partition which is not suitable for dynamic
|
||||||
|
data such as the mixer settings. Hence move the location of asound.state
|
||||||
|
to /var/lib.
|
||||||
|
|
||||||
|
This is based on a patch from Ubuntu/Debian which hardcoded the pah in
|
||||||
|
/var/lib.
|
||||||
|
|
||||||
|
Signed-off-by: Lennart Poettering <mznyfn@0pointer.de>
|
||||||
|
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
|
||||||
|
---
|
||||||
|
Makefile.am | 3 +++
|
||||||
|
alsaconf/alsaconf.in | 5 +++--
|
||||||
|
alsactl/Makefile.am | 1 +
|
||||||
|
alsactl/alsactl.1 | 4 ++--
|
||||||
|
alsactl/alsactl.c | 4 +++-
|
||||||
|
configure.in | 6 ++++++
|
||||||
|
6 files changed, 18 insertions(+), 5 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/Makefile.am b/Makefile.am
|
||||||
|
index 62e1ba6..48a4780 100644
|
||||||
|
--- a/Makefile.am
|
||||||
|
+++ b/Makefile.am
|
||||||
|
@@ -38,5 +38,8 @@ dist-hook:
|
||||||
|
$(TAR) --create --verbose --file=- $(distdir) | bzip2 -c -9 > $(distdir).tar.bz2 ; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
+install-data-hook:
|
||||||
|
+ $(MKDIR_P) -m 0755 $(DESTDIR)$(ASOUND_STATE_DIR)
|
||||||
|
+
|
||||||
|
DISTCHECK_CONFIGURE_FLAGS = \
|
||||||
|
--with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir)
|
||||||
|
diff --git a/alsaconf/alsaconf.in b/alsaconf/alsaconf.in
|
||||||
|
index ccc1b37..5c23787 100644
|
||||||
|
--- a/alsaconf/alsaconf.in
|
||||||
|
+++ b/alsaconf/alsaconf.in
|
||||||
|
@@ -956,8 +956,9 @@ If you have a big amplifier, lower your volumes or say no.
|
||||||
|
aplay -N $TESTSOUND
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
- if [ ! -r /etc/asound.state ]; then
|
||||||
|
- xecho "Saving the mixer setup used for this in /etc/asound.state."
|
||||||
|
+ mkdir -p -m 0755 @ASOUND_STATE_DIR@
|
||||||
|
+ if [ ! -r @ASOUND_STATE_DIR@/asound.state ]; then
|
||||||
|
+ xecho "Saving the mixer setup used for this in @ASOUND_STATE_DIR@/asound.state."
|
||||||
|
$sbindir/alsactl store
|
||||||
|
fi
|
||||||
|
clear
|
||||||
|
diff --git a/alsactl/Makefile.am b/alsactl/Makefile.am
|
||||||
|
index 9a2d30e..721b619 100644
|
||||||
|
--- a/alsactl/Makefile.am
|
||||||
|
+++ b/alsactl/Makefile.am
|
||||||
|
@@ -8,6 +8,7 @@ endif
|
||||||
|
EXTRA_DIST=alsactl.1 alsactl_init.xml
|
||||||
|
|
||||||
|
alsactl_SOURCES=alsactl.c state.c utils.c init_parse.c
|
||||||
|
+alsactl_CFLAGS=$(AM_CFLAGS) -DSYS_ASOUNDRC=\"$(ASOUND_STATE_DIR)/asound.state\"
|
||||||
|
noinst_HEADERS=alsactl.h list.h init_sysdeps.c init_utils_string.c init_utils_run.c init_sysfs.c
|
||||||
|
|
||||||
|
udevrulesdir=/lib/udev/rules.d
|
||||||
|
diff --git a/alsactl/alsactl.1 b/alsactl/alsactl.1
|
||||||
|
index eb3cbd1..eb5968c 100644
|
||||||
|
--- a/alsactl/alsactl.1
|
||||||
|
+++ b/alsactl/alsactl.1
|
||||||
|
@@ -43,7 +43,7 @@ Print alsactl version number.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fI\-f, \-\-file\fP
|
||||||
|
-Select the configuration file to use. The default is /etc/asound.state.
|
||||||
|
+Select the configuration file to use. The default is /var/lib/alsa/asound.state.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fI\-F, \-\-force\fP
|
||||||
|
@@ -90,7 +90,7 @@ The configuration file for init. By default, PREFIX/share/alsa/init/00main
|
||||||
|
is used.
|
||||||
|
|
||||||
|
.SH FILES
|
||||||
|
-\fI/etc/asound.state\fP (or whatever file you specify with the
|
||||||
|
+\fI/var/lib/alsa/asound.state\fP (or whatever file you specify with the
|
||||||
|
\fB\-f\fP flag) is used to store current settings for your
|
||||||
|
soundcards. The settings include all the usual soundcard mixer
|
||||||
|
settings. More importantly, alsactl is
|
||||||
|
diff --git a/alsactl/alsactl.c b/alsactl/alsactl.c
|
||||||
|
index 3b5dfda..c2120bd 100644
|
||||||
|
--- a/alsactl/alsactl.c
|
||||||
|
+++ b/alsactl/alsactl.c
|
||||||
|
@@ -30,7 +30,9 @@
|
||||||
|
#include <alsa/asoundlib.h>
|
||||||
|
#include "alsactl.h"
|
||||||
|
|
||||||
|
-#define SYS_ASOUNDRC "/etc/asound.state"
|
||||||
|
+#ifndef SYS_ASOUNDRC
|
||||||
|
+#define SYS_ASOUNDRC "/var/lib/alsa/asound.state"
|
||||||
|
+#endif
|
||||||
|
|
||||||
|
int debugflag = 0;
|
||||||
|
int force_restore = 1;
|
||||||
|
diff --git a/configure.in b/configure.in
|
||||||
|
index 54ea74c..94a2b17 100644
|
||||||
|
--- a/configure.in
|
||||||
|
+++ b/configure.in
|
||||||
|
@@ -289,6 +289,12 @@ if test "x$with_systemdsystemunitdir" != xno; then
|
||||||
|
fi
|
||||||
|
AM_CONDITIONAL(HAVE_SYSTEMD, [test -n "$with_systemdsystemunitdir" -a "x$with_systemdsystemunitdir" != xno ])
|
||||||
|
|
||||||
|
+AC_ARG_WITH(ASOUND_STATE_DIR,
|
||||||
|
+ AS_HELP_STRING([--with-asound-state-dir=DIR], [Directory to place asound.state file in]),
|
||||||
|
+ [ASOUND_STATE_DIR="$withval"],
|
||||||
|
+ [ASOUND_STATE_DIR="/var/lib/alsa"])
|
||||||
|
+AC_SUBST(ASOUND_STATE_DIR)
|
||||||
|
+
|
||||||
|
AC_OUTPUT(Makefile alsactl/Makefile alsactl/init/Makefile \
|
||||||
|
alsamixer/Makefile amidi/Makefile amixer/Makefile \
|
||||||
|
m4/Makefile po/Makefile.in \
|
||||||
|
--
|
||||||
|
1.7.3.1
|
||||||
|
|
34
0039-configure.in-Fix-variable-name.patch
Normal file
34
0039-configure.in-Fix-variable-name.patch
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
From 53b08bfc1451937bb19a86e4b116d28cd15c81ac Mon Sep 17 00:00:00 2001
|
||||||
|
From: =?UTF-8?q?Ozan=20=C3=87a=C4=9Flayan?= <ozan@pardus.org.tr>
|
||||||
|
Date: Thu, 25 Nov 2010 09:36:37 +0200
|
||||||
|
Subject: [PATCH] configure.in: Fix variable name
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
Content-Transfer-Encoding: 8bit
|
||||||
|
|
||||||
|
Fix variable name for --with-asound-state-dir as currently we have
|
||||||
|
to pass --with-ASOUND_STATE_DIR= which is wrong and inconsistent with
|
||||||
|
the other switches.
|
||||||
|
|
||||||
|
Signed-off-by: Ozan Çağlayan <ozan@pardus.org.tr>
|
||||||
|
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
||||||
|
---
|
||||||
|
configure.in | 2 +-
|
||||||
|
1 files changed, 1 insertions(+), 1 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/configure.in b/configure.in
|
||||||
|
index 94a2b17..77778da 100644
|
||||||
|
--- a/configure.in
|
||||||
|
+++ b/configure.in
|
||||||
|
@@ -289,7 +289,7 @@ if test "x$with_systemdsystemunitdir" != xno; then
|
||||||
|
fi
|
||||||
|
AM_CONDITIONAL(HAVE_SYSTEMD, [test -n "$with_systemdsystemunitdir" -a "x$with_systemdsystemunitdir" != xno ])
|
||||||
|
|
||||||
|
-AC_ARG_WITH(ASOUND_STATE_DIR,
|
||||||
|
+AC_ARG_WITH([asound-state-dir],
|
||||||
|
AS_HELP_STRING([--with-asound-state-dir=DIR], [Directory to place asound.state file in]),
|
||||||
|
[ASOUND_STATE_DIR="$withval"],
|
||||||
|
[ASOUND_STATE_DIR="/var/lib/alsa"])
|
||||||
|
--
|
||||||
|
1.7.3.1
|
||||||
|
|
2200
alsa-utils-po-pre-patch.diff
Normal file
2200
alsa-utils-po-pre-patch.diff
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,3 +1,42 @@
|
|||||||
|
-------------------------------------------------------------------
|
||||||
|
Fri Nov 26 09:05:03 CET 2010 - tiwai@suse.de
|
||||||
|
|
||||||
|
- backport GIT PATCHES:
|
||||||
|
* A few alsactl init fix patches:
|
||||||
|
0014-alsactl-init-Handle-Capture-Source-and-Mic-Boost-in-.patch
|
||||||
|
0015-alsactl-init-Initialize-also-Master-Front-Playback-V.patch
|
||||||
|
* amixer control-id parse fix
|
||||||
|
0016-amixer-fix-parsing-of-control-ID-name.patch
|
||||||
|
* new aloop utility
|
||||||
|
0017-Introduce-alsaloop-utility.patch
|
||||||
|
0018-alsaloop-Fix-loopbacks-pointer-initialization-and-al.patch
|
||||||
|
0019-alsaloop-Fix-thread-handling.patch
|
||||||
|
0020-alsaloop-fix-a-option-and-slave-mode-processing.patch
|
||||||
|
0021-alsaloop-fix-resample-argument-parsing.patch
|
||||||
|
0022-alsaloop-added-resampling-for-unsupported-soundcard-.patch
|
||||||
|
0023-alsaloop-Add-OSS-mixer-redirection-support.patch
|
||||||
|
0024-alsaloop-Fix-command-line-parsing-and-pollfd-initial.patch
|
||||||
|
0025-alsaloop-Fixes-and-added-workaround-option.patch
|
||||||
|
0026-alsaloop-add-pctl-and-cctl-options.patch
|
||||||
|
0027-alsaloop-add-pctl-and-cctl-options-to-man-page.patch
|
||||||
|
0028-alsaloop-added-xrun-profiling-support-U-xrun-added-S.patch
|
||||||
|
0029-alsaloop-add-U-xrun-to-alsaloop.1-man-page.patch
|
||||||
|
0030-alsaloop-fixes-added-W-wake-option.patch
|
||||||
|
0031-alsaloop-Fix-latency-print.patch
|
||||||
|
0033-alsaloop-Delay-the-restart-a-bit-to-handle-snd-aloop.patch
|
||||||
|
0034-alsaloop-rework-the-ctl-event-handling-routine.patch
|
||||||
|
* robusitfy speaker-test
|
||||||
|
0032-speaker-test-Don-t-retry-after-fatal-errors.patch
|
||||||
|
* misc clean up, translation updates
|
||||||
|
0035-alsamixer-remove-obsolete-e-mail.patch
|
||||||
|
0036-update-German-translations.patch
|
||||||
|
* systemd integration
|
||||||
|
0037-alsactl-systemd-and-udev-hookup.patch
|
||||||
|
0038-alsactl-Move-asound.state-location-to-var-lib-alsa.patch
|
||||||
|
0039-configure.in-Fix-variable-name.patch
|
||||||
|
- Use systemd for openSUSE 11.4
|
||||||
|
- Put udev rules into this package instead of alsa.rpm
|
||||||
|
|
||||||
-------------------------------------------------------------------
|
-------------------------------------------------------------------
|
||||||
Thu Sep 2 16:06:17 CEST 2010 - tiwai@suse.de
|
Thu Sep 2 16:06:17 CEST 2010 - tiwai@suse.de
|
||||||
|
|
||||||
|
@ -17,9 +17,17 @@
|
|||||||
|
|
||||||
# norootforbuild
|
# norootforbuild
|
||||||
|
|
||||||
|
%if %suse_version > 1130
|
||||||
|
%define use_systemd 1
|
||||||
|
%else
|
||||||
|
%define use_systemd 0
|
||||||
|
%endif
|
||||||
|
|
||||||
Name: alsa-utils
|
Name: alsa-utils
|
||||||
BuildRequires: alsa-devel ncurses-devel xmlto
|
BuildRequires: alsa-devel ncurses-devel xmlto pkgconfig
|
||||||
|
%if %use_systemd
|
||||||
|
BuildRequires: systemd
|
||||||
|
%endif
|
||||||
%define package_version 1.0.23
|
%define package_version 1.0.23
|
||||||
License: GPLv2+
|
License: GPLv2+
|
||||||
Group: Productivity/Multimedia/Sound/Players
|
Group: Productivity/Multimedia/Sound/Players
|
||||||
@ -44,8 +52,34 @@ Patch10: 0010-aplay-arecord-term_c_lflag-variable-might-be-unitial.patch
|
|||||||
Patch11: 0011-alsactl-init-Use-Found-hardware-instead-Unknown-hard.patch
|
Patch11: 0011-alsactl-init-Use-Found-hardware-instead-Unknown-hard.patch
|
||||||
Patch12: 0012-alsactl-init-use-generic-method-instead-guess-method.patch
|
Patch12: 0012-alsactl-init-use-generic-method-instead-guess-method.patch
|
||||||
Patch13: 0013-alsactl-Change-handling-of-inactive-controls.patch
|
Patch13: 0013-alsactl-Change-handling-of-inactive-controls.patch
|
||||||
|
Patch14: 0014-alsactl-init-Handle-Capture-Source-and-Mic-Boost-in-.patch
|
||||||
|
Patch15: 0015-alsactl-init-Initialize-also-Master-Front-Playback-V.patch
|
||||||
|
Patch16: 0016-amixer-fix-parsing-of-control-ID-name.patch
|
||||||
|
Patch17: 0017-Introduce-alsaloop-utility.patch
|
||||||
|
Patch18: 0018-alsaloop-Fix-loopbacks-pointer-initialization-and-al.patch
|
||||||
|
Patch19: 0019-alsaloop-Fix-thread-handling.patch
|
||||||
|
Patch20: 0020-alsaloop-fix-a-option-and-slave-mode-processing.patch
|
||||||
|
Patch21: 0021-alsaloop-fix-resample-argument-parsing.patch
|
||||||
|
Patch22: 0022-alsaloop-added-resampling-for-unsupported-soundcard-.patch
|
||||||
|
Patch23: 0023-alsaloop-Add-OSS-mixer-redirection-support.patch
|
||||||
|
Patch24: 0024-alsaloop-Fix-command-line-parsing-and-pollfd-initial.patch
|
||||||
|
Patch25: 0025-alsaloop-Fixes-and-added-workaround-option.patch
|
||||||
|
Patch26: 0026-alsaloop-add-pctl-and-cctl-options.patch
|
||||||
|
Patch27: 0027-alsaloop-add-pctl-and-cctl-options-to-man-page.patch
|
||||||
|
Patch28: 0028-alsaloop-added-xrun-profiling-support-U-xrun-added-S.patch
|
||||||
|
Patch29: 0029-alsaloop-add-U-xrun-to-alsaloop.1-man-page.patch
|
||||||
|
Patch30: 0030-alsaloop-fixes-added-W-wake-option.patch
|
||||||
|
Patch31: 0031-alsaloop-Fix-latency-print.patch
|
||||||
|
Patch32: 0032-speaker-test-Don-t-retry-after-fatal-errors.patch
|
||||||
|
Patch33: 0033-alsaloop-Delay-the-restart-a-bit-to-handle-snd-aloop.patch
|
||||||
|
Patch34: 0034-alsaloop-rework-the-ctl-event-handling-routine.patch
|
||||||
|
Patch35: 0035-alsamixer-remove-obsolete-e-mail.patch
|
||||||
|
Patch36: 0036-update-German-translations.patch
|
||||||
|
Patch37: 0037-alsactl-systemd-and-udev-hookup.patch
|
||||||
|
Patch38: 0038-alsactl-Move-asound.state-location-to-var-lib-alsa.patch
|
||||||
|
Patch39: 0039-configure.in-Fix-variable-name.patch
|
||||||
Patch99: alsa-utils-gettext-version-removal.diff
|
Patch99: alsa-utils-gettext-version-removal.diff
|
||||||
# Patch100: alsa-utils-po-pre-patch.diff
|
Patch100: alsa-utils-po-pre-patch.diff
|
||||||
Url: http://www.alsa-project.org/
|
Url: http://www.alsa-project.org/
|
||||||
BuildRoot: %{_tmppath}/%{name}-%{version}-build
|
BuildRoot: %{_tmppath}/%{name}-%{version}-build
|
||||||
|
|
||||||
@ -65,9 +99,9 @@ Authors:
|
|||||||
# fix stupid automake's automatic action
|
# fix stupid automake's automatic action
|
||||||
sed -i -e's/EXTRA_DIST= config.rpath /EXTRA_DIST=/' Makefile.am
|
sed -i -e's/EXTRA_DIST= config.rpath /EXTRA_DIST=/' Makefile.am
|
||||||
# fix po changes in tarball first
|
# fix po changes in tarball first
|
||||||
# %patch100 -p1
|
%patch100 -p1
|
||||||
# rm -f po/Makefile* po/*.gmo po/*.pot po/*.header po/stamp-*
|
# rm -f po/Makefile* po/*.gmo po/*.pot po/*.header po/stamp-*
|
||||||
# %patch -p1
|
# %%patch -p1
|
||||||
%patch1 -p1
|
%patch1 -p1
|
||||||
%patch2 -p1
|
%patch2 -p1
|
||||||
%patch3 -p1
|
%patch3 -p1
|
||||||
@ -81,6 +115,32 @@ sed -i -e's/EXTRA_DIST= config.rpath /EXTRA_DIST=/' Makefile.am
|
|||||||
%patch11 -p1
|
%patch11 -p1
|
||||||
%patch12 -p1
|
%patch12 -p1
|
||||||
%patch13 -p1
|
%patch13 -p1
|
||||||
|
%patch14 -p1
|
||||||
|
%patch15 -p1
|
||||||
|
%patch16 -p1
|
||||||
|
%patch17 -p1
|
||||||
|
%patch18 -p1
|
||||||
|
%patch19 -p1
|
||||||
|
%patch20 -p1
|
||||||
|
%patch21 -p1
|
||||||
|
%patch22 -p1
|
||||||
|
%patch23 -p1
|
||||||
|
%patch24 -p1
|
||||||
|
%patch25 -p1
|
||||||
|
%patch26 -p1
|
||||||
|
%patch27 -p1
|
||||||
|
%patch28 -p1
|
||||||
|
%patch29 -p1
|
||||||
|
%patch30 -p1
|
||||||
|
%patch31 -p1
|
||||||
|
%patch32 -p1
|
||||||
|
%patch33 -p1
|
||||||
|
%patch34 -p1
|
||||||
|
%patch35 -p1
|
||||||
|
%patch36 -p1
|
||||||
|
%patch37 -p1
|
||||||
|
%patch38 -p1
|
||||||
|
%patch39 -p1
|
||||||
%if %suse_version < 1020
|
%if %suse_version < 1020
|
||||||
%patch99 -p1
|
%patch99 -p1
|
||||||
%endif
|
%endif
|
||||||
@ -91,12 +151,14 @@ export AUTOMAKE_JOBS=%{?jobs:%jobs}
|
|||||||
gettextize -f
|
gettextize -f
|
||||||
%endif
|
%endif
|
||||||
autoreconf -fi
|
autoreconf -fi
|
||||||
%if %suse_version < 1030
|
opts=""
|
||||||
%define moreopts --disable-xmlto
|
%if %suse_version < 1140
|
||||||
%else
|
opts="$opts --with-asound-state-dir=/etc"
|
||||||
%define moreopts
|
|
||||||
%endif
|
%endif
|
||||||
%configure --with-curses=ncursesw %moreopts
|
%if %suse_version < 1030
|
||||||
|
opts="$opts --disable-xmlto"
|
||||||
|
%endif
|
||||||
|
%configure --with-curses=ncursesw $opts
|
||||||
make %{?jobs:-j %jobs}
|
make %{?jobs:-j %jobs}
|
||||||
|
|
||||||
%install
|
%install
|
||||||
@ -117,5 +179,10 @@ make %{?jobs:-j %jobs}
|
|||||||
%{_sbindir}/*
|
%{_sbindir}/*
|
||||||
%{_datadir}/sounds/alsa
|
%{_datadir}/sounds/alsa
|
||||||
%{_datadir}/alsa
|
%{_datadir}/alsa
|
||||||
|
/lib/udev/rules.d/*.rules
|
||||||
|
%if %use_systemd
|
||||||
|
/lib/systemd/system/*.service
|
||||||
|
/lib/systemd/system/*/*.service
|
||||||
|
%endif
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
Loading…
Reference in New Issue
Block a user