HOWTO: две аудиодорожки одновременно
От: Roman Odaisky Украина  
Дата: 08.02.09 22:05
Оценка: 11 (3)

Задача

В сообщении на форуме «О жизни»
Автор: NikeByNike
Дата: 08.02.09
была поставлена интересная и важная задача: открыть видеофайл, одновременно воспроизводя две звуковые дорожки на разных устройствах. Например, чтобы двое могли смотреть один фильм на одном экране, но слушать разные дорожки в разных наушниках.

Решение естественным образом делится на две части: разделить устройства на уровне драйвера и обеспечить синхронное воспроизведение двух дорожек.

Драйвер

Мой компьютер оборудован интегрированным восьмиканальным аудиомодулем Intel HDA, шесть разъемов сзади и два спереди. Теоретически, задний выход переднего канала (где колонки) отличен от переднего выхода (где наушники), и если дать драйверу не те настройки, то сзади звук есть, а спереди нет. Но мне не удалось заставить драйвер отличать одно от другого. Поэтому я прибегнул к хитрости: поскольку колонки у меня шестиканальные (5.1), а выход восьмиканальный (7.1), то я попросту подключил передние колонки в разъем боковых, чем и отделил колонки от наушников. Осталось только перенастроить драйвер:
pcm.headphones {
    type dshare
    ipc_key 3071
    slave.pcm "hw:0"
    slave.channels 8
    bindings {
        0 0
        1 1
    }
}

pcm.speakers {
    type dshare
    ipc_key 3071
    slave.pcm "hw:0"
    slave.channels 8
    bindings {
        0 6
        1 7
        2 2
        3 3
        4 4
        5 5
    }
}

pcm.!default {
    type dshare
    ipc_key 3071
    slave.pcm "hw:0"
    slave.channels 8
    bindings {
        0 0
        1 1
        0 6
        1 7
        2 2
        3 3
        4 4
        5 5
    }
}

Вышеуказанное отправляется в ~/.asoundrc или в /etc/asound.conf. Вообще, из документации у меня сложилось впечатление, что должно быть одно устройство типа dshare (чтобы избежать блокировок на /dev/snd/pcmC0D0p — (d)share позволяет разным процессам открывать одно устройство, если используются разные каналы), а остальные бы перенаправляли туда свои каналы с помощью устройств route, но почему-то работает только так, как указано выше. Ключ IPC может быть любой, лишь бы совпадал для этих устройств и отличался от ключей остальных.

Проигрыватель

Осталось только заставить проигрыватель запустить сразу две дорожки, причем так, чтобы сохранить возможность делать паузы и прокручивать видео в любом направлении. Как это сделать? Нужно каким-то образом запустить два экземпляра проигрывателя и давать им одинаковые команды. Берем любой фронт-енд к MPlayer и вклиниваемся туда, перехватывая команды и дублируя их.

#!/usr/bin/python

import sys, os, subprocess

ACTIVATION_KEY = "SPLIT_MPLAYER_AID"
MPLAYER = "/usr/bin/mplayer"

if ACTIVATION_KEY not in os.environ:
    os.execv("/usr/bin/mplayer", sys.argv)

def remove_args(args, *argnames):
    res = []
    skip = False
    for i in args:
        add = not skip
        skip = i in argnames
        if skip:
            add = False
        if add:
            res.append(i)
    return res

aid1, aid2 = os.environ[ACTIVATION_KEY].split(":")
file = sys.argv[-1]
args = sys.argv[1:-1]
args1 = [MPLAYER, "-ao", "alsa:device=speakers", "-aid", aid1] + remove_args(args, "-ao", "-alang", "-aid") + [file]
args2 = [MPLAYER, "-vfm", "null", "-vo", "null", "-ao", "alsa:device=headphones", "-aid", aid2] + \
    remove_args(args, "-ao", "-aid", "-alang", "-vo", "-vf", "-vfm", "-wid") + [file]

mplayer1 = subprocess.Popen(args1, stdin=subprocess.PIPE)
mplayer2 = subprocess.Popen(args2, stdin=subprocess.PIPE, stdout=open("/dev/null", "r"))
while True:
    line = sys.stdin.readline()
    if line == "":
        break
    mplayer1.stdin.write(line)
    mplayer2.stdin.write(line)
    mplayer1.stdin.flush()
    mplayer2.stdin.flush()
mplayer1.communicate()
mplayer2.communicate()

Соответственно, в настройках SMPlayer вместо собственно /usr/bin/mplayer указывается этот скрипт, который при наличии определенного параметра среды запускает второй MPlayer с отключенным видео и указывает разные устройства для экземпляров проигрывателей.

Заключение

С точки зрения пользователя это выглядит всего лишь так:
SPLIT_MPLAYER_AID=1:5 smplayer /srv/video/Groundhog_Day.mkv

и voilà, в наушниках английская дорожка, в колонках русская.

TODO

— сделать устройства типа route, чтобы задействовать аппаратный микшер;
— сделать устройства green, orange и т. д., чтобы избежать путаницы со всеми этими цифрами.
До последнего не верил в пирамиду Лебедева.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.