WASAPI_Notification_Interfaces/IAudioSessionEvents.c

190 lines
6.1 KiB
C

#include "IAudioSessionEvents.h"
static IAudioSessionEventsVtbl* pvtbl = NULL;
static HRESULT CreateVTBL(void);
// Creates a session events interface and gives it the relevant information
HRESULT InitializeAudioSessionEvents(myIAudioSessionEvents** this, IAudioSessionControl * pParentInterface, IAudioSessionControl *** pControlInterfaceArrayAddress)
{
// If the vtbl of all the events functions hasn't already been created then make it now
// Return the error from the vtbl creation if there is a problem
HRESULT result = S_OK;
if (!pvtbl) result = CreateVTBL();
if (result) return result;
// The VTBL is constant for all events interfaces
// There are different interfaces with different parent interfaces and refernce numbers
//Assign memory for the events struct. Cast the pointer returned from malloc to the correct type
myIAudioSessionEvents* AudioSessionEvents;
AudioSessionEvents = (myIAudioSessionEvents*) malloc(sizeof(myIAudioSessionEvents));
//printf("\nMalloc: %p", AudioSessionEvents);
if (!AudioSessionEvents)
{
return E_OUTOFMEMORY;
}
// Add the virtual table to the strut
AudioSessionEvents->lpVtbl = pvtbl;
AudioSessionEvents->cRef = 0;
AudioSessionEvents->pParentAudioSessionControl = pParentInterface;
AudioSessionEvents->pControlInterfaceArrayAddress = pControlInterfaceArrayAddress;
*this = AudioSessionEvents;
//printf("\nSession events: %p", *this);
return S_OK;
}
HRESULT CreateVTBL(void)
{
// Initializes the IAudioSessionNotification struct, this involves creating it, allocating memory, setting initial vaules and assigning the functions to be used
//Allocate memory for the vtable
pvtbl = malloc(sizeof(IAudioSessionEventsVtbl));
if (!pvtbl)
{
// If the vtable memory cannot be assigned
return E_OUTOFMEMORY;
}
// Asign all the functions
pvtbl->AddRef = (*IAudioSessionEventsAddRef);
pvtbl->QueryInterface = (*IAudioSessionEventsQueryInterface);
pvtbl->Release = (*IAudioSessionEventsRelease);
pvtbl->OnChannelVolumeChanged = (*IAudioSessionEventsOnChannelVolumeChanged);
pvtbl->OnDisplayNameChanged = (*IAudioSessionEventsOnDisplayNameChanged);
pvtbl->OnGroupingParamChanged = (*IAudioSessionEventsOnGroupingParamChanged);
pvtbl->OnIconPathChanged = (*IAudioSessionEventsOnIconPathChanged);
pvtbl->OnSessionDisconnected = (*IAudioSessionEventsOnSessionDisconnected);
pvtbl->OnSimpleVolumeChanged = (*IAudioSessionEventsOnSimpleVolumeChanged);
pvtbl->OnStateChanged = (*IAudioSessionEventsOnStateChanged);
//printf("\nEvents VTBL at %p", pvtbl);
return S_OK;
}
HRESULT STDMETHODCALLTYPE IAudioSessionEventsQueryInterface(IAudioSessionEvents* this, REFIID riid, void** ppvoid)
{
if (!this)
{
return E_INVALIDARG;
}
// Validate other parameters.
if (!ppvoid)
{
return E_INVALIDARG;
}
// Set the output pointer to NULL.
*ppvoid = NULL;
// Check the interface identifier. memcmp() returns 0 if they are equal.
if (memcmp(riid, &IID_IUnknown, sizeof(IID)) && memcmp(riid, &IID_IAudioSessionNotification, sizeof(IID)))
{
return E_NOINTERFACE;
}
// The interface is supported. Increment the reference count and return.
this->lpVtbl->AddRef(this);
*ppvoid = this;
return S_OK;
}
ULONG STDMETHODCALLTYPE IAudioSessionEventsAddRef(IAudioSessionEvents* this)
{
// Cast the standard interface to my interface to allow access to cRef
myIAudioSessionEvents* castInterface = (myIAudioSessionEvents*)this;
return InterlockedIncrement(&castInterface->cRef);
}
ULONG STDMETHODCALLTYPE IAudioSessionEventsRelease(IAudioSessionEvents* this)
{
// Cast the standard interface to my interface to allow access to cRef
myIAudioSessionEvents* castInterface = (myIAudioSessionEvents*)this;
ULONG cRef = InterlockedDecrement(&castInterface->cRef);
if (cRef == 0)
{
free(castInterface->lpVtbl);
free(castInterface);
//printf("\nAudio session notification memory freed");
}
//printf("\nNotification release, ref count : %ld\n", cRef);
return cRef;
}
HRESULT IAudioSessionEventsOnChannelVolumeChanged(IAudioSessionEvents* this, DWORD ChannelCount, float* NewChannelVolumeArray, DWORD ChangedChannel, LPCGUID EventContext)
{
printf("\nChannel %d volume changed to %f.3", ChangedChannel, NewChannelVolumeArray[ChangedChannel]);
return S_OK;
}
HRESULT IAudioSessionEventsOnDisplayNameChanged(IAudioSessionEvents* this, LPCWSTR NewDisplayName, LPCGUID EventContext)
{
printf("\nNew session display name: %ws", NewDisplayName);
return S_OK;
}
HRESULT IAudioSessionEventsOnGroupingParamChanged(IAudioSessionEvents* this, LPCGUID NewGroupingParam, LPCGUID EventContext)
{
printf("\nNew grouping param");
return S_OK;
}
HRESULT IAudioSessionEventsOnIconPathChanged(IAudioSessionEvents* this, LPCWSTR NewIconPath, LPCGUID EventContext)
{
printf("\nNew icon path");
return S_OK;
}
HRESULT IAudioSessionEventsOnSessionDisconnected(IAudioSessionEvents* this, AudioSessionDisconnectReason DisconnectReason)
{
myIAudioSessionEvents* castInterface = (myIAudioSessionEvents*)this;
printf("\nSession with control interface at %p disconnected.", castInterface->pParentAudioSessionControl);
// Delete the unused control interface from the array of interfaces
// It seems like the session is not disconnected generally, instead it is marked as inactive and IAudioSessionEventsOnStateChanged() is called
// Seems like the best option would be to have the control interface deleted and released when that is called and then just a confirmation when this function is called
// Supposedly releasing the interface in the state change callback should make this unnecessary but just in case I think it is worth doing
return S_OK;
}
HRESULT IAudioSessionEventsOnSimpleVolumeChanged(IAudioSessionEvents* this, float NewVolume, BOOL NewMute, LPCGUID EventContext)
{
printf("\nSession simple volume changed to %f. Session is ", NewVolume);
if (NewMute) printf("muted");
else printf("ummuted");
return S_OK;
}
HRESULT IAudioSessionEventsOnStateChanged(IAudioSessionEvents* this, AudioSessionState NewState)
{
printf("\nSession state changed to ");
switch (NewState)
{
case(2):
printf("Expired");
break;
case(1):
printf("Active");
break;
case(0):
printf("Inactive");
break;
default:
printf("Unknown");
break;
}
return S_OK;
}