我需要找到一个好方法来强制淡出 moc 守护进程的声音播放
我有以下情况:
我正在运行一个小型的 Ubuntu 12.04 服务器盒,里面有一个 MOC(musiconconsole)守护进程和一个自定义的 ruby 应用程序。
ruby 应用程序偶尔会在周期性或事件驱动场景中播放 wav 或其他声音文件。例如,晚上 7 点播放“store_is_closing.mp3”或类似的内容。
我还有一个运行着 mp3 播放列表的 MOC 守护进程,它全天播放音乐。
我正在使用 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
检查实际的控制名称。)