import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'package:diplomaticquarterapp/locator.dart'; import 'package:diplomaticquarterapp/models/LiveCare/IncomingCallData.dart'; import 'package:diplomaticquarterapp/routes.dart'; import 'package:diplomaticquarterapp/uitl/navigation_service.dart'; import 'package:diplomaticquarterapp/uitl/utils.dart'; import 'package:diplomaticquarterapp/voipcall/call/chat_incoming_call_screen.dart'; import 'package:diplomaticquarterapp/voipcall/model/call.dart'; import 'package:diplomaticquarterapp/voipcall/model/webrtc_payloads.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_webrtc/flutter_webrtc.dart'; import 'package:http/http.dart'; import 'package:just_audio/just_audio.dart'; import 'package:logger/logger.dart' as log; import 'package:logging/logging.dart'; import 'package:signalr_netcore/signalr_client.dart'; class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin { ///////////////////// Web RTC Video Calling ////////////////////// // Video Call HubConnection? chatHubConnection; RTCPeerConnection? _pc; //late ChatProviderModel chatProvModel; RTCVideoRenderer? localVideoRenderer; RTCVideoRenderer? remoteRenderer; final AudioPlayer player = AudioPlayer(); MediaStream? _localStream; CallDataModel? outGoingCallData; bool isMicOff = false; bool isLoudSpeaker = false; bool isCamOff = false; bool isCallEnded = false; // This need to Be Changed to dynamic bool isVideoCall = true; bool isAudioCall = false; bool isCallStarted = false; bool isFrontCamera = true; //SingleUserChatModel? incomingCallData; /// WebRTC Connection Variables bool isIncomingCallLoader = true; bool isIncomingCall = false; bool isOutGoingCall = false; bool isUserOnline = false; List devices = []; log.Logger debuglogger = log.Logger(); IncomingCallData? _incomingCallData; IncomingCallData? get incomingCallData => _incomingCallData; set incomingCallData(IncomingCallData? value) { _incomingCallData = value; } // // // If you want only to log out the message for the higer level hub protocol: // final hubProtLogger = Logger("SignalR - hub"); // final transportProtLogger = Logger("SignalR - transport"); // late Logger _logger; // late StreamSubscription _logMessagesSub; // // void _handleLogMessage(LogRecord msg) { // print(msg.message); // } // // Future buildHubConnection() async { // try { // Logger.root.level = Level.ALL; // _logMessagesSub = Logger.root.onRecord.listen(_handleLogMessage); // _logger = Logger("ChatPageViewModel"); // // // chatHubConnection = await getHubConnection(); // String to = "ytvF4zQfUrJHOUfpE7UE1Q"; // HttpConnectionOptions httpOp = HttpConnectionOptions(skipNegotiation: false, logMessageContent: true, logger: transportProtLogger); // // hub = HubConnectionBuilder() // // .withUrl(ApiConsts.chatHubConnectionUrl + "?UserId=${AppState().chatDetails!.response!.id}&source=Desktop&access_token=${AppState().chatDetails!.response!.token}", options: httpOp) // // .withAutomaticReconnect(retryDelays: [2000, 5000, 10000, 20000]).build(); // var urlWithParams = "https://ms.hmg.com/livecare/liveCareHub?UserID=4767770&ProjectId=12&IsAdmin=false&To=$to"; // print("ChatHubURL:::: " + urlWithParams); // chatHubConnection = await HubConnectionBuilder().withUrl(urlWithParams, options: httpOp).build(); // await chatHubConnection!.start(); // print(chatHubConnection!.state); // chatHubConnection!.onclose(({error}) { // print("Connection Closed"); // }); // // if (chatHubConnection!.state == HubConnectionState.Connected) { // // print("Success Chat Con ID::: " + chatHubConnection!.connectionId.toString()); // // if (kDebugMode) { // // print("Hub Conn: Startedddddddd"); // // } // // //registerCallListners(); // // } // } catch (e) { // print(e.toString()); // Utils.showErrorToast(e.toString()); // } // } //{"id":341682,"userName":"Aamir.Muhammad","email":"Aamir.Muhammad@cloudsolutions.com.sa","phone":null,"title":"Aamir Saleem Ahmad Dost Muhammad","token":"eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJuYW1laWQiOiIzNDE2ODIiLCJlbWFpbCI6IkFhbWlyLk11aGFtbWFkQGNsb3Vkc29sdXRpb25zLmNvbS5zYSIsImh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd3MvMjAwOC8wNi9pZGVudGl0eS9jbGFpbXMvdXNlcmRhdGEiOiJBYW1pci5NdWhhbW1hZCIsIm5iZiI6MTcwNzIwNTAyMywiZXhwIjoxNzA3MjkxNDIzLCJpYXQiOjE3MDcyMDUwMjN9.Zz2bcsMwiLAAWGZh2E_p5Qs6ItMt0JHhDFI_0DLdggCQtt6HHcT4n8nvqMZx-uYr3jLwqhA_IAjTuaCeSE15sw","isDomainUser":true,"isActiveCode":false,"encryptedUserId":"nn7RkYzbnQc=","encryptedUserName":"/QruOyp4QMcmNXKZlljUgg=="} // Future getHubConnection() async { // AppState().chatDetails = getUserToken.UserAutoLoginModel( // response: getUserToken.Response.fromJson({ // "id": 341682, // "userName": "Aamir.Muhammad", // "email": "Aamir.Muhammad@cloudsolutions.com.sa", // "phone": null, // "title": "Aamir Saleem Ahmad Dost Muhammad", // "token": // "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJuYW1laWQiOiIzNDE2ODIiLCJlbWFpbCI6IkFhbWlyLk11aGFtbWFkQGNsb3Vkc29sdXRpb25zLmNvbS5zYSIsImh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd3MvMjAwOC8wNi9pZGVudGl0eS9jbGFpbXMvdXNlcmRhdGEiOiJBYW1pci5NdWhhbW1hZCIsIm5iZiI6MTcwODI1NjI5NywiZXhwIjoxNzA4MzQyNjk3LCJpYXQiOjE3MDgyNTYyOTd9.Y-QDVbSbPzcMVkHyIT06WgM0EsKH183hASZrIsXGkFOR_XZcqCJS-CrgdN0nOtxCWV6wd01dgfhMTNTZhybwiQ", // "isDomainUser": true, // "isActiveCode": false, // "encryptedUserId": "nn7RkYzbnQc=", // "encryptedUserName": "/QruOyp4QMcmNXKZlljUgg==" // }), // ); // String to = "dfK3ZqFD-BTlJLnuf1F5Cw"; // HubConnection hub; // HttpConnectionOptions httpOp = HttpConnectionOptions(skipNegotiation: false, logMessageContent: true); // // hub = HubConnectionBuilder() // // .withUrl(ApiConsts.chatHubConnectionUrl + "?UserId=${AppState().chatDetails!.response!.id}&source=Desktop&access_token=${AppState().chatDetails!.response!.token}", options: httpOp) // // .withAutomaticReconnect(retryDelays: [2000, 5000, 10000, 20000]).build(); // var urlWithParams = "https://ms.hmg.com/livecare/liveCareHub?UserID=4767770&ProjectId=15&IsAdmin=false&To=$to"; // print("ChatHubURL:::: " + urlWithParams); // hub = await HubConnectionBuilder().withUrl(urlWithParams, options: httpOp).withAutomaticReconnect(retryDelays: [2000, 5000, 10000, 20000]).build(); // return hub; // } // Future makeCall({required String callType}) async { // Map json = { // "callerID": AppState().chatDetails!.response!.id, // "callerName": AppState().chatDetails!.response!.userName, // "callerEmail": AppState().chatDetails!.response!.email, // "callerTitle": AppState().chatDetails!.response!.title, // "callerPhone": AppState().chatDetails!.response!.phone, // "receiverID": 266642, // "receiverName": "Muhammad Alam", // "receiverEmail": "Muhamad.Alam@cloudsolutions.com.sa", // "receiverTitle": "Muhammad Alam", // "receiverPhone": "123456789", // "title": "Muhammad Alam", // "callType": callType == "VIDEO" ? "Video" : "Audio", // }; // CallDataModel res = CallDataModel.fromJson(json); // return res; // } // void registerCallListners() { // if (kDebugMode) { // print("=================== Call Listeners Registered ======================="); // } // chatHubConnection!.on("OnCallAcceptedAsync", onCallAcceptedAsync); // chatHubConnection!.on("OnIceCandidateAsync", onIceCandidateAsync); // chatHubConnection!.on("OnOfferAsync", onOfferAsync); // chatHubConnection!.on("OnAnswerOffer", onAnswerOffer); // chatHubConnection!.on("OnHangUpAsync", onHangUpAsync); // // chatHubConnection!.on("OnCallDeclinedAsync", onCallDeclinedAsync); // // chatHubConnection!.on("OnIncomingCallAsync", OnIncomingCallAsync); // } // Audio Constraints Map audioConstraints = { "sampleRate": 8000, "sampleSize": 16, "channelCount": 2, "echoCancellation": true, "audio": true, }; // Future init() async { // _pc = await creatOfferWithCon(); // Future.delayed(const Duration(seconds: 2), () { // connectIncomingCall(); // }); // } ///////////////////////////////////////////////OutGoing Call//////////////////////////////////////////////////// // // Future initLocalCamera({callData, bool isIncomingCall = false}) async { // isCallEnded = false; // outGoingCallData = callData; // await initStreams(); // await startCall(); // _pc = await creatOfferWithCon(); // connectOutgoing(); // notifyListeners(); // } // // void connectOutgoing() { // isOutGoingCall = true; // // notifyListeners(); // } // // Future startCall() async { // // chatProvModel.isTextMsg = true; // // chatProvModel.isAttachmentMsg = false; // // chatProvModel.isVoiceMsg = false; // // chatProvModel.isReplyMsg = false; // // chatProvModel.isCall = true; // // chatProvModel.message.text = "Start $callType call ${outGoingCallData.receiverName.toString().replaceAll(".", " ")}"; // // chatProvModel.sendChatMessage( // // context, // // targetUserId: outGoingCallData.receiverId, // // userStatus: 1, // // userEmail: outGoingCallData.receiverEmail, // // targetUserName: outGoingCallData.receiverName, // // ); // await invoke( // invokeMethod: "CallUserAsync", // currentUserID: outGoingCallData!.callerId!, // targetUserID: outGoingCallData!.receiverId!, // ); // await invoke(invokeMethod: "UpdateUserStatusAsync", currentUserID: outGoingCallData!.callerId!, targetUserID: outGoingCallData!.receiverId!, userStatus: 4); // } // // OutGoing Listeners // void onCallAcceptedAsync(List? params) async { // dynamic items = params!.toList(); // RTCSessionDescription description = await _createOffer(); // await _pc!.setLocalDescription(description); // dynamic payload = {"target": items[0]["id"], "caller": outGoingCallData!.callerId, "sdp": description.toMap()}; // invoke(invokeMethod: "OfferAsync", currentUserID: outGoingCallData!.callerId!, targetUserID: items[0]["id"], data: jsonEncode(payload)); // } // // Future onIceCandidateAsync(List? params) async { // dynamic items = params!.toList(); // if (isIncomingCall) { // RemoteIceCandidatePayLoad data = RemoteIceCandidatePayLoad.fromJson(jsonDecode(items.first.toString())); // if (_pc != null) { // await _pc!.addCandidate(RTCIceCandidate(data.candidate!.candidate, data.candidate!.sdpMid, data.candidate!.sdpMLineIndex)); // } // } else { // if (kDebugMode) { // print("res: " + items.toString()); // } // RemoteIceCandidatePayLoad data = RemoteIceCandidatePayLoad.fromJson(jsonDecode(items.first.toString())); // if (_pc != null) { // await _pc!.addCandidate(RTCIceCandidate(data.candidate!.candidate, data.candidate!.sdpMid, data.candidate!.sdpMLineIndex)); // if (!isCallStarted) { // isCallStarted = true; // notifyListeners(); // if (isCallStarted) { // isIncomingCallLoader = false; // isOutGoingCall = true; // if (Platform.isIOS) { // Future.delayed(Duration(seconds: 2), () { // Navigator.pushReplacement( // locator().navigatorKey.currentContext!, // MaterialPageRoute( // builder: (BuildContext context) => StartCallPage(), // )); // }); // } else { // Navigator.pushReplacement( // locator().navigatorKey.currentContext!, // MaterialPageRoute( // builder: (BuildContext context) => StartCallPage(), // )); // } // } // } // } // notifyListeners(); // } // } // // Future onOfferAsync(List? params) async { // dynamic items = params!.toList(); // var data = jsonDecode(items.toString()); // if (isIncomingCall) { // _pc!.setRemoteDescription(RTCSessionDescription(data[0]["sdp"]["sdp"], data[0]["sdp"]["type"])); // RTCSessionDescription description = await _createAnswer(); // await _pc!.setLocalDescription(description); // dynamic payload = {"target": data[0]["caller"], "caller": AppState().chatDetails!.response!.id!, "sdp": description.toMap()}; // invoke(invokeMethod: "AnswerOfferAsync", currentUserID: AppState().chatDetails!.response!.id!, targetUserID: incomingCallData!.targetUserId!, data: jsonEncode(payload)); // } // // else { // // RTCSessionDescription description = await _createAnswer(); // // await _pc.setLocalDescription(description); // // var payload = {"target": items[0]["id"], "caller": outGoingCallData.callerId, "sdp": description.toMap()}; // // invoke(invokeMethod: "AnswerOffer", currentUserID: outGoingCallData.callerId!, targetUserID: items[0]["id"], data: jsonEncode(payload)); // // } // notifyListeners(); // } //////////////////////////// OutGoing Call End /////////////////////////////////////// // Future endCall({bool? isUserOnline}) async { // if (isIncomingCall) { // print("-----------------------Endeddddd By Me---------------------------"); // if (chatHubConnection!.state == HubConnectionState.Connected) { // await invoke(invokeMethod: "HangUpAsync", currentUserID: AppState().chatDetails!.response!.id!, targetUserID: incomingCallData!.targetUserId!, userStatus: 0); // await invoke(invokeMethod: "UpdateUserStatusAsync", currentUserID: AppState().chatDetails!.response!.id!, targetUserID: incomingCallData!.targetUserId!, userStatus: 1); // } // isCallStarted = false; // isVideoCall = false; // isCamOff = false; // isMicOff = false; // isLoudSpeaker = false; // isIncomingCall = false; // isOutGoingCall = false; // isAudioCall = false; // // if (isCallConnected) { // if (_pc!.connectionState == RTCPeerConnectionState.RTCPeerConnectionStateConnected) { // if (kDebugMode) { // print("------------------ PC Stopped ----------------------------"); // } // _pc!.close(); // _pc!.dispose(); // } // } // if (remoteRenderer != null) { // remoteRenderer!.dispose(); // remoteRenderer = null; // } // if (localVideoRenderer != null) { // localVideoRenderer!.dispose(); // localVideoRenderer = null; // } // // if (_localStream != null) { // _localStream!.dispose(); // _localStream = null; // } // if (chatHubConnection != null && !isUserOnline!) { // chatHubConnection!.stop(); // } // await FlutterCallkitIncoming.endAllCalls(); // return true; // } else { // if (isOutGoingCall) { // await invoke(invokeMethod: "HangUpAsync", currentUserID: outGoingCallData!.callerId!, targetUserID: outGoingCallData!.receiverId!, userStatus: 1); // await invoke(invokeMethod: "UpdateUserStatusAsync", currentUserID: outGoingCallData!.callerId!, targetUserID: outGoingCallData!.receiverId!, userStatus: 1); // } else if (isIncomingCall) { // await invoke(invokeMethod: "UpdateUserStatusAsync", currentUserID: AppState().chatDetails!.response!.id!, targetUserID: incomingCallData!.targetUserId!, userStatus: 1); // } // isCallStarted = false; // isVideoCall = false; // isCamOff = false; // isMicOff = false; // isLoudSpeaker = false; // if (isCallConnected) { // if (_pc!.connectionState == RTCPeerConnectionState.RTCPeerConnectionStateConnected) { // _pc!.close(); // _pc!.dispose(); // } // } // if (remoteRenderer != null) { // remoteRenderer!.dispose(); // remoteRenderer = null; // } // if (localVideoRenderer != null) { // localVideoRenderer!.dispose(); // localVideoRenderer = null; // } // // if (_localStream != null) { // _localStream!.dispose(); // _localStream = null; // } // isOutGoingCall = false; // isIncomingCall = false; // isAudioCall = false; // return true; // } // } // Incoming Listeners // void onAnswerOffer(List? payload) async { // // if (isIncomingCall) { // // // print("--------------------- On Answer Offer Async ---------------------------------------"); // // //await invoke(invokeMethod: "InvokeMobile", currentUserID: AppState().getchatUserDetails!.response!.id!, targetUserID: incomingCallData.targetUserId!, debugData: {"On Answer Offer Async"}); // // } else { // var items = payload!.toList(); // if (kDebugMode) { // print("res: " + items.toString()); // } // CallSessionPayLoad data = CallSessionPayLoad.fromJson(jsonDecode(items.first.toString())); // RTCSessionDescription description = RTCSessionDescription(data.sdp!.sdp, 'answer'); // _pc!.setRemoteDescription(description); // // } // } // void onHangUpAsync(List? params) { // print("--------------------- onHangUp ASYNC ---------------------------------"); // // dynamic items = params!.toList(); // // if (kDebugMode) { // // logger.i("res: " + items.toString()); // // } // if (items[0]["id"] != AppState().chatDetails!.response!.id!) { // if (kDebugMode) { // print("Call Ended By Other User"); // } // if (isIncomingCall) { // endCall(isUserOnline: isUserOnline).then((bool value) { // if (isCallConnected && isUserOnline) { // isCallConnected = false; // if (!AppState().isLogged) { // Navigator.of(locator().navigatorKey.currentContext!).pop(); // } else { // Navigator.of(locator().navigatorKey.currentContext!).popUntil(ModalRoute.withName(HOME)); // } // } else { // Navigator.of(locator().navigatorKey.currentContext!).pop(); // } // }); // } else { // if (isOutGoingCall) { // endCall(isUserOnline: isUserOnline).then((bool value) { // if (isCallConnected && isUserOnline) { // isCallConnected = false; // Navigator.of(locator().navigatorKey.currentContext!).popUntil(ModalRoute.withName(HOME)); // } else { // Navigator.of(locator().navigatorKey.currentContext!).pop(); // } // }); // } // } // } else { // if (kDebugMode) { // print("Call Ended By Me"); // } // if (isOutGoingCall) { // if (isCallConnected && isUserOnline) { // isCallConnected = false; // Navigator.of(locator().navigatorKey.currentContext!).popUntil(ModalRoute.withName(HOME)); // } else { // Navigator.of(locator().navigatorKey.currentContext!).pop(); // } // } // } // // endCall(isUserOnline: isUserOnline).then((bool value) { // // if (isCallConnected && isUserOnline) { // // Navigator.of(AppRoutes.navigatorKey.currentContext!).popUntil(ModalRoute.withName(AppRoutes.chatDetailed)); // // isCallConnected = false; // // } // // if (items[0]["id"] != AppState().chatDetails!!.response!.id && !AppState().isBackgroundCall) { // // if (kDebugMode) { // // print("Popped Due to Another User"); // // } // // if (AppState().isBackgroundCall) { // // Navigator.of(AppRoutes.navigatorKey.currentContext!).pop(); // // // Navigator.of(AppRoutes.navigatorKey.currentContext!).popUntil(ModalRoute.withName(AppRoutes.login)); // // } else { // // Navigator.of(AppRoutes.navigatorKey.currentContext!).popUntil(ModalRoute.withName(AppRoutes.chat)); // // } // // } // // if (AppState().isBackgroundCall) { // // Navigator.of(AppRoutes.navigatorKey.currentContext!).pop(); // // } // // // notifyListeners(); // isCallEnded = true; // // }); // } // Future OnIncomingCallAsync(List? params) async { // 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); // // ChatVoipCall().showCallkitIncoming(uuid: const Uuid().v4(), isOnline: true, incomingCallData: 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) { print("================= On Declained ========================"); print(params); // endCall().then((bool value) { // if (value) { // isCallEnded = true; // notifyListeners(); // } // }); // if (params != null) { // endCall(isUserOnline: isUserOnline).then((bool value) { // if (isCallConnected) { // // Navigator.of(AppRoutes.navigatorKey.currentContext!).pop(); // isCallConnected = false; // } // isCallEnded = true; // }); // } } //// Invoke Methods // Future invoke({required String invokeMethod, required int currentUserID, required int targetUserID, var data, int userStatus = 1, var debugData}) async { // List args = []; // if (invokeMethod == "CallUserAsync") { // args = [currentUserID, targetUserID, isVideoCall]; // } else if (invokeMethod == "answerCallAsync") { // args = [currentUserID, targetUserID]; // } else if (invokeMethod == "IceCandidateAsync") { // args = [targetUserID, data]; // } else if (invokeMethod == "OfferAsync") { // args = [targetUserID, data]; // } else if (invokeMethod == "AnswerOfferAsync") { // args = [targetUserID, data]; // // json In Data // } else if (invokeMethod == "UpdateUserStatusAsync") { // args = [currentUserID, userStatus]; // } else if (invokeMethod == "HangUpAsync") { // args = [currentUserID, targetUserID]; // } else if (invokeMethod == "InvokeMobile") { // args = [debugData]; // } // try { // await chatHubConnection!.invoke("$invokeMethod", args: args); // } catch (e) { // print(e); // } // } void stopListeners() async { chatHubConnection!.off('OnCallDeclinedAsync'); chatHubConnection!.off('OnCallAcceptedAsync'); chatHubConnection!.off('OnIceCandidateAsync'); chatHubConnection!.off('OnAnswerOffer'); } void playRingtone() async { player.stop(); await player.setVolume(1.0); String audioAsset = ""; if (Platform.isAndroid) { audioAsset = "assets/audio/ring_60Sec.mp3"; } else { audioAsset = "assets/audio/ring_30Sec.caf"; } try { await player.setAsset(audioAsset); await player.load(); player.play(); } catch (e) { print("Error: $e"); } } //////////////////// Web RTC Offers & Connections //////////////////////// // Future creatOfferWithCon() async { // Map configuration = { // "sdpSemantics": "plan-b", // 'iceServers': [ // { // 'urls': 'stun:15.185.116.59:3478', // }, // { // 'urls': 'turn:15.185.116.59:3479', // 'username': 'admin', // 'credential': 'admin', // }, // ] // }; // Map offerSdpConstraints = { // 'mandatory': { // 'OfferToReceiveAudio': true, // 'OfferToReceiveVideo': true, // }, // 'optional': [] // }; // RTCPeerConnection pc = await createPeerConnection(configuration, offerSdpConstraints); // // await pc.addStream(_localStream!); // //Changed By Aamir // _localStream?.getTracks().forEach((track) { // pc.addTrack(track, _localStream!); // }); // pc.onConnectionState = (RTCPeerConnectionState state) {}; // pc.onAddStream = (MediaStream stream) { // remoteRenderer!.srcObject = stream; // notifyListeners(); // }; // pc.onIceCandidate = (RTCIceCandidate e) async { // if (isIncomingCall) { // if (e.candidate != null) { // var payload = {"target": incomingCallData!.targetUserId, "candidate": e.toMap()}; // invoke(invokeMethod: "IceCandidateAsync", currentUserID: AppState().chatDetails!.response!.id!, targetUserID: incomingCallData!.targetUserId!, data: jsonEncode(payload)); // notifyListeners(); // } // } else { // if (e.candidate != null) { // var payload = {"target": outGoingCallData!.callerId, "candidate": e.toMap()}; // invoke(invokeMethod: "IceCandidateAsync", currentUserID: outGoingCallData!.callerId!, targetUserID: outGoingCallData!.receiverId!, data: jsonEncode(payload)); // } // } // }; // // pc!.onTrack = (RTCTrackEvent event) async { // // // // String streamId = const Uuid().toString(); // // MediaStream remoteStream = await createLocalMediaStream(streamId); // // event.streams[0].getTracks().forEach((MediaStreamTrack element) { // // logger.i("Stream Track: " + element.id.toString()); // // // remoteRenderer.srcObject = element; // // remoteStream.addTrack(element); // // }); // // }; // pc.onSignalingState = (RTCSignalingState state) { // print("signaling state: " + state.name); // // invoke( // // invokeMethod: "InvokeMobile", // // currentUserID: AppState().getchatUserDetails!.response!.id!, // // targetUserID: incomingCallData.targetUserId!, // // debugData: {"location": "Signaling", "parms": state.name}); // }; // pc.onIceGatheringState = (RTCIceGatheringState state) { // print("rtc ice gathering state: " + state.name); // }; // pc.onIceConnectionState = (RTCIceConnectionState state) { // if (RTCIceConnectionState.RTCIceConnectionStateFailed == state || // RTCIceConnectionState.RTCIceConnectionStateDisconnected == state || // RTCIceConnectionState.RTCIceConnectionStateClosed == state) { // print("Ice Connection State:" + state.name); // // // endCall().then((value) { // // notifyListeners(); // // }); // } // }; // // pc!.onRenegotiationNeeded = _onRenegotiate; // return pc; // } // void _onRenegotiate() async { // try { // print('onRenegotiationNeeded start'); // // makingOffer = true; // await _pc.setLocalDescription(await _pc.createOffer(videoConstraints)); // print('onRenegotiationNeeded state after setLocalDescription: ' + _pc.signalingState.toString()); // // send offer via callManager // var localDesc = await _pc.getLocalDescription(); // // callManager.sendCallMessage(MsgType.rtc_offer, RtcOfferAnswer(localDesc.sdp, localDesc.type)); // print('onRenegotiationNeeded; offer sent'); // } catch (e) { // print("onRenegotiationNeeded error: " + e.toString()); // } finally { // // makingOffer = false; // print('onRenegotiationNeeded done'); // } // } // Future _createOffer() async { // RTCSessionDescription description = await _pc!.createOffer(); // // _offer = true; // return description; // } // // Future _createAnswer() async { // RTCSessionDescription description = await _pc!.createAnswer(); // // _offer = false; // return description; // } //////////////////// Web RTC End Offers //////////////////// //////////////////// CallPage Buttons ////////////////////// void micOff() { isMicOff = !isMicOff; _localStream!.getAudioTracks().forEach((track) { track.enabled = !track.enabled; }); notifyListeners(); } void camOff() { isCamOff = !isCamOff; _localStream!.getVideoTracks().forEach((track) { track.enabled = !track.enabled; }); // if (isCamOff) { // isVideoCall = false; // } else { // isVideoCall = true; // } notifyListeners(); } void loudOn() { isLoudSpeaker = !isLoudSpeaker; remoteRenderer!.srcObject?.getAudioTracks().forEach((track) { if (isLoudSpeaker) { track.enableSpeakerphone(true); } else { track.enableSpeakerphone(false); } }); notifyListeners(); } void switchCamera() { isFrontCamera = !isFrontCamera; Helper.switchCamera(_localStream!.getVideoTracks()[0]); notifyListeners(); } ///////////////// Incoming Call /////////////////////////////// Future initStreams() async { List devices = await navigator.mediaDevices.enumerateDevices(); remoteRenderer = RTCVideoRenderer(); localVideoRenderer ??= RTCVideoRenderer(); await localVideoRenderer!.initialize(); try { _localStream = await navigator.mediaDevices.getUserMedia({ 'audio': true, 'video': { 'mandatory': { 'minWidth': '640', // Provide your own width, height and frame rate here 'minHeight': '480', 'minFrameRate': '25', }, 'facingMode': 'user', 'optional': [], "audio": true, } }); _localStream!.getAudioTracks().first.enableSpeakerphone(true); localVideoRenderer!.srcObject = _localStream; localVideoRenderer!.value = (const RTCVideoValue( width: 200, height: 200, renderVideo: true, )); print("Working localStream"); } catch (e) { print("Failed to get user media: $e"); } await remoteRenderer!.initialize(); notifyListeners(); } // Future startIncomingCallViaKit({bool isVCall = true, var inCallData}) async { // AppSharedPrefs().setStringFromPrefs("isIncomingCall", "false"); // if (isVCall) { // isVideoCall = isVCall; // } else { // isAudioCall = true; // } // await initStreams(); // isIncomingCall = true; // incomingCallData = SingleUserChatModel.fromJson(inCallData); // loudOn(); // // notifyListeners(); // } // void connectIncomingCall() { // invoke(invokeMethod: "answerCallAsync", currentUserID: AppState().getchatUserDetails.response!.id!, targetUserID: incomingCallData!.targetUserId!); // isIncomingCallLoader = false; // isIncomingCall = true; // // isVideoCall = true; // // notifyListeners(); // } // void startRecording() async { // print("=-=-=-=-=-=-= Call Recoding Started -=-=-=-=-=-=-=-=-==-="); // if (_localStream == null) throw Exception('Stream is not initialized'); // if (Platform.isIOS) { // print('Recording is not available on iOS'); // return; // } // Directory appDirectory = await getApplicationDocumentsDirectory(); // String dirPath = '${appDirectory.path}/webrtc_sample'; // if (!await Directory(dirPath).exists()) { // await Directory(dirPath).create(); // await File('$dirPath/.nomedia').create(); // } // if (appDirectory == null) throw Exception('Can\'t find storagePath'); // String filePath = dirPath + '/mobile.mp4'; // mobileRecoder = MediaRecorder(); // notifyListeners(); // MediaStreamTrack videoTrack = _localStream!.getVideoTracks().firstWhere((track) => track.kind == 'video'); // await mobileRecoder!.start(filePath, videoTrack: videoTrack); // // Future.delayed(Duration(minutes: 1), () { // stopRecording(); // }); // } // // void stopRecording() async { // print("=-=-=-=-=-=-= Call Recoding Stopped -=-=-=-=-=-=-=-=-==-="); // await mobileRecoder!.stop(); // mobileRecoder = null; // notifyListeners(); // } // WebRtc final transportProtLogger = Logger("SignalR - transport"); late Logger _logger; RTCPeerConnection? pCon; String? _doctorID; String? _patientID; String? get doctorID => _doctorID; set doctorID(String? value) { _doctorID = value; } String? get patientID => _patientID; set patientID(String? value) { _patientID = value; } bool _isAccepted = false; bool get isAccepted => _isAccepted; set isAccepted(bool value) { _isAccepted = value; } // int _secondsRemaining = 30; // late Timer _timer; // void startCountTimer() { // _timer = Timer.periodic(Duration(seconds: 1), (timer) async { // if (_secondsRemaining > 0) { // _secondsRemaining--; // if (isAccepted) { // _timer.cancel(); // Stop the timer if isAccepted becomes true // } // } else { // _timer.cancel(); // if (chatHubConnection != null) { // chatHubConnection!.stop(); // chatHubConnection = null; // } // chatHubConnection = await createHub(); // NoAnswer(); // } // }); // // notifyListeners(); // } NoAnswer() { handleCallComplete([{}]); } void httpCallback(Client httpClient) { HttpOverrides.global = HttpOverrideCertificateVerificationInDev(); } Future createHub() async { doctorID = incomingCallData!.sessionId!.split("**").last; String path = incomingCallData!.sessionId!.split("**").first; patientID = incomingCallData!.receiverID; _logger = Logger("ChatPageViewModel"); final httpConnectionOptions = HttpConnectionOptions(logMessageContent: true, httpClient: WebSupportingHttpClient(_logger, httpClientCreateCallback: httpCallback)); var urlWithParams = path + "UserID=$patientID&ProjectId=15&IsAdmin=false&To=$doctorID"; HubConnection hubCon = await HubConnectionBuilder().withUrl(urlWithParams, options: httpConnectionOptions).withAutomaticReconnect(retryDelays: [2000, 5000, 10000, 20000]).configureLogging(_logger).build(); return hubCon; } Future initCall({required bool isConnectCall}) async { if (chatHubConnection != null) { chatHubConnection!.stop(); chatHubConnection = null; } chatHubConnection = await createHub(); if (doctorID != null) { try { chatHubConnection!.onclose(({error}) { Utils.showErrorToast(error.toString()); }); register(); if (chatHubConnection!.state == HubConnectionState.Disconnected) { await chatHubConnection!.start(); } if (chatHubConnection!.state == HubConnectionState.Connected) { if (chatHubConnection != null) { patientID = chatHubConnection!.connectionId; print("DOC: " + doctorID.toString()); print("PAT " + patientID.toString()); try { isConnectCall ? ping("Call_Accept") : ping("Call_Decline"); } catch (e) { print(e); } } } } catch (e) { print(e.toString()); Utils.showErrorToast(e.toString()); } } else { Utils.showErrorToast("Doctor ID is not correct"); } } ping(String eventName) async { print("============ $eventName ====================="); if (chatHubConnection != null) if (chatHubConnection!.state == HubConnectionState.Connected) { print("============ CONNECTED =============="); dynamic payload = {"UserID": int.parse(incomingCallData!.receiverID!)}; if (eventName == "Call_Complete") payload = {"from": patientID, "to": doctorID}; await chatHubConnection!.invoke(eventName, args: [payload]).onError((error, stackTrace) {}).whenComplete(() { if (eventName == "Call_Decline" || eventName == "Call_Complete" || eventName == "Call_NoAnswer") { if (chatHubConnection != null) { chatHubConnection!.stop(); } } }); } else { print("============ ELSE RECONNECT =============="); chatHubConnection = await createHub(); chatHubConnection!.start(); ping(eventName); } } void register() async { chatHubConnection!.on("pre_offer", handlePreOffer); chatHubConnection!.on("on_offer", handleOnOffer); chatHubConnection!.on("on_ice_candidate", handleIceCandidate); // New Events chatHubConnection!.on("Call_Decline", handleCallDecline); chatHubConnection!.on("call_completed", handleCallComplete); if (kDebugMode) debugPrint("Listners Initiated"); } // genericCheckEvent(List? params) async { // print("------------- Generic Event Triggered ---------------"); // print("------------- Generic Event Triggered ---------------"); // print(params); // print("------------- Generic Event Triggered ---------------"); // print("------------- Generic Event Triggered ---------------"); // } handlePreOffer(List? params) async { print("----------Event Pre Offer Received ----------"); dynamic items = params!.toList(); if (kDebugMode) { print("Doctor ID : " + items[0]['from'].toString()); print("Patient ID: " + items[0]['to'].toString()); } doctorID = items[0]['from']; patientID = items[0]['to']; initStreams(); createPConnection(); sendPreAnswerOffer(); } handleOnOffer(List? params) async { print("----------Event On Offer Received ----------"); dynamic items = params!.toList(); var data = jsonDecode(items[0]["offer"]); _localStream?.getTracks().forEach((track) { pCon!.addTrack(track, _localStream!); }); await pCon!.setRemoteDescription(RTCSessionDescription(data["sdp"], data["type"])); RTCSessionDescription description = await pCon!.createAnswer(); await pCon!.setLocalDescription(description); var payload = { "to": doctorID, "callerSocketId": patientID, "answer": "${json.encode(description.toMap())}", }; if (chatHubConnection!.state == HubConnectionState.Connected) { print("---------Answer Offer Invoke --------"); await chatHubConnection!.invoke("OnAnswerOffer", args: [payload]).onError((error, stackTrace) { print("error sending offer answer"); Utils.showErrorToast(error.toString()); }); } startCallByRTC(); Future.delayed(Duration(seconds: 2), () { Navigator.pushReplacement( locator().navigatorKey.currentContext!, MaterialPageRoute( builder: (BuildContext context) => StartCallPage(), )); }); } handleIceCandidate(List? params) async { print("----------Event Ice Candidate Received ----------"); dynamic items = params!.toList(); var val = jsonDecode(items[0]["candidate"]); RemoteIceCandidatePayLoad data = await RemoteIceCandidatePayLoad( target: 00000, candidate: Candidate(candidate: val["candidate"], sdpMid: val["sdpMid"], sdpMLineIndex: val["sdpMLineIndex"], usernameFragment: val["usernameFragment"])); if (pCon != null) { pCon!.addCandidate(RTCIceCandidate(data.candidate!.candidate, data.candidate!.sdpMid, data.candidate!.sdpMLineIndex)); } } handleCallDecline(List? params) { print("----------handle Call Decline Received ----------"); dynamic items = params!.toList(); debuglogger.d(items); } handleCallComplete(List? params) { print("----------handle Call Complete Received ----------"); dynamic items = params!.toList(); debuglogger.d(items); if (isCallConnected) ping("Call_Complete"); if (!isCallConnected && !isAccepted) { ping("Call_NoAnswer"); } else { if (!isCallConnected) ping("Call_Decline"); } isCallConnected = false; isCallStarted = false; isVideoCall = false; isCamOff = false; isMicOff = false; isLoudSpeaker = false; isIncomingCall = false; isOutGoingCall = false; isAudioCall = false; isAccepted = false; if (pCon != null) if (pCon!.connectionState == RTCPeerConnectionState.RTCPeerConnectionStateConnected) { if (_localStream != null) pCon!.removeStream(_localStream!); pCon!.close(); pCon!.dispose(); } if (remoteRenderer != null) { remoteRenderer!.dispose(); remoteRenderer = null; } if (localVideoRenderer != null) { localVideoRenderer!.dispose(); localVideoRenderer = null; } if (_localStream != null) { _localStream!.dispose(); _localStream = null; } // if (chatHubConnection != null && !isUserOnline) { // chatHubConnection!.stop(); // } Navigator.of(locator().navigatorKey.currentContext!).popAndPushNamed(HOME); } void createPConnection() async { Map configuration = { "sdpSemantics": "plan-b", 'iceServers': [ { 'urls': 'stun:15.185.116.59:3478', }, { 'urls': 'turn:15.185.116.59:3479', 'username': 'admin', 'credential': 'admin', } ], "iceCandidatePoolSize": 10 }; Map offerSdpConstraints = { 'mandatory': { 'OfferToReceiveAudio': true, 'OfferToReceiveVideo': true, }, 'optional': [] }; pCon = await createPeerConnection(configuration, offerSdpConstraints); pCon!.onConnectionState = (RTCPeerConnectionState state) {}; pCon!.onAddStream = (MediaStream stream) { remoteRenderer!.srcObject = stream; notifyListeners(); }; pCon!.onIceCandidate = (RTCIceCandidate e) async { if (e.candidate != null) { await pCon!.addCandidate(e); var data = {"target": doctorID, "callerSocketId": doctorID, "from": patientID, "calleePersonalCode": patientID, "to": doctorID, "candidate": "${json.encode(e.toMap())}"}; if (chatHubConnection!.state == HubConnectionState.Connected) { await chatHubConnection!.invoke('IceCandidate', args: [data]).onError((error, stackTrace) { Utils.showErrorToast(error.toString()); }); } } }; pCon!.onSignalingState = (RTCSignalingState state) { print("signaling state: " + state.name); }; pCon!.onIceGatheringState = (RTCIceGatheringState state) { print("rtc ice gathering state: " + state.name); }; pCon!.onIceConnectionState = (RTCIceConnectionState state) { if (RTCIceConnectionState.RTCIceConnectionStateFailed == state || RTCIceConnectionState.RTCIceConnectionStateDisconnected == state || RTCIceConnectionState.RTCIceConnectionStateClosed == state) { print("Ice Connection State:" + state.name); } }; } sendPreAnswerOffer() async { var data = { "to": doctorID, "calleePersonalCode": patientID, "preOfferAnswer": "", }; print(data); if (chatHubConnection!.state == HubConnectionState.Connected) { await chatHubConnection!.invoke("SendPreOfferAnswer", args: [data]).onError((error, stackTrace) { print("error sending pre offer answer"); Utils.showErrorToast(error.toString()); }); } } startCallByRTC() { isVideoCall = true; isIncomingCallLoader = false; isIncomingCall = true; isCallConnected = true; } } class HttpOverrideCertificateVerificationInDev extends HttpOverrides { @override HttpClient createHttpClient(SecurityContext? context) { return super.createHttpClient(context)..badCertificateCallback = (X509Certificate cert, String host, int port) => true; } } // class ChatService extends BaseService { // Future getUserCallToken({required String userid}) async { // getUserToken.UserAutoLoginModel userLoginResponse = getUserToken.UserAutoLoginModel(); // http.post(Uri.parse("${ApiConsts.chatLoginTokenUrl}externaluserlogin"), body: { // "employeeNumber": userid, // "password": "FxIu26rWIKoF8n6mpbOmAjDLphzFGmpG", // }).then((response) { // userLoginResponse = getUserToken.userAutoLoginModelFromJson(response.body); // }).onError((error, stackTrace) { // hasError = true; // print(error); // super.error = error.toString(); // }); // // return userLoginResponse; // } // }