123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640 |
- import 'dart:io';
- import 'package:ctjt_flutter/common/trtc/ProfileManager_Mock.dart';
- import 'package:ctjt_flutter/common/trtc/TxUtils.dart';
- import 'package:ctjt_flutter/common/trtc/calling/model/TRTCCalling.dart';
- import 'package:ctjt_flutter/common/trtc/calling/model/TRTCCallingDelegate.dart';
- import 'package:ctjt_flutter/common/trtc/calling/ui/base/CallTypes.dart';
- import 'package:ctjt_flutter/common/trtc/calling/ui/base/CallingScenes.dart';
- import 'package:flutter/cupertino.dart';
- import 'package:flutter/material.dart';
- import 'package:flutter_screenutil/flutter_screenutil.dart';
- import 'package:tencent_trtc_cloud/trtc_cloud_def.dart';
- import 'package:tencent_trtc_cloud/trtc_cloud_video_view.dart';
- import 'dart:async';
- import '../base/ExtendButton.dart';
- import '../base/CallStatus.dart';
- class TRTCCallingVideo extends StatefulWidget {
- @override
- _TRTCCallingVideoState createState() => _TRTCCallingVideoState();
- }
- class _TRTCCallingVideoState extends State<TRTCCallingVideo> {
- CallStatus _currentCallStatus = CallStatus.calling;
- CallTypes _currentCallType = CallTypes.Type_Call_Someone;
- CallingScenes _callingScenes = CallingScenes.AudioOneVOne;
- //已经通话时长
- String _hadCallingTime = "00:00";
- late DateTime _startAnswerTime;
- bool _isCameraOff = false;
- bool _isHandsFree = true;
- bool _isMicrophoneOff = false;
- bool _isFrontCamera = true;
- int _bigVideoViewId = -1;
- Timer? _hadCalledCalcTimer;
- late int _smallVideoViewId;
- double _smallViewTop = 64.h;
- double _smallViewRight = 20.w;
- //为false的时候,在已接听状态的时候。小画面显示本地视频,大画面显示远端视频。
- bool isChangeBigSmallVideo = false;
- UserModel? _remoteUserInfo;
- //远端画面可见不可见
- bool _remoteUserAvailable = true;
- late TRTCCalling _tRTCCallingService;
- @override
- void initState() {
- super.initState();
- Future.delayed(Duration.zero, () {
- this.initRemoteInfo();
- });
- initTrtc();
- }
- initTrtc() async {
- _tRTCCallingService = await TRTCCalling.sharedInstance();
- _tRTCCallingService.registerListener(onRtcListener);
- }
- onRtcListener(type, params) {
- switch (type) {
- case TRTCCallingDelegate.onError:
- showMessageTips("发生错误:" + params['errCode'] + "," + params['errMsg'],
- stopCameraAndFinish);
- break;
- case TRTCCallingDelegate.onWarning:
- print('onWarning:warning code = ' +
- params['warningCode'] +
- " ,warning msg = " +
- params['warningMsg']);
- break;
- case TRTCCallingDelegate.onUserEnter:
- handleOnUserAnswer();
- break;
- case TRTCCallingDelegate.onUserLeave:
- showMessageTips("用户离开了", stopCameraAndFinish);
- break;
- case TRTCCallingDelegate.onReject:
- showMessageTips("拒绝通话", stopCameraAndFinish);
- break;
- case TRTCCallingDelegate.onNoResp:
- showMessageTips("无响应", stopCameraAndFinish);
- break;
- case TRTCCallingDelegate.onLineBusy:
- showMessageTips("忙线", stopCameraAndFinish);
- break;
- case TRTCCallingDelegate.onCallingCancel:
- showMessageTips("取消了通话", stopCameraAndFinish);
- break;
- case TRTCCallingDelegate.onCallingTimeout:
- showMessageTips("本次通话超时未应答", stopCameraAndFinish);
- break;
- case TRTCCallingDelegate.onCallEnd:
- showMessageTips("结束通话", stopCameraAndFinish);
- break;
- case TRTCCallingDelegate.onUserVideoAvailable:
- handleOnUserVideoAvailable(params);
- break;
- case TRTCCallingDelegate.onKickedOffline:
- showMessageTips("你被踢下线了", stopCameraAndFinish);
- break;
- }
- }
- initRemoteInfo() async {
- Map arguments = ModalRoute.of(context)!.settings.arguments! as Map;
- safeSetState(() {
- _remoteUserInfo = arguments['remoteUserInfo'] as UserModel;
- _currentCallType = arguments["callType"] as CallTypes;
- _callingScenes = arguments['callingScenes'] as CallingScenes;
- Future.delayed(Duration(microseconds: 100), () {
- if (_currentCallType == CallTypes.Type_Call_Someone) {
- _tRTCCallingService.call(
- _remoteUserInfo!.userId,
- _callingScenes == CallingScenes.VideoOneVOne
- ? TRTCCalling.typeVideoCall
- : TRTCCalling.typeAudioCall);
- }
- });
- });
- }
- //用户接听
- handleOnUserAnswer() async {
- if (_remoteUserInfo != null) {
- _startAnswerTime = DateTime.now();
- safeSetState(() async {
- _currentCallStatus = CallStatus.answer;
- _hadCallingTime = "00:00";
- if (_bigVideoViewId != -1) {
- await _tRTCCallingService.startRemoteView(
- _remoteUserInfo!.userId,
- TRTCCloudDef.TRTC_VIDEO_STREAM_TYPE_SMALL,
- _bigVideoViewId,
- );
- }
- });
- this._callIngTimeUpdate();
- }
- }
- handleOnUserVideoAvailable(params) async {
- if (_remoteUserInfo != null &&
- params["userId"].toString() == _remoteUserInfo!.userId) {
- safeSetState(() {
- _remoteUserAvailable = params["available"] as bool;
- });
- }
- }
- showMessageTips(String msg, Function callback) {
- TxUtils.showErrorToast(msg, context);
- Future.delayed(Duration(seconds: 1), () {
- callback();
- });
- }
- stopCameraAndFinish() {
- _tRTCCallingService.setMicMute(true);
- _tRTCCallingService.closeCamera();
- Future.delayed(Duration(seconds: 1), () {
- if (mounted) {
- Navigator.pushReplacementNamed(
- context,
- "/index",
- );
- }
- });
- }
- String _twoDigits(int n) {
- if (n >= 10) return "$n";
- return "0$n";
- }
- _getDurationTimeString(Duration duration) {
- String line = "";
- if (duration.inHours != 0) {
- line = _twoDigits(duration.inHours.remainder(24)) + ":";
- }
- line = line + _twoDigits(duration.inMinutes.remainder(60)) + ":";
- line = line + _twoDigits(duration.inSeconds.remainder(60));
- return line;
- }
- _callIngTimeUpdate() {
- _hadCalledCalcTimer = Timer.periodic(Duration(seconds: 1), (Timer timer) {
- DateTime now = DateTime.now();
- Duration duration = now.difference(_startAnswerTime);
- safeSetState(() {
- _hadCallingTime = _getDurationTimeString(duration);
- });
- });
- }
- double _getOpacityByVis(bool vis) {
- return vis ? 1.0 : 0;
- }
- safeSetState(callBack) {
- setState(() {
- if (mounted) {
- callBack();
- }
- });
- }
- @override
- dispose() {
- if (_hadCalledCalcTimer != null) {
- _hadCalledCalcTimer!.cancel();
- }
- _tRTCCallingService.unRegisterListener(onRtcListener);
- super.dispose();
- }
- //前后摄像头切换
- onSwitchCamera() {
- _tRTCCallingService.switchCamera(!_isFrontCamera);
- safeSetState(() {
- _isFrontCamera = !_isFrontCamera;
- });
- }
- //麦克风启用禁用
- onMicrophoneTap() {
- _tRTCCallingService.setMicMute(!_isMicrophoneOff);
- setState(() {
- _isMicrophoneOff = !_isMicrophoneOff;
- });
- }
- //摄像头启用禁用
- onCameraTap() async {
- if (!_isCameraOff) {
- await _tRTCCallingService.closeCamera();
- } else {
- //为false的时候,在已接听状态的时候。小画面显示本地视频,大画面显示远端视频。
- if (isChangeBigSmallVideo) {
- await _tRTCCallingService.openCamera(_isFrontCamera, _bigVideoViewId);
- } else {
- await _tRTCCallingService.openCamera(_isFrontCamera, _smallVideoViewId);
- }
- }
- safeSetState(() {
- _isCameraOff = !_isCameraOff;
- });
- }
- //扬声器是否禁用
- onHandsfreeTap() {
- _tRTCCallingService.setHandsFree(!_isHandsFree);
- setState(() {
- _isHandsFree = !_isHandsFree;
- });
- }
- onSwitchAudioTap() {
- //先不支持切到语音通话
- // _tRTCCallingService.closeCamera();
- // safeSetState(() {
- // _callingScenes = CallingScenes.AudioOneVOne;
- // });
- }
- //挂断
- onHangUpCall() async {
- _tRTCCallingService.closeCamera();
- if (_currentCallType == CallTypes.Type_Being_Called &&
- _currentCallStatus == CallStatus.calling) {
- await _tRTCCallingService.reject();
- } else {
- await _tRTCCallingService.hangup();
- }
- Navigator.pushReplacementNamed(
- context,
- "/index",
- );
- }
- //接听
- onAcceptCall() async {
- await _tRTCCallingService.accept();
- safeSetState(() {
- _currentCallStatus = CallStatus.answer;
- });
- }
- getTopBarWidget() {
- bool isCalling = _currentCallStatus == CallStatus.calling ? true : false;
- var topWidget = Positioned(
- left: 0,
- top: _callingScenes == CallingScenes.VideoOneVOne ? 64.h : 185.h,
- width: MediaQuery.of(context).size.width,
- child: Column(
- mainAxisAlignment: MainAxisAlignment.center,
- children: isCalling
- ? [
- Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- Text(
- _remoteUserInfo != null ? _remoteUserInfo!.name : "--",
- style: TextStyle(
- fontSize: 24.sp,
- color: Colors.white,
- fontWeight: FontWeight.bold,
- ),
- ),
- ],
- ),
- Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- Text(
- '正在等待对方接受邀请…',
- style: TextStyle(fontSize: 12.sp, color: Colors.white),
- ),
- ],
- )
- ]
- : _callingScenes == CallingScenes.VideoOneVOne
- ? [
- Row(
- mainAxisAlignment: MainAxisAlignment.start,
- children: [
- Container(
- margin: EdgeInsets.only(
- left: 20.w,
- ),
- decoration: BoxDecoration(),
- child: InkWell(
- onTap: () {
- onSwitchCamera();
- },
- child: Image.asset(
- 'assets/images/callingDemo/switch-camera.png',
- height: 32.h,
- color: Color.fromRGBO(125, 123, 123, 1.0),
- ),
- ),
- )
- ],
- )
- ]
- : [
- //1V1语音通话显示名字
- Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- Text(
- _remoteUserInfo != null
- ? _remoteUserInfo!.name
- : "--",
- style: TextStyle(
- fontSize: 24.sp,
- color: Colors.white,
- fontWeight: FontWeight.bold,
- ),
- ),
- ],
- ),
- ],
- ),
- );
- return topWidget;
- }
- getButtomWidget() {
- var callSomeBtnList = [
- _currentCallStatus == CallStatus.answer
- ? ExtendButton(
- imgUrl: _isMicrophoneOff
- ? "assets/images/callingDemo/microphone-off.png"
- : "assets/images/callingDemo/microphone-on.png",
- tips: "麦克风",
- onTap: () {
- onMicrophoneTap();
- },
- )
- : SizedBox(
- height: 0,
- width: 0,
- ),
- ExtendButton(
- imgUrl: "assets/images/callingDemo/hangup.png",
- tips: "挂断",
- onTap: () {
- onHangUpCall();
- },
- ),
- _currentCallStatus == CallStatus.answer
- ? ExtendButton(
- imgUrl: _callingScenes == CallingScenes.VideoOneVOne
- ? _isCameraOff
- ? "assets/images/callingDemo/camera-off.png"
- : "assets/images/callingDemo/camera-on.png"
- : _isHandsFree
- ? "assets/images/callingDemo/trtccalling_ic_handsfree_enable.png"
- : "assets/images/callingDemo/trtccalling_ic_handsfree_disable.png",
- tips:
- _callingScenes == CallingScenes.VideoOneVOne ? "摄像头" : "扬声器",
- onTap: () {
- if (_callingScenes == CallingScenes.VideoOneVOne)
- onCameraTap();
- else
- onHandsfreeTap();
- },
- )
- : SizedBox(
- height: 0,
- width: 0,
- ),
- ];
- if (_currentCallType == CallTypes.Type_Being_Called &&
- _currentCallStatus == CallStatus.calling) {
- callSomeBtnList.insert(
- 2,
- SizedBox(
- height: 0,
- width: 0,
- ),
- );
- callSomeBtnList.insert(
- 3,
- ExtendButton(
- imgUrl: "assets/images/callingDemo/trtccalling_ic_dialing.png",
- tips: "接听",
- onTap: () {
- onAcceptCall();
- },
- ),
- );
- }
- var buttomWidget = Positioned(
- left: 0,
- bottom: 50.h,
- width: MediaQuery.of(context).size.width,
- child: Column(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- Container(
- margin: EdgeInsets.only(bottom: 20.h),
- child: _currentCallStatus == CallStatus.answer
- ? Text(
- '$_hadCallingTime',
- style: TextStyle(color: Colors.white),
- )
- :
- // _callingScenes == CallingScenes.VideoOneVOne
- // ? ExtendButton(
- // imgUrl: "assets/images/callingDemo/switchToAudio.png",
- // imgHieght: 18,
- // imgColor: Color.fromRGBO(125, 123, 123, 1.0),
- // tips: "切到语音通话",
- // onTap: () {
- // onSwitchAudioTap();
- // },
- // ):
- SizedBox(
- height: 0,
- width: 0,
- ),
- ),
- Row(
- mainAxisAlignment: MainAxisAlignment.spaceEvenly,
- children: callSomeBtnList,
- )
- ],
- ),
- );
- return buttomWidget;
- }
- getBigVideo() {
- if (_callingScenes == CallingScenes.AudioOneVOne) return Container();
- bool nowIsLocalView = true; //判断当前大窗口是否显示本地摄像头
- if (_currentCallStatus == CallStatus.calling)
- nowIsLocalView = true;
- else {
- //已经接听
- if (isChangeBigSmallVideo) {
- nowIsLocalView = true;
- } else {
- nowIsLocalView = false; //远端画面
- }
- }
- var opacityVal = nowIsLocalView
- ? _getOpacityByVis(!_isCameraOff)
- : _getOpacityByVis(_remoteUserAvailable);
- return _callingScenes == CallingScenes.VideoOneVOne
- ? AnimatedOpacity(
- duration: Duration(milliseconds: 100),
- opacity: opacityVal,
- child: TRTCCloudVideoView(
- key: ValueKey("_bigVideoViewId"),
- viewType: TRTCCloudDef.TRTC_VideoView_SurfaceView,
- onViewCreated: (viewId) async {
- _bigVideoViewId = viewId;
- if (_callingScenes == CallingScenes.VideoOneVOne) {
- await _tRTCCallingService.openCamera(
- _isFrontCamera, _bigVideoViewId);
- }
- },
- ),
- )
- : Container();
- }
- getSmallVideoContainer() {
- if (_callingScenes == CallingScenes.AudioOneVOne) {
- return Container(
- height: 100.h,
- width: 100.w,
- child: Container(),
- decoration: _remoteUserInfo != null
- ? BoxDecoration(
- image: DecorationImage(
- image: NetworkImage(_remoteUserInfo!.avatar),
- fit: BoxFit.cover,
- ),
- )
- : BoxDecoration(),
- );
- }
- bool nowIsRemoteView = false; //判断当前小窗口是否显示远端画面
- if (_currentCallStatus == CallStatus.calling)
- nowIsRemoteView = true;
- else {
- //已经接听
- if (isChangeBigSmallVideo) {
- nowIsRemoteView = true;
- } else {
- nowIsRemoteView = false; //本地摄像头
- }
- }
- return Container(
- height: _currentCallStatus == CallStatus.calling ? 100.h : 216.h,
- width: 100.w,
- child: _currentCallStatus == CallStatus.answer
- ? AnimatedOpacity(
- duration: Duration(milliseconds: 100),
- opacity: nowIsRemoteView
- ? _getOpacityByVis(_remoteUserAvailable)
- : _getOpacityByVis(!_isCameraOff),
- child: TRTCCloudVideoView(
- key: ValueKey("_smallVideoViewId"),
- viewType: TRTCCloudDef.TRTC_VideoView_SurfaceView,
- onViewCreated: (viewId) async {
- _smallVideoViewId = viewId;
- if (Platform.isIOS) {
- await _tRTCCallingService
- .updateLocalView(_smallVideoViewId);
- } else {
- await _tRTCCallingService.openCamera(
- _isFrontCamera, _smallVideoViewId);
- }
- },
- ),
- )
- : Container(),
- decoration:
- _remoteUserInfo != null && _currentCallStatus == CallStatus.calling
- ? BoxDecoration(
- image: DecorationImage(
- image: NetworkImage(_remoteUserInfo!.avatar),
- fit: BoxFit.cover,
- ),
- )
- : BoxDecoration(),
- );
- }
- changeVideoView() {
- if (_callingScenes == CallingScenes.AudioOneVOne ||
- _currentCallStatus == CallStatus.calling) return;
- setState(() async {
- isChangeBigSmallVideo = !isChangeBigSmallVideo;
- //为false的时候,在已接听状态的时候。小画面显示本地视频,大画面显示远端视频。
- if (isChangeBigSmallVideo) {
- await _tRTCCallingService.updateLocalView(_bigVideoViewId);
- await _tRTCCallingService.updateRemoteView(_remoteUserInfo!.userId,
- TRTCCloudDef.TRTC_VIDEO_STREAM_TYPE_SMALL, _smallVideoViewId);
- } else {
- await _tRTCCallingService.updateLocalView(_smallVideoViewId);
- await _tRTCCallingService.updateRemoteView(_remoteUserInfo!.userId,
- TRTCCloudDef.TRTC_VIDEO_STREAM_TYPE_SMALL, _bigVideoViewId);
- }
- });
- }
- @override
- Widget build(BuildContext context) {
- var remotePanel = Positioned(
- top: _smallViewTop,
- right: _callingScenes == CallingScenes.VideoOneVOne
- ? _smallViewRight
- : MediaQuery.of(context).size.width / 2 - 100 / 2,
- child: GestureDetector(
- onDoubleTap: () {
- if (Platform.isIOS) changeVideoView();
- },
- onPanUpdate: (DragUpdateDetails e) {
- //用户手指滑动时,更新偏移,重新构建
- if (_callingScenes == CallingScenes.VideoOneVOne) {
- safeSetState(() {
- _smallViewRight -= e.delta.dx;
- _smallViewTop += e.delta.dy;
- });
- }
- },
- child: getSmallVideoContainer(),
- ));
- return Scaffold(
- body: WillPopScope(
- onWillPop: () async {
- return true;
- },
- child: Stack(
- alignment: Alignment.topLeft,
- fit: StackFit.expand,
- children: [
- Container(
- color: Color.fromRGBO(
- 93, 91, 90, 1), //Color.fromRGBO(242, 243, 248, 1),
- child: getBigVideo(),
- ),
- remotePanel,
- getTopBarWidget(),
- getButtomWidget(),
- ],
- ),
- ),
- );
- }
- }
|