1 /*
2  * Copyright 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 "bluetooth_audio_port_impl.h"
18 
19 #include <bluetooth/log.h>
20 #include <com_android_bluetooth_flags.h>
21 
22 #include <vector>
23 
24 #include "android/binder_ibinder_platform.h"
25 #include "btif/include/btif_common.h"
26 #include "client_interface_aidl.h"
27 #include "common/stop_watch_legacy.h"
28 
29 namespace bluetooth {
30 namespace audio {
31 namespace aidl {
32 namespace a2dp {
33 
34 using ::bluetooth::common::StopWatchLegacy;
35 
BluetoothAudioPortImpl(IBluetoothTransportInstance * transport_instance,const std::shared_ptr<IBluetoothAudioProvider> & provider)36 BluetoothAudioPortImpl::BluetoothAudioPortImpl(
37         IBluetoothTransportInstance* transport_instance,
38         const std::shared_ptr<IBluetoothAudioProvider>& provider)
39     : transport_instance_(transport_instance), provider_(provider) {}
40 
~BluetoothAudioPortImpl()41 BluetoothAudioPortImpl::~BluetoothAudioPortImpl() {}
42 
startStream(bool is_low_latency)43 ndk::ScopedAStatus BluetoothAudioPortImpl::startStream(bool is_low_latency) {
44   StopWatchLegacy stop_watch(__func__);
45   Status ack = transport_instance_->StartRequest(is_low_latency);
46   if (ack != Status::PENDING) {
47     auto aidl_retval = provider_->streamStarted(StatusToHalStatus(ack));
48     if (!aidl_retval.isOk()) {
49       log::error("BluetoothAudioHal failure: {}", aidl_retval.getDescription());
50     }
51   }
52   return ndk::ScopedAStatus::ok();
53 }
54 
suspendStream()55 ndk::ScopedAStatus BluetoothAudioPortImpl::suspendStream() {
56   StopWatchLegacy stop_watch(__func__);
57   Status ack = transport_instance_->SuspendRequest();
58   if (ack != Status::PENDING) {
59     auto aidl_retval = provider_->streamSuspended(StatusToHalStatus(ack));
60     if (!aidl_retval.isOk()) {
61       log::error("BluetoothAudioHal failure: {}", aidl_retval.getDescription());
62     }
63   }
64   return ndk::ScopedAStatus::ok();
65 }
66 
stopStream()67 ndk::ScopedAStatus BluetoothAudioPortImpl::stopStream() {
68   StopWatchLegacy stop_watch(__func__);
69   transport_instance_->StopRequest();
70   return ndk::ScopedAStatus::ok();
71 }
72 
getPresentationPosition(PresentationPosition * _aidl_return)73 ndk::ScopedAStatus BluetoothAudioPortImpl::getPresentationPosition(
74         PresentationPosition* _aidl_return) {
75   StopWatchLegacy stop_watch(__func__);
76   uint64_t remote_delay_report_ns;
77   uint64_t total_bytes_read;
78   timespec data_position;
79   bool retval = transport_instance_->GetPresentationPosition(&remote_delay_report_ns,
80                                                              &total_bytes_read, &data_position);
81 
82   PresentationPosition::TimeSpec transmittedOctetsTimeStamp;
83   if (retval) {
84     transmittedOctetsTimeStamp = timespec_convert_to_hal(data_position);
85   } else {
86     remote_delay_report_ns = 0;
87     total_bytes_read = 0;
88     transmittedOctetsTimeStamp = {};
89   }
90   log::verbose("result={}, delay={}, data={} byte(s), timestamp={}", retval, remote_delay_report_ns,
91                total_bytes_read, transmittedOctetsTimeStamp.toString());
92   _aidl_return->remoteDeviceAudioDelayNanos = static_cast<int64_t>(remote_delay_report_ns);
93   _aidl_return->transmittedOctets = static_cast<int64_t>(total_bytes_read);
94   _aidl_return->transmittedOctetsTimestamp = transmittedOctetsTimeStamp;
95   return ndk::ScopedAStatus::ok();
96 }
97 
updateSourceMetadata(const SourceMetadata &)98 ndk::ScopedAStatus BluetoothAudioPortImpl::updateSourceMetadata(
99         const SourceMetadata& /*source_metadata*/) {
100   return ndk::ScopedAStatus::ok();
101 }
102 
updateSinkMetadata(const SinkMetadata &)103 ndk::ScopedAStatus BluetoothAudioPortImpl::updateSinkMetadata(
104         const SinkMetadata& /*sink_metadata*/) {
105   return ndk::ScopedAStatus::ok();
106 }
107 
setLatencyMode(LatencyMode latency_mode)108 ndk::ScopedAStatus BluetoothAudioPortImpl::setLatencyMode(LatencyMode latency_mode) {
109   bool is_low_latency = latency_mode == LatencyMode::LOW_LATENCY ? true : false;
110   invoke_switch_buffer_size_cb(is_low_latency);
111   transport_instance_->SetLatencyMode(latency_mode);
112   return ndk::ScopedAStatus::ok();
113 }
114 
timespec_convert_to_hal(const timespec & ts)115 PresentationPosition::TimeSpec BluetoothAudioPortImpl::timespec_convert_to_hal(const timespec& ts) {
116   return {.tvSec = static_cast<int64_t>(ts.tv_sec), .tvNSec = static_cast<int64_t>(ts.tv_nsec)};
117 }
118 
119 // Overriding create binder and inherit RT from caller.
120 // In our case, the caller is the AIDL session control, so we match the priority
121 // of the AIDL session / AudioFlinger writer thread.
createBinder()122 ndk::SpAIBinder BluetoothAudioPortImpl::createBinder() {
123   auto binder = BnBluetoothAudioPort::createBinder();
124   if (com::android::bluetooth::flags::audio_port_binder_inherit_rt()) {
125     AIBinder_setInheritRt(binder.get(), true);
126   }
127   return binder;
128 }
129 
130 }  // namespace a2dp
131 }  // namespace aidl
132 }  // namespace audio
133 }  // namespace bluetooth
134