| /****************************************************************************** |
| * |
| * 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 |