Может показаться, что разработка проекта для видеостриминга — это просто: слепи плеер, возьми контент с сервера — и готово. Но только после того, как мы сами начали делать такой проект, мы поняли, что это — весьма нетривиальная задача для разработки и тестирования.
Меня зовут Влад Попов, я — QA в Surf. В статье расскажу, на что нужно обращать внимание при тестировании мобильных приложений для аудио- и видео стриминга.
Материал — не о технической реализации видеостриминга, а о продуктовых нюансах. Полтора года назад проект стал для нас вызовом: до этого никто не сталкивался с разработкой и тестированием видеостримингов. Всё, о чем я пишу, — личный опыт, которым хочется поделиться с сообществом.
По какому принципу работают видеостриминги
Чтобы тестировать видеостриминги, следует разобраться, что это такое и как они работают.
Видеостриминг — это потоковая передача видео в режиме реального времени на устройство пользователя через интернет. Современные видеостриминговые сервисы работают так:
- Большой кусок разбивается на мелкие — «чанки». 
- Чанки последовательно передаются пользователю: посмотрел кусочек — дали другие. 
Способы получения видео
Широко используется протокол получения видео HLS. Технологию сделали ребята из Apple: это стандарт для их техники.
В мастер-плейлист с сервера приходят медиафайлы доступного качества в формате m3u8. Устройство само выбирает нужное качество из списка, и мы получаем файлы-фрагменты, в которых содержатся видео.

Внутри мастер-плейлистов лежат чанки: они скачиваются по HTTP и по ним передаётся видеоконтент. Аудиодорожка может быть отдельным артефактом в мастер-плейлисте или вшита в фрагменты.

Content Delivery Network (CDN) — способ получать видео по прямой ссылке на сервере-хранилище.
Сеть доставки содержимого — географически распределённая сетевая инфраструктура. Позволяет оптимизировать доставку и дистрибуцию содержимого конечным пользователям в интернете.

Это удобный вариант для коротких видео: например, рекламных. Минус только в том, что надо ждать, пока видео полностью загрузится до конца. Но разница несущественная: фрагменты в HLS имеют длительность 10 секунд, реклама — 15. Зато посреди просмотра не будет ошибки.
Из каких элементов состоит видеостриминговое приложение
Представим приложение как слоеный пирог, который содержит следующие части:
- Работа с сетью. Основание пирога: всё строится на взаимодействии клиента и сервера. Не уделим внимание основанию — приложение будет «невкусным». 
- Логика плеера. Не менее важная часть пирога: видна пользователю, он взаимодействует с ней напрямую. 
- Картинка в картинке и воспроизведение в фоне. Можно сравнить с декоративными украшениями пирога: пользователю «вкусно» и удобно. 
- Удобство пользования плеером. Вишенка на торте. Хорошо, когда плеером пользоваться удобно и ничего не отвлекает от контента. Например, когда не нужно лишний раз тапать на плеер для перемотки, чтобы вызвать контролы. 
Рассмотрим каждую составляющую подробнее.
Работа с сетью
Начнем с инициализации: нужно понять, откуда приложение получает видеофайлы. Есть два варианта:
- Прямая ссылка на hls/mp4. Она может приходить в API в качестве одного из полей. Приложение само уходит по ней и запрашивает мастер-плейлист. 
- Отдельный запрос, в котором получаем мастер-плейлист: бэк оборачивает запрос на мастер-плейлист в свое API (например, получение плейлиста по id серии id/playlist). В качестве ответа приходят плейлисты определенного качества. 
Возможна ситуация, когда аудио- и видеодорожки приходят в разных полях: тогда приложение склеивает их «на лету». Отсюда возникает вопрос с обработкой ошибок при старте воспроизведения видео.
Обработка ошибок при старте
Это важный пункт: в этот момент происходит первое соприкосновение пользователя с приложением. Стоит обратить внимание:
- Как показывается ошибка. 
- Запрос на повтор отправляется фоном или пользователь должен самостоятельно нажать на повтор. 
- Какова периодичность повтора запросов, если они идут фоном. 
- Что будет, если упал видеоконтент, но аудиодорожка при этом есть. 
- Что будет, если упало аудио, но видеодорожка при этом есть. 
Обработка ошибок при воспроизведении
- Каков размер буфера для воспроизведения. 
- Как обрабатывается ошибка на фрагмент. 
- Как восстанавливается воспроизведение после ошибки. 
- Как ведёт себя аудио при падении видео — и наоборот. 
- Как они восстанавливают коннект. 
Автоматическое переключение качества при ухудшении сети или при старте с плохой сетью
- Подгружает ли приложение видео сразу в самом высоком качестве. 
- Или берёт первый доступный плейлист. 
- Или «умно» проверяет скорость интернета и подстраивается под нужное качество. 
Лучший вариант — загрузить сначала видео в плохом качестве и «на лету» поменять на подходящее. Долго заставлять пользователя ждать контент не стоит.
Ручная смена качества
- Воспроизведение стартует в новом качестве или сначала доигрывает буфер, а потом уже подкачивается новое. 
- Если переключение качества не удалось, показываем ошибку или оставляем пользователя на том качестве на котором он был. 
Субтитры
Фича хоть и мелкая, но важная. Нужно определиться:
- Как получаем субтитры. 
- Как они себя ведут при ошибках воспроизведения. 
- Как ведёт себя плеер при ошибке на загрузку субтитров. 
Логика плеера
С логикой плеера пользователь взаимодействует чаще всего. Этот раздел — больше продуктовый, чем технический. Мы убеждены, что QA обеспечивают качество продукта во всех смыслах. Поэтому важно убедиться не только в том, что фичи сделаны по ТЗ, но и в том, что они удобны для пользователей. Например, кнопка может работать технически правильно, но чтобы её нажать, потребуется выполнить лишние действия. На всё это как раз и стоит обратить внимание именно QA: он имеет доступ к проекту в той стадии, где всё это можно быстро отловить и изменить.
Прерывания
У мобильных приложений есть прерывания: например, звонок, пуши, показ шторок, переходы в другие приложения с воспроизведением видео или аудио в фоне. Понятно, что пользователю не хочется, чтобы звонящий услышал посторонние звуки и узнал, какие шоу он смотрит :)
Логично, что видео в таком случае должно запаузиться. Кроме этого, важно обратить внимание на продолжение воспроизведения после прерывания: контрол плеера может явно стоять на паузе либо видео воспроизведётся дальше само.
Рубрика «Интересные баги на iOS»
Столкнулся с багом как пользователь стримингов.
Срабатывал режим экранного времени, приложение завершало работу. После нажатия на кнопку «Позже» и временного отключения ограничения, видео или аудио «замораживалось». При этом кнопка на самом плеере была в положении «поставить паузу». Чтобы начать воспроизведение дальше, надо было тапнуть либо два раза (поставить паузу -> снять с паузы), либо четыре раза по кнопке, что весьма бесит.
Не буду упоминать про отставание картинки от звука после срабатывания прерывания :) Также отставать может картинка от звука при ускорении видео, но это уже другая история. Набравшись опыта с шарингом видео на ТВ могу сказать, что иногда он вылетает и это жутко бесит, но подобная ситуация чаще появлялась в браузерах, чем в приложениях.
Ориентация экрана
Ориентация север, я хочу, чтобы ты верил, я хочу, чтобы ты перевернул мне картинку, так как я положил телефон.
Интерактив! Представьте: вы открываете приложение с игрой, которая разворачивается в альбом, или нажимаете в видеоплеере на кнопку разворота видео. Автоповорот при этом запрещён. Представили? А теперь ответьте на вопрос «С какой стороны у вас находится кнопка „Домой“ на телефоне?»
Для меня и большинства моих коллег ответ был «справа». То есть после открытия игры или нажатия на разворот в полноэкранный режим, вы на автомате повернёте устройство влево.

Мы не описали явно этот момент в ТЗ и сделали наоборот: кнопка «Домой» оказывалась слева. Пришлось потом доказывать команде, что это не моя хотелка, как вредного QA, а такое поведение ожидает пользователь.
Отдельно стоит уточнить момент про автоповорот плеера, когда стоит блокировка автоповорота. На некоторых андроид-устройствах встречал, что плееры это игнорируют: они поворачиваются в ту сторону, в которую пользователь завалил телефон, и игнорируют блокировку автоповорота. Поэтому пропишите в ТЗ явно, что делать в таком случае. Это поможет не схлопотать лишних багов, которые одна сторона считает заведенными верно, а другая, опираясь на опыт другого приложения, — нет.
Контролы плеера
Хорош тот плеер, которым удобно пользоваться.
Появление и скрытие контролов. Стоит обращать внимание:
- Когда контролы пропадают автоматически — например, начинается воспроизведение, и через две секунды они исчезают. 
- Когда они автоматически не исчезают. 
Мы не обдумали этот момент, и контролы всегда пропадали через две секунды — даже когда видео на паузе. Но ведь если пользователь поставил на паузу, он захочет снять с неё. Придётся лишний раз тапать на экран, чтобы они снова появились. Это лишний шаг.
Перемотка. Похожая ситуация с перемоткой дабл-тапами и кнопками на плеере. Заметили, что у популярных приложений перемотка дабл-тапом работает так: если пользователь только что перемотал фрагмент, и на экране ещё есть контрол перемотки, последующая перемотка срабатывает на каждый тап.
Пример
Чтобы перемотать на 30 секунд вперед с шагом перемотки 10 сек, нужно тапнуть 4 раза, а не 6. Два раза, чтобы активировать перемотку и прыгнуть на 10 секунд вперед, и каждый следующий тап даёт +10 секунд вперед. Это удобно и не создаёт ощущение лагов при перемотке.

Контролы при открытых шторках:
- Работают ли контролы, когда на плеере открыта какая-нибудь шторка. 
- Как эта шторка закрывается: тапом вне шторки или явно должен быть крестик. 

Жесты плеера
Не забываем, конечно же, про жесты плеера: область применения и удобство расположения. Это могут быть жесты выключения рамок, жест прибавления яркости или громкости, особые жесты для вызова фич плеера. Главное — чтобы они не конфликтовали друг с другом и корректно перестраивали свою область применения на экранах с разными размерами (привет, iPhone SE).
Состояние настроек для следующего видео
Сохраняется ли состояние настроек плеера для следующего видео. Под состоянием я имею в виду:
- скорость видео, 
- качество, 
- состояние рамок, 
- яркость (если она меняется в плеере), 
- включённость субтитров. 
Если настройки выставлены явно — в настройках приложения — они должны сохраняться везде.
Если они выставлены один раз на плеере, то в рамках одной сессии работы с приложением должны сохраняться при переходе на другое видео.
Кнопки на плеере
Логика. Лишних прерываний видео быть не должно: лучше всё сделать бесшовно.
Область тапов. Области тапов не должны быть слишком мелкими или наезжать друг на друга. Особенно это важно для кнопок, которые находятся рядом с таймлайном плеера: чтобы случайно не перемотать в конец или в начало.
Субтитры
Важно, чтобы субтитры:
- не мешали просмотру, 
- хорошо читались, 
- не блочили видео, если не могут отображаться, 
- удобно выключались, но это уже опционально — важно не захламлять экран плеера контролами. 
Картинка в картинке и воспроизведение в фоне (пипафон)
Переходим к авторской и самой больной рубрике: картинка в картинке и воспроизведение в фоне. Больная она потому, что стриминговое приложение мы делали на Flutter: плагины нативные, логику дописывали на нативе, где-то получалось криво. Плюс тестить это довольно сложно: живых примеров всего несколько.
Почему «пипафон»: лирическое отступление
Мы в команде назвали фичу картинки в картинке и воспроизведения в фоне «пипафон». Pip — «картинка в картинке», потом добавили в приложение воспроизведение в фоне, а потом сделали, чтобы пип и фон были доступны одновременно.
Требований к картинке в картинке и фону немного: кастомизация практически отсутствует. Расскажу, на что важно смотреть при тестировании фичи.
Логика контролов в этих режимах: какими они могут быть. И на то когда контролы недоступны совсем.

Очередь воспроизведения: должен быть плавный и бесшовный переход от одного контента к другому без длинных пауз и задержек.
Если вы решили внедрить в видео рекламу, которую нельзя пропускать и она доступна в режиме пипафон, позаботьтесь о том, чтобы:
- Контролы плеера в этом режиме были недоступны для перемотки и пропуска. 
- После окончания рекламы они обязательно вернулись в исходное состояние. 
- Если реклама в середине видео, контролы на ней тоже должны быть заблочены для перемотки. 
Сюда же отнесу окончание воспроизведения контента. Важно, чтобы пользователь понимал, что происходит у него на экране, и не был шокирован изменениями.
Скорость видео, качество и субтитры должны вести себя, как и у «большого» плеера.
Совет от автора
Если у вас доступен режим пипафон, проверьте его на всех доступных ОС и оболочках. Очень много подводных камней и специфичных багов зависят как раз от оболочки.
Ну взаимодействия картинки в картинке и фона — отдельное искусство. Бывает, после активации одного второй перестает работать и чинится только перезапуском приложения.
Удобство пользования плеером
Мелочи, которые позволяют пользователю не думать о том, что между ним и контентом ещё есть прослойка в виде приложения.
Работа с наушниками. Наушники умеют во всякие сенсоры, жесты, голосовое управление, могут останавливать контент, когда из уха вытаскивается один из них. Они даже могут произносить сообщения в момент прослушивания.
Представьте ситуацию: человек едет в автобусе и слушает подкаст. Вытащил наушник из уха, чтобы уточнить, какая остановка следующая, а контент начинает орать на весь автобус. Будет очень неловко. Наверно, многие (и я в том числе) опасаются такой ситуации.
Аналогично при подключении наушников: что происходит с контентом, паузится ли или продолжает воспроизведение. Ну и всем известные жесты и кнопки на наушниках должны корректно отрабатывать с приложением.
Перемотка. Не любим рекламу, которая встроена в видео, или хотим перемотать до припева? Перемотка — наше все, но только если у нее удобный шаг. Согласитесь, не суперкруто, когда перемотка идёт вперёд сразу на минуту, когда хотелось бы перемотать на несколько секунд. Хорошо, когда она настраивается в приложении. Обговорите с командой и заказчиком, проведите исследование и предоставьте доказательство того, что это неудобно. И потом вам скажут спасибо.
Удобство расположения кнопок на плеере и какую роль они играют. Например, кнопка настроек в левом верхнем углу. Представили? Согласен, неудобно совсем. Если вы держите телефон с диагональю 6,6 дюйма правой рукой и пытаетесь дотянуться до кнопки настроек — могу только пожелать удачи. Сделать это могут не только лишь все.
Стриминг на ТВ. Вначале я не обратил никакого внимания на то, что существует стриминг из приложений на ТВ. Но попробовал один раз и уже не могу остановиться.
Смотреть видео на большом экране с любимыми закусками и лежа на диване — огромное удовольствие. Не лишайте пользователей этого — укажите на это команде сразу. AirPlay для iOS или любой другой каст для Android — залог отсутствия негативных отзывов от пользователей на тему «Кто смотрит контент в 2к22 на телефоне?»
Важно не только указать, что можно кастить на ТВ, но и проверить на нескольких моделях ТВ возможность каста. Да, в этом случае придется прибегнуть к помощи коллег, но оно того стоит.
В тестировании видеостримингов нет ничего сложного по части кода, зато много продуктовой работы
С технической стороны QA ждёт всё то же самое, что и в других приложениях: всё те же компонентные проверки на каждый элемент плеера плюс некоторые особенности с интеграциями библиотек или фич.
А вот продуктовки и головняка с логикой будет много: я говорю про мелкие вещи типа «следить за поведением контролов в каких-то супернеочевидных кейсах» или «следить за удобством расположения разных кнопок, когда смотришь видео лежа на диване».
И это весьма важные моменты, ведь мы смотрим на проект не с точки зрения «проверить, чтобы всё было по ТЗ», а именно с точки зрения качества итогового продукта. И если не учесть этих мелочей, продукт будет качественный с точки зрения отсутствия багов, но некачественный с точки зрения пользовательского опыта.
Поэтому, дорогие друзья, по коду — делайте вашу обычную работу. А вот по логике — объединяйтесь с продактами и аналитиками и фигачьте, чтобы всё было круто и красиво.
 
          