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

Commit 95a23b1a authored by Hsin-Yu Chao's avatar Hsin-Yu Chao Committed by Hansong Zhang
Browse files

blietooth_media: A2DP methods and callbacks dispatch

Bug: 189497374
Tag: #floss
Test: Manual test with audio server changes
Change-Id: I89d4cd0cfc0702036e23f18095e903cbbf41601f
parent 27fcf974
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -36,4 +36,19 @@ impl IBluetoothMedia for IBluetoothMediaDBus {
    fn initialize(&mut self) -> bool {
        true
    }

    #[dbus_method("Connect")]
    fn connect(&mut self, device: String) {}

    #[dbus_method("SetActiveDevice")]
    fn set_active_device(&mut self, device: String) {}

    #[dbus_method("Disconnect")]
    fn disconnect(&mut self, device: String) {}

    #[dbus_method("StartSession")]
    fn start_session(&mut self) {}

    #[dbus_method("StopSession")]
    fn stop_session(&mut self) {}
}
+5 −1
Original line number Diff line number Diff line
@@ -73,7 +73,11 @@ fn main() -> Result<(), Box<dyn Error>> {
        )));

        // Run the stack main dispatch loop.
        tokio::spawn(Stack::dispatch(rx, bluetooth.clone()));
        topstack::get_runtime().spawn(Stack::dispatch(
            rx,
            bluetooth.clone(),
            bluetooth_media.clone(),
        ));

        // Set up the disconnect watcher to monitor client disconnects.
        let disconnect_watcher = Arc::new(Mutex::new(DisconnectWatcher::new()));
+51 −1
Original line number Diff line number Diff line
//! Anything related to audio and media API.

use bt_topshim::btif::BluetoothInterface;
use bt_topshim::profiles::a2dp::{A2dp, A2dpCallbacksDispatcher};
use bt_topshim::profiles::a2dp::{
    A2dp, A2dpCallbacks, A2dpCallbacksDispatcher, BtavConnectionState, RawAddress,
};
use bt_topshim::topstack;

use std::sync::Arc;
@@ -17,6 +19,11 @@ pub trait IBluetoothMedia {

    ///
    fn initialize(&mut self) -> bool;
    fn connect(&mut self, device: String);
    fn set_active_device(&mut self, device: String);
    fn disconnect(&mut self, device: String);
    fn start_session(&mut self);
    fn stop_session(&mut self);
}

pub trait IBluetoothMediaCallback {
@@ -47,6 +54,30 @@ impl BluetoothMedia {
            a2dp: None,
        }
    }

    pub fn dispatch_a2dp_callbacks(&mut self, cb: A2dpCallbacks) {
        match cb {
            A2dpCallbacks::ConnectionState(addr, state) => match BtavConnectionState::from(state) {
                BtavConnectionState::Connected => {
                    self.for_all_callbacks(|callback| {
                        callback.on_bluetooth_audio_device_added(addr.to_string());
                    });
                }
                BtavConnectionState::Connecting => {}
                BtavConnectionState::Disconnected => {}
                BtavConnectionState::Disconnecting => {}
            },
            A2dpCallbacks::AudioState(addr, state) => {}
            A2dpCallbacks::AudioConfig(addr, config, local_caps, selectable_caps) => {}
            A2dpCallbacks::MandatoryCodecPreferred(addr) => {}
        }
    }

    fn for_all_callbacks<F: Fn(&Box<dyn IBluetoothMediaCallback + Send>)>(&self, f: F) {
        for callback in &self.callbacks {
            f(&callback.1);
        }
    }
}

fn get_a2dp_dispatcher(tx: Sender<Message>) -> A2dpCallbacksDispatcher {
@@ -76,4 +107,23 @@ impl IBluetoothMedia for BluetoothMedia {
        self.a2dp.as_mut().unwrap().initialize(a2dp_dispatcher);
        true
    }

    fn connect(&mut self, device: String) {
        self.a2dp.as_mut().unwrap().connect(device);
    }

    fn set_active_device(&mut self, device: String) {
        self.a2dp.as_mut().unwrap().set_active_device(device);
    }

    fn disconnect(&mut self, device: String) {
        self.a2dp.as_mut().unwrap().disconnect(device);
    }

    fn start_session(&mut self) {
        self.a2dp.as_mut().unwrap().start_session();
    }
    fn stop_session(&mut self) {
        self.a2dp.as_mut().unwrap().stop_session();
    }
}
+7 −3
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ use tokio::sync::mpsc::channel;
use tokio::sync::mpsc::{Receiver, Sender};

use crate::bluetooth::Bluetooth;
use crate::bluetooth_media::BluetoothMedia;

/// Represents a Bluetooth address.
// TODO: Add support for LE random addresses.
@@ -105,7 +106,11 @@ impl Stack {
    }

    /// Runs the main dispatch loop.
    pub async fn dispatch(mut rx: Receiver<Message>, bluetooth: Arc<Mutex<Box<Bluetooth>>>) {
    pub async fn dispatch(
        mut rx: Receiver<Message>,
        bluetooth: Arc<Mutex<Box<Bluetooth>>>,
        bluetooth_media: Arc<Mutex<Box<BluetoothMedia>>>,
    ) {
        loop {
            let m = rx.recv().await;

@@ -116,8 +121,7 @@ impl Stack {

            match m.unwrap() {
                Message::A2dp(a) => {
                    //
                    println!("RX {:?}", a);
                    bluetooth_media.lock().unwrap().dispatch_a2dp_callbacks(a);
                }
                Message::Base(b) => {
                    bluetooth.lock().unwrap().dispatch_base_callbacks(b);
+73 −3
Original line number Diff line number Diff line
@@ -149,6 +149,8 @@ pub mod ffi {
            bt_addr: RustRawAddress,
            codec_preferences: Vec<A2dpCodecConfig>,
        ) -> i32;
        fn start_audio_request(self: Pin<&mut A2dpIntf>) -> bool;
        fn stop_audio_request(self: Pin<&mut A2dpIntf>) -> bool;
        fn cleanup(self: Pin<&mut A2dpIntf>);

    }
@@ -168,6 +170,44 @@ pub mod ffi {
pub type RawAddress = ffi::RustRawAddress;
pub type A2dpCodecConfig = ffi::A2dpCodecConfig;

// TODO(hychao): copied from BDAddr, need to move to a shared addr.
impl ToString for RawAddress {
    fn to_string(&self) -> String {
        String::from(format!(
            "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
            self.address[0],
            self.address[1],
            self.address[2],
            self.address[3],
            self.address[4],
            self.address[5]
        ))
    }
}

impl RawAddress {
    pub fn from_string<S: Into<String>>(addr: S) -> Option<RawAddress> {
        let addr: String = addr.into();
        let s = addr.split(':').collect::<Vec<&str>>();

        if s.len() != 6 {
            return None;
        }

        let mut raw: [u8; 6] = [0; 6];
        for i in 0..s.len() {
            raw[i] = match u8::from_str_radix(s[i], 16) {
                Ok(res) => res,
                Err(_) => {
                    return None;
                }
            };
        }

        Some(RawAddress { address: raw })
    }
}

#[derive(Debug)]
pub enum A2dpCallbacks {
    ConnectionState(RawAddress, BtavConnectionState),
@@ -216,8 +256,38 @@ impl A2dp {
        true
    }

    pub fn connect(&self) -> bool {
        // TODO(hychao)
        true
    pub fn connect(&mut self, device: String) {
        let addr = RawAddress::from_string(device.clone());
        if addr.is_none() {
            eprintln!("Invalid device string {}", device);
            return;
        }
        self.internal.pin_mut().connect(addr.unwrap());
    }

    pub fn set_active_device(&mut self, device: String) {
        let addr = RawAddress::from_string(device.clone());
        if addr.is_none() {
            eprintln!("Invalid device string {}", device);
            return;
        }
        self.internal.pin_mut().set_active_device(addr.unwrap());
    }

    pub fn disconnect(&mut self, device: String) {
        let addr = RawAddress::from_string(device.clone());
        if addr.is_none() {
            eprintln!("Invalid device string {}", device);
            return;
        }
        self.internal.pin_mut().disconnect(addr.unwrap());
    }

    pub fn start_session(&mut self) {
        self.internal.pin_mut().start_audio_request();
    }

    pub fn stop_session(&mut self) {
        self.internal.pin_mut().stop_audio_request();
    }
}