1.视频逻辑梳理(除别人关闭视频或取消发言还有待商榷)

2.正在讲话需求
This commit is contained in:
fuenmao 2024-12-10 15:44:12 +08:00
parent 8d4979b484
commit e91c400d2f
4 changed files with 386 additions and 231 deletions

View File

@ -2,6 +2,9 @@
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
<application
android:label="智汇享"

View File

@ -37,10 +37,10 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{
state.floating.value?.close();
state.memberNameSearchController.dispose();
state.sendMsgController.dispose();
state.pageController.dispose();
stopTime();
leaveMeetingToRtc();
leaveMeetingToSocket();
state.hubConnection.value?.stop();
}
/// Token
@ -95,7 +95,7 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{
void getMeetingRoomAllUser(List<MeetingRoomUser> meetingRoomUsers) async {
state.users.value = meetingRoomUsers;
state.cacheUsers.value = meetingRoomUsers;
// doHttpGetTvAnchor();
doHttpGetTvAnchor();
}
///
@ -167,58 +167,146 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{
Future<void> doHttpGetTvAnchor() async {
BaseStructureResult res = await getClient().getTvAnchor(state.roomNumber.value);
state.remoteUid.value = res.data!.toString();
if(res.data!.toString().length != 9){
//
//
if(state.remoteUid.value == UserStore.to.userInfoEntity.value!.uid) {
state.isSelf.value = true;
}else{
state.isSelf.value = false;
}
if(state.isSelf.value == true){
//
if(state.isOpenCamera.value == true){
//
changePageState(1);
state.floating.value?.close();
}else{
//
changePageState(0);
}
}else{
//
var isCurrentUserIsCamera = false;
//
for(var i = 0; i < state.cacheUsers.value.length; i++){
if(state.remoteUid.value == state.cacheUsers.value[i].uid && state.cacheUsers.value[i].enableCamera == true){
isCurrentUserIsCamera = true;
}
}
if(isCurrentUserIsCamera == true){
changePageState(1);
}else{
changePageState(0);
}
}
}else{
//
//
if(state.remoteUid.value != UserStore.to.userInfoEntity.value!.screenShareId){
state.isSelf.value = false;
}else{
state.isSelf.value = true;
}
//
if(state.isSelf.value == false){
changePageState(1);
}
}
/*if(res.data!.toString().length != 9){
if(state.remoteUid.value != UserStore.to.userInfoEntity.value!.uid) {
state.isSelf.value = false;
}else{
state.isSelf.value = true;
}
}else{
if(state.remoteUid.value != UserStore.to.userInfoEntity.value!.screenShareId){
if(state.remoteUid.value != UserStore.to.userInfoEntity.value!.uid) {
state.isSelf.value = false;
if(state.isSelf.value == true){
if(state.isOpenCamera.value == true){
changePageState(1);
}else{
state.isSelf.value = true;
changePageState(0);
}
state.floating.value?.close();
}else{
var isCurrentUserIsCamera = false;
for(var i = 0; i < state.cacheUsers.value.length; i++){
if(state.remoteUid.value == state.cacheUsers.value[i].uid && state.cacheUsers.value[i].enableCamera == true){
isCurrentUserIsCamera = true;
}
}
if(isCurrentUserIsCamera == true){
changePageState(1);
}else{
changePageState(0);
}
}
}
if(state.isSelf.value == true){
state.floating.value?.close();
}
Future.delayed(const Duration(milliseconds: 1000), () {
changePageState(1);
});
}else{
if(state.remoteUid.value != UserStore.to.userInfoEntity.value!.screenShareId){
state.isSelf.value = false;
}else{
state.isSelf.value = true;
}
if(state.isSelf.value == false){
changePageState(1);
}
}*/
}
///
Future<void> setScreenShareOpen(bool isOpen) async {
state.isOpenShare.value = isOpen;
if(isOpen == true){
await getClient().setTvAnchor(
state.roomNumber.value,
UserStore.to.userInfoEntity.value!.screenShareId,
UserStore.to.userInfoEntity.value!.userName
);
await state.rctEngine.value?.startScreenCapture(const ScreenCaptureParameters2(captureAudio: true, captureVideo: true));
await state.rctEngine.value?.joinChannelEx(
token: state.meetingToken.value,
connection: RtcConnection(channelId: state.roomNumber.value, localUid: int.tryParse(UserStore.to.userInfoEntity.value!.screenShareId)),
options: const ChannelMediaOptions(
publishScreenCaptureAudio: true,
publishScreenCaptureVideo: true,
clientRoleType: ClientRoleType.clientRoleBroadcaster,
));
}else{
await state.rctEngine.value?.stopScreenCapture();
await state.rctEngine.value?.leaveChannelEx(
connection: RtcConnection(channelId: state.roomNumber.value, localUid: int.tryParse(UserStore.to.userInfoEntity.value!.screenShareId)),
options: const LeaveChannelOptions(
stopMicrophoneRecording: false,
stopAllEffect: false
));
}
///
Future<void> doHttpSetTvAnchor(String id) async {
await getClient().setTvAnchor(
state.roomNumber.value,
id,
UserStore.to.userInfoEntity.value!.userName
);
}
///
Future<void> startScreenCapture() async {
debugPrint("wgs输出===RTC-启动屏幕共享");
state.isOpenShare.value = true;
final shareShareUid = int.tryParse(UserStore.to.userInfoEntity.value!.screenShareId);
await state.rctEngine.value?.setAudioScenario(AudioScenarioType.audioScenarioGameStreaming);
await state.rctEngine.value?.startScreenCapture(const ScreenCaptureParameters2(captureAudio: true, captureVideo: true));
await state.rctEngine.value?.joinChannelEx(
token: state.meetingToken.value,
connection: RtcConnection(channelId: state.roomNumber.value, localUid: shareShareUid),
options: const ChannelMediaOptions(
autoSubscribeVideo: false,
autoSubscribeAudio: false,
publishScreenTrack: true,
publishSecondaryScreenTrack: true,
publishCameraTrack: false,
publishMicrophoneTrack: false,
publishScreenCaptureAudio: true,
publishScreenCaptureVideo: true,
clientRoleType: ClientRoleType.clientRoleBroadcaster,
));
doHttpSetTvAnchor(UserStore.to.userInfoEntity.value!.screenShareId);
}
///
Future<void> stopScreenCapture() async {
debugPrint("wgs输出===RTC-停止屏幕共享");
state.isOpenShare.value = false;
final shareShareUid = int.tryParse(UserStore.to.userInfoEntity.value!.screenShareId);
await state.rctEngine.value?.stopScreenCapture();
await state.rctEngine.value?.leaveChannelEx(
connection: RtcConnection(
channelId: state.roomNumber.value,
localUid: shareShareUid
),
options: const LeaveChannelOptions(
stopMicrophoneRecording: false,
stopAllEffect: false
));
doHttpSetTvAnchor(UserStore.to.userInfoEntity.value!.uid);
}
/// ------------------------------------------------------------------------------signalR Socket相关
/// Socket长连接
Future<void> signalRSocket() async {
@ -271,6 +359,9 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{
state.isSpeak.value = false;
state.isOpenMicrophone.value = false;
state.isOpenCamera.value = false;
state.isOpenShare.value = false;
state.isSelf.value = false;
state.remoteUid.value = "";
// SDK角色为观众
setClientRole("观众");
@ -280,9 +371,11 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{
stopPreview();
//
state.floating.value?.close();
//
changePageState(0);
state.isSelf.value = false;
state.remoteUid.value = "";
//
stopScreenCapture();
debugPrint("wgs输出===Socket-关闭发言权限:观众");
}
@ -448,6 +541,13 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{
stopPreview();
//
state.floating.value?.close();
}else{
if(meetingRoomUser.uid == state.remoteUid.value || meetingRoomUser.screenShareId == state.remoteUid.value){
if(state.isOpenCamera.value == true){
state.remoteUid.value = "";
changePageState(0);
}
}
}
}
});
@ -474,6 +574,7 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{
///
Future<void> leaveMeetingToSocket() async {
await state.hubConnection.value?.invoke("levelChannel", args: [state.roomNumber.value]);
state.hubConnection.value?.stop();
}
///
@ -577,14 +678,24 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{
if(speakers.isNotEmpty){
for(AudioVolumeInfo avi in speakers){
for(MeetingRoomUser mru in state.cacheUsers.value){
//
if(avi.uid == 0){
debugPrint("wgs输出===RTC-用户音量提示(自己):${CountMicrophoneVolume.getVolume(avi.volume!)}");
//debugPrint("wgs输出===RTC-用户音量提示(自己):${CountMicrophoneVolume.getVolume(avi.volume!)}");
mru.volume = CountMicrophoneVolume.getVolume(avi.volume!);
state.microphoneVolume.value = CountMicrophoneVolume.getVolume(avi.volume!);
}else{
if(avi.uid.toString() == mru.uid){
debugPrint("wgs输出===RTC-用户音量提示(远端用户):${speakers[0].uid}--${speakers[0].volume}");
//debugPrint("wgs输出===RTC-用户音量提示(远端用户):${speakers[0].uid}--${speakers[0].volume}");
mru.volume = CountMicrophoneVolume.getVolume(avi.volume!);
if(avi.volume != 0){
state.spokesman.value = mru.userName;
state.spokesmanVolume.value = CountMicrophoneVolume.getVolume(avi.volume!);
}else{
state.spokesman.value = "";
state.spokesmanVolume.value = 0;
}
}
}
}
@ -601,9 +712,24 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{
debugPrint("wgs输出===RTC-切换用户角色为:${newRole == ClientRoleType.clientRoleBroadcaster ? "主播" : "观众"}");
},
// token即将在30秒内过期
// token即将在30秒内过期回调
onTokenPrivilegeWillExpire: (RtcConnection connection, String token){
doHttpGetMeetingToken(false);
},
//
onLocalVideoStateChanged: (VideoSourceType source, LocalVideoStreamState state, LocalVideoStreamReason reason){
debugPrint("wgs输出===RTC-本地视频状态发生改变:$source--$state--$reason");
},
//
onPermissionError: (PermissionType permissionType){
debugPrint("wgs输出===RTC-获取设备权限出错:$permissionType");
if(permissionType == PermissionType.screenCapture){
//
state.isOpenShare.value = false;
stopScreenCapture();
}
}
),
);

View File

@ -5,6 +5,7 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter_floating/floating/floating.dart';
import 'package:get/get.dart';
import 'package:get/get_rx/src/rx_types/rx_types.dart';
import 'package:preload_page_view/preload_page_view.dart';
import 'package:signalr_core/signalr_core.dart';
import '../../common/models/meeting_room_info.dart';
@ -19,6 +20,7 @@ class MeetingMainState {
late TextEditingController memberNameSearchController = TextEditingController();
late TextEditingController sendMsgController = TextEditingController();
late PreloadPageController pageController = PreloadPageController(initialPage: 0);
late Rx<Floating?> floating = Rx(null);
late Rx<BuildContext?> context = Rx(null);
@ -64,12 +66,17 @@ class MeetingMainState {
late RxDouble microphoneVolume = 0.0.obs;
///
late RxBool isOpenCamera = false.obs;
///
late RxBool isOpenShare = false.obs;
/// ID
late RxString remoteUid = "".obs;
///
late RxBool isSelf = false.obs;
///
late RxBool isOpenShare = false.obs;
///
late RxString spokesman = "".obs;
///
late RxDouble spokesmanVolume = 0.0.obs;
///
late RxList<MeetingRoomMsg> meetingRoomMsgs = RxList([]);

View File

@ -518,9 +518,9 @@ class MeetingMainPageState extends State<MeetingMainPage> {
onTap: () {
if (state.isSpeak.value == true) {
if (state.isOpenShare.value == true) {
logic.setScreenShareOpen(false);
logic.stopScreenCapture();
} else {
logic.setScreenShareOpen(true);
logic.startScreenCapture();
}
}
},
@ -1517,6 +1517,7 @@ class MeetingMainPageState extends State<MeetingMainPage> {
/// -
Widget returnPageToOther(int position){
debugPrint("wgs输出===:全员观看是别人时布局");
var pageList = [];
///
pageList.add(Stack(
@ -1559,13 +1560,209 @@ class MeetingMainPageState extends State<MeetingMainPage> {
fontSize: 10.sp,
color: ColorUtil.Color_185_184_184),
),
Image.asset(
'assets/images/meeting_main_speak2.png',
SizedBox(
width: 20.w,
height: 20.h,
child: LiquidCustomProgressIndicator(
value:
state.spokesmanVolume.value,
valueColor:
const AlwaysStoppedAnimation(
ColorUtil
.Color_2_177_136),
backgroundColor:
ColorUtil.Color_255_255_255,
direction: Axis.vertical,
shapePath: ViewSvgPath
.getMicrpphonePath()),
),
Text(
'晓晓',
state.spokesman.value,
style: TextStyle(
fontSize: 10.sp,
color: ColorUtil.Color_185_184_184),
)
],
),
),
),
],
));
/// gridview
pageList.add(Container(
color: ColorUtil.Color_57_57_57,
child: GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 0.8,
crossAxisSpacing: 0),
itemCount: state.cacheUsers.value.length,
itemBuilder: (BuildContext ctx, index) {
return Stack(
children: [
state.cacheUsers.value[index].enableCamera == true ? state.cacheUsers.value[index].uid ==
UserStore.to.userInfoEntity.value!.uid
? AgoraVideoView(
controller: VideoViewController(
rtcEngine: state.rctEngine.value!,
canvas: const VideoCanvas(uid: 0, setupMode: VideoViewSetupMode.videoViewSetupAdd)
),
)
: AgoraVideoView(
controller: VideoViewController.remote(
rtcEngine: state.rctEngine.value!,
canvas: VideoCanvas(
uid: int.tryParse(
state.cacheUsers.value[index].uid), setupMode: VideoViewSetupMode.videoViewSetupAdd),
connection: RtcConnection(
channelId: state.roomNumber.value),
),
)
:
Container(
color: Colors.amber,
),
Positioned(
left: 4,
bottom: 4,
child: Row(
children: [
Visibility(
visible: state.cacheUsers.value[index].uid == UserStore.to.userInfoEntity.value!.uid,
child: Image.asset(
'assets/images/meeting_main_own.png',
width: 24.w,
height: 24.h,
),
),
Container(
height: 20,
margin: const EdgeInsets.only(left: 4),
padding:
const EdgeInsets.only(left: 4, right: 4),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(2),
color: ColorUtil.Color_0_0_0_96),
child: state.cacheUsers.value[index].enableMicr == true
? Row(
mainAxisAlignment:
MainAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.center,
children: [
SizedBox(
width: 20.w,
height: 20.h,
child: LiquidCustomProgressIndicator(
value:
state.cacheUsers.value[index]
.volume ??
0.0,
valueColor:
const AlwaysStoppedAnimation(
ColorUtil
.Color_2_177_136),
backgroundColor:
ColorUtil.Color_255_255_255,
direction: Axis.vertical,
shapePath: ViewSvgPath
.getMicrpphonePath()),
),
],
)
: Row(
mainAxisAlignment:
MainAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.center,
children: [
Image.asset(
'assets/images/meeting_main_microphone_open.png',
width: 20.w,
height: 20.h,
),
Text(
state.cacheUsers.value[index].userName,
style: TextStyle(
fontSize: 12.sp,
color: ColorUtil
.Color_255_255_255),
)
],
),
)
],
),
)
],
);
}),
));
return pageList[position];
}
/// -
Widget returnPageSelf(int position){
debugPrint("wgs输出===:全员观看是自己时布局");
var pageList = [];
///
pageList.add(Stack(
alignment: Alignment.center,
children: [
AgoraVideoView(
controller: VideoViewController(
rtcEngine: state.rctEngine.value!,
canvas: const VideoCanvas(uid: 0, setupMode: VideoViewSetupMode.videoViewSetupAdd),
),
),
/*Positioned(
bottom: 110,
child: GestureDetector(
child: Image.asset(
'assets/images/meeting_main_hang_up.png',
width: 50.w,
height: 50.h,
),
onTap: () {
},
),
),*/
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),
),
SizedBox(
width: 20.w,
height: 20.h,
child: LiquidCustomProgressIndicator(
value:
state.spokesmanVolume.value,
valueColor:
const AlwaysStoppedAnimation(
ColorUtil
.Color_2_177_136),
backgroundColor:
ColorUtil.Color_255_255_255,
direction: Axis.vertical,
shapePath: ViewSvgPath
.getMicrpphonePath()),
),
Text(
state.spokesman.value,
style: TextStyle(
fontSize: 10.sp,
color: ColorUtil.Color_185_184_184),
@ -1696,182 +1893,4 @@ class MeetingMainPageState extends State<MeetingMainPage> {
return pageList[position];
}
/// -
Widget returnPageSelf(int position){
var pageList = [];
///
pageList.add(Stack(
alignment: Alignment.center,
children: [
AgoraVideoView(
controller: VideoViewController(
rtcEngine: state.rctEngine.value!,
canvas: const VideoCanvas(uid: 0, setupMode: VideoViewSetupMode.videoViewSetupAdd),
),
),
/*Positioned(
bottom: 110,
child: GestureDetector(
child: Image.asset(
'assets/images/meeting_main_hang_up.png',
width: 50.w,
height: 50.h,
),
onTap: () {
},
),
),*/
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),
)
],
),
),
),
],
));
/// gridview
pageList.add(Container(
color: ColorUtil.Color_57_57_57,
child: GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 0.8,
crossAxisSpacing: 0),
itemCount: state.cacheUsers.value.length,
itemBuilder: (BuildContext ctx, index) {
return Stack(
children: [
state.cacheUsers.value[index].enableCamera == true ? state.cacheUsers.value[index].uid ==
UserStore.to.userInfoEntity.value!.uid
? AgoraVideoView(
controller: VideoViewController(
rtcEngine: state.rctEngine.value!,
canvas: const VideoCanvas(uid: 0, setupMode: VideoViewSetupMode.videoViewSetupAdd)
),
)
: AgoraVideoView(
controller: VideoViewController.remote(
rtcEngine: state.rctEngine.value!,
canvas: VideoCanvas(
uid: int.tryParse(
state.cacheUsers.value[index].uid), setupMode: VideoViewSetupMode.videoViewSetupAdd),
connection: RtcConnection(
channelId: state.roomNumber.value),
),
)
:
Container(
color: Colors.amber,
),
Positioned(
left: 4,
bottom: 4,
child: Row(
children: [
Visibility(
visible: state.cacheUsers.value[index].uid == UserStore.to.userInfoEntity.value!.uid,
child: Image.asset(
'assets/images/meeting_main_own.png',
width: 24.w,
height: 24.h,
),
),
Container(
height: 20,
margin: const EdgeInsets.only(left: 4),
padding:
const EdgeInsets.only(left: 4, right: 4),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(2),
color: ColorUtil.Color_0_0_0_96),
child: state.cacheUsers.value[index].enableMicr == true
? Row(
mainAxisAlignment:
MainAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.center,
children: [
SizedBox(
width: 20.w,
height: 20.h,
child: LiquidCustomProgressIndicator(
value:
state.cacheUsers.value[index]
.volume ??
0.0,
valueColor:
const AlwaysStoppedAnimation(
ColorUtil
.Color_2_177_136),
backgroundColor:
ColorUtil.Color_255_255_255,
direction: Axis.vertical,
shapePath: ViewSvgPath
.getMicrpphonePath()),
),
Text(
state.cacheUsers.value[index].userName,
style: TextStyle(
fontSize: 12.sp,
color: ColorUtil
.Color_255_255_255),
)
],
)
: Row(
mainAxisAlignment:
MainAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.center,
children: [
Image.asset(
'assets/images/meeting_main_microphone_open.png',
width: 20.w,
height: 20.h,
),
Text(
state.cacheUsers.value[index].userName,
style: TextStyle(
fontSize: 12.sp,
color: ColorUtil
.Color_255_255_255),
)
],
),
)
],
),
)
],
);
}),
));
return pageList[position];
}
}