import 'package:fis_jsonrpc/rpc.dart'; import 'package:fis_lib_media_rt/config.dart'; import 'package:fis_lib_media_rt/implementations/nt_rtmp/models.dart'; import 'package:fis_lib_media_rt/implementations/nt_rtmp/rtc_adapter.dart'; import 'package:flyinsonolite/managers/basemanager.dart'; import 'package:flyinsonolite/managers/interfaces/irtmpmockrtcmanager.dart'; import 'package:flyinsonolite/infrastructure/storage.dart'; import 'package:get/get.dart'; class RtmpMockRtcManager extends BaseManager implements IRtmpMockRtcManager { List? _originMembers; bool get isRtmpMode => FRTMediaConfig.serviceType == FRealTimeMediaServiceType.ntRtmp; @override void handleRemoteAccept(LiveConsultatioAccepterInfo accepter) { if (!isRtmpMode) return; final member = _originMembers?.firstWhereOrNull((e) => e.id == accepter.id); RtmpLiveInfo? liveInfo; if (member != null) { final liveData = member.liveData!; liveInfo = RtmpLiveInfo( flvUrl: liveData.httpPullUrl!, rtmpUrl: liveData.rtmpPullUrl!, height: liveData.height, width: liveData.width, ); } final data = RtmpMemberInfo( id: accepter.id!, liveInfo: liveInfo, deviceInfoList: null, ); NTRtmp2RtcAdapter.adapter.remoteMemberJoineEvent.emit(this, data); } @override void handleRemoteJoinIn(LiveConsultationJoinerInfo joiner) { if (isRtmpMode) { final liveData = joiner.liveData!; final data = RtmpMemberInfo( id: joiner.id!, liveInfo: RtmpLiveInfo( flvUrl: liveData.httpPullUrl!, rtmpUrl: liveData.rtmpPullUrl!, height: liveData.height, width: liveData.width, ), deviceInfoList: null, ); _emitMemberJoin(data); } } @override void handleRemoteLeave(LiveConsultationLeaverInfo joiner) { if (isRtmpMode) { final id = joiner.id!; NTRtmp2RtcAdapter.adapter.remoteMemberLeaveEvent.emit(this, id); } } @override void storeOriginData(List? members) { if (!isRtmpMode) return; if (members == null || members.isEmpty) return; _originMembers = List.from(members); final localIndex = _originMembers!.indexWhere((e) => e.id == Storage.user.userCode); if (localIndex < 0) return; // 本地成员 final member = _originMembers![localIndex]; _originMembers!.removeAt(localIndex); final liveData = member.liveData!; NTRtmp2RtcAdapter.adapter.localMemberInfo = RtmpMemberInfo( id: member.id!, liveInfo: RtmpLiveInfo( pushUrl: liveData.rtmpPushUrl, flvUrl: '', rtmpUrl: '', height: 0, width: 0, ), ); } @override void updateDevice(LiveConsultationMember device) { if (!isRtmpMode) return; _handleDeviceLeave(); /// 将设备更新为新设备 final deviceIndex = _originMembers! .indexWhere((e) => e.memberType == LiveMemberEnum.Device); if (deviceIndex >= 0) { _originMembers![deviceIndex] = device; } _handleDeviceJoin(device); } @override void handleEnterRoom() { if (!isRtmpMode) return; final members = _originMembers; if (members == null || members.isEmpty) return; final userMembers = members.where((e) => e.memberType == LiveMemberEnum.User); for (final member in userMembers) { _emitExistRemoteJoin(member); } // 设备成员 final deviceMember = members.firstWhereOrNull((e) => e.memberType == LiveMemberEnum.Device); if (deviceMember != null) { _handleDeviceJoin(deviceMember); } } @override void handleRemoteMuteVideo(String id, bool isMute) { NTRtmp2RtcAdapter.adapter.mmberMuteVideoEvent.emit( this, RtmpSetMuteEventArgs(userId: id, isMute: isMute), ); } @override void handleRemoteMuteAudio(String id, bool isMute) { NTRtmp2RtcAdapter.adapter.mmberMuteAudioEvent.emit( this, RtmpSetMuteEventArgs(userId: id, isMute: isMute), ); } void _emitExistRemoteJoin(LiveConsultationMember member) { final liveData = member.liveData!; final data = RtmpMemberInfo( id: member.id!, liveInfo: RtmpLiveInfo( rtmpUrl: liveData.rtmpPullUrl!, flvUrl: liveData.httpPullUrl!, height: liveData.height, width: liveData.width, ), deviceInfoList: null, ); _emitMemberJoin(data); } void _handleDeviceJoin(LiveConsultationMember member) { if (member.videoDeviceInfos == null || member.videoDeviceInfos!.isEmpty) { return; } // 如果只有一个设备 if (member.videoDeviceInfos!.length == 1) { final device = member.videoDeviceInfos!.first; final data = RtmpMemberInfo( id: device.videoDeviceId!, // 进入WebRTC时的用户名 deviceInfoList: [_convertDeviceLiveInfo(member, device)], ); _emitMemberJoin(data); } else { // 如果有多个设备,先找出主画面,再过滤出摄像头数组 final mainview = member.videoDeviceInfos!.first; final subViewList = member.videoDeviceInfos! .where((e) => e.videoDeviceSourceType == VideoDeviceSourceTypeEnum.Camera) .toList(); final mainViewData = RtmpMemberInfo( id: mainview.videoDeviceId!, // 进入WebRTC时的用户名 deviceInfoList: _convertDeviceLiveInfoList(member, member.videoDeviceInfos!), ); _emitMemberJoin(mainViewData); for (var device in subViewList) { // 一个设备一个成员,设备成员↔设备Channel一对一 final data = RtmpMemberInfo( id: device.videoDeviceId!, // 进入WebRTC时的用户名 deviceInfoList: [_convertDeviceLiveInfo(member, device)], ); _emitMemberJoin(data); } } } void _handleDeviceLeave() { /// 将当前存在的设备都退出房间 final deviceIndex = _originMembers! .indexWhere((e) => e.memberType == LiveMemberEnum.Device); if (deviceIndex < 0) return; final member = _originMembers![deviceIndex]; for (VideoDeviceOutputInfo device in member.videoDeviceInfos!) { NTRtmp2RtcAdapter.adapter.remoteMemberLeaveEvent .emit(this, device.videoDeviceId!); } } void _emitMemberJoin(RtmpMemberInfo member) { NTRtmp2RtcAdapter.adapter.remoteMemberJoineEvent.emit(this, member); Future.delayed(const Duration(milliseconds: 100), () { handleRemoteMuteVideo(member.id, true); handleRemoteMuteAudio(member.id, true); }); } DeviceRtmpLiveInfo _convertDeviceLiveInfo( LiveConsultationMember member, VideoDeviceOutputInfo device, ) { return DeviceRtmpLiveInfo( type: DeviceTypeEnum.values[device.videoDeviceSourceType.index], rtmpUrl: device.liveData!.rtmpPullUrl!, flvUrl: device.liveData!.httpPullUrl!, height: device.outputHeight, width: device.outputWidth, isMerge: member.mergedChannel, isOldPlatform: member.isOldPlatform, mergeWidth: member.mergedVideoOutputWidth, mergeHeight: member.mergedVideoOutputHeight, ); } List _convertDeviceLiveInfoList( LiveConsultationMember member, List devices, ) { return devices.map((e) => _convertDeviceLiveInfo(member, e)).toList(); } }