Closed wujek-srujek closed 1 year ago
Ok, the reason is that AudioContextConfig
has forceSpeaker
as the default, which is pretty surprising, as:
AudioContextConfig()
) behaves differently than not setting the context. I don't know, I wouldn't expect this behavior.forceSpeaker
requires the playAndRecord
, but this is not set in buildIOS
correctly, and it crashes with
Error: category option 'defaultToSpeaker' is only applicable with category 'playAndRecord'
So, turning forceSpeakers
to false
fixes the crash, but it causes a different issue - when there is a BT speaker connected, sound from other app (Spotify in my case) gets quieter when my app plays its own sound, but then when my app is done, Spotify never goes back to the original volume. I can't make the combination BT speaker playing music from another app + my app playing sound over the speaker but ducking the other sound not work without side effects. Is this supported on iOS?
Could you state a ios context configuration, that you would consider as default? See: https://pub.dev/documentation/audioplayers_platform_interface/latest/audioplayers_platform_interface/AudioContextIOS-class.html I expect something like this maybe:
AudioContextIOS(
category: AVAudioSessionCategory.playAndRecord,
options: [
AVAudioSessionOptions.mixWithOthers,
AVAudioSessionOptions.defaultToSpeaker,
AVAudioSessionOptions.allowBluetooth,
AVAudioSessionOptions.allowBluetoothA2DP,
AVAudioSessionOptions.allowAirPlay,
],
)
Unfortunately I cannot really test any of these params, as I don't own a physical device.
The default for me would be the same exact behavior that we get when we don't specify any AudioContext
in Dart at all. I don't know what it actually is, but the people who know the code should be able to quickly get the information. Maybe this means the platform default apply?
Currently, the constructors, when called without any parameters, result in different behavior, e.g. for Android they change the audioFocus
to something other than null
(see https://github.com/bluefireteam/audioplayers/issues/1495), and they are definitely not good on iOS as they cause a crash (due to setting the category to playback
, but playAndRecord
is needed). This makes it hard or even impossible to change the settings for one platform and keep the default for the other. This is definitely the case when I need to change them for iOS, as this forces me to set one for Android as well, and this in turn makes it impossible to revert to the default behavior (again, see https://github.com/bluefireteam/audioplayers/issues/1495).
The default values for native ios are stated here: https://github.com/bluefireteam/audioplayers/blob/6cd5656c0c5deaab1fb4af78a5b7632402c3a1d3/packages/audioplayers_darwin/ios/Classes/AudioContext.swift#L9
The default values for ios context in dart are here: https://github.com/bluefireteam/audioplayers/blob/6cd5656c0c5deaab1fb4af78a5b7632402c3a1d3/packages/audioplayers_platform_interface/lib/src/api/audio_context.dart#L108
This should also be applied here: https://github.com/bluefireteam/audioplayers/blob/6cd5656c0c5deaab1fb4af78a5b7632402c3a1d3/packages/audioplayers_platform_interface/lib/src/api/audio_context_config.dart#L121
So the only difference would be changing AVAudioSessionCategory.playback
to playAndRecord
.
Hmm the default for ios is playback
and not playAndRecord
.
https://developer.apple.com/documentation/avfaudio/avaudiosession
We should maybe use playback
as the default in the AudioContextIOS?
I also could not reproduce the Error: category option 'defaultToSpeaker' is only applicable with category 'playAndRecord'
although it would make sense. Maybe I need a real device so that it is thrown?
I could also imagine that defaultToSpeaker
is only needed, because we also use playAndRecord
, so we could just leave out both and it would not play from Earpiece, but don't actually know:
https://developer.apple.com/documentation/avfaudio/avaudiosession/categoryoptions/1616462-defaulttospeaker
Yes you need a device. The sample starts just fine on the simulator but crashes on a real device 100% of the time.
We should maybe use
playback
as the default in the AudioContextIOS?
It currently is the default on in AudioContextIOS
, but this doesn't work with the other default of enabling the defaultToSpeaker
option, that's the whole issue here. The crash happens and it is documented that it is not allowed: https://developer.apple.com/documentation/avfaudio/avaudiosession/categoryoptions/1616462-defaulttospeaker#discussion (You can set this option only when using the playAndRecord category.
)
I'm guessing that's why the native default of audioplayers_ios
is playAndRecord
. All my PR does is it aligns the Dart default with it.
As for the defaults, AFAIK there are 3 of them:
audioplayers
uses when no other context is set. This one differs from the iOS defaults (playback
vs playAndRecord
and forcing speakers) and this must have been your decision at some point in the past.I think it is valid for your package to have other defaults than the platform (i.e. you chose to ignore 1. above), but they should be consistent between iOS and Dart, and this is violated. As far as what you want the defaults to be, you need to decide, your package.
Having playback
as the default category, and NOT specifying defaultToSpeaker
is exactly what I'm doing, and it's working fine. However, it has its own set of issues if you do this in the library:
AudioContextConfig
and its buildIOS
functions - if someone wants ducking the AudioContextConfig.buildIOS
should change the category to playAndRecord
, or AudioContextConfig.validateIOS
should fail.As you can see, changing the default is a much more involved task than just making this consistent across iOS and Dart (my PR). But I am all for removing the default of forcing to speaker, I don't understand why you want this, and according to my tests it doesn't even work anyway (or maybe I don't understand what it should do?).
Forcing to speaker fixes this issue: #1194, but don't know it would have been fixed by just using playback
as default.
Checklist
Current bug behaviour
When the application wants to set ducking, it works on Android but crashes on iOS.
It seems like the category
defaultToSpeaker
is set by default, and setting theduck
option in addition causes the crash.Expected behaviour
The application doesn't crash on iOS and ducking works.
Steps to reproduce
Run the code included in the snippet.
Code sample
Code sample
```dart import 'dart:async'; import 'package:audioplayers/audioplayers.dart'; import 'package:flutter/material.dart'; FutureAffected platforms
iOS
Platform details
iPhone 14, iOS 16.0 iPhone Xs, iOS 16.4.1 (a)
AudioPlayers Version
4.0.1
Build mode
debug, release
Audio Files/URLs/Sources
No need for sound files, the application crashes before that.
Screenshots
No response
Logs
Full Logs
``` 2023-05-06 14:51:54.377566+0200 Runner[717:47684] Metal API Validation Enabled 2023-05-06 14:51:54.534371+0200 Runner[717:47963] flutter: The Dart VM service is listening on http://127.0.0.1:54130/uL1ofWVhMDI=/ 2023-05-06 14:51:54.675303+0200 Runner[717:47684] [as_client] AVAudioSession_iOS.mm:2194 Error: category option 'defaultToSpeaker' is only applicable with category 'playAndRecord' 2023-05-06 14:51:54.675830+0200 Runner[717:47684] [as_client] AVAudioSession_iOS.mm:2370 Failed to set category, error: -50 2023-05-06 14:51:54.679279+0200 Runner[717:47945] [VERBOSE-2:dart_vm_initializer.cc(41)] Unhandled Exception: PlatformException(DarwinAudioError, Error configuring global audio session: Error Domain=NSOSStatusErrorDomain Code=-50 "(null)", null, null) #0 StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:653:7) #1 MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:315:18)Related issues / more information
No response
Working on PR
no way