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