如果其他應用程式開始播放某些內容,則淡出 MOC

如果其他應用程式開始播放某些內容,則淡出 MOC

我需要找到一個好方法來強制淡出 moc 守護程式的聲音播放

我有以下場景:

我正在運行一個小型 Ubuntu 12.04 伺服器,其中包含 MOC(musiconconsole)守護程式和自訂 ruby​​ 應用程式。

ruby 應用程式偶爾會在週期性或事件驅動的場景中播放 wav 或其他聲音檔案。例如,晚上 7 點它會播放“store_is_looking.mp3”或類似的內容。

我還有一個 MOC 守護進程,它運行著一個 mp3 播放列表,可以全天播放音樂。

我正在使用 ALSA 進行混合。

一切正常,但我缺少一點。

如果,假設 MOC 正在播放一首歌曲,而 ruby​​ 應用程式播放一個聲音文件,那麼一切都處於相同的聲音等級(顯然)。因此,您無法理解 ruby​​ 應用程式播放的任何聲音檔案。

我需要找到一種方法來強制 MOC 守護程序將歌曲的播放淡入到定義的百分比(比方說原始聲音級別的 10%),並且在 ruby​​ 應用程序播放聲音文件後,應該將 moc 切換回來至原始聲級。

答案1

MOC 守護程式只能透過mocp客戶端進行控制。

如果您使用 PulseAudio,則可以用來pacmd變更 MOC 的音量。

如果您將 MOC 替換為MPD,您可以用來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檢查實際的控制項名稱。)

相關內容