Говорим и показываем в пандемию: как мы создали сервис синхронного просмотра видео ITSkino
О том, что самоизоляция — это не только «тук-тук-тук» в крышку гроба экономики, но и новые «горизонты возможностей», уже написано немало статей. Правда, многие из них вызывают в памяти басню Крылова про лису и виноград. Но всё же в одном карантинные коучи правы: вся эта ситуация заставляет изобретать — не обязательно какие-то глобальные штуки, которые изменят новый мировой порядок. Иногда — просто небольшие продукты, которые помогли сделать самоизоляцию чуть более выносимой.
Один из них — плеер ITSkino. И мы хотим рассказать, как и что мы делали, чтобы наделить VLC функцией синхронного просмотра потокового или локального видео у неограниченного количества человек одновременно.
У нас сейчас есть две сборки — под Windows и под MacOS. Исходные коды можно найти по этой ссылке. Я и мой коллега Александр Бортник рассказываем о нюансах, с которыми столкнулись в процессе создания сборок.
Windows
Сборка как самого приложения, так и окружения описана здесь. Мы использовали метод сборки MinGW on Linux (ОС – Ubuntu 16.04.6 LTS).
Во время сборки могут приключиться разного рода сложности. Что-то можно нагуглить сходу, что-то не сразу, что-то можно найти у наших китайских братьев по ссылкам, например, www.cnblogs.com/johnsen/p/11721632.html или blog.csdn.net/DANFBAORE/article/details/95188935. В конечном итоге, всё получится!
Идеологически правильно было бы сделать отдельный модуль, но хотелось побыстрее собрать mvp, посмотреть и «пощупать», что получится. Поэтому решили немного допилить уже имеющийся модуль интерфейса (/modules/gui/qt
). Версия qt
, которая собирается «из коробки», не имела на борту поддержки сети (QNetwork), https (openSSL), а также был выключен плагин поддержки gif. Чтобы добавить необходимую функциональность, нужно было:
- Собрать openSSL
git clone https://github.com/openssl/openssl.git
cd openssl
git checkout OpenSSL_1_0_2-stable
./Configure --cross-compile-prefix=x86_64-w64-mingw32- mingw64
make
sudo make install
- Добавить поддержку необходимых сетевых подсистем и плагинов, изменив файлы configure.ac и contrib/src/qt/rules.mak.
- Собрать (пересобрать) qt.
«Центр» всей системы — ShareService — синглтон, который инициализируется вместе с модулем интерфейса.
Его основная функциональность:
- «перехват» и обработка элементов списка воспроизведения, использующих в качестве источника адреса, начинающиеся с itsshare://
- обработка изменения состояния элементов списка воспроизведения (play/pause/stop);
- обработка события «поделиться»;
- регистрация плейера как обработчика протокола itsshare.
Второстепенные функции:
- установка директории для синхронизации локальных видеофайлов;
- проигрывание видеоинструкции при первом запуске;
- сохранение и загрузка параметров, необходимых для работы сервиса.
API вызовы:
- Создание сеанса — api/stream/create
- Получить источник сеанса по хэшу — api/session/get
- Play — api/stream/play
- Pause — api/session/pause
- Stop — api/session/stop
При первом запуске приложения генерируется уникальный идентификатор пользователя и происходит регистрация плеера как обработчика протокола itsshare.
Если во время воспроизведения видео, которое не участвует в сеансе совместного просмотра, пользователь нажал на кнопку «поделиться» (выбрал соответствующий пункт в меню ITSKino), то на эндпойнт api/stream/create
отправляется запрос, содержащий источник (имя локального файла или ссылка на потоковое видео) и текущее время воспроизведения. В ответ мы получаем хэш созданного сеанса и ссылку на него, которая автоматически копируется в буфер обмена. Данный хэш сеанса, ассоциированный с источником, мы храним для последующего использования при взаимодействии с API.
При открытии в браузере ссылки
https://itskino.ru/join?stream=
происходит редирект на
itsshare://
Далее открывается плеер VLC (так как он является обработчиком данного протокола), в который передается соответствующий URL. ShareService перехватывает данный URL, извлекает хэш сессии и обращается с ним на эндпойнт api/session/get
для получения источника воспроизведения. Источник связывается с хэшем сеанса для последующего использования при взаимодействии с API.
При изменении статуса элемента списка воспроизведения (play/pause/stop) идёт проверка, имеется ли связанный с ним хэш сеанса — и если есть, то он отсылается на соответствующий событию эндпойнт — api/stream/play
, api/session/pause
, api/session/stop
. Запрос на api/stream/play
возвращает текущее время воспроизведения сеанса совместного просмотра.
Если все участники сеанса отослали запрос api/session/pause
, то сеанс приостанавливается и возобновляется только при первом запросе api/stream/play
. При переключении элементов списка воспроизведения, источники которых связаны с хэшем сеанса, происходит обращение на api/session/stop
. Сеанс перестает существовать, если все участники процесса отослали api/session/stop
.
Публичный репозиторий
macOS
Билд:
Обнаружилась проблема с libiconv: если есть libiconv
в /usr/local/ lib
, надо временно переименовать папку lib
, чтобы подсосался дефолтный libiconv из usr/lib
.
Юнит:
- Сделан класс ItsUnit (фактически, аналог ShareService в виндовой сборке) и добавлен в мейк
modules/gui/macosx/Makefile.am
: юнит обрабатывает 5 эндпойнтов API (play, pause, stop, create, connect) и дополнительные методы (реакция на изменение элемента в плейлисте, проигрывание видеоинструкции, добавление, выбор папки синхронизации и т.д.) - Чтобы приложение в macOS открывалось по кастомному протоколу, нужно следовать инструкции.
- Методы класса интегрированы в нужных местах модуля macOS GUI (в основном —
modules/gui/macosx/playlist/VLCPlayerController
, а такжеmodules/gui/macosx/os-integration/applescript.m
,modules/gui/macosx/library/VLCLibraryWindow.m
иmodules/gui/macosx/menus/VLCMainMenu.m
/ - Инициализирован юнит в классе
modules/gui/macosx/main/VLCMain.m
Вместо вывода
Тут, в общем, и нет никакого вывода: +\- какие-то похожие решения существовали и раньше. Просто мы сильно скучали по офису и друг другу. И решили, что раз мы айтишники, то можем себе позволить потратить немного времени, чтобы сделать штуку, которая объединит классные функции других решений и будет при этом open source, как мы любим. Ребята, которые писали выше про сборки, чуток поскромничали: не всё элементарно (и упорядочено) в исходниках VLC, и поразбираться всё-таки пришлось. Но на выходе получилось и красиво, и полезно — потому что самоизоляция закончится (ну, рано или поздно), а наше решение пригодится и дальше. И не только тем, кто хочет посмотреть вместе кино, но и, например, в дистанционном обучении.
Ну, а пока — вы знаете, чем занять себя сегодняшним вечером :-)