178 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			Dart
		
	
	
	
			
		
		
	
	
			178 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			Dart
		
	
	
	
| import 'dart:core';
 | |
| 
 | |
| import 'package:flutter/foundation.dart';
 | |
| import 'package:flutter/material.dart';
 | |
| 
 | |
| import 'package:flutter_foreground_task/flutter_foreground_task.dart';
 | |
| import 'package:flutter_webrtc/flutter_webrtc.dart' as webrtc_impl;
 | |
| import 'package:matrix/matrix.dart';
 | |
| import 'package:webrtc_interface/webrtc_interface.dart' hide Navigator;
 | |
| 
 | |
| import 'package:fluffychat/pages/chat_list/chat_list.dart';
 | |
| import 'package:fluffychat/pages/dialer/dialer.dart';
 | |
| import 'package:fluffychat/utils/platform_infos.dart';
 | |
| import '../../utils/voip/user_media_manager.dart';
 | |
| import '../widgets/matrix.dart';
 | |
| 
 | |
| class VoipPlugin with WidgetsBindingObserver implements WebRTCDelegate {
 | |
|   final MatrixState matrix;
 | |
|   Client get client => matrix.client;
 | |
|   VoipPlugin(this.matrix) {
 | |
|     voip = VoIP(client, this);
 | |
|     if (!kIsWeb) {
 | |
|       final wb = WidgetsBinding.instance;
 | |
|       wb.addObserver(this);
 | |
|       didChangeAppLifecycleState(wb.lifecycleState);
 | |
|     }
 | |
|   }
 | |
|   bool background = false;
 | |
|   bool speakerOn = false;
 | |
|   late VoIP voip;
 | |
|   OverlayEntry? overlayEntry;
 | |
|   BuildContext get context => matrix.context;
 | |
| 
 | |
|   @override
 | |
|   void didChangeAppLifecycleState(AppLifecycleState? state) {
 | |
|     background = (state == AppLifecycleState.detached ||
 | |
|         state == AppLifecycleState.paused);
 | |
|   }
 | |
| 
 | |
|   void addCallingOverlay(String callId, CallSession call) {
 | |
|     final context =
 | |
|         kIsWeb ? ChatList.contextForVoip! : this.context; // web is weird
 | |
| 
 | |
|     if (overlayEntry != null) {
 | |
|       Logs().e('[VOIP] addCallingOverlay: The call session already exists?');
 | |
|       overlayEntry!.remove();
 | |
|     }
 | |
|     // Overlay.of(context) is broken on web
 | |
|     // falling back on a dialog
 | |
|     if (kIsWeb) {
 | |
|       showDialog(
 | |
|         context: context,
 | |
|         builder: (context) => Calling(
 | |
|           context: context,
 | |
|           client: client,
 | |
|           callId: callId,
 | |
|           call: call,
 | |
|           onClear: () => Navigator.of(context).pop(),
 | |
|         ),
 | |
|       );
 | |
|     } else {
 | |
|       overlayEntry = OverlayEntry(
 | |
|         builder: (_) => Calling(
 | |
|           context: context,
 | |
|           client: client,
 | |
|           callId: callId,
 | |
|           call: call,
 | |
|           onClear: () {
 | |
|             overlayEntry?.remove();
 | |
|             overlayEntry = null;
 | |
|           },
 | |
|         ),
 | |
|       );
 | |
|       Overlay.of(context).insert(overlayEntry!);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   @override
 | |
|   MediaDevices get mediaDevices => webrtc_impl.navigator.mediaDevices;
 | |
| 
 | |
|   @override
 | |
|   bool get isWeb => kIsWeb;
 | |
| 
 | |
|   @override
 | |
|   Future<RTCPeerConnection> createPeerConnection(
 | |
|     Map<String, dynamic> configuration, [
 | |
|     Map<String, dynamic> constraints = const {},
 | |
|   ]) =>
 | |
|       webrtc_impl.createPeerConnection(configuration, constraints);
 | |
| 
 | |
|   Future<bool> get hasCallingAccount async => false;
 | |
| 
 | |
|   @override
 | |
|   Future<void> playRingtone() async {
 | |
|     if (!background && !await hasCallingAccount) {
 | |
|       try {
 | |
|         await UserMediaManager().startRingingTone();
 | |
|       } catch (_) {}
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   @override
 | |
|   Future<void> stopRingtone() async {
 | |
|     if (!background && !await hasCallingAccount) {
 | |
|       try {
 | |
|         await UserMediaManager().stopRingingTone();
 | |
|       } catch (_) {}
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   @override
 | |
|   Future<void> handleNewCall(CallSession call) async {
 | |
|     if (PlatformInfos.isAndroid) {
 | |
|       try {
 | |
|         final wasForeground = await FlutterForegroundTask.isAppOnForeground;
 | |
| 
 | |
|         await matrix.store.setString(
 | |
|           'wasForeground',
 | |
|           wasForeground == true ? 'true' : 'false',
 | |
|         );
 | |
|         FlutterForegroundTask.setOnLockScreenVisibility(true);
 | |
|         FlutterForegroundTask.wakeUpScreen();
 | |
|         FlutterForegroundTask.launchApp();
 | |
|       } catch (e) {
 | |
|         Logs().e('VOIP foreground failed $e');
 | |
|       }
 | |
|       // use fallback flutter call pages for outgoing and video calls.
 | |
|       addCallingOverlay(call.callId, call);
 | |
|     } else {
 | |
|       addCallingOverlay(call.callId, call);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   @override
 | |
|   Future<void> handleCallEnded(CallSession session) async {
 | |
|     if (overlayEntry != null) {
 | |
|       overlayEntry!.remove();
 | |
|       overlayEntry = null;
 | |
|       if (PlatformInfos.isAndroid) {
 | |
|         FlutterForegroundTask.setOnLockScreenVisibility(false);
 | |
|         FlutterForegroundTask.stopService();
 | |
|         final wasForeground = matrix.store.getString('wasForeground');
 | |
|         wasForeground == 'false' ? FlutterForegroundTask.minimizeApp() : null;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   @override
 | |
|   Future<void> handleGroupCallEnded(GroupCallSession groupCall) async {
 | |
|     // TODO: implement handleGroupCallEnded
 | |
|   }
 | |
| 
 | |
|   @override
 | |
|   Future<void> handleNewGroupCall(GroupCallSession groupCall) async {
 | |
|     // TODO: implement handleNewGroupCall
 | |
|   }
 | |
| 
 | |
|   @override
 | |
|   // TODO: implement canHandleNewCall
 | |
|   bool get canHandleNewCall =>
 | |
|       voip.currentCID == null && voip.currentGroupCID == null;
 | |
| 
 | |
|   @override
 | |
|   Future<void> handleMissedCall(CallSession session) async {
 | |
|     // TODO: implement handleMissedCall
 | |
|   }
 | |
| 
 | |
|   @override
 | |
|   // TODO: implement keyProvider
 | |
|   EncryptionKeyProvider? get keyProvider => throw UnimplementedError();
 | |
| 
 | |
|   @override
 | |
|   Future<void> registerListeners(CallSession session) {
 | |
|     // TODO: implement registerListeners
 | |
|     throw UnimplementedError();
 | |
|   }
 | |
| }
 |