From 3a3f9cb665cc15749ba7292cba3f5b33e24aa4e2 Mon Sep 17 00:00:00 2001 From: fuenmao <980740792@qq.com> Date: Mon, 2 Dec 2024 14:59:14 +0800 Subject: [PATCH] =?UTF-8?q?1.=E5=85=A8=E5=91=98=E8=A7=82=E7=9C=8Bhttp?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E4=BB=A5=E5=8F=8Asocket=E5=9B=9E=E8=B0=83=20?= =?UTF-8?q?2.=E7=94=A8=E6=88=B7=E5=BC=80=E9=97=AD=E9=BA=A6=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=203.=E7=94=A8=E6=88=B7=E5=BC=80=E9=97=AD=E6=91=84?= =?UTF-8?q?=E5=83=8F=E5=A4=B4=E6=8E=A5=E5=8F=A3=204.=E8=A7=86=E9=A2=91-?= =?UTF-8?q?=E5=8F=B3=E4=B8=8A=E8=A7=92=E8=A7=82=E7=9C=8B=E8=87=AA=E5=B7=B1?= =?UTF-8?q?=205.=E8=A7=86=E9=A2=91-=E5=A4=A7=E5=B1=8F=E8=BF=9C=E7=AB=AF?= =?UTF-8?q?=E8=A7=82=E7=9C=8B=E5=88=AB=E4=BA=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- wgshare/lib/common/api/retrofit_client.dart | 22 +++ .../lib/pages/metting/meeting_main_logic.dart | 83 +++++++-- .../lib/pages/metting/meeting_main_state.dart | 2 + .../lib/pages/metting/meeting_main_view.dart | 7 +- .../video/meeting_main_video_view.dart | 160 +++++++++--------- 5 files changed, 185 insertions(+), 89 deletions(-) diff --git a/wgshare/lib/common/api/retrofit_client.dart b/wgshare/lib/common/api/retrofit_client.dart index 28897f2..d06f6f2 100644 --- a/wgshare/lib/common/api/retrofit_client.dart +++ b/wgshare/lib/common/api/retrofit_client.dart @@ -67,4 +67,26 @@ abstract class RetrofitClient { @Field("roomNum") String roomNum, @Field("userId") String userId, ); + + /// 获取当前全员观看视频主播 + @GET("/room/show-user") + Future> getTvAnchor( + @Query("roomNum") String roomNum, + ); + + /// 用户开闭麦 + @GET("/room/oper-micr") + Future> setMicr( + @Query("roomNum") String roomNum, + @Query("enableMicr") bool enableMicr, + @Query("uid") String uid, + ); + + /// 用户开闭摄像头 + @GET("/room/oper-camera") + Future> setCamera( + @Query("roomNum") String roomNum, + @Query("enableCamera") bool enableCamera, + @Query("uid") String uid, + ); } diff --git a/wgshare/lib/pages/metting/meeting_main_logic.dart b/wgshare/lib/pages/metting/meeting_main_logic.dart index 502dadf..b75b77e 100644 --- a/wgshare/lib/pages/metting/meeting_main_logic.dart +++ b/wgshare/lib/pages/metting/meeting_main_logic.dart @@ -6,6 +6,7 @@ import 'package:get/get.dart'; import 'package:signalr_core/signalr_core.dart'; import 'package:wgshare/common/store/user_store.dart'; import 'package:wgshare/utils/count_microphone_volume.dart'; +import 'package:wgshare/utils/storage.dart'; import '../../common/config/request_config.dart'; import '../../common/mixins/request_tool_mixin.dart'; import '../../common/models/common/base_structure_result.dart'; @@ -135,14 +136,27 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{ BaseStructureResult res = await getClient().applySpeak(state.roomNumber.value); } + /// 用户开闭麦 + Future doHttpSetMicr() async { + BaseStructureResult res = await getClient().setMicr(state.roomNumber.value, state.isOpenMicrophone.value, UserStore.to.userInfoEntity.value!.uid); + } + + /// 用户开闭摄像头 + Future doHttpSetCamer() async { + BaseStructureResult res = await getClient().setCamera(state.roomNumber.value, state.isOpenCamera.value, UserStore.to.userInfoEntity.value!.uid); + } + /// 结束发言 Future doHttpCancelSpeak() async { BaseStructureResult res = await getClient().cancelSpeak(state.meetingRoomInfo.value!.id, state.meetingRoomInfo.value!.roomNum, UserStore.to.userInfoEntity.value!.uid); setClientRole("观众"); + setMicrophoneOpen(false); + setCameraOpen(false); + changePageState(0); } /// 设置麦克风是否开启 - void setMicrophoneOpen(bool isOpen){ + Future setMicrophoneOpen(bool isOpen) async{ state.isOpenMicrophone.value = isOpen; for(var i = 0; i < state.cacheUsers.value.length; i++){ if(state.cacheUsers.value[i].uid == UserStore.to.userInfoEntity.value!.uid){ @@ -150,21 +164,42 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{ } } state.users.value = state.cacheUsers.value; - if(isOpen == true){ - setClientRole("主播"); - }else{ - setClientRole("观众"); - } + setEnableLocalAudio(isOpen); + doHttpSetMicr(); } /// 设置视频是否打开 void setCameraOpen(bool isOpen){ state.isOpenCamera.value = isOpen; + setEnableLocalVideo(isOpen); + if(state.isOpenMicrophone.value == false){ + setMicrophoneOpen(isOpen); + } if(isOpen == true){ - setEnableLocalVideo(isOpen); setClientRole("主播"); + changePageState(1); + doHttpGetTvAnchor(); }else{ - setClientRole("观众"); + changePageState(0); + } + doHttpSetCamer(); + } + + /// 获取当前全员观看视频主播 + Future doHttpGetTvAnchor() async { + BaseStructureResult res = await getClient().getTvAnchor(state.roomNumber.value); + if(res.data!.toString().length != 9){ + state.remoteUid.value = res.data!; + changePageState(1); + /*var isSaveLive = false; + for(MeetingRoomUser mru in state.cacheUsers.value){ + if(mru.uid == state.remoteUid.value){ + isSaveLive = true; + } + } + if(isSaveLive == true){ + changePageState(1); + }*/ } } @@ -230,6 +265,8 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{ state.isSpeak.value = true; state.isOpenMicrophone.value = true; setClientRole("主播"); + setEnableLocalAudio(true); + doHttpSetMicr(); } }else{ debugPrint("wgs输出===:Socket-停止发言:${e?[0]}--${e?[1]}"); @@ -244,6 +281,8 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{ state.isSpeak.value = false; state.isOpenMicrophone.value = false; setClientRole("观众"); + setEnableLocalAudio(false); + doHttpSetMicr(); } } update(); @@ -317,6 +356,18 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{ state.isOpenMicrophone.value = false; } }); + + /// 设置新的全员观看视频主播回调 + state.hubConnection.value?.on("ShowUser", (e){ + // var jsonStr = const Utf8Decoder().convert(json.encode(e).runes.toList()); + var jsonStr = json.encode(e); + List list = json.decode(jsonStr); + /*if(list[0].toString().length != 9){ + state.remoteUid.value = list[0].toString(); + }*/ + doHttpGetTvAnchor(); + debugPrint("wgs输出===:Socket-设置新的全员观看视频主播:${list[0]}"); + }); } /// 加入会议室 @@ -365,7 +416,7 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{ // 打开用户音量回调 await state.rctEngine.value?.enableAudioVolumeIndication(interval: 200, smooth: 3, reportVad: true); // 启用音频模块 - await state.rctEngine.value?.enableAudio(); + setEnableLocalAudio(true); joinMeetingToRtc(); @@ -503,9 +554,19 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{ await state.rctEngine.value?.setEnableSpeakerphone(mode == 1 ? false : true); } - /// 设置是否打开本地视频采集 + /// 设置是否启用音频模块 + Future setEnableLocalAudio(bool enabled) async { + if(enabled == true){ + // 启用音频模块 + await state.rctEngine.value?.enableAudio(); + }else{ + // 关闭音频模块 + await state.rctEngine.value?.disableAudio(); + } + } + + /// 设置是否启用视频模块 Future setEnableLocalVideo(bool enabled) async { - state.isOpenCamera.value = enabled; if(enabled == true){ // 启用视频模块 await state.rctEngine.value?.enableVideo(); diff --git a/wgshare/lib/pages/metting/meeting_main_state.dart b/wgshare/lib/pages/metting/meeting_main_state.dart index 9cac268..02baad0 100644 --- a/wgshare/lib/pages/metting/meeting_main_state.dart +++ b/wgshare/lib/pages/metting/meeting_main_state.dart @@ -59,6 +59,8 @@ class MeetingMainState { late RxDouble microphoneVolume = 0.0.obs; /// 是否打开摄像头 late RxBool isOpenCamera = false.obs; + /// 当前视频主播ID + late RxString remoteUid = "".obs; /// 聊天数据 late RxList meetingRoomMsgs = RxList([]); diff --git a/wgshare/lib/pages/metting/meeting_main_view.dart b/wgshare/lib/pages/metting/meeting_main_view.dart index 5b54775..14d9633 100644 --- a/wgshare/lib/pages/metting/meeting_main_view.dart +++ b/wgshare/lib/pages/metting/meeting_main_view.dart @@ -177,7 +177,12 @@ class MeetingMainPage extends StatelessWidget { Visibility( visible: state.pageState.value == 1, child: null != state.rctEngine.value - ? MeetingMainVideoComponent(rtcEngine: state.rctEngine.value!, channelId: state.roomNumber.value,isOpenCamera: state.isOpenCamera.value) + ? MeetingMainVideoComponent( + rtcEngine: state.rctEngine.value!, + channelId: state.roomNumber.value, + isOpenCamera: state.isOpenCamera.value, + remoteUid: state.remoteUid.value, + ) : Container() ), diff --git a/wgshare/lib/pages/metting/video/meeting_main_video_view.dart b/wgshare/lib/pages/metting/video/meeting_main_video_view.dart index a9cba26..901e088 100644 --- a/wgshare/lib/pages/metting/video/meeting_main_video_view.dart +++ b/wgshare/lib/pages/metting/video/meeting_main_video_view.dart @@ -9,10 +9,16 @@ import 'meeting_main_video_logic.dart'; import 'meeting_main_video_state.dart'; class MeetingMainVideoComponent extends StatelessWidget { - MeetingMainVideoComponent({super.key, required this.rtcEngine, required this.channelId, required this.isOpenCamera}); + MeetingMainVideoComponent( + {super.key, + required this.rtcEngine, + required this.channelId, + required this.isOpenCamera, + required this.remoteUid}); final RtcEngine rtcEngine; final String channelId; + final String remoteUid; final bool isOpenCamera; final MeetingMainVideoLogic logic = Get.put(MeetingMainVideoLogic()); @@ -38,82 +44,81 @@ class MeetingMainVideoComponent extends StatelessWidget { debugPrint('wgs输出===:$index'); }, children: [ - Container( - child: Stack( - alignment: Alignment.center, - children: [ - Container( - decoration: BoxDecoration( - image: DecorationImage( - fit: BoxFit.fill, - image: NetworkImage( - "https://tse4-mm.cn.bing.net/th/id/OIP-C.acWMNnQ04Ks6Bh2b9Zq8XwHaKF?rs=1&pid=ImgDetMain", - ), + Stack( + alignment: Alignment.center, + children: [ + remoteUid != "" + ? AgoraVideoView( + controller: VideoViewController.remote( + rtcEngine: rtcEngine, + canvas: VideoCanvas(uid: int.tryParse(remoteUid)), + connection: RtcConnection(channelId: channelId), ), - )), - Positioned( - bottom: 110, - child: Image.asset( - 'assets/images/meeting_main_hang_up.png', - width: 50.w, - height: 50.h, + ) + : const CircularProgressIndicator(), + Positioned( + bottom: 110, + child: Image.asset( + 'assets/images/meeting_main_hang_up.png', + width: 50.w, + height: 50.h, + ), + ), + Positioned( + top: 16, + right: 16, + child: Container( + height: 30, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + color: ColorUtil.Color_0_0_0_96), + padding: const EdgeInsets.only(left: 12, right: 12), + child: Row( + children: [ + Text( + '正在讲话:', + style: TextStyle( + fontSize: 10.sp, + color: ColorUtil.Color_185_184_184), + ), + Image.asset( + 'assets/images/meeting_main_speak2.png', + width: 20.w, + height: 20.h, + ), + Text( + '晓晓', + style: TextStyle( + fontSize: 10.sp, + color: ColorUtil.Color_185_184_184), + ) + ], ), ), - Positioned( - top: 16, - right: 16, - child: Container( - height: 30, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - color: ColorUtil.Color_0_0_0_96), - padding: const EdgeInsets.only(left: 12, right: 12), - child: Row( - children: [ - Text( - '正在讲话:', - style: TextStyle( - fontSize: 10.sp, - color: ColorUtil.Color_185_184_184), - ), - Image.asset( - 'assets/images/meeting_main_speak2.png', - width: 20.w, - height: 20.h, - ), - Text( - '晓晓', - style: TextStyle( - fontSize: 10.sp, - color: ColorUtil.Color_185_184_184), - ) - ], - ), - ), - ), - /// 右上角小窗 - Positioned( + ), + + /// 右上角小窗 + Visibility( + visible: isOpenCamera, + child: Positioned( top: 58, - right: 12, + right: 13, child: Stack( children: [ - Visibility( - visible: isOpenCamera, - child: SizedBox( - width: 120.w, - height: 150.h, + SizedBox( + width: 120, + height: 150, child: Center( child: isOpenCamera ? AgoraVideoView( - controller: VideoViewController( - rtcEngine: rtcEngine, - canvas: VideoCanvas(uid: int.parse(UserStore.to.userInfoEntity.value!.uid)), - ), - ) + controller: VideoViewController( + rtcEngine: rtcEngine, + canvas: const VideoCanvas(uid: 0), + ), + ) : const CircularProgressIndicator(), ), ), - ), Positioned( left: 4, bottom: 4, @@ -127,20 +132,22 @@ class MeetingMainVideoComponent extends StatelessWidget { Container( height: 15, margin: const EdgeInsets.only(left: 4), - padding: const EdgeInsets.only(left: 4, right: 4), + padding: + const EdgeInsets.only(left: 4, right: 4), decoration: BoxDecoration( borderRadius: BorderRadius.circular(2), color: ColorUtil.Color_0_0_0_96), child: Row( children: [ - Image.asset( + /*Image.asset( 'assets/images/meeting_main_microphone_open.png', width: 13.w, height: 14.h, ), - SizedBox(width: 4.w), + SizedBox(width: 4.w),*/ Text( - '晓晓', + UserStore + .to.userInfoEntity.value!.userName, style: TextStyle( fontSize: 10.sp, color: ColorUtil.Color_185_184_184), @@ -153,15 +160,14 @@ class MeetingMainVideoComponent extends StatelessWidget { ) ], ), - ) - ], - ), + ), + ) + ], ), Container( color: ColorUtil.Color_57_57_57, child: GridView.builder( - gridDelegate: - SliverGridDelegateWithFixedCrossAxisCount( + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, childAspectRatio: 0.8, crossAxisSpacing: 0), @@ -178,8 +184,7 @@ class MeetingMainVideoComponent extends StatelessWidget { "https://tse1-mm.cn.bing.net/th/id/OIP-C.hdhK40Dw3yN_2mjNQNqFCgAAAA?w=186&h=186&c=7&r=0&o=5&pid=1.7", ), ), - ) - ), + )), Positioned( left: 4, bottom: 4, @@ -193,7 +198,8 @@ class MeetingMainVideoComponent extends StatelessWidget { Container( height: 15, margin: const EdgeInsets.only(left: 4), - padding: const EdgeInsets.only(left: 4, right: 4), + padding: + const EdgeInsets.only(left: 4, right: 4), decoration: BoxDecoration( borderRadius: BorderRadius.circular(2), color: ColorUtil.Color_0_0_0_96),