Code Monkey home page Code Monkey logo

Comments (9)

ryanheise avatar ryanheise commented on July 21, 2024 1

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.

ryanheise avatar ryanheise commented on July 21, 2024

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.

mirkancal avatar mirkancal commented on July 21, 2024

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.

ryanheise avatar ryanheise commented on July 21, 2024

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:

from audio_session.

Vilmir avatar Vilmir commented on July 21, 2024

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.

ryanheise avatar ryanheise commented on July 21, 2024

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.

ryanheise avatar ryanheise commented on July 21, 2024

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.

ryanheise avatar ryanheise commented on July 21, 2024

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.

mikemcelligott avatar mikemcelligott commented on July 21, 2024

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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.