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