/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifdef ANDROID
#include "media/AudioEffect.h"
#include "hardware/audio_effect.h"
#endif

/* Interface structures */

typedef struct Object_interface {
    const struct SLObjectItf_ *mItf;    // const
    // field mThis would be redundant within an IObject, so we substitute mEngine
    CEngine *mEngine;               // const
    const ClassTable *mClass;       // const
    SLuint32 mInstanceID;           // const for debugger and for RPC, 0 means unpublished
    slObjectCallback mCallback;
    void *mContext;
    unsigned mGottenMask;           ///< bit-mask of interfaces exposed or added, then gotten
    unsigned mLossOfControlMask;    // interfaces with loss of control enabled
    unsigned mAttributesMask;       // attributes which have changed since last sync
#if USE_PROFILES & USE_PROFILES_BASE
    SLint32 mPriority;
#endif
    pthread_mutex_t mMutex;
#ifdef USE_DEBUG
    // Only keep the pthread_t, not the kernel tid, because pthread_self() is very fast
    // (typically just arithmetic on the stack pointer). But a gettid() is a kernel call
    // and so too slow to do every time a mutex is acquired. However, we can determine
    // the kernel tid from the pthread_t.
    pthread_t mOwner;
    const char *mFile;
    int mLine;
    volatile int32_t mGeneration;   // read without a lock, incremented with a lock
#endif
    pthread_cond_t mCond;
    SLuint8 mState;                 // really SLuint32, but SLuint8 to save space
#if USE_PROFILES & USE_PROFILES_BASE
    SLuint8 mPreemptable;           // really SLboolean, but SLuint8 to save space
#else
    SLuint8 mPadding;
#endif
    SLuint8 mStrongRefCount;        // number of strong references to this object
    // (object cannot be destroyed as long as > 0, and referrers _prefer_ it stay in Realized state)
    // for best alignment, do not add any fields here
#define INTERFACES_Default 1
    SLuint8 mInterfaceStates[INTERFACES_Default];    // state of each of interface
    // do not add any fields here
} IObject;

#include "locks.h"

typedef struct {
    const struct SL3DCommitItf_ *mItf;
    IObject *mThis;
    SLboolean mDeferred;
    SLuint32 mGeneration;   // incremented each master clock cycle
    SLuint32 mWaiting;      // number of threads waiting in Commit
} I3DCommit;

enum CartesianSphericalActive {
    CARTESIAN_COMPUTED_SPHERICAL_SET,
    CARTESIAN_REQUESTED_SPHERICAL_SET,
    CARTESIAN_UNKNOWN_SPHERICAL_SET,
    CARTESIAN_SET_SPHERICAL_COMPUTED,   // not in 1.0.1
    CARTESIAN_SET_SPHERICAL_REQUESTED,  // not in 1.0.1
    CARTESIAN_SET_SPHERICAL_UNKNOWN
};

typedef struct {
    const struct SL3DDopplerItf_ *mItf;
    IObject *mThis;
    // The API allows client to specify either Cartesian and spherical velocities.
    // But an implementation will likely prefer one or the other. So for
    // maximum portablity, we maintain both units and an indication of which
    // unit was set most recently. In addition, we keep a flag saying whether
    // the other unit has been derived yet. It can take significant time
    // to compute the other unit, so this may be deferred to another thread.
    // For this reason we also keep an indication of whether the secondary
    // has been computed yet, and its accuracy.
    // Though only one unit is primary at a time, a union is inappropriate:
    // the application might read in both units (not in 1.0.1),
    // and due to multi-threading concerns.
    SLVec3D mVelocityCartesian;
    struct {
        SLmillidegree mAzimuth;
        SLmillidegree mElevation;
        SLmillidegree mSpeed;
    } mVelocitySpherical;
    enum CartesianSphericalActive mVelocityActive;
    SLpermille mDopplerFactor;
} I3DDoppler;

typedef struct {
    const struct SL3DGroupingItf_ *mItf;
    IObject *mThis;
    C3DGroup *mGroup;   // strong reference to associated group or NULL
} I3DGrouping;

enum AnglesVectorsActive {
    ANGLES_COMPUTED_VECTORS_SET,    // not in 1.0.1
    ANGLES_REQUESTED_VECTORS_SET,   // not in 1.0.1
    ANGLES_UNKNOWN_VECTORS_SET,
    ANGLES_SET_VECTORS_COMPUTED,
    ANGLES_SET_VECTORS_REQUESTED,
    ANGLES_SET_VECTORS_UNKNOWN
};

typedef struct {
    const struct SL3DLocationItf_ *mItf;
    IObject *mThis;
    SLVec3D mLocationCartesian;
    struct {
        SLmillidegree mAzimuth;
        SLmillidegree mElevation;
        SLmillimeter mDistance;
    } mLocationSpherical;
    enum CartesianSphericalActive mLocationActive;
    struct {
        SLmillidegree mHeading;
        SLmillidegree mPitch;
        SLmillidegree mRoll;
    } mOrientationAngles;
    struct {
        SLVec3D mFront;
        SLVec3D mAbove;
        SLVec3D mUp;
    } mOrientationVectors;
    enum AnglesVectorsActive mOrientationActive;
    // Rotations can be slow, so are deferred.
    SLmillidegree mTheta;
    SLVec3D mAxis;
    SLboolean mRotatePending;
} I3DLocation;

typedef struct {
    const struct SL3DMacroscopicItf_ *mItf;
    IObject *mThis;
    struct {
        SLmillimeter mWidth;
        SLmillimeter mHeight;
        SLmillimeter mDepth;
    } mSize;
    struct {
        SLmillimeter mHeading;
        SLmillimeter mPitch;
        SLmillimeter mRoll;
    } mOrientationAngles;
    struct {
        SLVec3D mFront;
        SLVec3D mAbove;
        SLVec3D mUp;
    } mOrientationVectors;
    enum AnglesVectorsActive mOrientationActive;
    // Rotations can be slow, so are deferred.
    SLmillidegree mTheta;
    SLVec3D mAxis;
    SLboolean mRotatePending;
} I3DMacroscopic;

typedef struct {
    const struct SL3DSourceItf_ *mItf;
    IObject *mThis;
    SLboolean mHeadRelative;
    SLboolean mRolloffMaxDistanceMute;
    SLmillimeter mMaxDistance;
    SLmillimeter mMinDistance;
    SLmillidegree mConeInnerAngle;
    SLmillidegree mConeOuterAngle;
    SLmillibel mConeOuterLevel;
    SLpermille mRolloffFactor;
    SLpermille mRoomRolloffFactor;
    SLuint8 mDistanceModel;
} I3DSource;

typedef struct {
    const struct SLAudioDecoderCapabilitiesItf_ *mItf;
    IObject *mThis;
} IAudioDecoderCapabilities;

typedef struct {
    const struct SLAudioEncoderItf_ *mItf;
    IObject *mThis;
    SLAudioEncoderSettings mSettings;
} IAudioEncoder;

typedef struct {
    const struct SLAudioEncoderCapabilitiesItf_ *mItf;
    IObject *mThis;
} IAudioEncoderCapabilities;

typedef struct {
    const struct SLAudioIODeviceCapabilitiesItf_ *mItf;
    IObject *mThis;
    slAvailableAudioInputsChangedCallback mAvailableAudioInputsChangedCallback;
    void *mAvailableAudioInputsChangedContext;
    slAvailableAudioOutputsChangedCallback mAvailableAudioOutputsChangedCallback;
    void *mAvailableAudioOutputsChangedContext;
    slDefaultDeviceIDMapChangedCallback mDefaultDeviceIDMapChangedCallback;
    void *mDefaultDeviceIDMapChangedContext;
} IAudioIODeviceCapabilities;

typedef struct {
    const struct SLBassBoostItf_ *mItf;
    IObject *mThis;
    SLboolean mEnabled;
    SLpermille mStrength;
#if defined(ANDROID)
    effect_descriptor_t mBassBoostDescriptor;
    android::sp<android::AudioEffect> mBassBoostEffect;
#endif
} IBassBoost;

typedef struct BufferQueue_interface {
    const struct SLBufferQueueItf_ *mItf;
    IObject *mThis;
    SLBufferQueueState mState;
    slBufferQueueCallback mCallback;
    void *mContext;
    // originally SLuint32, but range-checked down to SLuint16
    SLuint16 mNumBuffers;
    /*SLboolean*/ SLuint16 mClearRequested;
    BufferHeader *mArray;
    BufferHeader *mFront, *mRear;
#ifdef ANDROID
    SLuint32 mSizeConsumed;
#endif
    // saves a malloc in the typical case
#define BUFFER_HEADER_TYPICAL 4
    BufferHeader mTypical[BUFFER_HEADER_TYPICAL+1];
} IBufferQueue;

#define MAX_DEVICE 2    // hard-coded array size for default in/out

typedef struct {
    const struct SLDeviceVolumeItf_ *mItf;
    IObject *mThis;
    SLint32 mVolume[MAX_DEVICE];
} IDeviceVolume;

typedef struct {
    const struct SLDynamicInterfaceManagementItf_ *mItf;
    IObject *mThis;
    slDynamicInterfaceManagementCallback mCallback;
    void *mContext;
} IDynamicInterfaceManagement;

typedef struct {
    const struct SLDynamicSourceItf_ *mItf;
    IObject *mThis;
    SLDataSource *mDataSource;
} IDynamicSource;

// private

struct EnableLevel {
    SLboolean mEnable;
    SLmillibel mSendLevel;
};

// indexes into IEffectSend.mEnableLevels

#define AUX_ENVIRONMENTALREVERB 0
#define AUX_PRESETREVERB        1
#define AUX_MAX                 2

typedef struct {
    const struct SLEffectSendItf_ *mItf;
    IObject *mThis;
    struct EnableLevel mEnableLevels[AUX_MAX];  // wet enable and volume per effect type
} IEffectSend;

typedef struct Engine_interface {
    const struct SLEngineItf_ *mItf;
    IObject *mThis;
    SLboolean mLossOfControlGlobal;
#ifdef USE_SDL
    COutputMix *mOutputMix; // SDL pulls PCM from an arbitrary IOutputMixExt
#endif
    // Each engine is its own universe.
    SLuint32 mInstanceCount;
    unsigned mInstanceMask; // 1 bit per active object
    unsigned mChangedMask;  // objects which have changed since last sync
#define MAX_INSTANCE 32     // maximum active objects per engine, see mInstanceMask
    IObject *mInstances[MAX_INSTANCE];
    SLboolean mShutdown;
    SLboolean mShutdownAck;
    // SLuint32 mVersion;      // 0xXXYYZZ where XX=major, YY=minor, ZZ=step
} IEngine;

typedef struct {
    const struct SLEngineCapabilitiesItf_ *mItf;
    IObject *mThis;
    SLboolean mThreadSafe;
    // const
    SLuint32 mMaxIndexLED;
    SLuint32 mMaxIndexVibra;
} IEngineCapabilities;

typedef struct {
    const struct SLEnvironmentalReverbItf_ *mItf;
    IObject *mThis;
    SLEnvironmentalReverbSettings mProperties;
#if defined(ANDROID)
    effect_descriptor_t mEnvironmentalReverbDescriptor;
    android::sp<android::AudioEffect> mEnvironmentalReverbEffect;
#endif
} IEnvironmentalReverb;

struct EqualizerBand {
    SLmilliHertz mMin;
    SLmilliHertz mCenter;
    SLmilliHertz mMax;
};

#if defined(ANDROID)
#define MAX_EQ_BANDS 0
#else
#define MAX_EQ_BANDS 4  // compile-time limit, runtime limit may be smaller
#endif

typedef struct {
    const struct SLEqualizerItf_ *mItf;
    IObject *mThis;
    SLboolean mEnabled;
    SLuint16 mPreset;
#if 0 < MAX_EQ_BANDS
    SLmillibel mLevels[MAX_EQ_BANDS];
#endif
    // const to end of struct
    SLuint16 mNumPresets;
    SLuint16 mNumBands;
#if !defined(ANDROID)
    const struct EqualizerBand *mBands;
    const struct EqualizerPreset *mPresets;
#endif
    SLmillibel mBandLevelRangeMin;
    SLmillibel mBandLevelRangeMax;
#if defined(ANDROID)
    effect_descriptor_t mEqDescriptor;
    android::sp<android::AudioEffect> mEqEffect;
#endif
} IEqualizer;

#define MAX_LED_COUNT 32

typedef struct {
    const struct SLLEDArrayItf_ *mItf;
    IObject *mThis;
    SLuint32 mLightMask;
    SLHSL mColors[MAX_LED_COUNT];
    // const
    SLuint8 mCount;
} ILEDArray;

typedef struct {
    const struct SLMetadataExtractionItf_ *mItf;
    IObject *mThis;
    SLuint32 mKeySize;
    const void *mKey;
    SLuint32 mKeyEncoding;
    const SLchar *mValueLangCountry;
    SLuint32 mValueEncoding;
    SLuint8 mFilterMask;
    int mKeyFilter;
} IMetadataExtraction;

typedef struct {
    const struct SLMetadataTraversalItf_ *mItf;
    IObject *mThis;
    SLuint32 mIndex;
    SLuint32 mMode;
    SLuint32 mCount;
    SLuint32 mSize;
} IMetadataTraversal;

typedef struct {
    const struct SLMIDIMessageItf_ *mItf;
    IObject *mThis;
    slMetaEventCallback mMetaEventCallback;
    void *mMetaEventContext;
    slMIDIMessageCallback mMessageCallback;
    void *mMessageContext;
    SLuint8 mMessageTypes;
} IMIDIMessage;

typedef struct {
    const struct SLMIDIMuteSoloItf_ *mItf;
    IObject *mThis;
    SLuint16 mChannelMuteMask;
    SLuint16 mChannelSoloMask;
    SLuint32 mTrackMuteMask;
    SLuint32 mTrackSoloMask;
    // const
    SLuint16 mTrackCount;
} IMIDIMuteSolo;

typedef struct {
    const struct SLMIDITempoItf_ *mItf;
    IObject *mThis;
    SLuint32 mTicksPerQuarterNote;
    SLuint32 mMicrosecondsPerQuarterNote;
} IMIDITempo;

typedef struct {
    const struct SLMIDITimeItf_ *mItf;
    IObject *mThis;
    SLuint32 mDuration;
    SLuint32 mPosition;
    SLuint32 mStartTick;
    SLuint32 mNumTicks;
} IMIDITime;

typedef struct {
    const struct SLMuteSoloItf_ *mItf;
    IObject *mThis;
    // fields that were formerly here are now at CAudioPlayer
} IMuteSolo;

#define MAX_TRACK 32        // see mActiveMask

typedef struct {
    const struct SLOutputMixItf_ *mItf;
    IObject *mThis;
    slMixDeviceChangeCallback mCallback;
    void *mContext;
} IOutputMix;

#ifdef USE_OUTPUTMIXEXT
typedef struct {
    const struct SLOutputMixExtItf_ *mItf;
    IObject *mThis;
    unsigned mActiveMask;   // 1 bit per active track
    Track mTracks[MAX_TRACK];
    SLboolean mDestroyRequested;    ///< Mixer to acknowledge application's call to Object::Destroy
} IOutputMixExt;
#endif

typedef struct {
    const struct SLPitchItf_ *mItf;
    IObject *mThis;
    SLpermille mPitch;
    // const
    SLpermille mMinPitch;
    SLpermille mMaxPitch;
} IPitch;

typedef struct Play_interface {
    const struct SLPlayItf_ *mItf;
    IObject *mThis;
    SLuint32 mState;
    // next 2 fields are read-only to application
    SLmillisecond mDuration;
    SLmillisecond mPosition;
    slPlayCallback mCallback;
    void *mContext;
    SLuint32 mEventFlags;
    // the ISeek trick of using a distinct value doesn't work here because it's readable by app
    SLmillisecond mMarkerPosition;
    SLmillisecond mPositionUpdatePeriod; // Zero means do not do position updates (FIXME ~0)
#ifdef USE_OUTPUTMIXEXT
    SLuint32 mFrameUpdatePeriod;         // mPositionUpdatePeriod in frame units
    SLmillisecond mLastSeekPosition;     // Last known accurate position, set at Seek
    SLuint32 mFramesSinceLastSeek;       // Frames mixed since last known accurate position
    SLuint32 mFramesSincePositionUpdate; // Frames mixed since last position update callback
#endif
} IPlay;

typedef struct {
    const struct SLPlaybackRateItf_ *mItf;
    IObject *mThis;
    SLpermille mRate;
    SLuint32 mProperties;
    // const after initialization
    SLpermille mMinRate;
    SLpermille mMaxRate;
    SLpermille mStepSize;
    SLuint32 mCapabilities;
} IPlaybackRate;

typedef struct {
    const struct SLPrefetchStatusItf_ *mItf;
    IObject *mThis;
    SLuint32 mStatus;
    SLpermille mLevel;
    slPrefetchCallback mCallback;
    void *mContext;
    SLuint32 mCallbackEventsMask;
    SLpermille mFillUpdatePeriod;
#ifdef ANDROID
    /** FIXME used to call PrefetchStatus callback with object unlocked prior to return from API */
    slPrefetchCallback mDeferredPrefetchCallback;
    void *mDeferredPrefetchContext;
    SLuint32 mDeferredPrefetchEvents;
#endif
} IPrefetchStatus;

typedef struct {
    const struct SLPresetReverbItf_ *mItf;
    IObject *mThis;
    SLuint16 mPreset;
#if defined(ANDROID)
    effect_descriptor_t mPresetReverbDescriptor;
    android::sp<android::AudioEffect> mPresetReverbEffect;
#endif
} IPresetReverb;

typedef struct {
    const struct SLRatePitchItf_ *mItf;
    IObject *mThis;
    SLpermille mRate;
    // const
    SLpermille mMinRate;
    SLpermille mMaxRate;
} IRatePitch;

typedef struct {
    const struct SLRecordItf_ *mItf;
    IObject *mThis;
    SLuint32 mState;
    SLmillisecond mDurationLimit;
    SLmillisecond mPosition;
    slRecordCallback mCallback;
    void *mContext;
    SLuint32 mCallbackEventsMask;
    SLmillisecond mMarkerPosition;
    SLmillisecond mPositionUpdatePeriod;
} IRecord;

typedef struct {
    const struct SLSeekItf_ *mItf;
    IObject *mThis;
    SLmillisecond mPos;     // mPos != SL_TIME_UNKNOWN means pending seek request
    SLboolean mLoopEnabled;
    SLmillisecond mStartPos;
    SLmillisecond mEndPos;
} ISeek;

typedef struct {
    const struct SLThreadSyncItf_ *mItf;
    IObject *mThis;
    SLboolean mInCriticalSection;
    SLuint32 mWaiting;  // number of threads waiting
    pthread_t mOwner;
} IThreadSync;

typedef struct {
    const struct SLVibraItf_ *mItf;
    IObject *mThis;
    SLboolean mVibrate;
    SLmilliHertz mFrequency;
    SLpermille mIntensity;
} IVibra;

typedef struct {
    const struct SLVirtualizerItf_ *mItf;
    IObject *mThis;
    SLboolean mEnabled;
    SLpermille mStrength;
#if defined(ANDROID)
    effect_descriptor_t mVirtualizerDescriptor;
    android::sp<android::AudioEffect> mVirtualizerEffect;
#endif
} IVirtualizer;

typedef struct {
    const struct SLVisualizationItf_ *mItf;
    IObject *mThis;
    slVisualizationCallback mCallback;
    void *mContext;
    SLmilliHertz mRate;
} IVisualization;

typedef struct /*Volume_interface*/ {
    const struct SLVolumeItf_ *mItf;
    IObject *mThis;
    // Values as specified by the application
    SLmillibel mLevel;
    SLpermille mStereoPosition;
    SLuint8 /*SLboolean*/ mMute;
    SLuint8 /*SLboolean*/ mEnableStereoPosition;
} IVolume;

typedef struct {
    const struct XAEngineItf_ *mItf;
    IObject *mThis;
} IXAEngine;

#define NB_SUPPORTED_STREAMS 1 // only one (video) stream supported in this implementation
typedef struct {
    const struct XAStreamInformationItf_ *mItf;
    IObject *mThis;
    xaStreamEventChangeCallback mCallback;
    void *mContext;
    XAboolean mActiveStreams[NB_SUPPORTED_STREAMS];
#ifdef ANDROID
    android::Vector<StreamInfo> mStreamInfoTable;
#endif
} IStreamInformation;

typedef struct {
    const struct XAVideoDecoderCapabilitiesItf_ *mItf;
    IObject *mThis;
} IVideoDecoderCapabilities;

/* Class structures */

/*typedef*/ struct C3DGroup_struct {
    IObject mObject;
#define INTERFACES_3DGroup 6 // see MPH_to_3DGroup in MPH_to.c for list of interfaces
    SLuint8 mInterfaceStates2[INTERFACES_3DGroup - INTERFACES_Default];
    IDynamicInterfaceManagement mDynamicInterfaceManagement;
    I3DLocation m3DLocation;
    I3DDoppler m3DDoppler;
    I3DSource m3DSource;
    I3DMacroscopic m3DMacroscopic;
    // remaining are per-instance private fields not associated with an interface
    unsigned mMemberMask;   // set of member objects
} /*C3DGroup*/;

#ifdef ANDROID

// FIXME Move these into the I... section above

typedef struct {
    const struct SLAndroidEffectItf_ *mItf;
    IObject *mThis;
    android::KeyedVector<SLuint32, android::AudioEffect* > *mEffects;
} IAndroidEffect;

typedef struct {
    const struct SLAndroidEffectCapabilitiesItf_ *mItf;
    IObject *mThis;
    SLuint32 mNumFx;
    effect_descriptor_t* mFxDescriptors;
} IAndroidEffectCapabilities;

typedef struct {
    const struct SLAndroidEffectSendItf_ *mItf;
    IObject *mThis;
    // only one send per interface for now (1 bus)
    SLboolean mEnabled;
    SLmillibel mSendLevel; //android::KeyedVector<SLuint32, SLmillibel> mSendLevels;
} IAndroidEffectSend;

typedef struct {
    const struct SLAndroidConfigurationItf_ *mItf;
    IObject *mThis;
} IAndroidConfiguration;

typedef struct {
    const struct SLAndroidBufferQueueItf_ *mItf;
    IObject *mThis;
    SLAndroidBufferQueueState mState;
    slAndroidBufferQueueCallback mCallback;
    SLuint32 mCallbackEventsMask;
    void *mContext;
    SLuint16 mNumBuffers;
    AndroidBufferType_type mBufferType;
    AdvancedBufferHeader *mBufferArray;
    AdvancedBufferHeader *mFront, *mRear;
    bool mEOS;  // whether EOS has been enqueued; never reset
} IAndroidBufferQueue;

#endif