#pragma once

#include <Audioclient.h>
#include "kpi_impl.h"
#include "kpi_device.h"
#include "kbwasapi_enum.h"
#include "../../../kpi_common/ringbuf.h"

class KbWasapiDevice : public KbKpiUnknownImpl<IKpiOutDevice>
{
private:
    static HINSTANCE s_hAvrtDll;
    IMMDevice          *m_pDevice;
    IAudioClient       *m_pAudioClient;
    IAudioRenderClient *m_pRenderClient;
    IAudioClock        *m_pAudioClock;
    KbRingBuffer m_RingBuffer;
    HANDLE m_hEvent;
    HANDLE m_hEventStop;
    HANDLE m_hEventCanOutput;
    HANDLE m_hThread;
    CRITICAL_SECTION m_cs;
    int    m_nSampleRate;
    int    m_nChannels;
    int    m_nBps;
    int    m_nBufferSizeSample;//バッファサイズ（サンプル単位）
    int    m_nBlockAlign;
    int    m_nBufferFrame;
    int    m_nMode;//event or push
    int    m_nFinished;
    DWORD  m_dwTime;
    UINT64 m_qwPrevPosition;
    UINT64 m_qwTotalWritten;
    UINT64 m_qwProcessedSample;//WASAPI が実際に再生し終えたバッファのサイズ
    UINT64 m_qwProcessedMax;   //WASAPI に渡したバッファのサイズ
    UINT64 m_qwLatencySample;
    static unsigned __stdcall ThreadProc(void *p);
    void __fastcall ThreadProc(void);
    void __fastcall Lock(void){EnterCriticalSection(&m_cs);}
    void __fastcall Unlock(void){LeaveCriticalSection(&m_cs);}
public:
    virtual BOOL   WINAPI Output(BYTE *pOutput, int nSizeSample);//デバイスにデータを出力
    virtual void   WINAPI Wait(void);           //次の書き込みが可能になるまで待つ
    virtual UINT64 WINAPI GetPosition(void);    //デバイスの再生位置をサンプル単位で返す
    virtual void   WINAPI Stop(void);            //再生を停止
    virtual void   WINAPI Pause(void);           //一時停止
    virtual void   WINAPI Restart(void);         //再開
    virtual BOOL   WINAPI SetVolume(int nVolume);//音量制御
    virtual BOOL   WINAPI SetRate(int nRate);    //サンプリングレートを変換
    virtual DWORD  WINAPI UpdateConfig(void *pvReserved){return 0;}
    BOOL __fastcall Open(const wchar_t *cszDeviceName, 
                         const wchar_t *cszId, 
                         const KPI_DEVICE_FORMAT *cpFormat, //再生周波数等
                         int nBufferSizeSample,
                         IKpiConfig *pConfig);        //プラグイン独自の設定
    bool IsEventMode(void){return m_nMode == KbWasapiEnumerator::MODE_EVENT;}
	static BOOL load_avrt(void);
    static void unload_avrt(void);//プラグインアンロード時に呼び出す
    KbWasapiDevice(void);
	virtual ~KbWasapiDevice(void);
};
