import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_webrtc/webrtc.dart';
import 'package:adhara_socket_io/adhara_socket_io.dart';
class studentCall extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: _homeBody(),
);
}
}
class _homeBody extends StatefulWidget {
@override
__homeBodyState createState() => __homeBodyState();
}
class __homeBodyState extends State<_homeBody> {
// Connection Variables
var room = 'test';
RTCVideoRenderer _localRenderer = RTCVideoRenderer();
RTCVideoRenderer _remoteRenderer = RTCVideoRenderer();
MediaStream _localStream = null;
RTCPeerConnection _peerConnection = null;
// IO.Socket socket = null;
SocketIOManager manager = null;
SocketIO socket = null;
// Socket Variables
bool roomChecked = false;
// Connection Data Variables
final Map<String, dynamic> mediaConstraints = {
"audio": true,
"video": {
"mandatory": {
"minWidth": '640', // Provide your own width, height and frame rate here
"minHeight": '480',
"minFrameRate": '30',
},
"facingMode": "user",
"optional": [],
}
};
Map<String, dynamic> configuration = {
"iceServers": [
]
};
final Map<String, dynamic> _offer_constraints = {
"mandatory": {
"OfferToReceiveAudio": true,
"OfferToReceiveVideo": true,
},
"optional": [],
};
final Map<String, dynamic> constraints = {
"mandatory": {},
"optional": [
{"DtlsSrtpKeyAgreement": true},
],
};
// Initialize functions
@override
void initState() {
super.initState();
// _initialize();
}
void dispose() {
super.dispose();
// _localRenderer.dispose();
// _remoteRenderer.dispose();
// manager.clearInstance(socket);
}
_initialize() async {
if (socket != null) return;
_localRenderer.initialize();
_remoteRenderer.initialize();
manager = SocketIOManager();
socket = await manager
socket.connect();
// Socket Listening Functions
socket.onConnect((data) {
socket.emit('room-check', [
{'room': room}
]);
});
socket.on('room-exists', (data) {
_createPeer();
});
socket.on('room-not-exists', (data) {
_snackBar('not exists');
});
socket.on('studentResponse', (data) async {
try {
var answer = data['answer'].toString();
await _peerConnection
.setRemoteDescription(RTCSessionDescription(answer, 'answer'));
} catch (e) {
_snackBar(e.toString());
}
});
socket.on('candidate', (data) async {
if (_peerConnection == null) return;
try {
var map = data['candidate']['candidate'];
var sdpMid = data['candidate']['sdpMid'];
var sdpMLineIndex = data['candidate']['sdpMLineIndex'];
RTCIceCandidate candidate = RTCIceCandidate(map, sdpMid, sdpMLineIndex);
_snackBar(candidate.candidate);
_peerConnection.addCandidate(candidate);
} catch (e) {
_snackBar(e.toString());
}
});
}
_createPeer() async {
try {
if (_peerConnection != null) return;
navigator.getUserMedia(mediaConstraints).then((stream) {
_localStream = stream;
_localRenderer.srcObject = stream;
});
_peerConnection = await createPeerConnection(configuration, constraints);
_peerConnection.onSignalingState = _onSignalingState;
_peerConnection.onIceGatheringState = _onIceGatheringState;
_peerConnection.onIceConnectionState = _onIceConnectionState;
_peerConnection.onAddStream = _onAddStream;
_peerConnection.onRemoveStream = _onRemoveStream;
_peerConnection.onIceCandidate = _onCandidate;
_peerConnection.onRenegotiationNeeded = _onRenegotiationNeeded;
_peerConnection.addStream(_localStream);
RTCSessionDescription offer =
await _peerConnection.createOffer(_offer_constraints);
_peerConnection.setLocalDescription(offer);
socket.emit('add-student', [
{'room': room, 'offer': offer.sdp}
]);
} catch (e) {
_snackBar(e.toString());
}
}
_onSignalingState(RTCSignalingState state) {
_snackBar(state.toString());
}
_onIceGatheringState(RTCIceGatheringState state) {
_snackBar(state.toString());
}
_onIceConnectionState(RTCIceConnectionState state) {
_snackBar(state.toString());
}
_onAddStream(MediaStream stream) {
if (stream == null) {
_snackBar('null');
return;
}
_remoteRenderer.srcObject = stream;
setState(() {});
}
_onRemoveStream(MediaStream stream) {
_snackBar('remove');
}
_onCandidate(RTCIceCandidate candidate) {
socket.emit('studentCandidate', [
{
'room': room,
'candidate': {
'candidate': candidate.candidate,
'sdpMid': candidate.sdpMid,
'sdpMLineIndex': candidate.sdpMlineIndex
}
}
]);
}
_onRenegotiationNeeded() {
_snackBar('reneg');
}
// Display Functions and Variables
_snackBar(String msg) {
Scaffold.of(context).showSnackBar(SnackBar(
content: Text(msg),
));
}
Widget _progress = Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
),
);
@override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
Container(
decoration: BoxDecoration(
color: Colors.white,
),
width: double.infinity,
height: double.infinity,
child: RTCVideoView(
_remoteRenderer,
),
),
// _progress,
Positioned(
child: Container(
decoration: BoxDecoration(color: Colors.black, boxShadow: [
BoxShadow(
color: Colors.grey,
)
]),
width: 150,
height: 200,
child: RTCVideoView(
_localRenderer,
),
),
bottom: 20,
right: 30,
)
],
);
}
}