|
|
|
@ -11,6 +11,9 @@ import '../pages/discover/live_room_page.dart'; |
|
|
|
class RTCManager { |
|
|
|
/// 频道加入状态通知,用于UI监听 |
|
|
|
final ValueNotifier<bool> channelJoinedNotifier = ValueNotifier<bool>(false); |
|
|
|
final ValueNotifier<List<int>> remoteUsersNotifier = ValueNotifier<List<int>>( |
|
|
|
<int>[], |
|
|
|
); |
|
|
|
RtcEngine? get engine => _engine; |
|
|
|
bool get isInChannel => _isInChannel; |
|
|
|
int? get currentUid => _currentUid; |
|
|
|
@ -26,8 +29,8 @@ class RTCManager { |
|
|
|
bool _isInChannel = false; |
|
|
|
String? _currentChannelId; |
|
|
|
int? _currentUid; |
|
|
|
int? _streamId; |
|
|
|
|
|
|
|
ClientRoleType _clientRole = ClientRoleType.clientRoleBroadcaster; |
|
|
|
final List<int> _remoteUserIds = <int>[]; |
|
|
|
// 事件回调 |
|
|
|
Function(RtcConnection connection, int elapsed)? onJoinChannelSuccess; |
|
|
|
Function(RtcConnection connection, int remoteUid, int elapsed)? onUserJoined; |
|
|
|
@ -86,9 +89,9 @@ class RTCManager { |
|
|
|
await _engine!.initialize( |
|
|
|
RtcEngineContext(appId: appId, channelProfile: channelProfile), |
|
|
|
); |
|
|
|
await _engine?.setClientRole(role: ClientRoleType.clientRoleBroadcaster); |
|
|
|
await _engine?.setClientRole(role: _clientRole); |
|
|
|
await _engine?.enableVideo(); |
|
|
|
await _engine?.startPreview(); |
|
|
|
// await _engine?.startPreview(); |
|
|
|
// 注册事件处理器 |
|
|
|
_registerEventHandlers(); |
|
|
|
|
|
|
|
@ -107,16 +110,19 @@ class RTCManager { |
|
|
|
|
|
|
|
_engine!.registerEventHandler( |
|
|
|
RtcEngineEventHandler( |
|
|
|
onJoinChannelSuccess: (RtcConnection connection, int elapsed) async{ |
|
|
|
onJoinChannelSuccess: (RtcConnection connection, int elapsed) async { |
|
|
|
_isInChannel = true; |
|
|
|
_remoteUserIds.clear(); |
|
|
|
remoteUsersNotifier.value = const []; |
|
|
|
channelJoinedNotifier.value = true; |
|
|
|
_currentChannelId = connection.channelId; |
|
|
|
print('加入频道成功,频道名:${connection.channelId},耗时:${elapsed}ms'); |
|
|
|
if(connection.localUid == _currentUid){ |
|
|
|
if (connection.localUid == _currentUid) { |
|
|
|
|
|
|
|
await RTMManager.instance.subscribe(_currentChannelId ?? ''); |
|
|
|
await RTMManager.instance.publishChannelMessage( |
|
|
|
channelName: _currentChannelId ?? '', |
|
|
|
message: json.encode({'type': 'join_room', 'uid': _currentUid}) |
|
|
|
channelName: _currentChannelId ?? '', |
|
|
|
message: json.encode({'type': 'join_room', 'uid': _currentUid}), |
|
|
|
); |
|
|
|
Get.to(() => const LiveRoomPage(id: 0)); |
|
|
|
} |
|
|
|
@ -126,13 +132,11 @@ class RTCManager { |
|
|
|
}, |
|
|
|
onUserJoined: (RtcConnection connection, int remoteUid, int elapsed) { |
|
|
|
print('用户加入,UID:$remoteUid'); |
|
|
|
_handleRemoteUserJoined(remoteUid); |
|
|
|
if (onUserJoined != null) { |
|
|
|
onUserJoined!(connection, remoteUid, elapsed); |
|
|
|
} |
|
|
|
}, |
|
|
|
onStreamMessage: (RtcConnection connection, int remoteUid, int streamId, Uint8List data, int length, int sentTs){ |
|
|
|
print('收到消息,UID:$remoteUid,流ID:$streamId,数据:${utf8.decode(data)}'); |
|
|
|
}, |
|
|
|
onUserOffline: |
|
|
|
( |
|
|
|
RtcConnection connection, |
|
|
|
@ -140,12 +144,15 @@ class RTCManager { |
|
|
|
UserOfflineReasonType reason, |
|
|
|
) { |
|
|
|
print('用户离开,UID:$remoteUid,原因:$reason'); |
|
|
|
_handleRemoteUserOffline(remoteUid); |
|
|
|
if (onUserOffline != null) { |
|
|
|
onUserOffline!(connection, remoteUid, reason); |
|
|
|
} |
|
|
|
}, |
|
|
|
onLeaveChannel: (RtcConnection connection, RtcStats stats) { |
|
|
|
_isInChannel = false; |
|
|
|
_remoteUserIds.clear(); |
|
|
|
remoteUsersNotifier.value = const []; |
|
|
|
channelJoinedNotifier.value = false; |
|
|
|
_currentChannelId = null; |
|
|
|
print('离开频道,统计信息:${stats.duration}秒'); |
|
|
|
@ -343,7 +350,7 @@ class RTCManager { |
|
|
|
String? token, |
|
|
|
required String channelId, |
|
|
|
int uid = 0, |
|
|
|
ChannelMediaOptions? options, |
|
|
|
ClientRoleType role = ClientRoleType.clientRoleBroadcaster, |
|
|
|
}) async { |
|
|
|
if (_engine == null) { |
|
|
|
throw Exception('RTC Engine not initialized'); |
|
|
|
@ -352,15 +359,24 @@ class RTCManager { |
|
|
|
print('已经在频道中,先离开当前频道'); |
|
|
|
await leaveChannel(); |
|
|
|
} |
|
|
|
|
|
|
|
await setClientRole(role: role); |
|
|
|
_currentUid = uid; |
|
|
|
if (role == ClientRoleType.clientRoleBroadcaster) { |
|
|
|
await _engine?.startPreview(); |
|
|
|
} |
|
|
|
await _engine!.joinChannel( |
|
|
|
token: token ?? '', |
|
|
|
channelId: channelId, |
|
|
|
uid: uid, |
|
|
|
options: options ?? const ChannelMediaOptions(), |
|
|
|
options: ChannelMediaOptions( |
|
|
|
channelProfile: ChannelProfileType.channelProfileLiveBroadcasting, |
|
|
|
clientRoleType: role, |
|
|
|
autoSubscribeAudio: true, |
|
|
|
autoSubscribeVideo: true, |
|
|
|
publishCameraTrack: true, |
|
|
|
publishMicrophoneTrack: true, |
|
|
|
), |
|
|
|
); |
|
|
|
_streamId = await _engine?.createDataStream(DataStreamConfig(syncWithAudio: false, ordered: false)); |
|
|
|
print('正在加入频道:$channelId,UID:$uid'); |
|
|
|
} |
|
|
|
|
|
|
|
@ -373,7 +389,7 @@ class RTCManager { |
|
|
|
print('当前不在频道中'); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
await RTMManager.instance.unsubscribe(_currentChannelId ?? ''); |
|
|
|
await _engine!.leaveChannel(); |
|
|
|
_currentUid = null; |
|
|
|
print('已离开频道'); |
|
|
|
@ -417,24 +433,18 @@ class RTCManager { |
|
|
|
if (_engine == null) { |
|
|
|
throw Exception('RTC Engine not initialized'); |
|
|
|
} |
|
|
|
_clientRole = role; |
|
|
|
await _engine!.setClientRole(role: role, options: options); |
|
|
|
print('客户端角色已设置为:$role'); |
|
|
|
} |
|
|
|
|
|
|
|
/// 发送消息 |
|
|
|
Future<void> sendMessage(String message) async { |
|
|
|
Uint8List data = utf8.encode(message); |
|
|
|
await _engine!.sendStreamMessage( |
|
|
|
streamId: _streamId ?? 0, |
|
|
|
data: data, |
|
|
|
length: data.length, |
|
|
|
); |
|
|
|
print('已发送消息:$message'); |
|
|
|
} |
|
|
|
|
|
|
|
/// 获取当前频道ID |
|
|
|
String? get currentChannelId => _currentChannelId; |
|
|
|
|
|
|
|
ClientRoleType get clientRole => _clientRole; |
|
|
|
|
|
|
|
List<int> get remoteUserIds => List<int>.unmodifiable(_remoteUserIds); |
|
|
|
|
|
|
|
/// 释放资源 |
|
|
|
Future<void> dispose() async { |
|
|
|
try { |
|
|
|
@ -445,6 +455,8 @@ class RTCManager { |
|
|
|
await _engine!.release(); |
|
|
|
_engine = null; |
|
|
|
} |
|
|
|
_remoteUserIds.clear(); |
|
|
|
remoteUsersNotifier.value = const []; |
|
|
|
_isInitialized = false; |
|
|
|
_isInChannel = false; |
|
|
|
_currentChannelId = null; |
|
|
|
@ -455,4 +467,17 @@ class RTCManager { |
|
|
|
print('Failed to dispose RTC Engine: $e'); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void _handleRemoteUserJoined(int remoteUid) { |
|
|
|
print('用户已加入频道:$remoteUid'); |
|
|
|
if (_remoteUserIds.contains(remoteUid)) return; |
|
|
|
_remoteUserIds.add(remoteUid); |
|
|
|
remoteUsersNotifier.value = List<int>.unmodifiable(_remoteUserIds); |
|
|
|
} |
|
|
|
|
|
|
|
void _handleRemoteUserOffline(int remoteUid) { |
|
|
|
final removed = _remoteUserIds.remove(remoteUid); |
|
|
|
if (!removed) return; |
|
|
|
remoteUsersNotifier.value = List<int>.unmodifiable(_remoteUserIds); |
|
|
|
} |
|
|
|
} |