blob: 6801dd16baa24acb41bcf590f5280ec6f673062a [file] [log] [blame]
/*
* Copyright 2020 HIMSA II K/S - www.himsa.com. Represented by EHIMA
* - www.ehima.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <map>
#include <memory>
#include <optional>
#include <tuple>
#include <vector>
#include "bt_types.h"
#include "bta_groups.h"
#include "btm_iso_api_types.h"
#include "client_audio.h"
#include "gatt_api.h"
#include "le_audio_types.h"
#include "osi/include/alarm.h"
#include "raw_address.h"
namespace le_audio {
/* Class definitions */
/* LeAudioDevice class represents GATT server device with ASCS, PAC services as
* mandatory. Device may contain multiple ASEs, PACs, audio locations. ASEs from
* multiple devices may be formed in group.
*
* Device is created after connection or after storage restoration.
*
* Active device means that device has at least one ASE which will participate
* in any state transition of state machine. ASEs and devices will be activated
* according to requested by upper context type.
*/
class LeAudioDevice {
public:
RawAddress address_;
bool known_service_handles_;
bool notify_connected_after_read_;
bool removing_device_;
/* we are making active attempt to connect to this device, 'direct connect'.
* This is true only during initial phase of first connection. */
bool first_connection_;
bool connecting_actively_;
uint16_t conn_id_;
bool encrypted_;
int group_id_;
bool csis_member_;
uint8_t audio_directions_;
types::AudioLocations snk_audio_locations_;
types::AudioLocations src_audio_locations_;
types::PublishedAudioCapabilities snk_pacs_;
types::PublishedAudioCapabilities src_pacs_;
struct types::hdl_pair snk_audio_locations_hdls_;
struct types::hdl_pair src_audio_locations_hdls_;
struct types::hdl_pair audio_avail_hdls_;
struct types::hdl_pair audio_supp_cont_hdls_;
std::vector<struct types::ase> ases_;
struct types::hdl_pair ctp_hdls_;
alarm_t* link_quality_timer;
uint16_t link_quality_timer_data;
LeAudioDevice(const RawAddress& address_, bool first_connection,
int group_id = bluetooth::groups::kGroupUnknown)
: address_(address_),
known_service_handles_(false),
notify_connected_after_read_(false),
removing_device_(false),
first_connection_(first_connection),
connecting_actively_(first_connection),
conn_id_(GATT_INVALID_CONN_ID),
encrypted_(false),
group_id_(group_id),
csis_member_(false),
audio_directions_(0),
link_quality_timer(nullptr) {}
~LeAudioDevice(void);
void ClearPACs(void);
void RegisterPACs(std::vector<struct types::acs_ac_record>* apr_db,
std::vector<struct types::acs_ac_record>* apr);
struct types::ase* GetAseByValHandle(uint16_t val_hdl);
struct types::ase* GetFirstActiveAse(void);
struct types::ase* GetFirstActiveAseByDirection(uint8_t direction);
struct types::ase* GetNextActiveAseWithSameDirection(
struct types::ase* base_ase);
struct types::ase* GetFirstActiveAseByDataPathState(
types::AudioStreamDataPathState state);
struct types::ase* GetFirstInactiveAse(uint8_t direction,
bool reconnect = false);
struct types::ase* GetFirstInactiveAseWithState(uint8_t direction,
types::AseState state);
struct types::ase* GetNextActiveAse(struct types::ase* ase);
struct types::ase* GetAseToMatchBidirectionCis(struct types::ase* ase);
types::BidirectAsesPair GetAsesByCisConnHdl(uint16_t conn_hdl);
types::BidirectAsesPair GetAsesByCisId(uint8_t cis_id);
bool HaveActiveAse(void);
bool HaveAllActiveAsesSameState(types::AseState state);
bool HaveAnyUnconfiguredAses(void);
bool IsReadyToCreateStream(void);
bool IsReadyToSuspendStream(void);
bool HaveAllActiveAsesCisEst(void);
bool HaveAllAsesCisDisc(void);
bool HasCisId(uint8_t id);
uint8_t GetMatchingBidirectionCisId(const struct types::ase* base_ase);
bool IsCodecConfigurationSupported(
uint8_t direction, const set_configurations::CodecCapabilitySetting&
codec_capability_setting);
uint8_t GetLc3SupportedChannelCount(uint8_t direction);
uint8_t GetPhyBitmask(void);
bool ConfigureAses(const le_audio::set_configurations::SetConfiguration& ent,
types::LeAudioContextType context_type,
uint8_t* number_of_already_active_group_ase,
types::AudioLocations& group_snk_audio_locations,
types::AudioLocations& group_src_audio_locations,
bool reconnect = false);
void SetSupportedContexts(types::AudioContexts snk_contexts,
types::AudioContexts src_contexts);
types::AudioContexts GetAvailableContexts(void);
types::AudioContexts SetAvailableContexts(types::AudioContexts snk_cont_val,
types::AudioContexts src_cont_val);
void DeactivateAllAses(void);
void Dump(int fd);
std::vector<uint8_t> GetMetadata(types::LeAudioContextType context_type);
bool IsMetadataChanged(types::LeAudioContextType context_type);
private:
types::AudioContexts avail_snk_contexts_;
types::AudioContexts avail_src_contexts_;
types::AudioContexts supp_snk_context_;
types::AudioContexts supp_src_context_;
};
/* LeAudioDevices class represents a wraper helper over all devices in le audio
* implementation. It allows to operate on device from a list (vector container)
* using determinants like address, connection id etc.
*/
class LeAudioDevices {
public:
void Add(const RawAddress& address, bool first_connection,
int group_id = bluetooth::groups::kGroupUnknown);
void Remove(const RawAddress& address);
LeAudioDevice* FindByAddress(const RawAddress& address);
std::shared_ptr<LeAudioDevice> GetByAddress(const RawAddress& address);
LeAudioDevice* FindByConnId(uint16_t conn_id);
LeAudioDevice* FindByCisConnHdl(const uint16_t conn_hdl);
size_t Size(void);
void Dump(int fd, int group_id);
void Cleanup(void);
private:
std::vector<std::shared_ptr<LeAudioDevice>> leAudioDevices_;
};
/* LeAudioDeviceGroup class represents group of LeAudioDevices and allows to
* perform operations on them. Group states are ASE states due to nature of
* group which operates finally of ASEs.
*
* Group is created after adding a node to new group id (which is not on list).
*/
class LeAudioDeviceGroup {
public:
const int group_id_;
bool cig_created_;
struct stream_configuration stream_conf;
uint8_t audio_directions_;
types::AudioLocations snk_audio_locations_;
types::AudioLocations src_audio_locations_;
explicit LeAudioDeviceGroup(const int group_id)
: group_id_(group_id),
cig_created_(false),
audio_directions_(0),
transport_latency_mtos_(0),
transport_latency_stom_(0),
active_context_type_(types::LeAudioContextType::UNINITIALIZED),
target_state_(types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE),
current_state_(types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE),
context_type_(types::LeAudioContextType::UNINITIALIZED) {
stream_conf.valid = false;
stream_conf.conf = nullptr;
stream_conf.sink_num_of_devices = 0;
stream_conf.source_num_of_devices = 0;
}
~LeAudioDeviceGroup(void);
void AddNode(const std::shared_ptr<LeAudioDevice>& leAudioDevice);
void RemoveNode(const std::shared_ptr<LeAudioDevice>& leAudioDevice);
bool IsEmpty(void);
bool IsAnyDeviceConnected(void);
int Size(void);
int NumOfConnected(
types::LeAudioContextType context_type = types::LeAudioContextType::RFU);
void Deactivate(void);
void Cleanup(void);
LeAudioDevice* GetFirstDevice(void);
LeAudioDevice* GetFirstDeviceWithActiveContext(
types::LeAudioContextType context_type);
LeAudioDevice* GetNextDevice(LeAudioDevice* leAudioDevice);
LeAudioDevice* GetNextDeviceWithActiveContext(
LeAudioDevice* leAudioDevice, types::LeAudioContextType context_type);
LeAudioDevice* GetFirstActiveDevice(void);
LeAudioDevice* GetNextActiveDevice(LeAudioDevice* leAudioDevice);
bool IsDeviceInTheGroup(LeAudioDevice* leAudioDevice);
bool HaveAllActiveDevicesAsesTheSameState(types::AseState state);
bool IsGroupStreamReady(void);
bool HaveAllActiveDevicesCisDisc(void);
uint8_t GetFirstFreeCisId(void);
bool Configure(types::LeAudioContextType context_type);
bool SetContextType(types::LeAudioContextType context_type);
types::LeAudioContextType GetContextType(void);
uint32_t GetSduInterval(uint8_t direction);
uint8_t GetSCA(void);
uint8_t GetPacking(void);
uint8_t GetFraming(void);
uint8_t GetTargetLatency(void);
uint16_t GetMaxTransportLatencyStom(void);
uint16_t GetMaxTransportLatencyMtos(void);
void SetTransportLatency(uint8_t direction, uint16_t transport_latency);
uint8_t GetPhyBitmask(uint8_t direction);
uint8_t GetTargetPhy(uint8_t direction);
bool GetPresentationDelay(uint32_t* delay, uint8_t direction);
uint16_t GetRemoteDelay(uint8_t direction);
std::optional<types::AudioContexts> UpdateActiveContextsMap(
types::AudioContexts contexts);
std::optional<types::AudioContexts> UpdateActiveContextsMap(void);
bool ReloadAudioLocations(void);
const set_configurations::AudioSetConfiguration* GetActiveConfiguration(void);
types::LeAudioContextType GetCurrentContextType(void);
types::AudioContexts GetActiveContexts(void);
std::optional<LeAudioCodecConfiguration> GetCodecConfigurationByDirection(
types::LeAudioContextType group_context_type, uint8_t direction);
bool IsMetadataChanged(types::LeAudioContextType group_context_type);
inline types::AseState GetState(void) const { return current_state_; }
void SetState(types::AseState state) {
LOG(INFO) << __func__ << " current state: " << current_state_
<< " new state: " << state;
current_state_ = state;
}
inline types::AseState GetTargetState(void) const { return target_state_; }
void SetTargetState(types::AseState state) {
LOG(INFO) << __func__ << " target state: " << target_state_
<< " new target state: " << state;
target_state_ = state;
}
bool IsInTransition(void);
bool IsReleasing(void);
void Dump(int fd);
private:
uint16_t transport_latency_mtos_;
uint16_t transport_latency_stom_;
const set_configurations::AudioSetConfiguration*
FindFirstSupportedConfiguration(types::LeAudioContextType context_type);
bool ConfigureAses(
const set_configurations::AudioSetConfiguration* audio_set_conf,
types::LeAudioContextType context_type);
bool IsConfigurationSupported(
const set_configurations::AudioSetConfiguration* audio_set_configuration,
types::LeAudioContextType context_type);
uint16_t GetTransportLatency(uint8_t direction);
/* Mask and table of currently supported contexts */
types::LeAudioContextType active_context_type_;
types::AudioContexts active_contexts_mask_;
std::map<types::LeAudioContextType,
const set_configurations::AudioSetConfiguration*>
active_context_to_configuration_map;
types::AseState target_state_;
types::AseState current_state_;
types::LeAudioContextType context_type_;
std::vector<std::weak_ptr<LeAudioDevice>> leAudioDevices_;
};
/* LeAudioDeviceGroup class represents a wraper helper over all device groups in
* le audio implementation. It allows to operate on device group from a list
* (vector container) using determinants like id.
*/
class LeAudioDeviceGroups {
public:
LeAudioDeviceGroup* Add(int group_id);
void Remove(const int group_id);
LeAudioDeviceGroup* FindById(int group_id);
std::vector<int> GetGroupsIds(void);
size_t Size();
bool IsAnyInTransition();
void Cleanup(void);
void Dump(int fd);
private:
std::vector<std::unique_ptr<LeAudioDeviceGroup>> groups_;
};
} // namespace le_audio