Follow along with the video below to see how to install our site as a web app on your home screen.
Note: This feature may not be available in some browsers.
unit MMDevApi;
{$MINENUMSIZE 4}
{$WEAKPACKAGEUNIT}
interface
uses
Windows, ActiveX, ComObj, propsys;
const
CLASS_IMMDeviceEnumerator: TGUID = '{BCDE0395-E52F-467C-8E3D-C4579291692E}';
IID_IMMDeviceEnumerator: TGUID = '{A95664D2-9614-4F35-A746-DE8DB63617E6}';
IID_IMMDevice: TGUID = '{D666063F-1587-4E43-81F1-B948E807363F}';
IID_IMMDeviceCollection: TGUID = '{0BD7A1BE-7A1A-44DB-8397-CC5392387B5E}';
IID_IAudioEndpointVolume: TGUID = '{5CDF2C82-841E-4546-9722-0CF74078229A}';
IID_IAudioMeterInformation: TGUID = '{C02216F6-8C67-4B5B-9D00-D008E73E0064}';
IID_IAudioEndpointVolumeCallback: TGUID = '{657804FA-D6AD-4496-8A60-352752AF4F89}';
// undocumented
IID_IRemoteAudioSession: TGUID = '{33969B1D-D06F-4281-B837-7EAAFD21A9C0}';
IID_IAudioSessionQuerier: TGUID = '{94BE9D30-53AC-4802-829C-F13E5AD34776}';
IID_IAudioSessionQuery: TGUID = '{94BE9D30-53AC-4802-829C-F13E5AD34775}';
//
IID_IAudioSessionEvents: TGUID = '{24918ACC-64B3-37C1-8CA9-74A66E9957A8}';
IID_IAudioSessionControl: TGUID = '{F4B1A599-7266-4319-A8CA-E70ACB11E8CD}';
IID_ISimpleAudioVolume: TGUID = '{87CE5498-68D6-44E5-9215-6DA47EF883D8}';
IID_IAudioSessionManager: TGUID = '{BFA971F1-4D5E-40BB-935E-967039BFBEE4}';
IID_IAudioClient: TGUID = '{1CB9AD4C-DBFA-4c32-B178-C2F568A703B2}';
DEVICE_STATE_ACTIVE = $00000001;
DEVICE_STATE_DISABLE = $00000002;
DEVICE_STATE_NOTPRESENT = $00000004;
DEVICE_STATE_UNPLUGGED = $00000008;
DEVICE_STATEMASK_ALL = $0000000F;
// QueryHardwareSupport
ENDPOINT_HARDWARE_SUPPORT_VOLUME = $00000001;
ENDPOINT_HARDWARE_SUPPORT_MUTE = $00000002;
ENDPOINT_HARDWARE_SUPPORT_METER = $00000004;
type
EDataFlow = TOleEnum;
const
eRender = $00000000;
eCapture = $00000001;
eAll = $00000002;
EDataFlow_enum_count = $00000003;
type
ERole = TOleEnum;
const
eConsole = $00000000;
eMultimedia = $00000001;
eCommunications = $00000002;
ERole_enum_count = $00000003;
// AudioSessionState
AudioSessionStateInactive = 0;
AudioSessionStateActive = 1;
AudioSessionStateExpired = 2;
// AudioSessionDisconnectReason
DisconnectReasonDeviceRemoval = 0;
DisconnectReasonServerShutdown = DisconnectReasonDeviceRemoval + 1;
DisconnectReasonFormatChanged = DisconnectReasonServerShutdown + 1;
DisconnectReasonSessionLogoff = DisconnectReasonFormatChanged + 1;
DisconnectReasonSessionDisconnected = DisconnectReasonSessionLogoff + 1;
DisconnectReasonExclusiveModeOverride = DisconnectReasonSessionDisconnected + 1;
type
PAUDIO_VOLUME_NOTIFICATION_DATA = ^AUDIO_VOLUME_NOTIFICATION_DATA;
AUDIO_VOLUME_NOTIFICATION_DATA = packed record
guidEventContext: TGUID;
bMuted: BOOL;
fMasterVolume: Single;
nChannels: UINT;
afChannelVolumes: array[1..1] of Single;
end;
type
IAudioClient = interface(IUnknown)
['{1CB9AD4C-DBFA-4c32-B178-C2F568A703B2}']
end;
IAudioEndpointVolumeCallback = interface(IUnknown)
['{657804FA-D6AD-4496-8A60-352752AF4F89}']
function OnNotify(pNotify: PAUDIO_VOLUME_NOTIFICATION_DATA): HRESULT; stdcall;
end;
IAudioEndpointVolume = interface(IUnknown)
['{5CDF2C82-841E-4546-9722-0CF74078229A}']
function RegisterControlChangeNotify(pNotify: IAudioEndpointVolumeCallback): HRESULT; stdcall;
function UnregisterControlChangeNotify(pNotify: IAudioEndpointVolumeCallback): HRESULT; stdcall;
function GetChannelCount(var pnChannelCount: uint): HRESULT; stdcall;
function SetMasterVolumeLevel(fLevelDB: Single; pguidEventContext: PGuid): HRESULT; stdcall;
function SetMasterVolumeLevelScalar(fLevel: Single; pguidEventContext: PGuid): HRESULT; stdcall;
function GetMasterVolumeLevel(var pfLevelDB: Single): HRESULT; stdcall
;
function GetMasterVolumeLevelScalar(var pfLevel: Single): HRESULT; stdcall;
function SetChannelVolumeLevel(nChannel: uint; fLevelDB: Single; pguidEventContext: PGuid): HRESULT; stdcall;
function SetChannelVolumeLevelScalar(nChannel: uint; fLevel: Single; pguidEventContext: PGuid): HRESULT; stdcall
;
function GetChannelVolumeLevel(nChannel: uint; fLevelDB: Single): HRESULT; stdcall;
function GetChannelVolumeLevelScalar(nChannel: uint; fLevel: Single): HRESULT; stdcall;
function SetMute(bMute: bool; pguidEventContext: PGuid): HRESULT; stdcall;
function GetMute(var pbMute: bool): HRESULT; stdcall;
function GetVolumeStepInfo(var pnStep: uint; var pnStepCount: uint): HRESULT; stdcall;
function VolumeStepUp(pguidEventContext: PGuid): HRESULT; stdcall;
function VolumeStepDown(pguidEventContext: PGuid): HRESULT; stdcall;
function QueryHardwareSupport(var pdwHardwareSupportMask: uint): HRESULT; stdcall;
function GetVolumeRange(var pflVolumeMindB: Single; var pflVolumeMaxdB: Single;
var pflVolumeIncrementdB: Single): HRESULT; stdcall;
end;
IAudioMeterInformation = interface(IUnknown)
['{C02216F6-8C67-4B5B-9D00-D008E73E0064}']
function GetPeakValue(out pfPeak: Single): HResult; stdcall;
function GetMeteringChannelCount(out pnChannelCount: uint): HResult; stdcall;
function GetChannelsPeakValues(u32ChannelCount: uint; afPeakValues: pSingle): HResult; stdcall;
function QueryHardwareSupport(out pdwHardwareSupportMask: uint): HResult; stdcall;
end;
IMMDevice = interface(IUnknown)
['{D666063F-1587-4E43-81F1-B948E807363F}']
function Activate(const iid: TGUID; dwClsCtx: uint; pActivationParams: PPropVariant; out ppInterface: IUnknown): HRESULT; stdcall;
function OpenPropertyStore(stgmAccess: integer; out ppProperties: IPropertyStore): HRESULT; stdcall;
function GetId(ppstrId: PWChar): HRESULT; stdcall;
function GetState(var pdwState: uint): HRESULT; stdcall;
end;
IMMDeviceCollection = interface(IUnknown)
['{0BD7A1BE-7A1A-44DB-8397-CC5392387B5E}']
function GetCount(var pcDevices: uint): HRESULT; stdcall;
function Item(nDevice: uint; out ppDevice: IMMDevice): HRESULT; stdcall;
end;
IMMNotificationClient = interface(IUnknown)
['{7991EEC9-7E89-4D85-8390-6C703CEC60C0}']
end;
IMMDeviceEnumerator = interface(IUnknown)
['{A95664D2-9614-4F35-A746-DE8DB63617E6}']
function EnumAudioEndpoints(dataFlow: EDataFlow; dwStateMask: DWORD; out ppDevices: IMMDeviceCollection): HRESULT; stdcall;
function GetDefaultAudioEndpoint(dataFlow: EDataFlow; role: ERole; out ppEndpoint: IMMDevice): HRESULT; stdcall;
function GetDevice(pwstrId: PWChar; out ppDevice: IMMDevice): HRESULT; stdcall;
function RegisterEndpointNotificationCallback(var pClient: IMMNotificationClient): HRESULT; stdcall;
function UnregisterEndpointNotificationCallback(var pClient: IMMNotificationClient): HRESULT; stdcall;
end;
{ undocumented }
IRemoteAudioSession = interface(IUnknown)
['{33969B1D-D06F-4281-B837-7EAAFD21A9C0}']
function func_a: HResult; stdcall;
function func_b: HResult; stdcall;
function func_c: HResult; stdcall;
function func_d: HResult; stdcall;
function func_e: HResult; stdcall;
function func_f: HResult; stdcall;
function func_g: HResult; stdcall;
function func_h: HResult; stdcall;
function func_i: HResult; stdcall;
function func_j: HResult; stdcall;
function func_k: HResult; stdcall;
function GetProcessID(out pid: uint): HResult; stdcall;
end;
{ undocumented }
IAudioSessionQuerier = interface(IUnknown)
['{94BE9D30-53AC-4802-829C-F13E5AD34776}']
function GetNumSessions(out NumSessions: uint): HResult; stdcall;
function QuerySession(Num: uint; out Session: IUnknown): HResult; stdcall;
end;
{ undocumented }
IAudioSessionQuery = interface(IUnknown)
['{94BE9D30-53AC-4802-829C-F13E5AD34775}']
function GetQueryInterface(out AudioQuerier: IAudioSessionQuerier): HResult; stdcall;
end;
IAudioSessionEvents = interface(IUnknown)
['{24918ACC-64B3-37C1-8CA9-74A66E9957A8}']
function OnDisplayNameChanged(NewDisplayName: LPCWSTR; EventContext: pGuid): HResult; stdcall;
function OnIconPathChanged(NewIconPath: LPCWSTR; EventContext: pGuid): HResult; stdcall;
function OnSimpleVolumeChanged(NewVolume: Single; NewMute: LongBool; EventContext: pGuid): HResult; stdcall;
function OnChannelVolumeChanged(ChannelCount: uint; NewChannelArray: PSingle; ChangedChannel: uint;
EventContext: pGuid): HResult; stdcall;
function OnGroupingParamChanged(NewGroupingParam, EventContext: pGuid): HResult; stdcall;
function OnStateChanged(NewState: uint): HResult; stdcall; // AudioSessionState
function OnSessionDisconnected(DisconnectReason: uint): HResult; stdcall; // AudioSessionDisconnectReason
end;
IAudioSessionControl = interface(IUnknown)
['{F4B1A599-7266-4319-A8CA-E70ACB11E8CD}']
function GetState(out pRetVal: uint): HResult; stdcall;
function GetDisplayName(out pRetVal: LPWSTR): HResult; stdcall; // pRetVal must be freed by CoTaskMemFree
function SetDisplayName(Value: LPCWSTR; EventContext: pGuid): HResult; stdcall;
function GetIconPath(out pRetVal: LPWSTR): HResult; stdcall; // pRetVal must be freed by CoTaskMemFree
function SetIconPath(Value: LPCWSTR; EventContext: pGuid): HResult; stdcall;
function GetGroupingParam(pRetVal: pGuid): HResult; stdcall;
function SetGroupingParam(OverrideValue, EventContext: pGuid): HResult; stdcall;
function RegisterAudioSessionNotification(const NewNotifications: IAudioSessionEvents): HResult; stdcall;
function UnregisterAudioSessionNotification(const NewNotifications: IAudioSessionEvents): HResult; stdcall;
end;
ISimpleAudioVolume = interface(IUnknown)
['{87CE5498-68D6-44E5-9215-6DA47EF883D8}']
function SetMasterVolume(fLevel: Single; EventContext: pGuid): HResult; stdcall;
function GetMasterVolume(out fLevel: Single): HResult; stdcall;
function SetMute(bMute: LongBool; EventContext: pGuid): HResult; stdcall;
function GetMute(out bMute: LongBool): HResult; stdcall;
end;
IAudioSessionManager = interface(IUnknown)
['{BFA971F1-4D5E-40BB-935E-967039BFBEE4}']
function GetAudioSessionControl(AudioSessionGuid: pGUID; StreamFlag: uint;
out SessionControl: IAudioSessionControl): HResult; stdcall;
function GetSimpleAudioVolume(AudioSessionGuid: pGuid; StreamFlag: uint;
out AudioVolume: ISimpleAudioVolume): HResult; stdcall;
end;
// get ISimpleAudioVolume from ProcessID
function GetSimpleAudioVolumeFromPid(const AudioDevice: IMMDevice; pid: uint; out SimpleAudio: ISimpleAudioVolume; out currguid: tguid): Boolean; stdcall;
// get ISimpleAudioVolume from Process Handle
function GetSimpleAudioVolumeFromHandle(const AudioDevice: IMMDevice; Hnd: uint; out SimpleAudio: ISimpleAudioVolume; out currguid: tguid): Boolean; stdcall;
//
function GetSimpleAudioVolumeFromModuleName(const AudioDevice: IMMDevice; ModuleName: pWideChar; out SimpleAudio: ISimpleAudioVolume; out currguid: tguid): Boolean; stdcall;
implementation
uses tlhelp32;
function GetProcessIdFromModuleName(ModuleName: pWideChar): LongWord;
var
ToolSnap: LongWord;
ProcessEntry: ProcessEntry32W;
bCont: LongBool;
ModuleName16: WideString;
begin
Result := 0;
ModuleName16 := ModuleName;
ToolSnap := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
ProcessEntry.dwSize := sizeof(ProcessEntry);
bCont := Process32FirstW(ToolSnap, ProcessEntry);
while bCont do begin
if ProcessEntry.szExeFile = ModuleName16 then
Result := ProcessEntry.th32ProcessID;
ProcessEntry.dwSize := sizeof(ProcessEntry);
bCont := (Result = 0) and Process32NextW(ToolSnap, ProcessEntry);
end;
CloseHandle(ToolSnap);
end;
function GetSimpleAudioVolumeFromModuleName(const AudioDevice: IMMDevice; ModuleName: pWideChar; out SimpleAudio: ISimpleAudioVolume; out currguid: tguid): Boolean; stdcall;
var
pid: LongWord;
begin
pid := GetProcessIdFromModuleName(ModuleName);
Result := GetSimpleAudioVolumeFromPid(AudioDevice, pid, SimpleAudio, currguid);
end;
function GetSimpleAudioVolumeFromHandle(const AudioDevice: IMMDevice; Hnd: uint; out SimpleAudio: ISimpleAudioVolume; out currguid: tguid): Boolean; stdcall;
var
pid: uint;
begin
GetWindowThreadProcessId(Hnd, pid);
Result := GetSimpleAudioVolumeFromPid(AudioDevice, pid, SimpleAudio, currguid);
end;
function GetSimpleAudioVolumeFromPid(const AudioDevice: IMMDevice; pid: uint; out SimpleAudio: ISimpleAudioVolume; out currguid: tguid): Boolean; stdcall;
var
SessionManager: IAudioSessionManager;
SessionQuery: IAudioSessionQuery;
SessionQuerier: IAudioSessionQuerier;
RemoteSession: IRemoteAudioSession;
SessionControl: IAudioSessionControl;
dummy: IUnknown;
MaxSession, Sessionpid: uint;
hr, i: Integer;
begin
Result := False;
SessionManager := nil;
SessionQuery := nil;
SessionQuerier := nil;
SessionControl := nil;
// get AudioSessionManager
hr := AudioDevice.Activate(IID_IAudioSessionManager, CLSCTX_ALL, nil, IUnknown(SessionManager));
if Succeeded(hr) then begin
// get SessionQuery
hr := SessionManager.QueryInterface(IID_IAudioSessionQuery, SessionQuery);
if Succeeded(hr) then begin
// get SessionQuerier
hr := SessionQuery.GetQueryInterface(SessionQuerier);
if Succeeded(hr) then begin
// check sessions
hr := SessionQuerier.GetNumSessions(MaxSession);
if Succeeded(hr) then
if MaxSession > 0 then
for i := 0 to MaxSession - 1 do begin
dummy := nil;
hr := SessionQuerier.QuerySession(i, dummy);
RemoteSession := nil;
if Succeeded(hr) then begin
// get RemoteSession
hr := dummy.QueryInterface(IID_IRemoteAudioSession, RemoteSession);
if Succeeded(hr) then begin
// compare ProcessID
if Succeeded(RemoteSession.GetProcessID(Sessionpid)) then
if Sessionpid <> 0 then
if Sessionpid = pid then begin
Result := Succeeded(RemoteSession.QueryInterface(IID_ISimpleAudioVolume, SimpleAudio));
if Succeeded(dummy.QueryInterface(IID_IAudioSessionControl, SessionControl)) then
SessionControl.GetGroupingParam(@currguid);
SessionControl := nil;
end;
if Result then
Break;
end;
end;
end;
RemoteSession := nil;
SessionQuerier := nil;
end;
SessionQuery := nil;
end;
SessionManager := nil;
end;
end;
end.