Accepting request 59789 from multimedia:libs

Accepted submit request 59789 from user tiwai

OBS-URL: https://build.opensuse.org/request/show/59789
OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/alsa-utils?expand=0&rev=51
This commit is contained in:
Ruediger Oertel 2011-02-03 00:37:43 +00:00 committed by Git OBS Bridge
commit 6c952dfd2d
48 changed files with 16 additions and 12925 deletions

View File

@ -1,332 +0,0 @@
From e509df69a5100df28921980362488f6947df0aae Mon Sep 17 00:00:00 2001
From: Clemens Ladisch <clemens@ladisch.de>
Date: Wed, 26 May 2010 10:07:47 +0200
Subject: [PATCH 01/13] alsactl: use snd_config_imake* functions
To save a call to snd_config_set_xxx, replace the calls to
snd_config_make_xxx with snd_config_imake_xxx.
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
---
alsactl/alsactl.h | 10 ++++----
alsactl/state.c | 43 ++++++++++++----------------------------
alsactl/utils.c | 6 +----
configure.in | 2 +-
seq/aconnect/aconnect.c | 49 ++++++++++++++++++++++++++++++++--------------
5 files changed, 54 insertions(+), 56 deletions(-)
diff --git a/alsactl/alsactl.h b/alsactl/alsactl.h
index be90efb..89ad295 100644
--- a/alsactl/alsactl.h
+++ b/alsactl/alsactl.h
@@ -34,16 +34,16 @@ extern char *statefile;
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
#define cerror(cond, ...) do {\
- if (cond || debugflag) { \
- fprintf(stderr, "%s%s: %s:%d: ", debugflag ? "WARNING: " : "", command, __FUNCTION__, __LINE__); \
+ if (cond) { \
+ fprintf(stderr, "%s: %s:%d: ", command, __FUNCTION__, __LINE__); \
fprintf(stderr, __VA_ARGS__); \
putc('\n', stderr); \
} \
} while (0)
#else
#define cerror(cond, args...) do {\
- if (cond || debugflag) { \
- fprintf(stderr, "%s%s: %s:%d: ", debugflag ? "WARNING: " : "", command, __FUNCTION__, __LINE__); \
+ if (cond) { \
+ fprintf(stderr, "%s: %s:%d: ", command, __FUNCTION__, __LINE__); \
fprintf(stderr, ##args); \
putc('\n', stderr); \
} \
@@ -78,7 +78,7 @@ int generate_names(const char *cfgfile);
int file_map(const char *filename, char **buf, size_t *bufsize);
void file_unmap(void *buf, size_t bufsize);
size_t line_width(const char *buf, size_t bufsize, size_t pos);
-void initfailed(int cardnumber, const char *reason, int exitcode);
+void initfailed(int cardnumber, const char *reason);
static inline int hextodigit(int c)
{
diff --git a/alsactl/state.c b/alsactl/state.c
index e70c6f9..a9ffeea 100644
--- a/alsactl/state.c
+++ b/alsactl/state.c
@@ -58,7 +58,7 @@ static int snd_config_integer_add(snd_config_t *father, char *id, long integer)
{
int err;
snd_config_t *leaf;
- err = snd_config_make_integer(&leaf, id);
+ err = snd_config_imake_integer(&leaf, id, integer);
if (err < 0)
return err;
err = snd_config_add(father, leaf);
@@ -66,11 +66,6 @@ static int snd_config_integer_add(snd_config_t *father, char *id, long integer)
snd_config_delete(leaf);
return err;
}
- err = snd_config_set_integer(leaf, integer);
- if (err < 0) {
- snd_config_delete(leaf);
- return err;
- }
return 0;
}
@@ -78,7 +73,7 @@ static int snd_config_integer64_add(snd_config_t *father, char *id, long long in
{
int err;
snd_config_t *leaf;
- err = snd_config_make_integer64(&leaf, id);
+ err = snd_config_imake_integer64(&leaf, id, integer);
if (err < 0)
return err;
err = snd_config_add(father, leaf);
@@ -86,11 +81,6 @@ static int snd_config_integer64_add(snd_config_t *father, char *id, long long in
snd_config_delete(leaf);
return err;
}
- err = snd_config_set_integer64(leaf, integer);
- if (err < 0) {
- snd_config_delete(leaf);
- return err;
- }
return 0;
}
@@ -98,7 +88,7 @@ static int snd_config_string_add(snd_config_t *father, const char *id, const cha
{
int err;
snd_config_t *leaf;
- err = snd_config_make_string(&leaf, id);
+ err = snd_config_imake_string(&leaf, id, string);
if (err < 0)
return err;
err = snd_config_add(father, leaf);
@@ -106,11 +96,6 @@ static int snd_config_string_add(snd_config_t *father, const char *id, const cha
snd_config_delete(leaf);
return err;
}
- err = snd_config_set_string(leaf, string);
- if (err < 0) {
- snd_config_delete(leaf);
- return err;
- }
return 0;
}
@@ -1117,6 +1102,7 @@ static int restore_config_value2(snd_ctl_t *handle, snd_ctl_elem_info_t *info,
}
snd_ctl_elem_value_set_byte(ctl, idx, val);
return 1;
+ break;
default:
break;
}
@@ -1403,7 +1389,6 @@ static int set_controls(int card, snd_config_t *top, int doit)
snd_ctl_card_info_alloca(&info);
sprintf(name, "hw:%d", card);
- dbg("device='%s', doit=%i", name, doit);
err = snd_ctl_open(&handle, name, 0);
if (err < 0) {
error("snd_ctl_open error: %s", snd_strerror(err));
@@ -1415,7 +1400,6 @@ static int set_controls(int card, snd_config_t *top, int doit)
goto _close;
}
id = snd_ctl_card_info_get_id(info);
- dbg("card-info-id: '%s'", id);
err = snd_config_searchv(top, &control, "state", id, "control", 0);
if (err < 0) {
if (force_restore) {
@@ -1441,25 +1425,24 @@ static int set_controls(int card, snd_config_t *top, int doit)
goto _close;
}
- dbg("maxnumid=%i", maxnumid);
/* check if we have additional controls in driver */
/* in this case we should go through init procedure */
if (!doit && maxnumid >= 0) {
+ snd_ctl_elem_id_t *id;
snd_ctl_elem_info_t *info;
+ snd_ctl_elem_id_alloca(&id);
snd_ctl_elem_info_alloca(&info);
snd_ctl_elem_info_set_numid(info, maxnumid+1);
if (snd_ctl_elem_info(handle, info) == 0) {
/* not very informative */
/* but value is used for check only */
err = -EAGAIN;
- dbg("more controls than maxnumid?");
goto _close;
}
}
_close:
snd_ctl_close(handle);
- dbg("result code: %i", err);
return err;
}
@@ -1584,9 +1567,9 @@ int load_state(const char *file, const char *initfile, const char *cardname,
err = init(initfile, cardname1);
if (err < 0) {
finalerr = err;
- initfailed(card, "init", err);
+ initfailed(card, "init");
}
- initfailed(card, "restore", -ENOENT);
+ initfailed(card, "restore");
}
if (first)
finalerr = 0; /* no cards, no error code */
@@ -1619,14 +1602,14 @@ int load_state(const char *file, const char *initfile, const char *cardname,
sprintf(cardname1, "%i", card);
err = init(initfile, cardname1);
if (err < 0) {
- initfailed(card, "init", err);
+ initfailed(card, "init");
finalerr = err;
}
}
if ((err = set_controls(card, config, 1))) {
if (!force_restore)
finalerr = err;
- initfailed(card, "restore", err);
+ initfailed(card, "restore");
}
}
} else {
@@ -1641,12 +1624,12 @@ int load_state(const char *file, const char *initfile, const char *cardname,
if (do_init && set_controls(cardno, config, 0)) {
err = init(initfile, cardname);
if (err < 0) {
- initfailed(cardno, "init", err);
- finalerr = err;
+ initfailed(cardno, "init");
+ return err;
}
}
if ((err = set_controls(cardno, config, 1))) {
- initfailed(cardno, "restore", err);
+ initfailed(cardno, "restore");
if (!force_restore)
return err;
}
diff --git a/alsactl/utils.c b/alsactl/utils.c
index a27eb6e..ab4dbd4 100644
--- a/alsactl/utils.c
+++ b/alsactl/utils.c
@@ -79,23 +79,19 @@ size_t line_width(const char *buf, size_t bufsize, size_t pos)
return count - pos;
}
-void initfailed(int cardnumber, const char *reason, int exitcode)
+void initfailed(int cardnumber, const char *reason)
{
int fp;
char *str;
- char sexitcode[16];
if (statefile == NULL)
return;
if (snd_card_get_name(cardnumber, &str) < 0)
return;
- sprintf(sexitcode, "%i", exitcode);
fp = open(statefile, O_WRONLY|O_CREAT|O_APPEND, 0644);
write(fp, str, strlen(str));
write(fp, ":", 1);
write(fp, reason, strlen(reason));
- write(fp, ":", 1);
- write(fp, sexitcode, strlen(sexitcode));
write(fp, "\n", 1);
close(fp);
free(str);
diff --git a/configure.in b/configure.in
index 8bae007..66b785f 100644
--- a/configure.in
+++ b/configure.in
@@ -2,7 +2,7 @@ dnl Process this file with autoconf to produce a configure script.
AC_PREREQ(2.59)
AC_INIT(aplay/aplay.c)
AC_PREFIX_DEFAULT(/usr)
-AM_INIT_AUTOMAKE(alsa-utils, 1.0.23)
+AM_INIT_AUTOMAKE(alsa-utils, 1.0.22)
AM_GNU_GETTEXT([external])
AM_GNU_GETTEXT_VERSION([0.15])
diff --git a/seq/aconnect/aconnect.c b/seq/aconnect/aconnect.c
index 8c66cfd..1a50666 100644
--- a/seq/aconnect/aconnect.c
+++ b/seq/aconnect/aconnect.c
@@ -192,33 +192,52 @@ static void remove_connection(snd_seq_t *seq, snd_seq_client_info_t *cinfo,
snd_seq_port_info_t *pinfo, int count)
{
snd_seq_query_subscribe_t *query;
- snd_seq_port_info_t *port;
- snd_seq_port_subscribe_t *subs;
snd_seq_query_subscribe_alloca(&query);
snd_seq_query_subscribe_set_root(query, snd_seq_port_info_get_addr(pinfo));
+
snd_seq_query_subscribe_set_type(query, SND_SEQ_QUERY_SUBS_READ);
snd_seq_query_subscribe_set_index(query, 0);
-
- snd_seq_port_info_alloca(&port);
- snd_seq_port_subscribe_alloca(&subs);
-
- while (snd_seq_query_port_subscribers(seq, query) >= 0) {
+ for (; snd_seq_query_port_subscribers(seq, query) >= 0;
+ snd_seq_query_subscribe_set_index(query, snd_seq_query_subscribe_get_index(query) + 1)) {
+ snd_seq_port_info_t *port;
+ snd_seq_port_subscribe_t *subs;
const snd_seq_addr_t *sender = snd_seq_query_subscribe_get_root(query);
const snd_seq_addr_t *dest = snd_seq_query_subscribe_get_addr(query);
+ snd_seq_port_info_alloca(&port);
+ if (snd_seq_get_any_port_info(seq, dest->client, dest->port, port) < 0)
+ continue;
+ if (!(snd_seq_port_info_get_capability(port) & SND_SEQ_PORT_CAP_SUBS_WRITE))
+ continue;
+ if (snd_seq_port_info_get_capability(port) & SND_SEQ_PORT_CAP_NO_EXPORT)
+ continue;
+ snd_seq_port_subscribe_alloca(&subs);
+ snd_seq_port_subscribe_set_queue(subs, snd_seq_query_subscribe_get_queue(query));
+ snd_seq_port_subscribe_set_sender(subs, sender);
+ snd_seq_port_subscribe_set_dest(subs, dest);
+ snd_seq_unsubscribe_port(seq, subs);
+ }
- if (snd_seq_get_any_port_info(seq, dest->client, dest->port, port) < 0 ||
- !(snd_seq_port_info_get_capability(port) & SND_SEQ_PORT_CAP_SUBS_WRITE) ||
- (snd_seq_port_info_get_capability(port) & SND_SEQ_PORT_CAP_NO_EXPORT)) {
- snd_seq_query_subscribe_set_index(query, snd_seq_query_subscribe_get_index(query) + 1);
+ snd_seq_query_subscribe_set_type(query, SND_SEQ_QUERY_SUBS_WRITE);
+ snd_seq_query_subscribe_set_index(query, 0);
+ for (; snd_seq_query_port_subscribers(seq, query) >= 0;
+ snd_seq_query_subscribe_set_index(query, snd_seq_query_subscribe_get_index(query) + 1)) {
+ snd_seq_port_info_t *port;
+ snd_seq_port_subscribe_t *subs;
+ const snd_seq_addr_t *dest = snd_seq_query_subscribe_get_root(query);
+ const snd_seq_addr_t *sender = snd_seq_query_subscribe_get_addr(query);
+ snd_seq_port_info_alloca(&port);
+ if (snd_seq_get_any_port_info(seq, sender->client, sender->port, port) < 0)
continue;
- }
+ if (!(snd_seq_port_info_get_capability(port) & SND_SEQ_PORT_CAP_SUBS_READ))
+ continue;
+ if (snd_seq_port_info_get_capability(port) & SND_SEQ_PORT_CAP_NO_EXPORT)
+ continue;
+ snd_seq_port_subscribe_alloca(&subs);
snd_seq_port_subscribe_set_queue(subs, snd_seq_query_subscribe_get_queue(query));
snd_seq_port_subscribe_set_sender(subs, sender);
snd_seq_port_subscribe_set_dest(subs, dest);
- if (snd_seq_unsubscribe_port(seq, subs) < 0) {
- snd_seq_query_subscribe_set_index(query, snd_seq_query_subscribe_get_index(query) + 1);
- }
+ snd_seq_unsubscribe_port(seq, subs);
}
}
--
1.7.2.1

View File

@ -1,50 +0,0 @@
From ad47784b01b9dd532ba2c2249547ce55505bbf08 Mon Sep 17 00:00:00 2001
From: Clemens Ladisch <clemens@ladisch.de>
Date: Wed, 26 May 2010 10:18:43 +0200
Subject: [PATCH 02/13] alsactl: move alloca out of loop
Reserving new space from the stack in every loop iteration is not
necessary, so move the call to snd_ctl_elem_id_alloca outside where it
is executed only once.
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
---
alsactl/state.c | 8 ++++----
1 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/alsactl/state.c b/alsactl/state.c
index a9ffeea..86f7748 100644
--- a/alsactl/state.c
+++ b/alsactl/state.c
@@ -523,6 +523,7 @@ static int get_controls(int cardno, snd_config_t *top)
snd_ctl_card_info_t *info;
snd_config_t *state, *card, *control;
snd_ctl_elem_list_t *list;
+ snd_ctl_elem_id_t *elem_id;
unsigned int idx;
int err;
char name[32];
@@ -530,6 +531,7 @@ static int get_controls(int cardno, snd_config_t *top)
const char *id;
snd_ctl_card_info_alloca(&info);
snd_ctl_elem_list_alloca(&list);
+ snd_ctl_elem_id_alloca(&elem_id);
sprintf(name, "hw:%d", cardno);
err = snd_ctl_open(&handle, name, SND_CTL_READONLY);
@@ -604,10 +606,8 @@ static int get_controls(int cardno, snd_config_t *top)
goto _free;
}
for (idx = 0; idx < count; ++idx) {
- snd_ctl_elem_id_t *id;
- snd_ctl_elem_id_alloca(&id);
- snd_ctl_elem_list_get_id(list, idx, id);
- err = get_control(handle, id, control);
+ snd_ctl_elem_list_get_id(list, idx, elem_id);
+ err = get_control(handle, elem_id, control);
if (err < 0)
goto _free;
}
--
1.7.2.1

View File

@ -1,79 +0,0 @@
From 224c12238e484ec795ace29bf5ff712dbae21633 Mon Sep 17 00:00:00 2001
From: Clemens Ladisch <clemens@ladisch.de>
Date: Wed, 26 May 2010 10:19:17 +0200
Subject: [PATCH 03/13] alsactl: remove open-coded search
Remove search_comment_item since it does the same as snd_config_search.
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
---
alsactl/state.c | 30 +++++-------------------------
1 files changed, 5 insertions(+), 25 deletions(-)
diff --git a/alsactl/state.c b/alsactl/state.c
index 86f7748..815345a 100644
--- a/alsactl/state.c
+++ b/alsactl/state.c
@@ -900,31 +900,14 @@ static int add_user_control(snd_ctl_t *handle, snd_ctl_elem_info_t *info, snd_co
}
/*
- * look for a config node with the given item name
- */
-static snd_config_t *search_comment_item(snd_config_t *conf, const char *name)
-{
- snd_config_iterator_t i, next;
- snd_config_for_each(i, next, conf) {
- snd_config_t *n = snd_config_iterator_entry(i);
- const char *id;
- if (snd_config_get_id(n, &id) < 0)
- continue;
- if (strcmp(id, name) == 0)
- return n;
- }
- return NULL;
-}
-
-/*
* check whether the config item has the same of compatible type
*/
static int check_comment_type(snd_config_t *conf, int type)
{
- snd_config_t *n = search_comment_item(conf, "type");
+ snd_config_t *n;
int ctype;
- if (!n)
+ if (snd_config_search(conf, "type", &n) < 0)
return 0; /* not defined */
ctype = get_comment_type(n);
if (ctype == type)
@@ -980,8 +963,7 @@ static int check_comment_range(snd_ctl_t *handle, snd_config_t *conf,
long ndbmin, ndbmax;
snd_ctl_elem_id_t *id;
- n = search_comment_item(conf, "range");
- if (!n)
+ if (snd_config_search(conf, "range", &n) < 0)
return 0;
if (get_comment_range(n, SND_CTL_ELEM_TYPE_INTEGER,
&omin, &omax, &ostep) < 0)
@@ -996,13 +978,11 @@ static int check_comment_range(snd_ctl_t *handle, snd_config_t *conf,
if (omin >= omax || nmin >= nmax)
return 0; /* invalid values */
- n = search_comment_item(conf, "dbmin");
- if (!n)
+ if (snd_config_search(conf, "dbmin", &n) < 0)
return 0;
if (config_integer(n, &odbmin, doit) < 0)
return 0;
- n = search_comment_item(conf, "dbmax");
- if (!n)
+ if (snd_config_search(conf, "dbmax", &n) < 0)
return 0;
if (config_integer(n, &odbmax, doit) < 0)
return 0;
--
1.7.2.1

View File

@ -1,168 +0,0 @@
From 4f29877d54f9132219261218c2357e2b6e8910f4 Mon Sep 17 00:00:00 2001
From: Clemens Ladisch <clemens@ladisch.de>
Date: Wed, 26 May 2010 10:27:25 +0200
Subject: [PATCH 04/13] alsactl: correctly restore dB values of controls with changed range
When the range of a control has changed between driver versions, it is a
good idea to restore the same dB value of the control. However,
computing the dB value by interpolating betweem the min/max dB values
duplicates alsa-lib's TLV functions and does not even work for controls
with a linear dB range.
A simple conversion to dB and back can be done if we add the dB value(s)
to the saved state.
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
---
alsactl/state.c | 85 +++++++++++++++++++++++++++++++++++++++++-------------
1 files changed, 64 insertions(+), 21 deletions(-)
diff --git a/alsactl/state.c b/alsactl/state.c
index 815345a..538fa82 100644
--- a/alsactl/state.c
+++ b/alsactl/state.c
@@ -164,14 +164,18 @@ static unsigned int *str_to_tlv(const char *s)
}
/*
- * add the TLV string and dB ranges to comment fields
+ * add the TLV string, dB ranges, and dB values to comment fields
*/
static int add_tlv_comments(snd_ctl_t *handle, snd_ctl_elem_id_t *id,
- snd_ctl_elem_info_t *info, snd_config_t *comment)
+ snd_ctl_elem_info_t *info, snd_ctl_elem_value_t *ctl,
+ snd_config_t *comment)
{
unsigned int tlv[MAX_USER_TLV_SIZE];
unsigned int *db;
- long dbmin, dbmax;
+ long rangemin, rangemax;
+ long dbmin, dbmax, dbgain;
+ snd_config_t *value;
+ unsigned int i, count;
int err;
if (snd_ctl_elem_tlv_read(handle, id, tlv, sizeof(tlv)) < 0)
@@ -193,13 +197,35 @@ static int add_tlv_comments(snd_ctl_t *handle, snd_ctl_elem_id_t *id,
if (err <= 0)
return 0;
- snd_tlv_get_dB_range(db, snd_ctl_elem_info_get_min(info),
- snd_ctl_elem_info_get_max(info),
- &dbmin, &dbmax);
+ rangemin = snd_ctl_elem_info_get_min(info);
+ rangemax = snd_ctl_elem_info_get_max(info);
+ snd_tlv_get_dB_range(db, rangemin, rangemax, &dbmin, &dbmax);
if (err < 0)
return err;
snd_config_integer_add(comment, "dbmin", dbmin);
snd_config_integer_add(comment, "dbmax", dbmax);
+
+ if (snd_ctl_elem_info_get_type(info) == SND_CTL_ELEM_TYPE_INTEGER) {
+ err = snd_config_compound_add(comment, "dbvalue", 1, &value);
+ if (err < 0) {
+ error("snd_config_compound_add: %s", snd_strerror(err));
+ return err;
+ }
+ count = snd_ctl_elem_info_get_count(info);
+ for (i = 0; i < count; i++) {
+ err = snd_tlv_convert_to_dB(db, rangemin, rangemax,
+ snd_ctl_elem_value_get_integer(ctl, i), &dbgain);
+ if (err < 0) {
+ error("snd_tlv_convert_to_dB: %s", snd_strerror(err));
+ return err;
+ }
+ err = snd_config_integer_add(value, num_str(i), dbgain);
+ if (err < 0) {
+ error("snd_config_integer_add: %s", snd_strerror(err));
+ return err;
+ }
+ }
+ }
return 0;
}
@@ -302,7 +328,7 @@ static int get_control(snd_ctl_t *handle, snd_ctl_elem_id_t *id, snd_config_t *t
return err;
}
if (snd_ctl_elem_info_is_tlv_readable(info)) {
- err = add_tlv_comments(handle, id, info, comment);
+ err = add_tlv_comments(handle, id, info, ctl, comment);
if (err < 0)
return err;
}
@@ -930,20 +956,31 @@ static int check_comment_type(snd_config_t *conf, int type)
static int convert_to_new_db(snd_config_t *value, long omin, long omax,
long nmin, long nmax,
long odbmin, long odbmax,
- long ndbmin, long ndbmax,
+ snd_config_t *comment, const char *index,
+ snd_ctl_t *device, snd_ctl_elem_id_t *id,
int doit)
{
- long val;
- if (config_integer(value, &val, doit) < 0)
- return -EINVAL;
- if (val < omin || val > omax)
- return -EINVAL;
- val = ((val - omin) * (odbmax - odbmin)) / (omax - omin) + odbmin;
- if (val < ndbmin)
- val = ndbmin;
- else if (val > ndbmax)
- val = ndbmax;
- val = ((val - ndbmin) * (nmax - nmin)) / (ndbmax - ndbmin) + nmin;
+ snd_config_t *db_node;
+ long db, val;
+ int err;
+
+ if (snd_config_searchv(comment, &db_node, "dbvalue", index, NULL) < 0 ||
+ snd_config_get_integer(db_node, &db) < 0) {
+ err = config_integer(value, &val, doit);
+ if (err < 0)
+ return err;
+ if (val < omin || val > omax)
+ return -EINVAL;
+ db = ((val - omin) * (odbmax - odbmin)) / (omax - omin) + odbmin;
+ }
+
+ err = snd_ctl_convert_from_dB(device, id, db, &val, db > 0);
+ if (err < 0)
+ return err;
+ if (val < nmin)
+ val = nmin;
+ else if (val > nmax)
+ val = nmax;
return snd_config_set_integer(value, val);
}
@@ -961,6 +998,7 @@ static int check_comment_range(snd_ctl_t *handle, snd_config_t *conf,
long nmin, nmax;
long odbmin, odbmax;
long ndbmin, ndbmax;
+ long db;
snd_ctl_elem_id_t *id;
if (snd_config_search(conf, "range", &n) < 0)
@@ -1003,12 +1041,17 @@ static int check_comment_range(snd_ctl_t *handle, snd_config_t *conf,
snd_config_iterator_t i, next;
snd_config_for_each(i, next, value) {
snd_config_t *n = snd_config_iterator_entry(i);
+ const char *idxstr;
+ if (snd_config_get_id(n, &idxstr) < 0)
+ continue;
convert_to_new_db(n, omin, omax, nmin, nmax,
- odbmin, odbmax, ndbmin, ndbmax, doit);
+ odbmin, odbmax, conf, idxstr,
+ handle, id, doit);
}
} else
convert_to_new_db(value, omin, omax, nmin, nmax,
- odbmin, odbmax, ndbmin, ndbmax, doit);
+ odbmin, odbmax, conf, "0",
+ handle, id, doit);
return 0;
}
--
1.7.2.1

View File

@ -1,88 +0,0 @@
From bd15b1e5ea23d25fcb2ccccd1cf25350c60fe527 Mon Sep 17 00:00:00 2001
From: Clemens Ladisch <clemens@ladisch.de>
Date: Wed, 26 May 2010 10:28:11 +0200
Subject: [PATCH 05/13] alsactl: change format of comment node in state file
Make the comment node a separate node in the state file (join=0), and
move it after the other fields of the respective control.
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
---
alsactl/state.c | 20 +++++++++++++-------
1 files changed, 13 insertions(+), 7 deletions(-)
diff --git a/alsactl/state.c b/alsactl/state.c
index 538fa82..01b1cd6 100644
--- a/alsactl/state.c
+++ b/alsactl/state.c
@@ -266,9 +266,9 @@ static int get_control(snd_ctl_t *handle, snd_ctl_elem_id_t *id, snd_config_t *t
error("snd_config_compound_add: %s", snd_strerror(err));
return err;
}
- err = snd_config_compound_add(control, "comment", 1, &comment);
+ err = snd_config_make_compound(&comment, "comment", 0);
if (err < 0) {
- error("snd_config_compound_add: %s", snd_strerror(err));
+ error("snd_config_make_compound: %s", snd_strerror(err));
return err;
}
@@ -432,7 +432,7 @@ static int get_control(snd_ctl_t *handle, snd_ctl_elem_id_t *id, snd_config_t *t
error("snd_config_string_add: %s", snd_strerror(err));
return err;
}
- return 0;
+ goto finish;
}
default:
break;
@@ -446,21 +446,21 @@ static int get_control(snd_ctl_t *handle, snd_ctl_elem_id_t *id, snd_config_t *t
error("snd_config_string_add: %s", snd_strerror(err));
return err;
}
- return 0;
+ goto finish;
case SND_CTL_ELEM_TYPE_INTEGER:
err = snd_config_integer_add(control, "value", snd_ctl_elem_value_get_integer(ctl, 0));
if (err < 0) {
error("snd_config_integer_add: %s", snd_strerror(err));
return err;
}
- return 0;
+ goto finish;
case SND_CTL_ELEM_TYPE_INTEGER64:
err = snd_config_integer64_add(control, "value", snd_ctl_elem_value_get_integer64(ctl, 0));
if (err < 0) {
error("snd_config_integer64_add: %s", snd_strerror(err));
return err;
}
- return 0;
+ goto finish;
case SND_CTL_ELEM_TYPE_ENUMERATED:
{
unsigned int v = snd_ctl_elem_value_get_enumerated(ctl, 0);
@@ -475,7 +475,7 @@ static int get_control(snd_ctl_t *handle, snd_ctl_elem_id_t *id, snd_config_t *t
}
if (err < 0)
error("snd_config add: %s", snd_strerror(err));
- return 0;
+ goto finish;
}
default:
error("Unknown control type: %d\n", type);
@@ -540,6 +540,12 @@ static int get_control(snd_ctl_t *handle, snd_ctl_elem_id_t *id, snd_config_t *t
return -EINVAL;
}
+finish:
+ err = snd_config_add(control, comment);
+ if (err < 0) {
+ error("snd_config_add: %s", snd_strerror(err));
+ return err;
+ }
return 0;
}
--
1.7.2.1

View File

@ -1,269 +0,0 @@
From b4ff58b685fe9da25901cd3e395dd2f2d64532df Mon Sep 17 00:00:00 2001
From: Clemens Ladisch <clemens@ladisch.de>
Date: Wed, 26 May 2010 10:37:58 +0200
Subject: [PATCH 06/13] Revert wrong parts of "alsactl: use snd_config_imake* functions"
This reverts the parts of commit e509df69a5100df28921980362488f6947df0aae
that accidentally reverted a bunch of earlier commits.
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
---
alsactl/alsactl.h | 10 ++++----
alsactl/state.c | 22 +++++++++++---------
alsactl/utils.c | 6 ++++-
configure.in | 2 +-
seq/aconnect/aconnect.c | 49 ++++++++++++++--------------------------------
5 files changed, 38 insertions(+), 51 deletions(-)
diff --git a/alsactl/alsactl.h b/alsactl/alsactl.h
index 89ad295..be90efb 100644
--- a/alsactl/alsactl.h
+++ b/alsactl/alsactl.h
@@ -34,16 +34,16 @@ extern char *statefile;
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
#define cerror(cond, ...) do {\
- if (cond) { \
- fprintf(stderr, "%s: %s:%d: ", command, __FUNCTION__, __LINE__); \
+ if (cond || debugflag) { \
+ fprintf(stderr, "%s%s: %s:%d: ", debugflag ? "WARNING: " : "", command, __FUNCTION__, __LINE__); \
fprintf(stderr, __VA_ARGS__); \
putc('\n', stderr); \
} \
} while (0)
#else
#define cerror(cond, args...) do {\
- if (cond) { \
- fprintf(stderr, "%s: %s:%d: ", command, __FUNCTION__, __LINE__); \
+ if (cond || debugflag) { \
+ fprintf(stderr, "%s%s: %s:%d: ", debugflag ? "WARNING: " : "", command, __FUNCTION__, __LINE__); \
fprintf(stderr, ##args); \
putc('\n', stderr); \
} \
@@ -78,7 +78,7 @@ int generate_names(const char *cfgfile);
int file_map(const char *filename, char **buf, size_t *bufsize);
void file_unmap(void *buf, size_t bufsize);
size_t line_width(const char *buf, size_t bufsize, size_t pos);
-void initfailed(int cardnumber, const char *reason);
+void initfailed(int cardnumber, const char *reason, int exitcode);
static inline int hextodigit(int c)
{
diff --git a/alsactl/state.c b/alsactl/state.c
index 01b1cd6..7eb107f 100644
--- a/alsactl/state.c
+++ b/alsactl/state.c
@@ -1131,7 +1131,6 @@ static int restore_config_value2(snd_ctl_t *handle, snd_ctl_elem_info_t *info,
}
snd_ctl_elem_value_set_byte(ctl, idx, val);
return 1;
- break;
default:
break;
}
@@ -1418,6 +1417,7 @@ static int set_controls(int card, snd_config_t *top, int doit)
snd_ctl_card_info_alloca(&info);
sprintf(name, "hw:%d", card);
+ dbg("device='%s', doit=%i", name, doit);
err = snd_ctl_open(&handle, name, 0);
if (err < 0) {
error("snd_ctl_open error: %s", snd_strerror(err));
@@ -1429,6 +1429,7 @@ static int set_controls(int card, snd_config_t *top, int doit)
goto _close;
}
id = snd_ctl_card_info_get_id(info);
+ dbg("card-info-id: '%s'", id);
err = snd_config_searchv(top, &control, "state", id, "control", 0);
if (err < 0) {
if (force_restore) {
@@ -1454,24 +1455,25 @@ static int set_controls(int card, snd_config_t *top, int doit)
goto _close;
}
+ dbg("maxnumid=%i", maxnumid);
/* check if we have additional controls in driver */
/* in this case we should go through init procedure */
if (!doit && maxnumid >= 0) {
- snd_ctl_elem_id_t *id;
snd_ctl_elem_info_t *info;
- snd_ctl_elem_id_alloca(&id);
snd_ctl_elem_info_alloca(&info);
snd_ctl_elem_info_set_numid(info, maxnumid+1);
if (snd_ctl_elem_info(handle, info) == 0) {
/* not very informative */
/* but value is used for check only */
err = -EAGAIN;
+ dbg("more controls than maxnumid?");
goto _close;
}
}
_close:
snd_ctl_close(handle);
+ dbg("result code: %i", err);
return err;
}
@@ -1596,9 +1598,9 @@ int load_state(const char *file, const char *initfile, const char *cardname,
err = init(initfile, cardname1);
if (err < 0) {
finalerr = err;
- initfailed(card, "init");
+ initfailed(card, "init", err);
}
- initfailed(card, "restore");
+ initfailed(card, "restore", -ENOENT);
}
if (first)
finalerr = 0; /* no cards, no error code */
@@ -1631,14 +1633,14 @@ int load_state(const char *file, const char *initfile, const char *cardname,
sprintf(cardname1, "%i", card);
err = init(initfile, cardname1);
if (err < 0) {
- initfailed(card, "init");
+ initfailed(card, "init", err);
finalerr = err;
}
}
if ((err = set_controls(card, config, 1))) {
if (!force_restore)
finalerr = err;
- initfailed(card, "restore");
+ initfailed(card, "restore", err);
}
}
} else {
@@ -1653,12 +1655,12 @@ int load_state(const char *file, const char *initfile, const char *cardname,
if (do_init && set_controls(cardno, config, 0)) {
err = init(initfile, cardname);
if (err < 0) {
- initfailed(cardno, "init");
- return err;
+ initfailed(cardno, "init", err);
+ finalerr = err;
}
}
if ((err = set_controls(cardno, config, 1))) {
- initfailed(cardno, "restore");
+ initfailed(cardno, "restore", err);
if (!force_restore)
return err;
}
diff --git a/alsactl/utils.c b/alsactl/utils.c
index ab4dbd4..a27eb6e 100644
--- a/alsactl/utils.c
+++ b/alsactl/utils.c
@@ -79,19 +79,23 @@ size_t line_width(const char *buf, size_t bufsize, size_t pos)
return count - pos;
}
-void initfailed(int cardnumber, const char *reason)
+void initfailed(int cardnumber, const char *reason, int exitcode)
{
int fp;
char *str;
+ char sexitcode[16];
if (statefile == NULL)
return;
if (snd_card_get_name(cardnumber, &str) < 0)
return;
+ sprintf(sexitcode, "%i", exitcode);
fp = open(statefile, O_WRONLY|O_CREAT|O_APPEND, 0644);
write(fp, str, strlen(str));
write(fp, ":", 1);
write(fp, reason, strlen(reason));
+ write(fp, ":", 1);
+ write(fp, sexitcode, strlen(sexitcode));
write(fp, "\n", 1);
close(fp);
free(str);
diff --git a/configure.in b/configure.in
index 66b785f..8bae007 100644
--- a/configure.in
+++ b/configure.in
@@ -2,7 +2,7 @@ dnl Process this file with autoconf to produce a configure script.
AC_PREREQ(2.59)
AC_INIT(aplay/aplay.c)
AC_PREFIX_DEFAULT(/usr)
-AM_INIT_AUTOMAKE(alsa-utils, 1.0.22)
+AM_INIT_AUTOMAKE(alsa-utils, 1.0.23)
AM_GNU_GETTEXT([external])
AM_GNU_GETTEXT_VERSION([0.15])
diff --git a/seq/aconnect/aconnect.c b/seq/aconnect/aconnect.c
index 1a50666..8c66cfd 100644
--- a/seq/aconnect/aconnect.c
+++ b/seq/aconnect/aconnect.c
@@ -192,52 +192,33 @@ static void remove_connection(snd_seq_t *seq, snd_seq_client_info_t *cinfo,
snd_seq_port_info_t *pinfo, int count)
{
snd_seq_query_subscribe_t *query;
+ snd_seq_port_info_t *port;
+ snd_seq_port_subscribe_t *subs;
snd_seq_query_subscribe_alloca(&query);
snd_seq_query_subscribe_set_root(query, snd_seq_port_info_get_addr(pinfo));
-
snd_seq_query_subscribe_set_type(query, SND_SEQ_QUERY_SUBS_READ);
snd_seq_query_subscribe_set_index(query, 0);
- for (; snd_seq_query_port_subscribers(seq, query) >= 0;
- snd_seq_query_subscribe_set_index(query, snd_seq_query_subscribe_get_index(query) + 1)) {
- snd_seq_port_info_t *port;
- snd_seq_port_subscribe_t *subs;
+
+ snd_seq_port_info_alloca(&port);
+ snd_seq_port_subscribe_alloca(&subs);
+
+ while (snd_seq_query_port_subscribers(seq, query) >= 0) {
const snd_seq_addr_t *sender = snd_seq_query_subscribe_get_root(query);
const snd_seq_addr_t *dest = snd_seq_query_subscribe_get_addr(query);
- snd_seq_port_info_alloca(&port);
- if (snd_seq_get_any_port_info(seq, dest->client, dest->port, port) < 0)
- continue;
- if (!(snd_seq_port_info_get_capability(port) & SND_SEQ_PORT_CAP_SUBS_WRITE))
- continue;
- if (snd_seq_port_info_get_capability(port) & SND_SEQ_PORT_CAP_NO_EXPORT)
- continue;
- snd_seq_port_subscribe_alloca(&subs);
- snd_seq_port_subscribe_set_queue(subs, snd_seq_query_subscribe_get_queue(query));
- snd_seq_port_subscribe_set_sender(subs, sender);
- snd_seq_port_subscribe_set_dest(subs, dest);
- snd_seq_unsubscribe_port(seq, subs);
- }
- snd_seq_query_subscribe_set_type(query, SND_SEQ_QUERY_SUBS_WRITE);
- snd_seq_query_subscribe_set_index(query, 0);
- for (; snd_seq_query_port_subscribers(seq, query) >= 0;
- snd_seq_query_subscribe_set_index(query, snd_seq_query_subscribe_get_index(query) + 1)) {
- snd_seq_port_info_t *port;
- snd_seq_port_subscribe_t *subs;
- const snd_seq_addr_t *dest = snd_seq_query_subscribe_get_root(query);
- const snd_seq_addr_t *sender = snd_seq_query_subscribe_get_addr(query);
- snd_seq_port_info_alloca(&port);
- if (snd_seq_get_any_port_info(seq, sender->client, sender->port, port) < 0)
- continue;
- if (!(snd_seq_port_info_get_capability(port) & SND_SEQ_PORT_CAP_SUBS_READ))
+ if (snd_seq_get_any_port_info(seq, dest->client, dest->port, port) < 0 ||
+ !(snd_seq_port_info_get_capability(port) & SND_SEQ_PORT_CAP_SUBS_WRITE) ||
+ (snd_seq_port_info_get_capability(port) & SND_SEQ_PORT_CAP_NO_EXPORT)) {
+ snd_seq_query_subscribe_set_index(query, snd_seq_query_subscribe_get_index(query) + 1);
continue;
- if (snd_seq_port_info_get_capability(port) & SND_SEQ_PORT_CAP_NO_EXPORT)
- continue;
- snd_seq_port_subscribe_alloca(&subs);
+ }
snd_seq_port_subscribe_set_queue(subs, snd_seq_query_subscribe_get_queue(query));
snd_seq_port_subscribe_set_sender(subs, sender);
snd_seq_port_subscribe_set_dest(subs, dest);
- snd_seq_unsubscribe_port(seq, subs);
+ if (snd_seq_unsubscribe_port(seq, subs) < 0) {
+ snd_seq_query_subscribe_set_index(query, snd_seq_query_subscribe_get_index(query) + 1);
+ }
}
}
--
1.7.2.1

View File

@ -1,192 +0,0 @@
From 3bd65336222a4d00cefc4db5e74a7a96c07ab567 Mon Sep 17 00:00:00 2001
From: Jaroslav Kysela <perex@perex.cz>
Date: Thu, 15 Jul 2010 10:40:21 +0200
Subject: [PATCH 07/13] aplay/arecord: Added hardware pause support (press SPACE or Enter)
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
---
aplay/aplay.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 73 insertions(+), 5 deletions(-)
diff --git a/aplay/aplay.c b/aplay/aplay.c
index e1d8e6a..b5203a7 100644
--- a/aplay/aplay.c
+++ b/aplay/aplay.c
@@ -41,6 +41,7 @@
#include <locale.h>
#include <alsa/asoundlib.h>
#include <assert.h>
+#include <termios.h>
#include <sys/poll.h>
#include <sys/uio.h>
#include <sys/time.h>
@@ -102,6 +103,7 @@ static int avail_min = -1;
static int start_delay = 0;
static int stop_delay = 0;
static int monotonic = 0;
+static int can_pause = 0;
static int verbose = 0;
static int vumeter = VUMETER_NONE;
static int buffer_pos = 0;
@@ -1111,6 +1113,7 @@ static void set_params(void)
}
assert(err >= 0);
monotonic = snd_pcm_hw_params_is_monotonic(params);
+ can_pause = snd_pcm_hw_params_can_pause(params);
err = snd_pcm_hw_params(handle, params);
if (err < 0) {
error(_("Unable to install hw params:"));
@@ -1182,7 +1185,7 @@ static void set_params(void)
int i;
err = snd_pcm_mmap_begin(handle, &areas, &offset, &size);
if (err < 0) {
- error("snd_pcm_mmap_begin problem: %s", snd_strerror(err));
+ error(_("snd_pcm_mmap_begin problem: %s"), snd_strerror(err));
prg_exit(EXIT_FAILURE);
}
for (i = 0; i < hwparams.channels; i++)
@@ -1194,6 +1197,65 @@ static void set_params(void)
buffer_frames = buffer_size; /* for position test */
}
+static void init_stdin(void)
+{
+ struct termios term;
+ long flags;
+
+ if (fd == fileno(stdin))
+ return;
+ flags = fcntl(fileno(stdin), F_GETFL);
+ if (flags < 0 || fcntl(fileno(stdin), F_SETFL, flags|O_NONBLOCK) < 0)
+ fprintf(stderr, _("stdin O_NONBLOCK flag setup failed\n"));
+ tcgetattr(fileno(stdin), &term);
+ term.c_lflag &= ~ICANON;
+ tcsetattr(fileno(stdin), TCSANOW, &term);
+}
+
+static void do_pause(void)
+{
+ int err;
+ unsigned char b;
+
+ if (!can_pause) {
+ fprintf(stderr, _("\rPAUSE command ignored (no hw support)\n"));
+ return;
+ }
+ err = snd_pcm_pause(handle, 1);
+ if (err < 0) {
+ error(_("pause push error: %s"), snd_strerror(err));
+ return;
+ }
+ while (1) {
+ while (read(fileno(stdin), &b, 1) != 1);
+ if (b == ' ' || b == '\r') {
+ while (read(fileno(stdin), &b, 1) == 1);
+ err = snd_pcm_pause(handle, 0);
+ if (err < 0)
+ error(_("pause release error: %s"), snd_strerror(err));
+ return;
+ }
+ }
+}
+
+static void check_stdin(void)
+{
+ unsigned char b;
+
+ if (fd != fileno(stdin)) {
+ while (read(fileno(stdin), &b, 1) == 1) {
+ if (b == ' ' || b == '\r') {
+ while (read(fileno(stdin), &b, 1) == 1);
+ fprintf(stderr, _("\r=== PAUSE === "));
+ fflush(stderr);
+ do_pause();
+ fprintf(stderr, " \r");
+ fflush(stderr);
+ }
+ }
+ }
+}
+
#ifndef timersub
#define timersub(a, b, result) \
do { \
@@ -1589,12 +1651,13 @@ static ssize_t pcm_write(u_char *data, size_t count)
while (count > 0) {
if (test_position)
do_test_position();
+ check_stdin();
r = writei_func(handle, data, count);
if (test_position)
do_test_position();
if (r == -EAGAIN || (r >= 0 && (size_t)r < count)) {
if (!test_nowait)
- snd_pcm_wait(handle, 1000);
+ snd_pcm_wait(handle, 100);
} else if (r == -EPIPE) {
xrun();
} else if (r == -ESTRPIPE) {
@@ -1635,12 +1698,13 @@ static ssize_t pcm_writev(u_char **data, unsigned int channels, size_t count)
bufs[channel] = data[channel] + offset * bits_per_sample / 8;
if (test_position)
do_test_position();
+ check_stdin();
r = writen_func(handle, bufs, count);
if (test_position)
do_test_position();
if (r == -EAGAIN || (r >= 0 && (size_t)r < count)) {
if (!test_nowait)
- snd_pcm_wait(handle, 1000);
+ snd_pcm_wait(handle, 100);
} else if (r == -EPIPE) {
xrun();
} else if (r == -ESTRPIPE) {
@@ -1678,12 +1742,13 @@ static ssize_t pcm_read(u_char *data, size_t rcount)
while (count > 0) {
if (test_position)
do_test_position();
+ check_stdin();
r = readi_func(handle, data, count);
if (test_position)
do_test_position();
if (r == -EAGAIN || (r >= 0 && (size_t)r < count)) {
if (!test_nowait)
- snd_pcm_wait(handle, 1000);
+ snd_pcm_wait(handle, 100);
} else if (r == -EPIPE) {
xrun();
} else if (r == -ESTRPIPE) {
@@ -1721,12 +1786,13 @@ static ssize_t pcm_readv(u_char **data, unsigned int channels, size_t rcount)
bufs[channel] = data[channel] + offset * bits_per_sample / 8;
if (test_position)
do_test_position();
+ check_stdin();
r = readn_func(handle, bufs, count);
if (test_position)
do_test_position();
if (r == -EAGAIN || (r >= 0 && (size_t)r < count)) {
if (!test_nowait)
- snd_pcm_wait(handle, 1000);
+ snd_pcm_wait(handle, 100);
} else if (r == -EPIPE) {
xrun();
} else if (r == -ESTRPIPE) {
@@ -2361,6 +2427,7 @@ static void playback(char *name)
fd = fileno(stdin);
name = "stdin";
} else {
+ init_stdin();
if ((fd = open64(name, O_RDONLY, 0)) == -1) {
perror(name);
prg_exit(EXIT_FAILURE);
@@ -2616,6 +2683,7 @@ static void capture(char *orig_name)
if (count > fmt_rec_table[file_type].max_filesize)
count = fmt_rec_table[file_type].max_filesize;
}
+ init_stdin();
do {
/* open a file to write */
--
1.7.2.1

View File

@ -1,75 +0,0 @@
From 73c79ebf26a51a2d9b582a4cae82867873875743 Mon Sep 17 00:00:00 2001
From: Jaroslav Kysela <perex@perex.cz>
Date: Thu, 15 Jul 2010 13:39:14 +0200
Subject: [PATCH 08/13] aplay: fix termio settings - return back old c_flag value on exit
- symptom - ssh client password authentication does not work with
the modified terminal settings
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
---
aplay/aplay.c | 18 +++++++++++++++++-
1 files changed, 17 insertions(+), 1 deletions(-)
diff --git a/aplay/aplay.c b/aplay/aplay.c
index b5203a7..a92ca93 100644
--- a/aplay/aplay.c
+++ b/aplay/aplay.c
@@ -117,6 +117,7 @@ static long long max_file_size = 0;
static int max_file_time = 0;
static int use_strftime = 0;
volatile static int recycle_capture_file = 0;
+static long term_c_lflag = 0;
static int fd = -1;
static off64_t pbrec_count = LLONG_MAX, fdcount;
@@ -128,6 +129,8 @@ static int pidfile_written = 0;
/* needed prototypes */
+static void done_stdin(void);
+
static void playback(char *filename);
static void capture(char *filename);
static void playbackv(char **filenames, unsigned int count);
@@ -343,6 +346,7 @@ static void version(void)
*/
static void prg_exit(int code)
{
+ done_stdin();
if (handle)
snd_pcm_close(handle);
if (pidfile_written)
@@ -1202,16 +1206,28 @@ static void init_stdin(void)
struct termios term;
long flags;
+ tcgetattr(fileno(stdin), &term);
+ term_c_lflag = term.c_lflag;
if (fd == fileno(stdin))
return;
flags = fcntl(fileno(stdin), F_GETFL);
if (flags < 0 || fcntl(fileno(stdin), F_SETFL, flags|O_NONBLOCK) < 0)
fprintf(stderr, _("stdin O_NONBLOCK flag setup failed\n"));
- tcgetattr(fileno(stdin), &term);
term.c_lflag &= ~ICANON;
tcsetattr(fileno(stdin), TCSANOW, &term);
}
+static void done_stdin(void)
+{
+ struct termios term;
+
+ if (fd == fileno(stdin))
+ return;
+ tcgetattr(fileno(stdin), &term);
+ term.c_lflag = term_c_lflag;
+ tcsetattr(fileno(stdin), TCSANOW, &term);
+}
+
static void do_pause(void)
{
int err;
--
1.7.2.1

View File

@ -1,129 +0,0 @@
From 4c337275d1cc0579cc8ad45b4c138287e8658f0d Mon Sep 17 00:00:00 2001
From: Jaroslav Kysela <perex@perex.cz>
Date: Wed, 18 Aug 2010 08:22:23 +0200
Subject: [PATCH 09/13] speaker-test: add test pattern for PCM layer debugging purposes
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
---
speaker-test/speaker-test.c | 75 +++++++++++++++++++++++++++++++++++++++++-
1 files changed, 73 insertions(+), 2 deletions(-)
diff --git a/speaker-test/speaker-test.c b/speaker-test/speaker-test.c
index d8d68e2..458a8d7 100644
--- a/speaker-test/speaker-test.c
+++ b/speaker-test/speaker-test.c
@@ -63,7 +63,8 @@
enum {
TEST_PINK_NOISE = 1,
TEST_SINE,
- TEST_WAV
+ TEST_WAV,
+ TEST_PATTERN,
};
#define MAX_CHANNELS 16
@@ -303,6 +304,71 @@ static void generate_pink_noise( uint8_t *frames, int channel, int count) {
}
}
+/*
+ * useful for tests
+ */
+static void generate_pattern(uint8_t *frames, int channel, int count, int *_pattern) {
+ int pattern = *_pattern;
+ int chn;
+ int8_t *samp8 = (int8_t*) frames;
+ int16_t *samp16 = (int16_t*) frames;
+ int32_t *samp32 = (int32_t*) frames;
+ float *samp_f = (float*) frames;
+
+ while (count-- > 0) {
+ for(chn=0;chn<channels;chn++,pattern++) {
+ switch (format) {
+ case SND_PCM_FORMAT_S8:
+ if (chn==channel) {
+ *samp8++ = pattern & 0xff;
+ } else {
+ *samp8++ = 0;
+ }
+ break;
+ case SND_PCM_FORMAT_S16_LE:
+ if (chn==channel) {
+ *samp16++ = LE_SHORT(pattern & 0xfffff);
+ } else {
+ *samp16++ = 0;
+ }
+ break;
+ case SND_PCM_FORMAT_S16_BE:
+ if (chn==channel) {
+ *samp16++ = BE_SHORT(pattern & 0xffff);
+ } else {
+ *samp16++ = 0;
+ }
+ break;
+ case SND_PCM_FORMAT_FLOAT_LE:
+ if (chn==channel) {
+ *samp_f++ = LE_INT(((double)pattern) / INT32_MAX);
+ } else {
+ *samp_f++ = 0.0;
+ }
+ break;
+ case SND_PCM_FORMAT_S32_LE:
+ if (chn==channel) {
+ *samp32++ = LE_INT(pattern);
+ } else {
+ *samp32++ = 0;
+ }
+ break;
+ case SND_PCM_FORMAT_S32_BE:
+ if (chn==channel) {
+ *samp32++ = BE_INT(pattern);
+ } else {
+ *samp32++ = 0;
+ }
+ break;
+ default:
+ ;
+ }
+ }
+ }
+
+ *_pattern = pattern;
+}
+
static int set_hwparams(snd_pcm_t *handle, snd_pcm_hw_params_t *params, snd_pcm_access_t access) {
unsigned int rrate;
int err;
@@ -687,6 +753,7 @@ static int write_buffer(snd_pcm_t *handle, uint8_t *ptr, int cptr)
static int write_loop(snd_pcm_t *handle, int channel, int periods, uint8_t *frames)
{
double phase = 0;
+ int pattern = 0;
int err, n;
fflush(stdout);
@@ -713,6 +780,8 @@ static int write_loop(snd_pcm_t *handle, int channel, int periods, uint8_t *fram
for(n = 0; n < periods; n++) {
if (test_type == TEST_PINK_NOISE)
generate_pink_noise(frames, channel, period_size);
+ else if (test_type == TEST_PATTERN)
+ generate_pattern(frames, channel, period_size, &pattern);
else
generate_sine(frames, channel, period_size, &phase);
@@ -860,9 +929,11 @@ int main(int argc, char *argv[]) {
test_type = TEST_SINE;
else if (*optarg == 'w')
test_type = TEST_WAV;
+ else if (*optarg == 't')
+ test_type = TEST_PATTERN;
else if (isdigit(*optarg)) {
test_type = atoi(optarg);
- if (test_type < TEST_PINK_NOISE || test_type > TEST_WAV) {
+ if (test_type < TEST_PINK_NOISE || test_type > TEST_PATTERN) {
fprintf(stderr, _("Invalid test type %s\n"), optarg);
exit(1);
}
--
1.7.2.1

View File

@ -1,38 +0,0 @@
From bb865dc10b6dcee9d428d3c5a17ee312e0aaf7e0 Mon Sep 17 00:00:00 2001
From: Jaroslav Kysela <perex@perex.cz>
Date: Wed, 18 Aug 2010 08:23:09 +0200
Subject: [PATCH 10/13] aplay/arecord: term_c_lflag variable might be unitialized in some cases
The term_c_lflag variable might be unitialized in some cases. Add extra
check to avoid setting of wrong value.
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
---
aplay/aplay.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/aplay/aplay.c b/aplay/aplay.c
index a92ca93..c09f23c 100644
--- a/aplay/aplay.c
+++ b/aplay/aplay.c
@@ -117,7 +117,7 @@ static long long max_file_size = 0;
static int max_file_time = 0;
static int use_strftime = 0;
volatile static int recycle_capture_file = 0;
-static long term_c_lflag = 0;
+static long term_c_lflag = -1;
static int fd = -1;
static off64_t pbrec_count = LLONG_MAX, fdcount;
@@ -1221,7 +1221,7 @@ static void done_stdin(void)
{
struct termios term;
- if (fd == fileno(stdin))
+ if (fd == fileno(stdin) || term_c_lflag == -1)
return;
tcgetattr(fileno(stdin), &term);
term.c_lflag = term_c_lflag;
--
1.7.2.1

View File

@ -1,29 +0,0 @@
From dcb90a779e74315596a4cdb4741983b21cba69c9 Mon Sep 17 00:00:00 2001
From: Jaroslav Kysela <perex@perex.cz>
Date: Thu, 2 Sep 2010 15:03:23 +0200
Subject: [PATCH 11/13] alsactl init: Use "Found hardware:" instead "Unknown hardware:"
It seems that "Unknown hardware:" confuses users. Use "Found hardware:"
instead.
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
---
alsactl/init/00main | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/alsactl/init/00main b/alsactl/init/00main
index 2d26bbf..fb7f02c 100644
--- a/alsactl/init/00main
+++ b/alsactl/init/00main
@@ -37,7 +37,7 @@ CARDINFO{driver}=="Test", INCLUDE="test", GOTO="init_end"
LABEL="init_end"
ACCESS=="postinit", INCLUDE="postinit"
RESULT=="true", GOTO="00_mainend"
-ERROR="Unknown hardware: \"$cardinfo{driver}\" \"$cardinfo{mixername}\" \"$cardinfo{components}\" \"$attr{subsystem_vendor}\" \"$attr{subsystem_device}\"\n"
+ERROR="Found hardware: \"$cardinfo{driver}\" \"$cardinfo{mixername}\" \"$cardinfo{components}\" \"$attr{subsystem_vendor}\" \"$attr{subsystem_device}\"\n"
ERROR="Hardware is initialized using a guess method\n"
INCLUDE="default"
EXIT="99"
--
1.7.2.1

View File

@ -1,26 +0,0 @@
From 7f6a55e203e2bb069c35006b605e1a19cfcd88cb Mon Sep 17 00:00:00 2001
From: Jaroslav Kysela <perex@perex.cz>
Date: Thu, 2 Sep 2010 15:36:56 +0200
Subject: [PATCH 12/13] alsactl init: use "generic method" instead "guess method"
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
---
alsactl/init/00main | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/alsactl/init/00main b/alsactl/init/00main
index fb7f02c..660df38 100644
--- a/alsactl/init/00main
+++ b/alsactl/init/00main
@@ -38,7 +38,7 @@ LABEL="init_end"
ACCESS=="postinit", INCLUDE="postinit"
RESULT=="true", GOTO="00_mainend"
ERROR="Found hardware: \"$cardinfo{driver}\" \"$cardinfo{mixername}\" \"$cardinfo{components}\" \"$attr{subsystem_vendor}\" \"$attr{subsystem_device}\"\n"
-ERROR="Hardware is initialized using a guess method\n"
+ERROR="Hardware is initialized using a generic method\n"
INCLUDE="default"
EXIT="99"
--
1.7.2.1

View File

@ -1,76 +0,0 @@
From 0fea2452cb8bca5b5d28daedeb31df7a21284e7d Mon Sep 17 00:00:00 2001
From: Jaroslav Kysela <perex@perex.cz>
Date: Thu, 2 Sep 2010 15:48:43 +0200
Subject: [PATCH 13/13] alsactl: Change handling of inactive controls
The inactive controls are stored, but they are not restored
when they are marked inactive in the state file or in the
driver.
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
---
alsactl/state.c | 13 +++++++------
1 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/alsactl/state.c b/alsactl/state.c
index 7eb107f..7422deb 100644
--- a/alsactl/state.c
+++ b/alsactl/state.c
@@ -251,8 +251,7 @@ static int get_control(snd_ctl_t *handle, snd_ctl_elem_id_t *id, snd_config_t *t
return err;
}
- if (snd_ctl_elem_info_is_inactive(info) ||
- !snd_ctl_elem_info_is_readable(info))
+ if (!snd_ctl_elem_info_is_readable(info))
return 0;
snd_ctl_elem_value_set_id(ctl, id);
err = snd_ctl_elem_read(handle, ctl);
@@ -778,7 +777,7 @@ static int config_integer64(snd_config_t *n, long long *val, int doit)
return err;
}
-static int is_user_control(snd_config_t *conf)
+static int check_comment_access(snd_config_t *conf, const char *str)
{
snd_config_iterator_t i, next;
@@ -790,7 +789,7 @@ static int is_user_control(snd_config_t *conf)
if (strcmp(id, "access") == 0) {
if (snd_config_get_string(n, &s) < 0)
return 0;
- if (strstr(s, "user"))
+ if (strstr(s, str))
return 1;
}
}
@@ -1004,7 +1003,6 @@ static int check_comment_range(snd_ctl_t *handle, snd_config_t *conf,
long nmin, nmax;
long odbmin, odbmax;
long ndbmin, ndbmax;
- long db;
snd_ctl_elem_id_t *id;
if (snd_config_search(conf, "range", &n) < 0)
@@ -1256,7 +1254,7 @@ static int set_control(snd_ctl_t *handle, snd_config_t *control,
snd_ctl_elem_info_set_name(info, name);
snd_ctl_elem_info_set_index(info, index);
err = snd_ctl_elem_info(handle, info);
- if (err < 0 && comment && is_user_control(comment)) {
+ if (err < 0 && comment && check_comment_access(comment, "user")) {
err = add_user_control(handle, info, comment);
if (err < 0) {
cerror(doit, "failed to add user control #%d (%s)",
@@ -1305,6 +1303,9 @@ static int set_control(snd_ctl_t *handle, snd_config_t *control,
return -EINVAL;
}
}
+ /* inactive controls are not restored */
+ if (comment && check_comment_access(comment, "inactive"))
+ return 0;
}
if (snd_ctl_elem_info_is_inactive(info) ||
--
1.7.2.1

View File

@ -1,35 +0,0 @@
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

@ -1,31 +0,0 @@
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

@ -1,27 +0,0 @@
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

@ -1,45 +0,0 @@
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

@ -1,80 +0,0 @@
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

@ -1,85 +0,0 @@
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

@ -1,49 +0,0 @@
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

@ -1,618 +0,0 @@
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

@ -1,317 +0,0 @@
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

@ -1,227 +0,0 @@
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

@ -1,449 +0,0 @@
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

@ -1,149 +0,0 @@
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

@ -1,34 +0,0 @@
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

@ -1,677 +0,0 @@
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

@ -1,30 +0,0 @@
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

@ -1,371 +0,0 @@
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

@ -1,26 +0,0 @@
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

@ -1,32 +0,0 @@
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

@ -1,104 +0,0 @@
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

@ -1,95 +0,0 @@
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

@ -1,88 +0,0 @@
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

@ -1,211 +0,0 @@
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

@ -1,123 +0,0 @@
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

@ -1,34 +0,0 @@
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

View File

@ -1,53 +0,0 @@
From a97bcd19dcea98be86f15c6af0b5e0a8d234d190 Mon Sep 17 00:00:00 2001
From: Colin Guthrie <cguthrie@mandriva.org>
Date: Thu, 25 Nov 2010 21:40:25 +0000
Subject: [PATCH 40/43] alsactl: Add a --with-udev-rules-dir configure option.
After the previous patch to install udev rules it is impossible to do a
non-root, custom-prefix make install. This is generally not a problem
when building official packages but it can be a pain for developers
and debuggers etc.
This is essentially the same patch as was already made in PulseAudio
in commit e8a5746f2fcae59bfd18d39b621509b3ef130453.
Signed-off-by: Colin Guthrie <gmane@colin.guthr.ie>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
---
alsactl/Makefile.am | 2 --
configure.in | 6 ++++++
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/alsactl/Makefile.am b/alsactl/Makefile.am
index 721b619..5cfc415 100644
--- a/alsactl/Makefile.am
+++ b/alsactl/Makefile.am
@@ -11,8 +11,6 @@ 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
-
dist_udevrules_DATA = \
90-alsa-restore.rules
diff --git a/configure.in b/configure.in
index 77778da..2d6c80c 100644
--- a/configure.in
+++ b/configure.in
@@ -112,6 +112,12 @@ if test x"$alsaconf" = xtrue; then
fi
AM_CONDITIONAL(USE_XMLTO, test x"$xmlto" = xyes)
+AC_ARG_WITH(
+ [udev-rules-dir],
+ AS_HELP_STRING([--with-udev-rules-dir],[Directory where to install udev rules to (defaults to /lib/udev/rules.d)]),
+ [udevrulesdir=$withval], [udevrulesdir="/lib/udev/rules.d"])
+AC_SUBST(udevrulesdir)
+
dnl Checks for header files.
AC_HEADER_STDC
if test x$alsamixer = xtrue; then
--
1.7.3.1

View File

@ -1,28 +0,0 @@
From e57f619c82e2fec20c20c30f56d3fa4db22a8353 Mon Sep 17 00:00:00 2001
From: Clemens Ladisch <clemens@ladisch.de>
Date: Mon, 6 Dec 2010 14:04:39 +0100
Subject: [PATCH 41/43] alsamixer: remove obsolete e-mail
Remove the no-longer-valid e-mail address also from the man page.
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
---
alsamixer/alsamixer.1 | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/alsamixer/alsamixer.1 b/alsamixer/alsamixer.1
index ba05aca..cd88404 100644
--- a/alsamixer/alsamixer.1
+++ b/alsamixer/alsamixer.1
@@ -171,7 +171,7 @@ fault. Plain old \fBxterm\fP seems to be fine.
.SH AUTHOR
.B alsamixer
-has been written by Tim Janik <timj@gtk.org> and
+has been written by Tim Janik and
been further improved by Jaroslav Kysela <perex@perex.cz>
and Clemens Ladisch <clemens@ladisch.de>.
--
1.7.3.1

View File

@ -1,40 +0,0 @@
From 70a01748d594ef57a1962e4cb012927faf6d852f Mon Sep 17 00:00:00 2001
From: Clemens Ladisch <clemens@ladisch.de>
Date: Mon, 6 Dec 2010 14:05:10 +0100
Subject: [PATCH 42/43] alsamixer: increase step size for big control value ranges
For controls with a big range, stepping through all values can become
tedious and make it impossible to adjust the volume easily. Therefore,
ensure that all steps are big enough so that the full range has at most
one hundred steps.
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
---
alsamixer/mixer_widget.c | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/alsamixer/mixer_widget.c b/alsamixer/mixer_widget.c
index c8ca156..adb4568 100644
--- a/alsamixer/mixer_widget.c
+++ b/alsamixer/mixer_widget.c
@@ -318,7 +318,7 @@ static void change_volume_to_percent(struct control *control, int value, unsigne
set_func(control->elem, control->volume_channels[1], min + (max - min) * value / 100);
}
-static void change_volume_relative(struct control *control, int delta, unsigned int channels)
+static void change_volume_relative(struct control *control, long delta, unsigned int channels)
{
int (*get_range_func)(snd_mixer_elem_t *, long *, long *);
int (*get_func)(snd_mixer_elem_t *, snd_mixer_selem_channel_id_t, long *);
@@ -352,6 +352,8 @@ static void change_volume_relative(struct control *control, int delta, unsigned
if (err < 0)
return;
}
+ if (max - min > 100)
+ delta = (delta * (max - min) + (delta > 0 ? 99 : -99)) / 100;
if (channels & LEFT) {
value = left + delta;
if (value < min)
--
1.7.3.1

View File

@ -1,538 +0,0 @@
From 34bb514b5fd1d6f91ba9a7b3a70b0ea0c6014250 Mon Sep 17 00:00:00 2001
From: Clemens Ladisch <clemens@ladisch.de>
Date: Mon, 6 Dec 2010 14:07:48 +0100
Subject: [PATCH 43/43] alsamixer: use cubic scale for volume bars
Instead of mapping the raw volume values linearly to the screen, use
a mapping where the bar height is proportional to the audible volume,
i.e., where the amplitude is the cube of the bar height.
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
---
alsamixer/Makefile.am | 1 +
alsamixer/mixer_display.c | 53 ++++---------
alsamixer/mixer_widget.c | 120 +++++++++++-------------------
alsamixer/volume_mapping.c | 180 ++++++++++++++++++++++++++++++++++++++++++++
alsamixer/volume_mapping.h | 19 +++++
5 files changed, 260 insertions(+), 113 deletions(-)
create mode 100644 alsamixer/volume_mapping.c
create mode 100644 alsamixer/volume_mapping.h
diff --git a/alsamixer/Makefile.am b/alsamixer/Makefile.am
index 1de47c6..8a82323 100644
--- a/alsamixer/Makefile.am
+++ b/alsamixer/Makefile.am
@@ -15,6 +15,7 @@ alsamixer_SOURCES = card_select.c card_select.h \
proc_files.c proc_files.h \
textbox.c textbox.h \
utils.c utils.h \
+ volume_mapping.c volume_mapping.h \
widget.c widget.h
man_MANS = alsamixer.1
EXTRA_DIST = alsamixer.1
diff --git a/alsamixer/mixer_display.c b/alsamixer/mixer_display.c
index 20d6d6a..51a1546 100644
--- a/alsamixer/mixer_display.c
+++ b/alsamixer/mixer_display.c
@@ -17,10 +17,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#define _C99_SOURCE /* lrint() */
#include "aconfig.h"
#include <stdlib.h>
#include <string.h>
#include <strings.h>
+#include <math.h>
#include CURSESINC
#include <alsa/asoundlib.h>
#include "gettext_curses.h"
@@ -28,6 +30,7 @@
#include "mem.h"
#include "colors.h"
#include "widget.h"
+#include "volume_mapping.h"
#include "mixer_widget.h"
#include "mixer_controls.h"
#include "mixer_display.h"
@@ -390,24 +393,14 @@ static void display_string_centered_in_control(int y, int col, const char *s, in
display_string_in_field(y, x, s, width, ALIGN_CENTER);
}
-static long clamp(long value, long min, long max)
-{
- if (value < min)
- return min;
- if (value > max)
- return max;
- return value;
-}
-
static void display_control(unsigned int control_index)
{
struct control *control;
int col;
int i, c;
int left, frame_left;
- int bar_height, value;
- long volumes[2];
- long min, max;
+ int bar_height;
+ double volumes[2];
int switches[2];
unsigned int index;
const char *s;
@@ -452,35 +445,22 @@ static void display_control(unsigned int control_index)
waddch(mixer_widget.window, ACS_LRCORNER);
}
if (control->flags & (TYPE_PVOLUME | TYPE_CVOLUME)) {
- int (*get_vol_func)(snd_mixer_elem_t *, snd_mixer_selem_channel_id_t, long *);
+ double (*get_vol_func)(snd_mixer_elem_t *, snd_mixer_selem_channel_id_t);
if (control->flags & TYPE_PVOLUME)
- get_vol_func = snd_mixer_selem_get_playback_volume;
+ get_vol_func = get_normalized_playback_volume;
else
- get_vol_func = snd_mixer_selem_get_capture_volume;
- err = get_vol_func(control->elem, control->volume_channels[0], &volumes[0]);
- if (err >= 0 && (control->flags & HAS_VOLUME_1))
- err = get_vol_func(control->elem, control->volume_channels[1], &volumes[1]);
+ get_vol_func = get_normalized_capture_volume;
+ volumes[0] = get_vol_func(control->elem, control->volume_channels[0]);
+ if (control->flags & HAS_VOLUME_1)
+ volumes[1] = get_vol_func(control->elem, control->volume_channels[1]);
else
volumes[1] = volumes[0];
- if (err < 0)
- return;
- if (control->flags & TYPE_PVOLUME)
- err = snd_mixer_selem_get_playback_volume_range(control->elem, &min, &max);
- else
- err = snd_mixer_selem_get_capture_volume_range(control->elem, &min, &max);
- if (err < 0)
- return;
- if (min >= max)
- max = min + 1;
- volumes[0] = clamp(volumes[0], min, max);
- volumes[1] = clamp(volumes[1], min, max);
if (control->flags & IS_ACTIVE)
wattrset(mixer_widget.window, 0);
for (c = 0; c < 2; c++) {
- bar_height = ((volumes[c] - min) * volume_height +
- max - min - 1) / (max - min);
+ bar_height = lrint(volumes[c] * volume_height);
for (i = 0; i < volume_height; ++i) {
chtype ch;
if (i + 1 > bar_height)
@@ -505,19 +485,18 @@ static void display_control(unsigned int control_index)
}
if (control->flags & IS_ACTIVE)
wattrset(mixer_widget.window, attr_mixer_active);
- value = ((volumes[0] - min) * 100 + (max - min) / 2) / (max - min);
if (!(control->flags & HAS_VOLUME_1)) {
- sprintf(buf, "%d", value);
+ sprintf(buf, "%d", lrint(volumes[0] * 100));
display_string_in_field(values_y, frame_left - 2, buf, 8, ALIGN_CENTER);
} else {
- mvwprintw(mixer_widget.window, values_y, frame_left - 2, "%3d", value);
+ mvwprintw(mixer_widget.window, values_y, frame_left - 2,
+ "%3d", lrint(volumes[0] * 100));
if (control->flags & IS_ACTIVE)
wattrset(mixer_widget.window, attr_ctl_frame);
waddstr(mixer_widget.window, "<>");
if (control->flags & IS_ACTIVE)
wattrset(mixer_widget.window, attr_mixer_active);
- value = ((volumes[1] - min) * 100 + (max - min) / 2) / (max - min);
- wprintw(mixer_widget.window, "%-3d", value);
+ wprintw(mixer_widget.window, "%-3d", lrint(volumes[1] * 100));
}
}
diff --git a/alsamixer/mixer_widget.c b/alsamixer/mixer_widget.c
index adb4568..fb352d3 100644
--- a/alsamixer/mixer_widget.c
+++ b/alsamixer/mixer_widget.c
@@ -33,6 +33,7 @@
#include "textbox.h"
#include "proc_files.h"
#include "card_select.h"
+#include "volume_mapping.h"
#include "mixer_controls.h"
#include "mixer_display.h"
#include "mixer_widget.h"
@@ -295,82 +296,57 @@ static void change_enum_relative(struct control *control, int delta)
static void change_volume_to_percent(struct control *control, int value, unsigned int channels)
{
- int (*get_range_func)(snd_mixer_elem_t *, long *, long *);
- int (*set_func)(snd_mixer_elem_t *, snd_mixer_selem_channel_id_t, long);
- long min, max;
- int err;
+ int (*set_func)(snd_mixer_elem_t *, snd_mixer_selem_channel_id_t, double, int);
if (!(control->flags & HAS_VOLUME_1))
channels = LEFT;
- if (control->flags & TYPE_PVOLUME) {
- get_range_func = snd_mixer_selem_get_playback_volume_range;
- set_func = snd_mixer_selem_set_playback_volume;
- } else {
- get_range_func = snd_mixer_selem_get_capture_volume_range;
- set_func = snd_mixer_selem_set_capture_volume;
- }
- err = get_range_func(control->elem, &min, &max);
- if (err < 0)
- return;
+ if (control->flags & TYPE_PVOLUME)
+ set_func = set_normalized_playback_volume;
+ else
+ set_func = set_normalized_capture_volume;
if (channels & LEFT)
- set_func(control->elem, control->volume_channels[0], min + (max - min) * value / 100);
+ set_func(control->elem, control->volume_channels[0], value / 100.0, 0);
if (channels & RIGHT)
- set_func(control->elem, control->volume_channels[1], min + (max - min) * value / 100);
+ set_func(control->elem, control->volume_channels[1], value / 100.0, 0);
}
-static void change_volume_relative(struct control *control, long delta, unsigned int channels)
+static double clamp_volume(double v)
{
- int (*get_range_func)(snd_mixer_elem_t *, long *, long *);
- int (*get_func)(snd_mixer_elem_t *, snd_mixer_selem_channel_id_t, long *);
- int (*set_func)(snd_mixer_elem_t *, snd_mixer_selem_channel_id_t, long);
- long min, max;
- long left, right;
- long value;
- int err;
+ if (v < 0)
+ return 0;
+ if (v > 1)
+ return 1;
+ return v;
+}
+
+static void change_volume_relative(struct control *control, int delta, unsigned int channels)
+{
+ double (*get_func)(snd_mixer_elem_t *, snd_mixer_selem_channel_id_t);
+ int (*set_func)(snd_mixer_elem_t *, snd_mixer_selem_channel_id_t, double, int);
+ double left, right;
+ int dir;
if (!(control->flags & HAS_VOLUME_1))
channels = LEFT;
if (control->flags & TYPE_PVOLUME) {
- get_range_func = snd_mixer_selem_get_playback_volume_range;
- get_func = snd_mixer_selem_get_playback_volume;
- set_func = snd_mixer_selem_set_playback_volume;
+ get_func = get_normalized_playback_volume;
+ set_func = set_normalized_playback_volume;
} else {
- get_range_func = snd_mixer_selem_get_capture_volume_range;
- get_func = snd_mixer_selem_get_capture_volume;
- set_func = snd_mixer_selem_set_capture_volume;
+ get_func = get_normalized_capture_volume;
+ set_func = set_normalized_capture_volume;
}
- err = get_range_func(control->elem, &min, &max);
- if (err < 0)
- return;
- if (channels & LEFT) {
- err = get_func(control->elem, control->volume_channels[0], &left);
- if (err < 0)
- return;
- }
- if (channels & RIGHT) {
- err = get_func(control->elem, control->volume_channels[1], &right);
- if (err < 0)
- return;
- }
- if (max - min > 100)
- delta = (delta * (max - min) + (delta > 0 ? 99 : -99)) / 100;
+ if (channels & LEFT)
+ left = get_func(control->elem, control->volume_channels[0]);
+ if (channels & RIGHT)
+ right = get_func(control->elem, control->volume_channels[1]);
+ dir = delta > 0 ? 1 : -1;
if (channels & LEFT) {
- value = left + delta;
- if (value < min)
- value = min;
- else if (value > max)
- value = max;
- if (value != left)
- set_func(control->elem, control->volume_channels[0], value);
+ left = clamp_volume(left + delta / 100.0);
+ set_func(control->elem, control->volume_channels[0], left, dir);
}
if (channels & RIGHT) {
- value = right + delta;
- if (value < min)
- value = min;
- else if (value > max)
- value = max;
- if (value != right)
- set_func(control->elem, control->volume_channels[1], value);
+ right = clamp_volume(right + delta / 100.0);
+ set_func(control->elem, control->volume_channels[1], right, dir);
}
}
@@ -460,34 +436,26 @@ static void toggle_capture(unsigned int channels)
static void balance_volumes(void)
{
struct control *control;
- long left, right;
+ double left, right;
int err;
control = get_focus_control(TYPE_PVOLUME | TYPE_CVOLUME);
if (!control || !(control->flags & HAS_VOLUME_1))
return;
if (control->flags & TYPE_PVOLUME) {
- err = snd_mixer_selem_get_playback_volume(control->elem, control->volume_channels[0], &left);
- if (err < 0)
- return;
- err = snd_mixer_selem_get_playback_volume(control->elem, control->volume_channels[1], &right);
- if (err < 0)
- return;
+ left = get_normalized_playback_volume(control->elem, control->volume_channels[0]);
+ right = get_normalized_playback_volume(control->elem, control->volume_channels[1]);
} else {
- err = snd_mixer_selem_get_capture_volume(control->elem, control->volume_channels[0], &left);
- if (err < 0)
- return;
- err = snd_mixer_selem_get_capture_volume(control->elem, control->volume_channels[1], &right);
- if (err < 0)
- return;
+ left = get_normalized_capture_volume(control->elem, control->volume_channels[0]);
+ right = get_normalized_capture_volume(control->elem, control->volume_channels[1]);
}
left = (left + right) / 2;
if (control->flags & TYPE_PVOLUME) {
- snd_mixer_selem_set_playback_volume(control->elem, control->volume_channels[0], left);
- snd_mixer_selem_set_playback_volume(control->elem, control->volume_channels[1], left);
+ set_normalized_playback_volume(control->elem, control->volume_channels[0], left, 0);
+ set_normalized_playback_volume(control->elem, control->volume_channels[1], left, 0);
} else {
- snd_mixer_selem_set_capture_volume(control->elem, control->volume_channels[0], left);
- snd_mixer_selem_set_capture_volume(control->elem, control->volume_channels[1], left);
+ set_normalized_capture_volume(control->elem, control->volume_channels[0], left, 0);
+ set_normalized_capture_volume(control->elem, control->volume_channels[1], left, 0);
}
display_controls();
}
diff --git a/alsamixer/volume_mapping.c b/alsamixer/volume_mapping.c
new file mode 100644
index 0000000..9cacad8
--- /dev/null
+++ b/alsamixer/volume_mapping.c
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2010 Clemens Ladisch <clemens@ladisch.de>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * The functions in this file map the value ranges of ALSA mixer controls onto
+ * the interval 0..1.
+ *
+ * The mapping is designed so that the position in the interval is proportional
+ * to the volume as a human ear would perceive it (i.e., the position is the
+ * cubic root of the linear sample multiplication factor). For controls with
+ * a small range (24 dB or less), the mapping is linear in the dB values so
+ * that each step has the same size visually. Only for controls without dB
+ * information, a linear mapping of the hardware volume register values is used
+ * (this is the same algorithm as used in the old alsamixer).
+ *
+ * When setting the volume, 'dir' is the rounding direction:
+ * -1/0/1 = down/nearest/up.
+ */
+
+#define _ISOC99_SOURCE /* lrint() */
+#define _GNU_SOURCE /* exp10() */
+#include "aconfig.h"
+#include <math.h>
+#include <stdbool.h>
+#include "volume_mapping.h"
+
+#define MAX_LINEAR_DB_SCALE 24
+
+static inline bool use_linear_dB_scale(long dBmin, long dBmax)
+{
+ return dBmax - dBmin <= MAX_LINEAR_DB_SCALE * 100;
+}
+
+static long lrint_dir(double x, int dir)
+{
+ if (dir > 0)
+ return lrint(ceil(x));
+ else if (dir < 0)
+ return lrint(floor(x));
+ else
+ return lrint(x);
+}
+
+enum ctl_dir { PLAYBACK, CAPTURE };
+
+static int (* const get_dB_range[2])(snd_mixer_elem_t *, long *, long *) = {
+ snd_mixer_selem_get_playback_dB_range,
+ snd_mixer_selem_get_capture_dB_range,
+};
+static int (* const get_raw_range[2])(snd_mixer_elem_t *, long *, long *) = {
+ snd_mixer_selem_get_playback_volume_range,
+ snd_mixer_selem_get_capture_volume_range,
+};
+static int (* const get_dB[2])(snd_mixer_elem_t *, snd_mixer_selem_channel_id_t, long *) = {
+ snd_mixer_selem_get_playback_dB,
+ snd_mixer_selem_get_capture_dB,
+};
+static int (* const get_raw[2])(snd_mixer_elem_t *, snd_mixer_selem_channel_id_t, long *) = {
+ snd_mixer_selem_get_playback_volume,
+ snd_mixer_selem_get_capture_volume,
+};
+static int (* const set_dB[2])(snd_mixer_elem_t *, snd_mixer_selem_channel_id_t, long, int) = {
+ snd_mixer_selem_set_playback_dB,
+ snd_mixer_selem_set_capture_dB,
+};
+static int (* const set_raw[2])(snd_mixer_elem_t *, snd_mixer_selem_channel_id_t, long) = {
+ snd_mixer_selem_set_playback_volume,
+ snd_mixer_selem_set_capture_volume,
+};
+
+static double get_normalized_volume(snd_mixer_elem_t *elem,
+ snd_mixer_selem_channel_id_t channel,
+ enum ctl_dir ctl_dir)
+{
+ long min, max, value;
+ double normalized, min_norm;
+ int err;
+
+ err = get_dB_range[ctl_dir](elem, &min, &max);
+ if (err < 0 || min >= max) {
+ err = get_raw_range[ctl_dir](elem, &min, &max);
+ if (err < 0 || min == max)
+ return 0;
+
+ err = get_raw[ctl_dir](elem, channel, &value);
+ if (err < 0)
+ return 0;
+
+ return (value - min) / (double)(max - min);
+ }
+
+ err = get_dB[ctl_dir](elem, channel, &value);
+ if (err < 0)
+ return 0;
+
+ if (use_linear_dB_scale(min, max))
+ return (value - min) / (double)(max - min);
+
+ normalized = exp10((value - max) / 6000.0);
+ if (min != SND_CTL_TLV_DB_GAIN_MUTE) {
+ min_norm = exp10((min - max) / 6000.0);
+ normalized = (normalized - min_norm) / (1 - min_norm);
+ }
+
+ return normalized;
+}
+
+static int set_normalized_volume(snd_mixer_elem_t *elem,
+ snd_mixer_selem_channel_id_t channel,
+ double volume,
+ int dir,
+ enum ctl_dir ctl_dir)
+{
+ long min, max, value;
+ double min_norm;
+ int err;
+
+ err = get_dB_range[ctl_dir](elem, &min, &max);
+ if (err < 0 || min >= max) {
+ err = get_raw_range[ctl_dir](elem, &min, &max);
+ if (err < 0)
+ return err;
+
+ value = lrint_dir(volume * (max - min), dir) + min;
+ return set_raw[ctl_dir](elem, channel, value);
+ }
+
+ if (use_linear_dB_scale(min, max)) {
+ value = lrint_dir(volume * (max - min), dir) + min;
+ return set_dB[ctl_dir](elem, channel, value, dir);
+ }
+
+ if (min != SND_CTL_TLV_DB_GAIN_MUTE) {
+ min_norm = exp10((min - max) / 6000.0);
+ volume = volume * (1 - min_norm) + min_norm;
+ }
+ value = lrint_dir(6000.0 * log10(volume), dir) + max;
+ return set_dB[ctl_dir](elem, channel, value, dir);
+}
+
+double get_normalized_playback_volume(snd_mixer_elem_t *elem,
+ snd_mixer_selem_channel_id_t channel)
+{
+ return get_normalized_volume(elem, channel, PLAYBACK);
+}
+
+double get_normalized_capture_volume(snd_mixer_elem_t *elem,
+ snd_mixer_selem_channel_id_t channel)
+{
+ return get_normalized_volume(elem, channel, CAPTURE);
+}
+
+int set_normalized_playback_volume(snd_mixer_elem_t *elem,
+ snd_mixer_selem_channel_id_t channel,
+ double volume,
+ int dir)
+{
+ return set_normalized_volume(elem, channel, volume, dir, PLAYBACK);
+}
+
+int set_normalized_capture_volume(snd_mixer_elem_t *elem,
+ snd_mixer_selem_channel_id_t channel,
+ double volume,
+ int dir)
+{
+ return set_normalized_volume(elem, channel, volume, dir, CAPTURE);
+}
diff --git a/alsamixer/volume_mapping.h b/alsamixer/volume_mapping.h
new file mode 100644
index 0000000..d4251d6
--- /dev/null
+++ b/alsamixer/volume_mapping.h
@@ -0,0 +1,19 @@
+#ifndef VOLUME_MAPPING_H_INCLUDED
+#define VOLUME_MAPPING_H_INCLUDED
+
+#include <alsa/asoundlib.h>
+
+double get_normalized_playback_volume(snd_mixer_elem_t *elem,
+ snd_mixer_selem_channel_id_t channel);
+double get_normalized_capture_volume(snd_mixer_elem_t *elem,
+ snd_mixer_selem_channel_id_t channel);
+int set_normalized_playback_volume(snd_mixer_elem_t *elem,
+ snd_mixer_selem_channel_id_t channel,
+ double volume,
+ int dir);
+int set_normalized_capture_volume(snd_mixer_elem_t *elem,
+ snd_mixer_selem_channel_id_t channel,
+ double volume,
+ int dir);
+
+#endif
--
1.7.3.1

View File

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b7d05e915e25f8540ad151c6dd558cf0fc1e9bb0ee23052d531c983666a1f7b0
size 1076937

View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:95127f740291086486c06c28118cabca0814bde48fd14dac041a9812a5ac1be2
size 1130734

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,10 @@
-------------------------------------------------------------------
Mon Jan 31 17:21:52 CET 2011 - tiwai@suse.de
- updated to version 1.0.24.2:
* including previous fixes
* add UCM support
-------------------------------------------------------------------
Thu Dec 9 14:03:18 CET 2010 - tiwai@suse.de

View File

@ -1,5 +1,5 @@
#
# spec file for package alsa-utils (Version 1.0.23)
# spec file for package alsa-utils (Version 1.0.24.2)
#
# Copyright (c) 2010 SUSE LINUX Products GmbH, Nuernberg, Germany.
#
@ -27,62 +27,19 @@
Name: alsa-utils
BuildRequires: alsa-devel ncurses-devel pkgconfig xmlto
%define package_version 1.0.23
%define package_version 1.0.24.2
License: GPLv2+
Group: Productivity/Multimedia/Sound/Players
Provides: alsa-conf
Requires: dialog pciutils
AutoReqProv: on
Summary: Advanced Linux Sound Architecture Utilities
Version: 1.0.23
Release: 7
Version: 1.0.24.2
Release: 1
Source: ftp://ftp.alsa-project.org/pub/util/alsa-utils-%{package_version}.tar.bz2
# Patch: alsa-utils-git-fixes.diff
Patch1: 0001-alsactl-use-snd_config_imake-functions.patch
Patch2: 0002-alsactl-move-alloca-out-of-loop.patch
Patch3: 0003-alsactl-remove-open-coded-search.patch
Patch4: 0004-alsactl-correctly-restore-dB-values-of-controls-with.patch
Patch5: 0005-alsactl-change-format-of-comment-node-in-state-file.patch
Patch6: 0006-Revert-wrong-parts-of-alsactl-use-snd_config_imake-f.patch
Patch7: 0007-aplay-arecord-Added-hardware-pause-support-press-SPA.patch
Patch8: 0008-aplay-fix-termio-settings-return-back-old-c_flag-val.patch
Patch9: 0009-speaker-test-add-test-pattern-for-PCM-layer-debuggin.patch
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
Patch40: 0040-alsactl-Add-a-with-udev-rules-dir-configure-option.patch
Patch41: 0041-alsamixer-remove-obsolete-e-mail.patch
Patch42: 0042-alsamixer-increase-step-size-for-big-control-value-r.patch
Patch43: 0043-alsamixer-use-cubic-scale-for-volume-bars.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
@ -102,52 +59,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
%patch1 -p1
%patch2 -p1
%patch3 -p1
%patch4 -p1
%patch5 -p1
%patch6 -p1
%patch7 -p1
%patch8 -p1
%patch9 -p1
%patch10 -p1
%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
%patch40 -p1
%patch41 -p1
%patch42 -p1
%patch43 -p1
%if %suse_version < 1020
%patch99 -p1
%endif