summaryrefslogtreecommitdiffstats
path: root/services/radio
diff options
context:
space:
mode:
authorEric Laurent <elaurent@google.com>2015-03-12 09:12:01 -0700
committerEric Laurent <elaurent@google.com>2015-03-19 10:53:21 -0700
commit53810823a6613f54fc0b3c3bc0de267dc1f4e1e5 (patch)
treee65a116aa468a5dd5f1e60fc5ca4a84f949b3714 /services/radio
parentb89b86d48cd5a6258e24fefd0eab888062cbdfb0 (diff)
downloadframeworks_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.mk1
-rw-r--r--services/radio/RadioService.cpp94
-rw-r--r--services/radio/RadioService.h48
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;
};