WWDC Quick Look 💓 By SwiftGGTeam
Display ads and interstitials in SharePlay

Display ads and interstitials in SharePlay

观看原视频

Highlight

SharePlay 的协调播放支持广告和插播内容场景:通过 AVPlayerPlaybackCoordinatorDelegate 标记广告时间范围,配合 suspensionReasonsThatTriggerWaiting 配置等待策略,让不同参与者看完不同时长的广告后自动恢复同步。

核心内容

问题:广告让同步播放变得复杂

你和好友在 FaceTime 上一起追剧,本来进度完全一致。但你们身处不同地区,看到的广告不一样——你的广告 15 秒,他的 30 秒,还有人根本不看广告。广告结束后,大家的位置就错乱了。

SharePlay 的基础协调播放很简单:把 groupSession 关联到 playbackCoordinator,所有人的播放控制指令实时同步。但广告打破了这种一致性,因为每个人的”呈现时间线”里插入了不同内容。

两种用户体验策略

广告时长不一致时,有两种处理方式:

等待策略:先看完广告的人等着,等所有人都看完再一起继续。优点是没人漏掉主内容,缺点是等待的人要盯着暂停画面。

追赶策略:先看完广告的人继续看主内容,其他人广告结束后跳过去追上。优点是流畅无等待,缺点是有人会错过一部分节目内容。

这两种策略通过 suspensionReasonsThatTriggerWaiting 数组配置。默认行为是不等待(追赶策略),把 "playingInterstitial" 加进数组则启用等待策略。

缝合式广告:手动标记时间范围

对于 VOD 内容,广告片段直接缝合在主 HLS 播放列表里(用 discontinuity 标签分隔)。开发者需要在 AVPlayerPlaybackCoordinatorDelegate 里告诉系统哪些时间范围是广告。

系统拿到这些时间范围后,参与者进入广告时段时按配置的等待策略处理。如果有人拖动进度条进了广告范围,整个 SharePlay 组会一起跳到那段广告的开头。

一个关键约束:SharePlay 要求主内容(去掉广告后的实际节目)的时长相等。广告可以不同,但正片必须一样长。

HLS Interstitials:更灵活的广告调度

WWDC21 引入的 HLS Interstitials 把广告当作独立于主内容时间线的对象。广告通过多码率播放列表 URI 引用,可以服务端插入,也可以客户端用 AVFoundation API 动态调度。

用 HLS Interstitials 时,AVFoundation 自动处理协调播放,开发者只需要配置等待策略。这种方式更适合动态定向广告和直播场景。

最佳实践

直播场景下,如果部分人没广告、部分人有广告,推荐用 HLS Interstitials 加默认等待策略。没广告的人继续看直播,有广告的人结束后自动追上来。这在体育赛事直播中很实用——无广告用户看现场画面,有广告的人回来刚好赶上比赛开始。

VOD 场景下,如果内容完整性很重要,推荐用等待策略。等待期间可以用 GroupSessionMessenger 共享广告排期,让等待的人知道还要等多久,同时用另一个播放器展示预告片或其他内容保持参与感。

详细内容

标记广告时间范围

05:13

class MyAVPlayerCoordinatorDelegate: NSObject, AVPlayerPlaybackCoordinatorDelegate {
    func playbackCoordinator(
        _ coordinator: AVPlayerPlaybackCoordinator,
        interstitialTimeRangesFor playerItem: AVPlayerItem
    ) -> [NSValue] {
        return interstitialTimeRanges
    }
}

关键点:

  • 实现 AVPlayerPlaybackCoordinatorDelegate 协议
  • interstitialTimeRangesFor 返回 [NSValue],每个元素是用 NSValue(timeRange:) 包装的 CMTimeRange
  • 这些时间范围必须是 sample accurate 的,基于实际媒体时长计算
  • 对于缝合式广告,时间范围通常通过累加 HLS 播放列表中 EXTINF 标签的时长得到

配置等待策略

// 启用等待策略:看完广告的人等其他人
playbackCoordinator.suspensionReasonsThatTriggerWaiting = ["playingInterstitial"]

// 默认行为(追赶策略):不等待
playbackCoordinator.suspensionReasonsThatTriggerWaiting = []

关键点:

  • suspensionReasonsThatTriggerWaiting 决定哪些暂停原因会触发等待
  • "playingInterstitial" 表示播放插播内容(广告)时,其他参与者等待
  • 等待时 player.timeControlStatus 变为 .waitingToPlayAtSpecifiedRate
  • player.reasonForWaitingToPlay.waitingForCoordinatedPlayback

检查等待状态

if player.timeControlStatus == .waitingToPlayAtSpecifiedRate,
   player.reasonForWaitingToPlay == .waitingForCoordinatedPlayback {
    // 用户正在等待其他参与者
    showWaitingUI()
}

用 GroupSessionMessenger 共享广告排期

import GroupActivities

// 发送广告排期
let messenger = GroupSessionMessenger(session: groupSession)
try await messenger.send(adSchedule)

// 接收广告排期
Task {
    for await (schedule, participant) in messenger.messages(of: AdSchedule.self) {
        updateWaitingTime(with: schedule)
    }
}

关键点:

  • GroupSessionMessenger 在 SharePlay 参与者之间传递自定义数据
  • 共享广告排期后,等待的人可以精确知道还要等多久
  • 可以在等待期间展示其他内容,提升用户体验

HLS Interstitials 播放列表示例

HLS Interstitials 在主内容播放列表中用 EXT-X-DATERANGE 标签标记广告:

#EXTM3U
#EXT-X-VERSION:6
#EXT-X-TARGETDURATION:10

#EXT-X-DATERANGE:ID="ad1",CLASS="com.apple.hls.interstitial",
START-DATE="2022-06-06T12:00:00Z",
X-ASSET-URI="https://example.com/ad-variant.m3u8"

#EXTINF:10,
segment1.ts
#EXTINF:10,
segment2.ts

关键点:

  • EXT-X-DATERANGECLASS 设为 "com.apple.hls.interstitial"
  • X-ASSET-URI 指向广告的多码率播放列表
  • AVFoundation 自动解析并处理这些标签,不需要手动标记时间范围

核心启发

1. 为视频 App 添加 SharePlay 一起看功能

  • 做什么:让用户在 FaceTime 通话中同步观看你的 App 里的视频内容
  • 为什么值得做:SharePlay 把单人观看变成社交体验,AVPlaybackCoordinator 处理了大部分同步复杂度,接入成本低
  • 怎么开始:创建 GroupActivity 定义可共享的内容,用 GroupSession 管理会话,把 groupSession 关联到 AVPlayerplaybackCoordinator

2. 构建分层订阅的视频服务

  • 做什么:设计免费用户看广告、付费用户免广告的订阅模式,同时支持 SharePlay
  • 为什么值得做suspensionReasonsThatTriggerWaiting 让不同层级用户能一起观看,等待期间可以给付费用户展示额外内容
  • 怎么开始:用 HLS Interstitials 调度广告,配置默认等待策略,用 GroupSessionMessenger 在参与者间同步订阅层级信息

3. 直播赛事的社交观看体验

  • 做什么:体育赛事直播时,让不同地区的用户一起观看,各自看到本地化广告
  • 为什么值得做:HLS Interstitials + 默认等待策略让无广告用户继续看现场,有广告的用户结束后自动追上,不会错过关键瞬间
  • 怎么开始:用服务端插入 HLS Interstitials,按地区返回不同的广告播放列表,客户端不需要额外代码处理同步

4. 等待期间的互动内容

  • 做什么:当用户在 SharePlay 中等待其他人看完广告时,展示互动内容而不是静态等待画面
  • 为什么值得做GroupSessionMessenger 可以共享广告排期,让你精确知道等待时长,同时用第二个播放器展示预告片、花絮或互动投票
  • 怎么开始:监听 timeControlStatus 变化,进入等待状态时切换到备用播放器,收到 GroupSessionMessenger 的排期消息后更新等待倒计时

关联 Session

评论

GitHub Issues · utterances