/*
 *      Copyright (C) 2010-2021 Hendrik Leppkes
 *      http://www.1f0.de
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#pragma once

// {4158A22B-6553-45D0-8069-24716F8FF171}
DEFINE_GUID(IID_ILAVAudioSettings, 0x4158a22b, 0x6553, 0x45d0, 0x80, 0x69, 0x24, 0x71, 0x6f, 0x8f, 0xf1, 0x71);

// {A668B8F2-BA87-4F63-9D41-768F7DE9C50E}
DEFINE_GUID(IID_ILAVAudioStatus, 0xa668b8f2, 0xba87, 0x4f63, 0x9d, 0x41, 0x76, 0x8f, 0x7d, 0xe9, 0xc5, 0xe);

// Codecs supported in the LAV Audio configuration
// Codecs not listed here cannot be turned off. You can request codecs to be added to this list, if you wish.
typedef enum LAVAudioCodec
{
    Codec_AAC,
    Codec_AC3,
    Codec_EAC3,
    Codec_DTS,
    Codec_MP2,
    Codec_MP3,
    Codec_TRUEHD,
    Codec_FLAC,
    Codec_VORBIS,
    Codec_LPCM,
    Codec_PCM,
    Codec_WAVPACK,
    Codec_TTA,
    Codec_WMA2,
    Codec_WMAPRO,
    Codec_Cook,
    Codec_RealAudio,
    Codec_WMALL,
    Codec_ALAC,
    Codec_Opus,
    Codec_AMR,
    Codec_Nellymoser,
    Codec_MSPCM,
    Codec_Truespeech,
    Codec_TAK,
    Codec_ATRAC,

    Codec_AudioNB // Number of entries (do not use when dynamically linking)
} LAVAudioCodec;

// Bitstreaming Codecs supported in LAV Audio
typedef enum LAVBitstreamCodec
{
    Bitstream_AC3,
    Bitstream_EAC3,
    Bitstream_TRUEHD,
    Bitstream_DTS,
    Bitstream_DTSHD,

    Bitstream_NB // Number of entries (do not use when dynamically linking)
} LAVBitstreamCodec;

// Supported Sample Formats in LAV Audio
typedef enum LAVAudioSampleFormat
{
    SampleFormat_None = -1,
    SampleFormat_16,
    SampleFormat_24,
    SampleFormat_32,
    SampleFormat_U8,
    SampleFormat_FP32,
    SampleFormat_Bitstream,

    SampleFormat_NB // Number of entries (do not use when dynamically linking)
} LAVAudioSampleFormat;

typedef enum LAVAudioMixingMode
{
    MatrixEncoding_None,
    MatrixEncoding_Dolby,
    MatrixEncoding_DPLII,

    MatrixEncoding_NB
} LAVAudioMixingMode;

// LAV Audio configuration interface
interface __declspec(uuid("4158A22B-6553-45D0-8069-24716F8FF171")) ILAVAudioSettings : public IUnknown
{
    // Switch to Runtime Config mode. This will reset all settings to default, and no changes to the settings will be
    // saved You can use this to programmatically configure LAV Audio without interfering with the users settings in the
    // registry. Subsequent calls to this function will reset all settings back to defaults, even if the mode does not
    // change.
    //
    // Note that calling this function during playback is not supported and may exhibit undocumented behaviour.
    // For smooth operations, it must be called before LAV Audio is connected to other filters.
    STDMETHOD(SetRuntimeConfig)(BOOL bRuntimeConfig) = 0;

    // Dynamic Range Compression
    // pbDRCEnabled: The state of DRC
    // piDRCLevel:   The DRC strength (0-100, 100 is maximum)
    STDMETHOD(GetDRC)(BOOL * pbDRCEnabled, int *piDRCLevel) = 0;
    STDMETHOD(SetDRC)(BOOL bDRCEnabled, int iDRCLevel) = 0;

    // Configure which codecs are enabled
    // If aCodec is invalid (possibly a version difference), Get will return FALSE, and Set E_FAIL.
    STDMETHOD_(BOOL, GetFormatConfiguration)(LAVAudioCodec aCodec) = 0;
    STDMETHOD(SetFormatConfiguration)(LAVAudioCodec aCodec, BOOL bEnabled) = 0;

    // Control Bitstreaming
    // If bsCodec is invalid (possibly a version difference), Get will return FALSE, and Set E_FAIL.
    STDMETHOD_(BOOL, GetBitstreamConfig)(LAVBitstreamCodec bsCodec) = 0;
    STDMETHOD(SetBitstreamConfig)(LAVBitstreamCodec bsCodec, BOOL bEnabled) = 0;

    // Should "normal" DTS frames be encapsulated in DTS-HD frames when bitstreaming?
    STDMETHOD_(BOOL, GetDTSHDFraming)() = 0;
    STDMETHOD(SetDTSHDFraming)(BOOL bHDFraming) = 0;

    // Control Auto A/V syncing
    STDMETHOD_(BOOL, GetAutoAVSync)() = 0;
    STDMETHOD(SetAutoAVSync)(BOOL bAutoSync) = 0;

    // Convert all Channel Layouts to standard layouts
    // Standard are: Mono, Stereo, 5.1, 6.1, 7.1
    STDMETHOD_(BOOL, GetOutputStandardLayout)() = 0;
    STDMETHOD(SetOutputStandardLayout)(BOOL bStdLayout) = 0;

    // Expand Mono to Stereo by simply doubling the audio
    STDMETHOD_(BOOL, GetExpandMono)() = 0;
    STDMETHOD(SetExpandMono)(BOOL bExpandMono) = 0;

    // Expand 6.1 to 7.1 by doubling the back center
    STDMETHOD_(BOOL, GetExpand61)() = 0;
    STDMETHOD(SetExpand61)(BOOL bExpand61) = 0;

    // Allow Raw PCM and SPDIF encoded input
    STDMETHOD_(BOOL, GetAllowRawSPDIFInput)() = 0;
    STDMETHOD(SetAllowRawSPDIFInput)(BOOL bAllow) = 0;

    // Configure which sample formats are enabled
    // Note: SampleFormat_Bitstream cannot be controlled by this
    STDMETHOD_(BOOL, GetSampleFormat)(LAVAudioSampleFormat format) = 0;
    STDMETHOD(SetSampleFormat)(LAVAudioSampleFormat format, BOOL bEnabled) = 0;

    // Configure a delay for the audio
    STDMETHOD(GetAudioDelay)(BOOL * pbEnabled, int *pDelay) = 0;
    STDMETHOD(SetAudioDelay)(BOOL bEnabled, int delay) = 0;

    // Enable/Disable Mixing
    STDMETHOD(SetMixingEnabled)(BOOL bEnabled) = 0;
    STDMETHOD_(BOOL, GetMixingEnabled)() = 0;

    // Control Mixing Layout
    STDMETHOD(SetMixingLayout)(DWORD dwLayout) = 0;
    STDMETHOD_(DWORD, GetMixingLayout)() = 0;

#define LAV_MIXING_FLAG_UNTOUCHED_STEREO 0x0001
#define LAV_MIXING_FLAG_NORMALIZE_MATRIX 0x0002
#define LAV_MIXING_FLAG_CLIP_PROTECTION 0x0004
    // Set Mixing Flags
    STDMETHOD(SetMixingFlags)(DWORD dwFlags) = 0;
    STDMETHOD_(DWORD, GetMixingFlags)() = 0;

    // Set Mixing Mode
    STDMETHOD(SetMixingMode)(LAVAudioMixingMode mixingMode) = 0;
    STDMETHOD_(LAVAudioMixingMode, GetMixingMode)() = 0;

    // Set Mixing Levels
    STDMETHOD(SetMixingLevels)(DWORD dwCenterLevel, DWORD dwSurroundLevel, DWORD dwLFELevel) = 0;
    STDMETHOD(GetMixingLevels)(DWORD * dwCenterLevel, DWORD * dwSurroundLevel, DWORD * dwLFELevel) = 0;

    // Toggle Tray Icon
    STDMETHOD(SetTrayIcon)(BOOL bEnabled) = 0;
    STDMETHOD_(BOOL, GetTrayIcon)() = 0;

    // Toggle Dithering for sample format conversion
    STDMETHOD(SetSampleConvertDithering)(BOOL bEnabled) = 0;
    STDMETHOD_(BOOL, GetSampleConvertDithering)() = 0;

    // Suppress sample format changes. This will allow channel count to increase, but not to reduce, instead adding
    // empty channels This option is NOT persistent
    STDMETHOD(SetSuppressFormatChanges)(BOOL bEnabled) = 0;
    STDMETHOD_(BOOL, GetSuppressFormatChanges)() = 0;

    // Use 5.1 legacy layout (using back channels instead of side)
    STDMETHOD_(BOOL, GetOutput51LegacyLayout)() = 0;
    STDMETHOD(SetOutput51LegacyLayout)(BOOL b51Legacy) = 0;

    // Fallback to audio decoding if bitstreaming is not supported by the audio renderer/hardware
    STDMETHOD_(BOOL, GetBitstreamingFallback)() = 0;
    STDMETHOD(SetBitstreamingFallback)(BOOL bBitstreamingFallback) = 0;
};

// LAV Audio Status Interface
// Get the current playback stats
interface __declspec(uuid("A668B8F2-BA87-4F63-9D41-768F7DE9C50E")) ILAVAudioStatus : public IUnknown
{
    // Check if the given sample format is supported by the current playback chain
    STDMETHOD_(BOOL, IsSampleFormatSupported)(LAVAudioSampleFormat sfCheck) = 0;

    // Get details about the current decoding format
    STDMETHOD(GetDecodeDetails)
    (LPCSTR * pCodec, LPCSTR * pDecodeFormat, int *pnChannels, int *pSampleRate, DWORD *pChannelMask) = 0;

    // Get details about the current output format
    STDMETHOD(GetOutputDetails)(LPCSTR * pOutputFormat, int *pnChannels, int *pSampleRate, DWORD *pChannelMask) = 0;

    // Enable Volume measurements
    STDMETHOD(EnableVolumeStats)() = 0;

    // Disable Volume measurements
    STDMETHOD(DisableVolumeStats)() = 0;

    // Get Volume Average for the given channel
    STDMETHOD(GetChannelVolumeAverage)(WORD nChannel, float *pfDb) = 0;
};
