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

1. Обзор

Логотип Google Cast

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

Что такое Google Cast?

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

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

Контрольный список 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 Hosting или ngrok .

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

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

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

4. Зарегистрируйте приложение в Cast Developer Console.

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

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

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

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

Выберите «Пользовательский приемник», это то, что мы создаем.

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

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

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

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

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

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

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

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

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

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

Логотип Google Chrome

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

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

Изображение вкладки «Cast Connect & Logger Controls» инструмента Command and Control (CaC)

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

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

  1. Перейдите на вкладку «Загрузить носитель» вверху.

Изображение вкладки «Загрузить носитель» инструмента Command and Control (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. Кастинг «базового» видеоконтента

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

Откройте в веб-браузере Command and Control (CaC) Tool .

Изображение вкладки «Cast Connect & Logger Controls» инструмента Command and Control (CaC)

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

Кастинг СМИ

На высоком уровне для воспроизведения мультимедиа на устройстве 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» инструмента Command and Control (CaC), показывающее, что оно подключено к приложению Receiver.

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

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

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

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

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

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

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

Перехватить запрос 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 на наш медиафайл.

Изображение вкладки «Загрузить носитель» инструмента Command and Control (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 объект UI Controls для Smart Displays будет отображаться, как в примере ниже.

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

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

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

Когда значение 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 поддерживает три соотношения сторон: SQUARE_1_TO_1 , PORTRAIT_2_TO_3 , LANDSCAPE_16_TO_9 .

BrowseItem

Используйте 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 , чтобы удалить пользовательский интерфейс Media Browse.

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

Cast Receiver SDK предоставляет разработчикам еще один вариант простой отладки приложений-приемников с помощью CastDebugLogger API и сопутствующего инструмента Command and Control (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 вы можете легко регистрировать события игрока, которые запускаются 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
}

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

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

  • 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.

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