Создайте собственный веб-приемник

1. Обзор

логотип Google Cast

В этом практическом занятии вы научитесь создавать пользовательское веб-приложение для воспроизведения контента на устройствах с поддержкой Cast .

Что такое Google Cast?

Google Cast позволяет пользователям транслировать контент с мобильного устройства на телевизор. Затем пользователи могут использовать свое мобильное устройство или браузер Chrome на компьютере в качестве пульта дистанционного управления для воспроизведения мультимедиа на телевизоре.

SDK Google Cast позволяет вашему приложению управлять устройствами с поддержкой Google Cast (например, телевизором или звуковой системой). SDK Cast предоставляет необходимые компоненты пользовательского интерфейса в соответствии с контрольным списком дизайна Google Cast .

Контрольный список по дизайну Google Cast предназначен для того, чтобы сделать взаимодействие с Cast простым и предсказуемым на всех поддерживаемых платформах. Подробнее см. здесь.

Что мы будем строить?

После завершения этого практического занятия у вас будет HTML5-приложение, которое будет выступать в качестве вашего собственного пользовательского приемника, способного отображать видеоконтент на устройствах с поддержкой Cast.

Что вы узнаете

  • Как подготовиться к разработке приемника.
  • Основы работы приемника с поддержкой Cast на основе платформы Cast Application Framework.
  • Как получить видео, снятое на заказ.
  • Как интегрировать отладочный логгер.
  • Как оптимизировать ресивер для работы со смарт-дисплеями.

Что вам понадобится

  • Последняя версия браузера Google Chrome .
  • HTTPS-хостинг, например, Firebase Hosting или ngrok .
  • Устройство Google Cast, такое как Chromecast или Android TV, с подключением к интернету.
  • Телевизор или монитор с HDMI-входом.

Опыт

  • Вам потребуются предварительные знания в области веб-разработки.
  • Вам также понадобятся предварительные знания о просмотре телевизора :)

Как вы будете использовать этот учебный материал?

Прочитайте только от начала до конца. Прочитайте текст и выполните упражнения.

Как бы вы оценили свой опыт в разработке веб-приложений?

Новичок Средний Профессионал

Как бы вы оценили свой опыт просмотра телевизора?

Новичок Средний Профессионал

2. Получите пример кода.

Вы можете загрузить весь примерный код на свой компьютер...

и распакуйте загруженный zip-файл.

3. Локальное развертывание приемника

Для использования веб-ресивера с устройством Cast необходимо, чтобы он размещался в месте, доступном для вашего устройства Cast. Если у вас уже есть сервер, поддерживающий HTTPS, пропустите следующие инструкции и запишите URL-адрес , так как он понадобится вам в следующем разделе.

Если у вас нет доступного сервера, вы можете использовать Firebase Hosting или ngrok .

Запустите сервер

После того, как вы настроили выбранную вами службу, перейдите в app-start и запустите сервер.

Запишите URL-адрес вашего размещенного ресивера. Он понадобится вам в следующем разделе.

4. Зарегистрируйте приложение в консоли разработчика Cast.

Для запуска пользовательского приемника, созданного в этом практическом задании, на устройствах Chromecast необходимо зарегистрировать ваше приложение . После регистрации приложения вы получите идентификатор приложения, который ваше приложение-отправитель должно использовать для выполнения вызовов API, например, для запуска приложения-приемника.

Изображение консоли разработчика Google Cast SDK с выделенной кнопкой «Добавить новое приложение».

Нажмите «Добавить новое приложение».

Изображение экрана «Новое приложение для приемника» с выделенной опцией «Пользовательский приемник».

Выберите "Пользовательский приемник", именно его мы и создаем.

Изображение экрана «Создать новый пользовательский приемник», показывающее URL-адрес, который пользователь вводит в поле «URL-адрес приложения-приемника».

Введите данные вашего нового приемника, обязательно используйте полученный вами URL-адрес.

в последнем разделе. Запишите идентификатор приложения, присвоенный вашему новому приемнику.

Перед публикацией приложения необходимо также зарегистрировать устройство Google Cast, чтобы оно могло получить к нему доступ. После публикации приложение станет доступно для всех устройств Google Cast. Для целей данного практического занятия рекомендуется работать с неопубликованным приложением.

Изображение консоли разработчика Google Cast SDK с выделенной кнопкой «Добавить новое устройство».

Нажмите «Добавить новое устройство».

Изображение диалогового окна «Добавить устройство приема Cast».

Введите серийный номер, напечатанный на задней панели вашего устройства Cast, и присвойте ему описательное имя. Вы также можете найти свой серийный номер, транслируя экран в Chrome через консоль разработчика Google Cast SDK.

Для подготовки ресивера и устройства к тестированию потребуется от 5 до 15 минут. После этого необходимо перезагрузить устройство Cast.

5. Запустите демонстрационное приложение.

логотип Google Chrome

Пока мы ждём, когда наше новое приложение-приёмник будет готово к тестированию, давайте посмотрим, как выглядит пример готового приложения-приёмника. Приёмник, который мы собираемся создать, сможет воспроизводить медиаконтент с использованием адаптивной потоковой передачи с переменным битрейтом (мы будем использовать пример контента, закодированного для динамической адаптивной потоковой передачи по HTTP (DASH)).

Откройте в браузере инструмент управления и контроля (CaC) .

Изображение вкладки «Управление подключением и регистрацией данных» инструмента управления и контроля (CaC).

  1. Вам следует ознакомиться с нашим инструментом CaC.
  2. Используйте идентификатор приемника по умолчанию "CC1AD845" и нажмите кнопку "Установить идентификатор приложения".
  3. Нажмите кнопку «Трансляция» в левом верхнем углу и выберите ваше устройство Google Cast.

Изображение вкладки «Управление подключением и регистрацией данных» инструмента управления и контроля (CaC), указывающее на подключение к приложению приемника.

  1. Перейдите на вкладку "Загрузить медиафайлы" вверху страницы.

Изображение вкладки «Загрузка носителя» инструмента управления и контроля (CaC).

  1. Нажмите кнопку "Загрузить по содержимому", чтобы воспроизвести пример видео.
  2. Видео начнет воспроизводиться на вашем устройстве Google Cast, демонстрируя основные функции приемника при использовании стандартного приемника.

6. Подготовьте стартовый проект.

Нам необходимо добавить поддержку Google Cast в загруженное вами стартовое приложение. Вот некоторые термины, связанные с Google Cast, которые мы будем использовать в этом практическом занятии:

  • Приложение отправителя работает на мобильном устройстве или ноутбуке.
  • Приложение- приемник работает на устройстве Google Cast.

Теперь вы готовы продолжить работу над стартовым проектом, используя свой любимый текстовый редактор:

  1. Выберите значок папки Каталог app-start из загруженного вами примера кода.
  2. Откройте js/receiver.js и index.html

Обратите внимание, что во время выполнения этого практического задания http-server должен отслеживать внесенные вами изменения. Если вы этого не замечаете, попробуйте завершить процесс и перезапустить http-server .

Дизайн приложений

Приложение-приемник инициализирует сессию Cast и будет находиться в режиме ожидания до получения запроса на загрузку (то есть команды на воспроизведение медиафайла) от отправителя.

Приложение состоит из одного основного представления, определенного в index.html , и одного файла JavaScript под названием js/receiver.js , содержащего всю логику, необходимую для работы нашего приемника.

index.html

Этот HTML-файл будет содержать пользовательский интерфейс нашего приложения-приемника. Пока он пуст, и мы будем добавлять в него информацию на протяжении всего практического занятия по программированию.

receiver.js

Этот скрипт будет управлять всей логикой нашего приложения-приемника. Сейчас это просто пустой файл, но в следующем разделе мы превратим его в полноценный приемник Cast всего несколькими строками кода.

7. Базовый приемник Cast

Базовый приемник Cast инициализирует сессию Cast при запуске. Это необходимо для того, чтобы сообщить всем подключенным приложениям-отправителям об успешном запуске приемника. Кроме того, новый SDK поставляется с предустановленной поддержкой потоковой передачи мультимедиа с адаптивным битрейтом (с использованием DASH, HLS и Smooth Streaming) и обычных файлов MP4. Давайте попробуем это проверить.

Инициализация

Добавьте следующий код в заголовок index.html :

<head>
  ...

  <script src="//www.gstatic.com/cast/sdk/libs/caf_receiver/v3/cast_receiver_framework.js"></script>
</head>

Добавьте следующий код в index.html <body> перед footer> загружающим receiver.js, чтобы предоставить SDK Receiver место для отображения стандартного пользовательского интерфейса Receiver, который поставляется вместе с только что добавленным скриптом.

<cast-media-player></cast-media-player>

Теперь нам нужно инициализировать SDK в js/receiver.js , который состоит из следующих компонентов:

  • Получение ссылки на CastReceiverContext , вашу основную точку входа во весь SDK Receiver.
  • Сохранение ссылки на PlayerManager , объект, обрабатывающий воспроизведение, и предоставление всех необходимых инструментов для подключения собственной пользовательской логики.
  • Инициализация SDK осуществляется путем вызова метода start() для CastReceiverContext

Добавьте следующий код в js/receiver.js .

const context = cast.framework.CastReceiverContext.getInstance();
const playerManager = context.getPlayerManager();

context.start();

8. Трансляция «базового» видеоконтента.

Для выполнения этого практического задания используйте инструмент CaC Tool, чтобы протестировать свой новый приемник.

Откройте в веб-браузере инструмент управления и контроля (CaC) .

Изображение вкладки «Управление подключением и регистрацией данных» инструмента управления и контроля (CaC).

Обязательно укажите в поле свой собственный идентификатор приложения , зарегистрированный ранее, и нажмите «Установить идентификатор приложения». Это даст указание инструменту использовать ваш приемник при запуске сеанса трансляции.

СМИ для кастинга

В общих чертах, для воспроизведения мультимедиа на устройстве Cast необходимо выполнить следующие действия:

  1. Отправитель создает JSON объект MediaInfo из Cast SDK, который моделирует медиафайл.
  2. Отправитель подключается к устройству Cast для запуска приложения получателя.
  3. Для воспроизведения контента ресивер загружает объект MediaInfo посредством запроса LOAD .
  4. Приёмник отслеживает и контролирует состояние носителя информации.
  5. Отправитель передает получателю команды воспроизведения для управления воспроизведением на основе взаимодействия пользователя с приложением отправителя.

В этой первой простой попытке мы заполним MediaInfo URL-адресом воспроизводимого ресурса (хранящимся в MediaInfo.contentUrl ).

В реальных условиях отправитель использует идентификатор медиафайла, специфичный для приложения, в MediaInfo.contentId . Получатель использует contentId в качестве идентификатора для выполнения соответствующих вызовов API бэкэнда, чтобы определить фактический URL-адрес ресурса и установить его значение равным MediaInfo.contentUrl. Получатель также будет обрабатывать такие задачи, как получение лицензии DRM или внедрение информации о рекламных паузах.

В следующем разделе мы расширим возможности вашего ресивера, чтобы он мог делать нечто подобное. А пока нажмите на значок Cast и выберите ваше устройство, чтобы открыть ресивер.

Изображение вкладки «Управление подключением и регистрацией данных» инструмента управления и контроля (CaC), указывающее на подключение к приложению приемника.

Перейдите на вкладку «Загрузка медиафайлов» и нажмите кнопку «Загрузить по содержимому». Ваш ресивер должен начать воспроизведение демонстрационного контента.

Изображение вкладки «Загрузка носителя» инструмента управления и контроля (CaC).

Таким образом, SDK Receiver по умолчанию обрабатывает следующее:

  • Инициализация сессии Cast
  • Обрабатывать входящие запросы LOAD от отправителей, содержащих воспроизводимые ресурсы.
  • Предоставьте базовый пользовательский интерфейс плеера, готовый к отображению на большом экране.

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

9. Интеграция с внешним API

В соответствии с тем, как большинство разработчиков взаимодействуют со своими Cast Receiver в реальных приложениях, мы собираемся модифицировать наш приемник, чтобы он обрабатывал запросы LOAD , которые ссылаются на нужный медиаконтент по его API-ключу, вместо отправки URL-адреса воспроизводимого ресурса.

Приложения обычно делают это по следующим причинам:

  • Отправитель может не знать URL-адрес содержимого.
  • Приложение Cast предназначено для обработки аутентификации, другой бизнес-логики или вызовов API непосредственно на стороне получателя.

Эта функциональность в основном реализована в методе setMessageInterceptor() PlayerManager . Это позволяет перехватывать входящие сообщения по типу и изменять их до того, как они достигнут внутреннего обработчика сообщений SDK. В этом разделе мы рассматриваем запросы LOAD , где будем выполнять следующие действия:

  • Прочитайте входящий запрос LOAD и его пользовательский contentId .
  • Выполните GET запрос к нашему API, чтобы найти потоковый ресурс по его contentId .
  • Измените запрос LOAD , указав URL-адрес потока.
  • Измените объект MediaInformation , чтобы задать параметры типа потока.
  • Передайте запрос в SDK для воспроизведения или отклоните команду, если нам не удастся найти запрошенный медиафайл.

Представленный пример API демонстрирует возможности SDK по настройке типовых задач обработки данных, при этом в основном используя стандартные функции.

Пример API

Откройте в браузере страницу https://storage.googleapis.com/cpe-sample-media/content.json и ознакомьтесь с нашим каталогом примеров видео. Контент включает URL-адреса для изображений-заставок в формате png, а также потоки DASH и HLS. Потоки DASH и HLS указывают на демультиплексированные видео- и аудиоисточники, хранящиеся во фрагментированных контейнерах mp4.

{
  "bbb": {
    "author": "The Blender Project",
    "description": "Grumpy Bunny is grumpy",
    "poster": "https://[...]/[...]/BigBuckBunny/images/screenshot1.png",
    "stream": {
      "dash": "https://[...]/[...]/BigBuckBunny/BigBuckBunny_master.mpd",
      "hls": "https://[...]/[...]/BigBuckBunny/BigBuckBunny_master.m3u8",
    "title": "Big Buck Bunny"
  },
  "fbb_ad": {
    "author": "Google Inc.",
    "description": "Introducing Chromecast. The easiest way to enjoy [...]",
    "poster": "https://[...]/[...]/ForBiggerBlazes/images/screenshot8.png",
    "stream": {
      "dash": "https://[...]/[...]/ForBiggerBlazes/ForBiggerBlazes.mpd",
      "hls": "https://[...]/[...]/ForBiggerBlazes/ForBiggerBlazes.m3u8",
    "title": "For Bigger Blazes"
  },

  [...]

}

На следующем шаге мы сопоставим ключ каждой записи (например, bbb, fbb_ad ) с URL-адресом потока после того, как получатель получит запрос LOAD .

Перехватите запрос на загрузку.

На этом этапе мы создадим перехватчик загрузки с функцией, которая будет отправлять XHR запрос к размещенному JSON файлу. После получения JSON файла мы проанализируем его содержимое и установим метаданные. В следующих разделах мы настроим параметры MediaInformation , чтобы указать тип содержимого.

Добавьте следующий код в файл js/receiver.js непосредственно перед вызовом context.start() .

function makeRequest (method, url) {
  return new Promise(function (resolve, reject) {
    let xhr = new XMLHttpRequest();
    xhr.open(method, url);
    xhr.onload = function () {
      if (this.status >= 200 && this.status < 300) {
        resolve(JSON.parse(xhr.response));
      } else {
        reject({
          status: this.status,
          statusText: xhr.statusText
        });
      }
    };
    xhr.onerror = function () {
      reject({
        status: this.status,
        statusText: xhr.statusText
      });
    };
    xhr.send();
  });
}

playerManager.setMessageInterceptor(
    cast.framework.messages.MessageType.LOAD,
    request => {
      return new Promise((resolve, reject) => {
        // Fetch content repository by requested contentId
        makeRequest('GET', 'https://storage.googleapis.com/cpe-sample-media/content.json').then(function (data) {
          let item = data[request.media.contentId];
          if(!item) {
            // Content could not be found in repository
            reject();
          } else {
            // Add metadata
            let metadata = new
               cast.framework.messages.GenericMediaMetadata();
            metadata.title = item.title;
            metadata.subtitle = item.author;

            request.media.metadata = metadata;

            // Resolve request
            resolve(request);
          }
        });
      });
    });

В следующем разделе будет описано, как настроить свойство media запроса на загрузку контента DASH.

Использование примера содержимого DASH API

Теперь, когда мы подготовили перехватчик загрузки, мы укажем получателю тип контента. Эта информация предоставит получателю URL-адрес основного плейлиста и MIME-тип потока. Добавьте следующий код в файл js/receiver.js в Promise() перехватчика LOAD :

...
playerManager.setMessageInterceptor(
    cast.framework.messages.MessageType.LOAD,
    request => {
      return new Promise((resolve, reject) => {
          ...
          } else {
            // Adjusting request to make requested content playable
            request.media.contentUrl = item.stream.dash;
            request.media.contentType = 'application/dash+xml';
            ...
          }
        });
      });
    });

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

Использование примера содержимого HLS API

Пример API включает контент HLS, а также DASH. В дополнение к установке contentType , как мы делали на предыдущем шаге, запросу на загрузку потребуются некоторые дополнительные свойства для использования URL-адресов HLS из примера API. Когда приемник настроен на воспроизведение потоков HLS, ожидаемый тип контейнера по умолчанию — транспортный поток (TS). В результате приемник попытается открыть примеры потоков MP4 в формате TS, если изменено только свойство contentUrl . В запросе на загрузку объект MediaInformation должен быть изменен с добавлением дополнительных свойств, чтобы приемник знал, что контент имеет тип MP4, а не TS. Добавьте следующий код в файл js/receiver.js в перехватчик загрузки, чтобы изменить свойства contentUrl и contentType . Дополнительно добавьте свойства HlsSegmentFormat и HlsVideoSegmentFormat .

...
playerManager.setMessageInterceptor(
    cast.framework.messages.MessageType.LOAD,
    request => {
      return new Promise((resolve, reject) => {
          ...
          } else {
            // Adjusting request to make requested content playable
            request.media.contentUrl = item.stream.hls;
            request.media.contentType = 'application/x-mpegurl';
            request.media.hlsSegmentFormat = cast.framework.messages.HlsSegmentFormat.FMP4;
            request.media.hlsVideoSegmentFormat = cast.framework.messages.HlsVideoSegmentFormat.FMP4;
            ...
          }
        });
      });
    });

Проверяю это.

Снова откройте инструмент «Управление и контроль» (CaC) и установите идентификатор приложения (App ID) на идентификатор приложения вашего ресивера. Выберите ваше устройство с помощью кнопки «Трансляция» (Cast).

Перейдите на вкладку «Загрузить медиафайлы». На этот раз удалите текст в поле «URL-адрес контента» рядом с кнопкой «Загрузить по контенту», что заставит наше приложение отправить запрос LOAD содержащий только ссылку contentId , на наши медиафайлы.

Изображение вкладки «Загрузка носителя» инструмента управления и контроля (CaC).

Если ваши модификации приемника работают корректно, то перехватчик должен позаботиться о преобразовании объекта MediaInfo в формат, который SDK сможет воспроизвести на экране.

Нажмите кнопку "Загрузить по содержимому", чтобы проверить, правильно ли воспроизводится ваш медиафайл. Вы можете изменить идентификатор содержимого (Content ID) на другой идентификатор в файле content.json .

10. Оптимизация для интеллектуальных дисплеев

«Умные» дисплеи — это устройства с сенсорным управлением, которые позволяют приложениям-приемникам поддерживать сенсорное управление.

В этом разделе объясняется, как оптимизировать приложение ресивера при запуске на смарт-дисплеях, а также как настроить элементы управления плеером.

Доступ к элементам управления пользовательского интерфейса

Объект UI Controls для Smart Displays доступен по адресу cast.framework.ui.Controls.GetInstance() . Добавьте следующий код в файл js/receiver.js перед context.start() :

...

// Optimizing for smart displays
const touchControls = cast.framework.ui.Controls.getInstance();

context.start();

Если вы не используете элемент <cast-media-player>, вам потребуется установить touchScreenOptimizedApp в CastReceiverOptions . В этом практическом задании мы используем элемент <cast-media-player>.

context.start({ touchScreenOptimizedApp: true });

Кнопки управления по умолчанию назначаются каждому слоту на основе MetadataType и MediaStatus.supportedMediaCommands .

Управление видео

Для MetadataType.MOVIE , MetadataType.TV_SHOW и MetadataType.GENERIC объект UI Controls для интеллектуальных дисплеев будет отображаться, как показано в примере ниже.

Изображение воспроизводимого видео с наложенными поверх него элементами управления пользовательского интерфейса.

  1. --playback-logo-image
  2. MediaMetadata.subtitle
  3. MediaMetadata.title
  4. MediaStatus.currentTime
  5. MediaInformation.duration
  6. ControlsSlot.SLOT_SECONDARY_1 : ControlsButton.QUEUE_PREV
  7. ControlsSlot.SLOT_PRIMARY_1 : ControlsButton.SEEK_BACKWARD_30
  8. PLAY/PAUSE
  9. ControlsSlot.SLOT_PRIMARY_2 : ControlsButton.SEEK_FORWARD_30
  10. ControlsSlot.SLOT_SECONDARY_2 : ControlsButton.QUEUE_NEXT

Регуляторы звука

Для MetadataType.MUSIC_TRACK объект UI Controls для интеллектуальных дисплеев будет отображаться следующим образом:

Изображение воспроизводимой музыки с наложенными поверх него элементами управления пользовательского интерфейса.

  1. --playback-logo-image
  2. MusicTrackMediaMetadata.albumName
  3. MusicTrackMediaMetadata.title
  4. MusicTrackMediaMetadata.albumArtist
  5. MusicTrackMediaMetadata.images[0]
  6. MediaStatus.currentTime
  7. MediaInformation.duration
  8. ControlsSlot.SLOT_SECONDARY_1 : ControlsButton.NO_BUTTON
  9. ControlsSlot.SLOT_PRIMARY_1 : ControlsButton.QUEUE_PREV
  10. PLAY/PAUSE
  11. ControlsSlot.SLOT_PRIMARY_2 : ControlsButton.QUEUE_NEXT
  12. ControlsSlot.SLOT_SECONDARY_2 : ControlsButton.NO_BUTTON

Обновление поддерживаемых команд мультимедиа

Объект UI Controls также определяет, отображается ли ControlsButton или нет, на основе параметра MediaStatus.supportedMediaCommands .

Если значение параметра supportedMediaCommands равно ALL_BASIC_MEDIA , то по умолчанию будет отображаться следующий макет элементов управления:

Изображение элементов управления медиаплеера: индикатор выполнения, кнопка «Воспроизвести», кнопки «Перемотать вперед» и «Перемотать назад» включены.

Если значение параметра supportedMediaCommands равно ALL_BASIC_MEDIA | QUEUE_PREV | QUEUE_NEXT , то по умолчанию будет отображаться следующий макет элементов управления:

Изображение элементов управления медиаплеера: индикатор выполнения, кнопка «Воспроизвести», кнопки «Перемотать вперед» и «Перемотать назад», а также кнопки «Предыдущий» и «Следующий» включены.

Когда значение supportedMediaCommands равно PAUSE | QUEUE_PREV | QUEUE_NEXT , будет отображаться стандартная компоновка элементов управления, как показано ниже:

Изображение элементов управления медиаплеера: индикатор выполнения, кнопка «Воспроизвести», а также кнопки «Предыдущий» и «Следующий» включены.

Если доступны текстовые дорожки, кнопка субтитров всегда будет отображаться в SLOT_1 .

Изображение элементов управления медиаплеера: индикатор выполнения, кнопка «Воспроизвести», кнопки «Перемотать вперед» и «Перемотать назад», кнопки «Предыдущий» и «Следующий», а также кнопки «Субтитры» включены.

Чтобы динамически изменять значение supportedMediaCommands после запуска контекста приемника, можно вызвать PlayerManager.setSupportedMediaCommands для переопределения значения. Также можно добавить новую команду с помощью addSupportedMediaCommands или удалить существующую команду с помощью removeSupportedMediaCommands .

Настройка кнопок управления

Вы можете настроить элементы управления с помощью PlayerDataBinder . Добавьте следующий код в файл js/receiver.js ниже элемента touchControls, чтобы задать первый слот для ваших элементов управления:

...

// Optimizing for smart displays
const touchControls = cast.framework.ui.Controls.getInstance();
const playerData = new cast.framework.ui.PlayerData();
const playerDataBinder = new cast.framework.ui.PlayerDataBinder(playerData);

playerDataBinder.addEventListener(
  cast.framework.ui.PlayerDataEventType.MEDIA_CHANGED,
  (e) => {
    if (!e.value) return;

    // Clear default buttons and re-assign
    touchControls.clearDefaultSlotAssignments();
    touchControls.assignButton(
      cast.framework.ui.ControlsSlot.SLOT_PRIMARY_1,
      cast.framework.ui.ControlsButton.SEEK_BACKWARD_30
    );
  });

context.start();

11. Реализация просмотра медиафайлов на смарт-дисплеях

Функция Media Browse в CAF Receiver позволяет пользователям просматривать дополнительный контент на сенсорных устройствах. Для её реализации необходимо использовать PlayerDataBinder для настройки пользовательского интерфейса BrowseContent . Затем его можно заполнить объектами BrowseItems в зависимости от контента, который вы хотите отобразить.

BrowseContent

Ниже приведён пример интерфейса BrowseContent и его свойств:

Изображение интерфейса BrowseContent, демонстрирующее два миниатюрных изображения видео и часть третьего.

  1. BrowseContent.title
  2. BrowseContent.items

Соотношение сторон

Используйте targetAspectRatio property , чтобы выбрать оптимальное соотношение сторон для ваших изображений. SDK CAF Receiver поддерживает три соотношения сторон: SQUARE_1_TO_1 , PORTRAIT_2_TO_3 , LANDSCAPE_16_TO_9 .

Просмотреть товар

Используйте BrowseItem для отображения заголовка, подзаголовка, продолжительности и изображения для каждого элемента:

Изображение интерфейса BrowseContent, демонстрирующее два миниатюрных изображения видео и часть третьего.

  1. BrowseItem.image
  2. BrowseItem.duration
  3. BrowseItem.title
  4. BrowseItem.subtitle

Установить медиафайлы. Просмотреть данные.

Вы можете предоставить список медиаконтента для просмотра, вызвав метод setBrowseContent . Добавьте следующий код в файл js/receiver.js ниже вашего playerDataBinder и в обработчик события MEDIA_CHANGED чтобы установить для элементов просмотра заголовок "Далее".

// Optimizing for smart displays
const touchControls = cast.framework.ui.Controls.getInstance();
const playerData = new cast.framework.ui.PlayerData();
const playerDataBinder = new cast.framework.ui.PlayerDataBinder(playerData);

...

let browseItems = getBrowseItems();

function getBrowseItems() {
  let browseItems = [];
  makeRequest('GET', 'https://storage.googleapis.com/cpe-sample-media/content.json')
  .then(function (data) {
    for (let key in data) {
      let item = new cast.framework.ui.BrowseItem();
      item.entity = key;
      item.title = data[key].title;
      item.subtitle = data[key].description;
      item.image = new cast.framework.messages.Image(data[key].poster);
      item.imageType = cast.framework.ui.BrowseImageType.MOVIE;
      browseItems.push(item);
    }
  });
  return browseItems;
}

let browseContent = new cast.framework.ui.BrowseContent();
browseContent.title = 'Up Next';
browseContent.items = browseItems;
browseContent.targetAspectRatio = cast.framework.ui.BrowseImageAspectRatio.LANDSCAPE_16_TO_9;

playerDataBinder.addEventListener(
  cast.framework.ui.PlayerDataEventType.MEDIA_CHANGED,
  (e) => {
    if (!e.value) return;

    ....

    // Media browse
    touchControls.setBrowseContent(browseContent);
  });

Нажатие на элемент медиафайла в меню просмотра запускает перехватчик LOAD . Добавьте следующий код в ваш перехватчик LOAD , чтобы сопоставить request.media.contentId с request.media.entity из элемента медиафайла в меню просмотра:

playerManager.setMessageInterceptor(
    cast.framework.messages.MessageType.LOAD,
    request => {
      ...

      // Map contentId to entity
      if (request.media && request.media.entity) {
        request.media.contentId = request.media.entity;
      }

      return new Promise((resolve, reject) => {
            ...
        });
    });

Также можно установить для объекта BrowseContent значение null , чтобы удалить интерфейс просмотра медиафайлов.

12. Отладка приложений-приемников

SDK Cast Receiver предоставляет разработчикам еще один способ упростить отладку приложений-приемников, используя API CastDebugLogger и сопутствующий инструмент управления и контроля (CaC) для сбора логов.

Инициализация

Для интеграции API добавьте исходный скрипт CastDebugLogger в файл index.html. Исходный код должен быть указан в теге <head> после объявления SDK Cast Receiver.

<head>
  ...
  <script src="//www.gstatic.com/cast/sdk/libs/caf_receiver/v3/cast_receiver_framework.js"></script>
  <!-- Cast Debug Logger -->
  <script src="//www.gstatic.com/cast/sdk/libs/devtools/debug_layer/caf_receiver_logger.js"></script>
</head>

В файле js/receiver.js в самом начале и под разделом playerManager , добавьте следующий код для получения экземпляра CastDebugLogger и включения логгера:

const context = cast.framework.CastReceiverContext.getInstance();
const playerManager = context.getPlayerManager();

// Debug Logger
const castDebugLogger = cast.debug.CastDebugLogger.getInstance();
const LOG_TAG = 'MyAPP.LOG';

// Enable debug logger and show a 'DEBUG MODE' overlay at top left corner.
context.addEventListener(cast.framework.system.EventType.READY, () => {
  if (!castDebugLogger.debugOverlayElement_) {
      castDebugLogger.setEnabled(true);
  }
});

Когда включен отладочный логгер, на приемнике отобразится всплывающее окно с надписью DEBUG MODE .

Изображение воспроизводимого видео с сообщением «РЕЖИМ ОТЛАДКИ», отображаемым на красном фоне в верхнем левом углу кадра.

Запись событий игрока в журнал

С помощью CastDebugLogger вы можете легко регистрировать события игрока, генерируемые SDK CAF Receiver, и использовать разные уровни логирования для записи данных событий. В конфигурации loggerLevelByEvents параметры cast.framework.events.EventType и cast.framework.events.category указывают, какие события будут регистрироваться.

Добавьте следующий код ниже объявления castDebugLogger , чтобы регистрировать события CORE плеера или передачу изменения mediaStatus :

// Debug Logger
const castDebugLogger = cast.debug.CastDebugLogger.getInstance();

// Enable debug logger and show a 'DEBUG MODE' overlay at top left corner.
context.addEventListener(cast.framework.system.EventType.READY, () => {
  if (!castDebugLogger.debugOverlayElement_) {
      castDebugLogger.setEnabled(true);
  }
});

// Set verbosity level for Core events.
castDebugLogger.loggerLevelByEvents = {
  'cast.framework.events.category.CORE': cast.framework.LoggerLevel.INFO,
  'cast.framework.events.EventType.MEDIA_STATUS': cast.framework.LoggerLevel.DEBUG
}

Сообщения журнала и пользовательские теги

API CastDebugLogger позволяет создавать сообщения журнала, которые отображаются на отладочном экране приемника разными цветами. Доступны следующие методы логирования, перечисленные в порядке от наивысшего к наинизшему приоритету:

  • castDebugLogger.error(custom_tag, message);
  • castDebugLogger.warn(custom_tag, message);
  • castDebugLogger.info(custom_tag, message);
  • castDebugLogger.debug(custom_tag, message);

Для каждого метода логирования первым параметром является пользовательский тег. Это может быть любая идентифицирующая строка, которую вы сочтете значимой. CastDebugLogger использует теги для фильтрации логов. Использование тегов подробно описано ниже. Вторым параметром является сообщение лога .

Чтобы продемонстрировать работу логов, добавьте логи в ваш перехватчик LOAD .

playerManager.setMessageInterceptor(
  cast.framework.messages.MessageType.LOAD,
  request => {
    castDebugLogger.info(LOG_TAG, 'Intercepting LOAD request');

    // Map contentId to entity
    if (request.media && request.media.entity) {
      request.media.contentId = request.media.entity;
    }

    return new Promise((resolve, reject) => {
      // Fetch content repository by requested contentId
      makeRequest('GET', 'https://storage.googleapis.com/cpe-sample-media/content.json')
        .then(function (data) {
          let item = data[request.media.contentId];
          if(!item) {
            // Content could not be found in repository
            castDebugLogger.error(LOG_TAG, 'Content not found');
            reject();
          } else {
            // Adjusting request to make requested content playable
            request.media.contentUrl = item.stream.dash;
            request.media.contentType = 'application/dash+xml';
            castDebugLogger.warn(LOG_TAG, 'Playable URL:', request.media.contentUrl);

            // Add metadata
            let metadata = new cast.framework.messages.MovieMediaMetadata();
            metadata.metadataType = cast.framework.messages.MetadataType.MOVIE;
            metadata.title = item.title;
            metadata.subtitle = item.author;

            request.media.metadata = metadata;

            // Resolve request
            resolve(request);
          }
      });
    });
  });

Вы можете управлять тем, какие сообщения отображаются в отладочном окне, устанавливая уровень логирования в параметре loggerLevelByTags для каждого пользовательского тега. Например, включение пользовательского тега с уровнем логирования cast.framework.LoggerLevel.DEBUG отобразит все сообщения, добавленные с помощью error, warn, info и debug. Включение пользовательского тега с уровнем WARNING отобразит только сообщения error и warn.

Параметр loggerLevelByTags является необязательным. Если для уровня логирования не указан пользовательский тег, все сообщения журнала будут отображаться в отладочном окне.

Добавьте следующий код ниже регистратора событий CORE :

// Set verbosity level for Core events.
castDebugLogger.loggerLevelByEvents = {
  'cast.framework.events.category.CORE': cast.framework.LoggerLevel.INFO,
  'cast.framework.events.EventType.MEDIA_STATUS': cast.framework.LoggerLevel.DEBUG
}

// Set verbosity level for custom tags.
castDebugLogger.loggerLevelByTags = {
    [LOG_TAG]: cast.framework.LoggerLevel.DEBUG,
};

Отладочное наложение

Отладочный логгер Cast предоставляет на приемнике отладочное наложение для отображения пользовательских сообщений журнала на устройстве Cast. Используйте showDebugLogs для переключения отладочного наложения и clearDebugLogs для очистки сообщений журнала в наложении.

Добавьте следующий код, чтобы просмотреть отладочное наложение на вашем приемнике.

context.addEventListener(cast.framework.system.EventType.READY, () => {
  if (!castDebugLogger.debugOverlayElement_) {
      // Enable debug logger and show a 'DEBUG MODE' overlay at top left corner.
      castDebugLogger.setEnabled(true);

      // Show debug overlay
      castDebugLogger.showDebugLogs(true);

      // Clear log messages on debug overlay
      castDebugLogger.clearDebugLogs();
  }
});

Изображение, демонстрирующее отладочное наложение: список отладочных сообщений журнала на полупрозрачном фоне поверх видеокадра.

13. Поздравляем!

Теперь вы знаете, как создать пользовательское приложение веб-приемника с помощью SDK Cast Web Receiver.

Для получения более подробной информации см. руководство разработчика Web Receiver .