flutter_soloud
flutter_soloud copied to clipboard
fix: Unable to play audio when used with `flutter_recorder` on iOS
First of all, thanks for creating this wonderful package.
I'm having trouble using this package with your flutter_recorder package, on iOS (haven't tested on Android).
If I call Recorder.instance.init() on any point, I'm unable to play any audio using SoLoud after that point.
Calling Recorder.instance.deinit() also doesn't work.
Here's a minimal reproducible example. "Play Sound" button doesn't work. It works when I comment out Recorder.instance.init().
import 'package:flutter/material.dart';
import 'package:flutter_recorder/flutter_recorder.dart';
import 'package:flutter_soloud/flutter_soloud.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await SoLoud.instance.init();
await Recorder.instance.init();
runApp(const _App());
}
class _App extends StatelessWidget {
const _App();
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
),
home: const _Page(),
);
}
}
class _Page extends StatefulWidget {
const _Page();
@override
State<_Page> createState() => _PageState();
}
class _PageState extends State<_Page> {
AudioSource? _audioSource;
@override
void initState() {
_initSound();
super.initState();
}
void _initSound() async {
_audioSource = await SoLoud.instance.loadAsset('assets/sample.mp3');
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Wrap(
alignment: WrapAlignment.center,
runAlignment: WrapAlignment.center,
crossAxisAlignment: WrapCrossAlignment.center,
children: [
TextButton(
onPressed: () {
SoLoud.instance.play(_audioSource!);
},
child: Text('Play Sound'),
),
TextButton(
onPressed: () {
Recorder.instance.start();
Recorder.instance.startStreamingData();
},
child: Text('Start Recording(Streaming)'),
),
TextButton(
onPressed: () {
Recorder.instance.stop();
Recorder.instance.stopStreamingData();
},
child: Text('Stop Recording(Streaming)'),
),
],
),
),
);
}
}
Using the audioplayers package with flutter_recorder works, which I suspect it is package-specific problem. Maybe it comes from both packages using the same miniaudio engine benath the surface? I've also tried audio session management with audio_session package, but that didn't help.
Additional Context Using the below latest versions: flutter_soloud: 3.1.3 flutter_recorder: 1.1.0
Hi @MinseokKang003,
I tried your code only on the simulator without problems (I don't have an iPhone).
Can you please try to use the Logging package to see if we can get some info? Just put this code at the beginning of main():
import 'dart:developer' as dev;
void main() async {
WidgetsFlutterBinding.ensureInitialized();
Logger.root.level = Level.FINE;
Logger.root.onRecord.listen((record) {
dev.log(
record.message,
time: record.time,
level: record.level.value,
name: record.loggerName,
zone: record.zone,
error: record.error,
stackTrace: record.stackTrace,
);
});
await SoLoud.instance.init();
await Recorder.instance.init();
runApp(const _App());
}
Have you tried your code on the simulator also?
Hi @alnitak, thanks for the swift response.
I've tried on the simulator and it doesn't have any problems there. But it still doesn't work on the actual iPhone device.
Here's a recording: https://github.com/user-attachments/assets/17aa227b-209e-4130-be7a-5f38d7531c82
You can see the "Play Sound" button doesn't work, and also pressing the volume up and down button on the device doesn't have any effects and also doesn't show the volume slider. Control Center also shows that the sound is disabled.
Also, no error logs were printed. Here's the full log:
Connecting to VM Service at ws://127.0.0.1:50351/TsBoYhdQmWA=/ws
Connected to the VM Service.
[flutter_soloud.SoLoudLoader_io] Temporary directory initialized at /Users/minseokkang/Library/Developer/CoreSimulator/Devices/080FD2A1-2DEB-4B22-B63B-813177F6E66C/data/Containers/Data/Application/D8D1B7C3-0D07-4F0A-8D6C-380D98157B5E/Library/Caches/SoLoudLoader-Temp-Files
Logs from simulator and iPhone with log Level.ALL:
Simulator(iOS 18.2)
Connecting to VM Service at ws://127.0.0.1:57903/ngB7xn8foi0=/ws
Connected to the VM Service.
[flutter_soloud.SoLoud] init() called
[flutter_soloud.SoLoudLoader_io] initialize() called
[flutter_soloud.FlutterSoLoudFfi] STATE CHANGED EVENT state: PlayerStateNotification.started
[flutter_soloud.SoLoudLoader_io] Temporary directory initialized at /Users/minseokkang/Library/Developer/CoreSimulator/Devices/080FD2A1-2DEB-4B22-B63B-813177F6E66C/data/Containers/Data/Application/8F550A9E-0D55-494B-954B-830A06850057/Library/Caches/SoLoudLoader-Temp-Files
[flutter_soloud.FlutterSoLoudFfi] FILE LOADED EVENT error: noError hash: 760801729 file: /Users/minseokkang/Library/Developer/CoreSimulator/Devices/080FD2A1-2DEB-4B22-B63B-813177F6E66C/data/Containers/Data/Application/8F550A9E-0D55-494B-954B-830A06850057/Library/Caches/SoLoudLoader-Temp-Files/temp-sound-asset-0xc1045dd
iPhone 13 Pro(iOS 18.4)
Connecting to VM Service at ws://127.0.0.1:58213/uOo3s33Zc7M=/ws
Connected to the VM Service.
[flutter_soloud.SoLoud] init() called
[flutter_soloud.SoLoudLoader_io] initialize() called
[flutter_soloud.FlutterSoLoudFfi] STATE CHANGED EVENT state: PlayerStateNotification.started
[flutter_soloud.SoLoudLoader_io] Temporary directory initialized at /var/mobile/Containers/Data/Application/0D9D1EF0-AEE3-46DD-AE29-B740DB8385C7/Library/Caches/SoLoudLoader-Temp-Files
[flutter_soloud.FlutterSoLoudFfi] STATE CHANGED EVENT state: PlayerStateNotification.rerouted
[flutter_soloud.FlutterSoLoudFfi] FILE LOADED EVENT error: noError hash: 1085802880 file: /var/mobile/Containers/Data/Application/0D9D1EF0-AEE3-46DD-AE29-B740DB8385C7/Library/Caches/SoLoudLoader-Temp-Files/temp-sound-asset-0xc1045dd
PlayerStateNotification.rerouted is additionally called on the iPhone, so that might be the difference?
Indeed, the rerouted is suspicious.
...and also doesn't show the volume slider. Control Center also shows that the sound is disabled.
also this makes me think! It seems that OS switches the output device but I can't really tell why. Is the sound actually reproduced? You can add a button to print this value SoLoud.instance.getPosition(_audioSource!.handles.first);.
Have you also added and asked for microphone permission in your app? Maybe this could change something.
Please let me know of any news!
Yes I have added NSMicrophoneUsageDescription.
I also found that on iOS, when AVAudioSessionCategory switches to .record, the volume slider becomes disabled.
Maybe flutter_recorder plugin is switching the audio session category to .record on init(), and flutter_soloud doesn't switch it back to .playback automatically.
If I change flutter_recorder plugin's src/capture.cpp code from:
deviceConfig = ma_device_config_init(ma_device_type_capture);
to:
deviceConfig = ma_device_config_init(ma_device_type_duplex);
The volume slider is shown but audio still doesn't play.
When I call print(SoLoud.instance.getPosition(_audioSource!.handles.first)); while the sound is playing (with no audio outputs and volume slider disabled), it does print the duration. However the duration does not change and it is stuck at the latest position right before calling recorder.init().
Sorry I can't help as I don't have an iPhone. Hope this gets solved!
Some time ago, I wrote a walky-talky like example to use both plugins. Maybe the pubspec.yaml should be updated with the new plugin versions. Maybe it will not work too, but if you wish to give it a try here the link.
Sure, I'll test it and hopefully try to figure it out. Thanks!
Hi @MinseokKang003, any luck? I am facing the same issue on iOS
The workaround I found is to do the following (although it's not really ideal):
// before starting playing audio via soloud:
recorder.deinit();
await solout.init();
// before starting recording audio via the recorder:
await recorder.init();
solout.deinit();
I have this issue also and it is a major blocker. @alnitak I will personally buy you an iphone to test on if you help me fix this. Thanks for all you have done with this package it has come a long way.
btw, anyone able to do step-level debugging on iOS for FFI like this? I'm able to step into soloud on android but this is an iOS only issue, very annoying.
#257 will probably fix this. I'll test it out later.
I have this issue also and it is a major blocker. @alnitak I will personally buy you an iphone to test on if you help me fix this.
I really touched! Thanks a billion, but let's wait the PR 257 if it helps :)
anyone able to do step-level debugging on iOS for FFI like this?
to debug C code on iOS, you have to debug using XCode, which is really unpleasant!
I have this issue also and it is a major blocker. @alnitak I will personally buy you an iphone to test on if you help me fix this.
I really touched! Thanks a billion, but let's wait the PR 257 if it helps :)
anyone able to do step-level debugging on iOS for FFI like this?
to debug C code on iOS, you have to debug using XCode, which is really unpleasant!
I haven't been able to get the xcode step-through to initialize. I'll keep poking.
This is still an issue for me @MinseokKang003 were you able to get this working?
Perhaps a hint:
objc[5049]: Class ma_ios_notification_handler is implemented in both /private/var/containers/Bundle/Application/3C62ACBF-C3FE-4133-BCA8-E857BA975F66/Runner.app/Frameworks/flutter_soloud.framework/flutter_soloud (0x105dec740) and /private/var/containers/Bundle/Application/3C62ACBF-C3FE-4133-BCA8-E857BA975F66/Runner.app/Frameworks/flutter_recorder.framework/flutter_recorder (0x1058485c8). This may cause spurious casting failures and mysterious crashes. One of the duplicates must be removed or renamed.
no idea if related.
Tried renaming the notification handler class in miniaudio.h of flutter_recorder but doesn't work. Was able to hook into debugger, but not sure what to slice at yet.
Not sure why, but I was able to get the intended behavior if I initialized flutter_recorder first, just once, before initializing flutter_soloud. Seems to be working, will write up more context tomorrow.
Hi, I have a related issue I think. I'm using https://pub.dev/packages/speech_to_text, and immediately after it starts recording, I see this line in the logs:
[flutter_soloud.FlutterSoLoudFfi] STATE CHANGED EVENT state: PlayerStateNotification.rerouted
Afterwards, I'm unable to play any audio without using
solout.deinit();
await solout.init();
hackery.
I have the same problem. I'm building app for real time communication with ElevenLabs. I'm using flutter_soloud for playing audio and flutter_recorder for streaming audio from mic to the ElevenLabs. Everything is working fine on Android, but on iOS I have described problem from this issue. Is there any fix for this?
Unfortunately I still don't have an iPhone to test and try to find a solution.