You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
278 lines
9.0 KiB
Dart
278 lines
9.0 KiB
Dart
import 'dart:convert';
|
|
|
|
import 'package:diplomaticquarterapp/uitl/SignalRUtil.dart';
|
|
import 'package:flutter/cupertino.dart';
|
|
import 'package:flutter_webrtc/flutter_webrtc.dart';
|
|
|
|
typedef void StreamStateCallback(MediaStream stream);
|
|
typedef void RTCIceGatheringStateCallback(RTCIceGatheringState state);
|
|
typedef void RTCPeerConnectionStateCallback(RTCPeerConnectionState state);
|
|
typedef void RTCSignalingStateCallback(RTCSignalingState state);
|
|
|
|
final Map<String, dynamic> constraints = {
|
|
'mandatory': {},
|
|
'optional': [
|
|
{'DtlsSrtpKeyAgreement': true},
|
|
]
|
|
};
|
|
|
|
Map<String, dynamic> snapsis_ice_config = {
|
|
'iceServers': [
|
|
{ "urls": 'stun:15.185.116.59:3478' },
|
|
{ "urls": "turn:15.185.116.59:3479", "username": "admin", "credential": "admin" },
|
|
],
|
|
// 'sdpSemantics': 'unified-plan'
|
|
};
|
|
Map<String, dynamic> twilio_ice_config = {
|
|
"ice_servers": [
|
|
{
|
|
"url": "stun:global.stun.twilio.com:3478?transport=udp",
|
|
"urls": "stun:global.stun.twilio.com:3478?transport=udp"
|
|
},
|
|
{
|
|
"url": "turn:global.turn.twilio.com:3478?transport=udp",
|
|
"username": "ce8042842b62c21bd20b176f80d6067fd3db81b1e9766312418ef5421d9ca2a2",
|
|
"urls": "turn:global.turn.twilio.com:3478?transport=udp",
|
|
"credential": "UzGOsiLwPZJ32cjafAebfDDpVrqeQjgpFHZEdau/8r4="
|
|
},
|
|
{
|
|
"url": "turn:global.turn.twilio.com:3478?transport=tcp",
|
|
"username": "ce8042842b62c21bd20b176f80d6067fd3db81b1e9766312418ef5421d9ca2a2",
|
|
"urls": "turn:global.turn.twilio.com:3478?transport=tcp",
|
|
"credential": "UzGOsiLwPZJ32cjafAebfDDpVrqeQjgpFHZEdau/8r4="
|
|
},
|
|
{
|
|
"url": "turn:global.turn.twilio.com:443?transport=tcp",
|
|
"username": "ce8042842b62c21bd20b176f80d6067fd3db81b1e9766312418ef5421d9ca2a2",
|
|
"urls": "turn:global.turn.twilio.com:443?transport=tcp",
|
|
"credential": "UzGOsiLwPZJ32cjafAebfDDpVrqeQjgpFHZEdau/8r4="
|
|
}
|
|
],
|
|
// 'sdpSemantics': 'unified-plan'
|
|
};
|
|
Map<String, dynamic> google_ice_config = {
|
|
'iceServers': [
|
|
{
|
|
'urls': [
|
|
'stun:stun.l.google.com:19302',
|
|
'stun:stun1.l.google.com:19302',
|
|
'stun:stun2.l.google.com:19302',
|
|
'stun:stun3.l.google.com:19302'
|
|
]
|
|
},
|
|
],
|
|
// 'sdpSemantics': 'unified-plan'
|
|
};
|
|
Map<String, dynamic> aws_ice_config = {
|
|
'iceServers': [
|
|
{'url': "stun:ec2-15-185-116-59.me-south-1.compute.amazonaws.com:3478"},
|
|
{'url': "turn:ec2-15-185-116-59.me-south-1.compute.amazonaws.com:3479", 'credential': "admin", 'username': "admin"}
|
|
],
|
|
// 'sdpSemantics': 'unified-plan'
|
|
};
|
|
|
|
class Signaling {
|
|
dispose() {
|
|
if (peerConnection != null) {
|
|
peerConnection.dispose();
|
|
peerConnection.getLocalStreams().forEach((e) => e.dispose());
|
|
peerConnection.getRemoteStreams().forEach((e) => e.dispose());
|
|
}
|
|
signalR.closeConnection();
|
|
}
|
|
|
|
init() async{
|
|
// Create Peer Connection
|
|
peerConnection = await createPeerConnection(google_ice_config, constraints);
|
|
registerPeerConnectionListeners();
|
|
}
|
|
|
|
initializeSignalR(String userName) async {
|
|
if (signalR != null) await signalR.closeConnection();
|
|
// https://vcallapi.hmg.com/webRTCHub?source=web&username=zohaib
|
|
// signalR = SignalRUtil(hubName: "https://vcallapi.hmg.com/webRTCHub?source=mobile&username=$userName");
|
|
signalR = SignalRUtil(hubName: "http://35.193.237.29/webRTCHub?source=mobile&username=$userName");
|
|
final connected = await signalR.openConnection();
|
|
if (!connected) throw 'Failed to connect SignalR';
|
|
}
|
|
|
|
Map<String, dynamic> configuration = {
|
|
// 'iceServers': [
|
|
// {
|
|
// 'urls': ['stun:stun1.l.google.com:19302', 'stun:stun2.l.google.com:19302']
|
|
// }
|
|
// ]
|
|
|
|
'iceServers': [
|
|
// {'url': "stun:ec2-15-185-116-59.me-south-1.compute.amazonaws.com:3478"},
|
|
// {'url': "turn:ec2-15-185-116-59.me-south-1.compute.amazonaws.com:3479", 'credential': "admin", 'username': "admin"}
|
|
// {'url': "stun:15.185.116.59:3478"},
|
|
// {
|
|
// "url":"turn:15.185.116.59:3479",
|
|
// "username": "admin",
|
|
// "credential":"admin"
|
|
// }
|
|
{
|
|
"url": "stun:global.stun.twilio.com:3478?transport=udp",
|
|
"urls": "stun:global.stun.twilio.com:3478?transport=udp"
|
|
},
|
|
{
|
|
"url": "turn:global.turn.twilio.com:3478?transport=udp",
|
|
"username": "f18fc347ba4aeeaa1b00f5199b1e900834b464962d434a4a89b4cdba02510047",
|
|
"urls": "turn:global.turn.twilio.com:3478?transport=udp",
|
|
"credential": "WX16BB+9nKm0f+Whf5EwpM8S/Yv+T2tlvQWLfdV7oqo="
|
|
}
|
|
]
|
|
};
|
|
|
|
SignalRUtil signalR;
|
|
|
|
RTCPeerConnection peerConnection;
|
|
MediaStream localStream;
|
|
MediaStream remoteStream;
|
|
RTCDataChannel dataChannel;
|
|
|
|
// Future<bool> call(String patientId, String mobile, {@required RTCVideoRenderer localVideo, @required RTCVideoRenderer remoteVideo}) async {
|
|
// await initializeSignalR(patientId);
|
|
//
|
|
// // final isCallPlaced = await FCM.sendCallNotifcationTo(DOCTOR_TOKEN, patientId, mobile);
|
|
// if(!isCallPlaced)
|
|
// throw 'Failed to notify target for call';
|
|
//
|
|
// return isCallPlaced;
|
|
// }
|
|
|
|
Future<bool> acceptCall(String caller, String receiver, {@required MediaStream localMediaStream, @required Function(MediaStream) onRemoteMediaStream, @required Function(RTCTrackEvent) onRemoteTrack}) async {
|
|
await initializeSignalR(receiver);
|
|
signalR.setContributors(caller: caller, receiver: receiver);
|
|
await signalR.acceptCall(receiver, caller).catchError((e) => throw 'Failed to inform signalR that i accepted a call');
|
|
|
|
peerConnection.addStream(localMediaStream);
|
|
|
|
// peerConnection?.onTrack = (track){
|
|
// onRemoteTrack(track);
|
|
// };
|
|
peerConnection?.onAddStream = (MediaStream stream) {
|
|
remoteStream = stream;
|
|
onRemoteMediaStream?.call(stream);
|
|
};
|
|
return true;
|
|
}
|
|
|
|
|
|
Future<bool> declineCall(String caller, String receiver) async {
|
|
await initializeSignalR(receiver);
|
|
signalR.setContributors(caller: caller, receiver: receiver);
|
|
await signalR.declineCall(receiver, caller).catchError((e) => throw 'Failed to inform signalR that i accepted a call');
|
|
|
|
// peerConnection.addStream(localMediaStream);
|
|
//
|
|
// peerConnection?.onAddStream = (MediaStream stream) {
|
|
// remoteStream = stream;
|
|
// onRemoteMediaStream?.call(stream);
|
|
// };
|
|
return true;
|
|
}
|
|
|
|
Future hangupCall(String caller, String receiver) async {
|
|
await signalR.hangupCall(caller, receiver);
|
|
dispose();
|
|
}
|
|
|
|
answerOffer(String sdp) async {
|
|
final offer = jsonDecode(sdp);
|
|
final caller = offer['caller'];
|
|
final receiver = offer['target'];
|
|
final offerSdp = offer['sdp'];
|
|
peerConnection.setRemoteDescription(rtcSessionDescriptionFrom(offerSdp)).then((value) {
|
|
return peerConnection.createAnswer().catchError((e){
|
|
print(e);
|
|
});
|
|
}).then((anwser) {
|
|
return peerConnection.setLocalDescription(anwser).catchError((e){
|
|
print(e);
|
|
});
|
|
}).then((value) {
|
|
return peerConnection.getLocalDescription().catchError((e){
|
|
print(e);
|
|
});
|
|
}).then((answer) {
|
|
return signalR.answerOffer(answer, caller, receiver).catchError((e){
|
|
print(e);
|
|
});
|
|
}).catchError((e) {
|
|
print(e);
|
|
});
|
|
}
|
|
|
|
Future<void> hangUp(RTCVideoRenderer localVideo) async {}
|
|
|
|
Future<String> createSdpAnswer(String toOfferSdp) async {
|
|
final offerSdp = rtcSessionDescriptionFrom(jsonDecode(toOfferSdp));
|
|
peerConnection.setRemoteDescription(offerSdp).catchError((e){
|
|
print(e);
|
|
});
|
|
|
|
final answer = await peerConnection.createAnswer().catchError((e){
|
|
print(e);
|
|
});
|
|
var answerSdp = json.encode(answer); // Send SDP via Push or any channel
|
|
return answerSdp;
|
|
}
|
|
|
|
Future<String> createSdpOffer() async {
|
|
final offer = await peerConnection.createOffer();
|
|
await peerConnection.setLocalDescription(offer).catchError((e){
|
|
print(e);
|
|
});
|
|
final map = offer.toMap();
|
|
var offerSdp = json.encode(map); // Send SDP via Push or any channel
|
|
return offerSdp;
|
|
}
|
|
|
|
addCandidate(String candidateJson) {
|
|
peerConnection.addCandidate(rtcIceCandidateFrom(candidateJson)).catchError((e){
|
|
print(e);
|
|
});
|
|
}
|
|
|
|
void registerPeerConnectionListeners() {
|
|
peerConnection.onRenegotiationNeeded = (){
|
|
print('Renegotiation Needed...');
|
|
};
|
|
|
|
peerConnection.onIceCandidate = (RTCIceCandidate candidate) {
|
|
// print(json.encode(candidate.toMap()));
|
|
signalR.addIceCandidate(json.encode(candidate.toMap())).catchError((e){
|
|
print(e);
|
|
});
|
|
};
|
|
|
|
peerConnection?.onIceGatheringState = (RTCIceGatheringState state) {
|
|
print('ICE gathering state changed: $state');
|
|
};
|
|
|
|
peerConnection?.onConnectionState = (RTCPeerConnectionState state) {
|
|
print('Connection state change: $state');
|
|
};
|
|
|
|
peerConnection?.onSignalingState = (RTCSignalingState state) {
|
|
print('Signaling state change: $state');
|
|
};
|
|
|
|
|
|
}
|
|
}
|
|
|
|
rtcSessionDescriptionFrom(Map sdp) {
|
|
return RTCSessionDescription(
|
|
sdp['sdp'],
|
|
sdp['type'],
|
|
);
|
|
}
|
|
|
|
rtcIceCandidateFrom(String json) {
|
|
final map = jsonDecode(json)['candidate'];
|
|
return RTCIceCandidate(map['candidate'], map['sdpMid'], map['sdpMLineIndex']);
|
|
}
|