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

Commit 5664351d authored by howardchung's avatar howardchung
Browse files

Floss: Implement APIs in topshim profiles to make them togglable

Implements the following APIs for topshim profiles
- enable
- disable
- is_enabled

The original logic of |initialize| is splitted into setting the
dispachers and enabling the internal interface. The new |initialize|
do the former part and |enable| do the latter part.

Bug: 239434117
Test: test along with the top of this chain
Tag: #floss

Change-Id: Ie604d38fb7e961c2b2c86817336db6f6e78c0069
parent 38a266a4
Loading
Loading
Loading
Loading
+79 −0
Original line number Diff line number Diff line
@@ -141,3 +141,82 @@ pub fn cb_variant(input: TokenStream) -> TokenStream {

    TokenStream::from(tokens)
}

// TODO: Replace below macro with a public crate, such as https://crates.io/crates/adorn
#[proc_macro_attribute]
/// Macro to check if the profile has been initialized
///
/// Function who applies this macro should also include log::warn and the self must implement
/// fn is_initialized(&self) -> bool
///
/// Example:
///     ```
///     use log::warn;
///     #[profile_enabled_or]
///     fn foo(&self) {
///         // actual code
///     }
///     ```
///     expands as
///     ```
///     use log::warn;
///     fn foo(&self) {
///         if !self.is_enabled() {
///             warn!("Tried to {} but internal hasn't been enabled", "foo");
///             return ;
///         }
///         // actual code
///     }
///     ```
/// One can specify a return value on uninitialized case
///     ```
///     use log::warn;
///     #[profile_enabled_or("not ready")]
///     fn foo(&self) -> &str {
///         // actual code
///     }
///     ```
///     expands as
///     ```
///     use log::warn;
///     fn foo(&self) -> &str {
///         if !self.is_enabled() {
///             warn!("Tried to {} but internal hasn't been enabled", "foo");
///             return "not ready";
///         }
///         // actual code
///         return "success"
///     }
///     ```
pub fn profile_enabled_or(attr: TokenStream, item: TokenStream) -> TokenStream {
    generate_profile_enabled_or_tokenstream(item, attr.to_string())
}

/// Similar to profile_enabled_or but return Default::default() when profile is not enabled.
#[proc_macro_attribute]
pub fn profile_enabled_or_default(_attr: TokenStream, item: TokenStream) -> TokenStream {
    generate_profile_enabled_or_tokenstream(item, String::from("Default::default()"))
}

fn generate_profile_enabled_or_tokenstream(item: TokenStream, attr_string: String) -> TokenStream {
    let mut input = syn::parse_macro_input!(item as syn::ItemFn);

    let fn_name = input.sig.ident.to_string();

    let ret_stmt: proc_macro2::TokenStream = format!("return {};", attr_string).parse().unwrap();

    let check_block = quote::quote! {
        if !self.is_enabled() {
            warn!("Tried to {} but internal hasn't been enabled", #fn_name);
            #ret_stmt
        }
    };

    input.block.stmts.insert(0, syn::parse(check_block.into()).unwrap());

    let output = quote::quote! {
        #input
    };

    output.into()
}
+12 −0
Original line number Diff line number Diff line
@@ -258,6 +258,12 @@ impl Into<u32> for BtStatus {
    }
}

impl Into<i32> for BtStatus {
    fn into(self) -> i32 {
        self.to_i32().unwrap_or_default()
    }
}

impl From<bindings::bt_bdname_t> for String {
    fn from(item: bindings::bt_bdname_t) -> Self {
        ascii_to_string(&item.name, item.name.len())
@@ -1228,6 +1234,12 @@ impl BluetoothInterface {
    }
}

pub trait ToggleableProfile {
    fn is_enabled(&self) -> bool;
    fn enable(&mut self) -> bool;
    fn disable(&mut self) -> bool;
}

pub fn get_btinterface() -> Option<BluetoothInterface> {
    let mut ret: Option<BluetoothInterface> = None;
    let mut ifptr: *const bindings::bt_interface_t = std::ptr::null();
+73 −6
Original line number Diff line number Diff line
use crate::btif::{BluetoothInterface, BtStatus, RawAddress};
use crate::btif::{BluetoothInterface, BtStatus, RawAddress, ToggleableProfile};
use crate::topstack::get_dispatchers;

use num_traits::cast::FromPrimitive;
use std::sync::{Arc, Mutex};
use topshim_macros::cb_variant;
use topshim_macros::{cb_variant, profile_enabled_or, profile_enabled_or_default};

use log::warn;

#[derive(Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd, Clone)]
#[repr(u32)]
@@ -300,11 +302,31 @@ FfiAddress -> RawAddress, A2dpCodecConfig, Vec<A2dpCodecConfig>, Vec<A2dpCodecCo
pub struct A2dp {
    internal: cxx::UniquePtr<ffi::A2dpIntf>,
    _is_init: bool,
    _is_enabled: bool,
}

// For *const u8 opaque btif
unsafe impl Send for A2dp {}

impl ToggleableProfile for A2dp {
    fn is_enabled(&self) -> bool {
        self._is_enabled
    }

    fn enable(&mut self) -> bool {
        self.internal.init();
        self._is_enabled = true;
        true
    }

    #[profile_enabled_or(false)]
    fn disable(&mut self) -> bool {
        self.internal.cleanup();
        self._is_enabled = false;
        true
    }
}

impl A2dp {
    pub fn new(intf: &BluetoothInterface) -> A2dp {
        let a2dpif: cxx::UniquePtr<ffi::A2dpIntf>;
@@ -312,42 +334,59 @@ impl A2dp {
            a2dpif = ffi::GetA2dpProfile(intf.as_raw_ptr());
        }

        A2dp { internal: a2dpif, _is_init: false }
        A2dp { internal: a2dpif, _is_init: false, _is_enabled: false }
    }

    pub fn is_initialized(&self) -> bool {
        self._is_init
    }

    pub fn initialize(&mut self, callbacks: A2dpCallbacksDispatcher) -> bool {
        if get_dispatchers().lock().unwrap().set::<A2dpCb>(Arc::new(Mutex::new(callbacks))) {
            panic!("Tried to set dispatcher for A2dp callbacks while it already exists");
        }
        self.internal.init();

        if self._is_init {
            warn!("A2dp has already been initialized");
            return false;
        }

        true
    }

    #[profile_enabled_or(BtStatus::NotReady)]
    pub fn connect(&mut self, addr: RawAddress) -> BtStatus {
        BtStatus::from(self.internal.connect(addr.into()))
    }

    #[profile_enabled_or]
    pub fn set_active_device(&mut self, addr: RawAddress) {
        self.internal.set_active_device(addr.into());
    }

    #[profile_enabled_or(BtStatus::NotReady)]
    pub fn disconnect(&mut self, addr: RawAddress) -> BtStatus {
        BtStatus::from(self.internal.disconnect(addr.into()))
    }

    #[profile_enabled_or]
    pub fn set_audio_config(&self, sample_rate: i32, bits_per_sample: i32, channel_mode: i32) {
        let config =
            A2dpCodecConfig { sample_rate, bits_per_sample, channel_mode, ..Default::default() };
        self.internal.set_audio_config(config);
    }

    #[profile_enabled_or]
    pub fn start_audio_request(&self) {
        self.internal.start_audio_request();
    }

    #[profile_enabled_or]
    pub fn stop_audio_request(&self) {
        self.internal.stop_audio_request();
    }

    #[profile_enabled_or_default]
    pub fn get_presentation_position(&self) -> PresentationPosition {
        self.internal.get_presentation_position()
    }
@@ -367,11 +406,31 @@ type A2dpSinkCb = Arc<Mutex<A2dpSinkCallbacksDispatcher>>;
pub struct A2dpSink {
    internal: cxx::UniquePtr<ffi::A2dpSinkIntf>,
    _is_init: bool,
    _is_enabled: bool,
}

// For *const u8 opaque btif
unsafe impl Send for A2dpSink {}

impl ToggleableProfile for A2dpSink {
    fn is_enabled(&self) -> bool {
        self._is_enabled
    }

    fn enable(&mut self) -> bool {
        self.internal.init();
        self._is_enabled = true;
        true
    }

    #[profile_enabled_or(false)]
    fn disable(&mut self) -> bool {
        self.internal.cleanup();
        self._is_enabled = false;
        true
    }
}

impl A2dpSink {
    pub fn new(intf: &BluetoothInterface) -> A2dpSink {
        let a2dp_sink: cxx::UniquePtr<ffi::A2dpSinkIntf>;
@@ -379,29 +438,37 @@ impl A2dpSink {
            a2dp_sink = ffi::GetA2dpSinkProfile(intf.as_raw_ptr());
        }

        A2dpSink { internal: a2dp_sink, _is_init: false }
        A2dpSink { internal: a2dp_sink, _is_init: false, _is_enabled: false }
    }

    pub fn is_initialized(&self) -> bool {
        self._is_init
    }

    pub fn initialize(&mut self, callbacks: A2dpSinkCallbacksDispatcher) -> bool {
        if get_dispatchers().lock().unwrap().set::<A2dpSinkCb>(Arc::new(Mutex::new(callbacks))) {
            panic!("Tried to set dispatcher for A2dp Sink Callbacks while it already exists");
        }
        self.internal.init();
        self._is_init = true;
        true
    }

    #[profile_enabled_or]
    pub fn connect(&mut self, bt_addr: RawAddress) {
        self.internal.connect(bt_addr.into());
    }

    #[profile_enabled_or]
    pub fn disconnect(&mut self, bt_addr: RawAddress) {
        self.internal.disconnect(bt_addr.into());
    }

    #[profile_enabled_or]
    pub fn set_active_device(&mut self, bt_addr: RawAddress) {
        self.internal.set_active_device(bt_addr.into());
    }

    #[profile_enabled_or]
    pub fn cleanup(&mut self) {}
}

+39 −9
Original line number Diff line number Diff line
use crate::btif::{BluetoothInterface, BtStatus, RawAddress};
use crate::btif::{BluetoothInterface, BtStatus, RawAddress, ToggleableProfile};
use crate::topstack::get_dispatchers;

use std::sync::{Arc, Mutex};
use topshim_macros::cb_variant;
use topshim_macros::{cb_variant, profile_enabled_or};

use log::warn;

#[derive(Debug, Default)]
pub struct PlayerMetadata {
@@ -115,11 +117,31 @@ cb_variant!(
pub struct Avrcp {
    internal: cxx::UniquePtr<ffi::AvrcpIntf>,
    _is_init: bool,
    _is_enabled: bool,
}

// For *const u8 opaque btif
unsafe impl Send for Avrcp {}

impl ToggleableProfile for Avrcp {
    fn is_enabled(&self) -> bool {
        self._is_enabled
    }

    fn enable(&mut self) -> bool {
        self.internal.pin_mut().init();
        self._is_enabled = true;
        true
    }

    #[profile_enabled_or(false)]
    fn disable(&mut self) -> bool {
        self.internal.pin_mut().cleanup();
        self._is_enabled = false;
        true
    }
}

impl Avrcp {
    pub fn new(intf: &BluetoothInterface) -> Avrcp {
        let avrcpif: cxx::UniquePtr<ffi::AvrcpIntf>;
@@ -127,31 +149,39 @@ impl Avrcp {
            avrcpif = ffi::GetAvrcpProfile(intf.as_raw_ptr());
        }

        Avrcp { internal: avrcpif, _is_init: false }
        Avrcp { internal: avrcpif, _is_init: false, _is_enabled: false }
    }

    pub fn is_initialized(&self) -> bool {
        self._is_init
    }

    pub fn initialize(&mut self, callbacks: AvrcpCallbacksDispatcher) -> bool {
        if get_dispatchers().lock().unwrap().set::<AvrcpCb>(Arc::new(Mutex::new(callbacks))) {
            panic!("Tried to set dispatcher for Avrcp callbacks while it already exists");
        }
        self.internal.pin_mut().init();
        true
    }

    pub fn cleanup(&mut self) -> bool {
        self.internal.pin_mut().cleanup();
        self._is_init = true;
        true
    }

    #[profile_enabled_or(BtStatus::NotReady)]
    pub fn connect(&mut self, addr: RawAddress) -> BtStatus {
        BtStatus::from(self.internal.pin_mut().connect(addr.into()))
    }

    #[profile_enabled_or(BtStatus::NotReady)]
    pub fn disconnect(&mut self, addr: RawAddress) -> BtStatus {
        BtStatus::from(self.internal.pin_mut().disconnect(addr.into()))
    }

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

    #[profile_enabled_or(false)]
    pub fn cleanup(&mut self) -> bool {
        self.internal.pin_mut().cleanup();
        true
    }
}
+37 −4
Original line number Diff line number Diff line
use crate::btif::{BluetoothInterface, BtStatus, RawAddress};
use crate::btif::{BluetoothInterface, BtStatus, RawAddress, ToggleableProfile};
use crate::topstack::get_dispatchers;

use num_traits::cast::FromPrimitive;
use std::convert::{TryFrom, TryInto};
use std::sync::{Arc, Mutex};
use topshim_macros::cb_variant;
use topshim_macros::{cb_variant, profile_enabled_or};

use log::warn;

#[derive(Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd, Clone)]
#[repr(u32)]
@@ -158,11 +160,31 @@ cb_variant!(
pub struct Hfp {
    internal: cxx::UniquePtr<ffi::HfpIntf>,
    _is_init: bool,
    _is_enabled: bool,
}

// For *const u8 opaque btif
unsafe impl Send for Hfp {}

impl ToggleableProfile for Hfp {
    fn is_enabled(&self) -> bool {
        self._is_enabled
    }

    fn enable(&mut self) -> bool {
        self.internal.pin_mut().init();
        self._is_enabled = true;
        true
    }

    #[profile_enabled_or(false)]
    fn disable(&mut self) -> bool {
        self.internal.pin_mut().cleanup();
        self._is_enabled = false;
        true
    }
}

impl Hfp {
    pub fn new(intf: &BluetoothInterface) -> Hfp {
        let hfpif: cxx::UniquePtr<ffi::HfpIntf>;
@@ -170,41 +192,52 @@ impl Hfp {
            hfpif = ffi::GetHfpProfile(intf.as_raw_ptr());
        }

        Hfp { internal: hfpif, _is_init: false }
        Hfp { internal: hfpif, _is_init: false, _is_enabled: false }
    }

    pub fn is_initialized(&self) -> bool {
        self._is_init
    }

    pub fn initialize(&mut self, callbacks: HfpCallbacksDispatcher) -> bool {
        if get_dispatchers().lock().unwrap().set::<HfpCb>(Arc::new(Mutex::new(callbacks))) {
            panic!("Tried to set dispatcher for HFP callbacks while it already exists");
        }
        self.internal.pin_mut().init();
        self._is_init = true;
        true
    }

    #[profile_enabled_or(BtStatus::NotReady)]
    pub fn connect(&mut self, addr: RawAddress) -> BtStatus {
        BtStatus::from(self.internal.pin_mut().connect(addr.into()))
    }

    #[profile_enabled_or(BtStatus::NotReady.into())]
    pub fn connect_audio(&mut self, addr: RawAddress, sco_offload: bool, force_cvsd: bool) -> i32 {
        self.internal.pin_mut().connect_audio(addr.into(), sco_offload, force_cvsd)
    }

    #[profile_enabled_or(BtStatus::NotReady.into())]
    pub fn set_active_device(&mut self, addr: RawAddress) -> i32 {
        self.internal.pin_mut().set_active_device(addr.into())
    }

    #[profile_enabled_or(BtStatus::NotReady.into())]
    pub fn set_volume(&mut self, volume: i8, addr: RawAddress) -> i32 {
        self.internal.pin_mut().set_volume(volume, addr.into())
    }

    #[profile_enabled_or(BtStatus::NotReady)]
    pub fn disconnect(&mut self, addr: RawAddress) -> BtStatus {
        BtStatus::from(self.internal.pin_mut().disconnect(addr.into()))
    }

    #[profile_enabled_or(BtStatus::NotReady.into())]
    pub fn disconnect_audio(&mut self, addr: RawAddress) -> i32 {
        self.internal.pin_mut().disconnect_audio(addr.into())
    }

    #[profile_enabled_or(false)]
    pub fn cleanup(&mut self) -> bool {
        self.internal.pin_mut().cleanup();
        true
Loading