#pragma once

#include "kpi_impl.h"
#include "kpi_device.h"

struct IDirectSound;
struct IDirectSoundBuffer;
struct IDirectSoundNotify;

class KbDSoundDevice : public KbKpiUnknownImpl<IKpiOutDevice>
{
private:
    static HINSTANCE s_hDSound;
    static HWND   s_hWnd;      //IDirectSound::SetCooperativeLevel に渡すウィンドウのハンドル
    static HANDLE s_hThread;   //↑のウィンドウを作成するスレッドのハンドル
    static DWORD  s_dwThreadId;//↑のスレッドの ID
    static DWORD WINAPI ThreadProc(void *pvParam);
    static HWND __fastcall CreateDSoundWindow(void);
    IDirectSound       *m_pDSound;
    IDirectSoundBuffer *m_pPrimary;
    IDirectSoundBuffer *m_pDsBuffer;
    IDirectSoundNotify *m_pNotify;
    enum{
        cNumBuffers = 2
    };
    int    m_nSampleRate;
    int    m_nChannels;
    int    m_nBps;
    int    m_nBufferSizeSample;
    int    m_nBufferSizeBytes;
    int    m_nBlockAlign;
    BOOL   m_bUseDsNotify;    //DirectSooundNotify を使う場合は TRUE
    DWORD  m_dwFinishCursor;  //終了時の再生カーソル(終了してないときは-1, 最後まで再生し終わったら-2)
    DWORD  m_dwFinishTime;    //終了時の実時刻
    UINT64 m_qwFinishPosition;//終了時の再生位置(終了してないときは-1)
    UINT64 m_qwOutputCount;   //Output を呼び出した回数
    UINT64 m_qwPrevPosition;  //前回 GetPosition 呼び出し時の再生位置
    HANDLE m_hStopEvent;
    HANDLE m_hNotifyEvents[cNumBuffers];

    BOOL __fastcall CreateDirectSound(const wchar_t *cszDeviceName, const wchar_t *cszId);
    IDirectSoundBuffer* __fastcall CreateDsBuffer(int nSampleRate,
                                                  int nChannels,
                                                  int nBps,
                                                  int nBufferSize,
                                                  BOOL bIsMME);
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);
    static BOOL __fastcall LoadDSoundDll(void);
    static void __fastcall Uninitialize(void);
    KbDSoundDevice(void);
    virtual ~KbDSoundDevice(void);
};
