blob: 46dfd4e8f9601611a8a7eb2d4e048fc6ddf02eab [file] [log] [blame]
/* 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 <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <dlfcn.h>
#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 "AudioHardwareALSA.h"
extern "C"
{
//
// Function for dlsym() to look up for creating a new AudioHardwareInterface.
//
android::AudioHardwareInterface *createAudioHardware(void) {
return android::AudioHardwareALSA::create();
}
} // extern "C"
namespace android
{
// ----------------------------------------------------------------------------
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';
LOG(LOG_ERROR, "ALSALib", buf);
va_end(arg);
}
AudioHardwareInterface *AudioHardwareALSA::create() {
return new AudioHardwareALSA();
}
AudioHardwareALSA::AudioHardwareALSA() :
mALSADevice(0),
mAcousticDevice(0)
{
snd_lib_error_set_handler(&ALSAErrorHandler);
mMixer = new ALSAMixer;
hw_module_t *module;
int err = hw_get_module(ALSA_HARDWARE_MODULE_ID,
(hw_module_t const**)&module);
if (err == 0) {
hw_device_t* device;
err = module->methods->open(module, ALSA_HARDWARE_NAME, &device);
if (err == 0) {
mALSADevice = (alsa_device_t *)device;
mALSADevice->init(mALSADevice, mDeviceList);
} else
LOGE("ALSA Module could not be opened!!!");
} else
LOGE("ALSA Module not found!!!");
err = hw_get_module(ACOUSTICS_HARDWARE_MODULE_ID,
(hw_module_t const**)&module);
if (err == 0) {
hw_device_t* device;
err = module->methods->open(module, ACOUSTICS_HARDWARE_NAME, &device);
if (err == 0)
mAcousticDevice = (acoustic_device_t *)device;
else
LOGE("Acoustics Module not found.");
}
}
AudioHardwareALSA::~AudioHardwareALSA()
{
if (mMixer) delete mMixer;
if (mALSADevice)
mALSADevice->common.close(&mALSADevice->common);
if (mAcousticDevice)
mAcousticDevice->common.close(&mAcousticDevice->common);
}
status_t AudioHardwareALSA::initCheck()
{
if (mALSADevice && mMixer && mMixer->isValid())
return NO_ERROR;
else
return NO_INIT;
}
status_t AudioHardwareALSA::setVoiceVolume(float volume)
{
// The voice volume is used by the VOICE_CALL audio stream.
if (mMixer)
return mMixer->setVolume(AudioSystem::DEVICE_OUT_EARPIECE, volume, volume);
else
return INVALID_OPERATION;
}
status_t AudioHardwareALSA::setMasterVolume(float volume)
{
if (mMixer)
return mMixer->setMasterVolume(volume);
else
return INVALID_OPERATION;
}
status_t AudioHardwareALSA::setMode(int mode)
{
status_t status = NO_ERROR;
if (mode != mMode) {
status = AudioHardwareBase::setMode(mode);
if (status == NO_ERROR) {
// take care of mode change.
for(ALSAHandleList::iterator it = mDeviceList.begin();
it != mDeviceList.end(); ++it) {
status = mALSADevice->route(&(*it), it->curDev, mode);
if (status != NO_ERROR)
break;
}
}
}
return status;
}
AudioStreamOut *
AudioHardwareALSA::openOutputStream(uint32_t devices,
int *format,
uint32_t *channels,
uint32_t *sampleRate,
status_t *status)
{
AutoMutex lock(mLock);
LOGD("openOutputStream called for devices: 0x%08x", devices);
status_t err = BAD_VALUE;
AudioStreamOutALSA *out = 0;
if (devices & (devices - 1)) {
if (status) *status = err;
LOGD("openOutputStream called with bad devices");
return out;
}
// Find the appropriate alsa device
for(ALSAHandleList::iterator it = mDeviceList.begin();
it != mDeviceList.end(); ++it)
if (it->devices & devices) {
err = mALSADevice->open(&(*it), devices, mode());
if (err) break;
out = new AudioStreamOutALSA(this, &(*it));
err = out->set(format, channels, sampleRate);
break;
}
if (status) *status = err;
return out;
}
void
AudioHardwareALSA::closeOutputStream(AudioStreamOut* out)
{
AutoMutex lock(mLock);
delete out;
}
AudioStreamIn *
AudioHardwareALSA::openInputStream(uint32_t devices,
int *format,
uint32_t *channels,
uint32_t *sampleRate,
status_t *status,
AudioSystem::audio_in_acoustics acoustics)
{
AutoMutex lock(mLock);
status_t err = BAD_VALUE;
AudioStreamInALSA *in = 0;
if (devices & (devices - 1)) {
if (status) *status = err;
return in;
}
// Find the appropriate alsa device
for(ALSAHandleList::iterator it = mDeviceList.begin();
it != mDeviceList.end(); ++it)
if (it->devices & devices) {
err = mALSADevice->open(&(*it), devices, mode());
if (err) break;
in = new AudioStreamInALSA(this, &(*it), acoustics);
err = in->set(format, channels, sampleRate);
break;
}
if (status) *status = err;
return in;
}
void
AudioHardwareALSA::closeInputStream(AudioStreamIn* in)
{
AutoMutex lock(mLock);
delete in;
}
status_t AudioHardwareALSA::setMicMute(bool state)
{
if (mMixer)
return mMixer->setCaptureMuteState(AudioSystem::DEVICE_OUT_EARPIECE, state);
return NO_INIT;
}
status_t AudioHardwareALSA::getMicMute(bool *state)
{
if (mMixer)
return mMixer->getCaptureMuteState(AudioSystem::DEVICE_OUT_EARPIECE, state);
return NO_ERROR;
}
status_t AudioHardwareALSA::dump(int fd, const Vector<String16>& args)
{
return NO_ERROR;
}
} // namespace android