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 #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