Google CAF网页接收器DRM视频无法播放 报错6007/905排查
CAF网页接收器Android TV端DRM视频无限加载问题修复
问题现象
- 播放器可正常显示标题、描述元数据,但DRM视频无法启动,预加载组件持续转圈
- 日志输出两类错误:
shakaErrorCode: 6007:许可证请求失败,通常由超时、网络故障、服务器拒绝导致detailedErrorCode: 905:加载命令执行失败
- 同一套DRM请求参数在其他普通播放器上可正常播放DRM视频,仅Cast接收器场景报错
故障环境
复现设备:物理真机 发送端:Redmi Note 8 Pro 接收端:搭载Chromecast的Android Box Chromecast内置版本:1.56.276477 CAST SDK CAF版本:3.0.0103
问题根因
核心问题出在许可证请求体构造逻辑的兼容性bug:
代码中使用Array.apply(null, new Uint8Array(requestInfo.content))将Widevine生成的二进制挑战数据转换为普通数组,该写法在Chromecast内置的Chrome 90内核环境下无法正确遍历TypedArray的所有元素,最终仅传入了挑战数据的前2个字节——即抓包看到的drm_info:[8,4]。
许可证服务器收到不完整的挑战请求后,返回错误提示内容(虽然HTTP状态码为200 OK),Shaka播放器无法将响应解析为合法DRM许可证,最终抛出6007错误,导致加载流程卡死。
次要隐患:在LOAD消息拦截器中动态修改全局playbackConfig的写法,在当前使用的CAF SDK版本中存在配置不生效的概率,会引发偶发加载失败。
修复方案
- 替换错误的TypedArray转换逻辑,使用标准
Array.from方法完成二进制到普通数组的转换,保证完整传递Widevine挑战数据 - 调整DRM配置的绑定逻辑,不要动态修改全局配置,改为在加载媒体时给当前播放项单独配置PlaybackConfig,通过
playerManager.setPlaybackConfig即时生效 - 显式声明许可证响应处理逻辑,避免二进制响应解析异常
修复后的完整receiver.js代码
const context = cast.framework.CastReceiverContext.getInstance(); const playerManager = context.getPlayerManager(); const ContentType = { DASH: 'application/dash+xml', HLS: 'application/x-mpegurl' }; const mediaFormatID = { DASH: 2, HLS: 4 }; // Debug Logger const castDebugLogger = cast.debug.CastDebugLogger.getInstance(); const LOG_TAG = 'MyAPP.LOG'; castDebugLogger.setEnabled(true); castDebugLogger.loggerLevelByEvents = { 'cast.framework.events.category.CORE': cast.framework.LoggerLevel.INFO, 'cast.framework.events.EventType.MEDIA_STATUS': cast.framework.LoggerLevel.DEBUG }; castDebugLogger.loggerLevelByTags = { LOG_TAG: cast.framework.LoggerLevel.DEBUG, }; playerManager.setMessageInterceptor( cast.framework.messages.MessageType.LOAD, request => { return new Promise((resolve, _reject) => { // 处理DASH流 if (request.media.metadata.mediaFormatID == mediaFormatID.DASH) { request.media.contentType = ContentType.DASH; // 配置DRM参数 if (request.media.metadata.licenseUrl) { const token = request.media.metadata.token; const contentId = request.media.metadata.contentId; // 构造当前播放项专属的播放配置 const playbackConfig = new cast.framework.PlaybackConfig(); playbackConfig.licenseUrl = request.media.metadata.licenseUrl; playbackConfig.protectionSystem = cast.framework.ContentProtection.WIDEVINE; playbackConfig.licenseRequestHandler = requestInfo => { requestInfo.withCredentials = false; // 修复:使用Array.from正确转换Uint8Array,保证挑战数据完整 const challengeData = Array.from(new Uint8Array(requestInfo.content)); const reqBody = { token: token, drm_info: challengeData, contentId: contentId }; requestInfo.content = JSON.stringify(reqBody); requestInfo.headers["Content-Type"] = "application/json"; }; playbackConfig.licenseResponseHandler = responseInfo => { // 直接返回二进制许可证数据,无需额外转换 return responseInfo.data; }; // 即时生效配置 playerManager.setPlaybackConfig(playbackConfig); } } else { // 处理HLS流 request.media.contentType = ContentType.HLS; request.media.hlsSegmentFormat = cast.framework.messages.HlsSegmentFormat.FMP4; request.media.hlsVideoSegmentFormat = cast.framework.messages.HlsVideoSegmentFormat.FMP4; } // 配置元数据 const metadata = new cast.framework.messages.GenericMediaMetadata(); metadata.title = request.media.metadata.title; metadata.subtitle = request.media.metadata.subtitle; request.media.metadata = metadata; resolve(request); }); }); // 启动接收器,无需提前传入全局playbackConfig context.start();
验证方法
部署修复后的代码,重新触发投屏播放,抓包查看许可证请求的drm_info字段:正常情况下该字段为长度几十到数百的数字数组,不再是固定的[8,4],此时许可证服务器会返回合法的DRM证书,视频即可正常加载播放。
内容的提问来源于stack exchange,提问作者Алексей Обронов
相关产品推荐
相关产品推荐

