AudioHardwareALSA::AudioHardwareALSA() :
mOutput(0),
mInput(0),
- mAcousticDevice(0),
- mPowerLock(false)
+ mAcousticDevice(0)
{
snd_lib_error_set_handler(&ALSAErrorHandler);
mMixer = new ALSAMixer;
return NO_INIT;
}
-status_t AudioHardwareALSA::standby()
-{
- AutoMutex lock(mLock);
-
- if (mOutput)
- mOutput->standby();
-
- if (mInput)
- mInput->standby();
-
- if (mPowerLock) {
- release_wake_lock ("AudioLock");
- mPowerLock = false;
- }
-
- return NO_ERROR;
-}
-
status_t AudioHardwareALSA::setVoiceVolume(float volume)
{
// The voice volume is used by the VOICE_CALL audio stream.
mOutput = out;
// Some information is expected to be available immediately after
// the device is open.
- uint32_t routes = mRoutes[mMode];
- mOutput->setDevice(mMode, routes);
+ *status = mOutput->setDevice(mMode, mRoutes[mMode]);
}
else {
delete out;
status_t *status,
AudioSystem::audio_in_acoustics acoustics)
{
- AutoMutex lock(mLock);
-
// check for valid input source
if ((inputSource < AudioRecord::DEFAULT_INPUT) ||
(inputSource >= AudioRecord::NUM_INPUT_SOURCES)) {
return 0;
}
+ AutoMutex lock(mLock);
+
// only one input stream allowed
if (mInput) {
*status = ALREADY_EXISTS;
mInput = in;
// Some information is expected to be available immediately after
// the device is open.
- uint32_t routes = mRoutes[mMode];
- mInput->setDevice(mMode, routes);
+ *status = mInput->setDevice(mMode, mRoutes[mMode]);
}
else {
delete in;
}
+
return mInput;
}
status_t AudioHardwareALSA::doRouting()
{
- uint32_t routes;
-
AutoMutex lock(mLock);
- if (mOutput) {
- routes = mRoutes[mMode];
- return mOutput->setDevice(mMode, routes);
- }
- return NO_INIT;
+ if (!mOutput)
+ return NO_INIT;
+
+ return mOutput->setDevice(mMode, mRoutes[mMode]);
}
status_t AudioHardwareALSA::setMicMute(bool state)
mHardwareParams(0),
mSoftwareParams(0),
mMode(-1),
- mDevice(0)
+ mDevice(0),
+ mPowerLock(false)
{
if (snd_pcm_hw_params_malloc(&mHardwareParams) < 0) {
LOG_ALWAYS_FATAL("Failed to allocate ALSA hardware parameters!");
ALSAStreamOps::~ALSAStreamOps()
{
+ AutoMutex lock(mLock);
+
close();
if (mHardwareParams)
int channels,
uint32_t rate)
{
- if (channels != 0)
+ if (channels > 0)
mDefaults->channels = channels;
- if (rate != 0)
+ if (rate > 0)
mDefaults->sampleRate = rate;
switch(format) {
unsigned int rate;
int err;
- if (! mHandle)
- return NO_INIT;
+ if (!mHandle)
+ return mDefaults->sampleRate;
return snd_pcm_hw_params_get_rate(mHardwareParams, &rate, 0) < 0
? 0 : static_cast<uint32_t>(rate);
rate, requestedRate);
}
else {
- LOGD("Set %s sample rate to %u HZ", stream, requestedRate);
+ LOGV("Set %s sample rate to %u HZ", stream, requestedRate);
}
return NO_ERROR;
}
//
size_t ALSAStreamOps::bufferSize() const
{
- int err;
-
if (!mHandle)
- return -1;
+ return NO_INIT;
snd_pcm_uframes_t bufferSize = 0;
snd_pcm_uframes_t periodSize = 0;
+ int err;
err = snd_pcm_get_params(mHandle, &bufferSize, &periodSize);
if (err < 0)
return -1;
- return static_cast<size_t>(snd_pcm_frames_to_bytes(mHandle, bufferSize));
+ size_t bytes = static_cast<size_t>(snd_pcm_frames_to_bytes(mHandle, bufferSize));
+
+ // Not sure when this happened, but unfortunately it now
+ // appears that the bufferSize must be reported as a
+ // power of 2. This might be the fault of 3rd party
+ // users.
+ for (size_t i = 1; (bytes & ~i) != 0; i<<=1)
+ bytes &= ~i;
+
+ return bytes;
}
int ALSAStreamOps::format() const
int ALSAStreamOps::channelCount() const
{
+ if (!mHandle)
+ return mDefaults->channels;
+
unsigned int val;
int err;
- if (!mHandle)
- return -1;
-
err = snd_pcm_hw_params_get_channels(mHardwareParams, &val);
if (err < 0) {
LOGE("Unable to get device channel count: %s",
snd_strerror(err));
- return -1;
+ return mDefaults->channels;
}
return val;
return BAD_VALUE;
}
- LOGD("Using %i %s for %s.",
+ LOGV("Using %i %s for %s.",
channels, channels == 1 ? "channel" : "channels", streamName());
return NO_ERROR;
// 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;
+ if (!tail) break;
*tail = 0;
}
snd_pcm_t *handle = mHandle;
mHandle = NULL;
- if (handle) {
+ if (handle)
snd_pcm_close(handle);
- mMode = -1;
- mDevice = 0;
- }
}
status_t ALSAStreamOps::setSoftwareParams()
// For recording, configure ALSA to start the transfer on the
// first frame.
startThreshold = 1;
- stopThreshold = (bufferSize / periodSize) * periodSize;
+ stopThreshold = bufferSize;
}
err = snd_pcm_sw_params_set_start_threshold(mHandle,
return NO_INIT;
}
- LOGD("Set %s PCM format to %s (%s)", streamName(), formatName, formatDesc);
+ LOGV("Set %s PCM format to %s (%s)", streamName(), formatName, formatDesc);
return NO_ERROR;
}
#endif
snd_pcm_uframes_t bufferSize = mDefaults->bufferSize;
- 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);
return NO_INIT;
}
+ unsigned int latency = mDefaults->latency;
+
// Setup buffers for latency
err = snd_pcm_hw_params_set_buffer_time_near (mHandle, mHardwareParams,
&latency, NULL);
}
}
- LOGD("Buffer size: %d", (int)bufferSize);
- LOGD("Latency: %d", (int)latency);
+ LOGV("Buffer size: %d", (int)bufferSize);
+ LOGV("Latency: %d", (int)latency);
mDefaults->bufferSize = bufferSize;
mDefaults->latency = latency;
};
setStreamDefaults(&_defaults);
+
+ snd_pcm_uframes_t bufferSize = mDefaults->bufferSize;
+
+ // See comment in bufferSize() method.
+ for (size_t i = 1; (bufferSize & ~i) != 0; i<<=1)
+ bufferSize &= ~i;
+
+ mDefaults->bufferSize = bufferSize;
}
AudioStreamOutALSA::~AudioStreamOutALSA()
status_t AudioStreamOutALSA::setVolume(float volume)
{
- if (! mParent->mMixer || ! mDevice)
+ if (!mParent->mMixer || !mDevice)
return NO_INIT;
return mParent->mMixer->setVolume (mDevice, volume);
size_t sent = 0;
status_t err;
- /* Scope for lock */ {
- AutoMutex lock(mParent->mLock);
-
- if (isStandby())
- return 0;
+ AutoMutex lock(mLock);
- if (!mParent->mPowerLock) {
- acquire_wake_lock (PARTIAL_WAKE_LOCK, "AudioLock");
- setDevice(mMode, mDevice);
- mParent->mPowerLock = true;
- }
+ if (!mPowerLock) {
+ acquire_wake_lock (PARTIAL_WAKE_LOCK, "AudioOutLock");
+ mPowerLock = true;
}
+ if (!mHandle)
+ ALSAStreamOps::setDevice(mMode, mDevice);
+
do {
n = snd_pcm_writei(mHandle,
(char *)buffer + sent,
if (n == -EBADFD) {
// Somehow the stream is in a bad state. The driver probably
// has a bug and snd_pcm_recover() doesn't seem to handle this.
- setDevice(mMode, mDevice);
+ ALSAStreamOps::setDevice(mMode, mDevice);
}
else if (n < 0) {
if (mHandle) {
status_t AudioStreamOutALSA::setDevice(int mode, uint32_t newDevice)
{
+ AutoMutex lock(mLock);
+
return ALSAStreamOps::setDevice(mode, newDevice);
}
status_t AudioStreamOutALSA::standby()
{
- if (mHandle)
+ AutoMutex lock(mLock);
+
+ if (mHandle) {
snd_pcm_drain (mHandle);
+ close();
+ }
- return NO_ERROR;
-}
+ if (mPowerLock) {
+ release_wake_lock ("AudioOutLock");
+ mPowerLock = false;
+ }
-bool AudioStreamOutALSA::isStandby()
-{
- return (!mHandle);
+ return NO_ERROR;
}
#define USEC_TO_MSEC(x) ((x + 999) / 1000)
snd_pcm_sframes_t n, frames = snd_pcm_bytes_to_frames(mHandle, bytes);
status_t err;
- /* Scope for lock */ {
- AutoMutex lock(mParent->mLock);
+ AutoMutex lock(mLock);
- if (!mParent->mPowerLock) {
- acquire_wake_lock (PARTIAL_WAKE_LOCK, "AudioLock");
- setDevice(mMode, mDevice);
- mParent->mPowerLock = true;
- }
+ if (!mPowerLock) {
+ acquire_wake_lock (PARTIAL_WAKE_LOCK, "AudioInLock");
+ mPowerLock = true;
}
+ if (!mHandle)
+ ALSAStreamOps::setDevice(mMode, mDevice);
+
n = snd_pcm_readi(mHandle, buffer, frames);
if (n < frames) {
if (mHandle) {
status_t AudioStreamInALSA::setDevice(int mode, uint32_t newDevice)
{
+ AutoMutex lock(mLock);
+
status_t status = ALSAStreamOps::setDevice(mode, newDevice);
if (status == NO_ERROR && mParent->mAcousticDevice)
status_t AudioStreamInALSA::standby()
{
+ AutoMutex lock(mLock);
+
+ close();
+
+ if (mPowerLock) {
+ release_wake_lock ("AudioInLock");
+ mPowerLock = false;
+ }
+
return NO_ERROR;
}
// 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)) {
}
}
- LOGD ("Mixer: master '%s' %s.", info->name, info->elem ? "found" : "not found");
+ LOGV("Mixer: master '%s' %s.", info->name, info->elem ? "found" : "not found");
for (int j = 0; mixerProp[j][i].routes; j++) {
break;
}
}
- LOGD ("Mixer: route '%s' %s.", info->name, info->elem ? "found" : "not found");
+ LOGV("Mixer: route '%s' %s.", info->name, info->elem ? "found" : "not found");
}
}
- LOGD("mixer initialized.");
+ LOGV("mixer initialized.");
}
ALSAMixer::~ALSAMixer()
}
}
}
- LOGD("mixer destroyed.");
+ LOGV("mixer destroyed.");
}
status_t ALSAMixer::setMasterVolume(float volume)
status_t ALSAMixer::getCaptureMuteState(uint32_t device, bool *state)
{
- if (! state) return BAD_VALUE;
+ 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) {
status_t ALSAMixer::getPlaybackMuteState(uint32_t device, bool *state)
{
- if (! state) return BAD_VALUE;
+ 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) {
class ALSAStreamOps
{
- public:
+ protected:
+ friend class AudioStreamOutALSA;
+ friend class AudioStreamInALSA;
+
struct StreamDefaults
{
const char * devicePrefix;
virtual int format() const;
virtual int channelCount() const;
status_t channelCount(int channels);
- const char *streamName();
- virtual status_t setDevice(int mode, uint32_t device);
-
- const char *deviceName(int mode, uint32_t device);
-
- protected:
- friend class AudioStreamOutALSA;
- friend class AudioStreamInALSA;
status_t open(int mode, uint32_t device);
void close();
status_t setPCMFormat(snd_pcm_format_t format);
status_t setHardwareResample(bool resample);
+ status_t setDevice(int mode, uint32_t device);
+
+ const char *streamName();
+ const char *deviceName(int mode, uint32_t device);
+
void setStreamDefaults(StreamDefaults *dev) {
mDefaults = dev;
}
uint32_t mDevice;
StreamDefaults *mDefaults;
- };
+
+ Mutex mLock;
+ bool mPowerLock;
+};
// ----------------------------------------------------------------------------
virtual ssize_t write(const void *buffer, size_t bytes);
virtual status_t dump(int fd, const Vector<String16>& args);
- virtual status_t setDevice(int mode, uint32_t newDevice);
status_t setVolume(float volume);
- status_t standby();
- bool isStandby();
+ virtual status_t standby();
+
+ protected:
+ friend class AudioHardwareALSA;
+
+ status_t setDevice(int mode, uint32_t newDevice);
};
class AudioStreamInALSA : public AudioStreamIn, public ALSAStreamOps
virtual ssize_t read(void* buffer, ssize_t bytes);
virtual status_t dump(int fd, const Vector<String16>& args);
- virtual status_t setDevice(int mode, uint32_t newDevice);
virtual status_t setGain(float gain);
virtual status_t standby();
+ protected:
+ friend class AudioHardwareALSA;
+
+ status_t setDevice(int mode, uint32_t newDevice);
+
private:
AudioSystem::audio_in_acoustics mAcoustics;
};
*/
virtual status_t initCheck();
- /**
- * put the audio hardware into standby mode to conserve power. Returns
- * status based on include/utils/Errors.h
- */
- virtual status_t standby();
-
/** set the audio volume of a voice call. Range is between 0.0 and 1.0 */
virtual status_t setVoiceVolume(float volume);
acoustic_device_t *mAcousticDevice;
private:
- Mutex mLock;
- bool mPowerLock;
+ Mutex mLock;
};
// ----------------------------------------------------------------------------