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