当其他应用程序开始播放某些内容时淡出 MOC

当其他应用程序开始播放某些内容时淡出 MOC

我需要找到一个好方法来强制淡出 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检查实际的控制名称。)

相关内容