WWDC Quick Look 💓 By SwiftGGTeam
Explore AirPlay with interstitials

Explore AirPlay with interstitials

观看原视频

Highlight

Apple 在 WWDC23 扩展了 HLS Interstitials 与 AirPlay 的集成能力,开发者可以通过 AVPlayerInterstitialEventrestrictions 属性控制广告播放时的导航限制(跳过/跳转),且这些限制会自动同步到 AirPlay 接收端(包括第三方智能电视),无需额外代码适配。

核心内容

插播广告(Interstitials)与 AirPlay 的痛点

视频应用经常需要在正片前后或中间插入广告、预告片等次要内容。传统方案中,这些插播内容(interstitials)与正片(primary content)混在一起,难以动态替换或精准控制。

HLS Interstitials 将广告作为独立资源,在正片时间轴上标记播放点。当播放到标记位置时,自动切换到广告内容,广告结束后再回到正片断点处继续播放。

这种方式支持 VOD 和直播两种场景,且不需要修改正片内容本身。广告可以动态调度、取消,甚至支持 late binding(临近播放时才决定展示哪条广告)。

导航限制的跨设备同步难题

广告播放通常有合同约束:用户不能跳过广告,也不能在广告间随意跳转。HLS Interstitials 内置了两种导航限制:

  • Skip:禁止以非标准速率播放广告(防止快进跳过)
  • Jump:禁止跳出当前广告(防止 seek 跳过)

这两种限制可以单独或组合使用。问题在于:当用户通过 AirPlay 将视频投屏到智能电视时,电视端运行的是接收端固件,不是 AVFoundation 代码。开发者一度担心需要为 AirPlay 接收端写额外适配代码。

Apple 的答案是:不需要。只要通过服务器端(HLS Playlist 的 X-RESTRICT 属性)或客户端(AVPlayerInterstitialEvent.restrictions)配置了导航限制,AirPlay 会自动将这些限制转发到接收端执行。

多订阅计划的服务端复用

一个典型的 VOD 服务有三种订阅计划:

  • Plan A:带广告,播放/暂停是唯一允许的操作
  • Plan B:无广告
  • Plan C:看完第一条广告后可以跳过后续广告

开发者可以用同一份 HLS Playlist 服务所有用户:

  • Plan A 不需要任何客户端改动,Playlist 中的限制规则直接生效
  • Plan B 在客户端设置 automaticallyHandlesInterstitialEvents = false,忽略 Playlist 中配置的所有插播事件
  • Plan C 在客户端复制并修改第二条广告的 restrictions 属性,清除其跳过限制

这大幅降低了服务端复杂度,同一份 Playlist 适配多种商业模式。

详细内容

客户端驱动:设置 Skip 限制

09:19

let player = AVPlayer(url: movieURL) // 正片,不含广告
let controller = AVPlayerInterstitialEventController(primaryPlayer: player)

let ad1Item = [AVPlayerItem(url: ad1Url)]
let ad1event = AVPlayerInterstitialEvent(
    primaryItem: player.currentItem,
    time: CMTime(seconds: 5, preferredTimescale: 1)
)
ad1event.identifier = "ad1"
ad1event.templateItems = ad1Item

// 设置 SKIP 限制:禁止快进跳过广告
ad1event.restrictions = [.requiresPlaybackAtPreferredRateForAdvancement]

controller.events = [ad1event]

关键点:

  • AVPlayerInterstitialEventController 负责为正片播放器调度插播事件
  • AVPlayerInterstitialEvent 定义了插播内容在正片时间轴上的位置
  • templateItems 指定插播内容(可以是多个广告连播)
  • restrictions 设置为 .requiresPlaybackAtPreferredRateForAdvancement 即 Skip 限制,用户无法快进跳过

覆盖服务端限制:Plan C 的实现

15:44

let player = AVPlayer(url: movieURL)
let controller = AVPlayerInterstitialEventController(primaryPlayer: player)

let ad1Event = controller.events[0]
let ad2Event = controller.events[1]

let newEvent = ad2Event.copy() as! AVPlayerInterstitialEvent
// 清除 ad2 的限制
newEvent.restrictions = []

// 用原始 ad1 和修改后的 ad2 更新控制器
controller.events = [ad1Event, newEvent]

关键点:

  • 从控制器获取已调度的事件(可能来自服务端 Playlist)
  • copy() 创建事件副本,修改其 restrictions 属性
  • 清空 restrictions 后,用户可以在 ad2 播放时自由跳过
  • 最后将修改后的事件数组重新赋值给控制器

减少 AirPlay 接收端切换延迟

09:46

AirPlay 接收端涵盖 Apple TV、机顶盒、智能电视、音箱等多种设备,硬件和编解码能力差异很大。正片和广告如果编码参数不匹配,接收端切换解码器时会产生明显延迟。

建议保持正片与插播内容的媒体参数一致:

视频音频
编码格式(AVC/HEVC)编码格式(AAC 等)
帧率采样频率
宽高比位深
声道布局

此外,所有媒体组件(音频、视频、字幕)的时间戳必须精确对齐,确保同步播放。

音轨与字幕的自动匹配

11:30

如果插播内容与正片有相似的音轨和字幕轨道,系统会自动选择匹配的轨道播放。这个行为在本地播放和 AirPlay 会话中一致,不需要额外代码。

AirPlay 测试建议

11:53

测试套件应覆盖多种接收端:

  • 从 Apple TV 开始,但至少要选一种非 Apple 的 AirPlay 接收设备
  • 按媒体处理能力分档:高端(支持 Dolby Vision)和低端(仅支持 SDR + 立体声 AAC)
  • 即使应用只面向 iPhone 用户,也要测试不同档次的接收端

核心启发

1. 用同一份 Playlist 支持多 tier 订阅模式

做什么:在视频 App 中实现「免费带广告 / 付费去广告 / 高级可跳过」三种订阅计划。

为什么值得做:HLS Interstitials 允许客户端覆盖服务端配置,服务端只需维护一份 Playlist,客户端根据用户订阅等级动态调整广告策略。

怎么开始:在应用启动时根据用户订阅状态设置 automaticallyHandlesInterstitialEvents,或在播放器初始化后遍历 controller.events 修改各事件的 restrictions

2. 为 AirPlay 用户优化广告体验

做什么:检测用户是否处于 AirPlay 状态,在投屏时自动选择编码参数匹配的广告素材。

为什么值得做:不同 AirPlay 接收端的解码能力差异大,保持正片与广告的编码参数一致可以显著减少切换延迟,提升观看体验。

怎么开始:通过 AVPlayer.externalPlaybackActive 检测 AirPlay 状态,根据当前接收端能力(可通过 AVPlayerItempreferredPeakBitRate 等属性推断)选择对应码率的广告素材。

3. 实现基于观看历史的广告重定向

做什么:用户回退到已观看过的片段时,自动替换为新的广告。

为什么值得做:HLS Interstitials 支持 late binding 和 rebinding,可以在播放接近广告标记时才决定展示哪条广告,避免重复展示相同内容。

怎么开始:监听 AVPlayerInterstitialEventMonitor 的事件,在 interstitialEventWillPlay 回调中根据用户观看历史动态更新 templateItems

4. 为直播场景插入实时广告

做什么:在直播流中动态插入广告,且直播时间不因广告而延迟。

为什么值得做:HLS Interstitials 支持直播场景,广告结束后正片会跳转到直播当前时间点,不会因为广告造成直播延迟累积。

怎么开始:在直播 Playlist 中插入 EXT-X-DATERANGE 标签,或使用 AVPlayerInterstitialEventresumptionOffset 属性控制直播恢复位置。

关联 Session

评论

GitHub Issues · utterances