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

1. Обзор

Логотип Google Cast

В этой лаборатории кода вы узнаете, как создать приложение Custom Web Receiver для воспроизведения контента на устройствах с поддержкой Cast .

Что такое Google Cast?

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

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

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

Что мы собираемся строить?

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

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

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

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

  • Новейший браузер Google Chrome .
  • Служба хостинга HTTPS, например Firebase Hosting или ngrok .
  • Устройство Google Cast, например Chromecast или Android TV, с доступом в Интернет.
  • Телевизор или монитор с входом HDMI.

Опыт

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

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

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

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

Новичок Средний Опытный

Как бы вы оценили свои впечатления от просмотра телевидения?

Новичок Средний Опытный

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

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

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

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

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

Если у вас нет доступного сервера, вы можете использовать хостинг Firebase или 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 минут, прежде чем ваш приемник и устройство будут готовы к тестированию. Подождав 5–15 минут, необходимо перезагрузить устройство Cast.

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

Логотип Google Chrome

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

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

Изображение вкладки «Элементы управления Cast Connect & Logger» инструмента управления и контроля (CaC)

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

Изображение вкладки «Cast Connect & Logger Controls» инструмента управления и контроля (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 и будет находиться в режиме ожидания до тех пор, пока не поступит запрос LOAD (другими словами, команда на воспроизведение фрагмента мультимедиа) от отправителя.

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

index.html

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

приемник.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 приемника место для вызова пользовательского интерфейса приемника по умолчанию, который поставляется вместе со сценарием, который вы только что добавили.

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

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

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

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

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

context.start();

8. Кастинг «базового» видеоконтента

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

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

Изображение вкладки «Элементы управления Cast Connect & Logger» инструмента управления и контроля (CaC)

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

Кастинг СМИ

На высоком уровне для воспроизведения мультимедиа на устройстве Cast должно произойти следующее:

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

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

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

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

Изображение вкладки «Cast Connect & Logger Controls» инструмента управления и контроля (CaC), показывающее, что оно подключено к приложению-приемнику.

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

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

Итак, в стандартной комплектации Receiver SDK обрабатывает:

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

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

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

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

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

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

Эта функциональность в основном реализована в методе PlayerManager setMessageInterceptor() . Это позволяет перехватывать входящие сообщения по типу и изменять их до того, как они достигнут внутреннего обработчика сообщений 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 .

Перехватить запрос 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.

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

Теперь, когда мы подготовили перехватчик нагрузки, мы укажем тип контента получателю. Эта информация предоставит получателю 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, перейдите к следующему шагу.

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

Пример 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) и установите идентификатор приложения на идентификатор приложения вашего ресивера. Выберите свое устройство с помощью кнопки Cast.

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

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

Предполагая, что с вашими изменениями в приемнике все работает нормально, перехватчик должен позаботиться о преобразовании объекта MediaInfo во что-то, что SDK может воспроизводить на экране.

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

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

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

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

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

Доступ к объекту элементов управления пользовательского интерфейса для интеллектуальных дисплеев можно получить с помощью 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 объект элементов управления пользовательского интерфейса для интеллектуальных дисплеев будет отображаться, как показано в примере ниже.

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

  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 объект элементов управления пользовательского интерфейса для интеллектуальных дисплеев будет отображаться, как показано ниже:

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

  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 , макет элемента управления по умолчанию будет отображаться, как показано ниже:

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

Когда значение supportMediaCommands равно 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, на котором показаны две миниатюры видео и часть третьей.

  1. BrowseContent.title
  2. BrowseContent.items

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

Используйте targetAspectRatio property , чтобы выбрать наилучшее соотношение сторон для ваших изображений. SDK CAF Receiver SDK поддерживает три соотношения сторон: 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. Отладка приложений-приемников

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

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

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

<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 вы можете легко регистрировать события игрока, которые запускаются CAF Receiver SDK, и использовать различные уровни регистрации для регистрации данных событий. Конфигурация 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 будет отображать все сообщения, добавленные с сообщениями об ошибках, предупреждениями, информацией и отладкой. Включение пользовательского тега с уровнем WARNING будет отображать только сообщения об ошибках и предупреждения.

Конфигурация 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 Debug Logger обеспечивает наложение отладки на приемнике для отображения ваших пользовательских сообщений журнала на устройстве трансляции. Используйте 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. Поздравления

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

Более подробную информацию см. в руководстве разработчика веб-приемника .