blob: ea069379ad7825f4862320542682f353189c538d [file] [log] [blame]
/******************************************************************************
*
* Copyright 2021 The Android Open Source Project
*
* 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.
*
******************************************************************************/
#include "bta_bap_uclient_api.h"
#include "ucast_client_int.h"
#include "bt_trace.h"
namespace bluetooth {
namespace bap {
namespace ucast {
using namespace std;
using bluetooth::bap::ucast::UstreamManagers;
using bluetooth::bap::ucast::UstreamManager;
std::map<StreamState, int> state_map = {
{StreamState::DISCONNECTED, StreamTracker::kStateIdle} ,
{StreamState::CONNECTING, StreamTracker::kStateConnecting},
{StreamState::CONNECTED, StreamTracker::kStateConnected},
{StreamState::STARTING, StreamTracker::kStateStarting},
{StreamState::STREAMING, StreamTracker::kStateStreaming},
{StreamState::STOPPING, StreamTracker::kStateStopping},
{StreamState::DISCONNECTING, StreamTracker::kStateDisconnecting},
{StreamState::RECONFIGURING, StreamTracker::kStateReconfiguring}
};
StreamContext *StreamContexts::FindByType(StreamType stream_type) {
auto iter = std::find_if(strm_contexts.begin(), strm_contexts.end(),
[&stream_type](StreamContext *context) {
return ((context->stream_type.type == stream_type.type)
&& (context->stream_type.direction ==
stream_type.direction));
});
if (iter == strm_contexts.end()) {
return nullptr;
} else {
return (*iter);
}
}
std::vector<StreamContext *> StreamContexts::FindByAseAttachedState(
uint16_t ase_id, StreamAttachedState state) {
std::vector<StreamContext *> contexts_list;
for(auto i = strm_contexts.begin(); i != strm_contexts.end();i++) {
if(static_cast<uint8_t>((*i)->attached_state) &
static_cast<uint8_t>(state)) {
for(auto j = (*i)->stream_ids.begin(); j != (*i)->stream_ids.end();j++) {
if(j->ase_id == ase_id) {
contexts_list.push_back(*i);
break;
}
}
}
}
return contexts_list;
}
StreamContext *StreamContexts::FindOrAddByType(StreamType stream_type) {
auto iter = std::find_if(strm_contexts.begin(), strm_contexts.end(),
[&stream_type](StreamContext *context) {
return ((context->stream_type.type ==
stream_type.type) &&
(context->stream_type.direction ==
stream_type.direction));
});
if (iter == strm_contexts.end()) {
StreamContext *context = new StreamContext(stream_type);
strm_contexts.push_back(context);
return context;
} else {
return (*iter);
}
}
void StreamContexts::Remove(StreamType stream_type) {
for (auto it = strm_contexts.begin(); it != strm_contexts.end();) {
if (((*it)->stream_type.type = stream_type.type) &&
((*it)->stream_type.direction = stream_type.direction)) {
delete(*it);
it = strm_contexts.erase(it);
} else {
it++;
}
}
}
bool StreamContexts::IsAseAttached(StreamType stream_type) {
return false;
}
StreamContext* StreamContexts::FindByAseId(uint16_t ase_id) {
auto iter = std::find_if(strm_contexts.begin(), strm_contexts.end(),
[&ase_id](StreamContext *context) {
auto it = std::find_if(context->stream_ids.begin(),
context->stream_ids.end(),
[&ase_id](StreamIdType id) {
return (id.ase_id == ase_id);
});
if (it != context->stream_ids.end()) {
return true;
} else return false;
});
if (iter == strm_contexts.end()) {
return nullptr;
} else {
return (*iter);
}
}
StreamTracker* StreamTrackers::FindOrAddByType(int init_state_id,
UstreamManager *strm_mgr,
std::vector<StreamConnect> *connect_streams,
std::vector<StreamReconfig> *reconfig_streams,
std::vector<StreamType> *streams,
StreamControlType ops_type) {
bool found = false;
auto iter = stream_trackers.begin();
while (iter != stream_trackers.end() && !found) {
if((*iter)->GetControlType() == ops_type) {
if(ops_type == StreamControlType::Connect) {
// compare connection streams
std::vector<StreamConnect> *conn_strms = (*iter)->GetConnStreams();
if(conn_strms->size() == connect_streams->size()) {
uint8_t len = connect_streams->size();
for (uint8_t i = 0; i < len ; i++) {
StreamConnect src = conn_strms->at(i);
StreamConnect dst = connect_streams->at(i);
if((src.stream_type.type == dst.stream_type.type) &&
(src.stream_type.direction == dst.stream_type.direction)) {
LOG(WARNING) << __func__ << " StreamConnect found";
found = true;
break;
}
}
}
} else if(ops_type == StreamControlType::Reconfig) {
// compare connection streams
std::vector<StreamReconfig> *reconf_strms = (*iter)->GetReconfStreams();
if(reconf_strms->size() == reconfig_streams->size()) {
uint8_t len = reconfig_streams->size();
for (uint8_t i = 0; i < len ; i++) {
StreamReconfig src = reconf_strms->at(i);
StreamReconfig dst = reconfig_streams->at(i);
if((src.stream_type.type == dst.stream_type.type) &&
(src.stream_type.direction == dst.stream_type.direction)) {
LOG(WARNING) << __func__ << " StreamReconfig found";
found = true;
break;
}
}
}
} else if(ops_type != StreamControlType::None &&
ops_type != StreamControlType::UpdateStream) {
// compare connection streams
std::vector<StreamType> *strms = (*iter)->GetStreams();
if(strms->size() == streams->size()) {
uint8_t len = streams->size();
for (uint8_t i = 0; i < len ; i++) {
StreamType src = strms->at(i);
StreamType dst = streams->at(i);
if((src.type == dst.type) &&
(src.direction == dst.direction)) {
LOG(WARNING) << __func__ << " StreamType found";
found = true;
break;
}
}
}
}
}
iter++;
}
if (iter == stream_trackers.end()) {
StreamTracker *tracker = new StreamTracker(init_state_id, strm_mgr,
connect_streams, reconfig_streams,
streams, ops_type);
stream_trackers.push_back(tracker);
return tracker;
} else {
return (*iter);
}
}
bool StreamTrackers::Remove(std::vector<StreamType> streams,
StreamControlType ops_type) {
return true;
}
std::vector<StreamTracker *> StreamTrackers::GetTrackersByStates(
std::vector<int> *state_ids) {
vector<StreamTracker *> trackers;
for (auto i = stream_trackers.begin();
i != stream_trackers.end();i++) {
for (auto j = state_ids->begin(); j != state_ids->end();j++) {
if((*i)->StateId() == *j) {
LOG(WARNING) << __func__ << " tracker found";
trackers.push_back(*i);
}
}
}
return trackers;
}
void StreamTrackers::RemoveByStates(std::vector<int> state_ids) {
for (auto i = stream_trackers.begin();
i != stream_trackers.end();) {
bool found = false;
for (auto j = state_ids.begin(); j != state_ids.end();j++) {
if((*i)->StateId() == *j) {
LOG(WARNING) << __func__ << " tracker found";
found = true;
break;
}
}
if(found) {
delete(*i);
i = stream_trackers.erase(i);
} else {
i++;
}
}
}
std::map<StreamTracker * , std::vector<StreamType> >
StreamTrackers::GetTrackersByType(
std::vector<StreamType> *streams) {
std::vector<StreamType> req_types = *streams;
std::vector<StreamType> all_types;
std::map<StreamTracker * , std::vector<StreamType> > tracker_and_type_map;
for (auto iter = stream_trackers.begin(); iter != stream_trackers.end();
iter++) {
all_types.clear();
if((*iter)->GetControlType() == StreamControlType::Connect) {
// compare connection streams
std::vector<StreamConnect> *conn_strms = (*iter)->GetConnStreams();
uint8_t len = conn_strms->size();
for (uint8_t i = 0; i < len ; i++) {
StreamConnect src = conn_strms->at(i);
all_types.push_back(src.stream_type);
}
} else if((*iter)->GetControlType() == StreamControlType::Reconfig) {
// compare connection streams
std::vector<StreamReconfig> *reconf_strms = (*iter)->GetReconfStreams();
uint8_t len = reconf_strms->size();
for (uint8_t i = 0; i < len ; i++) {
StreamReconfig src = reconf_strms->at(i);
all_types.push_back(src.stream_type);
}
} else if((*iter)->GetControlType() == StreamControlType::UpdateStream) {
// compare connection streams
std::vector<StreamUpdate> *update_streams = (*iter)->GetMetaUpdateStreams();
uint8_t len = update_streams->size();
for (uint8_t i = 0; i < len ; i++) {
StreamUpdate src = update_streams->at(i);
all_types.push_back(src.stream_type);
}
} else if((*iter)->GetControlType() != StreamControlType::None) {
// compare connection streams
std::vector<StreamType> *strms = (*iter)->GetStreams();
uint8_t len = strms->size();
for (uint8_t i = 0; i < len ; i++) {
StreamType src = strms->at(i);
all_types.push_back(src);
}
}
uint8_t count = 0;
std::vector<StreamType> filtered_types;
if(all_types.size() <= req_types.size()) {
filtered_types.clear();
for (auto it = all_types.begin(); it != all_types.end(); it++) {
for (auto it_2 = req_types.begin(); it_2 != req_types.end();) {
if (((it_2)->type == it->type) &&
((it_2)->direction == it->direction)) {
filtered_types.push_back(*it_2);
tracker_and_type_map[*iter] = filtered_types;
it_2 = req_types.erase(it_2);
count++;
} else {
it_2++;
}
}
}
if(all_types.size() != count) {
LOG(ERROR) << __func__ << " invalid request";
}
} else {
LOG(ERROR) << __func__ << " invalid request";
}
}
if(req_types.size()) {
tracker_and_type_map[nullptr] = req_types;
}
return tracker_and_type_map;
}
StreamTracker *StreamTrackers::FindByStreamsType(
std::vector<StreamType> *streams) {
bool found = false;
auto iter = stream_trackers.begin();
while (iter != stream_trackers.end()) {
if((*iter)->GetControlType() == StreamControlType::Connect) {
// compare connection streams
std::vector<StreamConnect> *conn_strms = (*iter)->GetConnStreams();
if(conn_strms->size() == streams->size()) {
uint8_t len = streams->size();
for (uint8_t i = 0; i < len ; i++) {
StreamConnect src = conn_strms->at(i);
StreamType dst = streams->at(i);
if((src.stream_type.type == dst.type) &&
(src.stream_type.direction == dst.direction)) {
LOG(WARNING) << __func__ << " StreamConnect found";
found = true;
break;
}
}
}
} else if((*iter)->GetControlType() == StreamControlType::Reconfig) {
// compare connection streams
std::vector<StreamReconfig> *reconf_strms = (*iter)->GetReconfStreams();
if(reconf_strms->size() == streams->size()) {
uint8_t len = streams->size();
for (uint8_t i = 0; i < len ; i++) {
StreamReconfig src = reconf_strms->at(i);
StreamType dst = streams->at(i);
if((src.stream_type.type == dst.type) &&
(src.stream_type.direction == dst.direction)) {
LOG(WARNING) << __func__ << " StreamReconfig found";
found = true;
break;
}
}
}
} else if((*iter)->GetControlType() == StreamControlType::UpdateStream) {
// compare connection streams
std::vector<StreamUpdate> *update_strms = (*iter)->GetMetaUpdateStreams();
if(update_strms->size() == streams->size()) {
uint8_t len = streams->size();
for (uint8_t i = 0; i < len ; i++) {
StreamUpdate src = update_strms->at(i);
StreamType dst = streams->at(i);
if((src.stream_type.type == dst.type) &&
(src.stream_type.direction == dst.direction)) {
LOG(WARNING) << __func__ << " StreamUpdate found";
found = true;
break;
}
}
}
} else if((*iter)->GetControlType() != StreamControlType::None) {
// compare connection streams
std::vector<StreamType> *strms = (*iter)->GetStreams();
if(strms->size() == streams->size()) {
uint8_t len = streams->size();
for (uint8_t i = 0; i < len ; i++) {
StreamType src = strms->at(i);
StreamType dst = streams->at(i);
if((src.type == dst.type) &&
(src.direction == dst.direction)) {
LOG(WARNING) << __func__ << " StreamType found";
found = true;
break;
}
}
}
}
if(found) break;
iter++;
}
if (iter == stream_trackers.end()) {
return nullptr;
} else {
return (*iter);
}
}
bool StreamTrackers::ChangeOpType( StreamType stream_type,
StreamControlType new_ops_type) {
return true;
}
bool StreamTrackers::IsStreamTrackerValid(StreamTracker* tracker,
std::vector<int> *state_ids) {
vector<StreamTracker *> trackers_ = GetTrackersByStates(state_ids);
LOG(WARNING) << __func__;
if(trackers_.empty()) return false;
for (auto it = trackers_.begin(); it != trackers_.end(); it++) {
if ((*it) == tracker) {
LOG(WARNING) << __func__ <<": Cached Tracker is valid";
return true;
}
}
return false;
}
bool UstreamManager::PushEventToTracker(uint32_t event, void *p_data,
std::vector<int> *state_ids) {
vector<StreamTracker *> trackers = stream_trackers.GetTrackersByStates(
state_ids);
if(trackers.empty()) return false;
for (auto it = trackers.begin(); it != trackers.end(); it++) {
(*it)->ProcessEvent(event, p_data);
}
return true;
}
std::map<int , std::vector<StreamType> > UstreamManager::SplitContextOnState(
std::vector<StreamType> *streams) {
StreamContexts *contexts = GetStreamContexts();
std::vector<StreamType> req_types = *streams;
std::map<int , std::vector<StreamType> > state_and_type_map;
for (auto it = req_types.begin(); it != req_types.end();) {
StreamContext *context = contexts->FindOrAddByType(*it);
if (context) {
int state = state_map[context->stream_state];
state_and_type_map[state].push_back(*it);
it = req_types.erase(it);
} else {
it++;
}
}
return state_and_type_map;
}
void UstreamManager::ProcessEvent(uint32_t event, void *p_data) {
LOG(WARNING) << __func__ <<": Event: " << GetEventName(event)
<<", bt_addr: " << GetAddress();
std::vector<int> stable_state_ids = {
StreamTracker::kStateConnected,
StreamTracker::kStateStreaming,
StreamTracker::kStateIdle
};
std::vector<int> transient_state_ids = {
StreamTracker::kStateConnecting,
StreamTracker::kStateReconfiguring,
StreamTracker::kStateDisconnecting,
StreamTracker::kStateStarting,
StreamTracker::kStateStopping,
StreamTracker::kStateUpdating,
};
StreamContexts *contexts = GetStreamContexts();
switch (event) {
case BAP_CONNECT_REQ_EVT: {
BapConnect *evt_data = (BapConnect *) p_data;
std::vector<StreamConnect> conn_streams = evt_data->streams;
LOG(WARNING) << __func__ << ": size: " << conn_streams.size();
for (auto it = conn_streams.begin(); it != conn_streams.end();) {
StreamContext *context = contexts->FindOrAddByType(it->stream_type);
if(context && context->stream_state != StreamState::DISCONNECTED) {
LOG(WARNING) << __func__ << ": Stream is not in disconnected state";
it = conn_streams.erase(it);
} else {
it++;
}
}
if(!conn_streams.size()) {
LOG(ERROR) << __func__ << ": All streams are not in disconnected state";
break;
}
// validate the combinations media Tx or voice TX|RX
StreamTracker *tracker = stream_trackers.FindOrAddByType(
StreamTracker::kStateIdle,
this, &conn_streams, nullptr, nullptr,
StreamControlType::Connect);
if(tracker) {
tracker->Start();
tracker->ProcessEvent(event, p_data);
}
} break;
case BAP_DISCONNECT_REQ_EVT: {
BapDisconnect *evt_data = (BapDisconnect *) p_data;
std::vector<StreamType> disc_streams = evt_data->streams;
BapDisconnect int_evt_data;
for (auto it = disc_streams.begin(); it != disc_streams.end();) {
StreamContext *context = contexts->FindOrAddByType(*it);
if(!context || context->stream_state == StreamState::DISCONNECTED) {
LOG(WARNING) << __func__ << " Stream is already disconnected";
it = disc_streams.erase(it);
} else {
it++;
}
}
if(!disc_streams.size()) {
LOG(ERROR) << __func__ << " All streams are already disconnected";
break;
}
LOG(WARNING) << __func__ << " disc streams size " << disc_streams.size();
// validate the combinations media Tx or voice TX|RX
std::map<StreamTracker * , std::vector<StreamType> >
tracker_and_type_list =
stream_trackers.GetTrackersByType(&disc_streams);
// check if all streams disconnection or subset of streams
// create the new tracker
for (auto itr = tracker_and_type_list.begin();
itr != tracker_and_type_list.end(); itr++) {
if(itr->first == nullptr) {
std::map<int , std::vector<StreamType> >
list = SplitContextOnState(&itr->second);
for (auto itr_2 = list.begin(); itr_2 != list.end(); itr_2++) {
StreamTracker *tracker = stream_trackers.FindOrAddByType(
itr_2->first,
this, nullptr, nullptr, &itr_2->second,
StreamControlType::Disconnect);
LOG(ERROR) << __func__ << " new tracker start ";
tracker->Start();
int_evt_data.streams = itr_2->second;
tracker->ProcessEvent(event, &int_evt_data);
}
} else {
LOG(ERROR) << __func__ << " existing tracker start ";
StreamTracker *tracker = itr->first;
int_evt_data.streams = itr->second;
tracker->ProcessEvent(event, &int_evt_data);
}
}
} break;
case BAP_START_REQ_EVT: {
BapStart *evt_data = (BapStart *) p_data;
std::vector<StreamType> start_streams = evt_data->streams;
LOG(WARNING) << __func__ << " start streams size " << start_streams.size();
for (auto it = start_streams.begin(); it != start_streams.end();) {
StreamContext *context = contexts->FindOrAddByType(*it);
if(!context || context->stream_state != StreamState::CONNECTED) {
LOG(WARNING) << __func__ << " Stream is not in connected state";
it = start_streams.erase(it);
} else {
it++;
}
}
if(!start_streams.size()) {
LOG(WARNING) << __func__ << " Not eligible for stream start";
break;
}
// validate the combinations media Tx or voice TX|RX
StreamTracker *tracker = stream_trackers.FindByStreamsType(
&start_streams);
// create new tracker
if(tracker == nullptr) {
StreamTracker *tracker = stream_trackers.FindOrAddByType(
StreamTracker::kStateConnected,
this, nullptr, nullptr, &start_streams,
StreamControlType::Start);
tracker->Start();
tracker->ProcessEvent(event, p_data);
} else {
tracker->ProcessEvent(event, p_data);
}
} break;
case BAP_STOP_REQ_EVT: {
BapStop *evt_data = (BapStop *) p_data;
std::vector<StreamType> stop_streams = evt_data->streams;
LOG(WARNING) << __func__ << " stop streams size " << stop_streams.size();
for (auto it = stop_streams.begin(); it != stop_streams.end();) {
StreamContext *context = contexts->FindOrAddByType(*it);
if(!context || (context->stream_state != StreamState::STREAMING &&
context->stream_state != StreamState::STARTING)) {
LOG(WARNING) << __func__ << " Stream is not in streaming state";
it = stop_streams.erase(it);
} else {
it++;
}
}
if(!stop_streams.size()) {
LOG(WARNING) << __func__ << " Not eligible for stream stop";
break;
}
StreamTracker *tracker = stream_trackers.FindByStreamsType(
&stop_streams);
// create the new tracker
if(tracker == nullptr) {
// validate the combinations media Tx or voice TX|RX
StreamTracker *tracker = stream_trackers.FindOrAddByType(
StreamTracker::kStateStreaming,
this, nullptr, nullptr, &stop_streams,
StreamControlType::Stop);
tracker->Start();
tracker->ProcessEvent(event, p_data);
} else {
tracker->ProcessEvent(event, p_data);
}
} break;
case BAP_STREAM_UPDATE_REQ_EVT: {
BapStreamUpdate *evt_data = (BapStreamUpdate *) p_data;
std::vector<StreamUpdate> update_streams = evt_data->update_streams;
std::vector<StreamType> streams;
for (auto it = update_streams.begin(); it != update_streams.end();) {
StreamContext *context = contexts->FindOrAddByType(it->stream_type);
if(!context || (context->stream_state != StreamState::STREAMING &&
context->stream_state != StreamState::STARTING)) {
LOG(WARNING) << __func__ << " Stream is not in proper state";
it = update_streams.erase(it);
} else {
it++;
}
}
if(!update_streams.size()) {
LOG(WARNING) << __func__ << " All streams are not in proper state";
break;
}
for (auto it = update_streams.begin();
it != update_streams.end(); it++) {
StreamType type = it->stream_type;
streams.push_back(type);
}
LOG(WARNING) << __func__ << " update streams size " << streams.size();
StreamTracker *tracker = stream_trackers.FindByStreamsType(
&streams);
// create the new tracker
if(tracker == nullptr) {
// validate the combinations media Tx or voice TX|RX
StreamTracker *tracker = stream_trackers.FindOrAddByType(
StreamTracker::kStateStreaming,
this, nullptr, nullptr, nullptr,
StreamControlType::UpdateStream);
tracker->Start();
tracker->ProcessEvent(event, p_data);
} else {
tracker->ProcessEvent(event, p_data);
}
} break;
case BAP_RECONFIG_REQ_EVT: {
BapReconfig *evt_data = (BapReconfig *) p_data;
std::vector<StreamReconfig> reconf_streams = evt_data->streams;
std::vector<StreamType> streams;
for (auto it = reconf_streams.begin(); it != reconf_streams.end();) {
StreamContext *context = contexts->FindOrAddByType(it->stream_type);
if(!context || context->stream_state != StreamState::CONNECTED) {
LOG(WARNING) << __func__ << " Stream is not in Connected state";
it = reconf_streams.erase(it);
} else {
it++;
}
}
if(!reconf_streams.size()) {
LOG(WARNING) << __func__ << " All streams are not connected";
break;
}
for (auto it = reconf_streams.begin();
it != reconf_streams.end(); it++) {
StreamType type = it->stream_type;
streams.push_back(type);
}
LOG(WARNING) << __func__ << " reconf streams size " << streams.size();
StreamTracker *tracker = stream_trackers.FindByStreamsType(
&streams);
// create the new tracker
if(tracker == nullptr) {
// validate the combinations media Tx or voice TX|RX
StreamTracker *tracker = stream_trackers.FindOrAddByType(
StreamTracker::kStateConnected,
this, nullptr, &reconf_streams, nullptr,
StreamControlType::Reconfig);
tracker->Start();
tracker->ProcessEvent(event, p_data);
} else {
tracker->ProcessEvent(event, p_data);
}
} break;
case PACS_CONNECTION_STATE_EVT: {
PacsConnectionState *pacs_state = (PacsConnectionState *) p_data;
UpdatePacsState(pacs_state->state);
int state = StreamTracker::kStateIdle;
if (pacs_state->state != ConnectionState::DISCONNECTED) {
if(PushEventToTracker(event, p_data, &transient_state_ids)) {
break;
} else {
std::vector<StreamContext *> *context_list = contexts->GetAllContexts();
std::vector<StreamType> streams;
for (auto it = context_list->begin(); it != context_list->end(); it++) {
if((*it)->stream_state != StreamState::DISCONNECTED) {
streams.push_back((*it)->stream_type);
state = state_map[(*it)->stream_state];
}
}
StreamTracker *tracker = stream_trackers.FindByStreamsType(
&streams);
// create the new tracker
if(tracker == nullptr) {
// validate the combinations media Tx or voice TX|RX
StreamTracker *tracker = stream_trackers.FindOrAddByType(
state,
this, nullptr, nullptr, &streams,
StreamControlType::Disconnect);
tracker->Start();
tracker->ProcessEvent(event, p_data);
} else {
tracker->ProcessEvent(event, p_data);
}
}
} else {
std::vector<StreamContext *> *context_list = contexts->GetAllContexts();
std::vector<StreamType> disc_streams;
for (auto it = context_list->begin(); it != context_list->end(); it++) {
if((*it)->stream_state != StreamState::DISCONNECTED) {
disc_streams.push_back((*it)->stream_type);
}
}
LOG(WARNING) << __func__ << ": size: " << disc_streams.size();
// validate the combinations media Tx or voice TX|RX
std::map<StreamTracker * , std::vector<StreamType> >
tracker_and_type_list =
stream_trackers.GetTrackersByType(&disc_streams);
// check if all streams disconnection or subset of streams
// create the new tracker
for (auto itr = tracker_and_type_list.begin();
itr != tracker_and_type_list.end(); itr++) {
if(itr->first == nullptr) {
std::map<int , std::vector<StreamType> >
list = SplitContextOnState(&itr->second);
for (auto itr_2 = list.begin(); itr_2 != list.end(); itr_2++) {
StreamTracker *tracker = stream_trackers.FindOrAddByType(
itr_2->first,
this, nullptr, nullptr, &itr_2->second,
StreamControlType::Disconnect);
LOG(ERROR) << __func__ << " new tracker start ";
tracker->Start();
tracker->ProcessEvent(event, p_data);
}
} else {
LOG(ERROR) << __func__ << " existing tracker start ";
StreamTracker *tracker = itr->first;
tracker->ProcessEvent(event, p_data);
}
}
}
} break;
case PACS_AUDIO_CONTEXT_RES_EVT: {
// update the same event to upper layers also
PacsAvailableContexts *contexts = (PacsAvailableContexts *) p_data;
ucl_callbacks->OnStreamAvailable(
address,
(contexts->available_contexts >> 16),
(contexts->available_contexts & 0xFFFF));
std::vector<int> state_ids = { StreamTracker::kStateStarting,
StreamTracker::kStateUpdating};
PushEventToTracker(event, p_data, &state_ids);
} break;
case PACS_DISCOVERY_RES_EVT:
case ASCS_DISCOVERY_RES_EVT: {
// validate the combinations media Tx or voice TX|RX
std::vector<int> state_ids = { StreamTracker::kStateConnecting,
StreamTracker::kStateReconfiguring };
PushEventToTracker(event, p_data, &state_ids);
} break;
case ASCS_CONNECTION_STATE_EVT: {
AscsConnectionState *ascs_state = (AscsConnectionState *) p_data;
UpdateAscsState(ascs_state->state);
PushEventToTracker(event, p_data, &transient_state_ids);
} break;
case ASCS_ASE_OP_FAILED_EVT: {
if(PushEventToTracker(event, p_data, &transient_state_ids)) {
break;
}
} break;
case ASCS_ASE_STATE_EVT: {
if(PushEventToTracker(event, p_data, &transient_state_ids)) {
break;
}
// create strm trackers based on ase ID and push it to
// newly created tracker.
// TODO Handle Releasing , disabling, codec configured states
// initiated from remote device
AscsState *ascs = ((AscsState *) p_data);
UcastAudioStream *audio_stream = nullptr;
// find out the stream for the given ase id
uint8_t ase_id = ascs->ase_params.ase_id;
std::vector<StreamType> streams;
int state = StreamTracker::kStateIdle;
UcastAudioStreams *audio_strms = GetAudioStreams();
audio_stream = audio_strms->FindByAseId(ase_id);
if(audio_stream) {
StreamType type = {
.type = audio_stream->audio_context,
.direction = audio_stream->direction
};
streams.push_back(type);
state = audio_stream->overall_state;
}
LOG(WARNING) << __func__ << " size " << streams.size();
if (ascs->ase_params.ase_state == ascs::ASE_STATE_RELEASING) {
StreamTracker *tracker = stream_trackers.FindOrAddByType(
state,
this, nullptr, nullptr, &streams,
StreamControlType::Disconnect);
tracker->Start();
tracker->ProcessEvent(event, p_data);
} else if (ascs->ase_params.ase_state == ascs::ASE_STATE_DISABLING) {
StreamTracker *tracker = stream_trackers.FindOrAddByType(
state,
this, nullptr, nullptr, &streams,
StreamControlType::Stop);
tracker->Start();
tracker->ProcessEvent(event, p_data);
} else if (ascs->ase_params.ase_state ==
ascs::ASE_STATE_CODEC_CONFIGURED) {
// TODO reconfig from remote device
} else if (ascs->ase_params.ase_state ==
ascs::ASE_STATE_QOS_CONFIGURED) {
// this can happen when CIS is lost and detected on remote side
// first so it will immediately transition to QOS configured.
StreamTracker *tracker = stream_trackers.FindOrAddByType(
state,
this, nullptr, nullptr, &streams,
StreamControlType::Stop);
tracker->Start();
tracker->ProcessEvent(event, p_data);
}
} break;
case CIS_GROUP_STATE_EVT: {
// validate the combinations media Tx or voice TX|RX
std::vector<int> state_ids = { StreamTracker::kStateStarting,
StreamTracker::kStateStopping,
StreamTracker::kStateDisconnecting };
PushEventToTracker(event, p_data, &state_ids);
} break;
case CIS_STATE_EVT: {
CisStreamState *data = (CisStreamState *) p_data;
if(PushEventToTracker(event, p_data, &transient_state_ids)) {
break;
}
// find out the stream for the given ase id
int state = StreamTracker::kStateIdle;
std::vector<StreamType> streams;
UcastAudioStreams *audio_strms = GetAudioStreams();
std::vector<UcastAudioStream *> cis_streams = audio_strms->FindByCisId(
data->cig_id, data->cis_id);
if(cis_streams.empty()) break;
for (auto it = cis_streams.begin(); it != cis_streams.end(); it++) {
StreamType type = {
.type = (*it)->audio_context,
.direction = (*it)->direction
};
streams.push_back(type);
state = (*it)->overall_state;
}
LOG(WARNING) << __func__ << " size " << streams.size();
// create strm trackers based on CIS ID and push it to
// newly created tracker.
// CIS disconnected
if(data->state == CisState::READY) {
StreamTracker *tracker = stream_trackers.FindOrAddByType(
state,
this, nullptr, nullptr, &streams,
StreamControlType::Stop);
tracker->Start();
tracker->ProcessEvent(event, p_data);
}
} break;
case BAP_TIME_OUT_EVT: {
BapTimeout* evt_data = (BapTimeout*) p_data;
//Get Cached tracker and check if it is valid
if (stream_trackers.IsStreamTrackerValid(evt_data->tracker,
&transient_state_ids)) {
PushEventToTracker(event, p_data, &transient_state_ids);
} else {
LOG(WARNING) << __func__ << ": Tracker is not valid ";
}
} break;
default:
break;
}
// look for all stream trackers which are moved to stable states
// like connected, streaming, idle, and destroy those trackers here
stream_trackers.RemoveByStates(stable_state_ids);
}
// TODO to introduce a queue for serializing the Audio stream establishment
UstreamManager* UstreamManagers::FindByAddress(const RawAddress& address) {
auto iter = std::find_if(strm_mgrs.begin(), strm_mgrs.end(),
[&address](UstreamManager *strm_mgr) {
return strm_mgr->GetAddress() == address;
});
return (iter == strm_mgrs.end()) ? nullptr : (*iter);
}
UstreamManager* UstreamManagers::FindorAddByAddress(const RawAddress& address,
PacsClient *pacs_client, uint16_t pacs_client_id,
AscsClient *ascs_client, CisInterface *cis_intf,
UcastClientCallbacks* ucl_callbacks,
BapAlarm *bap_alarm) {
auto iter = std::find_if(strm_mgrs.begin(), strm_mgrs.end(),
[&address](UstreamManager *strm_mgr) {
return strm_mgr->GetAddress() == address;
});
if (iter == strm_mgrs.end()) {
UstreamManager *strm_mgr = new UstreamManager(address, pacs_client,
pacs_client_id, ascs_client, cis_intf,
ucl_callbacks, bap_alarm);
strm_mgrs.push_back(strm_mgr);
return strm_mgr;
} else {
return (*iter);
}
}
std::vector<UstreamManager *> *UstreamManagers::GetAllManagers() {
return &strm_mgrs;
}
void UstreamManagers::Remove(const RawAddress& address) {
for (auto it = strm_mgrs.begin(); it != strm_mgrs.end();) {
if ((*it)->GetAddress() == address) {
delete(*it);
it = strm_mgrs.erase(it);
} else {
it++;
}
}
}
} // namespace ucast
} // namespace bap
} // namespace bluetooth