From 304f77b9bb47843ac4110163423c43c358d3a306 Mon Sep 17 00:00:00 2001 From: "Aamir.Muhammad" Date: Wed, 15 Feb 2023 09:00:53 +0300 Subject: [PATCH] Webrtc Calling --- ios/Runner/Info.plist | 3 + lib/classes/notifications.dart | 5 ++ lib/classes/voip_chat_call.dart | 64 +++++++++++++++ lib/provider/chat_call_provider.dart | 112 ++++++++++++++++++++------- pubspec.yaml | 2 +- 5 files changed, 159 insertions(+), 27 deletions(-) create mode 100644 lib/classes/voip_chat_call.dart diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 75c680b..a62656f 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -57,8 +57,11 @@ This app requires microphone access to for call. UIBackgroundModes + processing fetch remote-notification + voip + FirebaseAppDelegateProxyEnabled diff --git a/lib/classes/notifications.dart b/lib/classes/notifications.dart index f714662..3d82570 100644 --- a/lib/classes/notifications.dart +++ b/lib/classes/notifications.dart @@ -8,7 +8,10 @@ import 'package:huawei_hmsavailability/huawei_hmsavailability.dart'; import 'package:huawei_push/huawei_push.dart' as huawei_push; import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/utils.dart'; +import 'package:mohem_flutter_app/classes/voip_chat_call.dart'; +import 'package:mohem_flutter_app/provider/chat_call_provider.dart'; import 'package:permission_handler/permission_handler.dart'; +import 'package:uuid/uuid.dart'; final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); @@ -130,4 +133,6 @@ Future backgroundMessageHandler(RemoteMessage message) async { await Firebase.initializeApp(); Utils.saveStringFromPrefs("isAppOpendByChat", "false"); Utils.saveStringFromPrefs("notificationData", message.data["user_chat_history_response"].toString()); + + ChatVoipCall().showCallkitIncoming(uuid: const Uuid().v4(), data: message); } diff --git a/lib/classes/voip_chat_call.dart b/lib/classes/voip_chat_call.dart new file mode 100644 index 0000000..f96fb19 --- /dev/null +++ b/lib/classes/voip_chat_call.dart @@ -0,0 +1,64 @@ +import 'dart:convert'; + +import 'package:firebase_messaging/firebase_messaging.dart'; +import 'package:flutter_callkit_incoming/entities/entities.dart'; +import 'package:flutter_callkit_incoming/flutter_callkit_incoming.dart'; +import 'package:mohem_flutter_app/main.dart'; +import 'package:mohem_flutter_app/models/chat/get_single_user_chat_list_model.dart'; + +class ChatVoipCall { + static final ChatVoipCall _instance = ChatVoipCall._internal(); + + ChatVoipCall._internal(); + + factory ChatVoipCall() => _instance; + + Future showCallkitIncoming({required String uuid, required RemoteMessage data}) async { + logger.d(data.data["user_chat_history_response"]); + + SingleUserChatModel callerData = SingleUserChatModel.fromJson(jsonDecode(data.data["user_chat_history_response"])); + var params = CallKitParams( + id: uuid, + nameCaller: callerData.currentUserName, + appName: 'Mohemm', + avatar: 'https://i.pravatar.cc/100', + handle: '0123456789', + type: 0, + duration: 30000, + textAccept: 'Accept', + textDecline: 'Decline', + textMissedCall: 'Missed call', + textCallback: 'Call back', + extra: {'userId': '1a2b3c4d'}, + headers: {'apiKey': 'Abc@123!', 'platform': 'flutter'}, + android: const AndroidParams( + isCustomNotification: true, + isShowLogo: false, + isShowCallback: false, + isShowMissedCallNotification: true, + ringtonePath: 'system_ringtone_default', + backgroundColor: '#0955fa', + backgroundUrl: 'assets/test.png', + actionColor: '#4CAF50', + ), + ios: IOSParams( + iconName: 'CallKitLogo', + handleType: '', + supportsVideo: true, + maximumCallGroups: 2, + maximumCallsPerCallGroup: 1, + audioSessionMode: 'default', + audioSessionActive: true, + audioSessionPreferredSampleRate: 44100.0, + audioSessionPreferredIOBufferDuration: 0.005, + supportsDTMF: true, + supportsHolding: true, + supportsGrouping: false, + supportsUngrouping: false, + ringtonePath: 'system_ringtone_default', + ), + ); + logger.d(callerData.targetUserId); + await FlutterCallkitIncoming.showCallkitIncoming(params); + } +} diff --git a/lib/provider/chat_call_provider.dart b/lib/provider/chat_call_provider.dart index 06c5201..af8b100 100644 --- a/lib/provider/chat_call_provider.dart +++ b/lib/provider/chat_call_provider.dart @@ -3,6 +3,9 @@ import 'dart:io'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_callkit_incoming/entities/android_params.dart'; +import 'package:flutter_callkit_incoming/entities/call_kit_params.dart'; +import 'package:flutter_callkit_incoming/entities/ios_params.dart'; import 'package:flutter_webrtc/flutter_webrtc.dart'; import 'package:just_audio/just_audio.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; @@ -13,6 +16,7 @@ import 'package:mohem_flutter_app/provider/chat_provider_model.dart'; import 'package:mohem_flutter_app/ui/chat/call/chat_incoming_call_screen.dart'; import 'package:mohem_flutter_app/ui/chat/call/start_call_screen.dart'; import 'package:mohem_flutter_app/ui/landing/dashboard_screen.dart'; +import 'package:uuid/uuid.dart'; class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin { ///////////////////// Web RTC Video Calling ////////////////////// @@ -31,6 +35,7 @@ class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin { bool isVideoCall = false; bool isCallStarted = false; bool isFrontCamera = true; + bool isOnIncomingCallPage = false; /// WebRTC Connection Variables bool _offer = false; @@ -210,32 +215,33 @@ class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin { print("--------------------- On Incoming Call ---------------------------------------"); dynamic items = params!.toList(); logger.d(items); - Map json = { - "callerID": items[0]["id"], - "callerName": items[0]["userName"], - "callerEmail": items[0]["email"], - "callerTitle": items[0]["title"], - "callerPhone": null, - "receiverID": AppState().chatDetails!.response!.id, - "receiverName": AppState().chatDetails!.response!.userName, - "receiverEmail": AppState().chatDetails!.response!.email, - "receiverTitle": AppState().chatDetails!.response!.title, - "receiverPhone": AppState().chatDetails!.response!.phone, - "title": AppState().chatDetails!.response!.userName!.replaceAll(".", " "), - "callType": items[1] ? "Video" : "Audio", - }; - - CallDataModel callData = CallDataModel.fromJson(json); - await Navigator.push( - providerContext, - MaterialPageRoute( - builder: (BuildContext context) => - IncomingCall( - isVideoCall: items[1] ? true : false, - outGoingCallData: callData, - ), - ), - ); + if (!isOnIncomingCallPage) { + Map json = { + "callerID": items[0]["id"], + "callerName": items[0]["userName"], + "callerEmail": items[0]["email"], + "callerTitle": items[0]["title"], + "callerPhone": null, + "receiverID": AppState().chatDetails!.response!.id, + "receiverName": AppState().chatDetails!.response!.userName, + "receiverEmail": AppState().chatDetails!.response!.email, + "receiverTitle": AppState().chatDetails!.response!.title, + "receiverPhone": AppState().chatDetails!.response!.phone, + "title": AppState().chatDetails!.response!.userName!.replaceAll(".", " "), + "callType": items[1] ? "Video" : "Audio", + }; + CallDataModel callData = CallDataModel.fromJson(json); + await Navigator.push( + providerContext, + MaterialPageRoute( + builder: (BuildContext context) => IncomingCall( + isVideoCall: items[1] ? true : false, + outGoingCallData: callData, + ), + ), + ); + isOnIncomingCallPage = true; + } } void onCallDeclinedAsync(List? params) { @@ -418,4 +424,58 @@ class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin { Helper.switchCamera(localStream.getVideoTracks()[0]); notifyListeners(); } + + + + + + + CallKitParams callKitParams = CallKitParams( + id: "_currentUuid", + nameCaller: 'Hien Nguyen', + appName: 'Callkit', + avatar: 'https://i.pravatar.cc/100', + handle: '0123456789', + type: 0, + textAccept: 'Accept', + textDecline: 'Decline', + textMissedCall: 'Missed call', + textCallback: 'Call back', + duration: 30000, + extra: {'userId': '1a2b3c4d'}, + headers: {'apiKey': 'Abc@123!', 'platform': 'flutter'}, + android: const AndroidParams( + isCustomNotification: true, + isShowLogo: false, + isShowCallback: false, + isShowMissedCallNotification: true, + ringtonePath: 'system_ringtone_default', + backgroundColor: '#0955fa', + backgroundUrl: 'https://i.pravatar.cc/500', + actionColor: '#4CAF50', + incomingCallNotificationChannelName: "Incoming Call", + missedCallNotificationChannelName: "Missed Call"), + ios: IOSParams( + iconName: 'CallKitLogo', + handleType: 'generic', + supportsVideo: true, + maximumCallGroups: 2, + maximumCallsPerCallGroup: 1, + audioSessionMode: 'default', + audioSessionActive: true, + audioSessionPreferredSampleRate: 44100.0, + audioSessionPreferredIOBufferDuration: 0.005, + supportsDTMF: true, + supportsHolding: true, + supportsGrouping: false, + supportsUngrouping: false, + ringtonePath: 'system_ringtone_default', + ), + ); + + + + + + } diff --git a/pubspec.yaml b/pubspec.yaml index 3af712e..8ee84f9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -87,12 +87,12 @@ dependencies: flutter_webrtc: ^0.9.20 draggable_widget: ^2.0.0 flutter_local_notifications: any + flutter_callkit_incoming: ^1.0.3+3 #firebase_analytics: any #Chat Voice Message Recoding & Play audio_waveforms: ^0.1.5+1 rxdart: ^0.27.7 - #Encryption flutter_des: ^2.1.0