1 /*
2 * Copyright 2019 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 "BTAudioHalDeviceProxy"
18
19 #include <android-base/logging.h>
20 #include <android-base/stringprintf.h>
21 #include <audio_utils/primitives.h>
22 #include <inttypes.h>
23 #include <log/log.h>
24 #include <stdlib.h>
25
26 #include "BluetoothAudioSessionControl.h"
27 #include "device_port_proxy.h"
28 #include "stream_apis.h"
29 #include "utils.h"
30
31 namespace android {
32 namespace bluetooth {
33 namespace audio {
34
35 using ::android::base::StringPrintf;
36 using ::android::bluetooth::audio::BluetoothAudioSessionControl;
37 using ::android::hardware::bluetooth::audio::V2_0::BitsPerSample;
38 using ::android::hardware::bluetooth::audio::V2_0::ChannelMode;
39 using ::android::hardware::bluetooth::audio::V2_0::PcmParameters;
40 using ::android::hardware::bluetooth::audio::V2_0::SampleRate;
41 using BluetoothAudioStatus =
42 ::android::hardware::bluetooth::audio::V2_0::Status;
43 using ControlResultCallback = std::function<void(
44 uint16_t cookie, bool start_resp, const BluetoothAudioStatus& status)>;
45 using SessionChangedCallback = std::function<void(uint16_t cookie)>;
46
47 namespace {
48
SampleRateToAudioFormat(SampleRate sample_rate)49 unsigned int SampleRateToAudioFormat(SampleRate sample_rate) {
50 switch (sample_rate) {
51 case SampleRate::RATE_16000:
52 return 16000;
53 case SampleRate::RATE_24000:
54 return 24000;
55 case SampleRate::RATE_44100:
56 return 44100;
57 case SampleRate::RATE_48000:
58 return 48000;
59 case SampleRate::RATE_88200:
60 return 88200;
61 case SampleRate::RATE_96000:
62 return 96000;
63 case SampleRate::RATE_176400:
64 return 176400;
65 case SampleRate::RATE_192000:
66 return 192000;
67 default:
68 return kBluetoothDefaultSampleRate;
69 }
70 }
ChannelModeToAudioFormat(ChannelMode channel_mode)71 audio_channel_mask_t ChannelModeToAudioFormat(ChannelMode channel_mode) {
72 switch (channel_mode) {
73 case ChannelMode::MONO:
74 return AUDIO_CHANNEL_OUT_MONO;
75 case ChannelMode::STEREO:
76 return AUDIO_CHANNEL_OUT_STEREO;
77 default:
78 return kBluetoothDefaultOutputChannelModeMask;
79 }
80 }
81
BitsPerSampleToAudioFormat(BitsPerSample bits_per_sample)82 audio_format_t BitsPerSampleToAudioFormat(BitsPerSample bits_per_sample) {
83 switch (bits_per_sample) {
84 case BitsPerSample::BITS_16:
85 return AUDIO_FORMAT_PCM_16_BIT;
86 case BitsPerSample::BITS_24:
87 return AUDIO_FORMAT_PCM_24_BIT_PACKED;
88 case BitsPerSample::BITS_32:
89 return AUDIO_FORMAT_PCM_32_BIT;
90 default:
91 return kBluetoothDefaultAudioFormatBitsPerSample;
92 }
93 }
94
95 // The maximum time to wait in std::condition_variable::wait_for()
96 constexpr unsigned int kMaxWaitingTimeMs = 4500;
97
98 } // namespace
99
BluetoothAudioPortOut()100 BluetoothAudioPortOut::BluetoothAudioPortOut()
101 : state_(BluetoothStreamState::DISABLED),
102 session_type_(SessionType::UNKNOWN),
103 cookie_(android::bluetooth::audio::kObserversCookieUndefined) {}
104
SetUp(audio_devices_t devices)105 bool BluetoothAudioPortOut::SetUp(audio_devices_t devices) {
106 if (!init_session_type(devices)) return false;
107
108 state_ = BluetoothStreamState::STANDBY;
109
110 auto control_result_cb = [port = this](uint16_t cookie, bool start_resp,
111 const BluetoothAudioStatus& status) {
112 if (!port->in_use()) {
113 LOG(ERROR) << "control_result_cb: BluetoothAudioPortOut is not in use";
114 return;
115 }
116 if (port->cookie_ != cookie) {
117 LOG(ERROR) << "control_result_cb: proxy of device port (cookie=" << StringPrintf("%#hx", cookie)
118 << ") is corrupted";
119 return;
120 }
121 port->ControlResultHandler(status);
122 };
123 auto session_changed_cb = [port = this](uint16_t cookie) {
124 if (!port->in_use()) {
125 LOG(ERROR) << "session_changed_cb: BluetoothAudioPortOut is not in use";
126 return;
127 }
128 if (port->cookie_ != cookie) {
129 LOG(ERROR) << "session_changed_cb: proxy of device port (cookie=" << StringPrintf("%#hx", cookie)
130 << ") is corrupted";
131 return;
132 }
133 port->SessionChangedHandler();
134 };
135 ::android::bluetooth::audio::PortStatusCallbacks cbacks = {
136 .control_result_cb_ = control_result_cb,
137 .session_changed_cb_ = session_changed_cb};
138 cookie_ = BluetoothAudioSessionControl::RegisterControlResultCback(
139 session_type_, cbacks);
140 LOG(INFO) << __func__ << ": session_type=" << toString(session_type_) << ", cookie=" << StringPrintf("%#hx", cookie_);
141
142 return (cookie_ != android::bluetooth::audio::kObserversCookieUndefined);
143 }
144
init_session_type(audio_devices_t device)145 bool BluetoothAudioPortOut::init_session_type(audio_devices_t device) {
146 switch (device) {
147 case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP:
148 case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
149 case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER:
150 LOG(VERBOSE) << __func__ << ": device=AUDIO_DEVICE_OUT_BLUETOOTH_A2DP (HEADPHONES/SPEAKER) ("
151 << StringPrintf("%#x", device) << ")";
152 session_type_ = SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH;
153 break;
154 case AUDIO_DEVICE_OUT_HEARING_AID:
155 LOG(VERBOSE) << __func__ << ": device=AUDIO_DEVICE_OUT_HEARING_AID (MEDIA/VOICE) (" << StringPrintf("%#x", device)
156 << ")";
157 session_type_ = SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH;
158 break;
159 default:
160 LOG(ERROR) << __func__ << ": unknown device=" << StringPrintf("%#x", device);
161 return false;
162 }
163
164 if (!BluetoothAudioSessionControl::IsSessionReady(session_type_)) {
165 LOG(ERROR) << __func__ << ": device=" << StringPrintf("%#x", device) << ", session_type=" << toString(session_type_)
166 << " is not ready";
167 return false;
168 }
169 return true;
170 }
171
TearDown()172 void BluetoothAudioPortOut::TearDown() {
173 if (!in_use()) {
174 LOG(ERROR) << __func__ << ": session_type=" << toString(session_type_)
175 << ", cookie=" << StringPrintf("%#hx", cookie_) << " unknown monitor";
176 return;
177 }
178
179 LOG(INFO) << __func__ << ": session_type=" << toString(session_type_) << ", cookie=" << StringPrintf("%#hx", cookie_);
180 BluetoothAudioSessionControl::UnregisterControlResultCback(session_type_,
181 cookie_);
182 cookie_ = android::bluetooth::audio::kObserversCookieUndefined;
183 }
184
ControlResultHandler(const BluetoothAudioStatus & status)185 void BluetoothAudioPortOut::ControlResultHandler(
186 const BluetoothAudioStatus& status) {
187 if (!in_use()) {
188 LOG(ERROR) << __func__ << ": BluetoothAudioPortOut is not in use";
189 return;
190 }
191 std::unique_lock<std::mutex> port_lock(cv_mutex_);
192 BluetoothStreamState previous_state = state_;
193 LOG(INFO) << "control_result_cb: session_type=" << toString(session_type_)
194 << ", cookie=" << StringPrintf("%#hx", cookie_) << ", previous_state=" << previous_state
195 << ", status=" << toString(status);
196
197 switch (previous_state) {
198 case BluetoothStreamState::STARTING:
199 if (status == BluetoothAudioStatus::SUCCESS) {
200 state_ = BluetoothStreamState::STARTED;
201 } else {
202 // Set to standby since the stack may be busy switching between outputs
203 LOG(WARNING) << "control_result_cb: status=" << toString(status)
204 << " failure for session_type=" << toString(session_type_)
205 << ", cookie=" << StringPrintf("%#hx", cookie_) << ", previous_state=" << previous_state;
206 state_ = BluetoothStreamState::STANDBY;
207 }
208 break;
209 case BluetoothStreamState::SUSPENDING:
210 if (status == BluetoothAudioStatus::SUCCESS) {
211 state_ = BluetoothStreamState::STANDBY;
212 } else {
213 // It will be failed if the headset is disconnecting, and set to disable
214 // to wait for re-init again
215 LOG(WARNING) << "control_result_cb: status=" << toString(status)
216 << " failure for session_type=" << toString(session_type_)
217 << ", cookie=" << StringPrintf("%#hx", cookie_) << ", previous_state=" << previous_state;
218 state_ = BluetoothStreamState::DISABLED;
219 }
220 break;
221 default:
222 LOG(ERROR) << "control_result_cb: unexpected status=" << toString(status)
223 << " for session_type=" << toString(session_type_) << ", cookie=" << StringPrintf("%#hx", cookie_)
224 << ", previous_state=" << previous_state;
225 return;
226 }
227 port_lock.unlock();
228 internal_cv_.notify_all();
229 }
230
SessionChangedHandler()231 void BluetoothAudioPortOut::SessionChangedHandler() {
232 if (!in_use()) {
233 LOG(ERROR) << __func__ << ": BluetoothAudioPortOut is not in use";
234 return;
235 }
236 std::unique_lock<std::mutex> port_lock(cv_mutex_);
237 BluetoothStreamState previous_state = state_;
238 LOG(INFO) << "session_changed_cb: session_type=" << toString(session_type_)
239 << ", cookie=" << StringPrintf("%#hx", cookie_) << ", previous_state=" << previous_state;
240 if (previous_state != BluetoothStreamState::DISABLED) {
241 state_ = BluetoothStreamState::DISABLED;
242 } else {
243 state_ = BluetoothStreamState::STANDBY;
244 }
245 port_lock.unlock();
246 internal_cv_.notify_all();
247 }
248
in_use() const249 bool BluetoothAudioPortOut::in_use() const {
250 return (cookie_ != android::bluetooth::audio::kObserversCookieUndefined);
251 }
252
LoadAudioConfig(audio_config_t * audio_cfg) const253 bool BluetoothAudioPortOut::LoadAudioConfig(audio_config_t* audio_cfg) const {
254 if (!in_use()) {
255 LOG(ERROR) << __func__ << ": BluetoothAudioPortOut is not in use";
256 audio_cfg->sample_rate = kBluetoothDefaultSampleRate;
257 audio_cfg->channel_mask = kBluetoothDefaultOutputChannelModeMask;
258 audio_cfg->format = kBluetoothDefaultAudioFormatBitsPerSample;
259 return false;
260 }
261
262 const AudioConfiguration& hal_audio_cfg =
263 BluetoothAudioSessionControl::GetAudioConfig(session_type_);
264 if (hal_audio_cfg.getDiscriminator() !=
265 AudioConfiguration::hidl_discriminator::pcmConfig) {
266 audio_cfg->sample_rate = kBluetoothDefaultSampleRate;
267 audio_cfg->channel_mask = kBluetoothDefaultOutputChannelModeMask;
268 audio_cfg->format = kBluetoothDefaultAudioFormatBitsPerSample;
269 return false;
270 }
271 const PcmParameters& pcm_cfg = hal_audio_cfg.pcmConfig();
272 LOG(VERBOSE) << __func__ << ": session_type=" << toString(session_type_)
273 << ", cookie=" << StringPrintf("%#hx", cookie_) << ", state=" << state_ << ", PcmConfig=["
274 << toString(pcm_cfg) << "]";
275 if (pcm_cfg.sampleRate == SampleRate::RATE_UNKNOWN ||
276 pcm_cfg.channelMode == ChannelMode::UNKNOWN ||
277 pcm_cfg.bitsPerSample == BitsPerSample::BITS_UNKNOWN) {
278 return false;
279 }
280 audio_cfg->sample_rate = SampleRateToAudioFormat(pcm_cfg.sampleRate);
281 audio_cfg->channel_mask =
282 (is_stereo_to_mono_ ? AUDIO_CHANNEL_OUT_STEREO : ChannelModeToAudioFormat(pcm_cfg.channelMode));
283 audio_cfg->format = BitsPerSampleToAudioFormat(pcm_cfg.bitsPerSample);
284 return true;
285 }
286
CondwaitState(BluetoothStreamState state)287 bool BluetoothAudioPortOut::CondwaitState(BluetoothStreamState state) {
288 bool retval;
289 std::unique_lock<std::mutex> port_lock(cv_mutex_);
290 switch (state) {
291 case BluetoothStreamState::STARTING:
292 LOG(VERBOSE) << __func__ << ": session_type=" << toString(session_type_)
293 << ", cookie=" << StringPrintf("%#hx", cookie_) << " waiting for STARTED";
294 retval = internal_cv_.wait_for(
295 port_lock, std::chrono::milliseconds(kMaxWaitingTimeMs),
296 [this] { return this->state_ != BluetoothStreamState::STARTING; });
297 retval = retval && state_ == BluetoothStreamState::STARTED;
298 break;
299 case BluetoothStreamState::SUSPENDING:
300 LOG(VERBOSE) << __func__ << ": session_type=" << toString(session_type_)
301 << ", cookie=" << StringPrintf("%#hx", cookie_) << " waiting for SUSPENDED";
302 retval = internal_cv_.wait_for(
303 port_lock, std::chrono::milliseconds(kMaxWaitingTimeMs),
304 [this] { return this->state_ != BluetoothStreamState::SUSPENDING; });
305 retval = retval && state_ == BluetoothStreamState::STANDBY;
306 break;
307 default:
308 LOG(WARNING) << __func__ << ": session_type=" << toString(session_type_)
309 << ", cookie=" << StringPrintf("%#hx", cookie_) << " waiting for KNOWN";
310 return false;
311 }
312
313 return retval; // false if any failure like timeout
314 }
315
Start()316 bool BluetoothAudioPortOut::Start() {
317 if (!in_use()) {
318 LOG(ERROR) << __func__ << ": BluetoothAudioPortOut is not in use";
319 return false;
320 }
321
322 LOG(INFO) << __func__ << ": session_type=" << toString(session_type_) << ", cookie=" << StringPrintf("%#hx", cookie_)
323 << ", state=" << state_ << ", mono=" << (is_stereo_to_mono_ ? "true" : "false") << " request";
324 bool retval = false;
325 if (state_ == BluetoothStreamState::STANDBY) {
326 state_ = BluetoothStreamState::STARTING;
327 if (BluetoothAudioSessionControl::StartStream(session_type_)) {
328 retval = CondwaitState(BluetoothStreamState::STARTING);
329 } else {
330 LOG(ERROR) << __func__ << ": session_type=" << toString(session_type_)
331 << ", cookie=" << StringPrintf("%#hx", cookie_) << ", state=" << state_ << " Hal fails";
332 }
333 }
334
335 if (retval) {
336 LOG(INFO) << __func__ << ": session_type=" << toString(session_type_)
337 << ", cookie=" << StringPrintf("%#hx", cookie_) << ", state=" << state_
338 << ", mono=" << (is_stereo_to_mono_ ? "true" : "false") << " done";
339 } else {
340 LOG(ERROR) << __func__ << ": session_type=" << toString(session_type_)
341 << ", cookie=" << StringPrintf("%#hx", cookie_) << ", state=" << state_ << " failure";
342 }
343
344 return retval; // false if any failure like timeout
345 }
346
Suspend()347 bool BluetoothAudioPortOut::Suspend() {
348 if (!in_use()) {
349 LOG(ERROR) << __func__ << ": BluetoothAudioPortOut is not in use";
350 return false;
351 }
352
353 LOG(INFO) << __func__ << ": session_type=" << toString(session_type_) << ", cookie=" << StringPrintf("%#hx", cookie_)
354 << ", state=" << state_ << " request";
355 bool retval = false;
356 if (state_ == BluetoothStreamState::STARTED) {
357 state_ = BluetoothStreamState::SUSPENDING;
358 if (BluetoothAudioSessionControl::SuspendStream(session_type_)) {
359 retval = CondwaitState(BluetoothStreamState::SUSPENDING);
360 } else {
361 LOG(ERROR) << __func__ << ": session_type=" << toString(session_type_)
362 << ", cookie=" << StringPrintf("%#hx", cookie_) << ", state=" << state_ << " Hal fails";
363 }
364 }
365
366 if (retval) {
367 LOG(INFO) << __func__ << ": session_type=" << toString(session_type_)
368 << ", cookie=" << StringPrintf("%#hx", cookie_) << ", state=" << state_ << " done";
369 } else {
370 LOG(ERROR) << __func__ << ": session_type=" << toString(session_type_)
371 << ", cookie=" << StringPrintf("%#hx", cookie_) << ", state=" << state_ << " failure";
372 }
373
374 return retval; // false if any failure like timeout
375 }
376
Stop()377 void BluetoothAudioPortOut::Stop() {
378 if (!in_use()) {
379 LOG(ERROR) << __func__ << ": BluetoothAudioPortOut is not in use";
380 return;
381 }
382 LOG(INFO) << __func__ << ": session_type=" << toString(session_type_) << ", cookie=" << StringPrintf("%#hx", cookie_)
383 << ", state=" << state_ << " request";
384 state_ = BluetoothStreamState::DISABLED;
385 BluetoothAudioSessionControl::StopStream(session_type_);
386 LOG(INFO) << __func__ << ": session_type=" << toString(session_type_) << ", cookie=" << StringPrintf("%#hx", cookie_)
387 << ", state=" << state_ << " done";
388 }
389
WriteData(const void * buffer,size_t bytes) const390 size_t BluetoothAudioPortOut::WriteData(const void* buffer, size_t bytes) const {
391 if (!in_use()) return 0;
392 if (!is_stereo_to_mono_) {
393 return BluetoothAudioSessionControl::OutWritePcmData(session_type_, buffer, bytes);
394 }
395
396 // WAR to mix the stereo into Mono (16 bits per sample)
397 const size_t write_frames = bytes >> 2;
398 if (write_frames == 0) return 0;
399 auto src = static_cast<const int16_t*>(buffer);
400 std::unique_ptr<int16_t[]> dst{new int16_t[write_frames]};
401 downmix_to_mono_i16_from_stereo_i16(dst.get(), src, write_frames);
402 // a frame is 16 bits, and the size of a mono frame is equal to half a stereo.
403 return BluetoothAudioSessionControl::OutWritePcmData(session_type_, dst.get(), write_frames * 2) * 2;
404 }
405
GetPresentationPosition(uint64_t * delay_ns,uint64_t * bytes,timespec * timestamp) const406 bool BluetoothAudioPortOut::GetPresentationPosition(uint64_t* delay_ns,
407 uint64_t* bytes,
408 timespec* timestamp) const {
409 if (!in_use()) {
410 LOG(ERROR) << __func__ << ": BluetoothAudioPortOut is not in use";
411 return false;
412 }
413 bool retval = BluetoothAudioSessionControl::GetPresentationPosition(
414 session_type_, delay_ns, bytes, timestamp);
415 LOG(VERBOSE) << __func__ << ": session_type=" << StringPrintf("%#hhx", session_type_)
416 << ", cookie=" << StringPrintf("%#hx", cookie_) << ", state=" << state_ << ", delay=" << *delay_ns
417 << "ns, data=" << *bytes << " bytes, timestamp=" << timestamp->tv_sec << "."
418 << StringPrintf("%09ld", timestamp->tv_nsec) << "s";
419
420 return retval;
421 }
422
UpdateMetadata(const source_metadata * source_metadata) const423 void BluetoothAudioPortOut::UpdateMetadata(
424 const source_metadata* source_metadata) const {
425 if (!in_use()) {
426 LOG(ERROR) << __func__ << ": BluetoothAudioPortOut is not in use";
427 return;
428 }
429 LOG(DEBUG) << __func__ << ": session_type=" << toString(session_type_) << ", cookie=" << StringPrintf("%#hx", cookie_)
430 << ", state=" << state_ << ", " << source_metadata->track_count << " track(s)";
431 if (source_metadata->track_count == 0) return;
432 BluetoothAudioSessionControl::UpdateTracksMetadata(session_type_,
433 source_metadata);
434 }
435
GetState() const436 BluetoothStreamState BluetoothAudioPortOut::GetState() const { return state_; }
437
SetState(BluetoothStreamState state)438 void BluetoothAudioPortOut::SetState(BluetoothStreamState state) {
439 state_ = state;
440 }
441
442 } // namespace audio
443 } // namespace bluetooth
444 } // namespace android
445