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

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.

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

,

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 .

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

Приложение приемника инициализирует сеанс актеров и будет стоять до тех пор, пока не появится запрос на загрузку (другими словами, команда воспроизвести кусок носителя) от отправителя не появится.

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

index.html

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

приемник

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

7. базовый актерский приемник

Базовый актерский приемник инициализирует актеров при запуске. Это необходимо, чтобы сообщить всем приложениям подключенных отправителей, что поднятие получателя было успешным. Кроме того, новый 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 , вашу основную точку входа на весь приемник SDK
  • Хранив ссылку на PlayerManager , воспроизведение обработки объектов и предоставление вам всех крючков, необходимых для подключения собственной собственной логики
  • Инициализация SDK, вызывая start() на CastReceiverContext

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

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

context.start();

8. Casting "Basic" видеоконтента

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

Укажите свой веб -браузер на инструмент команды и управления (CAC) .

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

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

Кастинг СМИ

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

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

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

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

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

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

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

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

Итак, за рубежом SDK-получателя:

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

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

9. Интегрируйте с внешним API

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

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

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

Добавьте следующий код в свой файл js/receiver.js , непосредственно перед Call to 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 Content

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

...
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 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. Оптимизация для интеллектуальных дисплеев

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

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

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

  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

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

Объект управления пользовательским интерфейсом также определяет, отображается ли ControlsButton или не основан на MediaStatus.supportedMediaCommands .

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

Изображение Media Player Controls: Bar Bar, кнопка «Play», «Пропустить вперед» и «Пропустить кнопки назад»

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

Изображение Media Player Controls: Bar Prographing, кнопка «Play», кнопки «Skip Worthing» и «Skip Backward» и «Кнопки« queue »и« queue next ».

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

Изображение Media Player Controls: Bar Bar, кнопка «Play» и «queue»

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

Изображение Media Player Controls: Bar Bar, «Play», кнопка «пропустить вперед» и «Пропустить кнопки назад», «Очередь предыдущая» и «Следующая очередь», и кнопки «Закрытая подпись» включено

Чтобы динамически изменить значение 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 Spearse - это функция приемника CAF, которая позволяет пользователям изучать дополнительный контент на сенсорных устройствах. Чтобы реализовать это, вы будете использовать PlayerDataBinder для установки пользовательского интерфейса BrowseContent . Затем вы можете заполнить его BrowseItems на основе контента, который вы хотите отобразить.

Browsecontent

Ниже приведен пример пользовательского интерфейса BrowseContent и его свойства:

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

  1. BrowseContent.title
  2. BrowseContent.items

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

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

Rowseitem

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

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

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

Установить данные об просмотре СМИ

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

// 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);
  });

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

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 предоставляет разработчикам еще один вариант для легко отладка приложений приемника, используя API Castdebuglogger и инструмент Companion Command и Control (CAC) для захвата журналов.

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

Чтобы включить API, добавьте сценарий источника CastDebugLogger в свой файл index.html. Источник должен быть объявлен в теге <Head> после объявления 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 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 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. Используйте 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.

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