summaryrefslogtreecommitdiffstats
path: root/libaudio
diff options
context:
space:
mode:
authorEric Laurent <elaurent@google.com>2010-11-30 14:41:14 -0800
committerAndroid Git Automerger <android-git-automerger@android.com>2010-11-30 14:41:14 -0800
commitd59093ec60e6ae046722a132023d7cf15e3d690c (patch)
treeadfc01bd894def1f55325fa283a5116fe0cb0808 /libaudio
parente20c418e3bfc95cc821f601594ae9e9f42eaa398 (diff)
parent2739a5099838025963269b6ff0e448c9c8a3ba52 (diff)
downloaddevice_samsung_crespo-d59093ec60e6ae046722a132023d7cf15e3d690c.zip
device_samsung_crespo-d59093ec60e6ae046722a132023d7cf15e3d690c.tar.gz
device_samsung_crespo-d59093ec60e6ae046722a132023d7cf15e3d690c.tar.bz2
am 2739a509: Removed ALSA user space library and utilities
* commit '2739a5099838025963269b6ff0e448c9c8a3ba52': Removed ALSA user space library and utilities
Diffstat (limited to 'libaudio')
-rw-r--r--[-rwxr-xr-x]libaudio/Android.mk83
-rw-r--r--libaudio/AudioHardware.cpp2014
-rw-r--r--libaudio/AudioHardware.h348
-rwxr-xr-xlibaudio/AudioHardwareALSA.cpp2654
-rwxr-xr-xlibaudio/AudioHardwareALSA.h432
-rw-r--r--libaudio/AudioPolicyManager.cpp29
-rw-r--r--libaudio/AudioPolicyManager.h1
-rw-r--r--libaudio/NOTICE191
-rw-r--r--libaudio/alsa_audio.h77
-rw-r--r--libaudio/alsa_mixer.c371
-rw-r--r--libaudio/alsa_pcm.c405
-rw-r--r--libaudio/amix.c78
-rw-r--r--libaudio/aplay.c140
-rw-r--r--libaudio/arec.c128
-rw-r--r--libaudio/asound.h814
-rw-r--r--[-rwxr-xr-x]libaudio/secril-client.h3
16 files changed, 4441 insertions, 3327 deletions
diff --git a/libaudio/Android.mk b/libaudio/Android.mk
index 04f24e0..5ff0a21 100755..100644
--- a/libaudio/Android.mk
+++ b/libaudio/Android.mk
@@ -1,68 +1,53 @@
-# hardware/libaudio-alsa/Android.mk
-#
-# Copyright 2008 Wind River Systems
-#
+LOCAL_PATH:= $(call my-dir)
ifeq ($(TARGET_DEVICE),crespo)
-ifeq ($(BOARD_USES_ALSA_AUDIO),true)
-ifeq ($(filter-out s5pc110 s5pc100 s5p6440,$(TARGET_BOARD_PLATFORM)),)
-ifeq ($(BOARD_USES_GENERIC_AUDIO),false)
- LOCAL_PATH := $(call my-dir)
-
- include $(CLEAR_VARS)
-
- LOCAL_ARM_MODE := arm
- LOCAL_CFLAGS := -D_POSIX_SOURCE
- LOCAL_WHOLE_STATIC_LIBRARIES := libasound
-
- ifneq ($(ALSA_DEFAULT_SAMPLE_RATE),)
- LOCAL_CFLAGS += -DALSA_DEFAULT_SAMPLE_RATE=$(ALSA_DEFAULT_SAMPLE_RATE)
- endif
-
- LOCAL_C_INCLUDES += device/samsung/crespo/alsa-lib/include
- LOCAL_SRC_FILES := AudioHardwareALSA.cpp
-
- LOCAL_MODULE := libaudio
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES:= aplay.c alsa_pcm.c alsa_mixer.c
+LOCAL_MODULE:= aplay
+LOCAL_SHARED_LIBRARIES:= libc libcutils
+LOCAL_MODULE_TAGS:= debug
+include $(BUILD_EXECUTABLE)
- LOCAL_STATIC_LIBRARIES += libaudiointerface
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES:= arec.c alsa_pcm.c
+LOCAL_MODULE:= arec
+LOCAL_SHARED_LIBRARIES:= libc libcutils
+LOCAL_MODULE_TAGS:= debug
+include $(BUILD_EXECUTABLE)
- LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libutils \
- libmedia \
- libhardware_legacy \
- libdl \
- libc
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES:= amix.c alsa_mixer.c
+LOCAL_MODULE:= amix
+LOCAL_SHARED_LIBRARIES := libc libcutils
+LOCAL_MODULE_TAGS:= debug
+include $(BUILD_EXECUTABLE)
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES:= AudioHardware.cpp alsa_mixer.c alsa_pcm.c
+LOCAL_MODULE:= libaudio
+LOCAL_STATIC_LIBRARIES:= libaudiointerface
+LOCAL_SHARED_LIBRARIES:= libc libcutils libutils libmedia libhardware_legacy
ifeq ($(BOARD_HAVE_BLUETOOTH),true)
LOCAL_SHARED_LIBRARIES += liba2dp
endif
- include $(BUILD_SHARED_LIBRARY)
-
-# To build audiopolicy library
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- AudioPolicyManager.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libutils \
- libmedia
+ifeq ($(TARGET_SIMULATOR),true)
+ LOCAL_LDLIBS += -ldl
+else
+ LOCAL_SHARED_LIBRARIES += libdl
+endif
-LOCAL_STATIC_LIBRARIES := libaudiopolicybase
+include $(BUILD_SHARED_LIBRARY)
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES:= AudioPolicyManager.cpp
LOCAL_MODULE:= libaudiopolicy
-
+LOCAL_STATIC_LIBRARIES:= libaudiopolicybase
+LOCAL_SHARED_LIBRARIES:= libc libcutils libutils libmedia
ifeq ($(BOARD_HAVE_BLUETOOTH),true)
LOCAL_CFLAGS += -DWITH_A2DP
endif
-
include $(BUILD_SHARED_LIBRARY)
endif
-endif
-endif
-endif
diff --git a/libaudio/AudioHardware.cpp b/libaudio/AudioHardware.cpp
new file mode 100644
index 0000000..10409a1
--- /dev/null
+++ b/libaudio/AudioHardware.cpp
@@ -0,0 +1,2014 @@
+/*
+** 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.
+*/
+
+#include <math.h>
+
+//#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>
+
+extern "C" {
+#include "alsa_audio.h"
+}
+
+
+namespace android {
+
+const uint32_t AudioHardware::inputSamplingRates[] = {
+ 8000, 11025, 16000, 22050, 44100
+};
+
+// 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),
+ mMixer(NULL),
+ mPcmOpenCnt(0),
+ mMixerOpenCnt(0),
+ mInCallAudioMode(false),
+ mInputSource("Default"),
+ mBluetoothNrec(true),
+ mSecRilLibHandle(NULL),
+ mRilClient(0),
+ mActivatedCP(false),
+ mDriverOp(DRV_NONE)
+{
+ loadRILD();
+ mInit = true;
+}
+
+AudioHardware::~AudioHardware()
+{
+ for (size_t index = 0; index < mInputs.size(); index++) {
+ closeInputStream(mInputs[index].get());
+ }
+ mInputs.clear();
+ closeOutputStream((AudioStreamOut*)mOutput.get());
+
+ if (mMixer) {
+ TRACE_DRIVER_IN(DRV_MIXER_CLOSE)
+ mixer_close(mMixer);
+ TRACE_DRIVER_OUT
+ }
+ if (mPcm) {
+ TRACE_DRIVER_IN(DRV_PCM_CLOSE)
+ pcm_close(mPcm);
+ TRACE_DRIVER_OUT
+ }
+
+ if (mSecRilLibHandle) {
+ if (disconnectRILD(mRilClient) != RIL_CLIENT_ERR_SUCCESS)
+ LOGE("Disconnect_RILD() error");
+
+ if (closeClientRILD(mRilClient) != RIL_CLIENT_ERR_SUCCESS)
+ LOGE("CloseClient_RILD() error");
+
+ mRilClient = 0;
+
+ dlclose(mSecRilLibHandle);
+ mSecRilLibHandle = NULL;
+ }
+
+ 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) {
+ LOGV("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) {
+ LOGE("Can't load all functions from libsecril-client.so");
+
+ dlclose(mSecRilLibHandle);
+ mSecRilLibHandle = NULL;
+ } else {
+ mRilClient = openClientRILD();
+ if (!mRilClient) {
+ LOGE("OpenClient_RILD() error");
+
+ dlclose(mSecRilLibHandle);
+ mSecRilLibHandle = NULL;
+ }
+ }
+ } else {
+ LOGE("Can't load libsecril-client.so");
+ }
+}
+
+status_t AudioHardware::connectRILDIfRequired(void)
+{
+ if (!mSecRilLibHandle) {
+ LOGE("connectIfRequired() lib is not loaded");
+ return INVALID_OPERATION;
+ }
+
+ if (isConnectedRILD(mRilClient)) {
+ return OK;
+ }
+
+ if (connectRILD(mRilClient) != RIL_CLIENT_ERR_SUCCESS) {
+ LOGE("Connect_RILD() error");
+ return INVALID_OPERATION;
+ }
+
+ return OK;
+}
+
+AudioStreamOut* AudioHardware::openOutputStream(
+ uint32_t devices, int *format, uint32_t *channels,
+ uint32_t *sampleRate, status_t *status)
+{
+ sp <AudioStreamOutALSA> out;
+ status_t rc;
+
+ { // scope for the lock
+ 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();
+}
+
+void AudioHardware::closeOutputStream(AudioStreamOut* out) {
+ sp <AudioStreamOutALSA> spOut;
+ {
+ Mutex::Autolock lock(mLock);
+ if (mOutput == 0 || mOutput.get() != out) {
+ LOGW("Attempt to close invalid output stream");
+ return;
+ }
+ spOut = mOutput;
+ mOutput.clear();
+ }
+ spOut.clear();
+}
+
+AudioStreamIn* AudioHardware::openInputStream(
+ uint32_t devices, int *format, uint32_t *channels,
+ uint32_t *sampleRate, status_t *status,
+ AudioSystem::audio_in_acoustics acoustic_flags)
+{
+ // check for valid input source
+ if (!AudioSystem::isInputDevice((AudioSystem::audio_devices)devices)) {
+ if (status) {
+ *status = BAD_VALUE;
+ }
+ return NULL;
+ }
+
+ status_t rc = NO_ERROR;
+ sp <AudioStreamInALSA> in;
+
+ { // scope for the lock
+ 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;
+ }
+
+ LOGV("AudioHardware::openInputStream()%p", in.get());
+ return in.get();
+}
+
+void AudioHardware::closeInputStream(AudioStreamIn* in) {
+
+ sp<AudioStreamInALSA> spIn;
+ {
+ Mutex::Autolock lock(mLock);
+
+ ssize_t index = mInputs.indexOf((AudioStreamInALSA *)in);
+ if (index < 0) {
+ LOGW("Attempt to close invalid input stream");
+ return;
+ }
+ spIn = mInputs[index];
+ mInputs.removeAt(index);
+ }
+ LOGV("AudioHardware::closeInputStream()%p", in);
+ spIn.clear();
+}
+
+
+status_t AudioHardware::setMode(int mode)
+{
+ sp<AudioStreamOutALSA> spOut;
+ 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
+ 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();
+ }
+ }
+ // spOut is not 0 here only if the output is active
+
+ 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();
+ }
+ // spIn is not 0 here only if the input is active
+
+ setpriority(PRIO_PROCESS, 0, priority);
+
+ int prevMode = mMode;
+ status = AudioHardwareBase::setMode(mode);
+ LOGV("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;
+ }
+ }
+
+ if (mMode == AudioSystem::MODE_IN_CALL && !mInCallAudioMode) {
+ if (spOut != 0) {
+ LOGV("setMode() in call force output standby");
+ spOut->doStandby_l();
+ }
+ if (spIn != 0) {
+ LOGV("setMode() in call force input standby");
+ spIn->doStandby_l();
+ }
+
+ LOGV("setMode() openPcmOut_l()");
+ openPcmOut_l();
+ openMixer_l();
+ setInputSource_l(String8("Default"));
+ mInCallAudioMode = true;
+ }
+ if (mMode == AudioSystem::MODE_NORMAL && mInCallAudioMode) {
+ setInputSource_l(mInputSource);
+ if (mMixer != NULL) {
+ TRACE_DRIVER_IN(DRV_MIXER_GET)
+ struct mixer_ctl *ctl= mixer_get_control(mMixer, "Playback Path", 0);
+ TRACE_DRIVER_OUT
+ if (ctl != NULL) {
+ LOGV("setMode() reset Playback Path to RCV");
+ TRACE_DRIVER_IN(DRV_MIXER_SEL)
+ mixer_ctl_select(ctl, "RCV");
+ TRACE_DRIVER_OUT
+ }
+ }
+ LOGV("setMode() closePcmOut_l()");
+ closeMixer_l();
+ closePcmOut_l();
+
+ if (spOut != 0) {
+ LOGV("setMode() off call force output standby");
+ spOut->doStandby_l();
+ }
+ if (spIn != 0) {
+ LOGV("setMode() off call force input standby");
+ spIn->doStandby_l();
+ }
+
+ mInCallAudioMode = false;
+ }
+
+ 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)
+{
+ LOGV("setMicMute(%d) mMicMute %d", state, mMicMute);
+ sp<AudioStreamInALSA> spIn;
+ {
+ 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->standby();
+ }
+
+ 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;
+ LOGD("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();
+
+ LOGV("getParameters() %s", keys.string());
+
+ return reply.toString();
+}
+
+size_t AudioHardware::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
+{
+ if (format != AudioSystem::PCM_16_BIT) {
+ LOGW("getInputBufferSize bad format: %d", format);
+ return 0;
+ }
+ if (channelCount < 1 || channelCount > 2) {
+ LOGW("getInputBufferSize bad channel count: %d", channelCount);
+ return 0;
+ }
+ if (sampleRate != 8000 && sampleRate != 11025 && sampleRate != 16000 &&
+ sampleRate != 22050 && sampleRate != 44100) {
+ LOGW("getInputBufferSize bad sample rate: %d", sampleRate);
+ return 0;
+ }
+
+ return AudioStreamInALSA::getBufferSize(sampleRate, channelCount);
+}
+
+
+status_t AudioHardware::setVoiceVolume(float volume)
+{
+ LOGD("### setVoiceVolume");
+
+ AutoMutex lock(mLock);
+ if ( (AudioSystem::MODE_IN_CALL == mMode) && (mSecRilLibHandle) &&
+ (connectRILDIfRequired() == OK) ) {
+
+ uint32_t device = AudioSystem::DEVICE_OUT_EARPIECE;
+ if (mOutput != 0) {
+ device = mOutput->device();
+ }
+ int int_volume = (int)(volume * 5);
+ SoundType type;
+
+ LOGD("### route(%d) call volume(%f)", device, volume);
+ switch (device) {
+ case AudioSystem::DEVICE_OUT_EARPIECE:
+ LOGD("### earpiece call volume");
+ type = SOUND_TYPE_VOICE;
+ break;
+
+ case AudioSystem::DEVICE_OUT_SPEAKER:
+ LOGD("### speaker call volume");
+ type = SOUND_TYPE_SPEAKER;
+ break;
+
+ case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO:
+ case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
+ case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
+ LOGD("### bluetooth call volume");
+ type = SOUND_TYPE_BTVOICE;
+ break;
+
+ case AudioSystem::DEVICE_OUT_WIRED_HEADSET:
+ case AudioSystem::DEVICE_OUT_WIRED_HEADPHONE: // Use receive path with 3 pole headset.
+ LOGD("### headset call volume");
+ type = SOUND_TYPE_HEADSET;
+ break;
+
+ default:
+ LOGW("### Call volume setting error!!!0x%08x \n", device);
+ type = SOUND_TYPE_VOICE;
+ break;
+ }
+ setCallVolume(mRilClient, type, int_volume);
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioHardware::setMasterVolume(float volume)
+{
+ LOGV("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(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, "\tmMixer: %p\n", mMixer);
+ 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)
+{
+ LOGV("setIncallPath_l: device %x", device);
+
+ // Setup sound path for CP clocking
+ if ((mSecRilLibHandle) &&
+ (connectRILDIfRequired() == OK)) {
+
+ if (mMode == AudioSystem::MODE_IN_CALL) {
+ LOGD("### incall mode route (%d)", device);
+ AudioPath path;
+ switch(device){
+ case AudioSystem::DEVICE_OUT_EARPIECE:
+ LOGD("### incall mode earpiece route");
+ path = SOUND_AUDIO_PATH_HANDSET;
+ break;
+
+ case AudioSystem::DEVICE_OUT_SPEAKER:
+ LOGD("### incall mode speaker route");
+ path = SOUND_AUDIO_PATH_SPEAKER;
+ break;
+
+ case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO:
+ case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
+ case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
+ LOGD("### incall mode bluetooth route %s NR", mBluetoothNrec ? "" : "NO");
+ if (mBluetoothNrec) {
+ path = SOUND_AUDIO_PATH_BLUETOOTH;
+ } else {
+ path = SOUND_AUDIO_PATH_BLUETOOTH_NO_NR;
+ }
+ break;
+
+ case AudioSystem::DEVICE_OUT_WIRED_HEADPHONE :
+ LOGD("### incall mode headphone route");
+ path = SOUND_AUDIO_PATH_HEADPHONE;
+ break;
+
+ case AudioSystem::DEVICE_OUT_WIRED_HEADSET :
+ LOGD("### incall mode headset route");
+ path = SOUND_AUDIO_PATH_HEADSET;
+ break;
+
+ default:
+ LOGW("### incall mode Error!! route = [%d]", device);
+ path = SOUND_AUDIO_PATH_HANDSET;
+ break;
+ }
+
+ setCallAudioPath(mRilClient, path);
+
+ if (mMixer != NULL) {
+ TRACE_DRIVER_IN(DRV_MIXER_GET)
+ struct mixer_ctl *ctl= mixer_get_control(mMixer, "Voice Call Path", 0);
+ TRACE_DRIVER_OUT
+ LOGE_IF(ctl == NULL, "setIncallPath_l() could not get mixer ctl");
+ if (ctl != NULL) {
+ LOGV("setIncallPath_l() Voice Call Path, (%x)", device);
+ TRACE_DRIVER_IN(DRV_MIXER_SEL)
+ mixer_ctl_select(ctl, getVoiceRouteFromDevice(device));
+ TRACE_DRIVER_OUT
+ }
+ }
+ }
+ }
+ return NO_ERROR;
+}
+
+struct pcm *AudioHardware::openPcmOut_l()
+{
+ LOGD("openPcmOut_l() mPcmOpenCnt: %d", mPcmOpenCnt);
+ if (mPcmOpenCnt++ == 0) {
+ if (mPcm != NULL) {
+ LOGE("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;
+
+ TRACE_DRIVER_IN(DRV_PCM_OPEN)
+ mPcm = pcm_open(flags);
+ TRACE_DRIVER_OUT
+ if (!pcm_ready(mPcm)) {
+ LOGE("openPcmOut_l() cannot open pcm_out driver: %s\n", pcm_error(mPcm));
+ TRACE_DRIVER_IN(DRV_PCM_CLOSE)
+ pcm_close(mPcm);
+ TRACE_DRIVER_OUT
+ mPcmOpenCnt--;
+ mPcm = NULL;
+ }
+ }
+ return mPcm;
+}
+
+void AudioHardware::closePcmOut_l()
+{
+ LOGD("closePcmOut_l() mPcmOpenCnt: %d", mPcmOpenCnt);
+ if (mPcmOpenCnt == 0) {
+ LOGE("closePcmOut_l() mPcmOpenCnt == 0");
+ return;
+ }
+
+ if (--mPcmOpenCnt == 0) {
+ TRACE_DRIVER_IN(DRV_PCM_CLOSE)
+ pcm_close(mPcm);
+ TRACE_DRIVER_OUT
+ mPcm = NULL;
+ }
+}
+
+struct mixer *AudioHardware::openMixer_l()
+{
+ LOGV("openMixer_l() mMixerOpenCnt: %d", mMixerOpenCnt);
+ if (mMixerOpenCnt++ == 0) {
+ if (mMixer != NULL) {
+ LOGE("openMixer_l() mMixerOpenCnt == 0 and mMixer == %p\n", mMixer);
+ mMixerOpenCnt--;
+ return NULL;
+ }
+ TRACE_DRIVER_IN(DRV_MIXER_OPEN)
+ mMixer = mixer_open();
+ TRACE_DRIVER_OUT
+ if (mMixer == NULL) {
+ LOGE("openMixer_l() cannot open mixer");
+ mMixerOpenCnt--;
+ return NULL;
+ }
+ }
+ return mMixer;
+}
+
+void AudioHardware::closeMixer_l()
+{
+ LOGV("closeMixer_l() mMixerOpenCnt: %d", mMixerOpenCnt);
+ if (mMixerOpenCnt == 0) {
+ LOGE("closeMixer_l() mMixerOpenCnt == 0");
+ return;
+ }
+
+ if (--mMixerOpenCnt == 0) {
+ TRACE_DRIVER_IN(DRV_MIXER_CLOSE)
+ mixer_close(mMixer);
+ TRACE_DRIVER_OUT
+ mMixer = NULL;
+ }
+}
+
+const char *AudioHardware::getOutputRouteFromDevice(uint32_t device)
+{
+ switch (device) {
+ case AudioSystem::DEVICE_OUT_EARPIECE:
+ return "RCV";
+ case AudioSystem::DEVICE_OUT_SPEAKER:
+ if (mMode == AudioSystem::MODE_RINGTONE) return "RING_SPK";
+ else return "SPK";
+ case AudioSystem::DEVICE_OUT_WIRED_HEADPHONE:
+ if (mMode == AudioSystem::MODE_RINGTONE) return "RING_NO_MIC";
+ else return "HP_NO_MIC";
+ case AudioSystem::DEVICE_OUT_WIRED_HEADSET:
+ if (mMode == AudioSystem::MODE_RINGTONE) return "RING_HP";
+ else return "HP";
+ 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 "RING_SPK_HP";
+ else return "SPK_HP";
+ case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO:
+ case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
+ case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
+ return "BT";
+ default:
+ return "OFF";
+ }
+}
+
+const char *AudioHardware::getVoiceRouteFromDevice(uint32_t device)
+{
+ switch (device) {
+ case AudioSystem::DEVICE_OUT_EARPIECE:
+ return "RCV";
+ case AudioSystem::DEVICE_OUT_SPEAKER:
+ return "SPK";
+ case AudioSystem::DEVICE_OUT_WIRED_HEADPHONE:
+ return "HP_NO_MIC";
+ case AudioSystem::DEVICE_OUT_WIRED_HEADSET:
+ return "HP";
+ case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO:
+ case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
+ case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
+ return "BT";
+ default:
+ return "OFF";
+ }
+}
+
+const char *AudioHardware::getInputRouteFromDevice(uint32_t device)
+{
+ if (mMicMute) {
+ return "MIC OFF";
+ }
+
+ switch (device) {
+ case AudioSystem::DEVICE_IN_BUILTIN_MIC:
+ return "Main Mic";
+ case AudioSystem::DEVICE_IN_WIRED_HEADSET:
+ return "Hands Free Mic";
+ case AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET:
+ return "BT Sco Mic";
+ default:
+ return "MIC OFF";
+ }
+}
+
+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
+sp <AudioHardware::AudioStreamInALSA> AudioHardware::getActiveInput_l()
+{
+ 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)
+{
+ LOGV("setInputSource_l(%s)", source.string());
+ if (source != mInputSource) {
+ if ((source == "Default") || (mMode != AudioSystem::MODE_IN_CALL)) {
+ if (mMixer) {
+ TRACE_DRIVER_IN(DRV_MIXER_GET)
+ struct mixer_ctl *ctl= mixer_get_control(mMixer, "Input Source", 0);
+ TRACE_DRIVER_OUT
+ if (ctl == NULL) {
+ return NO_INIT;
+ }
+ LOGV("mixer_ctl_select, Input Source, (%s)", source.string());
+ TRACE_DRIVER_IN(DRV_MIXER_SEL)
+ mixer_ctl_select(ctl, source.string());
+ TRACE_DRIVER_OUT
+ }
+ }
+ mInputSource = source;
+ }
+
+ return NO_ERROR;
+}
+
+
+//------------------------------------------------------------------------------
+// AudioStreamOutALSA
+//------------------------------------------------------------------------------
+
+AudioHardware::AudioStreamOutALSA::AudioStreamOutALSA() :
+ mHardware(0), mPcm(0), mMixer(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)
+{
+}
+
+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();
+
+ // check values
+ if ((lFormat != format()) ||
+ (lChannels != channels()) ||
+ (lRate != sampleRate())) {
+ if (pFormat) *pFormat = format();
+ if (pChannels) *pChannels = channels();
+ if (pRate) *pRate = sampleRate();
+ return BAD_VALUE;
+ }
+
+ if (pFormat) *pFormat = lFormat;
+ if (pChannels) *pChannels = lChannels;
+ if (pRate) *pRate = lRate;
+
+ mChannels = lChannels;
+ mSampleRate = lRate;
+ mBufferSize = AUDIO_HW_OUT_PERIOD_BYTES;
+
+ return NO_ERROR;
+}
+
+AudioHardware::AudioStreamOutALSA::~AudioStreamOutALSA()
+{
+ standby();
+}
+
+ssize_t AudioHardware::AudioStreamOutALSA::write(const void* buffer, size_t bytes)
+{
+ // LOGV("AudioStreamOutALSA::write(%p, %u)", buffer, bytes);
+ status_t status = NO_INIT;
+ const uint8_t* p = static_cast<const uint8_t*>(buffer);
+ int ret;
+
+ if (mHardware == NULL) return NO_INIT;
+
+ { // scope for the lock
+
+ AutoMutex lock(mLock);
+
+ if (mStandby) {
+ AutoMutex hwLock(mHardware->lock());
+
+ LOGD("AudioHardware pcm playback is exiting standby.");
+ acquire_wake_lock (PARTIAL_WAKE_LOCK, "AudioOutLock");
+
+ 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())) {
+ LOGV("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 (mPcm == NULL) {
+ release_wake_lock("AudioOutLock");
+ goto Error;
+ }
+ mStandby = false;
+ }
+
+ TRACE_DRIVER_IN(DRV_PCM_WRITE)
+ ret = pcm_write(mPcm,(void*) p, bytes);
+ TRACE_DRIVER_OUT
+
+ if (ret == 0) {
+ return bytes;
+ }
+ LOGW("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;
+
+ AutoMutex lock(mLock);
+
+ { // scope for the AudioHardware lock
+ AutoMutex hwLock(mHardware->lock());
+
+ doStandby_l();
+ }
+
+ return NO_ERROR;
+}
+
+void AudioHardware::AudioStreamOutALSA::doStandby_l()
+{
+ mStandbyCnt++;
+
+ if (!mStandby) {
+ LOGD("AudioHardware pcm playback is going to standby.");
+ release_wake_lock("AudioOutLock");
+ mStandby = true;
+ }
+
+ close_l();
+}
+
+void AudioHardware::AudioStreamOutALSA::close_l()
+{
+ if (mMixer) {
+ mHardware->closeMixer_l();
+ mMixer = NULL;
+ mRouteCtl = NULL;
+ }
+ if (mPcm) {
+ mHardware->closePcmOut_l();
+ mPcm = NULL;
+ }
+}
+
+status_t AudioHardware::AudioStreamOutALSA::open_l()
+{
+ LOGV("open pcm_out driver");
+ mPcm = mHardware->openPcmOut_l();
+ if (mPcm == NULL) {
+ return NO_INIT;
+ }
+
+ mMixer = mHardware->openMixer_l();
+ if (mMixer) {
+ LOGV("open playback normal");
+ TRACE_DRIVER_IN(DRV_MIXER_GET)
+ mRouteCtl = mixer_get_control(mMixer, "Playback Path", 0);
+ TRACE_DRIVER_OUT
+ }
+ if (mHardware->mode() != AudioSystem::MODE_IN_CALL) {
+ const char *route = mHardware->getOutputRouteFromDevice(mDevices);
+ LOGV("write() wakeup setting route %s", route);
+ if (mRouteCtl) {
+ TRACE_DRIVER_IN(DRV_MIXER_SEL)
+ mixer_ctl_select(mRouteCtl, route);
+ TRACE_DRIVER_OUT
+ }
+ }
+ 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\tmPcm: %p\n", mPcm);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\t\tmMixer: %p\n", mMixer);
+ 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 device;
+ LOGD("AudioStreamOutALSA::setParameters() %s", keyValuePairs.string());
+
+ if (mHardware == NULL) return NO_INIT;
+
+ {
+ AutoMutex lock(mLock);
+
+ if (param.getInt(String8(AudioParameter::keyRouting), device) == NO_ERROR)
+ {
+ AutoMutex hwLock(mHardware->lock());
+
+ if (mDevices != (uint32_t)device) {
+ mDevices = (uint32_t)device;
+ if (mHardware->mode() != AudioSystem::MODE_IN_CALL) {
+ doStandby_l();
+ }
+ }
+ if (mHardware->mode() == AudioSystem::MODE_IN_CALL) {
+ mHardware->setIncallPath_l(device);
+ }
+ param.remove(String8(AudioParameter::keyRouting));
+ }
+ }
+
+ 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);
+ }
+
+ LOGV("AudioStreamOutALSA::getParameters() %s", param.toString().string());
+ return param.toString();
+}
+
+status_t AudioHardware::AudioStreamOutALSA::getRenderPosition(uint32_t *dspFrames)
+{
+ //TODO
+ return INVALID_OPERATION;
+}
+
+//------------------------------------------------------------------------------
+// AudioStreamInALSA
+//------------------------------------------------------------------------------
+
+AudioHardware::AudioStreamInALSA::AudioStreamInALSA() :
+ mHardware(0), mPcm(0), mMixer(0), mRouteCtl(0),
+ mStandby(true), mDevices(0), mChannels(AUDIO_HW_IN_CHANNELS), mChannelCount(1),
+ mSampleRate(AUDIO_HW_IN_SAMPLERATE), mBufferSize(AUDIO_HW_IN_PERIOD_BYTES),
+ mDownSampler(NULL), mReadStatus(NO_ERROR), mDriverOp(DRV_NONE),
+ mStandbyCnt(0)
+{
+}
+
+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;
+ }
+ uint32_t rate = AudioHardware::getInputSampleRate(*pRate);
+ if (rate != *pRate) {
+ *pRate = rate;
+ return BAD_VALUE;
+ }
+
+ if (pChannels == 0 || (*pChannels != AudioSystem::CHANNEL_IN_MONO &&
+ *pChannels != AudioSystem::CHANNEL_IN_STEREO)) {
+ *pChannels = AUDIO_HW_IN_CHANNELS;
+ return BAD_VALUE;
+ }
+
+ mHardware = hw;
+
+ LOGV("AudioStreamInALSA::set(%d, %d, %u)", *pFormat, *pChannels, *pRate);
+
+ mBufferSize = getBufferSize(*pRate, AudioSystem::popCount(*pChannels));
+ mDevices = devices;
+ mChannels = *pChannels;
+ mChannelCount = AudioSystem::popCount(mChannels);
+ mSampleRate = rate;
+ if (mSampleRate != AUDIO_HW_OUT_SAMPLERATE) {
+ mDownSampler = new AudioHardware::DownSampler(mSampleRate,
+ mChannelCount,
+ AUDIO_HW_IN_PERIOD_SZ,
+ this);
+ status_t status = mDownSampler->initCheck();
+ if (status != NO_ERROR) {
+ delete mDownSampler;
+ LOGW("AudioStreamInALSA::set() downsampler init failed: %d", status);
+ return status;
+ }
+
+ mPcmIn = new int16_t[AUDIO_HW_IN_PERIOD_SZ * mChannelCount];
+ }
+ return NO_ERROR;
+}
+
+AudioHardware::AudioStreamInALSA::~AudioStreamInALSA()
+{
+ standby();
+ if (mDownSampler != NULL) {
+ delete mDownSampler;
+ if (mPcmIn != NULL) {
+ delete[] mPcmIn;
+ }
+ }
+}
+
+ssize_t AudioHardware::AudioStreamInALSA::read(void* buffer, ssize_t bytes)
+{
+ // LOGV("AudioStreamInALSA::read(%p, %u)", buffer, bytes);
+ status_t status = NO_INIT;
+ int ret;
+
+ if (mHardware == NULL) return NO_INIT;
+
+ { // scope for the lock
+ AutoMutex lock(mLock);
+
+ if (mStandby) {
+ AutoMutex hwLock(mHardware->lock());
+
+ LOGD("AudioHardware pcm capture is exiting standby.");
+ acquire_wake_lock (PARTIAL_WAKE_LOCK, "AudioInLock");
+
+ 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())) {
+ LOGV("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) {
+ return bytes;
+ }
+
+ LOGW("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;
+
+ AutoMutex lock(mLock);
+
+ { // scope for AudioHardware lock
+ AutoMutex hwLock(mHardware->lock());
+
+ doStandby_l();
+ }
+ return NO_ERROR;
+}
+
+void AudioHardware::AudioStreamInALSA::doStandby_l()
+{
+ mStandbyCnt++;
+
+ if (!mStandby) {
+ LOGD("AudioHardware pcm capture is going to standby.");
+ release_wake_lock("AudioInLock");
+ mStandby = true;
+ }
+ close_l();
+}
+
+void AudioHardware::AudioStreamInALSA::close_l()
+{
+ if (mMixer) {
+ mHardware->closeMixer_l();
+ mMixer = NULL;
+ mRouteCtl = NULL;
+ }
+
+ if (mPcm) {
+ TRACE_DRIVER_IN(DRV_PCM_CLOSE)
+ pcm_close(mPcm);
+ TRACE_DRIVER_OUT
+ mPcm = NULL;
+ }
+}
+
+status_t AudioHardware::AudioStreamInALSA::open_l()
+{
+ unsigned flags = PCM_IN;
+ if (mChannels == AudioSystem::CHANNEL_IN_MONO) {
+ flags |= PCM_MONO;
+ }
+ flags |= (AUDIO_HW_IN_PERIOD_MULT - 1) << PCM_PERIOD_SZ_SHIFT;
+ flags |= (AUDIO_HW_IN_PERIOD_CNT - PCM_PERIOD_CNT_MIN)
+ << PCM_PERIOD_CNT_SHIFT;
+
+ LOGV("open pcm_in driver");
+ TRACE_DRIVER_IN(DRV_PCM_OPEN)
+ mPcm = pcm_open(flags);
+ TRACE_DRIVER_OUT
+ if (!pcm_ready(mPcm)) {
+ LOGE("cannot open pcm_in driver: %s\n", pcm_error(mPcm));
+ TRACE_DRIVER_IN(DRV_PCM_CLOSE)
+ pcm_close(mPcm);
+ TRACE_DRIVER_OUT
+ mPcm = NULL;
+ return NO_INIT;
+ }
+
+ if (mDownSampler != NULL) {
+ mInPcmInBuf = 0;
+ mDownSampler->reset();
+ }
+
+ mMixer = mHardware->openMixer_l();
+ if (mMixer) {
+ TRACE_DRIVER_IN(DRV_MIXER_GET)
+ mRouteCtl = mixer_get_control(mMixer, "Capture MIC Path", 0);
+ TRACE_DRIVER_OUT
+ }
+
+ if (mHardware->mode() != AudioSystem::MODE_IN_CALL) {
+ const char *route = mHardware->getInputRouteFromDevice(mDevices);
+ LOGV("read() wakeup setting route %s", route);
+ if (mRouteCtl) {
+ TRACE_DRIVER_IN(DRV_MIXER_SEL)
+ mixer_ctl_select(mRouteCtl, route);
+ 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\tmMixer: %p\n", mMixer);
+ 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;
+
+ LOGD("AudioStreamInALSA::setParameters() %s", keyValuePairs.string());
+
+ if (mHardware == NULL) return NO_INIT;
+
+ {
+ AutoMutex lock(mLock);
+
+ if (param.get(String8(INPUT_SOURCE_KEY), source) == NO_ERROR) {
+ AutoMutex hwLock(mHardware->lock());
+
+ mHardware->openMixer_l();
+ mHardware->setInputSource_l(source);
+ mHardware->closeMixer_l();
+
+ param.remove(String8(INPUT_SOURCE_KEY));
+ }
+
+ if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR)
+ {
+ if (value != 0) {
+ AutoMutex hwLock(mHardware->lock());
+
+ if (mDevices != (uint32_t)value) {
+ mDevices = (uint32_t)value;
+ if (mHardware->mode() != AudioSystem::MODE_IN_CALL) {
+ doStandby_l();
+ }
+ }
+ }
+ param.remove(String8(AudioParameter::keyRouting));
+ }
+ }
+
+
+ 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);
+ }
+
+ LOGV("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());
+ TRACE_DRIVER_OUT
+ if (mReadStatus != 0) {
+ buffer->raw = NULL;
+ buffer->frameCount = 0;
+ return mReadStatus;
+ }
+ mInPcmInBuf = AUDIO_HW_IN_PERIOD_SZ;
+ }
+
+ buffer->frameCount = (buffer->frameCount > mInPcmInBuf) ? mInPcmInBuf : buffer->frameCount;
+ buffer->i16 = mPcmIn + (AUDIO_HW_IN_PERIOD_SZ - 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:
+ ratio = 4;
+ break;
+ case 16000:
+ case 22050:
+ ratio = 2;
+ break;
+ case 44100:
+ 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 channelCount,
+ uint32_t frameCount,
+ AudioHardware::BufferProvider* provider)
+ : mStatus(NO_INIT), mProvider(provider), mSampleRate(outSampleRate),
+ mChannelCount(channelCount), mFrameCount(frameCount),
+ mInLeft(NULL), mInRight(NULL), mTmpLeft(NULL), mTmpRight(NULL),
+ mTmp2Left(NULL), mTmp2Right(NULL), mOutLeft(NULL), mOutRight(NULL)
+
+{
+ LOGV("AudioHardware::DownSampler() cstor %p SR %d channels %d frames %d",
+ this, mSampleRate, mChannelCount, mFrameCount);
+
+ if (mSampleRate != 8000 && mSampleRate != 11025 && mSampleRate != 16000 &&
+ mSampleRate != 22050) {
+ LOGW("AudioHardware::DownSampler cstor: bad sampling rate: %d", mSampleRate);
+ return;
+ }
+
+ mInLeft = new int16_t[mFrameCount];
+ mInRight = new int16_t[mFrameCount];
+ mTmpLeft = new int16_t[mFrameCount];
+ mTmpRight = new int16_t[mFrameCount];
+ mTmp2Left = new int16_t[mFrameCount];
+ mTmp2Right = new int16_t[mFrameCount];
+ mOutLeft = new int16_t[mFrameCount];
+ mOutRight = new int16_t[mFrameCount];
+
+ mStatus = NO_ERROR;
+}
+
+AudioHardware::DownSampler::~DownSampler()
+{
+ if (mInLeft) delete[] mInLeft;
+ if (mInRight) delete[] mInRight;
+ if (mTmpLeft) delete[] mTmpLeft;
+ if (mTmpRight) delete[] mTmpRight;
+ if (mTmp2Left) delete[] mTmp2Left;
+ if (mTmp2Right) delete[] mTmp2Right;
+ if (mOutLeft) delete[] mOutLeft;
+ if (mOutRight) delete[] mOutRight;
+}
+
+void AudioHardware::DownSampler::reset()
+{
+ mInInBuf = 0;
+ mInTmpBuf = 0;
+ mInTmp2Buf = 0;
+ 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;
+ }
+
+ int16_t *outLeft = mTmp2Left;
+ int16_t *outRight = mTmp2Left;
+ if (mSampleRate == 22050) {
+ outLeft = mTmpLeft;
+ outRight = mTmpRight;
+ } else if (mSampleRate == 8000){
+ outLeft = mOutLeft;
+ outRight = mOutRight;
+ }
+
+ int outFrames = 0;
+ int remaingFrames = *outFrameCount;
+
+ if (mInOutBuf) {
+ int frames = (remaingFrames > mInOutBuf) ? mInOutBuf : remaingFrames;
+
+ for (int i = 0; i < frames; ++i) {
+ out[i] = outLeft[mOutBufPos + i];
+ }
+ if (mChannelCount == 2) {
+ for (int i = 0; i < frames; ++i) {
+ out[i * 2] = outLeft[mOutBufPos + i];
+ out[i * 2 + 1] = outRight[mOutBufPos + i];
+ }
+ }
+ remaingFrames -= frames;
+ mInOutBuf -= frames;
+ mOutBufPos += frames;
+ outFrames += frames;
+ }
+
+ while (remaingFrames) {
+ LOGW_IF((mInOutBuf != 0), "mInOutBuf should be 0 here");
+
+ AudioHardware::BufferProvider::Buffer buf;
+ buf.frameCount = mFrameCount - mInInBuf;
+ int ret = mProvider->getNextBuffer(&buf);
+ if (buf.raw == NULL) {
+ *outFrameCount = outFrames;
+ return ret;
+ }
+
+ for (size_t i = 0; i < buf.frameCount; ++i) {
+ mInLeft[i + mInInBuf] = buf.i16[i];
+ }
+ if (mChannelCount == 2) {
+ for (size_t i = 0; i < buf.frameCount; ++i) {
+ mInLeft[i + mInInBuf] = buf.i16[i * 2];
+ mInRight[i + mInInBuf] = buf.i16[i * 2 + 1];
+ }
+ }
+ mInInBuf += buf.frameCount;
+ mProvider->releaseBuffer(&buf);
+
+ /* 44010 -> 22050 */
+ {
+ int samples_in_left = mInInBuf;
+ int samples_out_left;
+ resample_2_1(mInLeft, mTmpLeft + mInTmpBuf, &samples_in_left, &samples_out_left);
+
+ if (mChannelCount == 2) {
+ int samples_in_right = mInInBuf;
+ int samples_out_right;
+ resample_2_1(mInRight, mTmpRight + mInTmpBuf, &samples_in_right, &samples_out_right);
+ }
+
+ mInInBuf = samples_in_left;
+ mInTmpBuf += samples_out_left;
+ mInOutBuf = samples_out_left;
+ }
+
+ if (mSampleRate == 11025 || mSampleRate == 8000) {
+ /* 22050 - > 11025 */
+ int samples_in_left = mInTmpBuf;
+ int samples_out_left;
+ resample_2_1(mTmpLeft, mTmp2Left + mInTmp2Buf, &samples_in_left, &samples_out_left);
+
+ if (mChannelCount == 2) {
+ int samples_in_right = mInTmpBuf;
+ int samples_out_right;
+ resample_2_1(mTmpRight, mTmp2Right + mInTmp2Buf, &samples_in_right, &samples_out_right);
+ }
+
+
+ mInTmpBuf = samples_in_left;
+ mInTmp2Buf += samples_out_left;
+ mInOutBuf = samples_out_left;
+
+ if (mSampleRate == 8000) {
+ /* 11025 -> 8000*/
+ int samples_in_left = mInTmp2Buf;
+ int samples_out_left;
+ resample_441_320(mTmp2Left, mOutLeft, &samples_in_left, &samples_out_left);
+
+ if (mChannelCount == 2) {
+ int samples_in_right = mInTmp2Buf;
+ int samples_out_right;
+ resample_441_320(mTmp2Right, mOutRight, &samples_in_right, &samples_out_right);
+ }
+
+ mInTmp2Buf = samples_in_left;
+ mInOutBuf = samples_out_left;
+ } else {
+ mInTmp2Buf = 0;
+ }
+
+ } else if (mSampleRate == 16000) {
+ /* 22050 -> 16000*/
+ int samples_in_left = mInTmpBuf;
+ int samples_out_left;
+ resample_441_320(mTmpLeft, mTmp2Left, &samples_in_left, &samples_out_left);
+
+ if (mChannelCount == 2) {
+ int samples_in_right = mInTmpBuf;
+ int samples_out_right;
+ resample_441_320(mTmpRight, mTmp2Right, &samples_in_right, &samples_out_right);
+ }
+
+ mInTmpBuf = samples_in_left;
+ mInOutBuf = samples_out_left;
+ } else {
+ mInTmpBuf = 0;
+ }
+
+ int frames = (remaingFrames > mInOutBuf) ? mInOutBuf : remaingFrames;
+
+ for (int i = 0; i < frames; ++i) {
+ out[outFrames + i] = outLeft[i];
+ }
+ if (mChannelCount == 2) {
+ for (int i = 0; i < frames; ++i) {
+ out[(outFrames + i) * 2] = outLeft[i];
+ out[(outFrames + i) * 2 + 1] = outRight[i];
+ }
+ }
+ remaingFrames -= frames;
+ outFrames += frames;
+ mOutBufPos = frames;
+ mInOutBuf -= frames;
+ }
+
+ return 0;
+}
+
+
+
+
+
+
+
+//------------------------------------------------------------------------------
+// Factory
+//------------------------------------------------------------------------------
+
+extern "C" AudioHardwareInterface* createAudioHardware(void) {
+ return new AudioHardware();
+}
+
+}; // namespace android
diff --git a/libaudio/AudioHardware.h b/libaudio/AudioHardware.h
new file mode 100644
index 0000000..1379495
--- /dev/null
+++ b/libaudio/AudioHardware.h
@@ -0,0 +1,348 @@
+/*
+** Copyright 2008, 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.
+*/
+
+#ifndef ANDROID_AUDIO_HARDWARE_H
+#define ANDROID_AUDIO_HARDWARE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/threads.h>
+#include <utils/SortedVector.h>
+
+#include <hardware_legacy/AudioHardwareBase.h>
+
+#include "secril-client.h"
+
+extern "C" {
+ struct pcm;
+ struct mixer;
+ struct mixer_ctl;
+};
+
+namespace android {
+
+// TODO: determine actual audio DSP and hardware latency
+// Additionnal latency introduced by audio DSP and hardware in ms
+#define AUDIO_HW_OUT_LATENCY_MS 0
+// Default audio output sample rate
+#define AUDIO_HW_OUT_SAMPLERATE 44100
+// Default audio output channel mask
+#define AUDIO_HW_OUT_CHANNELS (AudioSystem::CHANNEL_OUT_STEREO)
+// Default audio output sample format
+#define AUDIO_HW_OUT_FORMAT (AudioSystem::PCM_16_BIT)
+// Kernel pcm out buffer size in frames at 44.1kHz
+#define AUDIO_HW_OUT_PERIOD_MULT 8 // (8 * 128 = 1024 frames)
+#define AUDIO_HW_OUT_PERIOD_SZ (PCM_PERIOD_SZ_MIN * AUDIO_HW_OUT_PERIOD_MULT)
+#define AUDIO_HW_OUT_PERIOD_CNT 4
+// Default audio output buffer size in bytes
+#define AUDIO_HW_OUT_PERIOD_BYTES (AUDIO_HW_OUT_PERIOD_SZ * 2 * sizeof(int16_t))
+
+// Default audio input sample rate
+#define AUDIO_HW_IN_SAMPLERATE 8000
+// Default audio input channel mask
+#define AUDIO_HW_IN_CHANNELS (AudioSystem::CHANNEL_IN_MONO)
+// Default audio input sample format
+#define AUDIO_HW_IN_FORMAT (AudioSystem::PCM_16_BIT)
+// Number of buffers in audio driver for input
+#define AUDIO_HW_NUM_IN_BUF 2
+// Kernel pcm in buffer size in frames at 44.1kHz (before resampling)
+#define AUDIO_HW_IN_PERIOD_MULT 16 // (16 * 128 = 2048 frames)
+#define AUDIO_HW_IN_PERIOD_SZ (PCM_PERIOD_SZ_MIN * AUDIO_HW_IN_PERIOD_MULT)
+#define AUDIO_HW_IN_PERIOD_CNT 2
+// Default audio input buffer size in bytes (8kHz mono)
+#define AUDIO_HW_IN_PERIOD_BYTES ((AUDIO_HW_IN_PERIOD_SZ*sizeof(int16_t))/8)
+
+#define INPUT_SOURCE_KEY "Input Source"
+
+class AudioHardware : public AudioHardwareBase
+{
+ class AudioStreamOutALSA;
+ class AudioStreamInALSA;
+public:
+
+ AudioHardware();
+ virtual ~AudioHardware();
+ virtual status_t initCheck();
+
+ virtual status_t setVoiceVolume(float volume);
+ virtual status_t setMasterVolume(float volume);
+
+ virtual status_t setMode(int mode);
+
+ virtual status_t setMicMute(bool state);
+ virtual status_t getMicMute(bool* state);
+
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
+
+ virtual AudioStreamOut* openOutputStream(
+ uint32_t devices, int *format=0, uint32_t *channels=0,
+ uint32_t *sampleRate=0, status_t *status=0);
+
+ virtual AudioStreamIn* openInputStream(
+ uint32_t devices, int *format, uint32_t *channels,
+ uint32_t *sampleRate, status_t *status,
+ AudioSystem::audio_in_acoustics acoustics);
+
+ virtual void closeOutputStream(AudioStreamOut* out);
+ virtual void closeInputStream(AudioStreamIn* in);
+
+ virtual size_t getInputBufferSize(
+ uint32_t sampleRate, int format, int channelCount);
+
+ int mode() { return mMode; }
+ const char *getOutputRouteFromDevice(uint32_t device);
+ const char *getInputRouteFromDevice(uint32_t device);
+ const char *getVoiceRouteFromDevice(uint32_t device);
+
+ status_t setIncallPath_l(uint32_t device);
+
+ status_t setInputSource_l(String8 source);
+
+ static uint32_t getInputSampleRate(uint32_t sampleRate);
+ sp <AudioStreamInALSA> getActiveInput_l();
+
+ Mutex& lock() { return mLock; }
+
+ struct pcm *openPcmOut_l();
+ void closePcmOut_l();
+
+ struct mixer *openMixer_l();
+ void closeMixer_l();
+
+ sp <AudioStreamOutALSA> output() { return mOutput; }
+
+protected:
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+private:
+
+ bool mInit;
+ bool mMicMute;
+ sp <AudioStreamOutALSA> mOutput;
+ SortedVector < sp<AudioStreamInALSA> > mInputs;
+ Mutex mLock;
+ struct pcm* mPcm;
+ struct mixer* mMixer;
+ uint32_t mPcmOpenCnt;
+ uint32_t mMixerOpenCnt;
+ bool mInCallAudioMode;
+
+ String8 mInputSource;
+ bool mBluetoothNrec;
+ void* mSecRilLibHandle;
+ HRilClient mRilClient;
+ bool mActivatedCP;
+ HRilClient (*openClientRILD) (void);
+ int (*disconnectRILD) (HRilClient);
+ int (*closeClientRILD) (HRilClient);
+ int (*isConnectedRILD) (HRilClient);
+ int (*connectRILD) (HRilClient);
+ int (*setCallVolume) (HRilClient, SoundType, int);
+ int (*setCallAudioPath)(HRilClient, AudioPath);
+ int (*setCallClockSync)(HRilClient, SoundClockCondition);
+ void loadRILD(void);
+ status_t connectRILDIfRequired(void);
+
+ // trace driver operations for dump
+ int mDriverOp;
+
+ static uint32_t checkInputSampleRate(uint32_t sampleRate);
+ static const uint32_t inputSamplingRates[];
+
+ class AudioStreamOutALSA : public AudioStreamOut, public RefBase
+ {
+ public:
+ AudioStreamOutALSA();
+ virtual ~AudioStreamOutALSA();
+ status_t set(AudioHardware* mHardware,
+ uint32_t devices,
+ int *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pRate);
+ virtual uint32_t sampleRate()
+ const { return mSampleRate; }
+ virtual size_t bufferSize()
+ const { return mBufferSize; }
+ virtual uint32_t channels()
+ const { return mChannels; }
+ virtual int format()
+ const { return AUDIO_HW_OUT_FORMAT; }
+ virtual uint32_t latency()
+ const { return (1000 * AUDIO_HW_OUT_PERIOD_CNT *
+ (bufferSize()/frameSize()))/sampleRate() +
+ AUDIO_HW_OUT_LATENCY_MS; }
+ virtual status_t setVolume(float left, float right)
+ { return INVALID_OPERATION; }
+ virtual ssize_t write(const void* buffer, size_t bytes);
+ virtual status_t standby();
+ bool checkStandby();
+
+ virtual status_t dump(int fd, const Vector<String16>& args);
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
+ uint32_t device() { return mDevices; }
+ virtual status_t getRenderPosition(uint32_t *dspFrames);
+
+ void doStandby_l();
+ void close_l();
+ status_t open_l();
+ int standbyCnt() { return mStandbyCnt; }
+
+ void lock() { mLock.lock(); }
+ void unlock() { mLock.unlock(); }
+
+ private:
+
+ Mutex mLock;
+ AudioHardware* mHardware;
+ struct pcm *mPcm;
+ struct mixer *mMixer;
+ struct mixer_ctl *mRouteCtl;
+ const char *next_route;
+ bool mStandby;
+ uint32_t mDevices;
+ uint32_t mChannels;
+ uint32_t mSampleRate;
+ size_t mBufferSize;
+ // trace driver operations for dump
+ int mDriverOp;
+ int mStandbyCnt;
+ };
+
+ class DownSampler;
+
+ class BufferProvider
+ {
+ public:
+
+ struct Buffer {
+ union {
+ void* raw;
+ short* i16;
+ int8_t* i8;
+ };
+ size_t frameCount;
+ };
+
+ virtual ~BufferProvider() {}
+
+ virtual status_t getNextBuffer(Buffer* buffer) = 0;
+ virtual void releaseBuffer(Buffer* buffer) = 0;
+ };
+
+ class DownSampler {
+ public:
+ DownSampler(uint32_t outSampleRate,
+ uint32_t channelCount,
+ uint32_t frameCount,
+ BufferProvider* provider);
+
+ virtual ~DownSampler();
+
+ void reset();
+ status_t initCheck() { return mStatus; }
+ int resample(int16_t* out, size_t *outFrameCount);
+
+ private:
+ status_t mStatus;
+ BufferProvider* mProvider;
+ uint32_t mSampleRate;
+ uint32_t mChannelCount;
+ uint32_t mFrameCount;
+ int16_t *mInLeft;
+ int16_t *mInRight;
+ int16_t *mTmpLeft;
+ int16_t *mTmpRight;
+ int16_t *mTmp2Left;
+ int16_t *mTmp2Right;
+ int16_t *mOutLeft;
+ int16_t *mOutRight;
+ int mInInBuf;
+ int mInTmpBuf;
+ int mInTmp2Buf;
+ int mOutBufPos;
+ int mInOutBuf;
+ };
+
+
+ class AudioStreamInALSA : public AudioStreamIn, public BufferProvider, public RefBase
+ {
+
+ public:
+ AudioStreamInALSA();
+ virtual ~AudioStreamInALSA();
+ status_t set(AudioHardware* hw,
+ uint32_t devices,
+ int *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pRate,
+ AudioSystem::audio_in_acoustics acoustics);
+ virtual size_t bufferSize() const { return mBufferSize; }
+ virtual uint32_t channels() const { return mChannels; }
+ virtual int format() const { return AUDIO_HW_IN_FORMAT; }
+ virtual uint32_t sampleRate() const { return mSampleRate; }
+ virtual status_t setGain(float gain) { return INVALID_OPERATION; }
+ virtual ssize_t read(void* buffer, ssize_t bytes);
+ virtual status_t dump(int fd, const Vector<String16>& args);
+ virtual status_t standby();
+ bool checkStandby();
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
+ virtual unsigned int getInputFramesLost() const { return 0; }
+ uint32_t device() { return mDevices; }
+ void doStandby_l();
+ void close_l();
+ status_t open_l();
+ int standbyCnt() { return mStandbyCnt; }
+
+ static size_t getBufferSize(uint32_t sampleRate, int channelCount);
+
+ // BufferProvider
+ virtual status_t getNextBuffer(BufferProvider::Buffer* buffer);
+ virtual void releaseBuffer(BufferProvider::Buffer* buffer);
+
+ void lock() { mLock.lock(); }
+ void unlock() { mLock.unlock(); }
+
+ private:
+ Mutex mLock;
+ AudioHardware* mHardware;
+ struct pcm *mPcm;
+ struct mixer *mMixer;
+ struct mixer_ctl *mRouteCtl;
+ const char *next_route;
+ bool mStandby;
+ uint32_t mDevices;
+ uint32_t mChannels;
+ uint32_t mChannelCount;
+ uint32_t mSampleRate;
+ size_t mBufferSize;
+ DownSampler *mDownSampler;
+ status_t mReadStatus;
+ size_t mInPcmInBuf;
+ int16_t *mPcmIn;
+ // trace driver operations for dump
+ int mDriverOp;
+ int mStandbyCnt;
+ };
+
+};
+
+}; // namespace android
+
+#endif
diff --git a/libaudio/AudioHardwareALSA.cpp b/libaudio/AudioHardwareALSA.cpp
deleted file mode 100755
index 45223f3..0000000
--- a/libaudio/AudioHardwareALSA.cpp
+++ /dev/null
@@ -1,2654 +0,0 @@
-/* AudioHardwareALSA.cpp
- **
- ** Copyright 2008-2009 Wind River Systems
- **
- ** 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.
- */
-#include <errno.h>
-#include <stdarg.h>
-#include <stdint.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "AudioHardwareALSA"
-#include <utils/Log.h>
-#include <utils/String8.h>
-
-#include <cutils/properties.h>
-#include <media/AudioRecord.h>
-#include <hardware_legacy/power.h>
-
-#include <alsa/asoundlib.h>
-#include "AudioHardwareALSA.h"
-// #define READ_FRAME_SIZE 2080
-// #define READ_FRAME_SIZE_STANDARD 4160
-
-#include <dlfcn.h>
-
-#define SND_MIXER_VOL_RANGE_MIN (0)
-#define SND_MIXER_VOL_RANGE_MAX (100)
-
-#define ALSA_NAME_MAX 128
-
-#define ALSA_STRCAT(x,y) \
- if (strlen(x) + strlen(y) < ALSA_NAME_MAX) \
- strcat(x, y);
-
-extern "C"
-{
- extern int ffs(int i);
-
- //
- // Make sure this prototype is consistent with what's in
- // external/libasound/alsa-lib-1.0.16/src/pcm/pcm_null.c!
- //
- extern int snd_pcm_null_open(snd_pcm_t **pcmp,
- const char *name,
- snd_pcm_stream_t stream,
- int mode);
-
- //
- // Function for dlsym() to look up for creating a new AudioHardwareInterface.
- //
- android::AudioHardwareInterface *createAudioHardware(void) {
- return new android::AudioHardwareALSA();
- }
-} // extern "C"
-
-namespace android
-{
-
-typedef AudioSystem::audio_devices audio_routes;
-#define ROUTE_ALL AudioSystem::DEVICE_OUT_ALL
-#define ROUTE_EARPIECE AudioSystem::DEVICE_OUT_EARPIECE
-#define ROUTE_HEADSET AudioSystem::DEVICE_OUT_WIRED_HEADSET
-#define ROUTE_HEADPHONE AudioSystem::DEVICE_OUT_WIRED_HEADPHONE
-#define ROUTE_SPEAKER AudioSystem::DEVICE_OUT_SPEAKER
-#define ROUTE_BLUETOOTH_SCO AudioSystem::DEVICE_OUT_BLUETOOTH_SCO
-#define ROUTE_BLUETOOTH_SCO_HEADSET AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET
-#define ROUTE_BLUETOOTH_SCO_CARKIT AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT
-#define ROUTE_BLUETOOTH_A2DP AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP
-#define ROUTE_BLUETOOTH_A2DP_HEADPHONES AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES
-#define ROUTE_BLUETOOTH_A2DP_SPEAKER AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER
-
-// ----------------------------------------------------------------------------
-
-
-static const char _nullALSADeviceName[] = "NULL_Device";
-
-static void ALSAErrorHandler(const char *file,
- int line,
- const char *function,
- int err,
- const char *fmt,
- ...)
-{
- char buf[BUFSIZ];
- va_list arg;
- int l;
-
- va_start(arg, fmt);
- l = snprintf(buf, BUFSIZ, "%s:%i:(%s) ", file, line, function);
- vsnprintf(buf + l, BUFSIZ - l, fmt, arg);
- buf[BUFSIZ-1] = '\0';
- LOGE("ALSALib %s.", buf);
- va_end(arg);
-}
-
-// ----------------------------------------------------------------------------
-
-/* The following table(s) need to match in order of the route bits
- */
-static const char *deviceSuffix[] = {
- // output devices
- /* ROUTE_EARPIECE */ "_Earpiece",
- /* ROUTE_SPEAKER */ "_Speaker",
- /* ROUTE_HEADSET */ "_Headset",
- /* ROUTE_HEADPHONE */ "_Headphone",
- /* ROUTE_BLUETOOTH_SCO */ "_Bluetooth",
- /* ROUTE_BLUETOOTH_SCO_HEADSET */ "_Bluetooth",
- /* ROUTE_BLUETOOTH_SCO_CARKIT */ "_Bluetooth", //"_Bluetooth_Carkit"
- /* ROUTE_BLUETOOTH_A2DP */ "_Bluetooth", //"_Bluetooth-A2DP"
- /* ROUTE_BLUETOOTH_A2DP_HEADPHONES */ "_Bluetooth", //"_Bluetooth-A2DP_HeadPhone"
- /* ROUTE_BLUETOOTH_A2DP_SPEAKER */ "_Bluetooth", // "_Bluetooth-A2DP_Speaker"
- /* ROUTE_AUX_DIGITAL */ "_AuxDigital",
- /* ROUTE_TV_OUT */ "_TvOut",
- /* ROUTE_AUX_DIGITAL */ "_ExtraDockSpeaker",
- /* ROUTE_NULL */ "_Null",
- /* ROUTE_NULL */ "_Null",
- /* ROUTE_DEFAULT */ "_OutDefault",
-
- // input devices
- /* ROUTE_COMMUNICATION */ "_Communication",
- /* ROUTE_AMBIENT */ "_Ambient",
- /* ROUTE_BUILTIN_MIC */ "_Speaker",
- /* ROUTE_BLUETOOTH_SCO_HEADSET */ "_Bluetooth",
- /* ROUTE_WIRED_HEADSET */ "_Headset",
- /* ROUTE_AUX_DIGITAL */ "_AuxDigital",
- /* ROUTE_VOICE_CALL */ "_VoiceCall",
- /* ROUTE_BACK_MIC */ "_BackMic",
- /* ROUTE_IN_DEFAULT */ "_InDefault",
-};
-
-static const int deviceSuffixLen = (sizeof(deviceSuffix) / sizeof(char *));
-
-struct mixer_info_t;
-
-struct alsa_properties_t
-{
- const audio_routes routes;
- const char *propName;
- const char *propDefault;
- mixer_info_t *mInfo;
-};
-
-static alsa_properties_t masterPlaybackProp = {
- ROUTE_ALL, "alsa.mixer.playback.master", "PCM", NULL
-};
-
-static alsa_properties_t masterCaptureProp = {
- ROUTE_ALL, "alsa.mixer.capture.master", "Capture", NULL
-};
-
-static alsa_properties_t
-mixerMasterProp[SND_PCM_STREAM_LAST+1] = {
- { ROUTE_ALL, "alsa.mixer.playback.master", "PCM", NULL},
- { ROUTE_ALL, "alsa.mixer.capture.master", "Capture", NULL}
-};
-
-static alsa_properties_t
-mixerProp[][SND_PCM_STREAM_LAST+1] = {
- {
- {ROUTE_EARPIECE, "alsa.mixer.playback.earpiece", "Earpiece", NULL},
- {ROUTE_EARPIECE, "alsa.mixer.capture.earpiece", "Capture", NULL}
- },
- {
- {ROUTE_SPEAKER, "alsa.mixer.playback.speaker", "Speaker", NULL},
- {ROUTE_SPEAKER, "alsa.mixer.capture.speaker", "", NULL}
- },
- {
- {ROUTE_BLUETOOTH_SCO, "alsa.mixer.playback.bluetooth.sco", "Bluetooth", NULL},
- {ROUTE_BLUETOOTH_SCO, "alsa.mixer.capture.bluetooth.sco", "Bluetooth Capture", NULL}
- },
- {
- {ROUTE_HEADSET, "alsa.mixer.playback.headset", "Headphone", NULL},
- {ROUTE_HEADSET, "alsa.mixer.capture.headset", "Capture", NULL}
- },
- {
- {ROUTE_BLUETOOTH_A2DP, "alsa.mixer.playback.bluetooth.a2dp", "Bluetooth A2DP", NULL},
- {ROUTE_BLUETOOTH_A2DP, "alsa.mixer.capture.bluetooth.a2dp", "Bluetooth A2DP Capture", NULL}
- },
- {
- {static_cast<audio_routes>(0), NULL, NULL, NULL},
- {static_cast<audio_routes>(0), NULL, NULL, NULL}
- }
-};
-
-const uint32_t AudioHardwareALSA::inputSamplingRates[] = {
- 8000, 11025, 16000, 22050, 44100
-};
-
-// ----------------------------------------------------------------------------
-
-AudioHardwareALSA::AudioHardwareALSA() :
- mOutput(0),
- mInput(0),
- mSecRilLibHandle(NULL),
- mRilClient(0),
- mVrModeEnabled(false),
- mActivatedCP(false),
- mBluetoothECOff(false)
-{
- snd_lib_error_set_handler(&ALSAErrorHandler);
- mMixer = new ALSAMixer;
-
- loadRILD();
-}
-
-AudioHardwareALSA::~AudioHardwareALSA()
-{
- if (mOutput) delete mOutput;
- if (mInput) delete mInput;
- if (mMixer) delete mMixer;
-
- if (mSecRilLibHandle) {
- if (disconnectRILD(mRilClient) != RIL_CLIENT_ERR_SUCCESS)
- LOGE("Disconnect_RILD() error");
-
- if (closeClientRILD(mRilClient) != RIL_CLIENT_ERR_SUCCESS)
- LOGE("CloseClient_RILD() error");
-
- mRilClient = 0;
-
- dlclose(mSecRilLibHandle);
- mSecRilLibHandle = NULL;
- }
-}
-
-
-void AudioHardwareALSA::loadRILD(void)
-{
- mSecRilLibHandle = dlopen("libsecril-client.so", RTLD_NOW);
-
- if (mSecRilLibHandle) {
- LOGV("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) {
- LOGE("Can't load all functions from libsecril-client.so");
-
- dlclose(mSecRilLibHandle);
- mSecRilLibHandle = NULL;
- } else {
- mRilClient = openClientRILD();
- if (!mRilClient) {
- LOGE("OpenClient_RILD() error");
-
- dlclose(mSecRilLibHandle);
- mSecRilLibHandle = NULL;
- }
- }
- } else {
- LOGE("Can't load libsecril-client.so");
- }
-}
-
-
-status_t AudioHardwareALSA::initCheck()
-{
- if (mMixer && mMixer->isValid())
- return NO_ERROR;
- else
- return NO_INIT;
-}
-
-
-status_t AudioHardwareALSA::connectRILDIfRequired(void)
-{
- if (!mSecRilLibHandle) {
- LOGE("connectIfRequired() lib is not loaded");
- return INVALID_OPERATION;
- }
-
- if (isConnectedRILD(mRilClient)) {
- return OK;
- }
-
- if (connectRILD(mRilClient) != RIL_CLIENT_ERR_SUCCESS) {
- LOGE("Connect_RILD() error");
- return INVALID_OPERATION;
- }
-
- return OK;
-}
-
-
-status_t AudioHardwareALSA::setVoiceVolume(float volume)
-{
- LOGI("### setVoiceVolume");
-
- AutoMutex lock(mLock);
- // sangsu fix : transmic volume level IPC to modem
- if ( (AudioSystem::MODE_IN_CALL == mMode) && (mSecRilLibHandle) &&
- (connectRILDIfRequired() == OK) ) {
-
- uint32_t routes = AudioSystem::ROUTE_EARPIECE;
- if (mOutput != NULL) {
- routes = mOutput->device();
- }
- int int_volume = (int)(volume * 5);
-
- LOGI("### route(%d) call volume(%f)", routes, volume);
- switch (routes) {
- case AudioSystem::ROUTE_EARPIECE:
- LOGI("### earpiece call volume");
- setCallVolume(mRilClient, SOUND_TYPE_VOICE, int_volume);
- break;
-
- case AudioSystem::ROUTE_SPEAKER:
- LOGI("### speaker call volume");
- setCallVolume(mRilClient, SOUND_TYPE_SPEAKER, int_volume);
- break;
-
- case AudioSystem::ROUTE_BLUETOOTH_SCO:
- case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
- case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
- case AudioSystem::ROUTE_BLUETOOTH_A2DP:
- LOGI("### bluetooth call volume");
- setCallVolume(mRilClient, SOUND_TYPE_BTVOICE, int_volume);
- break;
-
- case AudioSystem::ROUTE_HEADSET:
- case AudioSystem::ROUTE_HEADPHONE: // Use receive path with 3 pole headset.
- LOGI("### headset call volume");
- setCallVolume(mRilClient, SOUND_TYPE_HEADSET, int_volume);
- break;
-
- default:
- LOGE("### Call volume setting error!!!0x%08x \n", routes);
- break;
- }
- }
- // sangsu fix end
-
- // The voice volume is used by the VOICE_CALL audio stream.
- if (mMixer)
- return mMixer->setVolume(ROUTE_EARPIECE, volume);
- else
- return INVALID_OPERATION;
-}
-
-status_t AudioHardwareALSA::setMasterVolume(float volume)
-{
- if (mMixer)
- return mMixer->setMasterVolume(volume);
- else
- return INVALID_OPERATION;
-}
-
-AudioStreamOut *
-AudioHardwareALSA::openOutputStream(
- uint32_t devices,
- int *format,
- uint32_t *channels,
- uint32_t *sampleRate,
- status_t *status)
-{
- AudioStreamOutALSA *out = NULL;
- status_t ret = NO_ERROR;
- {
- AutoMutex lock(mLock);
-
- // only one output stream allowed
- if (mOutput) {
- ret = ALREADY_EXISTS;
- goto exit;
- }
-
- LOGV("[[[[[[[[\n%s - format = %d, channels = %d, sampleRate = %d, devices = %d]]]]]]]]\n", __func__, *format, *channels, *sampleRate,devices);
-
- out = new AudioStreamOutALSA(this);
-
- ret = out->set(format, channels, sampleRate);
-
- if (ret == NO_ERROR) {
- mOutput = out;
- }
- }
-exit:
- if (ret == NO_ERROR) {
- // Some information is expected to be available immediately after
- // the device is open.
- /* Tushar - Sets the current device output here - we may set device here */
- LOGI("%s] Setting ALSA device.", __func__);
- mOutput->setDevice(mMode, devices, PLAYBACK); /* tushar - Enable all devices as of now */
- } else if (out) {
- delete out;
- }
- if (status) {
- *status = ret;
- }
- return mOutput;
-}
-
-void
-AudioHardwareALSA::closeOutputStream(AudioStreamOut* out)
-{
- /* TODO:Tushar: May lead to segmentation fault - check*/
- //delete out;
- {
- AutoMutex lock(mLock);
-
- if (mOutput == 0 || mOutput != out) {
- LOGW("Attempt to close invalid output stream");
- return;
- }
- mOutput = 0;
- }
- delete out;
-}
-
-
-AudioStreamIn*
-AudioHardwareALSA::openInputStream(
- uint32_t devices,
- int *format,
- uint32_t *channels,
- uint32_t *sampleRate,
- status_t *status,
- AudioSystem::audio_in_acoustics acoustics)
-{
- AudioStreamInALSA *in = NULL;
- status_t ret = NO_ERROR;
- {
- AutoMutex lock(mLock);
-
- // only one input stream allowed
- if (mInput) {
- ret = ALREADY_EXISTS;
- goto exit;
- }
-
- in = new AudioStreamInALSA(this);
-
- ret = in->set(format, channels, sampleRate);
- if (ret == NO_ERROR) {
- mInput = in;
- }
- }
-exit:
- if (ret == NO_ERROR) {
- // Some information is expected to be available immediately after
- // the device is open.
- mInput->setDevice(mMode, devices, CAPTURE); /* Tushar - as per modified arch */
- } else if (in != NULL) {
- delete in;
- }
- if (status) {
- *status = ret;
- }
- return mInput;
-}
-
-void
-AudioHardwareALSA::closeInputStream(AudioStreamIn* in)
-{
- /* TODO:Tushar: May lead to segmentation fault - check*/
- //delete in;
- {
- AutoMutex lock(mLock);
-
- if (mInput == 0 || mInput != in) {
- LOGW("Attempt to close invalid input stream");
- return;
- } else {
- mInput = 0;
- }
- }
- delete in;
-}
-
-
-status_t AudioHardwareALSA::doRouting(uint32_t device, bool force)
-{
- AutoMutex lock(mLock);
- return doRouting_l(device, force);
-}
-
-status_t AudioHardwareALSA::doRouting_l(uint32_t device, bool force)
-{
- status_t ret;
- int mode = mMode; // Prevent to changing mode on setup sequence.
-
- LOGV("doRouting: device %x, force %d", device, force);
-
- if (mOutput) {
- //device = 0; /* Tushar - temp implementation */
- if (device == AudioSystem::DEVICE_OUT_DEFAULT) {
- device = mOutput->device();
- }
-
- // Setup sound path for CP clocking
- if ( (AudioSystem::MODE_IN_CALL == mode) && (mSecRilLibHandle) &&
- (connectRILDIfRequired() == OK) ) {
-
- LOGI("### incall mode route (%d)", device);
-
- switch(device){
- case AudioSystem::ROUTE_EARPIECE:
- LOGI("### incall mode earpiece route");
- setCallAudioPath(mRilClient, SOUND_AUDIO_PATH_HANDSET);
- break;
-
- case AudioSystem::ROUTE_SPEAKER:
- LOGI("### incall mode speaker route");
- setCallAudioPath(mRilClient, SOUND_AUDIO_PATH_SPEAKER);
- break;
-
- case AudioSystem::ROUTE_BLUETOOTH_SCO:
- case AudioSystem::ROUTE_BLUETOOTH_SCO_HEADSET:
- case AudioSystem::ROUTE_BLUETOOTH_SCO_CARKIT:
- LOGI("### incall mode bluetooth route %s NR", mBluetoothECOff ? "NO" : "");
- if (mBluetoothECOff)
- setCallAudioPath(mRilClient, SOUND_AUDIO_PATH_BLUETOOTH_NO_NR);
- else
- setCallAudioPath(mRilClient, SOUND_AUDIO_PATH_BLUETOOTH);
- break;
-
- case AudioSystem::ROUTE_HEADSET :
- case AudioSystem::ROUTE_HEADPHONE :
- LOGI("### incall mode headset route");
- setCallAudioPath(mRilClient, SOUND_AUDIO_PATH_HEADSET);
- break;
-
- case AudioSystem::ROUTE_BLUETOOTH_A2DP:
- LOGI("### incall mode bluetooth route");
- setCallAudioPath(mRilClient, SOUND_AUDIO_PATH_BLUETOOTH);
- break;
-
- default:
- LOGE("### incall mode Error!! route = [%d]", device);
- break;
- }
- }
-
- ret = mOutput->setDevice(mode, device, PLAYBACK, force);
-
- return ret;
- }
-
- return NO_INIT;
-}
-
-
-status_t AudioHardwareALSA::setMicMute(bool state)
-{
- if (mMixer)
- return mMixer->setCaptureMuteState(ROUTE_EARPIECE, state);
-
- return NO_INIT;
-}
-
-status_t AudioHardwareALSA::getMicMute(bool *state)
-{
- if (mMixer)
- return mMixer->getCaptureMuteState(ROUTE_EARPIECE, state);
-
- return NO_ERROR;
-}
-
-status_t AudioHardwareALSA::dump(int fd, const Vector<String16>& args)
-{
- return NO_ERROR;
-}
-
-
-uint32_t AudioHardwareALSA::bufferRatio(uint32_t samplingRate) {
- switch (samplingRate) {
- case 8000:
- case 11025:
- return 4;
- case 16000:
- case 22050:
- return 2;
- case 44100:
- default:
- break;
- }
- return 1;
-}
-
-
-size_t AudioHardwareALSA::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
-{
- if (sampleRate != 8000 && sampleRate != 11025 && sampleRate != 16000 &&
- sampleRate != 22050 && sampleRate != 44100) {
- LOGW("getInputBufferSize bad sampling rate: %d", sampleRate);
- return 0;
- }
- if (format != AudioSystem::PCM_16_BIT) {
- LOGW("getInputBufferSize bad format: %d", format);
- return 0;
- }
- if (channelCount != 1) {
- LOGW("getInputBufferSize bad channel count: %d", channelCount);
- return 0;
- }
-
- size_t size = (PERIOD_SZ_CAPTURE / bufferRatio(sampleRate)) * sizeof(int16_t);
- LOGV("getInputBufferSize() rate %d, ratio %d", sampleRate, size);
- return size;
-
-}
-
-uint32_t AudioHardwareALSA::checkInputSampleRate(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];
-}
-
-status_t AudioHardwareALSA::setMode(int mode)
-{
- AutoMutex lock(mLock);
- int prevMode = mMode;
- status_t status = AudioHardwareBase::setMode(mode);
- LOGV("setMode() : new %d, old %d", mMode, prevMode);
- if (status == NO_ERROR) {
- if ( (mMode == AudioSystem::MODE_RINGTONE) || (mMode == AudioSystem::MODE_IN_CALL) )
- {
- if ( (!mActivatedCP) && (mSecRilLibHandle) && (connectRILDIfRequired() == OK) ) {
- setCallClockSync(mRilClient, SOUND_CLOCK_START);
- mActivatedCP = true;
- }
- }
-
- // make sure that doAudioRouteOrMute() is called by doRouting()
- // when entering or exiting in call mode even if the new device
- // selected is the same as current one.
- if ((prevMode != AudioSystem::MODE_IN_CALL) && (mMode == AudioSystem::MODE_IN_CALL)) {
- LOGV("setMode() entering call");
- doRouting_l(AudioSystem::DEVICE_OUT_DEFAULT, true);
- setVoiceRecordGain_l(false);
- }
- if ((prevMode == AudioSystem::MODE_IN_CALL) && (mMode != AudioSystem::MODE_IN_CALL)) {
- LOGV("setMode() exiting call");
- doRouting_l(AudioSystem::DEVICE_OUT_DEFAULT, true);
- if (mOutput != NULL && !mOutput->isActive()) {
- mOutput->close();
- }
- }
-
- if (mMode == AudioSystem::MODE_NORMAL) {
- if(mActivatedCP)
- mActivatedCP = false;
- }
- }
-
- return status;
-}
-
-int AudioHardwareALSA::setVoiceRecordGain(bool enable)
-{
- AutoMutex lock(mLock);
- return setVoiceRecordGain_l(enable);
-}
-
-int AudioHardwareALSA::setVoiceRecordGain_l(bool enable)
-{
- LOGI("[%s], enable=%d", __func__, enable);
- if (enable != mVrModeEnabled &&
- !(enable && (mMode == AudioSystem::MODE_IN_CALL))) {
- ALSAControl *alsaControl = new ALSAControl();
- status_t ret = alsaControl->set("Recognition Control", enable ? RECOGNITION_ON : RECOGNITION_OFF);
- delete alsaControl;
- mVrModeEnabled = enable;
- }
-
- return NO_ERROR;
-}
-
-status_t AudioHardwareALSA::setParameters(const String8& keyValuePairs)
-{
- AudioParameter param = AudioParameter(keyValuePairs);
- String8 bt_nrec_key = String8("bt_headset_nrec");
- String8 value;
-
- LOGV("setParameters(%s)", keyValuePairs.string());
-
- if (param.get(bt_nrec_key, value) == NO_ERROR) {
- setBluetoothNrEcOnOff((value == "on") ? false : true);
- }
-
- return NO_ERROR;
-}
-
-void AudioHardwareALSA::setBluetoothNrEcOnOff(bool disable)
-{
- LOGV("setBluetoothNrEcOnOff(%s)", disable ? "true" : "false");
-
- if (disable != mBluetoothECOff)
- {
- mBluetoothECOff = disable;
-
- if ( (mOutput) && (AudioSystem::MODE_IN_CALL == mMode) &&
- (mSecRilLibHandle) && (connectRILDIfRequired() == OK)) {
-
- uint32_t device = mOutput->device();
-
- switch (device) {
- case AudioSystem::ROUTE_BLUETOOTH_SCO:
- case AudioSystem::ROUTE_BLUETOOTH_SCO_HEADSET:
- case AudioSystem::ROUTE_BLUETOOTH_SCO_CARKIT:
- LOGV("### incall mode bluetooth EC %s route", mBluetoothECOff ? "OFF" : "ON");
- if (mBluetoothECOff)
- setCallAudioPath(mRilClient, SOUND_AUDIO_PATH_BLUETOOTH_NO_NR);
- else
- setCallAudioPath(mRilClient, SOUND_AUDIO_PATH_BLUETOOTH);
- break;
-
- default :
- LOGE("Bluetooth path is not activated!!");
- break;
- }
- }
- }
-}
-
-
-// ----------------------------------------------------------------------------
-
-ALSAStreamOps::ALSAStreamOps() :
- mHandle(0),
- mHardwareParams(0),
- mSoftwareParams(0),
- mDevice(0)
-{
- if (snd_pcm_hw_params_malloc(&mHardwareParams) < 0) {
- LOG_ALWAYS_FATAL("Failed to allocate ALSA hardware parameters!");
- }
-
- if (snd_pcm_sw_params_malloc(&mSoftwareParams) < 0) {
- LOG_ALWAYS_FATAL("Failed to allocate ALSA software parameters!");
- }
-}
-
-ALSAStreamOps::~ALSAStreamOps()
-{
- AutoMutex lock(mLock);
-
- close();
-
- if (mHardwareParams)
- snd_pcm_hw_params_free(mHardwareParams);
-
- if (mSoftwareParams)
- snd_pcm_sw_params_free(mSoftwareParams);
-}
-
-
-status_t ALSAStreamOps::set(int *pformat,
- uint32_t *pchannels,
- uint32_t *prate)
-{
- int lformat = pformat ? *pformat : 0;
- unsigned int lchannels = pchannels ? *pchannels : 0;
- unsigned int lrate = prate ? *prate : 0;
-
-
- LOGD("ALSAStreamOps - input - format = %d, channels = %d, rate = %d\n", lformat, lchannels, lrate);
- LOGD("ALSAStreamOps - default - format = %d, channelCount = %d, rate = %d\n", mDefaults->format, mDefaults->channelCount, mDefaults->sampleRate);
-
- if (lformat == 0) lformat = getAndroidFormat(mDefaults->format);//format();
- if (lchannels == 0) lchannels = getAndroidChannels(mDefaults->channelCount);// channelCount();
- if (lrate == 0) lrate = mDefaults->sampleRate;
-
- if ( (lformat != getAndroidFormat(mDefaults->format)) ||
- (lchannels != getAndroidChannels(mDefaults->channelCount)) ) {
- if (pformat) *pformat = getAndroidFormat(mDefaults->format);
- if (pchannels) *pchannels = getAndroidChannels(mDefaults->channelCount);
- return BAD_VALUE;
- }
- if (mDefaults->direction == SND_PCM_STREAM_PLAYBACK) {
- if (lrate != mDefaults->sampleRate) {
- if (prate) *prate = mDefaults->sampleRate;
- return BAD_VALUE;
- }
- } else {
- uint32_t rate = AudioHardwareALSA::checkInputSampleRate(lrate);
- if (rate != lrate) {
- if (prate) *prate = rate;
- return BAD_VALUE;
- }
- lrate = rate;
- }
- mDefaults->bufferRatio = AudioHardwareALSA::bufferRatio(lrate);
- mDefaults->sampleRate = lrate;
-
- if(pformat) *pformat = getAndroidFormat(mDefaults->format);
- if(pchannels) *pchannels = getAndroidChannels(mDefaults->channelCount);
- if(prate) *prate = mDefaults->sampleRate;
-
- return NO_ERROR;
-}
-
-
-uint32_t ALSAStreamOps::sampleRate() const
-{
- return mDefaults->sampleRate;
-}
-
-status_t ALSAStreamOps::sampleRate(uint32_t rate)
-{
- const char *stream;
- unsigned int requestedRate;
- int err;
-
- if (!mHandle)
- return NO_INIT;
-
- stream = streamName();
- requestedRate = rate;
- err = snd_pcm_hw_params_set_rate_near(mHandle,
- mHardwareParams,
- &requestedRate,
- 0);
-
- if (err < 0) {
- LOGE("Unable to set %s sample rate to %u: %s",
- stream, rate, snd_strerror(err));
- return BAD_VALUE;
- }
- if (requestedRate != rate) {
- // Some devices have a fixed sample rate, and can not be changed.
- // This may cause resampling problems; i.e. PCM playback will be too
- // slow or fast.
- LOGW("Requested rate (%u HZ) does not match actual rate (%u HZ)",
- rate, requestedRate);
- }
- else {
- LOGD("Set %s sample rate to %u HZ", stream, requestedRate);
- }
- return NO_ERROR;
-}
-
-//
-// Return the number of bytes (not frames)
-//
-size_t ALSAStreamOps::bufferSize() const
-{
- int err;
-
- size_t size = ((mDefaults->periodSize / mDefaults->bufferRatio) * mDefaults->channelCount *
- snd_pcm_format_physical_width(mDefaults->format)) / 8;
- LOGV("bufferSize() channelCount %d, bufferRatio %d, size %d",
- mDefaults->channelCount, mDefaults->bufferRatio, size);
- return size;
-
-}
-
-int ALSAStreamOps::getAndroidFormat(snd_pcm_format_t format)
-{
- int pcmFormatBitWidth;
- int audioSystemFormat;
-
- pcmFormatBitWidth = snd_pcm_format_physical_width(format);
- audioSystemFormat = AudioSystem::DEFAULT;
- switch(pcmFormatBitWidth) {
- case 8:
- audioSystemFormat = AudioSystem::PCM_8_BIT;
- break;
-
- case 16:
- audioSystemFormat = AudioSystem::PCM_16_BIT;
- break;
-
- default:
- LOG_FATAL("Unknown AudioSystem bit width %i!", pcmFormatBitWidth);
- }
-
- return audioSystemFormat;
-
-}
-
-int ALSAStreamOps::format() const
-{
- snd_pcm_format_t ALSAFormat;
- int pcmFormatBitWidth;
- int audioSystemFormat;
-
- if (snd_pcm_hw_params_get_format(mHardwareParams, &ALSAFormat) < 0) {
- return -1;
- }
-
- pcmFormatBitWidth = snd_pcm_format_physical_width(ALSAFormat);
- audioSystemFormat = AudioSystem::DEFAULT;
- switch(pcmFormatBitWidth) {
- case 8:
- audioSystemFormat = AudioSystem::PCM_8_BIT;
- break;
-
- case 16:
- audioSystemFormat = AudioSystem::PCM_16_BIT;
- break;
-
- default:
- LOG_FATAL("Unknown AudioSystem bit width %i!", pcmFormatBitWidth);
- }
-
- return audioSystemFormat;
-}
-
-uint32_t ALSAStreamOps::getAndroidChannels(int channelCount) const
-{
- int AudioSystemChannels = AudioSystem::DEFAULT;
-
- if (mDefaults->direction == SND_PCM_STREAM_PLAYBACK) {
- switch(channelCount){
- case 1:
- AudioSystemChannels = AudioSystem::CHANNEL_OUT_MONO;
- break;
- case 2:
- AudioSystemChannels = AudioSystem::CHANNEL_OUT_STEREO;
- break;
- case 4:
- AudioSystemChannels = AudioSystem::CHANNEL_OUT_QUAD;
- break;
- case 6:
- AudioSystemChannels = AudioSystem::CHANNEL_OUT_5POINT1;
- break;
- default:
- LOGE("FATAL: AudioSystem does not support %d output channels.", channelCount);
- }
- } else {
- switch(channelCount){
- case 1:
- AudioSystemChannels = AudioSystem::CHANNEL_IN_MONO;
- break;
- case 2:
- AudioSystemChannels = AudioSystem::CHANNEL_IN_STEREO;
- break;
- default:
- LOGE("FATAL: AudioSystem does not support %d input channels.", channelCount);
- }
-
- }
- return AudioSystemChannels;
-}
-
-uint32_t ALSAStreamOps::channels() const
-{
- return getAndroidChannels(mDefaults->channelCount);
-}
-
-int ALSAStreamOps::channelCount() const
-{
- return mDefaults->channelCount;
-}
-
-status_t ALSAStreamOps::channelCount(int channelCount) {
- int err;
-
- if (!mHandle)
- return NO_INIT;
-
- err = snd_pcm_hw_params_set_channels(mHandle, mHardwareParams, channelCount);
- if (err < 0) {
- LOGE("Unable to set channel count to %i: %s",
- channelCount, snd_strerror(err));
- return BAD_VALUE;
- }
-
- LOGD("Using %i %s for %s.",
- channelCount, channelCount == 1 ? "channel" : "channels", streamName());
-
- return NO_ERROR;
-}
-
-status_t ALSAStreamOps::open(int mode, uint32_t device)
-{
- const char *stream = streamName();
- const char *devName = deviceName(mode, device);
-
- int err;
-
- LOGI("Try to open ALSA %s device %s", stream, devName);
-
- for(;;) {
- // The PCM stream is opened in blocking mode, per ALSA defaults. The
- // AudioFlinger seems to assume blocking mode too, so asynchronous mode
- // should not be used.
- err = snd_pcm_open(&mHandle, devName, mDefaults->direction, 0);
- if (err == 0) break;
-
- // See if there is a less specific name we can try.
- // Note: We are changing the contents of a const char * here.
- char *tail = strrchr(devName, '_');
- if (! tail) break;
- *tail = 0;
- }
-
- if (err < 0) {
- // None of the Android defined audio devices exist. Open a generic one.
- devName = "hw:00,1"; // 090507 SMDKC110 Froyo
-
- err = snd_pcm_open(&mHandle, devName, mDefaults->direction, 0);
- if (err < 0) {
- // Last resort is the NULL device (i.e. the bit bucket).
- devName = _nullALSADeviceName;
- err = snd_pcm_open(&mHandle, devName, mDefaults->direction, 0);
- }
- }
-
- mDevice = device;
-
- LOGI("Initialized ALSA %s device %s", stream, devName);
- return err;
-}
-
-void ALSAStreamOps::close()
-{
- snd_pcm_t *handle = mHandle;
- mHandle = NULL;
-
- if (handle) {
- LOGV("ALSAStreamOps::close()");
- snd_pcm_drain(handle);
- snd_pcm_close(handle);
- }
-}
-
-status_t ALSAStreamOps::setSoftwareParams()
-{
- if (!mHandle)
- return NO_INIT;
-
- int err;
-
- // Get the current software parameters
- err = snd_pcm_sw_params_current(mHandle, mSoftwareParams);
- if (err < 0) {
- LOGE("Unable to get software parameters: %s", snd_strerror(err));
- return NO_INIT;
- }
-
- snd_pcm_uframes_t bufferSize = 0;
- snd_pcm_uframes_t periodSize = 0;
- snd_pcm_uframes_t startThreshold;
-
- // Configure ALSA to start the transfer when the buffer is almost full.
- snd_pcm_get_params(mHandle, &bufferSize, &periodSize);
- LOGE("bufferSize %d, periodSize %d\n", (int)bufferSize, (int)periodSize);
-
- if (mDefaults->direction == SND_PCM_STREAM_PLAYBACK) {
- // For playback, configure ALSA to start the transfer when the
- // buffer is almost full.
- startThreshold = (bufferSize / periodSize) * periodSize;
- //startThreshold = 1;
- }
- else {
- // For recording, configure ALSA to start the transfer on the
- // first frame.
- startThreshold = 1;
- }
-
- err = snd_pcm_sw_params_set_start_threshold(mHandle,
- mSoftwareParams,
- startThreshold);
- if (err < 0) {
- LOGE("Unable to set start threshold to %lu frames: %s",
- startThreshold, snd_strerror(err));
- return NO_INIT;
- }
-
- // Stop the transfer when the buffer is full.
- err = snd_pcm_sw_params_set_stop_threshold(mHandle,
- mSoftwareParams,
- bufferSize);
- if (err < 0) {
- LOGE("Unable to set stop threshold to %lu frames: %s",
- bufferSize, snd_strerror(err));
- return NO_INIT;
- }
-
- // Allow the transfer to start when at least periodSize samples can be
- // processed.
- err = snd_pcm_sw_params_set_avail_min(mHandle,
- mSoftwareParams,
- periodSize);
- if (err < 0) {
- LOGE("Unable to configure available minimum to %lu: %s",
- periodSize, snd_strerror(err));
- return NO_INIT;
- }
-
- // Commit the software parameters back to the device.
- err = snd_pcm_sw_params(mHandle, mSoftwareParams);
- if (err < 0) {
- LOGE("Unable to configure software parameters: %s",
- snd_strerror(err));
- return NO_INIT;
- }
-
- return NO_ERROR;
-}
-
-status_t ALSAStreamOps::setPCMFormat(snd_pcm_format_t format)
-{
- const char *formatDesc;
- const char *formatName;
- bool validFormat;
- int err;
-
- // snd_pcm_format_description() and snd_pcm_format_name() do not perform
- // proper bounds checking.
- validFormat = (static_cast<int>(format) > SND_PCM_FORMAT_UNKNOWN) &&
- (static_cast<int>(format) <= SND_PCM_FORMAT_LAST);
- formatDesc = validFormat ?
- snd_pcm_format_description(format) : "Invalid Format";
- formatName = validFormat ?
- snd_pcm_format_name(format) : "UNKNOWN";
-
- err = snd_pcm_hw_params_set_format(mHandle, mHardwareParams, format);
- if (err < 0) {
- LOGE("Unable to configure PCM format %s (%s): %s",
- formatName, formatDesc, snd_strerror(err));
- return NO_INIT;
- }
-
- LOGD("Set %s PCM format to %s (%s)", streamName(), formatName, formatDesc);
- return NO_ERROR;
-}
-
-status_t ALSAStreamOps::setHardwareResample(bool resample)
-{
- int err;
-
- err = snd_pcm_hw_params_set_rate_resample(mHandle,
- mHardwareParams,
- static_cast<int>(resample));
- if (err < 0) {
- LOGE("Unable to %s hardware resampling: %s",
- resample ? "enable" : "disable",
- snd_strerror(err));
- return NO_INIT;
- }
- return NO_ERROR;
-}
-
-const char *ALSAStreamOps::streamName()
-{
- // Don't use snd_pcm_stream(mHandle), as the PCM stream may not be
- // opened yet. In such case, snd_pcm_stream() will abort().
- return snd_pcm_stream_name(mDefaults->direction);
-}
-
-//
-// Set playback or capture PCM device. It's possible to support audio output
-// or input from multiple devices by using the ALSA plugins, but this is
-// not supported for simplicity.
-//
-// The AudioHardwareALSA API does not allow one to set the input routing.
-//
-// If the "routes" value does not map to a valid device, the default playback
-// device is used.
-//
-status_t ALSAStreamOps::setDevice(int mode, uint32_t device, uint audio_mode)
-{
- // Close off previously opened device.
- // It would be nice to determine if the underlying device actually
- // changes, but we might be manipulating mixer settings (see asound.conf).
- //
- close();
-
- const char *stream = streamName();
-
-
- LOGD("\n------------------------>>>>>> ALSA OPEN mode %d,device %d \n",mode,device);
-
- status_t status = open (mode, device);
- int err;
- unsigned int period_val;
-
- if (status != NO_ERROR)
- return status;
-
- err = snd_pcm_hw_params_any(mHandle, mHardwareParams);
- if (err < 0) {
- LOGE("Unable to configure hardware: %s", snd_strerror(err));
- return NO_INIT;
- }
-
- status = setPCMFormat(mDefaults->format);
-
- // Set the interleaved read and write format.
- err = snd_pcm_hw_params_set_access(mHandle, mHardwareParams,
- SND_PCM_ACCESS_RW_INTERLEAVED);
- if (err < 0) {
- LOGE("Unable to configure PCM read/write format: %s",
- snd_strerror(err));
- return NO_INIT;
- }
-
-
- //
- // Some devices do not have the default two channels. Force an error to
- // prevent AudioMixer from crashing and taking the whole system down.
- //
- // Note that some devices will return an -EINVAL if the channel count
- // is queried before it has been set. i.e. calling channelCount()
- // before channelCount(channels) may return -EINVAL.
- //
- status = channelCount(mDefaults->channelCount);
- if (status != NO_ERROR)
- return status;
-
- // Don't check for failure; some devices do not support the default
- // sample rate.
- // FIXME:: always use default sampling rate
- sampleRate(DEFAULT_SAMPLE_RATE);
-
- snd_pcm_uframes_t bufferSize = mDefaults->bufferSize;
- snd_pcm_uframes_t periodSize = mDefaults->periodSize;
- period_val = bufferSize/periodSize;
-
- unsigned int latency = mDefaults->latency;
-
- // Make sure we have at least the size we originally wanted
- err = snd_pcm_hw_params_set_buffer_size(mHandle, mHardwareParams, bufferSize);
- if (err < 0) {
- LOGE("Unable to set buffer size to %d: %s",
- (int)bufferSize, snd_strerror(err));
- return NO_INIT;
- }
-
- err = snd_pcm_hw_params_set_period_size (mHandle, mHardwareParams, periodSize, NULL);
- if (err < 0) {
- LOGE("Unable to set the period size for latency: %s", snd_strerror(err));
- return NO_INIT;
- }
-
- err = snd_pcm_hw_params_get_period_size (mHardwareParams, &periodSize, NULL);
- if (err < 0) {
- LOGE("Unable to get the period size for latency: %s", snd_strerror(err));
- return NO_INIT;
- }
-
-// err = snd_pcm_hw_params_get_period_size (mHardwareParams, &periodSize, NULL);
-// if (err < 0) {
-// LOGE("Unable to get the period size for latency: %s", snd_strerror(err));
-// return NO_INIT;
-// }
-
-// // Setup buffers for latency
-// err = snd_pcm_hw_params_set_buffer_time_near (mHandle, mHardwareParams,
-// &latency, NULL);
-// if(audio_mode == PLAYBACK) {
-// period_val = PERIODS_PLAYBACK;
-// if(snd_pcm_hw_params_set_periods(mHandle, mHardwareParams, period_val, 0) < 0)
-// LOGE("Fail to set period size %d for playback", period_val);
-// }
-// else
-// period_val = PERIODS_CAPTURE;
-//
-// if (err < 0) {
-// LOGD("snd_pcm_hw_params_set_buffer_time_near() failed: %s", snd_strerror(err));
-// /* That didn't work, set the period instead */
-// unsigned int periodTime = latency / period_val;
-// err = snd_pcm_hw_params_set_period_time_near (mHandle, mHardwareParams,
-// &periodTime, NULL);
-// if (err < 0) {
-// LOGE("Unable to set the period time for latency: %s", snd_strerror(err));
-// return NO_INIT;
-// }
-// err = snd_pcm_hw_params_get_period_size (mHardwareParams, &periodSize, NULL);
-// if (err < 0) {
-// LOGE("Unable to get the period size for latency: %s", snd_strerror(err));
-// return NO_INIT;
-// }
-// bufferSize = periodSize * period_val;
-// if (bufferSize < mDefaults->bufferSize)
-// bufferSize = mDefaults->bufferSize;
-// err = snd_pcm_hw_params_set_buffer_size_near (mHandle, mHardwareParams, &bufferSize);
-// if (err < 0) {
-// LOGE("Unable to set the buffer size for latency: %s", snd_strerror(err));
-// return NO_INIT;
-// }
-// } else {
-// LOGD("snd_pcm_hw_params_set_buffer_time_near() OK");
-// // OK, we got buffer time near what we expect. See what that did for bufferSize.
-// err = snd_pcm_hw_params_get_buffer_size (mHardwareParams, &bufferSize);
-// if (err < 0) {
-// LOGE("Unable to get the buffer size for latency: %s", snd_strerror(err));
-// return NO_INIT;
-// }
-// // Does set_buffer_time_near change the passed value? It should.
-// err = snd_pcm_hw_params_get_buffer_time (mHardwareParams, &latency, NULL);
-// if (err < 0) {
-// LOGE("Unable to get the buffer time for latency: %s", snd_strerror(err));
-// return NO_INIT;
-// }
-// LOGD("got latency %d for bufferSize %d", latency, bufferSize);
-// unsigned int periodTime = latency / period_val;
-// LOGD("got latency %d for bufferSize %d => periodTime %d", latency, bufferSize, periodTime);
-// err = snd_pcm_hw_params_set_period_time_near (mHandle, mHardwareParams,
-// &periodTime, NULL);
-// if (err < 0) {
-// LOGE("Unable to set the period time for latency: %s", snd_strerror(err));
-// return NO_INIT;
-// }
-// err = snd_pcm_hw_params_get_period_size (mHardwareParams, &periodSize, NULL);
-// if (err < 0) {
-// LOGE("Unable to get the period size for latency: %s", snd_strerror(err));
-// return NO_INIT;
-// }
-// }
-
- LOGD("Buffer size: %d", (int)bufferSize);
- LOGD("Period size: %d", (int)periodSize);
- LOGD("Latency: %d", (int)latency);
-
- mDefaults->bufferSize = bufferSize;
- mDefaults->latency = latency;
- mDefaults->periodSize = periodSize;
-
- // Commit the hardware parameters back to the device.
- err = snd_pcm_hw_params(mHandle, mHardwareParams);
- if (err < 0) {
- LOGE("Unable to set hardware parameters: %s", snd_strerror(err));
- return NO_INIT;
- }
-
- status = setSoftwareParams();
-
- return status;
-}
-
-const char *ALSAStreamOps::deviceName(int mode, uint32_t device)
-{
- static char devString[ALSA_NAME_MAX];
- int dev;
- int hasDevExt = 0;
-
- strcpy (devString, mDefaults->devicePrefix);
-
- for (dev=0; device; dev++)
- if (device & (1 << dev)) {
- /* Don't go past the end of our list */
- if (dev >= deviceSuffixLen)
- break;
- ALSA_STRCAT (devString, deviceSuffix[dev]);
- device &= ~(1 << dev);
- hasDevExt = 1;
- }
-
- if (hasDevExt)
- switch (mode) {
- case AudioSystem::MODE_NORMAL:
- ALSA_STRCAT (devString, "_normal");
- break;
- case AudioSystem::MODE_RINGTONE:
- ALSA_STRCAT (devString, "_ringtone");
- break;
- case AudioSystem::MODE_IN_CALL:
- ALSA_STRCAT (devString, "_incall");
- break;
- };
-
- return devString;
-}
-
-// ----------------------------------------------------------------------------
-
-AudioStreamOutALSA::AudioStreamOutALSA(AudioHardwareALSA *parent) :
- mParent(parent),
- mPowerLock(false)
-{
- static StreamDefaults _defaults = {
- devicePrefix : "AndroidPlayback",
- direction : SND_PCM_STREAM_PLAYBACK,
- format : SND_PCM_FORMAT_S16_LE, // AudioSystem::PCM_16_BIT
- channelCount : 2,
- sampleRate : DEFAULT_SAMPLE_RATE,
- bufferRatio : 1,
- latency : LATENCY_PLAYBACK_MS, // Desired Delay in usec
- bufferSize : BUFFER_SZ_PLAYBACK, // Desired Number of samples
- periodSize : PERIOD_SZ_PLAYBACK
-};
-
- setStreamDefaults(&_defaults);
-}
-
-AudioStreamOutALSA::~AudioStreamOutALSA()
-{
- standby();
-}
-
-
-/* New arch */
-status_t AudioStreamOutALSA::setVolume(float left, float right)
-{
- if (! mParent->mMixer || ! mDevice)
- return NO_INIT;
-
- /** Tushar - Need to decide on the volume value
- * that we pass onto the mixer. */
- return mParent->mMixer->setVolume (mDevice, (left + right)/2);
-}
-
-status_t AudioStreamOutALSA::setVolume(float volume)
-{
- if (! mParent->mMixer || ! mDevice)
- return NO_INIT;
-
- return mParent->mMixer->setVolume (mDevice, volume);
-}
-
-/* New Arch */
-status_t AudioStreamOutALSA::setParameters(const String8& keyValuePairs)
-{
- AudioParameter param = AudioParameter(keyValuePairs);
- status_t status = NO_ERROR;
- int device;
- int value;
- LOGD("AudioStreamOutALSA::setParameters() %s", keyValuePairs.string());
-
- if (param.getInt(String8(AudioParameter::keyRouting), device) == NO_ERROR)
- {
- mParent->doRouting(device);
-
- param.remove(String8(AudioParameter::keyRouting));
- }
-
- if (param.size()) {
- status = BAD_VALUE;
- }
- return status;
-}
-
-
-String8 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)mDevice);
- }
-
- LOGD("AudioStreamOutALSA::getParameters() %s", param.toString().string());
- return param.toString();
-}
-
-
-status_t AudioStreamOutALSA::getRenderPosition(uint32_t *dspFrames)
-{
-
- //TODO: enable when supported by driver
- return INVALID_OPERATION;
-}
-
-
-ssize_t AudioStreamOutALSA::write(const void *buffer, size_t bytes)
-{
- snd_pcm_sframes_t n;
- size_t sent = 0;
- status_t err;
-
- mParent->lock().lock();
- AutoMutex lock(mLock);
-
- if (!mPowerLock) {
- LOGD("Calling setDevice from write @..%d.\n",__LINE__);
- ALSAStreamOps::setDevice(mParent->mode(), mDevice, PLAYBACK);
- acquire_wake_lock (PARTIAL_WAKE_LOCK, "AudioOutLock");
- mPowerLock = true;
- }
- mParent->lock().unlock();
-
- do {
- // write correct number of bytes per attempt
- n = snd_pcm_writei(mHandle, (char *) buffer + sent, snd_pcm_bytes_to_frames(mHandle, bytes
- - sent));
- if (n == -EBADFD) {
- LOGD("Calling setDevice.. pcm_write returned error @..%d.\n",__LINE__);
- // Somehow the stream is in a bad state. The driver probably
- // has a bug and snd_pcm_recover() doesn't seem to handle this.
- ALSAStreamOps::setDevice(mParent->mode(), mDevice, PLAYBACK);
- } else if (n < 0) {
- if (mHandle) {
- // snd_pcm_recover() will return 0 if successful in recovering from
- // // an error, or -errno if the error was unrecoverable.
- // We can make silent bit on as we are now handling the under-run and there will not be any data loss due to under-run
- n = snd_pcm_recover(mHandle, n, 1);
- if (n)
- return static_cast<ssize_t> (n);
- }
- } else
- sent += static_cast<ssize_t> (snd_pcm_frames_to_bytes(mHandle, n));
- } while (mHandle && sent < bytes);
- //LOGI("Request Bytes=%d, Actual Written=%d",bytes,sent);
- return snd_pcm_frames_to_bytes(mHandle, sent);
-}
-
-
-status_t AudioStreamOutALSA::dump(int fd, const Vector<String16>& args)
-{
- return NO_ERROR;
-}
-
-status_t AudioStreamOutALSA::setDevice(int mode,
- uint32_t newDevice,
- uint32_t audio_mode,
- bool force)
-{
- AutoMutex lock(mLock);
-
- LOGV("AudioStreamOutALSA::setDevice(mode %d, newDevice %x, audio_mode %d), mDevice %x",
- mode, newDevice, audio_mode, mDevice);
- if (newDevice != mDevice || force) {
- return ALSAStreamOps::setDevice(mode, newDevice, audio_mode);
- }
- return NO_ERROR;
-}
-
-status_t AudioStreamOutALSA::standby() {
- AutoMutex _l(mParent->lock());
- AutoMutex lock(mLock);
- LOGD("Inside AudioStreamOutALSA::standby\n");
-
- if (mParent->mode() != AudioSystem::MODE_IN_CALL) {
- ALSAStreamOps::close();
- }
-
- if (mPowerLock) {
- release_wake_lock("AudioOutLock");
- mPowerLock = false;
- }
- return NO_ERROR;
-}
-
-
-#define USEC_TO_MSEC(x) ((x + 999) / 1000)
-
-uint32_t AudioStreamOutALSA::latency() const
-{
- // Android wants latency in milliseconds.
- return USEC_TO_MSEC (mDefaults->latency);
-}
-
-// ----------------------------------------------------------------------------
-
-AudioStreamInALSA::AudioStreamInALSA(AudioHardwareALSA *parent) :
- mParent(parent), mPowerLock(false),
- mDownSampler(NULL), mPcmIn(NULL)
-{
- static StreamDefaults _defaults = {
- devicePrefix : "AndroidRecord",
- direction : SND_PCM_STREAM_CAPTURE,
- format : SND_PCM_FORMAT_S16_LE, // AudioSystem::PCM_16_BIT
- channelCount : 1,
- sampleRate : DEFAULT_SAMPLE_RATE,
- bufferRatio : 1,
- latency : LATENCY_CAPTURE_MS,// Desired Delay in usec
- bufferSize : BUFFER_SZ_CAPTURE, // Desired Number of samples
- periodSize : PERIOD_SZ_CAPTURE
- };
-
- setStreamDefaults(&_defaults);
-}
-
-status_t AudioStreamInALSA::set(int *pformat,
- uint32_t *pchannels,
- uint32_t *prate)
-{
- status_t status = ALSAStreamOps::set(pformat, pchannels, prate);
- if (status == NO_ERROR && prate && *prate != DEFAULT_SAMPLE_RATE) {
- mDownSampler = new ALSADownsampler(*prate,
- mDefaults->channelCount,
- PERIOD_SZ_CAPTURE,
- this);
- status = mDownSampler->initCheck();
- if (status != NO_ERROR) {
- return status;
- }
- mPcmIn = new int16_t[PERIOD_SZ_CAPTURE * mDefaults->channelCount];
- }
- return status;
-}
-
-AudioStreamInALSA::~AudioStreamInALSA()
-{
- standby();
- if (mDownSampler != NULL) {
- delete mDownSampler;
- }
- if (mPcmIn != NULL) {
- delete[] mPcmIn;
- }
-}
-
-status_t AudioStreamInALSA::setGain(float gain)
-{
- if (mParent->mMixer)
- return mParent->mMixer->setMasterGain (gain);
- else
- return NO_INIT;
-}
-
-ssize_t AudioStreamInALSA::read(void *buffer, ssize_t bytes)
-{
- snd_pcm_sframes_t n;
-
- mParent->lock().lock();
- AutoMutex lock(mLock);
- if (!mPowerLock) {
- acquire_wake_lock (PARTIAL_WAKE_LOCK, "AudioInLock");
-
- LOGD("Calling setDevice from read@..%d.\n",__LINE__);
- ALSAStreamOps::setDevice(mParent->mode(), mDevice, CAPTURE);
-
- if (mDownSampler != NULL) {
- mDownSampler->reset();
- mReadStatus = 0;
- mInPcmInBuf = 0;
- }
- mPowerLock = true;
- }
- mParent->lock().unlock();
-
- if (!mHandle) {
- return -1;
- }
-
- // FIXME: only support reads of exactly bufferSize() for now
- if (bytes != (ssize_t)bufferSize()) {
- LOGW("AudioStreamInALSA::read bad read size %d expected %d", (int)bytes, bufferSize());
- return -1;
- }
-
- size_t frames = snd_pcm_bytes_to_frames(mHandle, bytes);
- do {
- if (mDownSampler) {
- status_t status = mDownSampler->resample((int16_t *)buffer, &frames);
- if (status != NO_ERROR) {
- if (mReadStatus != 0) {
- n = mReadStatus;
- } else {
- n = status;
- }
- frames = snd_pcm_bytes_to_frames(mHandle, bytes);
- } else {
- n = frames;
- }
- } else {
- n = snd_pcm_readi(mHandle,
- (uint8_t *)buffer,
- frames);
- }
- if (n < 0) {
- LOGD("AudioStreamInALSA::read error %d", (int)n);
- n = snd_pcm_recover(mHandle, n, 0);
- LOGD("AudioStreamInALSA::snd_pcm_recover error %d", (int)n);
- if (n)
- return static_cast<ssize_t> (n);
- }
- } while (n == 0);
-
- return snd_pcm_frames_to_bytes(mHandle, n);
-}
-
-status_t AudioStreamInALSA::dump(int fd, const Vector<String16>& args)
-{
- return NO_ERROR;
-}
-
-status_t AudioStreamInALSA::setDevice(int mode,
- uint32_t newDevice,
- uint32_t audio_mode,
- bool force)
-{
- AutoMutex lock(mLock);
-
- return ALSAStreamOps::setDevice(mode, newDevice, audio_mode);
-}
-
-status_t AudioStreamInALSA::standby()
-{
- AutoMutex _l(mParent->lock());
- AutoMutex lock(mLock);
-
- LOGD("Entering AudioStreamInALSA::standby\n");
-
- ALSAStreamOps::close();
-
- if (mPowerLock) {
- release_wake_lock ("AudioInLock");
- mPowerLock = false;
- }
-
- return NO_ERROR;
-}
-
-/* New Arch */
-status_t AudioStreamInALSA::setParameters(const String8& keyValuePairs)
-{
- AudioParameter param = AudioParameter(keyValuePairs);
- String8 key = String8("vr_mode");
- status_t status = NO_ERROR;
- int value;
- LOGD("AudioStreamInALSA::setParameters() %s", keyValuePairs.string());
-
-
- if (param.getInt(key, value) == NO_ERROR) {
- mParent->setVoiceRecordGain((value != 0));
- param.remove(key);
- }
-
- key = String8(AudioParameter::keyRouting);
- if (param.getInt(key, value) == NO_ERROR) {
- if(mHandle != NULL && value != 0)
- setDevice(mParent->mode(), value, CAPTURE);
- param.remove(key);
- }
-
- if (param.size()) {
- status = BAD_VALUE;
- }
- return status;
-}
-
-
-String8 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)mDevice);
- }
-
- LOGD("AudioStreamInALSA::getParameters() %s", param.toString().string());
- return param.toString();
-}
-
-status_t AudioStreamInALSA::getNextBuffer(ALSABufferProvider::Buffer* buffer)
-{
- if (mHandle == NULL) {
- buffer->raw = NULL;
- buffer->frameCount = 0;
- return NO_INIT;
- }
-
- if (mInPcmInBuf == 0) {
- while (mInPcmInBuf < PERIOD_SZ_CAPTURE) {
- mReadStatus = snd_pcm_readi(mHandle,
- (uint8_t *)mPcmIn +
- (mInPcmInBuf * mDefaults->channelCount * sizeof(int16_t)),
- PERIOD_SZ_CAPTURE - mInPcmInBuf);
- if (mReadStatus < 0) {
- buffer->raw = NULL;
- buffer->frameCount = 0;
- LOGV("resampler read error %d", mReadStatus);
- return mReadStatus;
- }
- mInPcmInBuf += mReadStatus;
- }
- }
-
- buffer->frameCount = (buffer->frameCount > mInPcmInBuf) ? mInPcmInBuf : buffer->frameCount;
- buffer->i16 = mPcmIn + (PERIOD_SZ_CAPTURE - mInPcmInBuf) * mDefaults->channelCount;
-
- return NO_ERROR;
-}
-
-void AudioStreamInALSA::releaseBuffer(ALSABufferProvider::Buffer* buffer)
-{
- mInPcmInBuf -= buffer->frameCount;
-}
-
-
-// ----------------------------------------------------------------------------
-
-struct mixer_info_t
-{
- mixer_info_t() :
- elem(0),
- min(SND_MIXER_VOL_RANGE_MIN),
- max(SND_MIXER_VOL_RANGE_MAX),
- mute(false)
- {
- }
-
- snd_mixer_elem_t *elem;
- long min;
- long max;
- long volume;
- bool mute;
- char name[ALSA_NAME_MAX];
-};
-
-static int initMixer (snd_mixer_t **mixer, const char *name)
-{
- int err;
-
- if ((err = snd_mixer_open(mixer, 0)) < 0) {
- LOGE("Unable to open mixer: %s", snd_strerror(err));
- return err;
- }
-
- if ((err = snd_mixer_attach(*mixer, name)) < 0) {
- LOGE("Unable to attach mixer to device %s: %s",
- name, snd_strerror(err));
-
- if ((err = snd_mixer_attach(*mixer, "hw:00")) < 0) {
- LOGE("Unable to attach mixer to device default: %s",
- snd_strerror(err));
-
- snd_mixer_close (*mixer);
- *mixer = NULL;
- return err;
- }
- }
-
- if ((err = snd_mixer_selem_register(*mixer, NULL, NULL)) < 0) {
- LOGE("Unable to register mixer elements: %s", snd_strerror(err));
- snd_mixer_close (*mixer);
- *mixer = NULL;
- return err;
- }
-
- // Get the mixer controls from the kernel
- if ((err = snd_mixer_load(*mixer)) < 0) {
- LOGE("Unable to load mixer elements: %s", snd_strerror(err));
- snd_mixer_close (*mixer);
- *mixer = NULL;
- return err;
- }
-
- return 0;
-}
-
-typedef int (*hasVolume_t)(snd_mixer_elem_t*);
-
-static const hasVolume_t hasVolume[] = {
- snd_mixer_selem_has_playback_volume,
- snd_mixer_selem_has_capture_volume
-};
-
-typedef int (*getVolumeRange_t)(snd_mixer_elem_t*, long int*, long int*);
-
-static const getVolumeRange_t getVolumeRange[] = {
- snd_mixer_selem_get_playback_volume_range,
- snd_mixer_selem_get_capture_volume_range
-};
-
-typedef int (*setVolume_t)(snd_mixer_elem_t*, long int);
-
-static const setVolume_t setVol[] = {
- snd_mixer_selem_set_playback_volume_all,
- snd_mixer_selem_set_capture_volume_all
-};
-
-ALSAMixer::ALSAMixer()
-{
- int err;
-
- initMixer (&mMixer[SND_PCM_STREAM_PLAYBACK], "AndroidPlayback");
- initMixer (&mMixer[SND_PCM_STREAM_CAPTURE], "AndroidRecord");
-
- snd_mixer_selem_id_t *sid;
- snd_mixer_selem_id_alloca(&sid);
-
- for (int i = 0; i <= SND_PCM_STREAM_LAST; i++) {
-
- mixer_info_t *info = mixerMasterProp[i].mInfo = new mixer_info_t;
-
- property_get (mixerMasterProp[i].propName,
- info->name,
- mixerMasterProp[i].propDefault);
-
- for (snd_mixer_elem_t *elem = snd_mixer_first_elem(mMixer[i]);
- elem;
- elem = snd_mixer_elem_next(elem)) {
-
- if (!snd_mixer_selem_is_active(elem))
- continue;
-
- snd_mixer_selem_get_id(elem, sid);
-
- // Find PCM playback volume control element.
- const char *elementName = snd_mixer_selem_id_get_name(sid);
-
- if (hasVolume[i] (elem))
- LOGD ("Mixer: element name: '%s'", elementName);
-
- if (info->elem == NULL &&
- strcmp(elementName, info->name) == 0 &&
- hasVolume[i] (elem)) {
-
- info->elem = elem;
- getVolumeRange[i] (elem, &info->min, &info->max);
- info->volume = info->max;
- setVol[i] (elem, info->volume);
- if (i == SND_PCM_STREAM_PLAYBACK &&
- snd_mixer_selem_has_playback_switch (elem))
- snd_mixer_selem_set_playback_switch_all (elem, 1);
- break;
- }
- }
-
- LOGD ("Mixer: master '%s' %s.", info->name, info->elem ? "found" : "not found");
-
- for (int j = 0; mixerProp[j][i].routes; j++) {
-
- mixer_info_t *info = mixerProp[j][i].mInfo = new mixer_info_t;
-
- property_get (mixerProp[j][i].propName,
- info->name,
- mixerProp[j][i].propDefault);
-
- for (snd_mixer_elem_t *elem = snd_mixer_first_elem(mMixer[i]);
- elem;
- elem = snd_mixer_elem_next(elem)) {
-
- if (!snd_mixer_selem_is_active(elem))
- continue;
-
- snd_mixer_selem_get_id(elem, sid);
-
- // Find PCM playback volume control element.
- const char *elementName = snd_mixer_selem_id_get_name(sid);
-
- if (info->elem == NULL &&
- strcmp(elementName, info->name) == 0 &&
- hasVolume[i] (elem)) {
-
- info->elem = elem;
- getVolumeRange[i] (elem, &info->min, &info->max);
- info->volume = info->max;
- setVol[i] (elem, info->volume);
- if (i == SND_PCM_STREAM_PLAYBACK &&
- snd_mixer_selem_has_playback_switch (elem))
- snd_mixer_selem_set_playback_switch_all (elem, 1);
- break;
- }
- }
- LOGD ("Mixer: route '%s' %s.", info->name, info->elem ? "found" : "not found");
- }
- }
- LOGD("mixer initialized.");
-}
-
-ALSAMixer::~ALSAMixer()
-{
- for (int i = 0; i <= SND_PCM_STREAM_LAST; i++) {
- if (mMixer[i]) snd_mixer_close (mMixer[i]);
- if (mixerMasterProp[i].mInfo) {
- delete mixerMasterProp[i].mInfo;
- mixerMasterProp[i].mInfo = NULL;
- }
- for (int j = 0; mixerProp[j][i].routes; j++) {
- if (mixerProp[j][i].mInfo) {
- delete mixerProp[j][i].mInfo;
- mixerProp[j][i].mInfo = NULL;
- }
- }
- }
- LOGD("mixer destroyed.");
-}
-
-status_t ALSAMixer::setMasterVolume(float volume)
-{
- mixer_info_t *info = mixerMasterProp[SND_PCM_STREAM_PLAYBACK].mInfo;
- if (!info || !info->elem) return INVALID_OPERATION;
-
- long minVol = info->min;
- long maxVol = info->max;
-
- // Make sure volume is between bounds.
- long vol = minVol + volume * (maxVol - minVol);
- if (vol > maxVol) vol = maxVol;
- if (vol < minVol) vol = minVol;
-
- info->volume = vol;
- snd_mixer_selem_set_playback_volume_all (info->elem, vol);
-
- return NO_ERROR;
-}
-
-status_t ALSAMixer::setMasterGain(float gain)
-{
- mixer_info_t *info = mixerMasterProp[SND_PCM_STREAM_CAPTURE].mInfo;
- if (!info || !info->elem) return INVALID_OPERATION;
-
- long minVol = info->min;
- long maxVol = info->max;
-
- // Make sure volume is between bounds.
- long vol = minVol + gain * (maxVol - minVol);
- if (vol > maxVol) vol = maxVol;
- if (vol < minVol) vol = minVol;
-
- info->volume = vol;
- snd_mixer_selem_set_capture_volume_all (info->elem, vol);
-
- return NO_ERROR;
-}
-
-status_t ALSAMixer::setVolume(uint32_t device, float volume)
-{
- for (int j = 0; mixerProp[j][SND_PCM_STREAM_PLAYBACK].routes; j++)
- if (mixerProp[j][SND_PCM_STREAM_PLAYBACK].routes & device) {
-
- mixer_info_t *info = mixerProp[j][SND_PCM_STREAM_PLAYBACK].mInfo;
- if (!info || !info->elem) return INVALID_OPERATION;
-
- long minVol = info->min;
- long maxVol = info->max;
-
- // Make sure volume is between bounds.
- long vol = minVol + volume * (maxVol - minVol);
- if (vol > maxVol) vol = maxVol;
- if (vol < minVol) vol = minVol;
-
- info->volume = vol;
- snd_mixer_selem_set_playback_volume_all (info->elem, vol);
- }
-
- return NO_ERROR;
-}
-
-status_t ALSAMixer::setGain(uint32_t device, float gain)
-{
- for (int j = 0; mixerProp[j][SND_PCM_STREAM_CAPTURE].routes; j++)
- if (mixerProp[j][SND_PCM_STREAM_CAPTURE].routes & device) {
-
- mixer_info_t *info = mixerProp[j][SND_PCM_STREAM_CAPTURE].mInfo;
- if (!info || !info->elem) return INVALID_OPERATION;
-
- long minVol = info->min;
- long maxVol = info->max;
-
- // Make sure volume is between bounds.
- long vol = minVol + gain * (maxVol - minVol);
- if (vol > maxVol) vol = maxVol;
- if (vol < minVol) vol = minVol;
-
- info->volume = vol;
- snd_mixer_selem_set_capture_volume_all (info->elem, vol);
- }
-
- return NO_ERROR;
-}
-
-status_t ALSAMixer::setCaptureMuteState(uint32_t device, bool state)
-{
- for (int j = 0; mixerProp[j][SND_PCM_STREAM_CAPTURE].routes; j++)
- if (mixerProp[j][SND_PCM_STREAM_CAPTURE].routes & device) {
-
- mixer_info_t *info = mixerProp[j][SND_PCM_STREAM_CAPTURE].mInfo;
- if (!info || !info->elem) return INVALID_OPERATION;
-
- if (snd_mixer_selem_has_capture_switch (info->elem)) {
-
- int err = snd_mixer_selem_set_capture_switch_all (info->elem, static_cast<int>(!state));
- if (err < 0) {
- LOGE("Unable to %s capture mixer switch %s",
- state ? "enable" : "disable", info->name);
- return INVALID_OPERATION;
- }
- }
-
- info->mute = state;
- }
-
- return NO_ERROR;
-}
-
-status_t ALSAMixer::getCaptureMuteState(uint32_t device, bool *state)
-{
- if (! state) return BAD_VALUE;
-
- for (int j = 0; mixerProp[j][SND_PCM_STREAM_CAPTURE].routes; j++)
- if (mixerProp[j][SND_PCM_STREAM_CAPTURE].routes & device) {
-
- mixer_info_t *info = mixerProp[j][SND_PCM_STREAM_CAPTURE].mInfo;
- if (!info || !info->elem) return INVALID_OPERATION;
-
- *state = info->mute;
- return NO_ERROR;
- }
-
- return BAD_VALUE;
-}
-
-status_t ALSAMixer::setPlaybackMuteState(uint32_t device, bool state)
-{
-
- LOGE("\n set playback mute device %d, state %d \n", device,state);
-
- for (int j = 0; mixerProp[j][SND_PCM_STREAM_PLAYBACK].routes; j++)
- if (mixerProp[j][SND_PCM_STREAM_PLAYBACK].routes & device) {
-
- mixer_info_t *info = mixerProp[j][SND_PCM_STREAM_PLAYBACK].mInfo;
- if (!info || !info->elem) return INVALID_OPERATION;
-
- if (snd_mixer_selem_has_playback_switch (info->elem)) {
-
- int err = snd_mixer_selem_set_playback_switch_all (info->elem, static_cast<int>(!state));
- if (err < 0) {
- LOGE("Unable to %s playback mixer switch %s",
- state ? "enable" : "disable", info->name);
- return INVALID_OPERATION;
- }
- }
-
- info->mute = state;
- }
-
- return NO_ERROR;
-}
-
-status_t ALSAMixer::getPlaybackMuteState(uint32_t device, bool *state)
-{
- if (! state) return BAD_VALUE;
-
- for (int j = 0; mixerProp[j][SND_PCM_STREAM_PLAYBACK].routes; j++)
- if (mixerProp[j][SND_PCM_STREAM_PLAYBACK].routes & device) {
-
- mixer_info_t *info = mixerProp[j][SND_PCM_STREAM_PLAYBACK].mInfo;
- if (!info || !info->elem) return INVALID_OPERATION;
-
- *state = info->mute;
- return NO_ERROR;
- }
-
- return BAD_VALUE;
-}
-
-// ----------------------------------------------------------------------------
-
-ALSAControl::ALSAControl(const char *device)
-{
- snd_ctl_open(&mHandle, device, 0);
-}
-
-ALSAControl::~ALSAControl()
-{
- if (mHandle) snd_ctl_close(mHandle);
-}
-
-status_t ALSAControl::get(const char *name, unsigned int &value, int index)
-{
- if (!mHandle) return NO_INIT;
-
- snd_ctl_elem_id_t *id;
- snd_ctl_elem_info_t *info;
- snd_ctl_elem_value_t *control;
-
- snd_ctl_elem_id_alloca(&id);
- snd_ctl_elem_info_alloca(&info);
- snd_ctl_elem_value_alloca(&control);
-
- snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
- snd_ctl_elem_id_set_name(id, name);
- snd_ctl_elem_info_set_id(info, id);
-
- int ret = snd_ctl_elem_info(mHandle, info);
- if (ret < 0) return BAD_VALUE;
-
- snd_ctl_elem_info_get_id(info, id);
- snd_ctl_elem_type_t type = snd_ctl_elem_info_get_type(info);
- unsigned int count = snd_ctl_elem_info_get_count(info);
- if ((unsigned int)index >= count) return BAD_VALUE;
-
- snd_ctl_elem_value_set_id(control, id);
-
- ret = snd_ctl_elem_read(mHandle, control);
- if (ret < 0) return BAD_VALUE;
-
- switch (type) {
- case SND_CTL_ELEM_TYPE_BOOLEAN:
- value = snd_ctl_elem_value_get_boolean(control, index);
- break;
- case SND_CTL_ELEM_TYPE_INTEGER:
- value = snd_ctl_elem_value_get_integer(control, index);
- break;
- case SND_CTL_ELEM_TYPE_INTEGER64:
- value = snd_ctl_elem_value_get_integer64(control, index);
- break;
- case SND_CTL_ELEM_TYPE_ENUMERATED:
- value = snd_ctl_elem_value_get_enumerated(control, index);
- break;
- case SND_CTL_ELEM_TYPE_BYTES:
- value = snd_ctl_elem_value_get_byte(control, index);
- break;
- default:
- return BAD_VALUE;
- }
-
- return NO_ERROR;
-}
-
-status_t ALSAControl::set(const char *name, unsigned int value, int index)
-{
- if (!mHandle) return NO_INIT;
-
- snd_ctl_elem_id_t *id;
- snd_ctl_elem_info_t *info;
- snd_ctl_elem_value_t *control;
-
- snd_ctl_elem_id_alloca(&id);
- snd_ctl_elem_info_alloca(&info);
- snd_ctl_elem_value_alloca(&control);
-
- snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
- snd_ctl_elem_id_set_name(id, name);
- snd_ctl_elem_info_set_id(info, id);
-
- int ret = snd_ctl_elem_info(mHandle, info);
- if (ret < 0) return BAD_VALUE;
-
- snd_ctl_elem_info_get_id(info, id);
- snd_ctl_elem_type_t type = snd_ctl_elem_info_get_type(info);
- unsigned int count = snd_ctl_elem_info_get_count(info);
-
- if (index >= (int)count) return BAD_VALUE;
-
- if (index == -1)
- index = 0; // Range over all of them
- else
- count = index + 1; // Just do the one specified
-
- snd_ctl_elem_value_set_id(control, id);
-
- for (unsigned int i = index; i < count; i++)
- switch (type) {
- case SND_CTL_ELEM_TYPE_BOOLEAN:
- snd_ctl_elem_value_set_boolean(control, i, value);
- break;
- case SND_CTL_ELEM_TYPE_INTEGER:
- snd_ctl_elem_value_set_integer(control, i, value);
- break;
- case SND_CTL_ELEM_TYPE_INTEGER64:
- snd_ctl_elem_value_set_integer64(control, i, value);
- break;
- case SND_CTL_ELEM_TYPE_ENUMERATED:
- snd_ctl_elem_value_set_enumerated(control, i, value);
- break;
- case SND_CTL_ELEM_TYPE_BYTES:
- snd_ctl_elem_value_set_byte(control, i, value);
- break;
- default:
- break;
- }
- ret = snd_ctl_elem_write(mHandle, control);
- return (ret < 0) ? BAD_VALUE : NO_ERROR;
-}
-
-//------------------------------------------------------------------------------
-// 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;
-}
-
-
-ALSADownsampler::ALSADownsampler(uint32_t outSampleRate,
- uint32_t channelCount,
- uint32_t frameCount,
- ALSABufferProvider* provider)
- : mStatus(NO_INIT), mProvider(provider), mSampleRate(outSampleRate),
- mChannelCount(channelCount), mFrameCount(frameCount),
- mInLeft(NULL), mInRight(NULL), mTmpLeft(NULL), mTmpRight(NULL),
- mTmp2Left(NULL), mTmp2Right(NULL), mOutLeft(NULL), mOutRight(NULL)
-
-{
- LOGV("ALSADownsampler() cstor SR %d channels %d frames %d",
- mSampleRate, mChannelCount, mFrameCount);
-
- if (mSampleRate != 8000 && mSampleRate != 11025 && mSampleRate != 16000 &&
- mSampleRate != 22050) {
- LOGW("ALSADownsampler cstor: bad sampling rate: %d", mSampleRate);
- return;
- }
-
- mInLeft = new int16_t[mFrameCount];
- mInRight = new int16_t[mFrameCount];
- mTmpLeft = new int16_t[mFrameCount];
- mTmpRight = new int16_t[mFrameCount];
- mTmp2Left = new int16_t[mFrameCount];
- mTmp2Right = new int16_t[mFrameCount];
- mOutLeft = new int16_t[mFrameCount];
- mOutRight = new int16_t[mFrameCount];
-
- mStatus = NO_ERROR;
-}
-
-ALSADownsampler::~ALSADownsampler()
-{
- if (mInLeft) delete[] mInLeft;
- if (mInRight) delete[] mInRight;
- if (mTmpLeft) delete[] mTmpLeft;
- if (mTmpRight) delete[] mTmpRight;
- if (mTmp2Left) delete[] mTmp2Left;
- if (mTmp2Right) delete[] mTmp2Right;
- if (mOutLeft) delete[] mOutLeft;
- if (mOutRight) delete[] mOutRight;
-}
-
-void ALSADownsampler::reset()
-{
- mInInBuf = 0;
- mInTmpBuf = 0;
- mInTmp2Buf = 0;
- mOutBufPos = 0;
- mInOutBuf = 0;
-}
-
-
-int ALSADownsampler::resample(int16_t* out, size_t *outFrameCount)
-{
- if (mStatus != NO_ERROR) {
- return mStatus;
- }
-
- if (out == NULL || outFrameCount == NULL) {
- return BAD_VALUE;
- }
-
- int16_t *outLeft = mTmp2Left;
- int16_t *outRight = mTmp2Left;
- if (mSampleRate == 22050) {
- outLeft = mTmpLeft;
- outRight = mTmpRight;
- } else if (mSampleRate == 8000){
- outLeft = mOutLeft;
- outRight = mOutRight;
- }
-
- int outFrames = 0;
- int remaingFrames = *outFrameCount;
-
- if (mInOutBuf) {
- int frames = (remaingFrames > mInOutBuf) ? mInOutBuf : remaingFrames;
-
- for (int i = 0; i < frames; ++i) {
- out[i] = outLeft[mOutBufPos + i];
- }
- if (mChannelCount == 2) {
- for (int i = 0; i < frames; ++i) {
- out[i * 2] = outLeft[mOutBufPos + i];
- out[i * 2 + 1] = outRight[mOutBufPos + i];
- }
- }
- remaingFrames -= frames;
- mInOutBuf -= frames;
- mOutBufPos += frames;
- outFrames += frames;
- }
-
- while (remaingFrames) {
- LOGW_IF((mInOutBuf != 0), "mInOutBuf should be 0 here");
-
- ALSABufferProvider::Buffer buf;
- buf.frameCount = mFrameCount - mInInBuf;
- int ret = mProvider->getNextBuffer(&buf);
- if (buf.raw == NULL) {
- *outFrameCount = outFrames;
- return ret;
- }
-
- for (size_t i = 0; i < buf.frameCount; ++i) {
- mInLeft[i + mInInBuf] = buf.i16[i];
- }
- if (mChannelCount == 2) {
- for (size_t i = 0; i < buf.frameCount; ++i) {
- mInLeft[i + mInInBuf] = buf.i16[i * 2];
- mInRight[i + mInInBuf] = buf.i16[i * 2 + 1];
- }
- }
- mInInBuf += buf.frameCount;
- mProvider->releaseBuffer(&buf);
-
- /* 44010 -> 22050 */
- {
- int samples_in_left = mInInBuf;
- int samples_out_left;
- resample_2_1(mInLeft, mTmpLeft + mInTmpBuf, &samples_in_left, &samples_out_left);
-
- if (mChannelCount == 2) {
- int samples_in_right = mInInBuf;
- int samples_out_right;
- resample_2_1(mInRight, mTmpRight + mInTmpBuf, &samples_in_right, &samples_out_right);
- }
-
- mInInBuf = samples_in_left;
- mInTmpBuf += samples_out_left;
- mInOutBuf = samples_out_left;
- }
-
- if (mSampleRate == 11025 || mSampleRate == 8000) {
- /* 22050 - > 11025 */
- int samples_in_left = mInTmpBuf;
- int samples_out_left;
- resample_2_1(mTmpLeft, mTmp2Left + mInTmp2Buf, &samples_in_left, &samples_out_left);
-
- if (mChannelCount == 2) {
- int samples_in_right = mInTmpBuf;
- int samples_out_right;
- resample_2_1(mTmpRight, mTmp2Right + mInTmp2Buf, &samples_in_right, &samples_out_right);
- }
-
-
- mInTmpBuf = samples_in_left;
- mInTmp2Buf += samples_out_left;
- mInOutBuf = samples_out_left;
-
- if (mSampleRate == 8000) {
- /* 11025 -> 8000*/
- int samples_in_left = mInTmp2Buf;
- int samples_out_left;
- resample_441_320(mTmp2Left, mOutLeft, &samples_in_left, &samples_out_left);
-
- if (mChannelCount == 2) {
- int samples_in_right = mInTmp2Buf;
- int samples_out_right;
- resample_441_320(mTmp2Right, mOutRight, &samples_in_right, &samples_out_right);
- }
-
- mInTmp2Buf = samples_in_left;
- mInOutBuf = samples_out_left;
- } else {
- mInTmp2Buf = 0;
- }
-
- } else if (mSampleRate == 16000) {
- /* 22050 -> 16000*/
- int samples_in_left = mInTmpBuf;
- int samples_out_left;
- resample_441_320(mTmpLeft, mTmp2Left, &samples_in_left, &samples_out_left);
-
- if (mChannelCount == 2) {
- int samples_in_right = mInTmpBuf;
- int samples_out_right;
- resample_441_320(mTmpRight, mTmp2Right, &samples_in_right, &samples_out_right);
- }
-
- mInTmpBuf = samples_in_left;
- mInOutBuf = samples_out_left;
- } else {
- mInTmpBuf = 0;
- }
-
- int frames = (remaingFrames > mInOutBuf) ? mInOutBuf : remaingFrames;
-
- for (int i = 0; i < frames; ++i) {
- out[outFrames + i] = outLeft[i];
- }
- if (mChannelCount == 2) {
- for (int i = 0; i < frames; ++i) {
- out[(outFrames + i) * 2] = outLeft[i];
- out[(outFrames + i) * 2 + 1] = outRight[i];
- }
- }
- remaingFrames -= frames;
- outFrames += frames;
- mOutBufPos = frames;
- mInOutBuf -= frames;
- }
-
- return 0;
-}
-
-}; // namespace android
-
diff --git a/libaudio/AudioHardwareALSA.h b/libaudio/AudioHardwareALSA.h
deleted file mode 100755
index c3b6caa..0000000
--- a/libaudio/AudioHardwareALSA.h
+++ /dev/null
@@ -1,432 +0,0 @@
-/* AudioHardwareALSA.h
- **
- ** Copyright 2008, Wind River Systems
- **
- ** 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.
- */
-
-#ifndef ANDROID_AUDIO_HARDWARE_ALSA_H
-#define ANDROID_AUDIO_HARDWARE_ALSA_H
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <alsa/asoundlib.h>
-
-#include <hardware_legacy/AudioHardwareBase.h>
-
-// sangsu fix : headers for IPC
-#include "secril-client.h"
-
-#ifndef ALSA_DEFAULT_SAMPLE_RATE
-#define ALSA_DEFAULT_SAMPLE_RATE 44100 // in Hz
-#endif
-
-#define DEFAULT_SAMPLE_RATE ALSA_DEFAULT_SAMPLE_RATE
-
-#define PLAYBACK 0
-#define PERIOD_SZ_PLAYBACK 1024
-#define PERIODS_PLAYBACK 4
-#define BUFFER_SZ_PLAYBACK (PERIODS_PLAYBACK * PERIOD_SZ_PLAYBACK)
-#define LATENCY_PLAYBACK_MS ((BUFFER_SZ_PLAYBACK * 1000 / DEFAULT_SAMPLE_RATE) * 1000)
-
-#define CAPTURE 1
-#define PERIOD_SZ_CAPTURE 1024
-#define PERIODS_CAPTURE 4
-#define BUFFER_SZ_CAPTURE (PERIODS_CAPTURE * PERIOD_SZ_CAPTURE)
-#define LATENCY_CAPTURE_MS ((BUFFER_SZ_CAPTURE * 1000 / DEFAULT_SAMPLE_RATE) * 1000)
-
-//Recognition param
-#define RECOGNITION_OFF 0
-#define RECOGNITION_ON 1
-
-namespace android
-{
-
- class AudioHardwareALSA;
-
- // ----------------------------------------------------------------------------
-
- class ALSAMixer
- {
- public:
- ALSAMixer();
- virtual ~ALSAMixer();
-
- bool isValid() { return !!mMixer[SND_PCM_STREAM_PLAYBACK]; }
- status_t setMasterVolume(float volume);
- status_t setMasterGain(float gain);
-
- status_t setVolume(uint32_t device, float volume);
- status_t setGain(uint32_t device, float gain);
-
- status_t setCaptureMuteState(uint32_t device, bool state);
- status_t getCaptureMuteState(uint32_t device, bool *state);
- status_t setPlaybackMuteState(uint32_t device, bool state);
- status_t getPlaybackMuteState(uint32_t device, bool *state);
-
- private:
- snd_mixer_t *mMixer[SND_PCM_STREAM_LAST+1];
- };
-
- class ALSAControl
- {
- public:
- ALSAControl(const char *device = "default");
- virtual ~ALSAControl();
-
- status_t get(const char *name, unsigned int &value, int index = 0);
- status_t set(const char *name, unsigned int value, int index = -1);
-
- private:
- snd_ctl_t *mHandle;
- };
-
- class ALSAStreamOps
- {
- public:
- uint32_t device() { return mDevice; }
- void close();
-
- protected:
- friend class AudioStreamOutALSA;
- friend class AudioStreamInALSA;
-
- struct StreamDefaults
- {
- const char * devicePrefix;
- snd_pcm_stream_t direction; // playback or capture
- snd_pcm_format_t format;
- int channelCount;
- uint32_t sampleRate;
- uint32_t bufferRatio;
- unsigned int latency; // Delay in usec
- unsigned int bufferSize; // Size of sample buffer
- unsigned int periodSize; // Size of sample buffer
- };
-
- ALSAStreamOps();
- virtual ~ALSAStreamOps();
-
- status_t set(int *format,
- uint32_t *channels,
- uint32_t *rate);
- virtual uint32_t sampleRate() const;
- status_t sampleRate(uint32_t rate);
- virtual size_t bufferSize() const;
- virtual int format() const;
- int getAndroidFormat(snd_pcm_format_t format);
-
- virtual uint32_t channels() const;
- int channelCount() const;
- status_t channelCount(int channelCount);
- uint32_t getAndroidChannels(int channelCount) const;
-
- status_t open(int mode, uint32_t device);
- status_t setSoftwareParams();
- status_t setPCMFormat(snd_pcm_format_t format);
- status_t setHardwareResample(bool resample);
-
- const char *streamName();
- status_t setDevice(int mode, uint32_t device, uint32_t audio_mode);
-
- const char *deviceName(int mode, uint32_t device);
-
- void setStreamDefaults(StreamDefaults *dev) {
- mDefaults = dev;
- }
-
- Mutex mLock;
-
- private:
- snd_pcm_t *mHandle;
- snd_pcm_hw_params_t *mHardwareParams;
- snd_pcm_sw_params_t *mSoftwareParams;
- uint32_t mDevice;
-
- StreamDefaults *mDefaults;
- };
-
- // ----------------------------------------------------------------------------
-
- class AudioStreamOutALSA : public AudioStreamOut, public ALSAStreamOps
- {
- public:
- AudioStreamOutALSA(AudioHardwareALSA *parent);
- virtual ~AudioStreamOutALSA();
-
-
- status_t set(int *format,
- uint32_t *channelCount,
- uint32_t *sampleRate){
- return ALSAStreamOps::set(format, channelCount, sampleRate);
- }
-
- virtual uint32_t sampleRate() const {
- return ALSAStreamOps::sampleRate();
- }
-
- virtual size_t bufferSize() const
- {
- return ALSAStreamOps::bufferSize();
- }
-
- virtual uint32_t channels() const
- {
- return ALSAStreamOps::channels();
- }
-
- virtual int format() const
- {
- return ALSAStreamOps::format();
- }
-
- virtual uint32_t latency() const;
-
- virtual ssize_t write(const void *buffer, size_t bytes);
- virtual status_t dump(int fd, const Vector<String16>& args);
- status_t setDevice(int mode, uint32_t newDevice, uint32_t audio_mode,
- bool force = false);
- virtual status_t setVolume(float left, float right); //Tushar: New arch
-
- status_t setVolume(float volume);
-
- status_t standby();
-
- virtual status_t setParameters(const String8& keyValuePairs);
- virtual String8 getParameters(const String8& keys);
-
- virtual status_t getRenderPosition(uint32_t *dspFrames);
- bool isActive() { return mPowerLock; }
-
- private:
- AudioHardwareALSA *mParent;
- bool mPowerLock;
- };
-
- class ALSADownsampler;
-
- class ALSABufferProvider
- {
- public:
-
- struct Buffer {
- union {
- void* raw;
- short* i16;
- int8_t* i8;
- };
- size_t frameCount;
- };
-
- virtual ~ALSABufferProvider() {}
-
- virtual status_t getNextBuffer(Buffer* buffer) = 0;
- virtual void releaseBuffer(Buffer* buffer) = 0;
- };
-
- class AudioStreamInALSA : public AudioStreamIn, public ALSAStreamOps, public ALSABufferProvider
- {
- public:
- AudioStreamInALSA(AudioHardwareALSA *parent);
- virtual ~AudioStreamInALSA();
-
- status_t set(int *format,
- uint32_t *channelCount,
- uint32_t *sampleRate);
-
- virtual uint32_t sampleRate() const {
- return ALSAStreamOps::sampleRate();
- }
-
- virtual size_t bufferSize() const
- {
- return ALSAStreamOps::bufferSize();
- }
-
- virtual uint32_t channels() const
- {
- return ALSAStreamOps::channels();
- }
-
- virtual int format() const
- {
- return ALSAStreamOps::format();
- }
-
- virtual ssize_t read(void* buffer, ssize_t bytes);
- virtual status_t dump(int fd, const Vector<String16>& args);
- status_t setDevice(int mode, uint32_t newDevice, uint32_t audio_mode,
- bool force = false);
-
- virtual status_t setGain(float gain);
-
- virtual status_t standby();
-
- virtual status_t setParameters(const String8& keyValuePairs);
- virtual String8 getParameters(const String8& keys);
-
- virtual unsigned int getInputFramesLost() const { return 0; }
-
- bool isActive() { return mPowerLock; }
-
- // ALSABufferProvider
- virtual status_t getNextBuffer(ALSABufferProvider::Buffer* buffer);
- virtual void releaseBuffer(ALSABufferProvider::Buffer* buffer);
-
- private:
- AudioHardwareALSA *mParent;
- bool mPowerLock;
- ALSADownsampler *mDownSampler;
- status_t mReadStatus;
- size_t mInPcmInBuf;
- int16_t *mPcmIn;
- };
-
- class AudioHardwareALSA : public AudioHardwareBase
- {
- public:
- AudioHardwareALSA();
- virtual ~AudioHardwareALSA();
-
- /**
- * check to see if the audio hardware interface has been initialized.
- * return status based on values defined in include/utils/Errors.h
- */
- virtual status_t initCheck();
-
- /** set the audio volume of a voice call. Range is between 0.0 and 1.0 */
- virtual status_t setVoiceVolume(float volume);
-
- virtual status_t setMode(int mode);
-
- /**
- * set the audio volume for all audio activities other than voice call.
- * Range between 0.0 and 1.0. If any value other than NO_ERROR is returned,
- * the software mixer will emulate this capability.
- */
- virtual status_t setMasterVolume(float volume);
-
- // mic mute
- virtual status_t setMicMute(bool state);
- virtual status_t getMicMute(bool* state);
- virtual size_t getInputBufferSize(uint32_t sampleRate,
- int format,
- int channelCount);
-
- /** This method creates and opens the audio hardware output stream */
- virtual AudioStreamOut* openOutputStream(uint32_t devices,
- int *format = 0,
- uint32_t *channels = 0,
- uint32_t *sampleRate = 0,
- status_t *status = 0);
- virtual void closeOutputStream(AudioStreamOut* out);
-
- /** This method creates and opens the audio hardware input stream */
- virtual AudioStreamIn* openInputStream(uint32_t devices,
- int *format,
- uint32_t *channels,
- uint32_t *sampleRate,
- status_t *status,
- AudioSystem::audio_in_acoustics acoustics);
- virtual void closeInputStream(AudioStreamIn* in);
-
- static uint32_t checkInputSampleRate(uint32_t sampleRate);
- static const uint32_t inputSamplingRates[];
- static uint32_t bufferRatio(uint32_t samplingRate);
-
- int mode() { return mMode; }
- Mutex& lock() { return mLock; }
-
- int setVoiceRecordGain(bool enable);
- int setVoiceRecordGain_l(bool enable);
-
- virtual status_t setParameters(const String8& keyValuePairs);
-
- protected:
- /**
- * doRouting actually initiates the routing. A call to setRouting
- * or setMode may result in a routing change. The generic logic calls
- * doRouting when required. If the device has any special requirements these
- * methods can be overriden.
- */
- status_t doRouting(uint32_t device, bool force = false);
- status_t doRouting_l(uint32_t device, bool force = false);
-
- virtual status_t dump(int fd, const Vector<String16>& args);
-
- friend class AudioStreamOutALSA;
- friend class AudioStreamInALSA;
-
- ALSAMixer *mMixer;
- AudioStreamOutALSA *mOutput;
- AudioStreamInALSA *mInput;
-
- private:
- Mutex mLock;
- void *mSecRilLibHandle;
- HRilClient mRilClient;
- bool mVrModeEnabled;
- bool mActivatedCP;
- bool mBluetoothECOff;
-
- HRilClient (*openClientRILD) (void);
- int (*disconnectRILD) (HRilClient);
- int (*closeClientRILD) (HRilClient);
- int (*isConnectedRILD) (HRilClient);
- int (*connectRILD) (HRilClient);
- int (*setCallVolume) (HRilClient, SoundType, int);
- int (*setCallAudioPath)(HRilClient, AudioPath);
- int (*setCallClockSync)(HRilClient, SoundClockCondition);
-
- void loadRILD(void);
- status_t connectRILDIfRequired(void);
- void setBluetoothNrEcOnOff(bool disable);
-
- };
-
- class ALSADownsampler {
- public:
- ALSADownsampler(uint32_t outSampleRate,
- uint32_t channelCount,
- uint32_t frameCount,
- ALSABufferProvider* provider);
-
- virtual ~ALSADownsampler();
-
- void reset();
- status_t initCheck() { return mStatus; }
- int resample(int16_t* out, size_t *outFrameCount);
-
- private:
- status_t mStatus;
- ALSABufferProvider* mProvider;
- uint32_t mSampleRate;
- uint32_t mChannelCount;
- uint32_t mFrameCount;
- int16_t *mInLeft;
- int16_t *mInRight;
- int16_t *mTmpLeft;
- int16_t *mTmpRight;
- int16_t *mTmp2Left;
- int16_t *mTmp2Right;
- int16_t *mOutLeft;
- int16_t *mOutRight;
- int mInInBuf;
- int mInTmpBuf;
- int mInTmp2Buf;
- int mOutBufPos;
- int mInOutBuf;
- };
-
-}; // namespace android
-#endif // ANDROID_AUDIO_HARDWARE_ALSA_H
diff --git a/libaudio/AudioPolicyManager.cpp b/libaudio/AudioPolicyManager.cpp
index 41c0fd0..93d70d8 100644
--- a/libaudio/AudioPolicyManager.cpp
+++ b/libaudio/AudioPolicyManager.cpp
@@ -42,4 +42,33 @@ extern "C" void destroyAudioPolicyManager(AudioPolicyInterface *interface)
delete interface;
}
+
+status_t AudioPolicyManager::startInput(audio_io_handle_t input)
+{
+ status_t status = AudioPolicyManagerBase::startInput(input);
+
+ if (status == NO_ERROR) {
+ AudioInputDescriptor *inputDesc = mInputs.valueFor(input);
+ String8 key = String8("Input Source");
+ String8 value;
+ switch(inputDesc->mInputSource) {
+ case AUDIO_SOURCE_VOICE_RECOGNITION:
+ value = String8("Voice Recognition");
+ break;
+ case AUDIO_SOURCE_CAMCORDER:
+ value = String8("Camcorder");
+ break;
+ case AUDIO_SOURCE_DEFAULT:
+ case AUDIO_SOURCE_MIC:
+ value = String8("Default");
+ default:
+ break;
+ }
+ AudioParameter param = AudioParameter();
+ param.add(key, value);
+ mpClientInterface->setParameters(input, param.toString());
+ }
+ return status;
+}
+
}; // namespace android
diff --git a/libaudio/AudioPolicyManager.h b/libaudio/AudioPolicyManager.h
index 03141e5..ae283db 100644
--- a/libaudio/AudioPolicyManager.h
+++ b/libaudio/AudioPolicyManager.h
@@ -34,6 +34,7 @@ public:
virtual ~AudioPolicyManager() {}
+ virtual status_t startInput(audio_io_handle_t input);
protected:
// true is current platform implements a back microphone
virtual bool hasBackMicrophone() const { return false; }
diff --git a/libaudio/NOTICE b/libaudio/NOTICE
deleted file mode 100644
index ada44e1..0000000
--- a/libaudio/NOTICE
+++ /dev/null
@@ -1,191 +0,0 @@
-
- Copyright (c) 2005-2008, The Android Open Source Project
- Copyright 2008 Wind River Systems
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
-
- 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.
-
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
diff --git a/libaudio/alsa_audio.h b/libaudio/alsa_audio.h
new file mode 100644
index 0000000..3cb86d9
--- /dev/null
+++ b/libaudio/alsa_audio.h
@@ -0,0 +1,77 @@
+/*
+** 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.
+*/
+
+#ifndef _AUDIO_H_
+#define _AUDIO_H_
+
+struct pcm;
+
+#define PCM_OUT 0x00000000
+#define PCM_IN 0x10000000
+
+#define PCM_STEREO 0x00000000
+#define PCM_MONO 0x01000000
+
+#define PCM_44100HZ 0x00000000
+#define PCM_48000HZ 0x00100000
+#define PCM_8000HZ 0x00200000
+#define PCM_RATE_MASK 0x00F00000
+
+#define PCM_PERIOD_CNT_MIN 2
+#define PCM_PERIOD_CNT_SHIFT 16
+#define PCM_PERIOD_CNT_MASK (0xF << PCM_PERIOD_CNT_SHIFT)
+#define PCM_PERIOD_SZ_MIN 128
+#define PCM_PERIOD_SZ_SHIFT 12
+#define PCM_PERIOD_SZ_MASK (0xF << PCM_PERIOD_SZ_SHIFT)
+
+/* Acquire/release a pcm channel.
+ * Returns non-zero on error
+ */
+struct pcm *pcm_open(unsigned flags);
+int pcm_close(struct pcm *pcm);
+int pcm_ready(struct pcm *pcm);
+
+/* Returns a human readable reason for the last error. */
+const char *pcm_error(struct pcm *pcm);
+
+/* Returns the buffer size (int bytes) that should be used for pcm_write.
+ * This will be 1/2 of the actual fifo size.
+ */
+unsigned pcm_buffer_size(struct pcm *pcm);
+
+/* Write data to the fifo.
+ * Will start playback on the first write or on a write that
+ * occurs after a fifo underrun.
+ */
+int pcm_write(struct pcm *pcm, void *data, unsigned count);
+int pcm_read(struct pcm *pcm, void *data, unsigned count);
+
+struct mixer;
+struct mixer_ctl;
+
+struct mixer *mixer_open(void);
+void mixer_close(struct mixer *mixer);
+void mixer_dump(struct mixer *mixer);
+
+struct mixer_ctl *mixer_get_control(struct mixer *mixer,
+ const char *name, unsigned index);
+struct mixer_ctl *mixer_get_nth_control(struct mixer *mixer, unsigned n);
+
+int mixer_ctl_set(struct mixer_ctl *ctl, unsigned percent);
+int mixer_ctl_select(struct mixer_ctl *ctl, const char *value);
+void mixer_ctl_print(struct mixer_ctl *ctl);
+
+#endif
diff --git a/libaudio/alsa_mixer.c b/libaudio/alsa_mixer.c
new file mode 100644
index 0000000..3036ef8
--- /dev/null
+++ b/libaudio/alsa_mixer.c
@@ -0,0 +1,371 @@
+/*
+** 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.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include <linux/ioctl.h>
+#define __force
+#define __bitwise
+#define __user
+#include "asound.h"
+
+#include "alsa_audio.h"
+
+static const char *elem_iface_name(snd_ctl_elem_iface_t n)
+{
+ switch (n) {
+ case SNDRV_CTL_ELEM_IFACE_CARD: return "CARD";
+ case SNDRV_CTL_ELEM_IFACE_HWDEP: return "HWDEP";
+ case SNDRV_CTL_ELEM_IFACE_MIXER: return "MIXER";
+ case SNDRV_CTL_ELEM_IFACE_PCM: return "PCM";
+ case SNDRV_CTL_ELEM_IFACE_RAWMIDI: return "MIDI";
+ case SNDRV_CTL_ELEM_IFACE_TIMER: return "TIMER";
+ case SNDRV_CTL_ELEM_IFACE_SEQUENCER: return "SEQ";
+ default: return "???";
+ }
+}
+
+static const char *elem_type_name(snd_ctl_elem_type_t n)
+{
+ switch (n) {
+ case SNDRV_CTL_ELEM_TYPE_NONE: return "NONE";
+ case SNDRV_CTL_ELEM_TYPE_BOOLEAN: return "BOOL";
+ case SNDRV_CTL_ELEM_TYPE_INTEGER: return "INT32";
+ case SNDRV_CTL_ELEM_TYPE_ENUMERATED: return "ENUM";
+ case SNDRV_CTL_ELEM_TYPE_BYTES: return "BYTES";
+ case SNDRV_CTL_ELEM_TYPE_IEC958: return "IEC958";
+ case SNDRV_CTL_ELEM_TYPE_INTEGER64: return "INT64";
+ default: return "???";
+ }
+}
+
+
+struct mixer_ctl {
+ struct mixer *mixer;
+ struct snd_ctl_elem_info *info;
+ char **ename;
+};
+
+struct mixer {
+ int fd;
+ struct snd_ctl_elem_info *info;
+ struct mixer_ctl *ctl;
+ unsigned count;
+};
+
+void mixer_close(struct mixer *mixer)
+{
+ unsigned n,m;
+
+ if (mixer->fd >= 0)
+ close(mixer->fd);
+
+ if (mixer->ctl) {
+ for (n = 0; n < mixer->count; n++) {
+ if (mixer->ctl[n].ename) {
+ unsigned max = mixer->ctl[n].info->value.enumerated.items;
+ for (m = 0; m < max; m++)
+ free(mixer->ctl[n].ename[m]);
+ free(mixer->ctl[n].ename);
+ }
+ }
+ free(mixer->ctl);
+ }
+
+ if (mixer->info)
+ free(mixer->info);
+
+ free(mixer);
+}
+
+struct mixer *mixer_open(void)
+{
+ struct snd_ctl_elem_list elist;
+ struct snd_ctl_elem_info tmp;
+ struct snd_ctl_elem_id *eid = NULL;
+ struct mixer *mixer = NULL;
+ unsigned n, m;
+ int fd;
+
+ fd = open("/dev/snd/controlC0", O_RDWR);
+ if (fd < 0)
+ return 0;
+
+ memset(&elist, 0, sizeof(elist));
+ if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &elist) < 0)
+ goto fail;
+
+ mixer = calloc(1, sizeof(*mixer));
+ if (!mixer)
+ goto fail;
+
+ mixer->ctl = calloc(elist.count, sizeof(struct mixer_ctl));
+ mixer->info = calloc(elist.count, sizeof(struct snd_ctl_elem_info));
+ if (!mixer->ctl || !mixer->info)
+ goto fail;
+
+ eid = calloc(elist.count, sizeof(struct snd_ctl_elem_id));
+ if (!eid)
+ goto fail;
+
+ mixer->count = elist.count;
+ mixer->fd = fd;
+ elist.space = mixer->count;
+ elist.pids = eid;
+ if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &elist) < 0)
+ goto fail;
+
+ for (n = 0; n < mixer->count; n++) {
+ struct snd_ctl_elem_info *ei = mixer->info + n;
+ ei->id.numid = eid[n].numid;
+ if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_INFO, ei) < 0)
+ goto fail;
+ mixer->ctl[n].info = ei;
+ mixer->ctl[n].mixer = mixer;
+ if (ei->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) {
+ char **enames = calloc(ei->value.enumerated.items, sizeof(char*));
+ if (!enames)
+ goto fail;
+ mixer->ctl[n].ename = enames;
+ for (m = 0; m < ei->value.enumerated.items; m++) {
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.id.numid = ei->id.numid;
+ tmp.value.enumerated.item = m;
+ if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_INFO, &tmp) < 0)
+ goto fail;
+ enames[m] = strdup(tmp.value.enumerated.name);
+ if (!enames[m])
+ goto fail;
+ }
+ }
+ }
+
+ free(eid);
+ return mixer;
+
+fail:
+ if (eid)
+ free(eid);
+ if (mixer)
+ mixer_close(mixer);
+ else if (fd >= 0)
+ close(fd);
+ return 0;
+}
+
+void mixer_dump(struct mixer *mixer)
+{
+ unsigned n, m;
+
+ printf(" id iface dev sub idx num perms type name\n");
+ for (n = 0; n < mixer->count; n++) {
+ struct snd_ctl_elem_info *ei = mixer->info + n;
+
+ printf("%4d %5s %3d %3d %3d %3d %c%c%c%c%c%c%c%c%c %-6s %s",
+ ei->id.numid, elem_iface_name(ei->id.iface),
+ ei->id.device, ei->id.subdevice, ei->id.index,
+ ei->count,
+ (ei->access & SNDRV_CTL_ELEM_ACCESS_READ) ? 'r' : ' ',
+ (ei->access & SNDRV_CTL_ELEM_ACCESS_WRITE) ? 'w' : ' ',
+ (ei->access & SNDRV_CTL_ELEM_ACCESS_VOLATILE) ? 'V' : ' ',
+ (ei->access & SNDRV_CTL_ELEM_ACCESS_TIMESTAMP) ? 'T' : ' ',
+ (ei->access & SNDRV_CTL_ELEM_ACCESS_TLV_READ) ? 'R' : ' ',
+ (ei->access & SNDRV_CTL_ELEM_ACCESS_TLV_WRITE) ? 'W' : ' ',
+ (ei->access & SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND) ? 'C' : ' ',
+ (ei->access & SNDRV_CTL_ELEM_ACCESS_INACTIVE) ? 'I' : ' ',
+ (ei->access & SNDRV_CTL_ELEM_ACCESS_LOCK) ? 'L' : ' ',
+ elem_type_name(ei->type),
+ ei->id.name);
+ switch (ei->type) {
+ case SNDRV_CTL_ELEM_TYPE_INTEGER:
+ printf(ei->value.integer.step ?
+ " { %ld-%ld, %ld }\n" : " { %ld-%ld }",
+ ei->value.integer.min,
+ ei->value.integer.max,
+ ei->value.integer.step);
+ break;
+ case SNDRV_CTL_ELEM_TYPE_INTEGER64:
+ printf(ei->value.integer64.step ?
+ " { %lld-%lld, %lld }\n" : " { %lld-%lld }",
+ ei->value.integer64.min,
+ ei->value.integer64.max,
+ ei->value.integer64.step);
+ break;
+ case SNDRV_CTL_ELEM_TYPE_ENUMERATED: {
+ unsigned m;
+ printf(" { %s=0", mixer->ctl[n].ename[0]);
+ for (m = 1; m < ei->value.enumerated.items; m++)
+ printf(", %s=%d", mixer->ctl[n].ename[m],m);
+ printf(" }");
+ break;
+ }
+ }
+ printf("\n");
+ }
+}
+
+struct mixer_ctl *mixer_get_control(struct mixer *mixer,
+ const char *name, unsigned index)
+{
+ unsigned n;
+ for (n = 0; n < mixer->count; n++) {
+ if (mixer->info[n].id.index == index) {
+ if (!strcmp(name, (char*) mixer->info[n].id.name)) {
+ return mixer->ctl + n;
+ }
+ }
+ }
+ return 0;
+}
+
+struct mixer_ctl *mixer_get_nth_control(struct mixer *mixer, unsigned n)
+{
+ if (n < mixer->count)
+ return mixer->ctl + n;
+ return 0;
+}
+
+void mixer_ctl_print(struct mixer_ctl *ctl)
+{
+ struct snd_ctl_elem_value ev;
+ unsigned n;
+
+ memset(&ev, 0, sizeof(ev));
+ ev.id.numid = ctl->info->id.numid;
+ if (ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev))
+ return;
+ printf("%s:", ctl->info->id.name);
+
+ switch (ctl->info->type) {
+ case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
+ for (n = 0; n < ctl->info->count; n++)
+ printf(" %s", ev.value.integer.value[n] ? "ON" : "OFF");
+ break;
+ case SNDRV_CTL_ELEM_TYPE_INTEGER: {
+ for (n = 0; n < ctl->info->count; n++)
+ printf(" %ld", ev.value.integer.value[n]);
+ break;
+ }
+ case SNDRV_CTL_ELEM_TYPE_INTEGER64:
+ for (n = 0; n < ctl->info->count; n++)
+ printf(" %lld", ev.value.integer64.value[n]);
+ break;
+ case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
+ for (n = 0; n < ctl->info->count; n++) {
+ unsigned v = ev.value.enumerated.item[n];
+ printf(" %d (%s)", v,
+ (v < ctl->info->value.enumerated.items) ? ctl->ename[v] : "???");
+ }
+ break;
+ default:
+ printf(" ???");
+ }
+ printf("\n");
+}
+
+static long scale_int(struct snd_ctl_elem_info *ei, unsigned _percent)
+{
+ long percent;
+ long range;
+
+ if (_percent > 100)
+ percent = 100;
+ else
+ percent = (long) _percent;
+
+ range = (ei->value.integer.max - ei->value.integer.min);
+
+ return ei->value.integer.min + (range * percent) / 100LL;
+}
+
+static long long scale_int64(struct snd_ctl_elem_info *ei, unsigned _percent)
+{
+ long long percent;
+ long long range;
+
+ if (_percent > 100)
+ percent = 100;
+ else
+ percent = (long) _percent;
+
+ range = (ei->value.integer.max - ei->value.integer.min) * 100LL;
+
+ return ei->value.integer.min + (range / percent);
+}
+
+int mixer_ctl_set(struct mixer_ctl *ctl, unsigned percent)
+{
+ struct snd_ctl_elem_value ev;
+ unsigned n;
+
+ memset(&ev, 0, sizeof(ev));
+ ev.id.numid = ctl->info->id.numid;
+ switch (ctl->info->type) {
+ case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
+ for (n = 0; n < ctl->info->count; n++)
+ ev.value.integer.value[n] = !!percent;
+ break;
+ case SNDRV_CTL_ELEM_TYPE_INTEGER: {
+ long value = scale_int(ctl->info, percent);
+ for (n = 0; n < ctl->info->count; n++)
+ ev.value.integer.value[n] = value;
+ break;
+ }
+ case SNDRV_CTL_ELEM_TYPE_INTEGER64: {
+ long long value = scale_int64(ctl->info, percent);
+ for (n = 0; n < ctl->info->count; n++)
+ ev.value.integer64.value[n] = value;
+ break;
+ }
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ return ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev);
+}
+
+int mixer_ctl_select(struct mixer_ctl *ctl, const char *value)
+{
+ unsigned n, max;
+ struct snd_ctl_elem_value ev;
+
+ if (ctl->info->type != SNDRV_CTL_ELEM_TYPE_ENUMERATED) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ max = ctl->info->value.enumerated.items;
+ for (n = 0; n < max; n++) {
+ if (!strcmp(value, ctl->ename[n])) {
+ memset(&ev, 0, sizeof(ev));
+ ev.value.enumerated.item[0] = n;
+ ev.id.numid = ctl->info->id.numid;
+ if (ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev) < 0)
+ return -1;
+ return 0;
+ }
+ }
+
+ errno = EINVAL;
+ return -1;
+}
diff --git a/libaudio/alsa_pcm.c b/libaudio/alsa_pcm.c
new file mode 100644
index 0000000..5673391
--- /dev/null
+++ b/libaudio/alsa_pcm.c
@@ -0,0 +1,405 @@
+/*
+** 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_TAG "alsa_pcm"
+//#define LOG_NDEBUG 0
+#include <cutils/log.h>
+#include <cutils/config_utils.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+
+#include <linux/ioctl.h>
+
+#include "alsa_audio.h"
+
+#define __force
+#define __bitwise
+#define __user
+#include "asound.h"
+
+#define DEBUG 0
+
+/* alsa parameter manipulation cruft */
+
+#define PARAM_MAX SNDRV_PCM_HW_PARAM_LAST_INTERVAL
+
+static inline int param_is_mask(int p)
+{
+ return (p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) &&
+ (p <= SNDRV_PCM_HW_PARAM_LAST_MASK);
+}
+
+static inline int param_is_interval(int p)
+{
+ return (p >= SNDRV_PCM_HW_PARAM_FIRST_INTERVAL) &&
+ (p <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL);
+}
+
+static inline struct snd_interval *param_to_interval(struct snd_pcm_hw_params *p, int n)
+{
+ return &(p->intervals[n - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL]);
+}
+
+static inline struct snd_mask *param_to_mask(struct snd_pcm_hw_params *p, int n)
+{
+ return &(p->masks[n - SNDRV_PCM_HW_PARAM_FIRST_MASK]);
+}
+
+static void param_set_mask(struct snd_pcm_hw_params *p, int n, unsigned bit)
+{
+ if (bit >= SNDRV_MASK_MAX)
+ return;
+ if (param_is_mask(n)) {
+ struct snd_mask *m = param_to_mask(p, n);
+ m->bits[0] = 0;
+ m->bits[1] = 0;
+ m->bits[bit >> 5] |= (1 << (bit & 31));
+ }
+}
+
+static void param_set_min(struct snd_pcm_hw_params *p, int n, unsigned val)
+{
+ if (param_is_interval(n)) {
+ struct snd_interval *i = param_to_interval(p, n);
+ i->min = val;
+ }
+}
+
+static void param_set_max(struct snd_pcm_hw_params *p, int n, unsigned val)
+{
+ if (param_is_interval(n)) {
+ struct snd_interval *i = param_to_interval(p, n);
+ i->max = val;
+ }
+}
+
+static void param_set_int(struct snd_pcm_hw_params *p, int n, unsigned val)
+{
+ if (param_is_interval(n)) {
+ struct snd_interval *i = param_to_interval(p, n);
+ i->min = val;
+ i->max = val;
+ i->integer = 1;
+ }
+}
+
+static void param_init(struct snd_pcm_hw_params *p)
+{
+ int n;
+ memset(p, 0, sizeof(*p));
+ for (n = SNDRV_PCM_HW_PARAM_FIRST_MASK;
+ n <= SNDRV_PCM_HW_PARAM_LAST_MASK; n++) {
+ struct snd_mask *m = param_to_mask(p, n);
+ m->bits[0] = ~0;
+ m->bits[1] = ~0;
+ }
+ for (n = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL;
+ n <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; n++) {
+ struct snd_interval *i = param_to_interval(p, n);
+ i->min = 0;
+ i->max = ~0;
+ }
+}
+
+/* debugging gunk */
+
+#if DEBUG
+static const char *param_name[PARAM_MAX+1] = {
+ [SNDRV_PCM_HW_PARAM_ACCESS] = "access",
+ [SNDRV_PCM_HW_PARAM_FORMAT] = "format",
+ [SNDRV_PCM_HW_PARAM_SUBFORMAT] = "subformat",
+
+ [SNDRV_PCM_HW_PARAM_SAMPLE_BITS] = "sample_bits",
+ [SNDRV_PCM_HW_PARAM_FRAME_BITS] = "frame_bits",
+ [SNDRV_PCM_HW_PARAM_CHANNELS] = "channels",
+ [SNDRV_PCM_HW_PARAM_RATE] = "rate",
+ [SNDRV_PCM_HW_PARAM_PERIOD_TIME] = "period_time",
+ [SNDRV_PCM_HW_PARAM_PERIOD_SIZE] = "period_size",
+ [SNDRV_PCM_HW_PARAM_PERIOD_BYTES] = "period_bytes",
+ [SNDRV_PCM_HW_PARAM_PERIODS] = "periods",
+ [SNDRV_PCM_HW_PARAM_BUFFER_TIME] = "buffer_time",
+ [SNDRV_PCM_HW_PARAM_BUFFER_SIZE] = "buffer_size",
+ [SNDRV_PCM_HW_PARAM_BUFFER_BYTES] = "buffer_bytes",
+ [SNDRV_PCM_HW_PARAM_TICK_TIME] = "tick_time",
+};
+
+static void param_dump(struct snd_pcm_hw_params *p)
+{
+ int n;
+
+ for (n = SNDRV_PCM_HW_PARAM_FIRST_MASK;
+ n <= SNDRV_PCM_HW_PARAM_LAST_MASK; n++) {
+ struct snd_mask *m = param_to_mask(p, n);
+ LOGV("%s = %08x%08x\n", param_name[n],
+ m->bits[1], m->bits[0]);
+ }
+ for (n = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL;
+ n <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; n++) {
+ struct snd_interval *i = param_to_interval(p, n);
+ LOGV("%s = (%d,%d) omin=%d omax=%d int=%d empty=%d\n",
+ param_name[n], i->min, i->max, i->openmin,
+ i->openmax, i->integer, i->empty);
+ }
+ LOGV("info = %08x\n", p->info);
+ LOGV("msbits = %d\n", p->msbits);
+ LOGV("rate = %d/%d\n", p->rate_num, p->rate_den);
+ LOGV("fifo = %d\n", (int) p->fifo_size);
+}
+
+static void info_dump(struct snd_pcm_info *info)
+{
+ LOGV("device = %d\n", info->device);
+ LOGV("subdevice = %d\n", info->subdevice);
+ LOGV("stream = %d\n", info->stream);
+ LOGV("card = %d\n", info->card);
+ LOGV("id = '%s'\n", info->id);
+ LOGV("name = '%s'\n", info->name);
+ LOGV("subname = '%s'\n", info->subname);
+ LOGV("dev_class = %d\n", info->dev_class);
+ LOGV("dev_subclass = %d\n", info->dev_subclass);
+ LOGV("subdevices_count = %d\n", info->subdevices_count);
+ LOGV("subdevices_avail = %d\n", info->subdevices_avail);
+}
+#else
+static void param_dump(struct snd_pcm_hw_params *p) {}
+static void info_dump(struct snd_pcm_info *info) {}
+#endif
+
+#define PCM_ERROR_MAX 128
+
+struct pcm {
+ int fd;
+ unsigned flags;
+ int running:1;
+ int underruns;
+ unsigned buffer_size;
+ char error[PCM_ERROR_MAX];
+};
+
+unsigned pcm_buffer_size(struct pcm *pcm)
+{
+ return pcm->buffer_size;
+}
+
+const char* pcm_error(struct pcm *pcm)
+{
+ return pcm->error;
+}
+
+static int oops(struct pcm *pcm, int e, const char *fmt, ...)
+{
+ va_list ap;
+ int sz;
+
+ va_start(ap, fmt);
+ vsnprintf(pcm->error, PCM_ERROR_MAX, fmt, ap);
+ va_end(ap);
+ sz = strlen(pcm->error);
+
+ if (errno)
+ snprintf(pcm->error + sz, PCM_ERROR_MAX - sz,
+ ": %s", strerror(e));
+ return -1;
+}
+
+int pcm_write(struct pcm *pcm, void *data, unsigned count)
+{
+ struct snd_xferi x;
+
+ if (pcm->flags & PCM_IN)
+ return -EINVAL;
+
+ x.buf = data;
+ x.frames = (pcm->flags & PCM_MONO) ? (count / 2) : (count / 4);
+
+ for (;;) {
+ if (!pcm->running) {
+ if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE))
+ return oops(pcm, errno, "cannot prepare channel");
+ if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x))
+ return oops(pcm, errno, "cannot write initial data");
+ pcm->running = 1;
+ return 0;
+ }
+ if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x)) {
+ pcm->running = 0;
+ if (errno == EPIPE) {
+ /* we failed to make our window -- try to restart */
+ pcm->underruns++;
+ continue;
+ }
+ return oops(pcm, errno, "cannot write stream data");
+ }
+ return 0;
+ }
+}
+
+int pcm_read(struct pcm *pcm, void *data, unsigned count)
+{
+ struct snd_xferi x;
+
+ if (!(pcm->flags & PCM_IN))
+ return -EINVAL;
+
+ x.buf = data;
+ x.frames = (pcm->flags & PCM_MONO) ? (count / 2) : (count / 4);
+
+// LOGV("read() %d frames", x.frames);
+ for (;;) {
+ if (!pcm->running) {
+ if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE))
+ return oops(pcm, errno, "cannot prepare channel");
+ if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_START))
+ return oops(pcm, errno, "cannot start channel");
+ pcm->running = 1;
+ }
+ if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_READI_FRAMES, &x)) {
+ pcm->running = 0;
+ if (errno == EPIPE) {
+ /* we failed to make our window -- try to restart */
+ pcm->underruns++;
+ continue;
+ }
+ return oops(pcm, errno, "cannot read stream data");
+ }
+// LOGV("read() got %d frames", x.frames);
+ return 0;
+ }
+}
+
+static struct pcm bad_pcm = {
+ .fd = -1,
+};
+
+int pcm_close(struct pcm *pcm)
+{
+ if (pcm == &bad_pcm)
+ return 0;
+
+ if (pcm->fd >= 0)
+ close(pcm->fd);
+ pcm->running = 0;
+ pcm->buffer_size = 0;
+ pcm->fd = -1;
+ return 0;
+}
+
+struct pcm *pcm_open(unsigned flags)
+{
+ const char *dname;
+ struct pcm *pcm;
+ struct snd_pcm_info info;
+ struct snd_pcm_hw_params params;
+ struct snd_pcm_sw_params sparams;
+ unsigned period_sz;
+ unsigned period_cnt;
+
+ LOGV("pcm_open(0x%08x)",flags);
+
+ pcm = calloc(1, sizeof(struct pcm));
+ if (!pcm)
+ return &bad_pcm;
+
+ if (flags & PCM_IN) {
+ dname = "/dev/snd/pcmC0D0c";
+ } else {
+ dname = "/dev/snd/pcmC0D0p";
+ }
+
+ LOGV("pcm_open() period sz multiplier %d",
+ ((flags & PCM_PERIOD_SZ_MASK) >> PCM_PERIOD_SZ_SHIFT) + 1);
+ period_sz = 128 * (((flags & PCM_PERIOD_SZ_MASK) >> PCM_PERIOD_SZ_SHIFT) + 1);
+ LOGV("pcm_open() period cnt %d",
+ ((flags & PCM_PERIOD_CNT_MASK) >> PCM_PERIOD_CNT_SHIFT) + PCM_PERIOD_CNT_MIN);
+ period_cnt = ((flags & PCM_PERIOD_CNT_MASK) >> PCM_PERIOD_CNT_SHIFT) + PCM_PERIOD_CNT_MIN;
+
+ pcm->flags = flags;
+ pcm->fd = open(dname, O_RDWR);
+ if (pcm->fd < 0) {
+ oops(pcm, errno, "cannot open device '%s'");
+ return pcm;
+ }
+
+ if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_INFO, &info)) {
+ oops(pcm, errno, "cannot get info - %s");
+ goto fail;
+ }
+ info_dump(&info);
+
+ LOGV("pcm_open() period_cnt %d period_sz %d channels %d",
+ period_cnt, period_sz, (flags & PCM_MONO) ? 1 : 2);
+
+ param_init(&params);
+ param_set_mask(&params, SNDRV_PCM_HW_PARAM_ACCESS,
+ SNDRV_PCM_ACCESS_RW_INTERLEAVED);
+ param_set_mask(&params, SNDRV_PCM_HW_PARAM_FORMAT,
+ SNDRV_PCM_FORMAT_S16_LE);
+ param_set_mask(&params, SNDRV_PCM_HW_PARAM_SUBFORMAT,
+ SNDRV_PCM_SUBFORMAT_STD);
+ param_set_min(&params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, period_sz);
+ param_set_int(&params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, 16);
+ param_set_int(&params, SNDRV_PCM_HW_PARAM_FRAME_BITS,
+ (flags & PCM_MONO) ? 16 : 32);
+ param_set_int(&params, SNDRV_PCM_HW_PARAM_CHANNELS,
+ (flags & PCM_MONO) ? 1 : 2);
+ param_set_int(&params, SNDRV_PCM_HW_PARAM_PERIODS, period_cnt);
+ param_set_int(&params, SNDRV_PCM_HW_PARAM_RATE, 44100);
+
+ if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_HW_PARAMS, &params)) {
+ oops(pcm, errno, "cannot set hw params");
+ goto fail;
+ }
+ param_dump(&params);
+
+ memset(&sparams, 0, sizeof(sparams));
+ sparams.tstamp_mode = SNDRV_PCM_TSTAMP_NONE;
+ sparams.period_step = 1;
+ sparams.avail_min = 1;
+ sparams.start_threshold = period_cnt * period_sz;
+ sparams.stop_threshold = period_cnt * period_sz;
+ sparams.xfer_align = period_sz / 2; /* needed for old kernels */
+ sparams.silence_size = 0;
+ sparams.silence_threshold = 0;
+
+ if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_SW_PARAMS, &sparams)) {
+ oops(pcm, errno, "cannot set sw params");
+ goto fail;
+ }
+
+ pcm->buffer_size = period_cnt * period_sz;
+ pcm->underruns = 0;
+ return pcm;
+
+fail:
+ close(pcm->fd);
+ pcm->fd = -1;
+ return pcm;
+}
+
+int pcm_ready(struct pcm *pcm)
+{
+ return pcm->fd >= 0;
+}
diff --git a/libaudio/amix.c b/libaudio/amix.c
new file mode 100644
index 0000000..d978caa
--- /dev/null
+++ b/libaudio/amix.c
@@ -0,0 +1,78 @@
+/*
+** 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.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "alsa_audio.h"
+
+
+struct mixer_ctl *get_ctl(struct mixer *mixer, char *name)
+{
+ char *p;
+ unsigned idx = 0;
+
+ if (isdigit(name[0]))
+ return mixer_get_nth_control(mixer, atoi(name) - 1);
+
+ p = strrchr(name, '#');
+ if (p) {
+ *p++ = 0;
+ idx = atoi(p);
+ }
+
+ return mixer_get_control(mixer, name, idx);
+}
+
+int main(int argc, char **argv)
+{
+ struct mixer *mixer;
+ struct mixer_ctl *ctl;
+ int r;
+
+ mixer = mixer_open();
+ if (!mixer)
+ return -1;
+
+ if (argc == 1) {
+ mixer_dump(mixer);
+ return 0;
+ }
+
+ ctl = get_ctl(mixer, argv[1]);
+ argc -= 2;
+ argv += 2;
+
+ if (!ctl) {
+ fprintf(stderr,"can't find control\n");
+ return -1;
+ }
+
+ if (argc) {
+ if (isdigit(argv[0][0]))
+ r = mixer_ctl_set(ctl, atoi(argv[0]));
+ else
+ r = mixer_ctl_select(ctl, argv[0]);
+ if (r)
+ fprintf(stderr,"oops: %s\n", strerror(errno));
+ } else {
+ mixer_ctl_print(ctl);
+ }
+ return 0;
+}
diff --git a/libaudio/aplay.c b/libaudio/aplay.c
new file mode 100644
index 0000000..0ac0ac0
--- /dev/null
+++ b/libaudio/aplay.c
@@ -0,0 +1,140 @@
+/*
+** 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.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "alsa_audio.h"
+
+#define ID_RIFF 0x46464952
+#define ID_WAVE 0x45564157
+#define ID_FMT 0x20746d66
+#define ID_DATA 0x61746164
+
+#define FORMAT_PCM 1
+
+struct wav_header {
+ uint32_t riff_id;
+ uint32_t riff_sz;
+ uint32_t riff_fmt;
+ uint32_t fmt_id;
+ uint32_t fmt_sz;
+ uint16_t audio_format;
+ uint16_t num_channels;
+ uint32_t sample_rate;
+ uint32_t byte_rate; /* sample_rate * num_channels * bps / 8 */
+ uint16_t block_align; /* num_channels * bps / 8 */
+ uint16_t bits_per_sample;
+ uint32_t data_id;
+ uint32_t data_sz;
+};
+
+int play_file(unsigned rate, unsigned channels, int fd, unsigned count)
+{
+ struct pcm *pcm;
+ struct mixer *mixer;
+ struct pcm_ctl *ctl = NULL;
+ unsigned bufsize;
+ char *data;
+ unsigned flags = PCM_OUT;
+
+ if (channels == 1)
+ flags |= PCM_MONO;
+ else
+ flags |= PCM_STEREO;
+
+ pcm = pcm_open(flags);
+ if (!pcm_ready(pcm)) {
+ pcm_close(pcm);
+ return -1;
+ }
+
+ mixer = mixer_open();
+ if (mixer)
+ ctl = mixer_get_control(mixer,"Playback Path", 0);
+
+ bufsize = pcm_buffer_size(pcm);
+ data = malloc(bufsize);
+ if (!data) {
+ fprintf(stderr,"could not allocate %d bytes\n", count);
+ return -1;
+ }
+
+ while (read(fd, data, bufsize) == bufsize) {
+ if (pcm_write(pcm, data, bufsize))
+ break;
+
+ /* HACK: remove */
+ if (ctl) {
+ //mixer_ctl_select(ctl, "SPK");
+ ctl = 0;
+ }
+ }
+ pcm_close(pcm);
+ return 0;
+}
+
+int play_wav(const char *fn)
+{
+ struct wav_header hdr;
+ unsigned rate, channels;
+ int fd;
+ fd = open(fn, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "aplay: cannot open '%s'\n", fn);
+ return -1;
+ }
+ if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
+ fprintf(stderr, "aplay: cannot read header\n");
+ return -1;
+ }
+ fprintf(stderr,"aplay: %d ch, %d hz, %d bit, %s\n",
+ hdr.num_channels, hdr.sample_rate, hdr.bits_per_sample,
+ hdr.audio_format == FORMAT_PCM ? "PCM" : "unknown");
+
+ if ((hdr.riff_id != ID_RIFF) ||
+ (hdr.riff_fmt != ID_WAVE) ||
+ (hdr.fmt_id != ID_FMT)) {
+ fprintf(stderr, "aplay: '%s' is not a riff/wave file\n", fn);
+ return -1;
+ }
+ if ((hdr.audio_format != FORMAT_PCM) ||
+ (hdr.fmt_sz != 16)) {
+ fprintf(stderr, "aplay: '%s' is not pcm format\n", fn);
+ return -1;
+ }
+ if (hdr.bits_per_sample != 16) {
+ fprintf(stderr, "aplay: '%s' is not 16bit per sample\n", fn);
+ return -1;
+ }
+
+ return play_file(hdr.sample_rate, hdr.num_channels, fd, hdr.data_sz);
+}
+
+int main(int argc, char **argv)
+{
+ if (argc != 2) {
+ fprintf(stderr,"usage: aplay <file>\n");
+ return -1;
+ }
+
+ return play_wav(argv[1]);
+}
+
diff --git a/libaudio/arec.c b/libaudio/arec.c
new file mode 100644
index 0000000..b1e9eda
--- /dev/null
+++ b/libaudio/arec.c
@@ -0,0 +1,128 @@
+/*
+** 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.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "alsa_audio.h"
+
+#define ID_RIFF 0x46464952
+#define ID_WAVE 0x45564157
+#define ID_FMT 0x20746d66
+#define ID_DATA 0x61746164
+
+#define FORMAT_PCM 1
+
+struct wav_header {
+ uint32_t riff_id;
+ uint32_t riff_sz;
+ uint32_t riff_fmt;
+ uint32_t fmt_id;
+ uint32_t fmt_sz;
+ uint16_t audio_format;
+ uint16_t num_channels;
+ uint32_t sample_rate;
+ uint32_t byte_rate; /* sample_rate * num_channels * bps / 8 */
+ uint16_t block_align; /* num_channels * bps / 8 */
+ uint16_t bits_per_sample;
+ uint32_t data_id;
+ uint32_t data_sz;
+};
+
+int record_file(unsigned rate, unsigned channels, int fd, unsigned count)
+{
+ struct pcm *pcm;
+ unsigned avail, xfer, bufsize;
+ char *data, *next;
+ int r;
+
+ pcm = pcm_open(PCM_IN|PCM_MONO);
+ if (!pcm_ready(pcm)) {
+ pcm_close(pcm);
+ goto fail;
+ }
+
+ bufsize = pcm_buffer_size(pcm);
+
+ data = malloc(bufsize);
+ if (!data) {
+ fprintf(stderr,"could not allocate %d bytes\n", count);
+ return -1;
+ }
+
+ while (!pcm_read(pcm, data, bufsize)) {
+ if (write(fd, data, bufsize) != bufsize) {
+ fprintf(stderr,"could not write %d bytes\n", bufsize);
+ return -1;
+ }
+ }
+
+ close(fd);
+ pcm_close(pcm);
+ return 0;
+
+fail:
+ fprintf(stderr,"pcm error: %s\n", pcm_error(pcm));
+ return -1;
+}
+
+int rec_wav(const char *fn)
+{
+ struct wav_header hdr;
+ unsigned rate, channels;
+ int fd;
+ fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0664);
+ if (fd < 0) {
+ fprintf(stderr, "arec: cannot open '%s'\n", fn);
+ return -1;
+ }
+
+ hdr.riff_id = ID_RIFF;
+ hdr.riff_fmt = ID_WAVE;
+ hdr.fmt_id = ID_FMT;
+ hdr.audio_format = FORMAT_PCM;
+ hdr.fmt_sz = 16;
+ hdr.bits_per_sample = 16;
+ hdr.num_channels = 1;
+ hdr.data_sz = 0;
+ hdr.sample_rate = 44100;
+
+ if (write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
+ fprintf(stderr, "arec: cannot write header\n");
+ return -1;
+ }
+ fprintf(stderr,"arec: %d ch, %d hz, %d bit, %s\n",
+ hdr.num_channels, hdr.sample_rate, hdr.bits_per_sample,
+ hdr.audio_format == FORMAT_PCM ? "PCM" : "unknown");
+
+
+ return record_file(hdr.sample_rate, hdr.num_channels, fd, hdr.data_sz);
+}
+
+int main(int argc, char **argv)
+{
+ if (argc != 2) {
+ fprintf(stderr,"usage: arec <file>\n");
+ return -1;
+ }
+
+ return rec_wav(argv[1]);
+}
+
diff --git a/libaudio/asound.h b/libaudio/asound.h
new file mode 100644
index 0000000..6a17f29
--- /dev/null
+++ b/libaudio/asound.h
@@ -0,0 +1,814 @@
+/****************************************************************************
+ ****************************************************************************
+ ***
+ *** This header was automatically generated from a Linux kernel header
+ *** of the same name, to make information necessary for userspace to
+ *** call into the kernel available to libc. It contains only constants,
+ *** structures, and macros generated from the original header, and thus,
+ *** contains no copyrightable information.
+ ***
+ ****************************************************************************
+ ****************************************************************************/
+#ifndef __SOUND_ASOUND_H
+#define __SOUND_ASOUND_H
+
+#include <linux/types.h>
+
+#define SNDRV_PROTOCOL_VERSION(major, minor, subminor) (((major)<<16)|((minor)<<8)|(subminor))
+#define SNDRV_PROTOCOL_MAJOR(version) (((version)>>16)&0xffff)
+#define SNDRV_PROTOCOL_MINOR(version) (((version)>>8)&0xff)
+#define SNDRV_PROTOCOL_MICRO(version) ((version)&0xff)
+#define SNDRV_PROTOCOL_INCOMPATIBLE(kversion, uversion) (SNDRV_PROTOCOL_MAJOR(kversion) != SNDRV_PROTOCOL_MAJOR(uversion) || (SNDRV_PROTOCOL_MAJOR(kversion) == SNDRV_PROTOCOL_MAJOR(uversion) && SNDRV_PROTOCOL_MINOR(kversion) != SNDRV_PROTOCOL_MINOR(uversion)))
+
+struct snd_aes_iec958 {
+ unsigned char status[24];
+ unsigned char subcode[147];
+ unsigned char pad;
+ unsigned char dig_subframe[4];
+};
+
+#define SNDRV_HWDEP_VERSION SNDRV_PROTOCOL_VERSION(1, 0, 1)
+
+enum {
+ SNDRV_HWDEP_IFACE_OPL2 = 0,
+ SNDRV_HWDEP_IFACE_OPL3,
+ SNDRV_HWDEP_IFACE_OPL4,
+ SNDRV_HWDEP_IFACE_SB16CSP,
+ SNDRV_HWDEP_IFACE_EMU10K1,
+ SNDRV_HWDEP_IFACE_YSS225,
+ SNDRV_HWDEP_IFACE_ICS2115,
+ SNDRV_HWDEP_IFACE_SSCAPE,
+ SNDRV_HWDEP_IFACE_VX,
+ SNDRV_HWDEP_IFACE_MIXART,
+ SNDRV_HWDEP_IFACE_USX2Y,
+ SNDRV_HWDEP_IFACE_EMUX_WAVETABLE,
+ SNDRV_HWDEP_IFACE_BLUETOOTH,
+ SNDRV_HWDEP_IFACE_USX2Y_PCM,
+ SNDRV_HWDEP_IFACE_PCXHR,
+ SNDRV_HWDEP_IFACE_SB_RC,
+ SNDRV_HWDEP_IFACE_HDA,
+ SNDRV_HWDEP_IFACE_USB_STREAM,
+
+ SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_USB_STREAM
+};
+
+struct snd_hwdep_info {
+ unsigned int device;
+ int card;
+ unsigned char id[64];
+ unsigned char name[80];
+ int iface;
+ unsigned char reserved[64];
+};
+
+struct snd_hwdep_dsp_status {
+ unsigned int version;
+ unsigned char id[32];
+ unsigned int num_dsps;
+ unsigned int dsp_loaded;
+ unsigned int chip_ready;
+ unsigned char reserved[16];
+};
+
+struct snd_hwdep_dsp_image {
+ unsigned int index;
+ unsigned char name[64];
+ unsigned char __user *image;
+ size_t length;
+ unsigned long driver_data;
+};
+
+#define SNDRV_HWDEP_IOCTL_PVERSION _IOR ('H', 0x00, int)
+#define SNDRV_HWDEP_IOCTL_INFO _IOR ('H', 0x01, struct snd_hwdep_info)
+#define SNDRV_HWDEP_IOCTL_DSP_STATUS _IOR('H', 0x02, struct snd_hwdep_dsp_status)
+#define SNDRV_HWDEP_IOCTL_DSP_LOAD _IOW('H', 0x03, struct snd_hwdep_dsp_image)
+
+#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 10)
+
+typedef unsigned long snd_pcm_uframes_t;
+typedef signed long snd_pcm_sframes_t;
+
+enum {
+ SNDRV_PCM_CLASS_GENERIC = 0,
+ SNDRV_PCM_CLASS_MULTI,
+ SNDRV_PCM_CLASS_MODEM,
+ SNDRV_PCM_CLASS_DIGITIZER,
+
+ SNDRV_PCM_CLASS_LAST = SNDRV_PCM_CLASS_DIGITIZER,
+};
+
+enum {
+ SNDRV_PCM_SUBCLASS_GENERIC_MIX = 0,
+ SNDRV_PCM_SUBCLASS_MULTI_MIX,
+
+ SNDRV_PCM_SUBCLASS_LAST = SNDRV_PCM_SUBCLASS_MULTI_MIX,
+};
+
+enum {
+ SNDRV_PCM_STREAM_PLAYBACK = 0,
+ SNDRV_PCM_STREAM_CAPTURE,
+ SNDRV_PCM_STREAM_LAST = SNDRV_PCM_STREAM_CAPTURE,
+};
+
+typedef int __bitwise snd_pcm_access_t;
+#define SNDRV_PCM_ACCESS_MMAP_INTERLEAVED ((__force snd_pcm_access_t) 0)
+#define SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED ((__force snd_pcm_access_t) 1)
+#define SNDRV_PCM_ACCESS_MMAP_COMPLEX ((__force snd_pcm_access_t) 2)
+#define SNDRV_PCM_ACCESS_RW_INTERLEAVED ((__force snd_pcm_access_t) 3)
+#define SNDRV_PCM_ACCESS_RW_NONINTERLEAVED ((__force snd_pcm_access_t) 4)
+#define SNDRV_PCM_ACCESS_LAST SNDRV_PCM_ACCESS_RW_NONINTERLEAVED
+
+typedef int __bitwise snd_pcm_format_t;
+#define SNDRV_PCM_FORMAT_S8 ((__force snd_pcm_format_t) 0)
+#define SNDRV_PCM_FORMAT_U8 ((__force snd_pcm_format_t) 1)
+#define SNDRV_PCM_FORMAT_S16_LE ((__force snd_pcm_format_t) 2)
+#define SNDRV_PCM_FORMAT_S16_BE ((__force snd_pcm_format_t) 3)
+#define SNDRV_PCM_FORMAT_U16_LE ((__force snd_pcm_format_t) 4)
+#define SNDRV_PCM_FORMAT_U16_BE ((__force snd_pcm_format_t) 5)
+#define SNDRV_PCM_FORMAT_S24_LE ((__force snd_pcm_format_t) 6)
+#define SNDRV_PCM_FORMAT_S24_BE ((__force snd_pcm_format_t) 7)
+#define SNDRV_PCM_FORMAT_U24_LE ((__force snd_pcm_format_t) 8)
+#define SNDRV_PCM_FORMAT_U24_BE ((__force snd_pcm_format_t) 9)
+#define SNDRV_PCM_FORMAT_S32_LE ((__force snd_pcm_format_t) 10)
+#define SNDRV_PCM_FORMAT_S32_BE ((__force snd_pcm_format_t) 11)
+#define SNDRV_PCM_FORMAT_U32_LE ((__force snd_pcm_format_t) 12)
+#define SNDRV_PCM_FORMAT_U32_BE ((__force snd_pcm_format_t) 13)
+#define SNDRV_PCM_FORMAT_FLOAT_LE ((__force snd_pcm_format_t) 14)
+#define SNDRV_PCM_FORMAT_FLOAT_BE ((__force snd_pcm_format_t) 15)
+#define SNDRV_PCM_FORMAT_FLOAT64_LE ((__force snd_pcm_format_t) 16)
+#define SNDRV_PCM_FORMAT_FLOAT64_BE ((__force snd_pcm_format_t) 17)
+#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE ((__force snd_pcm_format_t) 18)
+#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE ((__force snd_pcm_format_t) 19)
+#define SNDRV_PCM_FORMAT_MU_LAW ((__force snd_pcm_format_t) 20)
+#define SNDRV_PCM_FORMAT_A_LAW ((__force snd_pcm_format_t) 21)
+#define SNDRV_PCM_FORMAT_IMA_ADPCM ((__force snd_pcm_format_t) 22)
+#define SNDRV_PCM_FORMAT_MPEG ((__force snd_pcm_format_t) 23)
+#define SNDRV_PCM_FORMAT_GSM ((__force snd_pcm_format_t) 24)
+#define SNDRV_PCM_FORMAT_SPECIAL ((__force snd_pcm_format_t) 31)
+#define SNDRV_PCM_FORMAT_S24_3LE ((__force snd_pcm_format_t) 32)
+#define SNDRV_PCM_FORMAT_S24_3BE ((__force snd_pcm_format_t) 33)
+#define SNDRV_PCM_FORMAT_U24_3LE ((__force snd_pcm_format_t) 34)
+#define SNDRV_PCM_FORMAT_U24_3BE ((__force snd_pcm_format_t) 35)
+#define SNDRV_PCM_FORMAT_S20_3LE ((__force snd_pcm_format_t) 36)
+#define SNDRV_PCM_FORMAT_S20_3BE ((__force snd_pcm_format_t) 37)
+#define SNDRV_PCM_FORMAT_U20_3LE ((__force snd_pcm_format_t) 38)
+#define SNDRV_PCM_FORMAT_U20_3BE ((__force snd_pcm_format_t) 39)
+#define SNDRV_PCM_FORMAT_S18_3LE ((__force snd_pcm_format_t) 40)
+#define SNDRV_PCM_FORMAT_S18_3BE ((__force snd_pcm_format_t) 41)
+#define SNDRV_PCM_FORMAT_U18_3LE ((__force snd_pcm_format_t) 42)
+#define SNDRV_PCM_FORMAT_U18_3BE ((__force snd_pcm_format_t) 43)
+#define SNDRV_PCM_FORMAT_LAST SNDRV_PCM_FORMAT_U18_3BE
+
+#ifdef SNDRV_LITTLE_ENDIAN
+#define SNDRV_PCM_FORMAT_S16 SNDRV_PCM_FORMAT_S16_LE
+#define SNDRV_PCM_FORMAT_U16 SNDRV_PCM_FORMAT_U16_LE
+#define SNDRV_PCM_FORMAT_S24 SNDRV_PCM_FORMAT_S24_LE
+#define SNDRV_PCM_FORMAT_U24 SNDRV_PCM_FORMAT_U24_LE
+#define SNDRV_PCM_FORMAT_S32 SNDRV_PCM_FORMAT_S32_LE
+#define SNDRV_PCM_FORMAT_U32 SNDRV_PCM_FORMAT_U32_LE
+#define SNDRV_PCM_FORMAT_FLOAT SNDRV_PCM_FORMAT_FLOAT_LE
+#define SNDRV_PCM_FORMAT_FLOAT64 SNDRV_PCM_FORMAT_FLOAT64_LE
+#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE
+#endif
+#ifdef SNDRV_BIG_ENDIAN
+#define SNDRV_PCM_FORMAT_S16 SNDRV_PCM_FORMAT_S16_BE
+#define SNDRV_PCM_FORMAT_U16 SNDRV_PCM_FORMAT_U16_BE
+#define SNDRV_PCM_FORMAT_S24 SNDRV_PCM_FORMAT_S24_BE
+#define SNDRV_PCM_FORMAT_U24 SNDRV_PCM_FORMAT_U24_BE
+#define SNDRV_PCM_FORMAT_S32 SNDRV_PCM_FORMAT_S32_BE
+#define SNDRV_PCM_FORMAT_U32 SNDRV_PCM_FORMAT_U32_BE
+#define SNDRV_PCM_FORMAT_FLOAT SNDRV_PCM_FORMAT_FLOAT_BE
+#define SNDRV_PCM_FORMAT_FLOAT64 SNDRV_PCM_FORMAT_FLOAT64_BE
+#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE
+#endif
+
+typedef int __bitwise snd_pcm_subformat_t;
+#define SNDRV_PCM_SUBFORMAT_STD ((__force snd_pcm_subformat_t) 0)
+#define SNDRV_PCM_SUBFORMAT_LAST SNDRV_PCM_SUBFORMAT_STD
+
+#define SNDRV_PCM_INFO_MMAP 0x00000001
+#define SNDRV_PCM_INFO_MMAP_VALID 0x00000002
+#define SNDRV_PCM_INFO_DOUBLE 0x00000004
+#define SNDRV_PCM_INFO_BATCH 0x00000010
+#define SNDRV_PCM_INFO_INTERLEAVED 0x00000100
+#define SNDRV_PCM_INFO_NONINTERLEAVED 0x00000200
+#define SNDRV_PCM_INFO_COMPLEX 0x00000400
+#define SNDRV_PCM_INFO_BLOCK_TRANSFER 0x00010000
+#define SNDRV_PCM_INFO_OVERRANGE 0x00020000
+#define SNDRV_PCM_INFO_RESUME 0x00040000
+#define SNDRV_PCM_INFO_PAUSE 0x00080000
+#define SNDRV_PCM_INFO_HALF_DUPLEX 0x00100000
+#define SNDRV_PCM_INFO_JOINT_DUPLEX 0x00200000
+#define SNDRV_PCM_INFO_SYNC_START 0x00400000
+#define SNDRV_PCM_INFO_FIFO_IN_FRAMES 0x80000000
+
+typedef int __bitwise snd_pcm_state_t;
+#define SNDRV_PCM_STATE_OPEN ((__force snd_pcm_state_t) 0)
+#define SNDRV_PCM_STATE_SETUP ((__force snd_pcm_state_t) 1)
+#define SNDRV_PCM_STATE_PREPARED ((__force snd_pcm_state_t) 2)
+#define SNDRV_PCM_STATE_RUNNING ((__force snd_pcm_state_t) 3)
+#define SNDRV_PCM_STATE_XRUN ((__force snd_pcm_state_t) 4)
+#define SNDRV_PCM_STATE_DRAINING ((__force snd_pcm_state_t) 5)
+#define SNDRV_PCM_STATE_PAUSED ((__force snd_pcm_state_t) 6)
+#define SNDRV_PCM_STATE_SUSPENDED ((__force snd_pcm_state_t) 7)
+#define SNDRV_PCM_STATE_DISCONNECTED ((__force snd_pcm_state_t) 8)
+#define SNDRV_PCM_STATE_LAST SNDRV_PCM_STATE_DISCONNECTED
+
+enum {
+ SNDRV_PCM_MMAP_OFFSET_DATA = 0x00000000,
+ SNDRV_PCM_MMAP_OFFSET_STATUS = 0x80000000,
+ SNDRV_PCM_MMAP_OFFSET_CONTROL = 0x81000000,
+};
+
+union snd_pcm_sync_id {
+ unsigned char id[16];
+ unsigned short id16[8];
+ unsigned int id32[4];
+};
+
+struct snd_pcm_info {
+ unsigned int device;
+ unsigned int subdevice;
+ int stream;
+ int card;
+ unsigned char id[64];
+ unsigned char name[80];
+ unsigned char subname[32];
+ int dev_class;
+ int dev_subclass;
+ unsigned int subdevices_count;
+ unsigned int subdevices_avail;
+ union snd_pcm_sync_id sync;
+ unsigned char reserved[64];
+};
+
+typedef int snd_pcm_hw_param_t;
+#define SNDRV_PCM_HW_PARAM_ACCESS 0
+#define SNDRV_PCM_HW_PARAM_FORMAT 1
+#define SNDRV_PCM_HW_PARAM_SUBFORMAT 2
+#define SNDRV_PCM_HW_PARAM_FIRST_MASK SNDRV_PCM_HW_PARAM_ACCESS
+#define SNDRV_PCM_HW_PARAM_LAST_MASK SNDRV_PCM_HW_PARAM_SUBFORMAT
+
+#define SNDRV_PCM_HW_PARAM_SAMPLE_BITS 8
+#define SNDRV_PCM_HW_PARAM_FRAME_BITS 9
+#define SNDRV_PCM_HW_PARAM_CHANNELS 10
+#define SNDRV_PCM_HW_PARAM_RATE 11
+#define SNDRV_PCM_HW_PARAM_PERIOD_TIME 12
+#define SNDRV_PCM_HW_PARAM_PERIOD_SIZE 13
+#define SNDRV_PCM_HW_PARAM_PERIOD_BYTES 14
+#define SNDRV_PCM_HW_PARAM_PERIODS 15
+#define SNDRV_PCM_HW_PARAM_BUFFER_TIME 16
+#define SNDRV_PCM_HW_PARAM_BUFFER_SIZE 17
+#define SNDRV_PCM_HW_PARAM_BUFFER_BYTES 18
+#define SNDRV_PCM_HW_PARAM_TICK_TIME 19
+#define SNDRV_PCM_HW_PARAM_FIRST_INTERVAL SNDRV_PCM_HW_PARAM_SAMPLE_BITS
+#define SNDRV_PCM_HW_PARAM_LAST_INTERVAL SNDRV_PCM_HW_PARAM_TICK_TIME
+
+#define SNDRV_PCM_HW_PARAMS_NORESAMPLE (1<<0)
+
+struct snd_interval {
+ unsigned int min, max;
+ unsigned int openmin:1,
+ openmax:1,
+ integer:1,
+ empty:1;
+};
+
+#define SNDRV_MASK_MAX 256
+
+struct snd_mask {
+ __u32 bits[(SNDRV_MASK_MAX+31)/32];
+};
+
+struct snd_pcm_hw_params {
+ unsigned int flags;
+ struct snd_mask masks[SNDRV_PCM_HW_PARAM_LAST_MASK -
+ SNDRV_PCM_HW_PARAM_FIRST_MASK + 1];
+ struct snd_mask mres[5];
+ struct snd_interval intervals[SNDRV_PCM_HW_PARAM_LAST_INTERVAL -
+ SNDRV_PCM_HW_PARAM_FIRST_INTERVAL + 1];
+ struct snd_interval ires[9];
+ unsigned int rmask;
+ unsigned int cmask;
+ unsigned int info;
+ unsigned int msbits;
+ unsigned int rate_num;
+ unsigned int rate_den;
+ snd_pcm_uframes_t fifo_size;
+ unsigned char reserved[64];
+};
+
+enum {
+ SNDRV_PCM_TSTAMP_NONE = 0,
+ SNDRV_PCM_TSTAMP_ENABLE,
+ SNDRV_PCM_TSTAMP_LAST = SNDRV_PCM_TSTAMP_ENABLE,
+};
+
+struct snd_pcm_sw_params {
+ int tstamp_mode;
+ unsigned int period_step;
+ unsigned int sleep_min;
+ snd_pcm_uframes_t avail_min;
+ snd_pcm_uframes_t xfer_align;
+ snd_pcm_uframes_t start_threshold;
+ snd_pcm_uframes_t stop_threshold;
+ snd_pcm_uframes_t silence_threshold;
+ snd_pcm_uframes_t silence_size;
+ snd_pcm_uframes_t boundary;
+ unsigned char reserved[64];
+};
+
+struct snd_pcm_channel_info {
+ unsigned int channel;
+ __kernel_off_t offset;
+ unsigned int first;
+ unsigned int step;
+};
+
+struct snd_pcm_status {
+ snd_pcm_state_t state;
+ struct timespec trigger_tstamp;
+ struct timespec tstamp;
+ snd_pcm_uframes_t appl_ptr;
+ snd_pcm_uframes_t hw_ptr;
+ snd_pcm_sframes_t delay;
+ snd_pcm_uframes_t avail;
+ snd_pcm_uframes_t avail_max;
+ snd_pcm_uframes_t overrange;
+ snd_pcm_state_t suspended_state;
+ unsigned char reserved[60];
+};
+
+struct snd_pcm_mmap_status {
+ snd_pcm_state_t state;
+ int pad1;
+ snd_pcm_uframes_t hw_ptr;
+ struct timespec tstamp;
+ snd_pcm_state_t suspended_state;
+};
+
+struct snd_pcm_mmap_control {
+ snd_pcm_uframes_t appl_ptr;
+ snd_pcm_uframes_t avail_min;
+};
+
+#define SNDRV_PCM_SYNC_PTR_HWSYNC (1<<0)
+#define SNDRV_PCM_SYNC_PTR_APPL (1<<1)
+#define SNDRV_PCM_SYNC_PTR_AVAIL_MIN (1<<2)
+
+struct snd_pcm_sync_ptr {
+ unsigned int flags;
+ union {
+ struct snd_pcm_mmap_status status;
+ unsigned char reserved[64];
+ } s;
+ union {
+ struct snd_pcm_mmap_control control;
+ unsigned char reserved[64];
+ } c;
+};
+
+struct snd_xferi {
+ snd_pcm_sframes_t result;
+ void __user *buf;
+ snd_pcm_uframes_t frames;
+};
+
+struct snd_xfern {
+ snd_pcm_sframes_t result;
+ void __user * __user *bufs;
+ snd_pcm_uframes_t frames;
+};
+
+enum {
+ SNDRV_PCM_TSTAMP_TYPE_GETTIMEOFDAY = 0,
+ SNDRV_PCM_TSTAMP_TYPE_MONOTONIC,
+ SNDRV_PCM_TSTAMP_TYPE_LAST = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC,
+};
+
+#define SNDRV_PCM_IOCTL_PVERSION _IOR('A', 0x00, int)
+#define SNDRV_PCM_IOCTL_INFO _IOR('A', 0x01, struct snd_pcm_info)
+#define SNDRV_PCM_IOCTL_TSTAMP _IOW('A', 0x02, int)
+#define SNDRV_PCM_IOCTL_TTSTAMP _IOW('A', 0x03, int)
+#define SNDRV_PCM_IOCTL_HW_REFINE _IOWR('A', 0x10, struct snd_pcm_hw_params)
+#define SNDRV_PCM_IOCTL_HW_PARAMS _IOWR('A', 0x11, struct snd_pcm_hw_params)
+#define SNDRV_PCM_IOCTL_HW_FREE _IO('A', 0x12)
+#define SNDRV_PCM_IOCTL_SW_PARAMS _IOWR('A', 0x13, struct snd_pcm_sw_params)
+#define SNDRV_PCM_IOCTL_STATUS _IOR('A', 0x20, struct snd_pcm_status)
+#define SNDRV_PCM_IOCTL_DELAY _IOR('A', 0x21, snd_pcm_sframes_t)
+#define SNDRV_PCM_IOCTL_HWSYNC _IO('A', 0x22)
+#define SNDRV_PCM_IOCTL_SYNC_PTR _IOWR('A', 0x23, struct snd_pcm_sync_ptr)
+#define SNDRV_PCM_IOCTL_CHANNEL_INFO _IOR('A', 0x32, struct snd_pcm_channel_info)
+#define SNDRV_PCM_IOCTL_PREPARE _IO('A', 0x40)
+#define SNDRV_PCM_IOCTL_RESET _IO('A', 0x41)
+#define SNDRV_PCM_IOCTL_START _IO('A', 0x42)
+#define SNDRV_PCM_IOCTL_DROP _IO('A', 0x43)
+#define SNDRV_PCM_IOCTL_DRAIN _IO('A', 0x44)
+#define SNDRV_PCM_IOCTL_PAUSE _IOW('A', 0x45, int)
+#define SNDRV_PCM_IOCTL_REWIND _IOW('A', 0x46, snd_pcm_uframes_t)
+#define SNDRV_PCM_IOCTL_RESUME _IO('A', 0x47)
+#define SNDRV_PCM_IOCTL_XRUN _IO('A', 0x48)
+#define SNDRV_PCM_IOCTL_FORWARD _IOW('A', 0x49, snd_pcm_uframes_t)
+#define SNDRV_PCM_IOCTL_WRITEI_FRAMES _IOW('A', 0x50, struct snd_xferi)
+#define SNDRV_PCM_IOCTL_READI_FRAMES _IOR('A', 0x51, struct snd_xferi)
+#define SNDRV_PCM_IOCTL_WRITEN_FRAMES _IOW('A', 0x52, struct snd_xfern)
+#define SNDRV_PCM_IOCTL_READN_FRAMES _IOR('A', 0x53, struct snd_xfern)
+#define SNDRV_PCM_IOCTL_LINK _IOW('A', 0x60, int)
+#define SNDRV_PCM_IOCTL_UNLINK _IO('A', 0x61)
+
+#define SNDRV_RAWMIDI_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 0)
+
+enum {
+ SNDRV_RAWMIDI_STREAM_OUTPUT = 0,
+ SNDRV_RAWMIDI_STREAM_INPUT,
+ SNDRV_RAWMIDI_STREAM_LAST = SNDRV_RAWMIDI_STREAM_INPUT,
+};
+
+#define SNDRV_RAWMIDI_INFO_OUTPUT 0x00000001
+#define SNDRV_RAWMIDI_INFO_INPUT 0x00000002
+#define SNDRV_RAWMIDI_INFO_DUPLEX 0x00000004
+
+struct snd_rawmidi_info {
+ unsigned int device;
+ unsigned int subdevice;
+ int stream;
+ int card;
+ unsigned int flags;
+ unsigned char id[64];
+ unsigned char name[80];
+ unsigned char subname[32];
+ unsigned int subdevices_count;
+ unsigned int subdevices_avail;
+ unsigned char reserved[64];
+};
+
+struct snd_rawmidi_params {
+ int stream;
+ size_t buffer_size;
+ size_t avail_min;
+ unsigned int no_active_sensing: 1;
+ unsigned char reserved[16];
+};
+
+struct snd_rawmidi_status {
+ int stream;
+ struct timespec tstamp;
+ size_t avail;
+ size_t xruns;
+ unsigned char reserved[16];
+};
+
+#define SNDRV_RAWMIDI_IOCTL_PVERSION _IOR('W', 0x00, int)
+#define SNDRV_RAWMIDI_IOCTL_INFO _IOR('W', 0x01, struct snd_rawmidi_info)
+#define SNDRV_RAWMIDI_IOCTL_PARAMS _IOWR('W', 0x10, struct snd_rawmidi_params)
+#define SNDRV_RAWMIDI_IOCTL_STATUS _IOWR('W', 0x20, struct snd_rawmidi_status)
+#define SNDRV_RAWMIDI_IOCTL_DROP _IOW('W', 0x30, int)
+#define SNDRV_RAWMIDI_IOCTL_DRAIN _IOW('W', 0x31, int)
+
+#define SNDRV_TIMER_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 6)
+
+enum {
+ SNDRV_TIMER_CLASS_NONE = -1,
+ SNDRV_TIMER_CLASS_SLAVE = 0,
+ SNDRV_TIMER_CLASS_GLOBAL,
+ SNDRV_TIMER_CLASS_CARD,
+ SNDRV_TIMER_CLASS_PCM,
+ SNDRV_TIMER_CLASS_LAST = SNDRV_TIMER_CLASS_PCM,
+};
+
+enum {
+ SNDRV_TIMER_SCLASS_NONE = 0,
+ SNDRV_TIMER_SCLASS_APPLICATION,
+ SNDRV_TIMER_SCLASS_SEQUENCER,
+ SNDRV_TIMER_SCLASS_OSS_SEQUENCER,
+ SNDRV_TIMER_SCLASS_LAST = SNDRV_TIMER_SCLASS_OSS_SEQUENCER,
+};
+
+#define SNDRV_TIMER_GLOBAL_SYSTEM 0
+#define SNDRV_TIMER_GLOBAL_RTC 1
+#define SNDRV_TIMER_GLOBAL_HPET 2
+#define SNDRV_TIMER_GLOBAL_HRTIMER 3
+
+#define SNDRV_TIMER_FLG_SLAVE (1<<0)
+
+struct snd_timer_id {
+ int dev_class;
+ int dev_sclass;
+ int card;
+ int device;
+ int subdevice;
+};
+
+struct snd_timer_ginfo {
+ struct snd_timer_id tid;
+ unsigned int flags;
+ int card;
+ unsigned char id[64];
+ unsigned char name[80];
+ unsigned long reserved0;
+ unsigned long resolution;
+ unsigned long resolution_min;
+ unsigned long resolution_max;
+ unsigned int clients;
+ unsigned char reserved[32];
+};
+
+struct snd_timer_gparams {
+ struct snd_timer_id tid;
+ unsigned long period_num;
+ unsigned long period_den;
+ unsigned char reserved[32];
+};
+
+struct snd_timer_gstatus {
+ struct snd_timer_id tid;
+ unsigned long resolution;
+ unsigned long resolution_num;
+ unsigned long resolution_den;
+ unsigned char reserved[32];
+};
+
+struct snd_timer_select {
+ struct snd_timer_id id;
+ unsigned char reserved[32];
+};
+
+struct snd_timer_info {
+ unsigned int flags;
+ int card;
+ unsigned char id[64];
+ unsigned char name[80];
+ unsigned long reserved0;
+ unsigned long resolution;
+ unsigned char reserved[64];
+};
+
+#define SNDRV_TIMER_PSFLG_AUTO (1<<0)
+#define SNDRV_TIMER_PSFLG_EXCLUSIVE (1<<1)
+#define SNDRV_TIMER_PSFLG_EARLY_EVENT (1<<2)
+
+struct snd_timer_params {
+ unsigned int flags;
+ unsigned int ticks;
+ unsigned int queue_size;
+ unsigned int reserved0;
+ unsigned int filter;
+ unsigned char reserved[60];
+};
+
+struct snd_timer_status {
+ struct timespec tstamp;
+ unsigned int resolution;
+ unsigned int lost;
+ unsigned int overrun;
+ unsigned int queue;
+ unsigned char reserved[64];
+};
+
+#define SNDRV_TIMER_IOCTL_PVERSION _IOR('T', 0x00, int)
+#define SNDRV_TIMER_IOCTL_NEXT_DEVICE _IOWR('T', 0x01, struct snd_timer_id)
+#define SNDRV_TIMER_IOCTL_TREAD _IOW('T', 0x02, int)
+#define SNDRV_TIMER_IOCTL_GINFO _IOWR('T', 0x03, struct snd_timer_ginfo)
+#define SNDRV_TIMER_IOCTL_GPARAMS _IOW('T', 0x04, struct snd_timer_gparams)
+#define SNDRV_TIMER_IOCTL_GSTATUS _IOWR('T', 0x05, struct snd_timer_gstatus)
+#define SNDRV_TIMER_IOCTL_SELECT _IOW('T', 0x10, struct snd_timer_select)
+#define SNDRV_TIMER_IOCTL_INFO _IOR('T', 0x11, struct snd_timer_info)
+#define SNDRV_TIMER_IOCTL_PARAMS _IOW('T', 0x12, struct snd_timer_params)
+#define SNDRV_TIMER_IOCTL_STATUS _IOR('T', 0x14, struct snd_timer_status)
+
+#define SNDRV_TIMER_IOCTL_START _IO('T', 0xa0)
+#define SNDRV_TIMER_IOCTL_STOP _IO('T', 0xa1)
+#define SNDRV_TIMER_IOCTL_CONTINUE _IO('T', 0xa2)
+#define SNDRV_TIMER_IOCTL_PAUSE _IO('T', 0xa3)
+
+struct snd_timer_read {
+ unsigned int resolution;
+ unsigned int ticks;
+};
+
+enum {
+ SNDRV_TIMER_EVENT_RESOLUTION = 0,
+ SNDRV_TIMER_EVENT_TICK,
+ SNDRV_TIMER_EVENT_START,
+ SNDRV_TIMER_EVENT_STOP,
+ SNDRV_TIMER_EVENT_CONTINUE,
+ SNDRV_TIMER_EVENT_PAUSE,
+ SNDRV_TIMER_EVENT_EARLY,
+ SNDRV_TIMER_EVENT_SUSPEND,
+ SNDRV_TIMER_EVENT_RESUME,
+
+ SNDRV_TIMER_EVENT_MSTART = SNDRV_TIMER_EVENT_START + 10,
+ SNDRV_TIMER_EVENT_MSTOP = SNDRV_TIMER_EVENT_STOP + 10,
+ SNDRV_TIMER_EVENT_MCONTINUE = SNDRV_TIMER_EVENT_CONTINUE + 10,
+ SNDRV_TIMER_EVENT_MPAUSE = SNDRV_TIMER_EVENT_PAUSE + 10,
+ SNDRV_TIMER_EVENT_MSUSPEND = SNDRV_TIMER_EVENT_SUSPEND + 10,
+ SNDRV_TIMER_EVENT_MRESUME = SNDRV_TIMER_EVENT_RESUME + 10,
+};
+
+struct snd_timer_tread {
+ int event;
+ struct timespec tstamp;
+ unsigned int val;
+};
+
+#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 6)
+
+struct snd_ctl_card_info {
+ int card;
+ int pad;
+ unsigned char id[16];
+ unsigned char driver[16];
+ unsigned char name[32];
+ unsigned char longname[80];
+ unsigned char reserved_[16];
+ unsigned char mixername[80];
+ unsigned char components[128];
+};
+
+typedef int __bitwise snd_ctl_elem_type_t;
+#define SNDRV_CTL_ELEM_TYPE_NONE ((__force snd_ctl_elem_type_t) 0)
+#define SNDRV_CTL_ELEM_TYPE_BOOLEAN ((__force snd_ctl_elem_type_t) 1)
+#define SNDRV_CTL_ELEM_TYPE_INTEGER ((__force snd_ctl_elem_type_t) 2)
+#define SNDRV_CTL_ELEM_TYPE_ENUMERATED ((__force snd_ctl_elem_type_t) 3)
+#define SNDRV_CTL_ELEM_TYPE_BYTES ((__force snd_ctl_elem_type_t) 4)
+#define SNDRV_CTL_ELEM_TYPE_IEC958 ((__force snd_ctl_elem_type_t) 5)
+#define SNDRV_CTL_ELEM_TYPE_INTEGER64 ((__force snd_ctl_elem_type_t) 6)
+#define SNDRV_CTL_ELEM_TYPE_LAST SNDRV_CTL_ELEM_TYPE_INTEGER64
+
+typedef int __bitwise snd_ctl_elem_iface_t;
+#define SNDRV_CTL_ELEM_IFACE_CARD ((__force snd_ctl_elem_iface_t) 0)
+#define SNDRV_CTL_ELEM_IFACE_HWDEP ((__force snd_ctl_elem_iface_t) 1)
+#define SNDRV_CTL_ELEM_IFACE_MIXER ((__force snd_ctl_elem_iface_t) 2)
+#define SNDRV_CTL_ELEM_IFACE_PCM ((__force snd_ctl_elem_iface_t) 3)
+#define SNDRV_CTL_ELEM_IFACE_RAWMIDI ((__force snd_ctl_elem_iface_t) 4)
+#define SNDRV_CTL_ELEM_IFACE_TIMER ((__force snd_ctl_elem_iface_t) 5)
+#define SNDRV_CTL_ELEM_IFACE_SEQUENCER ((__force snd_ctl_elem_iface_t) 6)
+#define SNDRV_CTL_ELEM_IFACE_LAST SNDRV_CTL_ELEM_IFACE_SEQUENCER
+
+#define SNDRV_CTL_ELEM_ACCESS_READ (1<<0)
+#define SNDRV_CTL_ELEM_ACCESS_WRITE (1<<1)
+#define SNDRV_CTL_ELEM_ACCESS_READWRITE (SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE)
+#define SNDRV_CTL_ELEM_ACCESS_VOLATILE (1<<2)
+#define SNDRV_CTL_ELEM_ACCESS_TIMESTAMP (1<<3)
+#define SNDRV_CTL_ELEM_ACCESS_TLV_READ (1<<4)
+#define SNDRV_CTL_ELEM_ACCESS_TLV_WRITE (1<<5)
+#define SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE (SNDRV_CTL_ELEM_ACCESS_TLV_READ|SNDRV_CTL_ELEM_ACCESS_TLV_WRITE)
+#define SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND (1<<6)
+#define SNDRV_CTL_ELEM_ACCESS_INACTIVE (1<<8)
+#define SNDRV_CTL_ELEM_ACCESS_LOCK (1<<9)
+#define SNDRV_CTL_ELEM_ACCESS_OWNER (1<<10)
+#define SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK (1<<28)
+#define SNDRV_CTL_ELEM_ACCESS_USER (1<<29)
+
+#define SNDRV_CTL_POWER_D0 0x0000
+#define SNDRV_CTL_POWER_D1 0x0100
+#define SNDRV_CTL_POWER_D2 0x0200
+#define SNDRV_CTL_POWER_D3 0x0300
+#define SNDRV_CTL_POWER_D3hot (SNDRV_CTL_POWER_D3|0x0000)
+#define SNDRV_CTL_POWER_D3cold (SNDRV_CTL_POWER_D3|0x0001)
+
+struct snd_ctl_elem_id {
+ unsigned int numid;
+ snd_ctl_elem_iface_t iface;
+ unsigned int device;
+ unsigned int subdevice;
+ unsigned char name[44];
+ unsigned int index;
+};
+
+struct snd_ctl_elem_list {
+ unsigned int offset;
+ unsigned int space;
+ unsigned int used;
+ unsigned int count;
+ struct snd_ctl_elem_id __user *pids;
+ unsigned char reserved[50];
+};
+
+struct snd_ctl_elem_info {
+ struct snd_ctl_elem_id id;
+ snd_ctl_elem_type_t type;
+ unsigned int access;
+ unsigned int count;
+ __kernel_pid_t owner;
+ union {
+ struct {
+ long min;
+ long max;
+ long step;
+ } integer;
+ struct {
+ long long min;
+ long long max;
+ long long step;
+ } integer64;
+ struct {
+ unsigned int items;
+ unsigned int item;
+ char name[64];
+ } enumerated;
+ unsigned char reserved[128];
+ } value;
+ union {
+ unsigned short d[4];
+ unsigned short *d_ptr;
+ } dimen;
+ unsigned char reserved[64-4*sizeof(unsigned short)];
+};
+
+struct snd_ctl_elem_value {
+ struct snd_ctl_elem_id id;
+ unsigned int indirect: 1;
+ union {
+ union {
+ long value[128];
+ long *value_ptr;
+ } integer;
+ union {
+ long long value[64];
+ long long *value_ptr;
+ } integer64;
+ union {
+ unsigned int item[128];
+ unsigned int *item_ptr;
+ } enumerated;
+ union {
+ unsigned char data[512];
+ unsigned char *data_ptr;
+ } bytes;
+ struct snd_aes_iec958 iec958;
+ } value;
+ struct timespec tstamp;
+ unsigned char reserved[128-sizeof(struct timespec)];
+};
+
+struct snd_ctl_tlv {
+ unsigned int numid;
+ unsigned int length;
+ unsigned int tlv[0];
+};
+
+#define SNDRV_CTL_IOCTL_PVERSION _IOR('U', 0x00, int)
+#define SNDRV_CTL_IOCTL_CARD_INFO _IOR('U', 0x01, struct snd_ctl_card_info)
+#define SNDRV_CTL_IOCTL_ELEM_LIST _IOWR('U', 0x10, struct snd_ctl_elem_list)
+#define SNDRV_CTL_IOCTL_ELEM_INFO _IOWR('U', 0x11, struct snd_ctl_elem_info)
+#define SNDRV_CTL_IOCTL_ELEM_READ _IOWR('U', 0x12, struct snd_ctl_elem_value)
+#define SNDRV_CTL_IOCTL_ELEM_WRITE _IOWR('U', 0x13, struct snd_ctl_elem_value)
+#define SNDRV_CTL_IOCTL_ELEM_LOCK _IOW('U', 0x14, struct snd_ctl_elem_id)
+#define SNDRV_CTL_IOCTL_ELEM_UNLOCK _IOW('U', 0x15, struct snd_ctl_elem_id)
+#define SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS _IOWR('U', 0x16, int)
+#define SNDRV_CTL_IOCTL_ELEM_ADD _IOWR('U', 0x17, struct snd_ctl_elem_info)
+#define SNDRV_CTL_IOCTL_ELEM_REPLACE _IOWR('U', 0x18, struct snd_ctl_elem_info)
+#define SNDRV_CTL_IOCTL_ELEM_REMOVE _IOWR('U', 0x19, struct snd_ctl_elem_id)
+#define SNDRV_CTL_IOCTL_TLV_READ _IOWR('U', 0x1a, struct snd_ctl_tlv)
+#define SNDRV_CTL_IOCTL_TLV_WRITE _IOWR('U', 0x1b, struct snd_ctl_tlv)
+#define SNDRV_CTL_IOCTL_TLV_COMMAND _IOWR('U', 0x1c, struct snd_ctl_tlv)
+#define SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE _IOWR('U', 0x20, int)
+#define SNDRV_CTL_IOCTL_HWDEP_INFO _IOR('U', 0x21, struct snd_hwdep_info)
+#define SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE _IOR('U', 0x30, int)
+#define SNDRV_CTL_IOCTL_PCM_INFO _IOWR('U', 0x31, struct snd_pcm_info)
+#define SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE _IOW('U', 0x32, int)
+#define SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE _IOWR('U', 0x40, int)
+#define SNDRV_CTL_IOCTL_RAWMIDI_INFO _IOWR('U', 0x41, struct snd_rawmidi_info)
+#define SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE _IOW('U', 0x42, int)
+#define SNDRV_CTL_IOCTL_POWER _IOWR('U', 0xd0, int)
+#define SNDRV_CTL_IOCTL_POWER_STATE _IOR('U', 0xd1, int)
+
+enum sndrv_ctl_event_type {
+ SNDRV_CTL_EVENT_ELEM = 0,
+ SNDRV_CTL_EVENT_LAST = SNDRV_CTL_EVENT_ELEM,
+};
+
+#define SNDRV_CTL_EVENT_MASK_VALUE (1<<0)
+#define SNDRV_CTL_EVENT_MASK_INFO (1<<1)
+#define SNDRV_CTL_EVENT_MASK_ADD (1<<2)
+#define SNDRV_CTL_EVENT_MASK_TLV (1<<3)
+#define SNDRV_CTL_EVENT_MASK_REMOVE (~0U)
+
+struct snd_ctl_event {
+ int type;
+ union {
+ struct {
+ unsigned int mask;
+ struct snd_ctl_elem_id id;
+ } elem;
+ unsigned char data8[60];
+ } data;
+};
+
+#define SNDRV_CTL_NAME_NONE ""
+#define SNDRV_CTL_NAME_PLAYBACK "Playback "
+#define SNDRV_CTL_NAME_CAPTURE "Capture "
+
+#define SNDRV_CTL_NAME_IEC958_NONE ""
+#define SNDRV_CTL_NAME_IEC958_SWITCH "Switch"
+#define SNDRV_CTL_NAME_IEC958_VOLUME "Volume"
+#define SNDRV_CTL_NAME_IEC958_DEFAULT "Default"
+#define SNDRV_CTL_NAME_IEC958_MASK "Mask"
+#define SNDRV_CTL_NAME_IEC958_CON_MASK "Con Mask"
+#define SNDRV_CTL_NAME_IEC958_PRO_MASK "Pro Mask"
+#define SNDRV_CTL_NAME_IEC958_PCM_STREAM "PCM Stream"
+#define SNDRV_CTL_NAME_IEC958(expl,direction,what) "IEC958 " expl SNDRV_CTL_NAME_##direction SNDRV_CTL_NAME_IEC958_##what
+
+#endif
+
diff --git a/libaudio/secril-client.h b/libaudio/secril-client.h
index 2473ae7..7bbaa03 100755..100644
--- a/libaudio/secril-client.h
+++ b/libaudio/secril-client.h
@@ -138,7 +138,8 @@ typedef enum _AudioPath {
SOUND_AUDIO_PATH_HEADSET,
SOUND_AUDIO_PATH_SPEAKER,
SOUND_AUDIO_PATH_BLUETOOTH,
- SOUND_AUDIO_PATH_BLUETOOTH_NO_NR
+ SOUND_AUDIO_PATH_BLUETOOTH_NO_NR,
+ SOUND_AUDIO_PATH_HEADPHONE
} AudioPath;
/**