跳到主要内容

Flutter SDK

TgoRTC Flutter SDK,基于 LiveKit 的跨平台音视频通话 SDK。

安装

最新版本:

pubspec.yaml 中添加依赖:

dependencies:
tgortcflutter: ^1.0.0

依赖项

SDK 自动包含以下依赖:

  • livekit_client: ^2.3.6
  • flutter_webrtc: ^0.12.12

常用功能介绍

TgoRTC.instance.roomManager
TgoRTC.instance.participantManager
TgoRTC.instance.audioManager

快速开始

1. 初始化 SDK

import 'package:tgortcflutter/tgortc.dart';

TgoRTC.instance.init(
Options()
..debug = true
..mirror = false,
);

2. 创建房间信息并加入

import 'package:tgortcflutter/entity/const.dart';
import 'package:tgortcflutter/entity/room_info.dart';

final roomInfo = RoomInfo(
'roomName',
'token',
'url',
'loginUID',
'creatorUID',
);

roomInfo.maxParticipants = 9;
roomInfo.rtcType = RTCType.video;
roomInfo.timeout = 30;

await TgoRTC.instance.roomManager.joinRoom(
roomInfo,
micEnabled: true,
cameraEnabled: true,
screenShareEnabled: false,
);

说明: SDK 当前同时兼容 screenShareEnabled 和旧拼写 scrennShareEnabled, 文档示例统一使用 screenShareEnabled

3. 监听连接状态

import 'package:tgortcflutter/entity/const.dart';

void handleConnectStatus(String roomName, ConnectStatus status, String reason) {
print('房间 $roomName: $status - $reason');

switch (status) {
case ConnectStatus.connecting:
print('正在连接...');
break;
case ConnectStatus.connected:
print('已连接到房间');
break;
case ConnectStatus.reconnecting:
print('正在重连...');
break;
case ConnectStatus.reconnected:
print('已重新连接到房间');
break;
case ConnectStatus.disconnected:
print('已断开连接');
break;
}
}

TgoRTC.instance.roomManager.addConnectListener(handleConnectStatus);
TgoRTC.instance.roomManager.removeConnectListener(handleConnectStatus);

4. 获取参与者

final local = TgoRTC.instance.participantManager.getLocalParticipant();
final remotes = TgoRTC.instance.participantManager.getRemoteParticipants();
final all = TgoRTC.instance.participantManager.getAllParticipants();

TgoRTC.instance.participantManager.addNewParticipantListener((participant) {
print('新参与者加入: ${participant.uid}');
});

5. 媒体控制和事件

媒体控制仅适用于本地参与者。

import 'package:tgortcflutter/entity/const.dart';
import 'package:tgortcflutter/entity/video_info.dart';

final participant = TgoRTC.instance.participantManager.getLocalParticipant();

await participant?.setMicrophoneEnabled(true);
await participant?.setCameraEnabled(true);
await participant?.setScreenShareEnabled(true);
participant?.switchCamera();

await participant?.setSpeakerphoneOn(true, forceSpeakerOutput: false);
await participant?.toggleSpeakerphone();

final micEnabled = participant?.getMicrophoneEnabled() ?? false;
final cameraEnabled = participant?.getCameraEnabled() ?? false;
final screenShareEnabled = participant?.getScreenShareEnabled() ?? false;
final speakerEnabled = participant?.getSpeakerEnabled() ?? false;
final cameraPosition = participant?.getCameraPosition();
final audioLevel = participant?.getAudioLevel() ?? 0;
final isSpeaking = participant?.getIsSpeaking() ?? false;
final createdAt = participant?.createdAt;
final currentVideoInfo = participant?.currentVideoInfo;

void onMicChange(bool enabled) {
print('麦克风: ${enabled ? "开启" : "关闭"}');
}

void onCameraChange(bool enabled) {
print('摄像头: ${enabled ? "开启" : "关闭"}');
}

void onSpeakerChange(bool enabled) {
print('扬声器: ${enabled ? "开启" : "关闭"}');
}

void onScreenShareChange(bool enabled) {
print('屏幕共享: ${enabled ? "开启" : "关闭"}');
}

void onCameraPositionChange(TgoCameraPosition position) {
print('摄像头位置: $position');
}

void onSpeakingChange(bool speaking) {
print('正在说话: $speaking');
}

void onConnQualityChange(TgoConnectionQuality quality) {
print('连接质量: $quality');
}

void onJoined() {
print('参与者已加入');
}

void onLeave() {
print('参与者已离开');
}

void onTrackPublished() {
print('轨道已发布');
}

void onTrackUnpublished() {
print('轨道已取消发布');
}

void onVideoInfoChange(VideoInfo info) {
print('视频: ${info.resolutionString}, ${info.bitrateString}');
}

participant?.addMicrophoneStatusListener(onMicChange);
participant?.addCameraStatusListener(onCameraChange);
participant?.addSpeakerStatusListener(onSpeakerChange);
participant?.addScreenShareStatusListener(onScreenShareChange);
participant?.addCameraPositionListener(onCameraPositionChange);
participant?.addSpeakingListener(onSpeakingChange);
participant?.addConnQualityListener(onConnQualityChange);
participant?.addJoinedListener(onJoined);
participant?.addLeaveListener(onLeave);
participant?.addTrackPublishedListener(onTrackPublished);
participant?.addTrackUnpublishedListener(onTrackUnpublished);
participant?.addVideoInfoListener(onVideoInfoChange);

participant?.removeMicrophoneStatusListener(onMicChange);
participant?.removeCameraStatusListener(onCameraChange);
participant?.removeSpeakerStatusListener(onSpeakerChange);
participant?.removeScreenShareStatusListener(onScreenShareChange);
participant?.removeCameraPositionListener(onCameraPositionChange);
participant?.removeSpeakingListener(onSpeakingChange);
participant?.removeConnQualityListener(onConnQualityChange);
participant?.removeJoinedListener(onJoined);
participant?.removeLeaveListener(onLeave);
participant?.removeTrackPublishedListener(onTrackPublished);
participant?.removeTrackUnpublishedListener(onTrackUnpublished);
participant?.removeVideoInfoListener(onVideoInfoChange);

6. 渲染视频轨道

import 'package:flutter/material.dart';
import 'package:flutter_webrtc/flutter_webrtc.dart';
import 'package:livekit_client/livekit_client.dart';
import 'package:tgortcflutter/tgortc.dart';
import 'package:tgortcflutter/track/tgo_track_renderer.dart';

class VideoView extends StatefulWidget {
final TgoParticipant participant;

const VideoView({super.key, required this.participant});


State<VideoView> createState() => _VideoViewState();
}

class _VideoViewState extends State<VideoView> {
late final TgoTrackRenderer _renderer;


void initState() {
super.initState();
_renderer = TgoTrackRenderer(
source: TrackSource.camera,
fit: RTCVideoViewObjectFit.RTCVideoViewObjectFitCover,
mirror: true,
placeholder: const SizedBox.shrink(),
onTrackChange: (hasTrack) {
debugPrint('轨道可用: $hasTrack');
},
);
_renderer.setParticipant(widget.participant);
}


Widget build(BuildContext context) {
return _renderer.build();
}
}

7. 音频管理

final isSpeakerOn = TgoRTC.instance.audioManager.isSpeakerOn;
final canSwitchSpeaker = TgoRTC.instance.audioManager.canSwitchSpeakerphone;
final speakerOn = TgoRTC.instance.audioManager.speakerOn;

final inputDevices = await TgoRTC.instance.audioManager.getAudioInputDevices();
final outputDevices = await TgoRTC.instance.audioManager.getAudioOutputDevices();
final videoDevices = await TgoRTC.instance.audioManager.getDevices('videoinput');

await TgoRTC.instance.audioManager.setSpeakerphoneOn(true);
await TgoRTC.instance.audioManager.toggleSpeakerphone();

if (inputDevices.isNotEmpty) {
await TgoRTC.instance.audioManager.switchAudioInputDevice(
inputDevices.first.deviceId,
);
}

if (outputDevices.isNotEmpty) {
await TgoRTC.instance.audioManager.switchAudioOutputDevice(
outputDevices.first.deviceId,
);
}

void onDeviceChange(List<dynamic> devices) {
print('设备变化: $devices');
}

TgoRTC.instance.audioManager.addDeviceChangeListener(onDeviceChange);
TgoRTC.instance.audioManager.removeDeviceChangeListener(onDeviceChange);

8. 离开房间

await TgoRTC.instance.roomManager.leaveRoom();

API 参考

TgoRTC

属性类型说明
instanceTgoRTC单例实例
optionsOptionsSDK 配置
roomManagerTgoRoomManager房间管理
participantManagerTgoParticipantManager参与者管理
audioManagerTgoAudioManager音频管理

TgoRoomManager

方法说明
joinRoom(roomInfo, {micEnabled, cameraEnabled, screenShareEnabled})加入房间
leaveRoom()离开当前房间
addConnectListener(listener)添加连接状态监听器
removeConnectListener(listener)移除连接状态监听器
addVideoInfoListener(listener)添加本地视频信息监听器
removeVideoInfoListener(listener)移除本地视频信息监听器
属性说明
roomLiveKit Room 实例
currentRoomInfo当前房间信息
currentVideoInfo当前本地视频信息

TgoParticipantManager

方法说明
getLocalParticipant()获取本地参与者
getRemoteParticipants()获取远程参与者
getAllParticipants()获取所有参与者
getPendingParticipantCreatedAt()获取未加入参与者的创建时间
removeParticipantByUid(uid)按 UID 移除未加入参与者
removePendingParticipants(roomName, uids)移除未加入参与者
missed(roomName, uids)标记未接听参与者
inviteParticipant(uids, {roomName})邀请参与者
invite(roomName, uids)邀请参与者
addNewParticipantListener(listener)监听新参与者
removeNewParticipantListener(listener)移除新参与者监听

TgoParticipant

媒体控制方法

方法说明
setMicrophoneEnabled(enabled)启用/禁用麦克风
setCameraEnabled(enabled)启用/禁用摄像头
setScreenShareEnabled(enabled)启用/禁用屏幕共享
switchCamera()切换前后摄像头
setSpeakerphoneOn(on, {forceSpeakerOutput})设置扬声器
toggleSpeakerphone()切换扬声器

状态获取方法

方法说明
getMicrophoneEnabled()获取麦克风状态
getCameraEnabled()获取摄像头状态
getScreenShareEnabled()获取屏幕共享状态
getSpeakerEnabled()获取扬声器状态
getCameraPosition()获取摄像头位置
getVideoTrack({source})获取视频轨道
getAudioLevel()获取当前音量
getIsSpeaking()是否正在说话

事件监听方法

方法说明
addMicrophoneStatusListener(listener)监听麦克风状态变化
addCameraStatusListener(listener)监听摄像头状态变化
addSpeakerStatusListener(listener)监听扬声器状态变化
addScreenShareStatusListener(listener)监听屏幕共享状态变化
addCameraPositionListener(listener)监听摄像头位置变化
addSpeakingListener(listener)监听说话状态变化
addConnQualityListener(listener)监听连接质量变化
addJoinedListener(listener)监听参与者加入
addLeaveListener(listener)监听参与者离开
addTrackPublishedListener(listener)监听轨道发布
addTrackUnpublishedListener(listener)监听轨道取消发布
addVideoInfoListener(listener)监听视频信息变化
remove...Listener(listener)移除对应监听器

属性

属性说明
uid参与者 ID
isLocal是否为本地参与者
isJoined是否已加入
createdAt创建时间
currentVideoInfo当前视频信息

TgoTrackRenderer

TgoTrackRenderer({
TrackSource source = TrackSource.camera,
RTCVideoViewObjectFit fit = RTCVideoViewObjectFit.RTCVideoViewObjectFitCover,
bool? mirror,
Widget? placeholder,
ValueChanged<bool>? onTrackChange,
})
方法说明
setParticipant(participant)设置参与者
clear()清除参与者
build()构建视频 Widget

TgoAudioManager

方法 / 属性说明
isSpeakerOn当前是否使用扬声器
canSwitchSpeakerphone是否支持切换扬声器
speakerOn底层硬件扬声器状态
currentAudioInputDeviceId当前输入设备 ID
currentAudioOutputDeviceId当前输出设备 ID
addDeviceChangeListener(listener)添加设备变化监听
removeDeviceChangeListener(listener)移除设备变化监听
setSpeakerphoneOn(on, {forceSpeakerOutput})设置扬声器
toggleSpeakerphone()切换扬声器
getAudioInputDevices()获取音频输入设备
getAudioOutputDevices()获取音频输出设备
getDevices(kind)获取指定类型设备
switchAudioInputDevice(deviceId, {setAsDefault = true})切换音频输入设备
switchAudioOutputDevice(deviceId, {setAsDefault = true})切换音频输出设备

枚举类型

ConnectStatus

enum ConnectStatus {
connecting,
connected,
reconnecting,
reconnected,
disconnected,
}

RTCType

enum RTCType {
audio,
video,
}

TgoConnectionQuality

enum TgoConnectionQuality {
unknown,
excellent,
good,
poor,
lost,
}

TgoCameraPosition

enum TgoCameraPosition {
front,
back,
}

RoomInfo 类

class RoomInfo {
String roomName;
String token;
String url;
String loginUID;
String creatorUID;
int maxParticipants;
RTCType rtcType;
bool isP2P;
List<String> uidList;
int timeout;

String getP2PToUID();
bool isCreator();
}

配置选项

class Options {
bool mirror = false;
bool debug = true;
}

最佳实践

保存参与者引用

避免重复调用 getLocalParticipant(),建议在连接成功后保存本地参与者引用,并在销毁时移除监听器。

连接成功后再启用媒体

参考实际 Flutter 集成示例,Android 上为了避免 flutter_webrtc 在部分场景下的状态不同步或崩溃问题,推荐先仅建立房间连接,再在连接成功后顺序启用本地媒体:

await TgoRTC.instance.roomManager.joinRoom(
roomInfo,
micEnabled: false,
cameraEnabled: false,
);

final local = TgoRTC.instance.participantManager.getLocalParticipant();
await local?.setMicrophoneEnabled(true);
await local?.setCameraEnabled(true);

处理未接听参与者

如果业务侧已经知道哪些被邀请成员未接听,可以调用:

TgoRTC.instance.participantManager.removePendingParticipants(
roomInfo.roomName,
['user_b', 'user_c'],
);

平台配置

Android

android/app/src/main/AndroidManifest.xml 添加权限:

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />

iOS

ios/Runner/Info.plist 添加权限描述:

<key>NSCameraUsageDescription</key>
<string>需要访问摄像头进行视频通话</string>
<key>NSMicrophoneUsageDescription</key>
<string>需要访问麦克风进行语音通话</string>