summaryrefslogtreecommitdiffstats
path: root/libaudio2
diff options
context:
space:
mode:
authorEric Laurent <elaurent@google.com>2010-11-02 08:39:27 -0700
committerEric Laurent <elaurent@google.com>2010-11-11 12:18:48 -0800
commit6ab6d7021e5eb7ff43e56692a92b628a48add525 (patch)
treef18e7d0759aed78c9e1211b5dd27111fd93a67cb /libaudio2
parent80b3419a4dec477136444bc51b579ff6c7fd404b (diff)
downloaddevice_samsung_crespo-6ab6d7021e5eb7ff43e56692a92b628a48add525.zip
device_samsung_crespo-6ab6d7021e5eb7ff43e56692a92b628a48add525.tar.gz
device_samsung_crespo-6ab6d7021e5eb7ff43e56692a92b628a48add525.tar.bz2
Fix issue 3148223.
This change fixes issue 3148223 but also other issues with audio routing that could happen from time to time. The cause for those issues is the weakness of kernel codec driver with regard to timing and order in which audio path and pcm stream state changes are requested. Other issues reported are: - music sometimes distorted/inaudible after several voice search / phone calls - loss of incall audio after switching between SIP and PSTN Calls. The fix consists in systematically make sure that the codec driver is shutdown whenever an audio path change is requested: both output and input streams are forced into standby every time a change occurs in phone state, input path selection or output path selection. Change-Id: I3a534393cf6e551ce7b9f7569bcbcf33271e6a6c
Diffstat (limited to 'libaudio2')
-rw-r--r--libaudio2/AudioHardware.cpp512
-rw-r--r--libaudio2/AudioHardware.h20
2 files changed, 346 insertions, 186 deletions
diff --git a/libaudio2/AudioHardware.cpp b/libaudio2/AudioHardware.cpp
index 86a2f80..333e3cc 100644
--- a/libaudio2/AudioHardware.cpp
+++ b/libaudio2/AudioHardware.cpp
@@ -310,55 +310,114 @@ status_t AudioHardware::setMode(int mode)
sp<AudioStreamOutALSA> spOut;
sp<AudioStreamInALSA> spIn;
status_t status;
- { // scope for the lock
- AutoMutex lock(mLock);
- int prevMode = mMode;
- status = AudioHardwareBase::setMode(mode);
- LOGV("setMode() : new %d, old %d", mMode, prevMode);
- if (status == NO_ERROR) {
- // 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_NORMAL)
- {
- if ((!mActivatedCP) && (mSecRilLibHandle) && (connectRILDIfRequired() == OK)) {
- setCallClockSync(mRilClient, SOUND_CLOCK_START);
- mActivatedCP = true;
- }
+
+ // 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
+
+ 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) {
- LOGV("setMode() openPcmOut_l()");
- openPcmOut_l();
- openMixer_l();
- setInputSource_l(String8("Default"));
- mInCallAudioMode = true;
+ if (mMode == AudioSystem::MODE_IN_CALL && !mInCallAudioMode) {
+ if (spOut != 0) {
+ LOGV("setMode() in call force output standby");
+ spOut->doStandby_l();
}
- if (mMode == AudioSystem::MODE_NORMAL && mInCallAudioMode) {
- setInputSource_l(mInputSource);
- LOGV("setMode() closeMixer_l()");
- closeMixer_l();
- LOGV("setMode() closePcmOut_l()");
- closePcmOut_l();
- spOut = mOutput;
- spIn = getActiveInput_l();
- mInCallAudioMode = false;
+ if (spIn != 0) {
+ LOGV("setMode() in call force input standby");
+ spIn->doStandby_l();
}
- if (mMode == AudioSystem::MODE_NORMAL) {
- if(mActivatedCP)
- mActivatedCP = false;
+ 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 (spOut != 0) {
- spOut->setNextRoute(getOutputRouteFromDevice(spOut->device()));
- spOut->standby();
+ if (mMode == AudioSystem::MODE_NORMAL) {
+ if(mActivatedCP)
+ mActivatedCP = false;
+ }
}
+
if (spIn != 0) {
- spIn->setNextRoute(getInputRouteFromDevice(spIn->device()));
- spIn->standby();
+ spIn->unlock();
+ }
+ if (spOut != 0) {
+ spOut->unlock();
}
return status;
@@ -380,7 +439,6 @@ status_t AudioHardware::setMicMute(bool state)
}
if (spIn != 0) {
- spIn->setNextRoute(getInputRouteFromDevice(spIn->device()));
spIn->standby();
}
@@ -407,7 +465,7 @@ status_t AudioHardware::setParameters(const String8& keyValuePairs)
mBluetoothNrec = true;
} else {
mBluetoothNrec = false;
- LOGI("Turning noise reduction and echo cancellation off for BT "
+ LOGD("Turning noise reduction and echo cancellation off for BT "
"headset");
}
}
@@ -447,7 +505,7 @@ size_t AudioHardware::getInputBufferSize(uint32_t sampleRate, int format, int ch
status_t AudioHardware::setVoiceVolume(float volume)
{
- LOGI("### setVoiceVolume");
+ LOGD("### setVoiceVolume");
AutoMutex lock(mLock);
if ( (AudioSystem::MODE_IN_CALL == mMode) && (mSecRilLibHandle) &&
@@ -460,28 +518,28 @@ status_t AudioHardware::setVoiceVolume(float volume)
int int_volume = (int)(volume * 5);
SoundType type;
- LOGI("### route(%d) call volume(%f)", device, volume);
+ LOGD("### route(%d) call volume(%f)", device, volume);
switch (device) {
case AudioSystem::DEVICE_OUT_EARPIECE:
- LOGI("### earpiece call volume");
+ LOGD("### earpiece call volume");
type = SOUND_TYPE_VOICE;
break;
case AudioSystem::DEVICE_OUT_SPEAKER:
- LOGI("### speaker call volume");
+ 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:
- LOGI("### bluetooth call volume");
+ 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.
- LOGI("### headset call volume");
+ LOGD("### headset call volume");
type = SOUND_TYPE_HEADSET;
break;
@@ -588,23 +646,23 @@ status_t AudioHardware::setIncallPath_l(uint32_t device)
(connectRILDIfRequired() == OK)) {
if (mMode == AudioSystem::MODE_IN_CALL) {
- LOGI("### incall mode route (%d)", device);
+ LOGD("### incall mode route (%d)", device);
AudioPath path;
switch(device){
case AudioSystem::DEVICE_OUT_EARPIECE:
- LOGI("### incall mode earpiece route");
+ LOGD("### incall mode earpiece route");
path = SOUND_AUDIO_PATH_HANDSET;
break;
case AudioSystem::DEVICE_OUT_SPEAKER:
- LOGI("### incall mode speaker route");
+ 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:
- LOGI("### incall mode bluetooth route %s NR", mBluetoothNrec ? "" : "NO");
+ LOGD("### incall mode bluetooth route %s NR", mBluetoothNrec ? "" : "NO");
if (mBluetoothNrec) {
path = SOUND_AUDIO_PATH_BLUETOOTH;
} else {
@@ -613,12 +671,12 @@ status_t AudioHardware::setIncallPath_l(uint32_t device)
break;
case AudioSystem::DEVICE_OUT_WIRED_HEADPHONE :
- LOGI("### incall mode headphone route");
+ LOGD("### incall mode headphone route");
path = SOUND_AUDIO_PATH_HEADPHONE;
break;
case AudioSystem::DEVICE_OUT_WIRED_HEADSET :
- LOGI("### incall mode headset route");
+ LOGD("### incall mode headset route");
path = SOUND_AUDIO_PATH_HEADSET;
break;
@@ -649,7 +707,7 @@ status_t AudioHardware::setIncallPath_l(uint32_t device)
struct pcm *AudioHardware::openPcmOut_l()
{
- LOGI("openPcmOut_l() mPcmOpenCnt: %d", mPcmOpenCnt);
+ LOGD("openPcmOut_l() mPcmOpenCnt: %d", mPcmOpenCnt);
if (mPcmOpenCnt++ == 0) {
if (mPcm != NULL) {
LOGE("openPcmOut_l() mPcmOpenCnt == 0 and mPcm == %p\n", mPcm);
@@ -678,7 +736,7 @@ struct pcm *AudioHardware::openPcmOut_l()
void AudioHardware::closePcmOut_l()
{
- LOGI("closePcmOut_l() mPcmOpenCnt: %d", mPcmOpenCnt);
+ LOGD("closePcmOut_l() mPcmOpenCnt: %d", mPcmOpenCnt);
if (mPcmOpenCnt == 0) {
LOGE("closePcmOut_l() mPcmOpenCnt == 0");
return;
@@ -697,7 +755,7 @@ 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", mPcm);
+ LOGE("openMixer_l() mMixerOpenCnt == 0 and mMixer == %p\n", mMixer);
mMixerOpenCnt--;
return NULL;
}
@@ -707,6 +765,7 @@ struct mixer *AudioHardware::openMixer_l()
if (mMixer == NULL) {
LOGE("openMixer_l() cannot open mixer");
mMixerOpenCnt--;
+ return NULL;
}
}
return mMixer;
@@ -857,7 +916,7 @@ 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)
+ mDriverOp(DRV_NONE), mStandbyCnt(0)
{
}
@@ -913,35 +972,47 @@ ssize_t AudioHardware::AudioStreamOutALSA::write(const void* buffer, size_t byte
if (mHardware == NULL) return NO_INIT;
{ // scope for the lock
+
AutoMutex lock(mLock);
if (mStandby) {
AutoMutex hwLock(mHardware->lock());
- LOGV("open pcm_out driver");
- mPcm = mHardware->openPcmOut_l();
- if (mPcm == NULL) {
- goto Error;
+ 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
- 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
+ // open output before input
+ open_l();
+
+ if (spIn != 0) {
+ spIn->open_l();
+ spIn->unlock();
}
- if (mHardware->mode() != AudioSystem::MODE_IN_CALL) {
- next_route = mHardware->getOutputRouteFromDevice(mDevices);
- LOGV("write() wakeup setting route %s", next_route);
- if (next_route && mRouteCtl) {
- TRACE_DRIVER_IN(DRV_MIXER_SEL)
- mixer_ctl_select(mRouteCtl, next_route);
- TRACE_DRIVER_OUT
- }
+ if (mPcm == NULL) {
+ release_wake_lock("AudioOutLock");
+ goto Error;
}
- next_route = 0;
- acquire_wake_lock (PARTIAL_WAKE_LOCK, "AudioOutLock");
mStandby = false;
}
@@ -950,13 +1021,6 @@ ssize_t AudioHardware::AudioStreamOutALSA::write(const void* buffer, size_t byte
TRACE_DRIVER_OUT
if (ret == 0) {
- if (next_route && mRouteCtl) {
- LOGV("write() setting route %s", next_route);
- TRACE_DRIVER_IN(DRV_MIXER_SEL)
- mixer_ctl_select(mRouteCtl, next_route);
- TRACE_DRIVER_OUT
- next_route = 0;
- }
return bytes;
}
LOGW("write error: %d", errno);
@@ -981,29 +1045,62 @@ status_t AudioHardware::AudioStreamOutALSA::standby()
{ // scope for the AudioHardware lock
AutoMutex hwLock(mHardware->lock());
- if (!mStandby) {
- if (next_route && mRouteCtl) {
- TRACE_DRIVER_IN(DRV_MIXER_SEL)
- mixer_ctl_select(mRouteCtl, next_route);
- TRACE_DRIVER_OUT
- next_route = 0;
- }
- release_wake_lock("AudioOutLock");
- mStandby = true;
- LOGV("AudioHardware pcm playback is going to standby.");
- }
+ doStandby_l();
+ }
- if (mMixer) {
- mHardware->closeMixer_l();
- mMixer = 0;
- mRouteCtl = 0;
- }
- if (mPcm) {
- mHardware->closePcmOut_l();
- mPcm = 0;
- }
+ 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;
}
@@ -1028,9 +1125,6 @@ status_t AudioHardware::AudioStreamOutALSA::dump(int fd, const Vector<String16>&
result.append(buffer);
snprintf(buffer, SIZE, "\t\tmRouteCtl: %p\n", mRouteCtl);
result.append(buffer);
- snprintf(buffer, SIZE, "\t\tnext_route: %s\n",
- (next_route == 0 ) ? "none" : next_route);
- 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);
@@ -1063,22 +1157,24 @@ status_t AudioHardware::AudioStreamOutALSA::setParameters(const String8& keyValu
if (mHardware == NULL) return NO_INIT;
- AutoMutex lock(mLock);
-
- if (param.getInt(String8(AudioParameter::keyRouting), device) == NO_ERROR)
{
- AutoMutex hwLock(mHardware->lock());
+ 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) {
- next_route = mHardware->getOutputRouteFromDevice(device);
+ 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 (mHardware->mode() == AudioSystem::MODE_IN_CALL) {
- mHardware->setIncallPath_l(device);
- }
- param.remove(String8(AudioParameter::keyRouting));
}
if (param.size()) {
@@ -1118,7 +1214,8 @@ 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)
+ mDownSampler(NULL), mReadStatus(NO_ERROR), mDriverOp(DRV_NONE),
+ mStandbyCnt(0)
{
}
@@ -1194,53 +1291,49 @@ ssize_t AudioHardware::AudioStreamInALSA::read(void* buffer, ssize_t bytes)
AutoMutex lock(mLock);
if (mStandby) {
- 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;
+ AutoMutex hwLock(mHardware->lock());
- 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_out driver: %s\n", pcm_error(mPcm));
- TRACE_DRIVER_IN(DRV_PCM_CLOSE)
- pcm_close(mPcm);
- TRACE_DRIVER_OUT
- mPcm = 0;
- goto Error;
- }
+ LOGD("AudioHardware pcm capture is exiting standby.");
+ acquire_wake_lock (PARTIAL_WAKE_LOCK, "AudioInLock");
- if (mDownSampler != NULL) {
- mInPcmInBuf = 0;
- mDownSampler->reset();
+ 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
- AutoMutex hwLock(mHardware->lock());
-
- mMixer = mHardware->openMixer_l();
- if (mMixer) {
- TRACE_DRIVER_IN(DRV_MIXER_GET)
- mRouteCtl = mixer_get_control(mMixer, "Capture MIC Path", 0);
- TRACE_DRIVER_OUT
+ // open output before input
+ if (spOut != 0) {
+ spOut->open_l();
+ spOut->unlock();
}
- if (mHardware->mode() != AudioSystem::MODE_IN_CALL) {
- next_route = mHardware->getInputRouteFromDevice(mDevices);
- LOGV("read() wakeup setting route %s", next_route);
- if (next_route && mRouteCtl) {
- TRACE_DRIVER_IN(DRV_MIXER_SEL)
- mixer_ctl_select(mRouteCtl, next_route);
- TRACE_DRIVER_OUT
- }
- }
- next_route = 0;
+ open_l();
- acquire_wake_lock (PARTIAL_WAKE_LOCK, "AudioInLock");
+ if (mPcm == NULL) {
+ release_wake_lock("AudioInLock");
+ goto Error;
+ }
mStandby = false;
}
@@ -1291,25 +1384,84 @@ status_t AudioHardware::AudioStreamInALSA::standby()
{ // scope for AudioHardware lock
AutoMutex hwLock(mHardware->lock());
- if (!mStandby) {
- release_wake_lock("AudioInLock");
- mStandby = true;
- LOGI("AudioHardware pcm playback is going to standby.");
- }
+ doStandby_l();
+ }
+ return NO_ERROR;
+}
- if (mMixer) {
- mHardware->closeMixer_l();
- mMixer = 0;
- mRouteCtl = 0;
- }
+void AudioHardware::AudioStreamInALSA::doStandby_l()
+{
+ mStandbyCnt++;
- if (mPcm) {
- TRACE_DRIVER_IN(DRV_PCM_CLOSE)
- pcm_close(mPcm);
+ 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_out 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
- mPcm = 0;
}
}
+
return NO_ERROR;
}
@@ -1332,9 +1484,6 @@ status_t AudioHardware::AudioStreamInALSA::dump(int fd, const Vector<String16>&
result.append(buffer);
snprintf(buffer, SIZE, "\t\tmMixer: %p\n", mMixer);
result.append(buffer);
- snprintf(buffer, SIZE, "\t\tnext_route: %s\n",
- (next_route == 0 ) ? "none" : next_route);
- 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);
@@ -1363,7 +1512,6 @@ status_t AudioHardware::AudioStreamInALSA::setParameters(const String8& keyValue
status_t status = NO_ERROR;
int value;
String8 source;
- bool forceStandby = false;
LOGD("AudioStreamInALSA::setParameters() %s", keyValuePairs.string());
@@ -1388,20 +1536,16 @@ status_t AudioHardware::AudioStreamInALSA::setParameters(const String8& keyValue
AutoMutex hwLock(mHardware->lock());
if (mDevices != (uint32_t)value) {
+ mDevices = (uint32_t)value;
if (mHardware->mode() != AudioSystem::MODE_IN_CALL) {
- next_route = mHardware->getInputRouteFromDevice((uint32_t)value);
- forceStandby = true;
+ doStandby_l();
}
- mDevices = (uint32_t)value;
}
}
param.remove(String8(AudioParameter::keyRouting));
}
}
- if (forceStandby) {
- standby();
- }
if (param.size()) {
status = BAD_VALUE;
diff --git a/libaudio2/AudioHardware.h b/libaudio2/AudioHardware.h
index 256624b..1379495 100644
--- a/libaudio2/AudioHardware.h
+++ b/libaudio2/AudioHardware.h
@@ -124,6 +124,8 @@ public:
struct mixer *openMixer_l();
void closeMixer_l();
+ sp <AudioStreamOutALSA> output() { return mOutput; }
+
protected:
virtual status_t dump(int fd, const Vector<String16>& args);
@@ -196,7 +198,13 @@ private:
uint32_t device() { return mDevices; }
virtual status_t getRenderPosition(uint32_t *dspFrames);
- void setNextRoute(const char *route) { AutoMutex lock(mLock); next_route = route; }
+ void doStandby_l();
+ void close_l();
+ status_t open_l();
+ int standbyCnt() { return mStandbyCnt; }
+
+ void lock() { mLock.lock(); }
+ void unlock() { mLock.unlock(); }
private:
@@ -213,6 +221,7 @@ private:
size_t mBufferSize;
// trace driver operations for dump
int mDriverOp;
+ int mStandbyCnt;
};
class DownSampler;
@@ -296,7 +305,10 @@ private:
virtual String8 getParameters(const String8& keys);
virtual unsigned int getInputFramesLost() const { return 0; }
uint32_t device() { return mDevices; }
- void setNextRoute(const char *route) { AutoMutex lock(mLock); next_route = route; }
+ void doStandby_l();
+ void close_l();
+ status_t open_l();
+ int standbyCnt() { return mStandbyCnt; }
static size_t getBufferSize(uint32_t sampleRate, int channelCount);
@@ -304,6 +316,9 @@ private:
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;
@@ -323,6 +338,7 @@ private:
int16_t *mPcmIn;
// trace driver operations for dump
int mDriverOp;
+ int mStandbyCnt;
};
};