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