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

#ifndef _APPLEUSBAUDIOENGINE_H
#define _APPLEUSBAUDIOENGINE_H

#include <libkern/OSByteOrder.h>
#include <libkern/c++/OSCollectionIterator.h>
#include <libkern/c++/OSMetaClass.h>

#include <IOKit/IOLib.h>
#include <IOKit/IOSyncer.h>
#include <IOKit/IOService.h>
#include <IOKit/IOMessage.h>
#include <IOKit/IOMemoryCursor.h>
#include <IOKit/IOMemoryDescriptor.h>
#include <IOKit/IOBufferMemoryDescriptor.h>
#include <IOKit/IOTimerEventSource.h>
#include <IOKit/IOMultiMemoryDescriptor.h>

#include <IOKit/audio/IOAudioDevice.h>
#include <IOKit/audio/IOAudioPort.h>
#include <IOKit/audio/IOAudioTypes.h>
#include <IOKit/audio/IOAudioDefines.h>
#include <IOKit/audio/IOAudioLevelControl.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 "AppleUSBAudioCommon.h"
#include "AppleUSBAudioDevice.h"
#include "AppleUSBAudioLevelControl.h"
#include "AppleUSBAudioMuteControl.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

#define RECORD_NUM_USB_FRAME_LISTS				128
#define RECORD_NUM_USB_FRAMES_PER_LIST			2
#define RECORD_NUM_USB_FRAME_LISTS_TO_QUEUE		64

#define PLAY_NUM_USB_FRAME_LISTS				4
#define PLAY_NUM_USB_FRAMES_PER_LIST			64
#define PLAY_NUM_USB_FRAME_LISTS_TO_QUEUE		2

class IOSyncer;
class AppleUSBAudioEngine;
class AppleUSBAudioPlugin;

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 requestiSubClose (IOAudioEngine * audioEngine);

	static void sampleRateHandler (void * target, void * parameter, IOReturn result, IOUSBIsocFrame * pFrames);

    static void readHandler (void * object, void * frameListIndex, IOReturn result, IOUSBLowLatencyIsocFrame * pFrames);
    static void writeHandler (void * object, void * parameter, IOReturn result, IOUSBLowLatencyIsocFrame * pFrames);
	static IOReturn iSubAttachChangeHandler (IOService *target, IOAudioControl *passThruControl, SInt32 oldValue, SInt32 newValue);
	virtual IOReturn pluginDeviceRequest (IOUSBDevRequest * request, IOUSBCompletion * completion);
	virtual void registerPlugin (AppleUSBAudioPlugin * thePlugin);
	static void	pluginLoaded (AppleUSBAudioEngine * usbAudioEngineObject);

protected:
	UInt64								usbFrameToQueueAt;
	UInt64								nextSynchReadFrame;
	IOUSBLowLatencyIsocFrame *			theUSBIsocFrames;
	IOUSBIsocFrame						theSampleRateFrame;
	IOUSBLowLatencyIsocCompletion *		usbCompletion;
	IOUSBIsocCompletion					sampleRateCompletion;
	IOUSBInterface *					streamInterface;
	IOUSBInterface *					previousInterface;
	IOUSBPipe *							thePipe;
	IOUSBPipe *							theAssociatedPipe;
	IOSyncer *							signal;
	AppleUSBAudioDevice *				usbAudioDevice;
	IOBufferMemoryDescriptor *			mUSBBufferDescriptor;
	IOBufferMemoryDescriptor *			sampleBufferMemoryDescriptor;
	IOMultiMemoryDescriptor *			theWrapRangeDescriptor;
	IOSubMemoryDescriptor *				theWrapDescriptors[2];
	IOSubMemoryDescriptor **			soundBufferDescriptors;
	IOMemoryDescriptor *				neededSampleRateDescriptor;
//	IOVirtualRange						theWrapRanges[2];
	IONotifier *						streamNotifier;
	OSObject *							interfaceVendor;
	OSObject *							interfaceProduct;
	OSObject *							deviceReleaseNumber;
	OSObject *							configurationValue;
	OSObject *							interfaceNumber;
	void *								readBuffer;
	void *								theStartBuffer;
	UInt32 *							aveSampleRateBuf;		// only needs to be 3 bytes for the 10.14 value
	IOTimerEventSource *				startTimer;
	thread_call_t						iSubTeardownThreadCall;
	thread_call_t						mPluginInitThread;
	thread_call_t						iSubOpenThreadCall;
	thread_call_t						firstUSBFrameCompletionThread;
	IOAudioSampleRate					curSampleRate;
	UInt32								previouslyPreparedBufferOffset;
	UInt32								safeToEraseTo;
	UInt32								lastSafeErasePoint;
	UInt32								theStartBufferSize;
	UInt32								previousClippedToFrame;
	UInt32								readUSBFrameListSize;
	UInt32								bufferOffset;
	UInt32								averageSampleRate;
	UInt32								sum;					// This is the number of samples we have sent in the previous frames in this period
	UInt32								numUSBFrameLists;
	UInt32								numUSBFramesPerList;
	UInt32								numUSBFrameListsToQueue;
	UInt32								currentFrameList;
	UInt32								bufferSize;
	UInt32								bytesPerSampleFrame;
	UInt32								safetyOffset;
	UInt32								fractionalSamplesRemaining;
	UInt16								samplesThisFrame;
	UInt8								ourInterfaceNumber;
	UInt8								shouldStop;
	UInt8								alternateInterfaceID;
	UInt8								refreshInterval;
	UInt8								framesUntilRefresh;
	UInt8								direction;
	Boolean								inCompletion;
	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;

	IONotifier *						mPluginNotification;
	AppleUSBAudioPlugin *				mPlugin;

	// 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;
	PreviousValues						filterState2;
	PreviousValues						phaseCompState;
	float								srcPhase;
	float								srcState;
	Boolean								needToSync;
	Boolean								needTimeStamps;

	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	PrepareWriteFrameList (UInt32 usbFrameListIndex);
	IOReturn	PrepareAndReadFrameLists (UInt8 sampleSize, UInt8 numChannels, UInt32 usbFrameListIndex);
	IOReturn	SetSampleRate (USBAudioConfigObject *usbAudio, UInt32 sampleRate);
	IOReturn	AddAvailableFormatsFromDevice (USBAudioConfigObject *usbAudio);
	IOReturn	CheckForAssociatedEndpoint (USBAudioConfigObject *usbAudio);

    static bool audioDevicePublished (AppleUSBAudioEngine *audioEngine, void *ref, IOService *newService);
    static bool	iSubEnginePublished (AppleUSBAudioEngine * usbAudioEngineObject, void * refCon, IOService * newService);
	static void waitForFirstUSBFrameCompletion (OSObject * owner, IOTimerEventSource * sender);

	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, IOUSBLowLatencyIsocFrame * pFrames, UInt32 startingFrameList);
	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 */
