#ifndef DUBBING_SDK_DEVICE_H
#define DUBBING_SDK_DEVICE_H


#include <string>
#include <vector>
#include <queue>
#include <shared_mutex>
#include <memory>
#include <thread>

#include "idevice_data_observer.h"
#include "mini_audio.h"
#include "dubbing_global.h"

namespace DUBBING
{

    class DUBBING_CLIENT_EXPORT DubbingSdkDevice
    {
    public:
    public:
        static std::vector<MiniDeviceInfo> getDeviceInfoList();
        static std::vector<MiniDeviceInfo> getPlaybackDeviceInfoList();
        static std::vector<MiniDeviceInfo> getCaptureDeviceInfoList();
        static MiniDeviceInfo getDeviceInfo(std::wstring wasapiDeviceId);
        static MiniDeviceInfo getDefaultPlaybackDeviceInfo();
        static MiniDeviceInfo getDefaultCaptureDeviceInfo();
        static void dataCallback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount);
        static void stopCallback(ma_device* pDevice);
        static void notificationCallback(const ma_device_notification* pNotification);

    public:
        DubbingSdkDevice();
        ~DubbingSdkDevice();

        void onDataEvent(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount);
        void onCaptureDataEvent(ma_device* pDevice, const void* pInput, ma_uint32 frameCount);
        void onPlaybackDataEvent(ma_device* pDevice, void* pOutput, ma_uint32 frameCount);
        void onLoopbackDataEvent(ma_device* pDevice, const void* pInput, ma_uint32 frameCount);
        void onStopDeviceEvent(ma_device* pDevice);
        void onNotificationDeviceEvent(const ma_device_notification* pNotification);

        void initDeviceConfig(ma_device_config& deviceConfig, ma_device_type deviceType, const ma_device_id* playbackId = nullptr, const ma_device_id* captrueId = nullptr);
        void modifyPlaybackDeviceConfig(ma_device_config& deviceConfig, ma_format format, uint32_t channel);
        void modifyCaptureDeviceConfig(ma_device_config& deviceConfig, ma_format format, uint32_t channel);
        void modifyDeviceConfig(ma_device_config& deviceConfig, uint32_t sampleRate, uint32_t periodSizeInFrames);
        ma_device* startDevice(ma_device_config deviceConfig);
        ma_device* startPlaybackDevice(const ma_device_id& playbackId);
        ma_device* startCaptureDevice(const ma_device_id& captureId);
        ma_device* startLoopbackDevice(const ma_device_id& playbackId);
        ma_device* startDevice(const ma_device_id& playbackId, const ma_device_id& captureId);
        void stopDevice(ma_device* device);
        
        void registerDeviceDataObserver(IDeviceDataObserver* deviceDataObserver);
        void unregisterDeviceDataObserver(IDeviceDataObserver* deviceDataObserver);

    private:
        IDeviceDataObserver* m_deviceDataObserver = nullptr;
    };
}

#endif // DUBBING_SDK_DEVICE_H
