Мне нужно найти хороший способ принудительного уменьшения громкости воспроизведения звука демона MOC.
У меня следующий сценарий:
У меня запущен небольшой сервер Ubuntu 12.04 с демоном MOC (musiconconsole) и пользовательским приложением Ruby.
Приложение Ruby время от времени воспроизводит wav-файл или другой звуковой файл в периодических или событийных сценариях. Например, в 7 часов вечера оно воспроизводит «store_is_closing.mp3» или что-то в этом роде.
У меня также запущен демон MOC с плейлистом mp3, который проигрывает музыку целый день.
Для микширования я использую ALSA.
Все работает отлично, но мне не хватает одного момента.
Если, скажем, MOC воспроизводит песню, а приложение Ruby воспроизводит звуковой файл, то все будет на одном уровне звука (что очевидно). Таким образом, вы ничего не сможете понять из звукового файла, воспроизводимого приложением Ruby.
Мне нужно найти способ заставить демон MOC уменьшить громкость воспроизведения песни до определенного процента (скажем, 10% от исходного уровня звука), а после того, как приложение Ruby воспроизведет звуковой файл, MOC должен вернуться к исходному уровню звука.
решение1
Управление демоном MOC возможно только с помощью mocp
клиента.
Если вы используете PulseAudio, вы можете использовать его pacmd
для изменения громкости MOC.
Если вы заменили MOC наМПД, вы можете использовать mpc
для изменения громкости MPD.
Если вы действительно хотите сделать это с помощью ALSA, вы можете поместить следующее в /etc/asound.conf
:
pcm.moc_with_volume {
type softvol
slave.pcm "default" # or whatever you're using in MOC
control {
name "MOC Playback Volume"
count 1
}
}
и настройте MOC для использования имени устройства ALSA moc_with_volume
вместо default
.
Если ваша программа изменения громкости не позволяет настраивать свой микшерный контроллер, вам придется следить за другим микшерным контроллером и копировать его значение в микшерный контроллер MOC. Это можно сделать с помощью такой программы:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <alsa/asoundlib.h>
#define CHECK(fn) check((fn), #fn)
static void check(int err, const char *fn)
{
if (err < 0) {
fprintf(stderr, "%s failed: %s\n", fn, snd_strerror(err));
exit(EXIT_FAILURE);
}
}
int main()
{
snd_ctl_t *ctl;
snd_ctl_event_t *event;
snd_ctl_elem_id_t *id_src, *id_dst;
snd_ctl_elem_value_t *value;
unsigned int mask;
long raw, db;
CHECK(snd_ctl_open(&ctl, "hw:0", 0));
CHECK(snd_ctl_subscribe_events(ctl, 1));
snd_ctl_event_alloca(&event);
snd_ctl_elem_id_alloca(&id_src);
snd_ctl_elem_id_alloca(&id_dst);
snd_ctl_elem_value_alloca(&value);
snd_ctl_elem_id_set_interface(id_dst, SND_CTL_ELEM_IFACE_MIXER);
snd_ctl_elem_id_set_name(id_dst, "MOC Playback Volume");
for (;;) {
CHECK(snd_ctl_read(ctl, event));
if (snd_ctl_event_get_type(event) != SND_CTL_EVENT_ELEM)
continue;
mask = snd_ctl_event_elem_get_mask(event);
if (mask == SND_CTL_EVENT_MASK_REMOVE ||
!(mask & SND_CTL_EVENT_MASK_VALUE) ||
strcmp(snd_ctl_event_elem_get_name(event),
"Some Mic Capture Volume"))
continue;
snd_ctl_event_elem_get_id(event, id_src);
snd_ctl_elem_value_set_id(value, id_src);
CHECK(snd_ctl_elem_read(ctl, value));
raw = snd_ctl_elem_value_get_integer(value, 0);
CHECK(snd_ctl_convert_to_dB(ctl, id_src, raw, &db));
CHECK(snd_ctl_convert_from_dB(ctl, id_dst, db, &raw, 0));
snd_ctl_elem_value_set_id(value, id_dst);
snd_ctl_elem_value_set_integer(value, 0, raw);
snd_ctl_elem_value_set_integer(value, 1, raw);
CHECK(snd_ctl_elem_write(ctl, value));
}
}
(Используйте amixer controls
для проверки фактических названий элементов управления.)