blob: 57ca6ca3b96bafbb5c31d353e2212538b447b1f1 [file] [log] [blame]
Josh Wu20bac522021-12-29 23:52:39 -08001/*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <sys/types.h>
18#define LOG_TAG "BTAudioSessionAidl"
19
20#include <android-base/logging.h>
21#include <android-base/stringprintf.h>
22#include <android/binder_manager.h>
23
24#include "BluetoothAudioSession.h"
25
26namespace aidl {
27namespace android {
28namespace hardware {
29namespace bluetooth {
30namespace audio {
31
32static constexpr int kFmqSendTimeoutMs = 1000; // 1000 ms timeout for sending
33static constexpr int kFmqReceiveTimeoutMs =
34 1000; // 1000 ms timeout for receiving
35static constexpr int kWritePollMs = 1; // polled non-blocking interval
36static constexpr int kReadPollMs = 1; // polled non-blocking interval
37
Josh Wu20bac522021-12-29 23:52:39 -080038BluetoothAudioSession::BluetoothAudioSession(const SessionType& session_type)
Josh Wu75462aa2022-01-21 21:51:21 -080039 : session_type_(session_type), stack_iface_(nullptr), data_mq_(nullptr) {}
Josh Wu20bac522021-12-29 23:52:39 -080040
41/***
42 *
43 * Callback methods
44 *
45 ***/
46
47void BluetoothAudioSession::OnSessionStarted(
48 const std::shared_ptr<IBluetoothAudioPort> stack_iface,
49 const DataMQDesc* mq_desc, const AudioConfiguration& audio_config) {
50 std::lock_guard<std::recursive_mutex> guard(mutex_);
51 if (stack_iface == nullptr) {
52 LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_)
53 << ", IBluetoothAudioPort Invalid";
54 } else if (!UpdateAudioConfig(audio_config)) {
55 LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_)
56 << ", AudioConfiguration=" << audio_config.toString()
57 << " Invalid";
58 } else if (!UpdateDataPath(mq_desc)) {
59 LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_)
60 << " MqDescriptor Invalid";
Josh Wu75462aa2022-01-21 21:51:21 -080061 audio_config_ = nullptr;
Josh Wu20bac522021-12-29 23:52:39 -080062 } else {
63 stack_iface_ = stack_iface;
64 LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
65 << ", AudioConfiguration=" << audio_config.toString();
66 ReportSessionStatus();
67 }
68}
69
70void BluetoothAudioSession::OnSessionEnded() {
71 std::lock_guard<std::recursive_mutex> guard(mutex_);
72 bool toggled = IsSessionReady();
73 LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_);
Josh Wu75462aa2022-01-21 21:51:21 -080074 audio_config_ = nullptr;
Josh Wu20bac522021-12-29 23:52:39 -080075 stack_iface_ = nullptr;
76 UpdateDataPath(nullptr);
77 if (toggled) {
78 ReportSessionStatus();
79 }
80}
81
82/***
83 *
84 * Util methods
85 *
86 ***/
87
Josh Wu75462aa2022-01-21 21:51:21 -080088const AudioConfiguration BluetoothAudioSession::GetAudioConfig() {
Josh Wu20bac522021-12-29 23:52:39 -080089 std::lock_guard<std::recursive_mutex> guard(mutex_);
90 if (!IsSessionReady()) {
Josh Wu20bac522021-12-29 23:52:39 -080091 switch (session_type_) {
92 case SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH:
Josh Wu75462aa2022-01-21 21:51:21 -080093 return AudioConfiguration(CodecConfiguration{});
Josh Wu20bac522021-12-29 23:52:39 -080094 case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH:
95 case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH:
Josh Wu75462aa2022-01-21 21:51:21 -080096 return AudioConfiguration(LeAudioConfiguration{});
Josh Wu20bac522021-12-29 23:52:39 -080097 default:
Josh Wu75462aa2022-01-21 21:51:21 -080098 return AudioConfiguration(PcmConfiguration{});
Josh Wu20bac522021-12-29 23:52:39 -080099 }
100 }
101 return *audio_config_;
102}
103
104void BluetoothAudioSession::ReportAudioConfigChanged(
105 const AudioConfiguration& audio_config) {
106 if (session_type_ !=
107 SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
108 session_type_ !=
109 SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
110 return;
111 }
112 std::lock_guard<std::recursive_mutex> guard(mutex_);
113 audio_config_ = std::make_unique<AudioConfiguration>(audio_config);
114 if (observers_.empty()) {
115 LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
116 << " has NO port state observer";
117 return;
118 }
119 for (auto& observer : observers_) {
120 uint16_t cookie = observer.first;
121 std::shared_ptr<struct PortStatusCallbacks> cb = observer.second;
122 LOG(INFO) << __func__ << " for SessionType=" << toString(session_type_)
123 << ", bluetooth_audio=0x"
124 << ::android::base::StringPrintf("%04x", cookie);
125 if (cb->audio_configuration_changed_cb_ != nullptr) {
126 cb->audio_configuration_changed_cb_(cookie);
127 }
128 }
129}
130
131bool BluetoothAudioSession::IsSessionReady() {
132 std::lock_guard<std::recursive_mutex> guard(mutex_);
133
134 bool is_mq_valid =
135 (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
136 session_type_ ==
137 SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
138 session_type_ ==
139 SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH ||
140 (data_mq_ != nullptr && data_mq_->isValid()));
Josh Wu75462aa2022-01-21 21:51:21 -0800141 return stack_iface_ != nullptr && is_mq_valid && audio_config_ != nullptr;
Josh Wu20bac522021-12-29 23:52:39 -0800142}
143
144/***
145 *
146 * Status callback methods
147 *
148 ***/
149
150uint16_t BluetoothAudioSession::RegisterStatusCback(
151 const PortStatusCallbacks& callbacks) {
152 std::lock_guard<std::recursive_mutex> guard(mutex_);
153 uint16_t cookie = ObserversCookieGetInitValue(session_type_);
154 uint16_t cookie_upper_bound = ObserversCookieGetUpperBound(session_type_);
155
156 while (cookie < cookie_upper_bound) {
157 if (observers_.find(cookie) == observers_.end()) {
158 break;
159 }
160 ++cookie;
161 }
162 if (cookie >= cookie_upper_bound) {
163 LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_)
164 << " has " << observers_.size()
165 << " observers already (No Resource)";
166 return kObserversCookieUndefined;
167 }
168 std::shared_ptr<PortStatusCallbacks> cb =
169 std::make_shared<PortStatusCallbacks>();
170 *cb = callbacks;
171 observers_[cookie] = cb;
172 return cookie;
173}
174
175void BluetoothAudioSession::UnregisterStatusCback(uint16_t cookie) {
176 std::lock_guard<std::recursive_mutex> guard(mutex_);
177 if (observers_.erase(cookie) != 1) {
178 LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
179 << " no such provider=0x"
180 << ::android::base::StringPrintf("%04x", cookie);
181 }
182}
183
184/***
185 *
186 * Stream methods
187 *
188 ***/
189
190bool BluetoothAudioSession::StartStream() {
191 std::lock_guard<std::recursive_mutex> guard(mutex_);
192 if (!IsSessionReady()) {
193 LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
194 << " has NO session";
195 return false;
196 }
197 auto hal_retval = stack_iface_->startStream();
198 if (!hal_retval.isOk()) {
199 LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
200 << toString(session_type_) << " failed";
201 return false;
202 }
203 return true;
204}
205
206bool BluetoothAudioSession::SuspendStream() {
207 std::lock_guard<std::recursive_mutex> guard(mutex_);
208 if (!IsSessionReady()) {
209 LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
210 << " has NO session";
211 return false;
212 }
213 auto hal_retval = stack_iface_->suspendStream();
214 if (!hal_retval.isOk()) {
215 LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
216 << toString(session_type_) << " failed";
217 return false;
218 }
219 return true;
220}
221
222void BluetoothAudioSession::StopStream() {
223 std::lock_guard<std::recursive_mutex> guard(mutex_);
224 if (!IsSessionReady()) {
225 return;
226 }
227 auto hal_retval = stack_iface_->stopStream();
228 if (!hal_retval.isOk()) {
229 LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
230 << toString(session_type_) << " failed";
231 }
232}
233
234/***
235 *
236 * Private methods
237 *
238 ***/
239
240bool BluetoothAudioSession::UpdateDataPath(const DataMQDesc* mq_desc) {
241 if (mq_desc == nullptr) {
242 // usecase of reset by nullptr
243 data_mq_ = nullptr;
244 return true;
245 }
246 std::unique_ptr<DataMQ> temp_mq;
247 temp_mq.reset(new DataMQ(*mq_desc));
248 if (!temp_mq || !temp_mq->isValid()) {
249 data_mq_ = nullptr;
250 return false;
251 }
252 data_mq_ = std::move(temp_mq);
253 return true;
254}
255
256bool BluetoothAudioSession::UpdateAudioConfig(
257 const AudioConfiguration& audio_config) {
258 bool is_software_session =
259 (session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH ||
260 session_type_ == SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH ||
261 session_type_ == SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH ||
262 session_type_ == SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH);
263 bool is_offload_a2dp_session =
264 (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH);
265 bool is_offload_le_audio_session =
266 (session_type_ ==
267 SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
268 session_type_ ==
269 SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH);
270 auto audio_config_tag = audio_config.getTag();
271 bool is_software_audio_config =
272 (is_software_session &&
273 audio_config_tag == AudioConfiguration::pcmConfig);
274 bool is_a2dp_offload_audio_config =
275 (is_offload_a2dp_session &&
276 audio_config_tag == AudioConfiguration::a2dpConfig);
277 bool is_le_audio_offload_audio_config =
278 (is_offload_le_audio_session &&
279 audio_config_tag == AudioConfiguration::leAudioConfig);
280 if (!is_software_audio_config && !is_a2dp_offload_audio_config &&
281 !is_le_audio_offload_audio_config) {
282 return false;
283 }
284 audio_config_ = std::make_unique<AudioConfiguration>(audio_config);
285 return true;
286}
287
288void BluetoothAudioSession::ReportSessionStatus() {
289 // This is locked already by OnSessionStarted / OnSessionEnded
290 if (observers_.empty()) {
291 LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
292 << " has NO port state observer";
293 return;
294 }
295 for (auto& observer : observers_) {
296 uint16_t cookie = observer.first;
297 std::shared_ptr<PortStatusCallbacks> callback = observer.second;
298 LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
299 << " notify to bluetooth_audio=0x"
300 << ::android::base::StringPrintf("%04x", cookie);
301 callback->session_changed_cb_(cookie);
302 }
303}
304
305/***
306 *
307 * PCM methods
308 *
309 ***/
310
311size_t BluetoothAudioSession::OutWritePcmData(const void* buffer,
312 size_t bytes) {
313 if (buffer == nullptr || bytes <= 0) {
314 return 0;
315 }
316 size_t total_written = 0;
317 int timeout_ms = kFmqSendTimeoutMs;
318 do {
319 std::unique_lock<std::recursive_mutex> lock(mutex_);
320 if (!IsSessionReady()) {
321 break;
322 }
323 size_t num_bytes_to_write = data_mq_->availableToWrite();
324 if (num_bytes_to_write) {
325 if (num_bytes_to_write > (bytes - total_written)) {
326 num_bytes_to_write = bytes - total_written;
327 }
328
329 if (!data_mq_->write(
330 static_cast<const MQDataType*>(buffer) + total_written,
331 num_bytes_to_write)) {
332 LOG(ERROR) << "FMQ datapath writing " << total_written << "/" << bytes
333 << " failed";
334 return total_written;
335 }
336 total_written += num_bytes_to_write;
337 } else if (timeout_ms >= kWritePollMs) {
338 lock.unlock();
339 usleep(kWritePollMs * 1000);
340 timeout_ms -= kWritePollMs;
341 } else {
342 LOG(DEBUG) << "Data " << total_written << "/" << bytes << " overflow "
343 << (kFmqSendTimeoutMs - timeout_ms) << " ms";
344 return total_written;
345 }
346 } while (total_written < bytes);
347 return total_written;
348}
349
350size_t BluetoothAudioSession::InReadPcmData(void* buffer, size_t bytes) {
351 if (buffer == nullptr || bytes <= 0) {
352 return 0;
353 }
354 size_t total_read = 0;
355 int timeout_ms = kFmqReceiveTimeoutMs;
356 do {
357 std::unique_lock<std::recursive_mutex> lock(mutex_);
358 if (!IsSessionReady()) {
359 break;
360 }
361 size_t num_bytes_to_read = data_mq_->availableToRead();
362 if (num_bytes_to_read) {
363 if (num_bytes_to_read > (bytes - total_read)) {
364 num_bytes_to_read = bytes - total_read;
365 }
366 if (!data_mq_->read(static_cast<MQDataType*>(buffer) + total_read,
367 num_bytes_to_read)) {
368 LOG(ERROR) << "FMQ datapath reading " << total_read << "/" << bytes
369 << " failed";
370 return total_read;
371 }
372 total_read += num_bytes_to_read;
373 } else if (timeout_ms >= kReadPollMs) {
374 lock.unlock();
375 usleep(kReadPollMs * 1000);
376 timeout_ms -= kReadPollMs;
377 continue;
378 } else {
379 LOG(DEBUG) << "Data " << total_read << "/" << bytes << " overflow "
380 << (kFmqReceiveTimeoutMs - timeout_ms) << " ms";
381 return total_read;
382 }
383 } while (total_read < bytes);
384 return total_read;
385}
386
387/***
388 *
389 * Other methods
390 *
391 ***/
392
393void BluetoothAudioSession::ReportControlStatus(bool start_resp,
394 BluetoothAudioStatus status) {
395 std::lock_guard<std::recursive_mutex> guard(mutex_);
396 if (observers_.empty()) {
397 LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
398 << " has NO port state observer";
399 return;
400 }
401 for (auto& observer : observers_) {
402 uint16_t cookie = observer.first;
403 std::shared_ptr<PortStatusCallbacks> callback = observer.second;
404 LOG(INFO) << __func__ << " - status=" << toString(status)
405 << " for SessionType=" << toString(session_type_)
406 << ", bluetooth_audio=0x"
407 << ::android::base::StringPrintf("%04x", cookie)
408 << (start_resp ? " started" : " suspended");
409 callback->control_result_cb_(cookie, start_resp, status);
410 }
411}
412
Chen Chen81f38e52022-02-09 13:27:35 -0800413void BluetoothAudioSession::ReportLowLatencyModeAllowedChanged(bool allowed) {
414 std::lock_guard<std::recursive_mutex> guard(mutex_);
415 if (observers_.empty()) {
416 LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
417 << " has NO port state observer";
418 return;
419 }
420 for (auto& observer : observers_) {
421 uint16_t cookie = observer.first;
422 std::shared_ptr<PortStatusCallbacks> callback = observer.second;
423 LOG(INFO) << __func__ << " - allowed="
424 << allowed ? " allowed" : " disallowed";
425 callback->low_latency_mode_allowed_cb_(cookie, allowed);
426 }
427}
428
Josh Wu20bac522021-12-29 23:52:39 -0800429bool BluetoothAudioSession::GetPresentationPosition(
430 PresentationPosition& presentation_position) {
431 std::lock_guard<std::recursive_mutex> guard(mutex_);
432 if (!IsSessionReady()) {
433 LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
434 << " has NO session";
435 return false;
436 }
437 bool retval = false;
438
439 if (!stack_iface_->getPresentationPosition(&presentation_position).isOk()) {
440 LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
441 << toString(session_type_) << " failed";
442 return false;
443 }
444 return retval;
445}
446
447void BluetoothAudioSession::UpdateSourceMetadata(
448 const struct source_metadata& source_metadata) {
449 std::lock_guard<std::recursive_mutex> guard(mutex_);
450 if (!IsSessionReady()) {
451 LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
452 << " has NO session";
453 return;
454 }
455
456 ssize_t track_count = source_metadata.track_count;
457 LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) << ","
458 << track_count << " track(s)";
459 if (session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH ||
460 session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
461 return;
462 }
463
464 SourceMetadata hal_source_metadata;
465 hal_source_metadata.tracks.resize(track_count);
466 for (int i = 0; i < track_count; i++) {
467 hal_source_metadata.tracks[i].usage =
468 static_cast<media::audio::common::AudioUsage>(
469 source_metadata.tracks[i].usage);
470 hal_source_metadata.tracks[i].contentType =
471 static_cast<media::audio::common::AudioContentType>(
472 source_metadata.tracks[i].content_type);
473 hal_source_metadata.tracks[i].gain = source_metadata.tracks[i].gain;
474 LOG(VERBOSE) << __func__ << " - SessionType=" << toString(session_type_)
475 << ", usage=" << toString(hal_source_metadata.tracks[i].usage)
476 << ", content="
477 << toString(hal_source_metadata.tracks[i].contentType)
478 << ", gain=" << hal_source_metadata.tracks[i].gain;
479 }
480
481 auto hal_retval = stack_iface_->updateSourceMetadata(hal_source_metadata);
482 if (!hal_retval.isOk()) {
483 LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
484 << toString(session_type_) << " failed";
485 }
486}
487
488void BluetoothAudioSession::UpdateSinkMetadata(
489 const struct sink_metadata& sink_metadata) {
490 std::lock_guard<std::recursive_mutex> guard(mutex_);
491 if (!IsSessionReady()) {
492 LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
493 << " has NO session";
494 return;
495 }
496
497 ssize_t track_count = sink_metadata.track_count;
498 LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) << ","
499 << track_count << " track(s)";
500 if (session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH ||
501 session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
502 return;
503 }
504
505 SinkMetadata hal_sink_metadata;
506 hal_sink_metadata.tracks.resize(track_count);
507 for (int i = 0; i < track_count; i++) {
508 hal_sink_metadata.tracks[i].source =
509 static_cast<media::audio::common::AudioSource>(
510 sink_metadata.tracks[i].source);
511 hal_sink_metadata.tracks[i].gain = sink_metadata.tracks[i].gain;
512 LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
513 << ", source=" << sink_metadata.tracks[i].source
514 << ", dest_device=" << sink_metadata.tracks[i].dest_device
515 << ", gain=" << sink_metadata.tracks[i].gain
516 << ", dest_device_address="
517 << sink_metadata.tracks[i].dest_device_address;
518 }
519
520 auto hal_retval = stack_iface_->updateSinkMetadata(hal_sink_metadata);
521 if (!hal_retval.isOk()) {
522 LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
523 << toString(session_type_) << " failed";
524 }
525}
526
Chen Chena4c4c612022-02-07 18:01:05 -0800527void BluetoothAudioSession::SetLatencyMode(LatencyMode latency_mode) {
528 std::lock_guard<std::recursive_mutex> guard(mutex_);
529 if (!IsSessionReady()) {
530 LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
531 << " has NO session";
532 return;
533 }
534
535 auto hal_retval = stack_iface_->setLatencyMode(latency_mode);
536 if (!hal_retval.isOk()) {
537 LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
538 << toString(session_type_) << " failed";
539 }
540}
541
542void BluetoothAudioSession::SetCodecType(CodecType codec_type) {
543 std::lock_guard<std::recursive_mutex> guard(mutex_);
544 if (!IsSessionReady()) {
545 LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
546 << " has NO session";
547 return;
548 }
549
550 auto hal_retval = stack_iface_->setCodecType(codec_type);
551 if (!hal_retval.isOk()) {
552 LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
553 << toString(session_type_) << " failed";
554 }
555}
556
Josh Wu20bac522021-12-29 23:52:39 -0800557bool BluetoothAudioSession::IsAidlAvailable() {
558 if (is_aidl_checked) return is_aidl_available;
559 is_aidl_available =
560 (AServiceManager_checkService(
561 kDefaultAudioProviderFactoryInterface.c_str()) != nullptr);
562 is_aidl_checked = true;
563 return is_aidl_available;
564}
565
566/***
567 *
568 * BluetoothAudioSessionInstance
569 *
570 ***/
571std::mutex BluetoothAudioSessionInstance::mutex_;
572std::unordered_map<SessionType, std::shared_ptr<BluetoothAudioSession>>
573 BluetoothAudioSessionInstance::sessions_map_;
574
575std::shared_ptr<BluetoothAudioSession>
576BluetoothAudioSessionInstance::GetSessionInstance(
577 const SessionType& session_type) {
578 std::lock_guard<std::mutex> guard(mutex_);
579
580 if (!sessions_map_.empty()) {
581 auto entry = sessions_map_.find(session_type);
582 if (entry != sessions_map_.end()) {
583 return entry->second;
584 }
585 }
586 std::shared_ptr<BluetoothAudioSession> session_ptr =
587 std::make_shared<BluetoothAudioSession>(session_type);
588 sessions_map_[session_type] = session_ptr;
589 return session_ptr;
590}
591
592} // namespace audio
593} // namespace bluetooth
594} // namespace hardware
595} // namespace android
596} // namespace aidl