Merge branch 'development_aamir' into 'master'
Chat Fix & Web RTC -- Inprogress See merge request Cloud_Solution/mohemm-flutter-app!154merge-requests/155/merge
commit
2b35c3d8d6
@ -0,0 +1,187 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter_webrtc/flutter_webrtc.dart';
|
||||||
|
import 'package:mohem_flutter_app/ui/landing/dashboard_screen.dart';
|
||||||
|
|
||||||
|
class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
|
||||||
|
///////////////////// Web RTC Video Calling //////////////////////
|
||||||
|
// Video Call
|
||||||
|
late RTCPeerConnection _peerConnection;
|
||||||
|
RTCVideoRenderer _localVideoRenderer = RTCVideoRenderer();
|
||||||
|
final RTCVideoRenderer _remoteRenderer = RTCVideoRenderer();
|
||||||
|
|
||||||
|
MediaStream? _localStream;
|
||||||
|
MediaStream? _remoteStream;
|
||||||
|
|
||||||
|
void initCallListeners() {
|
||||||
|
chatHubConnection.on("OnCallAcceptedAsync", onCallAcceptedAsync);
|
||||||
|
chatHubConnection.on("OnIceCandidateAsync", onIceCandidateAsync);
|
||||||
|
chatHubConnection.on("OnOfferAsync", onOfferAsync);
|
||||||
|
chatHubConnection.on("OnAnswerOffer", onAnswerOffer);
|
||||||
|
chatHubConnection.on("OnHangUpAsync", onHangUpAsync);
|
||||||
|
chatHubConnection.on("OnCallDeclinedAsync", onCallDeclinedAsync);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Video Constraints
|
||||||
|
var videoConstraints = {
|
||||||
|
"video": {
|
||||||
|
"mandatory": {
|
||||||
|
"width": {"min": 320},
|
||||||
|
"height": {"min": 180}
|
||||||
|
},
|
||||||
|
"optional": [
|
||||||
|
{
|
||||||
|
"width": {"max": 1280}
|
||||||
|
},
|
||||||
|
{"frameRate": 25},
|
||||||
|
{"facingMode": "user"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"frameRate": 25,
|
||||||
|
"width": 420, //420,//640,//1280,
|
||||||
|
"height": 240 //240//480//720
|
||||||
|
};
|
||||||
|
|
||||||
|
// Audio Constraints
|
||||||
|
var audioConstraints = {
|
||||||
|
"sampleRate": 8000,
|
||||||
|
"sampleSize": 16,
|
||||||
|
"channelCount": 2,
|
||||||
|
"echoCancellation": true,
|
||||||
|
"audio": true,
|
||||||
|
};
|
||||||
|
|
||||||
|
Future<RTCPeerConnection> _createPeerConnection() async {
|
||||||
|
// {"url": "stun:stun.l.google.com:19302"},
|
||||||
|
Map<String, dynamic> configuration = {
|
||||||
|
"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);
|
||||||
|
// if (pc != null) print(pc);
|
||||||
|
//pc.addStream(widget.localStream);
|
||||||
|
|
||||||
|
pc.onIceCandidate = (e) {
|
||||||
|
if (e.candidate != null) {
|
||||||
|
print(json.encode({
|
||||||
|
'candidate': e.candidate.toString(),
|
||||||
|
'sdpMid': e.sdpMid.toString(),
|
||||||
|
'sdpMlineIndex': e.sdpMLineIndex,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
pc.onIceConnectionState = (e) {
|
||||||
|
print(e);
|
||||||
|
};
|
||||||
|
pc.onAddStream = (stream) {
|
||||||
|
print('addStream: ' + stream.id);
|
||||||
|
_remoteRenderer.srcObject = stream;
|
||||||
|
};
|
||||||
|
return pc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init() {
|
||||||
|
initRenderers();
|
||||||
|
_createPeerConnection().then((pc) {
|
||||||
|
_peerConnection = pc;
|
||||||
|
// _setRemoteDescription(widget.info);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void initRenderers() {
|
||||||
|
_localVideoRenderer.initialize();
|
||||||
|
_remoteRenderer.initialize();
|
||||||
|
initLocalCamera();
|
||||||
|
}
|
||||||
|
|
||||||
|
void initLocalCamera() async {
|
||||||
|
_localStream = await navigator.mediaDevices.getUserMedia({'video': true, 'audio': true});
|
||||||
|
_localVideoRenderer.srcObject = _localStream;
|
||||||
|
// _localVideoRenderer.srcObject = await navigator.mediaDevices
|
||||||
|
// .getUserMedia({'video': true, 'audio': true});
|
||||||
|
print('this source Object');
|
||||||
|
print('this suarce ${_localVideoRenderer.srcObject != null}');
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
void startCall({required String callType}) {}
|
||||||
|
|
||||||
|
void endCall() {}
|
||||||
|
|
||||||
|
void checkCall(Map<String, dynamic> message) {
|
||||||
|
switch (message["callStatus"]) {
|
||||||
|
case 'connected':
|
||||||
|
{}
|
||||||
|
break;
|
||||||
|
case 'offer':
|
||||||
|
{}
|
||||||
|
break;
|
||||||
|
case 'accept':
|
||||||
|
{}
|
||||||
|
break;
|
||||||
|
case 'candidate':
|
||||||
|
{}
|
||||||
|
break;
|
||||||
|
case 'bye':
|
||||||
|
{}
|
||||||
|
break;
|
||||||
|
case 'leave':
|
||||||
|
{}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//// Listeners Methods ////
|
||||||
|
|
||||||
|
void onCallAcceptedAsync(List<Object?>? params) {}
|
||||||
|
|
||||||
|
void onIceCandidateAsync(List<Object?>? params) {}
|
||||||
|
|
||||||
|
void onOfferAsync(List<Object?>? params) {}
|
||||||
|
|
||||||
|
void onAnswerOffer(List<Object?>? params) {}
|
||||||
|
|
||||||
|
void onHangUpAsync(List<Object?>? params) {}
|
||||||
|
|
||||||
|
void onCallDeclinedAsync(List<Object?>? params) {}
|
||||||
|
|
||||||
|
//// Invoke Methods
|
||||||
|
|
||||||
|
Future<void> invoke({required String invokeMethod, required String currentUserID, required String targetUserID, bool isVideoCall = false, var data}) async {
|
||||||
|
List<Object> args = [];
|
||||||
|
if (invokeMethod == "answerCallAsync") {
|
||||||
|
args = [currentUserID, targetUserID];
|
||||||
|
} else if (invokeMethod == "CallUserAsync") {
|
||||||
|
args = [currentUserID, targetUserID, isVideoCall];
|
||||||
|
} else if (invokeMethod == "IceCandidateAsync") {
|
||||||
|
args = [targetUserID, data];
|
||||||
|
} else if (invokeMethod == "OfferAsync") {
|
||||||
|
args = [targetUserID, data];
|
||||||
|
} else if (invokeMethod == "AnswerOfferAsync") {
|
||||||
|
args = [targetUserID, data];
|
||||||
|
//json In Data
|
||||||
|
}
|
||||||
|
await chatHubConnection.invoke(invokeMethod, args: args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void stopListeners() async {
|
||||||
|
chatHubConnection.off('OnCallDeclinedAsync');
|
||||||
|
chatHubConnection.off('OnCallAcceptedAsync');
|
||||||
|
chatHubConnection.off('OnIceCandidateAsync');
|
||||||
|
chatHubConnection.off('OnAnswerOffer');
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:intl/intl.dart' as intl;
|
||||||
|
|
||||||
|
class CustomAutoDirection extends StatefulWidget {
|
||||||
|
final String text;
|
||||||
|
final Widget child;
|
||||||
|
final void Function(bool isRTL)? onDirectionChange;
|
||||||
|
|
||||||
|
const CustomAutoDirection({Key? key, required this.text, required this.child, this.onDirectionChange}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_CustomAutoDirectionState createState() => _CustomAutoDirectionState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CustomAutoDirectionState extends State<CustomAutoDirection> {
|
||||||
|
late String text;
|
||||||
|
late Widget childWidget;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
text = widget.text;
|
||||||
|
childWidget = widget.child;
|
||||||
|
return Directionality(textDirection: isRTL(text) ? TextDirection.rtl : TextDirection.ltr, child: childWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didUpdateWidget(CustomAutoDirection oldWidget) {
|
||||||
|
if (isRTL(oldWidget.text) != isRTL(widget.text)) {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) => widget.onDirectionChange?.call(isRTL(widget.text)));
|
||||||
|
}
|
||||||
|
super.didUpdateWidget(oldWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isRTL(String text) {
|
||||||
|
if (text.isEmpty) return Directionality.of(context) == TextDirection.rtl;
|
||||||
|
return intl.Bidi.detectRtlDirectionality(text);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue