1a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland/*
28dd179b07f00e35208dd4cf48e14264717e8d5a0Jean-Baptiste Queru** Copyright 2008, The Android Open-Source Project
3a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland**
47510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the "License");
57510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project** you may not use this file except in compliance with the License.
67510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project** You may obtain a copy of the License at
7a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland**
87510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project**     http://www.apache.org/licenses/LICENSE-2.0
9a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland**
107510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project** Unless required by applicable law or agreed to in writing, software
117510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project** distributed under the License is distributed on an "AS IS" BASIS,
127510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project** See the License for the specific language governing permissions and
14a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland** limitations under the License.
15a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland*/
16a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
17a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland#include <math.h>
18a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
197510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project//#define LOG_NDEBUG 0
20a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland#define LOG_TAG "AudioHardwareMSM72XX"
21a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland#include <utils/Log.h>
22a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland#include <utils/String8.h>
23a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
24a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland#include <stdio.h>
25a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland#include <unistd.h>
26a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland#include <sys/ioctl.h>
27a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland#include <sys/types.h>
28a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland#include <sys/stat.h>
29a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland#include <dlfcn.h>
30a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland#include <fcntl.h>
31a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
32a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland// hardware specific functions
33a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
34a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland#include "AudioHardware.h"
359e8b6821afad923dcc616768f7582545c90a0bc6Dave Sparks#include <media/AudioRecord.h>
36a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
37a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland#define LOG_SND_RPC 0  // Set to 1 to log sound RPC's
38a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
39a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetlandnamespace android {
407510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Projectstatic int audpre_index, tx_iir_index;
417510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Projectstatic void * acoustic;
427510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Projectconst uint32_t AudioHardware::inputSamplingRates[] = {
437510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project        8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
447510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project};
45a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland// ----------------------------------------------------------------------------
46a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
47a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian SwetlandAudioHardware::AudioHardware() :
487510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    mInit(false), mMicMute(true), mBluetoothNrec(true), mBluetoothId(0),
492735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    mOutput(0), mSndEndpoints(NULL), mCurSndDevice(-1),
50a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    SND_DEVICE_CURRENT(-1),
51a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    SND_DEVICE_HANDSET(-1),
527510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    SND_DEVICE_SPEAKER(-1),
53a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    SND_DEVICE_HEADSET(-1),
542735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    SND_DEVICE_BT(-1),
552735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    SND_DEVICE_CARKIT(-1),
562735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    SND_DEVICE_TTY_FULL(-1),
572735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    SND_DEVICE_TTY_VCO(-1),
582735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    SND_DEVICE_TTY_HCO(-1),
592735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    SND_DEVICE_NO_MIC_HEADSET(-1),
602735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    SND_DEVICE_FM_HEADSET(-1),
612735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    SND_DEVICE_HEADSET_AND_SPEAKER(-1),
622735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    SND_DEVICE_FM_SPEAKER(-1),
632735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    SND_DEVICE_BT_EC_OFF(-1)
64a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland{
65a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
667510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    int (*snd_get_num)();
677510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    int (*snd_get_endpoint)(int, msm_snd_endpoint *);
687510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    int (*set_acoustic_parameters)();
697510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project
707510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    struct msm_snd_endpoint *ept;
717510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project
727510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    acoustic = ::dlopen("/system/lib/libhtc_acoustic.so", RTLD_NOW);
737510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    if (acoustic == NULL ) {
74c3dee7890047bad1136078f0f6e2b6d1a9a24947Steve Block        ALOGE("Could not open libhtc_acoustic.so");
75d498a9ce9863bd979d3403473568c6e1e38b7daeBrian Swetland        /* this is not really an error on non-htc devices... */
76d498a9ce9863bd979d3403473568c6e1e38b7daeBrian Swetland        mNumSndEndpoints = 0;
7735f70b5d158659c59981365ecd8e2acfb09b3181Brian Swetland        mInit = true;
787510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project        return;
797510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    }
807510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project
817510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    set_acoustic_parameters = (int (*)(void))::dlsym(acoustic, "set_acoustic_parameters");
827510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    if ((*set_acoustic_parameters) == 0 ) {
83c3dee7890047bad1136078f0f6e2b6d1a9a24947Steve Block        ALOGE("Could not open set_acoustic_parameters()");
843ccfb0bb4f6f8c18d5b66b5568a9aa1d969a598aIliyan Malchev        return;
853ccfb0bb4f6f8c18d5b66b5568a9aa1d969a598aIliyan Malchev    }
863ccfb0bb4f6f8c18d5b66b5568a9aa1d969a598aIliyan Malchev
877510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    int rc = set_acoustic_parameters();
887510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    if (rc < 0) {
89c3dee7890047bad1136078f0f6e2b6d1a9a24947Steve Block        ALOGE("Could not set acoustic parameters to share memory: %d", rc);
907510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project//        return;
917510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    }
927510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project
937510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    snd_get_num = (int (*)(void))::dlsym(acoustic, "snd_get_num_endpoints");
947510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    if ((*snd_get_num) == 0 ) {
95c3dee7890047bad1136078f0f6e2b6d1a9a24947Steve Block        ALOGE("Could not open snd_get_num()");
967510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project//        return;
977510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    }
987510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project
997510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    mNumSndEndpoints = snd_get_num();
100f9452ed4a7c7bbde537f3f2690fc124e5a1beaffSteve Block    ALOGD("mNumSndEndpoints = %d", mNumSndEndpoints);
1017510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    mSndEndpoints = new msm_snd_endpoint[mNumSndEndpoints];
1027510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    mInit = true;
10322f2554680715d1ea993409217a4a21f652ef130Steve Block    ALOGV("constructed %d SND endpoints)", mNumSndEndpoints);
1047510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    ept = mSndEndpoints;
1057510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    snd_get_endpoint = (int (*)(int, msm_snd_endpoint *))::dlsym(acoustic, "snd_get_endpoint");
1067510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    if ((*snd_get_endpoint) == 0 ) {
107c3dee7890047bad1136078f0f6e2b6d1a9a24947Steve Block        ALOGE("Could not open snd_get_endpoint()");
1087510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project        return;
1097510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    }
1107510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project
1117510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    for (int cnt = 0; cnt < mNumSndEndpoints; cnt++, ept++) {
1127510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project        ept->id = cnt;
1137510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project        snd_get_endpoint(cnt, ept);
1147510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project#define CHECK_FOR(desc) \
1157510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project        if (!strcmp(ept->name, #desc)) { \
1167510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project            SND_DEVICE_##desc = ept->id; \
117f9452ed4a7c7bbde537f3f2690fc124e5a1beaffSteve Block            ALOGD("BT MATCH " #desc); \
1187510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project        } else
1197510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project        CHECK_FOR(CURRENT)
1207510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project        CHECK_FOR(HANDSET)
1217510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project        CHECK_FOR(SPEAKER)
1227510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project        CHECK_FOR(BT)
1237510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project        CHECK_FOR(BT_EC_OFF)
1247510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project        CHECK_FOR(HEADSET)
1252735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        CHECK_FOR(CARKIT)
1262735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        CHECK_FOR(TTY_FULL)
1272735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        CHECK_FOR(TTY_VCO)
1282735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        CHECK_FOR(TTY_HCO)
1292735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        CHECK_FOR(NO_MIC_HEADSET)
1302735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        CHECK_FOR(FM_HEADSET)
1312735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        CHECK_FOR(FM_SPEAKER)
1327510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project        CHECK_FOR(HEADSET_AND_SPEAKER) {}
133a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland#undef CHECK_FOR
134a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    }
135a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland}
136a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
137a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian SwetlandAudioHardware::~AudioHardware()
138a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland{
1392735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    for (size_t index = 0; index < mInputs.size(); index++) {
1402735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        closeInputStream((AudioStreamIn*)mInputs[index]);
1412735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    }
1422735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    mInputs.clear();
1432735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    closeOutputStream((AudioStreamOut*)mOutput);
144a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    delete [] mSndEndpoints;
145d498a9ce9863bd979d3403473568c6e1e38b7daeBrian Swetland    if (acoustic) {
146d498a9ce9863bd979d3403473568c6e1e38b7daeBrian Swetland        ::dlclose(acoustic);
147d498a9ce9863bd979d3403473568c6e1e38b7daeBrian Swetland        acoustic = 0;
148d498a9ce9863bd979d3403473568c6e1e38b7daeBrian Swetland    }
149a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    mInit = false;
150a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland}
151a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
152a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetlandstatus_t AudioHardware::initCheck()
153a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland{
154a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    return mInit ? NO_ERROR : NO_INIT;
155a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland}
156a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
157a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian SwetlandAudioStreamOut* AudioHardware::openOutputStream(
1582735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status)
159a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland{
1602735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    { // scope for the lock
1612735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        Mutex::Autolock lock(mLock);
162a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
1632735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        // only one output stream allowed
1642735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        if (mOutput) {
1652735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent            if (status) {
1662735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent                *status = INVALID_OPERATION;
1672735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent            }
1682735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent            return 0;
1697510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project        }
170a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
1712735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        // create new output stream
1722735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        AudioStreamOutMSM72xx* out = new AudioStreamOutMSM72xx();
1732735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        status_t lStatus = out->set(this, devices, format, channels, sampleRate);
1742735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        if (status) {
1752735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent            *status = lStatus;
1762735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        }
1772735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        if (lStatus == NO_ERROR) {
1782735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent            mOutput = out;
1792735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        } else {
1802735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent            delete out;
1812735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        }
182a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    }
183a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    return mOutput;
184a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland}
185a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
1862735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurentvoid AudioHardware::closeOutputStream(AudioStreamOut* out) {
187a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    Mutex::Autolock lock(mLock);
1882735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    if (mOutput == 0 || mOutput != out) {
1893fb19cd0b6534ef9d36f8ac0c5ddbdc73ed92a26Steve Block        ALOGW("Attempt to close invalid output stream");
190a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    }
191a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    else {
1922735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        delete mOutput;
193a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        mOutput = 0;
194a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    }
195a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland}
196a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
197a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian SwetlandAudioStreamIn* AudioHardware::openInputStream(
1982735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status,
1992735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        AudioSystem::audio_in_acoustics acoustic_flags)
200a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland{
2019e8b6821afad923dcc616768f7582545c90a0bc6Dave Sparks    // check for valid input source
2022735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    if (!AudioSystem::isInputDevice((AudioSystem::audio_devices)devices)) {
2039e8b6821afad923dcc616768f7582545c90a0bc6Dave Sparks        return 0;
2049e8b6821afad923dcc616768f7582545c90a0bc6Dave Sparks    }
2059e8b6821afad923dcc616768f7582545c90a0bc6Dave Sparks
2067510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    mLock.lock();
207a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
208a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    AudioStreamInMSM72xx* in = new AudioStreamInMSM72xx();
2092735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    status_t lStatus = in->set(this, devices, format, channels, sampleRate, acoustic_flags);
2107510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    if (status) {
2117510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project        *status = lStatus;
2127510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    }
2137510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    if (lStatus != NO_ERROR) {
2147510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project        mLock.unlock();
215a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        delete in;
216a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        return 0;
217a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    }
218a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
2192735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    mInputs.add(in);
2207510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    mLock.unlock();
2217510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project
2222735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    return in;
223a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland}
224a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
2252735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurentvoid AudioHardware::closeInputStream(AudioStreamIn* in) {
226a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    Mutex::Autolock lock(mLock);
2272735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent
2282735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    ssize_t index = mInputs.indexOf((AudioStreamInMSM72xx *)in);
2292735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    if (index < 0) {
2303fb19cd0b6534ef9d36f8ac0c5ddbdc73ed92a26Steve Block        ALOGW("Attempt to close invalid input stream");
2312735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    } else {
2322735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        mLock.unlock();
2332735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        delete mInputs[index];
2342735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        mLock.lock();
2352735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        mInputs.removeAt(index);
236a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    }
237a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland}
238a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
23963ca66ea9da5ea61806ee547f3aa1c498ac235feEric Laurentstatus_t AudioHardware::setMode(int mode)
24063ca66ea9da5ea61806ee547f3aa1c498ac235feEric Laurent{
24163ca66ea9da5ea61806ee547f3aa1c498ac235feEric Laurent    status_t status = AudioHardwareBase::setMode(mode);
24263ca66ea9da5ea61806ee547f3aa1c498ac235feEric Laurent    if (status == NO_ERROR) {
24363ca66ea9da5ea61806ee547f3aa1c498ac235feEric Laurent        // make sure that doAudioRouteOrMute() is called by doRouting()
24463ca66ea9da5ea61806ee547f3aa1c498ac235feEric Laurent        // even if the new device selected is the same as current one.
24511c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent        clearCurDevice();
24663ca66ea9da5ea61806ee547f3aa1c498ac235feEric Laurent    }
24763ca66ea9da5ea61806ee547f3aa1c498ac235feEric Laurent    return status;
24863ca66ea9da5ea61806ee547f3aa1c498ac235feEric Laurent}
24963ca66ea9da5ea61806ee547f3aa1c498ac235feEric Laurent
2507510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Projectbool AudioHardware::checkOutputStandby()
251a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland{
2527510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    if (mOutput)
2537510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project        if (!mOutput->checkStandby())
2547510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project            return false;
255a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
2567510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    return true;
257a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland}
258a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
259a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetlandstatus_t AudioHardware::setMicMute(bool state)
260a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland{
261a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    Mutex::Autolock lock(mLock);
262a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    return setMicMute_nosync(state);
263a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland}
264a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
265a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland// always call with mutex held
266a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetlandstatus_t AudioHardware::setMicMute_nosync(bool state)
267a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland{
268a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    if (mMicMute != state) {
269a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        mMicMute = state;
270a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        return doAudioRouteOrMute(SND_DEVICE_CURRENT);
271a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    }
272a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    return NO_ERROR;
273a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland}
274a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
275a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetlandstatus_t AudioHardware::getMicMute(bool* state)
276a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland{
277a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    *state = mMicMute;
278a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    return NO_ERROR;
279a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland}
280a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
2812735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurentstatus_t AudioHardware::setParameters(const String8& keyValuePairs)
282a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland{
2832735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    AudioParameter param = AudioParameter(keyValuePairs);
2842735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    String8 value;
2852735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    String8 key;
286a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    const char BT_NREC_KEY[] = "bt_headset_nrec";
287a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    const char BT_NAME_KEY[] = "bt_headset_name";
288a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    const char BT_NREC_VALUE_ON[] = "on";
289a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
2902735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent
29122f2554680715d1ea993409217a4a21f652ef130Steve Block    ALOGV("setParameters() %s", keyValuePairs.string());
2922735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent
2932735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    if (keyValuePairs.length() == 0) return BAD_VALUE;
2942735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent
2952735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    key = String8(BT_NREC_KEY);
2962735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    if (param.get(key, value) == NO_ERROR) {
2972735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        if (value == BT_NREC_VALUE_ON) {
298a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland            mBluetoothNrec = true;
299a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        } else {
300a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland            mBluetoothNrec = false;
3015a182ec3e8b87b6538b4b492cb993239a677915fSteve Block            ALOGI("Turning noise reduction and echo cancellation off for BT "
302a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland                 "headset");
303a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        }
3042735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    }
3052735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    key = String8(BT_NAME_KEY);
3062735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    if (param.get(key, value) == NO_ERROR) {
307a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        mBluetoothId = 0;
3087510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project        for (int i = 0; i < mNumSndEndpoints; i++) {
3092735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent            if (!strcasecmp(value.string(), mSndEndpoints[i].name)) {
3107510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project                mBluetoothId = mSndEndpoints[i].id;
3115a182ec3e8b87b6538b4b492cb993239a677915fSteve Block                ALOGI("Using custom acoustic parameters for %s", value.string());
312a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland                break;
313a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland            }
314a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        }
315a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        if (mBluetoothId == 0) {
3165a182ec3e8b87b6538b4b492cb993239a677915fSteve Block            ALOGI("Using default acoustic parameters "
3172735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent                 "(%s not in acoustic database)", value.string());
31811c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent            doRouting();
319a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        }
320a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    }
321a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    return NO_ERROR;
322a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland}
3232735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent
3242735e3b55bdaf33cfd0dbaa1b914231243933e92Eric LaurentString8 AudioHardware::getParameters(const String8& keys)
3252735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent{
326ba77ed6e3c6006d2797867f14ffd01e99cafc03bEric Laurent    AudioParameter param = AudioParameter(keys);
327ba77ed6e3c6006d2797867f14ffd01e99cafc03bEric Laurent    return param.toString();
3282735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent}
3292735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent
3302735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent
3317510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Projectstatic unsigned calculate_audpre_table_index(unsigned index)
332a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland{
3337510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    switch (index) {
3347510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project        case 48000:    return SAMP_RATE_INDX_48000;
3357510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project        case 44100:    return SAMP_RATE_INDX_44100;
3367510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project        case 32000:    return SAMP_RATE_INDX_32000;
3377510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project        case 24000:    return SAMP_RATE_INDX_24000;
3387510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project        case 22050:    return SAMP_RATE_INDX_22050;
3397510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project        case 16000:    return SAMP_RATE_INDX_16000;
3407510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project        case 12000:    return SAMP_RATE_INDX_12000;
3417510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project        case 11025:    return SAMP_RATE_INDX_11025;
3427510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project        case 8000:    return SAMP_RATE_INDX_8000;
3437510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project        default:     return -1;
344a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    }
345a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland}
3467510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Projectsize_t AudioHardware::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
347a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland{
3487510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    if (format != AudioSystem::PCM_16_BIT) {
3493fb19cd0b6534ef9d36f8ac0c5ddbdc73ed92a26Steve Block        ALOGW("getInputBufferSize bad format: %d", format);
3507510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project        return 0;
351a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    }
3527510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    if (channelCount < 1 || channelCount > 2) {
3533fb19cd0b6534ef9d36f8ac0c5ddbdc73ed92a26Steve Block        ALOGW("getInputBufferSize bad channel count: %d", channelCount);
3547510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project        return 0;
355a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    }
356a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
3577510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    return 2048*channelCount;
358a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland}
359a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
360a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetlandstatic status_t set_volume_rpc(uint32_t device,
361a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland                               uint32_t method,
362a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland                               uint32_t volume)
363a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland{
364a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    int fd;
365a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland#if LOG_SND_RPC
366f9452ed4a7c7bbde537f3f2690fc124e5a1beaffSteve Block    ALOGD("rpc_snd_set_volume(%d, %d, %d)\n", device, method, volume);
367a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland#endif
368a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
369a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    if (device == -1UL) return NO_ERROR;
370a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
371a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    fd = open("/dev/msm_snd", O_RDWR);
372a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    if (fd < 0) {
373c3dee7890047bad1136078f0f6e2b6d1a9a24947Steve Block        ALOGE("Can not open snd device");
374a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        return -EPERM;
375a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    }
376a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    /* rpc_snd_set_volume(
377a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland     *     device,            # Any hardware device enum, including
378a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland     *                        # SND_DEVICE_CURRENT
379a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland     *     method,            # must be SND_METHOD_VOICE to do anything useful
380a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland     *     volume,            # integer volume level, in range [0,5].
381a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland     *                        # note that 0 is audible (not quite muted)
382a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland     *  )
383a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland     * rpc_snd_set_volume only works for in-call sound volume.
384a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland     */
3857510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project     struct msm_snd_volume_config args;
3867510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project     args.device = device;
3877510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project     args.method = method;
3887510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project     args.volume = volume;
389a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
3907510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project     if (ioctl(fd, SND_SET_VOLUME, &args) < 0) {
391c3dee7890047bad1136078f0f6e2b6d1a9a24947Steve Block         ALOGE("snd_set_volume error.");
3927510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project         close(fd);
3937510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project         return -EIO;
3947510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project     }
3957510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project     close(fd);
3967510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project     return NO_ERROR;
397a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland}
398a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
399a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetlandstatus_t AudioHardware::setVoiceVolume(float v)
400a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland{
401a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    if (v < 0.0) {
4023fb19cd0b6534ef9d36f8ac0c5ddbdc73ed92a26Steve Block        ALOGW("setVoiceVolume(%f) under 0.0, assuming 0.0\n", v);
403a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        v = 0.0;
404a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    } else if (v > 1.0) {
4053fb19cd0b6534ef9d36f8ac0c5ddbdc73ed92a26Steve Block        ALOGW("setVoiceVolume(%f) over 1.0, assuming 1.0\n", v);
406a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        v = 1.0;
407a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    }
408a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
409a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    int vol = lrint(v * 5.0);
410f9452ed4a7c7bbde537f3f2690fc124e5a1beaffSteve Block    ALOGD("setVoiceVolume(%f)\n", v);
4115a182ec3e8b87b6538b4b492cb993239a677915fSteve Block    ALOGI("Setting in-call volume to %d (available range is 0 to 5)\n", vol);
412a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
413d066973de83218a24c773e5de04d10ed2d730873Eric Laurent    Mutex::Autolock lock(mLock);
414a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    set_volume_rpc(SND_DEVICE_CURRENT, SND_METHOD_VOICE, vol);
415a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    return NO_ERROR;
416a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland}
417a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
418a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetlandstatus_t AudioHardware::setMasterVolume(float v)
419a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland{
420a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    Mutex::Autolock lock(mLock);
421a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    int vol = ceil(v * 5.0);
4225a182ec3e8b87b6538b4b492cb993239a677915fSteve Block    ALOGI("Set master volume to %d.\n", vol);
4232735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    /*
424a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    set_volume_rpc(SND_DEVICE_HANDSET, SND_METHOD_VOICE, vol);
425a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    set_volume_rpc(SND_DEVICE_SPEAKER, SND_METHOD_VOICE, vol);
426a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    set_volume_rpc(SND_DEVICE_BT,      SND_METHOD_VOICE, vol);
427a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    set_volume_rpc(SND_DEVICE_HEADSET, SND_METHOD_VOICE, vol);
4282735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    */
429a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    // We return an error code here to let the audioflinger do in-software
430a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    // volume on top of the maximum volume that we set through the SND API.
431a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    // return error - software mixer will handle it
432a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    return -1;
433a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland}
434a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
435a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetlandstatic status_t do_route_audio_rpc(uint32_t device,
436a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland                                   bool ear_mute, bool mic_mute)
437a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland{
438a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    if (device == -1UL)
439a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        return NO_ERROR;
440a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
441a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    int fd;
442a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland#if LOG_SND_RPC
443f9452ed4a7c7bbde537f3f2690fc124e5a1beaffSteve Block    ALOGD("rpc_snd_set_device(%d, %d, %d)\n", device, ear_mute, mic_mute);
444a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland#endif
445a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
446a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    fd = open("/dev/msm_snd", O_RDWR);
447a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    if (fd < 0) {
448c3dee7890047bad1136078f0f6e2b6d1a9a24947Steve Block        ALOGE("Can not open snd device");
449a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        return -EPERM;
450a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    }
451a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    // RPC call to switch audio path
452a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    /* rpc_snd_set_device(
453a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland     *     device,            # Hardware device enum to use
454a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland     *     ear_mute,          # Set mute for outgoing voice audio
455a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland     *                        # this should only be unmuted when in-call
456a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland     *     mic_mute,          # Set mute for incoming voice audio
457a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland     *                        # this should only be unmuted when in-call or
458a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland     *                        # recording.
459a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland     *  )
460a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland     */
4613ccfb0bb4f6f8c18d5b66b5568a9aa1d969a598aIliyan Malchev    struct msm_snd_device_config args;
462a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    args.device = device;
463a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    args.ear_mute = ear_mute ? SND_MUTE_MUTED : SND_MUTE_UNMUTED;
464a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    args.mic_mute = mic_mute ? SND_MUTE_MUTED : SND_MUTE_UNMUTED;
465a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
466a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    if (ioctl(fd, SND_SET_DEVICE, &args) < 0) {
467c3dee7890047bad1136078f0f6e2b6d1a9a24947Steve Block        ALOGE("snd_set_device error.");
468a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        close(fd);
469a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        return -EIO;
470a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    }
471a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
472a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    close(fd);
473a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    return NO_ERROR;
474a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland}
475a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
476a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland// always call with mutex held
477a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetlandstatus_t AudioHardware::doAudioRouteOrMute(uint32_t device)
478a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland{
47916327daa90dffd97f03d24c59ec0a4d38aa94b90Eric Laurent    if (device == (uint32_t)SND_DEVICE_BT || device == (uint32_t)SND_DEVICE_CARKIT) {
480a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        if (mBluetoothId) {
481a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland            device = mBluetoothId;
482a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        } else if (!mBluetoothNrec) {
483a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland            device = SND_DEVICE_BT_EC_OFF;
484a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        }
485a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    }
48622f2554680715d1ea993409217a4a21f652ef130Steve Block    ALOGV("doAudioRouteOrMute() device %x, mMode %d, mMicMute %d", device, mMode, mMicMute);
487a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    return do_route_audio_rpc(device,
4887510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project                              mMode != AudioSystem::MODE_IN_CALL, mMicMute);
489a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland}
490a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
49111c6a166fa684a2e44d22a142aad106f74a9409fEric Laurentstatus_t AudioHardware::doRouting()
492a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland{
493d498a9ce9863bd979d3403473568c6e1e38b7daeBrian Swetland    /* currently this code doesn't work without the htc libacoustic */
494d498a9ce9863bd979d3403473568c6e1e38b7daeBrian Swetland    if (!acoustic)
495d498a9ce9863bd979d3403473568c6e1e38b7daeBrian Swetland        return 0;
496d498a9ce9863bd979d3403473568c6e1e38b7daeBrian Swetland
497a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    Mutex::Autolock lock(mLock);
4982735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    uint32_t outputDevices = mOutput->devices();
4992735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    status_t ret = NO_ERROR;
5007510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    int (*msm72xx_enable_audpp)(int);
5017510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    msm72xx_enable_audpp = (int (*)(int))::dlsym(acoustic, "msm72xx_enable_audpp");
5022735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    int audProcess = (ADRC_DISABLE | EQ_DISABLE | RX_IIR_DISABLE);
50311c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent    AudioStreamInMSM72xx *input = getActiveInput_l();
50411c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent    uint32_t inputDevice = (input == NULL) ? 0 : input->devices();
5052735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    int sndDevice = -1;
5062735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent
50711c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent    if (inputDevice != 0) {
5085a182ec3e8b87b6538b4b492cb993239a677915fSteve Block        ALOGI("do input routing device %x\n", inputDevice);
50911c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent        if (inputDevice & AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
5105a182ec3e8b87b6538b4b492cb993239a677915fSteve Block            ALOGI("Routing audio to Bluetooth PCM\n");
51111c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent            sndDevice = SND_DEVICE_BT;
51211c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent        } else if (inputDevice & AudioSystem::DEVICE_IN_WIRED_HEADSET) {
51311c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent            if ((outputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET) &&
51411c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent                (outputDevices & AudioSystem::DEVICE_OUT_SPEAKER)) {
5155a182ec3e8b87b6538b4b492cb993239a677915fSteve Block                ALOGI("Routing audio to Wired Headset and Speaker\n");
51611c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent                sndDevice = SND_DEVICE_HEADSET_AND_SPEAKER;
51711c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent                audProcess = (ADRC_ENABLE | EQ_ENABLE | RX_IIR_ENABLE);
51811c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent            } else {
5195a182ec3e8b87b6538b4b492cb993239a677915fSteve Block                ALOGI("Routing audio to Wired Headset\n");
52011c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent                sndDevice = SND_DEVICE_HEADSET;
52111c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent            }
52211c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent        } else {
52311c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent            if (outputDevices & AudioSystem::DEVICE_OUT_SPEAKER) {
5245a182ec3e8b87b6538b4b492cb993239a677915fSteve Block                ALOGI("Routing audio to Speakerphone\n");
52511c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent                sndDevice = SND_DEVICE_SPEAKER;
52611c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent                audProcess = (ADRC_ENABLE | EQ_ENABLE | RX_IIR_ENABLE);
5272735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent            } else {
5285a182ec3e8b87b6538b4b492cb993239a677915fSteve Block                ALOGI("Routing audio to Handset\n");
52911c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent                sndDevice = SND_DEVICE_HANDSET;
5302735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent            }
5312735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        }
5322735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    }
53311c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent    // if inputDevice == 0, restore output routing
5342735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent
5352735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    if (sndDevice == -1) {
5362735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        if (outputDevices & (outputDevices - 1)) {
5372735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent            if ((outputDevices & AudioSystem::DEVICE_OUT_SPEAKER) == 0) {
5383fb19cd0b6534ef9d36f8ac0c5ddbdc73ed92a26Steve Block                ALOGW("Hardware does not support requested route combination (%#X),"
5392735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent                     " picking closest possible route...", outputDevices);
5402735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent            }
5412735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        }
5422735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent
543dd65e38951ed174f9d3d34886795438440f7eea0Eric Laurent        if (outputDevices &
544dd65e38951ed174f9d3d34886795438440f7eea0Eric Laurent            (AudioSystem::DEVICE_OUT_BLUETOOTH_SCO | AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET)) {
5455a182ec3e8b87b6538b4b492cb993239a677915fSteve Block            ALOGI("Routing audio to Bluetooth PCM\n");
5462735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent            sndDevice = SND_DEVICE_BT;
54716327daa90dffd97f03d24c59ec0a4d38aa94b90Eric Laurent        } else if (outputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT) {
5485a182ec3e8b87b6538b4b492cb993239a677915fSteve Block            ALOGI("Routing audio to Bluetooth PCM\n");
54916327daa90dffd97f03d24c59ec0a4d38aa94b90Eric Laurent            sndDevice = SND_DEVICE_CARKIT;
5502735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        } else if ((outputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET) &&
5512735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent                   (outputDevices & AudioSystem::DEVICE_OUT_SPEAKER)) {
5525a182ec3e8b87b6538b4b492cb993239a677915fSteve Block            ALOGI("Routing audio to Wired Headset and Speaker\n");
5532735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent            sndDevice = SND_DEVICE_HEADSET_AND_SPEAKER;
5542735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent            audProcess = (ADRC_ENABLE | EQ_ENABLE | RX_IIR_ENABLE);
5552735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        } else if (outputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE) {
5562735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent            if (outputDevices & AudioSystem::DEVICE_OUT_SPEAKER) {
5575a182ec3e8b87b6538b4b492cb993239a677915fSteve Block                ALOGI("Routing audio to No microphone Wired Headset and Speaker (%d,%x)\n", mMode, outputDevices);
5582735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent                sndDevice = SND_DEVICE_HEADSET_AND_SPEAKER;
5592735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent                audProcess = (ADRC_ENABLE | EQ_ENABLE | RX_IIR_ENABLE);
5602735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent            } else {
5615a182ec3e8b87b6538b4b492cb993239a677915fSteve Block                ALOGI("Routing audio to No microphone Wired Headset (%d,%x)\n", mMode, outputDevices);
5622735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent                sndDevice = SND_DEVICE_NO_MIC_HEADSET;
5632735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent            }
5642735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        } else if (outputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET) {
5655a182ec3e8b87b6538b4b492cb993239a677915fSteve Block            ALOGI("Routing audio to Wired Headset\n");
5662735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent            sndDevice = SND_DEVICE_HEADSET;
5672735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        } else if (outputDevices & AudioSystem::DEVICE_OUT_SPEAKER) {
5685a182ec3e8b87b6538b4b492cb993239a677915fSteve Block            ALOGI("Routing audio to Speakerphone\n");
5692735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent            sndDevice = SND_DEVICE_SPEAKER;
5702735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent            audProcess = (ADRC_ENABLE | EQ_ENABLE | RX_IIR_ENABLE);
5712735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        } else {
5725a182ec3e8b87b6538b4b492cb993239a677915fSteve Block            ALOGI("Routing audio to Handset\n");
5732735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent            sndDevice = SND_DEVICE_HANDSET;
5742735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        }
5752735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    }
5762735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent
5772735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    if (sndDevice != -1 && sndDevice != mCurSndDevice) {
5782735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        ret = doAudioRouteOrMute(sndDevice);
5792735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        if ((*msm72xx_enable_audpp) == 0 ) {
580c3dee7890047bad1136078f0f6e2b6d1a9a24947Steve Block            ALOGE("Could not open msm72xx_enable_audpp()");
5812735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        } else {
5822735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent            msm72xx_enable_audpp(audProcess);
5832735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        }
5842735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        mCurSndDevice = sndDevice;
585a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    }
586a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
587a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    return ret;
588a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland}
589a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
590a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetlandstatus_t AudioHardware::checkMicMute()
591a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland{
592a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    Mutex::Autolock lock(mLock);
593a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    if (mMode != AudioSystem::MODE_IN_CALL) {
594a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        setMicMute_nosync(true);
595a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    }
5967510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project
597a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    return NO_ERROR;
598a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland}
599a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
600a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetlandstatus_t AudioHardware::dumpInternals(int fd, const Vector<String16>& args)
601a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland{
602a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    const size_t SIZE = 256;
603a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    char buffer[SIZE];
604a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    String8 result;
605a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    result.append("AudioHardware::dumpInternals\n");
606a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    snprintf(buffer, SIZE, "\tmInit: %s\n", mInit? "true": "false");
607a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    result.append(buffer);
608a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    snprintf(buffer, SIZE, "\tmMicMute: %s\n", mMicMute? "true": "false");
609a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    result.append(buffer);
610a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    snprintf(buffer, SIZE, "\tmBluetoothNrec: %s\n", mBluetoothNrec? "true": "false");
611a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    result.append(buffer);
612a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    snprintf(buffer, SIZE, "\tmBluetoothId: %d\n", mBluetoothId);
613a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    result.append(buffer);
614a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    ::write(fd, result.string(), result.size());
615a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    return NO_ERROR;
616a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland}
617a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
618a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetlandstatus_t AudioHardware::dump(int fd, const Vector<String16>& args)
619a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland{
620a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    dumpInternals(fd, args);
6212735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    for (size_t index = 0; index < mInputs.size(); index++) {
6222735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        mInputs[index]->dump(fd, args);
623a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    }
6242735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent
625a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    if (mOutput) {
626a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        mOutput->dump(fd, args);
627a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    }
628a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    return NO_ERROR;
629a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland}
630a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
6312735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurentuint32_t AudioHardware::getInputSampleRate(uint32_t sampleRate)
6327510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project{
6332735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    uint32_t i;
6342735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    uint32_t prevDelta;
6352735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    uint32_t delta;
6362735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent
6372735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    for (i = 0, prevDelta = 0xFFFFFFFF; i < sizeof(inputSamplingRates)/sizeof(uint32_t); i++, prevDelta = delta) {
6382735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        delta = abs(sampleRate - inputSamplingRates[i]);
6392735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        if (delta > prevDelta) break;
6407510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    }
6412735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    // i is always > 0 here
6422735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    return inputSamplingRates[i-1];
6437510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project}
6447510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project
64511c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent// getActiveInput_l() must be called with mLock held
64611c6a166fa684a2e44d22a142aad106f74a9409fEric LaurentAudioHardware::AudioStreamInMSM72xx *AudioHardware::getActiveInput_l()
64711c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent{
64811c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent    for (size_t i = 0; i < mInputs.size(); i++) {
64911c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent        // return first input found not being in standby mode
65011c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent        // as only one input can be in this state
65111c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent        if (mInputs[i]->state() > AudioStreamInMSM72xx::AUDIO_INPUT_CLOSED) {
65211c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent            return mInputs[i];
65311c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent        }
65411c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent    }
65511c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent
65611c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent    return NULL;
65711c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent}
658a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland// ----------------------------------------------------------------------------
659a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
660a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian SwetlandAudioHardware::AudioStreamOutMSM72xx::AudioStreamOutMSM72xx() :
6612735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    mHardware(0), mFd(-1), mStartCount(0), mRetryCount(0), mStandby(true), mDevices(0)
662a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland{
663a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland}
664a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
665a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetlandstatus_t AudioHardware::AudioStreamOutMSM72xx::set(
6662735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        AudioHardware* hw, uint32_t devices, int *pFormat, uint32_t *pChannels, uint32_t *pRate)
667a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland{
6682735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    int lFormat = pFormat ? *pFormat : 0;
6692735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    uint32_t lChannels = pChannels ? *pChannels : 0;
6702735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    uint32_t lRate = pRate ? *pRate : 0;
6712735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent
6722735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    mHardware = hw;
6732735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent
674a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    // fix up defaults
6752735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    if (lFormat == 0) lFormat = format();
6762735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    if (lChannels == 0) lChannels = channels();
6772735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    if (lRate == 0) lRate = sampleRate();
678a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
679a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    // check values
6802735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    if ((lFormat != format()) ||
6812735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        (lChannels != channels()) ||
6822735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        (lRate != sampleRate())) {
6832735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        if (pFormat) *pFormat = format();
6842735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        if (pChannels) *pChannels = channels();
6852735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        if (pRate) *pRate = sampleRate();
686a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        return BAD_VALUE;
6872735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    }
688a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
6892735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    if (pFormat) *pFormat = lFormat;
6902735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    if (pChannels) *pChannels = lChannels;
6912735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    if (pRate) *pRate = lRate;
6922735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent
6932735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    mDevices = devices;
694a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
695a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    return NO_ERROR;
696a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland}
697a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
698a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian SwetlandAudioHardware::AudioStreamOutMSM72xx::~AudioStreamOutMSM72xx()
699a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland{
70034a989e873c51c4fbef5beaf068283e82f41ff29Eric Laurent    if (mFd >= 0) close(mFd);
701a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland}
702a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
703a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetlandssize_t AudioHardware::AudioStreamOutMSM72xx::write(const void* buffer, size_t bytes)
704a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland{
705f9452ed4a7c7bbde537f3f2690fc124e5a1beaffSteve Block    // ALOGD("AudioStreamOutMSM72xx::write(%p, %u)", buffer, bytes);
706a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    status_t status = NO_INIT;
707a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    size_t count = bytes;
708a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    const uint8_t* p = static_cast<const uint8_t*>(buffer);
709a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
7107510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    if (mStandby) {
711a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
712a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        // open driver
71322f2554680715d1ea993409217a4a21f652ef130Steve Block        ALOGV("open driver");
714a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        status = ::open("/dev/msm_pcm_out", O_RDWR);
715a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        if (status < 0) {
716c3dee7890047bad1136078f0f6e2b6d1a9a24947Steve Block            ALOGE("Cannot open /dev/msm_pcm_out errno: %d", errno);
717a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland            goto Error;
718a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        }
719a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        mFd = status;
720a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
721a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        // configuration
72222f2554680715d1ea993409217a4a21f652ef130Steve Block        ALOGV("get config");
723a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        struct msm_audio_config config;
724a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        status = ioctl(mFd, AUDIO_GET_CONFIG, &config);
725a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        if (status < 0) {
726c3dee7890047bad1136078f0f6e2b6d1a9a24947Steve Block            ALOGE("Cannot read config");
727a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland            goto Error;
728a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        }
729a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
73022f2554680715d1ea993409217a4a21f652ef130Steve Block        ALOGV("set config");
7312735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        config.channel_count = AudioSystem::popCount(channels());
732a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        config.sample_rate = sampleRate();
733a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        config.buffer_size = bufferSize();
7347510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project        config.buffer_count = AUDIO_HW_NUM_OUT_BUF;
735a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        config.codec_type = CODEC_TYPE_PCM;
736a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        status = ioctl(mFd, AUDIO_SET_CONFIG, &config);
737a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        if (status < 0) {
738c3dee7890047bad1136078f0f6e2b6d1a9a24947Steve Block            ALOGE("Cannot set config");
739a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland            goto Error;
740a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        }
741a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
74222f2554680715d1ea993409217a4a21f652ef130Steve Block        ALOGV("buffer_size: %u", config.buffer_size);
74322f2554680715d1ea993409217a4a21f652ef130Steve Block        ALOGV("buffer_count: %u", config.buffer_count);
74422f2554680715d1ea993409217a4a21f652ef130Steve Block        ALOGV("channel_count: %u", config.channel_count);
74522f2554680715d1ea993409217a4a21f652ef130Steve Block        ALOGV("sample_rate: %u", config.sample_rate);
746a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
747a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        // fill 2 buffers before AUDIO_START
7487510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project        mStartCount = AUDIO_HW_NUM_OUT_BUF;
7497510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project        mStandby = false;
750a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    }
751a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
752a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    while (count) {
753a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        ssize_t written = ::write(mFd, p, count);
754a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        if (written >= 0) {
755a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland            count -= written;
756a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland            p += written;
757a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        } else {
758a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland            if (errno != EAGAIN) return written;
759a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland            mRetryCount++;
7603fb19cd0b6534ef9d36f8ac0c5ddbdc73ed92a26Steve Block            ALOGW("EAGAIN - retry");
761a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        }
762a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    }
763a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
764a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    // start audio after we fill 2 buffers
765a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    if (mStartCount) {
766a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        if (--mStartCount == 0) {
767a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland            ioctl(mFd, AUDIO_START, 0);
768a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        }
769a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    }
770a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    return bytes;
771a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
772a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian SwetlandError:
77334a989e873c51c4fbef5beaf068283e82f41ff29Eric Laurent    if (mFd >= 0) {
774a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        ::close(mFd);
775a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        mFd = -1;
776a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    }
777a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    // Simulate audio output timing in case of error
7787510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    usleep(bytes * 1000000 / frameSize() / sampleRate());
779a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
780a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    return status;
781a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland}
782a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
783a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetlandstatus_t AudioHardware::AudioStreamOutMSM72xx::standby()
784a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland{
785a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    status_t status = NO_ERROR;
78634a989e873c51c4fbef5beaf068283e82f41ff29Eric Laurent    if (!mStandby && mFd >= 0) {
787a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        ::close(mFd);
788a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        mFd = -1;
789a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    }
7907510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    mStandby = true;
791a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    return status;
792a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland}
793a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
794a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetlandstatus_t AudioHardware::AudioStreamOutMSM72xx::dump(int fd, const Vector<String16>& args)
795a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland{
796a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    const size_t SIZE = 256;
797a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    char buffer[SIZE];
798a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    String8 result;
799a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    result.append("AudioStreamOutMSM72xx::dump\n");
800a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate());
801a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    result.append(buffer);
802a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
803a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    result.append(buffer);
8042735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    snprintf(buffer, SIZE, "\tchannels: %d\n", channels());
805a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    result.append(buffer);
806a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    snprintf(buffer, SIZE, "\tformat: %d\n", format());
807a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    result.append(buffer);
808a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    snprintf(buffer, SIZE, "\tmHardware: %p\n", mHardware);
809a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    result.append(buffer);
810a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    snprintf(buffer, SIZE, "\tmFd: %d\n", mFd);
811a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    result.append(buffer);
812a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    snprintf(buffer, SIZE, "\tmStartCount: %d\n", mStartCount);
813a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    result.append(buffer);
814a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    snprintf(buffer, SIZE, "\tmRetryCount: %d\n", mRetryCount);
815a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    result.append(buffer);
8167510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    snprintf(buffer, SIZE, "\tmStandby: %s\n", mStandby? "true": "false");
8177510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    result.append(buffer);
818a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    ::write(fd, result.string(), result.size());
819a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    return NO_ERROR;
820a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland}
821a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
8227510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Projectbool AudioHardware::AudioStreamOutMSM72xx::checkStandby()
8237510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project{
8247510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    return mStandby;
8257510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project}
8267510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project
8272735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent
8282735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurentstatus_t AudioHardware::AudioStreamOutMSM72xx::setParameters(const String8& keyValuePairs)
8292735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent{
8302735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    AudioParameter param = AudioParameter(keyValuePairs);
8312735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    String8 key = String8(AudioParameter::keyRouting);
8322735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    status_t status = NO_ERROR;
8332735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    int device;
83422f2554680715d1ea993409217a4a21f652ef130Steve Block    ALOGV("AudioStreamOutMSM72xx::setParameters() %s", keyValuePairs.string());
8352735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent
8362735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    if (param.getInt(key, device) == NO_ERROR) {
8372735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        mDevices = device;
83822f2554680715d1ea993409217a4a21f652ef130Steve Block        ALOGV("set output routing %x", mDevices);
83911c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent        status = mHardware->doRouting();
8402735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        param.remove(key);
8412735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    }
8422735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent
8432735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    if (param.size()) {
8442735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        status = BAD_VALUE;
8452735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    }
8462735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    return status;
8472735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent}
8482735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent
8492735e3b55bdaf33cfd0dbaa1b914231243933e92Eric LaurentString8 AudioHardware::AudioStreamOutMSM72xx::getParameters(const String8& keys)
8502735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent{
8512735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    AudioParameter param = AudioParameter(keys);
8522735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    String8 value;
8532735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    String8 key = String8(AudioParameter::keyRouting);
8542735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent
8552735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    if (param.get(key, value) == NO_ERROR) {
85622f2554680715d1ea993409217a4a21f652ef130Steve Block        ALOGV("get routing %x", mDevices);
8572735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        param.addInt(key, (int)mDevices);
8582735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    }
8592735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent
86022f2554680715d1ea993409217a4a21f652ef130Steve Block    ALOGV("AudioStreamOutMSM72xx::getParameters() %s", param.toString().string());
8612735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    return param.toString();
8622735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent}
8632735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent
8643b9744cccd99fd9f32ae3b99fbc8d6898b118a43Eric Laurentstatus_t AudioHardware::AudioStreamOutMSM72xx::getRenderPosition(uint32_t *dspFrames)
8653b9744cccd99fd9f32ae3b99fbc8d6898b118a43Eric Laurent{
8663b9744cccd99fd9f32ae3b99fbc8d6898b118a43Eric Laurent    //TODO: enable when supported by driver
8673b9744cccd99fd9f32ae3b99fbc8d6898b118a43Eric Laurent    return INVALID_OPERATION;
8683b9744cccd99fd9f32ae3b99fbc8d6898b118a43Eric Laurent}
8692735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent
870a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland// ----------------------------------------------------------------------------
871a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
872a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian SwetlandAudioHardware::AudioStreamInMSM72xx::AudioStreamInMSM72xx() :
8737510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    mHardware(0), mFd(-1), mState(AUDIO_INPUT_CLOSED), mRetryCount(0),
8742735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    mFormat(AUDIO_HW_IN_FORMAT), mChannels(AUDIO_HW_IN_CHANNELS),
8757510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    mSampleRate(AUDIO_HW_IN_SAMPLERATE), mBufferSize(AUDIO_HW_IN_BUFFERSIZE),
8762735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    mAcoustics((AudioSystem::audio_in_acoustics)0), mDevices(0)
877a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland{
878a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland}
879a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
880a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetlandstatus_t AudioHardware::AudioStreamInMSM72xx::set(
8812735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        AudioHardware* hw, uint32_t devices, int *pFormat, uint32_t *pChannels, uint32_t *pRate,
8827510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project        AudioSystem::audio_in_acoustics acoustic_flags)
883a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland{
8842735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    if (pFormat == 0 || *pFormat != AUDIO_HW_IN_FORMAT) {
8852735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        *pFormat = AUDIO_HW_IN_FORMAT;
8862735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        return BAD_VALUE;
8872735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    }
8882735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    if (pRate == 0) {
8892735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        return BAD_VALUE;
8902735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    }
8912735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    uint32_t rate = hw->getInputSampleRate(*pRate);
8922735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    if (rate != *pRate) {
8932735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        *pRate = rate;
8942735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        return BAD_VALUE;
8952735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    }
8962735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent
8972735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    if (pChannels == 0 || (*pChannels != AudioSystem::CHANNEL_IN_MONO &&
8982735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        *pChannels != AudioSystem::CHANNEL_IN_STEREO)) {
8992735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        *pChannels = AUDIO_HW_IN_CHANNELS;
9002735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        return BAD_VALUE;
9012735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    }
9022735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent
9032735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    mHardware = hw;
9042735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent
90522f2554680715d1ea993409217a4a21f652ef130Steve Block    ALOGV("AudioStreamInMSM72xx::set(%d, %d, %u)", *pFormat, *pChannels, *pRate);
906a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    if (mFd >= 0) {
907c3dee7890047bad1136078f0f6e2b6d1a9a24947Steve Block        ALOGE("Audio record already open");
908a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        return -EPERM;
909a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    }
910a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
911a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    // open audio input device
912a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    status_t status = ::open("/dev/msm_pcm_in", O_RDWR);
913a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    if (status < 0) {
914c3dee7890047bad1136078f0f6e2b6d1a9a24947Steve Block        ALOGE("Cannot open /dev/msm_pcm_in errno: %d", errno);
915a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        goto Error;
916a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    }
917a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    mFd = status;
918a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
919a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    // configuration
92022f2554680715d1ea993409217a4a21f652ef130Steve Block    ALOGV("get config");
921a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    struct msm_audio_config config;
922a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    status = ioctl(mFd, AUDIO_GET_CONFIG, &config);
923a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    if (status < 0) {
924c3dee7890047bad1136078f0f6e2b6d1a9a24947Steve Block        ALOGE("Cannot read config");
925a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        goto Error;
926a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    }
927a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
92822f2554680715d1ea993409217a4a21f652ef130Steve Block    ALOGV("set config");
9292735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    config.channel_count = AudioSystem::popCount(*pChannels);
9302735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    config.sample_rate = *pRate;
931a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    config.buffer_size = bufferSize();
932a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    config.buffer_count = 2;
933a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    config.codec_type = CODEC_TYPE_PCM;
934a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    status = ioctl(mFd, AUDIO_SET_CONFIG, &config);
935a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    if (status < 0) {
936c3dee7890047bad1136078f0f6e2b6d1a9a24947Steve Block        ALOGE("Cannot set config");
9372735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        if (ioctl(mFd, AUDIO_GET_CONFIG, &config) == 0) {
9382735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent            if (config.channel_count == 1) {
9392735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent                *pChannels = AudioSystem::CHANNEL_IN_MONO;
9402735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent            } else {
9412735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent                *pChannels = AudioSystem::CHANNEL_IN_STEREO;
9422735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent            }
9432735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent            *pRate = config.sample_rate;
9442735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        }
945a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        goto Error;
946a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    }
947a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
94822f2554680715d1ea993409217a4a21f652ef130Steve Block    ALOGV("confirm config");
949a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    status = ioctl(mFd, AUDIO_GET_CONFIG, &config);
950a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    if (status < 0) {
951c3dee7890047bad1136078f0f6e2b6d1a9a24947Steve Block        ALOGE("Cannot read config");
952a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        goto Error;
953a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    }
95422f2554680715d1ea993409217a4a21f652ef130Steve Block    ALOGV("buffer_size: %u", config.buffer_size);
95522f2554680715d1ea993409217a4a21f652ef130Steve Block    ALOGV("buffer_count: %u", config.buffer_count);
95622f2554680715d1ea993409217a4a21f652ef130Steve Block    ALOGV("channel_count: %u", config.channel_count);
95722f2554680715d1ea993409217a4a21f652ef130Steve Block    ALOGV("sample_rate: %u", config.sample_rate);
958a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
9592735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    mDevices = devices;
9602735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    mFormat = AUDIO_HW_IN_FORMAT;
9612735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    mChannels = *pChannels;
9627510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    mSampleRate = config.sample_rate;
9637510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    mBufferSize = config.buffer_size;
9647510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project
9652735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    //mHardware->setMicMute_nosync(false);
9667510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    mState = AUDIO_INPUT_OPENED;
967d498a9ce9863bd979d3403473568c6e1e38b7daeBrian Swetland
968d498a9ce9863bd979d3403473568c6e1e38b7daeBrian Swetland    if (!acoustic)
969d498a9ce9863bd979d3403473568c6e1e38b7daeBrian Swetland        return NO_ERROR;
970d498a9ce9863bd979d3403473568c6e1e38b7daeBrian Swetland
9712735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    audpre_index = calculate_audpre_table_index(mSampleRate);
9727510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    tx_iir_index = (audpre_index * 2) + (hw->checkOutputStandby() ? 0 : 1);
973f9452ed4a7c7bbde537f3f2690fc124e5a1beaffSteve Block    ALOGD("audpre_index = %d, tx_iir_index = %d\n", audpre_index, tx_iir_index);
9747510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project
9757510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    /**
9767510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project     * If audio-preprocessing failed, we should not block record.
9777510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project     */
9787510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    int (*msm72xx_set_audpre_params)(int, int);
9797510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    msm72xx_set_audpre_params = (int (*)(int, int))::dlsym(acoustic, "msm72xx_set_audpre_params");
9807510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    status = msm72xx_set_audpre_params(audpre_index, tx_iir_index);
9817510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    if (status < 0)
982c3dee7890047bad1136078f0f6e2b6d1a9a24947Steve Block        ALOGE("Cannot set audpre parameters");
9837510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project
9847510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    int (*msm72xx_enable_audpre)(int, int, int);
9857510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    msm72xx_enable_audpre = (int (*)(int, int, int))::dlsym(acoustic, "msm72xx_enable_audpre");
9867510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    mAcoustics = acoustic_flags;
9877510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    status = msm72xx_enable_audpre((int)acoustic_flags, audpre_index, tx_iir_index);
9887510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    if (status < 0)
989c3dee7890047bad1136078f0f6e2b6d1a9a24947Steve Block        ALOGE("Cannot enable audpre");
9907510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project
991a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    return NO_ERROR;
992a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
993a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian SwetlandError:
99434a989e873c51c4fbef5beaf068283e82f41ff29Eric Laurent    if (mFd >= 0) {
995a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        ::close(mFd);
996a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        mFd = -1;
997a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    }
998a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    return status;
999a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland}
1000a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
1001a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian SwetlandAudioHardware::AudioStreamInMSM72xx::~AudioStreamInMSM72xx()
1002a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland{
100322f2554680715d1ea993409217a4a21f652ef130Steve Block    ALOGV("AudioStreamInMSM72xx destructor");
10042735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    standby();
1005a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland}
1006a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
1007a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetlandssize_t AudioHardware::AudioStreamInMSM72xx::read( void* buffer, ssize_t bytes)
1008a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland{
100922f2554680715d1ea993409217a4a21f652ef130Steve Block    ALOGV("AudioStreamInMSM72xx::read(%p, %ld)", buffer, bytes);
10107510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    if (!mHardware) return -1;
1011a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
1012a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    size_t count = bytes;
1013a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    uint8_t* p = static_cast<uint8_t*>(buffer);
1014a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
10157510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    if (mState < AUDIO_INPUT_OPENED) {
1016d066973de83218a24c773e5de04d10ed2d730873Eric Laurent        Mutex::Autolock lock(mHardware->mLock);
10172735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        if (set(mHardware, mDevices, &mFormat, &mChannels, &mSampleRate, mAcoustics) != NO_ERROR) {
10187510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project            return -1;
10197510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project        }
10207510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    }
10212735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent
10227510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    if (mState < AUDIO_INPUT_STARTED) {
102311c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent        mState = AUDIO_INPUT_STARTED;
102411c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent        // force routing to input device
102511c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent        mHardware->clearCurDevice();
102611c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent        mHardware->doRouting();
1027a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        if (ioctl(mFd, AUDIO_START, 0)) {
1028c3dee7890047bad1136078f0f6e2b6d1a9a24947Steve Block            ALOGE("Error starting record");
102911c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent            standby();
1030a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland            return -1;
1031a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        }
1032a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    }
1033a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
1034a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    while (count) {
1035a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        ssize_t bytesRead = ::read(mFd, buffer, count);
1036a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        if (bytesRead >= 0) {
1037a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland            count -= bytesRead;
1038a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland            p += bytesRead;
1039a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        } else {
1040a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland            if (errno != EAGAIN) return bytesRead;
1041a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland            mRetryCount++;
10423fb19cd0b6534ef9d36f8ac0c5ddbdc73ed92a26Steve Block            ALOGW("EAGAIN - retrying");
1043a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland        }
1044a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    }
1045a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    return bytes;
1046a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland}
1047a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
10487510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Projectstatus_t AudioHardware::AudioStreamInMSM72xx::standby()
10497510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project{
10507510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    if (mState > AUDIO_INPUT_CLOSED) {
105134a989e873c51c4fbef5beaf068283e82f41ff29Eric Laurent        if (mFd >= 0) {
10527510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project            ::close(mFd);
10537510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project            mFd = -1;
10547510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project        }
10557510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project        mState = AUDIO_INPUT_CLOSED;
10567510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    }
105711c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent    if (!mHardware) return -1;
105811c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent    // restore output routing if necessary
105911c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent    mHardware->clearCurDevice();
106011c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent    mHardware->doRouting();
10617510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    return NO_ERROR;
10627510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project}
10637510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project
1064a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetlandstatus_t AudioHardware::AudioStreamInMSM72xx::dump(int fd, const Vector<String16>& args)
1065a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland{
1066a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    const size_t SIZE = 256;
1067a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    char buffer[SIZE];
1068a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    String8 result;
1069a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    result.append("AudioStreamInMSM72xx::dump\n");
1070a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate());
1071a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    result.append(buffer);
1072a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
1073a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    result.append(buffer);
10742735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    snprintf(buffer, SIZE, "\tchannels: %d\n", channels());
1075a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    result.append(buffer);
1076a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    snprintf(buffer, SIZE, "\tformat: %d\n", format());
1077a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    result.append(buffer);
1078a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    snprintf(buffer, SIZE, "\tmHardware: %p\n", mHardware);
1079a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    result.append(buffer);
1080a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    snprintf(buffer, SIZE, "\tmFd count: %d\n", mFd);
1081a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    result.append(buffer);
10827510aaf4b3a3c545d943b09e0fb9f56ea2fc5e24The Android Open Source Project    snprintf(buffer, SIZE, "\tmState: %d\n", mState);
1083a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    result.append(buffer);
1084a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    snprintf(buffer, SIZE, "\tmRetryCount: %d\n", mRetryCount);
1085a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    result.append(buffer);
1086a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    ::write(fd, result.string(), result.size());
1087a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    return NO_ERROR;
1088a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland}
1089a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
10902735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurentstatus_t AudioHardware::AudioStreamInMSM72xx::setParameters(const String8& keyValuePairs)
10912735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent{
10922735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    AudioParameter param = AudioParameter(keyValuePairs);
10932735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    String8 key = String8(AudioParameter::keyRouting);
10942735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    status_t status = NO_ERROR;
10952735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    int device;
109622f2554680715d1ea993409217a4a21f652ef130Steve Block    ALOGV("AudioStreamInMSM72xx::setParameters() %s", keyValuePairs.string());
10972735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent
10982735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    if (param.getInt(key, device) == NO_ERROR) {
109922f2554680715d1ea993409217a4a21f652ef130Steve Block        ALOGV("set input routing %x", device);
11002735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        if (device & (device - 1)) {
11012735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent            status = BAD_VALUE;
11022735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        } else {
11032735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent            mDevices = device;
110411c6a166fa684a2e44d22a142aad106f74a9409fEric Laurent            status = mHardware->doRouting();
11052735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        }
11062735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        param.remove(key);
11072735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    }
11082735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent
11092735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    if (param.size()) {
11102735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        status = BAD_VALUE;
11112735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    }
11122735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    return status;
11132735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent}
11142735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent
11152735e3b55bdaf33cfd0dbaa1b914231243933e92Eric LaurentString8 AudioHardware::AudioStreamInMSM72xx::getParameters(const String8& keys)
11162735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent{
11172735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    AudioParameter param = AudioParameter(keys);
11182735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    String8 value;
11192735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    String8 key = String8(AudioParameter::keyRouting);
11202735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent
11212735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    if (param.get(key, value) == NO_ERROR) {
112222f2554680715d1ea993409217a4a21f652ef130Steve Block        ALOGV("get routing %x", mDevices);
11232735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent        param.addInt(key, (int)mDevices);
11242735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    }
11252735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent
112622f2554680715d1ea993409217a4a21f652ef130Steve Block    ALOGV("AudioStreamInMSM72xx::getParameters() %s", param.toString().string());
11272735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent    return param.toString();
11282735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent}
11292735e3b55bdaf33cfd0dbaa1b914231243933e92Eric Laurent
1130a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland// ----------------------------------------------------------------------------
1131a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
1132a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetlandextern "C" AudioHardwareInterface* createAudioHardware(void) {
1133a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland    return new AudioHardware();
1134a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland}
1135a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland
1136a3a947cc7e1bfaf7b5cfc85b71f602edf562836Brian Swetland}; // namespace android
1137