//--------------------------------------------------------------------------------
//
//	File:		AppleUSBAudioEngine.h
//
//	Contains:	Support for the USB Audio Class Stream Interface.
//
//	Technology:	Mac OS X
//
//--------------------------------------------------------------------------------

#ifndef _APPLEUSBAUDIOENGINE_H
#define _APPLEUSBAUDIOENGINE_H

#include <IOKit/IOBufferMemoryDescriptor.h>
#include <IOKit/audio/IOAudioEngine.h>
#include <IOKit/audio/IOAudioStream.h>
#include <IOKit/usb/IOUSBPipe.h>
#include <IOKit/usb/IOUSBDevice.h>
#include <IOKit/usb/IOUSBInterface.h>

#include "USBAudioObject.h"
#include "AppleiSubEngine.h"
#include "AppleUSBAudioClip.h"

class AppleUSBAudioDevice;

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

#define	kSampleRate_44100				44100
#define kDefaultSamplingRate			kSampleRate_44100
#define	kBitDepth_16bits				16
#define	kChannelDepth_MONO				1
#define	kChannelDepth_STEREO			2

#define kMinimumFrameOffset				1

// Don't make NUM_FRAME_LISTS * NUM_FRAMES_PER_LIST smaller than 375ms or else the HAL will have problems
#define NUM_FRAME_LISTS					40
#if FIXEDSIZEPACKETS
#define NUM_FRAMES_PER_LIST				10
#else
#define NUM_FRAMES_PER_LIST				64
#endif
#define NUM_FRAME_LISTS_TO_QUEUE		10

#define MAX_WRITE_RETRIES				10

class IOSyncer;
class AppleUSBAudioEngine;

typedef struct FrameListWriteInfo {
    AppleUSBAudioEngine *				audioEngine;
    UInt32								frameListNum;
    UInt32								retryCount;
} FrameListWriteInfo;

class AppleUSBAudioEngine : public IOAudioEngine {
    friend class AppleUSBAudioDevice;

    OSDeclareDefaultStructors (AppleUSBAudioEngine);

public:
    virtual bool init (OSDictionary *properties);
    virtual void free ();
    virtual bool initHardware (IOService *provider);
    virtual bool start (IOService *provider);
    virtual void stop (IOService *provider);
	virtual bool requestTerminate (IOService * provider, IOOptionBits options);
    virtual bool terminate (IOOptionBits options = 0);

    virtual IOReturn performAudioEngineStart ();
    virtual IOReturn performAudioEngineStop ();
    
    virtual IOAudioEngineState _setState (IOAudioEngineState newState);

    static void readHandler (void * object, void * frameListIndex, IOReturn result, IOUSBIsocFrame * pFrames);
	static void sampleRateHandler (void * target, void * parameter, IOReturn result, IOUSBIsocFrame * pFrames);
    static void writeHandler (void * object, void * parameter, IOReturn result, IOUSBIsocFrame * pFrames);
	static IOReturn iSubAttachChangeHandler (IOService *target, IOAudioControl *passThruControl, SInt32 oldValue, SInt32 newValue);

protected:
	UInt64					theFirstFrame;
	UInt64					nextSynchReadFrame;
	IOUSBIsocFrame *		theFrames;
	IOUSBIsocFrame			theSampleRateFrame;
	IOUSBIsocFrame			theStartFrame;
	IOUSBIsocCompletion *	usbCompletion;
	IOUSBIsocCompletion		theStartCompletion;
	IOUSBIsocCompletion		sampleRateCompletion;
	IOSyncer *				signal;
	AppleUSBAudioDevice *	usbAudioDevice;
	IOUSBInterface *		streamInterface;
	IOUSBInterface *		previousInterface;
	IOUSBPipe *				thePipe;
	IOUSBPipe *				theAssociatedPipe;
	IOMemoryDescriptor **	soundBuffer;
	IOMemoryDescriptor *	theStartBufferDescriptor;
	IOMemoryDescriptor *	neededSampleRate;
	FrameListWriteInfo *	pendingFrameListWriteInfo;
	IONotifier *			streamNotifier;
	OSObject *				interfaceVendor;
	OSObject *				interfaceProduct;
	OSObject *				deviceReleaseNumber;
	OSObject *				configurationValue;
	OSObject *				interfaceNumber;
	void *					readBuffer;
	void *					theStartBuffer;
	thread_call_t			pendingFrameListCall;
	thread_call_t			iSubTeardownThreadCall;
	thread_call_t			iSubOpenThreadCall;
	IOAudioSampleRate		curSampleRate;
	UInt64					expectedBusFrame;		// For output, the frame on which we expect to get our next USB isoc completion
													// For input, the frame on which we last received a USB isoc completion and
													// wrapped the sample buffer.
	UInt64					startTime;
	UInt64					previousWrappedReadUSBFrame;
	UInt32					theStartBufferSize;
	UInt32					previous;
	UInt32					previousClippedToFrame;
	UInt32					theMaxPacket;
	UInt32					frameListSize;
	UInt32					readFrameListSize;
	UInt32					bufferOffset;
	UInt32					aveSampleRateBuf;		// only needs to be 3 bytes for the 10.14 value, but this is more convenient
	UInt32					averageSampleRate;
	UInt32					sum;					// This is the number of samples we have sent in the previous frames in this period
	UInt32					sampleNum;				// The number of the frame that we are currently sending, it goes between 1 and 1000
	UInt32					numFrameLists;
	UInt32					numFramesPerList;
	UInt32					numFrameListsToQueue;
	UInt32					currentFrameList;
	UInt32					bufferSize;
	UInt32					bytesPerSampleFrame;
	UInt32					safetyOffset;
	UInt16					samplesThisFrame;
	UInt8					ourInterfaceNumber;
	UInt8					shouldStop;
	UInt8					alternateInterfaceID;
	UInt8					refreshInterval;
	UInt8					framesUntilRefresh;
	UInt8					direction;
	Boolean					usbStreamRunning;
	Boolean					notifyDeviceOfStop;
	Boolean					startingEngine;
	Boolean					startiSub;
	Boolean					justResetClipPosition;		// aml 3.29.02 added to match AOA
	Boolean					gotRequestClose;
	Boolean					gotStopCall;
	Boolean					iSubIsOpen;
	Boolean					terminatingDriver;
	IOAudioStream *			mainStream;

	// For iSub
	IOMemoryDescriptor *	iSubBufferMemory;
	UInt32					iSubLoopCount;
	SInt32					iSubBufferOffset;		// Where we are writing to in the iSub buffer
	IOService *				ourProvider;
	IONotifier *			iSubEngineNotifier;
	IOAudioToggleControl *	iSubAttach;
	AppleiSubEngine *		iSubEngine;
	AppleiSubEngine *		oldiSubEngine;
	float *					lowFreqSamples;
	float *					highFreqSamples;
	PreviousValues				filterState;
	// aml 2.21.02 adding extra state for 4th order with phase comp filter
	PreviousValues				filterState2;
	PreviousValues				phaseCompState;
	float					srcPhase;			 // aml 3.4.02
	float					srcState;			 // aml 3.6.02
       
        
	Boolean					needToSync;

	static inline IOFixed IOUFixedDivide(UInt32 a, UInt32 b)
	{
		return (IOFixed)((((UInt64) a) << 16) / ((UInt64) b));
	}

	static inline UInt32 IOUFixedMultiply(UInt32 a, UInt32 b)
	{
		return (UInt32)((((UInt64) a) * ((UInt64) b)) >> 16);
	}

	void	GetDeviceInfo (void);
	IOReturn	PrepareFrameLists (UInt32 numFrameLists, UInt8 sampleSize, UInt8 numChannels);
	IOReturn	SetSampleRate (USBAudioConfigObject *usbAudio, UInt32 sampleRate);
	IOReturn	AddAvailableFormatsFromDevice (USBAudioConfigObject *usbAudio);
	UInt32		CalculateNumSamplesPerFrameList (UInt32 sampleRate, UInt32 numFrames, UInt32 theNumFrameLists = 1);
	IOReturn	CheckForAssociatedEndpoint (USBAudioConfigObject *usbAudio);

    static bool audioDevicePublished (AppleUSBAudioEngine *audioEngine, void *ref, IOService *newService);
    static bool	iSubEnginePublished (AppleUSBAudioEngine * usbAudioEngineObject, void * refCon, IOService * newService);

	virtual bool willTerminate (IOService * provider, IOOptionBits options);

	virtual OSString * getGlobalUniqueID ();
    virtual IOReturn readFrameList (UInt32 frameListNum);
    virtual IOReturn writeFrameList (UInt32 frameListNum);

    virtual IOReturn startUSBStream ();
    virtual IOReturn stopUSBStream ();

	static IOReturn iSubCloseAction (OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4);
	static IOReturn iSubOpenAction (OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4);
	static void iSubTeardown (AppleUSBAudioEngine *usbAudioEngine, thread_call_t iSubTeardownThreadCall);
	static void iSubOpen (AppleUSBAudioEngine *usbAudioEngineObject);
	virtual void iSubTeardownConnection (void);

    virtual UInt32 getCurrentSampleFrame (void);

    virtual IOAudioStreamDirection getDirection (void);
    virtual void *getSampleBuffer (void);
	virtual UInt32 getSampleBufferSize (void);

	virtual void CoalesceInputSamples (UInt32 numBytesToCoalesce);

	virtual void resetClipPosition (IOAudioStream *audioStream, UInt32 clipSampleFrame);
    virtual IOReturn clipOutputSamples (const void *mixBuf, void *sampleBuf, UInt32 firstSampleFrame, UInt32 numSampleFrames, const IOAudioStreamFormat *streamFormat, IOAudioStream *audioStream);
	virtual IOReturn convertInputSamples (const void *sampleBuf, void *destBuf, UInt32 firstSampleFrame, UInt32 numSampleFrames, const IOAudioStreamFormat *streamFormat, IOAudioStream *audioStream);

    virtual IOReturn performFormatChange (IOAudioStream *audioStream, const IOAudioStreamFormat *newFormat, const IOAudioSampleRate *newSampleRate);
	void CalculateSamplesPerFrame (UInt32 sampleRate, UInt16 * averageFrameSize, UInt16 * additionalSampleFrameFreq);
};

#endif /* _APPLEUSBAUDIOENGINE_H */
