---
# System prepended metadata

title: Slack Huddle Radio Bot

---

# 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)

Вдобавок, в хадлах невозможно говорить нескольким людям одновременно, так что идея с обсуждением на фоне музыки тоже оказалась нереализуемой. Остается лишь надежда, что слак решит доработать хадлы для качественного звука, и тогда этот проект может возродиться.