Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 29b039b9 authored by Archie Pusaka's avatar Archie Pusaka Committed by Archie Pusaka
Browse files

Floss: Support multiple volume callbacks

Currently we assume there is only one volume callback and we always
replace the callback if a new audio device is connected.

When two audio devices are connected simultaneously, the later device
is disconnected because we can only stream audio to one device.
However, the volume callback is tied to that device, so now if the user
changes the volume, we can't call the correct callback.

This CL stores callback to all connected devices, so we can get the
correct callback when user updates the system volume.
Also, to simplify things, whenever floss layer receives an AVRCP
connection when there is an existing connection, we ask libbluetooth
to drop the newer connection. This behavior can be updated later, e.g.
when the old connection is disconnected we can smartly switch to the
new connection.

Bug: 366387141
Test: m -j
Test: Pair two headsets that connects AVRCP when they reconnects.
      Connect each headset one by one. Verify the 2nd device is
      disconnected, and the 1st device still receive volume updates.
Flag: EXEMPT, floss only change

Change-Id: I2e0f707fd11a3a6dbf827d839f95ec57f47e98d9
parent 6976c730
Loading
Loading
Loading
Loading
+55 −39
Original line number Diff line number Diff line
//! Anything related to audio and media API.

use bt_topshim::btif::{
    BluetoothInterface, BtBondState, BtConnectionDirection, BtStatus, BtTransport, DisplayAddress,
    RawAddress, ToggleableProfile,
    BluetoothInterface, BtBondState, BtStatus, BtTransport, DisplayAddress, RawAddress,
    ToggleableProfile,
};
use bt_topshim::profiles::a2dp::{
    A2dp, A2dpCallbacks, A2dpCallbacksDispatcher, A2dpCodecBitsPerSample, A2dpCodecChannelMode,
@@ -472,7 +472,8 @@ pub struct BluetoothMedia {
    adapter: Arc<Mutex<Box<Bluetooth>>>,
    a2dp: A2dp,
    avrcp: Avrcp,
    avrcp_direction: BtConnectionDirection,
    avrcp_address: Option<RawAddress>,
    avrcp_states: HashMap<RawAddress, BtavConnectionState>,
    a2dp_states: HashMap<RawAddress, BtavConnectionState>,
    a2dp_audio_state: HashMap<RawAddress, BtavAudioState>,
    a2dp_has_interrupted_stream: bool, // Only used for qualification.
@@ -548,7 +549,8 @@ impl BluetoothMedia {
            adapter,
            a2dp,
            avrcp,
            avrcp_direction: BtConnectionDirection::Unknown,
            avrcp_address: None,
            avrcp_states: HashMap::new(),
            a2dp_states: HashMap::new(),
            a2dp_audio_state: HashMap::new(),
            a2dp_has_interrupted_stream: false,
@@ -1307,6 +1309,31 @@ impl BluetoothMedia {
                    supported
                );

                // If is device initiated the AVRCP connection, emit a fake connecting state as
                // stack don't receive one.
                if self.avrcp_states.get(&addr) != Some(&BtavConnectionState::Connecting) {
                    metrics::profile_connection_state_changed(
                        addr,
                        Profile::AvrcpController as u32,
                        BtStatus::Success,
                        BtavConnectionState::Connecting as u32,
                    );
                }
                metrics::profile_connection_state_changed(
                    addr,
                    Profile::AvrcpController as u32,
                    BtStatus::Success,
                    BtavConnectionState::Connected as u32,
                );
                self.avrcp_states.insert(addr, BtavConnectionState::Connected);

                if self.avrcp_address.is_some() {
                    warn!("Another AVRCP connection exists. Disconnect {}", DisplayAddress(&addr));
                    self.avrcp.disconnect(addr);
                    return;
                }
                self.avrcp_address = Some(addr);

                match self.uinput.create(self.adapter_get_remote_name(addr), addr.to_string()) {
                    Ok(()) => info!("uinput device created for: {}", DisplayAddress(&addr)),
                    Err(e) => warn!("{}", e),
@@ -1325,30 +1352,34 @@ impl BluetoothMedia {
                }

                self.absolute_volume = supported;
                self.add_connected_profile(addr, Profile::AvrcpController);
            }
            AvrcpCallbacks::AvrcpDeviceDisconnected(addr) => {
                info!("[{}]: avrcp disconnected.", DisplayAddress(&addr));

                // If is device initiated the AVRCP connection, emit a fake connecting state as
                // stack don't receive one.
                if self.avrcp_direction != BtConnectionDirection::Outgoing {
                // If the peer device initiated the AVRCP disconnection, emit a fake connecting
                // state as stack don't receive one.
                if self.avrcp_states.get(&addr) != Some(&BtavConnectionState::Disconnecting) {
                    metrics::profile_connection_state_changed(
                        addr,
                        Profile::AvrcpController as u32,
                        BtStatus::Success,
                        BtavConnectionState::Connecting as u32,
                        BtavConnectionState::Disconnecting as u32,
                    );
                }
                metrics::profile_connection_state_changed(
                    addr,
                    Profile::AvrcpController as u32,
                    BtStatus::Success,
                    BtavConnectionState::Connected as u32,
                    BtavConnectionState::Disconnected as u32,
                );
                // Reset direction to unknown.
                self.avrcp_direction = BtConnectionDirection::Unknown;
                self.avrcp_states.remove(&addr);

                self.add_connected_profile(addr, Profile::AvrcpController);
                if self.avrcp_address != Some(addr) {
                    // Ignore disconnection to address we don't care
                    return;
                }
            AvrcpCallbacks::AvrcpDeviceDisconnected(addr) => {
                info!("[{}]: avrcp disconnected.", DisplayAddress(&addr));
                self.avrcp_address = None;

                self.uinput.close(addr.to_string());

@@ -1362,25 +1393,6 @@ impl BluetoothMedia {
                    None => false,
                };

                // If the peer device initiated the AVRCP disconnection, emit a fake connecting
                // state as stack don't receive one.
                if self.avrcp_direction != BtConnectionDirection::Outgoing {
                    metrics::profile_connection_state_changed(
                        addr,
                        Profile::AvrcpController as u32,
                        BtStatus::Success,
                        BtavConnectionState::Disconnecting as u32,
                    );
                }
                metrics::profile_connection_state_changed(
                    addr,
                    Profile::AvrcpController as u32,
                    BtStatus::Success,
                    BtavConnectionState::Disconnected as u32,
                );
                // Reset direction to unknown.
                self.avrcp_direction = BtConnectionDirection::Unknown;

                self.rm_connected_profile(addr, Profile::AvrcpController, is_profile_critical);
            }
            AvrcpCallbacks::AvrcpAbsoluteVolumeUpdate(volume) => {
@@ -3336,11 +3348,11 @@ impl IBluetoothMedia for BluetoothMedia {
                        BtStatus::Success,
                        BtavConnectionState::Connecting as u32,
                    );
                    self.avrcp_direction = BtConnectionDirection::Outgoing;
                    self.avrcp_states.insert(addr, BtavConnectionState::Connecting);
                    let status = self.avrcp.connect(addr);
                    if BtStatus::Success != status {
                        // Reset direction to unknown.
                        self.avrcp_direction = BtConnectionDirection::Unknown;
                        self.avrcp_states.remove(&addr);
                        metrics::profile_connection_state_changed(
                            addr,
                            Profile::AvrcpController as u32,
@@ -3463,11 +3475,11 @@ impl IBluetoothMedia for BluetoothMedia {
                        BtStatus::Success,
                        BtavConnectionState::Disconnecting as u32,
                    );
                    self.avrcp_direction = BtConnectionDirection::Outgoing;
                    self.avrcp_states.insert(addr, BtavConnectionState::Disconnecting);
                    let status = self.avrcp.disconnect(addr);
                    if BtStatus::Success != status {
                        // Reset direction to unknown.
                        self.avrcp_direction = BtConnectionDirection::Unknown;
                        self.avrcp_states.remove(&addr);
                        metrics::profile_connection_state_changed(
                            addr,
                            Profile::AvrcpController as u32,
@@ -3569,6 +3581,10 @@ impl IBluetoothMedia for BluetoothMedia {
    }

    fn set_volume(&mut self, volume: u8) {
        if self.avrcp_address.is_none() {
            return;
        }

        // Guard the range 0-127 by the try_from cast from u8 to i8.
        let vol = match i8::try_from(volume) {
            Ok(val) => val,
@@ -3578,7 +3594,7 @@ impl IBluetoothMedia for BluetoothMedia {
            }
        };

        self.avrcp.set_volume(vol);
        self.avrcp.set_volume(self.avrcp_address.unwrap(), vol);
    }

    fn set_hfp_volume(&mut self, volume: u8, addr: RawAddress) {
+13 −7
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#include "rust/topshim/btav/btav_shim.h"

#include <cstdio>
#include <map>
#include <memory>

#include "base/functional/callback.h"
@@ -155,12 +156,12 @@ public:
  }

  void DeviceConnected(const RawAddress& addr, VolumeChangedCb cb) override {
    volumeCb = std::move(cb);
    volumeCbs[addr] = std::move(cb);
    rusty::avrcp_device_connected(addr, /*absolute_volume_enabled=*/true);
  }

  void DeviceDisconnected(const RawAddress& addr) override {
    volumeCb.Reset();
    volumeCbs.erase(addr);
    rusty::avrcp_device_disconnected(addr);
  }

@@ -174,16 +175,19 @@ public:
  }

  // Set CT's (headsets, speakers) volume.
  void SetDeviceVolume(int8_t volume) {
    if (!volumeCb || volume < 0) {
  void SetDeviceVolume(const RawAddress& addr, int8_t volume) {
    if (volume < 0) {
      return;
    }

    volumeCb.Run(volume);
    const auto& cb_iter = this->volumeCbs.find(addr);
    if (cb_iter != this->volumeCbs.end()) {
      cb_iter->second.Run(volume);
    }
  }

private:
  VolumeInterface::VolumeChangedCb volumeCb;
  std::map<RawAddress, VolumeInterface::VolumeChangedCb> volumeCbs;
};

}  // namespace bluetooth::avrcp
@@ -361,7 +365,9 @@ void AvrcpIntf::cleanup() { intf_->Cleanup(); }
uint32_t AvrcpIntf::connect(RawAddress addr) { return intf_->ConnectDevice(addr); }
uint32_t AvrcpIntf::disconnect(RawAddress addr) { return intf_->DisconnectDevice(addr); }

void AvrcpIntf::set_volume(int8_t volume) { return mVolumeInterface.SetDeviceVolume(volume); }
void AvrcpIntf::set_volume(RawAddress addr, int8_t volume) {
  return mVolumeInterface.SetDeviceVolume(addr, volume);
}

void AvrcpIntf::set_playback_status(const ::rust::String& status) {
  avrcp::PlayState state = avrcp::PlayState::STOPPED;
+1 −1
Original line number Diff line number Diff line
@@ -67,7 +67,7 @@ public:
  uint32_t disconnect(RawAddress addr);

  // interface for Audio server
  void set_volume(int8_t volume);
  void set_volume(RawAddress addr, int8_t volume);

  void set_playback_status(const ::rust::String& status);
  void set_position(int64_t position_us);
+3 −3
Original line number Diff line number Diff line
@@ -38,7 +38,7 @@ pub mod ffi {
        fn cleanup(self: Pin<&mut AvrcpIntf>);
        fn connect(self: Pin<&mut AvrcpIntf>, bt_addr: RawAddress) -> u32;
        fn disconnect(self: Pin<&mut AvrcpIntf>, bt_addr: RawAddress) -> u32;
        fn set_volume(self: Pin<&mut AvrcpIntf>, volume: i8);
        fn set_volume(self: Pin<&mut AvrcpIntf>, bt_addr: RawAddress, volume: i8);
        fn set_playback_status(self: Pin<&mut AvrcpIntf>, status: &String);
        fn set_position(self: Pin<&mut AvrcpIntf>, position_us: i64);
        fn set_metadata(
@@ -173,8 +173,8 @@ impl Avrcp {
    }

    #[profile_enabled_or]
    pub fn set_volume(&mut self, volume: i8) {
        self.internal.pin_mut().set_volume(volume);
    pub fn set_volume(&mut self, addr: RawAddress, volume: i8) {
        self.internal.pin_mut().set_volume(addr, volume);
    }

    #[profile_enabled_or(false)]