forked from pool/alsa-utils
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:
commit
6c952dfd2d
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:b7d05e915e25f8540ad151c6dd558cf0fc1e9bb0ee23052d531c983666a1f7b0
|
|
||||||
size 1076937
|
|
3
alsa-utils-1.0.24.2.tar.bz2
Normal file
3
alsa-utils-1.0.24.2.tar.bz2
Normal 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
@ -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
|
Thu Dec 9 14:03:18 CET 2010 - tiwai@suse.de
|
||||||
|
|
||||||
|
@ -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.
|
# Copyright (c) 2010 SUSE LINUX Products GmbH, Nuernberg, Germany.
|
||||||
#
|
#
|
||||||
@ -27,62 +27,19 @@
|
|||||||
|
|
||||||
Name: alsa-utils
|
Name: alsa-utils
|
||||||
BuildRequires: alsa-devel ncurses-devel pkgconfig xmlto
|
BuildRequires: alsa-devel ncurses-devel pkgconfig xmlto
|
||||||
%define package_version 1.0.23
|
%define package_version 1.0.24.2
|
||||||
License: GPLv2+
|
License: GPLv2+
|
||||||
Group: Productivity/Multimedia/Sound/Players
|
Group: Productivity/Multimedia/Sound/Players
|
||||||
Provides: alsa-conf
|
Provides: alsa-conf
|
||||||
Requires: dialog pciutils
|
Requires: dialog pciutils
|
||||||
AutoReqProv: on
|
AutoReqProv: on
|
||||||
Summary: Advanced Linux Sound Architecture Utilities
|
Summary: Advanced Linux Sound Architecture Utilities
|
||||||
Version: 1.0.23
|
Version: 1.0.24.2
|
||||||
Release: 7
|
Release: 1
|
||||||
Source: ftp://ftp.alsa-project.org/pub/util/alsa-utils-%{package_version}.tar.bz2
|
Source: ftp://ftp.alsa-project.org/pub/util/alsa-utils-%{package_version}.tar.bz2
|
||||||
# Patch: alsa-utils-git-fixes.diff
|
# 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
|
Patch99: alsa-utils-gettext-version-removal.diff
|
||||||
Patch100: alsa-utils-po-pre-patch.diff
|
# Patch100: alsa-utils-po-pre-patch.diff
|
||||||
Url: http://www.alsa-project.org/
|
Url: http://www.alsa-project.org/
|
||||||
BuildRoot: %{_tmppath}/%{name}-%{version}-build
|
BuildRoot: %{_tmppath}/%{name}-%{version}-build
|
||||||
|
|
||||||
@ -102,52 +59,9 @@ Authors:
|
|||||||
# fix stupid automake's automatic action
|
# fix stupid automake's automatic action
|
||||||
sed -i -e's/EXTRA_DIST= config.rpath /EXTRA_DIST=/' Makefile.am
|
sed -i -e's/EXTRA_DIST= config.rpath /EXTRA_DIST=/' Makefile.am
|
||||||
# fix po changes in tarball first
|
# fix po changes in tarball first
|
||||||
%patch100 -p1
|
# %patch100 -p1
|
||||||
# rm -f po/Makefile* po/*.gmo po/*.pot po/*.header po/stamp-*
|
# rm -f po/Makefile* po/*.gmo po/*.pot po/*.header po/stamp-*
|
||||||
# %%patch -p1
|
# %%patch -p1
|
||||||
%patch1 -p1
|
|
||||||
%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
|
%if %suse_version < 1020
|
||||||
%patch99 -p1
|
%patch99 -p1
|
||||||
%endif
|
%endif
|
||||||
|
Loading…
Reference in New Issue
Block a user