diff --git a/system/btif/src/bluetooth.cc b/system/btif/src/bluetooth.cc index cce99c2248c6c07bab57fa8160367fb57095bbad..d6ba57592990d29742249b337d2611228ad897ec 100644 --- a/system/btif/src/bluetooth.cc +++ b/system/btif/src/bluetooth.cc @@ -87,6 +87,7 @@ #include "common/metrics.h" #include "common/os_utils.h" #include "device/include/device_iot_config.h" +#include "device/include/esco_parameters.h" #include "device/include/interop.h" #include "device/include/interop_config.h" #include "include/check.h" @@ -489,6 +490,10 @@ static bool get_swb_supported() { return hfp_hal_interface::get_swb_supported(); } +static bool is_coding_format_supported(esco_coding_format_t coding_format) { + return hfp_hal_interface::is_coding_format_supported(coding_format); +} + bool is_common_criteria_mode() { return is_bluetooth_uid() && common_criteria_mode; } @@ -1205,6 +1210,7 @@ EXPORT_SYMBOL bt_interface_t bluetoothInterface = { set_event_filter_connection_setup_all_devices, .get_wbs_supported = get_wbs_supported, .get_swb_supported = get_swb_supported, + .is_coding_format_supported = is_coding_format_supported, .metadata_changed = metadata_changed, .interop_match_addr = interop_match_addr, .interop_match_name = interop_match_name, diff --git a/system/gd/rust/linux/client/src/dbus_iface.rs b/system/gd/rust/linux/client/src/dbus_iface.rs index dabeb6d9af4c03dad528ea08e29036dfbc6f7ebe..fb392a3795952b79ac27398373a04b7259bd9da2 100644 --- a/system/gd/rust/linux/client/src/dbus_iface.rs +++ b/system/gd/rust/linux/client/src/dbus_iface.rs @@ -10,7 +10,7 @@ use bt_topshim::profiles::a2dp::{ }; use bt_topshim::profiles::avrcp::PlayerMetadata; use bt_topshim::profiles::gatt::{AdvertisingStatus, GattStatus, LePhy}; -use bt_topshim::profiles::hfp::HfpCodecCapability; +use bt_topshim::profiles::hfp::{EscoCodingFormat, HfpCodecBitId, HfpCodecFormat}; use bt_topshim::profiles::hid_host::BthhReportType; use bt_topshim::profiles::sdp::{ BtSdpDipRecord, BtSdpHeaderOverlay, BtSdpMasRecord, BtSdpMnsRecord, BtSdpMpsRecord, @@ -435,13 +435,16 @@ impl_dbus_arg_from_into!(A2dpCodecSampleRate, i32); impl_dbus_arg_from_into!(A2dpCodecBitsPerSample, i32); impl_dbus_arg_from_into!(A2dpCodecChannelMode, i32); -impl_dbus_arg_from_into!(HfpCodecCapability, i32); +impl_dbus_arg_from_into!(EscoCodingFormat, u8); +impl_dbus_arg_from_into!(HfpCodecBitId, i32); +impl_dbus_arg_from_into!(HfpCodecFormat, i32); + #[dbus_propmap(BluetoothAudioDevice)] pub struct BluetoothAudioDeviceDBus { address: String, name: String, a2dp_caps: Vec<A2dpCodecConfig>, - hfp_cap: HfpCodecCapability, + hfp_cap: HfpCodecFormat, absolute_volume: bool, } @@ -1001,6 +1004,11 @@ impl IBluetooth for BluetoothDBus { fn get_supported_roles(&self) -> Vec<BtAdapterRole> { dbus_generated!() } + + #[dbus_method("IsCodingFormatSupported")] + fn is_coding_format_supported(&self, coding_format: EscoCodingFormat) -> bool { + dbus_generated!() + } } pub(crate) struct BluetoothQALegacyDBus { @@ -2656,7 +2664,7 @@ impl IBluetoothMedia for BluetoothMediaDBus { &mut self, address: String, sco_offload: bool, - disabled_codecs: HfpCodecCapability, + disabled_codecs: HfpCodecBitId, ) -> bool { dbus_generated!() } diff --git a/system/gd/rust/linux/service/src/iface_bluetooth.rs b/system/gd/rust/linux/service/src/iface_bluetooth.rs index c84e076b74acd27991b3e081fb09a92b6f0ce0ff..d1783e38cd6f92470712c7ed6c779f021ed07011 100644 --- a/system/gd/rust/linux/service/src/iface_bluetooth.rs +++ b/system/gd/rust/linux/service/src/iface_bluetooth.rs @@ -5,6 +5,8 @@ use bt_topshim::btif::{ use bt_topshim::profiles::socket::SocketType; use bt_topshim::profiles::ProfileConnectionState; +use bt_topshim::profiles::hfp::EscoCodingFormat; + use bt_topshim::profiles::hid_host::BthhReportType; use bt_topshim::profiles::sdp::{ @@ -424,6 +426,7 @@ impl DBusArg for BtSdpRecord { } impl_dbus_arg_enum!(BtDiscMode); +impl_dbus_arg_from_into!(EscoCodingFormat, u8); #[allow(dead_code)] struct IBluetoothDBus {} @@ -712,6 +715,11 @@ impl IBluetooth for IBluetoothDBus { fn get_supported_roles(&self) -> Vec<BtAdapterRole> { dbus_generated!() } + + #[dbus_method("IsCodingFormatSupported", DBusLog::Disable)] + fn is_coding_format_supported(&self, coding_format: EscoCodingFormat) -> bool { + dbus_generated!() + } } impl_dbus_arg_enum!(SocketType); diff --git a/system/gd/rust/linux/service/src/iface_bluetooth_media.rs b/system/gd/rust/linux/service/src/iface_bluetooth_media.rs index cb575bd22afc958fa40c84bb6c610cc97d1de153..0dc4b47c4364448339f426e456b3a569cbe35973 100644 --- a/system/gd/rust/linux/service/src/iface_bluetooth_media.rs +++ b/system/gd/rust/linux/service/src/iface_bluetooth_media.rs @@ -3,7 +3,7 @@ use bt_topshim::profiles::a2dp::{ A2dpCodecSampleRate, PresentationPosition, }; use bt_topshim::profiles::avrcp::PlayerMetadata; -use bt_topshim::profiles::hfp::HfpCodecCapability; +use bt_topshim::profiles::hfp::{HfpCodecBitId, HfpCodecFormat}; use btstack::bluetooth_media::{BluetoothAudioDevice, IBluetoothMedia, IBluetoothMediaCallback}; use btstack::RPCProxy; @@ -43,11 +43,12 @@ pub struct BluetoothAudioDeviceDBus { address: String, name: String, a2dp_caps: Vec<A2dpCodecConfig>, - hfp_cap: HfpCodecCapability, + hfp_cap: HfpCodecFormat, absolute_volume: bool, } -impl_dbus_arg_from_into!(HfpCodecCapability, i32); +impl_dbus_arg_from_into!(HfpCodecBitId, i32); +impl_dbus_arg_from_into!(HfpCodecFormat, i32); impl_dbus_arg_enum!(A2dpCodecIndex); impl_dbus_arg_from_into!(A2dpCodecSampleRate, i32); impl_dbus_arg_from_into!(A2dpCodecBitsPerSample, i32); @@ -254,7 +255,7 @@ impl IBluetoothMedia for IBluetoothMediaDBus { &mut self, address: String, sco_offload: bool, - disabled_codecs: HfpCodecCapability, + disabled_codecs: HfpCodecBitId, ) -> bool { dbus_generated!() } diff --git a/system/gd/rust/linux/stack/src/bluetooth.rs b/system/gd/rust/linux/stack/src/bluetooth.rs index 2a655c4496e85b3cfd08b80a1ab0e78ad5327578..2e0cf877c40670809cc7040b59be7ccc686618ba 100644 --- a/system/gd/rust/linux/stack/src/bluetooth.rs +++ b/system/gd/rust/linux/stack/src/bluetooth.rs @@ -10,6 +10,7 @@ use bt_topshim::btif::{ use bt_topshim::{ controller, metrics, profiles::gatt::GattStatus, + profiles::hfp::EscoCodingFormat, profiles::hid_host::{ BthhConnectionState, BthhHidInfo, BthhProtocolMode, BthhReportType, BthhStatus, HHCallbacks, HHCallbacksDispatcher, HidHost, @@ -251,6 +252,9 @@ pub trait IBluetooth { /// Returns a list of all the roles that are supported. fn get_supported_roles(&self) -> Vec<BtAdapterRole>; + + /// Returns whether the coding format is supported. + fn is_coding_format_supported(&self, coding_format: EscoCodingFormat) -> bool; } /// Adapter API for Bluetooth qualification and verification. @@ -2797,6 +2801,10 @@ impl IBluetooth for Bluetooth { roles } + + fn is_coding_format_supported(&self, coding_format: EscoCodingFormat) -> bool { + self.intf.lock().unwrap().is_coding_format_supported(coding_format as u8) + } } impl BtifSdpCallbacks for Bluetooth { diff --git a/system/gd/rust/linux/stack/src/bluetooth_media.rs b/system/gd/rust/linux/stack/src/bluetooth_media.rs index e96c882f0612b339d8711f4b54f8d759ff455d3a..4c93aa4dc67c2daf161f765999b47e3c68cd5a27 100644 --- a/system/gd/rust/linux/stack/src/bluetooth_media.rs +++ b/system/gd/rust/linux/stack/src/bluetooth_media.rs @@ -14,9 +14,9 @@ use bt_topshim::profiles::avrcp::{ }; use bt_topshim::profiles::hfp::interop_insert_call_when_sco_start; use bt_topshim::profiles::hfp::{ - BthfAudioState, BthfConnectionState, CallHoldCommand, CallInfo, CallSource, CallState, Hfp, - HfpCallbacks, HfpCallbacksDispatcher, HfpCodecCapability, HfpCodecId, PhoneState, - TelephonyDeviceStatus, + BthfAudioState, BthfConnectionState, CallHoldCommand, CallInfo, CallSource, CallState, + EscoCodingFormat, Hfp, HfpCallbacks, HfpCallbacksDispatcher, HfpCodecBitId, HfpCodecFormat, + HfpCodecId, PhoneState, TelephonyDeviceStatus, }; use bt_topshim::profiles::ProfileConnectionState; use bt_topshim::{metrics, topstack}; @@ -129,7 +129,7 @@ pub trait IBluetoothMedia { &mut self, address: String, sco_offload: bool, - disabled_codecs: HfpCodecCapability, + disabled_codecs: HfpCodecBitId, ) -> bool; fn stop_sco_call(&mut self, address: String); @@ -247,7 +247,7 @@ pub struct BluetoothAudioDevice { pub address: String, pub name: String, pub a2dp_caps: Vec<A2dpCodecConfig>, - pub hfp_cap: HfpCodecCapability, + pub hfp_cap: HfpCodecFormat, pub absolute_volume: bool, } @@ -256,7 +256,7 @@ impl BluetoothAudioDevice { address: String, name: String, a2dp_caps: Vec<A2dpCodecConfig>, - hfp_cap: HfpCodecCapability, + hfp_cap: HfpCodecFormat, absolute_volume: bool, ) -> BluetoothAudioDevice { BluetoothAudioDevice { address, name, a2dp_caps, hfp_cap, absolute_volume } @@ -304,7 +304,7 @@ pub struct BluetoothMedia { hfp_states: HashMap<RawAddress, BthfConnectionState>, hfp_audio_state: HashMap<RawAddress, BthfAudioState>, a2dp_caps: HashMap<RawAddress, Vec<A2dpCodecConfig>>, - hfp_cap: HashMap<RawAddress, HfpCodecCapability>, + hfp_cap: HashMap<RawAddress, HfpCodecFormat>, fallback_tasks: Arc<Mutex<HashMap<RawAddress, Option<(JoinHandle<()>, Instant)>>>>, absolute_volume: bool, uinput: UInput, @@ -711,7 +711,7 @@ impl BluetoothMedia { // The device may not support codec-negotiation, // in which case we shall assume it supports CVSD at this point. if !self.hfp_cap.contains_key(&addr) { - self.hfp_cap.insert(addr, HfpCodecCapability::CVSD); + self.hfp_cap.insert(addr, HfpCodecFormat::CVSD); } self.add_connected_profile(addr, uuid::Profile::Hfp); @@ -719,11 +719,7 @@ impl BluetoothMedia { // This is only used for Bluetooth HFP qualification. if self.mps_qualification_enabled && self.phone_state.num_active > 0 { debug!("[{}]: Connect SCO due to active call.", DisplayAddress(&addr)); - self.start_sco_call_impl( - addr.to_string(), - false, - HfpCodecCapability::NONE, - ); + self.start_sco_call_impl(addr.to_string(), false, HfpCodecBitId::NONE); } self.uhid_create(addr); @@ -910,32 +906,55 @@ impl BluetoothMedia { .set_battery_info(self.battery_provider_id, battery_set); } HfpCallbacks::WbsCapsUpdate(wbs_supported, addr) => { + let is_transparent_coding_format_supported = match &self.adapter { + Some(adapter) => adapter + .lock() + .unwrap() + .is_coding_format_supported(EscoCodingFormat::TRANSPARENT), + _ => false, + }; + + let is_msbc_coding_format_supported = match &self.adapter { + Some(adapter) => { + adapter.lock().unwrap().is_coding_format_supported(EscoCodingFormat::MSBC) + } + _ => false, + }; + + let mut codec_diff = HfpCodecFormat::NONE; + if is_transparent_coding_format_supported { + codec_diff |= HfpCodecFormat::MSBC_TRANSPARENT; + } + if is_msbc_coding_format_supported { + codec_diff |= HfpCodecFormat::MSBC; + } + if let Some(cur_hfp_cap) = self.hfp_cap.get_mut(&addr) { if wbs_supported { - *cur_hfp_cap |= HfpCodecCapability::MSBC; - } else if (*cur_hfp_cap & HfpCodecCapability::MSBC) == HfpCodecCapability::MSBC - { - *cur_hfp_cap ^= HfpCodecCapability::MSBC; + *cur_hfp_cap |= codec_diff; + } else { + *cur_hfp_cap &= !codec_diff; } } else { let new_hfp_cap = match wbs_supported { - true => HfpCodecCapability::CVSD | HfpCodecCapability::MSBC, - false => HfpCodecCapability::CVSD, + true => HfpCodecFormat::CVSD | codec_diff, + false => HfpCodecFormat::CVSD, }; self.hfp_cap.insert(addr, new_hfp_cap); } } HfpCallbacks::SwbCapsUpdate(swb_supported, addr) => { + // LC3 can be propagated to this point only if adapter supports transparent mode. if let Some(cur_hfp_cap) = self.hfp_cap.get_mut(&addr) { if swb_supported { - *cur_hfp_cap |= HfpCodecCapability::LC3; - } else if (*cur_hfp_cap & HfpCodecCapability::LC3) == HfpCodecCapability::LC3 { - *cur_hfp_cap ^= HfpCodecCapability::LC3; + *cur_hfp_cap |= HfpCodecFormat::LC3_TRANSPARENT; + } else { + *cur_hfp_cap &= !HfpCodecFormat::LC3_TRANSPARENT; } } else { let new_hfp_cap = match swb_supported { - true => HfpCodecCapability::CVSD | HfpCodecCapability::LC3, - false => HfpCodecCapability::CVSD, + true => HfpCodecFormat::CVSD | HfpCodecFormat::LC3_TRANSPARENT, + false => HfpCodecFormat::CVSD, }; self.hfp_cap.insert(addr, new_hfp_cap); } @@ -994,7 +1013,7 @@ impl BluetoothMedia { if self.mps_qualification_enabled { debug!("[{}]: Start SCO call due to ATA", DisplayAddress(&addr)); - self.start_sco_call_impl(addr.to_string(), false, HfpCodecCapability::NONE); + self.start_sco_call_impl(addr.to_string(), false, HfpCodecBitId::NONE); } self.uhid_send_input_report(&addr); } @@ -1599,7 +1618,7 @@ impl BluetoothMedia { addr.to_string(), name.clone(), cur_a2dp_caps.unwrap_or(&Vec::new()).to_vec(), - *cur_hfp_cap.unwrap_or(&HfpCodecCapability::NONE), + *cur_hfp_cap.unwrap_or(&HfpCodecFormat::NONE), absolute_volume, ); @@ -1799,7 +1818,7 @@ impl BluetoothMedia { &mut self, address: String, sco_offload: bool, - disabled_codecs: HfpCodecCapability, + disabled_codecs: HfpCodecBitId, ) -> bool { match (|| -> Result<(), &str> { let addr = RawAddress::from_string(address.clone()) @@ -2756,7 +2775,7 @@ impl IBluetoothMedia for BluetoothMedia { &mut self, address: String, sco_offload: bool, - disabled_codecs: HfpCodecCapability, + disabled_codecs: HfpCodecBitId, ) -> bool { self.start_sco_call_impl(address, sco_offload, disabled_codecs) } @@ -2791,16 +2810,33 @@ impl IBluetoothMedia for BluetoothMedia { match self.hfp_audio_state.get(&addr) { Some(BthfAudioState::Connected) => match self.hfp_cap.get(&addr) { - Some(caps) if (*caps & HfpCodecCapability::LC3) == HfpCodecCapability::LC3 => 4, - Some(caps) if (*caps & HfpCodecCapability::MSBC) == HfpCodecCapability::MSBC => 2, - Some(caps) if (*caps & HfpCodecCapability::CVSD) == HfpCodecCapability::CVSD => 1, + Some(caps) + if (*caps & HfpCodecFormat::LC3_TRANSPARENT) + == HfpCodecFormat::LC3_TRANSPARENT => + { + HfpCodecBitId::LC3 + } + Some(caps) if (*caps & HfpCodecFormat::MSBC) == HfpCodecFormat::MSBC => { + HfpCodecBitId::MSBC + } + Some(caps) + if (*caps & HfpCodecFormat::MSBC_TRANSPARENT) + == HfpCodecFormat::MSBC_TRANSPARENT => + { + HfpCodecBitId::MSBC + } + Some(caps) if (*caps & HfpCodecFormat::CVSD) == HfpCodecFormat::CVSD => { + HfpCodecBitId::CVSD + } _ => { warn!("hfp_cap not found, fallback to CVSD."); - 1 + HfpCodecBitId::CVSD } }, - _ => 0, + _ => HfpCodecBitId::NONE, } + .try_into() + .unwrap() } fn get_presentation_position(&mut self) -> PresentationPosition { @@ -3029,7 +3065,7 @@ impl IBluetoothTelephony for BluetoothMedia { } }) { info!("Start SCO call due to call answered"); - self.start_sco_call_impl(addr.to_string(), false, HfpCodecCapability::NONE); + self.start_sco_call_impl(addr.to_string(), false, HfpCodecBitId::NONE); } } @@ -3090,7 +3126,7 @@ impl IBluetoothTelephony for BluetoothMedia { } fn audio_connect(&mut self, address: String) -> bool { - self.start_sco_call_impl(address, false, HfpCodecCapability::NONE) + self.start_sco_call_impl(address, false, HfpCodecBitId::NONE) } fn audio_disconnect(&mut self, address: String) { diff --git a/system/gd/rust/topshim/src/btif.rs b/system/gd/rust/topshim/src/btif.rs index 6ac58ee379f7cb5f46e7f877bad7a9d0c6144aed..5620932cda112fee58a1bf77afce4a9b5e100ce5 100644 --- a/system/gd/rust/topshim/src/btif.rs +++ b/system/gd/rust/topshim/src/btif.rs @@ -1327,6 +1327,10 @@ impl BluetoothInterface { ccall!(self, get_swb_supported) } + pub fn is_coding_format_supported(&self, coding_format: u8) -> bool { + ccall!(self, is_coding_format_supported, coding_format) + } + pub fn le_rand(&self) -> i32 { ccall!(self, le_rand) } diff --git a/system/gd/rust/topshim/src/profiles/hfp.rs b/system/gd/rust/topshim/src/profiles/hfp.rs index 3017986aa125cba6092954b0c6834ea0f024bebb..4ea72e959e7fc4ce0c1122f6a3e0164b400e3786 100644 --- a/system/gd/rust/topshim/src/profiles/hfp.rs +++ b/system/gd/rust/topshim/src/profiles/hfp.rs @@ -11,6 +11,7 @@ use topshim_macros::{cb_variant, profile_enabled_or}; use log::warn; #[derive(Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd, Clone)] +#[repr(u8)] pub enum HfpCodecId { NONE = 0x00, CVSD = 0x01, @@ -18,6 +19,32 @@ pub enum HfpCodecId { LC3 = 0x03, } +#[derive(Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd, Clone)] +#[repr(u8)] +pub enum EscoCodingFormat { + ULAW = 0x00, + ALAW = 0x01, + CVSD = 0x02, + TRANSPARENT = 0x03, + LINEAR = 0x04, + MSBC = 0x05, + LC3 = 0x06, + G729A = 0x07, + VENDOR = 0xff, +} + +impl From<u8> for EscoCodingFormat { + fn from(item: u8) -> Self { + EscoCodingFormat::from_u8(item).unwrap() + } +} + +impl From<EscoCodingFormat> for u8 { + fn from(item: EscoCodingFormat) -> Self { + item as u8 + } +} + #[derive(Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd, Clone)] #[repr(u32)] pub enum BthfConnectionState { @@ -49,24 +76,58 @@ impl From<u32> for BthfAudioState { } } +// This is used for codec-negotiation related methods that do not +// concern with the coding format. Do not confuse this with |HfpCodecFormat|. +bitflags! { + #[derive(Default)] + pub struct HfpCodecBitId: i32 { + const NONE = 0b000; + const CVSD = 0b001; + const MSBC = 0b010; + const LC3 = 0b100; + } +} + +impl TryInto<u8> for HfpCodecBitId { + type Error = (); + fn try_into(self) -> Result<u8, Self::Error> { + Ok(self.bits().try_into().unwrap()) + } +} + +impl TryInto<i32> for HfpCodecBitId { + type Error = (); + fn try_into(self) -> Result<i32, Self::Error> { + Ok(self.bits()) + } +} + +impl TryFrom<i32> for HfpCodecBitId { + type Error = (); + fn try_from(val: i32) -> Result<Self, Self::Error> { + Self::from_bits(val).ok_or(()) + } +} + bitflags! { #[derive(Default)] - pub struct HfpCodecCapability: i32 { - const NONE = 0b00; - const CVSD = 0b01; - const MSBC = 0b10; - const LC3 = 0b100; + pub struct HfpCodecFormat: i32 { + const NONE = 0b0000; + const CVSD = 0b0001; + const MSBC_TRANSPARENT = 0b0010; + const MSBC = 0b0100; + const LC3_TRANSPARENT = 0b1000; } } -impl TryInto<i32> for HfpCodecCapability { +impl TryInto<i32> for HfpCodecFormat { type Error = (); fn try_into(self) -> Result<i32, Self::Error> { Ok(self.bits()) } } -impl TryFrom<i32> for HfpCodecCapability { +impl TryFrom<i32> for HfpCodecFormat { type Error = (); fn try_from(val: i32) -> Result<Self, Self::Error> { Self::from_bits(val).ok_or(()) diff --git a/system/include/hardware/bluetooth.h b/system/include/hardware/bluetooth.h index 57c59645db25c7c7f7578de9f809da19acb2f390..aabe594abce63da0b54304f7889fe459478f64ad 100644 --- a/system/include/hardware/bluetooth.h +++ b/system/include/hardware/bluetooth.h @@ -942,6 +942,13 @@ typedef struct { */ bool (*get_swb_supported)(); + /** + * + * Is the specified coding format supported by the adapter + * + */ + bool (*is_coding_format_supported)(uint8_t coding_format); + /** * Data passed from BluetoothDevice.metadata_changed * diff --git a/system/stack/btm/btm_sco_hfp_hal.cc b/system/stack/btm/btm_sco_hfp_hal.cc index 9e2496ebd0e45dd16695146e2effc0d68450162a..e10a92148d9df752b2d05a8bd5d6e02d8d6ac105 100644 --- a/system/stack/btm/btm_sco_hfp_hal.cc +++ b/system/stack/btm/btm_sco_hfp_hal.cc @@ -48,6 +48,11 @@ void init() { cached_codecs.emplace_back(msbc); } +// This is not used in Android. +bool is_coding_format_supported(esco_coding_format_t coding_format) { + return true; +} + // Android statically compiles WBS support. bool get_wbs_supported() { return !DISABLE_WBS; } diff --git a/system/stack/btm/btm_sco_hfp_hal.h b/system/stack/btm/btm_sco_hfp_hal.h index 741aa6853f7a3331c50410d7472da2168d4e81c8..624f387bc43f0cefae2b04dffd9954d3622d8fd1 100644 --- a/system/stack/btm/btm_sco_hfp_hal.h +++ b/system/stack/btm/btm_sco_hfp_hal.h @@ -69,6 +69,9 @@ constexpr inline int esco_coding_to_codec(esco_coding_format_t esco_coding) { // Initialize the SCO HFP HAL module void init(); +// Check if specified coding format is supported by the adapter. +bool is_coding_format_supported(esco_coding_format_t coding_format); + // Check if wideband speech is supported on local device. bool get_wbs_supported(); diff --git a/system/stack/btm/btm_sco_hfp_hal_linux.cc b/system/stack/btm/btm_sco_hfp_hal_linux.cc index 236b6c00de36d1150df0eb604b7cf989193dc0d0..655b41b25b32db4f139fe54dae7099e9d47bc870 100644 --- a/system/stack/btm/btm_sco_hfp_hal_linux.cc +++ b/system/stack/btm/btm_sco_hfp_hal_linux.cc @@ -319,25 +319,37 @@ void init() { close(fd); } -// Check if wideband speech is supported on local device -bool get_wbs_supported() { +// Check if the specified coding format is supported by the adapter. +bool is_coding_format_supported(esco_coding_format_t coding_format) { + if (coding_format != ESCO_CODING_FORMAT_TRANSPNT && + coding_format != ESCO_CODING_FORMAT_MSBC) { + log::warn("Unsupported coding format to query: {}", coding_format); + return false; + } + for (cached_codec_info c : cached_codecs) { - if (c.inner.codec == MSBC || c.inner.codec == MSBC_TRANSPARENT) { + if (c.inner.codec == MSBC_TRANSPARENT && + coding_format == ESCO_CODING_FORMAT_TRANSPNT) { + return true; + } + if (c.inner.codec == MSBC && coding_format == ESCO_CODING_FORMAT_MSBC) { return true; } } + return false; } +// Check if wideband speech is supported on local device +bool get_wbs_supported() { + return is_coding_format_supported(ESCO_CODING_FORMAT_TRANSPNT) || + is_coding_format_supported(ESCO_CODING_FORMAT_MSBC); +} + // Check if super-wideband speech is supported on local device bool get_swb_supported() { - for (cached_codec_info c : cached_codecs) { - // SWB runs on the same path as MSBC non-offload. - if (c.inner.codec == MSBC_TRANSPARENT) { - return true; - } - } - return false; + // We only support SWB via transparent mode. + return is_coding_format_supported(ESCO_CODING_FORMAT_TRANSPNT); } // Checks the supported codecs diff --git a/system/test/mock/mock_stack_btm_sco_hfp_hal.cc b/system/test/mock/mock_stack_btm_sco_hfp_hal.cc index 96d18afe24a738b0131889bd4aac74c522f2c9fb..1083a3601afaccfb2f3bf209ccfc0ce8755b8322 100644 --- a/system/test/mock/mock_stack_btm_sco_hfp_hal.cc +++ b/system/test/mock/mock_stack_btm_sco_hfp_hal.cc @@ -47,6 +47,7 @@ struct init init; struct notify_sco_connection_change notify_sco_connection_change; struct set_codec_datapath set_codec_datapath; struct update_esco_parameters update_esco_parameters; +struct is_coding_format_supported is_coding_format_supported; } // namespace stack_btm_sco_hfp_hal } // namespace mock @@ -64,6 +65,7 @@ bool get_offload_supported::return_value = false; int get_packet_size::return_value = 0; bool get_wbs_supported::return_value = false; bool get_swb_supported::return_value = false; +bool is_coding_format_supported::return_value = false; } // namespace stack_btm_sco_hfp_hal } // namespace mock @@ -100,6 +102,11 @@ bool get_swb_supported() { inc_func_call_count(__func__); return test::mock::stack_btm_sco_hfp_hal::get_swb_supported(); } +bool is_coding_format_supported(esco_coding_format_t coding_format) { + inc_func_call_count(__func__); + return test::mock::stack_btm_sco_hfp_hal::is_coding_format_supported( + coding_format); +} void init() { inc_func_call_count(__func__); test::mock::stack_btm_sco_hfp_hal::init(); diff --git a/system/test/mock/mock_stack_btm_sco_hfp_hal.h b/system/test/mock/mock_stack_btm_sco_hfp_hal.h index fdabd2b150240e8dc69d50341c657659ef3d8955..9474d4c9c62d43b86878e70b7d7f8ed50c957a14 100644 --- a/system/test/mock/mock_stack_btm_sco_hfp_hal.h +++ b/system/test/mock/mock_stack_btm_sco_hfp_hal.h @@ -114,6 +114,19 @@ struct get_swb_supported { }; extern struct get_swb_supported get_swb_supported; +// Name: is_coding_format_supported +// Params: esco_coding_format_t coding_format +// Return: bool +struct is_coding_format_supported { + static bool return_value; + std::function<bool(esco_coding_format_t coding_format)> body{ + [](esco_coding_format_t /* coding_format */) { return return_value; }}; + bool operator()(esco_coding_format_t coding_format) { + return body(coding_format); + }; +}; +extern struct is_coding_format_supported is_coding_format_supported; + // Name: init // Params: // Return: void