|
|
|
@ -8,7 +8,7 @@ import '../utils/turn.dart' if (dart.library.js) '../utils/turn_web.dart';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
enum SignalingState { Open, Closed, Error }
|
|
|
|
enum SignalingState { Open, Closed, Error }
|
|
|
|
enum CallState { Calling, Ringing, Invite, Connected, Bye }
|
|
|
|
enum CallState {Bye}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const JsonEncoder _encoder = JsonEncoder();
|
|
|
|
const JsonEncoder _encoder = JsonEncoder();
|
|
|
|
@ -50,6 +50,8 @@ class SocketUser{
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class Signaling {
|
|
|
|
class Signaling {
|
|
|
|
|
|
|
|
SignalingState state;
|
|
|
|
|
|
|
|
|
|
|
|
var _host;
|
|
|
|
var _host;
|
|
|
|
var _turnCredential;
|
|
|
|
var _turnCredential;
|
|
|
|
|
|
|
|
|
|
|
|
@ -68,7 +70,8 @@ class Signaling {
|
|
|
|
Function(SessionOneToOne session, MediaStream stream) onRemoveRemoteStream;
|
|
|
|
Function(SessionOneToOne session, MediaStream stream) onRemoveRemoteStream;
|
|
|
|
Function(dynamic event) onPeersUpdate;
|
|
|
|
Function(dynamic event) onPeersUpdate;
|
|
|
|
Function(dynamic event) onConnected;
|
|
|
|
Function(dynamic event) onConnected;
|
|
|
|
Function(dynamic event) onRemoteConnected;
|
|
|
|
Function(dynamic event) onCallAccepted;
|
|
|
|
|
|
|
|
Function(dynamic event) onCallRejected;
|
|
|
|
Function(SessionOneToOne session, RTCDataChannel dc, RTCDataChannelMessage data) onDataChannelMessage;
|
|
|
|
Function(SessionOneToOne session, RTCDataChannel dc, RTCDataChannelMessage data) onDataChannelMessage;
|
|
|
|
Function(SessionOneToOne session, RTCDataChannel dc) onDataChannel;
|
|
|
|
Function(SessionOneToOne session, RTCDataChannel dc) onDataChannel;
|
|
|
|
|
|
|
|
|
|
|
|
@ -105,7 +108,7 @@ class Signaling {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
close() async {
|
|
|
|
close() async {
|
|
|
|
await finishSessions();
|
|
|
|
finishSessions();
|
|
|
|
_socket?.close();
|
|
|
|
_socket?.close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@ -129,6 +132,12 @@ class Signaling {
|
|
|
|
'from': session.local_user.id,
|
|
|
|
'from': session.local_user.id,
|
|
|
|
'session_id': session.id,
|
|
|
|
'session_id': session.id,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_send('patient_call_accepted', {
|
|
|
|
|
|
|
|
'to': session.remote_user?.id,
|
|
|
|
|
|
|
|
'from': session.local_user.id,
|
|
|
|
|
|
|
|
'session_id': session.id,
|
|
|
|
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void offer(String media, bool useScreen) async {
|
|
|
|
void offer(String media, bool useScreen) async {
|
|
|
|
@ -139,17 +148,26 @@ class Signaling {
|
|
|
|
_createDataChannel(session);
|
|
|
|
_createDataChannel(session);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_createOffer(session, media);
|
|
|
|
_createOffer(session, media);
|
|
|
|
onCallStateChange?.call(session, CallState.Calling);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void bye(SessionOneToOne session) {
|
|
|
|
void bye(SessionOneToOne session, {bool callRejected = false}) {
|
|
|
|
_send('bye', {
|
|
|
|
_send('bye', {
|
|
|
|
'session_id': session.id,
|
|
|
|
'session_id': session.id,
|
|
|
|
'from': session.local_user.id,
|
|
|
|
'from': session.local_user.id,
|
|
|
|
|
|
|
|
// 'call_rejected' : callRejected
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
_closeSession(session);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void callDisconnected(SessionOneToOne session, {bool callRejected = false}) {
|
|
|
|
|
|
|
|
_send('patient_call_rejected', {
|
|
|
|
|
|
|
|
'session_id': session.id,
|
|
|
|
|
|
|
|
'to': session.remote_user.id,
|
|
|
|
|
|
|
|
'from': session.local_user.id,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
_closeSession(session);
|
|
|
|
_closeSession(session);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void onMessage(message) async {
|
|
|
|
void onMessage(message) async {
|
|
|
|
Map<String, dynamic> mapData = message;
|
|
|
|
Map<String, dynamic> mapData = message;
|
|
|
|
var data = mapData['data'];
|
|
|
|
var data = mapData['data'];
|
|
|
|
@ -157,7 +175,7 @@ class Signaling {
|
|
|
|
switch (mapData['type']) {
|
|
|
|
switch (mapData['type']) {
|
|
|
|
case 'call_accepted':
|
|
|
|
case 'call_accepted':
|
|
|
|
{
|
|
|
|
{
|
|
|
|
onRemoteConnected?.call(data);
|
|
|
|
onCallAccepted?.call(data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
@ -171,8 +189,6 @@ class Signaling {
|
|
|
|
|
|
|
|
|
|
|
|
case 'offer':
|
|
|
|
case 'offer':
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
var peerId = data['from'];
|
|
|
|
|
|
|
|
var description = data['description'];
|
|
|
|
var description = data['description'];
|
|
|
|
var media = data['media'];
|
|
|
|
var media = data['media'];
|
|
|
|
|
|
|
|
|
|
|
|
@ -186,12 +202,10 @@ class Signaling {
|
|
|
|
});
|
|
|
|
});
|
|
|
|
session.remoteCandidates.clear();
|
|
|
|
session.remoteCandidates.clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
onCallStateChange?.call(session, CallState.Calling);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
case 'answer':
|
|
|
|
case 'answer':
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
var description = data['description'];
|
|
|
|
var description = data['description'];
|
|
|
|
var sessionId = data['session_id'];
|
|
|
|
var sessionId = data['session_id'];
|
|
|
|
session.pc?.setRemoteDescription(
|
|
|
|
session.pc?.setRemoteDescription(
|
|
|
|
@ -200,8 +214,6 @@ class Signaling {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
case 'candidate':
|
|
|
|
case 'candidate':
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
var peerId = data['from'];
|
|
|
|
|
|
|
|
var candidateMap = data['candidate'];
|
|
|
|
var candidateMap = data['candidate'];
|
|
|
|
var sessionId = data['session_id'];
|
|
|
|
var sessionId = data['session_id'];
|
|
|
|
RTCIceCandidate candidate = RTCIceCandidate(candidateMap['candidate'],
|
|
|
|
RTCIceCandidate candidate = RTCIceCandidate(candidateMap['candidate'],
|
|
|
|
@ -219,21 +231,11 @@ class Signaling {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
case 'leave':
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
var peerId = data as String;
|
|
|
|
|
|
|
|
_closeSessionById(peerId);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'bye':
|
|
|
|
case 'bye':
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
if(session.local_user.id != data["from"])
|
|
|
|
var sessionId = data['session_id'];
|
|
|
|
|
|
|
|
print('bye: ' + sessionId);
|
|
|
|
|
|
|
|
if (session != null) {
|
|
|
|
|
|
|
|
onCallStateChange?.call(session, CallState.Bye);
|
|
|
|
onCallStateChange?.call(session, CallState.Bye);
|
|
|
|
_closeSession(session);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
case 'keepalive':
|
|
|
|
case 'keepalive':
|
|
|
|
@ -269,11 +271,15 @@ class Signaling {
|
|
|
|
},
|
|
|
|
},
|
|
|
|
]
|
|
|
|
]
|
|
|
|
};
|
|
|
|
};
|
|
|
|
} catch (e) {}
|
|
|
|
} catch (e) {
|
|
|
|
|
|
|
|
print("jsjhs" + e.toString());
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_socket?.onOpen = () {
|
|
|
|
_socket?.onOpen = () {
|
|
|
|
print('onOpen');
|
|
|
|
print('onOpen');
|
|
|
|
|
|
|
|
state = SignalingState.Open;
|
|
|
|
|
|
|
|
|
|
|
|
onSignalingStateChange?.call(SignalingState.Open);
|
|
|
|
onSignalingStateChange?.call(SignalingState.Open);
|
|
|
|
_send('connect', session.local_user.toJson());
|
|
|
|
_send('connect', session.local_user.toJson());
|
|
|
|
};
|
|
|
|
};
|
|
|
|
@ -284,10 +290,13 @@ class Signaling {
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
_socket?.onClose = (int code, String reason) {
|
|
|
|
_socket?.onClose = (int code, String reason) {
|
|
|
|
|
|
|
|
state = SignalingState.Closed;
|
|
|
|
|
|
|
|
|
|
|
|
print('Closed by server [$code => $reason]!');
|
|
|
|
print('Closed by server [$code => $reason]!');
|
|
|
|
onSignalingStateChange?.call(SignalingState.Closed);
|
|
|
|
onSignalingStateChange?.call(SignalingState.Closed);
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
await _socket?.connect();
|
|
|
|
await _socket?.connect();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@ -403,7 +412,7 @@ class Signaling {
|
|
|
|
'to': session.remote_user?.id,
|
|
|
|
'to': session.remote_user?.id,
|
|
|
|
'from': session.local_user.id,
|
|
|
|
'from': session.local_user.id,
|
|
|
|
'candidate': {
|
|
|
|
'candidate': {
|
|
|
|
'sdpMLineIndex': candidate.sdpMlineIndex, // sdpMlineIndex or sdpMLineIndex
|
|
|
|
'sdpMLineIndex': candidate.sdpMLineIndex, // sdpMlineIndex or sdpMLineIndex
|
|
|
|
'sdpMid': candidate.sdpMid,
|
|
|
|
'sdpMid': candidate.sdpMid,
|
|
|
|
'candidate': candidate.candidate,
|
|
|
|
'candidate': candidate.candidate,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
@ -486,14 +495,7 @@ class Signaling {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Future<void> finishSessions() async {
|
|
|
|
Future<void> finishSessions() async {
|
|
|
|
_closeSessionById(session.id);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void _closeSessionById(String sessionId) {
|
|
|
|
|
|
|
|
if (session != null && session.id == sessionId) {
|
|
|
|
|
|
|
|
_closeSession(session);
|
|
|
|
_closeSession(session);
|
|
|
|
onCallStateChange?.call(session, CallState.Bye);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Future<void> _closeSession(SessionOneToOne session) async {
|
|
|
|
Future<void> _closeSession(SessionOneToOne session) async {
|
|
|
|
@ -502,7 +504,6 @@ class Signaling {
|
|
|
|
});
|
|
|
|
});
|
|
|
|
await localStream?.dispose();
|
|
|
|
await localStream?.dispose();
|
|
|
|
localStream = null;
|
|
|
|
localStream = null;
|
|
|
|
|
|
|
|
|
|
|
|
await session.pc?.close();
|
|
|
|
await session.pc?.close();
|
|
|
|
await session.dc?.close();
|
|
|
|
await session.dc?.close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|