Каждый, кто хоть раз смотрел видео в интернете, понимает эту боль: видео запускается быстро, но в ужасном качестве. Или, наоборот, приходится по несколько секунд ждать, когда контент прогрузится сразу в высоком качестве. Как решить эту проблему, придумала команда онлайн-кинотеатра KION. О релизе новой функции и первых успехах рассказали продакт-менеджер Дмитрий Пискунов и разработчик Денис Чорный.
Суть проблемы
В стриминге есть актуальная и до сих пор толком не решенная проблема — как определить, в каком качестве начинать воспроизводить видео. Понятно, что благодаря адаптивному битрейту любой контент со временем подстроится: если есть возможность поднять качество, плеер это сделает. Но что делать на старте, какое качество выбрать?
Некоторые сервисы онлайн-кинотеатров сразу замахиваются на самое высокое качество. И потом зритель со слабым интернетом долго смотрит на «бублик» загрузки, ожидая начала воспроизведения.
Другие запускают видео с самого низкого качества вне зависимости от пропускной способности сети — и неприятно удивляют размазанной картинкой зрителей с хорошим интернет-сигналом. Если на мобильных гаджетах это еще не очень заметно, то на умных телевизорах сразу бросается в глаза.
До апреля этого года мы в KION стартовали с дефолтного качества — 480p. Но это решение не оптимально, оно не затрагивает крайности: тех, у кого очень медленное и нестабильное подключение, и тех, у кого интернет очень быстрый.
Мы понимали, что негативный опыт на старте просмотра может отразиться на всем впечатлении от платформы. Особенно, если речь о первом взаимодействии пользователя с продуктом. Поэтому для нас было важно быстрее решить проблему.
Та самая механика
В поисках оптимального решения мы разработали механизм, который замеряет скорость интернета, а потом, на основании этих данных, подбирает качество для старта воспроизведения. Например, если в конкретный момент пользовательская пропускная способность в диапазоне 6-8 Мб/сек и выше, мы можем предложить пользователю смотреть контент в качестве Full HD на старте воспроизведения.
Когда мы успеваем измерить скорость интернета? Мы делаем замеры везде, где запускается плеер. То есть проверяем пропускную способность сети на:
баннерах на платформе;
трейлерах в карточке контента;
трейлерах непосредственно перед контентом;
на этапе загрузки приложения и других элементах — об этом мои коллеги рассказали в статье «Как мы загрузочный экран приложения в полезный для пользователя инструмент превратили».
Потом мы учитываем данные о качестве подключения уже при показе основного контента. Например, когда вы выбираете контент и перед ним смотрите рекламу, плеер уже работает и в том числе замеряет пропускную способность сети. Данные о вашем подключении плеер хранит определенное время — мы называем его valid time. А потом с учетом собранных данных о подключении запускает контент соответствующего качества. Если ваше подключение будет меняться, плеер адаптирует качество контента.
Все видеобаннеры на старте, на главной странице, трейлеры и так далее — это ExoPlayer. Под капотом в них используется bandwidthMeter, который может передавать информацию о текущем битрейте. Ее мы и собираем.
Реализуется это так:
bandwidthMeter.addEventListener(Handler(Looper.getMainLooper())) { _, _, bitrateEstimate ->
// получение текущего значения битрейта bitrateEstimate
bandwidthManager.provideNewBitrate(bitrateEstimate)
}
Для сбора информации по текущей пропускной способности и ее хранения в кэше был создан менеджер (BandwidthManager). Его контракт:
interface BandwidthManager {
/**
* Предоставить новый доступный битрейт
* @param bitrate новый битрейт
*/
fun provideNewBitrate(bitrate: Long)
/**
* Текущее значения битрейта
*/
val currentBandwidth: StateFlow<Long>
}
Как долго будет храниться значение, регулируется динамически с помощью Remote Configs. Если по истечении заданного времени мы не получаем новых данных о битрейте, то сбрасываем значение на дефолтное.
Теперь перейдем к использованию значения пропускной способности из менеджера. Нужно обеспечить старт на хорошем качестве в тех случаях, когда пользователь сидит на «хорошем интернете», то есть тип подключения не ниже 4G LTE или устройство подключено к Wi-Fi.
Для Android TV хорошее и стабильное подключение — через Ethernet-кабель. Специфика Android TV в том, что подключение по проводу или Wi-Fi не обеспечивает нам стабильную пропускную способность. Телевизор может находиться на даче, за пределами города, где плохо ловит интернет, есть перебои со связью. Поэтому старт воспроизведения контента с максимального качества в таком случае не будет правильным решением.
Если же речь о «хорошем интернете», нам следует обеспечить пользователю хорошую пропускную способность на старте. Делаем это через билдер BandwidthMeter:
override fun getCustomBandwidthMeter(
context: Context,
defaultInitialBitrate: Long?
): DefaultBandwidthMeter {
val currentBitrate = bandwidthManager.currentBandwidth.value
return DefaultBandwidthMeter.Builder(context)
.setInitialBitrateEstimate(defaultInitialBitrate ?: DEFAULT_BITRATE)
.setInitialBitrateEstimate(NETWORK_TYPE_4G, currentBitrate)
.setInitialBitrateEstimate(NETWORK_TYPE_5G_SA, currentBitrate)
.setInitialBitrateEstimate(NETWORK_TYPE_5G_NSA, currentBitrate)
.setInitialBitrateEstimate(NETWORK_TYPE_WIFI, currentBitrate)
.setInitialBitrateEstimate(NETWORK_TYPE_ETHERNET, currentBitrate)
.build()
}
Фабрика по созданию BandwidthMeter может быть использована вместе с подключением слушателя битрейта:
override fun getBandwidthMeterWithListener(
context: Context,
bandwidthMeter: DefaultBandwidthMeter
): DefaultBandwidthMeter = bandwidthMeter.apply {
addEventListener(Handler(Looper.getMainLooper())) { _, _, bitrateEstimate ->
bandwidthManager.provideNewBitrate(bitrateEstimate)
}
}
Для этого в качестве параметра bandwidthMeter можно передать из метода getCustomBandwidthMeter().
Еще стоит учитывать, что в случае Android TV и мобильной платформы время жизни актуального битрейта разное. Например, с мобильным устройством мы можем ехать в метро и постоянно ловить проблемы с интернетом, поэтому искомый параметр не должен быть актуальным долгое время. В случае же с Android TV мы говорим о более стабильной сети. К тому же экраны в Android TV выглядят иначе, чем в смартфоне, и мы не всегда можем попасть на загрузку какого-либо видеобаннера или трейлера перед тем, как начнет проигрываться контент. Поэтому значения времени жизни актуальной пропускной способности мы сделали разными для разных платформ. Пока это эксперимент, он в процессе.
Мы выяснили, что разное время жизни дало нам больше стартов с высокого качества на Android TV, чем если бы мы выбирали одинаковое время жизни информации о битрейте для обеих платформ.
Первые результаты
Всего за две недели с момента внедрения функции мы добились довольно впечатляющих результатов.
На Android Mobile мы на 0,33% улучшили конверсию в осознанный просмотр. Осознанным просмотром мы считаем любой просмотр контента дольше пяти секунд.
Кроме того, если посмотреть, с какого качества стартует контент на мобильных устройствах, то после внедрения функции просмотр контента стал на 171% чаще стартовать с самого высокого качества — Full HD 1080p. При этом доля сессий с плохим стартовым качеством уменьшилась на 50%.
Единственный показатель, который немного просел, это join time — время от нажатия кнопки «Смотреть» до показа первого кадра. Это вполне ожидаемо: из-за того, что мы подстраиваемся под текущий битрейт пользователя и улучшаем качество видео, банально увеличивается размер файла с контентом. Чем больше файл, тем дольше он скачивается и запускается, поэтому после релиза фичи на запуск контента мы стали тратить на 141 мс больше. Теперь это наша новая точка роста, и мы и уже работаем над функциями, которые позволят нам сократить время между нажатием кнопки «Смотреть» и показом первого кадра.
Что касается Android TV, доля сессий с максимальным стартовым качеством (Full HD 1080p) улучшилась еще значительнее — на 1594%. При этом долю сессий с плохим стартовым качеством мы уменьшили на 55%.
На Android TV время с момента нажатия кнопки «Смотреть» до старта воспроизведения тоже немного увеличилось — на 168 мс. Впрочем, как и с Android Mobile, мы планируем в ближайшее время нивелировать это увеличение запуском новой фичи.
Из-за технических особенностей функция пока доступна только на мобильных устройствах на базе Android и на Android TV. Но мы планируем разрабатывать и реализовывать подобную механику и на iOS.
На этом все. Спасибо, что читали! Если есть вопросы, обязательно пишите в комментариях. На все ответим!