AudioRecorder.stop() is not saving file in linux
Package version
record: ^5.0.4 Flutter version 3.16.1
Environment
- OS: [Linux - Ubuntu 22.04.3 LTS]
Describe the bug
start is triggered, but when stop is requested the path returned does not contain the expected file
RecordConfig(encoder: rc.AudioEncoder.aacLc, numChannels: 1)
To Reproduce
Code:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_beep/flutter_beep.dart';
import 'package:path_provider/path_provider.dart';
import 'package:pocket/components/audio/recorder/recorder_layout.dart';
import 'package:pocket/components/audio/recorder/recorder_layout_desktop.dart';
import 'package:pocket/models/attachment.dart';
import 'package:pocket/redux/actions/action_creator.dart';
import 'package:pocket/redux/state.dart';
import 'package:pocket/streams/audio_stream.dart';
import 'package:pocket/utils/platform_manager.dart';
import 'package:record/record.dart' as rc;
class AudioRecorder extends StatefulWidget {
final String recordId;
final String sheetId;
final String columnKey;
final String attachmentMode;
final void Function(bool) isRecordingCallback;
final int maxSecondsDuration;
final AudioStream audioStream;
const AudioRecorder(
this.recordId,
this.sheetId,
this.columnKey,
this.attachmentMode,
this.isRecordingCallback,
this.audioStream, {
this.maxSecondsDuration = 300,
Key? key,
}) : super(key: key);
@override
State<AudioRecorder> createState() => _AudioRecorderState();
}
class _AudioRecorderState extends State<AudioRecorder> {
final rc.AudioRecorder audioRecorder = rc.AudioRecorder();
rc.RecordState recordState = rc.RecordState.stop;
Timer? timer;
int recordDuration = 0;
double? maxSoundWavesWidth;
late String audioRecordId;
@override
void initState() {
super.initState();
audioRecordId = DateTime.now().millisecondsSinceEpoch.toString();
checkPermission().then((bool permission) {
if (!permission) return;
recordState = rc.RecordState.record;
audioRecorder.onStateChanged().listen((rc.RecordState recordState) {
if (mounted) {
setState(() {
this.recordState = recordState;
if (recordState != rc.RecordState.stop) {
widget.audioStream.updateStatus(AudioStreamState.isRecording);
return widget.isRecordingCallback(true);
}
widget.audioStream.updateStatus(AudioStreamState.none);
widget.isRecordingCallback(false);
});
}
});
start();
});
}
@override
void dispose() {
timer?.cancel();
audioRecorder.dispose();
super.dispose();
}
Future<bool> checkPermission() async {
bool permission = await audioRecorder.hasPermission();
widget.isRecordingCallback(permission);
return permission;
}
@override
Widget build(BuildContext context) {
if (PlatformManager.isDesktop())
return RecorderLayoutDesktop(
audioRecorder,
recordDuration,
recordState: recordState,
onSend: () => stop(),
onDiscard: () => discard(),
);
return RecorderLayout(
audioRecorder,
recordDuration,
recordState: recordState,
onSend: () => stop(),
onDiscard: () => discard(),
);
}
Future<void> discard() async {
timer?.cancel();
recordDuration = 0;
await audioRecorder.stop();
}
Future<void> start() async {
try {
if (await audioRecorder.hasPermission()) {
const config =
rc.RecordConfig(encoder: rc.AudioEncoder.aacLc, numChannels: 1);
String path = await getPath();
await recordFile(audioRecorder, config, path);
recordDuration = 0;
}
} catch (e) {
return null;
}
}
Future<void> stop() async {
timer?.cancel();
recordDuration = 0;
String? path = await audioRecorder.stop();
if (path == null) return;
File file = File(filePath);
// Verifica se o arquivo existe
if (file.existsSync()) {
print('YES');
} else {
print('NOT');
}
}
void startTimer() {
timer?.cancel();
timer = Timer.periodic(const Duration(seconds: 1), (Timer t) async {
setState(() {
recordDuration++;
});
if (recordDuration >= widget.maxSecondsDuration) {
FlutterBeep.beep();
await stop();
}
});
}
Future<void> recordFile(
rc.AudioRecorder recorder,
rc.RecordConfig config,
String path,
) async {
await recorder.start(config, path: path);
}
Future<String> getPath() async {
String audioExtension = '.m4a';
String dir = '';
dir = (await getApplicationDocumentsDirectory()).path;
String path = dir + '/' + audioRecordId + audioExtension;
return path;
}
}
Log:
flutter: AudioPlayers Exception: AudioPlayerException( DeviceFileSource(path: /home/anderson/Documentos/1704232220808.m4a), PlatformException(LinuxAudioError, Failed to set source. For troubleshooting, see: https://github.com/bluefireteam/audioplayers/blob/main/troubleshooting.md, Unable to set the pipeline from GST_STATE_READY to GST_STATE_PAUSED., null) [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: PlatformException(LinuxAudioError, Failed to set source. For troubleshooting, see: https://github.com/bluefireteam/audioplayers/blob/main/troubleshooting.md, Unable to set the pipeline from GST_STATE_READY to GST_STATE_PAUSED., null)
@tiagogoncalves this error is from AudioPlayers, the problem of Issue is happening before that, the file is not being saved, so the player cannot find it along the way
Well..., I'm completely blind on Linux platform as I don't have any instance of it. Can you ensure that record_linux is set to 0.7.1 in your pubspec.lock?
fmedia seems to start, otherwise you would obtain an exception so it may be related to parameters.
But I can't find any break in changelog or documentation.
Also what is the version of fmedia? I started to implement linux platform with v1.27
Finally, when the recording is started do you see the incoming file at your given path?
@llfbandit I will test the 0.7.1 version that you requested
'Also what is the version of fmedia?' fmedia is v1.31 (linux-amd64)
'Finally, when the recording is started do you see the incoming file at your given path?' No, I tested for other path/dir and didn't find them either
In my case, first run created file but second run not. I think this happen because first run somehow break process. But I discovered that such command [ '--record', '-o', _path, '-y', '--globcmd=listen'], ['--globcmd=stop'] work well
Is there any issue on Linux platform? If so, can you fill a PR to update it?
We are also facing the same issue.
After record.stop() is called, - On Android: The recorded file exists as recordedFile.existsSync() returns true. - On Linux Desktop: The recorded file does not exist as recordedFile.existsSync() returns false.
import 'package:path_provider/path_provider.dart';
import 'dart:io';
final record = Record();
Future<void> startRecording() async {
if (await record.hasPermission()) {
final tempDir = await getTemporaryDirectory();
await record.start(path: '${tempDir.path}/voice.m4a');
}
}
Future<File?> stopRecording() async {
final path = await record.stop();
if (path != null) {
final recordedFile = File(path);
return recordedFile;
}
return null;
}
void main() async {
await startRecording();
// Record audio for some time
final recordedFile = await stopRecording();
if (recordedFile != null && recordedFile.existsSync()) {
print('File exists at: ${recordedFile.path}');
} else {
print('File does not exist.');
}
}```
the file does exist but is not accessible...problem should be fixed when my pull request is merged.
record_linux 0.7.2 has just been published with the fix above.