1 /*
2 * Copyright 2018 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 #define LOG_TAG "BTAudioProviderSession"
18
19 #include "BluetoothAudioSession.h"
20
21 #include <android-base/logging.h>
22 #include <android-base/stringprintf.h>
23
24 #include "../aidl_session/HidlToAidlMiddleware_2_0.h"
25
26 namespace android {
27 namespace bluetooth {
28 namespace audio {
29
30 using ::aidl::android::hardware::bluetooth::audio::HidlToAidlMiddleware_2_0;
31 using ::android::hardware::audio::common::V5_0::AudioContentType;
32 using ::android::hardware::audio::common::V5_0::AudioUsage;
33 using ::android::hardware::audio::common::V5_0::PlaybackTrackMetadata;
34 using ::android::hardware::audio::common::V5_0::SourceMetadata;
35 using ::android::hardware::bluetooth::audio::V2_0::CodecType;
36 using ::android::hardware::bluetooth::audio::V2_0::TimeSpec;
37
38 const CodecConfiguration BluetoothAudioSession::kInvalidCodecConfiguration = {
39 .codecType = CodecType::UNKNOWN,
40 .encodedAudioBitrate = 0x00000000,
41 .peerMtu = 0xffff,
42 .isScmstEnabled = false,
43 .config = {}};
44 AudioConfiguration BluetoothAudioSession::invalidSoftwareAudioConfiguration =
45 {};
46 AudioConfiguration BluetoothAudioSession::invalidOffloadAudioConfiguration = {};
47
48 static constexpr int kFmqSendTimeoutMs = 1000; // 1000 ms timeout for sending
49 static constexpr int kFmqReceiveTimeoutMs =
50 1000; // 1000 ms timeout for receiving
51 static constexpr int kWritePollMs = 1; // polled non-blocking interval
52 static constexpr int kReadPollMs = 1; // polled non-blocking interval
53
timespec_convert_from_hal(const TimeSpec & TS)54 static inline timespec timespec_convert_from_hal(const TimeSpec& TS) {
55 return {.tv_sec = static_cast<long>(TS.tvSec),
56 .tv_nsec = static_cast<long>(TS.tvNSec)};
57 }
58
BluetoothAudioSession(const SessionType & session_type)59 BluetoothAudioSession::BluetoothAudioSession(const SessionType& session_type)
60 : session_type_(session_type), stack_iface_(nullptr), mDataMQ(nullptr) {
61 invalidSoftwareAudioConfiguration.pcmConfig(kInvalidPcmParameters);
62 invalidOffloadAudioConfiguration.codecConfig(kInvalidCodecConfiguration);
63 }
64
65 // The report function is used to report that the Bluetooth stack has started
66 // this session without any failure, and will invoke session_changed_cb_ to
67 // notify those registered bluetooth_audio outputs
OnSessionStarted(const sp<IBluetoothAudioPort> stack_iface,const DataMQ::Descriptor * dataMQ,const AudioConfiguration & audio_config)68 void BluetoothAudioSession::OnSessionStarted(
69 const sp<IBluetoothAudioPort> stack_iface, const DataMQ::Descriptor* dataMQ,
70 const AudioConfiguration& audio_config) {
71 std::lock_guard<std::recursive_mutex> guard(mutex_);
72 if (stack_iface == nullptr) {
73 LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_)
74 << ", IBluetoothAudioPort Invalid";
75 } else if (!UpdateAudioConfig(audio_config)) {
76 LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_)
77 << ", AudioConfiguration=" << toString(audio_config)
78 << " Invalid";
79 } else if (!UpdateDataPath(dataMQ)) {
80 LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_)
81 << " DataMQ Invalid";
82 audio_config_ =
83 (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH
84 ? kInvalidOffloadAudioConfiguration
85 : kInvalidSoftwareAudioConfiguration);
86 } else {
87 stack_iface_ = stack_iface;
88 LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
89 << ", AudioConfiguration=" << toString(audio_config);
90 ReportSessionStatus();
91 }
92 }
93
94 // The report function is used to report that the Bluetooth stack has ended the
95 // session, and will invoke session_changed_cb_ to notify registered
96 // bluetooth_audio outputs
OnSessionEnded()97 void BluetoothAudioSession::OnSessionEnded() {
98 std::lock_guard<std::recursive_mutex> guard(mutex_);
99 bool toggled = IsSessionReady();
100 LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_);
101 audio_config_ = (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH
102 ? kInvalidOffloadAudioConfiguration
103 : kInvalidSoftwareAudioConfiguration);
104 stack_iface_ = nullptr;
105 UpdateDataPath(nullptr);
106 if (toggled) {
107 ReportSessionStatus();
108 }
109 }
110
111 // invoking the registered session_changed_cb_
ReportSessionStatus()112 void BluetoothAudioSession::ReportSessionStatus() {
113 // This is locked already by OnSessionStarted / OnSessionEnded
114 if (observers_.empty()) {
115 LOG(INFO) << __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__ << " - SessionType=" << toString(session_type_)
123 << " notify to bluetooth_audio=0x"
124 << android::base::StringPrintf("%04x", cookie);
125 cb->session_changed_cb_(cookie);
126 }
127 }
128
129 // The report function is used to report that the Bluetooth stack has notified
130 // the result of startStream or suspendStream, and will invoke
131 // control_result_cb_ to notify registered bluetooth_audio outputs
ReportControlStatus(bool start_resp,const BluetoothAudioStatus & status)132 void BluetoothAudioSession::ReportControlStatus(
133 bool start_resp, const BluetoothAudioStatus& status) {
134 std::lock_guard<std::recursive_mutex> guard(mutex_);
135 if (observers_.empty()) {
136 LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
137 << " has NO port state observer";
138 return;
139 }
140 for (auto& observer : observers_) {
141 uint16_t cookie = observer.first;
142 std::shared_ptr<struct PortStatusCallbacks> cb = observer.second;
143 LOG(INFO) << __func__ << " - status=" << toString(status)
144 << " for SessionType=" << toString(session_type_)
145 << ", bluetooth_audio=0x"
146 << android::base::StringPrintf("%04x", cookie)
147 << (start_resp ? " started" : " suspended");
148 cb->control_result_cb_(cookie, start_resp, status);
149 }
150 }
151
152 // The function helps to check if this session is ready or not
153 // @return: true if the Bluetooth stack has started the specified session
IsSessionReady()154 bool BluetoothAudioSession::IsSessionReady() {
155 if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
156 return HidlToAidlMiddleware_2_0::IsSessionReady(session_type_);
157 std::lock_guard<std::recursive_mutex> guard(mutex_);
158 bool dataMQ_valid =
159 (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH ||
160 (mDataMQ != nullptr && mDataMQ->isValid()));
161 return stack_iface_ != nullptr && dataMQ_valid;
162 }
163
UpdateDataPath(const DataMQ::Descriptor * dataMQ)164 bool BluetoothAudioSession::UpdateDataPath(const DataMQ::Descriptor* dataMQ) {
165 if (dataMQ == nullptr) {
166 // usecase of reset by nullptr
167 mDataMQ = nullptr;
168 return true;
169 }
170 std::unique_ptr<DataMQ> tempDataMQ;
171 tempDataMQ.reset(new DataMQ(*dataMQ));
172 if (!tempDataMQ || !tempDataMQ->isValid()) {
173 mDataMQ = nullptr;
174 return false;
175 }
176 mDataMQ = std::move(tempDataMQ);
177 return true;
178 }
179
UpdateAudioConfig(const AudioConfiguration & audio_config)180 bool BluetoothAudioSession::UpdateAudioConfig(
181 const AudioConfiguration& audio_config) {
182 bool is_software_session =
183 (session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH ||
184 session_type_ == SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH);
185 bool is_offload_session =
186 (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH);
187 auto audio_config_discriminator = audio_config.getDiscriminator();
188 bool is_software_audio_config =
189 (is_software_session &&
190 audio_config_discriminator ==
191 AudioConfiguration::hidl_discriminator::pcmConfig);
192 bool is_offload_audio_config =
193 (is_offload_session &&
194 audio_config_discriminator ==
195 AudioConfiguration::hidl_discriminator::codecConfig);
196 if (!is_software_audio_config && !is_offload_audio_config) {
197 return false;
198 }
199 audio_config_ = audio_config;
200 return true;
201 }
202
203 // The control function helps the bluetooth_audio module to register
204 // PortStatusCallbacks
205 // @return: cookie - the assigned number to this bluetooth_audio output
RegisterStatusCback(const PortStatusCallbacks & cbacks)206 uint16_t BluetoothAudioSession::RegisterStatusCback(
207 const PortStatusCallbacks& cbacks) {
208 if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
209 return HidlToAidlMiddleware_2_0::RegisterControlResultCback(session_type_,
210 cbacks);
211 std::lock_guard<std::recursive_mutex> guard(mutex_);
212 uint16_t cookie = ObserversCookieGetInitValue(session_type_);
213 uint16_t cookie_upper_bound = ObserversCookieGetUpperBound(session_type_);
214
215 while (cookie < cookie_upper_bound) {
216 if (observers_.find(cookie) == observers_.end()) {
217 break;
218 }
219 ++cookie;
220 }
221 if (cookie >= cookie_upper_bound) {
222 LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_)
223 << " has " << observers_.size()
224 << " observers already (No Resource)";
225 return kObserversCookieUndefined;
226 }
227 std::shared_ptr<struct PortStatusCallbacks> cb =
228 std::make_shared<struct PortStatusCallbacks>();
229 *cb = cbacks;
230 observers_[cookie] = cb;
231 return cookie;
232 }
233
234 // The control function helps the bluetooth_audio module to unregister
235 // PortStatusCallbacks
236 // @param: cookie - indicates which bluetooth_audio output is
UnregisterStatusCback(uint16_t cookie)237 void BluetoothAudioSession::UnregisterStatusCback(uint16_t cookie) {
238 if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
239 return HidlToAidlMiddleware_2_0::UnregisterControlResultCback(session_type_,
240 cookie);
241 std::lock_guard<std::recursive_mutex> guard(mutex_);
242 if (observers_.erase(cookie) != 1) {
243 LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
244 << " no such provider=0x"
245 << android::base::StringPrintf("%04x", cookie);
246 }
247 }
248
249 // The control function is for the bluetooth_audio module to get the current
250 // AudioConfiguration
GetAudioConfig()251 const AudioConfiguration& BluetoothAudioSession::GetAudioConfig() {
252 if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
253 return (audio_config_ =
254 HidlToAidlMiddleware_2_0::GetAudioConfig(session_type_));
255 std::lock_guard<std::recursive_mutex> guard(mutex_);
256 if (IsSessionReady()) {
257 return audio_config_;
258 } else if (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH) {
259 return kInvalidOffloadAudioConfiguration;
260 } else {
261 return kInvalidSoftwareAudioConfiguration;
262 }
263 }
264
265 // Those control functions are for the bluetooth_audio module to start, suspend,
266 // stop stream, to check position, and to update metadata.
StartStream()267 bool BluetoothAudioSession::StartStream() {
268 if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
269 return HidlToAidlMiddleware_2_0::StartStream(session_type_);
270 std::lock_guard<std::recursive_mutex> guard(mutex_);
271 if (!IsSessionReady()) {
272 LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
273 << " has NO session";
274 return false;
275 }
276 auto hal_retval = stack_iface_->startStream();
277 if (!hal_retval.isOk()) {
278 LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
279 << toString(session_type_) << " failed";
280 return false;
281 }
282 return true;
283 }
284
SuspendStream()285 bool BluetoothAudioSession::SuspendStream() {
286 if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
287 return HidlToAidlMiddleware_2_0::SuspendStream(session_type_);
288 std::lock_guard<std::recursive_mutex> guard(mutex_);
289 if (!IsSessionReady()) {
290 LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
291 << " has NO session";
292 return false;
293 }
294 auto hal_retval = stack_iface_->suspendStream();
295 if (!hal_retval.isOk()) {
296 LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
297 << toString(session_type_) << " failed";
298 return false;
299 }
300 return true;
301 }
302
StopStream()303 void BluetoothAudioSession::StopStream() {
304 if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
305 return HidlToAidlMiddleware_2_0::StopStream(session_type_);
306 std::lock_guard<std::recursive_mutex> guard(mutex_);
307 if (!IsSessionReady()) {
308 return;
309 }
310 auto hal_retval = stack_iface_->stopStream();
311 if (!hal_retval.isOk()) {
312 LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
313 << toString(session_type_) << " failed";
314 }
315 }
316
GetPresentationPosition(uint64_t * remote_delay_report_ns,uint64_t * total_bytes_readed,timespec * data_position)317 bool BluetoothAudioSession::GetPresentationPosition(
318 uint64_t* remote_delay_report_ns, uint64_t* total_bytes_readed,
319 timespec* data_position) {
320 if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
321 return HidlToAidlMiddleware_2_0::GetPresentationPosition(
322 session_type_, remote_delay_report_ns, total_bytes_readed,
323 data_position);
324 std::lock_guard<std::recursive_mutex> guard(mutex_);
325 if (!IsSessionReady()) {
326 LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
327 << " has NO session";
328 return false;
329 }
330 bool retval = false;
331 auto hal_retval = stack_iface_->getPresentationPosition(
332 [&retval, &remote_delay_report_ns, &total_bytes_readed, &data_position](
333 BluetoothAudioStatus status,
334 const uint64_t& remoteDeviceAudioDelayNanos,
335 uint64_t transmittedOctets,
336 const TimeSpec& transmittedOctetsTimeStamp) {
337 if (status == BluetoothAudioStatus::SUCCESS) {
338 if (remote_delay_report_ns)
339 *remote_delay_report_ns = remoteDeviceAudioDelayNanos;
340 if (total_bytes_readed) *total_bytes_readed = transmittedOctets;
341 if (data_position)
342 *data_position =
343 timespec_convert_from_hal(transmittedOctetsTimeStamp);
344 retval = true;
345 }
346 });
347 if (!hal_retval.isOk()) {
348 LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
349 << toString(session_type_) << " failed";
350 return false;
351 }
352 return retval;
353 }
354
UpdateTracksMetadata(const struct source_metadata * source_metadata)355 void BluetoothAudioSession::UpdateTracksMetadata(
356 const struct source_metadata* source_metadata) {
357 if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
358 return HidlToAidlMiddleware_2_0::UpdateTracksMetadata(session_type_,
359 source_metadata);
360 std::lock_guard<std::recursive_mutex> guard(mutex_);
361 if (!IsSessionReady()) {
362 LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
363 << " has NO session";
364 return;
365 }
366
367 ssize_t track_count = source_metadata->track_count;
368 LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) << ", "
369 << track_count << " track(s)";
370 if (session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH ||
371 session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH) {
372 return;
373 }
374
375 struct playback_track_metadata* track = source_metadata->tracks;
376 SourceMetadata sourceMetadata;
377 PlaybackTrackMetadata* halMetadata;
378
379 sourceMetadata.tracks.resize(track_count);
380 halMetadata = sourceMetadata.tracks.data();
381 while (track_count && track) {
382 halMetadata->usage = static_cast<AudioUsage>(track->usage);
383 halMetadata->contentType =
384 static_cast<AudioContentType>(track->content_type);
385 halMetadata->gain = track->gain;
386 LOG(VERBOSE) << __func__ << " - SessionType=" << toString(session_type_)
387 << ", usage=" << toString(halMetadata->usage)
388 << ", content=" << toString(halMetadata->contentType)
389 << ", gain=" << halMetadata->gain;
390 --track_count;
391 ++track;
392 ++halMetadata;
393 }
394 auto hal_retval = stack_iface_->updateMetadata(sourceMetadata);
395 if (!hal_retval.isOk()) {
396 LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
397 << toString(session_type_) << " failed";
398 }
399 }
400
401 // The control function writes stream to FMQ
OutWritePcmData(const void * buffer,size_t bytes)402 size_t BluetoothAudioSession::OutWritePcmData(const void* buffer,
403 size_t bytes) {
404 if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
405 return HidlToAidlMiddleware_2_0::OutWritePcmData(session_type_, buffer,
406 bytes);
407 if (buffer == nullptr || !bytes) return 0;
408 size_t totalWritten = 0;
409 int ms_timeout = kFmqSendTimeoutMs;
410 do {
411 std::unique_lock<std::recursive_mutex> lock(mutex_);
412 if (!IsSessionReady()) break;
413 size_t availableToWrite = mDataMQ->availableToWrite();
414 if (availableToWrite) {
415 if (availableToWrite > (bytes - totalWritten)) {
416 availableToWrite = bytes - totalWritten;
417 }
418
419 if (!mDataMQ->write(static_cast<const uint8_t*>(buffer) + totalWritten,
420 availableToWrite)) {
421 ALOGE("FMQ datapath writting %zu/%zu failed", totalWritten, bytes);
422 return totalWritten;
423 }
424 totalWritten += availableToWrite;
425 } else if (ms_timeout >= kWritePollMs) {
426 lock.unlock();
427 usleep(kWritePollMs * 1000);
428 ms_timeout -= kWritePollMs;
429 } else {
430 ALOGD("data %zu/%zu overflow %d ms", totalWritten, bytes,
431 (kFmqSendTimeoutMs - ms_timeout));
432 return totalWritten;
433 }
434 } while (totalWritten < bytes);
435 return totalWritten;
436 }
437
438 // The control function reads stream from FMQ
InReadPcmData(void * buffer,size_t bytes)439 size_t BluetoothAudioSession::InReadPcmData(void* buffer, size_t bytes) {
440 if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
441 return HidlToAidlMiddleware_2_0::InReadPcmData(session_type_, buffer,
442 bytes);
443 if (buffer == nullptr || !bytes) return 0;
444 size_t totalRead = 0;
445 int ms_timeout = kFmqReceiveTimeoutMs;
446 do {
447 std::unique_lock<std::recursive_mutex> lock(mutex_);
448 if (!IsSessionReady()) break;
449 size_t availableToRead = mDataMQ->availableToRead();
450 if (availableToRead) {
451 if (availableToRead > (bytes - totalRead)) {
452 availableToRead = bytes - totalRead;
453 }
454 if (!mDataMQ->read(static_cast<uint8_t*>(buffer) + totalRead,
455 availableToRead)) {
456 ALOGE("FMQ datapath reading %zu/%zu failed", totalRead, bytes);
457 return totalRead;
458 }
459 totalRead += availableToRead;
460 } else if (ms_timeout >= kReadPollMs) {
461 lock.unlock();
462 usleep(kReadPollMs * 1000);
463 ms_timeout -= kReadPollMs;
464 continue;
465 } else {
466 ALOGD("in data %zu/%zu overflow %d ms", totalRead, bytes,
467 (kFmqReceiveTimeoutMs - ms_timeout));
468 return totalRead;
469 }
470 } while (totalRead < bytes);
471 return totalRead;
472 }
473
474 std::unique_ptr<BluetoothAudioSessionInstance>
475 BluetoothAudioSessionInstance::instance_ptr =
476 std::unique_ptr<BluetoothAudioSessionInstance>(
477 new BluetoothAudioSessionInstance());
478
479 // API to fetch the session of A2DP / Hearing Aid
480 std::shared_ptr<BluetoothAudioSession>
GetSessionInstance(const SessionType & session_type)481 BluetoothAudioSessionInstance::GetSessionInstance(
482 const SessionType& session_type) {
483 std::lock_guard<std::mutex> guard(instance_ptr->mutex_);
484 if (!instance_ptr->sessions_map_.empty()) {
485 auto entry = instance_ptr->sessions_map_.find(session_type);
486 if (entry != instance_ptr->sessions_map_.end()) {
487 return entry->second;
488 }
489 }
490 std::shared_ptr<BluetoothAudioSession> session_ptr =
491 std::make_shared<BluetoothAudioSession>(session_type);
492 instance_ptr->sessions_map_[session_type] = session_ptr;
493 return session_ptr;
494 }
495
496 } // namespace audio
497 } // namespace bluetooth
498 } // namespace android
499