向 Web Sender 应用添加高级功能

广告插播时间点

Web 发送端 SDK 支持在给定媒体串流中播放广告插播时间点和随播广告。

如需详细了解广告插播时间点的运作方式,请参阅 Web 接收器广告插播时间点概览。

虽然可以在发送端和接收端上指定广告插播时间点,但建议在 Web 接收端和 Android TV 接收端上指定,以便在各个平台上保持一致的行为。

在 Web 上,使用 BreakClip 和 Break 在加载命令中指定广告插播时间点:

let breakClip1 = new BreakClip('bc0');
breakClip1.title = 'Clip title'
breakClip1.posterUrl = 'https://www.some.url';
breakClip1.duration = 60;
breakClip.whenSKippable = 5;

let breakClip2 = ...
let breakClip3 = ...

let break1 = new Break('b0', ['bc0', 'bc1', 'bc2'], 10);

let mediaInfo = new chrome.cast.media.MediaInfo(<contentId>, '<contentType');
...
mediaInfo.breakClips = [breakClip1, breakClip2, breakClip3];
mediaInfo.breaks = [break1];

let request = new chrome.cast.media.LoadRequest(mediaInfo);

cast.framework.CastContext.getInstance().getCurrentSession().loadMedia(request)

使用 Tracks API

轨道可以是文本(字幕或说明字幕)对象,也可以是音频或视频流对象。借助 Tracks API,您可以在应用中使用这些对象。

Track 对象表示 SDK 中的轨道。您可以配置轨道并为其分配唯一 ID,如下所示:

var englishSubtitle = new chrome.cast.media.Track(1, // track ID
  chrome.cast.media.TrackType.TEXT);
englishSubtitle.trackContentId = 'https://some-url/caption_en.vtt';
englishSubtitle.trackContentType = 'text/vtt';
englishSubtitle.subtype = chrome.cast.media.TextTrackType.SUBTITLES;
englishSubtitle.name = 'English Subtitles';
englishSubtitle.language = 'en-US';
englishSubtitle.customData = null;

var frenchSubtitle = new chrome.cast.media.Track(2, // track ID
  chrome.cast.media.TrackType.TEXT);
frenchSubtitle.trackContentId = 'https://some-url/caption_fr.vtt';
frenchSubtitle.trackContentType = 'text/vtt';
frenchSubtitle.subtype = chrome.cast.media.TextTrackType.SUBTITLES;
frenchSubtitle.name = 'French Subtitles';
frenchSubtitle.language = 'fr';
frenchSubtitle.customData = null;

var frenchAudio = new chrome.cast.media.Track(3, // track ID
  chrome.cast.media.TrackType.AUDIO);
frenchAudio.trackContentId = 'trk0001';
frenchAudio.trackContentType = 'audio/mp3';
frenchAudio.subtype = null;
frenchAudio.name = 'French Audio';
frenchAudio.language = 'fr';
frenchAudio.customData = null;

一个媒体文件可能有多个轨道;例如,它可能有多个字幕(每个字幕对应一种不同的语言)或多个备用音频串流(对应不同的语言)。

MediaInfo 是对媒体文件进行建模的类。如需将 Track 对象的集合与媒体文件相关联,请更新其 tracks 属性。在将媒体加载到接收器之前,需要建立此关联:

var tracks = [englishSubtitle, frenchSubtitle, frenchAudio];
var mediaInfo = new chrome.cast.media.MediaInfo(mediaURL);
mediaInfo.contentType = 'video/mp4';
mediaInfo.metadata = new chrome.cast.media.GenericMediaMetadata();
mediaInfo.customData = null;
mediaInfo.streamType = chrome.cast.media.StreamType.BUFFERED;
mediaInfo.textTrackStyle = new chrome.cast.media.TextTrackStyle();
mediaInfo.duration = null;
mediaInfo.tracks = tracks;

您可以在媒体 activeTrackIds 请求中设置活动轨道。

您还可以在媒体加载后,通过调用 EditTracksInfoRequest(opt_activeTrackIds, opt_textTrackStyle) 并传递要在 opt_activeTrackIds 中激活的曲目的 ID,来激活与媒体文件相关联的一个或多个曲目。请注意,这两个参数都是可选的,您可以自行决定设置哪些参数(有效轨道或样式)。例如,以下是启用法语字幕 (2) 和法语音频 (3) 的方法:

var activeTrackIds = [2, 3];
var tracksInfoRequest = new chrome.cast.media.EditTracksInfoRequest(activeTrackIds);
media.editTracksInfo(tracksInfoRequest, successCallback, errorCallback);

如需从当前媒体中移除所有音频或视频轨道,只需设置 mediaInfo.tracks=null(空数组)并重新加载媒体即可。

如需从当前媒体中移除所有文本轨道(例如关闭字幕),请执行以下操作之一:

  • 更新 var activeTrackIds = [2, 3];(如上所示),使其仅包含 [3](即音轨)。
  • 只需设置 mediaInfo.tracks=null。请注意,无需重新加载媒体即可关闭文字字幕 (track.hidden)。发送不包含先前启用的 trackId 的 activeTracksId 数组会停用文字轨道。

设置文本轨道样式

TextTrackStyle 是封装文本轨道样式信息的对象。创建或更新现有 TextTrackStyle 对象后,您可以通过调用其 editTrackInfo 方法将其应用于当前播放的媒体文件,如下所示:

var textTrackStyle = new chrome.cast.media.TextTrackStyle();
var tracksInfoRequest = new chrome.cast.media.EditTracksInfoRequest(textTrackStyle);
media.editTracksInfo(tracksInfoRequest, successCallback, errorCallback);

您可以通过回调结果(成功或错误)跟踪请求的状态,并相应地更新原始发送方。

应用应允许用户使用系统或应用本身提供的设置来更新文本轨道的样式。

您可以为以下文本轨道样式元素设置样式:

  • 前景色(文本颜色)和不透明度
  • 背景颜色和不透明度
  • 边缘类型
  • 边缘颜色
  • 字体缩放
  • 字体系列
  • 字体样式

例如,将文本颜色设置为不透明度为 75% 的红色,如下所示:

var textTrackStyle = new chrome.cast.media.TextTrackStyle();
textTrackStyle.foregroundColor = '#80FF0000';

音量控制

您可以使用 RemotePlayer 和 RemotePlayerController 设置接收器音量。

function changeVolume(newVolume) {
  player.volumeLevel = newVolume;
  playerController.setVolumeLevel();
  // Update sender UI to reflect change
}

发送端应用应遵循以下音量控制准则:

  • 发送器应用必须与接收器同步,以便发送器界面始终根据接收器报告音量。使用 RemotePlayerEventType.VOLUME_LEVEL_CHANGED 和 RemotePlayerEventType.IS_MUTED_CHANGED 回调来保持发送端上的音量。如需了解详情,请参阅状态更新。
  • 当应用在接收端加载时,发送端应用不得将音量设置为特定的预定义音量,也不得将音量设置为发送端设备的铃声/媒体音量。

请参阅设计核对清单中的发送端音量控件。

向接收端发送媒体消息

Media Messages 可以从发送方发送到接收方。例如,如需向接收器发送 SKIP_AD 消息,请执行以下操作:

// Get a handle to the skip button element
const skipButton = document.getElementById('skip');
skipButton.addEventListener("click", function() {
  if (castSession) {
    const media = castSession.getMediaSession();
    castSession.sendMessage('urn:x-cast:com.google.cast.media', {
      type: 'SKIP_AD',
      requestId: 1,
      mediaSessionId: media.mediaSessionId
    });
  }
});

动态更新

当多个发送器连接到同一接收器时,每个发送器都必须了解接收器上的更改,即使这些更改是由其他发送器发起的。

为此,您的应用应在 RemotePlayerController 上注册所有必要的监听器。如果当前媒体的 TextTrackStyle 发生变化,系统会通知所有已连接的发送端,并且当前媒体会话的相应属性(例如 MediaInfo 字段的 activeTrackIds 和 textTrackStyle)会在回调中发送给发送端。在这种情况下,接收器 SDK 不会验证新样式是否与之前的样式不同,而是会通知所有已连接的发送器。

进度指示器

对于大多数应用,都需要在发送端显示播放位置和进度指示器。Cast API 使用 Cast 媒体协议,该协议可针对此场景和其他场景优化带宽消耗,因此您无需实现自己的状态同步。如需了解如何使用 API 正确实现媒体播放进度指示器,请参阅 CastVideos-chrome 示例应用。

CORS 要求

对于自适应媒体流式传输,Google Cast 要求提供 CORS 标头,但即使是简单的 mp4 媒体流,如果包含轨道,也需要 CORS。如果您想为任何媒体启用轨道,则必须同时为轨道流和媒体流启用 CORS。因此,如果您的服务器上没有适用于简单 MP4 媒体的 CORS 标头,那么在您添加简单字幕轨道后,您将无法流式传输媒体,除非您更新服务器以添加适当的 CORS 标头。

您需要以下标头:Content-Type、Accept-Encoding 和 Range。 请注意,最后两个标头 Accept-Encoding 和 Range 是您之前可能不需要的额外标头。

通配符“*”不能用于 Access-Control-Allow-Origin 标头。如果网页包含受保护的媒体内容,则必须使用网域,而不是通配符。

在不重新加载网页的情况下恢复会话

如需恢复现有 CastSession,请将 requestSessionById(sessionId) 与您尝试加入的会话的 sessionId 搭配使用。

调用 loadMedia() 后,可以使用 getSessionId() 在活跃的 CastSession 上找到 sessionId。

建议的方法如下:

  1. 调用 loadMedia() 以启动会话
  2. 在本地存储 sessionId
  3. 在需要时使用 requestSessionById(sessionId) 重新加入会话
let sessionId;

function rejoinCastSession() {
  chrome.cast.requestSessionById(sessionId);

  // Add any business logic to load new content or only resume the session
}

document.getElementById('play-button').addEventListener(("click"), function() {
  if (sessionId == null) {
    let castSession = cast.framework.CastContext.getInstance().getCurrentSession();
    if (castSession) {
      let mediaInfo = createMediaInfo();
      let request = new chrome.cast.media.LoadRequest(mediaInfo);
      castSession.loadMedia(request)

      sessionId = CastSession.getSessionId();
    } else {
      console.log("Error: Attempting to play media without a Cast Session");
    }
  } else {
    rejoinCastSession();
  }
});

后续步骤

以上就是您可以添加到 Web 发送端应用的所有功能。现在,您可以为其他平台(Android 或 iOS)构建发送端应用,也可以构建接收端应用。