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

Commit 5120edaa authored by Ytai Ben-Tsvi's avatar Ytai Ben-Tsvi
Browse files

Expose capture state listener in AudioSystem

This is a client-side wrapper around the respective feature of APS.

Bug: 146157104
Test: Manual verification of proper behavior when starting/stopping
      recording, killing of audio server, by examination of the logs.
Merged-In: I9b56c431f69e77683151de19830ec6f45741dd6f
Change-Id: I1f5279c4a4b18e0a7862d3b103d383ac3de4c9a0
parent 85093d5e
Loading
Loading
Loading
Loading
+48 −0
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@
//#define LOG_NDEBUG 0

#include <utils/Log.h>

#include <android/media/BnCaptureStateListener.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include <binder/IPCThreadState.h>
@@ -44,6 +46,10 @@ std::set<audio_error_callback> AudioSystem::gAudioErrorCallbacks;
dynamic_policy_callback AudioSystem::gDynPolicyCallback = NULL;
record_config_callback AudioSystem::gRecordConfigCallback = NULL;

// Required to be held while calling into gSoundTriggerCaptureStateListener.
Mutex gSoundTriggerCaptureStateListenerLock;
sp<AudioSystem::CaptureStateListener> gSoundTriggerCaptureStateListener = nullptr;

// establish binder interface to AudioFlinger service
const sp<IAudioFlinger> AudioSystem::get_audio_flinger()
{
@@ -1623,6 +1629,48 @@ status_t AudioSystem::getPreferredDeviceForStrategy(product_strategy_t strategy,
    return aps->getPreferredDeviceForStrategy(strategy, device);
}

class CaptureStateListenerImpl : public media::BnCaptureStateListener,
                                 public IBinder::DeathRecipient {
public:
    binder::Status setCaptureState(bool active) override {
        Mutex::Autolock _l(gSoundTriggerCaptureStateListenerLock);
        gSoundTriggerCaptureStateListener->onStateChanged(active);
        return binder::Status::ok();
    }

    void binderDied(const wp<IBinder>&) override {
        Mutex::Autolock _l(gSoundTriggerCaptureStateListenerLock);
        gSoundTriggerCaptureStateListener->onServiceDied();
        gSoundTriggerCaptureStateListener = nullptr;
    }
};

status_t AudioSystem::registerSoundTriggerCaptureStateListener(
    const sp<CaptureStateListener>& listener) {
    const sp<IAudioPolicyService>& aps =
            AudioSystem::get_audio_policy_service();
    if (aps == 0) {
        return PERMISSION_DENIED;
    }

    sp<CaptureStateListenerImpl> wrapper = new CaptureStateListenerImpl();

    Mutex::Autolock _l(gSoundTriggerCaptureStateListenerLock);

    bool active;
    status_t status =
        aps->registerSoundTriggerCaptureStateListener(wrapper, &active);
    if (status != NO_ERROR) {
        listener->onServiceDied();
        return NO_ERROR;
    }
    gSoundTriggerCaptureStateListener = listener;
    listener->onStateChanged(active);
    sp<IBinder> binder = IInterface::asBinder(aps);
    binder->linkToDeath(wrapper);
    return NO_ERROR;
}

// ---------------------------------------------------------------------------

int AudioSystem::AudioPolicyServiceClient::addAudioPortCallback(
+24 −0
Original line number Diff line number Diff line
@@ -436,6 +436,30 @@ public:
    static status_t getDeviceForStrategy(product_strategy_t strategy,
            AudioDeviceTypeAddr &device);

    // A listener for capture state changes.
    class CaptureStateListener : public RefBase {
    public:
        // Called whenever capture state changes.
        virtual void onStateChanged(bool active) = 0;
        // Called whenever the service dies (and hence our listener is no longer
        // registered).
        virtual void onServiceDied() = 0;

        virtual ~CaptureStateListener() = default;
    };

    // Regiseters a listener for sound trigger capture state changes.
    // There may only be one such listener registered at any point.
    // The listener onStateChanged() method will be invoked sychronously from
    // this call with the initial value.
    // The listener onServiceDied() method will be invoked sychronously from
    // this call if initial attempt to register failed.
    // If the audio policy service cannot be reached, this method will return
    // PERMISSION_DENIED and will not invoke the callback, otherwise, it will
    // return NO_ERROR.
    static status_t registerSoundTriggerCaptureStateListener(
            const sp<CaptureStateListener>& listener);

    // ----------------------------------------------------------------------------

    class AudioVolumeGroupCallback : public RefBase