Skip to content

How to gate playback on Bluetooth Headset connection #15

Closed

Description

@yschimke

I'd like to ensure playback is only active when a bluetooth headset is connected.

For stopping when the audio output changes it seems like .setHandleAudioBecomingNoisy(true) is the right approach.

Is LoadControl, the right API when the user clicks play to trigger a headset selection before continuing?

I've seen the references in google/ExoPlayer#9694, so I understand I'll need to implement this myself, but am curious which APIs are the right ones to plug into, to effect availableCommands for example? Or maybe allow the command, but launch the Bluetooth settings automatically and wait for a connection before playing?

Activity

  1. ojw28 commented on Dec 3, 2021

    @ojw28
    Contributor

    I think this should be done outside of the player. In other words, you should query whether there's a bluetooth headset connected before you prepare your ExoPlayer instance. ExoPlayer's audio-becoming-noisy handling might be sufficient for stopping the audio, but it's probably cleaner and more symmetric if you also handle this outside of the player. In other words, listen for the headset disconnecting, and stop the player when this occurs.

    How to query bluetooth connected devices is outside the scope of this issue tracker, but you should be able to find what you need online. For example https://stackoverflow.com/questions/4715865/how-can-i-programmatically-tell-if-a-bluetooth-device-is-connected has some sample isBluetoothHeadsetConnected methods that might be useful to you.

  2. self-assigned this
    on Dec 3, 2021
  3. yschimke commented on Dec 3, 2021

    @yschimke
    ContributorAuthor

    @ojw28 Thanks. That makes sense, and I've got docs on how to check and connect to the bluetooth headset.

    It's not perfect, If the app laucnhes and then bluetooth disconnects before playback is started, I'll be in the same place. I can guard any play button presses, but it doesn't help for commands via the MediaSession, so I was hoping there was a nice approach to do this in ExoPlayer/Media3. Maybe show up via affecting availableCommands? Maybe interject during the LoadControl before it continues? I understand if not, and if there is some clean way to add, I'll suggest putting up a PR.

    Would there be a downside to using LoadControl?

  4. ojw28 commented on Dec 6, 2021

    @ojw28
    Contributor

    I don't think LoadControl is the right place to be doing this. It feels like it's too deep in the player.

    If you'd like to push your logic for starting playback just inside of the player, so that it works for commands via the MediaSession (and any other UI component), then you could use ForwardingPlayer. This is completely untested, but I'd imagine it would look something like:

    class BtPlayer extends ForwardingPlayer {
    
        public BtPlayer(ExoPlayer player) {
          super(player);
          player.setHandleAudioBecomingNoisy(true);
        }
    
        @Override
        public void prepare() {
          if (blockPlayback()) {
            return;
          }
          super.prepare();
        }
    
        @Override
        public void play() {
          if (blockPlayback()) {
            return;
          }
          super.play();
        }
    
        @Override
        public void setPlayWhenReady(boolean playWhenReady) {
          if (playWhenReady && blockPlayback()) {
            return;
          }
          super.setPlayWhenReady(playWhenReady);
        }
    
        private boolean blockPlayback() {
          // Return whether playback should be blocked from starting
        }
    }
    

    You can then wrap your ExoPlayer inside an instance of this class, and pass the BtPlayer to the media session and any other UI components.

  5. yschimke commented on Dec 7, 2021

    @yschimke
    ContributorAuthor

    Thanks I'll try that or fallback to external logic at all points before playing.

    Thanks.

  6. yschimke commented on Oct 3, 2022

    @yschimke
    ContributorAuthor

    The above solution has worked reasonably well, but it looks like to avoid errors like #167.

    We will need to implement google/horologist#562 and use playback suppression for this.

  7. locked and limited conversation to collaborators on Mar 4, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions