Root-Canal: Handle eSCO disconnection requests
Bug: 209800014
Tag: #feature
Test: cert/run
Change-Id: I16891dd50a40a36544149fc731cdb84947c80871
diff --git a/system/vendor_libs/test_vendor_lib/model/controller/acl_connection_handler.cc b/system/vendor_libs/test_vendor_lib/model/controller/acl_connection_handler.cc
index cd5af7a..d8bc019 100644
--- a/system/vendor_libs/test_vendor_lib/model/controller/acl_connection_handler.cc
+++ b/system/vendor_libs/test_vendor_lib/model/controller/acl_connection_handler.cc
@@ -31,8 +31,12 @@
return acl_connections_.count(handle) != 0;
}
+bool AclConnectionHandler::HasScoHandle(uint16_t handle) const {
+ return sco_connections_.count(handle) != 0;
+}
+
uint16_t AclConnectionHandler::GetUnusedHandle() {
- while (HasHandle(last_handle_) ||
+ while (HasHandle(last_handle_) || HasScoHandle(last_handle_) ||
isochronous_connection_handler_.HasHandle(last_handle_)) {
last_handle_ = (last_handle_ + 1) % kReservedHandle;
}
@@ -131,7 +135,18 @@
}
bool AclConnectionHandler::Disconnect(uint16_t handle) {
- return acl_connections_.erase(handle) > 0;
+ if (HasScoHandle(handle)) {
+ sco_connections_.erase(handle);
+ return true;
+ }
+ if (HasHandle(handle)) {
+ // It is the responsibility of the caller to remove SCO connections
+ // with connected peer first.
+ ASSERT(GetScoHandle(GetAddress(handle).GetAddress()) == 0);
+ acl_connections_.erase(handle);
+ return true;
+ }
+ return false;
}
uint16_t AclConnectionHandler::GetHandle(AddressWithType addr) const {
@@ -154,12 +169,17 @@
}
AddressWithType AclConnectionHandler::GetAddress(uint16_t handle) const {
- ASSERT_LOG(HasHandle(handle), "Handle unknown %hd", handle);
+ ASSERT_LOG(HasHandle(handle), "Unknown handle %hd", handle);
return acl_connections_.at(handle).GetAddress();
}
+Address AclConnectionHandler::GetScoAddress(uint16_t handle) const {
+ ASSERT_LOG(HasScoHandle(handle), "Unknown SCO handle %hd", handle);
+ return sco_connections_.at(handle).GetAddress();
+}
+
AddressWithType AclConnectionHandler::GetOwnAddress(uint16_t handle) const {
- ASSERT_LOG(HasHandle(handle), "Handle unknown %hd", handle);
+ ASSERT_LOG(HasHandle(handle), "Unknown handle %hd", handle);
return acl_connections_.at(handle).GetOwnAddress();
}
diff --git a/system/vendor_libs/test_vendor_lib/model/controller/acl_connection_handler.h b/system/vendor_libs/test_vendor_lib/model/controller/acl_connection_handler.h
index 83b51bf..9928137 100644
--- a/system/vendor_libs/test_vendor_lib/model/controller/acl_connection_handler.h
+++ b/system/vendor_libs/test_vendor_lib/model/controller/acl_connection_handler.h
@@ -63,10 +63,12 @@
bluetooth::hci::AddressWithType own_addr);
bool Disconnect(uint16_t handle);
bool HasHandle(uint16_t handle) const;
+ bool HasScoHandle(uint16_t handle) const;
uint16_t GetHandle(bluetooth::hci::AddressWithType addr) const;
uint16_t GetHandleOnlyAddress(bluetooth::hci::Address addr) const;
bluetooth::hci::AddressWithType GetAddress(uint16_t handle) const;
+ bluetooth::hci::Address GetScoAddress(uint16_t handle) const;
bluetooth::hci::AddressWithType GetOwnAddress(uint16_t handle) const;
void Encrypt(uint16_t handle);
diff --git a/system/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.cc b/system/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.cc
index 60caf9f..c86269b 100644
--- a/system/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.cc
+++ b/system/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.cc
@@ -568,6 +568,7 @@
void DualModeController::ReadLocalSupportedFeatures(CommandView command) {
auto command_view = gd_hci::ReadLocalSupportedFeaturesView::Create(command);
ASSERT(command_view.IsValid());
+
auto packet =
bluetooth::hci::ReadLocalSupportedFeaturesCompleteBuilder::Create(
kNumCommandPackets, ErrorCode::SUCCESS,
diff --git a/system/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.cc b/system/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.cc
index f2f9e64..27db9ee 100644
--- a/system/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.cc
+++ b/system/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.cc
@@ -16,6 +16,7 @@
#include "link_layer_controller.h"
+#include <cinttypes>
#include <hci/hci_packets.h>
#include "crypto_toolbox/crypto_toolbox.h"
@@ -390,6 +391,9 @@
case model::packets::PacketType::ESCO_CONNECTION_RESPONSE:
IncomingEScoConnectionResponse(incoming);
break;
+ case model::packets::PacketType::ESCO_DISCONNECT:
+ IncomingEScoDisconnect(incoming);
+ break;
default:
LOG_WARN("Dropping unhandled packet of type %s",
@@ -627,8 +631,7 @@
"GetHandle() returned invalid handle %hx", handle);
uint8_t reason = disconnect.GetReason();
- ScheduleTask(kShortDelayMs,
- [this, handle, reason]() { DisconnectCleanup(handle, reason); });
+ SendDisconnectionCompleteEvent(handle, reason);
}
void LinkLayerController::IncomingEncryptConnection(
@@ -1370,23 +1373,37 @@
Address address = incoming.GetSourceAddress();
auto request = model::packets::EScoConnectionRequestView::Create(incoming);
+ ASSERT(request.IsValid());
+
+ LOG_INFO("Received eSCO connection request from %s",
+ address.ToString().c_str());
// Automatically reject if connection request was already sent
// from the current device.
if (connections_.HasPendingScoConnection(address)) {
- auto packet = model::packets::EScoConnectionResponseBuilder::Create(
- properties_.GetLeAddress(), address,
- (uint8_t)ErrorCode::SYNCHRONOUS_CONNECTION_LIMIT_EXCEEDED, 0, 0, 0, 0, 0);
- SendLinkLayerPacket(std::move(packet));
+ LOG_INFO("Rejecting eSCO connection request from %s, "
+ "an eSCO connection already exist with this device",
+ address.ToString().c_str());
+
+ SendLinkLayerPacket(model::packets::EScoConnectionResponseBuilder::Create(
+ properties_.GetLeAddress(), address,
+ (uint8_t)ErrorCode::SYNCHRONOUS_CONNECTION_LIMIT_EXCEEDED,
+ 0, 0, 0, 0, 0));
return;
}
- // Send connection request event to use and wait for Accept or Reject
- // command.
- auto packet = bluetooth::hci::ConnectionRequestBuilder::Create(
+ // Create local connection context.
+ ScoConnectionParameters connection_parameters = {
+ request.GetTransmitBandwidth(), request.GetReceiveBandwidth(),
+ request.GetMaxLatency(), request.GetVoiceSetting(),
+ request.GetRetransmissionEffort(), request.GetPacketType()
+ };
+ connections_.CreatePendingScoConnection(address, connection_parameters);
+
+ // Send connection request event and wait for Accept or Reject command.
+ send_event_(bluetooth::hci::ConnectionRequestBuilder::Create(
address, ClassOfDevice(),
- bluetooth::hci::ConnectionRequestLinkType::ESCO);
- send_event_(std::move(packet));
+ bluetooth::hci::ConnectionRequestLinkType::ESCO));
}
void LinkLayerController::IncomingEScoConnectionResponse(
@@ -1394,8 +1411,12 @@
Address address = incoming.GetSourceAddress();
auto response = model::packets::EScoConnectionResponseView::Create(incoming);
+ ASSERT(response.IsValid());
auto status = response.GetStatus();
+ LOG_INFO("Received eSCO connection response with status %" PRIx8 " from %s",
+ status, incoming.GetSourceAddress().ToString().c_str());
+
if (status == (uint8_t)ErrorCode::SUCCESS) {
ScoLinkParameters link_parameters = {
response.GetTransmissionInterval(),
@@ -1405,23 +1426,38 @@
response.GetAirMode(),
};
connections_.AcceptPendingScoConnection(address, link_parameters);
- auto packet = bluetooth::hci::SynchronousConnectionCompleteBuilder::Create(
- ErrorCode(status), connections_.GetScoHandle(address), address,
- bluetooth::hci::ScoLinkType::ESCO,
- response.GetTransmissionInterval(),
- response.GetRetransmissionWindow(),
- response.GetRxPacketLength(),
- response.GetTxPacketLength(),
- bluetooth::hci::ScoAirMode(response.GetAirMode()));
-
- send_event_(std::move(packet));
+ send_event_(bluetooth::hci::SynchronousConnectionCompleteBuilder::Create(
+ ErrorCode(status), connections_.GetScoHandle(address), address,
+ bluetooth::hci::ScoLinkType::ESCO,
+ response.GetTransmissionInterval(),
+ response.GetRetransmissionWindow(),
+ response.GetRxPacketLength(),
+ response.GetTxPacketLength(),
+ bluetooth::hci::ScoAirMode(response.GetAirMode())));
} else {
connections_.CancelPendingScoConnection(address);
- auto packet = bluetooth::hci::SynchronousConnectionCompleteBuilder::Create(
- ErrorCode(status), 0, address, bluetooth::hci::ScoLinkType::ESCO,
- 0, 0, 0, 0, bluetooth::hci::ScoAirMode::TRANSPARENT);
+ send_event_(bluetooth::hci::SynchronousConnectionCompleteBuilder::Create(
+ ErrorCode(status), 0, address, bluetooth::hci::ScoLinkType::ESCO,
+ 0, 0, 0, 0, bluetooth::hci::ScoAirMode::TRANSPARENT));
+ }
+}
- send_event_(std::move(packet));
+void LinkLayerController::IncomingEScoDisconnect(
+ model::packets::LinkLayerPacketView incoming) {
+
+ Address address = incoming.GetSourceAddress();
+ auto request = model::packets::EScoDisconnectView::Create(incoming);
+ ASSERT(request.IsValid());
+ auto reason = request.GetReason();
+ uint16_t handle = connections_.GetScoHandle(address);
+
+ LOG_INFO("Received eSCO disconnection request with"
+ " reason 0x%" PRIx8 " from %s",
+ reason, incoming.GetSourceAddress().ToString().c_str());
+
+ if (handle != 0) {
+ connections_.Disconnect(handle);
+ SendDisconnectionCompleteEvent(handle, reason);
}
}
@@ -2546,39 +2582,67 @@
return ErrorCode::SUCCESS;
}
+void LinkLayerController::SendDisconnectionCompleteEvent(
+ uint16_t handle, uint8_t reason)
+{
+ if (properties_.IsUnmasked(EventCode::DISCONNECTION_COMPLETE)) {
+ ScheduleTask(kShortDelayMs, [this, handle, reason]() {
+ send_event_(bluetooth::hci::DisconnectionCompleteBuilder::Create(
+ ErrorCode::SUCCESS, handle, ErrorCode(reason)));
+ });
+ }
+}
+
ErrorCode LinkLayerController::Disconnect(uint16_t handle, uint8_t reason) {
+ if (connections_.HasScoHandle(handle)) {
+ const Address remote = connections_.GetScoAddress(handle);
+ LOG_INFO("Disconnecting eSCO connection with %s",
+ remote.ToString().c_str());
+
+ SendLinkLayerPacket(model::packets::EScoDisconnectBuilder::Create(
+ properties_.GetAddress(), remote, reason));
+
+ connections_.Disconnect(handle);
+ SendDisconnectionCompleteEvent(handle, reason);
+ return ErrorCode::SUCCESS;
+ }
+
if (!connections_.HasHandle(handle)) {
return ErrorCode::UNKNOWN_CONNECTION;
}
const AddressWithType remote = connections_.GetAddress(handle);
+
if (connections_.GetPhyType(handle) == Phy::Type::BR_EDR) {
+ LOG_INFO("Disconnecting ACL connection with %s",
+ remote.ToString().c_str());
+
+ uint16_t sco_handle = connections_.GetScoHandle(remote.GetAddress());
+ if (sco_handle != 0) {
+ SendLinkLayerPacket(model::packets::EScoDisconnectBuilder::Create(
+ properties_.GetAddress(), remote.GetAddress(), reason));
+
+ connections_.Disconnect(sco_handle);
+ SendDisconnectionCompleteEvent(sco_handle, reason);
+ }
+
SendLinkLayerPacket(model::packets::DisconnectBuilder::Create(
properties_.GetAddress(), remote.GetAddress(), reason));
+
} else {
+ LOG_INFO("Disconnecting LE connection with %s",
+ remote.ToString().c_str());
+
SendLeLinkLayerPacket(model::packets::DisconnectBuilder::Create(
connections_.GetOwnAddress(handle).GetAddress(), remote.GetAddress(),
reason));
}
- ASSERT_LOG(connections_.Disconnect(handle), "Disconnecting %hx", handle);
- ScheduleTask(kShortDelayMs, [this, handle]() {
- DisconnectCleanup(
- handle,
- static_cast<uint8_t>(ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST));
- });
-
+ connections_.Disconnect(handle);
+ SendDisconnectionCompleteEvent(handle, reason);
return ErrorCode::SUCCESS;
}
-void LinkLayerController::DisconnectCleanup(uint16_t handle, uint8_t reason) {
- // TODO: Clean up other connection state.
- if (properties_.IsUnmasked(EventCode::DISCONNECTION_COMPLETE)) {
- send_event_(bluetooth::hci::DisconnectionCompleteBuilder::Create(
- ErrorCode::SUCCESS, handle, static_cast<ErrorCode>(reason)));
- }
-}
-
ErrorCode LinkLayerController::ChangeConnectionPacketType(uint16_t handle,
uint16_t types) {
if (!connections_.HasHandle(handle)) {
@@ -3515,6 +3579,7 @@
if (!connections_.HasHandle(connection_handle)) {
return ErrorCode::UNKNOWN_CONNECTION;
}
+
Address bd_addr = connections_.GetAddress(connection_handle).GetAddress();
if (connections_.HasPendingScoConnection(bd_addr)) {
// This command may be used to modify an exising eSCO link.
@@ -3523,6 +3588,8 @@
return ErrorCode::COMMAND_DISALLOWED;
}
+ LOG_INFO("Creating eSCO connection with %s", bd_addr.ToString().c_str());
+
// Save connection parameters.
ScoConnectionParameters connection_parameters = {
transmit_bandwidth, receive_bandwidth, max_latency,
@@ -3533,11 +3600,10 @@
connection_parameters);
// Send eSCO connection request to peer.
- auto packet = model::packets::EScoConnectionRequestBuilder::Create(
- properties_.GetAddress(), bd_addr,
- transmit_bandwidth, receive_bandwidth, max_latency,
- voice_setting, retransmission_effort, packet_types);
- SendLinkLayerPacket(std::move(packet));
+ SendLinkLayerPacket(model::packets::EScoConnectionRequestBuilder::Create(
+ properties_.GetAddress(), bd_addr,
+ transmit_bandwidth, receive_bandwidth, max_latency,
+ voice_setting, retransmission_effort, packet_types));
return ErrorCode::SUCCESS;
}
@@ -3550,7 +3616,12 @@
uint8_t retransmission_effort,
uint16_t packet_types) {
+ LOG_INFO("Accepting eSCO connection request from %s",
+ bd_addr.ToString().c_str());
+
if (!connections_.HasPendingScoConnection(bd_addr)) {
+ LOG_INFO("No pending eSCO connection for %s",
+ bd_addr.ToString().c_str());
return ErrorCode::COMMAND_DISALLOWED;
}
@@ -3571,27 +3642,26 @@
}
// Send eSCO connection response to peer.
- auto packet = model::packets::EScoConnectionResponseBuilder::Create(
- properties_.GetAddress(), bd_addr, (uint8_t)status,
- link_parameters.transmission_interval,
- link_parameters.retransmission_window,
- link_parameters.rx_packet_length,
- link_parameters.tx_packet_length,
- link_parameters.air_mode);
- SendLinkLayerPacket(std::move(packet));
+ SendLinkLayerPacket(model::packets::EScoConnectionResponseBuilder::Create(
+ properties_.GetAddress(), bd_addr, (uint8_t)status,
+ link_parameters.transmission_interval,
+ link_parameters.retransmission_window,
+ link_parameters.rx_packet_length,
+ link_parameters.tx_packet_length,
+ link_parameters.air_mode));
// Schedule HCI Synchronous Connection Complete event.
ScheduleTask(kShortDelayMs,
[this, status, sco_handle, bd_addr, link_parameters]() {
- auto packet = bluetooth::hci::SynchronousConnectionCompleteBuilder::Create(
- ErrorCode(status), sco_handle, bd_addr,
- bluetooth::hci::ScoLinkType::ESCO,
- link_parameters.transmission_interval,
- link_parameters.retransmission_window,
- link_parameters.rx_packet_length,
- link_parameters.tx_packet_length,
- bluetooth::hci::ScoAirMode(link_parameters.air_mode));
- send_event_(std::move(packet));
+ send_event_(
+ bluetooth::hci::SynchronousConnectionCompleteBuilder::Create(
+ ErrorCode(status), sco_handle, bd_addr,
+ bluetooth::hci::ScoLinkType::ESCO,
+ link_parameters.transmission_interval,
+ link_parameters.retransmission_window,
+ link_parameters.rx_packet_length,
+ link_parameters.tx_packet_length,
+ bluetooth::hci::ScoAirMode(link_parameters.air_mode)));
});
return ErrorCode::SUCCESS;
@@ -3601,6 +3671,9 @@
Address bd_addr,
uint16_t reason) {
+ LOG_INFO("Rejecting eSCO connection request from %s",
+ bd_addr.ToString().c_str());
+
if (reason == (uint8_t)ErrorCode::SUCCESS) {
reason = (uint8_t)ErrorCode::REMOTE_USER_TERMINATED_CONNECTION;
}
@@ -3611,16 +3684,14 @@
connections_.CancelPendingScoConnection(bd_addr);
// Send eSCO connection response to peer.
- auto packet = model::packets::EScoConnectionResponseBuilder::Create(
- properties_.GetAddress(), bd_addr, reason, 0, 0, 0, 0, 0);
- SendLinkLayerPacket(std::move(packet));
+ SendLinkLayerPacket(model::packets::EScoConnectionResponseBuilder::Create(
+ properties_.GetAddress(), bd_addr, reason, 0, 0, 0, 0, 0));
// Schedule HCI Synchronous Connection Complete event.
ScheduleTask(kShortDelayMs, [this, reason, bd_addr]() {
- auto packet = bluetooth::hci::SynchronousConnectionCompleteBuilder::Create(
- ErrorCode(reason), 0, bd_addr, bluetooth::hci::ScoLinkType::ESCO,
- 0, 0, 0, 0, bluetooth::hci::ScoAirMode::TRANSPARENT);
- send_event_(std::move(packet));
+ send_event_(bluetooth::hci::SynchronousConnectionCompleteBuilder::Create(
+ ErrorCode(reason), 0, bd_addr, bluetooth::hci::ScoLinkType::ESCO,
+ 0, 0, 0, 0, bluetooth::hci::ScoAirMode::TRANSPARENT));
});
return ErrorCode::SUCCESS;
diff --git a/system/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.h b/system/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.h
index 23c36b4..71bfd5e 100644
--- a/system/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.h
+++ b/system/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.h
@@ -95,7 +95,7 @@
ErrorCode Disconnect(uint16_t handle, uint8_t reason);
private:
- void DisconnectCleanup(uint16_t handle, uint8_t reason);
+ void SendDisconnectionCompleteEvent(uint16_t handle, uint8_t reason);
public:
void IncomingPacket(model::packets::LinkLayerPacketView incoming);
@@ -446,6 +446,7 @@
model::packets::LinkLayerPacketView packet);
void IncomingEScoConnectionResponse(
model::packets::LinkLayerPacketView packet);
+ void IncomingEScoDisconnect(model::packets::LinkLayerPacketView packet);
private:
const DeviceProperties& properties_;
diff --git a/system/vendor_libs/test_vendor_lib/model/controller/sco_connection.cc b/system/vendor_libs/test_vendor_lib/model/controller/sco_connection.cc
index 2d080c9..ab5e0cb 100644
--- a/system/vendor_libs/test_vendor_lib/model/controller/sco_connection.cc
+++ b/system/vendor_libs/test_vendor_lib/model/controller/sco_connection.cc
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <cinttypes>
#include <vector>
#include <hci/hci_packets.h>
@@ -68,21 +69,24 @@
if (tx.length == 0)
continue;
- unsigned tx_count = (transmit_bandwidth + tx.length - 1) / tx.length;
- unsigned tx_max_interval = 1600 / tx_count;
+ unsigned tx_max_interval = (1600 * tx.length) / transmit_bandwidth;
for (auto rx : accepted_packets) {
if (rx.length == 0)
continue;
- unsigned rx_count = (receive_bandwidth + rx.length - 1) / rx.length;
- unsigned rx_max_interval = 1600 / rx_count;
+ LOG_INFO("Testing combination %u/%u : %u/%u",
+ tx.length, tx.slots, rx.length, rx.slots);
+
+ unsigned rx_max_interval = (1600 * rx.length) / receive_bandwidth;
// Choose the best interval satisfying both.
unsigned transmission_interval = std::min(tx_max_interval, rx_max_interval);
transmission_interval -= transmission_interval % 2;
transmission_interval = std::min(transmission_interval, 254u);
+ LOG_INFO("Transmission interval: %u slots", transmission_interval);
+
// Compute retransmission window.
unsigned retransmission_window =
retransmission_effort == (uint8_t)RetransmissionEffort::NO_RETRANSMISSION ? 0 :
@@ -91,6 +95,8 @@
retransmission_effort == (uint8_t)RetransmissionEffort::OPTIMIZED_FOR_LINK_QUALITY ?
rx.slots + tx.slots : 0;
+ LOG_INFO("Retransmission window: %u slots", retransmission_window);
+
// Compute transmission window and validate latency.
unsigned transmission_window = tx.slots + rx.slots +
retransmission_window;
@@ -102,7 +108,10 @@
// Compute and validate latency.
unsigned latency = (transmission_window * 1250) / 2;
- if (latency > max_latency)
+
+ LOG_INFO("Latency: %u us (max %u us)", latency, max_latency * 1000u);
+
+ if (latency > (1000 * max_latency))
// Oops
continue;
@@ -112,17 +121,28 @@
(double)transmission_window / (double)transmission_interval;
if (bandwidth_usage < best_bandwidth_usage) {
+ LOG_INFO("Valid combination!");
+
uint16_t tx_packet_length =
(transmit_bandwidth * transmission_interval + 1600 - 1) / 1600;
uint16_t rx_packet_length =
(receive_bandwidth * transmission_interval + 1600 - 1) / 1600;
- uint8_t air_mode = voice_setting & 0x3;
+
+ uint8_t air_coding = voice_setting & 0x3;
+ uint8_t air_coding_to_air_mode[] = {
+ 0x02, // CVSD
+ 0x00, // u-law
+ 0x01, // A-law
+ 0x03, // transparent data
+ };
best_bandwidth_usage = bandwidth_usage;
best_parameters = {
(uint8_t)transmission_interval,
(uint8_t)retransmission_window,
- rx_packet_length, tx_packet_length, air_mode };
+ rx_packet_length, tx_packet_length,
+ air_coding_to_air_mode[air_coding]
+ };
}
}
}
@@ -134,26 +154,28 @@
if (peer.transmit_bandwidth != 0xffff &&
peer.transmit_bandwidth != parameters_.receive_bandwidth) {
- LOG_WARN("transmit bandwidth requirements cannot be met");
+ LOG_WARN("Transmit bandwidth requirements cannot be met");
return false;
}
if (peer.receive_bandwidth != 0xffff &&
peer.receive_bandwidth != parameters_.transmit_bandwidth) {
- LOG_WARN("receive bandwidth requirements cannot be met");
+ LOG_WARN("Receive bandwidth requirements cannot be met");
return false;
}
if (peer.voice_setting != parameters_.voice_setting) {
- LOG_WARN("voice setting requirements cannot be met");
+ LOG_WARN("Voice setting requirements cannot be met");
return false;
}
- uint16_t packet_type = peer.packet_type & parameters_.packet_type & 0x3f;
- packet_type |= ~peer.packet_type & ~parameters_.packet_type & 0x3c0;
+ uint16_t packet_type = (peer.packet_type & parameters_.packet_type) & 0x3f;
+ packet_type |= (peer.packet_type | parameters_.packet_type) & 0x3c0;
if (packet_type == 0) {
- LOG_WARN("packet type requirements cannot be met");
+ LOG_WARN("Packet type requirements cannot be met");
+ LOG_WARN("Remote packet type: %" PRIx16, parameters_.packet_type);
+ LOG_WARN("Local packet type: %" PRIx16, peer.packet_type);
return false;
}
@@ -170,7 +192,7 @@
retransmission_effort = peer.retransmission_effort;
else if (peer.retransmission_effort == (uint8_t)RetransmissionEffort::NO_RETRANSMISSION ||
parameters_.retransmission_effort == (uint8_t)RetransmissionEffort::NO_RETRANSMISSION) {
- LOG_WARN("retransmission effort requirements cannot be met");
+ LOG_WARN("Retransmission effort requirements cannot be met");
return false;
} else {
retransmission_effort = (uint8_t)RetransmissionEffort::OPTIMIZED_FOR_POWER;
@@ -182,7 +204,20 @@
};
auto link_parameters = negotiated_parameters.GetLinkParameters();
- if (link_parameters.has_value())
+ if (link_parameters.has_value()) {
link_parameters_ = link_parameters.value();
+ LOG_INFO("Negotiated link parameters for eSCO connection:");
+ LOG_INFO(" Transmission interval: %" PRIu8 " slots",
+ link_parameters_.transmission_interval);
+ LOG_INFO(" Retransmission window: %" PRIu8 " slots",
+ link_parameters_.retransmission_window);
+ LOG_INFO(" RX packet length: %" PRIu16 " bytes",
+ link_parameters_.rx_packet_length);
+ LOG_INFO(" TX packet length: %" PRIu16 " bytes",
+ link_parameters_.tx_packet_length);
+ LOG_INFO(" Air mode: %" PRIu8, link_parameters_.air_mode);
+ } else {
+ LOG_WARN("Failed to derive link parameters");
+ }
return link_parameters.has_value();
}
diff --git a/system/vendor_libs/test_vendor_lib/model/devices/device_properties.h b/system/vendor_libs/test_vendor_lib/model/devices/device_properties.h
index fcac380..b52cef8 100644
--- a/system/vendor_libs/test_vendor_lib/model/devices/device_properties.h
+++ b/system/vendor_libs/test_vendor_lib/model/devices/device_properties.h
@@ -405,13 +405,12 @@
uint8_t lmp_pal_version_;
uint16_t manufacturer_name_;
uint16_t lmp_pal_subversion_;
- uint64_t supported_features_{};
uint64_t event_mask_{0x00001fffffffffff};
uint8_t authentication_enable_{};
std::vector<uint8_t> supported_codecs_;
std::vector<uint32_t> vendor_specific_codecs_;
std::array<uint8_t, 64> supported_commands_;
- std::vector<uint64_t> extended_features_{{0x875b3fd8fe8ffeff, 0x04}};
+ std::vector<uint64_t> extended_features_{{0x875bffdbfe8ffeff, 0x04}};
ClassOfDevice class_of_device_{{0, 0, 0}};
std::vector<uint8_t> extended_inquiry_data_;
std::array<uint8_t, 248> name_{};
diff --git a/system/vendor_libs/test_vendor_lib/packets/link_layer_packets.pdl b/system/vendor_libs/test_vendor_lib/packets/link_layer_packets.pdl
index 882b23e..74b2b05 100644
--- a/system/vendor_libs/test_vendor_lib/packets/link_layer_packets.pdl
+++ b/system/vendor_libs/test_vendor_lib/packets/link_layer_packets.pdl
@@ -55,6 +55,7 @@
ESCO_CONNECTION_REQUEST = 0x30,
ESCO_CONNECTION_RESPONSE = 0x31,
+ ESCO_DISCONNECT = 0x32,
}
packet LinkLayerPacket {
@@ -399,3 +400,7 @@
tx_packet_length : 16,
air_mode : 8,
}
+
+packet EScoDisconnect : LinkLayerPacket (type = ESCO_DISCONNECT) {
+ reason : 8,
+}