1 /*
2 * Copyright 2023 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 #define LOG_TAG "BTAudioHfpAIDL"
17
18 #include "hfp_client_interface_aidl.h"
19
20 #include <bluetooth/log.h>
21 #include <com_android_bluetooth_flags.h>
22
23 #include <map>
24
25 #include "aidl/android/hardware/bluetooth/audio/AudioConfiguration.h"
26 #include "aidl/transport_instance.h"
27 #include "bta/ag/bta_ag_int.h"
28 #include "btif/include/btif_hf.h"
29 #include "btm_api_types.h"
30 #include "hardware/bluetooth.h"
31 #include "hardware/bluetooth_headset_interface.h"
32 #include "provider_info.h"
33 #include "types/raw_address.h"
34
35 namespace bluetooth {
36 namespace audio {
37 namespace aidl {
38 namespace hfp {
39
40 std::map<bt_status_t, BluetoothAudioCtrlAck> status_to_ack_map = {
41 {BT_STATUS_SUCCESS, BluetoothAudioCtrlAck::SUCCESS_FINISHED},
42 {BT_STATUS_DONE, BluetoothAudioCtrlAck::SUCCESS_FINISHED},
43 {BT_STATUS_FAIL, BluetoothAudioCtrlAck::FAILURE},
44 {BT_STATUS_NOT_READY, BluetoothAudioCtrlAck::FAILURE_BUSY},
45 {BT_STATUS_BUSY, BluetoothAudioCtrlAck::FAILURE_BUSY},
46 {BT_STATUS_UNSUPPORTED, BluetoothAudioCtrlAck::FAILURE_UNSUPPORTED},
47 };
48
command_to_text(tHFP_CTRL_CMD cmd)49 static std::string command_to_text(tHFP_CTRL_CMD cmd) {
50 switch (cmd) {
51 case HFP_CTRL_CMD_NONE:
52 return "none";
53 case HFP_CTRL_CMD_CHECK_READY:
54 return "check ready";
55 case HFP_CTRL_CMD_START:
56 return "start";
57 case HFP_CTRL_CMD_STOP:
58 return "stop";
59 case HFP_CTRL_CMD_SUSPEND:
60 return "suspend";
61 case HFP_CTRL_GET_INPUT_AUDIO_CONFIG:
62 return "get input audio config";
63 case HFP_CTRL_GET_OUTPUT_AUDIO_CONFIG:
64 return "get output audio config";
65 case HFP_CTRL_SET_OUTPUT_AUDIO_CONFIG:
66 return "set output audio config";
67 case HFP_CTRL_GET_PRESENTATION_POSITION:
68 return "get presentation position";
69 default:
70 return "undefined";
71 }
72 }
73
get_hfp_active_device_callback()74 static tBTA_AG_SCB* get_hfp_active_device_callback() {
75 const RawAddress& addr = bta_ag_get_active_device();
76 if (addr.IsEmpty()) {
77 log::error("No active device found");
78 return nullptr;
79 }
80 auto idx = bta_ag_idx_by_bdaddr(&addr);
81 if (idx == 0) {
82 log::error("No index found for active device");
83 return nullptr;
84 }
85 auto cb = bta_ag_scb_by_idx(idx);
86 if (cb == nullptr) {
87 log::error("No callback for the active device");
88 return nullptr;
89 }
90 return cb;
91 }
92
GetHfpScoConfig(SessionType sessionType)93 std::unordered_map<tBTA_AG_UUID_CODEC, ::hfp::sco_config> HfpTransport::GetHfpScoConfig(
94 SessionType sessionType) {
95 auto providerInfo = ::bluetooth::audio::aidl::ProviderInfo::GetProviderInfo(sessionType);
96 return providerInfo->GetHfpScoConfig();
97 }
98
IsStreamActive()99 bool HfpTransport::IsStreamActive() { return is_stream_active; }
100
SetStreamActive(bool active)101 void HfpTransport::SetStreamActive(bool active) { is_stream_active = active; }
102
HfpTransport()103 HfpTransport::HfpTransport() {
104 hfp_pending_cmd_ = HFP_CTRL_CMD_NONE;
105 is_stream_active = false;
106 }
107
StartRequest()108 BluetoothAudioCtrlAck HfpTransport::StartRequest() {
109 if (hfp_pending_cmd_ == HFP_CTRL_CMD_START) {
110 log::info("HFP_CTRL_CMD_START in progress");
111 is_stream_active = true;
112 return BluetoothAudioCtrlAck::PENDING;
113 } else if (hfp_pending_cmd_ != HFP_CTRL_CMD_NONE) {
114 log::warn("busy in pending_cmd={}, {}", hfp_pending_cmd_, command_to_text(hfp_pending_cmd_));
115 return BluetoothAudioCtrlAck::FAILURE_BUSY;
116 }
117
118 auto cb = get_hfp_active_device_callback();
119 if (cb == nullptr) {
120 return BluetoothAudioCtrlAck::FAILURE;
121 }
122
123 if (bta_ag_sco_is_open(cb)) {
124 // Already started, ACK back immediately.
125 is_stream_active = true;
126 return BluetoothAudioCtrlAck::SUCCESS_FINISHED;
127 }
128
129 /* Post start SCO event and wait for sco to open */
130 hfp_pending_cmd_ = HFP_CTRL_CMD_START;
131 bool is_call_idle = bluetooth::headset::IsCallIdle();
132 bool is_during_vr = bluetooth::headset::IsDuringVoiceRecognition(&(cb->peer_addr));
133 if (is_call_idle && !is_during_vr) {
134 log::warn("Call ongoing={}, voice recognition ongoing={}, wait for retry", !is_call_idle,
135 is_during_vr);
136 hfp_pending_cmd_ = HFP_CTRL_CMD_NONE;
137 return BluetoothAudioCtrlAck::PENDING;
138 }
139 // as ConnectAudio only queues the command into main thread, keep PENDING
140 // status
141 auto status = bluetooth::headset::GetInterface()->ConnectAudio(&cb->peer_addr, 0);
142 log::info("ConnectAudio status = {} - {}", status, bt_status_text(status));
143 auto ctrl_ack = status_to_ack_map.find(status);
144 if (ctrl_ack == status_to_ack_map.end()) {
145 log::warn("Unmapped status={}", status);
146 hfp_pending_cmd_ = HFP_CTRL_CMD_NONE;
147 return BluetoothAudioCtrlAck::FAILURE;
148 }
149 if (ctrl_ack->second != BluetoothAudioCtrlAck::SUCCESS_FINISHED) {
150 hfp_pending_cmd_ = HFP_CTRL_CMD_NONE;
151 return ctrl_ack->second;
152 }
153 is_stream_active = true;
154 return BluetoothAudioCtrlAck::PENDING;
155 }
156
StopRequest()157 void HfpTransport::StopRequest() {
158 log::info("handling");
159
160 is_stream_active = false;
161
162 RawAddress addr = bta_ag_get_active_device();
163 if (addr.IsEmpty()) {
164 log::error("No active device found");
165 return;
166 }
167 hfp_pending_cmd_ = HFP_CTRL_CMD_STOP;
168 auto status = bluetooth::headset::GetInterface()->DisconnectAudio(&addr);
169 log::info("DisconnectAudio status = {} - {}", status, bt_status_text(status));
170 hfp_pending_cmd_ = HFP_CTRL_CMD_NONE;
171 return;
172 }
173
ResetPendingCmd()174 void HfpTransport::ResetPendingCmd() { hfp_pending_cmd_ = HFP_CTRL_CMD_NONE; }
175
GetPendingCmd() const176 uint8_t HfpTransport::GetPendingCmd() const { return hfp_pending_cmd_; }
177
178 // Unimplemented functions
LogBytesProcessed(size_t)179 void HfpTransport::LogBytesProcessed(size_t /*bytes_read*/) {}
180
SuspendRequest()181 BluetoothAudioCtrlAck HfpTransport::SuspendRequest() {
182 log::info("handling");
183 if (hfp_pending_cmd_ != HFP_CTRL_CMD_NONE) {
184 log::warn("busy in pending_cmd={}, {}", hfp_pending_cmd_, command_to_text(hfp_pending_cmd_));
185 return BluetoothAudioCtrlAck::FAILURE_BUSY;
186 }
187
188 RawAddress addr = bta_ag_get_active_device();
189 if (addr.IsEmpty()) {
190 log::info("No active device found, mark SCO as suspended");
191 return BluetoothAudioCtrlAck::SUCCESS_FINISHED;
192 }
193
194 hfp_pending_cmd_ = HFP_CTRL_CMD_SUSPEND;
195 auto instance = bluetooth::headset::GetInterface();
196 if (instance == nullptr) {
197 log::error("headset instance is nullptr");
198 return BluetoothAudioCtrlAck::FAILURE;
199 }
200 auto status = instance->DisconnectAudio(&addr);
201 log::info("DisconnectAudio status = {} - {}", status, bt_status_text(status));
202 // once disconnect audio is queued, not waiting on that
203 // because disconnect audio request can come when audio is disconnected
204 hfp_pending_cmd_ = HFP_CTRL_CMD_NONE;
205 if (status == BT_STATUS_SUCCESS) {
206 return BluetoothAudioCtrlAck::SUCCESS_FINISHED;
207 } else {
208 return BluetoothAudioCtrlAck::FAILURE;
209 }
210 }
211
SetLatencyMode(LatencyMode)212 void HfpTransport::SetLatencyMode(LatencyMode /*latency_mode*/) {}
213
SourceMetadataChanged(const source_metadata_v7_t &)214 void HfpTransport::SourceMetadataChanged(const source_metadata_v7_t& /*source_metadata*/) {}
215
SinkMetadataChanged(const sink_metadata_v7_t &)216 void HfpTransport::SinkMetadataChanged(const sink_metadata_v7_t&) {}
217
ResetPresentationPosition()218 void HfpTransport::ResetPresentationPosition() {}
219
GetPresentationPosition(uint64_t *,uint64_t *,timespec *)220 bool HfpTransport::GetPresentationPosition(uint64_t* /*remote_delay_report_ns*/,
221 uint64_t* /*total_bytes_read*/,
222 timespec* /*data_position*/) {
223 return false;
224 }
225
226 // Source / sink functions
HfpDecodingTransport(SessionType session_type)227 HfpDecodingTransport::HfpDecodingTransport(SessionType session_type)
228 : IBluetoothSourceTransportInstance(session_type, (AudioConfiguration){}) {
229 transport_ = new HfpTransport();
230 }
231
~HfpDecodingTransport()232 HfpDecodingTransport::~HfpDecodingTransport() { delete transport_; }
233
StartRequest(bool)234 BluetoothAudioCtrlAck HfpDecodingTransport::StartRequest(bool /*is_low_latency*/) {
235 return transport_->StartRequest();
236 }
237
SuspendRequest()238 BluetoothAudioCtrlAck HfpDecodingTransport::SuspendRequest() {
239 transport_->SetStreamActive(false);
240
241 if (HfpEncodingTransport::instance_ && HfpEncodingTransport::instance_->IsStreamActive()) {
242 log::info("SCO will suspend when encoding transport suspends.");
243 return BluetoothAudioCtrlAck::SUCCESS_FINISHED;
244 }
245
246 return transport_->SuspendRequest();
247 }
248
SetLatencyMode(LatencyMode latency_mode)249 void HfpDecodingTransport::SetLatencyMode(LatencyMode latency_mode) {
250 transport_->SetLatencyMode(latency_mode);
251 }
252
GetPresentationPosition(uint64_t * remote_delay_report_ns,uint64_t * total_bytes_written,timespec * data_position)253 bool HfpDecodingTransport::GetPresentationPosition(uint64_t* remote_delay_report_ns,
254 uint64_t* total_bytes_written,
255 timespec* data_position) {
256 return transport_->GetPresentationPosition(remote_delay_report_ns, total_bytes_written,
257 data_position);
258 }
259
SourceMetadataChanged(const source_metadata_v7_t & source_metadata)260 void HfpDecodingTransport::SourceMetadataChanged(const source_metadata_v7_t& source_metadata) {
261 transport_->SourceMetadataChanged(source_metadata);
262 }
263
SinkMetadataChanged(const sink_metadata_v7_t & sink_metadata)264 void HfpDecodingTransport::SinkMetadataChanged(const sink_metadata_v7_t& sink_metadata) {
265 transport_->SinkMetadataChanged(sink_metadata);
266 }
267
ResetPresentationPosition()268 void HfpDecodingTransport::ResetPresentationPosition() { transport_->ResetPresentationPosition(); }
269
LogBytesWritten(size_t bytes_written)270 void HfpDecodingTransport::LogBytesWritten(size_t bytes_written) {
271 transport_->LogBytesProcessed(bytes_written);
272 }
273
GetPendingCmd() const274 uint8_t HfpDecodingTransport::GetPendingCmd() const { return transport_->GetPendingCmd(); }
275
ResetPendingCmd()276 void HfpDecodingTransport::ResetPendingCmd() { transport_->ResetPendingCmd(); }
277
IsStreamActive()278 bool HfpDecodingTransport::IsStreamActive() { return transport_->IsStreamActive(); }
279
StopRequest()280 void HfpDecodingTransport::StopRequest() { transport_->StopRequest(); }
281
HfpEncodingTransport(SessionType session_type)282 HfpEncodingTransport::HfpEncodingTransport(SessionType session_type)
283 : IBluetoothSinkTransportInstance(session_type, (AudioConfiguration){}) {
284 transport_ = new HfpTransport();
285 }
286
~HfpEncodingTransport()287 HfpEncodingTransport::~HfpEncodingTransport() { delete transport_; }
288
StartRequest(bool)289 BluetoothAudioCtrlAck HfpEncodingTransport::StartRequest(bool /*is_low_latency*/) {
290 return transport_->StartRequest();
291 }
292
SuspendRequest()293 BluetoothAudioCtrlAck HfpEncodingTransport::SuspendRequest() {
294 transport_->SetStreamActive(false);
295
296 if (HfpDecodingTransport::instance_ && HfpDecodingTransport::instance_->IsStreamActive()) {
297 log::info("SCO will suspend when decoding transport suspends.");
298 return BluetoothAudioCtrlAck::SUCCESS_FINISHED;
299 }
300
301 return transport_->SuspendRequest();
302 }
303
StopRequest()304 void HfpEncodingTransport::StopRequest() { transport_->StopRequest(); }
305
SetLatencyMode(LatencyMode latency_mode)306 void HfpEncodingTransport::SetLatencyMode(LatencyMode latency_mode) {
307 transport_->SetLatencyMode(latency_mode);
308 }
309
GetPresentationPosition(uint64_t * remote_delay_report_ns,uint64_t * total_bytes_written,timespec * data_position)310 bool HfpEncodingTransport::GetPresentationPosition(uint64_t* remote_delay_report_ns,
311 uint64_t* total_bytes_written,
312 timespec* data_position) {
313 return transport_->GetPresentationPosition(remote_delay_report_ns, total_bytes_written,
314 data_position);
315 }
316
SourceMetadataChanged(const source_metadata_v7_t & source_metadata)317 void HfpEncodingTransport::SourceMetadataChanged(const source_metadata_v7_t& source_metadata) {
318 transport_->SourceMetadataChanged(source_metadata);
319 }
320
SinkMetadataChanged(const sink_metadata_v7_t & sink_metadata)321 void HfpEncodingTransport::SinkMetadataChanged(const sink_metadata_v7_t& sink_metadata) {
322 transport_->SinkMetadataChanged(sink_metadata);
323 }
324
ResetPresentationPosition()325 void HfpEncodingTransport::ResetPresentationPosition() { transport_->ResetPresentationPosition(); }
326
LogBytesRead(size_t bytes_written)327 void HfpEncodingTransport::LogBytesRead(size_t bytes_written) {
328 transport_->LogBytesProcessed(bytes_written);
329 }
330
GetPendingCmd() const331 uint8_t HfpEncodingTransport::GetPendingCmd() const { return transport_->GetPendingCmd(); }
332
ResetPendingCmd()333 void HfpEncodingTransport::ResetPendingCmd() { transport_->ResetPendingCmd(); }
334
IsStreamActive()335 bool HfpEncodingTransport::IsStreamActive() { return transport_->IsStreamActive(); }
336
337 } // namespace hfp
338 } // namespace aidl
339 } // namespace audio
340 } // namespace bluetooth
341