Home | History | Annotate | Download | only in audio
      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