Comments (9)
Here is an implementation of the suggested solutions (completely untested):
final _androidAudioManager =
!kIsWeb && Platform.isAndroid ? AndroidAudioManager() : null;
final _avAudioSession = !kIsWeb && Platform.isIOS ? AVAudioSession() : null;
Future<bool> switchToSpeaker() async {
if (_androidAudioManager != null) {
await _androidAudioManager!.setMode(AndroidAudioHardwareMode.normal);
await _androidAudioManager!.stopBluetoothSco();
await _androidAudioManager!.setBluetoothScoOn(false);
await _androidAudioManager!.setSpeakerphoneOn(true);
} else if (_avAudioSession != null) {
await _avAudioSession!
.overrideOutputAudioPort(AVAudioSessionPortOverride.speaker);
}
return true;
}
Future<bool> switchToReceiver() async {
if (_androidAudioManager != null) {
_androidAudioManager!.setMode(AndroidAudioHardwareMode.inCommunication);
_androidAudioManager!.stopBluetoothSco();
_androidAudioManager!.setBluetoothScoOn(false);
_androidAudioManager!.setSpeakerphoneOn(false);
return true;
} else if (_avAudioSession != null) {
return await _switchToAnyIosPortIn({AVAudioSessionPort.builtInMic});
}
return false;
}
Future<bool> switchToHeadphones() async {
if (_androidAudioManager != null) {
_androidAudioManager!.setMode(AndroidAudioHardwareMode.inCommunication);
_androidAudioManager!.stopBluetoothSco();
_androidAudioManager!.setBluetoothScoOn(false);
_androidAudioManager!.setSpeakerphoneOn(false);
return true;
} else if (_avAudioSession != null) {
return await _switchToAnyIosPortIn({AVAudioSessionPort.headsetMic});
}
return true;
}
Future<bool> switchToBluetooth() async {
if (_androidAudioManager != null) {
await _androidAudioManager!
.setMode(AndroidAudioHardwareMode.inCommunication);
await _androidAudioManager!.startBluetoothSco();
await _androidAudioManager!.setBluetoothScoOn(true);
return true;
} else if (_avAudioSession != null) {
return await _switchToAnyIosPortIn({
AVAudioSessionPort.bluetoothLe,
AVAudioSessionPort.bluetoothHfp,
AVAudioSessionPort.bluetoothA2dp,
});
}
return false;
}
Future<bool> _switchToAnyIosPortIn(Set<AVAudioSessionPort> ports) async {
if ((await _avAudioSession!.currentRoute)
.outputs
.any((r) => ports.contains(r.portType))) {
return true;
}
for (var input in await _avAudioSession!.availableInputs) {
if (ports.contains(input.portType)) {
await _avAudioSession!.setPreferredInput(input);
}
}
return false;
}
On Android, I did not provide the setWiredHeadsetOn
because it is not only deprecated, but actually does nothing on newer versions of Android.
from audio_session.
This plugin exposes the AVAudioSession API on iOS and the AudioManager API on Android (via the class AndroidAudioManager
), which allow you to route audio. Since it's platform specific, I would recommend either looking up the platform docs for AVAudioSession/AudioManager (or you'll probably find answers on StackOverflow for how to use these two APIs to achieve the desired effect.)
from audio_session.
I check couple SO posts, I read that it's not possible on iOS but it was an old answer. Anyway, I solve the iOS part by simple opening AirPlay. With this package flutter_to_airplay. Right now I'm looking to trigger to open this media view(native device picker view) on Android within the app. Since audio_service
package register the audio within the OS, once I can trigger this native device picker, I'll be more than enough.
Back to the topic, for programmatically changing the audio route, I've checked this SO post. I was looking for simple API call, like audioManager.changeOutputDevice(deviceId: device.id)
but the example codes I see on the SO is more like stopping something first and then setting another thing, and I don't see anything related to the devices but calls like setSpeakerphoneOn
or setBluetoothScoOn
. I also see just_audio package has this casting feature on the roadmap, so if you can point me to where it's been developing at the moment, I'd love contribute.
from audio_session.
Casting is another matter altogether, but you can take a look at audio_cast for the Android side of things.
As for the traditional audio devices, there are various answers on S/O:
- Android: https://stackoverflow.com/questions/22770321/android-switching-audio-between-bluetooth-and-phone-speaker-is-inconsistent
- iOS: https://stackoverflow.com/questions/52390659/avaudiosession-how-to-switch-between-speaker-and-headphones-output
from audio_session.
I have not found any working option to list and change the audio output routes on iOS, apparently Apple does not want this to be modified programmatically.
I have finally decided to opt in for invoking the OS audio route picker from my app. On iOS it's AVRoutePickerView, on Android MediaRouteSelector.
You can display native views in Flutter using the official guide for native views.
It works pretty well after a minimal amount of work on ios, on Android the choice of the rendering will have an impact on performances on Android 9 and earlier versions. It may involve more testing...
I wonder how Spotify can display their own customized view to pick the audio output.
from audio_session.
Some more info on iOS:
https://developer.apple.com/forums/thread/62954
It looks like you can programmatically set a Bluetooth input device, but you can't programmatically set a Bluetooth output device (unless that device is ALSO an input device, e.g. headset with a mic). For an output-only device, it needs to be done through a UI widget, so someone else would need to create a package for that to handle that use case.
from audio_session.
On Android, the typically recommended solution involves deprecated methods. I think I may need to eventually implement the newer API (probably using the new JNIgen):
https://developer.android.com/reference/androidx/mediarouter/media/package-summary
from audio_session.
Also suggestions from @Peng-Qian in #95 which I have folded into this issue. On the Android side, it seems to align with the usual S/O advice (and hence should probably be done with the newer MediaRouter
API). Note that until these convenience methods are implemented, you can still achieve the goal with the current release of audio_session by manually invoking the same lower level methods as described in the solutions linked above (e.g. #95 ).
from audio_session.
Just a heads up that I'm getting OSStatus error -50 when attempting to use the code above (though it does compile and looks like it's trying to do the right thing). When I print out the list of devices on my iPhone I only get (id, name, type.name) the below (even though spotify is currently playing on a bluetooth speaker). I'm guessing the app has to break out to a native chooser to connect a bluetooth / airplay output to the current app or something, as suggested above.
flutter: iPhone Microphone, Built-In Microphone, builtInMic
flutter: Speaker, Speaker, builtInSpeaker
from audio_session.
Related Issues (20)
- AVAudioSession.mm Failed to set category, error: -50 flutter HOT 2
- devicesChangedEventStream returns empty sets on first load HOT 2
- [iOS] Audio session activation failed when app is in background HOT 1
- Support rxdart 0.28
- Is it possible to set preferredIOBufferDuration for `AVAudioSession` HOT 3
- Stop audio when another app plays audio! HOT 1
- How to configure session to use Bluetooth headset mic on Android? HOT 6
- Can't build on android when targetting android 34 HOT 11
- Add privacy manifest for Apple HOT 6
- [iOS] Background audio not playing on iPhone 13+ HOT 3
- AVAudioSessionCategoryOptions.mixWithOthers stops background music the first time when audio is player, after continuing the music further sounds no longer stop the music HOT 1
- Call requires API level 23 (current min is 16) HOT 1
- Can not play by speaker on iOS HOT 3
- Is it possible to play audio when Do Not Disturb mode is on, but not in silent mode? HOT 1
- `AVAudioSessionCategoryOptions`'s `contains` method takes `AVAudioSessionInterruptionOptions`. Maybe it should be `AVAudioSessionCategoryOptions`? HOT 5
- Dependency causing an ANR in the Background HOT 3
- The music played by IOS17 is not output from Bluetooth earphones HOT 2
- Android detects the headset as if it is connected even if it is not HOT 1
- add windows SMTC support HOT 1
- Topics HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from audio_session.