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