Skip to content

Electron API 说明 ​

Electron SDK 在 Main 进程中连接设备、播放音视频、发送对讲音频并收发消息。安装、窗口隔离和打包配置见 Electron SDK 接入。

初始化与错误 ​

ts
TiRtc.init({ appId: 'your-app-id' }); // app.whenReady() 之后
// 释放所有连接和媒体对象之后:
TiRtc.shutdown();

大部分控制方法同步返回 void;正常返回表示操作被受理,SDK 失败抛出 TiRtcError,参数类型错误可能抛出 TypeError。TiRtcError.code 是字符串类别,nativeCode 是数字错误码。异步方法返回 Promise,必须捕获拒绝;状态与错误回调继续反映后续运行结果。

连接与播放 ​

已完成 TiRtc.init(),窗口 window 为 Main 持有的 BrowserWindow。以下会话对象创建音频、视频输出并发起连接。先持有实例,再调用 start(),使启动失败时也能处理资源清理。

ts
import type { BrowserWindow } from 'electron';
import {
  TiRtcConn, TiRtcAudioOutput, TiRtcVideoOutput, TiVideoView,
} from 'tirtc-electron';

export class PlaybackSession {
  private conn = new TiRtcConn();
  private audio: TiRtcAudioOutput | undefined;
  private video: TiRtcVideoOutput | undefined;
  private view: TiVideoView | undefined;

  start(window: BrowserWindow, remoteId: string, token: string): void {
    this.audio = new TiRtcAudioOutput();
    this.video = new TiRtcVideoOutput();
    this.view = new TiVideoView(window, { x: 0, y: 0, width: 640, height: 360 });
    this.audio.onError = error => console.error('audio', error.code, error.nativeCode);
    this.video.onError = error => console.error('video', error.code, error.nativeCode);
    this.audio.onStateChanged = state => console.info('audio', state);
    this.video.onStateChanged = state => console.info('video', state);
    this.audio.attach(this.conn, 10);
    this.video.mount(this.view);
    this.video.attach(this.conn, 11);
    this.conn.onStateChanged = (state, error) => {
      if (error) console.error('connection', error.code, error.nativeCode);
      if (state === 'connected') {
        try { this.conn.subscribeAudio(10); this.conn.subscribeVideo(11); }
        catch (error) { console.error('subscribe', error); }
      }
    };
    this.conn.connect({ remoteId, token });
  }

  close(): void {
    // 清理失败时保留实例,由业务控制流程处理或重试。
    if (this.video) {
      this.video.detach(); this.video.unmount(); this.video.dispose(); this.video = undefined;
    }
    if (this.audio) {
      this.audio.detach(); this.audio.dispose(); this.audio = undefined;
    }
    if (this.view) { this.view.dispose(); this.view = undefined; }
    this.conn.disconnect();
    this.conn.dispose();
  }
}

在 Main 控制流程中创建 const session = new PlaybackSession(),再调用 session.start(window, deviceId, token);启动失败或业务结束时调用 session.close()。每次调用都用 try/catch 处理异常;清理失败时保留 session,处理或重试成功后再关闭 SDK。一个会话实例只启动一轮,成功关闭后创建新实例。不要在 SDK 回调中同步关闭会话。

连接成功以状态 connected 为准;音频 playing、视频 rendering 表示输出已推进。播放不需要额外的 play()。

Stream ID 为 0..15,发送、输出绑定和订阅保持一致,同一方向不同音视频流不能共用编号。示例 10 / 11 可按业务修改。TiVideoView.setBounds(rectangle) 调整原生画面区域;分辨率变化由 video.onRenderSizeChanged 通知。

Connection 控制与消息 ​

用途方法 / 回调
建连与断开connect({remoteId, token})、disconnect()、dispose()
音频订阅subscribeAudio(id)、unsubscribeAudio(id)
视频订阅subscribeVideo(id)、unsubscribeVideo(id)、requestVideoKeyframe(id)
命令sendCommand(commandId, data: Uint8Array)、onCommand
流消息sendStreamMessage({streamId, timestampMs, data})、onStreamMessage

自定义命令字从 0x2001 起;流消息时间戳为非负 uint32 毫秒。用 try/catch 处理同步调用失败。

Audio Input ​

自定义音频输入需使用预发布包,安装方式见 Electron SDK 接入。

按任务选择麦克风对讲、发送外部 PCM或处理麦克风音频后发送。

ts
interface TiRtcAudioInputOptions {
  media?: number; // 1 PCM、2 G.711 A-law(默认)、3 AAC、4 Opus、5 AMR-NB
  sampleRateHz?: 8000 | 16000; // 默认 16000;AMR-NB 仅 8000
  channels?: 1;
  mode?: 'builtIn' | 'custom'; // 默认 builtIn
  captureEnabled?: boolean; // 默认 true
  aecMode?: 'disabled' | 'enabled';
  agcLevel?: 'disabled' | 'low' | 'medium' | 'high';
  ansLevel?: 'disabled' | 'low' | 'medium' | 'high';
}

默认模式由 SDK 采集、编码和发送。custom + false 使用外部 PCM,不打开麦克风;custom + true 通过 onPcmCaptured 回调 SDK 采集的 PCM,应用处理后必须显式提交。使用 SDK 麦克风前,应用取得系统权限。

操作签名
创建与配置new TiRtcAudioInput()、setOptions(options): void
绑定与启动attach(conn, streamId): void、start(): void
PCM 回调onPcmCaptured: ((pcm: Uint8Array) => void) | null
提交submitPcm(pcm: Uint8Array): void
停止与释放stop(): void、detach(): void、dispose(): void
状态与错误state、onStateChanged、onError

运行时不能修改参数;停止后可修改同一输入方式的参数,改变 mode 或 captureEnabled 还需先解绑。每次 setOptions 应显式传 media,省略时回到 G.711 A-law;其他省略字段保留已接受值。

PCM 为 S16LE、单声道、8 / 16 kHz,与配置一致。每次非空、偶数字节,不限固定帧长;单输入总预算 1 MiB。提交返回前复制当前 Uint8Array 的有效范围,成功不等于远端收到。暂满抛出 audio-input-buffer-full(6139),单次过大为 range-too-large(6117),本块均未受理。回调在 Main JavaScript 线程执行,收到 SDK 软件 3A 之前的 PCM;修改回调数据不会自动发送。

停止前先结束应用生产 / 处理任务。stop() 取消剩余数据,不等待排空,保留绑定供再次启动;停止成功后 detach()、dispose() 最终释放。已停止时可能抛出 not-started,处理后可继续清理。不要在 PCM 回调内同步停止或释放,安排到回调结束后的控制流程。

输出、录制与截图 ​

  • TiRtcAudioOutput.setOptions(...) 配置音频处理及缓冲;setVolume(percent) 调整播放音量。
  • TiRtcVideoOutput.setOptions(...) 配置解码偏好及缓冲;mount(view) / unmount() 挂载 / 解除原生视图。
  • conn.startRecording({videoStreamId: 11, audioStreamId: 10}) 返回 TiRtcRecordingTask;保持订阅送流,await task.stop() 取得 MP4 文件。
  • 解码有可用视频帧后,await video.takeSnapshot() 取得 JPEG 文件。
  • 文件提供 path,先用 Node.js 文件 API 复制到业务目录,再 await file.delete() 清理临时源。业务不需要音频时省略 audioStreamId。

释放与日志 ​

结束应用侧音频源及录制任务,再按输入停止 / 解绑 / 释放、输出解绑 / 解除视图 / 释放、视图释放、连接断开 / 释放、TiRtc.shutdown() 的顺序清理。每步失败时处理异常,保留对象引用,避免继续销毁仍在使用的父对象。

不要在 SDK 回调中同步销毁同一资源树,可通过 setImmediate 安排控制动作。回调自行捕获异常,避免异常进入事件循环。需要协助排查时,await TiRtcLogging.upload() 返回日志 ID。

TiRTC 开发文档