I have an app that records audio when the user taps a button. It writes a temporary file to the mobile device, then runs some FFMPEG code to change the pitch.
The normal way a user would use it is:
- Tap the button
- Record the audio (10 seconds)
- After recording is done, play back the audio with the pitch modified
This works fine when I do it once, but when I do it a second time (after playback has completely finished), I can record another audio file but my console says there was a source error for playback. I'm not sure why it can do it once but not twice. I feel as though the issue might be something with async/await. I don't fully understand when to use it so I try to avoid it, but Android Studio forced me to use it for the line final List<FileSystemEntity> files = await dir.list().toList(); and then I added it everywhere else that I thought kinda made sense but honestly it's a mess...
void startTapRecording() {
print('##MyApp## startTapRecording: 1');
controller?.stop();
controller?.reset();
cancelTimer();
print('##MyApp## startTapRecording: 2');
stopPlaying();
stopRecording();
final String filename = getNewMyAppAudioFileID();
setState(() {
currentMyAppFilename = filename;
});
startRecordingTimer();
print('##MyApp## startTapRecording: 3');
startRecording(MyAppsInProgressFileDir.path + currentMyAppFilename);
controller?.forward();
print('##MyApp## startTapRecording: 4 (finished)');
}
void startRecording(String filename) async {
print('##MyApp## startRecording: 1');
// Request Microphone permission if needed
await cleanupTempAudioFiles();
print('##MyApp## startRecording: 2');
PermissionStatus status = await Permission.microphone.request();
if (status != PermissionStatus.granted) {
throw RecordingPermissionException("Microphone permission not granted");
}
await myRecorder.startRecorder(toFile: filename);
print('##MyApp## startRecording: 3 (finished)');
}
Future<void> cleanupTempAudioFiles() async {
print('##MyApp## cleanupTempAudioFiles: 1');
final dir = Directory(MyAppsInProgressFileDir.path);
final List<FileSystemEntity> files = await dir.list().toList();
print('##MyApp## cleanupTempAudioFiles: 2 ');
files.forEach((file) async {
print('##MyApp## cleanupTempAudioFiles: file.path = ' + file.path);
if (file.path == MyAppsInProgressFileDir.path + currentMyAppFilename) {
await file.delete();
print('##MyApp## cleanupTempAudioFiles: file deleted');
}
if (file.path == MyAppsInProgressFileDir.path + currentMyAppFilename + 'High.mp3') {
await file.delete();
print('##MyApp## cleanupTempAudioFiles: file deleted High.mp3');
}
if (file.path == MyAppsInProgressFileDir.path + currentMyAppFilename + 'Low.mp3') {
await file.delete();
print('##MyApp## cleanupTempAudioFiles: file deleted Low.mp3');
}
});
print('##MyApp## cleanupTempAudioFiles: 3 (finished)');
}
Logcat output, filtered on ##MyApp##:
##MyApp## startTapRecording: 1
##MyApp## startTapRecording: 2
##MyApp## startTapRecording: 3
##MyApp## startRecording: 1
##MyApp## cleanupTempAudioFiles: 1
##MyApp## startTapRecording: 4 (finished)
##MyApp## cleanupTempAudioFiles: 2
##MyApp## cleanupTempAudioFiles: file.path = /data/user/0/com.example.MyApp_3/code_cache/MyApp/MyAppAudioFiles/MyAppsInProgress/MyAppAudioFile1
##MyApp## cleanupTempAudioFiles: file.path = /data/user/0/com.example.MyApp_3/code_cache/MyApp/MyAppAudioFiles/MyAppsInProgress/MyAppAudioFile1High.mp3
##MyApp## cleanupTempAudioFiles: 3 (finished)
##MyApp## startRecording: 2
##MyApp## cleanupTempAudioFiles: file deleted
##MyApp## cleanupTempAudioFiles: file deleted High.mp3
##MyApp## startRecording: 3 (finished)
##MyApp## handleTimeout sendableMyAppExists: 1
##MyApp## runFFMPEGHighLow
##MyApp## startTapRecording: 1
##MyApp## startTapRecording: 2
##MyApp## startTapRecording: 3
##MyApp## startRecording: 1
##MyApp## cleanupTempAudioFiles: 1
##MyApp## startTapRecording: 4 (finished)
##MyApp## cleanupTempAudioFiles: 2
##MyApp## cleanupTempAudioFiles: file.path = /data/user/0/com.example.MyApp_3/code_cache/MyApp/MyAppAudioFiles/MyAppsInProgress/MyAppAudioFile1
##MyApp## cleanupTempAudioFiles: file.path = /data/user/0/com.example.MyApp_3/code_cache/MyApp/MyAppAudioFiles/MyAppsInProgress/MyAppAudioFile1High.mp3
##MyApp## cleanupTempAudioFiles: 3 (finished)
##MyApp## startRecording: 2
##MyApp## cleanupTempAudioFiles: file deleted
##MyApp## cleanupTempAudioFiles: file deleted High.mp3
##MyApp## startRecording: 3 (finished)
##MyApp## handleTimeout sendableMyAppExists: 1
##MyApp## runFFMPEGHighLow
The error in the console:
E/ExoPlayerImplInternal(20582): Playback error
E/ExoPlayerImplInternal(20582): com.google.android.exoplayer2.ExoPlaybackException: Source error
E/ExoPlayerImplInternal(20582): at com.google.android.exoplayer2.ExoPlayerImplInternal.handleIoException(ExoPlayerImplInternal.java:624)
E/ExoPlayerImplInternal(20582): at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:594)
E/ExoPlayerImplInternal(20582): at android.os.Handler.dispatchMessage(Handler.java:102)
E/ExoPlayerImplInternal(20582): at android.os.Looper.loopOnce(Looper.java:226)
E/ExoPlayerImplInternal(20582): at android.os.Looper.loop(Looper.java:313)
E/ExoPlayerImplInternal(20582): at android.os.HandlerThread.run(HandlerThread.java:67)
E/ExoPlayerImplInternal(20582): Caused by: com.google.android.exoplayer2.source.UnrecognizedInputFormatException: None of the available extractors (Mp3Extractor, FlvExtractor, FlacExtractor, WavExtractor, FragmentedMp4Extractor, Mp4Extractor, AmrExtractor, PsExtractor, OggExtractor, TsExtractor, MatroskaExtractor, AdtsExtractor, Ac3Extractor, Ac4Extractor, JpegExtractor) could read the stream.
E/ExoPlayerImplInternal(20582): at com.google.android.exoplayer2.source.BundledExtractorsAdapter.init(BundledExtractorsAdapter.java:92)
E/ExoPlayerImplInternal(20582): at com.google.android.exoplayer2.source.ProgressiveMediaPeriod$ExtractingLoadable.load(ProgressiveMediaPeriod.java:1025)
E/ExoPlayerImplInternal(20582): at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:409)
E/ExoPlayerImplInternal(20582): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
E/ExoPlayerImplInternal(20582): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
E/ExoPlayerImplInternal(20582): at java.lang.Thread.run(Thread.java:920)
E/AudioPlayer(20582): TYPE_SOURCE: None of the available extractors (Mp3Extractor, FlvExtractor, FlacExtractor, WavExtractor, FragmentedMp4Extractor, Mp4Extractor, AmrExtractor, PsExtractor, OggExtractor, TsExtractor, MatroskaExtractor, AdtsExtractor, Ac3Extractor, Ac4Extractor, JpegExtractor) could read the stream.
I/ExoPlayerImpl(20582): Release cc7756c [ExoPlayerLib/2.15.0] [o1q, SM-G991U, samsung, 31] [goog.exo.core]
E/flutter (20582): [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: (0) Source error
E/flutter (20582): #0 AudioPlayer._load (package:just_audio/just_audio.dart:798:9)
E/flutter (20582): <asynchronous suspension>
E/flutter (20582): #1 AudioPlayer._setPlatformActive.setPlatform (package:just_audio/just_audio.dart:1365:28)
E/flutter (20582): <asynchronous suspension>
E/flutter (20582):