summaryrefslogtreecommitdiffstats
path: root/libaudio/AudioHardwareALSA.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libaudio/AudioHardwareALSA.cpp')
-rwxr-xr-xlibaudio/AudioHardwareALSA.cpp2654
1 files changed, 0 insertions, 2654 deletions
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
-