В
сообщении на форуме «О жизни»Автор: 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à, в наушниках английская дорожка, в колонках русская.
— сделать устройства типа route, чтобы задействовать аппаратный микшер;
— сделать устройства green, orange и т. д., чтобы избежать путаницы со всеми этими цифрами.