android13/hardware/rockchip/audio/legacy_hal/AudioHardware.cpp

2133 lines
65 KiB
C++
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
** Copyright 2010, The Android Open-Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
//#define LOG_NDEBUG 0
#define LOG_TAG "AudioHardware"
#include <utils/Log.h>
#include <utils/String8.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/resource.h>
#include <dlfcn.h>
#include <fcntl.h>
#include "AudioHardware.h"
#include <media/AudioRecord.h>
#include <hardware_legacy/power.h>
#include <cutils/properties.h>
#include "AudioUsbAudioHardware.h"
extern "C" {
#include "alsa_audio.h"
}
//when you want write the output data ,you can open this maroc.
//#define DEBUG_ALSA_OUT
//#define DEBUG_ALSA_IN
#ifdef TARGET_RK2928
#define AMP_ENABLE_TIME 230//TARGET_RK2928 codec use amplifier enable time (Unit:ms)
#endif
namespace android_audio_legacy {
const uint32_t AudioHardware::inputSamplingRates[] = {
8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
};
// trace driver operations for dump
//
#define DRIVER_TRACE
enum {
DRV_NONE,
DRV_PCM_OPEN,
DRV_PCM_CLOSE,
DRV_PCM_WRITE,
DRV_PCM_READ,
DRV_MIXER_OPEN,
DRV_MIXER_CLOSE,
DRV_MIXER_GET,
DRV_MIXER_SEL
};
#ifdef DRIVER_TRACE
#define TRACE_DRIVER_IN(op) mDriverOp = op;
#define TRACE_DRIVER_OUT mDriverOp = DRV_NONE;
#else
#define TRACE_DRIVER_IN(op)
#define TRACE_DRIVER_OUT
#endif
// ----------------------------------------------------------------------------
AudioHardware::AudioHardware() :
mInit(false),
mMicMute(false),
mPcm(NULL),
mPcmOpenCnt(0),
mMixerOpenCnt(0),
mInCallAudioMode(false),
mVoipAudioMode(false),
mInputSource("Default"),
mBluetoothNrec(true),
mSecRilLibHandle(NULL),
mRilClient(0),
mActivatedCP(false),
mDriverOp(DRV_NONE)
{
char pname[40];
snprintf(pname, sizeof(pname), AUDIO_HAL_VERSION_NAME);
property_set(pname, AUDIO_HAL_VERSION);
loadRILD();
mInit = true;
TRACE_DRIVER_IN(DRV_MIXER_OPEN)
route_init();
TRACE_DRIVER_OUT
}
AudioHardware::~AudioHardware()
{
for (size_t index = 0; index < mInputs.size(); index++) {
closeInputStream(mInputs[index].get());
}
mInputs.clear();
closeOutputStream((android_audio_legacy::AudioStreamOut*)mOutput.get());
if (mPcm) {
TRACE_DRIVER_IN(DRV_PCM_CLOSE)
route_pcm_close(PLAYBACK_OFF_ROUTE);
TRACE_DRIVER_OUT
}
TRACE_DRIVER_IN(DRV_MIXER_CLOSE)
route_uninit();
TRACE_DRIVER_OUT
mInit = false;
}
status_t AudioHardware::initCheck()
{
return mInit ? NO_ERROR : NO_INIT;
}
void AudioHardware::loadRILD(void)
{
/*mSecRilLibHandle = dlopen("libsecril-client.so", RTLD_NOW);
if (mSecRilLibHandle) {
ALOGV("libsecril-client.so is loaded");
openClientRILD = (HRilClient (*)(void))
dlsym(mSecRilLibHandle, "OpenClient_RILD");
disconnectRILD = (int (*)(HRilClient))
dlsym(mSecRilLibHandle, "Disconnect_RILD");
closeClientRILD = (int (*)(HRilClient))
dlsym(mSecRilLibHandle, "CloseClient_RILD");
isConnectedRILD = (int (*)(HRilClient))
dlsym(mSecRilLibHandle, "isConnected_RILD");
connectRILD = (int (*)(HRilClient))
dlsym(mSecRilLibHandle, "Connect_RILD");
setCallVolume = (int (*)(HRilClient, SoundType, int))
dlsym(mSecRilLibHandle, "SetCallVolume");
setCallAudioPath = (int (*)(HRilClient, AudioPath))
dlsym(mSecRilLibHandle, "SetCallAudioPath");
setCallClockSync = (int (*)(HRilClient, SoundClockCondition))
dlsym(mSecRilLibHandle, "SetCallClockSync");
if (!openClientRILD || !disconnectRILD || !closeClientRILD ||
!isConnectedRILD || !connectRILD ||
!setCallVolume || !setCallAudioPath || !setCallClockSync) {
ALOGE("Can't load all functions from libsecril-client.so");
dlclose(mSecRilLibHandle);
mSecRilLibHandle = NULL;
} else {
mRilClient = openClientRILD();
if (!mRilClient) {
ALOGE("OpenClient_RILD() error");
dlclose(mSecRilLibHandle);
mSecRilLibHandle = NULL;
}
}
} else {
ALOGE("Can't load libsecril-client.so");
}*/
}
status_t AudioHardware::connectRILDIfRequired(void)
{
if (!mSecRilLibHandle) {
ALOGE("connectIfRequired() lib is not loaded");
return INVALID_OPERATION;
}
if (isConnectedRILD(mRilClient)) {
return OK;
}
if (connectRILD(mRilClient) != RIL_CLIENT_ERR_SUCCESS) {
ALOGE("Connect_RILD() error");
return INVALID_OPERATION;
}
return OK;
}
android_audio_legacy::AudioStreamOut* AudioHardware::openOutputStream(
uint32_t devices, int *format, uint32_t *channels,
uint32_t *sampleRate, status_t *status)
{
android::sp <AudioStreamOutALSA> out;
status_t rc;
{ // scope for the lock
android::Mutex::Autolock lock(mLock);
// only one output stream allowed
if (mOutput != 0) {
if (status) {
*status = INVALID_OPERATION;
}
return NULL;
}
out = new AudioStreamOutALSA();
rc = out->set(this, devices, format, channels, sampleRate);
if (rc == NO_ERROR) {
mOutput = out;
}
}
if (rc != NO_ERROR) {
if (out != 0) {
out.clear();
}
}
if (status) {
*status = rc;
}
return out.get();
}
// default implementation calls its "without flags" counterpart
android_audio_legacy::AudioStreamOut* AudioHardware::openOutputStreamWithFlags(uint32_t devices,
audio_output_flags_t flags,
int *format,
uint32_t *channels,
uint32_t *sampleRate,
status_t *status)
{
return openOutputStream(devices, format, channels, sampleRate, status);
}
status_t AudioHardware::setMasterMute(bool muted){
return INVALID_OPERATION;
}
int AudioHardware::createAudioPatch(unsigned int num_sources,
const struct audio_port_config *sources,
unsigned int num_sinks,
const struct audio_port_config *sinks,
audio_patch_handle_t *handle){
return 0;
}
int AudioHardware::releaseAudioPatch(audio_patch_handle_t handle){
return 0;
}
int AudioHardware::getAudioPort(struct audio_port *port) {
return 0;
}
int AudioHardware::setAudioPortConfig(const struct audio_port_config *config) {
return 0;
}
void AudioHardware::closeOutputStream(android_audio_legacy::AudioStreamOut* out) {
android::sp <AudioStreamOutALSA> spOut;
{
android::Mutex::Autolock lock(mLock);
if (mOutput == 0 || mOutput.get() != out) {
ALOGW("Attempt to close invalid output stream");
return;
}
spOut = mOutput;
mOutput.clear();
}
spOut.clear();
}
android_audio_legacy::AudioStreamIn* AudioHardware::openInputStream(
uint32_t devices, int *format, uint32_t *channels,
uint32_t *sampleRate, status_t *status,
android_audio_legacy::AudioSystem::audio_in_acoustics acoustic_flags)
{
// check for valid input source
if (!android_audio_legacy::AudioSystem::isInputDevice((android_audio_legacy::AudioSystem::audio_devices)devices)) {
if (status) {
*status = BAD_VALUE;
}
return NULL;
}
status_t rc = NO_ERROR;
android::sp <AudioStreamInALSA> in;
{ // scope for the lock
android::Mutex::Autolock lock(mLock);
in = new AudioStreamInALSA();
rc = in->set(this, devices, format, channels, sampleRate, acoustic_flags);
if (rc == NO_ERROR) {
mInputs.add(in);
}
}
if (rc != NO_ERROR) {
if (in != 0) {
in.clear();
}
}
if (status) {
*status = rc;
}
ALOGV("AudioHardware::openInputStream()%p", in.get());
return in.get();
}
void AudioHardware::closeInputStream(AudioStreamIn* in) {
android::sp<AudioStreamInALSA> spIn;
{
android::Mutex::Autolock lock(mLock);
ssize_t index = mInputs.indexOf((AudioStreamInALSA *)in);
if (index < 0) {
ALOGW("Attempt to close invalid input stream");
return;
}
spIn = mInputs[index];
mInputs.removeAt(index);
}
ALOGV("AudioHardware::closeInputStream()%p", in);
spIn.clear();
}
status_t AudioHardware::setMode(int mode)
{
android::sp<AudioStreamOutALSA> spOut;
android::sp<AudioStreamInALSA> spIn;
status_t status;
// bump thread priority to speed up mutex acquisition
int priority = getpriority(PRIO_PROCESS, 0);
setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_URGENT_AUDIO);
// Mutex acquisition order is always out -> in -> hw
android::AutoMutex lock(mLock);
spOut = mOutput;
while (spOut != 0) {
if (!spOut->checkStandby()) {
int cnt = spOut->standbyCnt();
mLock.unlock();
spOut->lock();
mLock.lock();
// make sure that another thread did not change output state while the
// mutex is released
if ((spOut == mOutput) && (cnt == spOut->standbyCnt())) {
break;
}
spOut->unlock();
spOut = mOutput;
} else {
spOut.clear();
}
}
spIn = getActiveInput_l();
while (spIn != 0) {
int cnt = spIn->standbyCnt();
mLock.unlock();
spIn->lock();
mLock.lock();
// make sure that another thread did not change input state while the
// mutex is released
if ((spIn == getActiveInput_l()) && (cnt == spIn->standbyCnt())) {
break;
}
spIn->unlock();
spIn = getActiveInput_l();
}
setpriority(PRIO_PROCESS, 0, priority);
int prevMode = mMode;
status = AudioHardwareBase::setMode(mode);
ALOGV("setMode() : new %d, old %d", mMode, prevMode);
if (status == NO_ERROR) {
// activate call clock in radio when entering in call or ringtone mode
if (prevMode == AudioSystem::MODE_NORMAL)
{
if ((!mActivatedCP) && (mSecRilLibHandle) && (connectRILDIfRequired() == OK)) {
setCallClockSync(mRilClient, SOUND_CLOCK_START);
mActivatedCP = true;
}
}
//close voip before incall opening
if ((mMode != AudioSystem::MODE_IN_COMMUNICATION)
&& mVoipAudioMode) {
setInputSource_l(mInputSource);
TRACE_DRIVER_IN(DRV_MIXER_SEL)
route_set_controls(VOIP_OFF_ROUTE);//close voip
TRACE_DRIVER_OUT
mVoipAudioMode = false;
}
if (mMode == AudioSystem::MODE_IN_CALL && !mInCallAudioMode) {
//sleep latency time to finish music
if (mOutput != 0) {
mLock.unlock();
usleep((mOutput->latency() + 70) * 1000);
mLock.lock();
}
ALOGV("setMode() openPcmOut_l()");
openPcmOut_l();
setInputSource_l(String8("Default"));
if (mOutput != 0 && AudioSystem::popCount(mOutput->device()) == 1)
setIncallPath_l(mOutput->device());
mInCallAudioMode = true;
}
if (mMode != AudioSystem::MODE_IN_CALL && mInCallAudioMode) {
setInputSource_l(mInputSource);
TRACE_DRIVER_IN(DRV_MIXER_SEL)
route_pcm_close(INCALL_OFF_ROUTE);//close incall
TRACE_DRIVER_OUT
ALOGV("setMode() closePcmOut_l()");
closePcmOut_l();
mInCallAudioMode = false;
}
if (mMode == AudioSystem::MODE_IN_COMMUNICATION && !mVoipAudioMode) {
setInputSource_l(String8("Default"));
if (mOutput != 0) {
mOutput->doStandby_l();
}
mVoipAudioMode = true;
}
if (mMode == AudioSystem::MODE_NORMAL) {
if(mActivatedCP)
mActivatedCP = false;
}
}
if (spIn != 0) {
spIn->unlock();
}
if (spOut != 0) {
spOut->unlock();
}
return status;
}
status_t AudioHardware::setMicMute(bool state)
{
ALOGV("setMicMute(%d) mMicMute %d", state, mMicMute);
android::sp<AudioStreamInALSA> spIn;
{
android::AutoMutex lock(mLock);
if (mMicMute != state) {
mMicMute = state;
// in call mute is handled by RIL
if (mMode != AudioSystem::MODE_IN_CALL) {
spIn = getActiveInput_l();
}
}
}
if (spIn != 0) {
spIn->setGain(mMicMute?0.0:1.0);
}
return NO_ERROR;
}
status_t AudioHardware::getMicMute(bool* state)
{
*state = mMicMute;
return NO_ERROR;
}
status_t AudioHardware::setParameters(const String8& keyValuePairs)
{
AudioParameter param = AudioParameter(keyValuePairs);
String8 value;
String8 key;
const char BT_NREC_KEY[] = "bt_headset_nrec";
const char BT_NREC_VALUE_ON[] = "on";
key = String8(BT_NREC_KEY);
if (param.get(key, value) == NO_ERROR) {
if (value == BT_NREC_VALUE_ON) {
mBluetoothNrec = true;
} else {
mBluetoothNrec = false;
ALOGD("Turning noise reduction and echo cancellation off for BT "
"headset");
}
}
return NO_ERROR;
}
String8 AudioHardware::getParameters(const String8& keys)
{
AudioParameter request = AudioParameter(keys);
AudioParameter reply = AudioParameter();
ALOGV("getParameters() %s", keys.string());
return reply.toString();
}
size_t AudioHardware::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
{
if (format != AudioSystem::PCM_16_BIT) {
ALOGW("getInputBufferSize bad format: %d", format);
return 0;
}
if (channelCount < 1 || channelCount > 2) {
ALOGW("getInputBufferSize bad channel count: %d", channelCount);
return 0;
}
if (sampleRate != 8000 && sampleRate != 11025 && sampleRate != 16000 &&
sampleRate != 22050 && sampleRate != 44100 && sampleRate != 48000) {
ALOGW("getInputBufferSize bad sample rate: %d", sampleRate);
return 0;
}
return AudioStreamInALSA::getBufferSize(sampleRate, channelCount);
}
status_t AudioHardware::setVoiceVolume(float volume)
{
ALOGV("setVoiceVolume() volume %f", volume);
android::AutoMutex lock(mLock);
if (AudioSystem::MODE_IN_CALL == mMode) {
uint32_t device = AudioSystem::DEVICE_OUT_EARPIECE;
char ctlName[44] = "";
if (mOutput != 0) {
device = mOutput->device();
}
ALOGV("setVoiceVolume() route(%d)", device);
switch (device) {
case AudioSystem::DEVICE_OUT_EARPIECE:
ALOGV("earpiece call volume");
strcpy(ctlName, "Earpiece Playback Volume");
break;
case AudioSystem::DEVICE_OUT_SPEAKER:
ALOGV("speaker call volume");
strcpy(ctlName, "Speaker Playback Volume");
break;
case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO:
case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
ALOGV("bluetooth call volume");
break;
case AudioSystem::DEVICE_OUT_WIRED_HEADSET:
case AudioSystem::DEVICE_OUT_WIRED_HEADPHONE: // Use receive path with 3 pole headset.
ALOGV("headset call volume");
strcpy(ctlName, "Headphone Playback Volume");
break;
default:
ALOGW("Call volume setting error!!!0x%08x \n", device);
strcpy(ctlName, "Earpiece Playback Volume");
break;
}
TRACE_DRIVER_IN(DRV_MIXER_SEL)
route_set_voice_volume(ctlName, volume);
TRACE_DRIVER_OUT
}
return NO_ERROR;
}
status_t AudioHardware::setMasterVolume(float volume)
{
ALOGV("Set master volume to %f.\n", volume);
// We return an error code here to let the audioflinger do in-software
// volume on top of the maximum volume that we set through the SND API.
// return error - software mixer will handle it
return -1;
}
static const int kDumpLockRetries = 50;
static const int kDumpLockSleep = 20000;
static bool tryLock( android::Mutex& mutex)
{
bool locked = false;
for (int i = 0; i < kDumpLockRetries; ++i) {
if (mutex.tryLock() == NO_ERROR) {
locked = true;
break;
}
usleep(kDumpLockSleep);
}
return locked;
}
status_t AudioHardware::dump(int fd, const Vector<String16>& args)
{
const size_t SIZE = 256;
char buffer[SIZE];
String8 result;
bool locked = tryLock(mLock);
if (!locked) {
snprintf(buffer, SIZE, "\n\tAudioHardware maybe deadlocked\n");
} else {
mLock.unlock();
}
snprintf(buffer, SIZE, "\tInit %s\n", (mInit) ? "OK" : "Failed");
result.append(buffer);
snprintf(buffer, SIZE, "\tMic Mute %s\n", (mMicMute) ? "ON" : "OFF");
result.append(buffer);
snprintf(buffer, SIZE, "\tmPcm: %p\n", mPcm);
result.append(buffer);
snprintf(buffer, SIZE, "\tmPcmOpenCnt: %d\n", mPcmOpenCnt);
result.append(buffer);
snprintf(buffer, SIZE, "\tmMixerOpenCnt: %d\n", mMixerOpenCnt);
result.append(buffer);
snprintf(buffer, SIZE, "\tIn Call Audio Mode %s\n",
(mInCallAudioMode) ? "ON" : "OFF");
result.append(buffer);
snprintf(buffer, SIZE, "\tInput source %s\n", mInputSource.string());
result.append(buffer);
snprintf(buffer, SIZE, "\tmSecRilLibHandle: %p\n", mSecRilLibHandle);
result.append(buffer);
snprintf(buffer, SIZE, "\tmRilClient: %p\n", mRilClient);
result.append(buffer);
snprintf(buffer, SIZE, "\tCP %s\n",
(mActivatedCP) ? "Activated" : "Deactivated");
result.append(buffer);
snprintf(buffer, SIZE, "\tmDriverOp: %d\n", mDriverOp);
result.append(buffer);
snprintf(buffer, SIZE, "\n\tmOutput %p dump:\n", mOutput.get());
result.append(buffer);
write(fd, result.string(), result.size());
if (mOutput != 0) {
mOutput->dump(fd, args);
}
snprintf(buffer, SIZE, "\n\t%d inputs opened:\n", mInputs.size());
write(fd, buffer, strlen(buffer));
for (size_t i = 0; i < mInputs.size(); i++) {
snprintf(buffer, SIZE, "\t- input %d dump:\n", i);
write(fd, buffer, strlen(buffer));
mInputs[i]->dump(fd, args);
}
return NO_ERROR;
}
status_t AudioHardware::setIncallPath_l(uint32_t device)
{
ALOGV("setIncallPath_l: device %x", device);
if (mMode == AudioSystem::MODE_IN_CALL) {
TRACE_DRIVER_IN(DRV_PCM_OPEN)
if (!mPcm)
openPcmOut_l();
else
mPcm = route_pcm_open(getRouteFromDevice(device), mPcm->flags);
TRACE_DRIVER_OUT
}
return NO_ERROR;
}
struct pcm *AudioHardware::openPcmOut_l()
{
ALOGD("openPcmOut_l() mPcmOpenCnt: %d", mPcmOpenCnt);
if (mPcmOpenCnt++ == 0) {
if (mPcm != NULL) {
ALOGE("openPcmOut_l() mPcmOpenCnt == 0 and mPcm == %p\n", mPcm);
mPcmOpenCnt--;
return NULL;
}
unsigned flags = PCM_OUT;
flags |= (AUDIO_HW_OUT_PERIOD_MULT - 1) << PCM_PERIOD_SZ_SHIFT;
flags |= (AUDIO_HW_OUT_PERIOD_CNT - PCM_PERIOD_CNT_MIN) << PCM_PERIOD_CNT_SHIFT;
if (mOutput->sampleRate() == 48000) {
flags |= PCM_48000HZ;
}
TRACE_DRIVER_IN(DRV_PCM_OPEN)
mPcm = route_pcm_open(getRouteFromDevice(mOutput->device()), flags);
TRACE_DRIVER_OUT
if (!pcm_ready(mPcm)) {
ALOGE("openPcmOut_l() cannot open pcm_out driver: %s\n", pcm_error(mPcm));
TRACE_DRIVER_IN(DRV_PCM_CLOSE)
route_pcm_close(PLAYBACK_OFF_ROUTE);
TRACE_DRIVER_OUT
mPcmOpenCnt--;
mPcm = NULL;
}
}
return mPcm;
}
void AudioHardware::closePcmOut_l()
{
ALOGD("closePcmOut_l() mPcmOpenCnt: %d", mPcmOpenCnt);
if (mPcmOpenCnt == 0) {
ALOGE("closePcmOut_l() mPcmOpenCnt == 0");
return;
}
if (--mPcmOpenCnt == 0) {
ALOGV("close_l() reset Playback Path to OFF");
TRACE_DRIVER_IN(DRV_PCM_CLOSE)
route_pcm_close(PLAYBACK_OFF_ROUTE);
TRACE_DRIVER_OUT
mPcm = NULL;
}
}
unsigned AudioHardware::getOutputRouteFromDevice(uint32_t device)
{
if (mMode != AudioSystem::MODE_RINGTONE && mMode != AudioSystem::MODE_NORMAL)
return PLAYBACK_OFF_ROUTE;
switch (device) {
case AudioSystem::DEVICE_OUT_EARPIECE:
return EARPIECE_NORMAL_ROUTE;
case AudioSystem::DEVICE_OUT_SPEAKER:
if (mMode == AudioSystem::MODE_RINGTONE) return SPEAKER_RINGTONE_ROUTE;
else return SPEAKER_NORMAL_ROUTE;
case AudioSystem::DEVICE_OUT_WIRED_HEADPHONE:
if (mMode == AudioSystem::MODE_RINGTONE) return HEADPHONE_RINGTONE_ROUTE;
else return HEADPHONE_NORMAL_ROUTE;
case AudioSystem::DEVICE_OUT_WIRED_HEADSET:
if (mMode == AudioSystem::MODE_RINGTONE) return HEADSET_RINGTONE_ROUTE;
else return HEADSET_NORMAL_ROUTE;
case (AudioSystem::DEVICE_OUT_SPEAKER|AudioSystem::DEVICE_OUT_WIRED_HEADPHONE):
case (AudioSystem::DEVICE_OUT_SPEAKER|AudioSystem::DEVICE_OUT_WIRED_HEADSET):
if (mMode == AudioSystem::MODE_RINGTONE) return SPEAKER_HEADPHONE_RINGTONE_ROUTE;
else return SPEAKER_HEADPHONE_NORMAL_ROUTE;
case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO:
case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
return BLUETOOTH_NORMAL_ROUTE;
case AudioSystem::DEVICE_OUT_AUX_DIGITAL:
return HDMI_NORMAL_ROUTE;
case AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET:
case AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET:
return USB_NORMAL_ROUTE;
default:
return PLAYBACK_OFF_ROUTE;
}
}
unsigned AudioHardware::getVoiceRouteFromDevice(uint32_t device)
{
if (mMode != AudioSystem::MODE_IN_CALL && mMode != AudioSystem::MODE_IN_COMMUNICATION)
return INCALL_OFF_ROUTE;
if (device & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO ||
device & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET ||
device & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT) {
if (mMode == AudioSystem::MODE_IN_CALL) return BLUETOOTH_INCALL_ROUTE;
else return BLUETOOTH_VOIP_ROUTE;
} else if (device & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE) {
if (mMode == AudioSystem::MODE_IN_CALL) return HEADPHONE_INCALL_ROUTE;
else return HEADPHONE_VOIP_ROUTE;
} else if (device & AudioSystem::DEVICE_OUT_WIRED_HEADSET) {
if (mMode == AudioSystem::MODE_IN_CALL) return HEADSET_INCALL_ROUTE;
else return HEADSET_VOIP_ROUTE;
} else if (device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET ||
device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET) {
if (mMode == AudioSystem::MODE_IN_CALL) return EARPIECE_INCALL_ROUTE;
else return USB_NORMAL_ROUTE;
} else if (device & AudioSystem::DEVICE_OUT_AUX_DIGITAL) {
if (mMode == AudioSystem::MODE_IN_CALL) return EARPIECE_INCALL_ROUTE;
else return HDMI_NORMAL_ROUTE;
} else if (device & AudioSystem::DEVICE_OUT_EARPIECE) {
if (mMode == AudioSystem::MODE_IN_CALL) return EARPIECE_INCALL_ROUTE;
else return EARPIECE_VOIP_ROUTE;
} else if (device & AudioSystem::DEVICE_OUT_SPEAKER) {
if (mMode == AudioSystem::MODE_IN_CALL) return SPEAKER_INCALL_ROUTE;
else return SPEAKER_VOIP_ROUTE;
} else {
if (mMode == AudioSystem::MODE_IN_CALL) return INCALL_OFF_ROUTE;
else return VOIP_OFF_ROUTE;
}
}
unsigned AudioHardware::getInputRouteFromDevice(uint32_t device)
{
if (mMicMute) {
return CAPTURE_OFF_ROUTE;
}
switch (device) {
case AudioSystem::DEVICE_IN_BUILTIN_MIC:
return MAIN_MIC_CAPTURE_ROUTE;
case AudioSystem::DEVICE_IN_WIRED_HEADSET:
return HANDS_FREE_MIC_CAPTURE_ROUTE;
case AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET:
return BLUETOOTH_SOC_MIC_CAPTURE_ROUTE;
case AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET:
return USB_CAPTURE_ROUTE;
default:
return CAPTURE_OFF_ROUTE;
}
}
unsigned AudioHardware::getRouteFromDevice(uint32_t device)
{
if (device & AudioSystem::DEVICE_IN_ALL)
return getInputRouteFromDevice(device);
switch (mMode) {
case AudioSystem::MODE_IN_CALL:
case AudioSystem::MODE_IN_COMMUNICATION:
return getVoiceRouteFromDevice(device);
default:
return getOutputRouteFromDevice(device);
}
}
uint32_t AudioHardware::getInputSampleRate(uint32_t sampleRate)
{
uint32_t i;
uint32_t prevDelta;
uint32_t delta;
for (i = 0, prevDelta = 0xFFFFFFFF; i < sizeof(inputSamplingRates)/sizeof(uint32_t); i++, prevDelta = delta) {
delta = abs(sampleRate - inputSamplingRates[i]);
if (delta > prevDelta) break;
}
// i is always > 0 here
return inputSamplingRates[i-1];
}
// getActiveInput_l() must be called with mLock held
android::sp <AudioHardware::AudioStreamInALSA> AudioHardware::getActiveInput_l()
{
android::sp< AudioHardware::AudioStreamInALSA> spIn;
for (size_t i = 0; i < mInputs.size(); i++) {
// return first input found not being in standby mode
// as only one input can be in this state
if (!mInputs[i]->checkStandby()) {
spIn = mInputs[i];
break;
}
}
return spIn;
}
status_t AudioHardware::setInputSource_l(String8 source)
{
ALOGV("setInputSource_l(%s)", source.string());
if (source != mInputSource) {
if ((source == "Default") || (mMode != AudioSystem::MODE_IN_CALL)) {
ALOGV("mixer_ctl_select, Input Source, (%s)", source.string());
TRACE_DRIVER_IN(DRV_MIXER_SEL)
route_set_input_source(source.string());
TRACE_DRIVER_OUT
}
mInputSource = source;
}
return NO_ERROR;
}
//------------------------------------------------------------------------------
// AudioStreamOutALSA
//------------------------------------------------------------------------------
#ifdef DEBUG_ALSA_OUT
static FILE * alsa_out_fp = NULL;
#endif
AudioHardware::AudioStreamOutALSA::AudioStreamOutALSA() :
mHardware(0), mRouteCtl(0),
mStandby(true), mDevices(0), mChannels(AUDIO_HW_OUT_CHANNELS),
mSampleRate(AUDIO_HW_OUT_SAMPLERATE), mBufferSize(AUDIO_HW_OUT_PERIOD_BYTES),
mDriverOp(DRV_NONE), mStandbyCnt(0)
{
#ifdef DEBUG_ALSA_OUT
if(alsa_out_fp== NULL)
alsa_out_fp = fopen("/data/data/out.pcm","a+");
if(alsa_out_fp)
ALOGI("------------>openfile success");
#endif
}
status_t AudioHardware::AudioStreamOutALSA::set(
AudioHardware* hw, uint32_t devices, int *pFormat,
uint32_t *pChannels, uint32_t *pRate)
{
int lFormat = pFormat ? *pFormat : 0;
uint32_t lChannels = pChannels ? *pChannels : 0;
uint32_t lRate = pRate ? *pRate : 0;
mHardware = hw;
mDevices = devices;
// fix up defaults
if (lFormat == 0) lFormat = format();
if (lChannels == 0) lChannels = channels();
if (lRate == 0) lRate = sampleRate();
if (devices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET ||
devices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET) {
uint32_t usbChannels = (lChannels == AudioSystem::CHANNEL_OUT_MONO) ? 1 : 2;
mSampleRate = get_USBAudio_sampleRate(UA_Playback_type, lRate);
mChannels = (get_USBAudio_Channels(UA_Playback_type, usbChannels) == 1) ?
AudioSystem::CHANNEL_OUT_MONO : AudioSystem::CHANNEL_OUT_STEREO;
}
if (pFormat) *pFormat = format();
if (pChannels) *pChannels = channels();
if (pRate) *pRate = sampleRate();
mBufferSize = AUDIO_HW_OUT_PERIOD_BYTES;
return NO_ERROR;
}
AudioHardware::AudioStreamOutALSA::~AudioStreamOutALSA()
{
standby();
#ifdef DEBUG_ALSA_OUT
if(alsa_out_fp)
fclose(alsa_out_fp);
#endif
}
ssize_t AudioHardware::AudioStreamOutALSA::write(const void* buffer, size_t bytes)
{
// ALOGV("AudioStreamOutALSA::write(%p, %u)", buffer, bytes);
status_t status = NO_INIT;
const uint8_t* p = static_cast<const uint8_t*>(buffer);
int ret;
#ifdef DEBUG_ALSA_OUT
if(alsa_out_fp)
fwrite(buffer,1,bytes,alsa_out_fp);
#endif
if (mHardware == NULL) return NO_INIT;
{ // scope for the lock
android::AutoMutex lock(mLock);
if (mStandby) {
android::AutoMutex hwLock(mHardware->lock());
ALOGD("AudioHardware pcm playback is exiting standby.");
acquire_wake_lock (PARTIAL_WAKE_LOCK, "AudioOutLock");
/* android::sp<AudioStreamInALSA> spIn = mHardware->getActiveInput_l();
while (spIn != 0) {
int cnt = spIn->standbyCnt();
mHardware->lock().unlock();
// Mutex acquisition order is always out -> in -> hw
spIn->lock();
mHardware->lock().lock();
// make sure that another thread did not change input state
// while the mutex is released
if ((spIn == mHardware->getActiveInput_l()) &&
(cnt == spIn->standbyCnt())) {
ALOGV("AudioStreamOutALSA::write() force input standby");
spIn->close_l();
break;
}
spIn->unlock();
spIn = mHardware->getActiveInput_l();
}*/
// spIn is not 0 here only if the input was active and has been
// closed above
// open output before input
open_l();
/* if (spIn != 0) {
if (spIn->open_l() != NO_ERROR) {
spIn->doStandby_l();
}
spIn->unlock();
}*/
if (mHardware->getPcm() == NULL) {
release_wake_lock("AudioOutLock");
goto Error;
}
mStandby = false;
#ifdef TARGET_RK2928
usleep(AMP_ENABLE_TIME*1000);
#endif
}
TRACE_DRIVER_IN(DRV_PCM_WRITE)
ret = pcm_write(mHardware->getPcm(),(void*) p, bytes);
TRACE_DRIVER_OUT
if (ret == 0) {
return bytes;
}
ALOGW("write error: %d", errno);
status = -errno;
}
Error:
standby();
// Simulate audio output timing in case of error
usleep((((bytes * 1000) / frameSize()) * 1000) / sampleRate());
return status;
}
status_t AudioHardware::AudioStreamOutALSA::standby()
{
if (mHardware == NULL) return NO_INIT;
android::AutoMutex lock(mLock);
{ // scope for the AudioHardware lock
android::AutoMutex hwLock(mHardware->lock());
if (mHardware->mode() != AudioSystem::MODE_IN_CALL)
doStandby_l();
}
return NO_ERROR;
}
void AudioHardware::AudioStreamOutALSA::doStandby_l()
{
mStandbyCnt++;
if (!mStandby) {
ALOGD("AudioHardware pcm playback is going to standby.");
release_wake_lock("AudioOutLock");
mStandby = true;
}
close_l();
}
void AudioHardware::AudioStreamOutALSA::close_l()
{
if (mHardware->getPcm()) {
mHardware->closePcmOut_l();
}
}
status_t AudioHardware::AudioStreamOutALSA::open_l()
{
ALOGV("open pcm_out driver");
mHardware->openPcmOut_l();
if (mHardware->getPcm() == NULL) {
return NO_INIT;
}
return NO_ERROR;
}
status_t AudioHardware::AudioStreamOutALSA::dump(int fd, const Vector<String16>& args)
{
const size_t SIZE = 256;
char buffer[SIZE];
String8 result;
bool locked = tryLock(mLock);
if (!locked) {
snprintf(buffer, SIZE, "\n\t\tAudioStreamOutALSA maybe deadlocked\n");
} else {
mLock.unlock();
}
snprintf(buffer, SIZE, "\t\tmHardware: %p\n", mHardware);
result.append(buffer);
snprintf(buffer, SIZE, "\t\tmRouteCtl: %p\n", mRouteCtl);
result.append(buffer);
snprintf(buffer, SIZE, "\t\tStandby %s\n", (mStandby) ? "ON" : "OFF");
result.append(buffer);
snprintf(buffer, SIZE, "\t\tmDevices: 0x%08x\n", mDevices);
result.append(buffer);
snprintf(buffer, SIZE, "\t\tmChannels: 0x%08x\n", mChannels);
result.append(buffer);
snprintf(buffer, SIZE, "\t\tmSampleRate: %d\n", mSampleRate);
result.append(buffer);
snprintf(buffer, SIZE, "\t\tmBufferSize: %d\n", mBufferSize);
result.append(buffer);
snprintf(buffer, SIZE, "\t\tmDriverOp: %d\n", mDriverOp);
result.append(buffer);
::write(fd, result.string(), result.size());
return NO_ERROR;
}
bool AudioHardware::AudioStreamOutALSA::checkStandby()
{
return mStandby;
}
status_t AudioHardware::AudioStreamOutALSA::setParameters(const String8& keyValuePairs)
{
AudioParameter param = AudioParameter(keyValuePairs);
status_t status = NO_ERROR;
int value;
ALOGD("AudioStreamOutALSA::setParameters() %s", keyValuePairs.string());
if (mHardware == NULL) return NO_INIT;
{
bool needStandby = false;
android::AutoMutex lock(mLock);
if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR)
{
//for MID alsa ,not have a routing change.
android::AutoMutex hwLock(mHardware->lock());
if (mDevices != (uint32_t)value && value != AUDIO_DEVICE_NONE) {
mDevices = (uint32_t)value;
if (mHardware->mode() == AudioSystem::MODE_IN_CALL) {
mHardware->setIncallPath_l(mDevices);
} else
needStandby = true;
}
param.remove(String8(AudioParameter::keyRouting));
}
if (param.getInt(String8(AudioParameter::keySamplingRate), value) == NO_ERROR)
{
if (mSampleRate != (uint32_t)value && value != 0 &&
(value == 48000 || value == 44100)) {
mSampleRate = (uint32_t)value;
android::AutoMutex hwLock(mHardware->lock());
if (mHardware->mode() != AudioSystem::MODE_IN_CALL) {
needStandby = true;
}
}
param.remove(String8(AudioParameter::keySamplingRate));
}
if (needStandby){
android::AutoMutex hwLock(mHardware->lock());
doStandby_l();
}
}
if (param.size()) {
status = BAD_VALUE;
}
return status;
}
String8 AudioHardware::AudioStreamOutALSA::getParameters(const String8& keys)
{
AudioParameter param = AudioParameter(keys);
String8 value;
String8 key = String8(AudioParameter::keyRouting);
if (param.get(key, value) == NO_ERROR) {
param.addInt(key, (int)mDevices);
}
if (param.get(String8(AudioParameter::keySamplingRate), value) == NO_ERROR) {
param.addInt(String8(AudioParameter::keySamplingRate), (int)mSampleRate);
}
ALOGV("AudioStreamOutALSA::getParameters() %s", param.toString().string());
return param.toString();
}
status_t AudioHardware::AudioStreamOutALSA::getRenderPosition(uint32_t *dspFrames)
{
//TODO
return INVALID_OPERATION;
}
//------------------------------------------------------------------------------
// AudioStreamInALSA
//------------------------------------------------------------------------------
#ifdef DEBUG_ALSA_IN
static FILE * alsa_in_fp = NULL;
#endif
AudioHardware::AudioStreamInALSA::AudioStreamInALSA() :
mHardware(0), mPcm(0), mRouteCtl(0),
mStandby(true), mDevices(0), mChannels(AUDIO_HW_IN_CHANNELS), mChannelCount(1),
mSampleRate(AUDIO_HW_IN_SAMPLERATE), mReqSampleRate(AUDIO_HW_IN_SAMPLERATE),
mInSampleRate(AUDIO_HW_IN_SAMPLERATE), mBufferSize(AUDIO_HW_IN_PERIOD_BYTES),
mDownSampler(NULL), mReadStatus(NO_ERROR),mMicMute(false), mDriverOp(DRV_NONE),
mStandbyCnt(0), mDropCnt(0)
{
#ifdef DEBUG_ALSA_IN
alsa_in_fp = fopen("/data/data/in.pcm","wb");
if(alsa_in_fp)
ALOGI("alsa_streamin open /sdcard/in.pcm file success");
#endif
#if (SPEEX_AGC_ENABLE||SPEEX_DENOISE_ENABLE)
mSpeexState = NULL;
mSpeexFrameSize = 0;
mSpeexPcmIn = NULL;
#endif//SPEEX_AGC_ENABLE||SPEEX_DENOISE_ENABLE
}
status_t AudioHardware::AudioStreamInALSA::set(
AudioHardware* hw, uint32_t devices, int *pFormat,
uint32_t *pChannels, uint32_t *pRate, AudioSystem::audio_in_acoustics acoustics)
{
if (pFormat == 0 || *pFormat != AUDIO_HW_IN_FORMAT) {
*pFormat = AUDIO_HW_IN_FORMAT;
return BAD_VALUE;
}
if (pRate == 0) {
return BAD_VALUE;
}
if (*pRate == 0) *pRate = sampleRate();
uint32_t rate = AudioHardware::getInputSampleRate(*pRate);
if (rate != *pRate) {
*pRate = rate;
return BAD_VALUE;
}
if (devices & AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET) {
mInSampleRate = get_USBAudio_sampleRate(UA_Record_type, *pRate);
}
if (pChannels == 0 || (*pChannels != AudioSystem::CHANNEL_IN_MONO &&
*pChannels != AudioSystem::CHANNEL_IN_STEREO)) {
*pChannels = AUDIO_HW_IN_CHANNELS;
return BAD_VALUE;
}
if (devices & AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET) {
uint32_t usbChannels = (*pChannels == AudioSystem::CHANNEL_IN_MONO) ? 1 : 2;
*pChannels = (get_USBAudio_Channels(UA_Record_type, usbChannels) == 1) ?
AudioSystem::CHANNEL_IN_MONO : AudioSystem::CHANNEL_IN_STEREO;
} else
*pChannels = AudioSystem::CHANNEL_IN_STEREO;
mHardware = hw;
ALOGV("AudioStreamInALSA::set(%d, %d, %u)", *pFormat, *pChannels, *pRate);
mDevices = devices;
mChannels = *pChannels;
mChannelCount = AudioSystem::popCount(mChannels);
mReqSampleRate = rate;
if (rate >= mInSampleRate) {
mSampleRate = mInSampleRate;
} else {
mSampleRate = rate;
}
mBufferSize = getBufferSize(mSampleRate, AudioSystem::popCount(*pChannels));
ALOGV("mInSampleRate %d, mSampleRate %d", mInSampleRate, mSampleRate);
if (mSampleRate < mInSampleRate) {
mDownSampler = new AudioHardware::DownSampler(mSampleRate,
mInSampleRate,
mChannelCount,
AUDIO_HW_IN_PERIOD_SZ,
this);
status_t status = mDownSampler->initCheck();
if (status != NO_ERROR) {
delete mDownSampler;
mDownSampler = NULL;
ALOGW("AudioStreamInALSA::set() downsampler init failed: %d", status);
return status;
}
mPcmIn = new int16_t[AUDIO_HW_IN_PERIOD_SZ * mChannelCount];
}
#if (SPEEX_AGC_ENABLE||SPEEX_DENOISE_ENABLE)
mSpeexFrameSize = mBufferSize/((mChannelCount*sizeof(int16_t))*2);//
mSpeexPcmIn = new int16_t[mSpeexFrameSize];
mSpeexState = speex_preprocess_state_init(mSpeexFrameSize, mSampleRate);
if(mSpeexState == NULL)
return BAD_VALUE;
#if SPEEX_AGC_ENABLE
int agc = 1;
float q= 27000; //取值范围可以自己改不要超过30000
//actually default is 8000(0,32768),here make it louder for voice is not loudy enough by default. 8000
speex_preprocess_ctl(mSpeexState, SPEEX_PREPROCESS_SET_AGC, &agc);//增益
speex_preprocess_ctl(mSpeexState, SPEEX_PREPROCESS_SET_AGC_LEVEL,&q);
#endif//SPEEX_AGC_ENABLE
#if SPEEX_DENOISE_ENABLE
int denoise = 1;
#if SPEEX_AGC_ENABLE
int noiseSuppress = -32;//DB值可以自己改 根据具体产品修改出适合的值,-25~-45
#else
int noiseSuppress = -24;
#endif
speex_preprocess_ctl(mSpeexState, SPEEX_PREPROCESS_SET_DENOISE, &denoise);
speex_preprocess_ctl(mSpeexState, SPEEX_PREPROCESS_SET_NOISE_SUPPRESS, &noiseSuppress);
#endif//SPEEX_DENOISE_ENABLE
#endif//SPEEX_AGC_ENABLE||SPEEX_DENOISE_ENABLE
return NO_ERROR;
}
AudioHardware::AudioStreamInALSA::~AudioStreamInALSA()
{
standby();
if (mDownSampler != NULL) {
delete mDownSampler;
mDownSampler = NULL;
if (mPcmIn != NULL) {
delete[] mPcmIn;
mPcmIn = NULL;
}
}
#if (SPEEX_AGC_ENABLE||SPEEX_DENOISE_ENABLE)
if (mSpeexState) {
speex_preprocess_state_destroy(mSpeexState);
mSpeexState = NULL;
}
if(mSpeexPcmIn) {
delete[] mSpeexPcmIn;
mSpeexPcmIn = NULL;
}
#endif //SPEEX_AGC_ENABLE||SPEEX_DENOISE_ENABLE
#ifdef DEBUG_ALSA_IN
if(alsa_in_fp)
fclose(alsa_in_fp);
#endif
}
status_t AudioHardware::AudioStreamInALSA::setGain(float gain)
{
if(gain == 0.0)
mMicMute= true;
else
mMicMute = false;
return NO_ERROR;
}
ssize_t AudioHardware::AudioStreamInALSA::read(void* buffer, ssize_t bytes)
{
// ALOGV("AudioStreamInALSA::read(%p, %u)", buffer, bytes);
status_t status = NO_INIT;
int ret;
if (mHardware == NULL) return NO_INIT;
{ // scope for the lock
android::AutoMutex lock(mLock);
if (mStandby) {
android::AutoMutex hwLock(mHardware->lock());
ALOGD("AudioHardware pcm capture is exiting standby.");
acquire_wake_lock (PARTIAL_WAKE_LOCK, "AudioInLock");
/* android::sp<AudioStreamOutALSA> spOut = mHardware->output();
while (spOut != 0) {
if (!spOut->checkStandby()) {
int cnt = spOut->standbyCnt();
mHardware->lock().unlock();
mLock.unlock();
// Mutex acquisition order is always out -> in -> hw
spOut->lock();
mLock.lock();
mHardware->lock().lock();
// make sure that another thread did not change output state
// while the mutex is released
if ((spOut == mHardware->output()) && (cnt == spOut->standbyCnt())) {
ALOGV("AudioStreamInALSA::read() force output standby");
spOut->close_l();
break;
}
spOut->unlock();
spOut = mHardware->output();
} else {
spOut.clear();
}
}
// spOut is not 0 here only if the output was active and has been
// closed above
// open output before input
if (spOut != 0) {
if (spOut->open_l() != NO_ERROR) {
spOut->doStandby_l();
}
spOut->unlock();
}*/
open_l();
if (mPcm == NULL) {
release_wake_lock("AudioInLock");
goto Error;
}
mStandby = false;
}
if (mDownSampler != NULL) {
size_t frames = bytes / frameSize();
size_t framesIn = 0;
mReadStatus = 0;
do {
size_t outframes = frames - framesIn;
mDownSampler->resample(
(int16_t *)buffer + (framesIn * mChannelCount),
&outframes);
framesIn += outframes;
} while ((framesIn < frames) && mReadStatus == 0);
ret = mReadStatus;
bytes = framesIn * frameSize();
} else {
TRACE_DRIVER_IN(DRV_PCM_READ)
ret = pcm_read(mPcm, buffer, bytes);
TRACE_DRIVER_OUT
}
if (ret == 0) {
//drop 0.5S input data
if(mDropCnt < mSampleRate/2)
{
memset(buffer,0,bytes);
mDropCnt += bytes/frameSize();
}
else if (mMicMute)
{
memset(buffer,0,bytes);
}
#ifdef DEBUG_ALSA_IN
if(alsa_in_fp)
fwrite(buffer,1,bytes,alsa_in_fp);
#endif
#if (SPEEX_AGC_ENABLE||SPEEX_DENOISE_ENABLE)
if(!mMicMute)
{
int index = 0;
int startPos = 0;
spx_int16_t* data = (spx_int16_t*) buffer;
int curFrameSize = bytes/(mChannelCount*sizeof(int16_t));
if(curFrameSize != 2*mSpeexFrameSize)
ALOGV("the current request have some error mSpeexFrameSize %d bytes %d ",mSpeexFrameSize,bytes);
while(curFrameSize >= startPos+mSpeexFrameSize)
{
for(index = startPos; index< startPos + mSpeexFrameSize ;index++ )
mSpeexPcmIn[index-startPos] = data[index*mChannelCount]/2 + data[index*mChannelCount+1]/2;
speex_preprocess_run(mSpeexState,mSpeexPcmIn);
#ifndef TARGET_RK2928
for(unsigned long ch = 0 ; ch < mChannelCount;ch++)
for(index = startPos; index< startPos + mSpeexFrameSize ;index++ )
{
data[index*mChannelCount+ch] = mSpeexPcmIn[index-startPos];
}
#else
for(index = startPos; index< startPos + mSpeexFrameSize ;index++ )
{
int tmp = (int)mSpeexPcmIn[index-startPos]+ mSpeexPcmIn[index-startPos]/2;
data[index*mChannelCount+0] = tmp > 32767 ? 32767 : (tmp < -32768 ? -32768 : tmp);
}
for(int ch = 1 ; ch < mChannelCount;ch++)
for(index = startPos; index< startPos + mSpeexFrameSize ;index++ )
{
data[index*mChannelCount+ch] = data[index*mChannelCount+0];
}
#endif
startPos += mSpeexFrameSize;
}
}
#endif//(SPEEX_AGC_ENABLE||SPEEX_DENOISE_ENABLE)
return bytes;
}
ALOGW("read error: %d", ret);
status = ret;
}
Error:
standby();
// Simulate audio output timing in case of error
usleep((((bytes * 1000) / frameSize()) * 1000) / sampleRate());
return status;
}
status_t AudioHardware::AudioStreamInALSA::standby()
{
if (mHardware == NULL) return NO_INIT;
android::AutoMutex lock(mLock);
{ // scope for AudioHardware lock
android::AutoMutex hwLock(mHardware->lock());
doStandby_l();
}
return NO_ERROR;
}
void AudioHardware::AudioStreamInALSA::doStandby_l()
{
mStandbyCnt++;
if (!mStandby) {
ALOGD("AudioHardware pcm capture is going to standby.");
release_wake_lock("AudioInLock");
mStandby = true;
}
close_l();
}
void AudioHardware::AudioStreamInALSA::close_l()
{
if (mPcm) {
ALOGV("close_l() reset Capture MIC Path to OFF");
TRACE_DRIVER_IN(DRV_PCM_CLOSE)
route_pcm_close(CAPTURE_OFF_ROUTE);
TRACE_DRIVER_OUT
mPcm = NULL;
}
}
status_t AudioHardware::AudioStreamInALSA::open_l()
{
unsigned flags = PCM_IN;
flags |= (AUDIO_HW_IN_PERIOD_MULT * mInSampleRate / AUDIO_HW_IN_SAMPLERATE - 1) << PCM_PERIOD_SZ_SHIFT;
flags |= (AUDIO_HW_IN_PERIOD_CNT - PCM_PERIOD_CNT_MIN)
<< PCM_PERIOD_CNT_SHIFT;
if (mChannels == AudioSystem::CHANNEL_IN_MONO)
flags |= PCM_MONO;
if (mInSampleRate == 8000)
flags |= PCM_8000HZ;
else if (mInSampleRate == 48000)
flags |= PCM_48000HZ;
ALOGV("open pcm_in driver");
TRACE_DRIVER_IN(DRV_PCM_OPEN)
mPcm = route_pcm_open(mHardware->getRouteFromDevice(mDevices), flags);
TRACE_DRIVER_OUT
if (!pcm_ready(mPcm)) {
ALOGE("cannot open pcm_in driver: %s\n", pcm_error(mPcm));
TRACE_DRIVER_IN(DRV_PCM_CLOSE)
route_pcm_close(CAPTURE_OFF_ROUTE);
TRACE_DRIVER_OUT
mPcm = NULL;
return NO_INIT;
}
if (mDownSampler != NULL) {
mInPcmInBuf = 0;
mDownSampler->reset();
}
if (mHardware->mode() != AudioSystem::MODE_IN_CALL) {
ALOGV("read() wakeup setting Capture route");
TRACE_DRIVER_IN(DRV_MIXER_SEL)
route_set_controls(mHardware->getRouteFromDevice(mDevices));
TRACE_DRIVER_OUT
}
return NO_ERROR;
}
status_t AudioHardware::AudioStreamInALSA::dump(int fd, const Vector<String16>& args)
{
const size_t SIZE = 256;
char buffer[SIZE];
String8 result;
bool locked = tryLock(mLock);
if (!locked) {
snprintf(buffer, SIZE, "\n\t\tAudioStreamInALSA maybe deadlocked\n");
} else {
mLock.unlock();
}
snprintf(buffer, SIZE, "\t\tmHardware: %p\n", mHardware);
result.append(buffer);
snprintf(buffer, SIZE, "\t\tmPcm: %p\n", mPcm);
result.append(buffer);
snprintf(buffer, SIZE, "\t\tStandby %s\n", (mStandby) ? "ON" : "OFF");
result.append(buffer);
snprintf(buffer, SIZE, "\t\tmDevices: 0x%08x\n", mDevices);
result.append(buffer);
snprintf(buffer, SIZE, "\t\tmChannels: 0x%08x\n", mChannels);
result.append(buffer);
snprintf(buffer, SIZE, "\t\tmSampleRate: %d\n", mSampleRate);
result.append(buffer);
snprintf(buffer, SIZE, "\t\tmBufferSize: %d\n", mBufferSize);
result.append(buffer);
snprintf(buffer, SIZE, "\t\tmDriverOp: %d\n", mDriverOp);
result.append(buffer);
write(fd, result.string(), result.size());
return NO_ERROR;
}
bool AudioHardware::AudioStreamInALSA::checkStandby()
{
return mStandby;
}
status_t AudioHardware::AudioStreamInALSA::setParameters(const String8& keyValuePairs)
{
AudioParameter param = AudioParameter(keyValuePairs);
status_t status = NO_ERROR;
int value;
String8 source;
bool reconfig = false;
ALOGD("AudioStreamInALSA::setParameters() %s", keyValuePairs.string());
if (mHardware == NULL) return NO_INIT;
{
bool needStandby = false;
android::AutoMutex lock(mLock);
if (param.get(String8(INPUT_SOURCE_KEY), source) == NO_ERROR) {
android::AutoMutex hwLock(mHardware->lock());
mHardware->setInputSource_l(source);
param.remove(String8(INPUT_SOURCE_KEY));
}
if (param.getInt(String8(AudioParameter::keySamplingRate), value) == NO_ERROR)
{
if (mInSampleRate != (uint32_t)value && value != 0 &&
(value == 8000 || value == 44100 || value == 48000)) {
mInSampleRate = (uint32_t)value;
reconfig = true;
if (mHardware->mode() != AudioSystem::MODE_IN_CALL) {
needStandby = true;
}
}
param.remove(String8(AudioParameter::keySamplingRate));
}
if (param.getInt(String8(AudioParameter::keyChannels), value) == NO_ERROR)
{
if (mChannels != (uint32_t)value && (uint32_t)value != 0 &&
(value == AudioSystem::CHANNEL_IN_STEREO || value == AudioSystem::CHANNEL_IN_MONO)) {
mChannels = (uint32_t)value;
reconfig = true;
if (mHardware->mode() != AudioSystem::MODE_IN_CALL) {
needStandby = true;
}
}
param.remove(String8(AudioParameter::keyChannels));
}
if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR)
{
if (mDevices != (uint32_t)value && (uint32_t)value != AUDIO_DEVICE_NONE) {
mDevices = (uint32_t)value;
if (mHardware->mode() != AudioSystem::MODE_IN_CALL) {
needStandby = true;
}
}
param.remove(String8(AudioParameter::keyRouting));
}
if (needStandby){
android::AutoMutex hwLock(mHardware->lock());
doStandby_l();
}
//close downsampler and open again to update params
if (reconfig) {
android::AutoMutex hwLock(mHardware->lock());
if (mDownSampler != NULL) {
delete mDownSampler;
mDownSampler = NULL;
if (mPcmIn != NULL) {
delete[] mPcmIn;
mPcmIn = NULL;
}
}
#if (SPEEX_AGC_ENABLE||SPEEX_DENOISE_ENABLE)
if (mSpeexState) {
speex_preprocess_state_destroy(mSpeexState);
mSpeexState = NULL;
}
if(mSpeexPcmIn) {
delete[] mSpeexPcmIn;
mSpeexPcmIn = NULL;
}
#endif //SPEEX_AGC_ENABLE||SPEEX_DENOISE_ENABLE
int pFormat = AUDIO_HW_IN_FORMAT;
uint32_t pChannels = mChannels;
uint32_t pRate = mReqSampleRate;
if (set(mHardware, mDevices, &pFormat, &pChannels, &pRate, (AudioSystem::audio_in_acoustics)0) != NO_ERROR) {
ALOGE("AudioStreamInALSA; call set error!");
return BAD_VALUE;
}
}
}
if (param.size()) {
status = BAD_VALUE;
}
return status;
}
String8 AudioHardware::AudioStreamInALSA::getParameters(const String8& keys)
{
AudioParameter param = AudioParameter(keys);
String8 value;
String8 key = String8(AudioParameter::keyRouting);
if (param.get(key, value) == NO_ERROR) {
param.addInt(key, (int)mDevices);
}
if (param.get(String8(AudioParameter::keySamplingRate), value) == NO_ERROR) {
param.addInt(String8(AudioParameter::keySamplingRate), (int)mInSampleRate);
}
if (param.get(String8(AudioParameter::keyChannels), value) == NO_ERROR) {
param.addInt(String8(AudioParameter::keyChannels), (int)mChannels);
}
ALOGV("AudioStreamInALSA::getParameters() %s", param.toString().string());
return param.toString();
}
status_t AudioHardware::AudioStreamInALSA::getNextBuffer(AudioHardware::BufferProvider::Buffer* buffer)
{
if (mPcm == NULL) {
buffer->raw = NULL;
buffer->frameCount = 0;
mReadStatus = NO_INIT;
return NO_INIT;
}
if (mInPcmInBuf == 0) {
TRACE_DRIVER_IN(DRV_PCM_READ)
mReadStatus = pcm_read(mPcm,(void*) mPcmIn, AUDIO_HW_IN_PERIOD_SZ * frameSize() * mInSampleRate / AUDIO_HW_IN_SAMPLERATE);
TRACE_DRIVER_OUT
if (mReadStatus != 0) {
buffer->raw = NULL;
buffer->frameCount = 0;
return mReadStatus;
}
mInPcmInBuf = AUDIO_HW_IN_PERIOD_SZ * mInSampleRate / AUDIO_HW_IN_SAMPLERATE;
}
buffer->frameCount = (buffer->frameCount > mInPcmInBuf) ? mInPcmInBuf : buffer->frameCount;
buffer->i16 = mPcmIn + (AUDIO_HW_IN_PERIOD_SZ * mInSampleRate / AUDIO_HW_IN_SAMPLERATE - mInPcmInBuf) * mChannelCount;
return mReadStatus;
}
void AudioHardware::AudioStreamInALSA::releaseBuffer(Buffer* buffer)
{
mInPcmInBuf -= buffer->frameCount;
}
size_t AudioHardware::AudioStreamInALSA::getBufferSize(uint32_t sampleRate, int channelCount)
{
size_t ratio;
switch (sampleRate) {
case 8000:
case 11025:
case 12000:
ratio = 4;
break;
case 16000:
case 22050:
case 24000:
ratio = 2;
break;
case 32000:
case 44100:
case 48000:
default:
ratio = 1;
break;
}
return (AUDIO_HW_IN_PERIOD_SZ * channelCount * sizeof(int16_t)) / ratio ;
}
//------------------------------------------------------------------------------
// DownSampler
//------------------------------------------------------------------------------
/*
* 2.30 fixed point FIR filter coefficients for conversion 44100 -> 22050.
* (Works equivalently for 22010 -> 11025 or any other halving, of course.)
*
* Transition band from about 18 kHz, passband ripple < 0.1 dB,
* stopband ripple at about -55 dB, linear phase.
*
* Design and display in MATLAB or Octave using:
*
* filter = fir1(19, 0.5); filter = round(filter * 2**30); freqz(filter * 2**-30);
*/
static const int32_t filter_22khz_coeff[] = {
2089257, 2898328, -5820678, -10484531,
19038724, 30542725, -50469415, -81505260,
152544464, 478517512, 478517512, 152544464,
-81505260, -50469415, 30542725, 19038724,
-10484531, -5820678, 2898328, 2089257,
};
#define NUM_COEFF_22KHZ (sizeof(filter_22khz_coeff) / sizeof(filter_22khz_coeff[0]))
#define OVERLAP_22KHZ (NUM_COEFF_22KHZ - 2)
/*
* Convolution of signals A and reverse(B). (In our case, the filter response
* is symmetric, so the reversing doesn't matter.)
* A is taken to be in 0.16 fixed-point, and B is taken to be in 2.30 fixed-point.
* The answer will be in 16.16 fixed-point, unclipped.
*
* This function would probably be the prime candidate for SIMD conversion if
* you want more speed.
*/
int32_t fir_convolve(const int16_t* a, const int32_t* b, int num_samples)
{
int32_t sum = 1 << 13;
for (int i = 0; i < num_samples; ++i) {
sum += a[i] * (b[i] >> 16);
}
return sum >> 14;
}
/* Clip from 16.16 fixed-point to 0.16 fixed-point. */
int16_t clip(int32_t x)
{
if (x < -32768) {
return -32768;
} else if (x > 32767) {
return 32767;
} else {
return x;
}
}
/*
* Convert a chunk from 44 kHz to 22 kHz. Will update num_samples_in and num_samples_out
* accordingly, since it may leave input samples in the buffer due to overlap.
*
* Input and output are taken to be in 0.16 fixed-point.
*/
void resample_2_1(int16_t* input, int16_t* output, int* num_samples_in, int* num_samples_out)
{
if (*num_samples_in < (int)NUM_COEFF_22KHZ) {
*num_samples_out = 0;
return;
}
int odd_smp = *num_samples_in & 0x1;
int num_samples = *num_samples_in - odd_smp - OVERLAP_22KHZ;
for (int i = 0; i < num_samples; i += 2) {
output[i / 2] = clip(fir_convolve(input + i, filter_22khz_coeff, NUM_COEFF_22KHZ));
}
memmove(input, input + num_samples, (OVERLAP_22KHZ + odd_smp) * sizeof(*input));
*num_samples_out = num_samples / 2;
*num_samples_in = OVERLAP_22KHZ + odd_smp;
}
/*
* 2.30 fixed point FIR filter coefficients for conversion 22050 -> 16000,
* or 11025 -> 8000.
*
* Transition band from about 14 kHz, passband ripple < 0.1 dB,
* stopband ripple at about -50 dB, linear phase.
*
* Design and display in MATLAB or Octave using:
*
* filter = fir1(23, 16000 / 22050); filter = round(filter * 2**30); freqz(filter * 2**-30);
*/
static const int32_t filter_16khz_coeff[] = {
2057290, -2973608, 1880478, 4362037,
-14639744, 18523609, -1609189, -38502470,
78073125, -68353935, -59103896, 617555440,
617555440, -59103896, -68353935, 78073125,
-38502470, -1609189, 18523609, -14639744,
4362037, 1880478, -2973608, 2057290,
};
#define NUM_COEFF_16KHZ (sizeof(filter_16khz_coeff) / sizeof(filter_16khz_coeff[0]))
#define OVERLAP_16KHZ (NUM_COEFF_16KHZ - 1)
/*
* Convert a chunk from 22 kHz to 16 kHz. Will update num_samples_in and
* num_samples_out accordingly, since it may leave input samples in the buffer
* due to overlap.
*
* This implementation is rather ad-hoc; it first low-pass filters the data
* into a temporary buffer, and then converts chunks of 441 input samples at a
* time into 320 output samples by simple linear interpolation. A better
* implementation would use a polyphase filter bank to do these two operations
* in one step.
*
* Input and output are taken to be in 0.16 fixed-point.
*/
#define RESAMPLE_16KHZ_SAMPLES_IN 441
#define RESAMPLE_16KHZ_SAMPLES_OUT 320
void resample_441_320(int16_t* input, int16_t* output, int* num_samples_in, int* num_samples_out)
{
const int num_blocks = (*num_samples_in - OVERLAP_16KHZ) / RESAMPLE_16KHZ_SAMPLES_IN;
if (num_blocks < 1) {
*num_samples_out = 0;
return;
}
for (int i = 0; i < num_blocks; ++i) {
uint32_t tmp[RESAMPLE_16KHZ_SAMPLES_IN];
for (int j = 0; j < RESAMPLE_16KHZ_SAMPLES_IN; ++j) {
tmp[j] = fir_convolve(input + i * RESAMPLE_16KHZ_SAMPLES_IN + j,
filter_16khz_coeff,
NUM_COEFF_16KHZ);
}
const float step_float = (float)RESAMPLE_16KHZ_SAMPLES_IN / (float)RESAMPLE_16KHZ_SAMPLES_OUT;
uint32_t in_sample_num = 0; // 16.16 fixed point
const uint32_t step = (uint32_t)(step_float * 65536.0f + 0.5f); // 16.16 fixed point
for (int j = 0; j < RESAMPLE_16KHZ_SAMPLES_OUT; ++j, in_sample_num += step) {
const uint32_t whole = in_sample_num >> 16;
const uint32_t frac = (in_sample_num & 0xffff); // 0.16 fixed point
const int32_t s1 = tmp[whole];
const int32_t s2 = tmp[whole + 1];
*output++ = clip(s1 + (((s2 - s1) * (int32_t)frac) >> 16));
}
}
const int samples_consumed = num_blocks * RESAMPLE_16KHZ_SAMPLES_IN;
memmove(input, input + samples_consumed, (*num_samples_in - samples_consumed) * sizeof(*input));
*num_samples_in -= samples_consumed;
*num_samples_out = RESAMPLE_16KHZ_SAMPLES_OUT * num_blocks;
}
AudioHardware::DownSampler::DownSampler(uint32_t outSampleRate,
uint32_t inSampleRate,
uint32_t channelCount,
uint32_t frameCount,
AudioHardware::BufferProvider* provider)
: mStatus(NO_INIT), mProvider(provider), mSampleRate(outSampleRate),
mChannelCount(channelCount), mFrameCount(frameCount),
mTmpOutBuf(NULL),mInResampler(NULL)
{
ALOGV("AudioHardware::DownSampler() cstor %p SR %d channels %d frames %d",
this, mSampleRate, mChannelCount, mFrameCount);
if (mSampleRate != 8000 && mSampleRate != 11025 && mSampleRate != 12000&&mSampleRate != 16000 &&
mSampleRate != 22050 && mSampleRate != 24000 &&mSampleRate != 32000 && mSampleRate != 44100&& mSampleRate != 48000) {
ALOGW("AudioHardware::DownSampler cstor: bad sampling rate: %d", mSampleRate);
return;
}
mTmpOutBuf= new int16_t[mFrameCount*mChannelCount];
int error;
ALOGI("--->speex_resampler_init ch=%d in =%d,out =%d",mChannelCount,inSampleRate,mSampleRate);
mInResampler = speex_resampler_init(mChannelCount,
inSampleRate,
mSampleRate,
RESAMPLER_QUALITY,
&error);
if (mInResampler == NULL) {
ALOGW("Session_SetConfig Cannot create speex resampler: %s",
speex_resampler_strerror(error));
return ;
}
mStatus = NO_ERROR;
}
AudioHardware::DownSampler::~DownSampler()
{
if (mTmpOutBuf) delete[] mTmpOutBuf;
if (mInResampler) speex_resampler_destroy(mInResampler);
}
void AudioHardware::DownSampler::reset()
{
mOutBufPos = 0;
mInOutBuf = 0;
}
int AudioHardware::DownSampler::resample(int16_t* out, size_t *outFrameCount)
{
if (mStatus != NO_ERROR) {
return mStatus;
}
if (out == NULL || outFrameCount == NULL) {
return BAD_VALUE;
}
int outFrames = 0;
int remaingFrames = *outFrameCount;
if (mInOutBuf) {
//ALOGV("mInOutBuf = %d remaingFrames =%d",mInOutBuf,remaingFrames);
int frames = (remaingFrames > mInOutBuf) ? mInOutBuf : remaingFrames;
memcpy((void*)out, (void*)(mTmpOutBuf+mOutBufPos*mChannelCount),frames*mChannelCount*sizeof(int16_t));
remaingFrames -= frames;
mInOutBuf -= frames;
mOutBufPos += frames;
outFrames += frames;
}
while (remaingFrames) {
ALOGW_IF((mInOutBuf != 0), "mInOutBuf should be 0 here");
AudioHardware::BufferProvider::Buffer buf;
buf.frameCount = mFrameCount;
int ret = mProvider->getNextBuffer(&buf);
if (buf.raw == NULL) {
*outFrameCount = outFrames;
return ret;
}
uint inFrameCount = buf.frameCount;
uint outFrameCount = mFrameCount*mChannelCount;
//ALOGV("before resample inFrameCount = %d",inFrameCount);
if (mChannelCount == 1) {
speex_resampler_process_int(mInResampler,
0,
(const spx_int16_t *)buf.raw,
&inFrameCount,
mTmpOutBuf,
&outFrameCount);
} else {
speex_resampler_process_interleaved_int(mInResampler,
(const spx_int16_t *)buf.raw,
&inFrameCount,
mTmpOutBuf,
&outFrameCount);
}
//ALOGV("after resample inFrameCount use = %d outFrameCount = %d",inFrameCount,outFrameCount);
buf.frameCount = inFrameCount;
mProvider->releaseBuffer(&buf);
mInOutBuf = outFrameCount;
int frames = (remaingFrames > mInOutBuf) ? mInOutBuf : remaingFrames;
memcpy((void*)(out+outFrames*mChannelCount), (void*)mTmpOutBuf,frames*mChannelCount*sizeof(int16_t));
remaingFrames -= frames;
outFrames += frames;
mOutBufPos = frames;
mInOutBuf -= frames;
}
return 0;
}
//------------------------------------------------------------------------------
// Factory
//------------------------------------------------------------------------------
extern "C" AudioHardwareInterface* createAudioHardware(void) {
return new AudioHardware();
}
}; // namespace android