Browse Source

feat(rtc): 添加RTC管理器并初始化-声网SDK 新增RTCManager类,实现单例模式管理音视频通话

- 集成声网RTC SDK,支持频道加入、音视频控制等功能
- 在main.dart中初始化RTC引擎,配置App ID
- 提供完整的RTC事件回调处理机制- 实现本地和远程视频视图设置功能- 支持摄像头切换、音视频静音等基础操作
ios
Jolie 4 months ago
parent
commit
9f85413e18
2 changed files with 427 additions and 0 deletions
  1. 2
      lib/main.dart
  2. 425
      lib/rtc/rtc_manager.dart

2
lib/main.dart

@ -6,6 +6,7 @@ import 'package:dating_touchme_app/network/network_service.dart';
import 'package:dating_touchme_app/pages/main/main_page.dart';
import 'package:dating_touchme_app/pages/mine/login_page.dart';
import 'package:dating_touchme_app/pages/mine/user_info_page.dart';
import 'package:dating_touchme_app/rtc/rtc_manager.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
@ -21,6 +22,7 @@ void main() async {
// - release模式
EnvConfig.setEnvironment(Environment.dev);
RTCManager.instance.initialize(appId: '4c2ea9dcb4c5440593a418df0fdd512d');
IMManager.instance.initialize('1165251016193374#demo');
//
final networkService = NetworkService();

425
lib/rtc/rtc_manager.dart

@ -0,0 +1,425 @@
import 'package:agora_rtc_engine/agora_rtc_engine.dart';
/// RTC
class RTCManager {
//
static final RTCManager _instance = RTCManager._internal();
factory RTCManager() => _instance;
// getter用于instance访问
static RTCManager get instance => _instance;
RtcEngine? _engine;
bool _isInitialized = false;
bool _isInChannel = false;
String? _currentChannelId;
int? _currentUid;
//
Function(RtcConnection connection, int elapsed)? onJoinChannelSuccess;
Function(RtcConnection connection, int remoteUid, int elapsed)? onUserJoined;
Function(
RtcConnection connection,
int remoteUid,
UserOfflineReasonType reason,
)?
onUserOffline;
Function(RtcConnection connection, RtcStats stats)? onLeaveChannel;
Function(
RtcConnection connection,
ConnectionStateType state,
ConnectionChangedReasonType reason,
)?
onConnectionStateChanged;
Function(int uid, UserInfo userInfo)? onUserInfoUpdated;
Function(RtcConnection connection, int uid, int elapsed)?
onFirstRemoteVideoDecoded;
Function(
RtcConnection connection,
VideoSourceType sourceType,
int uid,
int width,
int height,
int rotation,
)?
onVideoSizeChanged;
Function(RtcConnection connection, int uid, bool muted)? onUserMuteAudio;
Function(RtcConnection connection, int uid, bool muted)? onUserMuteVideo;
Function(RtcConnection connection)? onConnectionLost;
Function(RtcConnection connection, int code, String msg)? onError;
RTCManager._internal() {
print('RTCManager instance created');
}
/// RTC Engine
/// [appId] App ID
/// [channelProfile]
Future<bool> initialize({
required String appId,
ChannelProfileType channelProfile =
ChannelProfileType.channelProfileCommunication,
}) async {
try {
if (_isInitialized && _engine != null) {
print('RTC Engine already initialized');
return true;
}
// RTC Engine
_engine = createAgoraRtcEngine();
// RTC Engine
await _engine!.initialize(
RtcEngineContext(appId: appId, channelProfile: channelProfile),
);
//
_registerEventHandlers();
_isInitialized = true;
print('RTC Engine initialized successfully');
return true;
} catch (e) {
print('Failed to initialize RTC Engine: $e');
return false;
}
}
///
void _registerEventHandlers() {
if (_engine == null) return;
_engine!.registerEventHandler(
RtcEngineEventHandler(
onJoinChannelSuccess: (RtcConnection connection, int elapsed) {
_isInChannel = true;
_currentChannelId = connection.channelId;
print('加入频道成功,频道名:${connection.channelId},耗时:${elapsed}ms');
if (onJoinChannelSuccess != null) {
onJoinChannelSuccess!(connection, elapsed);
}
},
onUserJoined: (RtcConnection connection, int remoteUid, int elapsed) {
print('用户加入,UID:$remoteUid');
if (onUserJoined != null) {
onUserJoined!(connection, remoteUid, elapsed);
}
},
onUserOffline:
(
RtcConnection connection,
int remoteUid,
UserOfflineReasonType reason,
) {
print('用户离开,UID:$remoteUid,原因:$reason');
if (onUserOffline != null) {
onUserOffline!(connection, remoteUid, reason);
}
},
onLeaveChannel: (RtcConnection connection, RtcStats stats) {
_isInChannel = false;
_currentChannelId = null;
print('离开频道,统计信息:${stats.duration}');
if (onLeaveChannel != null) {
onLeaveChannel!(connection, stats);
}
},
onConnectionStateChanged:
(
RtcConnection connection,
ConnectionStateType state,
ConnectionChangedReasonType reason,
) {
print('连接状态改变:$state,原因:$reason');
if (onConnectionStateChanged != null) {
onConnectionStateChanged!(connection, state, reason);
}
},
onUserInfoUpdated: (int uid, UserInfo userInfo) {
print('用户信息更新,UID:$uid');
if (onUserInfoUpdated != null) {
onUserInfoUpdated!(uid, userInfo);
}
},
onFirstRemoteVideoDecoded:
(
RtcConnection connection,
int uid,
int width,
int height,
int elapsed,
) {
print('首次远程视频解码,UID:$uid,分辨率:${width}x${height}');
if (onFirstRemoteVideoDecoded != null) {
onFirstRemoteVideoDecoded!(connection, uid, elapsed);
}
},
onVideoSizeChanged:
(
RtcConnection connection,
VideoSourceType sourceType,
int uid,
int width,
int height,
int rotation,
) {
print('视频尺寸改变,UID:$uid,分辨率:${width}x${height}');
if (onVideoSizeChanged != null) {
onVideoSizeChanged!(
connection,
sourceType,
uid,
width,
height,
rotation,
);
}
},
onUserMuteAudio: (RtcConnection connection, int uid, bool muted) {
print('用户静音状态改变,UID:$uid,静音:$muted');
if (onUserMuteAudio != null) {
onUserMuteAudio!(connection, uid, muted);
}
},
onUserMuteVideo: (RtcConnection connection, int uid, bool muted) {
print('用户视频状态改变,UID:$uid,关闭:$muted');
if (onUserMuteVideo != null) {
onUserMuteVideo!(connection, uid, muted);
}
},
onConnectionLost: (RtcConnection connection) {
print('连接丢失');
if (onConnectionLost != null) {
onConnectionLost!(connection);
}
},
onError: (ErrorCodeType err, String msg) {
print('RTC Engine 错误:$err,消息:$msg');
if (onError != null) {
onError!(
RtcConnection(
channelId: _currentChannelId ?? '',
localUid: _currentUid ?? 0,
),
err.value(),
msg,
);
}
},
),
);
}
///
Future<void> enableVideo() async {
if (_engine == null) {
throw Exception('RTC Engine not initialized');
}
await _engine!.enableVideo();
print('视频已启用');
}
///
Future<void> disableVideo() async {
if (_engine == null) {
throw Exception('RTC Engine not initialized');
}
await _engine!.disableVideo();
print('视频已禁用');
}
///
Future<void> enableAudio() async {
if (_engine == null) {
throw Exception('RTC Engine not initialized');
}
await _engine!.enableAudio();
print('音频已启用');
}
///
Future<void> disableAudio() async {
if (_engine == null) {
throw Exception('RTC Engine not initialized');
}
await _engine!.disableAudio();
print('音频已禁用');
}
///
Future<void> startPreview() async {
if (_engine == null) {
throw Exception('RTC Engine not initialized');
}
await _engine!.startPreview();
print('本地视频预览已开启');
}
///
Future<void> stopPreview() async {
if (_engine == null) {
throw Exception('RTC Engine not initialized');
}
await _engine!.stopPreview();
print('本地视频预览已停止');
}
///
/// [viewId] ID
/// [mirrorMode]
Future<void> setupLocalVideo({
required int viewId,
VideoSourceType sourceType = VideoSourceType.videoSourceCameraPrimary,
VideoMirrorModeType mirrorMode = VideoMirrorModeType.videoMirrorModeAuto,
}) async {
if (_engine == null) {
throw Exception('RTC Engine not initialized');
}
await _engine!.setupLocalVideo(
VideoCanvas(view: viewId, sourceType: sourceType, mirrorMode: mirrorMode),
);
print('本地视频视图已设置,viewId:$viewId');
}
///
/// [uid] ID
/// [viewId] ID
Future<void> setupRemoteVideo({
required int uid,
required int viewId,
VideoSourceType sourceType = VideoSourceType.videoSourceCameraPrimary,
VideoMirrorModeType mirrorMode =
VideoMirrorModeType.videoMirrorModeDisabled,
}) async {
if (_engine == null) {
throw Exception('RTC Engine not initialized');
}
await _engine!.setupRemoteVideo(
VideoCanvas(
uid: uid,
view: viewId,
sourceType: sourceType,
mirrorMode: mirrorMode,
),
);
print('远程视频视图已设置,UID:$uid,viewId:$viewId');
}
///
/// [token]
/// [channelId] ID
/// [uid] ID0
/// [options]
Future<void> joinChannel({
String? token,
required String channelId,
int uid = 0,
ChannelMediaOptions? options,
}) async {
if (_engine == null) {
throw Exception('RTC Engine not initialized');
}
if (_isInChannel) {
print('已经在频道中,先离开当前频道');
await leaveChannel();
}
_currentUid = uid;
await _engine!.joinChannel(
token: token ?? '',
channelId: channelId,
uid: uid,
options: options ?? const ChannelMediaOptions(),
);
print('正在加入频道:$channelId,UID:$uid');
}
///
Future<void> leaveChannel() async {
if (_engine == null) {
throw Exception('RTC Engine not initialized');
}
if (!_isInChannel) {
print('当前不在频道中');
return;
}
await _engine!.leaveChannel();
_currentUid = null;
print('已离开频道');
}
///
Future<void> switchCamera() async {
if (_engine == null) {
throw Exception('RTC Engine not initialized');
}
await _engine!.switchCamera();
print('摄像头已切换');
}
/// /
/// [muted] true表示静音false表示取消静音
Future<void> muteLocalAudio(bool muted) async {
if (_engine == null) {
throw Exception('RTC Engine not initialized');
}
await _engine!.muteLocalAudioStream(muted);
print('本地音频${muted ? "已静音" : "已取消静音"}');
}
/// /
/// [enabled] true表示开启false表示关闭
Future<void> muteLocalVideo(bool enabled) async {
if (_engine == null) {
throw Exception('RTC Engine not initialized');
}
await _engine!.muteLocalVideoStream(!enabled);
print('本地视频${enabled ? "已开启" : "已关闭"}');
}
///
/// [role]
Future<void> setClientRole({
required ClientRoleType role,
ClientRoleOptions? options,
}) async {
if (_engine == null) {
throw Exception('RTC Engine not initialized');
}
await _engine!.setClientRole(role: role, options: options);
print('客户端角色已设置为:$role');
}
///
bool get isInChannel => _isInChannel;
/// ID
String? get currentChannelId => _currentChannelId;
/// ID
int? get currentUid => _currentUid;
/// RTC Engine
RtcEngine? get engine => _engine;
///
Future<void> dispose() async {
try {
if (_isInChannel) {
await leaveChannel();
}
if (_engine != null) {
await _engine!.release();
_engine = null;
}
_isInitialized = false;
_isInChannel = false;
_currentChannelId = null;
_currentUid = null;
print('RTC Engine disposed');
} catch (e) {
print('Failed to dispose RTC Engine: $e');
}
}
}
Loading…
Cancel
Save