1 /* 2 * Copyright (C) 2008 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 #include <math.h> 18 19 //#define LOG_NDEBUG 0 20 #define LOG_TAG "A2dpAudioInterface" 21 #include <utils/Log.h> 22 #include <utils/String8.h> 23 #include <utils/Timers.h> 24 25 #include "A2dpAudioInterface.h" 26 #include "audio/liba2dp.h" 27 #include <hardware_legacy/power.h> 28 29 30 namespace android_audio_legacy { 31 32 static const char *sA2dpWakeLock = "A2dpOutputStream"; 33 #define MAX_WRITE_RETRIES 5 34 35 // ---------------------------------------------------------------------------- 36 37 //AudioHardwareInterface* A2dpAudioInterface::createA2dpInterface() 38 //{ 39 // AudioHardwareInterface* hw = 0; 40 // 41 // hw = AudioHardwareInterface::create(); 42 // ALOGD("new A2dpAudioInterface(hw: %p)", hw); 43 // hw = new A2dpAudioInterface(hw); 44 // return hw; 45 //} 46 47 A2dpAudioInterface::A2dpAudioInterface(AudioHardwareInterface* hw) : 48 mOutput(0), mHardwareInterface(hw), mBluetoothEnabled(true), mSuspended(false) 49 { 50 } 51 52 A2dpAudioInterface::~A2dpAudioInterface() 53 { 54 closeOutputStream((AudioStreamOut *)mOutput); 55 delete mHardwareInterface; 56 } 57 58 status_t A2dpAudioInterface::initCheck() 59 { 60 if (mHardwareInterface == 0) return NO_INIT; 61 return mHardwareInterface->initCheck(); 62 } 63 64 AudioStreamOut* A2dpAudioInterface::openOutputStream( 65 uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status) 66 { 67 if (!audio_is_a2dp_out_device(devices)) { 68 ALOGV("A2dpAudioInterface::openOutputStream() open HW device: %x", devices); 69 return mHardwareInterface->openOutputStream(devices, format, channels, sampleRate, status); 70 } 71 72 status_t err = 0; 73 74 // only one output stream allowed 75 if (mOutput) { 76 if (status) 77 *status = -1; 78 return NULL; 79 } 80 81 // create new output stream 82 A2dpAudioStreamOut* out = new A2dpAudioStreamOut(); 83 if ((err = out->set(devices, format, channels, sampleRate)) == NO_ERROR) { 84 mOutput = out; 85 mOutput->setBluetoothEnabled(mBluetoothEnabled); 86 mOutput->setSuspended(mSuspended); 87 } else { 88 delete out; 89 } 90 91 if (status) 92 *status = err; 93 return mOutput; 94 } 95 96 void A2dpAudioInterface::closeOutputStream(AudioStreamOut* out) { 97 if (mOutput == 0 || mOutput != out) { 98 mHardwareInterface->closeOutputStream(out); 99 } 100 else { 101 delete mOutput; 102 mOutput = 0; 103 } 104 } 105 106 107 AudioStreamIn* A2dpAudioInterface::openInputStream( 108 uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status, 109 AudioSystem::audio_in_acoustics acoustics) 110 { 111 return mHardwareInterface->openInputStream(devices, format, channels, sampleRate, status, acoustics); 112 } 113 114 void A2dpAudioInterface::closeInputStream(AudioStreamIn* in) 115 { 116 return mHardwareInterface->closeInputStream(in); 117 } 118 119 status_t A2dpAudioInterface::setMode(int mode) 120 { 121 return mHardwareInterface->setMode(mode); 122 } 123 124 status_t A2dpAudioInterface::setMicMute(bool state) 125 { 126 return mHardwareInterface->setMicMute(state); 127 } 128 129 status_t A2dpAudioInterface::getMicMute(bool* state) 130 { 131 return mHardwareInterface->getMicMute(state); 132 } 133 134 status_t A2dpAudioInterface::setParameters(const String8& keyValuePairs) 135 { 136 AudioParameter param = AudioParameter(keyValuePairs); 137 String8 value; 138 String8 key; 139 status_t status = NO_ERROR; 140 141 ALOGV("setParameters() %s", keyValuePairs.string()); 142 143 key = "bluetooth_enabled"; 144 if (param.get(key, value) == NO_ERROR) { 145 mBluetoothEnabled = (value == "true"); 146 if (mOutput) { 147 mOutput->setBluetoothEnabled(mBluetoothEnabled); 148 } 149 param.remove(key); 150 } 151 key = String8("A2dpSuspended"); 152 if (param.get(key, value) == NO_ERROR) { 153 mSuspended = (value == "true"); 154 if (mOutput) { 155 mOutput->setSuspended(mSuspended); 156 } 157 param.remove(key); 158 } 159 160 if (param.size()) { 161 status_t hwStatus = mHardwareInterface->setParameters(param.toString()); 162 if (status == NO_ERROR) { 163 status = hwStatus; 164 } 165 } 166 167 return status; 168 } 169 170 String8 A2dpAudioInterface::getParameters(const String8& keys) 171 { 172 AudioParameter param = AudioParameter(keys); 173 AudioParameter a2dpParam = AudioParameter(); 174 String8 value; 175 String8 key; 176 177 key = "bluetooth_enabled"; 178 if (param.get(key, value) == NO_ERROR) { 179 value = mBluetoothEnabled ? "true" : "false"; 180 a2dpParam.add(key, value); 181 param.remove(key); 182 } 183 key = "A2dpSuspended"; 184 if (param.get(key, value) == NO_ERROR) { 185 value = mSuspended ? "true" : "false"; 186 a2dpParam.add(key, value); 187 param.remove(key); 188 } 189 190 String8 keyValuePairs = a2dpParam.toString(); 191 192 if (param.size()) { 193 if (keyValuePairs != "") { 194 keyValuePairs += ";"; 195 } 196 keyValuePairs += mHardwareInterface->getParameters(param.toString()); 197 } 198 199 ALOGV("getParameters() %s", keyValuePairs.string()); 200 return keyValuePairs; 201 } 202 203 size_t A2dpAudioInterface::getInputBufferSize(uint32_t sampleRate, int format, int channelCount) 204 { 205 return mHardwareInterface->getInputBufferSize(sampleRate, format, channelCount); 206 } 207 208 status_t A2dpAudioInterface::setVoiceVolume(float v) 209 { 210 return mHardwareInterface->setVoiceVolume(v); 211 } 212 213 status_t A2dpAudioInterface::setMasterVolume(float v) 214 { 215 return mHardwareInterface->setMasterVolume(v); 216 } 217 218 status_t A2dpAudioInterface::dump(int fd, const Vector<String16>& args) 219 { 220 return mHardwareInterface->dumpState(fd, args); 221 } 222 223 // ---------------------------------------------------------------------------- 224 225 A2dpAudioInterface::A2dpAudioStreamOut::A2dpAudioStreamOut() : 226 mFd(-1), mStandby(true), mStartCount(0), mRetryCount(0), mData(NULL), 227 // assume BT enabled to start, this is safe because its only the 228 // enabled->disabled transition we are worried about 229 mBluetoothEnabled(true), mDevice(0), mClosing(false), mSuspended(false) 230 { 231 // use any address by default 232 strcpy(mA2dpAddress, "00:00:00:00:00:00"); 233 init(); 234 } 235 236 status_t A2dpAudioInterface::A2dpAudioStreamOut::set( 237 uint32_t device, int *pFormat, uint32_t *pChannels, uint32_t *pRate) 238 { 239 int lFormat = pFormat ? *pFormat : 0; 240 uint32_t lChannels = pChannels ? *pChannels : 0; 241 uint32_t lRate = pRate ? *pRate : 0; 242 243 ALOGD("A2dpAudioStreamOut::set %x, %d, %d, %d\n", device, lFormat, lChannels, lRate); 244 245 // fix up defaults 246 if (lFormat == 0) lFormat = format(); 247 if (lChannels == 0) lChannels = channels(); 248 if (lRate == 0) lRate = sampleRate(); 249 250 // check values 251 if ((lFormat != format()) || 252 (lChannels != channels()) || 253 (lRate != sampleRate())){ 254 if (pFormat) *pFormat = format(); 255 if (pChannels) *pChannels = channels(); 256 if (pRate) *pRate = sampleRate(); 257 return BAD_VALUE; 258 } 259 260 if (pFormat) *pFormat = lFormat; 261 if (pChannels) *pChannels = lChannels; 262 if (pRate) *pRate = lRate; 263 264 mDevice = device; 265 mBufferDurationUs = ((bufferSize() * 1000 )/ frameSize() / sampleRate()) * 1000; 266 return NO_ERROR; 267 } 268 269 A2dpAudioInterface::A2dpAudioStreamOut::~A2dpAudioStreamOut() 270 { 271 ALOGV("A2dpAudioStreamOut destructor"); 272 close(); 273 ALOGV("A2dpAudioStreamOut destructor returning from close()"); 274 } 275 276 ssize_t A2dpAudioInterface::A2dpAudioStreamOut::write(const void* buffer, size_t bytes) 277 { 278 status_t status = -1; 279 { 280 Mutex::Autolock lock(mLock); 281 282 size_t remaining = bytes; 283 284 if (!mBluetoothEnabled || mClosing || mSuspended) { 285 ALOGV("A2dpAudioStreamOut::write(), but bluetooth disabled \ 286 mBluetoothEnabled %d, mClosing %d, mSuspended %d", 287 mBluetoothEnabled, mClosing, mSuspended); 288 goto Error; 289 } 290 291 if (mStandby) { 292 acquire_wake_lock (PARTIAL_WAKE_LOCK, sA2dpWakeLock); 293 mStandby = false; 294 mLastWriteTime = systemTime(); 295 } 296 297 status = init(); 298 if (status < 0) 299 goto Error; 300 301 int retries = MAX_WRITE_RETRIES; 302 while (remaining > 0 && retries) { 303 status = a2dp_write(mData, buffer, remaining); 304 if (status < 0) { 305 ALOGE("a2dp_write failed err: %d\n", status); 306 goto Error; 307 } 308 if (status == 0) { 309 retries--; 310 } 311 remaining -= status; 312 buffer = (char *)buffer + status; 313 } 314 315 // if A2DP sink runs abnormally fast, sleep a little so that audioflinger mixer thread 316 // does no spin and starve other threads. 317 // NOTE: It is likely that the A2DP headset is being disconnected 318 nsecs_t now = systemTime(); 319 if ((uint32_t)ns2us(now - mLastWriteTime) < (mBufferDurationUs >> 2)) { 320 ALOGV("A2DP sink runs too fast"); 321 usleep(mBufferDurationUs - (uint32_t)ns2us(now - mLastWriteTime)); 322 } 323 mLastWriteTime = now; 324 return bytes; 325 326 } 327 Error: 328 329 standby(); 330 331 // Simulate audio output timing in case of error 332 usleep(mBufferDurationUs); 333 334 return status; 335 } 336 337 status_t A2dpAudioInterface::A2dpAudioStreamOut::init() 338 { 339 if (!mData) { 340 status_t status = a2dp_init(44100, 2, &mData); 341 if (status < 0) { 342 ALOGE("a2dp_init failed err: %d\n", status); 343 mData = NULL; 344 return status; 345 } 346 a2dp_set_sink(mData, mA2dpAddress); 347 } 348 349 return 0; 350 } 351 352 status_t A2dpAudioInterface::A2dpAudioStreamOut::standby() 353 { 354 Mutex::Autolock lock(mLock); 355 return standby_l(); 356 } 357 358 status_t A2dpAudioInterface::A2dpAudioStreamOut::standby_l() 359 { 360 int result = NO_ERROR; 361 362 if (!mStandby) { 363 ALOGV_IF(mClosing || !mBluetoothEnabled, "Standby skip stop: closing %d enabled %d", 364 mClosing, mBluetoothEnabled); 365 if (!mClosing && mBluetoothEnabled) { 366 result = a2dp_stop(mData); 367 } 368 release_wake_lock(sA2dpWakeLock); 369 mStandby = true; 370 } 371 372 return result; 373 } 374 375 status_t A2dpAudioInterface::A2dpAudioStreamOut::setParameters(const String8& keyValuePairs) 376 { 377 AudioParameter param = AudioParameter(keyValuePairs); 378 String8 value; 379 String8 key = String8("a2dp_sink_address"); 380 status_t status = NO_ERROR; 381 int device; 382 ALOGV("A2dpAudioStreamOut::setParameters() %s", keyValuePairs.string()); 383 384 if (param.get(key, value) == NO_ERROR) { 385 if (value.length() != strlen("00:00:00:00:00:00")) { 386 status = BAD_VALUE; 387 } else { 388 setAddress(value.string()); 389 } 390 param.remove(key); 391 } 392 key = String8("closing"); 393 if (param.get(key, value) == NO_ERROR) { 394 mClosing = (value == "true"); 395 if (mClosing) { 396 standby(); 397 } 398 param.remove(key); 399 } 400 key = AudioParameter::keyRouting; 401 if (param.getInt(key, device) == NO_ERROR) { 402 if (audio_is_a2dp_out_device(device)) { 403 mDevice = device; 404 status = NO_ERROR; 405 } else { 406 status = BAD_VALUE; 407 } 408 param.remove(key); 409 } 410 411 if (param.size()) { 412 status = BAD_VALUE; 413 } 414 return status; 415 } 416 417 String8 A2dpAudioInterface::A2dpAudioStreamOut::getParameters(const String8& keys) 418 { 419 AudioParameter param = AudioParameter(keys); 420 String8 value; 421 String8 key = String8("a2dp_sink_address"); 422 423 if (param.get(key, value) == NO_ERROR) { 424 value = mA2dpAddress; 425 param.add(key, value); 426 } 427 key = AudioParameter::keyRouting; 428 if (param.get(key, value) == NO_ERROR) { 429 param.addInt(key, (int)mDevice); 430 } 431 432 ALOGV("A2dpAudioStreamOut::getParameters() %s", param.toString().string()); 433 return param.toString(); 434 } 435 436 status_t A2dpAudioInterface::A2dpAudioStreamOut::setAddress(const char* address) 437 { 438 Mutex::Autolock lock(mLock); 439 440 if (strlen(address) != strlen("00:00:00:00:00:00")) 441 return -EINVAL; 442 443 strcpy(mA2dpAddress, address); 444 if (mData) 445 a2dp_set_sink(mData, mA2dpAddress); 446 447 return NO_ERROR; 448 } 449 450 status_t A2dpAudioInterface::A2dpAudioStreamOut::setBluetoothEnabled(bool enabled) 451 { 452 ALOGD("setBluetoothEnabled %d", enabled); 453 454 Mutex::Autolock lock(mLock); 455 456 mBluetoothEnabled = enabled; 457 if (!enabled) { 458 return close_l(); 459 } 460 return NO_ERROR; 461 } 462 463 status_t A2dpAudioInterface::A2dpAudioStreamOut::setSuspended(bool onOff) 464 { 465 ALOGV("setSuspended %d", onOff); 466 mSuspended = onOff; 467 standby(); 468 return NO_ERROR; 469 } 470 471 status_t A2dpAudioInterface::A2dpAudioStreamOut::close() 472 { 473 Mutex::Autolock lock(mLock); 474 ALOGV("A2dpAudioStreamOut::close() calling close_l()"); 475 return close_l(); 476 } 477 478 status_t A2dpAudioInterface::A2dpAudioStreamOut::close_l() 479 { 480 standby_l(); 481 if (mData) { 482 ALOGV("A2dpAudioStreamOut::close_l() calling a2dp_cleanup(mData)"); 483 a2dp_cleanup(mData); 484 mData = NULL; 485 } 486 return NO_ERROR; 487 } 488 489 status_t A2dpAudioInterface::A2dpAudioStreamOut::dump(int fd, const Vector<String16>& args) 490 { 491 return NO_ERROR; 492 } 493 494 status_t A2dpAudioInterface::A2dpAudioStreamOut::getRenderPosition(uint32_t *driverFrames) 495 { 496 //TODO: enable when supported by driver 497 return INVALID_OPERATION; 498 } 499 500 }; // namespace android 501