[BUG]: Audio does not record when screen locks
Version of flutter_sound ^9.10.4
flutter doctor [√] Flutter (Channel stable, 3.22.2, on Microsoft Windows [Version 10.0.19045.4780], locale en-IN) [√] Windows Version (Installed version of Windows is version 10 or higher) [√] Chrome - develop for the web [√] Android Studio (version 2022.2) [√] Connected device (4 available) [√] Network resources
Platforms you faced the error (IOS or Android or both?) Android
Expected behavior Keep recording even when the screen times out.
Actual behavior Recording continues, but mic audio cuts off when Android times out . For example, if you record an hour long presentation, you'll find that the output file is one hour long, but there is only 1 minute of usable audio, and 59 minutes of total silence.
Tested environment (Emulator? Real Device?) Real Device. Redmi 11i OS : Android 13
Steps to reproduce the behavior Start recording, let Android time out while you are recording. After a few minutes, stop the recording, and listen to the output.
Flutter version Flutter 3.22.2 • channel stable • https://github.com/flutter/flutter.git Framework • revision 761747bfc5 (2 months ago) • 2024-06-05 22:15:13 +0200 Engine • revision edd8546116 Tools • Dart 3.4.3 • DevTools 2.34.3
Thank you @akshay-kapase for your problem report.
We already have several issue reported around this area, so we need to address this issue.
Someone should investigate to understand what is the problem and what could be a solution.
I added this issue in the column todo in 10.0 of the Kanban table to be sure that we will do something.
10.0 is not for today, nor for tomorrow. So it would be good if someone does something in 9.x.
Perhaps the solution is in the new isBGService that we added recently on openRecorder().
Or perhaps this is something that can be fixed with some good parameters when opening the session...
Someone expert on Android should explain the problem and the solution.
Hi @Larpoux thanks for the feedback. I just tried using isBgService but did not got any success using it. May i know what does isBgService actually does ?
Perhaps Mohsin or @together87 could help you. We definitely need an Android expert to tell us what we need to do inside Flutter Sound. I am sure that this issue could be very easily fixed as soon as we understand what we must do.
ok, after going through a lot of documentation & trial and errors, it seems the recording should start by starting a foreground service with a notification. I have tried with flutter_sound + flutter_foreground_task which did not work because i was getting this error from flutter_sound package
Error starting recorder: MissingPluginException(No implementation found for method resetPlugin on channel xyz.canardoux.flutter_sound_recorder)
so then i tried with record plugin + flutter_foreground_task in which case the recording works even when the phone is locked.
Interesting. When you had success, it was not with Flutter Sound, was it ? I am not sure to have completely understood
yes with flutter sound i got this resetPlugin error. i tried to run it in release mode but still got the same error. so i have changed this small poc code from flutter_sound to record plugin
@Larpoux can you please guide me where you are running the background service inside the library
@Override
public void onAttachedToEngine ( FlutterPlugin.FlutterPluginBinding binding )
{
this.pluginBinding = binding;
new MethodChannel(binding.getBinaryMessenger(), "xyz.canardoux.flutter_sound_bgservice").setMethodCallHandler(new MethodCallHandler() {
@Override
public void onMethodCall ( final MethodCall call, final Result result )
{
if (call.method.equals("setBGService")) {
attachFlauto();
}
result.success(0);
}
});
}
Hi @akshay-kapase @Larpoux I am also getting the same error and I am trying to find the solution, have you got any solution for this issue?
use combination of record plugin + foreground service task plugin + audioplayers plugin it should work
use combination of record plugin + foreground service task plugin + audioplayers plugin it should work
@akshay-kapase would you share your code, we are also struggling with this problem.
use combination of record plugin + foreground service task plugin + audioplayers plugin it should work
Any chance you can share your code? Thanks a lot
use combination of record plugin + foreground service task plugin + audioplayers plugin it should work
is there any fix yet? or could you share the code? Thanksss
Subject: Solution for Background Recording after Screen Lock using Foreground Service
Hello everyone,
Addressing the issue of background recording after the screen locks, as highlighted by Android documentation Android Foreground Services, apps need to utilize a foreground service for recording to continue in the background after Android 14.
The following code implementation successfully enabled background recording for me. It leverages a combination of a foreground service and necessary permissions.
Code Implementation:
1. AndroidManifest.xml:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE" />
<service
android:name=".ForegroundNotificationService"
android:foregroundServiceType="microphone"
android:enabled="true"
android:exported="false"
android:label="Record Service"
android:permission="android.permission.FOREGROUND_SERVICE_MICROPHONE">
</service>
2. ForegroundNotificationService.kt:
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.Service
import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.IBinder
import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat
class ForegroundNotificationService : Service() {
companion object {
private const val CHANNEL_ID = "ForegroundNotificationChannel"
private const val NOTIFICATION_ID = 1
private const val ACTION_START_FOREGROUND_SERVICE = "ACTION_START_FOREGROUND_SERVICE"
private const val ACTION_STOP_FOREGROUND_SERVICE = "ACTION_STOP_FOREGROUND_SERVICE"
fun startForegroundService(context: Context, message: String) {
val intent = Intent(context, ForegroundNotificationService::class.java).apply {
action = ACTION_START_FOREGROUND_SERVICE
putExtra("message", message)
}
ContextCompat.startForegroundService(context, intent)
}
fun stopForegroundService(context: Context) {
val intent = Intent(context, ForegroundNotificationService::class.java).apply {
action = ACTION_STOP_FOREGROUND_SERVICE
}
context.startService(intent)
}
}
override fun onCreate() {
super.onCreate()
createNotificationChannel()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
intent?.action?.let { action ->
when (action) {
ACTION_START_FOREGROUND_SERVICE -> {
val message = intent.getStringExtra("message") ?: "Foreground Service is running"
startForegroundNotification(message)
}
ACTION_STOP_FOREGROUND_SERVICE -> {
stopForegroundNotification()
stopSelf()
}
}
}
return START_STICKY
}
override fun onDestroy() {
super.onDestroy()
}
override fun onBind(intent: Intent?): IBinder? {
return null
}
private fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val serviceChannel = NotificationChannel(
CHANNEL_ID,
"Foreground Service Channel",
NotificationManager.IMPORTANCE_DEFAULT
).apply {
description = "Notification channel for foreground service"
}
val manager = getSystemService(NotificationManager::class.java)
manager.createNotificationChannel(serviceChannel)
}
}
private fun startForegroundNotification(message: String) {
val notification: Notification = NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Foreground Service")
.setContentText(message)
.setSmallIcon(R.drawable.ic_notification) // Replace with your notification icon
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setOngoing(true)
.build()
startForeground(NOTIFICATION_ID, notification)
}
private fun stopForegroundNotification() {
stopForeground(STOP_FOREGROUND_REMOVE)
}
}
3. ForegroundNotificationServicePlugin.kt:
package com.example.foreground_notification_service_plugin
import android.content.Context
import androidx.annotation.NonNull
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
class ForegroundNotificationServicePlugin: MethodCallHandler {
private lateinit var channel : MethodChannel
private lateinit var context: Context
fun registerWith(flutterEngine: FlutterEngine, context: Context) {
channel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "foreground_notification_service_plugin")
channel.setMethodCallHandler(this)
this.context = context.applicationContext
}
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
when (call.method) {
"startService" -> {
val message = call.argument<String>("message") as String? ?: "Foreground Service is running"
startForegroundNotificationService(message)
result.success(null)
}
"stopService" -> {
stopForegroundNotificationService()
result.success(null)
}
else -> {
result.notImplemented()
}
}
}
private fun startForegroundNotificationService(message: String) {
ForegroundNotificationService.startForegroundService(context, message)
}
private fun stopForegroundNotificationService() {
ForegroundNotificationService.stopForegroundService(context)
}
}
4. Plugin Registration in MainActivity (MainActivity.kt):
ForegroundNotificationServicePlugin().registerWith(flutterEngine, this)
5. Flutter Plugin Dart Code (foreground_notification_service_plugin.dart):
import 'dart:async';
import 'package:flutter/services.dart';
class ForegroundNotificationServicePlugin {
static const MethodChannel _channel =
const MethodChannel('foreground_notification_service_plugin');
static Future<void> startService({String message = "Foreground Service is running"}) async {
await _channel.invokeMethod('startService', <String, String>{
'message': message, // Message parameter for Android side
});
}
static Future<void> stopService() async {
await _channel.invokeMethod('stopService');
}
}
Usage in Flutter:
import 'package:foreground_notification_service_plugin/foreground_notification_service_plugin.dart';
// ... inside your Flutter code ...
ForegroundNotificationServicePlugin.startService(message: "Recording in progress..."); // Start service before recording
ForegroundNotificationServicePlugin.stopService(); // Stop service after recording is finished
Subject: Solution for Background Recording after Screen Lock using Foreground Service
Hello everyone,
Addressing the issue of background recording after the screen locks, as highlighted by Android documentation Android Foreground Services, apps need to utilize a foreground service for recording to continue in the background after Android 14.
The following code implementation successfully enabled background recording for me. It leverages a combination of a foreground service and necessary permissions.
Code Implementation:
1. AndroidManifest.xml:
<service android:name=".ForegroundNotificationService" android:foregroundServiceType="microphone" android:enabled="true" android:exported="false" android:label="Record Service" android:permission="android.permission.FOREGROUND_SERVICE_MICROPHONE"> 2. ForegroundNotificationService.kt:
import android.app.Notification import android.app.NotificationChannel import android.app.NotificationManager import android.app.Service import android.content.Context import android.content.Intent import android.os.Build import android.os.IBinder import androidx.core.app.NotificationCompat import androidx.core.content.ContextCompat
class ForegroundNotificationService : Service() {
companion object { private const val CHANNEL_ID = "ForegroundNotificationChannel" private const val NOTIFICATION_ID = 1 private const val ACTION_START_FOREGROUND_SERVICE = "ACTION_START_FOREGROUND_SERVICE" private const val ACTION_STOP_FOREGROUND_SERVICE = "ACTION_STOP_FOREGROUND_SERVICE" fun startForegroundService(context: Context, message: String) { val intent = Intent(context, ForegroundNotificationService::class.java).apply { action = ACTION_START_FOREGROUND_SERVICE putExtra("message", message) } ContextCompat.startForegroundService(context, intent) } fun stopForegroundService(context: Context) { val intent = Intent(context, ForegroundNotificationService::class.java).apply { action = ACTION_STOP_FOREGROUND_SERVICE } context.startService(intent) } } override fun onCreate() { super.onCreate() createNotificationChannel() } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { intent?.action?.let { action -> when (action) { ACTION_START_FOREGROUND_SERVICE -> { val message = intent.getStringExtra("message") ?: "Foreground Service is running" startForegroundNotification(message) } ACTION_STOP_FOREGROUND_SERVICE -> { stopForegroundNotification() stopSelf() } } } return START_STICKY } override fun onDestroy() { super.onDestroy() } override fun onBind(intent: Intent?): IBinder? { return null } private fun createNotificationChannel() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val serviceChannel = NotificationChannel( CHANNEL_ID, "Foreground Service Channel", NotificationManager.IMPORTANCE_DEFAULT ).apply { description = "Notification channel for foreground service" } val manager = getSystemService(NotificationManager::class.java) manager.createNotificationChannel(serviceChannel) } } private fun startForegroundNotification(message: String) { val notification: Notification = NotificationCompat.Builder(this, CHANNEL_ID) .setContentTitle("Foreground Service") .setContentText(message) .setSmallIcon(R.drawable.ic_notification) // Replace with your notification icon .setPriority(NotificationCompat.PRIORITY_DEFAULT) .setOngoing(true) .build() startForeground(NOTIFICATION_ID, notification) } private fun stopForegroundNotification() { stopForeground(STOP_FOREGROUND_REMOVE) }} 3. ForegroundNotificationServicePlugin.kt:
package com.example.foreground_notification_service_plugin
import android.content.Context import androidx.annotation.NonNull import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodChannel import io.flutter.plugin.common.MethodChannel.MethodCallHandler import io.flutter.plugin.common.MethodChannel.Result
class ForegroundNotificationServicePlugin: MethodCallHandler {
private lateinit var channel : MethodChannel private lateinit var context: Context fun registerWith(flutterEngine: FlutterEngine, context: Context) { channel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "foreground_notification_service_plugin") channel.setMethodCallHandler(this) this.context = context.applicationContext } override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) { when (call.method) { "startService" -> { val message = call.argument<String>("message") as String? ?: "Foreground Service is running" startForegroundNotificationService(message) result.success(null) } "stopService" -> { stopForegroundNotificationService() result.success(null) } else -> { result.notImplemented() } } } private fun startForegroundNotificationService(message: String) { ForegroundNotificationService.startForegroundService(context, message) } private fun stopForegroundNotificationService() { ForegroundNotificationService.stopForegroundService(context) }} 4. Plugin Registration in MainActivity (MainActivity.kt):
ForegroundNotificationServicePlugin().registerWith(flutterEngine, this) 5. Flutter Plugin Dart Code (foreground_notification_service_plugin.dart):
import 'dart:async'; import 'package:flutter/services.dart';
class ForegroundNotificationServicePlugin { static const MethodChannel _channel = const MethodChannel('foreground_notification_service_plugin');
static Future
startService({String message = "Foreground Service is running"}) async { await _channel.invokeMethod('startService', <String, String>{ 'message': message, // Message parameter for Android side }); } static Future
stopService() async { await _channel.invokeMethod('stopService'); } } Usage in Flutter: import 'package:foreground_notification_service_plugin/foreground_notification_service_plugin.dart';
// ... inside your Flutter code ...
ForegroundNotificationServicePlugin.startService(message: "Recording in progress..."); // Start service before recording ForegroundNotificationServicePlugin.stopService(); // Stop service after recording is finished
What about IOS ?