blob: 95e473e5b932aa585200298224bf35ca58274da1 [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
38const CodecConfiguration BluetoothAudioSession::kInvalidCodecConfiguration = {};
39const LeAudioConfiguration kInvalidLeAudioConfiguration = {};
40AudioConfiguration BluetoothAudioSession::invalidSoftwareAudioConfiguration =
41 {};
42AudioConfiguration BluetoothAudioSession::invalidOffloadAudioConfiguration = {};
43AudioConfiguration BluetoothAudioSession::invalidLeOffloadAudioConfig = {};
44
45BluetoothAudioSession::BluetoothAudioSession(const SessionType& session_type)
46 : session_type_(session_type), stack_iface_(nullptr), data_mq_(nullptr) {
47 invalidSoftwareAudioConfiguration.set<AudioConfiguration::pcmConfig>(
48 kInvalidPcmConfiguration);
49 invalidOffloadAudioConfiguration.set<AudioConfiguration::a2dpConfig>(
50 kInvalidCodecConfiguration);
51 invalidLeOffloadAudioConfig.set<AudioConfiguration::leAudioConfig>(
52 kInvalidLeAudioConfiguration);
53}
54
55/***
56 *
57 * Callback methods
58 *
59 ***/
60
61void BluetoothAudioSession::OnSessionStarted(
62 const std::shared_ptr<IBluetoothAudioPort> stack_iface,
63 const DataMQDesc* mq_desc, const AudioConfiguration& audio_config) {
64 std::lock_guard<std::recursive_mutex> guard(mutex_);
65 if (stack_iface == nullptr) {
66 LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_)
67 << ", IBluetoothAudioPort Invalid";
68 } else if (!UpdateAudioConfig(audio_config)) {
69 LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_)
70 << ", AudioConfiguration=" << audio_config.toString()
71 << " Invalid";
72 } else if (!UpdateDataPath(mq_desc)) {
73 LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_)
74 << " MqDescriptor Invalid";
75 if (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
76 audio_config_ = std::make_unique<AudioConfiguration>(
77 invalidOffloadAudioConfiguration);
78 } else {
79 audio_config_ = std::make_unique<AudioConfiguration>(
80 invalidSoftwareAudioConfiguration);
81 }
82 } else {
83 stack_iface_ = stack_iface;
84 LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
85 << ", AudioConfiguration=" << audio_config.toString();
86 ReportSessionStatus();
87 }
88}
89
90void BluetoothAudioSession::OnSessionEnded() {
91 std::lock_guard<std::recursive_mutex> guard(mutex_);
92 bool toggled = IsSessionReady();
93 LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_);
94 if (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
95 audio_config_ =
96 std::make_unique<AudioConfiguration>(invalidOffloadAudioConfiguration);
97 } else {
98 audio_config_ =
99 std::make_unique<AudioConfiguration>(invalidSoftwareAudioConfiguration);
100 }
101 stack_iface_ = nullptr;
102 UpdateDataPath(nullptr);
103 if (toggled) {
104 ReportSessionStatus();
105 }
106}
107
108/***
109 *
110 * Util methods
111 *
112 ***/
113
114const AudioConfiguration& BluetoothAudioSession::GetAudioConfig() {
115 std::lock_guard<std::recursive_mutex> guard(mutex_);
116 if (!IsSessionReady()) {
117 if (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
118 return invalidOffloadAudioConfiguration;
119 } else {
120 return invalidSoftwareAudioConfiguration;
121 }
122 switch (session_type_) {
123 case SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH:
124 return invalidOffloadAudioConfiguration;
125 case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH:
126 case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH:
127 return invalidLeOffloadAudioConfig;
128 default:
129 return invalidSoftwareAudioConfiguration;
130 }
131 }
132 return *audio_config_;
133}
134
135void BluetoothAudioSession::ReportAudioConfigChanged(
136 const AudioConfiguration& audio_config) {
137 if (session_type_ !=
138 SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
139 session_type_ !=
140 SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
141 return;
142 }
143 std::lock_guard<std::recursive_mutex> guard(mutex_);
144 audio_config_ = std::make_unique<AudioConfiguration>(audio_config);
145 if (observers_.empty()) {
146 LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
147 << " has NO port state observer";
148 return;
149 }
150 for (auto& observer : observers_) {
151 uint16_t cookie = observer.first;
152 std::shared_ptr<struct PortStatusCallbacks> cb = observer.second;
153 LOG(INFO) << __func__ << " for SessionType=" << toString(session_type_)
154 << ", bluetooth_audio=0x"
155 << ::android::base::StringPrintf("%04x", cookie);
156 if (cb->audio_configuration_changed_cb_ != nullptr) {
157 cb->audio_configuration_changed_cb_(cookie);
158 }
159 }
160}
161
162bool BluetoothAudioSession::IsSessionReady() {
163 std::lock_guard<std::recursive_mutex> guard(mutex_);
164
165 bool is_mq_valid =
166 (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
167 session_type_ ==
168 SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
169 session_type_ ==
170 SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH ||
171 (data_mq_ != nullptr && data_mq_->isValid()));
172 return stack_iface_ != nullptr && is_mq_valid;
173}
174
175/***
176 *
177 * Status callback methods
178 *
179 ***/
180
181uint16_t BluetoothAudioSession::RegisterStatusCback(
182 const PortStatusCallbacks& callbacks) {
183 std::lock_guard<std::recursive_mutex> guard(mutex_);
184 uint16_t cookie = ObserversCookieGetInitValue(session_type_);
185 uint16_t cookie_upper_bound = ObserversCookieGetUpperBound(session_type_);
186
187 while (cookie < cookie_upper_bound) {
188 if (observers_.find(cookie) == observers_.end()) {
189 break;
190 }
191 ++cookie;
192 }
193 if (cookie >= cookie_upper_bound) {
194 LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_)
195 << " has " << observers_.size()
196 << " observers already (No Resource)";
197 return kObserversCookieUndefined;
198 }
199 std::shared_ptr<PortStatusCallbacks> cb =
200 std::make_shared<PortStatusCallbacks>();
201 *cb = callbacks;
202 observers_[cookie] = cb;
203 return cookie;
204}
205
206void BluetoothAudioSession::UnregisterStatusCback(uint16_t cookie) {
207 std::lock_guard<std::recursive_mutex> guard(mutex_);
208 if (observers_.erase(cookie) != 1) {
209 LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
210 << " no such provider=0x"
211 << ::android::base::StringPrintf("%04x", cookie);
212 }
213}
214
215/***
216 *
217 * Stream methods
218 *
219 ***/
220
221bool BluetoothAudioSession::StartStream() {
222 std::lock_guard<std::recursive_mutex> guard(mutex_);
223 if (!IsSessionReady()) {
224 LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
225 << " has NO session";
226 return false;
227 }
228 auto hal_retval = stack_iface_->startStream();
229 if (!hal_retval.isOk()) {
230 LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
231 << toString(session_type_) << " failed";
232 return false;
233 }
234 return true;
235}
236
237bool BluetoothAudioSession::SuspendStream() {
238 std::lock_guard<std::recursive_mutex> guard(mutex_);
239 if (!IsSessionReady()) {
240 LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
241 << " has NO session";
242 return false;
243 }
244 auto hal_retval = stack_iface_->suspendStream();
245 if (!hal_retval.isOk()) {
246 LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
247 << toString(session_type_) << " failed";
248 return false;
249 }
250 return true;
251}
252
253void BluetoothAudioSession::StopStream() {
254 std::lock_guard<std::recursive_mutex> guard(mutex_);
255 if (!IsSessionReady()) {
256 return;
257 }
258 auto hal_retval = stack_iface_->stopStream();
259 if (!hal_retval.isOk()) {
260 LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
261 << toString(session_type_) << " failed";
262 }
263}
264
265/***
266 *
267 * Private methods
268 *
269 ***/
270
271bool BluetoothAudioSession::UpdateDataPath(const DataMQDesc* mq_desc) {
272 if (mq_desc == nullptr) {
273 // usecase of reset by nullptr
274 data_mq_ = nullptr;
275 return true;
276 }
277 std::unique_ptr<DataMQ> temp_mq;
278 temp_mq.reset(new DataMQ(*mq_desc));
279 if (!temp_mq || !temp_mq->isValid()) {
280 data_mq_ = nullptr;
281 return false;
282 }
283 data_mq_ = std::move(temp_mq);
284 return true;
285}
286
287bool BluetoothAudioSession::UpdateAudioConfig(
288 const AudioConfiguration& audio_config) {
289 bool is_software_session =
290 (session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH ||
291 session_type_ == SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH ||
292 session_type_ == SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH ||
293 session_type_ == SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH);
294 bool is_offload_a2dp_session =
295 (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH);
296 bool is_offload_le_audio_session =
297 (session_type_ ==
298 SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
299 session_type_ ==
300 SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH);
301 auto audio_config_tag = audio_config.getTag();
302 bool is_software_audio_config =
303 (is_software_session &&
304 audio_config_tag == AudioConfiguration::pcmConfig);
305 bool is_a2dp_offload_audio_config =
306 (is_offload_a2dp_session &&
307 audio_config_tag == AudioConfiguration::a2dpConfig);
308 bool is_le_audio_offload_audio_config =
309 (is_offload_le_audio_session &&
310 audio_config_tag == AudioConfiguration::leAudioConfig);
311 if (!is_software_audio_config && !is_a2dp_offload_audio_config &&
312 !is_le_audio_offload_audio_config) {
313 return false;
314 }
315 audio_config_ = std::make_unique<AudioConfiguration>(audio_config);
316 return true;
317}
318
319void BluetoothAudioSession::ReportSessionStatus() {
320 // This is locked already by OnSessionStarted / OnSessionEnded
321 if (observers_.empty()) {
322 LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
323 << " has NO port state observer";
324 return;
325 }
326 for (auto& observer : observers_) {
327 uint16_t cookie = observer.first;
328 std::shared_ptr<PortStatusCallbacks> callback = observer.second;
329 LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
330 << " notify to bluetooth_audio=0x"
331 << ::android::base::StringPrintf("%04x", cookie);
332 callback->session_changed_cb_(cookie);
333 }
334}
335
336/***
337 *
338 * PCM methods
339 *
340 ***/
341
342size_t BluetoothAudioSession::OutWritePcmData(const void* buffer,
343 size_t bytes) {
344 if (buffer == nullptr || bytes <= 0) {
345 return 0;
346 }
347 size_t total_written = 0;
348 int timeout_ms = kFmqSendTimeoutMs;
349 do {
350 std::unique_lock<std::recursive_mutex> lock(mutex_);
351 if (!IsSessionReady()) {
352 break;
353 }
354 size_t num_bytes_to_write = data_mq_->availableToWrite();
355 if (num_bytes_to_write) {
356 if (num_bytes_to_write > (bytes - total_written)) {
357 num_bytes_to_write = bytes - total_written;
358 }
359
360 if (!data_mq_->write(
361 static_cast<const MQDataType*>(buffer) + total_written,
362 num_bytes_to_write)) {
363 LOG(ERROR) << "FMQ datapath writing " << total_written << "/" << bytes
364 << " failed";
365 return total_written;
366 }
367 total_written += num_bytes_to_write;
368 } else if (timeout_ms >= kWritePollMs) {
369 lock.unlock();
370 usleep(kWritePollMs * 1000);
371 timeout_ms -= kWritePollMs;
372 } else {
373 LOG(DEBUG) << "Data " << total_written << "/" << bytes << " overflow "
374 << (kFmqSendTimeoutMs - timeout_ms) << " ms";
375 return total_written;
376 }
377 } while (total_written < bytes);
378 return total_written;
379}
380
381size_t BluetoothAudioSession::InReadPcmData(void* buffer, size_t bytes) {
382 if (buffer == nullptr || bytes <= 0) {
383 return 0;
384 }
385 size_t total_read = 0;
386 int timeout_ms = kFmqReceiveTimeoutMs;
387 do {
388 std::unique_lock<std::recursive_mutex> lock(mutex_);
389 if (!IsSessionReady()) {
390 break;
391 }
392 size_t num_bytes_to_read = data_mq_->availableToRead();
393 if (num_bytes_to_read) {
394 if (num_bytes_to_read > (bytes - total_read)) {
395 num_bytes_to_read = bytes - total_read;
396 }
397 if (!data_mq_->read(static_cast<MQDataType*>(buffer) + total_read,
398 num_bytes_to_read)) {
399 LOG(ERROR) << "FMQ datapath reading " << total_read << "/" << bytes
400 << " failed";
401 return total_read;
402 }
403 total_read += num_bytes_to_read;
404 } else if (timeout_ms >= kReadPollMs) {
405 lock.unlock();
406 usleep(kReadPollMs * 1000);
407 timeout_ms -= kReadPollMs;
408 continue;
409 } else {
410 LOG(DEBUG) << "Data " << total_read << "/" << bytes << " overflow "
411 << (kFmqReceiveTimeoutMs - timeout_ms) << " ms";
412 return total_read;
413 }
414 } while (total_read < bytes);
415 return total_read;
416}
417
418/***
419 *
420 * Other methods
421 *
422 ***/
423
424void BluetoothAudioSession::ReportControlStatus(bool start_resp,
425 BluetoothAudioStatus status) {
426 std::lock_guard<std::recursive_mutex> guard(mutex_);
427 if (observers_.empty()) {
428 LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
429 << " has NO port state observer";
430 return;
431 }
432 for (auto& observer : observers_) {
433 uint16_t cookie = observer.first;
434 std::shared_ptr<PortStatusCallbacks> callback = observer.second;
435 LOG(INFO) << __func__ << " - status=" << toString(status)
436 << " for SessionType=" << toString(session_type_)
437 << ", bluetooth_audio=0x"
438 << ::android::base::StringPrintf("%04x", cookie)
439 << (start_resp ? " started" : " suspended");
440 callback->control_result_cb_(cookie, start_resp, status);
441 }
442}
443
444bool BluetoothAudioSession::GetPresentationPosition(
445 PresentationPosition& presentation_position) {
446 std::lock_guard<std::recursive_mutex> guard(mutex_);
447 if (!IsSessionReady()) {
448 LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
449 << " has NO session";
450 return false;
451 }
452 bool retval = false;
453
454 if (!stack_iface_->getPresentationPosition(&presentation_position).isOk()) {
455 LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
456 << toString(session_type_) << " failed";
457 return false;
458 }
459 return retval;
460}
461
462void BluetoothAudioSession::UpdateSourceMetadata(
463 const struct source_metadata& source_metadata) {
464 std::lock_guard<std::recursive_mutex> guard(mutex_);
465 if (!IsSessionReady()) {
466 LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
467 << " has NO session";
468 return;
469 }
470
471 ssize_t track_count = source_metadata.track_count;
472 LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) << ","
473 << track_count << " track(s)";
474 if (session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH ||
475 session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
476 return;
477 }
478
479 SourceMetadata hal_source_metadata;
480 hal_source_metadata.tracks.resize(track_count);
481 for (int i = 0; i < track_count; i++) {
482 hal_source_metadata.tracks[i].usage =
483 static_cast<media::audio::common::AudioUsage>(
484 source_metadata.tracks[i].usage);
485 hal_source_metadata.tracks[i].contentType =
486 static_cast<media::audio::common::AudioContentType>(
487 source_metadata.tracks[i].content_type);
488 hal_source_metadata.tracks[i].gain = source_metadata.tracks[i].gain;
489 LOG(VERBOSE) << __func__ << " - SessionType=" << toString(session_type_)
490 << ", usage=" << toString(hal_source_metadata.tracks[i].usage)
491 << ", content="
492 << toString(hal_source_metadata.tracks[i].contentType)
493 << ", gain=" << hal_source_metadata.tracks[i].gain;
494 }
495
496 auto hal_retval = stack_iface_->updateSourceMetadata(hal_source_metadata);
497 if (!hal_retval.isOk()) {
498 LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
499 << toString(session_type_) << " failed";
500 }
501}
502
503void BluetoothAudioSession::UpdateSinkMetadata(
504 const struct sink_metadata& sink_metadata) {
505 std::lock_guard<std::recursive_mutex> guard(mutex_);
506 if (!IsSessionReady()) {
507 LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
508 << " has NO session";
509 return;
510 }
511
512 ssize_t track_count = sink_metadata.track_count;
513 LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) << ","
514 << track_count << " track(s)";
515 if (session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH ||
516 session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
517 return;
518 }
519
520 SinkMetadata hal_sink_metadata;
521 hal_sink_metadata.tracks.resize(track_count);
522 for (int i = 0; i < track_count; i++) {
523 hal_sink_metadata.tracks[i].source =
524 static_cast<media::audio::common::AudioSource>(
525 sink_metadata.tracks[i].source);
526 hal_sink_metadata.tracks[i].gain = sink_metadata.tracks[i].gain;
527 LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
528 << ", source=" << sink_metadata.tracks[i].source
529 << ", dest_device=" << sink_metadata.tracks[i].dest_device
530 << ", gain=" << sink_metadata.tracks[i].gain
531 << ", dest_device_address="
532 << sink_metadata.tracks[i].dest_device_address;
533 }
534
535 auto hal_retval = stack_iface_->updateSinkMetadata(hal_sink_metadata);
536 if (!hal_retval.isOk()) {
537 LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
538 << toString(session_type_) << " failed";
539 }
540}
541
542bool BluetoothAudioSession::IsAidlAvailable() {
543 if (is_aidl_checked) return is_aidl_available;
544 is_aidl_available =
545 (AServiceManager_checkService(
546 kDefaultAudioProviderFactoryInterface.c_str()) != nullptr);
547 is_aidl_checked = true;
548 return is_aidl_available;
549}
550
551/***
552 *
553 * BluetoothAudioSessionInstance
554 *
555 ***/
556std::mutex BluetoothAudioSessionInstance::mutex_;
557std::unordered_map<SessionType, std::shared_ptr<BluetoothAudioSession>>
558 BluetoothAudioSessionInstance::sessions_map_;
559
560std::shared_ptr<BluetoothAudioSession>
561BluetoothAudioSessionInstance::GetSessionInstance(
562 const SessionType& session_type) {
563 std::lock_guard<std::mutex> guard(mutex_);
564
565 if (!sessions_map_.empty()) {
566 auto entry = sessions_map_.find(session_type);
567 if (entry != sessions_map_.end()) {
568 return entry->second;
569 }
570 }
571 std::shared_ptr<BluetoothAudioSession> session_ptr =
572 std::make_shared<BluetoothAudioSession>(session_type);
573 sessions_map_[session_type] = session_ptr;
574 return session_ptr;
575}
576
577} // namespace audio
578} // namespace bluetooth
579} // namespace hardware
580} // namespace android
581} // namespace aidl