Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1c15c670 authored by Eric Laurent's avatar Eric Laurent Committed by Android (Google) Code Review
Browse files

Merge "audio routing management for radio"

parents ae21e335 53810823
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ LOCAL_SHARED_LIBRARIES:= \
    libutils \
    libbinder \
    libcutils \
    libmedia \
    libhardware \
    libradio \
    libradio_metadata
+75 −19
Original line number Diff line number Diff line
@@ -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"

+25 −23
Original line number Diff line number Diff line
@@ -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;
};