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-DATERANGE的CLASS设为"com.apple.hls.interstitial"X-ASSET-URI指向广告的多码率播放列表- AVFoundation 自动解析并处理这些标签,不需要手动标记时间范围
核心启发
1. 为视频 App 添加 SharePlay 一起看功能
- 做什么:让用户在 FaceTime 通话中同步观看你的 App 里的视频内容
- 为什么值得做:SharePlay 把单人观看变成社交体验,
AVPlaybackCoordinator处理了大部分同步复杂度,接入成本低 - 怎么开始:创建
GroupActivity定义可共享的内容,用GroupSession管理会话,把groupSession关联到AVPlayer的playbackCoordinator
2. 构建分层订阅的视频服务
- 做什么:设计免费用户看广告、付费用户免广告的订阅模式,同时支持 SharePlay
- 为什么值得做:
suspensionReasonsThatTriggerWaiting让不同层级用户能一起观看,等待期间可以给付费用户展示额外内容 - 怎么开始:用 HLS Interstitials 调度广告,配置默认等待策略,用
GroupSessionMessenger在参与者间同步订阅层级信息
3. 直播赛事的社交观看体验
- 做什么:体育赛事直播时,让不同地区的用户一起观看,各自看到本地化广告
- 为什么值得做:HLS Interstitials + 默认等待策略让无广告用户继续看现场,有广告的用户结束后自动追上,不会错过关键瞬间
- 怎么开始:用服务端插入 HLS Interstitials,按地区返回不同的广告播放列表,客户端不需要额外代码处理同步
4. 等待期间的互动内容
- 做什么:当用户在 SharePlay 中等待其他人看完广告时,展示互动内容而不是静态等待画面
- 为什么值得做:
GroupSessionMessenger可以共享广告排期,让你精确知道等待时长,同时用第二个播放器展示预告片、花絮或互动投票 - 怎么开始:监听
timeControlStatus变化,进入等待状态时切换到备用播放器,收到GroupSessionMessenger的排期消息后更新等待倒计时
关联 Session
- Make a great SharePlay experience — 构建优秀 SharePlay 体验的设计原则和最佳实践
- Coordinate media playback in SharePlay — SharePlay 协调播放的基础实现指南
- Explore HLS variants for adaptive bitrate — HLS 多码率播放列表与动态内容调度
- What’s new in AVFoundation — AVFoundation 的异步 API 和响应式媒体处理
评论
GitHub Issues · utterances