简介:这是一份基于Java实现的阿里云直播服务接入案例,面向需要快速生成推流/拉流地址并将直播能力集成到自身应用的后端开发者或企业项目。核心演示了服务端如何调用阿里云直播SDK生成加密鉴权地址,从而支撑主播推流与用户拉流等常见互动场景。整个压缩包共152个文件,大小约137KB,其中以Maven及IntelliJ IDEA相关XML配置为主(123个XML),另有18个Java源码、4个YML配置、1个properties配置、1个JAR包及帮助文档等,对应项目构建、接口逻辑与开发环境配置。这份案例目前已吸引245人学习,适合正在研究直播推拉流鉴权地址生成的Java开发者。通过梳理源码与工程配置,可掌握pom.xml中直播SDK的引入方式、src/main/java下的工具类实现,以及.gitignore、mvnw等工程化细节;参考HELP.md还能快速搭建运行环境,理清阿里云直播接入的必备步骤,降低自行摸索成本,为上线直播功能提供可落地的范例。
1. citizen5zf 与阿里云直播:这个案例真正要解决的是链路接入问题
一个叫 citizen5zf 的直播间,在阿里云直播体系里能做什么?推流端用 RTMP 把画面送到 CDN,播流端按设备适配 FLV、HLS 或 RTS 打开,服务端再把转码、录制、截图、鉴权、数据统计这五件事一起接管。很多人上手直播的第一直觉是去调编码参数,实际上一周后踩的坑全在域名绑定、CNAME 生效、鉴权签算和回调抖动上。把这几层理顺,直播接入这件事就完成了一大半。
这篇内容写给两种人:一是被分配"把直播接进来"的后端或全栈工程师,二是要在自建直播和云直播之间做选型的团队负责人。下文把推拉流域名、协议取舍、转码录制、回调统计这条链路按可直接照做的顺序走一遍,并把 citizen5zf 当作贯穿示例的直播间标识,替换成自己的业务房间号就能用。
2. 阿里云直播的链路模型与协议选型:推流域名为什么必须和播流域名分开
2.1 一次推拉流请求的完整路径:CDN 节点、域名与 StreamName 的对应关系
先说链路。推流端(OBS、ffmpeg、移动端推流 SDK)把音视频帧封装成 RTMP 流,推到指定的推流域名;阿里云直播在边缘节点接收后同步流状态,再按播流域名把流分发给远端用户。这里存在两条逻辑链路:上行推流和下行播流,绝大多数线上事故出在两条链路共用一个域名,或者两套鉴权策略互相干扰。
一次会话对应一个三元组:域名(DomainName)、应用名(AppName)、流名(StreamName)。以本案例为例,推流地址可以写成rtmp://live-push.example.com/live/citizen5zf,其中live-push.example.com是推流域名,live是 AppName,citizen5zf是 StreamName。播流地址对应另一个播流域名,形如http://live-pull.example.com/live/citizen5zf.flv。StreamName 在同一 AppName 下不能重复,出现同名流时后推的一路会把先推的踢下线,这个机制在做直播间重建或无人直播循环推流时尤其要留意。
实际项目中,AppName 一般固定成一个全局值,比如live或app,不要按业务方拆分;业务维度留在 StreamName 里表达,例如citizen5zf_room1、citizen5zf_camera2。这样做的好处是,控制台排查和日志检索时过滤条件只有一个维度,后续接录制、转码模板时也可以按 AppName 统一匹配。
2.2 RTMP、FLV、HLS、RTS 怎么选:延迟、兼容性和采集端约束
直播协议决定了两头的接入方式。下面这张表是按实测经验整理的取舍,不是官方参数罗列:
| 协议 | 用途 | 延迟体验 | 适合的场景 | 常见坑 |
|---|---|---|---|---|
| RTMP | 推流 | 与播放端无关 | 采集端上行的默认选择 | 1935 端口在部分办公网络被禁 |
| FLV | 播流 | 较低 | 网页/自研播放器、低延迟直播接入 | 播放器要明确支持 HTTP-FLV |
| HLS | 播流 | 较高(切片缓冲) | 移动端 H5、回放、弱网兜底 | 首开等待首个关键帧切片 |
| RTS(ARTC) | 推拉流 | 超低延迟接入 | 连麦、互动教学、赛事陪看 | 需要集成对应音视频 SDK |
选型逻辑一句话概括:推流无脑走 RTMP,PC 端和移动 App 内的直播源用 FLV,H5 页面默认 HLS,连麦互动再考虑 RTS。做直播流测试时,优先验证 FLV 地址而不是 HLS 地址。FLV 连接建立快,能立刻暴露源流问题;HLS 要等切片生产,出错时你分不清是拉流问题还是切片封装问题。
2.3 CNAME 绑定与直播域名规划:上线前最容易被卡住的环节
域名规划的顺序是:先在控制台分别添加推流域名和播流域名,再为两个域名各自完成 CNAME 解析。CNAME 值由控制台生成,指向直播服务的调度域名,这一步完成后节点才能把这两个域名纳入路由。常见错误是把解析记录填成 A 记录,导致控制台一直提示 CNAME 未生效。
验证命令很简单:
# Linux/macOS 下验证推流域名的 CNAME 是否生效 dig live-push.example.com CNAME # 期望结果里出现 CNAME 记录,例如: # live-push.example.com. CNAME liveservice.cn-hangzhou.alicloud.....dig的结果里如果只有 A 记录而没有 CNAME 别名,说明解析类型填错或尚未生效。确认 CNAME 正常后再去地址生成器里取推流地址。控制台生成的测试地址有有效期,正式环境需要按 URL 鉴权规则自行签发,格式形如rtmp://推流域名/live/citizen5zf?auth_key=时间戳-随机数-uid-签名值。鉴权串在控制台里有明文的拼接模板,照着模板算即可。
这块顺带回应热搜里的"直播源"问题:很多 m3u8 直播源拿回来打不开,除去源本身失效,另一大原因是播放端拿到的 HLS 地址里的域名没有正确接入这条链路,或鉴权参数顺序不对。域名层理顺,后面推拉流才有意义。
3. 用控制台加 OpenAPI 跑通 citizen5zf 的推流与播流
3.1 控制台开通和域名配置:十分钟内能完成的四个动作
第一步,开通阿里云视频直播产品并完成实名认证;第二步,在域名管理里添加推流域名和播流域名,面向国内用户播放的域名需要完成 ICP 备案;第三步,按控制台给出的 CNAME 值到 DNS 服务商处添加解析;第四步,在"地址生成器"里输入 AppName 与 StreamName,验证推流地址和播流地址都能正常生成。这四步做通,基础链路已经可用了。
这个阶段容易忽略两个配置项:推流域名的推流协议限制,以及播流域名的访问协议放行。线上事故里最常见的现象是控制台显示流在推,但播放端一直黑屏,此时先检查播流域名是否放行了 FLV 或 HLS,而不是急着怀疑转码。另外,如果两个域名共用了同一张证书,也要确认证书覆盖了live-pull.example.com这一级域名,很多播放器在证书不匹配时会静默失败。
3.2 用 ffmpeg 和 ffplay 完成一次 rtmp 直播流测试
手边准备一个短视频素材,专门用来做直播流测试。Windows 命令行和 Linux 下用同一套 ffmpeg 命令,不需要额外安装图形工具。
# 单文件循环推流,适合无人直播或链路联调 ffmpeg -re -stream_loop -1 -i city.mp4 \ -c:v libx264 -preset veryfast -tune zerolatency \ -c:a aac -b:a 128k -f flv \ "rtmp://live-push.example.com/live/citizen5zf?auth_key=签名串"-re让 ffmpeg 按原始帧速率读取文件,否则推流速度远超实时,播流端会出现跳帧;-stream_loop -1让素材循环播放,无人直播或长时间测试时不需要反复重启进程;-tune zerolatency降低编码器缓冲,对延迟敏感场景更友好。如果素材没有音轨,-c:a aac会直接报错,换成-an去掉音频再推。
推流之后立刻用播放器验证:
# ffplay 直接打开 FLV 直播源 ffplay "http://live-pull.example.com/live/citizen5zf.flv?auth_key=签名串"窗口能出画面,说明推拉流链路和域名绑定全部正常。如果 ffplay 卡在 Opening 阶段,把地址 query 里的鉴权参数临时去掉再试:能通就是鉴权串问题,不能通则回头查 CNAME 和播流域名访问限制。Windows 命令行下要注意地址中&符号的转义,建议整个 URL 用双引号包裹。
3.3 用 OpenAPI 查在线流列表:把人工验证变成程序可判断
链路能跑通之后,把"直播间是否正在推流"变成接口可查询的数据。阿里云直播提供的 DescribeLiveStreamsOnlineList 可以做到这点,用 Python SDK 调用:
# 查询 citizen5zf 是否正在推流 from aliyunsdkcore.client import AcsClient from aliyunsdklive.request.v20161101.DescribeLiveStreamsOnlineListRequest import DescribeLiveStreamsOnlineListRequest client = AcsClient('<AccessKeyId>', '<AccessKeySecret>', 'cn-shanghai') req = DescribeLiveStreamsOnlineListRequest() req.set_DomainName('live-push.example.com') req.set_AppName('live') resp = client.do_action_with_exception(req) print(resp.decode('utf-8'))这段代码里的 DomainName 填推流域名,AppName 与推流地址保持一致。返回的OnlineStreamInfoList字段里会列出在线流的 StreamName、推流时间、编码方式。常用参数对照如下:
| OpenAPI 请求参数 | 含义 | 常见误用 |
|---|---|---|
| DomainName | 推流域名 | 误填播流域名导致查不到流 |
| AppName | 应用名 | 与推流地址不一致导致列表为空 |
| StreamName | 流名(可选) | 不填时列出该域下全部在线流 |
正式环境里,鉴权用的 AccessKey 不应出现在业务代码中。常见做法是后端单独起一个直播服务,用临时凭证签发地址,客户端拿到的直播地址本身带短期签名,双重动态下发。这样播放地址即使被完整截获,过期后也无法复用。判断直播间状态也不能只依赖这个接口,CDN 节点状态同步存在秒级延迟,要和业务房间状态结合判断。
4. 转码、录制、回调与直播数据:把案例从能看变成可运营
4.1 直播转码与多码率输出:H.264 下 GOP 和码率怎么定
当播流端规模上来后,不能所有用户都拿原画地址。直播转码在服务端把一路输入转成多路不同分辨率的输出,播放端按网络情况选择合适直播源。控制台先配置转码模板,再绑定到对应 AppName;转码后的流名会追加后缀,例如citizen5zf转码后变成citizen5zf_720p。
参数配置的经验值如下:
| 参数 | 建议值 | 说明 |
|---|---|---|
| 编码方式 | H.264 | 兼容性最好,H.265 网页端支持仍然混乱 |
| 分辨率 | 720p 推流,1080p/480p 转码 | 上行省带宽,多码率服务不同终端 |
| 帧率 | 与源流一致,通常 25/30 | 转码提高帧率没有意义 |
| 关键帧间隔 GOP | 1-2 秒 | GOP 过大切片等待长,过小压缩率下降 |
| 码率 | 720p 建议 1.5-2.5 Mbps | 按画面复杂度上下浮动 |
GOP 是最容易被忽略的参数。如果把关键帧间隔设到 10 秒,HLS 首屏最早也要等第一个切片里的关键帧出现,表现为播放器一直转圈。低延迟场景建议关键帧间隔和转码切片时长对齐,避免跨切片起播时的回源等待。
4.2 录制到 OSS:直播结束自动沉淀回放文件
直播场景几乎都要回放。录制配置顺序是:先创建 OSS Bucket,再在视频直播控制台配置录制模板,指定容器格式为 HLS(m3u8)或 MP4,然后把模板关联到 AppName 并开启自动录制。录制文件按AppName/StreamName/录制时间戳的目录结构落盘,在 OSS 里很容易定位。
录制格式的选择上,m3u8 适合做回放列表和分段索引,边录边看;MP4 对用户下载后离线观看更友好,但录制结束还需要服务端完成转封装,文件生成有延迟。FLV 录制保留的是原始直播流,适合后续接入剪辑或内容审核流程,但直接给用户播放的兼容性较差。录制开始和结束的边界由服务端判断,回调里如果没有明确返回录制文件 URL,需要到 OSS 目录里按时间戳自行匹配。
4.3 回调事件与直播数据:用事件驱动把状态同步给业务
录制、转码、推流状态变化可以通过事件通知推给业务服务器。在控制台配置回调地址后,推流结束、录制完成、截图完成等事件会以 HTTP POST 发送到指定 URL。回调消息体是 JSON,例如推流成功事件:
{ "Event": "LiveStreamPublish", "DomainName": "live-push.example.com", "AppName": "live", "StreamName": "citizen5zf", "PublishTime": "2025-01-01T10:00:00Z", "NotifyType": "publish" }收到回调后,业务系统把 StreamName 翻译成自己的房间号,更新数据库里的开播状态。回调不是强事务消息,偶发重复投递是正常的,接收方要做去重;网络异常时也可能丢失,所以核心状态还要靠定时调用在线流列表接口做补偿。如果你要的是直播数据层面的东西,可以用带宽、流量、直播观看趋势这类统计 API 拉分钟级粒度的指标做活动效果盘点。把转码、录制、回调、数据四块接进同一个业务,这个案例才从"能看"变成"可运营"。
5. 鉴权串偶发失效时,用 curl 状态码完成一次快速定界
拉流地址没变但播放器报错,这个现象在直播接入里出现频率很高。此时先绕过播放器,用 curl 直接访问播流地址:
# 直接复现鉴权结果,-I 只取响应头 curl -I "http://live-pull.example.com/live/citizen5zf.flv?auth_key=<时间戳>-0-0-<md5签名>" # 200 表示鉴权通过;403 表示签名或时间窗有问题;404 表示流不存在或已超过有效期返回 200 OK 说明鉴权串本身正确,问题在播放器缓存或 URL 被截断;返回 403 时按四个位点排查。一是时间戳是否超过生成地址时指定的有效期,直播鉴权常用 300 秒或 3600 秒,超时后同一串地址必然失效;二是服务端时间与本地时间偏差过大,鉴权按服务器时间校验,本地时钟漂移一分钟就会导致判断不一致;三是 URL 经过程序拼接后,是否把?、&转义成了%3F、%26;四是确认拼接源串里的路径与访问路径一致,包括 AppName 的大小写,直播服务的路径校验区分大小写。
如果播流域名开了 HTTPS 重定向,curl 需要加-L跟随跳转,否则拿到 301 后误判成异常。抓包看实际请求也是一个思路,把播放器发出去的 URL 原样复制到 curl 里重放,能立刻确认是播放器改写了地址还是服务端拒绝。
多语言接入时,鉴权签名函数要单独隔离出来配单元测试,测试用例里固定时间戳和路径,保证同一组输入永远输出同一签名。这个动作能省掉后面所有联调现场反复试错的时间。
本文还有配套的精品资源,点击获取