- 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:
Takashi Iwai 2010-11-26 08:10:21 +00:00 committed by Git OBS Bridge
parent 00b6532313
commit 3331bcfb82
29 changed files with 10735 additions and 9 deletions

View File

@ -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

View File

@ -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

View 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

File diff suppressed because it is too large Load Diff

View File

@ -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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -17,9 +17,17 @@
# norootforbuild
%if %suse_version > 1130
%define use_systemd 1
%else
%define use_systemd 0
%endif
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
License: GPLv2+
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
Patch12: 0012-alsactl-init-use-generic-method-instead-guess-method.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
# Patch100: alsa-utils-po-pre-patch.diff
Patch100: alsa-utils-po-pre-patch.diff
Url: http://www.alsa-project.org/
BuildRoot: %{_tmppath}/%{name}-%{version}-build
@ -65,9 +99,9 @@ Authors:
# fix stupid automake's automatic action
sed -i -e's/EXTRA_DIST= config.rpath /EXTRA_DIST=/' Makefile.am
# fix po changes in tarball first
# %patch100 -p1
%patch100 -p1
# rm -f po/Makefile* po/*.gmo po/*.pot po/*.header po/stamp-*
# %patch -p1
# %%patch -p1
%patch1 -p1
%patch2 -p1
%patch3 -p1
@ -81,6 +115,32 @@ sed -i -e's/EXTRA_DIST= config.rpath /EXTRA_DIST=/' Makefile.am
%patch11 -p1
%patch12 -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
%patch99 -p1
%endif
@ -91,12 +151,14 @@ export AUTOMAKE_JOBS=%{?jobs:%jobs}
gettextize -f
%endif
autoreconf -fi
%if %suse_version < 1030
%define moreopts --disable-xmlto
%else
%define moreopts
opts=""
%if %suse_version < 1140
opts="$opts --with-asound-state-dir=/etc"
%endif
%configure --with-curses=ncursesw %moreopts
%if %suse_version < 1030
opts="$opts --disable-xmlto"
%endif
%configure --with-curses=ncursesw $opts
make %{?jobs:-j %jobs}
%install
@ -117,5 +179,10 @@ make %{?jobs:-j %jobs}
%{_sbindir}/*
%{_datadir}/sounds/alsa
%{_datadir}/alsa
/lib/udev/rules.d/*.rules
%if %use_systemd
/lib/systemd/system/*.service
/lib/systemd/system/*/*.service
%endif
%changelog