Merge tag 'v1.2.15.1' of https://github.com/alsa-project/alsa-utils into android-16.0
Release v1.2.15.1 Signed-off-by: Jaroslav Kysela <perex@perex.cz>
This commit is contained in:
commit
c1f0920da1
29 changed files with 2087 additions and 95 deletions
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
|
|
@ -11,7 +11,7 @@ jobs:
|
|||
- name: Prepare environment
|
||||
run: |
|
||||
dnf -y upgrade
|
||||
dnf -y install @development-tools libtool bzip2 gettext-devel ncurses-devel
|
||||
dnf -y install @development-tools libtool bzip2 gettext-devel ncurses-devel awk
|
||||
|
||||
- name: Checkout alsa-lib
|
||||
uses: actions/checkout@v4
|
||||
|
|
|
|||
97
.github/workflows/coverity.yml
vendored
Normal file
97
.github/workflows/coverity.yml
vendored
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
name: Coverity Scan
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
# push:
|
||||
# branches:
|
||||
# - master
|
||||
schedule:
|
||||
# Run once a week on Sunday at 4am UTC
|
||||
- cron: '0 4 * * 0'
|
||||
|
||||
jobs:
|
||||
coverity:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: fedora:latest
|
||||
steps:
|
||||
- name: Prepare environment
|
||||
run: |
|
||||
dnf -y upgrade
|
||||
dnf -y install @development-tools libtool bzip2 gettext-devel ncurses-devel awk curl wget tar file
|
||||
|
||||
- name: Checkout alsa-lib
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: alsa-project/alsa-lib
|
||||
ref: master
|
||||
path: alsa-lib
|
||||
|
||||
- name: Configure alsa-lib
|
||||
run: |
|
||||
cd alsa-lib
|
||||
head -5 configure.ac
|
||||
libtoolize --force --copy --automake
|
||||
aclocal
|
||||
autoheader
|
||||
automake --foreign --copy --add-missing
|
||||
autoconf
|
||||
export CFLAGS="-O2 -Wall -W -Wunused-const-variable=0 -pipe -g"
|
||||
./configure
|
||||
echo "Version: $(cat version)"
|
||||
|
||||
- name: Build alsa-lib
|
||||
run: |
|
||||
cd alsa-lib
|
||||
make
|
||||
|
||||
- name: Install alsa-lib
|
||||
run: |
|
||||
cd alsa-lib
|
||||
make install
|
||||
|
||||
- name: Checkout alsa-utils
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: alsa-utils
|
||||
|
||||
- name: Configure alsa-utils
|
||||
run: |
|
||||
cd alsa-utils
|
||||
mv configure.ac configure.ac.old
|
||||
sed -e 's;po/Makefile.in;;' < configure.ac.old > configure.ac
|
||||
aclocal
|
||||
gettextize -c -f --no-changelog
|
||||
libtoolize --force --copy --automake
|
||||
aclocal -I m4
|
||||
autoheader
|
||||
automake --foreign --copy --add-missing
|
||||
autoconf
|
||||
export CFLAGS="-O2 -Wall -W -Wunused-const-variable=0 -pipe -g"
|
||||
./configure
|
||||
|
||||
- name: Download Coverity Build Tool
|
||||
run: |
|
||||
cd alsa-utils
|
||||
wget -q https://scan.coverity.com/download/linux64 \
|
||||
--post-data "token=${{ secrets.COVERITY_SCAN_TOKEN }}&project=${{ secrets.COVERITY_SCAN_PROJECT }}" \
|
||||
-O coverity_tool.tar.gz
|
||||
mkdir coverity-tool
|
||||
tar xzf coverity_tool.tar.gz --strip-components=1 -C coverity-tool
|
||||
|
||||
- name: Build with Coverity Build Tool
|
||||
run: |
|
||||
cd alsa-utils
|
||||
export PATH="$PWD/coverity-tool/bin:$PATH"
|
||||
cov-build --dir cov-int make
|
||||
|
||||
- name: Submit results to Coverity Scan
|
||||
run: |
|
||||
cd alsa-utils
|
||||
tar czvf alsa-utils.tgz cov-int
|
||||
curl --form token=${{ secrets.COVERITY_SCAN_TOKEN }} \
|
||||
--form email=${{ secrets.COVERITY_SCAN_EMAIL }} \
|
||||
--form file=@alsa-utils.tgz \
|
||||
--form version="$(git describe --tags --always)" \
|
||||
--form description="ALSA Utils Coverity Scan" \
|
||||
https://scan.coverity.com/builds?project=alsa-project%2Falsa-utils
|
||||
|
|
@ -24,8 +24,10 @@ cc_binary {
|
|||
name: "alsactl",
|
||||
srcs: [
|
||||
"alsactl/alsactl.c",
|
||||
"alsactl/boot_params.c",
|
||||
"alsactl/clean.c",
|
||||
"alsactl/daemon.c",
|
||||
"alsactl/export.c",
|
||||
"alsactl/info.c",
|
||||
"alsactl/init_parse.c",
|
||||
"alsactl/init_ucm.c",
|
||||
|
|
@ -33,6 +35,7 @@ cc_binary {
|
|||
"alsactl/monitor.c",
|
||||
"alsactl/state.c",
|
||||
"alsactl/utils.c",
|
||||
"alsactl/wait.c",
|
||||
],
|
||||
cflags: [
|
||||
"-DSYS_ASOUNDRC=\"/data/local/tmp/asound.state\"",
|
||||
|
|
|
|||
8
alsactl/.gitignore
vendored
8
alsactl/.gitignore
vendored
|
|
@ -1,3 +1,5 @@
|
|||
alsa-store.service
|
||||
alsa-restore.service
|
||||
90-alsa-restore.rules
|
||||
conf/90-alsa-restore.rules
|
||||
conf/alsa-state.service
|
||||
conf/alsa-store.service
|
||||
conf/alsa-restore.service
|
||||
conf/alsa-card-wait@.service
|
||||
|
|
|
|||
|
|
@ -11,8 +11,9 @@ AM_CFLAGS = -D_GNU_SOURCE
|
|||
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/include
|
||||
|
||||
alsactl_SOURCES=alsactl.c state.c lock.c utils.c init_parse.c init_ucm.c \
|
||||
daemon.c monitor.c clean.c info.c
|
||||
alsactl_SOURCES=alsactl.c state.c lock.c utils.c wait.c \
|
||||
init_parse.c init_ucm.c boot_params.c \
|
||||
daemon.c monitor.c clean.c info.c export.c
|
||||
|
||||
alsactl_CFLAGS=$(AM_CFLAGS) -D__USE_GNU \
|
||||
-DSYS_ASOUNDRC=\"$(ASOUND_STATE_DIR)/asound.state\" \
|
||||
|
|
@ -24,13 +25,14 @@ noinst_HEADERS=alsactl.h list.h init_sysdeps.c init_utils_string.c \
|
|||
init_utils_run.c init_sysfs.c
|
||||
|
||||
udevrules_DATA = \
|
||||
90-alsa-restore.rules
|
||||
conf/90-alsa-restore.rules
|
||||
|
||||
if HAVE_SYSTEMD
|
||||
|
||||
systemdsystemunit_DATA = \
|
||||
alsa-state.service \
|
||||
alsa-restore.service
|
||||
conf/alsa-state.service \
|
||||
conf/alsa-restore.service \
|
||||
conf/alsa-card-wait@.service
|
||||
|
||||
install-data-hook:
|
||||
$(MKDIR_P) -m 0755 \
|
||||
|
|
@ -45,6 +47,7 @@ endif
|
|||
edit = \
|
||||
extratest=$$(echo ' $(ALSACTL_UDEV_EXTRATEST)' | sed -e 's/__/ /g' -e 's/^ $$//'); \
|
||||
args=$$(echo ' $(ALSACTL_UDEV_ARGS)' | sed -e 's/__/ /g' -e 's/^ $$//'); \
|
||||
mkdir -p conf; \
|
||||
$(SED) -r -e 's,@sbindir\@,$(sbindir),g' \
|
||||
-e 's,@mydatadir\@,$(mydatadir),g' \
|
||||
-e 's,@daemonswitch\@,$(ALSACTL_DAEMONSWITCH),g' \
|
||||
|
|
@ -53,24 +56,29 @@ edit = \
|
|||
-e "s;@args\@;$${args};g" \
|
||||
< $< > $@ || rm $@
|
||||
|
||||
alsa-state.service: alsa-state.service.in
|
||||
conf/alsa-state.service: conf/alsa-state.service.in
|
||||
$(edit)
|
||||
|
||||
alsa-restore.service: alsa-restore.service.in
|
||||
conf/alsa-restore.service: conf/alsa-restore.service.in
|
||||
$(edit)
|
||||
|
||||
90-alsa-restore.rules: 90-alsa-restore.rules.in
|
||||
conf/alsa-card-wait@.service: conf/alsa-card-wait@.service.in
|
||||
$(edit)
|
||||
|
||||
conf/90-alsa-restore.rules: conf/90-alsa-restore.rules.in
|
||||
$(edit)
|
||||
|
||||
EXTRA_DIST += \
|
||||
alsa-state.service.in \
|
||||
alsa-restore.service.in \
|
||||
90-alsa-restore.rules.in
|
||||
conf/alsa-state.service.in \
|
||||
conf/alsa-restore.service.in \
|
||||
conf/alsa-card-wait@.service.in \
|
||||
conf/90-alsa-restore.rules.in
|
||||
|
||||
CLEANFILES = \
|
||||
alsa-state.service \
|
||||
alsa-restore.service \
|
||||
90-alsa-restore.rules
|
||||
conf/alsa-state.service \
|
||||
conf/alsa-restore.service \
|
||||
conf/alsa-card-wait@.service \
|
||||
conf/90-alsa-restore.rules
|
||||
|
||||
%.7: %.xml
|
||||
xmlto man $?
|
||||
|
|
|
|||
|
|
@ -44,14 +44,19 @@
|
|||
#ifndef SYS_LOCKPATH
|
||||
#define SYS_LOCKPATH "/var/lock"
|
||||
#endif
|
||||
#ifndef SYS_CARD_GROUP
|
||||
#define SYS_CARD_GROUP SYS_ASOUND_DIR "/card-group.state"
|
||||
#endif
|
||||
|
||||
int debugflag = 0;
|
||||
int force_restore = 1;
|
||||
int ignore_nocards = 0;
|
||||
int do_lock = 0;
|
||||
int use_syslog = 0;
|
||||
int do_export = 0;
|
||||
char *command;
|
||||
char *statefile = NULL;
|
||||
char *groupfile = SYS_CARD_GROUP;
|
||||
char *lockpath = SYS_LOCKPATH;
|
||||
char *lockfile = SYS_LOCKFILE;
|
||||
|
||||
|
|
@ -78,6 +83,7 @@ static struct arg args[] = {
|
|||
{ 'v', "version", "print version of this program" },
|
||||
{ HEADER, NULL, "Available state options:" },
|
||||
{ FILEARG | 'f', "file", "configuration file (default " SYS_ASOUNDRC ")" },
|
||||
{ FILEARG | 'G', "group-file", "card group configuration file (default " SYS_CARD_GROUP ")" },
|
||||
{ FILEARG | 'a', "config-dir", "boot / hotplug configuration directory (default " SYS_ASOUND_DIR ")" },
|
||||
{ 'l', "lock", "use file locking to serialize concurrent access" },
|
||||
{ 'L', "no-lock", "do not use file locking to serialize concurrent access" },
|
||||
|
|
@ -92,6 +98,7 @@ static struct arg args[] = {
|
|||
{ FILEARG | 'r', "runstate", "save restore and init state to this file (only errors)" },
|
||||
{ 0, NULL, " default settings is 'no file set'" },
|
||||
{ 'R', "remove", "remove runstate file at first, otherwise append errors" },
|
||||
{ 'Y', "export", "export card state as key=value pairs (restore command only)" },
|
||||
{ INTARG | 'p', "period", "store period in seconds for the daemon command" },
|
||||
{ FILEARG | 'e', "pid-file", "pathname for the process id (daemon mode)" },
|
||||
{ HEADER, NULL, "Available init options:" },
|
||||
|
|
@ -105,6 +112,7 @@ static struct arg args[] = {
|
|||
#ifdef HAVE_ALSA_USE_CASE_H
|
||||
{ 'D', "ucm-defaults", "execute also the UCM 'defaults' section" },
|
||||
{ 'U', "no-ucm", "don't init with UCM" },
|
||||
{ 'm', "force-ucm-restore", "force UCM restore for boot card groups" },
|
||||
#if SND_LIB_VER(1, 2, 5) < SND_LIB_VERSION
|
||||
{ 'X', "ucm-nodev", "show UCM no device errors" },
|
||||
#endif
|
||||
|
|
@ -115,6 +123,7 @@ static struct arg args[] = {
|
|||
{ CARDCMD, "restore", "load current driver setup for one or each soundcards" },
|
||||
{ EMPCMD, NULL, " from configuration file" },
|
||||
{ CARDCMD, "nrestore", "like restore, but notify the daemon to rescan soundcards" },
|
||||
{ CARDCMD, "wrestore", "wait for card ready, then restore" },
|
||||
{ CARDCMD, "init", "initialize driver to a default state" },
|
||||
{ CARDCMD, "daemon", "store state periodically for one or each soundcards" },
|
||||
{ CARDCMD, "rdaemon", "like daemon but do the state restore at first" },
|
||||
|
|
@ -301,6 +310,9 @@ int main(int argc, char *argv[])
|
|||
case 'f':
|
||||
cfgfile = optarg;
|
||||
break;
|
||||
case 'G':
|
||||
groupfile = optarg;
|
||||
break;
|
||||
case 'a':
|
||||
cfgdir = optarg;
|
||||
break;
|
||||
|
|
@ -341,6 +353,9 @@ int main(int argc, char *argv[])
|
|||
case 'U':
|
||||
initflags |= FLAG_UCM_DISABLED;
|
||||
break;
|
||||
case 'm':
|
||||
initflags |= FLAG_UCM_RESTORE;
|
||||
break;
|
||||
case 'X':
|
||||
initflags |= FLAG_UCM_NODEV;
|
||||
break;
|
||||
|
|
@ -350,6 +365,9 @@ int main(int argc, char *argv[])
|
|||
case 'R':
|
||||
removestate = 1;
|
||||
break;
|
||||
case 'Y':
|
||||
do_export = 1;
|
||||
break;
|
||||
case 'P':
|
||||
force_restore = 0;
|
||||
break;
|
||||
|
|
@ -441,7 +459,11 @@ int main(int argc, char *argv[])
|
|||
syslog(LOG_INFO, "alsactl " SND_UTIL_VERSION_STR " daemon started");
|
||||
}
|
||||
|
||||
#if SND_LIB_VER(1, 2, 15) < SND_LIB_VERSION
|
||||
snd_lib_error_set_handler(error_handler);
|
||||
#else
|
||||
snd_lib_log_set_handler(log_handler);
|
||||
#endif
|
||||
|
||||
if (!strcmp(cmd, "init")) {
|
||||
res = init(cfgdir, initfile, initflags | FLAG_UCM_FBOOT | FLAG_UCM_BOOT, cardname);
|
||||
|
|
@ -450,10 +472,15 @@ int main(int argc, char *argv[])
|
|||
res = save_state(cfgfile, cardname);
|
||||
} else if (!strcmp(cmd, "restore") ||
|
||||
!strcmp(cmd, "rdaemon") ||
|
||||
!strcmp(cmd, "nrestore")) {
|
||||
!strcmp(cmd, "nrestore") ||
|
||||
!strcmp(cmd, "wrestore")) {
|
||||
if (removestate)
|
||||
remove(statefile);
|
||||
if (!strcmp(cmd, "wrestore"))
|
||||
initflags |= FLAG_UCM_WAIT;
|
||||
res = load_state(cfgdir, cfgfile, initfile, initflags, cardname, init_fallback);
|
||||
if (do_export && res >= 0)
|
||||
res = export_cards(cardname);
|
||||
if (!strcmp(cmd, "rdaemon")) {
|
||||
do_nice(use_nice, sched_idle);
|
||||
res = state_daemon(cfgfile, cardname, period, pidfile);
|
||||
|
|
|
|||
|
|
@ -2,14 +2,17 @@
|
|||
#include <alsa/asoundlib.h>
|
||||
|
||||
#define LOCK_TIMEOUT 10
|
||||
#define DEFAULT_SYNC_TIME 20
|
||||
|
||||
extern int debugflag;
|
||||
extern int force_restore;
|
||||
extern int ignore_nocards;
|
||||
extern int do_lock;
|
||||
extern int use_syslog;
|
||||
extern int do_export;
|
||||
extern char *command;
|
||||
extern char *statefile;
|
||||
extern char *groupfile;
|
||||
extern char *lockpath;
|
||||
extern char *lockfile;
|
||||
|
||||
|
|
@ -24,7 +27,8 @@ void info_(const char *fcn, long line, const char *fmt, ...);
|
|||
void error_(const char *fcn, long line, const char *fmt, ...);
|
||||
void cerror_(const char *fcn, long line, int cond, const char *fmt, ...);
|
||||
void dbg_(const char *fcn, long line, const char *fmt, ...);
|
||||
void error_handler(const char *file, int line, const char *function, int err, const char *fmt, ...);
|
||||
void error_handler(const char *file, int line, const char *function, int errcode, const char *fmt, ...);
|
||||
void log_handler(int prio, int interface, const char *file, int line, const char *function, int errcode, const char *fmt, va_list arg);
|
||||
|
||||
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
|
||||
#define info(...) do { info_(__func__, __LINE__, __VA_ARGS__); } while (0)
|
||||
|
|
@ -43,6 +47,19 @@ void error_handler(const char *file, int line, const char *function, int err, co
|
|||
#define FLAG_UCM_BOOT (1<<2)
|
||||
#define FLAG_UCM_DEFAULTS (1<<3)
|
||||
#define FLAG_UCM_NODEV (1<<4)
|
||||
#define FLAG_UCM_RESTORE (1<<5)
|
||||
#define FLAG_UCM_WAIT (1<<6)
|
||||
|
||||
enum {
|
||||
CARD_STATE_WAIT = 1, /* skip configuration (wait for sync) */
|
||||
CARD_STATE_SKIP = 2, /* skip card */
|
||||
CARD_STATE_RESTORED = 3, /* card was restored */
|
||||
};
|
||||
|
||||
static inline bool card_state_is_okay(int state)
|
||||
{
|
||||
return state >= CARD_STATE_WAIT && state <= CARD_STATE_RESTORED;
|
||||
}
|
||||
|
||||
void snd_card_iterator_init(struct snd_card_iterator *iter, int cardno);
|
||||
int snd_card_iterator_sinit(struct snd_card_iterator *iter, const char *cardname);
|
||||
|
|
@ -52,14 +69,27 @@ int snd_card_iterator_error(struct snd_card_iterator *iter);
|
|||
int load_configuration(const char *file, snd_config_t **top, int *open_failed);
|
||||
int init(const char *cfgdir, const char *file, int flags, const char *cardname);
|
||||
int init_ucm(int flags, int cardno);
|
||||
bool validate_boot_time(long long boot_time, long long current_time, long long synctime);
|
||||
int read_boot_params(snd_ctl_t *handle, long long *boot_time, long long *sync_time, long long *restore_time, long long *primary_card);
|
||||
int write_boot_params(snd_ctl_t *handle, long long boot_time, long long sync_time, long long restore_time, long long primary_card);
|
||||
int card_group_load(snd_config_t **config);
|
||||
int card_group_save(snd_config_t *config);
|
||||
int card_group_get_int64(snd_config_t *config_group, const char *id, long long *val);
|
||||
int card_group_set_int64(snd_config_t *config_group, const char *id, long long val);
|
||||
int check_boot_params_validity(snd_ctl_t *handle, int cardno, char **boot_card_group, bool *valid, bool *in_sync, bool *restored, int *primary_card, long long *synctime);
|
||||
int update_boot_params(snd_ctl_t *handle, int cardno, const char *boot_card_group, bool valid, bool restored, long long synctime);
|
||||
int boot_params_remove_card(int cardno);
|
||||
int state_lock(const char *file, int timeout);
|
||||
int state_unlock(int lock_fd, const char *file);
|
||||
int card_lock(int card_number, int timeout);
|
||||
int card_unlock(int lock_fd, int card_number);
|
||||
int group_state_lock(const char *file, int timeout);
|
||||
int group_state_unlock(int lock_fd, const char *file);
|
||||
int save_state(const char *file, const char *cardname);
|
||||
int load_state(const char *cfgdir, const char *file,
|
||||
const char *initfile, int initflags,
|
||||
const char *cardname, int do_init);
|
||||
int wait_for_card(long long timeout, int cardno);
|
||||
int power(const char *argv[], int argc);
|
||||
int monitor(const char *name);
|
||||
int general_info(const char *name);
|
||||
|
|
@ -68,6 +98,12 @@ int state_daemon(const char *file, const char *cardname, int period,
|
|||
int state_daemon_kill(const char *pidfile, const char *cmd);
|
||||
int clean(const char *cardname, char *const *extra_args);
|
||||
int snd_card_clean_cfgdir(const char *cfgdir, int cardno);
|
||||
void add_linked_card(int cardno);
|
||||
|
||||
/* export */
|
||||
|
||||
int export_card_state_set(int card, int state);
|
||||
int export_cards(const char *cardname);
|
||||
|
||||
/* utils */
|
||||
|
||||
|
|
|
|||
1085
alsactl/boot_params.c
Normal file
1085
alsactl/boot_params.c
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -8,7 +8,7 @@ LABEL="alsa_restore_go"
|
|||
ENV{ALSA_CARD_NUMBER}="$attr{device/number}"
|
||||
|
||||
# mark HDA analog card; HDMI/DP card does not have capture devices
|
||||
DRIVERS=="snd_hda_intel", TEST=="device/pcmC$env{ALSA_CARD_NUMBER}D0p", RUN+="/bin/sh -c 'echo ALSA_CARD_HDA_ANALOG=$env{ALSA_CARD_NUMBER} >> /run/udev/alsa-hda-analog-card'"
|
||||
DRIVERS=="snd_hda_intel", TEST=="device/pcmC$env{ALSA_CARD_NUMBER}D0c", RUN+="/bin/sh -c 'echo ALSA_CARD_HDA_ANALOG=$env{ALSA_CARD_NUMBER} >> /run/udev/alsa-hda-analog-card'"
|
||||
|
||||
# check for ACP hardware
|
||||
TEST=="device/device/acp3x-dmic-capture", GOTO="alsa_hda_analog"
|
||||
|
|
@ -24,7 +24,8 @@ IMPORT{program}="/usr/bin/cat /run/udev/alsa-hda-analog-card"
|
|||
ENV{ALSA_CARD_HDA_ANALOG}!="", ENV{ALSA_CARD_NUMBER}="$env{ALSA_CARD_HDA_ANALOG}"
|
||||
|
||||
LABEL="alsa_restore_std"
|
||||
TEST!="@daemonswitch@", RUN+="@sbindir@/alsactl@args@ restore $env{ALSA_CARD_NUMBER}"
|
||||
TEST=="@daemonswitch@", RUN+="@sbindir@/alsactl@args@ nrestore $env{ALSA_CARD_NUMBER}"
|
||||
TEST!="@daemonswitch@", IMPORT{program}="@sbindir@/alsactl@args@ --export restore $env{ALSA_CARD_NUMBER}"
|
||||
TEST=="@daemonswitch@", IMPORT{program}="@sbindir@/alsactl@args@ --export nrestore $env{ALSA_CARD_NUMBER}"
|
||||
ENV{ALSA_CARD_STATE}=="waiting", ENV{SYSTEMD_WANTS}="alsa-card-wait@$env{ALSA_CARD_NUMBER}.service"
|
||||
|
||||
LABEL="alsa_restore_end"
|
||||
12
alsactl/conf/alsa-card-wait@.service.in
Normal file
12
alsactl/conf/alsa-card-wait@.service.in
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#
|
||||
# ALSA card initialization handler for cards in waiting state
|
||||
# This service is triggered by udev when ALSA_CARD_STATE=waiting
|
||||
#
|
||||
|
||||
[Unit]
|
||||
Description=ALSA Card Initialization for card %I
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
RemainAfterExit=no
|
||||
ExecStart=@sbindir@/alsactl@args@ wrestore %i
|
||||
133
alsactl/export.c
Normal file
133
alsactl/export.c
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* Advanced Linux Sound Architecture Control Program - Export
|
||||
* Copyright (c) by Jaroslav Kysela <perex@perex.cz>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Export variable syntax:
|
||||
*
|
||||
* For single card:
|
||||
*
|
||||
* ALSA_CARD_NUMBER=<number>
|
||||
* ALSA_CARD_STATE=<state>
|
||||
*
|
||||
* For multiple cards:
|
||||
*
|
||||
* ALSA_CARD#_STATE=<state> # where # is replaced with the card number
|
||||
*
|
||||
* State list:
|
||||
*
|
||||
* active # card was initialized and active
|
||||
* skip # card was skipped (other card in group)
|
||||
* waiting # card is waiting for the initial configuration
|
||||
*/
|
||||
|
||||
#include "aconfig.h"
|
||||
#include "version.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "alsactl.h"
|
||||
|
||||
/* Global array to store card states (0 = active, 1 = waiting) */
|
||||
static int export_card_state[32];
|
||||
|
||||
/**
|
||||
* export_card_state_set - Set card state
|
||||
* @card: Card number
|
||||
* @state: Card state (0 = active, 1 = waiting)
|
||||
*
|
||||
* Returns 0 on success, negative error code on failure
|
||||
*/
|
||||
int export_card_state_set(int card, int state)
|
||||
{
|
||||
/* Check bounds */
|
||||
if (card < 0 || (unsigned long)card >= ARRAY_SIZE(export_card_state))
|
||||
return -EINVAL;
|
||||
|
||||
export_card_state[card] = state;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* export_card_state_print - Export and print card state information
|
||||
* @iter: Card iterator containing current card information
|
||||
*
|
||||
* Prints key=value pairs based on iterator's single flag and export_card_state array.
|
||||
* Returns 0 on success, negative error code on failure
|
||||
*/
|
||||
static int export_card_state_print(struct snd_card_iterator *iter)
|
||||
{
|
||||
const char *state;
|
||||
int istate;
|
||||
|
||||
if (!iter)
|
||||
return -EINVAL;
|
||||
|
||||
/* Check bounds */
|
||||
if (iter->card < 0 || (unsigned long)iter->card >= ARRAY_SIZE(export_card_state))
|
||||
return -EINVAL;
|
||||
|
||||
/* Determine state from export_card_state array */
|
||||
istate = export_card_state[iter->card];
|
||||
switch (istate) {
|
||||
case CARD_STATE_WAIT: state = "waiting"; break;
|
||||
case CARD_STATE_SKIP: state = "skip"; break;
|
||||
default: state = "active"; break;
|
||||
}
|
||||
|
||||
if (iter->single) {
|
||||
/* Single card export format */
|
||||
printf("ALSA_CARD_NUMBER=%d\n", iter->card);
|
||||
printf("ALSA_CARD_STATE=%s\n", state);
|
||||
} else {
|
||||
/* Multiple cards export format */
|
||||
printf("ALSA_CARD%d_STATE=%s\n", iter->card, state);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* export_cards - Export state for all cards
|
||||
* @cardname: Card name or NULL for all cards
|
||||
*
|
||||
* Returns 0 on success, negative error code on failure
|
||||
*/
|
||||
int export_cards(const char *cardname)
|
||||
{
|
||||
struct snd_card_iterator iter;
|
||||
const char *name;
|
||||
int ret;
|
||||
|
||||
ret = snd_card_iterator_sinit(&iter, cardname);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
while ((name = snd_card_iterator_next(&iter)) != NULL) {
|
||||
ret = export_card_state_print(&iter);
|
||||
if (ret < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret == 0)
|
||||
ret = snd_card_iterator_error(&iter);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1762,7 +1762,7 @@ int init(const char *cfgdir, const char *filename, int flags, const char *cardna
|
|||
continue;
|
||||
}
|
||||
err = init_ucm(flags, iter.card);
|
||||
if (err == 0)
|
||||
if (err == 0 || card_state_is_okay(err))
|
||||
continue;
|
||||
err = init_space(&space, iter.card);
|
||||
if (err != 0)
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@
|
|||
|
||||
#include "aconfig.h"
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include "alsactl.h"
|
||||
|
||||
#ifdef HAVE_ALSA_USE_CASE_H
|
||||
|
|
@ -28,45 +30,269 @@
|
|||
#include <alsa/use-case.h>
|
||||
|
||||
/*
|
||||
* Keep it as simple as possible. Execute commands from the
|
||||
* FixedBootSequence and BootSequence only.
|
||||
* Helper: Check if card should skip initialization based on boot parameters
|
||||
* Returns: 1 if should skip, 2 if should skip other card, 0 if should continue, negative on error
|
||||
* If check_restored is true, also checks if card state is already restored
|
||||
*/
|
||||
static int should_skip_initialization(snd_ctl_t *ctl, int cardno, int flags,
|
||||
char **boot_card_group, bool *valid,
|
||||
bool *in_sync, bool *restored, int *primary_card,
|
||||
long long *synctime)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = check_boot_params_validity(ctl, cardno, boot_card_group, valid, in_sync, restored, primary_card, synctime);
|
||||
if (err < 0) {
|
||||
dbg("boot parameters validity failed: %s", snd_strerror(err));
|
||||
return err;
|
||||
}
|
||||
|
||||
/* do nothing for other cards in group */
|
||||
if (*valid && *primary_card != cardno) {
|
||||
dbg("Skipping card %d - not primary (primary is %d)", cardno, *primary_card);
|
||||
return CARD_STATE_SKIP;
|
||||
}
|
||||
|
||||
/* for immediate initialization, caller must set UCM force-restore flag */
|
||||
if (*valid && *in_sync && (flags & FLAG_UCM_RESTORE) == 0) {
|
||||
dbg("Skipping card %d - in sync and no force-restore flag", cardno);
|
||||
return CARD_STATE_WAIT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper: Get boot card group configuration from UCM
|
||||
* Returns: 0 on success, negative on error
|
||||
*/
|
||||
static int get_boot_card_group_config(snd_use_case_mgr_t *uc_mgr, char **boot_card_group, long long *synctime)
|
||||
{
|
||||
char *sync_time = NULL;
|
||||
int err;
|
||||
|
||||
err = snd_use_case_get(uc_mgr, "=BootCardGroup", (const char **)boot_card_group);
|
||||
if (err != 0 || *boot_card_group == NULL) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
dbg("BootCardGroup found: %s", *boot_card_group);
|
||||
|
||||
/* Get optional sync time */
|
||||
err = snd_use_case_get(uc_mgr, "=BootCardSyncTime", (const char **)&sync_time);
|
||||
if (err == 0 && sync_time != NULL) {
|
||||
char *endptr;
|
||||
errno = 0;
|
||||
*synctime = strtoll(sync_time, &endptr, 10);
|
||||
if (errno != 0 || *endptr != '\0' || endptr == sync_time) {
|
||||
error("Invalid BootCardSyncTime value '%s'", sync_time);
|
||||
*synctime = DEFAULT_SYNC_TIME;
|
||||
}
|
||||
free(sync_time);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper: Open UCM manager with appropriate flags
|
||||
* Returns: 0 on success, negative on error
|
||||
*/
|
||||
static int open_ucm_manager(snd_use_case_mgr_t **uc_mgr, int cardno, int flags,
|
||||
bool valid, bool fixed_boot)
|
||||
{
|
||||
char id[64], *nodev, *in_boot;
|
||||
int err;
|
||||
|
||||
nodev = (flags & FLAG_UCM_NODEV) ? "" : "-";
|
||||
in_boot = (valid || !fixed_boot) ? "" : "<<<InBoot=1>>>";
|
||||
snprintf(id, sizeof(id), "%s%shw:%d", nodev, in_boot, cardno);
|
||||
|
||||
err = snd_use_case_mgr_open(uc_mgr, id);
|
||||
dbg("ucm open '%s': %d", id, err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper: Reopen UCM manager without InBoot flag
|
||||
* Returns: 0 on success, negative on error
|
||||
*/
|
||||
static int reopen_ucm_manager(snd_use_case_mgr_t **uc_mgr, int cardno, int flags)
|
||||
{
|
||||
char id[64], *nodev;
|
||||
int err;
|
||||
|
||||
snd_use_case_mgr_close(*uc_mgr);
|
||||
|
||||
nodev = (flags & FLAG_UCM_NODEV) ? "" : "-";
|
||||
snprintf(id, sizeof(id), "%shw:%d", nodev, cardno);
|
||||
|
||||
err = snd_use_case_mgr_open(uc_mgr, id);
|
||||
dbg("ucm reopen '%s': %d", id, err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper: Execute boot sequences
|
||||
* Returns: 0 on success, negative on error
|
||||
*/
|
||||
static int execute_boot_sequences(snd_use_case_mgr_t *uc_mgr, int flags, bool fixed_boot)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
if (fixed_boot) {
|
||||
err = snd_use_case_set(uc_mgr, "_fboot", NULL);
|
||||
dbg("ucm _fboot: %d", err);
|
||||
if (err == -ENOENT && (flags & FLAG_UCM_BOOT) != 0) {
|
||||
/* _fboot not found but _boot requested - continue */
|
||||
err = 0;
|
||||
} else if (err < 0) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & FLAG_UCM_BOOT) {
|
||||
err = snd_use_case_set(uc_mgr, "_boot", NULL);
|
||||
dbg("ucm _boot: %d", err);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if ((flags & FLAG_UCM_DEFAULTS) != 0)
|
||||
err = snd_use_case_set(uc_mgr, "_defaults", NULL);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute commands from the FixedBootSequence and BootSequence.
|
||||
* Handle also card groups.
|
||||
* Returns: 0 = success, 1 = skip this card (e.g. linked or in-sync), negative on error
|
||||
*/
|
||||
int init_ucm(int flags, int cardno)
|
||||
{
|
||||
snd_use_case_mgr_t *uc_mgr;
|
||||
char id[32], *nodev;
|
||||
int err;
|
||||
char id[64];
|
||||
char *boot_card_group = NULL, *boot_card_group_verify = NULL;
|
||||
bool fixed_boot, valid = false, in_sync = false, restored = false;
|
||||
snd_ctl_t *ctl = NULL;
|
||||
int err, primary_card = -1, lock_fd = -1;
|
||||
long long synctime = -1;
|
||||
|
||||
if (flags & FLAG_UCM_DISABLED) {
|
||||
dbg("ucm disabled");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
nodev = (flags & FLAG_UCM_NODEV) ? "" : "-";
|
||||
snprintf(id, sizeof(id), "%shw:%d", nodev, cardno);
|
||||
err = snd_use_case_mgr_open(&uc_mgr, id);
|
||||
dbg("ucm open '%s': %d", id, err);
|
||||
if (err < 0)
|
||||
fixed_boot = (flags & FLAG_UCM_FBOOT) != 0;
|
||||
|
||||
snprintf(id, sizeof(id), "hw:%d", cardno);
|
||||
err = snd_ctl_open(&ctl, id, 0);
|
||||
if (err < 0) {
|
||||
dbg("UCM: unable to open control device '%s': %s", id, snd_strerror(err));
|
||||
return err;
|
||||
if (flags & FLAG_UCM_FBOOT) {
|
||||
err = snd_use_case_set(uc_mgr, "_fboot", NULL);
|
||||
dbg("ucm _fboot: %d", err);
|
||||
if (err == -ENOENT && (flags & FLAG_UCM_BOOT) != 0) {
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
err = should_skip_initialization(ctl, cardno, flags, &boot_card_group, &valid,
|
||||
&in_sync, &restored, &primary_card, &synctime);
|
||||
if (err != 0)
|
||||
goto _fin;
|
||||
|
||||
if (valid) {
|
||||
if (restored) {
|
||||
err = CARD_STATE_RESTORED;
|
||||
goto _fin;
|
||||
}
|
||||
lock_fd = group_state_lock(groupfile, LOCK_TIMEOUT);
|
||||
if (lock_fd < 0) {
|
||||
err = lock_fd;
|
||||
goto _fin;
|
||||
}
|
||||
}
|
||||
|
||||
err = open_ucm_manager(&uc_mgr, cardno, flags, valid, fixed_boot);
|
||||
if (err < 0)
|
||||
goto _fin;
|
||||
|
||||
if (!fixed_boot)
|
||||
goto _execute_boot;
|
||||
|
||||
if (!valid) {
|
||||
err = get_boot_card_group_config(uc_mgr, &boot_card_group, &synctime);
|
||||
if (err == -ENOENT) {
|
||||
/* No BootCardGroup - remove any existing boot params */
|
||||
err = boot_params_remove_card(cardno);
|
||||
if (err < 0)
|
||||
goto _error;
|
||||
goto _execute_boot;
|
||||
} else if (err < 0) {
|
||||
goto _error;
|
||||
}
|
||||
|
||||
if (lock_fd < 0) {
|
||||
lock_fd = group_state_lock(groupfile, LOCK_TIMEOUT);
|
||||
if (lock_fd < 0) {
|
||||
err = lock_fd;
|
||||
goto _error;
|
||||
}
|
||||
}
|
||||
|
||||
err = should_skip_initialization(ctl, cardno, flags, &boot_card_group_verify,
|
||||
&valid, &in_sync, &restored, &primary_card, &synctime);
|
||||
if (err != 0)
|
||||
goto _error;
|
||||
|
||||
if (valid && (boot_card_group_verify == NULL || strcmp(boot_card_group_verify, boot_card_group) != 0)) {
|
||||
dbg("expected different boot card group (got '%s', expected '%s')", boot_card_group_verify, boot_card_group);
|
||||
err = -EINVAL;
|
||||
goto _error;
|
||||
}
|
||||
|
||||
if ((flags & FLAG_UCM_RESTORE) == 0 && (!valid || restored)) {
|
||||
dbg("Skipping card %d (group '%s') - %s and no force-restore flag", cardno, boot_card_group,
|
||||
!valid ? "validity not passed" : "already restored");
|
||||
if (!valid) {
|
||||
/* create initial 'Boot' element */
|
||||
err = update_boot_params(ctl, cardno, boot_card_group, 0, restored, synctime);
|
||||
if (err < 0)
|
||||
goto _error;
|
||||
}
|
||||
err = restored ? CARD_STATE_RESTORED : CARD_STATE_WAIT;
|
||||
goto _error;
|
||||
}
|
||||
|
||||
err = reopen_ucm_manager(&uc_mgr, cardno, flags);
|
||||
if (err < 0)
|
||||
goto _fin;
|
||||
}
|
||||
if (flags & FLAG_UCM_BOOT) {
|
||||
err = snd_use_case_set(uc_mgr, "_boot", NULL);
|
||||
dbg("ucm _boot: %d", err);
|
||||
|
||||
_execute_boot:
|
||||
if (flags & FLAG_UCM_FBOOT)
|
||||
restored = true;
|
||||
|
||||
if (boot_card_group) {
|
||||
err = update_boot_params(ctl, cardno, boot_card_group, valid, restored, synctime);
|
||||
if (err < 0)
|
||||
goto _error;
|
||||
if ((flags & FLAG_UCM_DEFAULTS) != 0)
|
||||
err = snd_use_case_set(uc_mgr, "_defaults", NULL);
|
||||
}
|
||||
|
||||
err = execute_boot_sequences(uc_mgr, flags, fixed_boot);
|
||||
if (err < 0)
|
||||
goto _error;
|
||||
|
||||
err = 0;
|
||||
|
||||
_error:
|
||||
snd_use_case_mgr_close(uc_mgr);
|
||||
_fin:
|
||||
if (lock_fd >= 0)
|
||||
group_state_unlock(lock_fd, groupfile);
|
||||
if (ctl)
|
||||
snd_ctl_close(ctl);
|
||||
free(boot_card_group);
|
||||
free(boot_card_group_verify);
|
||||
dbg("ucm init complete %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -181,6 +181,40 @@ int state_unlock(int _fd, const char *file)
|
|||
return err;
|
||||
}
|
||||
|
||||
static void group_state_lock_file(char *buf, size_t buflen)
|
||||
{
|
||||
const char *name = strrchr(groupfile, '/');
|
||||
if (name && name[0])
|
||||
name++;
|
||||
else
|
||||
name = "card-group.state";
|
||||
snprintf(buf, buflen, "%s/%s.lock", lockpath, name);
|
||||
}
|
||||
|
||||
int group_state_lock(const char *file, int timeout)
|
||||
{
|
||||
char fn[PATH_SIZE];
|
||||
int err;
|
||||
|
||||
group_state_lock_file(fn, sizeof(fn));
|
||||
err = state_lock_(fn, 1, timeout, -1);
|
||||
if (err < 0)
|
||||
error("file %s lock error: %s", file, strerror(-err));
|
||||
return err;
|
||||
}
|
||||
|
||||
int group_state_unlock(int _fd, const char *file)
|
||||
{
|
||||
char fn[PATH_SIZE];
|
||||
int err;
|
||||
|
||||
group_state_lock_file(fn, sizeof(fn));
|
||||
err = state_lock_(fn, 0, 10, _fd);
|
||||
if (err < 0)
|
||||
error("file %s unlock error: %s", file, strerror(-err));
|
||||
return err;
|
||||
}
|
||||
|
||||
static void card_lock_file(char *buf, size_t buflen, int card_number)
|
||||
{
|
||||
snprintf(buf, buflen, "%s/card%i.lock", lockpath, card_number);
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ static int check_control_cdev(int infd, bool *retry)
|
|||
ssize_t len = read(infd, buf, sizeof(*ev) + NAME_MAX);
|
||||
if (len < 0) {
|
||||
if (errno != EAGAIN)
|
||||
err = errno;
|
||||
err = -errno;
|
||||
break;
|
||||
} else if (len == 0) {
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,33 @@
|
|||
#include <errno.h>
|
||||
#include "alsactl.h"
|
||||
|
||||
static int linked_cards[16];
|
||||
|
||||
static void init_linked_cards(void)
|
||||
{
|
||||
size_t index;
|
||||
|
||||
for (index = 0; index < ARRAY_SIZE(linked_cards); index++)
|
||||
linked_cards[index] = -1;
|
||||
}
|
||||
|
||||
void add_linked_card(int cardno)
|
||||
{
|
||||
size_t index;
|
||||
|
||||
for (index = 0; index < ARRAY_SIZE(linked_cards); index++) {
|
||||
if (linked_cards[index] == cardno)
|
||||
return;
|
||||
}
|
||||
|
||||
for (index = 0; index < ARRAY_SIZE(linked_cards); index++) {
|
||||
if (linked_cards[index] < 0) {
|
||||
linked_cards[index] = cardno;
|
||||
return;
|
||||
}
|
||||
}
|
||||
error("Too many linked cards!");
|
||||
}
|
||||
|
||||
static char *id_str(snd_ctl_elem_id_t *id)
|
||||
{
|
||||
|
|
@ -1511,7 +1538,7 @@ static int set_controls(int card, snd_config_t *top, int doit)
|
|||
snd_ctl_elem_id_t *elem_id;
|
||||
snd_config_t *control;
|
||||
snd_config_iterator_t i, next;
|
||||
int err, controls1 = -1, controls2 = -1;
|
||||
int err, controls1 = -1, controls2 = -1, ucontrols = -1, diff;
|
||||
unsigned int idx, count = 0;
|
||||
char name[32], tmpid[16];
|
||||
const char *id;
|
||||
|
|
@ -1571,7 +1598,7 @@ static int set_controls(int card, snd_config_t *top, int doit)
|
|||
count = snd_ctl_elem_list_get_count(list);
|
||||
dbg("list count: %u", count);
|
||||
if (count == 0)
|
||||
goto _check;
|
||||
goto _free;
|
||||
snd_ctl_elem_list_set_offset(list, 0);
|
||||
if (snd_ctl_elem_list_alloc_space(list, count) < 0) {
|
||||
error("No enough memory...");
|
||||
|
|
@ -1581,13 +1608,15 @@ static int set_controls(int card, snd_config_t *top, int doit)
|
|||
error("Cannot determine controls (2): %s", snd_strerror(err));
|
||||
goto _free;
|
||||
}
|
||||
controls2 = 0;
|
||||
/* skip non-readable elements */
|
||||
controls2 = ucontrols = 0;
|
||||
/* skip non-readable and count user elements */
|
||||
for (idx = 0; idx < count; ++idx) {
|
||||
snd_ctl_elem_info_clear(elem_info);
|
||||
snd_ctl_elem_list_get_id(list, idx, elem_id);
|
||||
snd_ctl_elem_info_set_id(elem_info, elem_id);
|
||||
if (snd_ctl_elem_info(handle, elem_info) == 0) {
|
||||
if (snd_ctl_elem_info_is_user(elem_info))
|
||||
ucontrols++;
|
||||
if (!snd_ctl_elem_info_is_readable(elem_info))
|
||||
continue;
|
||||
controls2++;
|
||||
|
|
@ -1596,9 +1625,9 @@ static int set_controls(int card, snd_config_t *top, int doit)
|
|||
|
||||
/* check if we have additional controls in driver */
|
||||
/* in this case we should go through init procedure */
|
||||
_check:
|
||||
dbg("controls1=%i controls2=%i", controls1, controls2);
|
||||
if (controls1 >= 0 && controls1 != controls2) {
|
||||
diff = controls2 - controls1;
|
||||
dbg("controls1=%i controls2=%i ucontrols=%i diff=%i", controls1, controls2, ucontrols, diff);
|
||||
if (controls1 >= 0 && (-diff > ucontrols || diff > ucontrols)) {
|
||||
/* not very informative */
|
||||
/* but value is used for check only */
|
||||
err = -EAGAIN;
|
||||
|
|
@ -1701,10 +1730,11 @@ int load_state(const char *cfgdir, const char *file,
|
|||
const char *initfile, int initflags,
|
||||
const char *cardname, int do_init)
|
||||
{
|
||||
int err, finalerr = 0, open_failed, lock_fd;
|
||||
int err, finalerr = 0, open_failed, lock_fd, cardno;
|
||||
struct snd_card_iterator iter;
|
||||
snd_config_t *config;
|
||||
const char *cardname1;
|
||||
size_t index;
|
||||
|
||||
config = NULL;
|
||||
err = load_configuration(file, &config, &open_failed);
|
||||
|
|
@ -1721,6 +1751,9 @@ int load_state(const char *cfgdir, const char *file,
|
|||
while ((cardname1 = snd_card_iterator_next(&iter)) != NULL) {
|
||||
if (!do_init)
|
||||
break;
|
||||
init_linked_cards();
|
||||
if (initflags & FLAG_UCM_WAIT)
|
||||
wait_for_card(-1, iter.card);
|
||||
lock_fd = card_lock(iter.card, LOCK_TIMEOUT);
|
||||
if (lock_fd < 0) {
|
||||
finalerr = lock_fd;
|
||||
|
|
@ -1729,9 +1762,12 @@ int load_state(const char *cfgdir, const char *file,
|
|||
}
|
||||
err = init(cfgdir, initfile, initflags | FLAG_UCM_FBOOT | FLAG_UCM_BOOT, cardname1);
|
||||
card_unlock(lock_fd, iter.card);
|
||||
if (card_state_is_okay(err))
|
||||
export_card_state_set(iter.card, err);
|
||||
if (err < 0) {
|
||||
finalerr = err;
|
||||
initfailed(iter.card, "init", err);
|
||||
continue;
|
||||
}
|
||||
initfailed(iter.card, "restore", -ENOENT);
|
||||
}
|
||||
|
|
@ -1745,6 +1781,9 @@ int load_state(const char *cfgdir, const char *file,
|
|||
if (err < 0)
|
||||
goto out;
|
||||
while ((cardname1 = snd_card_iterator_next(&iter)) != NULL) {
|
||||
init_linked_cards();
|
||||
if (initflags & FLAG_UCM_WAIT)
|
||||
wait_for_card(-1, iter.card);
|
||||
lock_fd = card_lock(iter.card, LOCK_TIMEOUT);
|
||||
if (lock_fd < 0) {
|
||||
initfailed(iter.card, "lock", lock_fd);
|
||||
|
|
@ -1752,7 +1791,12 @@ int load_state(const char *cfgdir, const char *file,
|
|||
continue;
|
||||
}
|
||||
/* error is ignored */
|
||||
init_ucm(initflags | FLAG_UCM_FBOOT, iter.card);
|
||||
err = init_ucm(initflags | FLAG_UCM_FBOOT, iter.card);
|
||||
/* return code 1 and 2 -> postpone initialization */
|
||||
if (card_state_is_okay(err)) {
|
||||
export_card_state_set(iter.card, err);
|
||||
goto unlock_card;
|
||||
}
|
||||
/* do a check if controls matches state file */
|
||||
if (do_init && set_controls(iter.card, config, 0)) {
|
||||
err = init(cfgdir, initfile, initflags | FLAG_UCM_BOOT, cardname1);
|
||||
|
|
@ -1766,6 +1810,18 @@ int load_state(const char *cfgdir, const char *file,
|
|||
finalerr = err;
|
||||
initfailed(iter.card, "restore", err);
|
||||
}
|
||||
/* for linked cards, restore controls, too */
|
||||
for (index = 0; index < ARRAY_SIZE(linked_cards); index++) {
|
||||
if ((cardno = linked_cards[index]) < 0)
|
||||
break;
|
||||
dbg("Restore for linked card %d", cardno);
|
||||
if ((err = set_controls(cardno, config, 1))) {
|
||||
if (!force_restore)
|
||||
finalerr = err;
|
||||
initfailed(cardno, "restore", err);
|
||||
}
|
||||
}
|
||||
unlock_card:
|
||||
card_unlock(lock_fd, iter.card);
|
||||
}
|
||||
err = finalerr ? finalerr : snd_card_iterator_error(&iter);
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@ void dbg_(const char *fcn, long line, const char *fmt, ...)
|
|||
va_end(ap);
|
||||
}
|
||||
|
||||
void error_handler(const char *file, int line, const char *function, int err, const char *fmt, ...)
|
||||
void error_handler(const char *file, int line, const char *function, int errcode, const char *fmt, ...)
|
||||
{
|
||||
char buf[2048];
|
||||
va_list arg;
|
||||
|
|
@ -187,12 +187,36 @@ void error_handler(const char *file, int line, const char *function, int err, co
|
|||
va_end(arg);
|
||||
if (use_syslog)
|
||||
syslog(LOG_ERR, "alsa-lib %s:%i:(%s) %s%s%s\n", file, line, function,
|
||||
buf, err ? ": " : "", err ? snd_strerror(err) : "");
|
||||
buf, errcode ? ": " : "", errcode ? snd_strerror(errcode) : "");
|
||||
else
|
||||
fprintf(stderr, "alsa-lib %s:%i:(%s) %s%s%s\n", file, line, function,
|
||||
buf, err ? ": " : "", err ? snd_strerror(err) : "");
|
||||
buf, errcode ? ": " : "", errcode ? snd_strerror(errcode) : "");
|
||||
}
|
||||
|
||||
#if SND_LIB_VER(1, 2, 15) >= SND_LIB_VERSION
|
||||
void log_handler(int prio, int interface, const char *file, int line, const char *function, int errcode, const char *fmt, va_list arg)
|
||||
{
|
||||
char buf[2048], level[50] = "";
|
||||
const char *text1, *text2;
|
||||
|
||||
if (!snd_lib_log_filter(prio, interface, NULL))
|
||||
return;
|
||||
|
||||
text1 = snd_lib_log_priority(prio);
|
||||
text2 = snd_lib_log_interface(interface);
|
||||
if (text1 || text2)
|
||||
snprintf(level, sizeof(level), "[%s.%s] ", text1 ? text1 : "", text2 ? text2 : "");
|
||||
|
||||
vsnprintf(buf, sizeof(buf), fmt, arg);
|
||||
if (use_syslog)
|
||||
syslog(LOG_ERR, "alsa-lib %s:%i:(%s) %s%s%s%s\n", file, line, function, level,
|
||||
buf, errcode ? ": " : "", errcode ? snd_strerror(errcode) : "");
|
||||
else
|
||||
fprintf(stderr, "alsa-lib %s:%i:(%s) %s%s%s%s\n", file, line, function, level,
|
||||
buf, errcode ? ": " : "", errcode ? snd_strerror(errcode) : "");
|
||||
}
|
||||
#endif
|
||||
|
||||
int load_configuration(const char *file, snd_config_t **top, int *open_failed)
|
||||
{
|
||||
snd_config_t *config;
|
||||
|
|
@ -329,6 +353,7 @@ int snd_card_clean_cfgdir(const char *cfgdir, int cardno)
|
|||
lasterr = -errno;
|
||||
}
|
||||
}
|
||||
free(list);
|
||||
|
||||
return lasterr;
|
||||
}
|
||||
|
|
|
|||
200
alsactl/wait.c
Normal file
200
alsactl/wait.c
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
/*
|
||||
* Advanced Linux Sound Architecture Control Program - Wait for Boot
|
||||
* Copyright (c) by Jaroslav Kysela <perex@perex.cz>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "aconfig.h"
|
||||
#include "version.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include <alsa/asoundlib.h>
|
||||
#include "alsactl.h"
|
||||
|
||||
/**
|
||||
* \brief Wait for card boot synchronization using Boot control element
|
||||
* \param timeout Maximum wait time in seconds
|
||||
* \param cardno Card number
|
||||
* \return 0 on success, negative error code on failure
|
||||
*
|
||||
* This function waits until the card releases the 'waiting' state (UCM).
|
||||
* It monitors the '.Boot' control element and uses snd_ctl_wait() and
|
||||
* snd_ctl_read() for event-based waiting, similar to boot_wait() in
|
||||
* ../alsa-lib/alsa-lib/src/ucm/main.c
|
||||
*/
|
||||
int wait_for_card(long long timeout, int cardno)
|
||||
{
|
||||
snd_ctl_t *handle;
|
||||
snd_ctl_event_t *event;
|
||||
snd_ctl_elem_id_t *id;
|
||||
snd_ctl_elem_info_t *info;
|
||||
snd_ctl_elem_value_t *value;
|
||||
long long boot_time_val, restore_time_val;
|
||||
long long synctime = -1;
|
||||
struct timespec start_time, now;
|
||||
char name[32];
|
||||
int err;
|
||||
|
||||
sprintf(name, "hw:%d", cardno);
|
||||
err = snd_ctl_open(&handle, name, SND_CTL_READONLY);
|
||||
if (err < 0) {
|
||||
error("snd_ctl_open error for %s: %s", name, snd_strerror(err));
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Try to get synctime from boot_synctime in group configuration */
|
||||
if (timeout <= 0) {
|
||||
bool valid = false, restored = false;
|
||||
err = check_boot_params_validity(handle, cardno, NULL, &valid, NULL, &restored, NULL, &synctime);
|
||||
if (err == 0 && synctime > 0) {
|
||||
timeout = synctime;
|
||||
dbg("Using boot_synctime value: %lld seconds", timeout);
|
||||
} else {
|
||||
timeout = DEFAULT_SYNC_TIME;
|
||||
}
|
||||
/* Break early if boot params are invalid or already restored */
|
||||
if (!valid || restored) {
|
||||
dbg("Boot params check: valid=%d, restored=%d - skipping wait", valid, restored);
|
||||
snd_ctl_close(handle);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
snd_ctl_event_alloca(&event);
|
||||
snd_ctl_elem_id_alloca(&id);
|
||||
snd_ctl_elem_info_alloca(&info);
|
||||
snd_ctl_elem_value_alloca(&value);
|
||||
|
||||
snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_CARD);
|
||||
snd_ctl_elem_id_set_name(id, ".Boot");
|
||||
|
||||
snd_ctl_elem_info_set_id(info, id);
|
||||
err = snd_ctl_elem_info(handle, info);
|
||||
if (err < 0) {
|
||||
dbg("Boot control element not present on card %d, skipping wait", cardno);
|
||||
snd_ctl_close(handle);
|
||||
return 0; /* No Boot element, no wait needed */
|
||||
}
|
||||
|
||||
if (snd_ctl_elem_info_get_type(info) != SND_CTL_ELEM_TYPE_INTEGER64) {
|
||||
error("Boot control element is not INTEGER64 type on card %d", cardno);
|
||||
snd_ctl_close(handle);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (snd_ctl_elem_info_get_count(info) < 3) {
|
||||
error("Boot control element does not have count >= 3 on card %d", cardno);
|
||||
snd_ctl_close(handle);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = snd_ctl_subscribe_events(handle, 1);
|
||||
if (err < 0) {
|
||||
error("Cannot subscribe to control events: %s", snd_strerror(err));
|
||||
snd_ctl_close(handle);
|
||||
return err;
|
||||
}
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC_RAW, &start_time);
|
||||
|
||||
dbg("Waiting for card %d to become ready (timeout=%lld seconds)", cardno, timeout);
|
||||
|
||||
while (1) {
|
||||
long long diff, remaining = 0;
|
||||
long long sync_time_val = -1;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC_RAW, &now);
|
||||
|
||||
/* Read current Boot control values */
|
||||
err = read_boot_params(handle, &boot_time_val, &sync_time_val, &restore_time_val, NULL);
|
||||
if (err < 0) {
|
||||
error("Failed to read Boot control element: %s", snd_strerror(err));
|
||||
goto _fin;
|
||||
}
|
||||
|
||||
dbg("Boot info: boot_time=%lld, sync_time=%lld, restore_time=%lld", boot_time_val, sync_time_val, restore_time_val);
|
||||
|
||||
if (restore_time_val > 0) {
|
||||
diff = now.tv_sec - restore_time_val;
|
||||
dbg("Controls already restored (diff=%lld seconds), card is ready", diff);
|
||||
err = 0;
|
||||
goto _fin;
|
||||
}
|
||||
|
||||
/* note that realtime may differ from monotonic time, add one second for safety */
|
||||
diff = now.tv_sec - start_time.tv_sec;
|
||||
if (diff > timeout + 1) {
|
||||
dbg("Maximum wait time exceeded (%lld >= %lld seconds), proceeding", diff, timeout);
|
||||
break;
|
||||
}
|
||||
|
||||
remaining = timeout - diff;
|
||||
|
||||
/* Use synctime from element to limit timeout if available */
|
||||
if (sync_time_val > 0 && sync_time_val < timeout) {
|
||||
dbg("Limiting timeout from %lld to sync_time %lld seconds", timeout, sync_time_val);
|
||||
timeout = sync_time_val;
|
||||
}
|
||||
|
||||
if (!validate_boot_time(boot_time_val, now.tv_sec, timeout)) {
|
||||
if (boot_time_val > 0) {
|
||||
diff = now.tv_sec - boot_time_val;
|
||||
dbg("Boot timeout reached (%lld >= %lld seconds), proceeding", diff, timeout);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
diff = now.tv_sec - boot_time_val;
|
||||
if (timeout - diff < remaining)
|
||||
remaining = timeout - diff;
|
||||
if (remaining <= 0)
|
||||
remaining = 1;
|
||||
|
||||
dbg("Waiting %lld seconds", remaining);
|
||||
err = snd_ctl_wait(handle, remaining * 1000);
|
||||
if (err < 0) {
|
||||
error("snd_ctl_wait failed: %s", snd_strerror(err));
|
||||
goto _fin;
|
||||
}
|
||||
|
||||
if (err == 0)
|
||||
continue; /* Timeout, no events */
|
||||
|
||||
/* Read and check events */
|
||||
while (snd_ctl_read(handle, event) > 0) {
|
||||
if (!(snd_ctl_event_elem_get_mask(event) & SND_CTL_EVENT_MASK_VALUE))
|
||||
continue; /* Not a value change event */
|
||||
|
||||
if (snd_ctl_event_elem_get_interface(event) != SND_CTL_ELEM_IFACE_CARD ||
|
||||
snd_ctl_event_elem_get_index(event) != 0 ||
|
||||
strcmp(snd_ctl_event_elem_get_name(event), ".Boot") != 0)
|
||||
continue;
|
||||
|
||||
dbg("Boot control element value changed");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
err = 0;
|
||||
_fin:
|
||||
snd_ctl_subscribe_events(handle, 0);
|
||||
snd_ctl_close(handle);
|
||||
return err;
|
||||
}
|
||||
|
|
@ -34,6 +34,7 @@
|
|||
|
||||
static WINDOW *curses_initialized;
|
||||
|
||||
#if SND_LIB_VER(1, 2, 15) < SND_LIB_VERSION
|
||||
static void black_hole_error_handler(const char *file ATTRIBUTE_UNUSED,
|
||||
int line ATTRIBUTE_UNUSED,
|
||||
const char *function ATTRIBUTE_UNUSED,
|
||||
|
|
@ -41,6 +42,18 @@ static void black_hole_error_handler(const char *file ATTRIBUTE_UNUSED,
|
|||
const char *fmt ATTRIBUTE_UNUSED, ...)
|
||||
{
|
||||
}
|
||||
#else
|
||||
static void black_hole_log_handler(int prio ATTRIBUTE_UNUSED,
|
||||
int interface ATTRIBUTE_UNUSED,
|
||||
const char *file ATTRIBUTE_UNUSED,
|
||||
int line ATTRIBUTE_UNUSED,
|
||||
const char *function ATTRIBUTE_UNUSED,
|
||||
int errcode ATTRIBUTE_UNUSED,
|
||||
const char *fmt ATTRIBUTE_UNUSED,
|
||||
va_list arg ATTRIBUTE_UNUSED)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
void initialize_curses(bool use_color, bool use_mouse)
|
||||
{
|
||||
|
|
@ -55,7 +68,11 @@ void initialize_curses(bool use_color, bool use_mouse)
|
|||
if (use_mouse)
|
||||
mousemask(ALL_MOUSE_EVENTS, NULL);
|
||||
|
||||
#if SND_LIB_VER(1, 2, 15) < SND_LIB_VERSION
|
||||
snd_lib_error_set_handler(black_hole_error_handler);
|
||||
#else
|
||||
snd_lib_log_set_handler(black_hole_log_handler);
|
||||
#endif
|
||||
}
|
||||
|
||||
void app_shutdown(void)
|
||||
|
|
|
|||
|
|
@ -52,6 +52,11 @@ Prints the current version.
|
|||
.I \-l, \-\-list\-devices
|
||||
Prints a list of all hardware MIDI ports.
|
||||
|
||||
.TP
|
||||
.I \-x, \-\-list\-inactive
|
||||
Use together with \fI\-l\fP option.
|
||||
Print all MIDI ports including inactive ports.
|
||||
|
||||
.TP
|
||||
.I \-L, \-\-list\-rawmidis
|
||||
Prints all RawMIDI definitions.
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ static int stop;
|
|||
static int sysex_interval;
|
||||
static snd_rawmidi_t *input, **inputp;
|
||||
static snd_rawmidi_t *output, **outputp;
|
||||
static int list_all;
|
||||
|
||||
static void error(const char *format, ...)
|
||||
{
|
||||
|
|
@ -76,6 +77,7 @@ static void usage(void)
|
|||
"-h, --help this help\n"
|
||||
"-V, --version print current version\n"
|
||||
"-l, --list-devices list all hardware ports\n"
|
||||
"-x, --list-inactive list inactive ports, too\n"
|
||||
"-L, --list-rawmidis list all RawMIDI definitions\n"
|
||||
"-p, --port=name select port by name\n"
|
||||
"-s, --send=file send the contents of a (.syx) file\n"
|
||||
|
|
@ -151,6 +153,9 @@ static void list_device(snd_ctl_t *ctl, int card, int device)
|
|||
card, device, sub, snd_strerror(err));
|
||||
return;
|
||||
}
|
||||
if (!list_all &&
|
||||
(snd_rawmidi_info_get_flags(info) & SNDRV_RAWMIDI_INFO_STREAM_INACTIVE))
|
||||
continue;
|
||||
name = snd_rawmidi_info_get_name(info);
|
||||
sub_name = snd_rawmidi_info_get_subdevice_name(info);
|
||||
if (sub == 0 && sub_name[0] == '\0') {
|
||||
|
|
@ -471,11 +476,12 @@ static void add_send_hex_data(const char *str)
|
|||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
static const char short_options[] = "hVlLp:s:r:S::dt:aci:T:";
|
||||
static const char short_options[] = "hVlxLp:s:r:S::dt:aci:T:";
|
||||
static const struct option long_options[] = {
|
||||
{"help", 0, NULL, 'h'},
|
||||
{"version", 0, NULL, 'V'},
|
||||
{"list-devices", 0, NULL, 'l'},
|
||||
{"list-inactive", 0, NULL, 'x'},
|
||||
{"list-rawmidis", 0, NULL, 'L'},
|
||||
{"port", 1, NULL, 'p'},
|
||||
{"send", 1, NULL, 's'},
|
||||
|
|
@ -508,6 +514,9 @@ int main(int argc, char *argv[])
|
|||
case 'l':
|
||||
do_device_list = 1;
|
||||
break;
|
||||
case 'x':
|
||||
list_all = 1;
|
||||
break;
|
||||
case 'L':
|
||||
do_rawmidi_list = 1;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -1464,6 +1464,13 @@ static void set_params(void)
|
|||
chunk_size, buffer_size);
|
||||
prg_exit(EXIT_FAILURE);
|
||||
}
|
||||
if (dump_hw_params) {
|
||||
fprintf(stderr, _("HW Params of device \"%s\":\n"),
|
||||
snd_pcm_name(handle));
|
||||
fprintf(stderr, "--------------------\n");
|
||||
snd_pcm_hw_params_dump(params, log);
|
||||
fprintf(stderr, "--------------------\n");
|
||||
}
|
||||
err = snd_pcm_sw_params_current(handle, swparams);
|
||||
if (err < 0) {
|
||||
error(_("Unable to get current sw params."));
|
||||
|
|
@ -2703,7 +2710,7 @@ static void begin_wave(int fd, size_t cnt)
|
|||
WaveHeader h;
|
||||
WaveFmtBody f;
|
||||
WaveChunkHeader cf, cd;
|
||||
int bits;
|
||||
int width, physical_width;
|
||||
uint32_t tmp;
|
||||
uint16_t tmp2;
|
||||
|
||||
|
|
@ -2711,23 +2718,22 @@ static void begin_wave(int fd, size_t cnt)
|
|||
if (cnt == (size_t)-2)
|
||||
cnt = 0x7fffff00;
|
||||
|
||||
bits = 8;
|
||||
width = snd_pcm_format_physical_width(hwparams.format);
|
||||
physical_width = snd_pcm_format_width(hwparams.format);
|
||||
|
||||
if (width < 0 || physical_width < 0)
|
||||
goto _format;
|
||||
|
||||
switch ((unsigned long) hwparams.format) {
|
||||
case SND_PCM_FORMAT_U8:
|
||||
bits = 8;
|
||||
break;
|
||||
case SND_PCM_FORMAT_S16_LE:
|
||||
bits = 16;
|
||||
break;
|
||||
case SND_PCM_FORMAT_S24_LE: /* S24_LE is 24 bits stored in 32 bit width with 8 bit padding */
|
||||
case SND_PCM_FORMAT_S32_LE:
|
||||
case SND_PCM_FORMAT_FLOAT_LE:
|
||||
bits = 32;
|
||||
break;
|
||||
case SND_PCM_FORMAT_S24_3LE:
|
||||
bits = 24;
|
||||
break;
|
||||
default:
|
||||
_format:
|
||||
error(_("Wave doesn't support %s format..."), snd_pcm_format_name(hwparams.format));
|
||||
prg_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
|
@ -2745,17 +2751,11 @@ static void begin_wave(int fd, size_t cnt)
|
|||
f.format = LE_SHORT(WAV_FMT_PCM);
|
||||
f.channels = LE_SHORT(hwparams.channels);
|
||||
f.sample_fq = LE_INT(hwparams.rate);
|
||||
#if 0
|
||||
tmp2 = (samplesize == 8) ? 1 : 2;
|
||||
f.byte_p_spl = LE_SHORT(tmp2);
|
||||
tmp = dsp_speed * hwparams.channels * (uint32_t) tmp2;
|
||||
#else
|
||||
tmp2 = hwparams.channels * snd_pcm_format_physical_width(hwparams.format) / 8;
|
||||
tmp2 = hwparams.channels * physical_width / 8;
|
||||
f.byte_p_spl = LE_SHORT(tmp2);
|
||||
tmp = (uint32_t) tmp2 * hwparams.rate;
|
||||
#endif
|
||||
f.byte_p_sec = LE_INT(tmp);
|
||||
f.bit_p_spl = LE_SHORT(bits);
|
||||
f.bit_p_spl = LE_SHORT(width);
|
||||
|
||||
cd.type = WAV_DATA;
|
||||
cd.length = LE_INT(cnt);
|
||||
|
|
|
|||
22
bat/alsa.c
22
bat/alsa.c
|
|
@ -221,7 +221,17 @@ static int set_snd_pcm_params(struct bat *bat, struct pcm_container *sndpcm)
|
|||
|
||||
period_time = buffer_time / DIV_BUFFERTIME;
|
||||
|
||||
/* Set buffer time and period time */
|
||||
/* Set period time and buffer time */
|
||||
err = snd_pcm_hw_params_set_period_time_near(sndpcm->handle,
|
||||
params, &period_time, 0);
|
||||
if (err < 0) {
|
||||
fprintf(bat->err, _("Set parameter to device error: "));
|
||||
fprintf(bat->err, _("period time: %d %s: %s(%d)\n"),
|
||||
period_time,
|
||||
device_name, snd_strerror(err), err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = snd_pcm_hw_params_set_buffer_time_near(sndpcm->handle,
|
||||
params, &buffer_time, 0);
|
||||
if (err < 0) {
|
||||
|
|
@ -231,16 +241,6 @@ static int set_snd_pcm_params(struct bat *bat, struct pcm_container *sndpcm)
|
|||
device_name, snd_strerror(err), err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = snd_pcm_hw_params_set_period_time_near(sndpcm->handle,
|
||||
params, &period_time, 0);
|
||||
if (err < 0) {
|
||||
fprintf(bat->err, _("Set parameter to device error: "));
|
||||
fprintf(bat->err, _("period time: %d %s: %s(%d)\n"),
|
||||
period_time,
|
||||
device_name, snd_strerror(err), err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
/* Write the parameters to the driver */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
dnl Process this file with autoconf to produce a configure script.
|
||||
AC_PREREQ(2.59)
|
||||
AC_INIT(alsa-utils, 1.2.14)
|
||||
AC_INIT(alsa-utils, 1.2.15.1)
|
||||
AC_CONFIG_SRCDIR([aplay/aplay.c])
|
||||
AC_PREFIX_DEFAULT(/usr)
|
||||
AM_INIT_AUTOMAKE([subdir-objects])
|
||||
|
|
@ -419,8 +419,8 @@ AC_ARG_WITH([systemdsystemunitdir],
|
|||
if test "x$with_systemdsystemunitdir" != xno; then
|
||||
AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir])
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_SYSTEMD, [test "$have_min_systemd" = "yes" \
|
||||
-a -n "$with_systemdsystemunitdir" -a "x$with_systemdsystemunitdir" != xno ])
|
||||
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]),
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@
|
|||
#define PACKAGE_NAME "alsa-utils"
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#define PACKAGE_STRING "alsa-utils 1.2.14"
|
||||
#define PACKAGE_STRING "alsa-utils 1.2.15.1"
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#define PACKAGE_TARNAME "alsa-utils"
|
||||
|
|
@ -150,7 +150,7 @@
|
|||
#define PACKAGE_URL ""
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION "1.2.14"
|
||||
#define PACKAGE_VERSION "1.2.15.1"
|
||||
|
||||
/* directory containing sample data */
|
||||
#define SOUNDSDIR "/vendor/usr/share/sounds/alsa"
|
||||
|
|
@ -165,7 +165,7 @@
|
|||
#define TIME_WITH_SYS_TIME 1
|
||||
|
||||
/* ALSA util version */
|
||||
#define VERSION "1.2.14"
|
||||
#define VERSION "1.2.15.1"
|
||||
|
||||
/* Define if FFADO library is available */
|
||||
/* #undef WITH_FFADO */
|
||||
|
|
|
|||
|
|
@ -4,6 +4,6 @@
|
|||
|
||||
#define SND_UTIL_MAJOR 1
|
||||
#define SND_UTIL_MINOR 2
|
||||
#define SND_UTIL_SUBMINOR 14
|
||||
#define SND_UTIL_SUBMINOR 15
|
||||
#define SND_UTIL_VERSION ((SND_UTIL_MAJOR<<16)|(SND_UTIL_MINOR<<8)|SND_UTIL_SUBMINOR)
|
||||
#define SND_UTIL_VERSION_STR "1.2.14"
|
||||
#define SND_UTIL_VERSION_STR "1.2.15.1"
|
||||
|
|
|
|||
|
|
@ -31,11 +31,13 @@
|
|||
|
||||
static int show_all;
|
||||
|
||||
static void error_handler(const char *file, int line, const char *function, int err, const char *fmt, ...)
|
||||
|
||||
#if SND_LIB_VER(1, 2, 15) < SND_LIB_VERSION
|
||||
static void error_handler(const char *file, int line, const char *function, int errcode, const char *fmt, ...)
|
||||
{
|
||||
va_list arg;
|
||||
|
||||
if (err == ENOENT) /* Ignore those misleading "warnings" */
|
||||
if (errcode == ENOENT) /* Ignore those misleading "warnings" */
|
||||
return;
|
||||
va_start(arg, fmt);
|
||||
fprintf(stderr, "ALSA lib %s:%i:(%s) ", file, line, function);
|
||||
|
|
@ -45,6 +47,16 @@ static void error_handler(const char *file, int line, const char *function, int
|
|||
putc('\n', stderr);
|
||||
va_end(arg);
|
||||
}
|
||||
#else
|
||||
static snd_lib_log_handler_t original_log_handler;
|
||||
static void log_handler(int prio, int interface, const char *file, int line, const char *function, int errcode, const char *fmt, va_list arg)
|
||||
{
|
||||
if (prio == SND_LOG_ERROR && errcode == ENOENT) /* Ignore those misleading "warnings" */
|
||||
return;
|
||||
if (original_log_handler)
|
||||
original_log_handler(prio, interface, file, line, function, errcode, fmt, arg);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
|
|
@ -356,7 +368,11 @@ int main(int argc, char **argv)
|
|||
return 1;
|
||||
}
|
||||
|
||||
#if SND_LIB_VER(1, 2, 15) < SND_LIB_VERSION
|
||||
snd_lib_error_set_handler(error_handler);
|
||||
#else
|
||||
original_log_handler = snd_lib_log_set_handler(log_handler);
|
||||
#endif
|
||||
|
||||
switch (command) {
|
||||
case LIST:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue