Loading services/radio/Android.mk +1 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ LOCAL_SHARED_LIBRARIES:= \ libutils \ libbinder \ libcutils \ libmedia \ libhardware \ libradio \ libradio_metadata Loading services/radio/RadioService.cpp +75 −19 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -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) Loading Loading @@ -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); } Loading Loading @@ -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) { } Loading Loading @@ -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; Loading @@ -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(), Loading @@ -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()); Loading Loading @@ -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) { Loading Loading @@ -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, ""); } } } Loading Loading @@ -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" Loading services/radio/RadioService.h +25 −23 Original line number Diff line number Diff line Loading @@ -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(); Loading @@ -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 { Loading @@ -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, Loading Loading @@ -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 Loading @@ -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; }; Loading Loading
services/radio/Android.mk +1 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ LOCAL_SHARED_LIBRARIES:= \ libutils \ libbinder \ libcutils \ libmedia \ libhardware \ libradio \ libradio_metadata Loading
services/radio/RadioService.cpp +75 −19 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -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) Loading Loading @@ -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); } Loading Loading @@ -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) { } Loading Loading @@ -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; Loading @@ -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(), Loading @@ -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()); Loading Loading @@ -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) { Loading Loading @@ -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, ""); } } } Loading Loading @@ -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" Loading
services/radio/RadioService.h +25 −23 Original line number Diff line number Diff line Loading @@ -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(); Loading @@ -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 { Loading @@ -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, Loading Loading @@ -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 Loading @@ -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; }; Loading