# Slack Huddle Radio Bot Летом 2021 года в слаке появились новые голосовые легковесные чаты - huddles. Мне они очень приглянулись в каждодневной рутине, и достаточно быстро появилась идея использовать их для улучшения жизни на работе. Дальше я расскажу о процессе создания бота, и подробнее остановлюсь на моменте работы с виртуальными звуковыми устройствами для ubuntu. Для людей практики весь опыт завернут в [репозиторий](https://github.com/serg-the-engineer/slack-huddle-radio-bot), чтение опционально :) ## Команды обычно создают болталки на нерабочую тематику, чтобы как-то компенсировать недостаток живого общения в новой реальности распределенной работы. Но в чатах обычно мало музыки, шерить ее неудобно, да и все привыкли к своим плейлистам. Было бы круто сделать что-то вроде локального радио, где можно ненавящиво делиться музыкой, и конечно, локальными мемами с проекта. В целом, сделать свой интернет-поток сейчас не трудно, но кто будет заходить в него и целенаправленно слушать, вот честно? Хадлы, мне показалось, идеально для этого подходят - все уже есть на канале, не нужно отвлекаться от рабочих инструментов. Просто заходишь в болталку, еще и можешь с кем-то сразу обсудить то, что услышал. "Выглядит достаточно круто, чтобы попробовать", - решил я. ![](https://i.imgur.com/TJZoli8.png) Реализация идеи легко разбивается на задачки. 1. Понять, как слак работает с хадлами 2. Сделать аудио-поток 3. Завернуть этот поток в хадл 4. Проверить, что все работает, и наслаждаться восторженными аплодисментами в свою честь 5. Бесконечно докручивать фичи: текущая песня, добавление юзерами песен в плейлист, лайки и т.п. ## Slack API В общем-то API для хадлов я найти не смог. При открытии в браузере видно, что обмен данными происходит через вебсокет, но возиться с ним желания не возникло. Проще и быстрее сэмулировать поведение юзера и воспользоваться микрофонным входом. Хорошо, попробовал быстро накидать скрипт на знакомой связке `python + selenium`, но клик по кнопке хадла работал очень нестабильно. В итоге перешел на `puppeteer`, где все нормально заработало, и реализовал логику входа-выхода. Сделал маленькую виртуалку на убунте 20.04, установил туда pulseaudio, google-chrome, node js и npm, подробнее опять же в [репозитории](https://github.com/serg-the-engineer/slack-huddle-radio-bot). ## Аудиопоток Самая простая часть. В общем-то источником можно использовать что угодно, основная идея завернуть внутри операционной системы выход с источника на дефолтный вход, который slack по умолчанию обнаружит. Я решил использовать [liquidsoap](https://www.liquidsoap.info/doc-1.4.1/) для генерации постоянного потока. Через пакетный менеджер установилась не самая свежая версия 1.4.1, но для наших целей хватит. Пришло время разбираться со звуковыми устройствами, и конкретно с pulseaudio. ## Pulseaudio. Настраиваем вход По мере гугления обнаруживается много запросов на тему того, как примешать звук с приложения к микрофону и завернуть в тот же зум, но мне они не помогли. После очередной вкладки stack overflow пришло осознание, что обычная работа программиста тут заканчивается, и требуется реальное исследование. Поэтому здесь я остановлюсь подробнее и расскажу детали простым языком, но на объективность не претендую. Да, речь пойдет по семейство linux, и безGUIвые разборки. Есть `ALSA`. Это максимально приближенный к железу звуковой карты софт. А есть `PulseAudio` - это абстракция над драйверами, этакой микшер, с которым нам и стоит работать. Далее в словаре терминов встречаем `Sinks` и `Sources`, что везде переводят как выходы (колонки), и входы (микрофон). Окей, значит мне нужно вероятно как-то сделать `source`, завести в него сигнал и использовать по умолчанию. Для управления есть утилиты `pactl` и `pacmd`. Разница среди них есть, но можно пользоваться и тем, и тем. Например, убедимся, что у нас нет никаких входов ``` pactl list short sources pacmd list-sources ``` Далее. У каждого выхода (sink) есть сущность `monitor`. Это как гнездо для подключения наушников у колонки, то есть вроде входа для чего-то еще. И кажется, это можно использовать как дефолтный микрофон! Разработчики PulseAudio предусмотрели как раз [модуль](https://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/User/Modules/#module-null-sink) для этого. Пробуем: ``` pacmd load-module module-null-sink sink_name=Virtual_Sink sink_properties=device.description=Virtual_Sink pacmd set-default-source Virtual_Sink.monitor ``` И говорю `liquidsoft` стримить плейлист на это устройство через конфиг: ``` output.pulseaudio(device="Virtual_Sink", radio) ``` Как проверить? Попробуем сделать запись звука в системе командой `arecord -f cd test.wav` (-f отвечает за качество записи). В моем случае записался кусок трека, который был в плейлисте, а значит успех! Запускаем бота `npm start`, ждем подключения, и ... тишина. ## Pulseaudio. Настраиваем выход Варианта два. Либо звук всё-таки теряется где-то на подходе к браузеру, либо сам браузер почему-то не хочет его использовать. Не буду описывать процесс исследования запуска хрома через `puppeteer`, важно обнаружение флага [--use-file-for-fake-audio-capture](https://peter.sh/experiments/chromium-command-line-switches/#use-file-for-fake-audio-capture) и рядом --use-fake-ui-for-media-stream. С их помощью запускаю бота с записанным ранее `test.wav`, и слышу наконец знакомый трек в слаке! Значит, хром сам по себе может передать звук, придется идти в настройки. Дописываю бота, делаю скриншоты. ![](https://i.imgur.com/EqaTWyW.png) Так и есть, не найден ни один микрофон. Параллельно с проверкой хрома я выполнял команды проверки списка входов выходов, и заметил кое что. Команда `pacmd list-sources` выводит стабильно 1 выход `Virtual_Sink.monitor`. А что за команда `pacmd list-source-outputs`? Что это за выходы входов? Как я в итоге понял, `Virtual_Sink` хоть и может быть источником засчет `monitor`, но создан как `sink`, и находится только как устройство выхода. А нам нужно устройство ввода, которое создается модулем `module-virtual-source`. При этом оно должно забирать звук с нашего `Virtual_Sink.monitor` явно, потому что попытка создать простой source в надежде, что default-source в него попадет, у меня не сработала. По непонятной мне причине описания модуля `module-virtual-source` нет на [офф странице](https://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/User/Modules/), через консоль аргументы создания я тоже не смог добыть. К счастью, гугл четвертой ссылкой привел меня [к исходникам](https://github.com/pulseaudio/pulseaudio/blob/master/src/modules/module-virtual-source.c), где я нашел нужный мне параметр с именем `master`. ``` pacmd load-module module-virtual-source master=Virtual_Sink.monitor source_name=MicOut source_properties=device.description=MicOut format=s16le pactl set-default-source MicOut ``` ![](https://i.imgur.com/gtNhQxn.png) ## Проверка и итоги Самое большое разочарование :) В итоге бот заработал как надо, но то, что я услышал... Ровно так же звучит музыка, которую мы слышим в телефоне при ожидании абонента, или просто поднесенный к микрофону плеер. Просто отвратительное качество. При этом запись с этого выхода в самой системе получается нормальной. Я проверил форматы потока при передаче между девайсами, там везде 16 бит 44100, этого должно быть достаточно. Звук в слаке явно хуже. Вопрос в техподдержку расставил все по своим местам. ![](https://i.imgur.com/8v4AzYQ.png) Вдобавок, в хадлах невозможно говорить нескольким людям одновременно, так что идея с обсуждением на фоне музыки тоже оказалась нереализуемой. Остается лишь надежда, что слак решит доработать хадлы для качественного звука, и тогда этот проект может возродиться.