From 3331bcfb8285f9fd1fea1b72d6ed448517f33edae70d66dfa87d3dd9f98c94da Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 26 Nov 2010 08:10:21 +0000 Subject: [PATCH 1/3] - backport GIT PATCHES: * A few alsactl init fix patches: * amixer control-id parse fix * new aloop utility * robusitfy speaker-test * misc clean up, translation updates - Use systemd for openSUSE 11.4 - Put udev rules into this package instead of alsa.rpm OBS-URL: https://build.opensuse.org/package/show/multimedia:libs/alsa-utils?expand=0&rev=23 --- ...dle-Capture-Source-and-Mic-Boost-in-.patch | 35 + ...tialize-also-Master-Front-Playback-V.patch | 31 + ...mixer-fix-parsing-of-control-ID-name.patch | 27 + 0017-Introduce-alsaloop-utility.patch | 3313 +++++++++++++++++ ...pbacks-pointer-initialization-and-al.patch | 45 + 0019-alsaloop-Fix-thread-handling.patch | 80 + ...x-a-option-and-slave-mode-processing.patch | 85 + ...saloop-fix-resample-argument-parsing.patch | 49 + ...esampling-for-unsupported-soundcard-.patch | 618 +++ ...op-Add-OSS-mixer-redirection-support.patch | 317 ++ ...mand-line-parsing-and-pollfd-initial.patch | 227 ++ ...op-Fixes-and-added-workaround-option.patch | 449 +++ 0026-alsaloop-add-pctl-and-cctl-options.patch | 149 + ...dd-pctl-and-cctl-options-to-man-page.patch | 34 + ...run-profiling-support-U-xrun-added-S.patch | 677 ++++ ...op-add-U-xrun-to-alsaloop.1-man-page.patch | 30 + 0030-alsaloop-fixes-added-W-wake-option.patch | 371 ++ 0031-alsaloop-Fix-latency-print.patch | 26 + ...-test-Don-t-retry-after-fatal-errors.patch | 32 + ...he-restart-a-bit-to-handle-snd-aloop.patch | 104 + ...ework-the-ctl-event-handling-routine.patch | 95 + 0035-alsamixer-remove-obsolete-e-mail.patch | 88 + 0036-update-German-translations.patch | 1170 ++++++ 0037-alsactl-systemd-and-udev-hookup.patch | 211 ++ ...sound.state-location-to-var-lib-alsa.patch | 123 + 0039-configure.in-Fix-variable-name.patch | 34 + alsa-utils-po-pre-patch.diff | 2200 +++++++++++ alsa-utils.changes | 39 + alsa-utils.spec | 85 +- 29 files changed, 10735 insertions(+), 9 deletions(-) create mode 100644 0014-alsactl-init-Handle-Capture-Source-and-Mic-Boost-in-.patch create mode 100644 0015-alsactl-init-Initialize-also-Master-Front-Playback-V.patch create mode 100644 0016-amixer-fix-parsing-of-control-ID-name.patch create mode 100644 0017-Introduce-alsaloop-utility.patch create mode 100644 0018-alsaloop-Fix-loopbacks-pointer-initialization-and-al.patch create mode 100644 0019-alsaloop-Fix-thread-handling.patch create mode 100644 0020-alsaloop-fix-a-option-and-slave-mode-processing.patch create mode 100644 0021-alsaloop-fix-resample-argument-parsing.patch create mode 100644 0022-alsaloop-added-resampling-for-unsupported-soundcard-.patch create mode 100644 0023-alsaloop-Add-OSS-mixer-redirection-support.patch create mode 100644 0024-alsaloop-Fix-command-line-parsing-and-pollfd-initial.patch create mode 100644 0025-alsaloop-Fixes-and-added-workaround-option.patch create mode 100644 0026-alsaloop-add-pctl-and-cctl-options.patch create mode 100644 0027-alsaloop-add-pctl-and-cctl-options-to-man-page.patch create mode 100644 0028-alsaloop-added-xrun-profiling-support-U-xrun-added-S.patch create mode 100644 0029-alsaloop-add-U-xrun-to-alsaloop.1-man-page.patch create mode 100644 0030-alsaloop-fixes-added-W-wake-option.patch create mode 100644 0031-alsaloop-Fix-latency-print.patch create mode 100644 0032-speaker-test-Don-t-retry-after-fatal-errors.patch create mode 100644 0033-alsaloop-Delay-the-restart-a-bit-to-handle-snd-aloop.patch create mode 100644 0034-alsaloop-rework-the-ctl-event-handling-routine.patch create mode 100644 0035-alsamixer-remove-obsolete-e-mail.patch create mode 100644 0036-update-German-translations.patch create mode 100644 0037-alsactl-systemd-and-udev-hookup.patch create mode 100644 0038-alsactl-Move-asound.state-location-to-var-lib-alsa.patch create mode 100644 0039-configure.in-Fix-variable-name.patch create mode 100644 alsa-utils-po-pre-patch.diff diff --git a/0014-alsactl-init-Handle-Capture-Source-and-Mic-Boost-in-.patch b/0014-alsactl-init-Handle-Capture-Source-and-Mic-Boost-in-.patch new file mode 100644 index 0000000..4e41fef --- /dev/null +++ b/0014-alsactl-init-Handle-Capture-Source-and-Mic-Boost-in-.patch @@ -0,0 +1,35 @@ +From 52bd2f8acedaacce32ca8e89cb1f21683658648e Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +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 +--- + 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 + diff --git a/0015-alsactl-init-Initialize-also-Master-Front-Playback-V.patch b/0015-alsactl-init-Initialize-also-Master-Front-Playback-V.patch new file mode 100644 index 0000000..5f48362 --- /dev/null +++ b/0015-alsactl-init-Initialize-also-Master-Front-Playback-V.patch @@ -0,0 +1,31 @@ +From ef919a4724169f4c0dc14168dec32c168b2471e4 Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +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 +--- + 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 + diff --git a/0016-amixer-fix-parsing-of-control-ID-name.patch b/0016-amixer-fix-parsing-of-control-ID-name.patch new file mode 100644 index 0000000..e682397 --- /dev/null +++ b/0016-amixer-fix-parsing-of-control-ID-name.patch @@ -0,0 +1,27 @@ +From 87c58b59b5c443fe3244bd06417c451581d1f635 Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +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 +--- + 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 + diff --git a/0017-Introduce-alsaloop-utility.patch b/0017-Introduce-alsaloop-utility.patch new file mode 100644 index 0000000..a81c2ec --- /dev/null +++ b/0017-Introduce-alsaloop-utility.patch @@ -0,0 +1,3313 @@ +From 1e75673035ffc0971719974715211d6a0a48e61a Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +Date: Wed, 18 Aug 2010 08:29:03 +0200 +Subject: [PATCH 17/38] Introduce alsaloop utility + +alsaloop allows create a PCM loopback between a PCM capture device +and a PCM playback device. + +alsaloop supports multiple soundcards, adaptive clock synchronization, +adaptive rate resampling using the samplerate library (if available in +the system). Also, mixer controls can be redirected from one card to +another (for example Master and PCM). + +Signed-off-by: Jaroslav Kysela +--- + Makefile.am | 3 + + alsaloop/Makefile.am | 13 + + alsaloop/alsaloop.1 | 170 ++++++ + alsaloop/alsaloop.c | 740 +++++++++++++++++++++++ + alsaloop/alsaloop.h | 181 ++++++ + alsaloop/control.c | 376 ++++++++++++ + alsaloop/effect-sweep.c | 128 ++++ + alsaloop/pcmjob.c | 1528 +++++++++++++++++++++++++++++++++++++++++++++++ + alsaloop/test.sh | 34 + + configure.in | 16 +- + 11 files changed, 3189 insertions(+), 1 deletions(-) + create mode 100644 alsaloop/Makefile.am + create mode 100644 alsaloop/alsaloop.1 + create mode 100644 alsaloop/alsaloop.c + create mode 100644 alsaloop/alsaloop.h + create mode 100644 alsaloop/control.c + create mode 100644 alsaloop/effect-sweep.c + create mode 100644 alsaloop/pcmjob.c + create mode 100755 alsaloop/test.sh + +diff --git a/Makefile.am b/Makefile.am +index 5296977..9951c46 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -15,6 +15,9 @@ SUBDIRS += alsaconf + endif + if HAVE_PCM + SUBDIRS += aplay iecset speaker-test ++if ALSALOOP ++SUBDIRS += alsaloop ++endif + endif + if HAVE_SEQ + SUBDIRS += seq +diff --git a/alsaloop/Makefile.am b/alsaloop/Makefile.am +new file mode 100644 +index 0000000..97d2e6f +--- /dev/null ++++ b/alsaloop/Makefile.am +@@ -0,0 +1,13 @@ ++INCLUDES = -I$(top_srcdir)/include ++LDADD = -lm ++if HAVE_SAMPLERATE ++LDADD += -lsamplerate ++endif ++# LDFLAGS = -static ++# CFLAGS += -g -Wall ++ ++bin_PROGRAMS = alsaloop ++alsaloop_SOURCES = alsaloop.c pcmjob.c control.c ++noinst_HEADERS = alsaloop.h ++man_MANS = alsaloop.1 ++EXTRA_DIST = alsaloop.1 +diff --git a/alsaloop/alsaloop.1 b/alsaloop/alsaloop.1 +new file mode 100644 +index 0000000..66be499 +--- /dev/null ++++ b/alsaloop/alsaloop.1 +@@ -0,0 +1,170 @@ ++.TH ALSALOOP 1 "5 Aug 2010" ++.SH NAME ++alsaloop \- command-line PCM loopback ++.SH SYNOPSIS ++\fBalsaloop\fP [\fI\-option\fP] [\fIcmd\fP] ++.SH DESCRIPTION ++ ++\fBalsaloop\fP allows create a PCM loopback between a PCM capture device ++and a PCM playback device. ++ ++\fBalsaloop\fP supports multiple soundcards, adaptive clock synchronization, ++adaptive rate resampling using the samplerate library (if available in ++the system). Also, mixer controls can be redirected from one card to ++another (for example Master and PCM). ++ ++.SH OPTIONS ++ ++.TP ++\fI\-h\fP | \fI\-\-help\fP ++ ++Prints the help information. ++ ++.TP ++\fI\-g \fP | \fI\-\-config=\fP ++ ++Use given configuration file. The syntax of this file is simple: one line ++contains the command line options for one job. The '#' means comment and ++rest of line is ignored. Example: ++ ++ # First line - comment, second line - first job ++ -C hw:1,0 -P hw:0,0 -t 50000 -T 1 ++ # Third line - comment, fourth line - second job ++ -C hw:1,1 -P hw:0,1 -t 40000 -T 2 ++ ++.TP ++\fI\-d\fP | \fI\-\-daemonize\fP ++ ++Daemonize the main process and use syslog for messages. ++ ++.TP ++\fI\-P \fP | \fI\-\-pdevice=\fP ++ ++Use given playback device. ++ ++.TP ++\fI\-C \fP | \fI\-\-cdevice=\fP ++ ++Use given capture device. ++ ++.TP ++\fI\-l \fP | \fI\-\-latency=\fP ++ ++Requested latency in frames. ++ ++.TP ++\fI\-t \fP | \fI\-\-tlatency=\fP ++ ++Requested latency in usec (1/1000000sec). ++ ++.TP ++\fI\-f \fP | \fI\-\-format=\fP ++ ++Format specification (usually S16_LE S32_LE). Use -h to list all formats. ++Default format is S16_LE. ++ ++.TP ++\fI\-c \fP | \fI\-\-channels=\fP ++ ++Channel count specification. Default value is 2. ++ ++.TP ++\fI\-c \fP | \fI\-\-rate=\fP ++ ++Rate specification. Default value is 48000 (Hz). ++ ++.TP ++\fI\-n\fP | \fI\-\-resample\fP ++ ++Allow rate resampling using alsa-lib. ++ ++.TP ++\fI\-A \fP | \fI\-\-samplerate=\fP ++ ++Use libsamplerate and choose a converter: ++ ++ 0 or sincbest - best quality ++ 1 or sincmedium - medium quality ++ 2 or sincfastest - lowest quality ++ 3 or zerohold - hold zero samples ++ 4 or linear - worst quality - linear resampling ++ 5 or auto - choose best method ++ ++.TP ++\fI\-B \fP | \fI\-\-buffer=\fP ++ ++Buffer size in frames. ++ ++.TP ++\fI\-E \fP | \fI\-\-period=\fP ++ ++Period size in frames. ++ ++.TP ++\fI\-s \fP | \fI\-\-seconds=\fP ++ ++Duration of loop in seconds. ++ ++.TP ++\fI\-b\fP | \fI\-\-nblock\fP ++ ++Non-block mode (very early process wakeup). Eats more CPU. ++ ++.TP ++\fI\-S \fP | \fI\-\-sync=\fP ++ ++Sync mode specification for capture to playback stream: ++ 0 or none - do not touch the stream ++ 1 or simple - add or remove samples to keep ++ both streams synchronized ++ 2 or captshift - use driver for the capture device ++ (if supported) to compensate ++ the rate shift ++ 3 or playshift - use driver for the playback device ++ (if supported) to compensate ++ the rate shift ++ 4 or samplerate - use samplerate library to do rate resampling ++ 5 or auto - automatically selects the best method ++ in this order: captshift, playshift, ++ samplerate, simple ++ ++.TP ++\fI\-T \fP | \fI\-\-thread=\fP ++ ++Thread number (-1 means create a unique thread). All jobs with same ++thread numbers are run within one thread. ++ ++.TP ++\fI\-m \fP | \fI\-\-mixer=\fP ++ ++Redirect mixer control from the playback card to the capture card. Format of ++\fImixid\fP is SRCID(PLAYBACK)[@DSTID(PLAYBACK)]: ++ ++ "name='Master Playback Switch'@name='Another Switch'" ++ "name='PCM Playback Volume'" ++ ++Known attributes: ++ ++ name - control ID name ++ index - control ID index ++ device - control ID device ++ subdevice - control ID subdevice ++ iface - control ID interface ++ numid - control ID numid ++ ++.TP ++\fI\-v\fP | \fI\-\-verbose\fP ++ ++Verbose mode. Use multiple times to increase verbosity. ++ ++ ++.SH EXAMPLES ++ ++.TP ++\fBalsaloop \-C hw:0,0 \-P hw:1,0 \-t 50000\fR ++ ++.SH BUGS ++None known. ++.SH AUTHOR ++\fBalsaloop\fP is by Jaroslav Kysela . ++This document is by Jaroslav Kysela . +diff --git a/alsaloop/alsaloop.c b/alsaloop/alsaloop.c +new file mode 100644 +index 0000000..4ba5203 +--- /dev/null ++++ b/alsaloop/alsaloop.c +@@ -0,0 +1,740 @@ ++/* ++ * A simple PCM loopback utility with adaptive sample rate support ++ * ++ * Author: Jaroslav Kysela ++ * ++ * ++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "alsaloop.h" ++ ++struct loopback_thread { ++ int threaded; ++ pthread_t thread; ++ int exitcode; ++ struct loopback **loopbacks; ++ int loopbacks_count; ++ snd_output_t *output; ++}; ++ ++int verbose = 0; ++int daemonize = 0; ++int use_syslog = 0; ++struct loopback **loopbacks; ++int loopbacks_count = 0; ++ ++static void my_exit(struct loopback_thread *thread, int exitcode) ++{ ++ int i; ++ ++ for (i = 0; i < thread->loopbacks_count; i++) ++ pcmjob_done(thread->loopbacks[i]); ++ if (thread->threaded) { ++ thread->exitcode = exitcode; ++ pthread_exit(0); ++ } ++ exit(exitcode); ++} ++ ++static int create_loopback_handle(struct loopback_handle **_handle, ++ const char *device, ++ const char *id) ++{ ++ char idbuf[1024]; ++ struct loopback_handle *handle; ++ ++ handle = calloc(1, sizeof(*handle)); ++ if (handle == NULL) ++ return -ENOMEM; ++ if (device == NULL) ++ device = "hw:0,0"; ++ handle->device = strdup(device); ++ snprintf(idbuf, sizeof(idbuf)-1, "%s %s", id, device); ++ idbuf[sizeof(idbuf)-1] = '\0'; ++ handle->id = strdup(idbuf); ++ handle->access = SND_PCM_ACCESS_RW_INTERLEAVED; ++ handle->format = SND_PCM_FORMAT_S16_LE; ++ handle->rate = 48000; ++ handle->channels = 2; ++ handle->resample = 1; ++ *_handle = handle; ++ return 0; ++} ++ ++static int create_loopback(struct loopback **_handle, ++ struct loopback_handle *play, ++ struct loopback_handle *capt, ++ snd_output_t *output) ++{ ++ struct loopback *handle; ++ ++ handle = calloc(1, sizeof(*handle)); ++ if (handle == NULL) ++ return -ENOMEM; ++ handle->play = play; ++ handle->capt = capt; ++ play->loopback = handle; ++ capt->loopback = handle; ++ handle->latency_req = 0; ++ handle->latency_reqtime = 10000; ++ handle->loop_time = ~0UL; ++ handle->loop_limit = ~0ULL; ++ handle->output = output; ++#ifdef USE_SAMPLERATE ++ handle->src_enable = 1; ++ handle->src_converter_type = SRC_SINC_BEST_QUALITY; ++#endif ++ *_handle = handle; ++ return 0; ++} ++ ++static void set_loop_time(struct loopback *loop, unsigned long loop_time) ++{ ++ loop->loop_time = loop_time; ++ loop->loop_limit = loop->capt->rate * loop_time; ++} ++ ++static void setscheduler(void) ++{ ++ struct sched_param sched_param; ++ ++ if (sched_getparam(0, &sched_param) < 0) { ++ logit(LOG_WARNING, "Scheduler getparam failed.\n"); ++ return; ++ } ++ sched_param.sched_priority = sched_get_priority_max(SCHED_RR); ++ if (!sched_setscheduler(0, SCHED_RR, &sched_param)) { ++ if (verbose) ++ logit(LOG_WARNING, "Scheduler set to Round Robin with priority %i\n", sched_param.sched_priority); ++ return; ++ } ++ if (verbose) ++ logit(LOG_INFO, "!!!Scheduler set to Round Robin with priority %i FAILED!\n", sched_param.sched_priority); ++} ++ ++void help(void) ++{ ++ int k; ++ printf( ++"Usage: alsaloop [OPTION]...\n\n" ++"-h,--help help\n" ++"-g,--config configuration file (one line = one job specified)\n" ++"-d,--daemonize daemonize the main process and use syslog for errors\n" ++"-P,--pdevice playback device\n" ++"-C,--cdevice capture device\n" ++"-l,--latency requested latency in frames\n" ++"-t,--tlatency requested latency in usec (1/1000000sec)\n" ++"-f,--format sample format\n" ++"-c,--channels channels\n" ++"-r,--rate rate\n" ++"-n,--resample resample in alsa-lib\n" ++"-A,--samplerate use converter (0=sincbest,1=sincmedium,2=sincfastest,\n" ++" 3=zerohold,4=linear)\n" ++"-B,--buffer buffer size in frames\n" ++"-E,--period period size in frames\n" ++"-s,--seconds duration of loop in seconds\n" ++"-b,--nblock non-block mode (very early process wakeup)\n" ++"-S,--sync sync mode(0=none,1=simple,2=captshift,3=playshift,4=samplerate,\n" ++" 5=auto)\n" ++"-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" ++"-e,--effect apply an effect (bandpass filter sweep)\n" ++"-v,--verbose verbose mode (more -v means more verbose)\n" ++); ++ printf("\nRecognized sample formats are:"); ++ for (k = 0; k < SND_PCM_FORMAT_LAST; ++k) { ++ const char *s = snd_pcm_format_name(k); ++ if (s) ++ printf(" %s", s); ++ } ++ printf("\n\n"); ++ printf( ++"Tip #1 (usable 500ms latency, good CPU usage, superb xrun prevention):\n" ++" alsaloop -t 500000\n" ++"Tip #2 (superb 1ms latency, but heavy CPU usage):\n" ++" alsaloop -t 1000\n" ++); ++} ++ ++static long timediff(struct timeval t1, struct timeval t2) ++{ ++ signed long l; ++ ++ t1.tv_sec -= t2.tv_sec; ++ l = (signed long) t1.tv_usec - (signed long) t2.tv_usec; ++ if (l < 0) { ++ t1.tv_sec--; ++ l = 1000000 + l; ++ l %= 1000000; ++ } ++ return (t1.tv_sec * 1000000) + l; ++} ++ ++static void add_loop(struct loopback *loop) ++{ ++ loopbacks = realloc(loopbacks, loopbacks_count * sizeof(struct loopback *)); ++ if (loopbacks == NULL) { ++ logit(LOG_CRIT, "No enough memory\n"); ++ exit(EXIT_FAILURE); ++ } ++ loopbacks[loopbacks_count++] = loop; ++} ++ ++static int init_mixer_control(struct loopback_control *control, ++ char *id) ++{ ++ int err; ++ ++ err = snd_ctl_elem_id_malloc(&control->id); ++ if (err < 0) ++ return err; ++ err = snd_ctl_elem_info_malloc(&control->info); ++ if (err < 0) ++ return err; ++ err = snd_ctl_elem_value_malloc(&control->value); ++ if (err < 0) ++ return err; ++ err = control_parse_id(id, control->id); ++ if (err < 0) ++ return err; ++ return 0; ++} ++ ++static int add_mixers(struct loopback *loop, ++ char **mixers, ++ int mixers_count) ++{ ++ struct loopback_mixer *mixer, *last = NULL; ++ char *str1; ++ int err; ++ ++ while (mixers_count > 0) { ++ mixer = calloc(1, sizeof(*mixer)); ++ if (mixer == NULL) ++ return -ENOMEM; ++ if (last) ++ last->next = mixer; ++ else ++ loop->controls = mixer; ++ last = mixer; ++ str1 = strchr(*mixers, '@'); ++ if (str1) ++ *str1 = '\0'; ++ err = init_mixer_control(&mixer->src, *mixers); ++ if (err < 0) { ++ logit(LOG_CRIT, "Wrong mixer control ID syntax '%s'\n", *mixers); ++ return -EINVAL; ++ } ++ err = init_mixer_control(&mixer->dst, str1 ? str1 + 1 : *mixers); ++ if (err < 0) { ++ logit(LOG_CRIT, "Wrong mixer control ID syntax '%s'\n", str1 ? str1 + 1 : *mixers); ++ return -EINVAL; ++ } ++ if (str1) ++ *str1 = '@'; ++ 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) ++{ ++ struct option long_option[] = ++ { ++ {"help", 0, NULL, 'h'}, ++ {"config", 1, NULL, 'g'}, ++ {"daemonize", 0, NULL, 'd'}, ++ {"pdevice", 1, NULL, 'P'}, ++ {"cdevice", 1, NULL, 'C'}, ++ {"latency", 1, NULL, 'l'}, ++ {"tlatency", 1, NULL, 't'}, ++ {"format", 1, NULL, 'f'}, ++ {"channels", 1, NULL, 'c'}, ++ {"rate", 1, NULL, 'r'}, ++ {"buffer", 1, NULL, 'B'}, ++ {"period", 1, NULL, 'E'}, ++ {"seconds", 1, NULL, 's'}, ++ {"nblock", 0, NULL, 'b'}, ++ {"effect", 0, NULL, 'e'}, ++ {"verbose", 0, NULL, 'v'}, ++ {"resample", 0, NULL, 'n'}, ++ {"samplerate", 1, NULL, 'A'}, ++ {"sync", 1, NULL, 'S'}, ++ {"slave", 1, NULL, 'a'}, ++ {"thread", 1, NULL, 'T'}, ++ {"mixer", 1, NULL, 'm'}, ++ {NULL, 0, NULL, 0}, ++ }; ++ int err, morehelp; ++ char *arg_config = NULL; ++ char *arg_pdevice = NULL; ++ char *arg_cdevice = NULL; ++ unsigned int arg_latency_req = 0; ++ unsigned int arg_latency_reqtime = 10000; ++ snd_pcm_format_t arg_format = SND_PCM_FORMAT_S16_LE; ++ unsigned int arg_channels = 2; ++ unsigned int arg_rate = 48000; ++ snd_pcm_uframes_t arg_buffer_size = 0; ++ snd_pcm_uframes_t arg_period_size = 0; ++ unsigned long arg_loop_time = ~0UL; ++ int arg_nblock = 0; ++ int arg_effect = 0; ++ int arg_resample = 0; ++ int arg_samplerate = 0; ++ int arg_sync = SYNC_TYPE_AUTO; ++ int arg_slave = SLAVE_TYPE_AUTO; ++ int arg_thread = 0; ++ struct loopback *loop = NULL; ++ char *arg_mixers[MAX_MIXERS]; ++ int arg_mixers_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:", long_option, NULL)) < 0) ++ break; ++ switch (c) { ++ case 'h': ++ morehelp++; ++ break; ++ case 'g': ++ arg_config = strdup(optarg); ++ break; ++ case 'd': ++ daemonize = 1; ++ use_syslog = 1; ++ openlog("alsaloop", LOG_NDELAY|LOG_PID, LOG_DAEMON); ++ break; ++ case 'P': ++ arg_pdevice = strdup(optarg); ++ break; ++ case 'C': ++ arg_cdevice = strdup(optarg); ++ break; ++ case 'l': ++ err = atoi(optarg); ++ arg_latency_req = err >= 4 ? err : 4; ++ break; ++ case 't': ++ err = atoi(optarg); ++ arg_latency_reqtime = err >= 500 ? err : 500; ++ break; ++ case 'f': ++ arg_format = snd_pcm_format_value(optarg); ++ if (arg_format == SND_PCM_FORMAT_UNKNOWN) { ++ logit(LOG_WARNING, "Unknown format, setting to default S16_LE\n"); ++ arg_format = SND_PCM_FORMAT_S16_LE; ++ } ++ break; ++ case 'c': ++ err = atoi(optarg); ++ arg_channels = err >= 1 && err < 1024 ? err : 1; ++ break; ++ case 'r': ++ err = atoi(optarg); ++ arg_rate = err >= 4000 && err < 200000 ? err : 44100; ++ break; ++ case 'B': ++ err = atoi(optarg); ++ arg_buffer_size = err >= 32 && err < 200000 ? err : 0; ++ break; ++ case 'E': ++ err = atoi(optarg); ++ arg_period_size = err >= 32 && err < 200000 ? err : 0; ++ break; ++ case 's': ++ err = atoi(optarg); ++ arg_loop_time = err >= 1 && err <= 100000 ? err : 30; ++ break; ++ case 'b': ++ arg_nblock = 1; ++ break; ++ case 'e': ++ arg_effect = 1; ++ break; ++ case 'n': ++ arg_resample = 0; ++ break; ++ case 'A': ++ if (strcasecmp(optarg, "sincbest") == 0) ++ arg_samplerate = SRC_SINC_BEST_QUALITY; ++ else if (strcasecmp(optarg, "sincmedium") == 0) ++ arg_samplerate = SRC_SINC_MEDIUM_QUALITY; ++ else if (strcasecmp(optarg, "sincfastest") == 0) ++ arg_samplerate = SRC_SINC_FASTEST; ++ else if (strcasecmp(optarg, "zerohold") == 0) ++ arg_samplerate = SRC_ZERO_ORDER_HOLD; ++ else if (strcasecmp(optarg, "linear") == 0) ++ arg_samplerate = SRC_LINEAR; ++ else ++ arg_samplerate = atoi(optarg); ++ if (arg_samplerate < 0 || arg_samplerate > SRC_LINEAR) ++ arg_sync = SRC_SINC_FASTEST; ++ arg_samplerate += 1; ++ break; ++ case 'S': ++ if (strcasecmp(optarg, "samplerate") == 0) ++ arg_sync = SYNC_TYPE_SAMPLERATE; ++ else if (optarg[0] == 'n') ++ arg_sync = SYNC_TYPE_NONE; ++ else if (optarg[0] == 's') ++ arg_sync = SYNC_TYPE_SIMPLE; ++ else if (optarg[0] == 'c') ++ arg_sync = SYNC_TYPE_CAPTRATESHIFT; ++ else if (optarg[0] == 'p') ++ arg_sync = SYNC_TYPE_PLAYRATESHIFT; ++ else if (optarg[0] == 'r') ++ arg_sync = SYNC_TYPE_SAMPLERATE; ++ else ++ arg_sync = atoi(optarg); ++ if (arg_sync < 0 || arg_sync > SYNC_TYPE_LAST) ++ arg_sync = SYNC_TYPE_AUTO; ++ break; ++ case 'a': ++ if (optarg[0] == 'a') ++ arg_slave = SLAVE_TYPE_AUTO; ++ else if (strcasecmp(optarg, "off")) ++ arg_slave = SLAVE_TYPE_ON; ++ else if (strcasecmp(optarg, "on")) ++ arg_slave = SLAVE_TYPE_OFF; ++ else ++ arg_slave = atoi(optarg); ++ if (arg_slave < 0 || arg_slave > SLAVE_TYPE_LAST) ++ arg_slave = SLAVE_TYPE_AUTO; ++ break; ++ case 'T': ++ arg_thread = atoi(optarg); ++ if (arg_thread < 0) ++ arg_thread = 10000000 + loopbacks_count; ++ break; ++ case 'm': ++ if (arg_mixers_count >= MAX_MIXERS) { ++ logit(LOG_CRIT, "Maximum redirected mixer controls reached (max %i)\n", (int)MAX_MIXERS); ++ exit(EXIT_FAILURE); ++ } ++ arg_mixers[arg_mixers_count++] = optarg; ++ break; ++ case 'v': ++ verbose++; ++ break; ++ } ++ } ++ ++ if (morehelp) { ++ help(); ++ exit(EXIT_SUCCESS); ++ } ++ if (arg_config == NULL) { ++ struct loopback_handle *play; ++ struct loopback_handle *capt; ++ err = create_loopback_handle(&play, arg_pdevice, "playback"); ++ if (err < 0) { ++ logit(LOG_CRIT, "Unable to create playback handle.\n"); ++ exit(EXIT_FAILURE); ++ } ++ err = create_loopback_handle(&capt, arg_cdevice, "capture"); ++ if (err < 0) { ++ logit(LOG_CRIT, "Unable to create capture handle.\n"); ++ exit(EXIT_FAILURE); ++ } ++ err = create_loopback(&loop, play, capt, output); ++ if (err < 0) { ++ logit(LOG_CRIT, "Unable to create loopback handle.\n"); ++ exit(EXIT_FAILURE); ++ } ++ play->format = capt->format = arg_format; ++ play->rate = capt->rate = 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; ++ play->resample = capt->resample = arg_resample; ++ play->nblock = capt->nblock = arg_nblock ? 1 : 0; ++ loop->latency_req = arg_latency_req; ++ loop->latency_reqtime = arg_latency_reqtime; ++ loop->sync = arg_sync; ++ loop->slave = arg_slave; ++ loop->thread = arg_thread; ++ err = add_mixers(loop, arg_mixers, arg_mixers_count); ++ if (err < 0) { ++ logit(LOG_CRIT, "Unable to add mixer controls.\n"); ++ exit(EXIT_FAILURE); ++ } ++#ifdef USE_SAMPLERATE ++ loop->src_enable = arg_samplerate > 0; ++ if (loop->src_enable) ++ loop->src_converter_type = arg_samplerate - 1; ++#else ++ if (arg_samplerate > 0) { ++ logit(LOG_CRIT, "No libsamplerate support.\n"); ++ exit(EXIT_FAILURE); ++ } ++#endif ++ set_loop_time(loop, arg_loop_time); ++ add_loop(loop); ++ return 0; ++ } ++ ++ return parse_config_file(arg_config, output); ++} ++ ++static int parse_config_file(const char *file, snd_output_t *output) ++{ ++ FILE *fp; ++ char line[2048], word[2048]; ++ char *str, *ptr; ++ 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)); ++ return -EIO; ++ } ++ while (!feof(fp)) { ++ if (fgets(line, sizeof(line)-1, fp) == NULL) ++ break; ++ line[sizeof(line)-1] = '\0'; ++ argc = 0; ++ argv[argc++] = strdup(""); ++ str = line; ++ while (*str) { ++ ptr = word; ++ while (*str && (*str == ' ' || *str < ' ')) ++ str++; ++ if (*str == '#') ++ goto __next; ++ if (*str == '\'' || *str == '\"') { ++ c = *str++; ++ while (*str && *str != c) ++ *ptr++ = *str++; ++ if (*str == c) ++ str++; ++ } else { ++ while (*str && *str != ' ' && *str != '\t') ++ *ptr++ = *str++; ++ } ++ if (ptr != word) { ++ *ptr = '\0'; ++ argv[argc++] = strdup(word); ++ } ++ } ++ /* erase runtime variables for getopt */ ++ optarg = NULL; ++ optind = opterr = 1; ++ optopt = 63; ++ ++ err = parse_config(argc, argv, output); ++ __next: ++ while (argc > 0) ++ free(argv[--argc]); ++ if (err < 0) ++ break; ++ err = 0; ++ } ++ fclose(fp); ++ free(argv); ++ ++ return err; ++} ++ ++static void thread_job1(void *_data) ++{ ++ struct loopback_thread *thread = _data; ++ snd_output_t *output = thread->output; ++ struct pollfd *pfds = NULL; ++ int pfds_count = 0; ++ int i, j, err; ++ ++ setscheduler(); ++ ++ for (i = 0; i < thread->loopbacks_count; i++) { ++ err = pcmjob_init(thread->loopbacks[i]); ++ if (err < 0) { ++ logit(LOG_CRIT, "Loopback initialization failure.\n"); ++ my_exit(thread, EXIT_FAILURE); ++ } ++ } ++ for (i = 0; i < thread->loopbacks_count; i++) { ++ err = pcmjob_start(thread->loopbacks[i]); ++ if (err < 0) { ++ logit(LOG_CRIT, "Loopback start failure.\n"); ++ my_exit(thread, EXIT_FAILURE); ++ } ++ pfds_count += thread->loopbacks[i]->pollfd_count; ++ } ++ pfds = calloc(pfds_count, sizeof(struct pollfd)); ++ if (pfds == NULL) { ++ logit(LOG_CRIT, "Poll FDs allocation failed.\n"); ++ my_exit(thread, EXIT_FAILURE); ++ } ++ while (1) { ++ struct timeval tv1, tv2; ++ for (i = j = 0; i < thread->loopbacks_count; i++) { ++ err = pcmjob_pollfds_init(thread->loopbacks[i], &pfds[j]); ++ if (err < 0) { ++ logit(LOG_CRIT, "Poll FD initialization failed.\n"); ++ my_exit(thread, EXIT_FAILURE); ++ } ++ j += err; ++ } ++ if (verbose > 10) ++ gettimeofday(&tv1, NULL); ++ err = poll(pfds, j, -1); ++ 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"); ++ my_exit(thread, EXIT_FAILURE); ++ } ++ for (i = j = 0; i < thread->loopbacks_count; i++) { ++ struct loopback *loop = thread->loopbacks[i]; ++ if (j < loop->active_pollfd_count) { ++ err = pcmjob_pollfds_handle(loop, &pfds[j]); ++ if (err < 0) { ++ logit(LOG_CRIT, "pcmjob failed.\n"); ++ exit(EXIT_FAILURE); ++ } ++ } ++ j += loop->active_pollfd_count; ++ } ++ } ++ ++ my_exit(thread, EXIT_SUCCESS); ++} ++ ++static void thread_job(struct loopback_thread *thread) ++{ ++ if (!thread->threaded) { ++ thread_job1(thread); ++ return; ++ } ++ pthread_create(&thread->thread, NULL, (void *) &thread_job1, ++ (void *) thread); ++} ++ ++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); ++ if (err < 0) { ++ logit(LOG_CRIT, "Unable to parse arguments or configuration...\n"); ++ exit(EXIT_FAILURE); ++ } ++ ++ if (loopbacks_count <= 0) { ++ logit(LOG_CRIT, "No loopback defined...\n"); ++ exit(EXIT_FAILURE); ++ } ++ ++ if (daemonize) { ++ if (daemon(0, 0) < 0) { ++ logit(LOG_CRIT, "daemon() failed: %s\n", strerror(errno)); ++ exit(EXIT_FAILURE); ++ } ++ i = fork(); ++ if (i < 0) { ++ logit(LOG_CRIT, "fork() failed: %s\n", strerror(errno)); ++ exit(EXIT_FAILURE); ++ } ++ if (i > 0) { ++ /* wait(&i); */ ++ exit(EXIT_SUCCESS); ++ } ++ } ++ ++ /* we must sort thread IDs */ ++ j = 0; ++ do { ++ k = 0x7fffffff; ++ for (i = 0; i < loopbacks_count; i++) { ++ if (loopbacks[i]->thread < k && ++ loopbacks[i]->thread > j) ++ k = loopbacks[i]->thread; ++ } ++ 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++) { ++ if (loopbacks[i]->thread > j) ++ j = loopbacks[i]->thread; ++ } ++ j += 1; ++ threads = calloc(1, sizeof(struct loopback_thread) * j); ++ if (threads == NULL) { ++ logit(LOG_CRIT, "No enough memory\n"); ++ exit(EXIT_FAILURE); ++ } ++ /* sort all threads */ ++ for (k = 0; k < j; k++) { ++ for (i = l = 0; i < loopbacks_count; i++) ++ if (loopbacks[i]->thread == k) ++ l++; ++ threads[k].loopbacks = malloc(l * sizeof(struct loopback *)); ++ threads[k].loopbacks_count = l; ++ threads[k].output = output; ++ threads[k].threaded = j > 1; ++ for (i = l = 0; i < loopbacks_count; i++) ++ if (loopbacks[i]->thread == k) ++ threads[k].loopbacks[l++] = loopbacks[i]; ++ } ++ ++ 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); ++ } ++ ++ if (use_syslog) ++ closelog(); ++ exit(EXIT_SUCCESS); ++} +diff --git a/alsaloop/alsaloop.h b/alsaloop/alsaloop.h +new file mode 100644 +index 0000000..4b357de +--- /dev/null ++++ b/alsaloop/alsaloop.h +@@ -0,0 +1,181 @@ ++/* ++ * A simple PCM loopback utility ++ * Copyright (c) 2010 by Jaroslav Kysela ++ * ++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#include "aconfig.h" ++#ifdef HAVE_SAMPLERATE_H ++#define USE_SAMPLERATE ++#include ++#else ++enum { ++ SRC_SINC_BEST_QUALITY = 0, ++ SRC_SINC_MEDIUM_QUALITY = 1, ++ SRC_SINC_FASTEST = 2, ++ SRC_ZERO_ORDER_HOLD = 3, ++ SRC_LINEAR = 4 ++}; ++#endif ++ ++#define MAX_ARGS 128 ++#define MAX_MIXERS 64 ++ ++#if 0 ++#define FILE_PWRITE "/tmp/alsaloop.praw" ++#define FILE_CWRITE "/tmp/alsaloop.craw" ++#endif ++ ++typedef enum _sync_type { ++ SYNC_TYPE_NONE = 0, ++ SYNC_TYPE_SIMPLE, /* add or remove samples */ ++ SYNC_TYPE_CAPTRATESHIFT, ++ SYNC_TYPE_PLAYRATESHIFT, ++ SYNC_TYPE_SAMPLERATE, ++ SYNC_TYPE_AUTO, /* order: CAPTRATESHIFT, PLAYRATESHIFT, */ ++ /* SAMPLERATE, SIMPLE */ ++ SYNC_TYPE_LAST = SYNC_TYPE_AUTO ++} sync_type_t; ++ ++typedef enum _slave_type { ++ SLAVE_TYPE_AUTO = 0, ++ SLAVE_TYPE_ON = 1, ++ SLAVE_TYPE_OFF = 2, ++ SLAVE_TYPE_LAST = SLAVE_TYPE_OFF ++} slave_type_t; ++ ++struct loopback_control { ++ snd_ctl_elem_id_t *id; ++ snd_ctl_elem_info_t *info; ++ snd_ctl_elem_value_t *value; ++}; ++ ++struct loopback_mixer { ++ unsigned int skip: 1; ++ struct loopback_control src; ++ struct loopback_control dst; ++ struct loopback_mixer *next; ++}; ++ ++struct loopback_handle { ++ struct loopback *loopback; ++ char *device; ++ char *id; ++ snd_pcm_t *handle; ++ snd_pcm_access_t access; ++ snd_pcm_format_t format; ++ unsigned int rate; ++ unsigned int channels; ++ unsigned int buffer_size; ++ unsigned int period_size; ++ unsigned int buffer_size_req; ++ unsigned int period_size_req; ++ unsigned int frame_size; ++ unsigned int resample:1; /* do resample */ ++ unsigned int nblock:1; /* do block (period size) transfers */ ++ unsigned int xrun_pending:1; ++ unsigned int pollfd_count; ++ /* I/O job */ ++ char *buf; /* I/O buffer */ ++ snd_pcm_uframes_t buf_pos; /* I/O position */ ++ snd_pcm_uframes_t buf_count; /* filled samples */ ++ snd_pcm_uframes_t buf_size; /* buffer size in frames */ ++ snd_pcm_uframes_t buf_over; /* capture buffer overflow */ ++ /* statistics */ ++ snd_pcm_uframes_t max; ++ unsigned long long counter; ++ unsigned long sync_point; /* in samples */ ++ snd_pcm_sframes_t last_delay; ++ /* control */ ++ snd_ctl_t *ctl; ++ unsigned int ctl_pollfd_count; ++ snd_ctl_elem_value_t *ctl_notify; ++ snd_ctl_elem_value_t *ctl_rate_shift; ++ snd_ctl_elem_value_t *ctl_active; ++ snd_ctl_elem_value_t *ctl_format; ++ snd_ctl_elem_value_t *ctl_rate; ++ snd_ctl_elem_value_t *ctl_channels; ++}; ++ ++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 */ ++ unsigned long loop_time; /* ~0 = unlimited (in seconds) */ ++ unsigned long long loop_limit; /* ~0 = unlimited (in frames) */ ++ snd_output_t *output; ++ int pollfd_count; ++ int active_pollfd_count; ++ unsigned int linked:1; /* linked streams */ ++ unsigned int reinit:1; ++ unsigned int running:1; ++ sync_type_t sync; /* type of sync */ ++ slave_type_t slave; ++ int thread; /* thread number */ ++ /* statistics */ ++ double pitch; ++ double pitch_delta; ++ 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 */ ++#ifdef USE_SAMPLERATE ++ unsigned int src_enable: 1; ++ int src_converter_type; ++ SRC_STATE *src_state; ++ SRC_DATA src_data; ++ unsigned int src_out_frames; ++#endif ++#ifdef FILE_CWRITE ++ FILE *cfile; ++#endif ++#ifdef FILE_PWRITE ++ FILE *pfile; ++#endif ++}; ++ ++extern int verbose; ++extern int use_syslog; ++ ++#define logit(priority, fmt, args...) do { \ ++ if (use_syslog) \ ++ syslog(priority, fmt, ##args); \ ++ else \ ++ fprintf(stderr, fmt, ##args); \ ++} while (0) ++ ++int pcmjob_init(struct loopback *loop); ++int pcmjob_done(struct loopback *loop); ++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); ++ ++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); ++int control_init(struct loopback *loop); ++int control_done(struct loopback *loop); ++int control_event(struct loopback_handle *lhandle, snd_ctl_event_t *ev); +diff --git a/alsaloop/control.c b/alsaloop/control.c +new file mode 100644 +index 0000000..ade7733 +--- /dev/null ++++ b/alsaloop/control.c +@@ -0,0 +1,376 @@ ++/* ++ * A simple PCM loopback utility ++ * Copyright (c) 2010 by Jaroslav Kysela ++ * ++ * Author: Jaroslav Kysela ++ * ++ * ++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#include ++#include ++#include ++#include "alsaloop.h" ++ ++static char *id_str(snd_ctl_elem_id_t *id) ++{ ++ static char str[128]; ++ ++ sprintf(str, "%i,%s,%i,%i,%s,%i", ++ snd_ctl_elem_id_get_numid(id), ++ snd_ctl_elem_iface_name(snd_ctl_elem_id_get_interface(id)), ++ snd_ctl_elem_id_get_device(id), ++ snd_ctl_elem_id_get_subdevice(id), ++ snd_ctl_elem_id_get_name(id), ++ snd_ctl_elem_id_get_index(id)); ++ return str; ++} ++ ++int control_parse_id(const char *str, snd_ctl_elem_id_t *id) ++{ ++ int c, size, numid; ++ char *ptr; ++ ++ while (*str == ' ' || *str == '\t') ++ str++; ++ if (!(*str)) ++ return -EINVAL; ++ snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER); /* default */ ++ while (*str) { ++ if (!strncasecmp(str, "numid=", 6)) { ++ str += 6; ++ numid = atoi(str); ++ if (numid <= 0) { ++ logit(LOG_CRIT, "Invalid numid %d\n", numid); ++ return -EINVAL; ++ } ++ snd_ctl_elem_id_set_numid(id, atoi(str)); ++ while (isdigit(*str)) ++ str++; ++ } else if (!strncasecmp(str, "iface=", 6)) { ++ str += 6; ++ if (!strncasecmp(str, "card", 4)) { ++ snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_CARD); ++ str += 4; ++ } else if (!strncasecmp(str, "mixer", 5)) { ++ snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER); ++ str += 5; ++ } else if (!strncasecmp(str, "pcm", 3)) { ++ snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_PCM); ++ str += 3; ++ } else if (!strncasecmp(str, "rawmidi", 7)) { ++ snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_RAWMIDI); ++ str += 7; ++ } else if (!strncasecmp(str, "timer", 5)) { ++ snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_TIMER); ++ str += 5; ++ } else if (!strncasecmp(str, "sequencer", 9)) { ++ snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_SEQUENCER); ++ str += 9; ++ } else { ++ return -EINVAL; ++ } ++ } else if (!strncasecmp(str, "name=", 5)) { ++ char buf[64]; ++ str += 5; ++ ptr = buf; ++ size = 0; ++ if (*str == '\'' || *str == '\"') { ++ c = *str++; ++ while (*str && *str != c) { ++ if (size < (int)sizeof(buf)) { ++ *ptr++ = *str; ++ size++; ++ } ++ str++; ++ } ++ if (*str == c) ++ str++; ++ } else { ++ while (*str && *str != ',') { ++ if (size < (int)sizeof(buf)) { ++ *ptr++ = *str; ++ size++; ++ } ++ str++; ++ } ++ } ++ *ptr = '\0'; ++ snd_ctl_elem_id_set_name(id, buf); ++ } else if (!strncasecmp(str, "index=", 6)) { ++ str += 6; ++ snd_ctl_elem_id_set_index(id, atoi(str)); ++ while (isdigit(*str)) ++ str++; ++ } else if (!strncasecmp(str, "device=", 7)) { ++ str += 7; ++ snd_ctl_elem_id_set_device(id, atoi(str)); ++ while (isdigit(*str)) ++ str++; ++ } else if (!strncasecmp(str, "subdevice=", 10)) { ++ str += 10; ++ snd_ctl_elem_id_set_subdevice(id, atoi(str)); ++ while (isdigit(*str)) ++ str++; ++ } ++ if (*str == ',') { ++ str++; ++ } else { ++ if (*str) ++ return -EINVAL; ++ } ++ } ++ return 0; ++} ++ ++int control_id_match(snd_ctl_elem_id_t *id1, snd_ctl_elem_id_t *id2) ++{ ++ if (snd_ctl_elem_id_get_interface(id1) != ++ snd_ctl_elem_id_get_interface(id2)) ++ return 0; ++ if (snd_ctl_elem_id_get_device(id1) != ++ snd_ctl_elem_id_get_device(id2)) ++ return 0; ++ if (snd_ctl_elem_id_get_subdevice(id1) != ++ snd_ctl_elem_id_get_subdevice(id2)) ++ return 0; ++ if (strcmp(snd_ctl_elem_id_get_name(id1), ++ snd_ctl_elem_id_get_name(id2)) != 0) ++ return 0; ++ if (snd_ctl_elem_id_get_index(id1) != ++ snd_ctl_elem_id_get_index(id2)) ++ return 0; ++ return 1; ++} ++ ++static int control_init1(struct loopback_handle *lhandle, ++ struct loopback_control *ctl) ++{ ++ int err; ++ ++ snd_ctl_elem_info_set_id(ctl->info, ctl->id); ++ snd_ctl_elem_value_set_id(ctl->value, ctl->id); ++ 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)); ++ return err; ++ } ++ err = snd_ctl_elem_read(lhandle->ctl, ctl->value); ++ if (err < 0) { ++ logit(LOG_WARNING, "Unable to read control value (init1) '%s': %s\n", id_str(ctl->id), snd_strerror(err)); ++ return err; ++ } ++ return 0; ++} ++ ++static int copy_value(struct loopback_control *dst, ++ struct loopback_control *src) ++{ ++ snd_ctl_elem_type_t type; ++ unsigned int count; ++ int i; ++ ++ type = snd_ctl_elem_info_get_type(dst->info); ++ count = snd_ctl_elem_info_get_count(dst->info); ++ switch (type) { ++ case SND_CTL_ELEM_TYPE_BOOLEAN: ++ for (i = 0; i < count; i++) ++ snd_ctl_elem_value_set_boolean(dst->value, ++ i, snd_ctl_elem_value_get_boolean(src->value, i)); ++ break; ++ case SND_CTL_ELEM_TYPE_INTEGER: ++ for (i = 0; i < count; i++) { ++ snd_ctl_elem_value_set_integer(dst->value, ++ i, snd_ctl_elem_value_get_integer(src->value, i)); ++ } ++ break; ++ default: ++ logit(LOG_CRIT, "Unable to copy control value for type %s\n", snd_ctl_elem_type_name(type)); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static int control_init2(struct loopback *loop, ++ struct loopback_mixer *mix) ++{ ++ snd_ctl_elem_type_t type; ++ unsigned int count; ++ int err; ++ ++ snd_ctl_elem_info_copy(mix->dst.info, mix->src.info); ++ snd_ctl_elem_info_set_id(mix->dst.info, mix->dst.id); ++ snd_ctl_elem_value_clear(mix->dst.value); ++ snd_ctl_elem_value_set_id(mix->dst.value, mix->dst.id); ++ type = snd_ctl_elem_info_get_type(mix->dst.info); ++ count = snd_ctl_elem_info_get_count(mix->dst.info); ++ snd_ctl_elem_remove(loop->capt->ctl, mix->dst.id); ++ switch (type) { ++ case SND_CTL_ELEM_TYPE_BOOLEAN: ++ err = snd_ctl_elem_add_boolean(loop->capt->ctl, ++ mix->dst.id, count); ++ copy_value(&mix->dst, &mix->src); ++ break; ++ case SND_CTL_ELEM_TYPE_INTEGER: ++ err = snd_ctl_elem_add_integer(loop->capt->ctl, ++ mix->dst.id, count, ++ snd_ctl_elem_info_get_min(mix->dst.info), ++ snd_ctl_elem_info_get_max(mix->dst.info), ++ snd_ctl_elem_info_get_step(mix->dst.info)); ++ copy_value(&mix->dst, &mix->src); ++ break; ++ default: ++ logit(LOG_CRIT, "Unable to handle control type %s\n", snd_ctl_elem_type_name(type)); ++ err = -EINVAL; ++ break; ++ } ++ if (err < 0) { ++ logit(LOG_CRIT, "Unable to create control '%s': %s\n", id_str(mix->dst.id), snd_strerror(err)); ++ return err; ++ } ++ err = snd_ctl_elem_unlock(loop->capt->ctl, mix->dst.id); ++ if (err < 0) { ++ logit(LOG_CRIT, "Unable to unlock control info '%s': %s\n", id_str(mix->dst.id), snd_strerror(err)); ++ return err; ++ } ++ err = snd_ctl_elem_info(loop->capt->ctl, mix->dst.info); ++ if (err < 0) { ++ logit(LOG_CRIT, "Unable to read control info '%s': %s\n", id_str(mix->dst.id), snd_strerror(err)); ++ return err; ++ } ++ if (snd_ctl_elem_info_is_tlv_writable(mix->dst.info)) { ++ unsigned int tlv[64]; ++ err = snd_ctl_elem_tlv_read(loop->play->ctl, ++ mix->src.id, ++ tlv, sizeof(tlv)); ++ if (err < 0) { ++ logit(LOG_CRIT, "Unable to read TLV for '%s': %s\n", id_str(mix->src.id), snd_strerror(err)); ++ tlv[0] = tlv[1] = 0; ++ } ++ err = snd_ctl_elem_tlv_write(loop->capt->ctl, ++ mix->dst.id, ++ tlv); ++ if (err < 0) { ++ logit(LOG_CRIT, "Unable to write TLV for '%s': %s\n", id_str(mix->src.id), snd_strerror(err)); ++ return err; ++ } ++ } ++ err = snd_ctl_elem_write(loop->capt->ctl, mix->dst.value); ++ if (err < 0) { ++ logit(LOG_CRIT, "Unable to write control value '%s': %s\n", id_str(mix->dst.id), snd_strerror(err)); ++ return err; ++ } ++ return 0; ++} ++ ++int control_init(struct loopback *loop) ++{ ++ struct loopback_mixer *mix; ++ int err; ++ ++ 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)); ++ mix->skip = 1; ++ continue; ++ } ++ err = control_init2(loop, mix); ++ if (err < 0) ++ return err; ++ } ++ return 0; ++} ++ ++int control_done(struct loopback *loop) ++{ ++ struct loopback_mixer *mix; ++ int err; ++ ++ if (loop->capt->ctl == NULL) ++ return 0; ++ 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)); ++ } ++ return 0; ++} ++ ++static int control_event1(struct loopback *loop, ++ struct loopback_mixer *mix, ++ snd_ctl_event_t *ev, ++ int capture) ++{ ++ unsigned int mask = snd_ctl_event_elem_get_mask(ev); ++ int err; ++ ++ if (mask == SND_CTL_EVENT_MASK_REMOVE) ++ return 0; ++ if ((mask & SND_CTL_EVENT_MASK_VALUE) == 0) ++ return 0; ++ if (!capture) { ++ snd_ctl_elem_value_set_id(mix->src.value, mix->src.id); ++ err = snd_ctl_elem_read(loop->play->ctl, mix->src.value); ++ if (err < 0) { ++ logit(LOG_CRIT, "Unable to read control value (event1) '%s': %s\n", id_str(mix->src.id), snd_strerror(err)); ++ return err; ++ } ++ copy_value(&mix->dst, &mix->src); ++ err = snd_ctl_elem_write(loop->capt->ctl, mix->dst.value); ++ if (err < 0) { ++ logit(LOG_CRIT, "Unable to write control value (event1) '%s': %s\n", id_str(mix->dst.id), snd_strerror(err)); ++ return err; ++ } ++ } else { ++ err = snd_ctl_elem_read(loop->capt->ctl, mix->dst.value); ++ if (err < 0) { ++ logit(LOG_CRIT, "Unable to read control value (event2) '%s': %s\n", id_str(mix->dst.id), snd_strerror(err)); ++ return err; ++ } ++ copy_value(&mix->src, &mix->dst); ++ err = snd_ctl_elem_write(loop->play->ctl, mix->src.value); ++ if (err < 0) { ++ logit(LOG_CRIT, "Unable to write control value (event2) '%s': %s\n", id_str(mix->src.id), snd_strerror(err)); ++ return err; ++ } ++ } ++ return 0; ++} ++ ++int control_event(struct loopback_handle *lhandle, snd_ctl_event_t *ev) ++{ ++ snd_ctl_elem_id_t *id2; ++ struct loopback_mixer *mix; ++ int capt = lhandle == lhandle->loopback->capt; ++ int err; ++ ++ snd_ctl_elem_id_alloca(&id2); ++ snd_ctl_event_elem_get_id(ev, id2); ++ for (mix = lhandle->loopback->controls; mix; mix = mix->next) { ++ if (mix->skip) ++ continue; ++ if (control_id_match(id2, capt ? mix->dst.id : mix->src.id)) { ++ err = control_event1(lhandle->loopback, mix, ev, capt); ++ if (err < 0) ++ return err; ++ } ++ } ++ return 0; ++} +diff --git a/alsaloop/effect-sweep.c b/alsaloop/effect-sweep.c +new file mode 100644 +index 0000000..4a0903d +--- /dev/null ++++ b/alsaloop/effect-sweep.c +@@ -0,0 +1,128 @@ ++/* ++ * Bandpass filter sweep effect ++ * Copyright (c) Maarten de Boer ++ * ++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#include ++#include ++ ++struct effect_private { ++ /* filter the sweep variables */ ++ float lfo,dlfo,fs,fc,BW,C,D,a0,a1,a2,b1,b2,*x[3],*y[3]; ++ float lfo_depth, lfo_center; ++ unsigned int channels; ++}; ++ ++static int effect_init(struct lookback *loopback, ++ void *private_data, ++ snd_pcm_access_t access, ++ unsigned int channels, ++ unsigned int rate, ++ snd_pcm_format_t format) ++{ ++ struct effect_private *priv = private_data; ++ int i; ++ ++#if __BYTE_ORDER == __LITTLE_ENDIAN ++ if (format != SND_PCM_FORMAT_S16_LE) ++ return -EIO; ++#elif __BYTE_ORDER == __BIG_ENDIAN ++ if (format != SND_PCM_FORMAT_S16_BE) ++ return -EIO; ++#else ++ return -EIO; ++#endif ++ priv->fs = (float) rate; ++ priv->channels = channels; ++ for (i = 0; i < 3; i++) { ++ priv->x[i] = calloc(channels * sizeof(float)); ++ priv->y[i] = calloc(channels * sizeof(float)); ++ } ++ return 0; ++} ++ ++static int effect_done(struct loopback *loopback, ++ void *private_data) ++{ ++ struct effect_private *priv = private_data; ++ int i; ++ ++ for (i = 0; i < 3; i++) { ++ free(priv->x[i]); ++ free(priv->y[i]); ++ } ++ return 0; ++} ++ ++static int effect_apply(struct loopback *loopback, ++ void *private_data, ++ const snd_pcm_channel_area_t *areas, ++ snd_uframes_t offset, ++ snd_uframes_t frames) ++{ ++ struct effect_private *priv = private_data; ++ short *samples = (short*)areas[0].addr + offset*priv->channels; ++ snd_uframes_t i; ++ ++ for (i=0; i < frames; i++) { ++ int chn; ++ ++ fc = sin(priv->lfo)*priv->lfo_depth+priv->lfo_center; ++ priv->lfo += priv->dlfo; ++ if (priv->lfo>2.*M_PI) priv->lfo -= 2.*M_PI; ++ priv->C = 1./tan(M_PI*priv->BW/priv->fs); ++ priv->D = 2.*cos(2*M_PI*fc/fs); ++ priv->a0 = 1./(1.+priv->C); ++ priv->a1 = 0; ++ priv->a2 = -priv->a0; ++ priv->b1 = -priv->C*priv->D*a0; ++ priv->b2 = (priv->C-1)*priv->a0; ++ ++ for (chn=0; chn < priv->channels; chn++) ++ { ++ priv->x[chn][2] = priv->x[chn][1]; ++ priv->x[chn][1] = priv->x[chn][0]; ++ ++ priv->y[chn][2] = priv->y[chn][1]; ++ priv->y[chn][1] = priv->y[chn][0]; ++ ++ priv->x[chn][0] = samples[i*channels+chn]; ++ priv->y[chn][0] = priv->a0*priv->x[0][chn] ++ + priv->a1*priv->x[1][chn] + priv->a2*x[2][chn] ++ - priv->b1*priv->y[1][chn] - priv->b2*y[2][chn]; ++ samples[i*channels+chn] = priv->y[chn][0]; ++ } ++ } ++ return 0; ++} ++ ++void effect_init_sweep(void) ++{ ++ struct effect_private *priv; ++ ++ priv = register_effect(effect_init, ++ effect_apply, ++ effect_done, ++ sizeof(struct effectprivate)); ++ if (priv) { ++ priv->lfo_center = 2000.; ++ priv->lfo_depth = 1800.; ++ priv->lfo_freq = 0.2; ++ priv->BW = 50; ++ } ++} +diff --git a/alsaloop/pcmjob.c b/alsaloop/pcmjob.c +new file mode 100644 +index 0000000..47256e0 +--- /dev/null ++++ b/alsaloop/pcmjob.c +@@ -0,0 +1,1528 @@ ++/* ++ * A simple PCM loopback utility ++ * Copyright (c) 2010 by Jaroslav Kysela ++ * ++ * Author: Jaroslav Kysela ++ * ++ * ++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "alsaloop.h" ++ ++static int set_rate_shift(struct loopback_handle *lhandle, double pitch); ++ ++#define SYNCTYPE(v) [SYNC_TYPE_##v] = #v ++ ++static const char *sync_types[] = { ++ SYNCTYPE(NONE), ++ SYNCTYPE(SIMPLE), ++ SYNCTYPE(CAPTRATESHIFT), ++ SYNCTYPE(PLAYRATESHIFT), ++ SYNCTYPE(SAMPLERATE), ++ SYNCTYPE(AUTO) ++}; ++ ++#define SRCTYPE(v) [SRC_##v] = "SRC_" #v ++ ++static const char *src_types[] = { ++ SRCTYPE(SINC_BEST_QUALITY), ++ SRCTYPE(SINC_MEDIUM_QUALITY), ++ SRCTYPE(SINC_FASTEST), ++ SRCTYPE(ZERO_ORDER_HOLD), ++ SRCTYPE(LINEAR) ++}; ++ ++static inline snd_pcm_uframes_t get_whole_latency(struct loopback *loop) ++{ ++ return loop->latency; ++} ++ ++static inline snd_pcm_uframes_t time_to_frames(struct loopback_handle *lhandle, ++ unsigned long long time) ++{ ++ return (time * lhandle->rate) / 1000000ULL; ++} ++ ++static int setparams_stream(struct loopback_handle *lhandle, ++ snd_pcm_hw_params_t *params) ++{ ++ snd_pcm_t *handle = lhandle->handle; ++ int err; ++ unsigned int rrate; ++ ++ 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); ++ return err; ++ } ++ err = snd_pcm_hw_params_set_rate_resample(handle, params, lhandle->resample); ++ if (err < 0) { ++ logit(LOG_CRIT, "Resample setup failed for %s (val %i): %s\n", lhandle->id, lhandle->resample, snd_strerror(err)); ++ return err; ++ } ++ err = snd_pcm_hw_params_set_access(handle, params, lhandle->access); ++ if (err < 0) { ++ logit(LOG_CRIT, "Access type not available for %s: %s\n", lhandle->id, snd_strerror(err)); ++ return err; ++ } ++ err = snd_pcm_hw_params_set_format(handle, params, lhandle->format); ++ if (err < 0) { ++ logit(LOG_CRIT, "Sample format not available for %s: %s\n", lhandle->id, snd_strerror(err)); ++ return err; ++ } ++ err = snd_pcm_hw_params_set_channels(handle, params, lhandle->channels); ++ if (err < 0) { ++ logit(LOG_CRIT, "Channels count (%i) not available for %s: %s\n", lhandle->channels, lhandle->id, snd_strerror(err)); ++ return err; ++ } ++ rrate = lhandle->rate; ++ 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)); ++ return err; ++ } ++ 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); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static int setparams_bufsize(struct loopback_handle *lhandle, ++ snd_pcm_hw_params_t *params, ++ snd_pcm_hw_params_t *tparams, ++ snd_pcm_uframes_t bufsize) ++{ ++ snd_pcm_t *handle = lhandle->handle; ++ int err; ++ snd_pcm_uframes_t periodsize; ++ snd_pcm_uframes_t buffersize; ++ snd_pcm_uframes_t last_bufsize = 0; ++ ++ if (lhandle->buffer_size_req > 0) { ++ bufsize = lhandle->buffer_size_req; ++ last_bufsize = bufsize; ++ goto __set_it; ++ } ++ __again: ++ if (lhandle->buffer_size_req > 0) { ++ logit(LOG_CRIT, "Unable to set buffer size %li for %s\n", (long)lhandle->buffer_size, lhandle->id); ++ return -EIO; ++ } ++ if (last_bufsize == bufsize) ++ bufsize += 4; ++ last_bufsize = bufsize; ++ if (bufsize > 10*1024*1024) { ++ logit(LOG_CRIT, "Buffer size too big\n"); ++ return -EIO; ++ } ++ __set_it: ++ snd_pcm_hw_params_copy(params, tparams); ++ periodsize = bufsize * 8; ++ err = snd_pcm_hw_params_set_buffer_size_near(handle, params, &periodsize); ++ if (err < 0) { ++ logit(LOG_CRIT, "Unable to set buffer size %li for %s: %s\n", periodsize, lhandle->id, snd_strerror(err)); ++ goto __again; ++ } ++ snd_pcm_hw_params_get_buffer_size(params, &periodsize); ++ if (lhandle->period_size_req > 0) ++ periodsize = lhandle->period_size_req; ++ else ++ periodsize /= 8; ++ err = snd_pcm_hw_params_set_period_size_near(handle, params, &periodsize, 0); ++ if (err < 0) { ++ logit(LOG_CRIT, "Unable to set period size %li for %s: %s\n", periodsize, lhandle->id, snd_strerror(err)); ++ goto __again; ++ } ++ snd_pcm_hw_params_get_period_size(params, &periodsize, NULL); ++ if (periodsize != bufsize) ++ bufsize = periodsize; ++ snd_pcm_hw_params_get_buffer_size(params, &buffersize); ++ if (periodsize * 2 > buffersize) ++ goto __again; ++ lhandle->period_size = periodsize; ++ lhandle->buffer_size = buffersize; ++ return 0; ++} ++ ++static int setparams_set(struct loopback_handle *lhandle, ++ snd_pcm_hw_params_t *params, ++ snd_pcm_sw_params_t *swparams) ++{ ++ snd_pcm_t *handle = lhandle->handle; ++ int err; ++ snd_pcm_uframes_t val, val1; ++ ++ err = snd_pcm_hw_params(handle, params); ++ if (err < 0) { ++ logit(LOG_CRIT, "Unable to set hw params for %s: %s\n", lhandle->id, snd_strerror(err)); ++ return err; ++ } ++ err = snd_pcm_sw_params_current(handle, swparams); ++ if (err < 0) { ++ logit(LOG_CRIT, "Unable to determine current swparams for %s: %s\n", lhandle->id, snd_strerror(err)); ++ return err; ++ } ++ err = snd_pcm_sw_params_set_start_threshold(handle, swparams, 0x7fffffff); ++ if (err < 0) { ++ 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); ++ if (lhandle->nblock) { ++ if (lhandle == lhandle->loopback->play) { ++ val = val1 - (2 * val - 4); ++ } else { ++ val = 4; ++ } ++ } else { ++ if (lhandle == lhandle->loopback->play) { ++ snd_pcm_hw_params_get_buffer_size(params, &val1); ++ val = val1 - val - val / 2; ++ } else { ++ val /= 2; ++ } ++ } ++ err = snd_pcm_sw_params_set_avail_min(handle, swparams, val); ++ if (err < 0) { ++ logit(LOG_CRIT, "Unable to set avail min for %s: %s\n", lhandle->id, snd_strerror(err)); ++ return err; ++ } ++ 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)); ++ return err; ++ } ++ return 0; ++} ++ ++static int setparams(struct loopback *loop, snd_pcm_uframes_t bufsize) ++{ ++ int err; ++ snd_pcm_hw_params_t *pt_params, *ct_params; /* templates with rate, format and channels */ ++ snd_pcm_hw_params_t *p_params, *c_params; ++ snd_pcm_sw_params_t *p_swparams, *c_swparams; ++ ++ snd_pcm_hw_params_alloca(&p_params); ++ snd_pcm_hw_params_alloca(&c_params); ++ snd_pcm_hw_params_alloca(&pt_params); ++ snd_pcm_hw_params_alloca(&ct_params); ++ snd_pcm_sw_params_alloca(&p_swparams); ++ snd_pcm_sw_params_alloca(&c_swparams); ++ if ((err = setparams_stream(loop->play, pt_params)) < 0) { ++ logit(LOG_CRIT, "Unable to set parameters for %s stream: %s\n", loop->play->id, snd_strerror(err)); ++ return err; ++ } ++ if ((err = setparams_stream(loop->capt, ct_params)) < 0) { ++ logit(LOG_CRIT, "Unable to set parameters for %s stream: %s\n", loop->capt->id, snd_strerror(err)); ++ return err; ++ } ++ ++ if ((err = setparams_bufsize(loop->play, p_params, pt_params, bufsize)) < 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) { ++ logit(LOG_CRIT, "Unable to set buffer parameters for %s stream: %s\n", loop->capt->id, snd_strerror(err)); ++ return err; ++ } ++ ++ if ((err = setparams_set(loop->play, p_params, p_swparams)) < 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) { ++ logit(LOG_CRIT, "Unable to set sw parameters for %s stream: %s\n", loop->capt->id, snd_strerror(err)); ++ return err; ++ } ++ ++#if 0 ++ if (!loop->linked) ++ if (snd_pcm_link(loop->capt->handle, loop->play->handle) >= 0) ++ loop->linked = 1; ++#endif ++ if ((err = snd_pcm_prepare(loop->play->handle)) < 0) { ++ logit(LOG_CRIT, "Prepare %s error: %s\n", loop->play->id, snd_strerror(err)); ++ return err; ++ } ++ if (!loop->linked && (err = snd_pcm_prepare(loop->capt->handle)) < 0) { ++ logit(LOG_CRIT, "Prepare %s error: %s\n", loop->capt->id, snd_strerror(err)); ++ return err; ++ } ++ ++ if (verbose) { ++ snd_pcm_dump(loop->play->handle, loop->output); ++ snd_pcm_dump(loop->capt->handle, loop->output); ++ } ++ return 0; ++} ++ ++static void showlatency(struct loopback *loop, size_t latency, unsigned int rate) ++{ ++ 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); ++} ++ ++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) { ++ t1.tv_sec--; ++ l = -l; ++ l %= 1000000; ++ } ++ return (t1.tv_sec * 1000000) + l; ++} ++ ++static int getcurtimestamp(snd_timestamp_t *ts) ++{ ++ struct timeval tv; ++ gettimeofday(&tv, NULL); ++ ts->tv_sec = tv.tv_sec; ++ ts->tv_usec = tv.tv_usec; ++ return 0; ++} ++ ++static inline snd_pcm_uframes_t buf_avail(struct loopback_handle *lhandle) ++{ ++ return lhandle->buf_size - lhandle->buf_count; ++} ++ ++static void buf_remove(struct loopback *loop, snd_pcm_uframes_t count) ++{ ++ /* remove samples from the capture buffer */ ++ if (count <= 0) ++ return; ++ if (loop->play->buf == loop->capt->buf) { ++ if (count < loop->capt->buf_count) ++ loop->capt->buf_count -= count; ++ else ++ loop->capt->buf_count = 0; ++ } ++} ++ ++#if 0 ++static void buf_add_copy(struct loopback *loop) ++{ ++ struct loopback_handle *capt = loop->capt; ++ struct loopback_handle *play = loop->play; ++ snd_pcm_uframes_t count, count1, cpos, ppos; ++ ++ count = capt->buf_count; ++ cpos = capt->buf_pos - count; ++ if (cpos > capt->buf_size) ++ cpos += capt->buf_size; ++ ppos = (play->buf_pos + play->buf_count) % play->buf_size; ++ while (count > 0) { ++ count1 = count; ++ if (count1 + cpos > capt->buf_size) ++ count1 = capt->buf_size - cpos; ++ if (count1 > buf_avail(play)) ++ count1 = buf_avail(play); ++ if (count1 + ppos > play->buf_size) ++ count1 = play->buf_size - ppos; ++ if (count1 == 0) ++ break; ++ memcpy(play->buf + ppos * play->frame_size, ++ capt->buf + cpos * capt->frame_size, ++ count1 * capt->frame_size); ++ play->buf_count += count1; ++ capt->buf_count -= count1; ++ ppos += count1; ++ ppos %= play->buf_size; ++ cpos += count1; ++ cpos %= capt->buf_size; ++ count -= count1; ++ } ++} ++#endif ++ ++#ifdef USE_SAMPLERATE ++static void buf_add_src(struct loopback *loop) ++{ ++ struct loopback_handle *capt = loop->capt; ++ struct loopback_handle *play = loop->play; ++ float *old_data_out; ++ snd_pcm_uframes_t count, pos, count1, pos1; ++ count = capt->buf_count; ++ pos = 0; ++ pos1 = capt->buf_pos - count; ++ if (pos1 > capt->buf_size) ++ pos1 += capt->buf_size; ++ while (count > 0) { ++ count1 = count; ++ if (count1 + pos1 > capt->buf_size) ++ count1 = capt->buf_size - pos1; ++ src_short_to_float_array((short *)(capt->buf + ++ pos1 * capt->frame_size), ++ loop->src_data.data_in + ++ pos * capt->channels, ++ count1 * capt->channels); ++ count -= count1; ++ pos += count1; ++ pos1 += count1; ++ pos1 %= capt->buf_size; ++ } ++ loop->src_data.input_frames = pos; ++ loop->src_data.output_frames = play->buf_size - ++ loop->src_out_frames; ++ loop->src_data.end_of_input = 0; ++ old_data_out = loop->src_data.data_out; ++ loop->src_data.data_out = old_data_out + loop->src_out_frames; ++ src_process(loop->src_state, &loop->src_data); ++ loop->src_data.data_out = old_data_out; ++ capt->buf_count -= loop->src_data.input_frames_used; ++ count = loop->src_data.output_frames_gen + ++ loop->src_out_frames; ++ pos = 0; ++ pos1 = (play->buf_pos + play->buf_count) % play->buf_size; ++ while (count > 0) { ++ count1 = count; ++ if (count1 + pos1 > play->buf_size) ++ count1 = play->buf_size - pos1; ++ if (count1 > buf_avail(play)) ++ count1 = buf_avail(play); ++ if (count1 == 0) ++ break; ++ src_float_to_short_array(loop->src_data.data_out + ++ pos * play->channels, ++ (short *)(play->buf + ++ pos1 * play->frame_size), ++ count1 * play->channels); ++ play->buf_count += count1; ++ count -= count1; ++ pos += count1; ++ pos1 += count1; ++ pos1 %= play->buf_size; ++ } ++#if 0 ++ printf("src: pos = %li, gen = %li, out = %li, count = %li\n", ++ (long)pos, (long)loop->src_data.output_frames_gen, ++ (long)loop->src_out_frames, play->buf_count); ++#endif ++ loop->src_out_frames = (loop->src_data.output_frames_gen + ++ loop->src_out_frames) - pos; ++ if (loop->src_out_frames > 0) { ++ memmove(loop->src_data.data_out, ++ loop->src_data.data_out + pos * play->channels, ++ loop->src_out_frames * play->channels * sizeof(float)); ++ } ++} ++#else ++static void buf_add_src(struct loopback *loop) ++{ ++} ++#endif ++ ++static void buf_add(struct loopback *loop, snd_pcm_uframes_t count) ++{ ++ /* copy samples from capture to playback buffer */ ++ if (count <= 0) ++ return; ++ if (loop->play->buf == loop->capt->buf) { ++ loop->play->buf_count += count; ++ } else { ++ buf_add_src(loop); ++ } ++} ++ ++static int xrun(struct loopback_handle *lhandle) ++{ ++ int err; ++ ++ if (lhandle == lhandle->loopback->play) { ++ logit(LOG_DEBUG, "underrun for %s\n", lhandle->id); ++ if ((err = snd_pcm_prepare(lhandle->handle)) < 0) ++ return err; ++ lhandle->xrun_pending = 1; ++ } else { ++ logit(LOG_DEBUG, "overrun for %s\n", lhandle->id); ++ if ((err = snd_pcm_prepare(lhandle->handle)) < 0) ++ return err; ++ lhandle->xrun_pending = 1; ++ } ++ return 0; ++} ++ ++static int suspend(struct loopback_handle *lhandle) ++{ ++ int err; ++ ++ while ((err = snd_pcm_resume(lhandle->handle)) == -EAGAIN) ++ usleep(1); ++ if (err < 0) ++ return xrun(lhandle); ++ return 0; ++} ++ ++static int readit(struct loopback_handle *lhandle) ++{ ++ snd_pcm_sframes_t r, res = 0; ++ snd_pcm_sframes_t avail; ++ int err; ++ ++ avail = snd_pcm_avail_update(lhandle->handle); ++ if (avail > buf_avail(lhandle)) { ++ lhandle->buf_over += avail - buf_avail(lhandle); ++ avail = buf_avail(lhandle); ++ } else if (avail == 0) { ++ if (snd_pcm_state(lhandle->handle) == SND_PCM_STATE_DRAINING) { ++ lhandle->loopback->reinit = 1; ++ return 0; ++ } ++ } ++ while (avail > 0) { ++ r = buf_avail(lhandle); ++ if (r + lhandle->buf_pos > lhandle->buf_size) ++ r = lhandle->buf_size - lhandle->buf_pos; ++ if (r > avail) ++ r = avail; ++ r = snd_pcm_readi(lhandle->handle, ++ lhandle->buf + ++ lhandle->buf_pos * ++ lhandle->frame_size, r); ++ if (r == 0) ++ return res; ++ if (r < 0) { ++ if (r == -EPIPE) { ++ err = xrun(lhandle); ++ return res > 0 ? res : err; ++ } else if (r == -ESTRPIPE) { ++ if ((err = suspend(lhandle)) < 0) ++ return res > 0 ? res : err; ++ r = 0; ++ } else { ++ return res > 0 ? res : r; ++ } ++ } ++#ifdef FILE_CWRITE ++ if (lhandle->loopback->cfile) ++ fwrite(lhandle->buf + lhandle->buf_pos * lhandle->frame_size, ++ r, lhandle->frame_size, lhandle->loopback->cfile); ++#endif ++ res += r; ++ if (lhandle->max < res) ++ lhandle->max = res; ++ lhandle->counter += r; ++ lhandle->buf_count += r; ++ lhandle->buf_pos += r; ++ lhandle->buf_pos %= lhandle->buf_size; ++ avail -= r; ++ } ++ return res; ++} ++ ++static int writeit(struct loopback_handle *lhandle) ++{ ++ snd_pcm_sframes_t avail; ++ snd_pcm_sframes_t r, res = 0; ++ int err; ++ ++ __again: ++ avail = snd_pcm_avail_update(lhandle->handle); ++ if (avail == -EPIPE) { ++ if ((err = xrun(lhandle)) < 0) ++ return err; ++ return res; ++ } else if (avail == -ESTRPIPE) { ++ if ((err = suspend(lhandle)) < 0) ++ return err; ++ goto __again; ++ } ++ while (avail > 0 && lhandle->buf_count > 0) { ++ r = lhandle->buf_count; ++ if (r + lhandle->buf_pos > lhandle->buf_size) ++ r = lhandle->buf_size - lhandle->buf_pos; ++ if (r > avail) ++ r = avail; ++ r = snd_pcm_writei(lhandle->handle, ++ lhandle->buf + ++ lhandle->buf_pos * ++ lhandle->frame_size, r); ++ if (r <= 0) { ++ if (r == -EPIPE) { ++ if ((err = xrun(lhandle)) < 0) ++ return err; ++ return res; ++ } else if (r == -ESTRPIPE) { ++ } ++ return res > 0 ? res : r; ++ } ++#ifdef FILE_PWRITE ++ if (lhandle->loopback->pfile) ++ fwrite(lhandle->buf + lhandle->buf_pos * lhandle->frame_size, ++ r, lhandle->frame_size, lhandle->loopback->pfile); ++#endif ++ res += r; ++ lhandle->counter += r; ++ lhandle->buf_count -= r; ++ lhandle->buf_pos += r; ++ lhandle->buf_pos %= lhandle->buf_size; ++ } ++ return res; ++} ++ ++static snd_pcm_sframes_t remove_samples(struct loopback *loop, ++ int capture_preferred, ++ snd_pcm_sframes_t count) ++{ ++ struct loopback_handle *play = loop->play; ++ struct loopback_handle *capt = loop->capt; ++ ++ if (loop->play->buf == loop->capt->buf) { ++ if (count > loop->play->buf_count) ++ count = loop->play->buf_count; ++ if (count > loop->capt->buf_count) ++ count = loop->capt->buf_count; ++ capt->buf_count -= count; ++ play->buf_pos += count; ++ play->buf_pos %= play->buf_size; ++ play->buf_count -= count; ++ return count; ++ } ++ if (capture_preferred) { ++ if (count > capt->buf_count) ++ count = capt->buf_count; ++ capt->buf_count -= count; ++ } else { ++ if (count > play->buf_count) ++ count = play->buf_count; ++ } ++ return count; ++} ++ ++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; ++ int err; ++ ++ __again: ++ if (verbose > 5) ++ snd_output_printf(loop->output, "%s: xrun sync %i %i\n", loop->id, capt->xrun_pending, play->xrun_pending); ++ if (capt->xrun_pending) { ++ __pagain: ++ capt->xrun_pending = 0; ++ if ((err = snd_pcm_prepare(capt->handle)) < 0) { ++ logit(LOG_CRIT, "%s prepare failed: %s\n", capt->id, snd_strerror(err)); ++ return err; ++ } ++ if ((err = snd_pcm_start(capt->handle)) < 0) { ++ logit(LOG_CRIT, "%s start failed: %s\n", capt->id, snd_strerror(err)); ++ return err; ++ } ++ } else { ++ diff = readit(capt); ++ buf_add(loop, diff); ++ if (capt->xrun_pending) ++ goto __pagain; ++ } ++ /* skip additional playback samples */ ++ if ((err = snd_pcm_delay(capt->handle, &cdelay)) < 0) { ++ if (err == -EPIPE) { ++ capt->xrun_pending = 1; ++ goto __again; ++ } ++ if (err == -ESTRPIPE) { ++ err = suspend(capt); ++ if (err < 0) ++ return err; ++ goto __again; ++ } ++ logit(LOG_CRIT, "%s capture delay failed: %s\n", capt->id, snd_strerror(err)); ++ return err; ++ } ++ if ((err = snd_pcm_delay(play->handle, &pdelay)) < 0) { ++ if (err == -EPIPE) { ++ pdelay = 0; ++ play->xrun_pending = 1; ++ } else if (err == -ESTRPIPE) { ++ err = suspend(play); ++ if (err < 0) ++ return err; ++ goto __again; ++ } else { ++ logit(LOG_CRIT, "%s playback delay failed: %s\n", play->id, snd_strerror(err)); ++ return err; ++ } ++ } ++ 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; ++#ifdef USE_SAMPLERATE ++ delay += loop->src_out_frames; ++ delayi += 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) { ++ 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); ++ goto __again; ++ } ++ if (delay > fill) { ++ diff = fill > delayi ? play->buf_count - (fill - delayi) : 0; ++ delay -= remove_samples(loop, 0, diff); ++ } ++ if (delay > fill) { ++ diff = fill > delayi ? capt->buf_count - (fill - delayi) : 0; ++ delay -= remove_samples(loop, 1, diff); ++ } ++ if (play->xrun_pending) { ++ play->xrun_pending = 0; ++ if (fill > delay && play->buf_count < fill - delay) { ++ diff = fill - delay - play->buf_count; ++ 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) ++ return err; ++ play->buf_count += diff; ++ } ++ 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); ++ 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) ++ snd_output_printf(loop->output, "%s: xrun sync ok\n", loop->id); ++ return 0; ++} ++ ++static int set_notify(struct loopback_handle *lhandle, int enable) ++{ ++ int err; ++ ++ if (lhandle->ctl_notify == NULL) ++ return 0; ++ snd_ctl_elem_value_set_boolean(lhandle->ctl_notify, 0, enable); ++ err = snd_ctl_elem_write(lhandle->ctl, lhandle->ctl_notify); ++ if (err < 0) { ++ logit(LOG_CRIT, "Cannot set PCM Notify element for %s: %s\n", lhandle->id, snd_strerror(err)); ++ return err; ++ } ++ err = snd_ctl_elem_read(lhandle->ctl, lhandle->ctl_notify); ++ if (err < 0) { ++ logit(LOG_CRIT, "Cannot get PCM Notify element for %s: %s\n", lhandle->id, snd_strerror(err)); ++ return err; ++ } ++ return 0; ++} ++ ++static int set_rate_shift(struct loopback_handle *lhandle, double pitch) ++{ ++ int err; ++ ++ if (lhandle->ctl_rate_shift == NULL) ++ return 0; ++ snd_ctl_elem_value_set_integer(lhandle->ctl_rate_shift, 0, pitch * 100000); ++ err = snd_ctl_elem_write(lhandle->ctl, lhandle->ctl_rate_shift); ++ if (err < 0) { ++ logit(LOG_CRIT, "Cannot set PCM Rate Shift element for %s: %s\n", lhandle->id, snd_strerror(err)); ++ return err; ++ } ++ return 0; ++} ++ ++static int get_active(struct loopback_handle *lhandle) ++{ ++ int err; ++ ++ if (lhandle->ctl_active == NULL) ++ return 0; ++ err = snd_ctl_elem_read(lhandle->ctl, lhandle->ctl_active); ++ if (err < 0) { ++ logit(LOG_CRIT, "Cannot get PCM Slave Active element for %s: %s\n", lhandle->id, snd_strerror(err)); ++ return err; ++ } ++ return snd_ctl_elem_value_get_boolean(lhandle->ctl_active, 0); ++} ++ ++static int get_format(struct loopback_handle *lhandle) ++{ ++ int err; ++ ++ if (lhandle->ctl_format == NULL) ++ return 0; ++ err = snd_ctl_elem_read(lhandle->ctl, lhandle->ctl_format); ++ if (err < 0) { ++ logit(LOG_CRIT, "Cannot get PCM Format element for %s: %s\n", lhandle->id, snd_strerror(err)); ++ return err; ++ } ++ return snd_ctl_elem_value_get_integer(lhandle->ctl_format, 0); ++} ++ ++static int get_rate(struct loopback_handle *lhandle) ++{ ++ int err; ++ ++ if (lhandle->ctl_rate == NULL) ++ return 0; ++ err = snd_ctl_elem_read(lhandle->ctl, lhandle->ctl_rate); ++ if (err < 0) { ++ logit(LOG_CRIT, "Cannot get PCM Rate element for %s: %s\n", lhandle->id, snd_strerror(err)); ++ return err; ++ } ++ return snd_ctl_elem_value_get_integer(lhandle->ctl_rate, 0); ++} ++ ++static int get_channels(struct loopback_handle *lhandle) ++{ ++ int err; ++ ++ if (lhandle->ctl_channels == NULL) ++ return 0; ++ err = snd_ctl_elem_read(lhandle->ctl, lhandle->ctl_channels); ++ if (err < 0) { ++ logit(LOG_CRIT, "Cannot get PCM Channels element for %s: %s\n", lhandle->id, snd_strerror(err)); ++ return err; ++ } ++ return snd_ctl_elem_value_get_integer(lhandle->ctl_channels, 0); ++} ++ ++static void openctl_elem(struct loopback_handle *lhandle, ++ int device, int subdevice, ++ const char *name, ++ snd_ctl_elem_value_t **elem) ++{ ++ int err; ++ ++ if (snd_ctl_elem_value_malloc(elem) < 0) { ++ *elem = NULL; ++ } else { ++ snd_ctl_elem_value_set_interface(*elem, ++ SND_CTL_ELEM_IFACE_PCM); ++ snd_ctl_elem_value_set_device(*elem, device); ++ snd_ctl_elem_value_set_subdevice(*elem, subdevice); ++ snd_ctl_elem_value_set_name(*elem, name); ++ err = snd_ctl_elem_read(lhandle->ctl, *elem); ++ if (err < 0) { ++ snd_ctl_elem_value_free(*elem); ++ *elem = NULL; ++ } ++ } ++} ++ ++static int openctl(struct loopback_handle *lhandle, int device, int subdevice) ++{ ++ int err; ++ ++ lhandle->ctl_rate_shift = NULL; ++ if (lhandle->loopback->play == lhandle) { ++ if (lhandle->loopback->controls) ++ goto __events; ++ return 0; ++ } ++ openctl_elem(lhandle, device, subdevice, "PCM Notify", ++ &lhandle->ctl_notify); ++ openctl_elem(lhandle, device, subdevice, "PCM Rate Shift 100000", ++ &lhandle->ctl_rate_shift); ++ set_rate_shift(lhandle, 1); ++ openctl_elem(lhandle, device, subdevice, "PCM Slave Active", ++ &lhandle->ctl_active); ++ openctl_elem(lhandle, device, subdevice, "PCM Slave Format", ++ &lhandle->ctl_format); ++ openctl_elem(lhandle, device, subdevice, "PCM Slave Rate", ++ &lhandle->ctl_rate); ++ openctl_elem(lhandle, device, subdevice, "PCM Slave Channels", ++ &lhandle->ctl_channels); ++ if ((lhandle->ctl_active && ++ lhandle->ctl_format && ++ lhandle->ctl_rate && ++ lhandle->ctl_channels) || ++ lhandle->loopback->controls) { ++ __events: ++ if ((err = snd_ctl_poll_descriptors_count(lhandle->ctl)) < 0) ++ lhandle->ctl_pollfd_count = 0; ++ else ++ lhandle->ctl_pollfd_count = err; ++ if (snd_ctl_subscribe_events(lhandle->ctl, 1) < 0) ++ lhandle->ctl_pollfd_count = 0; ++ } ++ return 0; ++} ++ ++static int openit(struct loopback_handle *lhandle) ++{ ++ snd_pcm_info_t *info; ++ int stream = lhandle == lhandle->loopback->play ? ++ 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) { ++ logit(LOG_CRIT, "%s open error: %s\n", lhandle->id, snd_strerror(err)); ++ return err; ++ } ++ if ((err = snd_pcm_info_malloc(&info)) < 0) ++ return err; ++ if ((err = snd_pcm_info(lhandle->handle, info)) < 0) { ++ snd_pcm_info_free(info); ++ return err; ++ } ++ card = snd_pcm_info_get_card(info); ++ device = snd_pcm_info_get_device(info); ++ subdevice = snd_pcm_info_get_subdevice(info); ++ snd_pcm_info_free(info); ++ lhandle->ctl = NULL; ++ if (card >= 0) { ++ char name[16]; ++ sprintf(name, "hw:%i", card); ++ err = snd_ctl_open(&lhandle->ctl, name, SND_CTL_NONBLOCK); ++ if (err < 0) { ++ logit(LOG_CRIT, "%s [%s] ctl open error: %s\n", lhandle->id, name, snd_strerror(err)); ++ lhandle->ctl = NULL; ++ } ++ if (lhandle->ctl) ++ openctl(lhandle, device, subdevice); ++ } ++ return 0; ++} ++ ++static int freeit(struct loopback_handle *lhandle) ++{ ++ free(lhandle->buf); ++ lhandle->buf = NULL; ++ return 0; ++} ++ ++static int closeit(struct loopback_handle *lhandle) ++{ ++ int err = 0; ++ ++ set_rate_shift(lhandle, 1); ++ if (lhandle->ctl_rate_shift) ++ snd_ctl_elem_value_free(lhandle->ctl_rate_shift); ++ lhandle->ctl_rate_shift = NULL; ++ if (lhandle->ctl) ++ err = snd_ctl_close(lhandle->ctl); ++ lhandle->ctl = NULL; ++ if (lhandle->handle) ++ err = snd_pcm_close(lhandle->handle); ++ lhandle->handle = NULL; ++ return err; ++} ++ ++static int init_handle(struct loopback_handle *lhandle, int alloc) ++{ ++ snd_pcm_uframes_t lat; ++ 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); ++ if (lhandle->buffer_size > lat) ++ lat = lhandle->buffer_size; ++ lhandle->buf_size = lat * 2; ++ if (alloc) { ++ lhandle->buf = calloc(1, lhandle->buf_size * lhandle->frame_size); ++ if (lhandle->buf == NULL) ++ return -ENOMEM; ++ } ++ return 0; ++} ++ ++int pcmjob_init(struct loopback *loop) ++{ ++ int err; ++ char id[128]; ++ ++#ifdef FILE_CWRITE ++ loop->cfile = fopen(FILE_CWRITE, "w+"); ++#endif ++#ifdef FILE_PWRITE ++ loop->pfile = fopen(FILE_PWRITE, "w+"); ++#endif ++ if ((err = openit(loop->play)) < 0) ++ goto __error; ++ if ((err = openit(loop->capt)) < 0) ++ goto __error; ++ snprintf(id, sizeof(id), "%s/%s", loop->play->id, loop->capt->id); ++ id[sizeof(id)-1] = '\0'; ++ loop->id = strdup(id); ++ if (loop->sync == SYNC_TYPE_AUTO && loop->capt->ctl_rate_shift) ++ loop->sync = SYNC_TYPE_CAPTRATESHIFT; ++ if (loop->sync == SYNC_TYPE_AUTO && loop->play->ctl_rate_shift) ++ loop->sync = SYNC_TYPE_PLAYRATESHIFT; ++#ifdef USE_SAMPLERATE ++ if (loop->sync == SYNC_TYPE_AUTO && loop->src_enable) ++ loop->sync = SYNC_TYPE_SAMPLERATE; ++#endif ++ if (loop->sync == SYNC_TYPE_AUTO) ++ loop->sync = SYNC_TYPE_SIMPLE; ++ if (loop->slave == SLAVE_TYPE_AUTO && ++ loop->capt->ctl_notify && ++ loop->capt->ctl_active && ++ loop->capt->ctl_format && ++ loop->capt->ctl_rate && ++ loop->capt->ctl_channels) ++ loop->slave = SLAVE_TYPE_ON; ++ if (loop->slave == SLAVE_TYPE_ON) { ++ err = set_notify(loop->capt, 1); ++ if (err < 0) ++ goto __error; ++ if (loop->capt->ctl_notify == NULL || ++ snd_ctl_elem_value_get_boolean(loop->capt->ctl_notify, 0) == 0) { ++ logit(LOG_CRIT, "unable to enable slave mode for %s\n", loop->id); ++ err = -EINVAL; ++ goto __error; ++ } ++ } ++ err = control_init(loop); ++ if (err < 0) ++ goto __error; ++ return 0; ++ __error: ++ pcmjob_done(loop); ++ return err; ++} ++ ++static void freeloop(struct loopback *loop) ++{ ++#ifdef USE_SAMPLERATE ++ if (loop->src_enable) { ++ src_delete(loop->src_state); ++ loop->src_state = NULL; ++ free(loop->src_data.data_in); ++ loop->src_data.data_in = NULL; ++ free(loop->src_data.data_out); ++ loop->src_data.data_out = NULL; ++ } ++#endif ++ if (loop->play->buf == loop->capt->buf) ++ loop->play->buf = NULL; ++ freeit(loop->play); ++ freeit(loop->capt); ++} ++ ++int pcmjob_done(struct loopback *loop) ++{ ++ control_done(loop); ++ closeit(loop->play); ++ closeit(loop->capt); ++ freeloop(loop); ++ free(loop->id); ++ loop->id = NULL; ++#ifdef FILE_PWRITE ++ if (loop->pfile) { ++ fclose(loop->pfile); ++ loop->pfile = NULL; ++ } ++#endif ++#ifdef FILE_CWRITE ++ if (loop->cfile) { ++ fclose(loop->cfile); ++ loop->cfile = NULL; ++ } ++#endif ++ return 0; ++} ++ ++static void lhandle_start(struct loopback_handle *lhandle) ++{ ++ lhandle->buf_pos = 0; ++ lhandle->buf_count = 0; ++ lhandle->counter = 0; ++} ++ ++int pcmjob_start(struct loopback *loop) ++{ ++ snd_pcm_uframes_t count; ++ int err; ++ ++ if (loop->slave == SLAVE_TYPE_ON) { ++ err = get_active(loop->capt); ++ if (err < 0) ++ goto __error; ++ if (err == 0) /* stream is not active */ ++ return 0; ++ err = get_format(loop->capt); ++ if (err < 0) ++ goto __error; ++ loop->play->format = loop->capt->format = err; ++ err = get_rate(loop->capt); ++ if (err < 0) ++ goto __error; ++ loop->play->rate = loop->capt->rate = err; ++ err = get_channels(loop->capt); ++ if (err < 0) ++ 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->latency = loop->latency_req; ++ if (loop->latency == 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); ++ if (loop->play->access == loop->capt->access && ++ loop->play->format == loop->capt->format && ++ loop->play->rate == loop->capt->rate && ++ loop->play->channels == loop->play->channels && ++ loop->sync != SYNC_TYPE_SAMPLERATE) { ++ if (verbose > 1) ++ snd_output_printf(loop->output, "shared buffer!!!\n"); ++ if ((err = init_handle(loop->play, 1)) < 0) ++ goto __error; ++ if ((err = init_handle(loop->capt, 0)) < 0) ++ goto __error; ++ if (loop->play->buf_size < loop->capt->buf_size) { ++ char *nbuf = realloc(loop->play->buf, ++ loop->capt->buf_size * ++ loop->capt->frame_size); ++ if (nbuf == NULL) { ++ err = -ENOMEM; ++ goto __error; ++ } ++ loop->play->buf = nbuf; ++ } ++ loop->capt->buf = loop->play->buf; ++ } else { ++ if ((err = init_handle(loop->play, 1)) < 0) ++ goto __error; ++ if ((err = init_handle(loop->capt, 1)) < 0) ++ goto __error; ++ } ++ 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->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); ++ if (loop->src_data.data_in == NULL) { ++ err = -ENOMEM; ++ goto __error; ++ } ++ loop->src_data.data_out = calloc(1, sizeof(float)*loop->play->channels*loop->play->buf_size); ++ if (loop->src_data.data_out == NULL) { ++ err = -ENOMEM; ++ goto __error; ++ } ++ loop->src_data.src_ratio = (double)loop->play->rate / ++ (double)loop->capt->rate; ++ loop->src_data.end_of_input = 0; ++ loop->src_out_frames = 0; ++ } else { ++ loop->src_state = NULL; ++ } ++#else ++ if (loop->sync == SYNC_TYPE_SAMPLERATE) { ++ logit(LOG_CRIT, "alsaloop is compiled without libsamplerate support\n"); ++ err = -EIO; ++ goto __error; ++ } ++#endif ++ if (verbose) { ++ snd_output_printf(loop->output, "%s sync type: %s", loop->id, sync_types[loop->sync]); ++#ifdef USE_SAMPLERATE ++ if (loop->sync == SYNC_TYPE_SAMPLERATE) ++ snd_output_printf(loop->output, " (%s)", src_types[loop->src_converter_type]); ++#endif ++ snd_output_printf(loop->output, "\n"); ++ } ++ lhandle_start(loop->play); ++ lhandle_start(loop->capt); ++ if ((err = snd_pcm_format_set_silence(loop->play->format, ++ loop->play->buf, ++ loop->play->buf_size * loop->play->channels)) < 0) { ++ logit(LOG_CRIT, "%s: silence error\n", loop->id); ++ goto __error; ++ } ++ loop->pitch = 1; ++ 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); ++ 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 = -EIO; ++ goto __error; ++ } ++ loop->running = 1; ++ 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; ++ } ++ if (!loop->linked) { ++ if ((err = snd_pcm_start(loop->play->handle)) < 0) { ++ logit(LOG_CRIT, "pcm start %s error: %s\n", loop->play->id, snd_strerror(err)); ++ goto __error; ++ } ++ } ++ return 0; ++ __error: ++ pcmjob_stop(loop); ++ return err; ++} ++ ++int pcmjob_stop(struct loopback *loop) ++{ ++ int err; ++ ++ if (loop->running) { ++ if ((err = snd_pcm_drop(loop->capt->handle)) < 0) ++ logit(LOG_WARNING, "pcm drop %s error: %s\n", loop->capt->id, snd_strerror(err)); ++ if ((err = snd_pcm_drop(loop->play->handle)) < 0) ++ logit(LOG_WARNING, "pcm drop %s error: %s\n", loop->play->id, snd_strerror(err)); ++ if ((err = snd_pcm_hw_free(loop->capt->handle)) < 0) ++ logit(LOG_WARNING, "pcm hw_free %s error: %s\n", loop->capt->id, snd_strerror(err)); ++ if ((err = snd_pcm_hw_free(loop->play->handle)) < 0) ++ logit(LOG_WARNING, "pcm hw_free %s error: %s\n", loop->play->id, snd_strerror(err)); ++ loop->running = 0; ++ } ++ freeloop(loop); ++ return 0; ++} ++ ++int pcmjob_pollfds_init(struct loopback *loop, struct pollfd *fds) ++{ ++ int err, idx = 0; ++ ++ if (loop->running) { ++ err = snd_pcm_poll_descriptors(loop->play->handle, fds + idx, loop->play->pollfd_count); ++ if (err < 0) ++ return err; ++ idx += loop->play->pollfd_count; ++ err = snd_pcm_poll_descriptors(loop->capt->handle, fds + idx, loop->capt->pollfd_count); ++ if (err < 0) ++ return err; ++ idx += loop->capt->pollfd_count; ++ } ++ if (loop->play->ctl_pollfd_count > 0 && ++ (loop->slave == SLAVE_TYPE_ON || loop->controls)) { ++ err = snd_ctl_poll_descriptors(loop->play->ctl, fds + idx, loop->play->ctl_pollfd_count); ++ if (err < 0) ++ return err; ++ idx += loop->play->ctl_pollfd_count; ++ } ++ if (loop->capt->ctl_pollfd_count > 0 && ++ (loop->slave == SLAVE_TYPE_ON || loop->controls)) { ++ err = snd_ctl_poll_descriptors(loop->capt->ctl, fds + idx, loop->capt->ctl_pollfd_count); ++ if (err < 0) ++ return err; ++ idx += loop->capt->ctl_pollfd_count; ++ } ++ loop->active_pollfd_count = idx; ++ return idx; ++} ++ ++static snd_pcm_sframes_t get_queued_samples(struct loopback *loop) ++{ ++ snd_pcm_sframes_t pdelay, cdelay, 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) ++ return 0; ++ loop->play->last_delay = pdelay; ++ loop->capt->last_delay = cdelay; ++ delay = pdelay + cdelay; ++ delay += loop->capt->buf_count; ++ delay += loop->play->buf_count; ++#ifdef USE_SAMPLERATE ++ delay += loop->src_out_frames; ++#endif ++ 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; ++ snd_ctl_elem_id_alloca(&id1); ++ snd_ctl_elem_id_alloca(&id2); ++ snd_ctl_elem_value_get_id(val, id1); ++ snd_ctl_event_elem_get_id(ev, id2); ++ if (snd_ctl_event_elem_get_mask(ev) == SND_CTL_EVENT_MASK_REMOVE) ++ return 0; ++ if ((snd_ctl_event_elem_get_mask(ev) & SND_CTL_EVENT_MASK_VALUE) == 0) ++ return 0; ++ return control_id_match(id1, id2); ++} ++ ++static int handle_ctl_events(struct loopback_handle *lhandle, ++ unsigned short events) ++{ ++ snd_ctl_event_t *ev; ++ int err; ++ ++ snd_ctl_event_alloca(&ev); ++ while ((err = snd_ctl_read(lhandle->ctl, ev)) != 0 && err != -EAGAIN) { ++ if (err < 0) ++ break; ++ if (snd_ctl_event_get_type(ev) != SND_CTL_EVENT_ELEM) ++ continue; ++ 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)); ++ if (ctl_event_check(lhandle->ctl_active, ev)) { ++ err = get_active(lhandle); ++ if (err != lhandle->loopback->running) ++ goto __restart; ++ } else if (ctl_event_check(lhandle->ctl_format, ev)) { ++ err = get_format(lhandle); ++ if (lhandle->format != err) ++ goto __restart; ++ } else if (ctl_event_check(lhandle->ctl_rate, ev)) { ++ err = get_rate(lhandle); ++ if (lhandle->rate != err) ++ goto __restart; ++ } else if (ctl_event_check(lhandle->ctl_channels, ev)) { ++ err = get_channels(lhandle); ++ if (lhandle->channels != err) ++ goto __restart; ++ } ++ __ctl_check: ++ control_event(lhandle, ev); ++ } ++ return 0; ++ ++ __restart: ++ pcmjob_stop(lhandle->loopback); ++ err = pcmjob_start(lhandle->loopback); ++ if (err < 0) ++ return err; ++ return 1; ++} ++ ++int pcmjob_pollfds_handle(struct loopback *loop, struct pollfd *fds) ++{ ++ struct loopback_handle *play = loop->play; ++ 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) ++ snd_output_printf(loop->output, "%s: pollfds handle\n", loop->id); ++ if (verbose > 13) ++ getcurtimestamp(&loop->tstamp_start); ++ 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)); ++ else ++ snd_output_printf(loop->output, "%s: delay %li\n", play->id, pdelay); ++ if ((err = snd_pcm_delay(capt->handle, &cdelay)) < 0) ++ snd_output_printf(loop->output, "%s: delay error: %s\n", capt->id, snd_strerror(err)); ++ else ++ snd_output_printf(loop->output, "%s: delay %li\n", capt->id, cdelay); ++ } ++ idx = 0; ++ if (loop->running) { ++ err = snd_pcm_poll_descriptors_revents(play->handle, fds, ++ play->pollfd_count, ++ &prevents); ++ if (err < 0) ++ return err; ++ idx += play->pollfd_count; ++ err = snd_pcm_poll_descriptors_revents(capt->handle, fds + idx, ++ capt->pollfd_count, ++ &crevents); ++ if (err < 0) ++ return err; ++ idx += capt->pollfd_count; ++ } else { ++ prevents = crevents = 0; ++ } ++ if (play->ctl_pollfd_count > 0 && ++ (loop->slave == SLAVE_TYPE_ON || loop->controls)) { ++ err = snd_ctl_poll_descriptors_revents(play->ctl, fds + idx, ++ play->ctl_pollfd_count, ++ &events); ++ if (err < 0) ++ return err; ++ if (events) { ++ err = handle_ctl_events(play, events); ++ if (err == 1) ++ return 0; ++ if (err < 0) ++ return err; ++ } ++ idx += play->ctl_pollfd_count; ++ } ++ if (capt->ctl_pollfd_count > 0 && ++ (loop->slave == SLAVE_TYPE_ON || loop->controls)) { ++ err = snd_ctl_poll_descriptors_revents(capt->ctl, fds + idx, ++ capt->ctl_pollfd_count, ++ &events); ++ if (err < 0) ++ return err; ++ if (events) { ++ err = handle_ctl_events(capt, events); ++ if (err == 1) ++ return 0; ++ if (err < 0) ++ return err; ++ } ++ idx += capt->ctl_pollfd_count; ++ } ++ if (verbose > 9) ++ snd_output_printf(loop->output, "%s: prevents = 0x%x, crevents = 0x%x\n", loop->id, prevents, crevents); ++ do { ++ ccount = readit(capt); ++ buf_add(loop, ccount); ++ if (capt->xrun_pending || loop->reinit) ++ break; ++ /* we read new samples, if we have a room in the playback ++ buffer, feed them there */ ++ pcount = writeit(play); ++ buf_remove(loop, pcount); ++ if (play->xrun_pending || loop->reinit) ++ break; ++ loopcount--; ++ } while ((ccount > 0 || pcount > 0) && loopcount > 0); ++ if (play->xrun_pending || capt->xrun_pending) { ++ if ((err = xrun_sync(loop)) < 0) ++ return err; ++ } ++ if (loop->reinit) { ++ err = pcmjob_stop(loop); ++ if (err < 0) ++ return err; ++ err = pcmjob_start(loop); ++ if (err < 0) ++ return err; ++ } ++ if (loop->sync != SYNC_TYPE_NONE && ++ 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 / ++ (double)loop->total_queued_count) - lat; ++ /* FIXME: this algorithm may be slightly better */ ++ if (verbose > 3) ++ snd_output_printf(loop->output, "%s: sync diff %li old diff %li\n", loop->id, diff, loop->pitch_diff); ++ if (diff > 0) { ++ if (diff == loop->pitch_diff) ++ loop->pitch += loop->pitch_delta; ++ 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) ++ loop->pitch -= loop->pitch_delta*2; ++ } ++ loop->pitch_diff = diff; ++ if (loop->pitch_diff_min > diff) ++ 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); ++ play->counter -= play->sync_point; ++ capt->counter -= play->sync_point; ++ loop->total_queued = 0; ++ loop->total_queued_count = 0; ++ } ++ if (loop->sync != SYNC_TYPE_NONE) { ++ queued = get_queued_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; ++ 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)); ++ else ++ snd_output_printf(loop->output, "%s: end delay %li\n", play->id, pdelay); ++ 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)); ++ else ++ snd_output_printf(loop->output, "%s: end delay %li\n", capt->id, cdelay); ++ } ++ 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)); ++ } ++ return 0; ++} +diff --git a/alsaloop/test.sh b/alsaloop/test.sh +new file mode 100755 +index 0000000..2033add +--- /dev/null ++++ b/alsaloop/test.sh +@@ -0,0 +1,34 @@ ++#!/bin/bash ++ ++#DBG="gdb --args " ++#DBG="strace" ++CFGFILE="/tmp/alsaloop.test.cfg" ++ ++test1() { ++ echo "TEST1" ++ $DBG ./alsaloop -C hw:1,0 -P hw:0,0 \ ++ --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'" ++} ++ ++test2() { ++ echo "TEST2" ++cat > $CFGFILE <]) + AC_CHECK_HEADERS([alsa/seq.h], [have_seq="yes"], [have_seq="no"], + [#include ]) ++AC_CHECK_HEADERS([samplerate.h], [have_samplerate="yes"], [have_samplerate="no"], ++ [#include ]) + + AM_CONDITIONAL(HAVE_PCM, test "$have_pcm" = "yes") + AM_CONDITIONAL(HAVE_MIXER, test "$have_mixer" = "yes") + AM_CONDITIONAL(HAVE_RAWMIDI, test "$have_rawmidi" = "yes") + AM_CONDITIONAL(HAVE_SEQ, test "$have_seq" = "yes") ++AM_CONDITIONAL(HAVE_SAMPLERATE, test "$have_samplerate" = "yes") + + dnl Check for librt + LIBRT="" +@@ -87,6 +90,16 @@ AC_ARG_ENABLE(alsaconf, + esac],[alsaconf=true]) + AM_CONDITIONAL(ALSACONF, test x$alsaconf = xtrue) + ++dnl Disable alsaloop ++AC_ARG_ENABLE(alsaloop, ++ [ --disable-alsaloop Disable alsaloop packaging], ++ [case "${enableval}" in ++ yes) alsaloop=true ;; ++ no) alsaloop=false ;; ++ *) AC_MSG_ERROR(bad value ${enableval} for --enable-alsaloop) ;; ++ esac],[alsaloop=true]) ++AM_CONDITIONAL(ALSALOOP, test x$alsaloop = xtrue) ++ + xmlto="" + if test x"$alsaconf" = xtrue; then + AC_ARG_ENABLE(xmlto, +@@ -273,4 +286,5 @@ AC_OUTPUT(Makefile alsactl/Makefile alsactl/init/Makefile \ + aplay/Makefile include/Makefile iecset/Makefile utils/Makefile \ + utils/alsa-utils.spec seq/Makefile seq/aconnect/Makefile \ + seq/aplaymidi/Makefile seq/aseqdump/Makefile seq/aseqnet/Makefile \ +- speaker-test/Makefile speaker-test/samples/Makefile) ++ speaker-test/Makefile speaker-test/samples/Makefile \ ++ alsaloop/Makefile) +-- +1.7.3.1 + diff --git a/0018-alsaloop-Fix-loopbacks-pointer-initialization-and-al.patch b/0018-alsaloop-Fix-loopbacks-pointer-initialization-and-al.patch new file mode 100644 index 0000000..ea3e7d3 --- /dev/null +++ b/0018-alsaloop-Fix-loopbacks-pointer-initialization-and-al.patch @@ -0,0 +1,45 @@ +From ad0e562373af1de5e911cf1d5def598a7b6523f2 Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +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 +--- + 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 + diff --git a/0019-alsaloop-Fix-thread-handling.patch b/0019-alsaloop-Fix-thread-handling.patch new file mode 100644 index 0000000..7b422d0 --- /dev/null +++ b/0019-alsaloop-Fix-thread-handling.patch @@ -0,0 +1,80 @@ +From 4fe4d22b73dd205521348583f8105de1c155f4a6 Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +Date: Wed, 6 Oct 2010 18:51:29 +0200 +Subject: [PATCH 19/38] alsaloop: Fix thread handling + +Signed-off-by: Jaroslav Kysela +--- + 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 < +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 +--- + 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 < +Date: Thu, 7 Oct 2010 00:12:38 +0200 +Subject: [PATCH 21/38] alsaloop: fix resample argument parsing + +Signed-off-by: Jaroslav Kysela +--- + 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 + diff --git a/0022-alsaloop-added-resampling-for-unsupported-soundcard-.patch b/0022-alsaloop-added-resampling-for-unsupported-soundcard-.patch new file mode 100644 index 0000000..5efcf96 --- /dev/null +++ b/0022-alsaloop-added-resampling-for-unsupported-soundcard-.patch @@ -0,0 +1,618 @@ +From 058357f04239e1c61d60c29f40409f91d6a6e413 Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +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 +--- + 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 + diff --git a/0023-alsaloop-Add-OSS-mixer-redirection-support.patch b/0023-alsaloop-Add-OSS-mixer-redirection-support.patch new file mode 100644 index 0000000..8a1ab84 --- /dev/null +++ b/0023-alsaloop-Add-OSS-mixer-redirection-support.patch @@ -0,0 +1,317 @@ +From 147a1cc75cf6002eb5ea2983a374d2e84eee8e1d Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +Date: Fri, 8 Oct 2010 15:10:23 +0200 +Subject: [PATCH 23/38] alsaloop: Add OSS mixer redirection support + +Signed-off-by: Jaroslav Kysela +--- + 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 \fP | \fI\-\-ossmixer=\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 + diff --git a/0024-alsaloop-Fix-command-line-parsing-and-pollfd-initial.patch b/0024-alsaloop-Fix-command-line-parsing-and-pollfd-initial.patch new file mode 100644 index 0000000..da527c7 --- /dev/null +++ b/0024-alsaloop-Fix-command-line-parsing-and-pollfd-initial.patch @@ -0,0 +1,227 @@ +From e77983d3c55a7822e2151dfd60d9a20ec2023c9f Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +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 +--- + 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(""); ++ 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 < $CFGFILE < +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 +--- + 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 + #include + #include ++#include + #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 < $CFGFILE < $CFGFILE < +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 +--- + 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 + diff --git a/0027-alsaloop-add-pctl-and-cctl-options-to-man-page.patch b/0027-alsaloop-add-pctl-and-cctl-options-to-man-page.patch new file mode 100644 index 0000000..b6f84c0 --- /dev/null +++ b/0027-alsaloop-add-pctl-and-cctl-options-to-man-page.patch @@ -0,0 +1,34 @@ +From af61ea60cfabb6b59b29a1e26769a7068a5742e1 Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +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 # 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 \fP | \fI\-\-pctl=\fP ++ ++Use given CTL device for playback. ++ ++.TP ++\fI\-Y \fP | \fI\-\-cctl=\fP ++ ++Use given CTL device for capture. ++ ++.TP + \fI\-l \fP | \fI\-\-latency=\fP + + Requested latency in frames. +-- +1.7.3.1 + diff --git a/0028-alsaloop-added-xrun-profiling-support-U-xrun-added-S.patch b/0028-alsaloop-added-xrun-profiling-support-U-xrun-added-S.patch new file mode 100644 index 0000000..a464e04 --- /dev/null +++ b/0028-alsaloop-added-xrun-profiling-support-U-xrun-added-S.patch @@ -0,0 +1,677 @@ +From 1a35bdf7c6c3a4727662d093963141dddc376072 Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +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 +--- + 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 + #include + #include ++#include + #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 + #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 < +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 +--- + 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 + diff --git a/0030-alsaloop-fixes-added-W-wake-option.patch b/0030-alsaloop-fixes-added-W-wake-option.patch new file mode 100644 index 0000000..9cbb999 --- /dev/null +++ b/0030-alsaloop-fixes-added-W-wake-option.patch @@ -0,0 +1,371 @@ +From 513a9c7ad179e9786a7d2ff0aa651d42f9674697 Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +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 +--- + 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 \fP | \fI\-\-wake=\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 < +Date: Thu, 14 Oct 2010 15:39:28 +0200 +Subject: [PATCH 31/38] alsaloop: Fix latency print + +Signed-off-by: Jaroslav Kysela +--- + 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 + diff --git a/0032-speaker-test-Don-t-retry-after-fatal-errors.patch b/0032-speaker-test-Don-t-retry-after-fatal-errors.patch new file mode 100644 index 0000000..0dc22a5 --- /dev/null +++ b/0032-speaker-test-Don-t-retry-after-fatal-errors.patch @@ -0,0 +1,32 @@ +From b67d215d20bcf546617de962dec60cc29b238e4e Mon Sep 17 00:00:00 2001 +From: David Henningsson +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 +Signed-off-by: Takashi Iwai +--- + 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 + diff --git a/0033-alsaloop-Delay-the-restart-a-bit-to-handle-snd-aloop.patch b/0033-alsaloop-Delay-the-restart-a-bit-to-handle-snd-aloop.patch new file mode 100644 index 0000000..48578dd --- /dev/null +++ b/0033-alsaloop-Delay-the-restart-a-bit-to-handle-snd-aloop.patch @@ -0,0 +1,104 @@ +From d53eb0309df34f058b33c18210c8949c8a2d8b8e Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +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 +--- + 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 + diff --git a/0034-alsaloop-rework-the-ctl-event-handling-routine.patch b/0034-alsaloop-rework-the-ctl-event-handling-routine.patch new file mode 100644 index 0000000..5094eae --- /dev/null +++ b/0034-alsaloop-rework-the-ctl-event-handling-routine.patch @@ -0,0 +1,95 @@ +From 7a11a2b5464e86573f01af6cf4637ffdc0351478 Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +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 +--- + 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 + diff --git a/0035-alsamixer-remove-obsolete-e-mail.patch b/0035-alsamixer-remove-obsolete-e-mail.patch new file mode 100644 index 0000000..a7efd1d --- /dev/null +++ b/0035-alsamixer-remove-obsolete-e-mail.patch @@ -0,0 +1,88 @@ +From f2e9e9a5b017a3834941256da52e1d608f9c4c7b Mon Sep 17 00:00:00 2001 +From: Clemens Ladisch +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 +--- + 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 ++ * Copyright (c) 1998,1999 Tim Janik + * Jaroslav Kysela + * Copyright (c) 2009 Clemens Ladisch + * +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 ++ * Copyright (c) 1998,1999 Tim Janik + * Jaroslav Kysela + * Copyright (c) 2009 Clemens Ladisch + * +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 ++ * Copyright (c) 1998,1999 Tim Janik + * Jaroslav Kysela + * Copyright (c) 2009 Clemens Ladisch + * +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 ++ * Copyright (c) 1998,1999 Tim Janik + * Jaroslav Kysela + * Copyright (c) 2009 Clemens Ladisch + * +@@ -211,7 +211,7 @@ static void show_help(void) + _("; ' Toggle left/right capture"), + "", + _("Authors:"), +- _(" Tim Janik "), ++ _(" Tim Janik"), + _(" Jaroslav Kysela "), + _(" Clemens Ladisch "), + }; +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 ++ * Copyright (c) 1998,1999 Tim Janik + * Jaroslav Kysela + * Copyright (c) 2009 Clemens Ladisch + * +-- +1.7.3.1 + diff --git a/0036-update-German-translations.patch b/0036-update-German-translations.patch new file mode 100644 index 0000000..a459c16 --- /dev/null +++ b/0036-update-German-translations.patch @@ -0,0 +1,1170 @@ +From b42a1c7a1979e1f5c01dc3d6ecf09169d7a912b0 Mon Sep 17 00:00:00 2001 +From: Clemens Ladisch +Date: Wed, 10 Nov 2010 10:16:07 +0100 +Subject: [PATCH 36/38] update German translations + +Signed-off-by: Clemens Ladisch +--- + po/de.po | 419 ++++++++++++++++++++++++++++++++++---------------------------- + 1 files changed, 232 insertions(+), 187 deletions(-) + +diff --git a/po/de.po b/po/de.po +index 7cae06e..0c47c65 100644 +--- a/po/de.po ++++ b/po/de.po +@@ -5,10 +5,10 @@ + # + msgid "" + msgstr "" +-"Project-Id-Version: alsa-utils 1.0.20\n" ++"Project-Id-Version: alsa-utils 1.0.23\n" + "Report-Msgid-Bugs-To: \n" +-"POT-Creation-Date: 2009-05-24 19:56+0200\n" +-"PO-Revision-Date: 2009-05-24 12:34+0200\n" ++"POT-Creation-Date: 2010-11-08 21:32+0100\n" ++"PO-Revision-Date: 2010-11-09 21:12+0100\n" + "Last-Translator: Clemens Ladisch \n" + "Language-Team: German\n" + "MIME-Version: 1.0\n" +@@ -179,47 +179,47 @@ msgid "This sound device does not have any controls." + msgstr "Dieses Gerät hat keine Regler." + + #. TRANSLATORS: playback on; one character +-#: alsamixer/mixer_display.c:512 alsamixer/mixer_display.c:517 ++#: alsamixer/mixer_display.c:537 alsamixer/mixer_display.c:542 + msgid "O" + msgstr "O" + + #. TRANSLATORS: playback muted; one character +-#: alsamixer/mixer_display.c:514 alsamixer/mixer_display.c:518 ++#: alsamixer/mixer_display.c:539 alsamixer/mixer_display.c:543 + msgid "M" + msgstr "M" + + #. TRANSLATORS: "left"; no more than two characters +-#: alsamixer/mixer_display.c:532 ++#: alsamixer/mixer_display.c:557 + msgid "L" + msgstr "L" + + #. TRANSLATORS: "right"; no more than two characters +-#: alsamixer/mixer_display.c:536 ++#: alsamixer/mixer_display.c:561 + msgid "R" + msgstr "R" + + #. TRANSLATORS: no more than eight characters +-#: alsamixer/mixer_display.c:538 ++#: alsamixer/mixer_display.c:563 + msgid "CAPTURE" + msgstr "AUFNAHME" + +-#: alsamixer/mixer_display.c:588 ++#: alsamixer/mixer_display.c:613 + msgid "Front" + msgstr "Vorne" + +-#: alsamixer/mixer_display.c:591 ++#: alsamixer/mixer_display.c:616 + msgid "Rear" + msgstr "Hinten" + +-#: alsamixer/mixer_display.c:594 speaker-test/speaker-test.c:106 ++#: alsamixer/mixer_display.c:619 speaker-test/speaker-test.c:108 + msgid "Center" + msgstr "Mitte" + +-#: alsamixer/mixer_display.c:597 ++#: alsamixer/mixer_display.c:622 + msgid "Woofer" + msgstr "Bass" + +-#: alsamixer/mixer_display.c:600 ++#: alsamixer/mixer_display.c:625 + msgid "Side" + msgstr "Seiten" + +@@ -336,8 +336,8 @@ msgid "Authors:" + msgstr "Autoren:" + + #: alsamixer/mixer_widget.c:214 +-msgid " Tim Janik " +-msgstr " Tim Janik " ++msgid " Tim Janik" ++msgstr " Tim Janik" + + #: alsamixer/mixer_widget.c:215 + msgid " Jaroslav Kysela " +@@ -364,23 +364,23 @@ msgstr "Fehler" + msgid "Cannot open file \"%s\"." + msgstr "Fehler beim Öffnen der Datei \"%s\"." + +-#: aplay/aplay.c:139 ++#: aplay/aplay.c:152 + msgid "raw data" + msgstr "Rohdaten" + +-#: aplay/aplay.c:140 ++#: aplay/aplay.c:153 + msgid "VOC" + msgstr "VOC" + +-#: aplay/aplay.c:142 ++#: aplay/aplay.c:155 + msgid "WAVE" + msgstr "WAVE" + +-#: aplay/aplay.c:143 ++#: aplay/aplay.c:156 + msgid "Sparc Audio" + msgstr "Sparc-Audio" + +-#: aplay/aplay.c:164 ++#: aplay/aplay.c:177 + #, c-format + msgid "" + "Usage: %s [OPTION]... [FILE]...\n" +@@ -419,6 +419,11 @@ msgid "" + " expression for validation is: coef * (buffer_size / " + "2)\n" + " --test-nowait do not wait for ring buffer - eats whole CPU\n" ++" --max-file-time=# start another output file when the old file has " ++"recorded\n" ++" for this many seconds\n" ++" --process-id-file write the process ID here\n" ++" --use-strftime apply the strftime facility to the output file name\n" + msgstr "" + "Verwendung: %s [Option]... [Datei]...\n" + "\n" +@@ -456,13 +461,16 @@ msgstr "" + "2)\n" + " --test-nowait kein Warten auf Ringpuffer; beansprucht volle CPU-" + "Leistung\n" ++" --max-file-time=# erzeuge mehrere Dateien; Wechsel nach # Sekunden\n" ++" --process-id-file=# schreibe Prozess-ID in diese Datei\n" ++" --use-strftime formatiere Dateiname mit strftime; %%v=Dateinummer\n" + +-#: aplay/aplay.c:199 speaker-test/speaker-test.c:740 ++#: aplay/aplay.c:216 speaker-test/speaker-test.c:819 + #, c-format + msgid "Recognized sample formats are:" + msgstr "Unterstützte Sample-Formate:" + +-#: aplay/aplay.c:205 ++#: aplay/aplay.c:222 + #, c-format + msgid "" + "\n" +@@ -471,115 +479,120 @@ msgstr "" + "\n" + "Nicht alle davon sind auf jeder Hardware verfügbar.\n" + +-#: aplay/aplay.c:206 ++#: aplay/aplay.c:223 + #, c-format + msgid "The availabled format shortcuts are:\n" + msgstr "Unterstütze Format-Abkürzungen:\n" + +-#: aplay/aplay.c:207 ++#: aplay/aplay.c:224 + #, c-format + msgid "-f cd (16 bit little endian, 44100, stereo)\n" + msgstr "-f cd (16 Bits, Little Endian, 44100 Hz, stereo)\n" + +-#: aplay/aplay.c:208 ++#: aplay/aplay.c:225 + #, c-format + msgid "-f cdr (16 bit big endian, 44100, stereo)\n" + msgstr "-f cdr (16 Bits, Big Endian, 44100 Hz, stereo)\n" + +-#: aplay/aplay.c:209 ++#: aplay/aplay.c:226 + #, c-format + msgid "-f dat (16 bit little endian, 48000, stereo)\n" + msgstr "-f dat (16 Bits, Little Endian, 48000 Hz, stereo)\n" + +-#: aplay/aplay.c:223 ++#: aplay/aplay.c:240 + msgid "no soundcards found..." + msgstr "keine Soundkarten gefunden ..." + +-#: aplay/aplay.c:226 ++#: aplay/aplay.c:243 + #, c-format + msgid "**** List of %s Hardware Devices ****\n" + msgstr "**** Liste der Hardware-Geräte (%s) ****\n" + +-#: aplay/aplay.c:255 ++#: aplay/aplay.c:272 + #, c-format + msgid "card %i: %s [%s], device %i: %s [%s]\n" + msgstr "Karte %i: %s [%s], Gerät %i: %s [%s]\n" + +-#: aplay/aplay.c:261 ++#: aplay/aplay.c:278 + #, c-format + msgid " Subdevices: %i/%i\n" + msgstr " Sub-Geräte: %i/%i\n" + +-#: aplay/aplay.c:268 ++#: aplay/aplay.c:285 + #, c-format + msgid " Subdevice #%i: %s\n" + msgstr " Sub-Gerät #%i: %s\n" + +-#: aplay/aplay.c:332 ++#: aplay/aplay.c:362 + #, c-format + msgid "Aborted by signal %s...\n" + msgstr "Abbruch durch Signal %s ...\n" + +-#: aplay/aplay.c:430 ++#: aplay/aplay.c:473 + msgid "command should be named either arecord or aplay" + msgstr "Befehl sollte arecord oder aplay sein" + +-#: aplay/aplay.c:469 ++#: aplay/aplay.c:512 + #, c-format + msgid "unrecognized file format %s" + msgstr "unbekanntes Dateiformat %s" + +-#: aplay/aplay.c:476 ++#: aplay/aplay.c:519 + #, c-format + msgid "value %i for channels is invalid" + msgstr "Kanalanzahl %i ist ungültig" + +-#: aplay/aplay.c:495 ++#: aplay/aplay.c:538 + #, c-format + msgid "wrong extended format '%s'" + msgstr "erweitertes Format '%s' ist ungültig" + +-#: aplay/aplay.c:506 ++#: aplay/aplay.c:549 + #, c-format + msgid "bad speed value %i" + msgstr "ungültige Rate %i" + +-#: aplay/aplay.c:592 ++#: aplay/aplay.c:644 + #, c-format + msgid "Try `%s --help' for more information.\n" + msgstr "Siehe `%s --help' für mehr Informationen.\n" + +-#: aplay/aplay.c:608 ++#: aplay/aplay.c:660 + #, c-format + msgid "audio open error: %s" + msgstr "Fehler beim Öffnen des Gerätes: %s" + +-#: aplay/aplay.c:613 ++#: aplay/aplay.c:665 + #, c-format + msgid "info error: %s" + msgstr "Fehler beim Lesen der Geräteinformationen: %s" + +-#: aplay/aplay.c:620 ++#: aplay/aplay.c:672 + #, c-format + msgid "nonblock setting error: %s" + msgstr "Fehler beim Setzen des nonblock-Modus: %s" + +-#: aplay/aplay.c:630 aplay/aplay.c:737 aplay/aplay.c:1092 ++#: aplay/aplay.c:682 aplay/aplay.c:806 aplay/aplay.c:1174 + msgid "not enough memory" + msgstr "nicht genug Speicher" + +-#: aplay/aplay.c:727 ++#: aplay/aplay.c:706 ++#, c-format ++msgid "Cannot create process ID file %s: %s" ++msgstr "Fehler beim Schreiben der Prozess-ID-Datei %s: %s" ++ ++#: aplay/aplay.c:796 + #, c-format + msgid "read error (called from line %i)" + msgstr "Lesefehler (aufgerufen von Zeile %i)" + +-#: aplay/aplay.c:785 ++#: aplay/aplay.c:854 + #, c-format + msgid "unknown length of 'fmt ' chunk (read %u, should be %u at least)" + msgstr "" + "unbekannte Länge des 'fmt '-Blocks (gelesen: %u, sollte mindestens %u sein)" + +-#: aplay/aplay.c:795 ++#: aplay/aplay.c:864 + #, c-format + msgid "" + "unknown length of extensible 'fmt ' chunk (read %u, should be %u at least)" +@@ -587,198 +600,230 @@ msgstr "" + "unbekannte Länge des erweiterten 'fmt '-Blocks (gelesen: %u, sollte " + "mindestens %u sein)" + +-#: aplay/aplay.c:800 ++#: aplay/aplay.c:869 + msgid "wrong format tag in extensible 'fmt ' chunk" + msgstr "ungültiger Format-Wert im erweiterten 'fmt '-Block" + +-#: aplay/aplay.c:807 ++#: aplay/aplay.c:876 + #, c-format + msgid "can't play WAVE-file format 0x%04x which is not PCM or FLOAT encoded" + msgstr "" + "kann WAVE-Datei-Format 0x%04x nicht abspielen; ist weder PCM noch FLOAT" + +-#: aplay/aplay.c:811 ++#: aplay/aplay.c:880 + #, c-format + msgid "can't play WAVE-files with %d tracks" + msgstr "kann WAVE-Datei mit %d Kanälen nicht abspielen" + +-#: aplay/aplay.c:819 aplay/aplay.c:919 ++#: aplay/aplay.c:888 aplay/aplay.c:988 + #, c-format + msgid "Warning: format is changed to U8\n" + msgstr "Warnung: benutztes Format ist U8\n" + +-#: aplay/aplay.c:825 ++#: aplay/aplay.c:894 + #, c-format + msgid "Warning: format is changed to S16_LE\n" + msgstr "Warnung: benutztes Format ist S16_LE\n" + +-#: aplay/aplay.c:833 ++#: aplay/aplay.c:902 + #, c-format + msgid "Warning: format is changed to S24_3LE\n" + msgstr "Warnung: benutztes Format ist S24_3LE\n" + +-#: aplay/aplay.c:839 ++#: aplay/aplay.c:908 + #, c-format + msgid "Warning: format is changed to S24_LE\n" + msgstr "Warnung: benutztes Format ist S24_LE\n" + +-#: aplay/aplay.c:843 ++#: aplay/aplay.c:912 + #, c-format + msgid "" + " can't play WAVE-files with sample %d bits in %d bytes wide (%d channels)" + msgstr "" + "kann WAVE-Datei mit %d-Bit-Samples in %d Bytes (%d Kanäle) nicht abspielen" + +-#: aplay/aplay.c:855 ++#: aplay/aplay.c:924 + #, c-format + msgid " can't play WAVE-files with sample %d bits wide" + msgstr "kann WAVE-Datei mit %d-Bit-Samples nicht abspielen" + +-#: aplay/aplay.c:913 ++#: aplay/aplay.c:982 + #, c-format + msgid "Warning: format is changed to MU_LAW\n" + msgstr "Warnung: benutztes Format ist MU_LAW\n" + +-#: aplay/aplay.c:925 ++#: aplay/aplay.c:994 + #, c-format + msgid "Warning: format is changed to S16_BE\n" + msgstr "Warnung: benutztes Format ist S16_BE\n" + +-#: aplay/aplay.c:938 aplay/aplay.c:1768 aplay/aplay.c:1775 aplay/aplay.c:2297 +-#: aplay/aplay.c:2309 ++#: aplay/aplay.c:1007 aplay/aplay.c:1925 aplay/aplay.c:1932 aplay/aplay.c:2455 ++#: aplay/aplay.c:2467 + msgid "read error" + msgstr "Lesefehler" + +-#: aplay/aplay.c:957 ++#: aplay/aplay.c:1037 + msgid "Broken configuration for this PCM: no configurations available" + msgstr "" + "ungültige Konfiguration für dieses Gerät: keine unterstützte Konfiguration" + +-#: aplay/aplay.c:974 ++#: aplay/aplay.c:1054 + msgid "Access type not available" + msgstr "Zugriffs-Modus nicht unterstützt" + +-#: aplay/aplay.c:979 ++#: aplay/aplay.c:1059 + msgid "Sample format non available" + msgstr "Sample-Format nicht unterstützt" + +-#: aplay/aplay.c:984 ++#: aplay/aplay.c:1065 + msgid "Channels count non available" + msgstr "Kanalanzahl nicht unterstützt" + +-#: aplay/aplay.c:999 ++#: aplay/aplay.c:1080 + #, c-format + msgid "Warning: rate is not accurate (requested = %iHz, got = %iHz)\n" + msgstr "" + "Warnung: Rate ist nicht exakt (angefordert: %i Hz, unterstützt: %i Hz)\n" + +-#: aplay/aplay.c:1005 ++#: aplay/aplay.c:1086 + #, c-format + msgid " please, try the plug plugin %s\n" + msgstr " probieren Sie bitte das plug-Plugin: %s\n" + +-#: aplay/aplay.c:1041 ++#: aplay/aplay.c:1123 + msgid "Unable to install hw params:" + msgstr "Fehler beim Setzen der Hardware-Parameter:" + +-#: aplay/aplay.c:1048 ++#: aplay/aplay.c:1130 + #, c-format + msgid "Can't use period equal to buffer size (%lu == %lu)" + msgstr "Periode gleich der Puffer-Größe wird nicht unterstützt (%lu == %lu)" + +-#: aplay/aplay.c:1079 ++#: aplay/aplay.c:1161 + msgid "unable to install sw params:" + msgstr "Fehler beim Setzen der Software-Parameter:" + +-#: aplay/aplay.c:1154 ++#: aplay/aplay.c:1192 ++#, c-format ++msgid "snd_pcm_mmap_begin problem: %s" ++msgstr "Fehler bei snd_pcm_mmap_begin: %s" ++ ++#: aplay/aplay.c:1215 ++#, c-format ++msgid "stdin O_NONBLOCK flag setup failed\n" ++msgstr "Fehler beim Setzen von O_NONBLOCK in stdin\n" ++ ++#: aplay/aplay.c:1237 ++#, c-format ++msgid "\rPAUSE command ignored (no hw support)\n" ++msgstr "\rPause-Kommando ignoriert (keine HW-Unterstützung)\n" ++ ++#: aplay/aplay.c:1242 ++#, c-format ++msgid "pause push error: %s" ++msgstr "Fehler beim Pausieren: %s" ++ ++#: aplay/aplay.c:1251 ++#, c-format ++msgid "pause release error: %s" ++msgstr "Fehler beim Beenden der Pause: %s" ++ ++#: aplay/aplay.c:1265 ++#, c-format ++msgid "" ++"\r=== PAUSE === " ++msgstr "" ++"\r=== PAUSE === " ++ ++#: aplay/aplay.c:1307 + #, c-format + msgid "status error: %s" + msgstr "Status-Fehler: %s" + +-#: aplay/aplay.c:1164 aplay/aplay.c:1175 ++#: aplay/aplay.c:1317 aplay/aplay.c:1328 + #, c-format + msgid "%s!!! (at least %.3f ms long)\n" + msgstr "%s!!! (mindestens %.3f ms)\n" + +-#: aplay/aplay.c:1165 aplay/aplay.c:1168 aplay/aplay.c:1176 ++#: aplay/aplay.c:1318 aplay/aplay.c:1321 aplay/aplay.c:1329 + msgid "underrun" + msgstr "Unterlauf" + +-#: aplay/aplay.c:1165 aplay/aplay.c:1176 ++#: aplay/aplay.c:1318 aplay/aplay.c:1329 + msgid "overrun" + msgstr "Überlauf" + +-#: aplay/aplay.c:1180 ++#: aplay/aplay.c:1333 + #, c-format + msgid "Status:\n" + msgstr "Status:\n" + +-#: aplay/aplay.c:1184 ++#: aplay/aplay.c:1337 + #, c-format + msgid "xrun: prepare error: %s" + msgstr "Unter-/Überlauf: Fehler beim Re-Initialisieren des Gerätes: %s" + +-#: aplay/aplay.c:1190 ++#: aplay/aplay.c:1343 + #, c-format + msgid "Status(DRAINING):\n" + msgstr "Status (DRAINING):\n" + +-#: aplay/aplay.c:1194 ++#: aplay/aplay.c:1347 + #, c-format + msgid "capture stream format change? attempting recover...\n" + msgstr "Format-Wechsel der Aufnahme-Daten? Versuche Wiederherstellung ...\n" + +-#: aplay/aplay.c:1196 ++#: aplay/aplay.c:1349 + #, c-format + msgid "xrun(DRAINING): prepare error: %s" + msgstr "XRUN (DRAINING): Fehler beim Re-Initialisieren des Gerätes: %s" + +-#: aplay/aplay.c:1203 ++#: aplay/aplay.c:1356 + #, c-format + msgid "Status(R/W):\n" + msgstr "Status (R/W):\n" + +-#: aplay/aplay.c:1206 ++#: aplay/aplay.c:1359 + #, c-format + msgid "read/write error, state = %s" + msgstr "Lese-/Schreibfehler, Status = %s" + +-#: aplay/aplay.c:1216 ++#: aplay/aplay.c:1369 + #, c-format + msgid "Suspended. Trying resume. " + msgstr "Ruhezustand. Versuche, aufzuwecken. " + +-#: aplay/aplay.c:1221 ++#: aplay/aplay.c:1374 + #, c-format + msgid "Failed. Restarting stream. " + msgstr "Fehlgeschlagen. Re-Initialisierung. " + +-#: aplay/aplay.c:1223 ++#: aplay/aplay.c:1376 + #, c-format + msgid "suspend: prepare error: %s" + msgstr "Ruhezustand: Fehler beim Re-Initialisieren: %s" + +-#: aplay/aplay.c:1228 ++#: aplay/aplay.c:1381 + #, c-format + msgid "Done.\n" + msgstr "Fertig.\n" + +-#: aplay/aplay.c:1250 ++#: aplay/aplay.c:1403 + #, c-format + msgid " !clip " + msgstr " !clip " + +-#: aplay/aplay.c:1397 ++#: aplay/aplay.c:1550 + #, c-format + msgid "Unsupported bit size %d.\n" + msgstr "%d-Bit-Samples werden nicht unterstützt.\n" + +-#: aplay/aplay.c:1431 ++#: aplay/aplay.c:1584 + #, c-format + msgid "Max peak (%li samples): 0x%08x " + msgstr "Höchstwert (%li Samples): 0x%08x " + +-#: aplay/aplay.c:1465 ++#: aplay/aplay.c:1618 + #, c-format + msgid "" + "Suspicious buffer position (%li total): avail = %li, delay = %li, buffer = %" +@@ -787,108 +832,108 @@ msgstr "" + "verdächtige Puffer-Position (total %li): avail = %li, delay = %li, buffer = %" + "li\n" + +-#: aplay/aplay.c:1528 ++#: aplay/aplay.c:1682 + #, c-format + msgid "write error: %s" + msgstr "Schreibfehler: %s" + +-#: aplay/aplay.c:1574 ++#: aplay/aplay.c:1729 + #, c-format + msgid "writev error: %s" + msgstr "Vektor-Schreib-Fehler: %s" + +-#: aplay/aplay.c:1617 ++#: aplay/aplay.c:1773 + #, c-format + msgid "read error: %s" + msgstr "Lesefehler: %s" + +-#: aplay/aplay.c:1660 ++#: aplay/aplay.c:1817 + #, c-format + msgid "readv error: %s" + msgstr "Vektor-Lese-Fehler: %s" + +-#: aplay/aplay.c:1708 ++#: aplay/aplay.c:1865 + msgid "can't allocate buffer for silence" + msgstr "nicht genug Speicher für Stille-Block" + +-#: aplay/aplay.c:1717 aplay/aplay.c:1943 aplay/aplay.c:1948 aplay/aplay.c:1995 +-#: aplay/aplay.c:2004 aplay/aplay.c:2011 aplay/aplay.c:2021 aplay/aplay.c:2027 +-#: aplay/aplay.c:2099 aplay/aplay.c:2129 aplay/aplay.c:2143 ++#: aplay/aplay.c:1874 aplay/aplay.c:2100 aplay/aplay.c:2105 aplay/aplay.c:2152 ++#: aplay/aplay.c:2161 aplay/aplay.c:2168 aplay/aplay.c:2178 aplay/aplay.c:2184 ++#: aplay/aplay.c:2256 aplay/aplay.c:2286 aplay/aplay.c:2300 + msgid "write error" + msgstr "Schreibfehler" + +-#: aplay/aplay.c:1730 ++#: aplay/aplay.c:1887 + #, c-format + msgid "voc_pcm_flush - silence error" + msgstr "voc_pcm_flush - Fehler in set_silence" + +-#: aplay/aplay.c:1733 ++#: aplay/aplay.c:1890 + msgid "voc_pcm_flush error" + msgstr "Schreibfehler" + +-#: aplay/aplay.c:1759 ++#: aplay/aplay.c:1916 + msgid "malloc error" + msgstr "nicht genug Speicher" + +-#: aplay/aplay.c:1763 ++#: aplay/aplay.c:1920 + #, c-format + msgid "Playing Creative Labs Channel file '%s'...\n" + msgstr "Spiele Creative Labs Channel-Datei '%s'...\n" + +-#: aplay/aplay.c:1831 aplay/aplay.c:1923 ++#: aplay/aplay.c:1988 aplay/aplay.c:2080 + msgid "can't play packed .voc files" + msgstr "kann komprimierte .voc-Dateien nicht abspielen" + +-#: aplay/aplay.c:1883 ++#: aplay/aplay.c:2040 + #, c-format + msgid "can't play loops; %s isn't seekable\n" + msgstr "" + "kann Schleife nicht abspielen; Dateiposition in %s ist nicht änderbar\n" + +-#: aplay/aplay.c:1932 ++#: aplay/aplay.c:2089 + #, c-format + msgid "unknown blocktype %d. terminate." + msgstr "Unbekannter Block-Typ %d. Abbruch." + +-#: aplay/aplay.c:2063 ++#: aplay/aplay.c:2220 + #, c-format + msgid "Wave doesn't support %s format..." + msgstr "Format %s wird in WAVE nicht unterstützt ..." + +-#: aplay/aplay.c:2123 ++#: aplay/aplay.c:2280 + #, c-format + msgid "Sparc Audio doesn't support %s format..." + msgstr "Format %s wird in Sparc-Audio nicht unterstützt ..." + +-#: aplay/aplay.c:2204 ++#: aplay/aplay.c:2361 + msgid "Playing" + msgstr "Wiedergabe:" + +-#: aplay/aplay.c:2204 ++#: aplay/aplay.c:2361 + msgid "Recording" + msgstr "Aufnahme:" + +-#: aplay/aplay.c:2208 ++#: aplay/aplay.c:2365 + #, c-format + msgid "Rate %d Hz, " + msgstr "Rate: %d Hz, " + +-#: aplay/aplay.c:2210 ++#: aplay/aplay.c:2367 + #, c-format + msgid "Mono" + msgstr "mono" + +-#: aplay/aplay.c:2212 ++#: aplay/aplay.c:2369 + #, c-format + msgid "Stereo" + msgstr "stereo" + +-#: aplay/aplay.c:2214 ++#: aplay/aplay.c:2371 + #, c-format + msgid "Channels %i" + msgstr "%i Kanäle" + +-#: aplay/aplay.c:2573 aplay/aplay.c:2626 ++#: aplay/aplay.c:2882 aplay/aplay.c:2935 + #, c-format + msgid "You need to specify %d files" + msgstr "Es werden %d Dateien benötigt." +@@ -999,47 +1044,47 @@ msgstr "User" + msgid "kernel" + msgstr "Kernel" + +-#: seq/aconnect/aconnect.c:326 ++#: seq/aconnect/aconnect.c:307 + #, c-format + msgid "can't open sequencer\n" + msgstr "Fehler beim Öffnen des Sequenzers\n" + +-#: seq/aconnect/aconnect.c:354 ++#: seq/aconnect/aconnect.c:335 + #, c-format + msgid "can't get client id\n" + msgstr "Fehler beim Lesen der Client-ID\n" + +-#: seq/aconnect/aconnect.c:361 ++#: seq/aconnect/aconnect.c:342 + #, c-format + msgid "can't set client info\n" + msgstr "Fehler beim Setzen des Client-Namens\n" + +-#: seq/aconnect/aconnect.c:368 ++#: seq/aconnect/aconnect.c:349 + #, c-format + msgid "invalid sender address %s\n" + msgstr "ungültige Sender-Adresse %s\n" + +-#: seq/aconnect/aconnect.c:373 seq/aseqnet/aseqnet.c:290 ++#: seq/aconnect/aconnect.c:354 seq/aseqnet/aseqnet.c:290 + #, c-format + msgid "invalid destination address %s\n" + msgstr "ungültige Ziel-Adresse %s\n" + +-#: seq/aconnect/aconnect.c:387 ++#: seq/aconnect/aconnect.c:368 + #, c-format + msgid "No subscription is found\n" + msgstr "keine Verbindung gefunden\n" + +-#: seq/aconnect/aconnect.c:392 ++#: seq/aconnect/aconnect.c:373 + #, c-format + msgid "Disconnection failed (%s)\n" + msgstr "Verbindungs-Trennung fehlgeschlagen (%s)\n" + +-#: seq/aconnect/aconnect.c:398 ++#: seq/aconnect/aconnect.c:379 + #, c-format + msgid "Connection is already subscribed\n" + msgstr "Verbindung ist bereits vorhanden\n" + +-#: seq/aconnect/aconnect.c:403 ++#: seq/aconnect/aconnect.c:384 + #, c-format + msgid "Connection failed (%s)\n" + msgstr "Verbindung fehlgeschlagen (%s)\n" +@@ -1169,262 +1214,262 @@ msgstr "Channel %2d: Note Off event: %5d\n" + msgid "disconnected\n" + msgstr "Verbindung getrennt\n" + +-#: speaker-test/speaker-test.c:102 ++#: speaker-test/speaker-test.c:104 + msgid "Front Left" + msgstr "Vorne links" + +-#: speaker-test/speaker-test.c:103 ++#: speaker-test/speaker-test.c:105 + msgid "Front Right" + msgstr "Vorne rechts" + +-#: speaker-test/speaker-test.c:104 ++#: speaker-test/speaker-test.c:106 + msgid "Rear Left" + msgstr "Hinten links" + +-#: speaker-test/speaker-test.c:105 ++#: speaker-test/speaker-test.c:107 + msgid "Rear Right" + msgstr "Hinten rechts" + +-#: speaker-test/speaker-test.c:107 ++#: speaker-test/speaker-test.c:109 + msgid "LFE" + msgstr "Bass" + +-#: speaker-test/speaker-test.c:108 ++#: speaker-test/speaker-test.c:110 + msgid "Side Left" + msgstr "Seitlich links" + +-#: speaker-test/speaker-test.c:109 ++#: speaker-test/speaker-test.c:111 + msgid "Side Right" + msgstr "Seitlich rechts" + +-#: speaker-test/speaker-test.c:110 ++#: speaker-test/speaker-test.c:112 + msgid "Channel 9" + msgstr "Kanal 9" + +-#: speaker-test/speaker-test.c:111 ++#: speaker-test/speaker-test.c:113 + msgid "Channel 10" + msgstr "Kanal 10" + +-#: speaker-test/speaker-test.c:112 ++#: speaker-test/speaker-test.c:114 + msgid "Channel 11" + msgstr "Kanal 11" + +-#: speaker-test/speaker-test.c:113 ++#: speaker-test/speaker-test.c:115 + msgid "Channel 12" + msgstr "Kanal 12" + +-#: speaker-test/speaker-test.c:114 ++#: speaker-test/speaker-test.c:116 + msgid "Channel 13" + msgstr "Kanal 13" + +-#: speaker-test/speaker-test.c:115 ++#: speaker-test/speaker-test.c:117 + msgid "Channel 14" + msgstr "Kanal 14" + +-#: speaker-test/speaker-test.c:116 ++#: speaker-test/speaker-test.c:118 + msgid "Channel 15" + msgstr "Kanal 15" + +-#: speaker-test/speaker-test.c:117 ++#: speaker-test/speaker-test.c:119 + msgid "Channel 16" + msgstr "Kanal 16" + +-#: speaker-test/speaker-test.c:307 ++#: speaker-test/speaker-test.c:383 + #, c-format + msgid "Broken configuration for playback: no configurations available: %s\n" + msgstr "Ungültige Konfiguration: keine unterstützte Konfiguration: %s\n" + +-#: speaker-test/speaker-test.c:314 ++#: speaker-test/speaker-test.c:390 + #, c-format + msgid "Access type not available for playback: %s\n" + msgstr "Zugriffsmodus nicht unterstützt: %s\n" + +-#: speaker-test/speaker-test.c:321 ++#: speaker-test/speaker-test.c:397 + #, c-format + msgid "Sample format not available for playback: %s\n" + msgstr "Sample-Format nicht unterstützt: %s\n" + +-#: speaker-test/speaker-test.c:328 ++#: speaker-test/speaker-test.c:404 + #, c-format + msgid "Channels count (%i) not available for playbacks: %s\n" + msgstr "Kanal-Anzahl %i nicht unterstützt: %s\n" + +-#: speaker-test/speaker-test.c:336 ++#: speaker-test/speaker-test.c:412 + #, c-format + msgid "Rate %iHz not available for playback: %s\n" + msgstr "Rate %i Hz nicht unterstützt: %s\n" + +-#: speaker-test/speaker-test.c:341 ++#: speaker-test/speaker-test.c:417 + #, c-format + msgid "Rate doesn't match (requested %iHz, get %iHz, err %d)\n" + msgstr "" + "Rate ist nicht exakt (angefordert: %i Hz, unterstützt: %i Hz, Fehlercode %" + "d)\n" + +-#: speaker-test/speaker-test.c:345 ++#: speaker-test/speaker-test.c:421 + #, c-format + msgid "Rate set to %iHz (requested %iHz)\n" + msgstr "Rate ist %i Hz (angefordert: %i Hz)\n" + +-#: speaker-test/speaker-test.c:351 ++#: speaker-test/speaker-test.c:427 + #, c-format + msgid "Buffer size range from %lu to %lu\n" + msgstr "Puffergröße von %lu bis %lu\n" + +-#: speaker-test/speaker-test.c:352 ++#: speaker-test/speaker-test.c:428 + #, c-format + msgid "Period size range from %lu to %lu\n" + msgstr "Periodengröße von %lu bis %lu\n" + +-#: speaker-test/speaker-test.c:354 ++#: speaker-test/speaker-test.c:430 + #, c-format + msgid "Requested period time %u us\n" + msgstr "Angeforderte Periodenzeit %u µs\n" + +-#: speaker-test/speaker-test.c:357 ++#: speaker-test/speaker-test.c:433 + #, c-format + msgid "Unable to set period time %u us for playback: %s\n" + msgstr "Fehler beim Setzen der Periodenzeit %u µs: %s\n" + +-#: speaker-test/speaker-test.c:363 ++#: speaker-test/speaker-test.c:439 + #, c-format + msgid "Requested buffer time %u us\n" + msgstr "Angeforderte Pufferlänge %u µs\n" + +-#: speaker-test/speaker-test.c:366 ++#: speaker-test/speaker-test.c:442 + #, c-format + msgid "Unable to set buffer time %u us for playback: %s\n" + msgstr "Fehler beim Setzen der Pufferlänge %u µs: %s\n" + +-#: speaker-test/speaker-test.c:375 ++#: speaker-test/speaker-test.c:451 + #, c-format + msgid "Using max buffer size %lu\n" + msgstr "Verwende maximale Puffergröße %lu\n" + +-#: speaker-test/speaker-test.c:378 ++#: speaker-test/speaker-test.c:454 + #, c-format + msgid "Unable to set buffer size %lu for playback: %s\n" + msgstr "Fehler beim Setzen der Puffergröße %lu: %s\n" + +-#: speaker-test/speaker-test.c:384 ++#: speaker-test/speaker-test.c:460 + #, c-format + msgid "Periods = %u\n" + msgstr "Perioden = %u\n" + +-#: speaker-test/speaker-test.c:387 ++#: speaker-test/speaker-test.c:463 + #, c-format + msgid "Unable to set nperiods %u for playback: %s\n" + msgstr "Fehler beim Setzen der Periodenanzahl %u: %s\n" + +-#: speaker-test/speaker-test.c:396 ++#: speaker-test/speaker-test.c:472 + #, c-format + msgid "Unable to set hw params for playback: %s\n" + msgstr "Fehler beim Setzen der Hardware-Parameter: %s\n" + +-#: speaker-test/speaker-test.c:402 ++#: speaker-test/speaker-test.c:478 + #, c-format + msgid "was set period_size = %lu\n" + msgstr "gesetzt: period_size = %lu\n" + +-#: speaker-test/speaker-test.c:403 ++#: speaker-test/speaker-test.c:479 + #, c-format + msgid "was set buffer_size = %lu\n" + msgstr "gesetzt: buffer_size = %lu\n" + +-#: speaker-test/speaker-test.c:405 ++#: speaker-test/speaker-test.c:481 + #, c-format + msgid "buffer to small, could not use\n" + msgstr "Puffer zu klein, kann nicht benutzt werden\n" + +-#: speaker-test/speaker-test.c:418 ++#: speaker-test/speaker-test.c:494 + #, c-format + msgid "Unable to determine current swparams for playback: %s\n" + msgstr "Fehler beim Lesen der Software-Parameter: %s\n" + +-#: speaker-test/speaker-test.c:425 ++#: speaker-test/speaker-test.c:501 + #, c-format + msgid "Unable to set start threshold mode for playback: %s\n" + msgstr "Fehler beim Setzen des Start-Schwellenwertes: %s\n" + +-#: speaker-test/speaker-test.c:432 ++#: speaker-test/speaker-test.c:508 + #, c-format + msgid "Unable to set avail min for playback: %s\n" + msgstr "Fehler beim Setzen des Mindest-verfügbar-Wertes: %s\n" + +-#: speaker-test/speaker-test.c:439 ++#: speaker-test/speaker-test.c:515 + #, c-format + msgid "Unable to set sw params for playback: %s\n" + msgstr "Fehler beim Setzen der Software-Parameter: %s\n" + +-#: speaker-test/speaker-test.c:454 ++#: speaker-test/speaker-test.c:530 + #, c-format + msgid "Can't recovery from underrun, prepare failed: %s\n" + msgstr "" + "Fehler bei Unterlauf-Behandlung, Re-Initialisierung fehlgeschlagen: %s\n" + +-#: speaker-test/speaker-test.c:465 ++#: speaker-test/speaker-test.c:541 + #, c-format + msgid "Can't recovery from suspend, prepare failed: %s\n" + msgstr "" + "Fehler beim Aufwachen aus dem Ruhezustand, Re-Initialisierung " + "fehlgeschlagen: %s\n" + +-#: speaker-test/speaker-test.c:529 speaker-test/speaker-test.c:926 ++#: speaker-test/speaker-test.c:605 speaker-test/speaker-test.c:1025 + #, c-format + msgid "No enough memory\n" + msgstr "Nicht genug Speicher\n" + +-#: speaker-test/speaker-test.c:534 ++#: speaker-test/speaker-test.c:610 + #, c-format + msgid "Cannot open WAV file %s\n" + msgstr "Kann WAV-Datei %s nicht öffnen\n" + +-#: speaker-test/speaker-test.c:538 speaker-test/speaker-test.c:567 ++#: speaker-test/speaker-test.c:614 speaker-test/speaker-test.c:643 + #, c-format + msgid "Invalid WAV file %s\n" + msgstr "Ungültige WAV-Datei %s\n" + +-#: speaker-test/speaker-test.c:543 ++#: speaker-test/speaker-test.c:619 + #, c-format + msgid "Not a WAV file: %s\n" + msgstr "Keine WAV-Datei: %s\n" + +-#: speaker-test/speaker-test.c:547 ++#: speaker-test/speaker-test.c:623 + #, c-format + msgid "Unsupported WAV format %d for %s\n" + msgstr "Nicht unterstütztes WAV-Format %d in %s\n" + +-#: speaker-test/speaker-test.c:552 ++#: speaker-test/speaker-test.c:628 + #, c-format + msgid "%s is not a mono stream (%d channels)\n" + msgstr "%s ist keine Mono-Datei (%d Kanäle)\n" + +-#: speaker-test/speaker-test.c:557 ++#: speaker-test/speaker-test.c:633 + #, c-format + msgid "Sample rate doesn't match (%d) for %s\n" + msgstr "Sample-Rate (%d) stimmt nicht überein in %s\n" + +-#: speaker-test/speaker-test.c:562 ++#: speaker-test/speaker-test.c:638 + #, c-format + msgid "Unsupported sample format bits %d for %s\n" + msgstr "Nicht unterstütztes Sample-Format mit %d Bits in %s\n" + +-#: speaker-test/speaker-test.c:612 ++#: speaker-test/speaker-test.c:688 + #, c-format + msgid "Undefined channel %d\n" + msgstr "Kanal %d nicht definiert\n" + +-#: speaker-test/speaker-test.c:663 ++#: speaker-test/speaker-test.c:739 + #, c-format + msgid "Write error: %d,%s\n" + msgstr "Schreibfehler: %d, %s\n" + +-#: speaker-test/speaker-test.c:665 ++#: speaker-test/speaker-test.c:741 + #, c-format + msgid "xrun_recovery failed: %d,%s\n" + msgstr "xrun_recovery fehlgeschlagen: %d, %s\n" + +-#: speaker-test/speaker-test.c:723 ++#: speaker-test/speaker-test.c:803 + #, c-format + msgid "" + "Usage: speaker-test [OPTION]... \n" +@@ -1461,72 +1506,72 @@ msgstr "" + "-W,--wavdir benutze Verzeichnis mit darin enthaltenen WAV-Dateien\n" + "\n" + +-#: speaker-test/speaker-test.c:835 ++#: speaker-test/speaker-test.c:921 + #, c-format + msgid "Invalid number of periods %d\n" + msgstr "Ungültige Periodenanzahl %d\n" + +-#: speaker-test/speaker-test.c:849 speaker-test/speaker-test.c:853 ++#: speaker-test/speaker-test.c:937 speaker-test/speaker-test.c:941 + #, c-format + msgid "Invalid test type %s\n" + msgstr "Ungültiger Test-Typ %s\n" + +-#: speaker-test/speaker-test.c:865 ++#: speaker-test/speaker-test.c:953 + #, c-format + msgid "Invalid parameter for -s option.\n" + msgstr "Ungültiger Wert für Option -s\n" + +-#: speaker-test/speaker-test.c:876 ++#: speaker-test/speaker-test.c:967 + #, c-format + msgid "Unknown option '%c'\n" + msgstr "Unbekannte Options '%c'\n" + +-#: speaker-test/speaker-test.c:890 ++#: speaker-test/speaker-test.c:981 + #, c-format + msgid "Playback device is %s\n" + msgstr "Wiedergabe-Gerät ist %s\n" + +-#: speaker-test/speaker-test.c:891 ++#: speaker-test/speaker-test.c:982 + #, c-format + msgid "Stream parameters are %iHz, %s, %i channels\n" + msgstr "Stream-Parameter sind %i Hz, %s, %i Kanäle\n" + +-#: speaker-test/speaker-test.c:894 ++#: speaker-test/speaker-test.c:985 + #, c-format + msgid "Using 16 octaves of pink noise\n" + msgstr "Verwende 16 Oktaven rosa Rauschen\n" + +-#: speaker-test/speaker-test.c:897 ++#: speaker-test/speaker-test.c:988 + #, c-format + msgid "Sine wave rate is %.4fHz\n" + msgstr "Sinuswelle mit Frequenz %.4f Hz\n" + +-#: speaker-test/speaker-test.c:900 ++#: speaker-test/speaker-test.c:991 + #, c-format + msgid "WAV file(s)\n" + msgstr "WAV-Datei(en)\n" + +-#: speaker-test/speaker-test.c:906 ++#: speaker-test/speaker-test.c:997 + #, c-format + msgid "Playback open error: %d,%s\n" + msgstr "Fehler beim Öffnen des Gerätes: %d, %s\n" + +-#: speaker-test/speaker-test.c:911 ++#: speaker-test/speaker-test.c:1002 + #, c-format + msgid "Setting of hwparams failed: %s\n" + msgstr "Fehler beim Setzen der Hardware-Parameter: %s\n" + +-#: speaker-test/speaker-test.c:916 ++#: speaker-test/speaker-test.c:1007 + #, c-format + msgid "Setting of swparams failed: %s\n" + msgstr "Fehler beim Setzen der Software-Parameter: %s\n" + +-#: speaker-test/speaker-test.c:957 speaker-test/speaker-test.c:979 ++#: speaker-test/speaker-test.c:1056 speaker-test/speaker-test.c:1078 + #, c-format + msgid "Transfer failed: %s\n" + msgstr "Schreibfehler: %s\n" + +-#: speaker-test/speaker-test.c:967 ++#: speaker-test/speaker-test.c:1066 + #, c-format + msgid "Time per period = %lf\n" + msgstr "Zeit pro Periode = %lf\n" +-- +1.7.3.1 + diff --git a/0037-alsactl-systemd-and-udev-hookup.patch b/0037-alsactl-systemd-and-udev-hookup.patch new file mode 100644 index 0000000..e2bc8da --- /dev/null +++ b/0037-alsactl-systemd-and-udev-hookup.patch @@ -0,0 +1,211 @@ +From de7c3eff0e371ce155403bbcdcf81ee79266fa0f Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +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 +Signed-off-by: Jaroslav Kysela +--- + 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=''; 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=''; 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=''; 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 + diff --git a/0038-alsactl-Move-asound.state-location-to-var-lib-alsa.patch b/0038-alsactl-Move-asound.state-location-to-var-lib-alsa.patch new file mode 100644 index 0000000..5b57098 --- /dev/null +++ b/0038-alsactl-Move-asound.state-location-to-var-lib-alsa.patch @@ -0,0 +1,123 @@ +From 81f015f5abdd8e6cfa75e37bd97eb22781019eec Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +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 +Signed-off-by: Jaroslav Kysela +--- + 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 + #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 + diff --git a/0039-configure.in-Fix-variable-name.patch b/0039-configure.in-Fix-variable-name.patch new file mode 100644 index 0000000..695863f --- /dev/null +++ b/0039-configure.in-Fix-variable-name.patch @@ -0,0 +1,34 @@ +From 53b08bfc1451937bb19a86e4b116d28cd15c81ac Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ozan=20=C3=87a=C4=9Flayan?= +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 +Signed-off-by: Takashi Iwai +--- + 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 + diff --git a/alsa-utils-po-pre-patch.diff b/alsa-utils-po-pre-patch.diff new file mode 100644 index 0000000..6d5dc72 --- /dev/null +++ b/alsa-utils-po-pre-patch.diff @@ -0,0 +1,2200 @@ +diff -ru po/de.po /export/git/alsa/alsa-utils/po/de.po +--- a/po/de.po 2010-04-16 13:19:27.000000000 +0200 ++++ b/po/de.po 2010-11-26 08:47:09.204870692 +0100 +@@ -7,7 +7,7 @@ + msgstr "" + "Project-Id-Version: alsa-utils 1.0.20\n" + "Report-Msgid-Bugs-To: \n" +-"POT-Creation-Date: 2010-04-16 13:19+0200\n" ++"POT-Creation-Date: 2009-05-24 19:56+0200\n" + "PO-Revision-Date: 2009-05-24 12:34+0200\n" + "Last-Translator: Clemens Ladisch \n" + "Language-Team: German\n" +@@ -179,47 +179,47 @@ + msgstr "Dieses Gerät hat keine Regler." + + #. TRANSLATORS: playback on; one character +-#: alsamixer/mixer_display.c:537 alsamixer/mixer_display.c:542 ++#: alsamixer/mixer_display.c:512 alsamixer/mixer_display.c:517 + msgid "O" + msgstr "O" + + #. TRANSLATORS: playback muted; one character +-#: alsamixer/mixer_display.c:539 alsamixer/mixer_display.c:543 ++#: alsamixer/mixer_display.c:514 alsamixer/mixer_display.c:518 + msgid "M" + msgstr "M" + + #. TRANSLATORS: "left"; no more than two characters +-#: alsamixer/mixer_display.c:557 ++#: alsamixer/mixer_display.c:532 + msgid "L" + msgstr "L" + + #. TRANSLATORS: "right"; no more than two characters +-#: alsamixer/mixer_display.c:561 ++#: alsamixer/mixer_display.c:536 + msgid "R" + msgstr "R" + + #. TRANSLATORS: no more than eight characters +-#: alsamixer/mixer_display.c:563 ++#: alsamixer/mixer_display.c:538 + msgid "CAPTURE" + msgstr "AUFNAHME" + +-#: alsamixer/mixer_display.c:613 ++#: alsamixer/mixer_display.c:588 + msgid "Front" + msgstr "Vorne" + +-#: alsamixer/mixer_display.c:616 ++#: alsamixer/mixer_display.c:591 + msgid "Rear" + msgstr "Hinten" + +-#: alsamixer/mixer_display.c:619 speaker-test/speaker-test.c:107 ++#: alsamixer/mixer_display.c:594 speaker-test/speaker-test.c:106 + msgid "Center" + msgstr "Mitte" + +-#: alsamixer/mixer_display.c:622 ++#: alsamixer/mixer_display.c:597 + msgid "Woofer" + msgstr "Bass" + +-#: alsamixer/mixer_display.c:625 ++#: alsamixer/mixer_display.c:600 + msgid "Side" + msgstr "Seiten" + +@@ -364,24 +364,24 @@ + msgid "Cannot open file \"%s\"." + msgstr "Fehler beim Öffnen der Datei \"%s\"." + +-#: aplay/aplay.c:147 ++#: aplay/aplay.c:139 + msgid "raw data" + msgstr "Rohdaten" + +-#: aplay/aplay.c:148 ++#: aplay/aplay.c:140 + msgid "VOC" + msgstr "VOC" + +-#: aplay/aplay.c:150 ++#: aplay/aplay.c:142 + msgid "WAVE" + msgstr "WAVE" + +-#: aplay/aplay.c:151 ++#: aplay/aplay.c:143 + msgid "Sparc Audio" + msgstr "Sparc-Audio" + +-#: aplay/aplay.c:172 +-#, fuzzy, c-format ++#: aplay/aplay.c:164 ++#, c-format + msgid "" + "Usage: %s [OPTION]... [FILE]...\n" + "\n" +@@ -419,11 +419,6 @@ + " expression for validation is: coef * (buffer_size / " + "2)\n" + " --test-nowait do not wait for ring buffer - eats whole CPU\n" +-" --max-file-time=# start another output file when the old file has " +-"recorded\n" +-" for this many seconds\n" +-" --process-id-file write the process ID here\n" +-" --use-strftime apply the strftime facility to the output file name\n" + msgstr "" + "Verwendung: %s [Option]... [Datei]...\n" + "\n" +@@ -462,12 +457,12 @@ + " --test-nowait kein Warten auf Ringpuffer; beansprucht volle CPU-" + "Leistung\n" + +-#: aplay/aplay.c:211 speaker-test/speaker-test.c:750 ++#: aplay/aplay.c:199 speaker-test/speaker-test.c:740 + #, c-format + msgid "Recognized sample formats are:" + msgstr "Unterstützte Sample-Formate:" + +-#: aplay/aplay.c:217 ++#: aplay/aplay.c:205 + #, c-format + msgid "" + "\n" +@@ -476,120 +471,115 @@ + "\n" + "Nicht alle davon sind auf jeder Hardware verfügbar.\n" + +-#: aplay/aplay.c:218 ++#: aplay/aplay.c:206 + #, c-format + msgid "The availabled format shortcuts are:\n" + msgstr "Unterstütze Format-Abkürzungen:\n" + +-#: aplay/aplay.c:219 ++#: aplay/aplay.c:207 + #, c-format + msgid "-f cd (16 bit little endian, 44100, stereo)\n" + msgstr "-f cd (16 Bits, Little Endian, 44100 Hz, stereo)\n" + +-#: aplay/aplay.c:220 ++#: aplay/aplay.c:208 + #, c-format + msgid "-f cdr (16 bit big endian, 44100, stereo)\n" + msgstr "-f cdr (16 Bits, Big Endian, 44100 Hz, stereo)\n" + +-#: aplay/aplay.c:221 ++#: aplay/aplay.c:209 + #, c-format + msgid "-f dat (16 bit little endian, 48000, stereo)\n" + msgstr "-f dat (16 Bits, Little Endian, 48000 Hz, stereo)\n" + +-#: aplay/aplay.c:235 ++#: aplay/aplay.c:223 + msgid "no soundcards found..." + msgstr "keine Soundkarten gefunden ..." + +-#: aplay/aplay.c:238 ++#: aplay/aplay.c:226 + #, c-format + msgid "**** List of %s Hardware Devices ****\n" + msgstr "**** Liste der Hardware-Geräte (%s) ****\n" + +-#: aplay/aplay.c:267 ++#: aplay/aplay.c:255 + #, c-format + msgid "card %i: %s [%s], device %i: %s [%s]\n" + msgstr "Karte %i: %s [%s], Gerät %i: %s [%s]\n" + +-#: aplay/aplay.c:273 ++#: aplay/aplay.c:261 + #, c-format + msgid " Subdevices: %i/%i\n" + msgstr " Sub-Geräte: %i/%i\n" + +-#: aplay/aplay.c:280 ++#: aplay/aplay.c:268 + #, c-format + msgid " Subdevice #%i: %s\n" + msgstr " Sub-Gerät #%i: %s\n" + +-#: aplay/aplay.c:356 ++#: aplay/aplay.c:332 + #, c-format + msgid "Aborted by signal %s...\n" + msgstr "Abbruch durch Signal %s ...\n" + +-#: aplay/aplay.c:467 ++#: aplay/aplay.c:430 + msgid "command should be named either arecord or aplay" + msgstr "Befehl sollte arecord oder aplay sein" + +-#: aplay/aplay.c:506 ++#: aplay/aplay.c:469 + #, c-format + msgid "unrecognized file format %s" + msgstr "unbekanntes Dateiformat %s" + +-#: aplay/aplay.c:513 ++#: aplay/aplay.c:476 + #, c-format + msgid "value %i for channels is invalid" + msgstr "Kanalanzahl %i ist ungültig" + +-#: aplay/aplay.c:532 ++#: aplay/aplay.c:495 + #, c-format + msgid "wrong extended format '%s'" + msgstr "erweitertes Format '%s' ist ungültig" + +-#: aplay/aplay.c:543 ++#: aplay/aplay.c:506 + #, c-format + msgid "bad speed value %i" + msgstr "ungültige Rate %i" + +-#: aplay/aplay.c:638 ++#: aplay/aplay.c:592 + #, c-format + msgid "Try `%s --help' for more information.\n" + msgstr "Siehe `%s --help' für mehr Informationen.\n" + +-#: aplay/aplay.c:654 ++#: aplay/aplay.c:608 + #, c-format + msgid "audio open error: %s" + msgstr "Fehler beim Öffnen des Gerätes: %s" + +-#: aplay/aplay.c:659 ++#: aplay/aplay.c:613 + #, c-format + msgid "info error: %s" + msgstr "Fehler beim Lesen der Geräteinformationen: %s" + +-#: aplay/aplay.c:666 ++#: aplay/aplay.c:620 + #, c-format + msgid "nonblock setting error: %s" + msgstr "Fehler beim Setzen des nonblock-Modus: %s" + +-#: aplay/aplay.c:676 aplay/aplay.c:800 aplay/aplay.c:1167 ++#: aplay/aplay.c:630 aplay/aplay.c:737 aplay/aplay.c:1092 + msgid "not enough memory" + msgstr "nicht genug Speicher" + +-#: aplay/aplay.c:700 +-#, fuzzy, c-format +-msgid "Cannot create process ID file %s: %s" +-msgstr "Kann WAV-Datei %s nicht öffnen\n" +- +-#: aplay/aplay.c:790 ++#: aplay/aplay.c:727 + #, c-format + msgid "read error (called from line %i)" + msgstr "Lesefehler (aufgerufen von Zeile %i)" + +-#: aplay/aplay.c:848 ++#: aplay/aplay.c:785 + #, c-format + msgid "unknown length of 'fmt ' chunk (read %u, should be %u at least)" + msgstr "" + "unbekannte Länge des 'fmt '-Blocks (gelesen: %u, sollte mindestens %u sein)" + +-#: aplay/aplay.c:858 ++#: aplay/aplay.c:795 + #, c-format + msgid "" + "unknown length of extensible 'fmt ' chunk (read %u, should be %u at least)" +@@ -597,198 +587,198 @@ + "unbekannte Länge des erweiterten 'fmt '-Blocks (gelesen: %u, sollte " + "mindestens %u sein)" + +-#: aplay/aplay.c:863 ++#: aplay/aplay.c:800 + msgid "wrong format tag in extensible 'fmt ' chunk" + msgstr "ungültiger Format-Wert im erweiterten 'fmt '-Block" + +-#: aplay/aplay.c:870 ++#: aplay/aplay.c:807 + #, c-format + msgid "can't play WAVE-file format 0x%04x which is not PCM or FLOAT encoded" + msgstr "" + "kann WAVE-Datei-Format 0x%04x nicht abspielen; ist weder PCM noch FLOAT" + +-#: aplay/aplay.c:874 ++#: aplay/aplay.c:811 + #, c-format + msgid "can't play WAVE-files with %d tracks" + msgstr "kann WAVE-Datei mit %d Kanälen nicht abspielen" + +-#: aplay/aplay.c:882 aplay/aplay.c:982 ++#: aplay/aplay.c:819 aplay/aplay.c:919 + #, c-format + msgid "Warning: format is changed to U8\n" + msgstr "Warnung: benutztes Format ist U8\n" + +-#: aplay/aplay.c:888 ++#: aplay/aplay.c:825 + #, c-format + msgid "Warning: format is changed to S16_LE\n" + msgstr "Warnung: benutztes Format ist S16_LE\n" + +-#: aplay/aplay.c:896 ++#: aplay/aplay.c:833 + #, c-format + msgid "Warning: format is changed to S24_3LE\n" + msgstr "Warnung: benutztes Format ist S24_3LE\n" + +-#: aplay/aplay.c:902 ++#: aplay/aplay.c:839 + #, c-format + msgid "Warning: format is changed to S24_LE\n" + msgstr "Warnung: benutztes Format ist S24_LE\n" + +-#: aplay/aplay.c:906 ++#: aplay/aplay.c:843 + #, c-format + msgid "" + " can't play WAVE-files with sample %d bits in %d bytes wide (%d channels)" + msgstr "" + "kann WAVE-Datei mit %d-Bit-Samples in %d Bytes (%d Kanäle) nicht abspielen" + +-#: aplay/aplay.c:918 ++#: aplay/aplay.c:855 + #, c-format + msgid " can't play WAVE-files with sample %d bits wide" + msgstr "kann WAVE-Datei mit %d-Bit-Samples nicht abspielen" + +-#: aplay/aplay.c:976 ++#: aplay/aplay.c:913 + #, c-format + msgid "Warning: format is changed to MU_LAW\n" + msgstr "Warnung: benutztes Format ist MU_LAW\n" + +-#: aplay/aplay.c:988 ++#: aplay/aplay.c:925 + #, c-format + msgid "Warning: format is changed to S16_BE\n" + msgstr "Warnung: benutztes Format ist S16_BE\n" + +-#: aplay/aplay.c:1001 aplay/aplay.c:1843 aplay/aplay.c:1850 aplay/aplay.c:2372 +-#: aplay/aplay.c:2384 ++#: aplay/aplay.c:938 aplay/aplay.c:1768 aplay/aplay.c:1775 aplay/aplay.c:2297 ++#: aplay/aplay.c:2309 + msgid "read error" + msgstr "Lesefehler" + +-#: aplay/aplay.c:1031 ++#: aplay/aplay.c:957 + msgid "Broken configuration for this PCM: no configurations available" + msgstr "" + "ungültige Konfiguration für dieses Gerät: keine unterstützte Konfiguration" + +-#: aplay/aplay.c:1048 ++#: aplay/aplay.c:974 + msgid "Access type not available" + msgstr "Zugriffs-Modus nicht unterstützt" + +-#: aplay/aplay.c:1053 ++#: aplay/aplay.c:979 + msgid "Sample format non available" + msgstr "Sample-Format nicht unterstützt" + +-#: aplay/aplay.c:1059 ++#: aplay/aplay.c:984 + msgid "Channels count non available" + msgstr "Kanalanzahl nicht unterstützt" + +-#: aplay/aplay.c:1074 ++#: aplay/aplay.c:999 + #, c-format + msgid "Warning: rate is not accurate (requested = %iHz, got = %iHz)\n" + msgstr "" + "Warnung: Rate ist nicht exakt (angefordert: %i Hz, unterstützt: %i Hz)\n" + +-#: aplay/aplay.c:1080 ++#: aplay/aplay.c:1005 + #, c-format + msgid " please, try the plug plugin %s\n" + msgstr " probieren Sie bitte das plug-Plugin: %s\n" + +-#: aplay/aplay.c:1116 ++#: aplay/aplay.c:1041 + msgid "Unable to install hw params:" + msgstr "Fehler beim Setzen der Hardware-Parameter:" + +-#: aplay/aplay.c:1123 ++#: aplay/aplay.c:1048 + #, c-format + msgid "Can't use period equal to buffer size (%lu == %lu)" + msgstr "Periode gleich der Puffer-Größe wird nicht unterstützt (%lu == %lu)" + +-#: aplay/aplay.c:1154 ++#: aplay/aplay.c:1079 + msgid "unable to install sw params:" + msgstr "Fehler beim Setzen der Software-Parameter:" + +-#: aplay/aplay.c:1229 ++#: aplay/aplay.c:1154 + #, c-format + msgid "status error: %s" + msgstr "Status-Fehler: %s" + +-#: aplay/aplay.c:1239 aplay/aplay.c:1250 ++#: aplay/aplay.c:1164 aplay/aplay.c:1175 + #, c-format + msgid "%s!!! (at least %.3f ms long)\n" + msgstr "%s!!! (mindestens %.3f ms)\n" + +-#: aplay/aplay.c:1240 aplay/aplay.c:1243 aplay/aplay.c:1251 ++#: aplay/aplay.c:1165 aplay/aplay.c:1168 aplay/aplay.c:1176 + msgid "underrun" + msgstr "Unterlauf" + +-#: aplay/aplay.c:1240 aplay/aplay.c:1251 ++#: aplay/aplay.c:1165 aplay/aplay.c:1176 + msgid "overrun" + msgstr "Überlauf" + +-#: aplay/aplay.c:1255 ++#: aplay/aplay.c:1180 + #, c-format + msgid "Status:\n" + msgstr "Status:\n" + +-#: aplay/aplay.c:1259 ++#: aplay/aplay.c:1184 + #, c-format + msgid "xrun: prepare error: %s" + msgstr "Unter-/Überlauf: Fehler beim Re-Initialisieren des Gerätes: %s" + +-#: aplay/aplay.c:1265 ++#: aplay/aplay.c:1190 + #, c-format + msgid "Status(DRAINING):\n" + msgstr "Status (DRAINING):\n" + +-#: aplay/aplay.c:1269 ++#: aplay/aplay.c:1194 + #, c-format + msgid "capture stream format change? attempting recover...\n" + msgstr "Format-Wechsel der Aufnahme-Daten? Versuche Wiederherstellung ...\n" + +-#: aplay/aplay.c:1271 ++#: aplay/aplay.c:1196 + #, c-format + msgid "xrun(DRAINING): prepare error: %s" + msgstr "XRUN (DRAINING): Fehler beim Re-Initialisieren des Gerätes: %s" + +-#: aplay/aplay.c:1278 ++#: aplay/aplay.c:1203 + #, c-format + msgid "Status(R/W):\n" + msgstr "Status (R/W):\n" + +-#: aplay/aplay.c:1281 ++#: aplay/aplay.c:1206 + #, c-format + msgid "read/write error, state = %s" + msgstr "Lese-/Schreibfehler, Status = %s" + +-#: aplay/aplay.c:1291 ++#: aplay/aplay.c:1216 + #, c-format + msgid "Suspended. Trying resume. " + msgstr "Ruhezustand. Versuche, aufzuwecken. " + +-#: aplay/aplay.c:1296 ++#: aplay/aplay.c:1221 + #, c-format + msgid "Failed. Restarting stream. " + msgstr "Fehlgeschlagen. Re-Initialisierung. " + +-#: aplay/aplay.c:1298 ++#: aplay/aplay.c:1223 + #, c-format + msgid "suspend: prepare error: %s" + msgstr "Ruhezustand: Fehler beim Re-Initialisieren: %s" + +-#: aplay/aplay.c:1303 ++#: aplay/aplay.c:1228 + #, c-format + msgid "Done.\n" + msgstr "Fertig.\n" + +-#: aplay/aplay.c:1325 ++#: aplay/aplay.c:1250 + #, c-format + msgid " !clip " + msgstr " !clip " + +-#: aplay/aplay.c:1472 ++#: aplay/aplay.c:1397 + #, c-format + msgid "Unsupported bit size %d.\n" + msgstr "%d-Bit-Samples werden nicht unterstützt.\n" + +-#: aplay/aplay.c:1506 ++#: aplay/aplay.c:1431 + #, c-format + msgid "Max peak (%li samples): 0x%08x " + msgstr "Höchstwert (%li Samples): 0x%08x " + +-#: aplay/aplay.c:1540 ++#: aplay/aplay.c:1465 + #, c-format + msgid "" + "Suspicious buffer position (%li total): avail = %li, delay = %li, buffer = %" +@@ -797,108 +787,108 @@ + "verdächtige Puffer-Position (total %li): avail = %li, delay = %li, buffer = %" + "li\n" + +-#: aplay/aplay.c:1603 ++#: aplay/aplay.c:1528 + #, c-format + msgid "write error: %s" + msgstr "Schreibfehler: %s" + +-#: aplay/aplay.c:1649 ++#: aplay/aplay.c:1574 + #, c-format + msgid "writev error: %s" + msgstr "Vektor-Schreib-Fehler: %s" + +-#: aplay/aplay.c:1692 ++#: aplay/aplay.c:1617 + #, c-format + msgid "read error: %s" + msgstr "Lesefehler: %s" + +-#: aplay/aplay.c:1735 ++#: aplay/aplay.c:1660 + #, c-format + msgid "readv error: %s" + msgstr "Vektor-Lese-Fehler: %s" + +-#: aplay/aplay.c:1783 ++#: aplay/aplay.c:1708 + msgid "can't allocate buffer for silence" + msgstr "nicht genug Speicher für Stille-Block" + +-#: aplay/aplay.c:1792 aplay/aplay.c:2018 aplay/aplay.c:2023 aplay/aplay.c:2070 +-#: aplay/aplay.c:2079 aplay/aplay.c:2086 aplay/aplay.c:2096 aplay/aplay.c:2102 +-#: aplay/aplay.c:2174 aplay/aplay.c:2204 aplay/aplay.c:2218 ++#: aplay/aplay.c:1717 aplay/aplay.c:1943 aplay/aplay.c:1948 aplay/aplay.c:1995 ++#: aplay/aplay.c:2004 aplay/aplay.c:2011 aplay/aplay.c:2021 aplay/aplay.c:2027 ++#: aplay/aplay.c:2099 aplay/aplay.c:2129 aplay/aplay.c:2143 + msgid "write error" + msgstr "Schreibfehler" + +-#: aplay/aplay.c:1805 ++#: aplay/aplay.c:1730 + #, c-format + msgid "voc_pcm_flush - silence error" + msgstr "voc_pcm_flush - Fehler in set_silence" + +-#: aplay/aplay.c:1808 ++#: aplay/aplay.c:1733 + msgid "voc_pcm_flush error" + msgstr "Schreibfehler" + +-#: aplay/aplay.c:1834 ++#: aplay/aplay.c:1759 + msgid "malloc error" + msgstr "nicht genug Speicher" + +-#: aplay/aplay.c:1838 ++#: aplay/aplay.c:1763 + #, c-format + msgid "Playing Creative Labs Channel file '%s'...\n" + msgstr "Spiele Creative Labs Channel-Datei '%s'...\n" + +-#: aplay/aplay.c:1906 aplay/aplay.c:1998 ++#: aplay/aplay.c:1831 aplay/aplay.c:1923 + msgid "can't play packed .voc files" + msgstr "kann komprimierte .voc-Dateien nicht abspielen" + +-#: aplay/aplay.c:1958 ++#: aplay/aplay.c:1883 + #, c-format + msgid "can't play loops; %s isn't seekable\n" + msgstr "" + "kann Schleife nicht abspielen; Dateiposition in %s ist nicht änderbar\n" + +-#: aplay/aplay.c:2007 ++#: aplay/aplay.c:1932 + #, c-format + msgid "unknown blocktype %d. terminate." + msgstr "Unbekannter Block-Typ %d. Abbruch." + +-#: aplay/aplay.c:2138 ++#: aplay/aplay.c:2063 + #, c-format + msgid "Wave doesn't support %s format..." + msgstr "Format %s wird in WAVE nicht unterstützt ..." + +-#: aplay/aplay.c:2198 ++#: aplay/aplay.c:2123 + #, c-format + msgid "Sparc Audio doesn't support %s format..." + msgstr "Format %s wird in Sparc-Audio nicht unterstützt ..." + +-#: aplay/aplay.c:2279 ++#: aplay/aplay.c:2204 + msgid "Playing" + msgstr "Wiedergabe:" + +-#: aplay/aplay.c:2279 ++#: aplay/aplay.c:2204 + msgid "Recording" + msgstr "Aufnahme:" + +-#: aplay/aplay.c:2283 ++#: aplay/aplay.c:2208 + #, c-format + msgid "Rate %d Hz, " + msgstr "Rate: %d Hz, " + +-#: aplay/aplay.c:2285 ++#: aplay/aplay.c:2210 + #, c-format + msgid "Mono" + msgstr "mono" + +-#: aplay/aplay.c:2287 ++#: aplay/aplay.c:2212 + #, c-format + msgid "Stereo" + msgstr "stereo" + +-#: aplay/aplay.c:2289 ++#: aplay/aplay.c:2214 + #, c-format + msgid "Channels %i" + msgstr "%i Kanäle" + +-#: aplay/aplay.c:2798 aplay/aplay.c:2851 ++#: aplay/aplay.c:2573 aplay/aplay.c:2626 + #, c-format + msgid "You need to specify %d files" + msgstr "Es werden %d Dateien benötigt." +@@ -1009,47 +999,47 @@ + msgid "kernel" + msgstr "Kernel" + +-#: seq/aconnect/aconnect.c:307 ++#: seq/aconnect/aconnect.c:326 + #, c-format + msgid "can't open sequencer\n" + msgstr "Fehler beim Öffnen des Sequenzers\n" + +-#: seq/aconnect/aconnect.c:335 ++#: seq/aconnect/aconnect.c:354 + #, c-format + msgid "can't get client id\n" + msgstr "Fehler beim Lesen der Client-ID\n" + +-#: seq/aconnect/aconnect.c:342 ++#: seq/aconnect/aconnect.c:361 + #, c-format + msgid "can't set client info\n" + msgstr "Fehler beim Setzen des Client-Namens\n" + +-#: seq/aconnect/aconnect.c:349 ++#: seq/aconnect/aconnect.c:368 + #, c-format + msgid "invalid sender address %s\n" + msgstr "ungültige Sender-Adresse %s\n" + +-#: seq/aconnect/aconnect.c:354 seq/aseqnet/aseqnet.c:290 ++#: seq/aconnect/aconnect.c:373 seq/aseqnet/aseqnet.c:290 + #, c-format + msgid "invalid destination address %s\n" + msgstr "ungültige Ziel-Adresse %s\n" + +-#: seq/aconnect/aconnect.c:368 ++#: seq/aconnect/aconnect.c:387 + #, c-format + msgid "No subscription is found\n" + msgstr "keine Verbindung gefunden\n" + +-#: seq/aconnect/aconnect.c:373 ++#: seq/aconnect/aconnect.c:392 + #, c-format + msgid "Disconnection failed (%s)\n" + msgstr "Verbindungs-Trennung fehlgeschlagen (%s)\n" + +-#: seq/aconnect/aconnect.c:379 ++#: seq/aconnect/aconnect.c:398 + #, c-format + msgid "Connection is already subscribed\n" + msgstr "Verbindung ist bereits vorhanden\n" + +-#: seq/aconnect/aconnect.c:384 ++#: seq/aconnect/aconnect.c:403 + #, c-format + msgid "Connection failed (%s)\n" + msgstr "Verbindung fehlgeschlagen (%s)\n" +@@ -1179,262 +1169,262 @@ + msgid "disconnected\n" + msgstr "Verbindung getrennt\n" + +-#: speaker-test/speaker-test.c:103 ++#: speaker-test/speaker-test.c:102 + msgid "Front Left" + msgstr "Vorne links" + +-#: speaker-test/speaker-test.c:104 ++#: speaker-test/speaker-test.c:103 + msgid "Front Right" + msgstr "Vorne rechts" + +-#: speaker-test/speaker-test.c:105 ++#: speaker-test/speaker-test.c:104 + msgid "Rear Left" + msgstr "Hinten links" + +-#: speaker-test/speaker-test.c:106 ++#: speaker-test/speaker-test.c:105 + msgid "Rear Right" + msgstr "Hinten rechts" + +-#: speaker-test/speaker-test.c:108 ++#: speaker-test/speaker-test.c:107 + msgid "LFE" + msgstr "Bass" + +-#: speaker-test/speaker-test.c:109 ++#: speaker-test/speaker-test.c:108 + msgid "Side Left" + msgstr "Seitlich links" + +-#: speaker-test/speaker-test.c:110 ++#: speaker-test/speaker-test.c:109 + msgid "Side Right" + msgstr "Seitlich rechts" + +-#: speaker-test/speaker-test.c:111 ++#: speaker-test/speaker-test.c:110 + msgid "Channel 9" + msgstr "Kanal 9" + +-#: speaker-test/speaker-test.c:112 ++#: speaker-test/speaker-test.c:111 + msgid "Channel 10" + msgstr "Kanal 10" + +-#: speaker-test/speaker-test.c:113 ++#: speaker-test/speaker-test.c:112 + msgid "Channel 11" + msgstr "Kanal 11" + +-#: speaker-test/speaker-test.c:114 ++#: speaker-test/speaker-test.c:113 + msgid "Channel 12" + msgstr "Kanal 12" + +-#: speaker-test/speaker-test.c:115 ++#: speaker-test/speaker-test.c:114 + msgid "Channel 13" + msgstr "Kanal 13" + +-#: speaker-test/speaker-test.c:116 ++#: speaker-test/speaker-test.c:115 + msgid "Channel 14" + msgstr "Kanal 14" + +-#: speaker-test/speaker-test.c:117 ++#: speaker-test/speaker-test.c:116 + msgid "Channel 15" + msgstr "Kanal 15" + +-#: speaker-test/speaker-test.c:118 ++#: speaker-test/speaker-test.c:117 + msgid "Channel 16" + msgstr "Kanal 16" + +-#: speaker-test/speaker-test.c:317 ++#: speaker-test/speaker-test.c:307 + #, c-format + msgid "Broken configuration for playback: no configurations available: %s\n" + msgstr "Ungültige Konfiguration: keine unterstützte Konfiguration: %s\n" + +-#: speaker-test/speaker-test.c:324 ++#: speaker-test/speaker-test.c:314 + #, c-format + msgid "Access type not available for playback: %s\n" + msgstr "Zugriffsmodus nicht unterstützt: %s\n" + +-#: speaker-test/speaker-test.c:331 ++#: speaker-test/speaker-test.c:321 + #, c-format + msgid "Sample format not available for playback: %s\n" + msgstr "Sample-Format nicht unterstützt: %s\n" + +-#: speaker-test/speaker-test.c:338 ++#: speaker-test/speaker-test.c:328 + #, c-format + msgid "Channels count (%i) not available for playbacks: %s\n" + msgstr "Kanal-Anzahl %i nicht unterstützt: %s\n" + +-#: speaker-test/speaker-test.c:346 ++#: speaker-test/speaker-test.c:336 + #, c-format + msgid "Rate %iHz not available for playback: %s\n" + msgstr "Rate %i Hz nicht unterstützt: %s\n" + +-#: speaker-test/speaker-test.c:351 ++#: speaker-test/speaker-test.c:341 + #, c-format + msgid "Rate doesn't match (requested %iHz, get %iHz, err %d)\n" + msgstr "" + "Rate ist nicht exakt (angefordert: %i Hz, unterstützt: %i Hz, Fehlercode %" + "d)\n" + +-#: speaker-test/speaker-test.c:355 ++#: speaker-test/speaker-test.c:345 + #, c-format + msgid "Rate set to %iHz (requested %iHz)\n" + msgstr "Rate ist %i Hz (angefordert: %i Hz)\n" + +-#: speaker-test/speaker-test.c:361 ++#: speaker-test/speaker-test.c:351 + #, c-format + msgid "Buffer size range from %lu to %lu\n" + msgstr "Puffergröße von %lu bis %lu\n" + +-#: speaker-test/speaker-test.c:362 ++#: speaker-test/speaker-test.c:352 + #, c-format + msgid "Period size range from %lu to %lu\n" + msgstr "Periodengröße von %lu bis %lu\n" + +-#: speaker-test/speaker-test.c:364 ++#: speaker-test/speaker-test.c:354 + #, c-format + msgid "Requested period time %u us\n" + msgstr "Angeforderte Periodenzeit %u µs\n" + +-#: speaker-test/speaker-test.c:367 ++#: speaker-test/speaker-test.c:357 + #, c-format + msgid "Unable to set period time %u us for playback: %s\n" + msgstr "Fehler beim Setzen der Periodenzeit %u µs: %s\n" + +-#: speaker-test/speaker-test.c:373 ++#: speaker-test/speaker-test.c:363 + #, c-format + msgid "Requested buffer time %u us\n" + msgstr "Angeforderte Pufferlänge %u µs\n" + +-#: speaker-test/speaker-test.c:376 ++#: speaker-test/speaker-test.c:366 + #, c-format + msgid "Unable to set buffer time %u us for playback: %s\n" + msgstr "Fehler beim Setzen der Pufferlänge %u µs: %s\n" + +-#: speaker-test/speaker-test.c:385 ++#: speaker-test/speaker-test.c:375 + #, c-format + msgid "Using max buffer size %lu\n" + msgstr "Verwende maximale Puffergröße %lu\n" + +-#: speaker-test/speaker-test.c:388 ++#: speaker-test/speaker-test.c:378 + #, c-format + msgid "Unable to set buffer size %lu for playback: %s\n" + msgstr "Fehler beim Setzen der Puffergröße %lu: %s\n" + +-#: speaker-test/speaker-test.c:394 ++#: speaker-test/speaker-test.c:384 + #, c-format + msgid "Periods = %u\n" + msgstr "Perioden = %u\n" + +-#: speaker-test/speaker-test.c:397 ++#: speaker-test/speaker-test.c:387 + #, c-format + msgid "Unable to set nperiods %u for playback: %s\n" + msgstr "Fehler beim Setzen der Periodenanzahl %u: %s\n" + +-#: speaker-test/speaker-test.c:406 ++#: speaker-test/speaker-test.c:396 + #, c-format + msgid "Unable to set hw params for playback: %s\n" + msgstr "Fehler beim Setzen der Hardware-Parameter: %s\n" + +-#: speaker-test/speaker-test.c:412 ++#: speaker-test/speaker-test.c:402 + #, c-format + msgid "was set period_size = %lu\n" + msgstr "gesetzt: period_size = %lu\n" + +-#: speaker-test/speaker-test.c:413 ++#: speaker-test/speaker-test.c:403 + #, c-format + msgid "was set buffer_size = %lu\n" + msgstr "gesetzt: buffer_size = %lu\n" + +-#: speaker-test/speaker-test.c:415 ++#: speaker-test/speaker-test.c:405 + #, c-format + msgid "buffer to small, could not use\n" + msgstr "Puffer zu klein, kann nicht benutzt werden\n" + +-#: speaker-test/speaker-test.c:428 ++#: speaker-test/speaker-test.c:418 + #, c-format + msgid "Unable to determine current swparams for playback: %s\n" + msgstr "Fehler beim Lesen der Software-Parameter: %s\n" + +-#: speaker-test/speaker-test.c:435 ++#: speaker-test/speaker-test.c:425 + #, c-format + msgid "Unable to set start threshold mode for playback: %s\n" + msgstr "Fehler beim Setzen des Start-Schwellenwertes: %s\n" + +-#: speaker-test/speaker-test.c:442 ++#: speaker-test/speaker-test.c:432 + #, c-format + msgid "Unable to set avail min for playback: %s\n" + msgstr "Fehler beim Setzen des Mindest-verfügbar-Wertes: %s\n" + +-#: speaker-test/speaker-test.c:449 ++#: speaker-test/speaker-test.c:439 + #, c-format + msgid "Unable to set sw params for playback: %s\n" + msgstr "Fehler beim Setzen der Software-Parameter: %s\n" + +-#: speaker-test/speaker-test.c:464 ++#: speaker-test/speaker-test.c:454 + #, c-format + msgid "Can't recovery from underrun, prepare failed: %s\n" + msgstr "" + "Fehler bei Unterlauf-Behandlung, Re-Initialisierung fehlgeschlagen: %s\n" + +-#: speaker-test/speaker-test.c:475 ++#: speaker-test/speaker-test.c:465 + #, c-format + msgid "Can't recovery from suspend, prepare failed: %s\n" + msgstr "" + "Fehler beim Aufwachen aus dem Ruhezustand, Re-Initialisierung " + "fehlgeschlagen: %s\n" + +-#: speaker-test/speaker-test.c:539 speaker-test/speaker-test.c:954 ++#: speaker-test/speaker-test.c:529 speaker-test/speaker-test.c:926 + #, c-format + msgid "No enough memory\n" + msgstr "Nicht genug Speicher\n" + +-#: speaker-test/speaker-test.c:544 ++#: speaker-test/speaker-test.c:534 + #, c-format + msgid "Cannot open WAV file %s\n" + msgstr "Kann WAV-Datei %s nicht öffnen\n" + +-#: speaker-test/speaker-test.c:548 speaker-test/speaker-test.c:577 ++#: speaker-test/speaker-test.c:538 speaker-test/speaker-test.c:567 + #, c-format + msgid "Invalid WAV file %s\n" + msgstr "Ungültige WAV-Datei %s\n" + +-#: speaker-test/speaker-test.c:553 ++#: speaker-test/speaker-test.c:543 + #, c-format + msgid "Not a WAV file: %s\n" + msgstr "Keine WAV-Datei: %s\n" + +-#: speaker-test/speaker-test.c:557 ++#: speaker-test/speaker-test.c:547 + #, c-format + msgid "Unsupported WAV format %d for %s\n" + msgstr "Nicht unterstütztes WAV-Format %d in %s\n" + +-#: speaker-test/speaker-test.c:562 ++#: speaker-test/speaker-test.c:552 + #, c-format + msgid "%s is not a mono stream (%d channels)\n" + msgstr "%s ist keine Mono-Datei (%d Kanäle)\n" + +-#: speaker-test/speaker-test.c:567 ++#: speaker-test/speaker-test.c:557 + #, c-format + msgid "Sample rate doesn't match (%d) for %s\n" + msgstr "Sample-Rate (%d) stimmt nicht überein in %s\n" + +-#: speaker-test/speaker-test.c:572 ++#: speaker-test/speaker-test.c:562 + #, c-format + msgid "Unsupported sample format bits %d for %s\n" + msgstr "Nicht unterstütztes Sample-Format mit %d Bits in %s\n" + +-#: speaker-test/speaker-test.c:622 ++#: speaker-test/speaker-test.c:612 + #, c-format + msgid "Undefined channel %d\n" + msgstr "Kanal %d nicht definiert\n" + +-#: speaker-test/speaker-test.c:673 ++#: speaker-test/speaker-test.c:663 + #, c-format + msgid "Write error: %d,%s\n" + msgstr "Schreibfehler: %d, %s\n" + +-#: speaker-test/speaker-test.c:675 ++#: speaker-test/speaker-test.c:665 + #, c-format + msgid "xrun_recovery failed: %d,%s\n" + msgstr "xrun_recovery fehlgeschlagen: %d, %s\n" + +-#: speaker-test/speaker-test.c:734 ++#: speaker-test/speaker-test.c:723 + #, c-format + msgid "" + "Usage: speaker-test [OPTION]... \n" +@@ -1471,72 +1461,72 @@ + "-W,--wavdir benutze Verzeichnis mit darin enthaltenen WAV-Dateien\n" + "\n" + +-#: speaker-test/speaker-test.c:852 ++#: speaker-test/speaker-test.c:835 + #, c-format + msgid "Invalid number of periods %d\n" + msgstr "Ungültige Periodenanzahl %d\n" + +-#: speaker-test/speaker-test.c:866 speaker-test/speaker-test.c:870 ++#: speaker-test/speaker-test.c:849 speaker-test/speaker-test.c:853 + #, c-format + msgid "Invalid test type %s\n" + msgstr "Ungültiger Test-Typ %s\n" + +-#: speaker-test/speaker-test.c:882 ++#: speaker-test/speaker-test.c:865 + #, c-format + msgid "Invalid parameter for -s option.\n" + msgstr "Ungültiger Wert für Option -s\n" + +-#: speaker-test/speaker-test.c:896 ++#: speaker-test/speaker-test.c:876 + #, c-format + msgid "Unknown option '%c'\n" + msgstr "Unbekannte Options '%c'\n" + +-#: speaker-test/speaker-test.c:910 ++#: speaker-test/speaker-test.c:890 + #, c-format + msgid "Playback device is %s\n" + msgstr "Wiedergabe-Gerät ist %s\n" + +-#: speaker-test/speaker-test.c:911 ++#: speaker-test/speaker-test.c:891 + #, c-format + msgid "Stream parameters are %iHz, %s, %i channels\n" + msgstr "Stream-Parameter sind %i Hz, %s, %i Kanäle\n" + +-#: speaker-test/speaker-test.c:914 ++#: speaker-test/speaker-test.c:894 + #, c-format + msgid "Using 16 octaves of pink noise\n" + msgstr "Verwende 16 Oktaven rosa Rauschen\n" + +-#: speaker-test/speaker-test.c:917 ++#: speaker-test/speaker-test.c:897 + #, c-format + msgid "Sine wave rate is %.4fHz\n" + msgstr "Sinuswelle mit Frequenz %.4f Hz\n" + +-#: speaker-test/speaker-test.c:920 ++#: speaker-test/speaker-test.c:900 + #, c-format + msgid "WAV file(s)\n" + msgstr "WAV-Datei(en)\n" + +-#: speaker-test/speaker-test.c:926 ++#: speaker-test/speaker-test.c:906 + #, c-format + msgid "Playback open error: %d,%s\n" + msgstr "Fehler beim Öffnen des Gerätes: %d, %s\n" + +-#: speaker-test/speaker-test.c:931 ++#: speaker-test/speaker-test.c:911 + #, c-format + msgid "Setting of hwparams failed: %s\n" + msgstr "Fehler beim Setzen der Hardware-Parameter: %s\n" + +-#: speaker-test/speaker-test.c:936 ++#: speaker-test/speaker-test.c:916 + #, c-format + msgid "Setting of swparams failed: %s\n" + msgstr "Fehler beim Setzen der Software-Parameter: %s\n" + +-#: speaker-test/speaker-test.c:985 speaker-test/speaker-test.c:1007 ++#: speaker-test/speaker-test.c:957 speaker-test/speaker-test.c:979 + #, c-format + msgid "Transfer failed: %s\n" + msgstr "Schreibfehler: %s\n" + +-#: speaker-test/speaker-test.c:995 ++#: speaker-test/speaker-test.c:967 + #, c-format + msgid "Time per period = %lf\n" + msgstr "Zeit pro Periode = %lf\n" +diff -ru po/ja.po /export/git/alsa/alsa-utils/po/ja.po +--- a/po/ja.po 2010-04-16 13:19:26.000000000 +0200 ++++ b/po/ja.po 2009-05-27 15:09:03.000000000 +0200 +@@ -8,7 +8,7 @@ + msgstr "" + "Project-Id-Version: alsa-utils 1.0.9a\n" + "Report-Msgid-Bugs-To: \n" +-"POT-Creation-Date: 2010-04-16 13:19+0200\n" ++"POT-Creation-Date: 2009-05-24 19:56+0200\n" + "PO-Revision-Date: 2009-05-27 15:08+0200\n" + "Last-Translator: Takashi Iwai \n" + "Language-Team: Japanese\n" +@@ -180,47 +180,47 @@ + msgstr "このカードには制御可能なミキサーがありません" + + #. TRANSLATORS: playback on; one character +-#: alsamixer/mixer_display.c:537 alsamixer/mixer_display.c:542 ++#: alsamixer/mixer_display.c:512 alsamixer/mixer_display.c:517 + msgid "O" + msgstr "" + + #. TRANSLATORS: playback muted; one character +-#: alsamixer/mixer_display.c:539 alsamixer/mixer_display.c:543 ++#: alsamixer/mixer_display.c:514 alsamixer/mixer_display.c:518 + msgid "M" + msgstr "" + + #. TRANSLATORS: "left"; no more than two characters +-#: alsamixer/mixer_display.c:557 ++#: alsamixer/mixer_display.c:532 + msgid "L" + msgstr "" + + #. TRANSLATORS: "right"; no more than two characters +-#: alsamixer/mixer_display.c:561 ++#: alsamixer/mixer_display.c:536 + msgid "R" + msgstr "" + + #. TRANSLATORS: no more than eight characters +-#: alsamixer/mixer_display.c:563 ++#: alsamixer/mixer_display.c:538 + msgid "CAPTURE" + msgstr "録音" + +-#: alsamixer/mixer_display.c:613 ++#: alsamixer/mixer_display.c:588 + msgid "Front" + msgstr "フロント" + +-#: alsamixer/mixer_display.c:616 ++#: alsamixer/mixer_display.c:591 + msgid "Rear" + msgstr "リア" + +-#: alsamixer/mixer_display.c:619 speaker-test/speaker-test.c:107 ++#: alsamixer/mixer_display.c:594 speaker-test/speaker-test.c:106 + msgid "Center" + msgstr "センター" + +-#: alsamixer/mixer_display.c:622 ++#: alsamixer/mixer_display.c:597 + msgid "Woofer" + msgstr "低音" + +-#: alsamixer/mixer_display.c:625 ++#: alsamixer/mixer_display.c:600 + msgid "Side" + msgstr "サイド" + +@@ -366,24 +366,24 @@ + msgid "Cannot open file \"%s\"." + msgstr "\"%s\"をオープンできません" + +-#: aplay/aplay.c:147 ++#: aplay/aplay.c:139 + msgid "raw data" + msgstr "raw データ" + +-#: aplay/aplay.c:148 ++#: aplay/aplay.c:140 + msgid "VOC" + msgstr "VOC" + +-#: aplay/aplay.c:150 ++#: aplay/aplay.c:142 + msgid "WAVE" + msgstr "WAVE" + +-#: aplay/aplay.c:151 ++#: aplay/aplay.c:143 + msgid "Sparc Audio" + msgstr "Sparc オーディオ" + +-#: aplay/aplay.c:172 +-#, fuzzy, c-format ++#: aplay/aplay.c:164 ++#, c-format + msgid "" + "Usage: %s [OPTION]... [FILE]...\n" + "\n" +@@ -421,11 +421,6 @@ + " expression for validation is: coef * (buffer_size / " + "2)\n" + " --test-nowait do not wait for ring buffer - eats whole CPU\n" +-" --max-file-time=# start another output file when the old file has " +-"recorded\n" +-" for this many seconds\n" +-" --process-id-file write the process ID here\n" +-" --use-strftime apply the strftime facility to the output file name\n" + msgstr "" + "使用法: %s [オプション]... [ファイル]...\n" + "\n" +@@ -462,12 +457,12 @@ + " テスト範囲: coef * (buffer_size / 2)\n" + " --test-nowait リングバッファのウエイトを禁止 - 注意:高CPU負荷\n" + +-#: aplay/aplay.c:211 speaker-test/speaker-test.c:750 ++#: aplay/aplay.c:199 speaker-test/speaker-test.c:740 + #, c-format + msgid "Recognized sample formats are:" + msgstr "認識されるサンプルフォーマット:" + +-#: aplay/aplay.c:217 ++#: aplay/aplay.c:205 + #, c-format + msgid "" + "\n" +@@ -476,159 +471,154 @@ + "\n" + "これらのいくつかは指定のハードウェアで使用不可能な場合があります\n" + +-#: aplay/aplay.c:218 ++#: aplay/aplay.c:206 + #, c-format + msgid "The availabled format shortcuts are:\n" + msgstr "可能なフォーマットの省略形:\n" + +-#: aplay/aplay.c:219 ++#: aplay/aplay.c:207 + #, c-format + msgid "-f cd (16 bit little endian, 44100, stereo)\n" + msgstr "-f cd (16 ビット、リトルエンディアン、44100、ステレオ)\n" + +-#: aplay/aplay.c:220 ++#: aplay/aplay.c:208 + #, c-format + msgid "-f cdr (16 bit big endian, 44100, stereo)\n" + msgstr "-f cdr (16 ビット、ビッグエンディアン、44100、ステレオ)\n" + +-#: aplay/aplay.c:221 ++#: aplay/aplay.c:209 + #, c-format + msgid "-f dat (16 bit little endian, 48000, stereo)\n" + msgstr "-f dat (16 ビット、リトルエンディアン、48000、ステレオ)\n" + +-#: aplay/aplay.c:235 ++#: aplay/aplay.c:223 + msgid "no soundcards found..." + msgstr "サウンドカードが見つかりません..." + +-#: aplay/aplay.c:238 ++#: aplay/aplay.c:226 + #, c-format + msgid "**** List of %s Hardware Devices ****\n" + msgstr "**** ハードウェアデバイス %s のリスト ****\n" + +-#: aplay/aplay.c:267 ++#: aplay/aplay.c:255 + #, c-format + msgid "card %i: %s [%s], device %i: %s [%s]\n" + msgstr "カード %i: %s [%s], デバイス %i: %s [%s]\n" + +-#: aplay/aplay.c:273 ++#: aplay/aplay.c:261 + #, c-format + msgid " Subdevices: %i/%i\n" + msgstr " サブデバイス: %i/%i\n" + +-#: aplay/aplay.c:280 ++#: aplay/aplay.c:268 + #, c-format + msgid " Subdevice #%i: %s\n" + msgstr " サブデバイス #%i: %s\n" + +-#: aplay/aplay.c:356 ++#: aplay/aplay.c:332 + #, c-format + msgid "Aborted by signal %s...\n" + msgstr "シグナル %s で中断...\n" + +-#: aplay/aplay.c:467 ++#: aplay/aplay.c:430 + msgid "command should be named either arecord or aplay" + msgstr "arecord または aplay コマンドのみ可能" + +-#: aplay/aplay.c:506 ++#: aplay/aplay.c:469 + #, c-format + msgid "unrecognized file format %s" + msgstr "不正なファイルフォーマット %s" + +-#: aplay/aplay.c:513 ++#: aplay/aplay.c:476 + #, c-format + msgid "value %i for channels is invalid" + msgstr "不正なチャネル数 %i" + +-#: aplay/aplay.c:532 ++#: aplay/aplay.c:495 + #, c-format + msgid "wrong extended format '%s'" + msgstr "不正な拡張フォーマット '%s'" + +-#: aplay/aplay.c:543 ++#: aplay/aplay.c:506 + #, c-format + msgid "bad speed value %i" + msgstr "不正なレート値 %i" + +-#: aplay/aplay.c:638 ++#: aplay/aplay.c:592 + #, c-format + msgid "Try `%s --help' for more information.\n" + msgstr "より詳しい情報は「%s --help」を実行してください\n" + +-#: aplay/aplay.c:654 ++#: aplay/aplay.c:608 + #, c-format + msgid "audio open error: %s" + msgstr "" + +-#: aplay/aplay.c:659 ++#: aplay/aplay.c:613 + #, c-format + msgid "info error: %s" + msgstr "" + +-#: aplay/aplay.c:666 ++#: aplay/aplay.c:620 + #, c-format + msgid "nonblock setting error: %s" + msgstr "" + +-#: aplay/aplay.c:676 aplay/aplay.c:800 aplay/aplay.c:1167 ++#: aplay/aplay.c:630 aplay/aplay.c:737 aplay/aplay.c:1092 + msgid "not enough memory" + msgstr "メモリが足りません" + +-#: aplay/aplay.c:700 +-#, fuzzy, c-format +-msgid "Cannot create process ID file %s: %s" +-msgstr "WAVファイルがオープンできません: %s\n" +- +-#: aplay/aplay.c:790 ++#: aplay/aplay.c:727 + #, c-format + msgid "read error (called from line %i)" + msgstr "リードエラー (%i 行)" + +-#: aplay/aplay.c:848 ++#: aplay/aplay.c:785 + #, c-format + msgid "unknown length of 'fmt ' chunk (read %u, should be %u at least)" + msgstr "" + +-#: aplay/aplay.c:858 ++#: aplay/aplay.c:795 + #, c-format + msgid "" + "unknown length of extensible 'fmt ' chunk (read %u, should be %u at least)" + msgstr "" + +-#: aplay/aplay.c:863 ++#: aplay/aplay.c:800 + msgid "wrong format tag in extensible 'fmt ' chunk" + msgstr "" + +-#: aplay/aplay.c:870 ++#: aplay/aplay.c:807 + #, c-format + msgid "can't play WAVE-file format 0x%04x which is not PCM or FLOAT encoded" + msgstr "" + +-#: aplay/aplay.c:874 ++#: aplay/aplay.c:811 + #, c-format + msgid "can't play WAVE-files with %d tracks" + msgstr "%d トラックを含む WAVE ファイルは再生できません" + +-#: aplay/aplay.c:882 aplay/aplay.c:982 ++#: aplay/aplay.c:819 aplay/aplay.c:919 + #, c-format + msgid "Warning: format is changed to U8\n" + msgstr "警告: フォーマットは U8 に変更されます\n" + +-#: aplay/aplay.c:888 ++#: aplay/aplay.c:825 + #, c-format + msgid "Warning: format is changed to S16_LE\n" + msgstr "警告: フォーマットは S16_LE に変更されます\n" + +-#: aplay/aplay.c:896 ++#: aplay/aplay.c:833 + #, c-format + msgid "Warning: format is changed to S24_3LE\n" + msgstr "警告: フォーマットは S24_3LE に変更されます\n" + +-#: aplay/aplay.c:902 ++#: aplay/aplay.c:839 + #, c-format + msgid "Warning: format is changed to S24_LE\n" + msgstr "警告: フォーマットは S24_LE に変更されます\n" + +-#: aplay/aplay.c:906 ++#: aplay/aplay.c:843 + #, c-format + msgid "" + " can't play WAVE-files with sample %d bits in %d bytes wide (%d channels)" +@@ -636,261 +626,261 @@ + "%2$d バイト長 %1$d サンプルビット (%3$d チャネル) の WAVE ファイルは再生でき" + "ません" + +-#: aplay/aplay.c:918 ++#: aplay/aplay.c:855 + #, c-format + msgid " can't play WAVE-files with sample %d bits wide" + msgstr "%d ビット長のサンプルの WAVE ファイルは再生できません" + +-#: aplay/aplay.c:976 ++#: aplay/aplay.c:913 + #, c-format + msgid "Warning: format is changed to MU_LAW\n" + msgstr "警告: フォーマットは MU_LAW に変更されます\n" + +-#: aplay/aplay.c:988 ++#: aplay/aplay.c:925 + #, c-format + msgid "Warning: format is changed to S16_BE\n" + msgstr "警告: フォーマットは S16_BE に変更されます\n" + +-#: aplay/aplay.c:1001 aplay/aplay.c:1843 aplay/aplay.c:1850 aplay/aplay.c:2372 +-#: aplay/aplay.c:2384 ++#: aplay/aplay.c:938 aplay/aplay.c:1768 aplay/aplay.c:1775 aplay/aplay.c:2297 ++#: aplay/aplay.c:2309 + msgid "read error" + msgstr "リードエラー" + +-#: aplay/aplay.c:1031 ++#: aplay/aplay.c:957 + msgid "Broken configuration for this PCM: no configurations available" + msgstr "指定の PCM を使用できません: 設定がありません" + +-#: aplay/aplay.c:1048 ++#: aplay/aplay.c:974 + msgid "Access type not available" + msgstr "アクセスタイプが使用不可能" + +-#: aplay/aplay.c:1053 ++#: aplay/aplay.c:979 + msgid "Sample format non available" + msgstr "サンプルフォーマットが使用不可能" + +-#: aplay/aplay.c:1059 ++#: aplay/aplay.c:984 + msgid "Channels count non available" + msgstr "チャネル数が使用不可能" + +-#: aplay/aplay.c:1074 ++#: aplay/aplay.c:999 + #, c-format + msgid "Warning: rate is not accurate (requested = %iHz, got = %iHz)\n" + msgstr "警告: レートが不正確です (要求値 = %iHz, 使用値 = %iHz)\n" + +-#: aplay/aplay.c:1080 ++#: aplay/aplay.c:1005 + #, c-format + msgid " please, try the plug plugin %s\n" + msgstr " plug プラグイン%s を使用してください\n" + +-#: aplay/aplay.c:1116 ++#: aplay/aplay.c:1041 + msgid "Unable to install hw params:" + msgstr "hw params のインストールに失敗しました:" + +-#: aplay/aplay.c:1123 ++#: aplay/aplay.c:1048 + #, c-format + msgid "Can't use period equal to buffer size (%lu == %lu)" + msgstr "period と buffer サイズには同じ値を使用できません (%lu == %lu)" + +-#: aplay/aplay.c:1154 ++#: aplay/aplay.c:1079 + msgid "unable to install sw params:" + msgstr "sw params のインストールに失敗しました:" + +-#: aplay/aplay.c:1229 ++#: aplay/aplay.c:1154 + #, c-format + msgid "status error: %s" + msgstr "ステータスエラー: %s" + +-#: aplay/aplay.c:1239 aplay/aplay.c:1250 ++#: aplay/aplay.c:1164 aplay/aplay.c:1175 + #, c-format + msgid "%s!!! (at least %.3f ms long)\n" + msgstr "%s!!! (少なくとも %.3f ms)\n" + +-#: aplay/aplay.c:1240 aplay/aplay.c:1243 aplay/aplay.c:1251 ++#: aplay/aplay.c:1165 aplay/aplay.c:1168 aplay/aplay.c:1176 + msgid "underrun" + msgstr "アンダーラン" + +-#: aplay/aplay.c:1240 aplay/aplay.c:1251 ++#: aplay/aplay.c:1165 aplay/aplay.c:1176 + msgid "overrun" + msgstr "オーバーラン" + +-#: aplay/aplay.c:1255 ++#: aplay/aplay.c:1180 + #, c-format + msgid "Status:\n" + msgstr "ステータス:\n" + +-#: aplay/aplay.c:1259 ++#: aplay/aplay.c:1184 + #, c-format + msgid "xrun: prepare error: %s" + msgstr "" + +-#: aplay/aplay.c:1265 ++#: aplay/aplay.c:1190 + #, c-format + msgid "Status(DRAINING):\n" + msgstr "ステータス(DRAINING):\n" + +-#: aplay/aplay.c:1269 ++#: aplay/aplay.c:1194 + #, c-format + msgid "capture stream format change? attempting recover...\n" + msgstr "録音ストリームのフォーマットが変更? 修復を試みます...\n" + +-#: aplay/aplay.c:1271 ++#: aplay/aplay.c:1196 + #, c-format + msgid "xrun(DRAINING): prepare error: %s" + msgstr "" + +-#: aplay/aplay.c:1278 ++#: aplay/aplay.c:1203 + #, c-format + msgid "Status(R/W):\n" + msgstr "ステータス(R/W):\n" + +-#: aplay/aplay.c:1281 ++#: aplay/aplay.c:1206 + #, c-format + msgid "read/write error, state = %s" + msgstr "読み書きエラー, ステータス = %s" + +-#: aplay/aplay.c:1291 ++#: aplay/aplay.c:1216 + #, c-format + msgid "Suspended. Trying resume. " + msgstr "サスペンド中です。レジュームします。" + +-#: aplay/aplay.c:1296 ++#: aplay/aplay.c:1221 + #, c-format + msgid "Failed. Restarting stream. " + msgstr "失敗しました。ストリームを再スタートします。" + +-#: aplay/aplay.c:1298 ++#: aplay/aplay.c:1223 + #, c-format + msgid "suspend: prepare error: %s" + msgstr "サスペンド: prepare エラー: %s" + +-#: aplay/aplay.c:1303 ++#: aplay/aplay.c:1228 + #, c-format + msgid "Done.\n" + msgstr "終了\n" + +-#: aplay/aplay.c:1325 ++#: aplay/aplay.c:1250 + #, c-format + msgid " !clip " + msgstr "" + +-#: aplay/aplay.c:1472 ++#: aplay/aplay.c:1397 + #, c-format + msgid "Unsupported bit size %d.\n" + msgstr "" + +-#: aplay/aplay.c:1506 ++#: aplay/aplay.c:1431 + #, c-format + msgid "Max peak (%li samples): 0x%08x " + msgstr "最大ピーク (%li サンプル): 0x%08x " + +-#: aplay/aplay.c:1540 ++#: aplay/aplay.c:1465 + #, c-format + msgid "" + "Suspicious buffer position (%li total): avail = %li, delay = %li, buffer = %" + "li\n" + msgstr "" + +-#: aplay/aplay.c:1603 ++#: aplay/aplay.c:1528 + #, c-format + msgid "write error: %s" + msgstr "書込エラー: %s" + +-#: aplay/aplay.c:1649 ++#: aplay/aplay.c:1574 + #, c-format + msgid "writev error: %s" + msgstr "書込(writev)エラー: %s" + +-#: aplay/aplay.c:1692 ++#: aplay/aplay.c:1617 + #, c-format + msgid "read error: %s" + msgstr "読込エラー: %s" + +-#: aplay/aplay.c:1735 ++#: aplay/aplay.c:1660 + #, c-format + msgid "readv error: %s" + msgstr "読込(readv)エラー: %s" + +-#: aplay/aplay.c:1783 ++#: aplay/aplay.c:1708 + msgid "can't allocate buffer for silence" + msgstr "サイレンス用のバッファの取得に失敗しました" + +-#: aplay/aplay.c:1792 aplay/aplay.c:2018 aplay/aplay.c:2023 aplay/aplay.c:2070 +-#: aplay/aplay.c:2079 aplay/aplay.c:2086 aplay/aplay.c:2096 aplay/aplay.c:2102 +-#: aplay/aplay.c:2174 aplay/aplay.c:2204 aplay/aplay.c:2218 ++#: aplay/aplay.c:1717 aplay/aplay.c:1943 aplay/aplay.c:1948 aplay/aplay.c:1995 ++#: aplay/aplay.c:2004 aplay/aplay.c:2011 aplay/aplay.c:2021 aplay/aplay.c:2027 ++#: aplay/aplay.c:2099 aplay/aplay.c:2129 aplay/aplay.c:2143 + msgid "write error" + msgstr "書込エラー" + +-#: aplay/aplay.c:1805 ++#: aplay/aplay.c:1730 + #, c-format + msgid "voc_pcm_flush - silence error" + msgstr "" + +-#: aplay/aplay.c:1808 ++#: aplay/aplay.c:1733 + msgid "voc_pcm_flush error" + msgstr "" + +-#: aplay/aplay.c:1834 ++#: aplay/aplay.c:1759 + msgid "malloc error" + msgstr "malloc エラー" + +-#: aplay/aplay.c:1838 ++#: aplay/aplay.c:1763 + #, c-format + msgid "Playing Creative Labs Channel file '%s'...\n" + msgstr "Creative Labs Channel ファイル '%s' を演奏中...\n" + +-#: aplay/aplay.c:1906 aplay/aplay.c:1998 ++#: aplay/aplay.c:1831 aplay/aplay.c:1923 + msgid "can't play packed .voc files" + msgstr "packed .voc ファイルは演奏できません" + +-#: aplay/aplay.c:1958 ++#: aplay/aplay.c:1883 + #, c-format + msgid "can't play loops; %s isn't seekable\n" + msgstr "ループ演奏できません。%s はシーク不可能です\n" + +-#: aplay/aplay.c:2007 ++#: aplay/aplay.c:1932 + #, c-format + msgid "unknown blocktype %d. terminate." + msgstr "未知のブロックタイプ %d: 終了します。" + +-#: aplay/aplay.c:2138 ++#: aplay/aplay.c:2063 + #, c-format + msgid "Wave doesn't support %s format..." + msgstr "WAVE は %s フォーマットをサポートしません..." + +-#: aplay/aplay.c:2198 ++#: aplay/aplay.c:2123 + #, c-format + msgid "Sparc Audio doesn't support %s format..." + msgstr "Sparc オーディオは %s フォーマットをサポートしません..." + +-#: aplay/aplay.c:2279 ++#: aplay/aplay.c:2204 + msgid "Playing" + msgstr "再生中" + +-#: aplay/aplay.c:2279 ++#: aplay/aplay.c:2204 + msgid "Recording" + msgstr "録音中" + +-#: aplay/aplay.c:2283 ++#: aplay/aplay.c:2208 + #, c-format + msgid "Rate %d Hz, " + msgstr "レート %d Hz, " + +-#: aplay/aplay.c:2285 ++#: aplay/aplay.c:2210 + #, c-format + msgid "Mono" + msgstr "モノラル" + +-#: aplay/aplay.c:2287 ++#: aplay/aplay.c:2212 + #, c-format + msgid "Stereo" + msgstr "ステレオ" + +-#: aplay/aplay.c:2289 ++#: aplay/aplay.c:2214 + #, c-format + msgid "Channels %i" + msgstr "チャネル数 %i" + +-#: aplay/aplay.c:2798 aplay/aplay.c:2851 ++#: aplay/aplay.c:2573 aplay/aplay.c:2626 + #, c-format + msgid "You need to specify %d files" + msgstr "%d 個のファイルを指定してください" +@@ -1001,47 +991,47 @@ + msgid "kernel" + msgstr "カーネル" + +-#: seq/aconnect/aconnect.c:307 ++#: seq/aconnect/aconnect.c:326 + #, c-format + msgid "can't open sequencer\n" + msgstr "sequencer をオープンできません\n" + +-#: seq/aconnect/aconnect.c:335 ++#: seq/aconnect/aconnect.c:354 + #, c-format + msgid "can't get client id\n" + msgstr "クライアント ID を取得できません\n" + +-#: seq/aconnect/aconnect.c:342 ++#: seq/aconnect/aconnect.c:361 + #, c-format + msgid "can't set client info\n" + msgstr "クライアント情報を取得できません\n" + +-#: seq/aconnect/aconnect.c:349 ++#: seq/aconnect/aconnect.c:368 + #, c-format + msgid "invalid sender address %s\n" + msgstr "送信アドレスが不正です: %s\n" + +-#: seq/aconnect/aconnect.c:354 seq/aseqnet/aseqnet.c:290 ++#: seq/aconnect/aconnect.c:373 seq/aseqnet/aseqnet.c:290 + #, c-format + msgid "invalid destination address %s\n" + msgstr "受信アドレスが不正です: %s\n" + +-#: seq/aconnect/aconnect.c:368 ++#: seq/aconnect/aconnect.c:387 + #, c-format + msgid "No subscription is found\n" + msgstr "接続が見つかりません\n" + +-#: seq/aconnect/aconnect.c:373 ++#: seq/aconnect/aconnect.c:392 + #, c-format + msgid "Disconnection failed (%s)\n" + msgstr "切り離しに失敗 (%s)\n" + +-#: seq/aconnect/aconnect.c:379 ++#: seq/aconnect/aconnect.c:398 + #, c-format + msgid "Connection is already subscribed\n" + msgstr "既に接続されています\n" + +-#: seq/aconnect/aconnect.c:384 ++#: seq/aconnect/aconnect.c:403 + #, c-format + msgid "Connection failed (%s)\n" + msgstr "接続に失敗 (%s)\n" +@@ -1171,257 +1161,257 @@ + msgid "disconnected\n" + msgstr "切り離し\n" + +-#: speaker-test/speaker-test.c:103 ++#: speaker-test/speaker-test.c:102 + msgid "Front Left" + msgstr "" + +-#: speaker-test/speaker-test.c:104 ++#: speaker-test/speaker-test.c:103 + msgid "Front Right" + msgstr "" + +-#: speaker-test/speaker-test.c:105 ++#: speaker-test/speaker-test.c:104 + msgid "Rear Left" + msgstr "" + +-#: speaker-test/speaker-test.c:106 ++#: speaker-test/speaker-test.c:105 + msgid "Rear Right" + msgstr "" + +-#: speaker-test/speaker-test.c:108 ++#: speaker-test/speaker-test.c:107 + msgid "LFE" + msgstr "" + +-#: speaker-test/speaker-test.c:109 ++#: speaker-test/speaker-test.c:108 + msgid "Side Left" + msgstr "" + +-#: speaker-test/speaker-test.c:110 ++#: speaker-test/speaker-test.c:109 + msgid "Side Right" + msgstr "" + +-#: speaker-test/speaker-test.c:111 ++#: speaker-test/speaker-test.c:110 + msgid "Channel 9" + msgstr "" + +-#: speaker-test/speaker-test.c:112 ++#: speaker-test/speaker-test.c:111 + msgid "Channel 10" + msgstr "" + +-#: speaker-test/speaker-test.c:113 ++#: speaker-test/speaker-test.c:112 + msgid "Channel 11" + msgstr "" + +-#: speaker-test/speaker-test.c:114 ++#: speaker-test/speaker-test.c:113 + msgid "Channel 12" + msgstr "" + +-#: speaker-test/speaker-test.c:115 ++#: speaker-test/speaker-test.c:114 + msgid "Channel 13" + msgstr "" + +-#: speaker-test/speaker-test.c:116 ++#: speaker-test/speaker-test.c:115 + msgid "Channel 14" + msgstr "" + +-#: speaker-test/speaker-test.c:117 ++#: speaker-test/speaker-test.c:116 + msgid "Channel 15" + msgstr "" + +-#: speaker-test/speaker-test.c:118 ++#: speaker-test/speaker-test.c:117 + msgid "Channel 16" + msgstr "" + +-#: speaker-test/speaker-test.c:317 ++#: speaker-test/speaker-test.c:307 + #, c-format + msgid "Broken configuration for playback: no configurations available: %s\n" + msgstr "再生用に設定できません: 設定がみつかりません: %s\n" + +-#: speaker-test/speaker-test.c:324 ++#: speaker-test/speaker-test.c:314 + #, c-format + msgid "Access type not available for playback: %s\n" + msgstr "アクセスタイプが不正です: %s\n" + +-#: speaker-test/speaker-test.c:331 ++#: speaker-test/speaker-test.c:321 + #, c-format + msgid "Sample format not available for playback: %s\n" + msgstr "指定のサンプルフォーマットを使用できません: %s\n" + +-#: speaker-test/speaker-test.c:338 ++#: speaker-test/speaker-test.c:328 + #, c-format + msgid "Channels count (%i) not available for playbacks: %s\n" + msgstr "チャネル数 (%i) を使用できません: %s\n" + +-#: speaker-test/speaker-test.c:346 ++#: speaker-test/speaker-test.c:336 + #, c-format + msgid "Rate %iHz not available for playback: %s\n" + msgstr "レート %iHz を使用できません: %s\n" + +-#: speaker-test/speaker-test.c:351 ++#: speaker-test/speaker-test.c:341 + #, c-format + msgid "Rate doesn't match (requested %iHz, get %iHz, err %d)\n" + msgstr "設定レートが一致しません< (要求値 %iHz, 取得値 %iHz, エラー %d)\n" + +-#: speaker-test/speaker-test.c:355 ++#: speaker-test/speaker-test.c:345 + #, c-format + msgid "Rate set to %iHz (requested %iHz)\n" + msgstr "レート %iHz (要求値 %iHz)\n" + +-#: speaker-test/speaker-test.c:361 ++#: speaker-test/speaker-test.c:351 + #, c-format + msgid "Buffer size range from %lu to %lu\n" + msgstr "バッファサイズ範囲 %lu 〜 %lu\n" + +-#: speaker-test/speaker-test.c:362 ++#: speaker-test/speaker-test.c:352 + #, c-format + msgid "Period size range from %lu to %lu\n" + msgstr "ピリオドサイズ範囲 %lu 〜 %lu\n" + +-#: speaker-test/speaker-test.c:364 ++#: speaker-test/speaker-test.c:354 + #, c-format + msgid "Requested period time %u us\n" + msgstr "要求されたピリオド長 %u us\n" + +-#: speaker-test/speaker-test.c:367 ++#: speaker-test/speaker-test.c:357 + #, c-format + msgid "Unable to set period time %u us for playback: %s\n" + msgstr "ピリオド長 %u us を設定できません: %s\n" + +-#: speaker-test/speaker-test.c:373 ++#: speaker-test/speaker-test.c:363 + #, c-format + msgid "Requested buffer time %u us\n" + msgstr "要求されたバッファ長 %u us\n" + +-#: speaker-test/speaker-test.c:376 ++#: speaker-test/speaker-test.c:366 + #, c-format + msgid "Unable to set buffer time %u us for playback: %s\n" + msgstr "バッファ長 %u us を設定できません: %s\n" + +-#: speaker-test/speaker-test.c:385 ++#: speaker-test/speaker-test.c:375 + #, c-format + msgid "Using max buffer size %lu\n" + msgstr "最大バッファサイズ %lu を使用\n" + +-#: speaker-test/speaker-test.c:388 ++#: speaker-test/speaker-test.c:378 + #, c-format + msgid "Unable to set buffer size %lu for playback: %s\n" + msgstr "バッファサイズ %lu を設定できません: %s\n" + +-#: speaker-test/speaker-test.c:394 ++#: speaker-test/speaker-test.c:384 + #, c-format + msgid "Periods = %u\n" + msgstr "ピリオド数 = %u\n" + +-#: speaker-test/speaker-test.c:397 ++#: speaker-test/speaker-test.c:387 + #, c-format + msgid "Unable to set nperiods %u for playback: %s\n" + msgstr "ピリオド数 %u を設定できません: %s\n" + +-#: speaker-test/speaker-test.c:406 ++#: speaker-test/speaker-test.c:396 + #, c-format + msgid "Unable to set hw params for playback: %s\n" + msgstr "hw params を設定できません: %s\n" + +-#: speaker-test/speaker-test.c:412 ++#: speaker-test/speaker-test.c:402 + #, c-format + msgid "was set period_size = %lu\n" + msgstr "period_size = %lu で設定\n" + +-#: speaker-test/speaker-test.c:413 ++#: speaker-test/speaker-test.c:403 + #, c-format + msgid "was set buffer_size = %lu\n" + msgstr "buffer_size = %lu で設定\n" + +-#: speaker-test/speaker-test.c:415 ++#: speaker-test/speaker-test.c:405 + #, c-format + msgid "buffer to small, could not use\n" + msgstr "バッファが小さすぎます\n" + +-#: speaker-test/speaker-test.c:428 ++#: speaker-test/speaker-test.c:418 + #, c-format + msgid "Unable to determine current swparams for playback: %s\n" + msgstr "現在の swparams を取得できません: %s\n" + +-#: speaker-test/speaker-test.c:435 ++#: speaker-test/speaker-test.c:425 + #, c-format + msgid "Unable to set start threshold mode for playback: %s\n" + msgstr "start_threshold モードを設定できません: %s\n" + +-#: speaker-test/speaker-test.c:442 ++#: speaker-test/speaker-test.c:432 + #, c-format + msgid "Unable to set avail min for playback: %s\n" + msgstr "avail_min を設定できません: %s\n" + +-#: speaker-test/speaker-test.c:449 ++#: speaker-test/speaker-test.c:439 + #, c-format + msgid "Unable to set sw params for playback: %s\n" + msgstr "再生用の sw params を設定できません: %s\n" + +-#: speaker-test/speaker-test.c:464 ++#: speaker-test/speaker-test.c:454 + #, c-format + msgid "Can't recovery from underrun, prepare failed: %s\n" + msgstr "アンダーランから復帰失敗: %s\n" + +-#: speaker-test/speaker-test.c:475 ++#: speaker-test/speaker-test.c:465 + #, c-format + msgid "Can't recovery from suspend, prepare failed: %s\n" + msgstr "サスペンドから復帰失敗: %s\n" + +-#: speaker-test/speaker-test.c:539 speaker-test/speaker-test.c:954 ++#: speaker-test/speaker-test.c:529 speaker-test/speaker-test.c:926 + #, c-format + msgid "No enough memory\n" + msgstr "メモリが足りません\n" + +-#: speaker-test/speaker-test.c:544 ++#: speaker-test/speaker-test.c:534 + #, c-format + msgid "Cannot open WAV file %s\n" + msgstr "WAVファイルがオープンできません: %s\n" + +-#: speaker-test/speaker-test.c:548 speaker-test/speaker-test.c:577 ++#: speaker-test/speaker-test.c:538 speaker-test/speaker-test.c:567 + #, c-format + msgid "Invalid WAV file %s\n" + msgstr "不正なWAVファイルです: %s\n" + +-#: speaker-test/speaker-test.c:553 ++#: speaker-test/speaker-test.c:543 + #, c-format + msgid "Not a WAV file: %s\n" + msgstr "WAVファイルではありません: %s\n" + +-#: speaker-test/speaker-test.c:557 ++#: speaker-test/speaker-test.c:547 + #, c-format + msgid "Unsupported WAV format %d for %s\n" + msgstr "未サポートのWAVフォーマット %d: %s\n" + +-#: speaker-test/speaker-test.c:562 ++#: speaker-test/speaker-test.c:552 + #, c-format + msgid "%s is not a mono stream (%d channels)\n" + msgstr "%s はモノストリームではありません (%d チャネル)\n" + +-#: speaker-test/speaker-test.c:567 ++#: speaker-test/speaker-test.c:557 + #, c-format + msgid "Sample rate doesn't match (%d) for %s\n" + msgstr "サンプルレートが不一致です(%d): %s\n" + +-#: speaker-test/speaker-test.c:572 ++#: speaker-test/speaker-test.c:562 + #, c-format + msgid "Unsupported sample format bits %d for %s\n" + msgstr "未サポートのサンプルフォーマットビット %d: %s\n" + +-#: speaker-test/speaker-test.c:622 ++#: speaker-test/speaker-test.c:612 + #, c-format + msgid "Undefined channel %d\n" + msgstr "未定義のチャネル %d\n" + +-#: speaker-test/speaker-test.c:673 ++#: speaker-test/speaker-test.c:663 + #, c-format + msgid "Write error: %d,%s\n" + msgstr "書込エラー: %d,%s\n" + +-#: speaker-test/speaker-test.c:675 ++#: speaker-test/speaker-test.c:665 + #, c-format + msgid "xrun_recovery failed: %d,%s\n" + msgstr "xrun_recovery 失敗: %d,%s\n" + +-#: speaker-test/speaker-test.c:734 ++#: speaker-test/speaker-test.c:723 + #, c-format + msgid "" + "Usage: speaker-test [OPTION]... \n" +@@ -1459,72 +1449,72 @@ + "-W,--wavdir WAVファイルのあるディレクトリを指定\n" + "\n" + +-#: speaker-test/speaker-test.c:852 ++#: speaker-test/speaker-test.c:835 + #, c-format + msgid "Invalid number of periods %d\n" + msgstr "不正なピリオド数 %d\n" + +-#: speaker-test/speaker-test.c:866 speaker-test/speaker-test.c:870 ++#: speaker-test/speaker-test.c:849 speaker-test/speaker-test.c:853 + #, c-format + msgid "Invalid test type %s\n" + msgstr "不正なテストタイプ %s\n" + +-#: speaker-test/speaker-test.c:882 ++#: speaker-test/speaker-test.c:865 + #, c-format + msgid "Invalid parameter for -s option.\n" + msgstr "-s オプションの値が不正です\n" + +-#: speaker-test/speaker-test.c:896 ++#: speaker-test/speaker-test.c:876 + #, c-format + msgid "Unknown option '%c'\n" + msgstr "未知のオプション '%c'\n" + +-#: speaker-test/speaker-test.c:910 ++#: speaker-test/speaker-test.c:890 + #, c-format + msgid "Playback device is %s\n" + msgstr "再生デバイス: %s\n" + +-#: speaker-test/speaker-test.c:911 ++#: speaker-test/speaker-test.c:891 + #, c-format + msgid "Stream parameters are %iHz, %s, %i channels\n" + msgstr "ストリームパラメータ: %iHz, %s, %i チャネル\n" + +-#: speaker-test/speaker-test.c:914 ++#: speaker-test/speaker-test.c:894 + #, c-format + msgid "Using 16 octaves of pink noise\n" + msgstr "16 オクターブのピンクノイズを使用\n" + +-#: speaker-test/speaker-test.c:917 ++#: speaker-test/speaker-test.c:897 + #, c-format + msgid "Sine wave rate is %.4fHz\n" + msgstr "正弦波レート: %.4fHz\n" + +-#: speaker-test/speaker-test.c:920 ++#: speaker-test/speaker-test.c:900 + #, c-format + msgid "WAV file(s)\n" + msgstr "WAV ファイル\n" + +-#: speaker-test/speaker-test.c:926 ++#: speaker-test/speaker-test.c:906 + #, c-format + msgid "Playback open error: %d,%s\n" + msgstr "再生オープンエラー: %d,%s\n" + +-#: speaker-test/speaker-test.c:931 ++#: speaker-test/speaker-test.c:911 + #, c-format + msgid "Setting of hwparams failed: %s\n" + msgstr "hwparams の設定に失敗: %s\n" + +-#: speaker-test/speaker-test.c:936 ++#: speaker-test/speaker-test.c:916 + #, c-format + msgid "Setting of swparams failed: %s\n" + msgstr "swparams の設定に失敗: %s\n" + +-#: speaker-test/speaker-test.c:985 speaker-test/speaker-test.c:1007 ++#: speaker-test/speaker-test.c:957 speaker-test/speaker-test.c:979 + #, c-format + msgid "Transfer failed: %s\n" + msgstr "転送に失敗しました: %s\n" + +-#: speaker-test/speaker-test.c:995 ++#: speaker-test/speaker-test.c:967 + #, c-format + msgid "Time per period = %lf\n" + msgstr "ピリオド時間 = %lf\n" diff --git a/alsa-utils.changes b/alsa-utils.changes index e0142fd..2a75372 100644 --- a/alsa-utils.changes +++ b/alsa-utils.changes @@ -1,3 +1,42 @@ +------------------------------------------------------------------- +Fri Nov 26 09:05:03 CET 2010 - tiwai@suse.de + +- backport GIT PATCHES: + * A few alsactl init fix patches: + 0014-alsactl-init-Handle-Capture-Source-and-Mic-Boost-in-.patch + 0015-alsactl-init-Initialize-also-Master-Front-Playback-V.patch + * amixer control-id parse fix + 0016-amixer-fix-parsing-of-control-ID-name.patch + * new aloop utility + 0017-Introduce-alsaloop-utility.patch + 0018-alsaloop-Fix-loopbacks-pointer-initialization-and-al.patch + 0019-alsaloop-Fix-thread-handling.patch + 0020-alsaloop-fix-a-option-and-slave-mode-processing.patch + 0021-alsaloop-fix-resample-argument-parsing.patch + 0022-alsaloop-added-resampling-for-unsupported-soundcard-.patch + 0023-alsaloop-Add-OSS-mixer-redirection-support.patch + 0024-alsaloop-Fix-command-line-parsing-and-pollfd-initial.patch + 0025-alsaloop-Fixes-and-added-workaround-option.patch + 0026-alsaloop-add-pctl-and-cctl-options.patch + 0027-alsaloop-add-pctl-and-cctl-options-to-man-page.patch + 0028-alsaloop-added-xrun-profiling-support-U-xrun-added-S.patch + 0029-alsaloop-add-U-xrun-to-alsaloop.1-man-page.patch + 0030-alsaloop-fixes-added-W-wake-option.patch + 0031-alsaloop-Fix-latency-print.patch + 0033-alsaloop-Delay-the-restart-a-bit-to-handle-snd-aloop.patch + 0034-alsaloop-rework-the-ctl-event-handling-routine.patch + * robusitfy speaker-test + 0032-speaker-test-Don-t-retry-after-fatal-errors.patch + * misc clean up, translation updates + 0035-alsamixer-remove-obsolete-e-mail.patch + 0036-update-German-translations.patch + * systemd integration + 0037-alsactl-systemd-and-udev-hookup.patch + 0038-alsactl-Move-asound.state-location-to-var-lib-alsa.patch + 0039-configure.in-Fix-variable-name.patch +- Use systemd for openSUSE 11.4 +- Put udev rules into this package instead of alsa.rpm + ------------------------------------------------------------------- Thu Sep 2 16:06:17 CEST 2010 - tiwai@suse.de diff --git a/alsa-utils.spec b/alsa-utils.spec index 5320f95..cac8379 100644 --- a/alsa-utils.spec +++ b/alsa-utils.spec @@ -17,9 +17,17 @@ # norootforbuild +%if %suse_version > 1130 +%define use_systemd 1 +%else +%define use_systemd 0 +%endif Name: alsa-utils -BuildRequires: alsa-devel ncurses-devel xmlto +BuildRequires: alsa-devel ncurses-devel xmlto pkgconfig +%if %use_systemd +BuildRequires: systemd +%endif %define package_version 1.0.23 License: GPLv2+ Group: Productivity/Multimedia/Sound/Players @@ -44,8 +52,34 @@ Patch10: 0010-aplay-arecord-term_c_lflag-variable-might-be-unitial.patch Patch11: 0011-alsactl-init-Use-Found-hardware-instead-Unknown-hard.patch Patch12: 0012-alsactl-init-use-generic-method-instead-guess-method.patch Patch13: 0013-alsactl-Change-handling-of-inactive-controls.patch +Patch14: 0014-alsactl-init-Handle-Capture-Source-and-Mic-Boost-in-.patch +Patch15: 0015-alsactl-init-Initialize-also-Master-Front-Playback-V.patch +Patch16: 0016-amixer-fix-parsing-of-control-ID-name.patch +Patch17: 0017-Introduce-alsaloop-utility.patch +Patch18: 0018-alsaloop-Fix-loopbacks-pointer-initialization-and-al.patch +Patch19: 0019-alsaloop-Fix-thread-handling.patch +Patch20: 0020-alsaloop-fix-a-option-and-slave-mode-processing.patch +Patch21: 0021-alsaloop-fix-resample-argument-parsing.patch +Patch22: 0022-alsaloop-added-resampling-for-unsupported-soundcard-.patch +Patch23: 0023-alsaloop-Add-OSS-mixer-redirection-support.patch +Patch24: 0024-alsaloop-Fix-command-line-parsing-and-pollfd-initial.patch +Patch25: 0025-alsaloop-Fixes-and-added-workaround-option.patch +Patch26: 0026-alsaloop-add-pctl-and-cctl-options.patch +Patch27: 0027-alsaloop-add-pctl-and-cctl-options-to-man-page.patch +Patch28: 0028-alsaloop-added-xrun-profiling-support-U-xrun-added-S.patch +Patch29: 0029-alsaloop-add-U-xrun-to-alsaloop.1-man-page.patch +Patch30: 0030-alsaloop-fixes-added-W-wake-option.patch +Patch31: 0031-alsaloop-Fix-latency-print.patch +Patch32: 0032-speaker-test-Don-t-retry-after-fatal-errors.patch +Patch33: 0033-alsaloop-Delay-the-restart-a-bit-to-handle-snd-aloop.patch +Patch34: 0034-alsaloop-rework-the-ctl-event-handling-routine.patch +Patch35: 0035-alsamixer-remove-obsolete-e-mail.patch +Patch36: 0036-update-German-translations.patch +Patch37: 0037-alsactl-systemd-and-udev-hookup.patch +Patch38: 0038-alsactl-Move-asound.state-location-to-var-lib-alsa.patch +Patch39: 0039-configure.in-Fix-variable-name.patch Patch99: alsa-utils-gettext-version-removal.diff -# Patch100: alsa-utils-po-pre-patch.diff +Patch100: alsa-utils-po-pre-patch.diff Url: http://www.alsa-project.org/ BuildRoot: %{_tmppath}/%{name}-%{version}-build @@ -65,9 +99,9 @@ Authors: # fix stupid automake's automatic action sed -i -e's/EXTRA_DIST= config.rpath /EXTRA_DIST=/' Makefile.am # fix po changes in tarball first -# %patch100 -p1 +%patch100 -p1 # rm -f po/Makefile* po/*.gmo po/*.pot po/*.header po/stamp-* -# %patch -p1 +# %%patch -p1 %patch1 -p1 %patch2 -p1 %patch3 -p1 @@ -81,6 +115,32 @@ sed -i -e's/EXTRA_DIST= config.rpath /EXTRA_DIST=/' Makefile.am %patch11 -p1 %patch12 -p1 %patch13 -p1 +%patch14 -p1 +%patch15 -p1 +%patch16 -p1 +%patch17 -p1 +%patch18 -p1 +%patch19 -p1 +%patch20 -p1 +%patch21 -p1 +%patch22 -p1 +%patch23 -p1 +%patch24 -p1 +%patch25 -p1 +%patch26 -p1 +%patch27 -p1 +%patch28 -p1 +%patch29 -p1 +%patch30 -p1 +%patch31 -p1 +%patch32 -p1 +%patch33 -p1 +%patch34 -p1 +%patch35 -p1 +%patch36 -p1 +%patch37 -p1 +%patch38 -p1 +%patch39 -p1 %if %suse_version < 1020 %patch99 -p1 %endif @@ -91,12 +151,14 @@ export AUTOMAKE_JOBS=%{?jobs:%jobs} gettextize -f %endif autoreconf -fi -%if %suse_version < 1030 -%define moreopts --disable-xmlto -%else -%define moreopts +opts="" +%if %suse_version < 1140 +opts="$opts --with-asound-state-dir=/etc" %endif -%configure --with-curses=ncursesw %moreopts +%if %suse_version < 1030 +opts="$opts --disable-xmlto" +%endif +%configure --with-curses=ncursesw $opts make %{?jobs:-j %jobs} %install @@ -117,5 +179,10 @@ make %{?jobs:-j %jobs} %{_sbindir}/* %{_datadir}/sounds/alsa %{_datadir}/alsa +/lib/udev/rules.d/*.rules +%if %use_systemd +/lib/systemd/system/*.service +/lib/systemd/system/*/*.service +%endif %changelog From c9eaaffcc8d362a080939e5c54485c15ae0a11626df63196a68fc4f12abfbe52 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 26 Nov 2010 08:21:50 +0000 Subject: [PATCH 2/3] - drop explicit buildrequires on systemd OBS-URL: https://build.opensuse.org/package/show/multimedia:libs/alsa-utils?expand=0&rev=24 --- alsa-utils.changes | 5 +++++ alsa-utils.spec | 11 +++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/alsa-utils.changes b/alsa-utils.changes index 2a75372..60c5392 100644 --- a/alsa-utils.changes +++ b/alsa-utils.changes @@ -1,3 +1,8 @@ +------------------------------------------------------------------- +Fri Nov 26 09:21:16 CET 2010 - tiwai@suse.de + +- drop explicit buildrequires on systemd + ------------------------------------------------------------------- Fri Nov 26 09:05:03 CET 2010 - tiwai@suse.de diff --git a/alsa-utils.spec b/alsa-utils.spec index cac8379..277df5c 100644 --- a/alsa-utils.spec +++ b/alsa-utils.spec @@ -25,9 +25,6 @@ Name: alsa-utils BuildRequires: alsa-devel ncurses-devel xmlto pkgconfig -%if %use_systemd -BuildRequires: systemd -%endif %define package_version 1.0.23 License: GPLv2+ Group: Productivity/Multimedia/Sound/Players @@ -152,6 +149,9 @@ gettextize -f %endif autoreconf -fi opts="" +%if %use_systemd +opts="$opts --with-systemdsystemunitdir=/lib/systemd/system" +%endif %if %suse_version < 1140 opts="$opts --with-asound-state-dir=/etc" %endif @@ -179,10 +179,9 @@ make %{?jobs:-j %jobs} %{_sbindir}/* %{_datadir}/sounds/alsa %{_datadir}/alsa -/lib/udev/rules.d/*.rules +/lib/udev %if %use_systemd -/lib/systemd/system/*.service -/lib/systemd/system/*/*.service +/lib/systemd %endif %changelog From 18baa7342b9118d95ce0410e108ca8e1097d71be1c463064806aef03d466f1b3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 26 Nov 2010 11:56:49 +0000 Subject: [PATCH 3/3] - add /lib/systemd/service/alsasound.service to make systemd skipping old sysv script OBS-URL: https://build.opensuse.org/package/show/multimedia:libs/alsa-utils?expand=0&rev=25 --- alsa-utils.changes | 6 ++++++ alsa-utils.spec | 3 +++ 2 files changed, 9 insertions(+) diff --git a/alsa-utils.changes b/alsa-utils.changes index 60c5392..869f045 100644 --- a/alsa-utils.changes +++ b/alsa-utils.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Fri Nov 26 09:58:58 CET 2010 - tiwai@suse.de + +- add /lib/systemd/service/alsasound.service to make systemd + skipping old sysv script + ------------------------------------------------------------------- Fri Nov 26 09:21:16 CET 2010 - tiwai@suse.de diff --git a/alsa-utils.spec b/alsa-utils.spec index 277df5c..e31fb3c 100644 --- a/alsa-utils.spec +++ b/alsa-utils.spec @@ -164,6 +164,9 @@ make %{?jobs:-j %jobs} %install %makeinstall %find_lang %{name} --all-name +%if %use_systemd +ln -s alsa-restore.service $RPM_BUILD_ROOT/lib/systemd/system/alsasound.service +%endif %clean [ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT