diff options
author | Eric Laurent <elaurent@google.com> | 2015-03-12 09:12:01 -0700 |
---|---|---|
committer | Eric Laurent <elaurent@google.com> | 2015-03-19 10:53:21 -0700 |
commit | 53810823a6613f54fc0b3c3bc0de267dc1f4e1e5 (patch) | |
tree | e65a116aa468a5dd5f1e60fc5ca4a84f949b3714 /services/radio | |
parent | b89b86d48cd5a6258e24fefd0eab888062cbdfb0 (diff) | |
download | frameworks_av-53810823a6613f54fc0b3c3bc0de267dc1f4e1e5.zip frameworks_av-53810823a6613f54fc0b3c3bc0de267dc1f4e1e5.tar.gz frameworks_av-53810823a6613f54fc0b3c3bc0de267dc1f4e1e5.tar.bz2 |
audio routing management for radio
Added radio tuner device connection/disconnection
indication to audio policy manager.
Added documentation and removed unused Module
class member.
Change-Id: I92438c1ff212c4d76f008149554fa89e367fee42
Diffstat (limited to 'services/radio')
-rw-r--r-- | services/radio/Android.mk | 1 | ||||
-rw-r--r-- | services/radio/RadioService.cpp | 94 | ||||
-rw-r--r-- | services/radio/RadioService.h | 48 |
3 files changed, 101 insertions, 42 deletions
diff --git a/services/radio/Android.mk b/services/radio/Android.mk index 5e89b22..9ee5666 100644 --- a/services/radio/Android.mk +++ b/services/radio/Android.mk @@ -26,6 +26,7 @@ LOCAL_SHARED_LIBRARIES:= \ libutils \ libbinder \ libcutils \ + libmedia \ libhardware \ libradio \ libradio_metadata diff --git a/services/radio/RadioService.cpp b/services/radio/RadioService.cpp index 152619b..a6c2bdf 100644 --- a/services/radio/RadioService.cpp +++ b/services/radio/RadioService.cpp @@ -22,6 +22,8 @@ #include <sys/types.h> #include <pthread.h> +#include <system/audio.h> +#include <system/audio_policy.h> #include <system/radio.h> #include <system/radio_metadata.h> #include <cutils/atomic.h> @@ -33,11 +35,13 @@ #include <binder/MemoryBase.h> #include <binder/MemoryHeapBase.h> #include <hardware/radio.h> +#include <media/AudioSystem.h> #include "RadioService.h" #include "RadioRegions.h" namespace android { +static const char kRadioTunerAudioDeviceName[] = "Radio tuner source"; RadioService::RadioService() : BnRadioService(), mNextUniqueId(1) @@ -84,7 +88,7 @@ void RadioService::onFirstRef() ALOGI("loaded default module %s, handle %d", properties.product, properties.handle); convertProperties(&properties, &halProperties); - sp<Module> module = new Module(this, dev, properties); + sp<Module> module = new Module(dev, properties); mModules.add(properties.handle, module); } @@ -380,10 +384,8 @@ void RadioService::CallbackThread::sendEvent(radio_hal_event_t *event) #undef LOG_TAG #define LOG_TAG "RadioService::Module" -RadioService::Module::Module(const sp<RadioService>& service, - radio_hw_device* hwDevice, - radio_properties properties) - : mService(service), mHwDevice(hwDevice), mProperties(properties), mMute(true) +RadioService::Module::Module(radio_hw_device* hwDevice, radio_properties properties) + : mHwDevice(hwDevice), mProperties(properties), mMute(true) { } @@ -416,6 +418,31 @@ sp<RadioService::ModuleClient> RadioService::Module::addClient(const sp<IRadioCl struct radio_hal_band_config halConfig; halConfig = config->band; + // Tuner preemption logic: + // There is a limited amount of tuners and a limited amount of radio audio sources per module. + // The minimum is one tuner and one audio source. + // The numbers of tuners and sources are indicated in the module properties. + // NOTE: current framework implementation only supports one radio audio source. + // It is possible to open more than one tuner at a time but only one tuner can be connected + // to the radio audio source (AUDIO_DEVICE_IN_FM_TUNER). + // The base rule is that a newly connected tuner always wins, i.e. always gets a tuner + // and can use the audio source if requested. + // If another client is preempted, it is notified by a callback with RADIO_EVENT_CONTROL + // indicating loss of control. + // - If the newly connected client requests the audio source (audio == true): + // - if an audio source is available + // no problem + // - if not: + // the oldest client in the list using audio is preempted. + // - If the newly connected client does not request the audio source (audio == false): + // - if a tuner is available + // no problem + // - if not: + // The oldest client not using audio is preempted first and if none is found the + // the oldest client using audio is preempted. + // Each time a tuner using the audio source is opened or closed, the audio policy manager is + // notified of the connection or disconnection of AUDIO_DEVICE_IN_FM_TUNER. + sp<ModuleClient> oldestTuner; sp<ModuleClient> oldestAudio; size_t allocatedTuners = 0; @@ -437,28 +464,31 @@ sp<RadioService::ModuleClient> RadioService::Module::addClient(const sp<IRadioCl } const struct radio_tuner *halTuner; + sp<ModuleClient> preemtedClient; if (audio) { if (allocatedAudio >= mProperties.num_audio_sources) { ALOG_ASSERT(oldestAudio != 0, "addClient() allocatedAudio/oldestAudio mismatch"); - halTuner = oldestAudio->getTuner(); - oldestAudio->setTuner(NULL); - mHwDevice->close_tuner(mHwDevice, halTuner); + preemtedClient = oldestAudio; } } else { if (allocatedAudio + allocatedTuners >= mProperties.num_tuners) { if (allocatedTuners != 0) { ALOG_ASSERT(oldestTuner != 0, "addClient() allocatedTuners/oldestTuner mismatch"); - halTuner = oldestTuner->getTuner(); - oldestTuner->setTuner(NULL); - mHwDevice->close_tuner(mHwDevice, halTuner); + preemtedClient = oldestTuner; } else { ALOG_ASSERT(oldestAudio != 0, "addClient() allocatedAudio/oldestAudio mismatch"); - halTuner = oldestAudio->getTuner(); - oldestAudio->setTuner(NULL); - mHwDevice->close_tuner(mHwDevice, halTuner); + preemtedClient = oldestAudio; } } } + if (preemtedClient != 0) { + halTuner = preemtedClient->getTuner(); + preemtedClient->setTuner(NULL); + mHwDevice->close_tuner(mHwDevice, halTuner); + if (preemtedClient->audio()) { + notifyDeviceConnection(false, ""); + } + } ret = mHwDevice->open_tuner(mHwDevice, &halConfig, audio, RadioService::callback, moduleClient->callbackThread().get(), @@ -467,11 +497,13 @@ sp<RadioService::ModuleClient> RadioService::Module::addClient(const sp<IRadioCl ALOGV("addClient() setTuner %p", halTuner); moduleClient->setTuner(halTuner); mModuleClients.add(moduleClient); + if (audio) { + notifyDeviceConnection(true, ""); + } } else { moduleClient.clear(); } - //TODO notify audio device connection to audio policy manager if audio is on ALOGV("addClient() DONE moduleClient %p", moduleClient.get()); @@ -501,19 +533,32 @@ void RadioService::Module::removeClient(const sp<ModuleClient>& moduleClient) { } mHwDevice->close_tuner(mHwDevice, halTuner); + if (moduleClient->audio()) { + notifyDeviceConnection(false, ""); + } - //TODO notify audio device disconnection to audio policy manager if audio was on mMute = true; if (mModuleClients.isEmpty()) { return; } + // Tuner reallocation logic: + // When a client is removed and was controlling a tuner, this tuner will be allocated to a + // previously preempted client. This client will be notified by a callback with + // RADIO_EVENT_CONTROL indicating gain of control. + // - If a preempted client is waiting for an audio source and one becomes available: + // Allocate the tuner to the most recently added client waiting for an audio source + // - If not: + // Allocate the tuner to the most recently added client. + // Each time a tuner using the audio source is opened or closed, the audio policy manager is + // notified of the connection or disconnection of AUDIO_DEVICE_IN_FM_TUNER. + sp<ModuleClient> youngestClient; sp<ModuleClient> youngestClientAudio; size_t allocatedTuners = 0; size_t allocatedAudio = 0; - for (ssize_t i = mModuleClients.size(); i >= 0; i--) { + for (ssize_t i = mModuleClients.size() - 1; i >= 0; i--) { if (mModuleClients[i]->getTuner() == NULL) { if (mModuleClients[i]->audio()) { if (youngestClientAudio == 0) { @@ -550,10 +595,11 @@ void RadioService::Module::removeClient(const sp<ModuleClient>& moduleClient) { RadioService::callback, moduleClient->callbackThread().get(), &halTuner); - //TODO notify audio device connection to audio policy manager if audio is on - if (ret == 0) { youngestClient->setTuner(halTuner); + if (youngestClient->audio()) { + notifyDeviceConnection(true, ""); + } } } @@ -583,6 +629,16 @@ const struct radio_band_config *RadioService::Module::getDefaultConfig() const return &mProperties.bands[0]; } +void RadioService::Module::notifyDeviceConnection(bool connected, + const char *address) { + int64_t token = IPCThreadState::self()->clearCallingIdentity(); + AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_IN_FM_TUNER, + connected ? AUDIO_POLICY_DEVICE_STATE_AVAILABLE : + AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, + address, kRadioTunerAudioDeviceName); + IPCThreadState::self()->restoreCallingIdentity(token); +} + #undef LOG_TAG #define LOG_TAG "RadioService::ModuleClient" diff --git a/services/radio/RadioService.h b/services/radio/RadioService.h index 9ede020..49feda6 100644 --- a/services/radio/RadioService.h +++ b/services/radio/RadioService.h @@ -66,8 +66,7 @@ public: class Module : public virtual RefBase { public: - Module(const sp<RadioService>& service, - radio_hw_device* hwDevice, + Module(radio_hw_device* hwDevice, struct radio_properties properties); virtual ~Module(); @@ -88,16 +87,17 @@ public: const struct radio_properties properties() const { return mProperties; } const struct radio_band_config *getDefaultConfig() const ; - wp<RadioService> service() const { return mService; } - private: - Mutex mLock; - wp<RadioService> mService; - const struct radio_hw_device *mHwDevice; - const struct radio_properties mProperties; - Vector< sp<ModuleClient> > mModuleClients; - bool mMute; + void notifyDeviceConnection(bool connected, const char *address); + + Mutex mLock; // protects mModuleClients + const struct radio_hw_device *mHwDevice; // HAL hardware device + const struct radio_properties mProperties; // cached hardware module properties + Vector< sp<ModuleClient> > mModuleClients; // list of attached clients + bool mMute; // radio audio source state + // when unmuted, audio is routed to the + // output device selected for media use case. }; // class Module class CallbackThread : public Thread { @@ -120,11 +120,11 @@ public: sp<IMemory> prepareEvent(radio_hal_event_t *halEvent); private: - wp<ModuleClient> mModuleClient; - Condition mCallbackCond; - Mutex mCallbackLock; - Vector< sp<IMemory> > mEventQueue; - sp<MemoryDealer> mMemoryDealer; + wp<ModuleClient> mModuleClient; // client module the thread belongs to + Condition mCallbackCond; // condition signaled when a new event is posted + Mutex mCallbackLock; // protects mEventQueue + Vector< sp<IMemory> > mEventQueue; // pending callback events + sp<MemoryDealer> mMemoryDealer; // shared memory for callback event }; // class CallbackThread class ModuleClient : public BnRadio, @@ -181,13 +181,15 @@ public: private: - mutable Mutex mLock; - wp<Module> mModule; - sp<IRadioClient> mClient; - radio_band_config_t mConfig; - sp<CallbackThread> mCallbackThread; + mutable Mutex mLock; // protects mClient, mConfig and mTuner + wp<Module> mModule; // The module this client is attached to + sp<IRadioClient> mClient; // event callback binder interface + radio_band_config_t mConfig; // current band configuration + sp<CallbackThread> mCallbackThread; // event callback thread const bool mAudio; - const struct radio_tuner *mTuner; + const struct radio_tuner *mTuner; // HAL tuner interface. NULL indicates that + // this client does not have control on any + // tuner }; // class ModuleClient @@ -199,8 +201,8 @@ private: static void convertProperties(radio_properties_t *properties, const radio_hal_properties_t *halProperties); - Mutex mServiceLock; - volatile int32_t mNextUniqueId; + Mutex mServiceLock; // protects mModules + volatile int32_t mNextUniqueId; // for module ID allocation DefaultKeyedVector< radio_handle_t, sp<Module> > mModules; }; |