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;  };  | 
