1. the events only fire if i change the volume for the purebasic app itself.
2. the volume event fired seems to return all audio sessions open.
Help would be appreciated.
Code: Select all
EnableExplicit
Enumeration
#AudioSessionStateInactive
#AudioSessionStateActive
#AudioSessionStateExpired
EndEnumeration
#CLSCTX_ALL = #CLSCTX_INPROC_SERVER | #CLSCTX_INPROC_HANDLER | #CLSCTX_LOCAL_SERVER | #CLSCTX_REMOTE_SERVER
Interface IMMDeviceEnumerator Extends IUnknown
EnumAudioEndpoints(dataFlow, dwStateMask, ppDevices)
GetDefaultAudioEndpoint(dataFlow, role, ppEndpoint)
GetDevice(pwstrId, ppDevice)
RegisterEndpointNotificationCallback(pClient)
UnregisterEndpointNotificationCallback(pClient)
EndInterface
Interface IMMDevice Extends IUnknown
Activate(iid, dwClsCtx, pActivationParams, ppInterface)
OpenPropertyStore(stgmAccess, ppProperties)
GetId(ppstrId)
GetState(pdwState)
EndInterface
Interface IAudioSessionManager Extends IUnknown
GetAudioSessionControl(AudioSessionGuid, StreamFlags, SessionControl)
GetSimpleAudioVolume(AudioSessionGuid, StreamFlags, AudioVolume)
EndInterface
Interface IAudioSessionManager2 Extends IAudioSessionManager
GetSessionEnumerator(SessionEnum)
RegisterSessionNotification(Notification)
UnregisterSessionNotification(Notification)
RegisterDuckNotification(sessionID, duckNotification)
UnregisterDuckNotification(duckNotification)
EndInterface
Interface IAudioSessionNotification Extends IUnknown
OnSessionCreated(NewSession)
EndInterface
Interface IAudioSessionControl Extends IUnknown
GetState(pRetVal)
GetDisplayName(*pRetVal)
SetDisplayName(Value, EventContext)
GetIconPath(pRetVal)
SetIconPath(Value, EventContext)
GetGroupingParam(pRetVal)
SetGroupingParam(Override, EventContext)
RegisterAudioSessionNotification(NewNotifications)
UnregisterAudioSessionNotification(NewNotifications)
EndInterface
Interface IAudioSessionControl2 Extends IAudioSessionControl
GetSessionIdentifier(*pRetVal)
GetSessionInstanceIdentifier(*pRetVal)
GetProcessId(pRetVal)
IsSystemSoundsSession()
SetDuckingPreference(optOut)
EndInterface
Interface IAudioSessionEnumerator Extends IUnknown
GetCount(count)
GetSession(sessionCount, session)
EndInterface
Interface IAudioSessionEvents Extends IUnknown
OnDisplayNameChanged(NewDisplayName, EventContext)
OnIconPathChanged(NewIconPath, EventContext)
OnSimpleVolumeChanged(NewVolume, NewMute, EventContext)
OnChannelVolumeChanged(ChannelCount, NewChannelVolumeArray, ChangedChannel, EventContext)
OnGroupingParamChanged(NewGroupingParam, EventContext)
OnStateChanged(NewState)
OnSessionDisconnected(DisconnectReason)
EndInterface
Global deviceEnumerator.IMMDeviceEnumerator
Global defaultRender.IMMDevice
Global ev_sessionMgr.IAudioSessionManager
Global sessionMgr.IAudioSessionManager2
Global sessionList.IAudioSessionEnumerator
Global MyAudioSessionNotification.IAudioSessionNotification
Global sessionEvents.IAudioSessionEvents
Global pControl.IAudioSessionControl
Structure MyAudioSessionNotificationObj
lpVtbl.i
RefCount.l
EndStructure
Structure MyAudioSessionEventsObj
lpVtbl.i
RefCount.l
ProcessID.l
*SessionID
EndStructure
Global *MyAudioSessionNotificationVTable = #Null
Global *MyAudioSessionEventsVTable = #Null
Procedure MyAddRef(*Object)
;Debug #PB_Compiler_Procedure
Protected newCount = PeekL(*Object + SizeOf(Quad)) + 1
PokeL(*Object + SizeOf(Quad), newCount)
ProcedureReturn newCount
EndProcedure
Procedure MyQueryInterface(*Object, riid.i, ppvObject.i)
;Debug #PB_Compiler_Procedure
PokeI(ppvObject, *Object)
MyAddRef(*Object)
ProcedureReturn #S_OK
EndProcedure
Procedure MyRelease(*Object)
;Debug #PB_Compiler_Procedure
Protected newCount = PeekL(*Object + SizeOf(Quad)) - 1
PokeL(*Object + SizeOf(Quad), newCount)
If newCount = 0
FreeStructure(*Object)
EndIf
ProcedureReturn newCount
EndProcedure
Procedure MySessionEvents_OnSessionDisconnected(*Object.MyAudioSessionEventsObj, DisconnectReason)
Debug #PB_Compiler_Procedure
Debug "Session Disconnected: PID=" + Str(*Object\ProcessID) + ", Reason=" + Str(DisconnectReason)
ProcedureReturn #S_OK
EndProcedure
Procedure MySessionEvents_OnDisplayNameChanged(*Object.MyAudioSessionEventsObj, NewDisplayName, EventContext)
Debug #PB_Compiler_Procedure
ProcedureReturn #S_OK
EndProcedure
Procedure MySessionEvents_OnIconPathChanged(*Object.MyAudioSessionEventsObj, NewIconPath, EventContext)
Debug #PB_Compiler_Procedure
ProcedureReturn #S_OK
EndProcedure
Procedure MySessionEvents_OnSimpleVolumeChanged(*Object.MyAudioSessionEventsObj, NewVolume, NewMute, EventContext)
Debug #PB_Compiler_Procedure
Debug PeekS(*Object\SessionID)
ProcedureReturn #S_OK
EndProcedure
Procedure MySessionEvents_OnChannelVolumeChanged(*Object.MyAudioSessionEventsObj, ChannelCount, NewChannelVolumeArray, ChangedChannel, EventContext)
Debug #PB_Compiler_Procedure
ProcedureReturn #S_OK
EndProcedure
Procedure MySessionEvents_OnGroupingParamChanged(*Object.MyAudioSessionEventsObj, NewGroupingParam, EventContext)
Debug #PB_Compiler_Procedure
ProcedureReturn #S_OK
EndProcedure
Procedure MySessionEvents_OnStateChanged(*Object.MyAudioSessionEventsObj, NewState)
Debug #PB_Compiler_Procedure
ProcedureReturn #S_OK
EndProcedure
Procedure CreateMyAudioSessionEvents(ProcessID, *SessionID)
;Debug #PB_Compiler_Procedure
Protected *pObj.MyAudioSessionEventsObj = AllocateStructure(MyAudioSessionEventsObj)
If *pObj = 0
ProcedureReturn #Null
EndIf
If *MyAudioSessionEventsVTable = #Null
*MyAudioSessionEventsVTable = AllocateMemory(10 * SizeOf(Quad))
If *MyAudioSessionEventsVTable = #Null
FreeStructure(*pObj)
ProcedureReturn #Null
EndIf
PokeI(*MyAudioSessionEventsVTable + 0 * SizeOf(Quad), @MyQueryInterface())
PokeI(*MyAudioSessionEventsVTable + 1 * SizeOf(Quad), @MyAddRef())
PokeI(*MyAudioSessionEventsVTable + 2 * SizeOf(Quad), @MyRelease())
PokeI(*MyAudioSessionEventsVTable + 3 * SizeOf(Quad), @MySessionEvents_OnDisplayNameChanged())
PokeI(*MyAudioSessionEventsVTable + 4 * SizeOf(Quad), @MySessionEvents_OnIconPathChanged())
PokeI(*MyAudioSessionEventsVTable + 5 * SizeOf(Quad), @MySessionEvents_OnSimpleVolumeChanged())
PokeI(*MyAudioSessionEventsVTable + 6 * SizeOf(Quad), @MySessionEvents_OnChannelVolumeChanged())
PokeI(*MyAudioSessionEventsVTable + 7 * SizeOf(Quad), @MySessionEvents_OnGroupingParamChanged())
PokeI(*MyAudioSessionEventsVTable + 8 * SizeOf(Quad), @MySessionEvents_OnStateChanged())
PokeI(*MyAudioSessionEventsVTable + 9 * SizeOf(Quad), @MySessionEvents_OnSessionDisconnected())
EndIf
*pObj\lpVtbl = *MyAudioSessionEventsVTable
*pObj\RefCount = 1
*pObj\ProcessID = ProcessID
*pObj\SessionID = AllocateMemory(StringByteLength(PeekS(*SessionID)) + 2)
If *pObj\SessionID
PokeS(*pObj\SessionID, PeekS(*SessionID))
EndIf
ProcedureReturn *pObj
EndProcedure
Procedure MyOnSessionCreated(*Object, pNewSession.IAudioSessionControl2)
;Debug #PB_Compiler_Procedure
Protected state, *sIdentifier, *dName, PID, hr
pNewSession\GetProcessId(@PID)
pNewSession\GetState(@state)
pNewSession\GetSessionInstanceIdentifier(@*sIdentifier)
If pNewSession And PID > 0
Debug "New audio session created. PID: " + Str(PID)
sessionEvents = CreateMyAudioSessionEvents(PID, *sIdentifier)
hr = ev_sessionMgr\GetAudioSessionControl(*sIdentifier, 0, @pControl)
If hr <> #S_OK
Debug "Error getting Session Control: " + Hex(hr)
EndIf
If sessionEvents
hr = pControl\RegisterAudioSessionNotification(sessionEvents)
If hr <> #S_OK
Debug "Error registering session events: " + Hex(hr)
MyRelease(sessionEvents)
EndIf
EndIf
EndIf
CoTaskMemFree_(*sIdentifier)
ProcedureReturn #S_OK
EndProcedure
Procedure CreateMyAudioSessionNotification()
;Debug #PB_Compiler_Procedure
Protected *pObj.MyAudioSessionNotificationObj = AllocateStructure(MyAudioSessionNotificationObj)
If *pObj = 0
ProcedureReturn #Null
EndIf
; Allocate and initialize the global vtable if it hasn't been created.
If *MyAudioSessionNotificationVTable = #Null
*MyAudioSessionNotificationVTable = AllocateMemory(4 * SizeOf(Quad))
If *MyAudioSessionNotificationVTable = #Null
FreeStructure(*pObj)
ProcedureReturn #Null
EndIf
PokeI(*MyAudioSessionNotificationVTable + 0 * SizeOf(Quad), @MyQueryInterface())
PokeI(*MyAudioSessionNotificationVTable + 1 * SizeOf(Quad), @MyAddRef())
PokeI(*MyAudioSessionNotificationVTable + 2 * SizeOf(Quad), @MyRelease())
PokeI(*MyAudioSessionNotificationVTable + 3 * SizeOf(Quad), @MyOnSessionCreated())
EndIf
*pObj\lpVtbl = *MyAudioSessionNotificationVTable
*pObj\RefCount = 1
ProcedureReturn *pObj
EndProcedure
Procedure CreateSessionManager()
;Debug #PB_Compiler_Procedure
Protected hr, PID, *sIdentifier
hr = CoCreateInstance_(?uuidof_MMDeviceEnumerator, #Null, #CLSCTX_INPROC_SERVER, ?uuidof_IMMDeviceEnumerator, @deviceEnumerator)
If hr <> #S_OK
Debug "CoCreateInstance_(MMDeviceEnumerator) failed, hr=" + Hex(hr)
EndIf
hr = deviceEnumerator\GetDefaultAudioEndpoint(0, 0, @defaultRender)
If hr <> #S_OK
Debug "GetDefaultAudioEndpoint(eRender) failed, hr=" + Hex(hr)
EndIf
If defaultRender\Activate(?IID_IAudioSessionManager2, #CLSCTX_ALL, #Null, @sessionMgr) <> #S_OK
Debug "Activate IAudioSessionManager2 failed"
EndIf
If defaultRender\Activate(?IID_IAudioSessionManager, #CLSCTX_ALL, #Null, @ev_sessionMgr) <> #S_OK
Debug "Activate IAudioSessionManager2 failed"
EndIf
ev_sessionMgr\AddRef()
ev_sessionMgr\Release()
sessionMgr\AddRef()
sessionMgr\Release()
deviceEnumerator\Release()
defaultRender\Release()
ProcedureReturn hr
EndProcedure
Procedure ProcessEnumeratedSessions()
;Debug #PB_Compiler_Procedure
Protected count.l, i.l, session.IAudioSessionControl2
sessionList\GetCount(@count)
For i = 0 To count - 1
sessionList\GetSession(i, @session)
If session <> #Null
MyOnSessionCreated(MyAudioSessionNotification, session)
session\Release()
EndIf
Next
EndProcedure
Procedure MTAThread(val)
Debug #PB_Compiler_Procedure
Protected hr = CoInitializeEx_(#Null, #COINIT_MULTITHREADED)
If hr <> #S_OK And hr <> #RPC_E_CHANGED_MODE
Debug "CoInitializeEx_ in new thread failed, hr=" + Hex(hr)
ProcedureReturn
EndIf
If CreateSessionManager() = #S_OK
If sessionMgr\GetSessionEnumerator(@sessionList) = #S_OK
ProcessEnumeratedSessions()
MyAudioSessionNotification = CreateMyAudioSessionNotification()
If MyAudioSessionNotification = #Null
Debug "Failed to create IAudioSessionNotification COM object."
EndIf
hr = sessionMgr\RegisterSessionNotification(MyAudioSessionNotification)
If hr <> #S_OK
Debug "RegisterSessionNotification failed, hr=" + Hex(hr)
EndIf
sessionList\Release()
Else
Debug "Failed to create IAudioSessionNotification callback object."
EndIf
Else
Debug "Get Session Enumerator failed"
EndIf
Repeat
Delay(1000)
ForEver
CoUninitialize_()
End
EndProcedure
CreateThread(@MTAThread(), 0)
Repeat
Delay(1000)
ForEver
DataSection
IID_IUnknown:
Data.l $00000000
Data.w $0000, $0000
Data.b $C0, $00, $00, $00, $00, $00, $00, $46
uuidof_MMDeviceEnumerator:
Data.l $BCDE0395
Data.w $E52F, $467C
Data.b $8E, $3D, $C4, $57, $92, $91, $69, $2E
uuidof_IMMDeviceEnumerator:
Data.l $A95664D2
Data.w $9614, $4F35
Data.b $A7, $46, $DE, $8D, $B6, $36, $17, $E6
IID_IAudioSessionManager:
Data.l $BFA971F1
Data.w $4D5E, $40BB
Data.b $93, $5E, $96, $70, $39, $BF, $BE, $E4
IID_IAudioSessionManager2:
Data.l $77AA99A0
Data.w $1BD6, $484F
Data.b $8B, $C7, $2C, $65, $4C, $9A, $9B, $6F
IID_IAudioSessionNotification:
Data.l $641DD20B
Data.w $4D41, $49CC
Data.b $AB, $A3, $17, $4B, $94, $77, $BB, $08
IID_IAudioSessionEnumerator:
Data.l $E2F5BB11
Data.w $0570, $40CA
Data.b $AC, $DD, $3A, $A0, $12, $77, $DE, $E8
IID_IAudioSessionControl:
Data.l $F4B1A599
Data.w $7266, $4319
Data.b $A8, $CA, $E7, $0A, $CB, $11, $E8, $CD
IID_IAudioSessionControl2:
Data.l $BFB7FF88
Data.w $7239, $4FC9
Data.b $8D, $A2, $B2, $7C, $48, $D6, $9D, $5D
IID_IAudioSessionEvents:
Data.l $24918ACC
Data.w $64B3, $37C1
Data.b $8C, $A9, $74, $A6, $6E, $99, $57, $A8
EndDataSection