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