Loading system/bta/le_audio/devices.cc +160 −44 Original line number Original line Diff line number Diff line Loading @@ -1384,7 +1384,6 @@ static uint32_t GetFirstLeft(const types::AudioLocations& audio_locations) { if (audio_location_ulong & codec_spec_conf::kLeAudioLocationLeftSurround) if (audio_location_ulong & codec_spec_conf::kLeAudioLocationLeftSurround) return codec_spec_conf::kLeAudioLocationLeftSurround; return codec_spec_conf::kLeAudioLocationLeftSurround; LOG_WARN("Can't find device able to render left audio channel"); return 0; return 0; } } Loading Loading @@ -1422,15 +1421,15 @@ static uint32_t GetFirstRight(const types::AudioLocations& audio_locations) { if (audio_location_ulong & codec_spec_conf::kLeAudioLocationRightSurround) if (audio_location_ulong & codec_spec_conf::kLeAudioLocationRightSurround) return codec_spec_conf::kLeAudioLocationRightSurround; return codec_spec_conf::kLeAudioLocationRightSurround; LOG_WARN("Can't find device able to render right audio channel"); return 0; return 0; } } uint32_t PickAudioLocation(types::LeAudioConfigurationStrategy strategy, uint32_t PickAudioLocation(types::LeAudioConfigurationStrategy strategy, types::AudioLocations device_locations, types::AudioLocations device_locations, types::AudioLocations* group_locations) { types::AudioLocations* group_locations) { LOG_DEBUG("strategy: %d, locations: %lx, group locations: %lx", (int)strategy, LOG_DEBUG("strategy: %d, locations: 0x%lx, group locations: 0x%lx", device_locations.to_ulong(), group_locations->to_ulong()); (int)strategy, device_locations.to_ulong(), group_locations->to_ulong()); auto is_left_not_yet_assigned = auto is_left_not_yet_assigned = !(group_locations->to_ulong() & codec_spec_conf::kLeAudioLocationAnyLeft); !(group_locations->to_ulong() & codec_spec_conf::kLeAudioLocationAnyLeft); Loading @@ -1439,6 +1438,10 @@ uint32_t PickAudioLocation(types::LeAudioConfigurationStrategy strategy, uint32_t left_device_loc = GetFirstLeft(device_locations); uint32_t left_device_loc = GetFirstLeft(device_locations); uint32_t right_device_loc = GetFirstRight(device_locations); uint32_t right_device_loc = GetFirstRight(device_locations); if (left_device_loc == 0 && right_device_loc == 0) { LOG_WARN("Can't find device able to render left and right audio channel"); } switch (strategy) { switch (strategy) { case types::LeAudioConfigurationStrategy::MONO_ONE_CIS_PER_DEVICE: case types::LeAudioConfigurationStrategy::MONO_ONE_CIS_PER_DEVICE: case types::LeAudioConfigurationStrategy::STEREO_TWO_CISES_PER_DEVICE: case types::LeAudioConfigurationStrategy::STEREO_TWO_CISES_PER_DEVICE: Loading Loading @@ -1496,6 +1499,12 @@ bool LeAudioDevice::ConfigureAses( return false; return false; } } /* The number_of_already_active_group_ase keeps all the active ases * in other devices in the group. * This function counts active ases only for this device, and we count here * new active ases and already active ases which we want to reuse in the * scenario */ uint8_t active_ases = *number_of_already_active_group_ase; uint8_t active_ases = *number_of_already_active_group_ase; uint8_t max_required_ase_per_dev = uint8_t max_required_ase_per_dev = ent.ase_cnt / ent.device_cnt + (ent.ase_cnt % ent.device_cnt); ent.ase_cnt / ent.device_cnt + (ent.ase_cnt % ent.device_cnt); Loading Loading @@ -1523,6 +1532,12 @@ bool LeAudioDevice::ConfigureAses( ase->configured_for_context_type = context_type; ase->configured_for_context_type = context_type; active_ases++; active_ases++; /* In case of late connect, we could be here for STREAMING ase. * in such case, it is needed to mark ase as known active ase which * is important to validate scenario and is done already few lines above. * Nothing more to do is needed here. */ if (ase->state != AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) { if (ase->state == AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED) if (ase->state == AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED) ase->reconfigure = true; ase->reconfigure = true; Loading @@ -1535,7 +1550,8 @@ bool LeAudioDevice::ConfigureAses( ase->codec_config.audio_channel_allocation = ase->codec_config.audio_channel_allocation = PickAudioLocation(strategy, audio_locations, group_audio_locations); PickAudioLocation(strategy, audio_locations, group_audio_locations); /* Get default value if no requirement for specific frame blocks per sdu */ /* Get default value if no requirement for specific frame blocks per sdu */ if (!ase->codec_config.codec_frames_blocks_per_sdu) { if (!ase->codec_config.codec_frames_blocks_per_sdu) { ase->codec_config.codec_frames_blocks_per_sdu = ase->codec_config.codec_frames_blocks_per_sdu = GetMaxCodecFramesPerSduFromPac(pac); GetMaxCodecFramesPerSduFromPac(pac); Loading @@ -1558,6 +1574,7 @@ bool LeAudioDevice::ConfigureAses( GetMetadata(AudioContexts(LeAudioContextType::UNSPECIFIED), GetMetadata(AudioContexts(LeAudioContextType::UNSPECIFIED), std::vector<uint8_t>()); std::vector<uint8_t>()); } } } LOG_DEBUG( LOG_DEBUG( "device=%s, activated ASE id=%d, direction=%s, max_sdu_size=%d, " "device=%s, activated ASE id=%d, direction=%s, max_sdu_size=%d, " Loading Loading @@ -1960,6 +1977,61 @@ bool LeAudioDeviceGroup::Configure(LeAudioContextType context_type, } } LeAudioDeviceGroup::~LeAudioDeviceGroup(void) { this->Cleanup(); } LeAudioDeviceGroup::~LeAudioDeviceGroup(void) { this->Cleanup(); } void LeAudioDeviceGroup::PrintDebugState(void) { auto* active_conf = GetActiveConfiguration(); std::stringstream debug_str; debug_str << "\n Groupd id: " << group_id_ << ", state: " << bluetooth::common::ToString(GetState()) << ", target state: " << bluetooth::common::ToString(GetTargetState()) << ", cig state: " << bluetooth::common::ToString(cig_state_) << ", \n group available contexts: " << bluetooth::common::ToString(GetAvailableContexts()) << ", \n configuration context type: " << bluetooth::common::ToString(GetConfigurationContextType()) << ", \n active configuration name: " << (active_conf ? active_conf->name : " not set"); if (cises_.size() > 0) { LOG_INFO("\n Allocated CISes: %d", static_cast<int>(cises_.size())); for (auto cis : cises_) { LOG_INFO("\n cis id: %d, type: %d, conn_handle %d, addr: %s", cis.id, cis.type, cis.conn_handle, cis.addr.ToString().c_str()); } } if (GetFirstActiveDevice() != nullptr) { uint32_t sink_delay = 0; uint32_t source_delay = 0; GetPresentationDelay(&sink_delay, le_audio::types::kLeAudioDirectionSink); GetPresentationDelay(&source_delay, le_audio::types::kLeAudioDirectionSource); auto phy_mtos = GetPhyBitmask(le_audio::types::kLeAudioDirectionSink); auto phy_stom = GetPhyBitmask(le_audio::types::kLeAudioDirectionSource); auto max_transport_latency_mtos = GetMaxTransportLatencyMtos(); auto max_transport_latency_stom = GetMaxTransportLatencyStom(); auto sdu_mts = GetSduInterval(le_audio::types::kLeAudioDirectionSink); auto sdu_stom = GetSduInterval(le_audio::types::kLeAudioDirectionSource); debug_str << "\n resentation_delay for sink (speaker): " << +sink_delay << " us, presentation_delay for source (microphone): " << +source_delay << "us, \n MtoS transport latency: " << +max_transport_latency_mtos << ", StoM transport latency: " << +max_transport_latency_stom << ", \n MtoS Phy: " << loghex(phy_mtos) << ", MtoS sdu: " << loghex(phy_stom) << " \n MtoS sdu: " << +sdu_mts << ", StoM sdu: " << +sdu_stom; } LOG_INFO("%s", debug_str.str().c_str()); for (const auto& device_iter : leAudioDevices_) { device_iter.lock()->PrintDebugState(); } } void LeAudioDeviceGroup::Dump(int fd, int active_group_id) { void LeAudioDeviceGroup::Dump(int fd, int active_group_id) { bool is_active = (group_id_ == active_group_id); bool is_active = (group_id_ == active_group_id); std::stringstream stream; std::stringstream stream; Loading Loading @@ -2454,27 +2526,71 @@ void LeAudioDevice::SetSupportedContexts(AudioContexts snk_contexts, supp_contexts_.source = src_contexts; supp_contexts_.source = src_contexts; } } void LeAudioDevice::PrintDebugState(void) { std::stringstream debug_str; debug_str << " address: " << address_ << ", " << bluetooth::common::ToString(connection_state_) << ", conn_id: " << +conn_id_ << ", mtu: " << +mtu_ << ", num_of_ase: " << static_cast<int>(ases_.size()); if (ases_.size() > 0) { debug_str << "\n == ASEs == "; for (auto& ase : ases_) { debug_str << "\n id: " << +ase.id << ", active: " << ase.active << ", dir: " << (ase.direction == types::kLeAudioDirectionSink ? "sink" : "source") << ", cis_id: " << +ase.cis_id << ", cis_handle: " << +ase.cis_conn_hdl << ", state: " << bluetooth::common::ToString(ase.data_path_state) << "\n ase max_latency: " << +ase.max_transport_latency << ", rtn: " << +ase.retrans_nb << ", max_sdu: " << +ase.max_sdu_size << ", target latency: " << +ase.target_latency; } } LOG_INFO("%s", debug_str.str().c_str()); } void LeAudioDevice::Dump(int fd) { void LeAudioDevice::Dump(int fd) { uint16_t acl_handle = BTM_GetHCIConnHandle(address_, BT_TRANSPORT_LE); uint16_t acl_handle = BTM_GetHCIConnHandle(address_, BT_TRANSPORT_LE); std::string location = "unknown location"; if (snk_audio_locations_.to_ulong() & codec_spec_conf::kLeAudioLocationAnyLeft) { std::string location_left = "left"; location.swap(location_left); } else if (snk_audio_locations_.to_ulong() & codec_spec_conf::kLeAudioLocationAnyRight) { std::string location_right = "right"; location.swap(location_right); } std::stringstream stream; std::stringstream stream; stream << std::boolalpha; stream << "\n\taddress: " << address_ << ": " << connection_state_ << ": " stream << "\n\taddress: " << address_ << ": " << connection_state_ << ": " << (conn_id_ == GATT_INVALID_CONN_ID ? "" : std::to_string(conn_id_)) << (conn_id_ == GATT_INVALID_CONN_ID ? "" : std::to_string(conn_id_)) << ", acl_handle: " << std::to_string(acl_handle) << ",\t" << ", acl_handle: " << std::to_string(acl_handle) << ", " << location << (encrypted_ ? "Encrypted" : "Unecrypted") << ",\t" << (encrypted_ ? "Encrypted" : "Unecrypted") << ",mtu: " << std::to_string(mtu_) << ",mtu: " << std::to_string(mtu_) << "\n\tnumber of ases_: " << static_cast<int>(ases_.size()); << "\n\tnumber of ases_: " << static_cast<int>(ases_.size()); if (ases_.size() > 0) { if (ases_.size() > 0) { stream << "\n\t == ASEs == "; stream << "\n\t== ASEs == \n\t"; stream << "id active dir cis_id cis_handle sdu latency rtn state"; for (auto& ase : ases_) { for (auto& ase : ases_) { stream << "\n\t id: " << static_cast<int>(ase.id) stream << std::setfill('\xA0') << "\n\t" << std::left << std::setw(4) << ",\tactive: " << ase.active << ", dir: " << static_cast<int>(ase.id) << std::left << std::setw(7) << (ase.active ? "true" : "false") << std::left << std::setw(8) << (ase.direction == types::kLeAudioDirectionSink ? "sink" << (ase.direction == types::kLeAudioDirectionSink ? "sink" : "source") : "source") << ",\tcis_id: " << static_cast<int>(ase.cis_id) << std::left << std::setw(8) << static_cast<int>(ase.cis_id) << ",\tcis_handle: " << ase.cis_conn_hdl << ",\tstate: " << std::left << std::setw(12) << ase.cis_conn_hdl << std::left << std::setw(5) << ase.max_sdu_size << std::left << std::setw(8) << ase.max_transport_latency << std::left << std::setw(5) << static_cast<int>(ase.retrans_nb) << std::left << std::setw(12) << bluetooth::common::ToString(ase.data_path_state); << bluetooth::common::ToString(ase.data_path_state); } } } } Loading system/bta/le_audio/devices.h +5 −0 Original line number Original line Diff line number Diff line Loading @@ -179,7 +179,10 @@ class LeAudioDevice { types::AudioContexts src_cont_val); types::AudioContexts src_cont_val); void DeactivateAllAses(void); void DeactivateAllAses(void); bool ActivateConfiguredAses(types::LeAudioContextType context_type); bool ActivateConfiguredAses(types::LeAudioContextType context_type); void PrintDebugState(void); void Dump(int fd); void Dump(int fd); void DisconnectAcl(void); void DisconnectAcl(void); std::vector<uint8_t> GetMetadata(types::AudioContexts context_type, std::vector<uint8_t> GetMetadata(types::AudioContexts context_type, const std::vector<uint8_t>& ccid_list); const std::vector<uint8_t>& ccid_list); Loading Loading @@ -370,6 +373,8 @@ class LeAudioDeviceGroup { bool IsInTransition(void); bool IsInTransition(void); bool IsReleasingOrIdle(void); bool IsReleasingOrIdle(void); void PrintDebugState(void); void Dump(int fd, int active_group_id); void Dump(int fd, int active_group_id); private: private: Loading system/bta/le_audio/le_audio_types.h +7 −0 Original line number Original line Diff line number Diff line Loading @@ -627,6 +627,13 @@ struct ase { data_path_state(AudioStreamDataPathState::IDLE), data_path_state(AudioStreamDataPathState::IDLE), configured_for_context_type(LeAudioContextType::UNINITIALIZED), configured_for_context_type(LeAudioContextType::UNINITIALIZED), preferred_phy(0), preferred_phy(0), max_sdu_size(0), retrans_nb(0), max_transport_latency(0), pres_delay_min(0), pres_delay_max(0), preferred_pres_delay_min(0), preferred_pres_delay_max(0), state(AseState::BTA_LE_AUDIO_ASE_STATE_IDLE) {} state(AseState::BTA_LE_AUDIO_ASE_STATE_IDLE) {} struct hdl_pair hdls; struct hdl_pair hdls; Loading system/bta/le_audio/state_machine.cc +32 −5 Original line number Original line Diff line number Diff line Loading @@ -1275,6 +1275,15 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { } } } } if ((sdu_interval_mtos == 0 && sdu_interval_stom == 0) || (max_trans_lat_mtos == le_audio::types::kMaxTransportLatencyMin && max_trans_lat_stom == le_audio::types::kMaxTransportLatencyMin) || (max_sdu_size_mtos == 0 && max_sdu_size_stom == 0)) { LOG_ERROR(" Trying to create invalid group"); group->PrintDebugState(); return false; } bluetooth::hci::iso_manager::cig_create_params param = { bluetooth::hci::iso_manager::cig_create_params param = { .sdu_itv_mtos = sdu_interval_mtos, .sdu_itv_mtos = sdu_interval_mtos, .sdu_itv_stom = sdu_interval_stom, .sdu_itv_stom = sdu_interval_stom, Loading Loading @@ -1972,6 +1981,9 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { LeAudioDevice* leAudioDevice) { LeAudioDevice* leAudioDevice) { std::vector<struct le_audio::client_parser::ascs::ctp_qos_conf> confs; std::vector<struct le_audio::client_parser::ascs::ctp_qos_conf> confs; bool validate_transport_latency = false; bool validate_max_sdu_size = false; for (struct ase* ase = leAudioDevice->GetFirstActiveAse(); ase != nullptr; for (struct ase* ase = leAudioDevice->GetFirstActiveAse(); ase != nullptr; ase = leAudioDevice->GetNextActiveAse(ase)) { ase = leAudioDevice->GetNextActiveAse(ase)) { LOG_DEBUG("device: %s, ase_id: %d, cis_id: %d, ase state: %s", LOG_DEBUG("device: %s, ase_id: %d, cis_id: %d, ase state: %s", Loading @@ -1988,14 +2000,16 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { conf.max_sdu = ase->max_sdu_size; conf.max_sdu = ase->max_sdu_size; conf.retrans_nb = ase->retrans_nb; conf.retrans_nb = ase->retrans_nb; if (!group->GetPresentationDelay(&conf.pres_delay, ase->direction)) { if (!group->GetPresentationDelay(&conf.pres_delay, ase->direction)) { LOG(ERROR) << __func__ << ", inconsistent presentation delay for group"; LOG_ERROR("inconsistent presentation delay for group"); group->PrintDebugState(); StopStream(group); StopStream(group); return; return; } } conf.sdu_interval = group->GetSduInterval(ase->direction); conf.sdu_interval = group->GetSduInterval(ase->direction); if (!conf.sdu_interval) { if (!conf.sdu_interval) { LOG(ERROR) << __func__ << ", unsupported SDU interval for group"; LOG_ERROR("unsupported SDU interval for group"); group->PrintDebugState(); StopStream(group); StopStream(group); return; return; } } Loading @@ -2005,15 +2019,28 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { } else { } else { conf.max_transport_latency = group->GetMaxTransportLatencyStom(); conf.max_transport_latency = group->GetMaxTransportLatencyStom(); } } if (conf.max_transport_latency > le_audio::types::kMaxTransportLatencyMin) { validate_transport_latency = true; } if (conf.max_sdu > 0) { validate_max_sdu_size = true; } confs.push_back(conf); confs.push_back(conf); } } LOG_ASSERT(confs.size() > 0) if (confs.size() == 0 || !validate_transport_latency || << __func__ << " shouldn't be called without an active ASE"; !validate_max_sdu_size) { LOG_ERROR("Invalid configuration or latency or sdu size"); group->PrintDebugState(); StopStream(group); return; } std::vector<uint8_t> value; std::vector<uint8_t> value; le_audio::client_parser::ascs::PrepareAseCtpConfigQos(confs, value); le_audio::client_parser::ascs::PrepareAseCtpConfigQos(confs, value); BtaGattQueue::WriteCharacteristic(leAudioDevice->conn_id_, BtaGattQueue::WriteCharacteristic(leAudioDevice->conn_id_, leAudioDevice->ctp_hdls_.val_hdl, value, leAudioDevice->ctp_hdls_.val_hdl, value, GATT_WRITE_NO_RSP, NULL, NULL); GATT_WRITE_NO_RSP, NULL, NULL); Loading system/bta/le_audio/state_machine_test.cc +7 −1 Original line number Original line Diff line number Diff line Loading @@ -865,7 +865,7 @@ class StateMachineTest : public Test { codec_configured_state_params.framing = codec_configured_state_params.framing = ascs::kAseParamFramingUnframedSupported; ascs::kAseParamFramingUnframedSupported; codec_configured_state_params.preferred_retrans_nb = 0x04; codec_configured_state_params.preferred_retrans_nb = 0x04; codec_configured_state_params.max_transport_latency = 0x0005; codec_configured_state_params.max_transport_latency = 0x0010; codec_configured_state_params.pres_delay_min = 0xABABAB; codec_configured_state_params.pres_delay_min = 0xABABAB; codec_configured_state_params.pres_delay_max = 0xCDCDCD; codec_configured_state_params.pres_delay_max = 0xCDCDCD; codec_configured_state_params.preferred_pres_delay_min = codec_configured_state_params.preferred_pres_delay_min = Loading Loading @@ -2917,6 +2917,7 @@ TEST_F(StateMachineTest, testAttachDeviceToTheStream) { auto* leAudioDevice = group->GetFirstDevice(); auto* leAudioDevice = group->GetFirstDevice(); LeAudioDevice* lastDevice; LeAudioDevice* lastDevice; LeAudioDevice* fistDevice = leAudioDevice; auto expected_devices_written = 0; auto expected_devices_written = 0; while (leAudioDevice) { while (leAudioDevice) { Loading Loading @@ -2996,6 +2997,11 @@ TEST_F(StateMachineTest, testAttachDeviceToTheStream) { auto ccids = ltv.Find(le_audio::types::kLeAudioMetadataTypeCcidList); auto ccids = ltv.Find(le_audio::types::kLeAudioMetadataTypeCcidList); ASSERT_TRUE(ccids.has_value()); ASSERT_TRUE(ccids.has_value()); ASSERT_NE(std::find(ccids->begin(), ccids->end(), media_ccid), ccids->end()); ASSERT_NE(std::find(ccids->begin(), ccids->end(), media_ccid), ccids->end()); /* Verify that ASE of first device are still good*/ auto ase = fistDevice->GetFirstActiveAse(); ASSERT_NE(ase->max_transport_latency, 0); ASSERT_NE(ase->retrans_nb, 0); } } TEST_F(StateMachineTest, StartStreamAfterConfigure) { TEST_F(StateMachineTest, StartStreamAfterConfigure) { Loading Loading
system/bta/le_audio/devices.cc +160 −44 Original line number Original line Diff line number Diff line Loading @@ -1384,7 +1384,6 @@ static uint32_t GetFirstLeft(const types::AudioLocations& audio_locations) { if (audio_location_ulong & codec_spec_conf::kLeAudioLocationLeftSurround) if (audio_location_ulong & codec_spec_conf::kLeAudioLocationLeftSurround) return codec_spec_conf::kLeAudioLocationLeftSurround; return codec_spec_conf::kLeAudioLocationLeftSurround; LOG_WARN("Can't find device able to render left audio channel"); return 0; return 0; } } Loading Loading @@ -1422,15 +1421,15 @@ static uint32_t GetFirstRight(const types::AudioLocations& audio_locations) { if (audio_location_ulong & codec_spec_conf::kLeAudioLocationRightSurround) if (audio_location_ulong & codec_spec_conf::kLeAudioLocationRightSurround) return codec_spec_conf::kLeAudioLocationRightSurround; return codec_spec_conf::kLeAudioLocationRightSurround; LOG_WARN("Can't find device able to render right audio channel"); return 0; return 0; } } uint32_t PickAudioLocation(types::LeAudioConfigurationStrategy strategy, uint32_t PickAudioLocation(types::LeAudioConfigurationStrategy strategy, types::AudioLocations device_locations, types::AudioLocations device_locations, types::AudioLocations* group_locations) { types::AudioLocations* group_locations) { LOG_DEBUG("strategy: %d, locations: %lx, group locations: %lx", (int)strategy, LOG_DEBUG("strategy: %d, locations: 0x%lx, group locations: 0x%lx", device_locations.to_ulong(), group_locations->to_ulong()); (int)strategy, device_locations.to_ulong(), group_locations->to_ulong()); auto is_left_not_yet_assigned = auto is_left_not_yet_assigned = !(group_locations->to_ulong() & codec_spec_conf::kLeAudioLocationAnyLeft); !(group_locations->to_ulong() & codec_spec_conf::kLeAudioLocationAnyLeft); Loading @@ -1439,6 +1438,10 @@ uint32_t PickAudioLocation(types::LeAudioConfigurationStrategy strategy, uint32_t left_device_loc = GetFirstLeft(device_locations); uint32_t left_device_loc = GetFirstLeft(device_locations); uint32_t right_device_loc = GetFirstRight(device_locations); uint32_t right_device_loc = GetFirstRight(device_locations); if (left_device_loc == 0 && right_device_loc == 0) { LOG_WARN("Can't find device able to render left and right audio channel"); } switch (strategy) { switch (strategy) { case types::LeAudioConfigurationStrategy::MONO_ONE_CIS_PER_DEVICE: case types::LeAudioConfigurationStrategy::MONO_ONE_CIS_PER_DEVICE: case types::LeAudioConfigurationStrategy::STEREO_TWO_CISES_PER_DEVICE: case types::LeAudioConfigurationStrategy::STEREO_TWO_CISES_PER_DEVICE: Loading Loading @@ -1496,6 +1499,12 @@ bool LeAudioDevice::ConfigureAses( return false; return false; } } /* The number_of_already_active_group_ase keeps all the active ases * in other devices in the group. * This function counts active ases only for this device, and we count here * new active ases and already active ases which we want to reuse in the * scenario */ uint8_t active_ases = *number_of_already_active_group_ase; uint8_t active_ases = *number_of_already_active_group_ase; uint8_t max_required_ase_per_dev = uint8_t max_required_ase_per_dev = ent.ase_cnt / ent.device_cnt + (ent.ase_cnt % ent.device_cnt); ent.ase_cnt / ent.device_cnt + (ent.ase_cnt % ent.device_cnt); Loading Loading @@ -1523,6 +1532,12 @@ bool LeAudioDevice::ConfigureAses( ase->configured_for_context_type = context_type; ase->configured_for_context_type = context_type; active_ases++; active_ases++; /* In case of late connect, we could be here for STREAMING ase. * in such case, it is needed to mark ase as known active ase which * is important to validate scenario and is done already few lines above. * Nothing more to do is needed here. */ if (ase->state != AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) { if (ase->state == AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED) if (ase->state == AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED) ase->reconfigure = true; ase->reconfigure = true; Loading @@ -1535,7 +1550,8 @@ bool LeAudioDevice::ConfigureAses( ase->codec_config.audio_channel_allocation = ase->codec_config.audio_channel_allocation = PickAudioLocation(strategy, audio_locations, group_audio_locations); PickAudioLocation(strategy, audio_locations, group_audio_locations); /* Get default value if no requirement for specific frame blocks per sdu */ /* Get default value if no requirement for specific frame blocks per sdu */ if (!ase->codec_config.codec_frames_blocks_per_sdu) { if (!ase->codec_config.codec_frames_blocks_per_sdu) { ase->codec_config.codec_frames_blocks_per_sdu = ase->codec_config.codec_frames_blocks_per_sdu = GetMaxCodecFramesPerSduFromPac(pac); GetMaxCodecFramesPerSduFromPac(pac); Loading @@ -1558,6 +1574,7 @@ bool LeAudioDevice::ConfigureAses( GetMetadata(AudioContexts(LeAudioContextType::UNSPECIFIED), GetMetadata(AudioContexts(LeAudioContextType::UNSPECIFIED), std::vector<uint8_t>()); std::vector<uint8_t>()); } } } LOG_DEBUG( LOG_DEBUG( "device=%s, activated ASE id=%d, direction=%s, max_sdu_size=%d, " "device=%s, activated ASE id=%d, direction=%s, max_sdu_size=%d, " Loading Loading @@ -1960,6 +1977,61 @@ bool LeAudioDeviceGroup::Configure(LeAudioContextType context_type, } } LeAudioDeviceGroup::~LeAudioDeviceGroup(void) { this->Cleanup(); } LeAudioDeviceGroup::~LeAudioDeviceGroup(void) { this->Cleanup(); } void LeAudioDeviceGroup::PrintDebugState(void) { auto* active_conf = GetActiveConfiguration(); std::stringstream debug_str; debug_str << "\n Groupd id: " << group_id_ << ", state: " << bluetooth::common::ToString(GetState()) << ", target state: " << bluetooth::common::ToString(GetTargetState()) << ", cig state: " << bluetooth::common::ToString(cig_state_) << ", \n group available contexts: " << bluetooth::common::ToString(GetAvailableContexts()) << ", \n configuration context type: " << bluetooth::common::ToString(GetConfigurationContextType()) << ", \n active configuration name: " << (active_conf ? active_conf->name : " not set"); if (cises_.size() > 0) { LOG_INFO("\n Allocated CISes: %d", static_cast<int>(cises_.size())); for (auto cis : cises_) { LOG_INFO("\n cis id: %d, type: %d, conn_handle %d, addr: %s", cis.id, cis.type, cis.conn_handle, cis.addr.ToString().c_str()); } } if (GetFirstActiveDevice() != nullptr) { uint32_t sink_delay = 0; uint32_t source_delay = 0; GetPresentationDelay(&sink_delay, le_audio::types::kLeAudioDirectionSink); GetPresentationDelay(&source_delay, le_audio::types::kLeAudioDirectionSource); auto phy_mtos = GetPhyBitmask(le_audio::types::kLeAudioDirectionSink); auto phy_stom = GetPhyBitmask(le_audio::types::kLeAudioDirectionSource); auto max_transport_latency_mtos = GetMaxTransportLatencyMtos(); auto max_transport_latency_stom = GetMaxTransportLatencyStom(); auto sdu_mts = GetSduInterval(le_audio::types::kLeAudioDirectionSink); auto sdu_stom = GetSduInterval(le_audio::types::kLeAudioDirectionSource); debug_str << "\n resentation_delay for sink (speaker): " << +sink_delay << " us, presentation_delay for source (microphone): " << +source_delay << "us, \n MtoS transport latency: " << +max_transport_latency_mtos << ", StoM transport latency: " << +max_transport_latency_stom << ", \n MtoS Phy: " << loghex(phy_mtos) << ", MtoS sdu: " << loghex(phy_stom) << " \n MtoS sdu: " << +sdu_mts << ", StoM sdu: " << +sdu_stom; } LOG_INFO("%s", debug_str.str().c_str()); for (const auto& device_iter : leAudioDevices_) { device_iter.lock()->PrintDebugState(); } } void LeAudioDeviceGroup::Dump(int fd, int active_group_id) { void LeAudioDeviceGroup::Dump(int fd, int active_group_id) { bool is_active = (group_id_ == active_group_id); bool is_active = (group_id_ == active_group_id); std::stringstream stream; std::stringstream stream; Loading Loading @@ -2454,27 +2526,71 @@ void LeAudioDevice::SetSupportedContexts(AudioContexts snk_contexts, supp_contexts_.source = src_contexts; supp_contexts_.source = src_contexts; } } void LeAudioDevice::PrintDebugState(void) { std::stringstream debug_str; debug_str << " address: " << address_ << ", " << bluetooth::common::ToString(connection_state_) << ", conn_id: " << +conn_id_ << ", mtu: " << +mtu_ << ", num_of_ase: " << static_cast<int>(ases_.size()); if (ases_.size() > 0) { debug_str << "\n == ASEs == "; for (auto& ase : ases_) { debug_str << "\n id: " << +ase.id << ", active: " << ase.active << ", dir: " << (ase.direction == types::kLeAudioDirectionSink ? "sink" : "source") << ", cis_id: " << +ase.cis_id << ", cis_handle: " << +ase.cis_conn_hdl << ", state: " << bluetooth::common::ToString(ase.data_path_state) << "\n ase max_latency: " << +ase.max_transport_latency << ", rtn: " << +ase.retrans_nb << ", max_sdu: " << +ase.max_sdu_size << ", target latency: " << +ase.target_latency; } } LOG_INFO("%s", debug_str.str().c_str()); } void LeAudioDevice::Dump(int fd) { void LeAudioDevice::Dump(int fd) { uint16_t acl_handle = BTM_GetHCIConnHandle(address_, BT_TRANSPORT_LE); uint16_t acl_handle = BTM_GetHCIConnHandle(address_, BT_TRANSPORT_LE); std::string location = "unknown location"; if (snk_audio_locations_.to_ulong() & codec_spec_conf::kLeAudioLocationAnyLeft) { std::string location_left = "left"; location.swap(location_left); } else if (snk_audio_locations_.to_ulong() & codec_spec_conf::kLeAudioLocationAnyRight) { std::string location_right = "right"; location.swap(location_right); } std::stringstream stream; std::stringstream stream; stream << std::boolalpha; stream << "\n\taddress: " << address_ << ": " << connection_state_ << ": " stream << "\n\taddress: " << address_ << ": " << connection_state_ << ": " << (conn_id_ == GATT_INVALID_CONN_ID ? "" : std::to_string(conn_id_)) << (conn_id_ == GATT_INVALID_CONN_ID ? "" : std::to_string(conn_id_)) << ", acl_handle: " << std::to_string(acl_handle) << ",\t" << ", acl_handle: " << std::to_string(acl_handle) << ", " << location << (encrypted_ ? "Encrypted" : "Unecrypted") << ",\t" << (encrypted_ ? "Encrypted" : "Unecrypted") << ",mtu: " << std::to_string(mtu_) << ",mtu: " << std::to_string(mtu_) << "\n\tnumber of ases_: " << static_cast<int>(ases_.size()); << "\n\tnumber of ases_: " << static_cast<int>(ases_.size()); if (ases_.size() > 0) { if (ases_.size() > 0) { stream << "\n\t == ASEs == "; stream << "\n\t== ASEs == \n\t"; stream << "id active dir cis_id cis_handle sdu latency rtn state"; for (auto& ase : ases_) { for (auto& ase : ases_) { stream << "\n\t id: " << static_cast<int>(ase.id) stream << std::setfill('\xA0') << "\n\t" << std::left << std::setw(4) << ",\tactive: " << ase.active << ", dir: " << static_cast<int>(ase.id) << std::left << std::setw(7) << (ase.active ? "true" : "false") << std::left << std::setw(8) << (ase.direction == types::kLeAudioDirectionSink ? "sink" << (ase.direction == types::kLeAudioDirectionSink ? "sink" : "source") : "source") << ",\tcis_id: " << static_cast<int>(ase.cis_id) << std::left << std::setw(8) << static_cast<int>(ase.cis_id) << ",\tcis_handle: " << ase.cis_conn_hdl << ",\tstate: " << std::left << std::setw(12) << ase.cis_conn_hdl << std::left << std::setw(5) << ase.max_sdu_size << std::left << std::setw(8) << ase.max_transport_latency << std::left << std::setw(5) << static_cast<int>(ase.retrans_nb) << std::left << std::setw(12) << bluetooth::common::ToString(ase.data_path_state); << bluetooth::common::ToString(ase.data_path_state); } } } } Loading
system/bta/le_audio/devices.h +5 −0 Original line number Original line Diff line number Diff line Loading @@ -179,7 +179,10 @@ class LeAudioDevice { types::AudioContexts src_cont_val); types::AudioContexts src_cont_val); void DeactivateAllAses(void); void DeactivateAllAses(void); bool ActivateConfiguredAses(types::LeAudioContextType context_type); bool ActivateConfiguredAses(types::LeAudioContextType context_type); void PrintDebugState(void); void Dump(int fd); void Dump(int fd); void DisconnectAcl(void); void DisconnectAcl(void); std::vector<uint8_t> GetMetadata(types::AudioContexts context_type, std::vector<uint8_t> GetMetadata(types::AudioContexts context_type, const std::vector<uint8_t>& ccid_list); const std::vector<uint8_t>& ccid_list); Loading Loading @@ -370,6 +373,8 @@ class LeAudioDeviceGroup { bool IsInTransition(void); bool IsInTransition(void); bool IsReleasingOrIdle(void); bool IsReleasingOrIdle(void); void PrintDebugState(void); void Dump(int fd, int active_group_id); void Dump(int fd, int active_group_id); private: private: Loading
system/bta/le_audio/le_audio_types.h +7 −0 Original line number Original line Diff line number Diff line Loading @@ -627,6 +627,13 @@ struct ase { data_path_state(AudioStreamDataPathState::IDLE), data_path_state(AudioStreamDataPathState::IDLE), configured_for_context_type(LeAudioContextType::UNINITIALIZED), configured_for_context_type(LeAudioContextType::UNINITIALIZED), preferred_phy(0), preferred_phy(0), max_sdu_size(0), retrans_nb(0), max_transport_latency(0), pres_delay_min(0), pres_delay_max(0), preferred_pres_delay_min(0), preferred_pres_delay_max(0), state(AseState::BTA_LE_AUDIO_ASE_STATE_IDLE) {} state(AseState::BTA_LE_AUDIO_ASE_STATE_IDLE) {} struct hdl_pair hdls; struct hdl_pair hdls; Loading
system/bta/le_audio/state_machine.cc +32 −5 Original line number Original line Diff line number Diff line Loading @@ -1275,6 +1275,15 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { } } } } if ((sdu_interval_mtos == 0 && sdu_interval_stom == 0) || (max_trans_lat_mtos == le_audio::types::kMaxTransportLatencyMin && max_trans_lat_stom == le_audio::types::kMaxTransportLatencyMin) || (max_sdu_size_mtos == 0 && max_sdu_size_stom == 0)) { LOG_ERROR(" Trying to create invalid group"); group->PrintDebugState(); return false; } bluetooth::hci::iso_manager::cig_create_params param = { bluetooth::hci::iso_manager::cig_create_params param = { .sdu_itv_mtos = sdu_interval_mtos, .sdu_itv_mtos = sdu_interval_mtos, .sdu_itv_stom = sdu_interval_stom, .sdu_itv_stom = sdu_interval_stom, Loading Loading @@ -1972,6 +1981,9 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { LeAudioDevice* leAudioDevice) { LeAudioDevice* leAudioDevice) { std::vector<struct le_audio::client_parser::ascs::ctp_qos_conf> confs; std::vector<struct le_audio::client_parser::ascs::ctp_qos_conf> confs; bool validate_transport_latency = false; bool validate_max_sdu_size = false; for (struct ase* ase = leAudioDevice->GetFirstActiveAse(); ase != nullptr; for (struct ase* ase = leAudioDevice->GetFirstActiveAse(); ase != nullptr; ase = leAudioDevice->GetNextActiveAse(ase)) { ase = leAudioDevice->GetNextActiveAse(ase)) { LOG_DEBUG("device: %s, ase_id: %d, cis_id: %d, ase state: %s", LOG_DEBUG("device: %s, ase_id: %d, cis_id: %d, ase state: %s", Loading @@ -1988,14 +2000,16 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { conf.max_sdu = ase->max_sdu_size; conf.max_sdu = ase->max_sdu_size; conf.retrans_nb = ase->retrans_nb; conf.retrans_nb = ase->retrans_nb; if (!group->GetPresentationDelay(&conf.pres_delay, ase->direction)) { if (!group->GetPresentationDelay(&conf.pres_delay, ase->direction)) { LOG(ERROR) << __func__ << ", inconsistent presentation delay for group"; LOG_ERROR("inconsistent presentation delay for group"); group->PrintDebugState(); StopStream(group); StopStream(group); return; return; } } conf.sdu_interval = group->GetSduInterval(ase->direction); conf.sdu_interval = group->GetSduInterval(ase->direction); if (!conf.sdu_interval) { if (!conf.sdu_interval) { LOG(ERROR) << __func__ << ", unsupported SDU interval for group"; LOG_ERROR("unsupported SDU interval for group"); group->PrintDebugState(); StopStream(group); StopStream(group); return; return; } } Loading @@ -2005,15 +2019,28 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { } else { } else { conf.max_transport_latency = group->GetMaxTransportLatencyStom(); conf.max_transport_latency = group->GetMaxTransportLatencyStom(); } } if (conf.max_transport_latency > le_audio::types::kMaxTransportLatencyMin) { validate_transport_latency = true; } if (conf.max_sdu > 0) { validate_max_sdu_size = true; } confs.push_back(conf); confs.push_back(conf); } } LOG_ASSERT(confs.size() > 0) if (confs.size() == 0 || !validate_transport_latency || << __func__ << " shouldn't be called without an active ASE"; !validate_max_sdu_size) { LOG_ERROR("Invalid configuration or latency or sdu size"); group->PrintDebugState(); StopStream(group); return; } std::vector<uint8_t> value; std::vector<uint8_t> value; le_audio::client_parser::ascs::PrepareAseCtpConfigQos(confs, value); le_audio::client_parser::ascs::PrepareAseCtpConfigQos(confs, value); BtaGattQueue::WriteCharacteristic(leAudioDevice->conn_id_, BtaGattQueue::WriteCharacteristic(leAudioDevice->conn_id_, leAudioDevice->ctp_hdls_.val_hdl, value, leAudioDevice->ctp_hdls_.val_hdl, value, GATT_WRITE_NO_RSP, NULL, NULL); GATT_WRITE_NO_RSP, NULL, NULL); Loading
system/bta/le_audio/state_machine_test.cc +7 −1 Original line number Original line Diff line number Diff line Loading @@ -865,7 +865,7 @@ class StateMachineTest : public Test { codec_configured_state_params.framing = codec_configured_state_params.framing = ascs::kAseParamFramingUnframedSupported; ascs::kAseParamFramingUnframedSupported; codec_configured_state_params.preferred_retrans_nb = 0x04; codec_configured_state_params.preferred_retrans_nb = 0x04; codec_configured_state_params.max_transport_latency = 0x0005; codec_configured_state_params.max_transport_latency = 0x0010; codec_configured_state_params.pres_delay_min = 0xABABAB; codec_configured_state_params.pres_delay_min = 0xABABAB; codec_configured_state_params.pres_delay_max = 0xCDCDCD; codec_configured_state_params.pres_delay_max = 0xCDCDCD; codec_configured_state_params.preferred_pres_delay_min = codec_configured_state_params.preferred_pres_delay_min = Loading Loading @@ -2917,6 +2917,7 @@ TEST_F(StateMachineTest, testAttachDeviceToTheStream) { auto* leAudioDevice = group->GetFirstDevice(); auto* leAudioDevice = group->GetFirstDevice(); LeAudioDevice* lastDevice; LeAudioDevice* lastDevice; LeAudioDevice* fistDevice = leAudioDevice; auto expected_devices_written = 0; auto expected_devices_written = 0; while (leAudioDevice) { while (leAudioDevice) { Loading Loading @@ -2996,6 +2997,11 @@ TEST_F(StateMachineTest, testAttachDeviceToTheStream) { auto ccids = ltv.Find(le_audio::types::kLeAudioMetadataTypeCcidList); auto ccids = ltv.Find(le_audio::types::kLeAudioMetadataTypeCcidList); ASSERT_TRUE(ccids.has_value()); ASSERT_TRUE(ccids.has_value()); ASSERT_NE(std::find(ccids->begin(), ccids->end(), media_ccid), ccids->end()); ASSERT_NE(std::find(ccids->begin(), ccids->end(), media_ccid), ccids->end()); /* Verify that ASE of first device are still good*/ auto ase = fistDevice->GetFirstActiveAse(); ASSERT_NE(ase->max_transport_latency, 0); ASSERT_NE(ase->retrans_nb, 0); } } TEST_F(StateMachineTest, StartStreamAfterConfigure) { TEST_F(StateMachineTest, StartStreamAfterConfigure) { Loading