feat: implement WebRTC calls
Signed-off-by: TheOneWithTheBraid <the-one@with-the-braid.cf>
This commit is contained in:
parent
61749a0e6a
commit
34600ac165
26 changed files with 1774 additions and 53 deletions
136
lib/utils/voip_plugin.dart
Normal file
136
lib/utils/voip_plugin.dart
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
import 'dart:core';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'package:connectivity_plus/connectivity_plus.dart';
|
||||
import 'package:flutter_webrtc/flutter_webrtc.dart' as webrtc_impl;
|
||||
import 'package:matrix/matrix.dart';
|
||||
import 'package:webrtc_interface/webrtc_interface.dart';
|
||||
|
||||
import 'package:fluffychat/pages/dialer/dialer.dart';
|
||||
import '../../utils/voip/user_media_manager.dart';
|
||||
|
||||
class VoipPlugin extends WidgetsBindingObserver implements WebRTCDelegate {
|
||||
VoipPlugin({required this.client, required this.context}) {
|
||||
voip = VoIP(client, this);
|
||||
Connectivity()
|
||||
.onConnectivityChanged
|
||||
.listen(_handleNetworkChanged)
|
||||
.onError((e) => _currentConnectivity = ConnectivityResult.none);
|
||||
Connectivity()
|
||||
.checkConnectivity()
|
||||
.then((result) => _currentConnectivity = result)
|
||||
.catchError((e) => _currentConnectivity = ConnectivityResult.none);
|
||||
if (!kIsWeb) {
|
||||
final wb = WidgetsBinding.instance;
|
||||
wb?.addObserver(this);
|
||||
if (wb != null) {
|
||||
didChangeAppLifecycleState(wb.lifecycleState!);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final Client client;
|
||||
bool background = false;
|
||||
bool speakerOn = false;
|
||||
late VoIP voip;
|
||||
ConnectivityResult? _currentConnectivity;
|
||||
ValueChanged<CallSession>? onIncomingCall;
|
||||
OverlayEntry? overlayEntry;
|
||||
|
||||
final BuildContext context;
|
||||
|
||||
void _handleNetworkChanged(ConnectivityResult result) async {
|
||||
/// Got a new connectivity status!
|
||||
if (_currentConnectivity != result) {
|
||||
voip.calls.forEach((_, sess) {
|
||||
sess.restartIce();
|
||||
});
|
||||
}
|
||||
_currentConnectivity = result;
|
||||
}
|
||||
|
||||
@override
|
||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||
Logs().v('AppLifecycleState = $state');
|
||||
background = !(state != AppLifecycleState.detached &&
|
||||
state != AppLifecycleState.paused);
|
||||
}
|
||||
|
||||
void addCallingOverlay(
|
||||
BuildContext context, String callId, CallSession call) {
|
||||
if (overlayEntry != null) {
|
||||
Logs().w('[VOIP] addCallingOverlay: The call session already exists?');
|
||||
overlayEntry?.remove();
|
||||
}
|
||||
overlayEntry = OverlayEntry(
|
||||
builder: (_) => Calling(
|
||||
context: context,
|
||||
client: client,
|
||||
callId: callId,
|
||||
call: call,
|
||||
onClear: () {
|
||||
overlayEntry?.remove();
|
||||
overlayEntry = null;
|
||||
}),
|
||||
);
|
||||
Overlay.of(context)!.insert(overlayEntry!);
|
||||
}
|
||||
|
||||
@override
|
||||
MediaDevices get mediaDevices => webrtc_impl.navigator.mediaDevices;
|
||||
|
||||
@override
|
||||
bool get isBackgroud => background;
|
||||
|
||||
@override
|
||||
bool get isWeb => kIsWeb;
|
||||
|
||||
@override
|
||||
Future<RTCPeerConnection> createPeerConnection(
|
||||
Map<String, dynamic> configuration,
|
||||
[Map<String, dynamic> constraints = const {}]) =>
|
||||
webrtc_impl.createPeerConnection(configuration, constraints);
|
||||
|
||||
@override
|
||||
VideoRenderer createRenderer() {
|
||||
return webrtc_impl.RTCVideoRenderer();
|
||||
}
|
||||
|
||||
@override
|
||||
void playRingtone() async {
|
||||
if (!background) {
|
||||
try {
|
||||
await UserMediaManager().startRingingTone();
|
||||
} catch (_) {}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void stopRingtone() async {
|
||||
if (!background) {
|
||||
try {
|
||||
await UserMediaManager().stopRingingTone();
|
||||
} catch (_) {}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void handleNewCall(CallSession call) async {
|
||||
/// Popup CallingPage for incoming call.
|
||||
if (!background) {
|
||||
addCallingOverlay(context, call.callId, call);
|
||||
} else {
|
||||
onIncomingCall?.call(call);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void handleCallEnded(CallSession session) async {
|
||||
if (overlayEntry != null) {
|
||||
overlayEntry?.remove();
|
||||
overlayEntry = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue