From 14513e1c14b88d7bee4596a14425ae6d7f76640d Mon Sep 17 00:00:00 2001 From: Pawit Pornkitprasan Date: Thu, 1 Sep 2011 22:39:48 +0700 Subject: libaudio: Fix FM Radio to work with other android sounds - Run openPcmOut_l and openMixer_l regardless if whether they are already initialized or not. (These functions have a open counter and they will be closed prematurely if we don't declare that we are going to use them.) - Fix invalid output device after playing notification - Fix resuming FM radio after call ended Note: resuming FM radio after notification is also dependent on a patch to FM.apk Change-Id: I8ab9fe74bb5a099252e0c1072a40e86209bc4a05 --- libaudio/AudioHardware.cpp | 106 +++++++++++++++++++++++++++++---------------- libaudio/AudioHardware.h | 3 ++ 2 files changed, 71 insertions(+), 38 deletions(-) diff --git a/libaudio/AudioHardware.cpp b/libaudio/AudioHardware.cpp index c2efbd1..8d0daeb 100644 --- a/libaudio/AudioHardware.cpp +++ b/libaudio/AudioHardware.cpp @@ -98,6 +98,7 @@ AudioHardware::AudioHardware() : mActivatedCP(false), #ifdef HAVE_FM_RADIO mFmFd(-1), + mFmResumeAfterCall(false), #endif mDriverOp(DRV_NONE) { @@ -435,6 +436,12 @@ status_t AudioHardware::setMode(int mode) spOut->unlock(); } + if (mFmResumeAfterCall) { + mFmResumeAfterCall = false; + + enableFMRadio(); + } + return status; } @@ -520,50 +527,14 @@ status_t AudioHardware::setParameters(const String8& keyValuePairs) // fm radio on key = String8(AudioParameter::keyFmOn); if (param.get(key, value) == NO_ERROR) { - LOGV("AudioHardware::setParameters() Turning FM Radio ON"); - if (mMixer == NULL) { - openPcmOut_l(); - openMixer_l(); - setInputSource_l(AUDIO_SOURCE_DEFAULT); - } - if (mMixer != NULL) { - LOGV("AudioHardware::setParameters() FM Radio is ON, calling setFMRadioPath_l()"); - setFMRadioPath_l(mOutput->device()); - } - - if (mFmFd < 0) { - mFmFd = open("/dev/radio0", O_RDWR); - } + enableFMRadio(); } param.remove(key); // fm radio off key = String8(AudioParameter::keyFmOff); if (param.get(key, value) == NO_ERROR) { - LOGV("AudioHardware::setParameters() Turning FM Radio OFF"); - - if (mMixer != NULL) { - // Disable FM radio flag to allow the codec to be turned off - // (the flag is automatically set by the kernel driver when FM is enabled) - // No need to turn off the FM Radio path as the kernel driver will handle that - TRACE_DRIVER_IN(DRV_MIXER_GET) - struct mixer_ctl *ctl = mixer_get_control(mMixer, "Codec Status", 0); - TRACE_DRIVER_OUT - - if (ctl != NULL) { - TRACE_DRIVER_IN(DRV_MIXER_SEL) - mixer_ctl_select(ctl, "FMR_FLAG_CLEAR"); - TRACE_DRIVER_OUT - } - - closeMixer_l(); - closePcmOut_l(); - } - - if (mFmFd > 0) { - close(mFmFd); - mFmFd = -1; - } + disableFMRadio(); } param.remove(key); #endif @@ -817,6 +788,56 @@ status_t AudioHardware::setIncallPath_l(uint32_t device) } #ifdef HAVE_FM_RADIO +void AudioHardware::enableFMRadio() { + LOGV("AudioHardware::enableFMRadio() Turning FM Radio ON"); + + if (mMode == AudioSystem::MODE_IN_CALL) { + LOGV("AudioHardware::enableFMRadio() Call is active. Delaying FM enable."); + mFmResumeAfterCall = true; + } + else { + openPcmOut_l(); + openMixer_l(); + setInputSource_l(AUDIO_SOURCE_DEFAULT); + + if (mMixer != NULL) { + LOGV("AudioHardware::enableFMRadio() FM Radio is ON, calling setFMRadioPath_l()"); + setFMRadioPath_l(mOutput->device()); + } + + if (mFmFd < 0) { + mFmFd = open("/dev/radio0", O_RDWR); + } + } +} + +void AudioHardware::disableFMRadio() { + LOGV("AudioHardware::disableFMRadio() Turning FM Radio OFF"); + + if (mMixer != NULL) { + // Disable FM radio flag to allow the codec to be turned off + // (the flag is automatically set by the kernel driver when FM is enabled) + // No need to turn off the FM Radio path as the kernel driver will handle that + TRACE_DRIVER_IN(DRV_MIXER_GET) + struct mixer_ctl *ctl = mixer_get_control(mMixer, "Codec Status", 0); + TRACE_DRIVER_OUT + + if (ctl != NULL) { + TRACE_DRIVER_IN(DRV_MIXER_SEL) + mixer_ctl_select(ctl, "FMR_FLAG_CLEAR"); + TRACE_DRIVER_OUT + } + + closeMixer_l(); + closePcmOut_l(); + } + + if (mFmFd > 0) { + close(mFmFd); + mFmFd = -1; + } +} + status_t AudioHardware::setFMRadioPath_l(uint32_t device) { LOGV("setFMRadioPath_l() device %x", device); @@ -824,6 +845,15 @@ status_t AudioHardware::setFMRadioPath_l(uint32_t device) AudioPath path; const char *fmpath; + if (device != AudioSystem::DEVICE_OUT_SPEAKER && (device & AudioSystem::DEVICE_OUT_SPEAKER) != 0) { + /* Fix the case where we're on headset and the system has just played a + * notification sound to both the speaker and the headset. The device + * now is an ORed value and we need to get back its original value. + */ + device -= AudioSystem::DEVICE_OUT_SPEAKER; + LOGD("setFMRadioPath_l() device removed speaker %x", device); + } + switch(device){ case AudioSystem::DEVICE_OUT_SPEAKER: LOGD("setFMRadioPath_l() fmradio speaker route"); diff --git a/libaudio/AudioHardware.h b/libaudio/AudioHardware.h index b50e273..2a1f6c7 100644 --- a/libaudio/AudioHardware.h +++ b/libaudio/AudioHardware.h @@ -121,6 +121,8 @@ public: status_t setIncallPath_l(uint32_t device); #ifdef HAVE_FM_RADIO + void enableFMRadio(); + void disableFMRadio(); status_t setFMRadioPath_l(uint32_t device); #endif @@ -182,6 +184,7 @@ private: #ifdef HAVE_FM_RADIO int mFmFd; + bool mFmResumeAfterCall; #endif // trace driver operations for dump -- cgit v1.1