mirror of
				https://gitlab.com/famedly/fluffychat.git
				synced 2025-10-31 12:07:24 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			174 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
			
		
		
	
	
			174 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
| import 'dart:core';
 | |
| 
 | |
| import 'package:flutter/foundation.dart';
 | |
| import 'package:flutter/material.dart';
 | |
| 
 | |
| import 'package:connectivity_plus/connectivity_plus.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/dialer/dialer.dart';
 | |
| import '../../utils/voip/user_media_manager.dart';
 | |
| 
 | |
| class VoipPlugin extends WidgetsBindingObserver implements WebRTCDelegate {
 | |
|   VoipPlugin({required this.client, required this.context}) {
 | |
|     voip = VoIP(client, this);
 | |
|     try {
 | |
|       Connectivity()
 | |
|           .onConnectivityChanged
 | |
|           .listen(_handleNetworkChanged)
 | |
|           .onError((e) => _currentConnectivity = ConnectivityResult.none);
 | |
|     } catch (e, s) {
 | |
|       Logs().w('Could not subscribe network updates', e, s);
 | |
|     }
 | |
|     Connectivity()
 | |
|         .checkConnectivity()
 | |
|         .then((result) => _currentConnectivity = result)
 | |
|         .catchError((e) => _currentConnectivity = ConnectivityResult.none);
 | |
|     if (!kIsWeb) {
 | |
|       final wb = WidgetsBinding.instance;
 | |
|       wb.addObserver(this);
 | |
|       didChangeAppLifecycleState(wb.lifecycleState!);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   final Client client;
 | |
|   bool background = false;
 | |
|   bool speakerOn = false;
 | |
|   late VoIP voip;
 | |
|   ConnectivityResult? _currentConnectivity;
 | |
|   ValueChanged<CallSession>? onIncomingCall;
 | |
|   OverlayEntry? overlayEntry;
 | |
| 
 | |
|   // hacky workaround: in order to have [Overlay.of] working on web, the context
 | |
|   // mus explicitly be re-assigned
 | |
|   //
 | |
|   // hours wasted: 5
 | |
|   BuildContext context;
 | |
| 
 | |
|   void _handleNetworkChanged(ConnectivityResult result) async {
 | |
|     /// Got a new connectivity status!
 | |
|     if (_currentConnectivity != result) {
 | |
|       voip.calls.forEach((_, sess) {
 | |
|         sess.restartIce();
 | |
|       });
 | |
|     }
 | |
|     _currentConnectivity = result;
 | |
|   }
 | |
| 
 | |
|   @override
 | |
|   void didChangeAppLifecycleState(AppLifecycleState state) {
 | |
|     Logs().v('AppLifecycleState = $state');
 | |
|     background = !(state != AppLifecycleState.detached &&
 | |
|         state != AppLifecycleState.paused);
 | |
|   }
 | |
| 
 | |
|   void addCallingOverlay(
 | |
|       BuildContext context, String callId, CallSession call) {
 | |
|     if (overlayEntry != null) {
 | |
|       Logs().w('[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 isBackgroud => background;
 | |
| 
 | |
|   @override
 | |
|   bool get isWeb => kIsWeb;
 | |
| 
 | |
|   @override
 | |
|   Future<RTCPeerConnection> createPeerConnection(
 | |
|           Map<String, dynamic> configuration,
 | |
|           [Map<String, dynamic> constraints = const {}]) =>
 | |
|       webrtc_impl.createPeerConnection(configuration, constraints);
 | |
| 
 | |
|   @override
 | |
|   VideoRenderer createRenderer() {
 | |
|     return webrtc_impl.RTCVideoRenderer();
 | |
|   }
 | |
| 
 | |
|   @override
 | |
|   void playRingtone() async {
 | |
|     if (!background) {
 | |
|       try {
 | |
|         await UserMediaManager().startRingingTone();
 | |
|       } catch (_) {}
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   @override
 | |
|   void stopRingtone() async {
 | |
|     if (!background) {
 | |
|       try {
 | |
|         await UserMediaManager().stopRingingTone();
 | |
|       } catch (_) {}
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   @override
 | |
|   void handleNewCall(CallSession call) async {
 | |
|     /// Popup CallingPage for incoming call.
 | |
|     if (!background) {
 | |
|       addCallingOverlay(context, call.callId, call);
 | |
|     } else {
 | |
|       onIncomingCall?.call(call);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   @override
 | |
|   void handleCallEnded(CallSession session) async {
 | |
|     if (overlayEntry != null) {
 | |
|       overlayEntry?.remove();
 | |
|       overlayEntry = null;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   @override
 | |
|   void handleGroupCallEnded(GroupCall groupCall) {
 | |
|     // TODO: implement handleGroupCallEnded
 | |
|   }
 | |
| 
 | |
|   @override
 | |
|   void handleNewGroupCall(GroupCall groupCall) {
 | |
|     // TODO: implement handleNewGroupCall
 | |
|   }
 | |
| 
 | |
|   @override
 | |
|   Future<webrtc_impl.MediaStream> cloneStream(webrtc_impl.MediaStream stream) {
 | |
|     // TODO: implement cloneStream
 | |
|     throw UnimplementedError();
 | |
|   }
 | |
| }
 | 
