diff --git a/wgshare/lib/pages/homePage/home_logic.dart b/wgshare/lib/pages/homePage/home_logic.dart index 5418dd7..f011789 100644 --- a/wgshare/lib/pages/homePage/home_logic.dart +++ b/wgshare/lib/pages/homePage/home_logic.dart @@ -16,7 +16,7 @@ class HomeLogic extends GetxController with RequestToolMixin { } /// 直接进入会议(匿名登录) - void doHttpGetMeetingRoomList(int pageIndex, int pageSize) async { + Future doHttpGetMeetingRoomList(int pageIndex, int pageSize) async { BaseStructureResult res = await getClient().getMeetingRoomList(pageIndex,pageSize); if(null != res.data){ if(state.pageIndex == 1){ diff --git a/wgshare/lib/pages/loginPage/login_logic.dart b/wgshare/lib/pages/loginPage/login_logic.dart index 32e5bc4..9375c69 100644 --- a/wgshare/lib/pages/loginPage/login_logic.dart +++ b/wgshare/lib/pages/loginPage/login_logic.dart @@ -26,7 +26,7 @@ class LoginLogic extends GetxController with RequestToolMixin { } /// 登录 - void doHttpLogin() async { + Future doHttpLogin() async { if(state.userNameController.text.isEmpty){ ToastUtils.showError("请输入账号"); }else if(state.passwordController.text.isEmpty){ @@ -46,7 +46,7 @@ class LoginLogic extends GetxController with RequestToolMixin { } /// 直接进入会议(匿名登录) - void doHttpAnonymousLogin() async { + Future doHttpAnonymousLogin() async { if(state.meetingCodeController.text.isEmpty){ ToastUtils.showError("请输入会议号"); }else if(state.meetingCodeController.text.length != 8){ diff --git a/wgshare/lib/pages/metting/meeting_main_logic.dart b/wgshare/lib/pages/metting/meeting_main_logic.dart index 3c1ef0e..6395211 100644 --- a/wgshare/lib/pages/metting/meeting_main_logic.dart +++ b/wgshare/lib/pages/metting/meeting_main_logic.dart @@ -1,6 +1,9 @@ import 'dart:async'; +import 'package:agora_rtc_engine/agora_rtc_engine.dart'; +import 'package:flutter/foundation.dart'; import 'package:get/get.dart'; +import 'package:permission_handler/permission_handler.dart'; import 'package:signalr_core/signalr_core.dart'; import 'package:wgshare/common/store/user_store.dart'; @@ -16,14 +19,14 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{ final MeetingMainState state = MeetingMainState(); @override - void onInit() async { + void onInit() { super.onInit(); // 接收参数 var data = Get.arguments; state.roomNumber.value = data["roomNumber"]; - signalRSocket(); + doHttpGetMeetingToken(); } @override @@ -31,24 +34,22 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{ super.onClose(); state.memberNameSearchController.dispose(); stopTime(); + leaveMeeting(); state.hubConnection.value?.stop(); } /// 合并请求 /// 1.获取会议室信息 /// 2.获取会议室所有用户 - /// 3.获取会议室Token - void mergeFetch() async { + Future mergeFetch() async { ToastUtils.showLoading(); var results = await Future.wait([ getClient().getMeetingRoomInfo(state.roomNumber.value), - getClient().getMeetingRoomAllUser(state.roomNumber.value), - getClient().getMeetingToken(state.roomNumber.value)]); + getClient().getMeetingRoomAllUser(state.roomNumber.value)]); - doHttpGetMeetingRoomInfo(results[0].data as MeetingRoomInfo); - doHttpGetMeetingRoomAllUser(results[1].data as List); - doHttpGetMeetingToken(results[2].data as String); + getMeetingRoomInfo(results[0].data as MeetingRoomInfo); + getMeetingRoomAllUser(results[1].data as List); ToastUtils.dismiss(); } @@ -64,11 +65,11 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{ await state.hubConnection.value?.start(); - joinChannel(); + joinChannelToSocket(); } /// 加入会议室 - void joinChannel() async { + Future joinChannelToSocket() async { await state.hubConnection.value?.invoke("joinChannel", args: [state.roomNumber.value, false, false, false]); mergeFetch(); } @@ -89,20 +90,24 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{ } /// 获取会议室信息 - void doHttpGetMeetingRoomInfo(MeetingRoomInfo meetingRoomInfo) async { + void getMeetingRoomInfo(MeetingRoomInfo meetingRoomInfo) async { state.meetingRoomInfo.value = meetingRoomInfo; startTime(); } /// 获取会议室所有用户 - void doHttpGetMeetingRoomAllUser(List meetingRoomUsers) async { + void getMeetingRoomAllUser(List meetingRoomUsers) async { state.users.value = meetingRoomUsers; state.cacheUsers.value = meetingRoomUsers; } /// 获取会议室Token - void doHttpGetMeetingToken(String meetingToken) async { - state.meetingToken.value = meetingToken; + Future doHttpGetMeetingToken() async { + BaseStructureResult res = await getClient().getMeetingToken(state.roomNumber.value); + state.meetingToken.value = res.data!; + + initRtc(); + signalRSocket(); } /// 启动计时 @@ -141,4 +146,69 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{ state.users.value = state.cacheUsers.value; } } + + /// 初始化声网SDK + Future initRtc() async { + // 请求麦克风权限 + if (defaultTargetPlatform == TargetPlatform.android) { + await [Permission.microphone].request(); + } + + // 创建 RtcEngine 对象 + state.rctEngine.value = createAgoraRtcEngine(); + + // 初始化 RtcEngine,设置频道场景为 channelProfileLiveBroadcasting(直播场景) + await state.rctEngine.value?.initialize(RtcEngineContext( + appId: state.appId, + channelProfile: ChannelProfileType.channelProfileLiveBroadcasting, + )); + + joinChannelToRtc(); + + // 回调 + state.rctEngine.value?.registerEventHandler( + RtcEngineEventHandler( + // 成功加入频道回调 + onJoinChannelSuccess: (RtcConnection connection, int elapsed) { + debugPrint("自己加入会议室,ID:${connection.localUid}"); + }, + // 远端用户或主播加入当前频道回调 + onUserJoined: (RtcConnection connection, int remoteUid, int elapsed) { + debugPrint("远端用户或主播加入会议室,用户或主机的ID:$remoteUid"); + }, + // 远端用户或主播离开当前频道回调 + onUserOffline: (RtcConnection connection, int remoteUid, UserOfflineReasonType reason) { + debugPrint("远端用户或主播离开会议室,用户或主机的ID:$remoteUid"); + }, + ), + ); + } + + /// 加入会议室 + Future joinChannelToRtc() async { + await state.rctEngine.value?.joinChannel( + token: state.meetingToken.value, + channelId: state.roomNumber.value, + uid: 0, + options: const ChannelMediaOptions( + // 自动订阅所有视频流 + autoSubscribeVideo: false, + // 自动订阅所有音频流 + autoSubscribeAudio: true, + // 发布摄像头采集的视频 + publishCameraTrack: false, + // 发布麦克风采集的音频 + publishMicrophoneTrack: false, + // 设置用户角色为clientRoleAudience(观众) + clientRoleType: ClientRoleType.clientRoleAudience), + ); + } + + /// 离开会议室 + Future leaveMeeting() async { + // 离开 + await state.rctEngine.value?.leaveChannel(); + // 释放资源 + await state.rctEngine.value?.release(); + } } diff --git a/wgshare/lib/pages/metting/meeting_main_state.dart b/wgshare/lib/pages/metting/meeting_main_state.dart index 4e280c2..63b3ab2 100644 --- a/wgshare/lib/pages/metting/meeting_main_state.dart +++ b/wgshare/lib/pages/metting/meeting_main_state.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:agora_rtc_engine/agora_rtc_engine.dart'; import 'package:flutter/cupertino.dart'; import 'package:get/get.dart'; import 'package:get/get_rx/src/rx_types/rx_types.dart'; @@ -30,6 +31,9 @@ class MeetingMainState { /// 会议室编号 late RxString roomNumber = "".obs; + + /// 会议室token + late RxString meetingToken = "".obs; /// 会议室信息 late Rx meetingRoomInfo = Rx(null); @@ -45,10 +49,19 @@ class MeetingMainState { /// 搜索用户时,缓存会议室所有用户原始数据 late RxList cacheUsers = RxList([]); - /// 会议室Token - late RxString meetingToken = "".obs; - /// signalR 长连接相关 late RxString serviceUrl = "http://192.168.2.9:5192/session-manage".obs; late Rx hubConnection = Rx(null); + + /// 声网相关 + final String appId = "4a4f7be64fa1404ebda74784fe9ac381"; + late Rx rctEngine = Rx(null); + /// 是否自动订阅所有视频流 + late RxBool isAutoSubscribeVideo = false.obs; + /// 是否自动订阅所有音频流 + late RxBool isAutoSubscribeAudio = false.obs; + /// 是否发布摄像头采集的视频 + late RxBool isPublishCameraTrack = false.obs; + /// 是否发布麦克风采集的音频 + late RxBool isPublishMicrophoneTrack = false.obs; }