录制与回放

  • Web

更新时间不可用

了解如何在互动白板 SDK 中录制与回放,包括适用场景、配置步骤、实现要点和注意事项。

声网互动白板 SDK 提供录制与回放功能,支持将实时房间中的所有互动行为录制下来,并支持高质量回放。相较于传统的录屏模式,白板录制和回放具有以下优势:

  • 高效录制:采用信令记录方式,相比传统录屏模式占用带宽更少、存储空间更小
  • 高质量回放:回放时还原现场效果,画质清晰、动画流畅
  • 服务端录制:录制在服务端自动进行,无需客户端额外处理
  • 灵活回放:支持指定时间范围回放、播放控制、视角跟随等功能
  • 完整记录:录制白板操作、自定义事件、视角变化等所有互动行为

本文介绍如何开启白板录制功能以及如何实现白板内容回放。

技术原理

白板录制

声网互动白板录制不是屏幕录制,而是记录信令与数据增量构成的私有二进制数据。录制过程完全在服务端进行,具有以下优势:

  • 自动录制:只需在创建房间时开启录制功能,服务端会自动录制房间内的所有互动行为
  • 智能管理:只有在房间活跃时才会生成录制信息,房间无活动时录制会自动停止
  • 数据紧凑:录制生成的数据相比传统音视频格式更紧凑,占用存储空间更小

白板回放

白板回放时,SDK 会依照录制的信令与数据增量还原现场,得到的效果和实时互动时一模一样。回放支持:

  • 指定时间范围回放
  • 播放、暂停、跳转等播放控制
  • 视角跟随和自由视角切换
  • 自定义事件和全局状态变化的回放

前提条件

开始前,请确保:

  1. 已在项目中集成声网互动白板 SDK。详见快速开始。
  2. 已获取有效的 SDK Token 和 Room Token。详见获取互动白板项目的安全密钥。
  3. 如需在业务服务器上创建房间,请参考房间管理服务端 API。

实现录制功能

开启录制

要开启白板录制功能,需要在创建房间时设置 isRecord: true 参数。以下示例展示如何通过服务端 API 创建支持录制的房间:

JavaScript
// 注意:建议在业务服务器上执行创建房间操作,不要在前端执行
var url = "https://api.netless.link/v5/rooms";
var requestInit = {
    method: "POST",
    headers: {
        "content-type": "application/json",
        "token": "NETLESSSDK_YWs9xxxxxxM2MjRi", // 替换为你的 SDK Token
        "region": "cn-hz", // 替换为你的数据中心
    },
    body: JSON.stringify({
        name: "我的录制房间",
        isRecord: true, // 开启录制功能
    }),
};

fetch(url, requestInit).then(function(response) {
    return response.json();
}).then(function(roomJSON) {
    // 创建房间成功,获取房间信息
    console.log("房间 UUID:", roomJSON.uuid);
    console.log("房间已开启录制功能");
}).catch(function(err) {
    console.error("创建房间失败:", err);
});

注意

  • SDK Token 是重要的安全凭证,建议在业务服务器中使用,不要写死在前端代码中。
  • 开启录制功能后,该房间内的所有互动行为都会被自动录制。

录制内容

开启录制功能后,以下内容会被自动录制:

  • 白板绘制操作(画笔、图形、文字等)
  • 场景切换和内容变化
  • 图片、MP3、MP4、课件(PPT、DOC)的展示和操作
  • 用户视角变化
  • 自定义事件(通过 dispatchMagixEvent 发送的事件)
  • 全局状态变化(GlobalState 的修改)

实现回放功能

检查录制内容是否可回放

在创建回放播放器之前,建议先检查指定时间段是否有可回放的录制内容:

JavaScript
var whiteWebSdk = new WhiteWebSdk({
    appIdentifier: "RMxxxAQ", // 替换为你的 App Identifier
});

var playableCheckingParams = {
    room: "a7xxx69", // 房间 UUID
    roomToken: "NETLESSROOM_YWxxxjk", // Room Token
    beginTimestamp: new Date("2023-01-01 08:00:00").getTime(), // 回放开始时间
    duration: 45 * 60 * 1000, // 回放持续时间(毫秒),这里是 45 分钟
};

whiteWebSdk.isPlayable(playableCheckingParams).then(function(isPlayable) {
    if (isPlayable) {
        console.log("该时间段有可回放的录制内容");
        // 可以创建回放播放器
    } else {
        console.log("该时间段没有录制内容");
    }
}).catch(function(err) {
    console.error("检查回放内容失败:", err);
});

创建回放播放器

使用 replayRoom 方法创建回放播放器:

JavaScript
var replayRoomParams = {
    room: "a7xxx69", // 房间 UUID
    roomToken: "NETLESSROOM_YWxxxjk", // Room Token
    beginTimestamp: new Date("2023-01-01 08:00:00").getTime(), // 回放开始时间
    duration: 45 * 60 * 1000, // 回放持续时间(毫秒)
};

whiteWebSdk.replayRoom(replayRoomParams).then(function(player) {
    // 成功创建回放播放器
    console.log("回放播放器创建成功");
    
    // 将播放器绑定到页面元素
    player.bindHtmlElement(document.getElementById("whiteboard"));
    
    // 开始播放
    player.play();
    
}).catch(function(err) {
    console.error("创建回放播放器失败:", err);
});

播放器控制

回放播放器提供了丰富的播放控制功能:

JavaScript
// 播放控制
player.play();     // 开始播放
player.pause();    // 暂停播放
player.stop();     // 停止播放

// 跳转到指定位置(单位:毫秒,相对于回放开始时间)
player.seekToProgressTime(10 * 60 * 1000) // 跳转到第 10 分钟
    .then(function(result) {
        console.log("跳转结果:", result);
    });

// 设置播放倍速
player.playbackSpeed = 1.5; // 1.5 倍速播放
player.playbackSpeed = 1.0; // 恢复正常速度

// 获取播放状态信息
console.log("当前播放进度:", player.progressTime); // 当前播放位置(毫秒)
console.log("总时长:", player.timeDuration);       // 回放总时长(毫秒)
console.log("播放状态:", player.phase);            // 播放状态

监听播放器状态变化

可以通过回调函数监听播放器状态的变化:

JavaScript
var playerCallbacks = {
    // 播放状态改变回调
    onPhaseChanged: function(phase) {
        switch(phase) {
            case "playing":
                console.log("正在播放");
                break;
            case "pause":
                console.log("已暂停");
                break;
            case "buffering":
                console.log("正在缓冲");
                break;
            case "ended":
                console.log("播放结束");
                break;
        }
    },
    
    // 播放进度改变回调
    onProgressTimeChanged: function(progressTime) {
        console.log("当前播放进度:", progressTime + "ms");
    },
    
    // 播放出错回调
    onStoppedWithError: function(error) {
        console.error("播放出错:", error);
    }
};

// 创建播放器时注册回调
whiteWebSdk.replayRoom(replayRoomParams, playerCallbacks).then(function(player) {
    // 播放器创建成功
});

视角控制

回放时可以控制观看视角:

JavaScript
// 设置观看模式
player.setObserverMode("directory"); // 跟随模式,跟随录制时的视角变化
player.setObserverMode("freedom");   // 自由模式,可以自由调整视角

// 禁止用户调整视角
player.disableCameraTransform = true;  // 禁止用户通过手势调整视角
player.disableCameraTransform = false; // 允许用户调整视角

回放自定义事件

如果录制时发送了自定义事件,回放时也可以监听这些事件:

JavaScript
// 监听回放中的自定义事件
player.addMagixEventListener("Greetings", function(event) {
    console.log("回放中收到自定义事件:", event.payload);
});

// 监听全局状态变化
var playerCallbacks = {
    onPlayerStateChanged: function(modifyState) {
        if (modifyState.globalState) {
            console.log("全局状态发生变化:", modifyState.globalState);
        }
    }
};

使用 React 展示回放

如果你使用 React 框架,可以使用 white-react-sdk 更方便地展示回放内容:

JSX
import React from "react";
import { PlayerWhiteboard } from "white-react-sdk";

class ReplayComponent extends React.Component {
    render() {
        const style = {
            width: "100%",
            height: "100vh",
        };
        
        return (
            <PlayerWhiteboard 
                player={this.props.player} 
                style={style}
            />
        );
    }
}

完整示例

以下是一个完整的录制和回放示例:

HTML
<!DOCTYPE html>
<html>
<head>
    <title>白板录制与回放示例</title>
    <script src="https://sdk.netless.link/white-web-sdk/2.16.59.js"></script>
</head>
<body>
    <div>
        <button onclick="createRecordingRoom()">创建录制房间</button>
        <button onclick="startReplay()">开始回放</button>
        <button onclick="pauseReplay()">暂停回放</button>
        <button onclick="resumeReplay()">继续回放</button>
    </div>
    <div id="whiteboard" style="width: 100%; height: 500px; border: 1px solid #ccc;"></div>

    <script>
        var whiteWebSdk = new WhiteWebSdk({
            appIdentifier: "RMxxxAQ", // 替换为你的 App Identifier
        });
        
        var player = null;

        // 创建录制房间
        function createRecordingRoom() {
            // 注意:实际项目中应该在服务端创建房间
            var url = "https://api.netless.link/v5/rooms";
            var requestInit = {
                method: "POST",
                headers: {
                    "content-type": "application/json",
                    "token": "NETLESSSDK_YWs9xxxxxxM2MjRi", // 替换为你的 SDK Token
                    "region": "cn-hz",
                },
                body: JSON.stringify({
                    name: "录制房间示例",
                    isRecord: true, // 开启录制
                }),
            };

            fetch(url, requestInit).then(function(response) {
                return response.json();
            }).then(function(roomJSON) {
                console.log("录制房间创建成功:", roomJSON);
                alert("录制房间创建成功,UUID: " + roomJSON.uuid);
            }).catch(function(err) {
                console.error("创建房间失败:", err);
            });
        }

        // 开始回放
        function startReplay() {
            var replayRoomParams = {
                room: "a7xxx69", // 替换为实际的房间 UUID
                roomToken: "NETLESSROOM_YWxxxjk", // 替换为实际的 Room Token
                beginTimestamp: new Date("2023-01-01 08:00:00").getTime(),
                duration: 45 * 60 * 1000, // 45 分钟
            };

            var playerCallbacks = {
                onPhaseChanged: function(phase) {
                    console.log("播放状态:", phase);
                },
                onProgressTimeChanged: function(progressTime) {
                    console.log("播放进度:", Math.floor(progressTime / 1000) + "秒");
                }
            };

            whiteWebSdk.replayRoom(replayRoomParams, playerCallbacks).then(function(replayPlayer) {
                player = replayPlayer;
                player.bindHtmlElement(document.getElementById("whiteboard"));
                player.play();
                console.log("开始回放");
            }).catch(function(err) {
                console.error("回放失败:", err);
            });
        }

        // 暂停回放
        function pauseReplay() {
            if (player) {
                player.pause();
                console.log("暂停回放");
            }
        }

        // 继续回放
        function resumeReplay() {
            if (player) {
                player.play();
                console.log("继续回放");
            }
        }
    </script>
</body>
</html>

参考信息

开发注意事项

在使用录制与回放功能时,需要注意以下几点:

  • 录制延时:录制内容不是实时生成的,新创建的房间可能需要等待一段时间才能获得录制内容
  • 时间范围:建议根据实际使用场景设置合适的回放时间范围,避免回放过长的无效内容
  • 网络缓冲:回放时可能需要网络缓冲,特别是跳转到较远时间点时
  • 存储成本:长期开启录制功能会产生存储成本,建议根据业务需要合理使用
  • 播放器释放:使用完毕后记得调用 player.stop() 释放播放器资源

错误处理

常见错误及处理方法:

JavaScript
whiteWebSdk.replayRoom(replayRoomParams).then(function(player) {
    // 成功
}).catch(function(err) {
    if (err.message.includes("couldn't find any matching slices")) {
        console.log("录制内容还未生成,请稍后再试");
    } else {
        console.error("回放失败:", err.message);
    }
});

API 参考

相关文档