//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "main.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "wclAudio"
#pragma resource "*.dfm"
//---------------------------------------------------------------------------
class TAudioDeviceStorage : public TObject
{
public:
        TwclAudioDevice Device;
};
//---------------------------------------------------------------------------
TfmMain *fmMain;
//---------------------------------------------------------------------------
__fastcall TfmMain::TfmMain(TComponent* Owner)
        : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::btClearClick(TObject *Sender)
{
        lbLog->Items->Clear();
}
//---------------------------------------------------------------------------
void TfmMain::Trace(const String& Msg)
{
        lbLog->Items->Add(Msg);
}
//---------------------------------------------------------------------------
void TfmMain::Trace(const String& Msg, const int Error)
{
        Trace(Msg + ": 0x" + IntToHex(Error, 8));
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::FormCreate(TObject *Sender)
{
        FBars.Length = 0;
        int Res = AudioSwitcher->Open();
        if (Res != WCL_E_SUCCESS)
                Trace("Audio switcher open failed", Res);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::FormDestroy(TObject *Sender)
{
        AudioVolume->Close();
        AudioMeter->Close();
        AudioSwitcher->Close();
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::AudioSwitcherClosed(TObject *Sender)
{
        Trace("Audio switcher closed");

        if (cbEndpoints->Items->Count > 0)
        {
                for (int i = 0; i < cbEndpoints->Items->Count; i++)
                {
                        cbEndpoints->Items->Objects[i]->Free();
                        cbEndpoints->Items->Clear();
                }
        }
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::AudioSwitcherOpened(TObject *Sender)
{
        Trace("Audio switcher opened");

        TwclAudioDevices Devices;
        int Res = AudioSwitcher->Enum(TwclAudioDeviceStates() << asActive,
                Devices);
        if (Res != WCL_E_SUCCESS)
                Trace("Enum audio endpoints failed", Res);
        else
        {
                if (Devices.Length == 0)
                        Trace("No active audio endpoints found");
                else
                {
                        for (int i = 0; i < Devices.Length; i++)
                        {
                                AddDevice(Devices[i]);

                                if (cbEndpoints->Items->Count == 0)
                                        Trace("No output audio endpoints found");
                                else
                                        SelectActiveDevice();
                        }
                }
        }
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::AudioSwitcherDeviceRemoved(TObject *Sender,
      const String Id)
{
        DeleteDevice(Id);
}
//---------------------------------------------------------------------------
void TfmMain::DeleteDevice(const String& Id)
{
        if (cbEndpoints->Items->Count > 0)
        {
                for (int i = 0; i < cbEndpoints->Items->Count; i++)
                {
                        TAudioDeviceStorage* Storage = (TAudioDeviceStorage*)cbEndpoints->Items->Objects[i];
                        if (Storage->Device.Id == Id)
                        {
                                Storage->Free();
                                cbEndpoints->Items->Delete(i);
                                if (cbEndpoints->Items->Count > 0)
                                        SelectActiveDevice();
                                break;
                        }
                }
        }
}
//---------------------------------------------------------------------------
void TfmMain::SelectActiveDevice()
{
        if (cbEndpoints->Items->Count > 0)
        {
                for (int i = 0; i < cbEndpoints->Items->Count; i++)
                {
                        TAudioDeviceStorage* Storage = (TAudioDeviceStorage*)cbEndpoints->Items->Objects[i];
                        TwclAudioDevice Device;
                        int Res = AudioSwitcher->GetDeviceDetails(Storage->Device.Id, Device);
                        if (Res == WCL_E_SUCCESS)
                                Storage->Device = Device;
                        if (Storage->Device.Roles.Contains(drMultimedia))
                        {
                                cbEndpoints->ItemIndex = i;
                                return;
                        }
                }
        }

        cbEndpoints->ItemIndex = -1;
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::AudioSwitcherDeviceAdded(TObject *Sender,
      const String Id)
{
        TwclAudioDevice Device;
        if (AudioSwitcher->GetDeviceDetails(Id, Device) == WCL_E_SUCCESS)
                AddDevice(Device);
}
//---------------------------------------------------------------------------
void TfmMain::AddDevice(const TwclAudioDevice& Device)
{
        if (Device.State == asActive && Device.Flow == dfRender)
        {
                TAudioDeviceStorage* Storage = new TAudioDeviceStorage();
                Storage->Device = Device;
                cbEndpoints->Items->AddObject(Device.FriendlyName, Storage);

                SelectActiveDevice();
        }
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::AudioMeterOpened(TObject *Sender)
{
        Trace("Audio meter opened");
        cbEndpoints->Enabled = false;
        pbMaster->Visible = true;

        TwclAudioHardwareFeatures Features;
        int Res = AudioMeter->GetHardwareFeatures(Features);
        if (Res != WCL_E_SUCCESS)
                Trace("Get hardware features failed", Res);
        else
        {
                Trace("Hardware features");
                if (Features.Contains(hfVolume))
                        Trace("  Volume");
                if (Features.Contains(hfMute))
                        Trace("  Mute");
                if (Features.Contains(hfMeter))
                        Trace("  Meter");
        }

        unsigned int Channels;
        Res = AudioMeter->GetChannels(Channels);
        if (Res != WCL_E_SUCCESS)
                Trace("Get channels count failed", Res);
        else
        {
                if (Channels == 0)
                {
                        Trace("No mettering channels available");
                        AudioMeter->Close();
                }
                else
                {
                        Trace("Channels: " + IntToStr((int)Channels));

                        int Pos = pbMaster->Left + pbMaster->Width + 5;
                        FBars.Length = Channels;
                        for (unsigned int i = 0; i < Channels; i++)
                        {
                                TProgressBar* Bar = new TProgressBar(this);
                                Bar->Parent = this;
                                Bar->Orientation = pbVertical;
                                Bar->Width = pbMaster->Width;
                                Bar->Height = pbMaster->Height;
                                Bar->Top = pbMaster->Top;
                                Bar->Left = Pos;
                                Bar->Smooth = pbMaster->Smooth;
                                Pos = Bar->Left + Bar->Width + 5;

                                FBars[i] = Bar;
                        }

                        UpdateChannelsValue();

                        Timer->Enabled = true;
                }
        }
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::AudioMeterClosed(TObject *Sender)
{
        Trace("Audio meter closed");
        Timer->Enabled = false;
        cbEndpoints->Enabled = true;

        if (FBars.Length > 0)
        {
                for (int i = 0; i < FBars.Length; i++)
                        FBars[i]->Free();
                FBars.Length = 0;
        }

        pbMaster->Position = 0;
        pbMaster->Visible = false;
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::AudioMeterDisconnected(TObject *Sender)
{
        Trace("Audio meter device " + AudioMeter->Id + " disconnected");        
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::btCloseClick(TObject *Sender)
{
        int Res = AudioVolume->Close();
        if (Res != WCL_E_SUCCESS)
                Trace("Audio volume close failed", Res);
        
        Res = AudioMeter->Close();
        if (Res != WCL_E_SUCCESS)
                Trace("Audio meter close failed", Res);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::btOpenClick(TObject *Sender)
{
        if (cbEndpoints->ItemIndex == -1)
                Trace("No audio endpoints found");
        else
        {
                String Id = ((TAudioDeviceStorage*)cbEndpoints->Items->Objects[cbEndpoints->ItemIndex])->Device.Id;

                int Res = AudioMeter->Open(Id);
                if (Res != WCL_E_SUCCESS)
                        Trace("Audio meter open failed", Res);

                Res = AudioVolume->Open(Id);
                if (Res != WCL_E_SUCCESS)
                        Trace("Audio volume open failed", Res);
        }
}
//---------------------------------------------------------------------------
void TfmMain::UpdateChannelsValue()
{
        Single Value;
        int Res = AudioMeter->GetPeak(Value);
        if (Res == WCL_E_SUCCESS)
        {
                if (tbMaster->Visible)
                {
                        Value = Value * 100.00 * ((100 - tbMaster->Position) / 100.00);
                        pbMaster->Position = Value;
                }
                else
                        pbMaster->Position = Value * 100;
        }
        
        if (FBars.Length > 0)
        {
                TwclAudioPeakValues Values;
                Res = AudioMeter->GetChannelsPeak(Values);
                if (Res == WCL_E_SUCCESS && Values.Length > 0)
                {
                        for (int i = 0; i < Values.Length; i++)
                                FBars[i]->Position = Values[i] * 100;
                }
        }
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::TimerTimer(TObject *Sender)
{
        UpdateChannelsValue();
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::AudioSwitcherStateChanged(TObject *Sender,
	  const String Id, const TwclAudioDeviceState State)
{
        if (State == asActive)
                AudioSwitcherDeviceAdded(AudioSwitcher, Id);
        else
                DeleteDevice(Id);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::AudioSwitcherDefaultDeviceChanged(TObject *Sender,
	  const String Id, const TwclAudioDeviceDataFlow Flow,
      const TwclAudioDeviceRole Role)
{
        Trace("Active device changed");

        if (!AudioMeter->Active)
                SelectActiveDevice();
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::AudioVolumeOpened(TObject *Sender)
{
        Trace("Audio volume opened");
        cbEndpoints->Enabled = false;

        TwclAudioHardwareFeatures Features;
        int Res = AudioVolume->GetHardwareFeatures(Features);
        if (Res != WCL_E_SUCCESS)
                Trace("Get hardware features failed", Res);
        else
        {
                Trace("Hardware features");
                if (Features.Contains(hfVolume))
                        Trace("  Volume");
                if (Features.Contains(hfMute))
                        Trace("  Mute");
                if (Features.Contains(hfMeter))
                        Trace("  Meter");
        }

        float Volume;
        Res = AudioVolume->GetVolume(Volume);
        if (Res != WCL_E_SUCCESS)
                Trace("Get volume failed", Res);
        else
        {
                tbMaster->Visible = true;
                tbMaster->Position = 100 - Volume * 100;
        }

        bool Mute;
        Res = AudioVolume->GetMute(Mute);
        if (Res != WCL_E_SUCCESS)
                Trace("Get mute failed", Res);
        else
        {
                cbMute->Visible = true;
                cbMute->Checked = Mute;
        }
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::AudioVolumeClosed(TObject *Sender)
{
        Trace("Audio volume closed");
        cbEndpoints->Enabled = true;
        tbMaster->Visible = false;
        tbMaster->Position = 100;
        cbMute->Visible = false;
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::AudioVolumeDisconnected(TObject *Sender)
{
        Trace("Audio volume device " + AudioVolume->Id + " disconnected");
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::tbMasterChange(TObject *Sender)
{
        if (AudioVolume->Active)
        {
                int Res = AudioVolume->SetVolume((100 - tbMaster->Position) / 100.00);
                if (Res != WCL_E_SUCCESS)
                        Trace("Set volume failed", Res);
        }
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::cbMuteClick(TObject *Sender)
{
        if (AudioVolume->Active)
        {
                int Res = AudioVolume->SetMute(cbMute->Checked);
                if (Res != WCL_E_SUCCESS)
                        Trace("Set mute failed", Res);
        }
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::AudioVolumeChanged(TObject *Sender,
      const bool Muted, const float Volume,
      const TwclAudioPeakValues Volumes)
{
        if (AudioVolume->Active)
        {
                Trace("Volume changed");

                cbMute->Checked = Muted;
                tbMaster->Position = 100 - Volume * 100;
        }
}
//---------------------------------------------------------------------------

