record icon indicating copy to clipboard operation
record copied to clipboard

AudioRecorder.stop() is not saving file in linux

Open Mrprey opened this issue 2 years ago • 5 comments

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)

Mrprey avatar Jan 02 '24 22:01 Mrprey

image

tiagogoncalves avatar Jan 02 '24 22:01 tiagogoncalves

@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

Mrprey avatar Jan 03 '24 12:01 Mrprey

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 avatar Jan 18 '24 14:01 llfbandit

@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

Mrprey avatar Jan 18 '24 15:01 Mrprey

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

pandora-house avatar Mar 12 '24 08:03 pandora-house

Is there any issue on Linux platform? If so, can you fill a PR to update it?

llfbandit avatar May 21 '24 11:05 llfbandit

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.');
  }
}```

Vinayak006 avatar May 29 '24 05:05 Vinayak006

the file does exist but is not accessible...problem should be fixed when my pull request is merged.

TheOther255 avatar Jun 26 '24 07:06 TheOther255

record_linux 0.7.2 has just been published with the fix above.

llfbandit avatar Jun 26 '24 12:06 llfbandit