跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
JavaScript大前端

WebRTC 直播流播放方案:原生客户端与 EasyPlayer 实战

WebRTC 直播流播放主要依赖后端 ZLMediaKit 服务,前端可选原生 ZLMRTCClient 或第三方 EasyPlayer 实现。原生方案需关注版本差异及事件绑定,注意资源清理;EasyPlayer 则提供更丰富的交互功能如截图录制。本文对比两种方案的配置要点与代码实现细节,帮助开发者快速落地低延迟直播播放功能。

GitMaster发布于 2026/3/30更新于 2026/10/15.7K 浏览
WebRTC 直播流播放方案:原生客户端与 EasyPlayer 实战

后端服务已基于 ZLMediaKit 框架搭建,现在我们来探讨前端如何接入并播放这些直播流。在实际项目中,我们通常有两种主流选择:使用官方提供的原生 SDK,或者集成成熟的第三方播放器。

一、原生 WebRTC 播放器(ZLMRTCClient)

如果你希望最小化依赖,直接使用 ZLMediaKit 配套的 ZLMRTCClient.js 是最直接的方式。这里以 1.0.2 版本为例,需要注意不同版本的初始化方式可能有所差异。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>WebRTC 播放示例</title>
    <!-- 引入官方 SDK -->
    <script src="http://117.40.242.70:35080/ZLMRTCClient.js"></script>
</head>
<body>
    <video id="videoPlayer" autoplay controls></video>
    <script>
        // 1. 获取视频元素
        const videoElement = document.getElementById('videoPlayer');

        // 2. 配置参数
        const config = {
            element: videoElement,      // 绑定播放容器(必填)
            debug: true,                // 开启调试日志
            zlmsdpUrl: 'http://117.40.242.70:35080/index/api/webrtc?app=live&stream=test1&type=play', // 后端流地址
            simulcast: false,           // 不启用 simulcast
            useCamera: false,           // 纯播放模式
            audioEnable: true,
            videoEnable: true,
            recvOnly: true,             // 仅接收
            resolution: { w: 800, h: 450 },
            usedatachannel: false
        };

        // 3. 创建实例(1.0.2 版本使用 Endpoint)
        const rtcClient = new ZLMRTCClient.Endpoint(config);

        // 4. 监听事件
        rtcClient.on('error', (err) => console.error('错误:', err));
        rtcClient.on('webrtcNotSupport', () => alert('浏览器不支持 WebRTC'));

        let remoteStream = null;
        rtcClient.on('WEBRTC_ON_REMOTE_STREAMS', (event) => {
            console.log('收到远程流');
            if (videoElement.srcObject !== event.streams) {
                videoElement.srcObject = event.streams[0];
                remoteStream = event.streams[0];
            }
        });

        rtcClient.on('WEBRTC_ON_CONNECTION_STATE_CHANGE', (state) => {
            console.log('连接状态:', state);
        });

        // 停止播放逻辑
        function stop() {
            if (!rtcClient) return;
            videoElement.pause();
            videoElement.srcObject = null;
            if (remoteStream) {
                remoteStream.getTracks().forEach(track => track.stop());
                remoteStream = null;
            }
            if (rtcClient.disconnect) rtcClient.disconnect();
            else if (rtcClient.close) rtcClient.close();
            rtcClient = null;
        }
    </script>
</body>
</html>

开发注意:

  • 版本差异:实例化对象时,旧版可能用 new ZLMRTCClient(),而 1.0.2 推荐使用 Endpoint 类。
  • 资源清理:务必在页面关闭或停止播放时调用 disconnect 并停止媒体轨道,否则可能导致内存泄漏或摄像头占用。

二、使用开源播放器 EasyPlayer

如果项目对功能有更高要求,比如需要截图、录制或更复杂的 UI 控制,EasyPlayer 是个不错的选择。它封装了底层逻辑,提供了更友好的 API。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>EasyPlayer 演示</title>
    <script src="./js/EasyPlayer-pro.js"></script>
    <style>
        .player_item { position: relative; padding-bottom: 56%; background-color: black; margin-bottom: 20px; }
        .player_box { position: absolute; top: 0; bottom: 0; right: 0; left: 0; }
        .inputs { width: 100%; max-width: 600px; height: 36px; border: 1px solid #dcdfe6; padding: 0 15px; }
        .btn-item { cursor: pointer; padding: 6px 12px; border-radius: 4px; border: 1px #ccc solid; margin-right: 15px; }
        .df { display: flex; align-items: center; margin-bottom: 16px; }
        .box { padding-top: 10px; margin: auto; max-width: 800px; }
    </style>
</head>
<body>
    <div class="box">
        <h2>EasyPlayerPro 案例演示</h2>
        <div class="player_item"><div id="player_box" class="player_box"></div></div>
        
        <div class="df">
            <input type="checkbox" id="hasAudio" /><span>音频</span>
        </div>
        
        <input type="text" id="input" class="inputs" value="ws://localhost:6230/ws_flv/live/stream_1_0.flv">
        
        <div class="df">
            <button id="onPlayer" class="btn-item">播放</button>
            <button id="onReplay" class="btn-item">重播</button>
            <button id="onMute" class="btn-item">静音</button>
            <button id="onStop" class="btn-item">注销</button>
        </div>
    </div>

    <script>
        window.onload = function () {
            var playerInfo = null;
            var config = { stretch: true, hasAudio: true };
            playCreate();

            var input = document.getElementById('input');
            var audio = document.getElementById('hasAudio');
            var player = document.getElementById('onPlayer');
            var replay = document.getElementById('onReplay');
            var mute = document.getElementById('onMute');
            var stop = document.getElementById('onStop');

            if (config.hasAudio) audio.checked = true;
            audio.onclick = () => { config.hasAudio = audio.checked; };
            player.onclick = onPlayer;
            replay.onclick = onReplay;
            mute.onclick = onMute;
            stop.onclick = onStop;

            function playCreate() {
                var container = document.getElementById('player_box');
                playerInfo = new EasyPlayerPro(container, config);
            }

            function onPlayer() {
                playerInfo && playerInfo.play(input.value).catch(e => console.error(e));
            }

            function onMute() {
                if (!playerInfo) return;
                playerInfo.setMute(true);
            }

            function onReplay() {
                onDestroy().then(() => { playCreate(); onPlayer(); });
            }

            function onDestroy() {
                return new Promise((resolve) => {
                    if (playerInfo) {
                        playerInfo.destroy();
                        playerInfo = null;
                    }
                    setTimeout(resolve, 100);
                });
            }

            function onStop() {
                onDestroy().then(() => { playCreate(); });
            }
        };
    </script>
</body>
</html>

开发注意:

  • ID 匹配:确保 HTML 元素的 ID 与 JS 中 getElementById 的查询一致,这是新手最容易踩坑的地方。
  • 异步处理:销毁和重建播放器涉及异步操作,建议配合 Promise 管理流程,避免状态冲突。

两种方案各有优劣,原生 SDK 轻量但需自行处理细节,EasyPlayer 功能丰富但依赖外部库。根据实际业务需求选择即可。

目录

  1. 一、原生 WebRTC 播放器(ZLMRTCClient)
  2. 二、使用开源播放器 EasyPlayer

更多推荐文章

查看全部
  • 基于 AI Ping 的大模型统一接入与成本优化实战
  • 以太网网口与 PHY 芯片硬件设计解析
  • VRM4U 插件完整指南:在 Unreal Engine 5 中高效处理 VRM 模型
  • CSS 盒子模型详解:边框、内边距、外边距及美化技巧
  • LangChain 封装 FAISS 的检索阈值坑点分析
  • 深入理解 Linux 网络层
  • C++ 动态规划:调手表问题求解
  • 线性 DP 五大经典模型:LIS、LCS、合唱队形、编辑距离详解与模板
  • 本地部署 Whisper 语音识别模型的完整指南与避坑实践
  • Arch Linux 安装 Niri 桌面环境完整指南
  • 二叉树 DFS 实战:计算布尔值及根到叶节点数字之和
  • NotoSansSC-Regular.otf 字体特性与应用场景解析
  • Python Numpy 库常见用法入门教程
  • Nanbeige4.1-3B 多场景落地实践:教育问答、代码辅助与智能写作
  • OpenClaw 接入企业微信:API 模式与自建应用配置指南
  • 第十五届蓝桥杯 C/C++省赛 C 组题解
  • JDK 21 核心新特性深度解析与实践
  • LLaMA 3.1 模型部署与实战:构建智能聊天机器人
  • Plottable 高级图表制作:从散点图到堆叠面积图的 10 种实现方法
  • 次模函数(Submodular Function)核心概念与机器学习应用

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online