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 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 } 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 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 100 BluetoothAudioPortOut::BluetoothAudioPortOut() 101 : state_(BluetoothStreamState::DISABLED), 102 session_type_(SessionType::UNKNOWN), 103 cookie_(android::bluetooth::audio::kObserversCookieUndefined) {} 104 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 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 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 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 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 249 bool BluetoothAudioPortOut::in_use() const { 250 return (cookie_ != android::bluetooth::audio::kObserversCookieUndefined); 251 } 252 253 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 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 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 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 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 390 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 406 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 423 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 436 BluetoothStreamState BluetoothAudioPortOut::GetState() const { return state_; } 437 438 void BluetoothAudioPortOut::SetState(BluetoothStreamState state) { 439 state_ = state; 440 } 441 442 } // namespace audio 443 } // namespace bluetooth 444 } // namespace android 445