Updated by netmaestro for Get and set Mute
Updated by Nico retrieve event sound level modification by user
For Vista and more.
Run as administrator account!
For compatibility x64 procedure InterlockedExchange asm by Mistrel implemented, here:
http://www.purebasic.fr/english/viewtop ... edExchange
Compile with thread activated.

Code: Select all
#CLSCTX_INPROC_SERVER = $01
#CLSCTX_INPROC_HANDLER = $02
#CLSCTX_LOCAL_SERVER = $04
#CLSCTX_REMOTE_SERVER = $10
#CLSCTX_ALL = #CLSCTX_INPROC_SERVER|#CLSCTX_INPROC_HANDLER|#CLSCTX_LOCAL_SERVER|#CLSCTX_REMOTE_SERVER
#CLSCTX_INPROC = #CLSCTX_INPROC_SERVER|#CLSCTX_INPROC_HANDLER
#CLSCTX_SERVER = #CLSCTX_INPROC_SERVER|#CLSCTX_LOCAL_SERVER|#CLSCTX_REMOTE_SERVER
Enumeration ; Flow
#eRender ; se connecter sur audio
#eCapture ; capturer audio
#eAll ; tous
EndEnumeration
Enumeration ;Role
#eConsole ; system
#eMultimedia ; (haut parleur ...)
#eCommunications ; (micro...)
EndEnumeration
CompilerIf #PB_Compiler_Thread = 0
MessageRequester("Info", "Ce code se compile avec la Gestion des Threads cochée!")
End
CompilerEndIf
Interface IMMDeviceEnumerator Extends IUnknown
EnumAudioEndpoints(Flow.l, dwStateMask.l, IMMDeviceCollection.i)
GetDefaultAudioEndpoint(Flow.l, role.l, IMMDevice.i)
GetDevice(pwstrId.i, IMMDevice.i)
RegisterEndpointNotificationCallback(IMMNotificationClient.i)
UnregisterEndpointNotificationCallback(IMMNotificationClient.i)
EndInterface
Interface IAudioEndpointVolume Extends IUnknown
RegisterControlChangeNotify(pNotify.i)
UnregisterControlChangeNotify(pNotify.i)
GetChannelCount(puchannelCount.i)
SetMasterVolumeLevel(levelDB.f, *context.Guid)
SetMasterVolumeLevelScalar(level.f, *context.Guid)
GetMasterVolumeLevel(pflevelDB.i)
GetMasterVolumeLevelScalar(pflevel.i)
SetChannelVolumeLevel(uchannel.l, levelDB.f, *context.Guid)
SetChannelVolumeLevelScalar(uchannel.l, level.f, *context.Guid)
GetChannelVolumeLevel(uchannel.l, plevelDB.i)
GetChannelVolumeLevelScalar(uchannel.l, pflevel.i)
SetMute(mute.l, *context.Guid)
GetMute(pmute.i)
GetVolumeStepInfo(puStep.i, pustepCount.i)
VolumeStepUp(*context.Guid)
VolumeStepDown(*context.Guid)
QueryHardwareSupport(pdwHardwareSupportMask.i)
GetVolumeRange(pflVolumeMindB.i, pflVolumeMaxdB.i, pflVolumeIncrementdB.i)
EndInterface
Interface IMMDevice Extends IUnknown
Activate(iid.i, dwClsCtx.l, pActivationParams.i, ppInterface.i)
OpenPropertyStore(stgmAccess.i, IPropertyStore.i)
GetId(ppstrId.i)
GetState(pdwState.i)
EndInterface
Structure AUDIO_VOLUME_NOTIFICATION_DATA Align #PB_Structure_AlignC
guidEventContext.GUID
bMuted.l
fMasterVolume.f
nChannels.l
afChannelVolumes.f[1]
EndStructure
Interface IAudioEndpointVolumeCallback Extends IUnknown
OnNotify(*pNotify.AUDIO_VOLUME_NOTIFICATION_DATA)
EndInterface
Structure AudioEndpointVolumeCallback Align #PB_Structure_AlignC
*pAudioEndpointVolume
QueryInterface.i
AddRef.i
Release.i
OnNotify.i
pAudioEndpointVolumeCallback.IAudioEndpointVolumeCallback
Refcount.i
Event.l
MyGuid.GUID
EndStructure
Global AudioEndpointVolumeCallback.AudioEndpointVolumeCallback
Procedure.i ConvertToUnicode(AsciiOrUnicode.s)
Protected *UnicodeString
Protected LenMemoryUnicode.l
LenMemoryUnicode = StringByteLength(AsciiOrUnicode , #PB_Unicode)
*UnicodeString = AllocateMemory(LenMemoryUnicode + 2)
If *UnicodeString <> 0
PokeS(*UnicodeString, AsciiOrUnicode, Len(AsciiOrUnicode), #PB_Unicode)
ProcedureReturn *UnicodeString
EndIf
ProcedureReturn 0
EndProcedure
Procedure.i CLSIDFromString(ClsidString.s, *CLSID.CLSID)
Protected *UnicodeString
If *CLSID <> 0
If ClsidString <> ""
CompilerIf #PB_Compiler_Unicode =0
*UnicodeString = ConvertToUnicode(ClsidString)
CompilerElse
*UnicodeString = @ClsidString
CompilerEndIf
If *UnicodeString <> 0
If CLSIDFromString_(*UnicodeString, @REFIID.CLSID) >= #S_OK
CopyMemory(REFIID, *CLSID, SizeOf(CLSID))
ProcedureReturn *CLSID
EndIf
CompilerIf #PB_Compiler_Unicode =0
FreeMemory(*UnicodeString)
CompilerEndIf
EndIf
EndIf
Else
ProcedureReturn 0
EndIf
FillMemory(*CLSID, SizeOf(CLSID), #Null)
ProcedureReturn *CLSID
EndProcedure
Procedure.i InterlockedExchange(*Destination.Integer, Value.i)
EnableASM
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
!mov rcx, [p.p_Destination]
!mov rax, [p.v_Value]
!lock xchg [rcx], rax
CompilerElse
!mov ecx, [p.p_Destination]
!mov eax, [p.v_Value]
!lock xchg [ecx], eax
CompilerEndIf
DisableASM
ProcedureReturn
EndProcedure
Procedure.i AudioEndpointVolumeCallback_AddRef(*pObject.AudioEndpointVolumeCallback)
Protected ulRef.i
Debug "AudioEndpointVolumeCallback_AddRef"
ulRef = InterlockedExchange(@*pObject\Refcount, *pObject\Refcount + 1)
Debug ulRef + 1
Debug "*pObject\Refcount = " + Str(*pObject\Refcount)
ProcedureReturn ulRef + 1
EndProcedure
Procedure.l AudioEndpointVolumeCallback_QueryInterface(*pObject.AudioEndpointVolumeCallback, *REFIID.CLSID, *ppvObj.INTEGER)
Protected REFIID.CLSID, Null.CLSID
Debug "AudioEndpointVolumeCallback_QueryInterface +++++++++++++++++++++++++++++++++++"
If *ppvObj = 0
ProcedureReturn #E_POINTER
ElseIf CompareMemory(CLSIDFromString("{657804fa-d6ad-4496-8a60-352752af4f89}", @REFIID), *REFIID, 16)
AudioEndpointVolumeCallback_AddRef(*pObject)
*ppvObj\i = *pObject
*pObject\pAudioEndpointVolumeCallback\AddRef()
ElseIf CompareMemory(CLSIDFromString("{00000000-0000-0000-0000-000000000000}", @Null), *REFIID, 16)
AudioEndpointVolumeCallback_AddRef(*pObject)
*ppvObj\i = *pObject
*pObject\pAudioEndpointVolumeCallback\AddRef()
Else
*ppvObj\i = #Null
ProcedureReturn #E_NOINTERFACE
EndIf
ProcedureReturn #S_OK
EndProcedure
Procedure.i AudioEndpointVolumeCallback_Release(*pObject.AudioEndpointVolumeCallback)
Protected ulRef.i
Debug "AudioEndpointVolumeCallback_Release"
ulRef = InterlockedExchange(@*pObject\Refcount, *pObject\Refcount - 1)
Debug ulRef + 1
Debug "*pObject\Refcount = " + Str(*pObject\Refcount)
If ulRef = 0
AudioEndpointVolumeCallback\pAudioEndpointVolumeCallback = 0
Debug "delete element --------------------------------"
*pObject\Refcount = 0
*pObject = 0
EndIf
ProcedureReturn ulRef + 1
EndProcedure
Procedure.l AudioEndpointVolumeCallback_OnNotify(*pObject.AudioEndpointVolumeCallback, *pNotify.AUDIO_VOLUME_NOTIFICATION_DATA)
Debug "AudioEndpointVolumeCallback_OnNotify"
; Debug *pNotify\fMasterVolume
; Debug "----------------------------------------------------"
; Debug *pObject\MyGuid\Data1
; Debug *pObject\MyGuid\Data2
; Debug *pObject\MyGuid\Data3
; Debug *pObject\MyGuid\Data4
; Debug "----------------------------------------------------"
;
; Debug *pNotify\guidEventContext\Data1
; Debug *pNotify\guidEventContext\Data2
; Debug *pNotify\guidEventContext\Data3
; Debug *pNotify\guidEventContext\Data4
; Debug "----------------------------------------------------"
If CompareMemory(*pObject\MyGuid, *pNotify\guidEventContext, 16) = 0
SetGadgetState(0, 100 * *pNotify\fMasterVolume)
If *pNotify\bMuted = 0
SetGadgetText(1, "Mute Off")
ElseIf *pNotify\bMuted = 1
SetGadgetText(1, "Mute On")
EndIf
EndIf
;guidEventContext.GUID
Debug *pNotify\bMuted.l
Debug *pNotify\nChannels
; afChannelVolumes.f[1]
ProcedureReturn #S_OK
EndProcedure
Procedure.i DataAudioEndPointVolume(Option.l, InterfaceCom.i=0)
Static AudioEndPointVolume.i
If Option = 1
If InterfaceCom <> 0
AudioEndPointVolume = InterfaceCom
ProcedureReturn #True
EndIf
ElseIf Option = 2
If AudioEndPointVolume <> 0
ProcedureReturn AudioEndPointVolume
EndIf
ElseIf Option = 3
AudioEndPointVolume = 0
ProcedureReturn 0
EndIf
ProcedureReturn #False
EndProcedure
Procedure.l ComEvent_SetAudioEndpointVolumeCallback()
Protected Volume.IAudioEndpointVolume
Protected Guid.GUID
Volume = DataAudioEndPointVolume(2)
If Volume <> 0
If AudioEndpointVolumeCallback <> 0
If AudioEndpointVolumeCallback\Refcount = 0
CopyMemory(CLSIDFromString("{00000000-1111-5555-0000-000000000000}", @Guid), AudioEndpointVolumeCallback\MyGuid, 16)
AudioEndpointVolumeCallback\QueryInterface = @AudioEndpointVolumeCallback_QueryInterface()
AudioEndpointVolumeCallback\AddRef = @AudioEndpointVolumeCallback_AddRef()
AudioEndpointVolumeCallback\Release = @AudioEndpointVolumeCallback_Release()
AudioEndpointVolumeCallback\OnNotify = @AudioEndpointVolumeCallback_OnNotify()
AudioEndpointVolumeCallback\pAudioEndpointVolume = @AudioEndpointVolumeCallback\QueryInterface
AudioEndpointVolumeCallback\pAudioEndpointVolumeCallback = @AudioEndpointVolumeCallback\pAudioEndpointVolume
AudioEndpointVolumeCallback\pAudioEndpointVolumeCallback\AddRef()
EndIf
If Volume\RegisterControlChangeNotify(@AudioEndpointVolumeCallback) >= #S_OK
ProcedureReturn #S_OK
EndIf
EndIf
EndIf
ProcedureReturn -1
EndProcedure
Procedure.l ComEvent_FreeAudioEndpointVolumeCallback()
Protected Volume.IAudioEndpointVolume
Volume = DataAudioEndPointVolume(2)
If Volume <> 0
If Volume\UnregisterControlChangeNotify(AudioEndpointVolumeCallback) >= #S_OK
ProcedureReturn #S_OK
EndIf
EndIf
ProcedureReturn -1
EndProcedure
Procedure.l Com_GetDefaultAudioEndPointVolume()
Protected pdeviceEnumerator.IMMDeviceEnumerator
Protected pAudioEndpointVolume.IAudioEndpointVolume
Protected pdefaultDevice.IMMDevice
Protected AudioEndpointVolumeCallback.IAudioEndpointVolumeCallback, RET.l=-1
If CoCreateInstance_(?uuidof_MMDeviceEnumerator, #Null, #CLSCTX_INPROC_SERVER, ?uuidof_IMMDeviceEnumerator,@pdeviceEnumerator) < #S_OK
Goto error
ElseIf pdeviceEnumerator = 0
Goto error
EndIf
If pdeviceEnumerator\GetDefaultAudioEndpoint(#eRender, #eMultimedia, @pdefaultDevice) < #S_OK
Goto error:
ElseIf pdefaultDevice = 0
Goto error
EndIf
If pdefaultDevice\Activate(?uuidof_IAudioEndpointVolume, #CLSCTX_INPROC_SERVER, #Null, @pAudioEndpointVolume.IAudioEndpointVolume) < #S_OK
Goto error
ElseIf pAudioEndpointVolume = 0
Goto error
Else
RET = #S_OK
Goto NoError
EndIf
Error:
If pAudioEndpointVolume <> 0
pAudioEndpointVolume\Release()
EndIf
NoError:
DataAudioEndPointVolume(1, pAudioEndpointVolume)
If pdefaultDevice <> 0
pdefaultDevice\Release()
EndIf
If pdeviceEnumerator <> 0
pdeviceEnumerator\Release()
EndIf
ProcedureReturn RET
EndProcedure
Procedure.l Com_FreeDefaultAudioEndPointVolume()
Protected Volume.IAudioEndpointVolume
Volume = DataAudioEndPointVolume(2)
If Volume <> 0
Volume\release()
DataAudioEndPointVolume(3)
ProcedureReturn #S_OK
EndIf
ProcedureReturn -1
EndProcedure
Procedure.l MediaSystemGetVolume()
Protected Volume.IAudioEndpointVolume
Protected volf.f
Volume = DataAudioEndPointVolume(2)
If Volume <> 0
If Volume\GetMasterVolumeLevelScalar(@volf) >= #S_OK
volf = Round(volf * 100, #PB_Round_Nearest)
ProcedureReturn Int(volf)
EndIf
EndIf
ProcedureReturn -1
EndProcedure
Procedure.l MediaSystemGetMute()
Protected Volume.IAudioEndpointVolume
Protected mute.l
Volume = DataAudioEndPointVolume(2)
If Volume <> 0
If Volume\GetMute(@mute) >= #S_OK
ProcedureReturn mute
EndIf
EndIf
ProcedureReturn -1
EndProcedure
Procedure.l MediaSystemSetVolume(vol.l)
Protected Volume.IAudioEndpointVolume
Protected volf.f
If vol < 0 : vol = 0 : EndIf
If vol > 100 : vol = 100 : EndIf
Volume = DataAudioEndPointVolume(2)
If Volume <> 0
volf = vol / 100
If Volume\SetMasterVolumeLevelScalar(volf, AudioEndpointVolumeCallback\MyGuid) >= #S_OK
ProcedureReturn #True
EndIf
EndIf
ProcedureReturn -1
EndProcedure
Procedure.l MediaSystemSetMute(value.l)
Protected Volume.IAudioEndpointVolume
Protected mute.l=1
Volume = DataAudioEndPointVolume(2)
If Volume <> 0
If Volume\SetMute(value, AudioEndpointVolumeCallback\MyGuid) >= #S_OK
ProcedureReturn #True
EndIf
EndIf
ProcedureReturn -1
EndProcedure
; Procedure test()
; Protected Volume.IAudioEndpointVolume
;
; ;test fonction queryinterface
; Volume2 = DataAudioEndPointVolume(2)
; AudioEndpointVolumeCallback_QueryInterface(Volume2, @REFIID.CLSID, @Volume)
;
; Volume\AddRef()
; EndProcedure
CoInitialize_(#Null)
If OpenWindow(0, 100, 200, 400, 400, "PureBasic Window", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget)
TrackBarGadget(0, 40, 40, 20, 200, 0, 100, #PB_TrackBar_Vertical | #PB_TrackBar_Ticks)
ButtonGadget(1, 20, 280, 60, 60, "Mute Off")
ButtonGadget(2, 100, 10, 100, 20,"Set Event")
ButtonGadget(3, 100, 40, 100, 20,"Free Event")
If Com_GetDefaultAudioEndPointVolume() = #S_OK
Vol = MediaSystemGetVolume()
SetGadgetState(0, Vol)
Mute = MediaSystemGetMute()
If Mute = 1
SetGadgetText(0, "Mute On")
EndIf
If ComEvent_SetAudioEndpointVolumeCallback() = #S_OK
DisableGadget(2, 1)
Else
DisableGadget(2, 1)
DisableGadget(3, 1)
EndIf
Else
DisableGadget(0, 1)
DisableGadget(1, 1)
DisableGadget(2, 1)
DisableGadget(3, 1)
EndIf
Repeat
Event = WaitWindowEvent()
Select Event
Case #PB_Event_Gadget
Select EventGadget()
Case 0
MediaSystemSetVolume(GetGadgetState(0))
Case 1
If Mute = 0
If MediaSystemSetMute(1)
Mute = 1
SetGadgetText(1, "Mute On")
EndIf
ElseIf Mute = 1
If MediaSystemSetMute(0)
Mute = 0
SetGadgetText(1, "Mute Off")
EndIf
EndIf
Case 2
If ComEvent_SetAudioEndpointVolumeCallback() = #S_OK
DisableGadget(2, 1)
DisableGadget(3, 0)
EndIf
Case 3
If ComEvent_FreeAudioEndpointVolumeCallback() = #S_OK
DisableGadget(3, 1)
DisableGadget(2, 0)
EndIf
EndSelect
Case #PB_Event_CloseWindow
Quit = 1
EndSelect
Until Quit = 1
EndIf
Com_FreeDefaultAudioEndPointVolume()
CoUninitialize_()
DataSection
uuidof_IAudioEndpointVolume:
Data.l $5CDF2C82
Data.w $841E,$4546
Data.b $97,$22,$0C,$F7,$40,$78,$22,$9A
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
Data.w $4F35
Data.b $A7,$46,$DE,$8D,$B6,$36,$17,$E6
EndDataSection