feat: enhance background streaming functionality with improved wake lock management
- Updated the wake lock duration in BackgroundStreamingHandler to 3 hours, ensuring the service remains active for longer periods. - Modified the keepAlive method to support both iOS and Android, allowing for better background task management across platforms. - Implemented a periodic keep-alive timer in VoiceCallService to refresh the wake lock every 5 minutes, enhancing service reliability during voice calls. - Added debug logging for successful keep-alive invocations, improving traceability of background operations.
This commit is contained in:
@@ -144,13 +144,13 @@ class BackgroundStreamingService : Service() {
|
|||||||
|
|
||||||
private fun acquireWakeLock() {
|
private fun acquireWakeLock() {
|
||||||
if (wakeLock?.isHeld == true) return
|
if (wakeLock?.isHeld == true) return
|
||||||
|
|
||||||
val powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager
|
val powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager
|
||||||
wakeLock = powerManager.newWakeLock(
|
wakeLock = powerManager.newWakeLock(
|
||||||
PowerManager.PARTIAL_WAKE_LOCK,
|
PowerManager.PARTIAL_WAKE_LOCK,
|
||||||
"Conduit::StreamingWakeLock"
|
"Conduit::StreamingWakeLock"
|
||||||
).apply {
|
).apply {
|
||||||
acquire(15 * 60 * 1000L) // 15 minutes max
|
acquire(3 * 60 * 60 * 1000L) // 3 hours max (refreshed every 5 minutes)
|
||||||
}
|
}
|
||||||
println("BackgroundStreamingService: Wake lock acquired")
|
println("BackgroundStreamingService: Wake lock acquired")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -169,12 +169,16 @@ class BackgroundStreamingHandler {
|
|||||||
return _streamStates[streamId];
|
return _streamStates[streamId];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Keep alive the background task (iOS only)
|
/// Keep alive the background task
|
||||||
|
///
|
||||||
|
/// On iOS: Refreshes background task to prevent early termination
|
||||||
|
/// On Android: Refreshes wake lock to keep service running
|
||||||
Future<void> keepAlive() async {
|
Future<void> keepAlive() async {
|
||||||
if (!Platform.isIOS) return;
|
if (!Platform.isIOS && !Platform.isAndroid) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await _channel.invokeMethod('keepAlive');
|
await _channel.invokeMethod('keepAlive');
|
||||||
|
DebugLogger.stream('keepalive-success', scope: 'background');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
DebugLogger.error('keepalive-failed', scope: 'background', error: e);
|
DebugLogger.error('keepalive-failed', scope: 'background', error: e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ class VoiceCallService {
|
|||||||
bool _isDisposed = false;
|
bool _isDisposed = false;
|
||||||
bool _isMuted = false;
|
bool _isMuted = false;
|
||||||
SocketEventSubscription? _socketSubscription;
|
SocketEventSubscription? _socketSubscription;
|
||||||
|
Timer? _keepAliveTimer;
|
||||||
|
|
||||||
final StreamController<VoiceCallState> _stateController =
|
final StreamController<VoiceCallState> _stateController =
|
||||||
StreamController<VoiceCallState>.broadcast();
|
StreamController<VoiceCallState>.broadcast();
|
||||||
@@ -137,6 +138,13 @@ class VoiceCallService {
|
|||||||
_voiceCallStreamId,
|
_voiceCallStreamId,
|
||||||
], requiresMicrophone: true);
|
], requiresMicrophone: true);
|
||||||
|
|
||||||
|
// Set up periodic keep-alive to refresh wake lock (every 5 minutes)
|
||||||
|
_keepAliveTimer?.cancel();
|
||||||
|
_keepAliveTimer = Timer.periodic(
|
||||||
|
const Duration(minutes: 5),
|
||||||
|
(_) => BackgroundStreamingHandler.instance.keepAlive(),
|
||||||
|
);
|
||||||
|
|
||||||
// Set up socket event listener for assistant responses
|
// Set up socket event listener for assistant responses
|
||||||
_socketSubscription = _socketService.addChatEventHandler(
|
_socketSubscription = _socketService.addChatEventHandler(
|
||||||
conversationId: conversationId,
|
conversationId: conversationId,
|
||||||
@@ -149,6 +157,8 @@ class VoiceCallService {
|
|||||||
await _startListening();
|
await _startListening();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
_updateState(VoiceCallState.error);
|
_updateState(VoiceCallState.error);
|
||||||
|
_keepAliveTimer?.cancel();
|
||||||
|
_keepAliveTimer = null;
|
||||||
await WakelockPlus.disable();
|
await WakelockPlus.disable();
|
||||||
await _notificationService.cancelNotification();
|
await _notificationService.cancelNotification();
|
||||||
await BackgroundStreamingHandler.instance.stopBackgroundExecution(const [
|
await BackgroundStreamingHandler.instance.stopBackgroundExecution(const [
|
||||||
@@ -334,6 +344,10 @@ class VoiceCallService {
|
|||||||
Future<void> stopCall() async {
|
Future<void> stopCall() async {
|
||||||
if (_isDisposed) return;
|
if (_isDisposed) return;
|
||||||
|
|
||||||
|
// Cancel keep-alive timer
|
||||||
|
_keepAliveTimer?.cancel();
|
||||||
|
_keepAliveTimer = null;
|
||||||
|
|
||||||
await _transcriptSubscription?.cancel();
|
await _transcriptSubscription?.cancel();
|
||||||
await _intensitySubscription?.cancel();
|
await _intensitySubscription?.cancel();
|
||||||
_socketSubscription?.dispose();
|
_socketSubscription?.dispose();
|
||||||
@@ -436,6 +450,10 @@ class VoiceCallService {
|
|||||||
Future<void> dispose() async {
|
Future<void> dispose() async {
|
||||||
_isDisposed = true;
|
_isDisposed = true;
|
||||||
|
|
||||||
|
// Cancel keep-alive timer
|
||||||
|
_keepAliveTimer?.cancel();
|
||||||
|
_keepAliveTimer = null;
|
||||||
|
|
||||||
await _transcriptSubscription?.cancel();
|
await _transcriptSubscription?.cancel();
|
||||||
await _intensitySubscription?.cancel();
|
await _intensitySubscription?.cancel();
|
||||||
_socketSubscription?.dispose();
|
_socketSubscription?.dispose();
|
||||||
|
|||||||
Reference in New Issue
Block a user