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 "common/stop_watch_legacy.h"
27
28 namespace bluetooth {
29 namespace audio {
30 namespace aidl {
31
32 using ::bluetooth::common::StopWatchLegacy;
33
BluetoothAudioPortImpl(IBluetoothTransportInstance * transport_instance,const std::shared_ptr<IBluetoothAudioProvider> & provider)34 BluetoothAudioPortImpl::BluetoothAudioPortImpl(
35 IBluetoothTransportInstance* transport_instance,
36 const std::shared_ptr<IBluetoothAudioProvider>& provider)
37 : transport_instance_(transport_instance), provider_(provider) {}
38
~BluetoothAudioPortImpl()39 BluetoothAudioPortImpl::~BluetoothAudioPortImpl() {}
40
startStream(bool is_low_latency)41 ndk::ScopedAStatus BluetoothAudioPortImpl::startStream(bool is_low_latency) {
42 StopWatchLegacy stop_watch(__func__);
43 BluetoothAudioCtrlAck ack = transport_instance_->StartRequest(is_low_latency);
44 if (ack != BluetoothAudioCtrlAck::PENDING) {
45 auto aidl_retval =
46 provider_->streamStarted(BluetoothAudioCtrlAckToHalStatus(ack));
47 if (!aidl_retval.isOk()) {
48 log::error("BluetoothAudioHal failure: {}", aidl_retval.getDescription());
49 }
50 }
51 return ndk::ScopedAStatus::ok();
52 }
53
suspendStream()54 ndk::ScopedAStatus BluetoothAudioPortImpl::suspendStream() {
55 StopWatchLegacy stop_watch(__func__);
56 BluetoothAudioCtrlAck ack = transport_instance_->SuspendRequest();
57 if (ack != BluetoothAudioCtrlAck::PENDING) {
58 auto aidl_retval =
59 provider_->streamSuspended(BluetoothAudioCtrlAckToHalStatus(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(
80 &remote_delay_report_ns, &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,
91 remote_delay_report_ns, total_bytes_read,
92 transmittedOctetsTimeStamp.toString());
93 _aidl_return->remoteDeviceAudioDelayNanos =
94 static_cast<int64_t>(remote_delay_report_ns);
95 _aidl_return->transmittedOctets = static_cast<int64_t>(total_bytes_read);
96 _aidl_return->transmittedOctetsTimestamp = transmittedOctetsTimeStamp;
97 return ndk::ScopedAStatus::ok();
98 }
99
updateSourceMetadata(const SourceMetadata & source_metadata)100 ndk::ScopedAStatus BluetoothAudioPortImpl::updateSourceMetadata(
101 const SourceMetadata& source_metadata) {
102 StopWatchLegacy stop_watch(__func__);
103 log::info("{} track(s)", source_metadata.tracks.size());
104
105 std::vector<playback_track_metadata_v7> tracks_vec;
106 tracks_vec.reserve(source_metadata.tracks.size());
107 for (const auto& track : source_metadata.tracks) {
108 auto num_of_tags = track.tags.size();
109 log::info("metadata tags size: {}", num_of_tags);
110
111 playback_track_metadata_v7 desc_track = {
112 .base = {.usage = static_cast<audio_usage_t>(track.usage),
113 .content_type =
114 static_cast<audio_content_type_t>(track.contentType),
115 .gain = track.gain},
116 };
117
118 if (num_of_tags != 0) {
119 int copied_size = 0;
120 int max_tags_size = sizeof(desc_track.tags);
121 std::string separator(1, AUDIO_ATTRIBUTES_TAGS_SEPARATOR);
122 for (size_t i = 0; i < num_of_tags - 1; i++) {
123 int string_len = track.tags[i].length();
124
125 if ((copied_size >= max_tags_size) ||
126 (copied_size + string_len >= max_tags_size)) {
127 log::error("Too many tags, copied size: {}", copied_size);
128 break;
129 }
130
131 track.tags[i].copy(desc_track.tags + copied_size, string_len, 0);
132 copied_size += string_len;
133 separator.copy(desc_track.tags + copied_size, 1, 0);
134 copied_size += 1;
135 }
136
137 int string_len = track.tags[num_of_tags - 1].length();
138 if ((copied_size >= max_tags_size) ||
139 (copied_size + string_len >= max_tags_size)) {
140 log::error("Too many tags, copied size: {}", copied_size);
141 } else {
142 track.tags[num_of_tags - 1].copy(desc_track.tags + copied_size,
143 string_len, 0);
144 }
145 } else {
146 memset(desc_track.tags, 0, sizeof(desc_track.tags));
147 }
148
149 tracks_vec.push_back(desc_track);
150 }
151
152 const source_metadata_v7_t legacy_source_metadata = {
153 .track_count = tracks_vec.size(), .tracks = tracks_vec.data()};
154 transport_instance_->SourceMetadataChanged(legacy_source_metadata);
155 return ndk::ScopedAStatus::ok();
156 }
157
updateSinkMetadata(const SinkMetadata & sink_metadata)158 ndk::ScopedAStatus BluetoothAudioPortImpl::updateSinkMetadata(
159 const SinkMetadata& sink_metadata) {
160 StopWatchLegacy stop_watch(__func__);
161 log::info("{} track(s)", sink_metadata.tracks.size());
162
163 std::vector<record_track_metadata_v7> tracks_vec;
164 tracks_vec.reserve(sink_metadata.tracks.size());
165 for (const auto& track : sink_metadata.tracks) {
166 auto num_of_tags = track.tags.size();
167 log::info("metadata tags size: {}", num_of_tags);
168
169 record_track_metadata_v7 desc_track = {
170 .base =
171 {
172 .source = static_cast<audio_source_t>(track.source),
173 .gain = track.gain,
174 },
175 };
176
177 if (num_of_tags != 0) {
178 int copied_size = 0;
179 int max_tags_size = sizeof(desc_track.tags);
180 std::string separator(1, AUDIO_ATTRIBUTES_TAGS_SEPARATOR);
181 for (size_t i = 0; i < num_of_tags - 1; i++) {
182 int string_len = track.tags[i].length();
183
184 if ((copied_size >= max_tags_size) ||
185 (copied_size + string_len >= max_tags_size)) {
186 log::error("Too many tags, copied size: {}", copied_size);
187 break;
188 }
189
190 track.tags[i].copy(desc_track.tags + copied_size, string_len, 0);
191 copied_size += string_len;
192 separator.copy(desc_track.tags + copied_size, 1, 0);
193 copied_size += 1;
194 }
195
196 int string_len = track.tags[num_of_tags - 1].length();
197 if ((copied_size >= max_tags_size) ||
198 (copied_size + string_len >= max_tags_size)) {
199 log::error("Too many tags, copied size: {}", copied_size);
200 } else {
201 track.tags[num_of_tags - 1].copy(desc_track.tags + copied_size,
202 string_len, 0);
203 }
204 } else {
205 memset(desc_track.tags, 0, sizeof(desc_track.tags));
206 }
207
208 tracks_vec.push_back(desc_track);
209 }
210
211 const sink_metadata_v7_t legacy_sink_metadata = {
212 .track_count = tracks_vec.size(), .tracks = tracks_vec.data()};
213 transport_instance_->SinkMetadataChanged(legacy_sink_metadata);
214 return ndk::ScopedAStatus::ok();
215 }
216
setLatencyMode(LatencyMode latency_mode)217 ndk::ScopedAStatus BluetoothAudioPortImpl::setLatencyMode(
218 LatencyMode latency_mode) {
219 bool is_low_latency = latency_mode == LatencyMode::LOW_LATENCY ? true : false;
220 invoke_switch_buffer_size_cb(is_low_latency);
221 transport_instance_->SetLatencyMode(latency_mode);
222 return ndk::ScopedAStatus::ok();
223 }
224
timespec_convert_to_hal(const timespec & ts)225 PresentationPosition::TimeSpec BluetoothAudioPortImpl::timespec_convert_to_hal(
226 const timespec& ts) {
227 return {.tvSec = static_cast<int64_t>(ts.tv_sec),
228 .tvNSec = static_cast<int64_t>(ts.tv_nsec)};
229 }
230
231 // Overriding create binder and inherit RT from caller.
232 // In our case, the caller is the AIDL session control, so we match the priority
233 // of the AIDL session / AudioFlinger writer thread.
createBinder()234 ndk::SpAIBinder BluetoothAudioPortImpl::createBinder() {
235 auto binder = BnBluetoothAudioPort::createBinder();
236 if (com::android::bluetooth::flags::audio_port_binder_inherit_rt()) {
237 AIBinder_setInheritRt(binder.get(), true);
238 }
239 return binder;
240 }
241
242 } // namespace aidl
243 } // namespace audio
244 } // namespace bluetooth
245