Goodday, i have been trying to record audio in the app background using flutter_background service but the record controller keeps saying ' LateInitializationError: Field 'recorderController' has not been initialized'.
i'm using audio_waveforms to record audio and here is the package https://pub.dev/packages/audio_waveforms
trying to record audio in app background
'import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:ui';
import 'package:audio_waveforms/audio_waveforms.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:ffmpeg_kit_flutter/ffmpeg_kit.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:headset_connection_event/headset_event.dart';
import 'package:path_provider/path_provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:speakbit/pages/navbar.dart';
import 'package:intl/intl.dart';
import 'package:speakbit/pages/recorder.dart';
import 'package:speakbit/pages/splash.dart';
import 'package:firebase_core/firebase_core.dart';
import
'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:flutter_background_service/flutter_background_service.dart';
import 'package:flutter_background_service/flutter_background_service.dart';
import 'package:flutter_background_service_android/flutter_background_service_android.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:speakbit/providers/riverpod/backgroundplayProvider.dart';
import 'package:permission_handler/permission_handler.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
await Permission.microphone.request();
await initializeService();
runApp(const MyApp());
}
final _headsetPlugin = HeadsetEvent();
HeadsetState? _headsetState;
late Directory directory;
String endtime = '';
String? path2;
// _getDir() async {
// directory = (await getApplicationDocumentsDirectory());
// // var file = File(directory.path).path;
// path2 =
"${directory.path}/test${DateTime.now().toIso8601String()}.m4a";
// print('this is path 2:${path2}');
// }
late final RecorderController recorderController;
Future<void> initializeService() async {
endtime = DateFormat("hh:mm").format(DateTime.now());
final service = FlutterBackgroundService();
/// OPTIONAL, using custom notification channel id
AndroidNotificationChannel channel = const
AndroidNotificationChannel(
'my_foreground', // id
'MY FOREGROUND SERVICE', // title
// description
importance: Importance.low, // importance must be at low or higher level
);
final FlutterLocalNotificationsPlugin
flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
if (Platform.isIOS) {
await flutterLocalNotificationsPlugin.initialize(
const InitializationSettings(iOS:
DarwinInitializationSettings()),
);
}
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
await service.configure(
androidConfiguration: AndroidConfiguration(
// this will be executed when app is in foreground or background in separated isolate
onStart: onStart,
// auto start service
autoStart: true,
isForegroundMode: true,
notificationChannelId: 'my_foreground',
initialNotificationTitle: 'SpeakBit SERVICE',
initialNotificationContent: 'Initializing',
foregroundServiceNotificationId: 888,
),
iosConfiguration: IosConfiguration(
// auto start service
autoStart: true,
// this will be executed when app is in foreground in separated isolate
onForeground: onStart,
// you have to enable background fetch capability on xcode project
onBackground: onIosBackground,
),
);
service.startService();
}
@pragma('vm:entry-point')
Future<bool> onIosBackground(ServiceInstance service) async {
WidgetsFlutterBinding.ensureInitialized();
DartPluginRegistrant.ensureInitialized();
return true;
}
@pragma('vm:entry-point')
void onStart(ServiceInstance service) async {
recorderController = RecorderController()
..androidEncoder = AndroidEncoder.aac
..androidOutputFormat = AndroidOutputFormat.mpeg4
..iosEncoder = IosEncoder.kAudioFormatMPEG4AAC
..sampleRate = 16000;
bool isRecording = false;
// Only available for flutter 3.0.0 and later
DartPluginRegistrant.ensureInitialized();
// For flutter prior to version 3.0.0
// We have to register the plugin manually
/// OPTIONAL when use custom notification
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
if (service is AndroidServiceInstance) {
service.on('setAsForeground').listen((event) {
service.setAsForegroundService();
});
service.on('setAsBackground').listen((event) {
service.setAsBackgroundService();
});
}
service.on('stopService').listen((event) {
service.stopSelf();
});
// bring to foreground
Timer.periodic(const Duration(seconds: 10), (timer) async {
if (service is AndroidServiceInstance) {
if (await service.isForegroundService()) {
// _headsetPlugin.getCurrentState.then((val) async {
// if (val == HeadsetState.CONNECT) {
bplay().getDir();
bplay().startOrStopRecording();
// SUCCESS
}
// }
// });
/// OPTIONAL for use custom notification
/// the notification id must be equals with AndroidConfiguration when you call configure() method.
flutterLocalNotificationsPlugin.show(
888,
'COOL SERVICE',
'Recording',
// ignore: prefer_const_constructors
NotificationDetails(
// ignore: prefer_const_constructors
android: AndroidNotificationDetails(
'my_foreground',
'SpeakBit SERVICE',
icon: 'ic_bg_service_small',
ongoing: true,
),
),
);
// if you don't using custom notification, uncomment this
// service.setForegroundNotificationInfo(
// title: "My App Service",
// content: "Recording",
// );
}
/// you can see this log in logcat
// test using external plugin
});
final deviceInfo = DeviceInfoPlugin();
String? device;
if (Platform.isAndroid) {
final androidInfo = await deviceInfo.androidInfo;
device = androidInfo.model;
}
if (Platform.isIOS) {
final iosInfo = await deviceInfo.iosInfo;
device = iosInfo.model;
}
service.invoke(
'update',
{
"current_date": DateTime.now().toIso8601String(),
"device": device,
},
);
}
and this is the bplay class
import 'dart:async';
import 'package:audio_waveforms/audio_waveforms.dart';
import 'package:ffmpeg_kit_flutter/ffmpeg_kit.dart';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'package:riverpod/riverpod.dart';
import 'package:intl/intl.dart';
import 'package:permission_handler/permission_handler.dart';
import '../../main.dart';
import '../../pages/recorder.dart';
class bplay {
bplay();
var audiosuper;
late final RecorderController recorderController;
String? path2;
getDir() async {
directory = (await getApplicationDocumentsDirectory());
// var file = File(directory.path).path;
path2 = "${directory.path}/test${DateTime.now().toIso8601String()}.m4a";
print('this is path 2:${path2}');
}
initialiseControllers()async {
if (await Permission.microphone.request().isGranted) {
recorderController = RecorderController()
..androidEncoder = AndroidEncoder.aac
..androidOutputFormat = AndroidOutputFormat.mpeg4
..iosEncoder = IosEncoder.kAudioFormatMPEG4AAC
..sampleRate = 16000;
}
}
void startOrStopRecording() async {
await recorderController.record(path: path2);
final timer = Timer(Duration(seconds: 10), () async {
final path = await recorderController.stop(false);
if (path != null) {
await audioconverter(path);
}
recorderController.setRefresh(false);
recorderController.reset();
}).cancel();
}
Future audioconverter(String audio) async {
String output1 = '${audio + '.wav'}';
String command = ' -i ${audio} -af "afftdn=nf=-75:tn=1:nr=30" ${output1}';
await FFmpegKit.execute(command).then((value) async {
if (output1 != null) {
var audiosuper = output1;
var now = DateTime.now();
var formatter = DateFormat(' d MMM, yyyy');
var endtime = DateFormat("hh:mm").format(DateTime.now());
var formattedDate = formatter.format(now);
audioList.add(
{
'audio': audiosuper,
'date': formattedDate,
'time': endtime,
'super': audiosuper
},
);
}
// SUCCESS
});
}
}
Change
late final RecorderController recorderController;
to
final RecorderController recorderController = RecorderController();