Tutorial: 如何实现音视频的自定义加解密

如何实现音视频的自定义加解密

本文介绍如何实现音视频数据的自定义加解密

原理说明

TRTC Electron SDK 从 11.7.602 版本开始,支持以动态库插件的方式,实现用户对音视频数据的自定义加密。

实现步骤:

  1. 基于 TRTC Electron SDK 提供的 C++ 头文件,开发自定义加解密库。
  2. Javascript 层调用 addPlugin() 接口添加自定义加解密插件,传入构建好的自定义加解密库文件路径;再用插件的 enable() 接口开启自定义加解密。

TRTC Electron SDK 加解密过程

开发自定义加解密插件(C++)

SDK 提供了两个 C++ 头文件实现自定义加解密:

  • ITRTCPlugin.h 头文件声明了插件对象的创建、销毁、初始化、设置参数等接口,用于管理插件的生命周期。
  • IMediaEncryptDecryptPlugin.h 头文件定义了监听 SDK 音视频编解码回调的接口,用于完成对音视频数据的加解密。

MediaEncryptDecryptPlugin.zip是一个示例工程,实现了一个简单的加解密插件,支持 Windows 和 Mac OS 下构建。

ITRTCPlugin.h

class ITRTCPlugin {
public:
    virtual ~ITRTCPlugin() {}

    /**
     * 初始化插件
     *
     * 创建插件后,会立刻触发该初始化函数,用户可以在这里做一些初始化操作。
     * @return true: 插件初始化成功,false: 插件初始化失败。
     *   如果返回 false 表示初始化失败,Javascript 层通过 setPluginCallback() 函数设置回调函数会收到错误码:-4.
     */
    virtual bool init() = 0;

    /**
     * 反初始化插件
     *
     * 插件销毁时,会触发该函数,用户可以在这里做一些清理操作。
     *
     * @return true: 插件反初始化成功,false: 插件反初始化失败。
     */
    virtual bool uninit() = 0;

    /**
     * 资源加载
     *
     * 会在 init() 函数之后被调用。
     *
     * @param path 插件资源目录。该目录为当前插件库文件所在目录,如果插件有其它资源文件依赖,可以放在插件库文件同目录下,在这里加载。
     * @return true: 资源加载成功,false: 资源加载失败。
     *   如果返回 false 表示资源加载失败,Javascript 层通过 setPluginCallback() 函数设置回调函数会收到错误码:-5.
     */
    virtual bool load(const char* path) = 0;

    /**
     * 资源卸载
     *
     * 会在 uninit() 函数之前被调用。
     */
    virtual bool unload() = 0;

    /**
     * 开启/关闭当前插件
     *
     * Javascript 层的 TRTCPluginInfo.enable/disable() 接口调用会触发该函数。
     *
     * @param enabled true: 开启插件,false: 关闭插件。
     * @return true: 成功开启/关闭插件,false: 失败。
     */
    virtual bool enable(bool enabled) = 0;

    /**
     * 设置插件参数
     *
     * Javascript 层的 TRTCPluginInfo.setParameter() 接口调用会触发该函数。
     *
     * @param param 插件参数,格式为 json 字符串。
     * @return true: 设置成功,false: 设置失败。
     */
    virtual bool setParameter(const char* param) = 0;

    /**
     * 获取插件类型
     *
     * 具体的插件子类中需要重写。
     */
    virtual TRTC_PLUGIN_TYPE getPluginType() {
        return TRTC_PLUGIN_TYPE::TRTC_PLUGIN_UNKNOWN;
    }

    /**
     * 设置错误回调函数
     *
     * @param callback 回调函数。是对 Javascript 层 setPluginCallback() 接口设置回调函数的封装。
     */
    void setErrorCallback(PluginErrorCallbackFunc callback, void* param) {
        error_callback_ = callback;
        param_ = param;
    }

    /**
     * 错误码上报函数
     *
     * 该函数调用后,会触发 Javascript 层 setPluginCallback() 接口设置的回调函数,将错误码和错误信息透传给 Javascript 层,用户可以根据错误码做相应处理。
     *
     * @param error 错误码。
     * @param msg 错误描述。
     */
    void onError(int error, const char* msg) {
        if (error_callback_) {
            error_callback_(error, msg, param_);
        }
    }

  private:
      PluginErrorCallbackFunc error_callback_ = nullptr;
      void* param_ = nullptr;
};

// 创建插件实例对象,Javascript 层 addPlugin() 接口最终会调用到该函数
extern "C" EXPORTS ITRTCPlugin* createTRTCPlugin();

// 销毁插件实例对象,Javascript 层 removePlugin() 接口最终会调用到该函数
extern "C" EXPORTS void destoryTRTCPlugin(ITRTCPlugin*);

IMediaEncryptDecryptPlugin.h

struct LiteAVBuffer {
  uint8_t* data;
  uint32_t size;
};

struct EncodedData {
  // didEncodeVideo 和 didEncodeAudio 回调时,此字段为 null;
  const char* userId;
  // 视频流类型,参考 TRTCVideoStreamType,audio 时,此字段为0
  int streamType;
  // 原始数据
  LiteAVBuffer originData;
  // 写回处理后的数据
  LiteAVBuffer processedData;
};

class IMediaEncryptDecryptPlugin : public ITRTCPlugin {
 public:
  ~IMediaEncryptDecryptPlugin() override {}

  virtual void setMallocMemoryCallback(MallocMemory callback) = 0;

  /**
   * 视频编码数据回调
   */
  virtual bool didEncodeVideo(EncodedData& data) = 0;

  /**
   * 视频解码数据回调
   */
  virtual bool willDecodeVideo(EncodedData& data) = 0;

  /**
   * 音频编码数据回调
   */
  virtual bool didEncodeAudio(EncodedData& data) = 0;

  /**
   * 音频解码数据回调
   */
  virtual bool willDecodeAudio(EncodedData& data) = 0;
};

使用自定义加解密插件(Javascript)

通过 SDK 提供的 addPlugin() 接口创建一个自定义加解密插件,返回一个 TRTCPluginInfo 对象,调用该对象的 enable() 接口开启自定义加解密。

import TRTCCloud, { TRTCPluginType, TRTCPluginInfo } from 'trtc-electron-sdk';

const trtcCloud = TRTCCloud.getTRTCShareInstance();

// 开启自定义加解密功能
trtcCloud.setPluginParams(TRTCPluginType.TRTCPluginTypeMediaEncryptDecrypt, {
  enable: true // 设置为 false 后,会停止发送音视频数据到自定义加解密插件
});

// 注册插件回调监听
trtcCloud.setPluginCallback((pluginId, errorCode, msg) => {
  console.log(`plugin callback: ${pluginId}, errorCode: ${errorCode}, msg: ${msg}`);
});

// 创建加解密插件
const plugin: TRTCPluginInfo = trtcCloud.addPlugin({
  id: 'custom-encrypt-decrypt-plugi', // 用户必须保证 ID 的唯一性
  path: '', // 构建好的加解密库文件,Windows 下是 ‘.dll’ 文件,MacOS 下是 ‘.dylib’ 文件
  type: TRTCPluginType.TRTCPluginTypeMediaEncryptDecrypt // 音视频自定义加解密插件类型
});
// 启动插件
plugin.enable();
// 设置插件参数
plugin.setParameter(JSON.stringify({'key1':'value1', 'key2':123}));
  • TRTCCloud.setPluginParams() 接口

    支持通过 enable 参数控制是否开启 SDK 的加解密功能。

  • TRTCCloud.addPlugin() 接口

    添加自定义插件,依次触发 C++ ITRTCPlugin.h 类中的 createTRTCPlugin()、init()、load() 函数。

  • TRTCCloud.removePlugin() 接口

    删除自定义插件,依次触发 C++ ITRTCPlugin.h 类中的 unload()、uninit()、destoryTRTCPlugin() 函数。

  • TRTCCloud.setPluginCallback() 接口

    设置插件回调函数,监听插件创建、销毁、运行情况。设置的回调函数有两个触发源头:

    1. addPlugin/removePlugin() 时的处理结果通知;
    2. 插件内部 C++ ITRTCPlugin.h 类中的 onError() 函数触发的异常通知。
  • TRTCPluginInfo.enable/disable() 接口

    开启/关闭当前插件,触发 C++ ITRTCPlugin.h 类中的 enable() 函数。

  • TRTCPluginInfo.setParameter() 接口

    给当前插件设置参数,触发 C++ ITRTCPlugin.h 类中的 setParameter() 函数。