Reputation: 2471
I am creating a Flutter plugin. Currently, the code:
When I run the application in Android, it perfectly works. Nevertheless, when I run it on iOS, it does not (assuming relates permissions/restrictions)
await flutterTts
.synthesizeToFile(
"This is my first audio synthesizer in Flutter", audioFileName)
.then((success) => {
if (success == 1)
{
print('Successfully synthesized!!'),
// Gets the path to the generated file depending on the platform
pathFile =
Platform.isAndroid ? pathToFileAndroid : pathToFileIos,
pathFile
.then((pathToAudioFile) => {
print('Path to file: ' + pathToAudioFile),
// Speakers/earpiece
// int result = await player.earpieceOrSpeakersToggle();
// Sets the path to the file
audioPlayer.setUrl(pathToAudioFile),
audioPlayer.setVolume(1.0),
// Gets the duration of the audio file to be reproduced
// Plays the audio file
playLocal(audioPlayer, pathToAudioFile),
}) // pathFile
.catchError((e) {
print('Error: Unable to get the path to the audio file');
}),
}, // success
}) //synthesizeToFile
.catchError((e) {
print('Error during the synthesisation: $e');
});
}
/// Gets the path to the file to be accessed (iOS)
static Future<String> get pathToFileIos async {
Directory appDocDir = await getApplicationDocumentsDirectory();
String appDocPath = appDocDir.path;
print('appDocPath: $appDocPath');
return '$appDocPath/$audioFileName';
}
I implemented audioPlayer.onDurationChanged.listen
to confirm that the path to the file is the correct one (it actually gets the duration of the file). Nevertheless, the file is not played.
I am using a simulator to test the application, and this is the path where the file is stored
/localPaty/Devices/deviceID/data/Containers/Data/Application/appID/Documents/temp_audio_cue.caf
I read different questions regarding this topic, but I did not find a solution for my case
I have tried:
Editing Transport security as the documentation recommends
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
Using AudioCache
(question)
Anyone has any other suggestion? Do I need to move the file to my local assets and use AudioCache
to reproduce the file?
Update
I have also tried to add the flag isLocal
.
playLocal() async {
int result = await audioPlayer.play(localPath, isLocal: true);
}
According to the documentation is is needed cause
The isLocal flag is required only because iOS and macOS make a difference about it
It returns 1
, so I guess that it means success, but the sound is still not triggered. Could be the simulator failing?
"iOS => call startHeadlessService, playerId ID"
"iOS => call setUrl, playerId ID"
"iOS => call setVolume, playerId ID"
"iOS => call play, playerId ID"
2021-02-03 11:59:33.149925+0100 Runner[61496:850044] flutter: Played successfully?: 1
I have also tested to call playLocal()
with a wrong path. It keeps returning 1
but after it it displays the following error:
FigFileForkOpenMainByCFURL signalled err=2 (errno) (open failed)
Nevertheless, the error is not triggered with calling the method with the correct localPath
so I assume it should be playing it correctly.
Note
If instead of calling playLocal()
, I call flutter_tts.speak('test')
, it works. Therefore, the error should probably be related to audioplayers
.
The versions that I am using are flutter_tts ^2.1.0
and audioplayers: ^0.17.3
Upvotes: 2
Views: 7056
Reputation: 98
final AudioContext audioContext = AudioContext(
iOS: AudioContextIOS(
defaultToSpeaker: true,
category: AVAudioSessionCategory.ambient,
options: [
AVAudioSessionOptions.defaultToSpeaker,
AVAudioSessionOptions.mixWithOthers,
],
),
android: AudioContextAndroid(
isSpeakerphoneOn: true,
stayAwake: true,
contentType: AndroidContentType.sonification,
usageType: AndroidUsageType.assistanceSonification,
audioFocus: AndroidAudioFocus.none,
),
);
AudioPlayer.global.setGlobalAudioContext(audioContext);
Add this in you main.dart file before this runApp(App());
Upvotes: 8
Reputation: 1
Use play() method instead of playBytes() while working with IOS. int result=0; if(Platform.isIOS){ result = await player.play("Audio url",isLocal: false); }
Upvotes: 0
Reputation: 1267
Today I've fixed this way. I was using audio from the URL and I was using this line
var res = await audioPlayer.play(url, isLocal: true);
I've to use this below line into my code
var res = await audioPlayer.play(url, isLocal: false);
isLocal
stands for your file is stored locally or not. if the file is stored remotely which means in the form of URL then set to isLocal:false
.
hope it solves your problem.
Upvotes: 0
Reputation: 7289
When you play sounds with audio players and use flutter_tts to say words, it makes flutter_tts dysfunctional on iOS
Thus, only one of the package works, but as soon as both are used at the same time, tts stops working after a while. Sometimes it lasts longer, but sometimes it stops immediately.
In reality ,this is due to a conflict on the iOS side.
Assuming it works on Android, that means there shouldn't be a problem in your code.
Another alternative would have to be found .
Upvotes: 0
Reputation: 2471
In the end, I realised that the problem was related to AVAudioSession
and its session management. Both libraries, flutter_tts
and audioplayers
make use of it and therefore they could overlay it other.
I had to change the method to the following:
/// Synthesises the current audio cue into an audio file
static Future<void> synthesiseStringToAudioFile() async {
int synthesized = await flutterTts.synthesizeToFile(
"This is my first audio synthesizer in Flutter", audioFileName);
if (synthesized == 1) {
String pathFile =
await (Platform.isAndroid ? pathToFileAndroid : pathToFileIos);
print('Path to file: ' + pathFile);
playAudioFile(pathFile);
} else {
print('Error during the synthesisation');
}
}
to start triggering some audio in iOS
. Still, there are some problems within the notifications, but I consider that the answer has been answered.
Upvotes: 0