为自定义网络接收器添加核心功能

本页包含自定义 Web 接收器应用可用的功能的代码段和说明。

  1. cast-media-player 元素,表示使用 Web 接收器提供的内置播放器界面。
  2. cast-media-player 元素自定义类似 CSS 的样式,以设置各种界面元素的样式,例如 background-imagesplash-imagefont-family
  3. 用于加载网络接收器框架的脚本元素。
  4. 用于拦截消息和处理事件的 JavaScript 代码。
  5. 自动播放队列。
  6. 用于配置播放的选项。
  7. 用于设置网络接收器上下文的选项。
  8. 设置网络接收器应用支持的命令的选项。
  9. 用于启动网络接收器应用的 JavaScript 调用。

应用配置和选项

CastReceiverContext 是向开发者公开的最外层类,负责管理底层库的加载并处理 Web Receiver SDK 的初始化。

如果 Web Receiver API 检测到发送者断开连接,则会引发 SENDER_DISCONNECTED 事件。对于我们所说的 maxInactivity 秒,如果网络接收器无法与发送者通信,它也会引发 SENDER_DISCONNECTED 事件。在开发过程中,最好将 maxInactivity 设置为较大的值,这样使用 Chrome 遥控器调试器调试 Web 接收器应用时就不会关闭:

const context = cast.framework.CastReceiverContext.getInstance();
const options = new cast.framework.CastReceiverOptions();
options.maxInactivity = 3600; //Development only
context.start(options);

不过,对于已发布的 Web 接收器应用,最好不要设置 maxInactivity 而是依赖于默认值。请注意,Web 接收器选项只在应用中设置一次。

另一种配置是 cast.framework.PlaybackConfig。这可以按如下方式设置:

const playbackConfig = new cast.framework.PlaybackConfig();
playbackConfig.manifestRequestHandler = requestInfo => {
  requestInfo.withCredentials = true;
};
context.start({playbackConfig: playbackConfig});

此配置会影响每个内容播放,并且本质上提供了替换行为。如需查看开发者可以替换的行为列表,请参阅 cast.framework.PlaybackConfig 的定义。如需更改内容之间的配置,可以使用 PlayerManager 获取其当前 playbackConfig,修改或添加替换值并重置 playbackConfig,如下所示:

const playerManager =
    cast.framework.CastReceiverContext.getInstance().getPlayerManager();
const playbackConfig = (Object.assign(
            new cast.framework.PlaybackConfig(), playerManager.getPlaybackConfig()));
playbackConfig.autoResumeNumberOfSegments = 1;
playerManager.setPlaybackConfig(playbackConfig);

请注意,如果 PlaybackConfig 未被替换,getPlaybackConfig() 会返回 null 对象。PlaybackConfig that 上的任何属性为 undefined 都将使用默认值。

事件监听器

Web 接收器 SDK 可让您的网络接收器应用处理播放器事件。事件监听器采用 cast.framework.events.EventType 参数(或这些参数数组)指定应触发监听器的事件。您可以在 cast.framework.events.category 中找到可用于调试的 cast.framework.events.EventType 预配置数组。event 参数提供有关事件的其他信息。

例如,如果您想知道何时有 mediaStatus 更改的广播,可以使用以下逻辑处理该事件:

const playerManager =
    cast.framework.CastReceiverContext.getInstance().getPlayerManager();
playerManager.addEventListener(
    cast.framework.events.EventType.MEDIA_STATUS, (event) => {
      // Write your own event handling code, for example
      // using the event.mediaStatus value
});

邮件拦截

Web 接收器 SDK 可让您的网络接收器应用拦截消息并对消息执行自定义代码。消息拦截器接受一个 cast.framework.messages.MessageType 参数,用于指定应该拦截哪些类型的消息。

拦截器应返回修改后的请求或会使用修改后的请求值解析的 Promise。返回 null 将阻止调用默认消息处理程序。如需了解详情,请参阅加载媒体

例如,如果您想更改加载请求数据,可以使用以下逻辑来拦截和修改这些数据:

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

playerManager.setMessageInterceptor(
    cast.framework.messages.MessageType.LOAD, loadRequestData => {
      const error = new cast.framework.messages.ErrorData(
                      cast.framework.messages.ErrorType.LOAD_FAILED);
      if (!loadRequestData.media) {
        error.reason = cast.framework.messages.ErrorReason.INVALID_PARAM;
        return error;
      }

      if (!loadRequestData.media.entity) {
        return loadRequestData;
      }

      return thirdparty.fetchAssetAndAuth(loadRequestData.media.entity,
                                          loadRequestData.credentials)
        .then(asset => {
          if (!asset) {
            throw cast.framework.messages.ErrorReason.INVALID_REQUEST;
          }

          loadRequestData.media.contentUrl = asset.url;
          loadRequestData.media.metadata = asset.metadata;
          loadRequestData.media.tracks = asset.tracks;
          return loadRequestData;
        }).catch(reason => {
          error.reason = reason; // cast.framework.messages.ErrorReason
          return error;
        });
    });

context.start();

错误处理

当消息拦截器出现错误时,您的 Web 接收器应用应返回相应的 cast.framework.messages.ErrorTypecast.framework.messages.ErrorReason

playerManager.setMessageInterceptor(
    cast.framework.messages.MessageType.LOAD, loadRequestData => {
      const error = new cast.framework.messages.ErrorData(
                      cast.framework.messages.ErrorType.LOAD_CANCELLED);
      if (!loadRequestData.media) {
        error.reason = cast.framework.messages.ErrorReason.INVALID_PARAM;
        return error;
      }

      ...

      return fetchAssetAndAuth(loadRequestData.media.entity,
                               loadRequestData.credentials)
        .then(asset => {
          ...
          return loadRequestData;
        }).catch(reason => {
          error.reason = reason; // cast.framework.messages.ErrorReason
          return error;
        });
    });

消息拦截与事件监听器

消息拦截和事件监听器之间的一些主要区别如下所示:

  • 事件监听器不允许您修改请求数据。
  • 事件监听器最适合用于触发分析或自定义函数。
playerManager.addEventListener(cast.framework.events.category.CORE,
    event => {
        console.log(event);
    });
  • 通过消息拦截,您可以监听、拦截消息并修改请求数据本身。
  • 消息拦截最适合用于处理与请求数据相关的自定义逻辑。

加载媒体

MediaInformation 提供了多种属性来加载 cast.framework.messages.MessageType.LOAD 消息中的媒体,包括 entitycontentUrlcontentId

entity 是建议在实现发送者和接收者应用时使用的属性。该属性是一个深层链接网址,可以是播放列表,也可以是特定媒体内容。

contentUrl 专为可播放的网址而设计,可以在可用后使用。

由于值是媒体的网址、实际 ID 还是用于自定义查找的关键参数,因此 contentId 已被弃用。

建议使用 entity 存储实际 ID 或键参数,并使用 contentUrl 作为媒体网址。以下代码段显示了一个示例,其中 entity 出现在 LOAD 请求中,并且检索了可播放的 contentUrl

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

      if (!loadRequestData.media.entity) {
        // Copy the value from contentId for legacy reasons if needed
        loadRequestData.media.entity = loadRequestData.media.contentId;
      }

      return thirdparty.fetchAssetAndAuth(loadRequestData.media.entity,
                                          loadRequestData.credentials)
        .then(asset => {
          loadRequestData.media.contentUrl = asset.url;
          ...
          return loadRequestData;
        });
    });

设备功能

getDeviceCapabilities 方法提供有关已连接的投射设备及其连接到的视频或音频设备的设备信息。getDeviceCapabilities 方法可为 Google 助理、蓝牙以及连接的显示屏和音频设备提供支持信息。

此方法会返回一个对象,您可以通过传入其中一个指定的枚举来查询该对象,以获取该枚举的设备功能。枚举在 cast.framework.system.DeviceCapabilities 中定义。

此示例会检查网络接收器设备能否分别使用 IS_HDR_SUPPORTEDIS_DV_SUPPORTED 键播放 HDR 和杜比视界 (DV) 视频。

const context = cast.framework.CastReceiverContext.getInstance();
context.addEventListener(cast.framework.system.EventType.READY, () => {
  const deviceCapabilities = context.getDeviceCapabilities();
  if (deviceCapabilities &&
      deviceCapabilities[cast.framework.system.DeviceCapabilities.IS_HDR_SUPPORTED]) {
    // Write your own event handling code, for example
    // using the deviceCapabilities[cast.framework.system.DeviceCapabilities.IS_HDR_SUPPORTED] value
  }
  if (deviceCapabilities &&
      deviceCapabilities[cast.framework.system.DeviceCapabilities.IS_DV_SUPPORTED]) {
    // Write your own event handling code, for example
    // using the deviceCapabilities[cast.framework.system.DeviceCapabilities.IS_DV_SUPPORTED] value
  }
});
context.start();

处理用户互动

用户可以通过发送器应用(Web、Android 和 iOS)、支持 Google 助理的设备上的语音指令、智能显示屏上的触控功能以及 Android TV 设备上的遥控器,与您的网络接收器应用互动。Cast SDK 提供了各种 API,使 Web 接收器应用能够处理这些互动、通过用户操作状态更新应用界面,以及选择发送更改以更新任何后端服务。

支持的媒体命令

界面控件状态由 iOS 和 Android 发送者扩展控制器的 MediaStatus.supportedMediaCommands、触摸设备上运行的接收器和遥控器应用以及 Android TV 设备上的接收器应用驱动。属性中启用了特定的按位 Command 后,与该操作相关的按钮就会启用。如果未设置该值,则按钮将停用。您可以通过以下方式在网络接收器中更改这些值:

  1. 使用 PlayerManager.setSupportedMediaCommands 设置特定的 Commands
  2. 使用 addSupportedMediaCommands 添加新命令
  3. 使用 removeSupportedMediaCommands 移除现有命令。
playerManager.setSupportedMediaCommands(cast.framework.messages.Command.SEEK |
  cast.framework.messages.Command.PAUSE);

当接收器准备更新后的 MediaStatus 时,它将包含对 supportedMediaCommands 属性的更改。广播消息时,连接的发送者应用会相应地更新界面中的按钮。

如需详细了解支持的媒体命令和触摸设备,请参阅 Accessing UI controls 指南。

管理用户操作状态

当用户与界面互动或发送语音指令时,他们可以控制与播放内容相关的内容和属性的播放。控制播放的请求由 SDK 自动处理。修改当前播放项的属性的请求(例如 LIKE 命令)要求接收方应用处理这些属性。SDK 提供了一系列 API 来处理这些类型的请求。为了支持这些请求,必须执行以下操作:

  • 拦截 USER_ACTION 消息并确定请求的操作。
  • 更新 MediaInformation UserActionState 以更新界面。

以下代码段会拦截 USER_ACTION 消息,并使用请求的更改来处理后端调用。然后,它会调用更新接收器上的 UserActionState

playerManager.setMessageInterceptor(cast.framework.messages.MessageType.USER_ACTION,
  (userActionRequestData) => {
    // Obtain the media information of the current content to associate the action to.
    let mediaInfo = playerManager.getMediaInformation();

    // If there is no media info return an error and ignore the request.
    if (!mediaInfo) {
        console.error('Not playing media, user action is not supported');
        return new cast.framework.messages.ErrorData(messages.ErrorType.BAD_REQUEST);
    }

    // Reach out to backend services to store user action modifications. See sample below.
    return sendUserAction(userActionRequestData, mediaInfo)

    // Upon response from the backend, update the client's UserActionState.
    .then(backendResponse => updateUserActionStates(backendResponse))

    // If any errors occurred in the backend return them to the cast receiver.
    .catch((error) => {
      console.error(error);
      return error;
    });
});

以下代码段模拟了对后端服务的调用。该函数会检查 UserActionRequestData 以查看用户请求的更改类型,并且仅在后端支持相应操作时才进行网络调用。

function sendUserAction(userActionRequestData, mediaInfo) {
  return new Promise((resolve, reject) => {
    switch (userActionRequestData.userAction) {
      // Handle user action changes supported by the backend.
      case cast.framework.messages.UserAction.LIKE:
      case cast.framework.messages.UserAction.DISLIKE:
      case cast.framework.messages.UserAction.FOLLOW:
      case cast.framework.messages.UserAction.UNFOLLOW:
      case cast.framework.messages.UserAction.FLAG:
      case cast.framework.messages.UserAction.SKIP_AD:
        let backendResponse = {userActionRequestData: userActionRequestData, mediaInfo: mediaInfo};
        setTimeout(() => {resolve(backendResponse)}, 1000);
        break;
      // Reject all other user action changes.
      default:
        reject(
          new cast.framework.messages.ErrorData(cast.framework.messages.ErrorType.INVALID_REQUEST));
    }
  });
}

以下代码段接受 UserActionRequestData,并在 MediaInformation 中添加或移除 UserActionState。更新 MediaInformationUserActionState 会更改与请求的操作相关联的按钮的状态。此更改会反映在智能显示屏控件界面、遥控器应用和 Android TV 界面中。它还会通过传出 MediaStatus 消息进行广播,以更新 iOS 和 Android 发送者的扩展控制器的界面。

function updateUserActionStates(backendResponse) {
  // Unwrap the backend response.
  let mediaInfo = backendResponse.mediaInfo;
  let userActionRequestData = backendResponse.userActionRequestData;

  // If the current item playing has changed, don't update the UserActionState for the current item.
  if (playerManager.getMediaInformation().entity !== mediaInfo.entity) {
    return;
  }

  // Check for existing userActionStates in the MediaInformation.
  // If none, initialize a new array to populate states with.
  let userActionStates = mediaInfo.userActionStates || [];

  // Locate the index of the UserActionState that will be updated in the userActionStates array.
  let index = userActionStates.findIndex((currUserActionState) => {
    return currUserActionState.userAction == userActionRequestData.userAction;
  });

  if (userActionRequestData.clear) {
    // Remove the user action state from the array if cleared.
    if (index >= 0) {
      userActionStates.splice(index, 1);
    }
    else {
      console.warn("Could not find UserActionState to remove in MediaInformation");
    }
  } else {
    // Add the UserActionState to the array if enabled.
    userActionStates.push(
      new cast.framework.messages.UserActionState(userActionRequestData.userAction));
  }

  // Update the UserActionState array and set the new MediaInformation
  mediaInfo.userActionStates = userActionStates;
  playerManager.setMediaInformation(mediaInfo, true);
  return;
}

语音指令

对于内置 Google 助理的设备,Web Receiver SDK 目前支持以下媒体命令。这些命令的默认实现位于 cast.framework.PlayerManager 中。

命令 说明
播放 从暂停状态播放或继续播放。
暂停 暂停当前正在播放的内容。
上一步 跳至媒体队列中的上一个媒体项。
下一步 跳至媒体队列中的下一个媒体项。
停止 停止当前正在播放的媒体。
无重复 播放队列中的最后一项内容后,禁止重复播放队列中的媒体内容。
重复单曲 无限期重复播放当前播放的媒体。
全部重复播放 播放队列中的最后一项之后,重复播放队列中的所有项。
重复播放和随机播放 队列中的最后一项内容播放完毕后,随机播放队列,并重复播放队列中的所有项。
随机播放 随机播放媒体队列中的媒体内容。
开启/关闭字幕 为媒体启用 / 停用字幕。“启用”/“停用”同样适用于不同的语言。
还原绝对时间 跳转到指定的绝对时间。
还原相对于当前时间的时间 相对于当前播放时间向前或向后跳转指定的时间段。
再玩一次 重启当前播放的媒体;如果当前未播放任何内容,则播放上次播放的媒体项。
设置播放速率 媒体播放速率不同。默认情况下,这种情况应该处理。您可以使用 SET_PLAYBACK_RATE 消息拦截器来替换传入的速率请求。

支持语音指令的媒体命令

为防止语音指令在内置 Google 助理的设备上触发媒体命令,你必须先设置计划支持的支持的媒体命令。然后,您必须启用 CastReceiverOptions.enforceSupportedCommands 属性来强制执行这些命令。Cast SDK 发送器和支持触摸操作的设备上的界面会发生变化,以反映这些配置。如果未启用此标志,则系统将执行传入的语音指令。

例如,如果您允许来自发送者应用和支持触摸功能的设备中的 PAUSE,则还必须配置接收器以反映这些设置。配置此标志时,如果未包含在支持的命令列表中,则传入的任何语音指令都将被丢弃。

在下面的示例中,我们在启动 CastReceiverContext 时提供了 CastReceiverOptions。我们添加了对 PAUSE 命令的支持,并已强制播放器仅支持该命令。现在,如果语音指令请求其他操作(例如 SEEK),该操作将遭到拒绝。系统会通知用户尚不支持该命令。

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

context.start({
  enforceSupportedCommands: true,
  supportedCommands: cast.framework.messages.Command.PAUSE
});

您可以为要限制的每个命令应用单独的逻辑。移除 enforceSupportedCommands 标志,对于要限制的每个命令,您可以拦截传入的消息。在这里,我们会拦截 SDK 提供的请求,这样,向支持 Google 助理的设备发出的 SEEK 命令就不会在网络接收器应用中触发跳转。

对于您的应用不支持的媒体命令,请返回相应的错误原因,例如 NOT_SUPPORTED

playerManager.setMessageInterceptor(cast.framework.messages.MessageType.SEEK,
  seekData => {
    // Block seeking if the SEEK supported media command is disabled
    if (!(playerManager.getSupportedMediaCommands() & cast.framework.messages.Command.SEEK)) {
      let e = new cast.framework.messages.ErrorData(cast.framework.messages.ErrorType
      .INVALID_REQUEST);
      e.reason = cast.framework.messages.ErrorReason.NOT_SUPPORTED;
      return e;
    }

    return seekData;
  });

从语音活动转到后台

如果 Cast 平台因 Google 助理活动(如监听用户语音或讲话)而将应用声音置于后台,那么当该 activity 启动时,系统会将 NOT_IN_FOCUSFocusState 消息发送到网络接收器应用。当 activity 结束时,系统会另外发送一条包含 IN_FOCUS 消息。 根据您的应用和正在播放的媒体,您可能希望在 FocusState 处于 NOT_IN_FOCUS 状态时通过拦截消息类型 FOCUS_STATE 来暂停媒体。

例如,如果 Google 助理响应用户查询,暂停有声读物播放是一种很好的体验。

playerManager.setMessageInterceptor(cast.framework.messages.MessageType.FOCUS_STATE,
  focusStateRequestData => {
    // Pause content when the app is out of focus. Resume when focus is restored.
    if (focusStateRequestData.state == cast.framework.messages.FocusState.NOT_IN_FOCUS) {
      playerManager.pause();
    } else {
      playerManager.play();
    }

    return focusStateRequestData;
  });

语音指定的字幕语言

如果用户未明确说明字幕语言,字幕所用的语言就是命令所用的语言。在这些情况下,传入消息的 isSuggestedLanguage 参数会指明关联的建议是用户建议还是明确提出的。

例如,针对命令“Ok Google,打开字幕”将 isSuggestedLanguage 设置为 true,因为语言是通过说出该命令的语言推断得出的。如果语言被明确请求(例如在“Ok Google,开启英语字幕”,则 isSuggestedLanguage 设为 false)。

元数据和语音投射

虽然语音指令由网络接收器默认处理,但您应确保内容的元数据完整且准确。这样可以确保 Google 助理能够正确处理语音指令,并且元数据可以在新类型的界面(例如 Google Home 应用和 Google Home Hub 等智能显示屏)中正确显示。

数据流传输

保留会话状态是流传输的基础,在这种情况下,用户可以使用语音指令、Google Home 应用或智能显示屏在设备之间移动现有音频和视频流。媒体会在一台设备上停止播放(来源),然后在另一台设备上(目的地)继续播放。具有最新固件的任何 Cast 设备都可以在流传输中用作来源或目的地。

视频流传输的事件流程如下:

  1. 在源设备上:
    1. 媒体会停止播放。
    2. 网络接收器应用会收到保存当前媒体状态的命令。
    3. 网络接收器应用已关闭。
  2. 在目标设备上:
    1. 网络接收器应用已加载。
    2. 网络接收器应用会收到恢复已保存的媒体状态的命令。
    3. 媒体继续播放。

媒体状态的元素包括:

  • 歌曲、视频或媒体项的具体位置或时间戳。
  • 它位于更广泛的队列(例如播放列表或音乐人电台)中。
  • 通过身份验证的用户。
  • 播放状态(例如,正在播放或已暂停)。

启用数据流传输

如需为您的网络接收器实现流传输,请执行以下操作:

  1. 使用 STREAM_TRANSFER 命令更新 supportedMediaCommands
    playerManager.addSupportedMediaCommands(
    cast.framework.messages.Command.STREAM_TRANSFER, true);
  2. (可选)替换 SESSION_STATERESUME_SESSION 消息拦截器,如保留会话状态中所述。仅当需要将自定义数据存储为会话快照的一部分时,才应替换这些自定义数据。否则,用于保留会话状态的默认实现将支持数据流传输。

保留会话状态

Web 接收器 SDK 为 Web 接收器应用提供了一个默认实现,可通过拍摄当前媒体状态的快照、将状态转换为加载请求以及恢复与加载请求的会话来保留会话状态。

如有必要,可在 SESSION_STATE 消息拦截器中替换 Web 接收器生成的加载请求。如果要在加载请求中添加自定义数据,建议将其放在 loadRequestData.customData 中。

playerManager.setMessageInterceptor(
    cast.framework.messages.MessageType.SESSION_STATE,
    function (sessionState) {
        // Override sessionState.loadRequestData if needed.
        const newCredentials = updateCredentials_(sessionState.loadRequestData.credentials);
        sessionState.loadRequestData.credentials = newCredentials;

        // Add custom data if needed.
        sessionState.loadRequestData.customData = {
            'membership': 'PREMIUM'
        };

        return sessionState;
    });

可以从 RESUME_SESSION 消息拦截器中的 loadRequestData.customData 检索自定义数据。

let cred_ = null;
let membership_ = null;

playerManager.setMessageInterceptor(
    cast.framework.messages.MessageType.RESUME_SESSION,
    function (resumeSessionRequest) {
        let sessionState = resumeSessionRequest.sessionState;

        // Modify sessionState.loadRequestData if needed.
        cred_ = sessionState.loadRequestData.credentials;

        // Retrieve custom data.
        membership_ = sessionState.loadRequestData.customData.membership;

        return resumeSessionRequest;
    });

内容预加载

网络接收器支持在队列中的当前播放项之后预加载媒体项。

预加载操作会预先下载多个即将发布的项。该规范是在 QueueItem 对象中的 preloadTime 值上指定的(如果未提供,则默认为 20 秒)。时间以秒为单位,相对于当前正在播放的内容的结尾。只有正值才有效。例如,如果值为 10 秒,则此项会在上一个项完成 10 秒后预加载。如果预加载时间长于 currentItem 上的剩余时间,系统会尽快进行预加载。因此,如果在 queueItem 上指定非常大的预加载值,则可以实现以下效果:每当我们播放当前项时,我们就已经在预加载下一项项。不过,我们将此设置的设置和选择留给开发者,因为此值可能会影响当前播放内容的带宽和流式传输性能。

默认情况下,预加载适用于 HLS、DASH 和 Smooth 流式内容。

常规 MP4 视频和音频文件(例如 MP3)不会预加载,因为 Cast 设备仅支持一个媒体元素,因此无法在现有内容项仍在播放时进行预加载。

自定义消息

消息交换是网络接收器应用的关键交互方法。

发送者使用发送者 API 针对发送者运行的平台(Android、iOS、Web)向网络接收器发出消息。传递给事件监听器的事件对象(即消息的表示形式)具有一个数据元素 (event.data),其中的数据会采用特定事件类型的属性。

网络接收器应用可能会选择监听指定命名空间中的消息。据此,网络接收器应用据称支持该命名空间协议。随后,任何想要在该命名空间上进行通信并使用相应协议的已连接发送者均由您自己决定。

所有命名空间都由字符串定义,且必须以“urn:x-cast:”开头,后跟任何字符串。例如,“urn:x-cast:com.example.cast.mynamespace”。

以下代码段可以让网络接收器监听来自连接的发送者的自定义消息:

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

const CUSTOM_CHANNEL = 'urn:x-cast:com.example.cast.mynamespace';
context.addCustomMessageListener(CUSTOM_CHANNEL, function(customEvent) {
  // handle customEvent.
});

context.start();

同样,网络接收器应用可以通过向连接的发送者发送消息,将网络接收器的状态告知发送者。Web 接收器应用可以使用 CastReceiverContext 上的 sendCustomMessage(namespace, senderId, message) 发送消息。网络接收器可以向单个发送者发送消息,以响应收到的消息或应用状态变化。除了点对点消息传递(上限为 64 KB)之外,网络接收器还可以向所有连接的发送者广播消息。

适用于音频设备的投射

如需获得关于纯音频播放的支持,请参阅适用于音频设备的 Google Cast 指南

Android TV

本部分将介绍 Google Web 接收器如何将输入用作播放内容以及 Android TV 兼容性。

将您的应用与遥控器集成

在 Android TV 设备上运行的 Google Web 接收器会将设备的控制输入(即手持遥控器)的输入转换为为 urn:x-cast:com.google.cast.media 命名空间定义的媒体播放消息,如媒体播放消息中所述。您的应用必须支持这些消息来控制应用媒体播放,以便通过 Android TV 的控制输入实现基本播放控制。

Android TV 兼容性指南

为了确保您的应用与 Android TV 兼容,您需要避免以下建议和常见误区:

  • 请注意,用户代理字符串既包含“Android”也包含“C 代码”;某些网站可能会因为检测到“Android”标签而重定向到专门面向移动设备的网站。请勿假定用户代理字符串中的“Android”始终表示移动设备用户。
  • Android 的媒体堆栈可以使用透明 GZIP 来获取数据。确保您的媒体数据可以响应 Accept-Encoding: gzip
  • Android TV HTML5 媒体事件的触发时间可能与 Chromecast 不同的时间,这可能会导致 Chromecast 上隐藏的问题。
  • 更新媒体时,请使用由 <audio>/<video> 元素(例如 timeupdatepausewaiting)触发的媒体相关事件。避免使用 progresssuspendstalled 等网络相关事件,因为这些事件往往依赖于平台。如需详细了解如何在接收器中处理媒体事件,请参阅媒体事件
  • 配置接收者网站的 HTTPS 证书时,请务必添加中间 CA 证书。请参阅 Qualsys SSL 测试页面,以验证:如果您的网站的受信认证路径包含标记为“额外下载”的 CA 证书,则它可能无法在基于 Android 的平台上加载。
  • 虽然 Chromecast 在 720p 的图形平面上显示接收方页面,但其他投射平台(包括 Android TV)可能会显示分辨率高达 1080p 的页面。确保接收者页面能够以不同的分辨率正常缩放。