forked from pool/alsa-utils
Takashi Iwai
3331bcfb82
* 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
318 lines
9.4 KiB
Diff
318 lines
9.4 KiB
Diff
From 147a1cc75cf6002eb5ea2983a374d2e84eee8e1d Mon Sep 17 00:00:00 2001
|
|
From: Jaroslav Kysela <perex@perex.cz>
|
|
Date: Fri, 8 Oct 2010 15:10:23 +0200
|
|
Subject: [PATCH 23/38] alsaloop: Add OSS mixer redirection support
|
|
|
|
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
|
|
---
|
|
alsaloop/alsaloop.1 | 16 +++++++++++++
|
|
alsaloop/alsaloop.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++-
|
|
alsaloop/alsaloop.h | 12 +++++++++-
|
|
alsaloop/control.c | 48 +++++++++++++++++++++++++++++++++++++-
|
|
alsaloop/pcmjob.c | 1 +
|
|
alsaloop/test.sh | 4 ++-
|
|
6 files changed, 138 insertions(+), 6 deletions(-)
|
|
|
|
diff --git a/alsaloop/alsaloop.1 b/alsaloop/alsaloop.1
|
|
index 66be499..1554b6e 100644
|
|
--- a/alsaloop/alsaloop.1
|
|
+++ b/alsaloop/alsaloop.1
|
|
@@ -153,6 +153,22 @@ Known attributes:
|
|
numid - control ID numid
|
|
|
|
.TP
|
|
+\fI\-O <ossmixid>\fP | \fI\-\-ossmixer=<midid>\fP
|
|
+
|
|
+Redirect mixer control from the OSS Mixer emulation layer (capture card)
|
|
+to the ALSA layer (capture card). Format of \fIossmixid\fP is
|
|
+ALSAID[,INDEX]@OSSID:
|
|
+
|
|
+ "Master@VOLUME"
|
|
+ "PCM,1@ALTPCM"
|
|
+
|
|
+Known OSS attributes:
|
|
+
|
|
+ VOLUME, BASS, TREBLE, SYNTH, PCM, SPEAKER, LINE, MIC, CD, IMIX, ALTPCM,
|
|
+ RECLEV, IGAIN, OGAIN, LINE1, LINE2, LINE3, DIGITAL1, DIGITAL2, DIGITAL3,
|
|
+ PHONEIN, PHONEOUT, VIDEO, RADIO, MONITOR
|
|
+
|
|
+.TP
|
|
\fI\-v\fP | \fI\-\-verbose\fP
|
|
|
|
Verbose mode. Use multiple times to increase verbosity.
|
|
diff --git a/alsaloop/alsaloop.c b/alsaloop/alsaloop.c
|
|
index bbf570e..effa073 100644
|
|
--- a/alsaloop/alsaloop.c
|
|
+++ b/alsaloop/alsaloop.c
|
|
@@ -164,7 +164,9 @@ void help(void)
|
|
"-a,--slave stream parameters slave mode (0=auto, 1=on, 2=off)\n"
|
|
"-T,--thread thread number (-1 = create unique)\n"
|
|
"-m,--mixer redirect mixer, argument is:\n"
|
|
-" SRC_SLAVE_ID(PLAYBACK)@DST_SLAVE_ID(CAPTURE)\n"
|
|
+" SRC_SLAVE_ID(PLAYBACK)[@DST_SLAVE_ID(CAPTURE)]\n"
|
|
+"-O,--ossmixer rescan and redirect oss mixer, argument is:\n"
|
|
+" ALSA_ID@OSS_ID (for example: \"Master@VOLUME\")\n"
|
|
"-e,--effect apply an effect (bandpass filter sweep)\n"
|
|
"-v,--verbose verbose mode (more -v means more verbose)\n"
|
|
);
|
|
@@ -266,6 +268,46 @@ static int add_mixers(struct loopback *loop,
|
|
return 0;
|
|
}
|
|
|
|
+static int add_oss_mixers(struct loopback *loop,
|
|
+ char **mixers,
|
|
+ int mixers_count)
|
|
+{
|
|
+ struct loopback_ossmixer *mixer, *last = NULL;
|
|
+ char *str1, *str2;
|
|
+
|
|
+ while (mixers_count > 0) {
|
|
+ mixer = calloc(1, sizeof(*mixer));
|
|
+ if (mixer == NULL)
|
|
+ return -ENOMEM;
|
|
+ if (last)
|
|
+ last->next = mixer;
|
|
+ else
|
|
+ loop->oss_controls = mixer;
|
|
+ last = mixer;
|
|
+ str1 = strchr(*mixers, ',');
|
|
+ if (str1)
|
|
+ *str1 = '\0';
|
|
+ str2 = strchr(str1 ? str1 + 1 : *mixers, '@');
|
|
+ if (str2)
|
|
+ *str2 = '\0';
|
|
+ mixer->alsa_id = strdup(*mixers);
|
|
+ if (str1)
|
|
+ mixer->alsa_index = atoi(str1);
|
|
+ mixer->oss_id = strdup(str2 ? str2 + 1 : *mixers);
|
|
+ if (mixer->alsa_id == NULL || mixer->oss_id == NULL) {
|
|
+ logit(LOG_CRIT, "Not enough memory");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+ if (str1)
|
|
+ *str1 = ',';
|
|
+ if (str2)
|
|
+ *str2 = ',';
|
|
+ mixers++;
|
|
+ mixers_count--;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static int parse_config_file(const char *file, snd_output_t *output);
|
|
|
|
static int parse_config(int argc, char *argv[], snd_output_t *output)
|
|
@@ -294,6 +336,7 @@ static int parse_config(int argc, char *argv[], snd_output_t *output)
|
|
{"slave", 1, NULL, 'a'},
|
|
{"thread", 1, NULL, 'T'},
|
|
{"mixer", 1, NULL, 'm'},
|
|
+ {"ossmixer", 1, NULL, 'O'},
|
|
{NULL, 0, NULL, 0},
|
|
};
|
|
int err, morehelp;
|
|
@@ -318,11 +361,15 @@ static int parse_config(int argc, char *argv[], snd_output_t *output)
|
|
struct loopback *loop = NULL;
|
|
char *arg_mixers[MAX_MIXERS];
|
|
int arg_mixers_count = 0;
|
|
+ char *arg_ossmixers[MAX_MIXERS];
|
|
+ int arg_ossmixers_count = 0;
|
|
|
|
morehelp = 0;
|
|
while (1) {
|
|
int c;
|
|
- if ((c = getopt_long(argc, argv, "hdg:P:C:l:t:F:f:c:r:s:benvA:S:a:m:T:", long_option, NULL)) < 0)
|
|
+ if ((c = getopt_long(argc, argv,
|
|
+ "hdg:P:C:l:t:F:f:c:r:s:benvA:S:a:m:T:O:",
|
|
+ long_option, NULL)) < 0)
|
|
break;
|
|
switch (c) {
|
|
case 'h':
|
|
@@ -445,6 +492,13 @@ static int parse_config(int argc, char *argv[], snd_output_t *output)
|
|
}
|
|
arg_mixers[arg_mixers_count++] = optarg;
|
|
break;
|
|
+ case 'O':
|
|
+ if (arg_ossmixers_count >= MAX_MIXERS) {
|
|
+ logit(LOG_CRIT, "Maximum redirected mixer controls reached (max %i)\n", (int)MAX_MIXERS);
|
|
+ exit(EXIT_FAILURE);
|
|
+ }
|
|
+ arg_ossmixers[arg_ossmixers_count++] = optarg;
|
|
+ break;
|
|
case 'v':
|
|
verbose++;
|
|
break;
|
|
@@ -490,6 +544,11 @@ static int parse_config(int argc, char *argv[], snd_output_t *output)
|
|
logit(LOG_CRIT, "Unable to add mixer controls.\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
+ err = add_oss_mixers(loop, arg_ossmixers, arg_ossmixers_count);
|
|
+ if (err < 0) {
|
|
+ logit(LOG_CRIT, "Unable to add ossmixer controls.\n");
|
|
+ exit(EXIT_FAILURE);
|
|
+ }
|
|
#ifdef USE_SAMPLERATE
|
|
loop->src_enable = arg_samplerate > 0;
|
|
if (loop->src_enable)
|
|
diff --git a/alsaloop/alsaloop.h b/alsaloop/alsaloop.h
|
|
index 9753c41..366a296 100644
|
|
--- a/alsaloop/alsaloop.h
|
|
+++ b/alsaloop/alsaloop.h
|
|
@@ -65,16 +65,25 @@ struct loopback_control {
|
|
};
|
|
|
|
struct loopback_mixer {
|
|
- unsigned int skip: 1;
|
|
+ unsigned int skip:1;
|
|
struct loopback_control src;
|
|
struct loopback_control dst;
|
|
struct loopback_mixer *next;
|
|
};
|
|
|
|
+struct loopback_ossmixer {
|
|
+ unsigned int skip:1;
|
|
+ const char *alsa_id;
|
|
+ int alsa_index;
|
|
+ const char *oss_id;
|
|
+ struct loopback_ossmixer *next;
|
|
+};
|
|
+
|
|
struct loopback_handle {
|
|
struct loopback *loopback;
|
|
char *device;
|
|
char *id;
|
|
+ int card_number;
|
|
snd_pcm_t *handle;
|
|
snd_pcm_access_t access;
|
|
snd_pcm_format_t format;
|
|
@@ -143,6 +152,7 @@ struct loopback {
|
|
snd_timestamp_t tstamp_end;
|
|
/* control mixer */
|
|
struct loopback_mixer *controls;
|
|
+ struct loopback_ossmixer *oss_controls;
|
|
/* sample rate */
|
|
unsigned int use_samplerate:1;
|
|
#ifdef USE_SAMPLERATE
|
|
diff --git a/alsaloop/control.c b/alsaloop/control.c
|
|
index ade7733..967f1e9 100644
|
|
--- a/alsaloop/control.c
|
|
+++ b/alsaloop/control.c
|
|
@@ -205,6 +205,34 @@ static int copy_value(struct loopback_control *dst,
|
|
return 0;
|
|
}
|
|
|
|
+static int oss_set(struct loopback *loop,
|
|
+ struct loopback_ossmixer *ossmix,
|
|
+ int enable)
|
|
+{
|
|
+ char buf[128], file[128];
|
|
+ int fd;
|
|
+
|
|
+ if (loop->capt->card_number < 0)
|
|
+ return 0;
|
|
+ if (!enable) {
|
|
+ sprintf(buf, "%s \"\" 0\n", ossmix->oss_id);
|
|
+ } else {
|
|
+ sprintf(buf, "%s \"%s\" %i\n", ossmix->oss_id, ossmix->alsa_id, ossmix->alsa_index);
|
|
+ }
|
|
+ sprintf(file, "/proc/asound/card%i/oss_mixer", loop->capt->card_number);
|
|
+ if (verbose)
|
|
+ snd_output_printf(loop->output, "%s: Initialize OSS volume %s: %s", loop->id, file, buf);
|
|
+ fd = open(file, O_WRONLY);
|
|
+ if (fd >= 0 && write(fd, buf, strlen(buf)) == strlen(buf)) {
|
|
+ close(fd);
|
|
+ return 0;
|
|
+ }
|
|
+ if (fd >= 0)
|
|
+ close(fd);
|
|
+ logit(LOG_INFO, "%s: Unable to initialize OSS Mixer ID '%s'\n", loop->id, ossmix->oss_id);
|
|
+ return -1;
|
|
+}
|
|
+
|
|
static int control_init2(struct loopback *loop,
|
|
struct loopback_mixer *mix)
|
|
{
|
|
@@ -280,12 +308,15 @@ static int control_init2(struct loopback *loop,
|
|
int control_init(struct loopback *loop)
|
|
{
|
|
struct loopback_mixer *mix;
|
|
+ struct loopback_ossmixer *ossmix;
|
|
int err;
|
|
|
|
+ for (ossmix = loop->oss_controls; ossmix; ossmix = ossmix->next)
|
|
+ oss_set(loop, ossmix, 0);
|
|
for (mix = loop->controls; mix; mix = mix->next) {
|
|
err = control_init1(loop->play, &mix->src);
|
|
if (err < 0) {
|
|
- logit(LOG_WARNING, "Disabling playback control '%s'\n", id_str(mix->src.id));
|
|
+ logit(LOG_WARNING, "%s: Disabling playback control '%s'\n", loop->id, id_str(mix->src.id));
|
|
mix->skip = 1;
|
|
continue;
|
|
}
|
|
@@ -293,22 +324,35 @@ int control_init(struct loopback *loop)
|
|
if (err < 0)
|
|
return err;
|
|
}
|
|
+ for (ossmix = loop->oss_controls; ossmix; ossmix = ossmix->next) {
|
|
+ err = oss_set(loop, ossmix, 1);
|
|
+ if (err < 0) {
|
|
+ ossmix->skip = 1;
|
|
+ logit(LOG_WARNING, "%s: Disabling OSS mixer ID '%s'\n", loop->id, ossmix->oss_id);
|
|
+ }
|
|
+ }
|
|
return 0;
|
|
}
|
|
|
|
int control_done(struct loopback *loop)
|
|
{
|
|
struct loopback_mixer *mix;
|
|
+ struct loopback_ossmixer *ossmix;
|
|
int err;
|
|
|
|
if (loop->capt->ctl == NULL)
|
|
return 0;
|
|
+ for (ossmix = loop->oss_controls; ossmix; ossmix = ossmix->next) {
|
|
+ err = oss_set(loop, ossmix, 0);
|
|
+ if (err < 0)
|
|
+ logit(LOG_WARNING, "%s: Unable to remove OSS control '%s'\n", loop->id, ossmix->oss_id);
|
|
+ }
|
|
for (mix = loop->controls; mix; mix = mix->next) {
|
|
if (mix->skip)
|
|
continue;
|
|
err = snd_ctl_elem_remove(loop->capt->ctl, mix->dst.id);
|
|
if (err < 0)
|
|
- logit(LOG_WARNING, "Unable to remove control '%s': %s\n", id_str(mix->dst.id), snd_strerror(err));
|
|
+ logit(LOG_WARNING, "%s: Unable to remove control '%s': %s\n", loop->id, id_str(mix->dst.id), snd_strerror(err));
|
|
}
|
|
return 0;
|
|
}
|
|
diff --git a/alsaloop/pcmjob.c b/alsaloop/pcmjob.c
|
|
index 86917ef..5c2fed0 100644
|
|
--- a/alsaloop/pcmjob.c
|
|
+++ b/alsaloop/pcmjob.c
|
|
@@ -1022,6 +1022,7 @@ static int openit(struct loopback_handle *lhandle)
|
|
device = snd_pcm_info_get_device(info);
|
|
subdevice = snd_pcm_info_get_subdevice(info);
|
|
snd_pcm_info_free(info);
|
|
+ lhandle->card_number = card;
|
|
lhandle->ctl = NULL;
|
|
if (card >= 0) {
|
|
char name[16];
|
|
diff --git a/alsaloop/test.sh b/alsaloop/test.sh
|
|
index fbd40c0..13a5ba7 100755
|
|
--- a/alsaloop/test.sh
|
|
+++ b/alsaloop/test.sh
|
|
@@ -10,7 +10,9 @@ test1() {
|
|
--tlatency 50000 \
|
|
--mixer "name='Master Playback Volume'@name='Master Playback Volume'" \
|
|
--mixer "name='Master Playback Switch'@name='Master Playback Switch'" \
|
|
- --mixer "name='PCM Playback Volume'"
|
|
+ --mixer "name='PCM Playback Volume'" \
|
|
+ --ossmixer "Master@VOLUME" \
|
|
+ --ossmixer "PCM@PCM"
|
|
}
|
|
|
|
test2() {
|
|
--
|
|
1.7.3.1
|
|
|