#include <windows.h>
#include <stdio.h>
#include <mmreg.h>
#include <ks.h>

#include "kbwaveout_module.h"
#include "kbwaveout_device.h"
#include "kbwaveout_enum.h"

// {AC73430A-018E-4CD6-9470-4F3A81FA1B0B}
static const GUID kbwaveout_GUID = 
{ 0xac73430a, 0x18e, 0x4cd6, { 0x94, 0x70, 0x4f, 0x3a, 0x81, 0xfa, 0x1b, 0xb } };

#define KBWAVEOUT_VERSION 5
#define KBWAVEOUT_VERSION_STR "0.05"

static const DWORD   kbwaveout_PluginVersion = KBWAVEOUT_VERSION;
static const wchar_t kbwaveout_Description[] = L"waveOut Device v" KBWAVEOUT_VERSION_STR ;
static const wchar_t kbwaveout_Copyright[] = L"Copyright (C) 2016-2019 Kobarin";
static const wchar_t kbwaveout_TypeName[] = L"waveOut";
static const DWORD   kbwaveout_SupportConfig = 0;
static const DWORD   kbwaveout_SupportFlags = //KPI_DEVICE_MODULEINFO::SUPPORT_FLAG_VOLUME |
                                              //KPI_DEVICE_MODULEINFO::SUPPORT_FLAG_RATE | 
                                              //KPI_DEVICE_MODULEINFO::SUPPORT_FLAG_BITPERFECT | 
                                              0;
static const DWORD   kbwaveout_MultipleInstance = KPI_MULTINST_INFINITE |
                                                  //KPI_MULTINST_ZERO |
                                                  //KPI_MULTINST_ONE |
                                                  //KPI_MULTINST_UNIQUE |
                                                  0;

///////////////////////////////////////////////////////////////////////////////
//KbWaveOutDeviceModule
///////////////////////////////////////////////////////////////////////////////
KbWaveOutDeviceModule::KbWaveOutDeviceModule(void)
    :m_ModuleInfo{
        sizeof(KPI_DEVICE_MODULEINFO),
        KPI_OUTDEVICE_MODULE_VERSION,
        kbwaveout_PluginVersion,
        kbwaveout_MultipleInstance,
        kbwaveout_GUID,
        kbwaveout_Description,
        kbwaveout_Copyright,
        kbwaveout_TypeName,
        kbwaveout_SupportConfig,
        kbwaveout_SupportFlags,
        0, 0, 0, 0 //reservved
    }
{
}
///////////////////////////////////////////////////////////////////////////////
KbWaveOutDeviceModule::~KbWaveOutDeviceModule(void)
{
}
///////////////////////////////////////////////////////////////////////////////
void  WINAPI KbWaveOutDeviceModule::GetModuleInfo(const KPI_DEVICE_MODULEINFO **ppInfo)
{
    *ppInfo = &m_ModuleInfo;
}
///////////////////////////////////////////////////////////////////////////////
BOOL WINAPI KbWaveOutDeviceModule::Open(const wchar_t *cszDeviceName, //デバイス名
                                        const wchar_t *cszId,         //識別文字列
                                        const KPI_DEVICE_FORMAT *cpFormat, //再生周波数等
                                        int nBufferSizeSample,     //再生バッファサイズ（サンプル単位）
                                        IKpiOutDevice **ppOutDevice)
{
    *ppOutDevice = NULL;
    if(cpFormat->dwFormatType != KPI_MEDIAINFO::FORMAT_PCM){
        return FALSE;
    }
    KbWaveOutDevice *pDevice = new KbWaveOutDevice;
    if(pDevice->Open(cszDeviceName, cszId, cpFormat, nBufferSizeSample)){
        *ppOutDevice = pDevice;
    }
    else{
        pDevice->Release();
    }
    return *ppOutDevice != NULL;
}
///////////////////////////////////////////////////////////////////////////////
void WINAPI KbWaveOutDeviceModule::EnumDevices(IKpiDeviceEnumerator *pEnumerator)
{//デバイス名の列挙
    KbWaveOutEnumerator woEnumerator;
    woEnumerator.EnumerateDevices(pEnumerator);
}
///////////////////////////////////////////////////////////////////////////////
BOOL  WINAPI KbWaveOutDeviceModule::EnumConfig(IKpiConfigEnumerator *pEnumerator)
{
    return FALSE;
}
///////////////////////////////////////////////////////////////////////////////
HRESULT WINAPI kpi_CreateInstance(REFIID riid, void **ppvObject, IKpiUnknown *pUnknown)
{
    *ppvObject = NULL;
    if(!IsEqualIID(riid, IID_IKpiOutDeviceModule)){
        return E_NOINTERFACE;
    }
    IKpiOutDeviceModule *pModule = new KbWaveOutDeviceModule;//(pConfig);
    *ppvObject = pModule;
    return S_OK;
}
///////////////////////////////////////////////////////////////////////////////
BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
    switch (ul_reason_for_call){
        case DLL_PROCESS_ATTACH:
            {
                DisableThreadLibraryCalls(hModule);
            }
            break;
        case DLL_PROCESS_DETACH:
            {
            }
            break;
    }
    return TRUE;
}
