import ' dart:async ' ;
import ' dart:convert ' ;
import ' dart:io ' ;
import ' package:diplomaticquarterapp/app_state/app_state.dart ' ;
import ' package:diplomaticquarterapp/core/service/base_service.dart ' ;
import ' package:diplomaticquarterapp/locator.dart ' ;
import ' package:diplomaticquarterapp/routes.dart ' ;
import ' package:diplomaticquarterapp/uitl/navigation_service.dart ' ;
import ' package:diplomaticquarterapp/voipcall/call/chat_incoming_call_screen.dart ' ;
import ' package:diplomaticquarterapp/voipcall/consts.dart ' ;
import ' package:diplomaticquarterapp/voipcall/model/call.dart ' ;
import ' package:diplomaticquarterapp/voipcall/model/get_single_user_chat_call.dart ' ;
import ' package:diplomaticquarterapp/voipcall/model/get_user_login_token.dart ' as getUserToken ;
import ' package:diplomaticquarterapp/voipcall/model/webrtc_payloads.dart ' ;
import ' package:flutter/foundation.dart ' ;
import ' package:flutter/material.dart ' ;
import ' package:flutter_callkit_incoming/flutter_callkit_incoming.dart ' ;
import ' package:flutter_webrtc/flutter_webrtc.dart ' ;
import ' package:http/http.dart ' as http ;
import ' package:http/http.dart ' ;
import ' package:just_audio/just_audio.dart ' ;
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 < MediaDeviceInfo > devices = [ ] ;
//
// // 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<LogRecord> _logMessagesSub;
//
// void _handleLogMessage(LogRecord msg) {
// print(msg.message);
// }
//
// Future<void> 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: <int>[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 < HubConnection > 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: <int>[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: < int > [ 2000 , 5000 , 10000 , 20000 ] ) . build ( ) ;
return hub ;
}
Future < CallDataModel > makeCall ( { required String callType } ) async {
Map < String , dynamic > 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 < String , Object > audioConstraints = {
" sampleRate " : 8000 ,
" sampleSize " : 16 ,
" channelCount " : 2 ,
" echoCancellation " : true ,
" audio " : true ,
} ;
Future < void > init ( ) async {
_pc = await creatOfferWithCon ( ) ;
Future . delayed ( const Duration ( seconds: 2 ) , ( ) {
connectIncomingCall ( ) ;
} ) ;
}
///////////////////////////////////////////////OutGoing Call////////////////////////////////////////////////////
Future < void > 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 < void > 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 < Object ? > ? 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 < void > onIceCandidateAsync ( List < Object ? > ? 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 < NavigationService > ( ) . navigatorKey . currentContext ! ,
MaterialPageRoute (
builder: ( BuildContext context ) = > StartCallPage ( ) ,
) ) ;
} ) ;
} else {
Navigator . pushReplacement (
locator < NavigationService > ( ) . navigatorKey . currentContext ! ,
MaterialPageRoute (
builder: ( BuildContext context ) = > StartCallPage ( ) ,
) ) ;
}
}
}
}
notifyListeners ( ) ;
}
}
Future < void > onOfferAsync ( List < Object ? > ? 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 < bool > 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 < Object ? > ? 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 < Object ? > ? 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 < NavigationService > ( ) . navigatorKey . currentContext ! ) . pop ( ) ;
} else {
Navigator . of ( locator < NavigationService > ( ) . navigatorKey . currentContext ! ) . popUntil ( ModalRoute . withName ( HOME ) ) ;
}
} else {
Navigator . of ( locator < NavigationService > ( ) . navigatorKey . currentContext ! ) . pop ( ) ;
}
} ) ;
} else {
if ( isOutGoingCall ) {
endCall ( isUserOnline: isUserOnline ) . then ( ( bool value ) {
if ( isCallConnected & & isUserOnline ) {
isCallConnected = false ;
Navigator . of ( locator < NavigationService > ( ) . navigatorKey . currentContext ! ) . popUntil ( ModalRoute . withName ( HOME ) ) ;
} else {
Navigator . of ( locator < NavigationService > ( ) . navigatorKey . currentContext ! ) . pop ( ) ;
}
} ) ;
}
}
} else {
if ( kDebugMode ) {
print ( " Call Ended By Me " ) ;
}
if ( isOutGoingCall ) {
if ( isCallConnected & & isUserOnline ) {
isCallConnected = false ;
Navigator . of ( locator < NavigationService > ( ) . navigatorKey . currentContext ! ) . popUntil ( ModalRoute . withName ( HOME ) ) ;
} else {
Navigator . of ( locator < NavigationService > ( ) . 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<void> OnIncomingCallAsync(List<Object?>? params) async {
// print("--------------------- On Incoming Call ---------------------------------------");
// dynamic items = params!.toList();
// logger.d(items);
// // Map<String, dynamic> 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<String, dynamic> 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 < Object > 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 < void > invoke ( { required String invokeMethod , required int currentUserID , required int targetUserID , var data , int userStatus = 1 , var debugData } ) async {
List < Object > 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 < RTCPeerConnection > creatOfferWithCon ( ) async {
Map < String , dynamic > configuration = {
" sdpSemantics " : " plan-b " ,
' iceServers ' : [
{
' urls ' : ' stun:15.185.116.59:3478 ' ,
} ,
{
' urls ' : ' turn:15.185.116.59:3479 ' ,
' username ' : ' admin ' ,
' credential ' : ' admin ' ,
} ,
]
} ;
Map < String , dynamic > 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 < RTCSessionDescription > _createOffer ( ) async {
RTCSessionDescription description = await _pc ! . createOffer ( ) ;
// _offer = true;
return description ;
}
Future < RTCSessionDescription > _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 < void > initStreams ( ) async {
List < MediaDeviceInfo > devices = await navigator . mediaDevices . enumerateDevices ( ) ;
remoteRenderer = RTCVideoRenderer ( ) ;
localVideoRenderer ? ? = RTCVideoRenderer ( ) ;
await localVideoRenderer ! . initialize ( ) ;
try {
_localStream = await navigator . mediaDevices . getUserMedia ( {
' audio ' : true ,
' video ' :
//isVideoCall?
{
' mandatory ' : {
' minWidth ' : ' 640 ' , // Provide your own width, height and frame rate here
' minHeight ' : ' 480 ' ,
' minFrameRate ' : ' 30 ' ,
} ,
' facingMode ' : ' user ' ,
' optional ' : [ ] ,
" audio " : true ,
}
// : false
} ) ;
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 " ) ;
}
// localVideoRenderer.srcObject = _localStream;
await remoteRenderer ! . initialize ( ) ;
notifyListeners ( ) ;
}
Future < void > 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
// 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 < LogRecord > _logMessagesSub ;
void _handleLogMessage ( LogRecord msg ) {
print ( msg . message ) ;
}
void _httpClientCreateCallback ( Client httpClient ) {
HttpOverrides . global = HttpOverrideCertificateVerificationInDev ( ) ;
}
// Future<void> buildHubConnection() async {
// try {
// 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());
// }
// }
handleRecivedOffer ( List < Object ? > ? val ) {
print ( " ----------Event Received ---------- " ) ;
print ( val ) ;
}
Future < void > openChatConnection ( ) async {
_logger = Logger ( " Demo " ) ;
final logger = _logger ;
if ( chatHubConnection = = null ) {
final httpConnectionOptions = HttpConnectionOptions ( httpClient: WebSupportingHttpClient ( logger , httpClientCreateCallback: _httpClientCreateCallback ) , logger: logger , logMessageContent: true ) ;
Logger . root . level = Level . ALL ;
_logMessagesSub = Logger . root . onRecord . listen ( _handleLogMessage ) ;
String to = " aXvFIMTEFRAKLJv5flIEWw " ;
var urlWithParams = " https://ms.hmg.com/livecare/liveCareHub?UserID=4767770&ProjectId=15&IsAdmin=false&To= $ to " ;
print ( " ChatHubURL:::: " + urlWithParams ) ;
chatHubConnection =
await HubConnectionBuilder ( ) . withUrl ( urlWithParams , options: httpConnectionOptions ) . withAutomaticReconnect ( retryDelays: [ 2000 , 5000 , 10000 , 20000 ] ) . configureLogging ( logger ) . build ( ) ;
}
print ( " ------------ Connection State -------------- " + chatHubConnection ! . state . toString ( ) ) ;
if ( chatHubConnection ! . state ! = HubConnectionState . Connected ) {
try {
await chatHubConnection ! . start ( ) ;
print ( " ------------ Connection State -------------- " + chatHubConnection ! . state . toString ( ) ) ;
print ( " Connection Stablished -------------- " ) ;
} catch ( e ) {
print ( e ) ;
}
}
print ( " ------------ Before Events Register -------------- " ) ;
chatHubConnection ! . on ( " pre-offer " , handleRecivedOffer ) ;
chatHubConnection ! . on ( " OnOffer " , handleRecivedOffer ) ;
chatHubConnection ! . on ( " IceCandidate " , handleRecivedOffer ) ;
print ( " ------------ After Events Register -------------- " ) ;
}
}
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 < getUserToken . UserAutoLoginModel > 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 ;
}
}