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

Commit eafff459 authored by Eric Laurent's avatar Eric Laurent
Browse files

Issue 2667801: [Audio Effect Framework] AudioFlinger, AudioMixer AudioTrack modifications.

First drop of audio framework modifications for audio effects support.

- AudioTrack/AudioRecord:
Added support for auxiliary effects in AudioTrack
Added support for audio sessions
Fixed left right channel inversion in setVolume()

- IAudioFlinger:
Added interface methods for effect enumeraiton and instantiation
Added support for audio sessions.

- IAudioTrack:
Added method to attach auxiliary effect.

- AudioFlinger
Created new classes to control effect engines in effect library and manage effect connections to tracks or
output mix:
  EffectModule: wrapper object controlling the effect engine implementation in the effect library. There
	is one EffectModule per instance of an effect in a given audio session
  EffectChain: group of effects associated to one audio session. There is one EffectChain per audio session.
	EffectChain for session 0 is for output mix effects, other chains are attached to audio tracks
	with same session ID. Each chain contains a variable number of EffectModules
  EffectHandle: implements the IEffect interface. There is one EffectHandle object for each application
	controlling (or using) an effect module. THe EffectModule maintians a list of EffectHandles.

Added support for effect modules and effect chains creation in PlaybackThread.
modified mixer thread loop to allow track volume control by effect modules and call effect processing.

-AudioMixer
Each track now specifies its output buffer used by mixer for accumulation
Modified mixer process functions to process tracks by groups of tracks with same buffer
Modified track process functions to support accumulation to auxiliary channel

Change-Id: I26d5f7c9e070a89bdd383e1a659f8b7ca150379c
parent 5b439d2a
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -87,7 +87,8 @@ LOCAL_SHARED_LIBRARIES := \
    libutils \
    libbinder \
    libmedia \
    libhardware_legacy
    libhardware_legacy \
    libeffects

ifeq ($(strip $(BOARD_USES_GENERIC_AUDIO)),true)
  LOCAL_STATIC_LIBRARIES += libaudiointerface libaudiopolicybase
+1979 −95

File changed.

Preview size limit exceeded, changes collapsed.

+296 −9
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@
namespace android {

class audio_track_cblk_t;
class effect_param_cblk_t;
class AudioMixer;
class AudioBuffer;
class AudioResampler;
@@ -75,6 +76,7 @@ public:
                                uint32_t flags,
                                const sp<IMemory>& sharedBuffer,
                                int output,
                                int *sessionId,
                                status_t *status);

    virtual     uint32_t    sampleRate(int output) const;
@@ -139,6 +141,28 @@ public:

    virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames, int output);

    virtual int newAudioSessionId();

    virtual status_t loadEffectLibrary(const char *libPath, int *handle);

    virtual status_t unloadEffectLibrary(int handle);

    virtual status_t queryNumberEffects(uint32_t *numEffects);

    virtual status_t queryNextEffect(effect_descriptor_t *descriptor);

    virtual status_t getEffectDescriptor(effect_uuid_t *pUuid, effect_descriptor_t *descriptor);

    virtual sp<IEffect> createEffect(pid_t pid,
                        effect_descriptor_t *pDesc,
                        const sp<IEffectClient>& effectClient,
                        int32_t priority,
                        int output,
                        int sessionId,
                        status_t *status,
                        int *id,
                        int *enabled);

    enum hardware_call_state {
        AUDIO_HW_IDLE = 0,
        AUDIO_HW_INIT,
@@ -167,6 +191,7 @@ public:
                                int channelCount,
                                int frameCount,
                                uint32_t flags,
                                int *sessionId,
                                status_t *status);

    virtual     status_t    onTransact(
@@ -233,6 +258,9 @@ private:
    class DuplicatingThread;
    class Track;
    class RecordTrack;
    class EffectModule;
    class EffectHandle;
    class EffectChain;

    class ThreadBase : public Thread {
    public:
@@ -268,13 +296,15 @@ private:
                                        int channelCount,
                                        int frameCount,
                                        uint32_t flags,
                                        const sp<IMemory>& sharedBuffer);
                                        const sp<IMemory>& sharedBuffer,
                                        int sessionId);
                                ~TrackBase();

            virtual status_t    start() = 0;
            virtual void        stop() = 0;
                    sp<IMemory> getCblk() const;
                    audio_track_cblk_t* cblk() const { return mCblk; }
                    int         sessionId() { return mSessionId; }

        protected:
            friend class ThreadBase;
@@ -323,6 +353,7 @@ private:
            int                 mClientTid;
            uint8_t             mFormat;
            uint32_t            mFlags;
            int                 mSessionId;
        };

        class ConfigEvent {
@@ -405,7 +436,8 @@ private:
                                        int format,
                                        int channelCount,
                                        int frameCount,
                                        const sp<IMemory>& sharedBuffer);
                                        const sp<IMemory>& sharedBuffer,
                                        int sessionId);
                                ~Track();

                    void        dump(char* buffer, size_t size);
@@ -424,6 +456,12 @@ private:
                    int type() const {
                        return mStreamType;
                    }
                    status_t    attachAuxEffect(int EffectId);
                    void        setAuxBuffer(int EffectId, int32_t *buffer);
                    int32_t     *auxBuffer() { return mAuxBuffer; }
                    void        setMainBuffer(int16_t *buffer) { mMainBuffer = buffer; }
                    int16_t     *mainBuffer() { return mMainBuffer; }
                    int         auxEffectId() { return mAuxEffectId; }


        protected:
@@ -464,6 +502,9 @@ private:
            bool                mResetDone;
            int                 mStreamType;
            int                 mName;
            int16_t             *mMainBuffer;
            int32_t             *mAuxBuffer;
            int                 mAuxEffectId;
        };  // end of Track


@@ -505,7 +546,7 @@ private:
            DuplicatingThread*          mSourceThread;
        };  // end of OutputTrack

        PlaybackThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id);
        PlaybackThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device);
        virtual             ~PlaybackThread();

        virtual     status_t    dump(int fd, const Vector<String16>& args);
@@ -538,6 +579,7 @@ private:
                                    int channelCount,
                                    int frameCount,
                                    const sp<IMemory>& sharedBuffer,
                                    int sessionId,
                                    status_t *status);

                    AudioStreamOut* getOutput() { return mOutput; }
@@ -549,6 +591,29 @@ private:
        virtual     String8     getParameters(const String8& keys);
        virtual     void        audioConfigChanged_l(int event, int param = 0);
        virtual     status_t    getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames);
                    int16_t     *mixBuffer() { return mMixBuffer; };

                    sp<EffectHandle> createEffect_l(
                                        const sp<AudioFlinger::Client>& client,
                                        const sp<IEffectClient>& effectClient,
                                        int32_t priority,
                                        int sessionId,
                                        effect_descriptor_t *desc,
                                        int *enabled,
                                        status_t *status);

                    bool hasAudioSession(int sessionId);
                    sp<EffectChain> getEffectChain(int sessionId);
                    sp<EffectChain> getEffectChain_l(int sessionId);
                    status_t addEffectChain_l(const sp<EffectChain>& chain);
                    size_t removeEffectChain_l(const sp<EffectChain>& chain);
                    void lockEffectChains_l();
                    void unlockEffectChains();

                    sp<AudioFlinger::EffectModule> getEffect_l(int sessionId, int effectId);
                    void detachAuxEffect_l(int effectId);
                    status_t attachAuxEffect(const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId);
                    status_t attachAuxEffect_l(const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId);

        struct  stream_type_t {
            stream_type_t()
@@ -591,8 +656,11 @@ private:

        void        readOutputParameters();

        uint32_t    device() { return mDevice; }

        virtual status_t    dumpInternals(int fd, const Vector<String16>& args);
        status_t    dumpTracks(int fd, const Vector<String16>& args);
        status_t    dumpEffectChains(int fd, const Vector<String16>& args);

        SortedVector< sp<Track> >       mTracks;
        // mStreamTypes[] uses 1 additionnal stream type internally for the OutputTrack used by DuplicatingThread
@@ -603,11 +671,13 @@ private:
        int                             mNumWrites;
        int                             mNumDelayedWrites;
        bool                            mInWrite;
        Vector< sp<EffectChain> >       mEffectChains;
        uint32_t                        mDevice;
    };

    class MixerThread : public PlaybackThread {
    public:
        MixerThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id);
        MixerThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device);
        virtual             ~MixerThread();

        // Thread virtuals
@@ -630,7 +700,7 @@ private:
    class DirectOutputThread : public PlaybackThread {
    public:

        DirectOutputThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id);
        DirectOutputThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device);
        ~DirectOutputThread();

        // Thread virtuals
@@ -645,8 +715,12 @@ private:
        virtual     uint32_t    idleSleepTimeUs();

    private:
        float mLeftVolume;
        float mRightVolume;
        void applyVolume(uint16_t leftVol, uint16_t rightVol, bool ramp);

        float mLeftVolFloat;
        float mRightVolFloat;
        uint16_t mLeftVolShort;
        uint16_t mRightVolShort;
    };

    class DuplicatingThread : public MixerThread {
@@ -676,6 +750,8 @@ private:
              float streamVolumeInternal(int stream) const { return mStreamTypes[stream].volume; }
              void audioConfigChanged_l(int event, int ioHandle, void *param2);

              int  nextUniqueId();

    friend class AudioBuffer;

    class TrackHandle : public android::BnAudioTrack {
@@ -689,6 +765,7 @@ private:
        virtual void        pause();
        virtual void        setVolume(float left, float right);
        virtual sp<IMemory> getCblk() const;
        virtual status_t    attachAuxEffect(int effectId);
        virtual status_t onTransact(
            uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
    private:
@@ -717,7 +794,8 @@ private:
                                        int format,
                                        int channelCount,
                                        int frameCount,
                                        uint32_t flags);
                                        uint32_t flags,
                                        int sessionId);
                                ~RecordTrack();

            virtual status_t    start();
@@ -792,6 +870,215 @@ private:
        sp<RecordThread::RecordTrack> mRecordTrack;
    };

    //--- Audio Effect Management

    // EffectModule and EffectChain classes both have their own mutex to protect
    // state changes or resource modifications. Always respect the following order
    // if multiple mutexes must be acquired to avoid cross deadlock:
    // AudioFlinger -> ThreadBase -> EffectChain -> EffectModule

    // The EffectModule class is a wrapper object controlling the effect engine implementation
    // in the effect library. It prevents concurrent calls to process() and command() functions
    // from different client threads. It keeps a list of EffectHandle objects corresponding
    // to all client applications using this effect and notifies applications of effect state,
    // control or parameter changes. It manages the activation state machine to send appropriate
    // reset, enable, disable commands to effect engine and provide volume
    // ramping when effects are activated/deactivated.
    // When controlling an auxiliary effect, the EffectModule also provides an input buffer used by
    // the attached track(s) to accumulate their auxiliary channel.
    class EffectModule: public RefBase {
    public:
        EffectModule(const wp<ThreadBase>& wThread,
                        const wp<AudioFlinger::EffectChain>& chain,
                        effect_descriptor_t *desc,
                        int id,
                        int sessionId);
        ~EffectModule();

        enum effect_state {
            IDLE,
            RESET,
            STARTING,
            ACTIVE,
            STOPPING,
            STOPPED
        };

        int         id() { return mId; }
        void process();
        status_t command(int cmdCode, int cmdSize, void *pCmdData, int *replySize, void *pReplyData);

        void reset();
        status_t configure();
        status_t init();
        uint32_t state() {
            return mState;
        }
        uint32_t status() {
            return mStatus;
        }
        status_t    setEnabled(bool enabled);
        bool isEnabled();

        void        setInBuffer(int16_t *buffer) { mConfig.inputCfg.buffer.s16 = buffer; }
        int16_t     *inBuffer() { return mConfig.inputCfg.buffer.s16; }
        void        setOutBuffer(int16_t *buffer) { mConfig.outputCfg.buffer.s16 = buffer; }
        int16_t     *outBuffer() { return mConfig.outputCfg.buffer.s16; }

        status_t addHandle(sp<EffectHandle>& handle);
        void disconnect(const wp<EffectHandle>& handle);
        size_t removeHandle (const wp<EffectHandle>& handle);

        effect_descriptor_t& desc() { return mDescriptor; }

        status_t         setDevice(uint32_t device);
        status_t         setVolume(uint32_t *left, uint32_t *right, bool controller);

        status_t         dump(int fd, const Vector<String16>& args);

    protected:

        EffectModule(const EffectModule&);
        EffectModule& operator = (const EffectModule&);

        status_t start();
        status_t stop();

        Mutex               mLock;      // mutex for process, commands and handles list protection
        wp<ThreadBase>      mThread;    // parent thread
        wp<EffectChain>     mChain;     // parent effect chain
        int                 mId;        // this instance unique ID
        int                 mSessionId; // audio session ID
        effect_descriptor_t mDescriptor;// effect descriptor received from effect engine
        effect_config_t     mConfig;    // input and output audio configuration
        effect_interface_t  mEffectInterface; // Effect module C API
        status_t mStatus;               // initialization status
        uint32_t mState;                // current activation state (effect_state)
        Vector< wp<EffectHandle> > mHandles;    // list of client handles
    };

    // The EffectHandle class implements the IEffect interface. It provides resources
    // to receive parameter updates, keeps track of effect control
    // ownership and state and has a pointer to the EffectModule object it is controlling.
    // There is one EffectHandle object for each application controlling (or using)
    // an effect module.
    // The EffectHandle is obtained by calling AudioFlinger::createEffect().
    class EffectHandle: public android::BnEffect {
    public:

        EffectHandle(const sp<EffectModule>& effect,
                const sp<AudioFlinger::Client>& client,
                const sp<IEffectClient>& effectClient,
                int32_t priority);
        virtual ~EffectHandle();

        // IEffect
        virtual status_t enable();
        virtual status_t disable();
        virtual status_t command(int cmdCode, int cmdSize, void *pCmdData, int *replySize, void *pReplyData);
        virtual void disconnect();
        virtual sp<IMemory> getCblk() const;
        virtual status_t onTransact(uint32_t code, const Parcel& data,
                Parcel* reply, uint32_t flags);


        // Give or take control of effect module
        void setControl(bool hasControl, bool signal);
        void commandExecuted(int cmdCode, int cmdSize, void *pCmdData, int replySize, void *pReplyData);
        void setEnabled(bool enabled);

        // Getters
        int id() { return mEffect->id(); }
        int priority() { return mPriority; }
        bool hasControl() { return mHasControl; }
        sp<EffectModule> effect() { return mEffect; }

        void dump(char* buffer, size_t size);

    protected:

        EffectHandle(const EffectHandle&);
        EffectHandle& operator =(const EffectHandle&);

        sp<EffectModule> mEffect;           // pointer to controlled EffectModule
        sp<IEffectClient> mEffectClient;    // callback interface for client notifications
        sp<Client>          mClient;        // client for shared memory allocation
        sp<IMemory>         mCblkMemory;    // shared memory for control block
        effect_param_cblk_t* mCblk;         // control block for deferred parameter setting via shared memory
        uint8_t*            mBuffer;        // pointer to parameter area in shared memory
        int mPriority;                      // client application priority to control the effect
        bool mHasControl;                   // true if this handle is controlling the effect
    };

    // the EffectChain class represents a group of effects associated to one audio session.
    // There can be any number of EffectChain objects per output mixer thread (PlaybackThread).
    // The EffecChain with session ID 0 contains global effects applied to the output mix.
    // Effects in this chain can be insert or auxiliary. Effects in other chains (attached to tracks)
    // are insert only. The EffectChain maintains an ordered list of effect module, the order corresponding
    // in the effect process order. When attached to a track (session ID != 0), it also provide it's own
    // input buffer used by the track as accumulation buffer.
    class EffectChain: public RefBase {
    public:
        EffectChain(const wp<ThreadBase>& wThread, int sessionId);
        ~EffectChain();

        void process_l();

        void lock() {
            mLock.lock();
        }
        void unlock() {
            mLock.unlock();
        }

        status_t addEffect(sp<EffectModule>& handle);
        size_t removeEffect(const sp<EffectModule>& handle);

        int sessionId() {
            return mSessionId;
        }
        sp<EffectModule> getEffectFromDesc(effect_descriptor_t *descriptor);
        sp<EffectModule> getEffectFromId(int id);
        sp<EffectModule> getVolumeController();
        bool setVolume(uint32_t *left, uint32_t *right);
        void setDevice(uint32_t device);

        void setInBuffer(int16_t *buffer, bool ownsBuffer = false) {
            mInBuffer = buffer;
            mOwnInBuffer = ownsBuffer;
        }
        int16_t *inBuffer() {
            return mInBuffer;
        }
        void setOutBuffer(int16_t *buffer) {
            mOutBuffer = buffer;
        }
        int16_t *outBuffer() {
            return mOutBuffer;
        }

        void startTrack() {mActiveTrackCnt++;}
        void stopTrack() {mActiveTrackCnt--;}
        int activeTracks() { return mActiveTrackCnt;}

        status_t dump(int fd, const Vector<String16>& args);

    protected:

        EffectChain(const EffectChain&);
        EffectChain& operator =(const EffectChain&);

        wp<ThreadBase> mThread;     // parent mixer thread
        Mutex mLock;                // mutex protecting effect list
        Vector<sp<EffectModule> > mEffects; // list of effect modules
        int mSessionId;             // audio session ID
        int16_t *mInBuffer;         // chain input buffer
        int16_t *mOutBuffer;        // chain output buffer
        int mVolumeCtrlIdx;         // index of insert effect having control over volume
        int mActiveTrackCnt;        // number of active tracks connected
        bool mOwnInBuffer;          // true if the chain owns its input buffer
    };

    friend class RecordThread;
    friend class PlaybackThread;

@@ -813,7 +1100,7 @@ private:
                DefaultKeyedVector< int, sp<RecordThread> >    mRecordThreads;

                DefaultKeyedVector< pid_t, sp<NotificationClient> >    mNotificationClients;
                int                                 mNextThreadId;
                volatile int32_t                    mNextUniqueId;
#ifdef LVMX
                int mLifeVibesClientPid;
#endif
+487 −207

File changed.

Preview size limit exceeded, changes collapsed.

+32 −18
Original line number Diff line number Diff line
@@ -63,11 +63,14 @@ public:
        // for target TRACK
        CHANNEL_COUNT   = 0x4000,
        FORMAT          = 0x4001,
        MAIN_BUFFER     = 0x4002,
        AUX_BUFFER      = 0x4003,
        // for TARGET RESAMPLE
        SAMPLE_RATE     = 0x4100,
        // for TARGET VOLUME (8 channels max)
        VOLUME0         = 0x4200,
        VOLUME1         = 0x4201,
        AUXLEVEL        = 0x4210,
    };


@@ -78,10 +81,10 @@ public:
    status_t    disable(int name);

    status_t    setActiveTrack(int track);
    status_t    setParameter(int target, int name, int value);
    status_t    setParameter(int target, int name, void *value);

    status_t    setBufferProvider(AudioBufferProvider* bufferProvider);
    void        process(void* output);
    void        process();

    uint32_t    trackNames() const { return mTrackNames; }

@@ -94,6 +97,7 @@ private:
        NEEDS_FORMAT__MASK          = 0x000000F0,
        NEEDS_MUTE__MASK            = 0x00000100,
        NEEDS_RESAMPLE__MASK        = 0x00001000,
        NEEDS_AUX__MASK             = 0x00010000,
    };

    enum {
@@ -107,6 +111,9 @@ private:

        NEEDS_RESAMPLE_DISABLED     = 0x00000000,
        NEEDS_RESAMPLE_ENABLED      = 0x00001000,

        NEEDS_AUX_DISABLED     = 0x00000000,
        NEEDS_AUX_ENABLED      = 0x00010000,
    };

    static inline int32_t applyVolume(int32_t in, int32_t v) {
@@ -115,9 +122,10 @@ private:


    struct state_t;
    struct track_t;

    typedef void (*mix_t)(state_t* state, void* output);

    typedef void (*mix_t)(state_t* state);
    typedef void (*hook_t)(track_t* t, int32_t* output, size_t numOutFrames, int32_t* temp, int32_t* aux);
    static const int BLOCKSIZE = 16; // 4 cache lines

    struct track_t {
@@ -131,6 +139,9 @@ private:
        int32_t     prevVolume[2];

        int32_t     volumeInc[2];
        int32_t     auxLevel;
        int32_t     auxInc;
        int32_t     prevAuxLevel;

        uint16_t    frameCount;

@@ -142,15 +153,17 @@ private:
        AudioBufferProvider*                bufferProvider;
        mutable AudioBufferProvider::Buffer buffer;

        void (*hook)(track_t* t, int32_t* output, size_t numOutFrames, int32_t* temp);
        hook_t      hook;
        void const* in;             // current location in buffer

        AudioResampler*     resampler;
        uint32_t            sampleRate;
        int32_t*           mainBuffer;
        int32_t*           auxBuffer;

        bool        setResampler(uint32_t sampleRate, uint32_t devSampleRate);
        bool        doesResample() const;
        void        adjustVolumeRamp();
        void        adjustVolumeRamp(bool aux);
    };

    // pad to 32-bytes to fill cache line
@@ -173,18 +186,19 @@ private:

    void invalidateState(uint32_t mask);

    static void track__genericResample(track_t* t, int32_t* out, size_t numFrames, int32_t* temp);
    static void track__nop(track_t* t, int32_t* out, size_t numFrames, int32_t* temp);
    static void volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp);
    static void track__16BitsStereo(track_t* t, int32_t* out, size_t numFrames, int32_t* temp);
    static void track__16BitsMono(track_t* t, int32_t* out, size_t numFrames, int32_t* temp);

    static void process__validate(state_t* state, void* output);
    static void process__nop(state_t* state, void* output);
    static void process__genericNoResampling(state_t* state, void* output);
    static void process__genericResampling(state_t* state, void* output);
    static void process__OneTrack16BitsStereoNoResampling(state_t* state, void* output);
    static void process__TwoTracks16BitsStereoNoResampling(state_t* state, void* output);
    static void track__genericResample(track_t* t, int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux);
    static void track__nop(track_t* t, int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux);
    static void track__16BitsStereo(track_t* t, int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux);
    static void track__16BitsMono(track_t* t, int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux);
    static void volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux);
    static void volumeStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux);

    static void process__validate(state_t* state);
    static void process__nop(state_t* state);
    static void process__genericNoResampling(state_t* state);
    static void process__genericResampling(state_t* state);
    static void process__OneTrack16BitsStereoNoResampling(state_t* state);
    static void process__TwoTracks16BitsStereoNoResampling(state_t* state);
};

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