forked from eatvio/eatvio_app
feat(video_calls): ios calle mic fix
This commit is contained in:
@@ -592,6 +592,7 @@ class VideoCallManager {
|
||||
);
|
||||
if (next) {
|
||||
await _audioSession.restartCapture();
|
||||
await _bindIosCallKitAudioEngine();
|
||||
}
|
||||
} catch (_) {
|
||||
return;
|
||||
@@ -791,6 +792,7 @@ class VideoCallManager {
|
||||
audioCaptureOptions: _micCaptureOptions,
|
||||
);
|
||||
await _audioSession.restartCapture();
|
||||
await _bindIosCallKitAudioEngine();
|
||||
} catch (_) {}
|
||||
}
|
||||
await _resumeVideoAfterForeground();
|
||||
@@ -1264,6 +1266,7 @@ class VideoCallManager {
|
||||
audioCaptureOptions: _micCaptureOptions,
|
||||
);
|
||||
await _audioSession.restartCapture();
|
||||
await _bindIosCallKitAudioEngine();
|
||||
} catch (_) {
|
||||
effectiveMic = false;
|
||||
}
|
||||
@@ -1304,6 +1307,17 @@ class VideoCallManager {
|
||||
_lastMutedMicTotalEnergy = null;
|
||||
}
|
||||
|
||||
Future<void> _bindIosCallKitAudioEngine() async {
|
||||
if (!Platform.isIOS) return;
|
||||
try {
|
||||
final calls = await FlutterCallkitIncoming.activeCalls();
|
||||
if (calls.isEmpty) return;
|
||||
} catch (_) {
|
||||
return;
|
||||
}
|
||||
await _audioSession.startCallKitCapture();
|
||||
}
|
||||
|
||||
Future<void> _startCallAudioSession() async {
|
||||
if (!_canHandleCallAudio) return;
|
||||
try {
|
||||
|
||||
@@ -5,6 +5,7 @@ import 'package:flutter/services.dart';
|
||||
|
||||
typedef VideoCallAudioSessionFactory = Future<AudioSession> Function();
|
||||
typedef IosCallAudioSessionHandler = Future<void> Function(String method);
|
||||
typedef IosAdmHandler = Future<void> Function();
|
||||
|
||||
/// Configures and owns the platform audio session for an active VoIP call.
|
||||
class VideoCallAudioSessionCoordinator {
|
||||
@@ -12,18 +13,27 @@ class VideoCallAudioSessionCoordinator {
|
||||
VideoCallAudioSessionFactory? audioSessionFactory,
|
||||
bool? isIos,
|
||||
IosCallAudioSessionHandler? iosCallAudioSession,
|
||||
IosAdmHandler? stopLocalRecording,
|
||||
IosAdmHandler? startLocalRecording,
|
||||
}) : _audioSessionFactory =
|
||||
audioSessionFactory ?? (() => AudioSession.instance),
|
||||
_isIos = isIos ?? Platform.isIOS,
|
||||
_iosCallAudioSession = iosCallAudioSession ?? _invokeIosCallAudioSession;
|
||||
_iosCallAudioSession = iosCallAudioSession ?? _invokeIosCallAudioSession,
|
||||
_stopLocalRecording = stopLocalRecording ?? _invokeStopLocalRecording,
|
||||
_startLocalRecording = startLocalRecording ?? _invokeStartLocalRecording;
|
||||
|
||||
static const MethodChannel _iosChannel = MethodChannel(
|
||||
'com.eatvioapp/call_audio_session',
|
||||
);
|
||||
static const MethodChannel _webrtcChannel = MethodChannel(
|
||||
'FlutterWebRTC.Method',
|
||||
);
|
||||
|
||||
final VideoCallAudioSessionFactory _audioSessionFactory;
|
||||
final bool _isIos;
|
||||
final IosCallAudioSessionHandler _iosCallAudioSession;
|
||||
final IosAdmHandler _stopLocalRecording;
|
||||
final IosAdmHandler _startLocalRecording;
|
||||
|
||||
static final AudioSessionConfiguration callConfiguration =
|
||||
AudioSessionConfiguration(
|
||||
@@ -54,6 +64,14 @@ class VideoCallAudioSessionCoordinator {
|
||||
return _iosChannel.invokeMethod<void>(method);
|
||||
}
|
||||
|
||||
static Future<void> _invokeStopLocalRecording() {
|
||||
return _webrtcChannel.invokeMethod<void>('stopLocalRecording');
|
||||
}
|
||||
|
||||
static Future<void> _invokeStartLocalRecording() {
|
||||
return _webrtcChannel.invokeMethod<void>('startLocalRecording');
|
||||
}
|
||||
|
||||
Future<void> start() async {
|
||||
if (_isIos) {
|
||||
await _iosCallAudioSession('activate');
|
||||
@@ -97,6 +115,21 @@ class VideoCallAudioSessionCoordinator {
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
/// flutter-webrtc 1.2 uses AudioEngine ADM. `isAudioEnabled` does not start
|
||||
/// that engine. Incoming CallKit therefore needs `initAndStartRecording`
|
||||
/// after the microphone track exists and CallKit has activated the session.
|
||||
Future<void> startCallKitCapture() async {
|
||||
if (!_isIos) return;
|
||||
try {
|
||||
await _stopLocalRecording();
|
||||
} catch (_) {}
|
||||
await Future<void>.delayed(const Duration(milliseconds: 120));
|
||||
try {
|
||||
await _startLocalRecording();
|
||||
_iosActive = true;
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
Future<void> stop() async {
|
||||
if (_isIos) {
|
||||
_iosActive = false;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: eatvio_app
|
||||
description: A new Flutter project.
|
||||
version: 1.3.63+152
|
||||
version: 1.3.64+153
|
||||
publish_to: 'none'
|
||||
|
||||
environment:
|
||||
|
||||
@@ -28,6 +28,21 @@ void main() {
|
||||
expect(calls, ['activate', 'activate', 'restart', 'deactivate']);
|
||||
});
|
||||
|
||||
test('startCallKitCapture restarts the AudioEngine ADM', () async {
|
||||
final adm = <String>[];
|
||||
final coordinator = VideoCallAudioSessionCoordinator(
|
||||
isIos: true,
|
||||
iosCallAudioSession: (_) async {},
|
||||
stopLocalRecording: () async => adm.add('stop'),
|
||||
startLocalRecording: () async => adm.add('start'),
|
||||
);
|
||||
|
||||
await coordinator.startCallKitCapture();
|
||||
|
||||
expect(coordinator.isActive, isTrue);
|
||||
expect(adm, ['stop', 'start']);
|
||||
});
|
||||
|
||||
test('stop clears the active session when deactivate fails', () async {
|
||||
final coordinator = VideoCallAudioSessionCoordinator(
|
||||
isIos: true,
|
||||
|
||||
Reference in New Issue
Block a user