as

Settings
Sign out
Notifications
Alexa
亚马逊应用商店
Ring
AWS
文档
Support
Contact Us
My Cases
新手入门
设计和开发
应用发布
参考
支持

使用无头方法实现客户端广告插入

使用无头方法实现客户端广告插入

在本教程中,您将使用无头方法在Vega应用中实现客户端广告插入 (CSAI)。这种方法使用客户端-服务器架构,其中用户界面层中的IPlayerClient实例通过基于JavaScript接口 (JSI)的进程间通信 (IPC) 与独立服务层中的VideoPlayer实例进行通信。您将设置一个双播放器架构,其中一个主播放器客户端用于播放内容,一个广告播放器客户端在广告插播期间接管共享视频展示位。

本教程中的示例演示了用于实现无缝广告过渡的预缓冲广告。有关CSAI概念、技巧和同步策略的背景信息,请参阅Vega中的客户端广告插入

在本教程中,您将学习如何:

  • 设置播放器客户端引用和导入
  • 检测广告标记并预初始化广告播放器客户端
  • 等待广告缓冲,然后暂停主要内容
  • 切换视频展示位并播放广告
  • 广告结束后返回至主要内容

先决条件

  • Vega开发环境已设置
  • Vega SDK v0.22或更高版本
  • @amazon-devices/kepler-player-client@amazon-devices/kepler-player-client程序包已安装
  • 主要内容播放器客户端已初始化并已连接到服务
  • React Native和TypeScript的基础知识

设置播放器客户端引用

导入所需的程序包并为主播放器客户端、广告播放器客户端和会话ID创建引用。

已复制到剪贴板。


import {
  PlayerClientFactory,
  IPlayerClient,
  IPlayerSessionPositionListener,
} from '@amazon-devices/kepler-player-client';

import {
  IPlayerSessionId,
  IPlayerSessionMediaInfo,
  IPlayerSessionStatus,
  IPlayerSessionState,
} from '@amazon-devices/kepler-player-server';

// 播放器客户端引用
const playerClient = useRef<IPlayerClient | undefined>(undefined);       // 主要内容播放器客户端(已初始化)
const adPlayerClient = useRef<IPlayerClient | undefined>(undefined);     // 广告播放器客户端
const playerSessionId = useRef<IPlayerSessionId | undefined>(undefined); // 主会话ID
const adPlayerSessionId = useRef<IPlayerSessionId | undefined>(undefined); // 广告会话ID
const sessionIdCounter = useRef(1);

检测广告标记并预初始化广告播放器客户端

当位置侦听器检测到即将到来的广告插播时,使用autoPlay=false预初始化广告播放器客户端,并注册侦听器以了解广告何时缓冲以及何时结束。

  1. 设置位置侦听器以检测即将到来的广告插播。

已复制到剪贴板。


const positionListener: IPlayerSessionPositionListener = {
  onPositionUpdated: (updatedPosition) => {
    const currentTime = updatedPosition[0]?.position || 0;
    // 用于确定广告插播是否临近的应用特定逻辑
    if (adBreakApproaching(currentTime)) {
      initializeAdPlayer(adMediaInfo);
    }
  },
};

  1. 创建广告播放器客户端初始化函数。注册状态侦听器以检测READY和ENDED状态。在IPlayerSessionState.READY不可用的平台上,该服务会发送playerReady消息作为回退。

已复制到剪贴板。


const initializeAdPlayer = async (adMediaInfo: IPlayerSessionMediaInfo) => {
  const factory = new PlayerClientFactory();
  adPlayerClient.current = factory.getOrMakeClient(serviceComponentId);
  adPlayerSessionId.current = { id: sessionIdCounter.current++ };

  // 注册状态侦听器以检测ENDED状态(如果可用,则为READY)
  await adPlayerClient.current?.registerStatusListener({
    onSessionStatusChanged: (updatedStatus: Array<IPlayerSessionStatus>) => {
      const adStatus = updatedStatus.find(
        s => s.sessionId?.id === adPlayerSessionId.current?.id
      );
      if (
        IPlayerSessionState.READY !== undefined &&
        adStatus?.playbackState === IPlayerSessionState.READY
      ) {
        onAdReady();
      } else if (adStatus?.playbackState === IPlayerSessionState.ENDED) {
        onAdEnded();
      }
    }
  }, adPlayerSessionId.current);

  // 回退: 在IPlayerSessionState.READY不可用的平台上,
  // 服务改为发送“playerReady”消息 
  if (IPlayerSessionState.READY === undefined) {
    await adPlayerClient.current?.registerMessageListener(
      {
        onMessageReceived: (message: any) => {
          if (message.type === 'playerReady') {
            onAdReady();
          }
        },
      },
      adPlayerSessionId.current,
    );
  }

  // 加载autoPlay=false的广告以进行手动控制
  await adPlayerClient.current?.load(
    adMediaInfo,
    { startPosition: 0, autoPlay: false },
    adPlayerSessionId.current,
  );
};

等待广告缓冲,然后暂停主要内容

在广告播放器发出READY(已缓冲)信号,且侦听器检测到广告开始时间已到来后,暂停主要内容。

已复制到剪贴板。


let adReady = false;

const onAdReady = () => {
  adReady = true;
  // 等待位置侦听器以检测广告开始时间
};

// 当达到广告开始时间且广告准备就绪时,侦听器就位:
if (adReady && currentTime >= adStartTime) {
  playerClient.current?.pause(playerSessionId.current);
}

切换展示位并播放广告

当主要内容状态更改为PAUSED时,清空主界面并将其交给广告播放器。

已复制到剪贴板。


await playerClient.current?.registerStatusListener({
  onSessionStatusChanged: (updatedStatus: Array<IPlayerSessionStatus>) => {
    const mainStatus = updatedStatus.find(
      s => s.sessionId?.id === playerSessionId.current?.id
    );
    if (mainStatus?.playbackState === IPlayerSessionState.PAUSED && adPlayerClient.current) {
      clearMainSurfaceHandle();
      setAdSurfaceHandle();
      adPlayerClient.current?.play(adPlayerSessionId.current);
    }
  }
}, playerSessionId.current);

返回至主要内容

广告结束后,清理广告展示位,清理广告播放器客户端,然后恢复主要内容。

已复制到剪贴板。


const onAdEnded = async () => {
  await clearAdSurfaceHandle();
  cleanupAdPlayer();
  await setMainSurfaceHandle();
  await playerClient.current?.play(playerSessionId.current);
};

const cleanupAdPlayer = () => {
  if (!adPlayerClient.current) return;
  adPlayerClient.current.unloadSync(1000, adPlayerSessionId.current);
  adPlayerClient.current = undefined;
  adReady = false;
};

清理资源

当您的组件卸载或播放器会话结束时,卸载广告播放器客户端并释放资源。

已复制到剪贴板。


const cleanup = () => {
  if (adPlayerClient.current) {
    adPlayerClient.current.unloadSync(1000, adPlayerSessionId.current);
    adPlayerClient.current = undefined;
  }
  // 主播放器客户端清理工作通过您现有的拆解逻辑处理
};


Last updated: 2026年3月13日