Wyciszenie dzwieku globalne a nie tylko mojej aplikacji

0

Wpisałem w google "delphi mute soundcard"
i znalazłem
https://www.swissdelphicenter.ch/en/showcode.php?id=1630

Testuje an Windows 10 i ten kod wycisza ale tylko dźwięki mojej aplikacji (widzę w mikserze ze jest wyciszona)
A potrzebował bym wyciszenie wszystkiego

Jak zrobić globalne "mute" ?

4
uses
  Windows, ActiveX, ComObj;

const
  CLASS_IMMDeviceEnumerator : TGUID = '{BCDE0395-E52F-467C-8E3D-C4579291692E}';
  IID_IMMDeviceEnumerator : TGUID = '{A95664D2-9614-4F35-A746-DE8DB63617E6}';
  IID_IAudioEndpointVolume : TGUID = '{5CDF2C82-841E-4546-9722-0CF74078229A}';
  APPCOMMAND_VOLUME_MUTE = $80000;
  WM_APPCOMMAND = $319;

type
  IAudioEndpointVolumeCallback = interface(IUnknown)
  ['{657804FA-D6AD-4496-8A60-352752AF4F89}']
  end;

  IAudioEndpointVolume = interface(IUnknown)
  ['{5CDF2C82-841E-4546-9722-0CF74078229A}']
    function RegisterControlChangeNotify(AudioEndPtVol: IAudioEndpointVolumeCallback): HRESULT; stdcall;
    function UnregisterControlChangeNotify(AudioEndPtVol: IAudioEndpointVolumeCallback): HRESULT; stdcall;
    function GetChannelCount(out PInteger): HRESULT; stdcall;
    function SetMasterVolumeLevel(fLevelDB: single; pguidEventContext: PGUID): HRESULT; stdcall;
    function SetMasterVolumeLevelScalar(fLevelDB: single; pguidEventContext: PGUID): HRESULT; stdcall;
    function GetMasterVolumeLevel(out fLevelDB: single): HRESULT; stdcall;
    function GetMasterVolumeLevelScaler(out fLevelDB: single): HRESULT; stdcall;
    function SetChannelVolumeLevel(nChannel: Integer; fLevelDB: double; pguidEventContext: PGUID): HRESULT; stdcall;
    function SetChannelVolumeLevelScalar(nChannel: Integer; fLevelDB: double; pguidEventContext: PGUID): HRESULT; stdcall;
    function GetChannelVolumeLevel(nChannel: Integer; out fLevelDB: double): HRESULT; stdcall;
    function GetChannelVolumeLevelScalar(nChannel: Integer; out fLevel: double): HRESULT; stdcall;
    function SetMute(bMute: Boolean; pguidEventContext: PGUID): HRESULT; stdcall;
    function GetMute(out bMute: Boolean): HRESULT; stdcall;
    function GetVolumeStepInfo(pnStep: Integer; out pnStepCount: Integer): HRESULT; stdcall;
    function VolumeStepUp(pguidEventContext: PGUID): HRESULT; stdcall;
    function VolumeStepDown(pguidEventContext: PGUID): HRESULT; stdcall;
    function QueryHardwareSupport(out pdwHardwareSupportMask): HRESULT; stdcall;
    function GetVolumeRange(out pflVolumeMindB: double; out pflVolumeMaxdB: double; out pflVolumeIncrementdB: double): HRESULT; stdcall;
  end;

  IAudioMeterInformation = interface(IUnknown)
  ['{C02216F6-8C67-4B5B-9D00-D008E73E0064}']
  end;

  IPropertyStore = interface(IUnknown)
  end;

  IMMDevice = interface(IUnknown)
  ['{D666063F-1587-4E43-81F1-B948E807363F}']
    function Activate(const refId: TGUID; dwClsCtx: DWORD;  pActivationParams: PInteger; out pEndpointVolume: IAudioEndpointVolume): HRESULT; stdCall;
    function OpenPropertyStore(stgmAccess: DWORD; out ppProperties: IPropertyStore): HRESULT; stdcall;
    function GetId(out ppstrId: PLPWSTR): HRESULT; stdcall;
    function GetState(out State: Integer): HRESULT; stdcall;
  end;


  IMMDeviceCollection = interface(IUnknown)
  ['{0BD7A1BE-7A1A-44DB-8397-CC5392387B5E}']
  end;

  IMMNotificationClient = interface(IUnknown)
  ['{7991EEC9-7E89-4D85-8390-6C703CEC60C0}']
  end;

  IMMDeviceEnumerator = interface(IUnknown)
  ['{A95664D2-9614-4F35-A746-DE8DB63617E6}']
    function EnumAudioEndpoints(dataFlow: TOleEnum; deviceState: SYSUINT; DevCollection: IMMDeviceCollection): HRESULT; stdcall;
    function GetDefaultAudioEndpoint(EDF: SYSUINT; ER: SYSUINT; out Dev :IMMDevice ): HRESULT; stdcall;
    function GetDevice(pwstrId: pointer; out Dev: IMMDevice): HRESULT; stdcall;
    function RegisterEndpointNotificationCallback(pClient: IMMNotificationClient): HRESULT; stdcall;
  end;

function IsMasterVolumeMute : Boolean;
var
  pEndpointVolume: IAudioEndpointVolume;
  LDeviceEnumerator: IMMDeviceEnumerator;
  Dev: IMMDevice;
  bMute: Boolean;
begin
  if not Succeeded(CoCreateInstance(CLASS_IMMDeviceEnumerator, nil, CLSCTX_INPROC_SERVER, IID_IMMDeviceEnumerator, LDeviceEnumerator)) then
   RaiseLastOSError;
  if not Succeeded(LDeviceEnumerator.GetDefaultAudioEndpoint($00000000, $00000000, Dev)) then
   RaiseLastOSError;

  if not Succeeded( Dev.Activate(IID_IAudioEndpointVolume, CLSCTX_INPROC_SERVER, nil, pEndpointVolume)) then
   RaiseLastOSError;

  if not Succeeded(pEndpointVolume.GetMute(bMute)) then
   RaiseLastOSError
  else
  Result:=bMute;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  wyciszony: Boolean;
begin
  CoInitialize(nil);
  try
    wyciszony:=IsMasterVolumeMute;
  finally
    CoUninitialize;
  end;
  //if not wyciszony then 
  SendMessageW(Handle, WM_APPCOMMAND, Handle, APPCOMMAND_VOLUME_MUTE); 
  if wyciszony then
  Caption:='Dźwięk został włączony'
  else
  Caption:='Dźwięk został wyciszony';
end;  
2
Adamek Adam napisał(a):

Testuje an Windows 10 i ten kod wycisza ale tylko dźwięki mojej aplikacji (widzę w mikserze ze jest wyciszona)

Ten kod używa starego API, kiedy jeszcze nie było możliwości ustalania głośności dla poszczególnych aplikacji (to weszło chyba w Windows Vista).

Najwyrażniej w Microsofcie zdecydowali, że lepiej będzie jeśli stare API w nowych systemach będzie sterować głośnością danej apki, a nie globalną.

0

Tak mi się tez wydawało że to kiedyś działało inaczej ale nawet nie mam żadnego XP aby to sprawdzić ;)

Co do rozwiązania Pana Pawła to działa.
Ten przykład z użyciem APPCOMMAND_VOLUME_MUTE tez testowałem i mi nie działał
okazuje się że w Delphi unit Windows jest stała **APPCOMMAND_VOLUME_MUTE = 8 **
A w przykładzie Pawła APPCOMMAND_VOLUME_MUTE = $80000;
Nie jest zgodne z dokumentacją https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-appcommand
ale działa

Do pełni szczęścia brakuje aby wyciszenie nie wyświetlało dodatkowych okien

Jest jeszcze IAudioEndpointVolume.SetMute
tez testowałem dzisiaj rano i mi nie działało na bazie innego przykłądu z internetu a na bazie przykładu Pana Pawała zachowuje sie poprawnie :)

0
// jak @p_mute wieksze od zero to jest MUTE !!!
function SetMuteAudioInt(p_mute: integer) : Boolean;
var
  pEndpointVolume: IAudioEndpointVolume;
  LDeviceEnumerator: IMMDeviceEnumerator;
  Dev: IMMDevice;
  bMute: Boolean;
begin
  if not Succeeded(CoCreateInstance(CLASS_IMMDeviceEnumerator, nil, CLSCTX_INPROC_SERVER, IID_IMMDeviceEnumerator, LDeviceEnumerator)) then
   RaiseLastOSError;
  if not Succeeded(LDeviceEnumerator.GetDefaultAudioEndpoint($00000000, $00000000, Dev)) then
   RaiseLastOSError;

  if not Succeeded( Dev.Activate(IID_IAudioEndpointVolume, CLSCTX_INPROC_SERVER, nil, pEndpointVolume)) then
   RaiseLastOSError;

  if not Succeeded(pEndpointVolume.GetMute(bMute)) then
    RaiseLastOSError
  else
    Result:=bMute;

  if p_mute > 0 then
  begin
    pEndpointVolume.SetMute(true,nil)
  end
  else
    pEndpointVolume.SetMute(false,nil)
end;


function SetMuteAudio(p_mute: boolean) : Boolean;
var
  pEndpointVolume: IAudioEndpointVolume;
  LDeviceEnumerator: IMMDeviceEnumerator;
  Dev: IMMDevice;
  bMute: Boolean;
begin
  if not Succeeded(CoCreateInstance(CLASS_IMMDeviceEnumerator, nil, CLSCTX_INPROC_SERVER, IID_IMMDeviceEnumerator, LDeviceEnumerator)) then
   RaiseLastOSError;
  if not Succeeded(LDeviceEnumerator.GetDefaultAudioEndpoint($00000000, $00000000, Dev)) then
   RaiseLastOSError;

  if not Succeeded( Dev.Activate(IID_IAudioEndpointVolume, CLSCTX_INPROC_SERVER, nil, pEndpointVolume)) then
   RaiseLastOSError;

  if not Succeeded(pEndpointVolume.GetMute(bMute)) then
    RaiseLastOSError
  else
    Result:=bMute;

  pEndpointVolume.SetMute(p_mute,nil)
end;

Dlaczego SetMuteAudio nie działa ? I dostaje wyjatek ? Wystarczy ze w kodzie ożyję parametru "p_mute" w wersji boolean i funkcja konczy sie wyjatkiem. W "event log" dostaje:

avcore\audiocore\client\audioclient\audioclientvolume.cpp(880)\AUDIOSES.DLL!63B5D73D: (caller: 63B5ECB6) ReturnHr(1) tid(3688) 80070057 The parameter is incorrect.
3

Bo bezmyślnie wklejasz kod @Paweł Dmitruk który swoją drogą ma błąd:

w deklaracji interfejsu zmień na

//...
function GetMute(out bMute: BOOL): HRESULT; stdcall;
//...

i funkcji

function IsMasterVolumeMute: Boolean;
var
//...
  bMute: BOOL; //zmienna ma być typu BOOL nie Boolean!
begin
//...

Ty niepotrzebnie masz w funkcji SetMuteAudio:

//...
  if not Succeeded(pEndpointVolume.GetMute(bMute)) then
    RaiseLastOSError
  else
    Result:=bMute;
//...

i na tym GetMute prawdopodobnie się wywala. W ogóle wywal ten fragment.
Twoja funkcja powinna wyglądać tak:

function SetMasterVolumeMute(bMute: Boolean): Boolean;
var
  pEndpointVolume: IAudioEndpointVolume;
  LDeviceEnumerator: IMMDeviceEnumerator;
  Dev: IMMDevice;
begin
  if not Succeeded(CoCreateInstance(CLASS_IMMDeviceEnumerator, nil, CLSCTX_INPROC_SERVER, IID_IMMDeviceEnumerator, LDeviceEnumerator)) then
    RaiseLastOSError;

  if not Succeeded(LDeviceEnumerator.GetDefaultAudioEndpoint($00000000, $00000000, Dev)) then
    RaiseLastOSError;

  if not Succeeded( Dev.Activate(IID_IAudioEndpointVolume, CLSCTX_INPROC_SERVER, nil, pEndpointVolume)) then
    RaiseLastOSError;

  result:= Succeeded(pEndpointVolume.SetMute(bMute, nil));
end;

Wywołanie CoInitialize przenieś do OnCreate a CoUninitialize do OnDestroy.

0

Zadziałał mi przykład z tej strony
https://bluexmas.tistory.com/961

unit MMDevApi;
 
interface
 
uses
  Windows, ActiveX, ComObj;
 
const
  CLSID_MMDeviceEnumerator : 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}';
  IID_IMMNotificationClient : TGUID = '{7991EEC9-7E89-4D85-8390-6C703CEC60C0}';
 
  DEVICE_STATE_ACTIVE = $00000001;
  DEVICE_STATE_UNPLUGGED = $00000002;
  DEVICE_STATE_NOTPRESENT = $00000004;
  DEVICE_STATEMASK_ALL = $00000007;
 
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
  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;
 
type
  IAudioEndpointVolumeCallback = interface(IUnknown)
  [IID_IAudioEndpointVolumeCallback]
    function OnNotify(pNotify: PAUDIO_VOLUME_NOTIFICATION_DATA): HRESULT; stdcall;
  end;
 
  IAudioEndpointVolume = interface(IUnknown)
  [IID_IAudioEndpointVolume]
    function RegisterControlChangeNotify(AudioEndPtVol: IAudioEndpointVolumeCallback): Integer; stdcall;
    function UnregisterControlChangeNotify(AudioEndPtVol: IAudioEndpointVolumeCallback): Integer; stdcall;
    function GetChannelCount(out PInteger): Integer; stdcall;
    function SetMasterVolumeLevel(fLevelDB: single; pguidEventContext: PGUID): Integer; stdcall;
    function SetMasterVolumeLevelScalar(fLevelDB: single; pguidEventContext: PGUID): Integer; stdcall;
    function GetMasterVolumeLevel(out fLevelDB: single): Integer; stdcall;
    function GetMasterVolumeLevelScaler(out fLevelDB: single): Integer; stdcall;
    function SetChannelVolumeLevel(nChannel: Integer; fLevelDB: double; pguidEventContext: PGUID): Integer; stdcall;
    function SetChannelVolumeLevelScalar(nChannel: Integer; fLevelDB: double; pguidEventContext: PGUID): Integer; stdcall;
    function GetChannelVolumeLevel(nChannel: Integer; out fLevelDB: double): Integer; stdcall;
    function GetChannelVolumeLevelScalar(nChannel: Integer; out fLevel: double): Integer; stdcall;
    function SetMute(bMute: Boolean; pguidEventContext: PGUID): Integer; stdcall;
    function GetMute(out bMute: Boolean): Integer; stdcall;
    function GetVolumeStepInfo(pnStep: Integer; out pnStepCount: Integer): Integer; stdcall;
    function VolumeStepUp(pguidEventContext: PGUID): Integer; stdcall;
    function VolumeStepDown(pguidEventContext: PGUID): Integer; stdcall;
    function QueryHardwareSupport(out pdwHardwareSupportMask): Integer; stdcall;
    function GetVolumeRange(out pflVolumeMindB: double; out pflVolumeMaxdB: double; out pflVolumeIncrementdB: double): Integer; stdcall;
  end;
 
  IAudioMeterInformation = interface(IUnknown)
  [IID_IAudioMeterInformation]
    function GetPeakValue(out Peak: Real): HRESULT; stdcall;
  end;
 
  IPropertyStore = interface(IUnknown)
  end;
 
  IMMDevice = interface(IUnknown)
  [IID_IMMDevice]
    function Activate(const refId: TGUID; dwClsCtx: DWORD; pActivationParams: PInteger; out pEndpointVolume: IAudioEndpointVolume): HRESULT; stdCall;
    function OpenPropertyStore(stgmAccess: DWORD; out ppProperties: IPropertyStore): HRESULT; stdcall;
    function GetId(out ppstrId: PLPWSTR): HRESULT; stdcall;
    function GetState(out State: Integer): HRESULT; stdcall;
  end;
 
  IMMDeviceCollection = interface(IUnknown)
  [IID_IMMDeviceCollection]
    function GetCount(out pcDevices: UINT): HRESULT; stdcall;
    function Item(nDevice: UINT; out ppDevice: IMMDevice): HRESULT; stdcall;
  end;
 
  IMMNotificationClient = interface(IUnknown)
  [IID_IMMNotificationClient]
  end;
 
  IMMDeviceEnumerator = interface(IUnknown)
  [IID_IMMDeviceEnumerator]
    function EnumAudioEndpoints(dataFlow: EDataFlow; deviceState: SYSUINT; out DevCollection: IMMDeviceCollection): HRESULT; stdcall;
    function GetDefaultAudioEndpoint(EDF: SYSUINT; ER: SYSUINT; out Dev: IMMDevice): HRESULT; stdcall;
    function GetDevice(pwstrId: pointer; out Dev: IMMDevice): HRESULT; stdcall;
    function RegisterEndpointNotificationCallback(pClient: IMMNotificationClient): HRESULT; stdcall;
    function UnregisterEndpointNotificationCallback(pClient: IMMNotificationClient): HRESULT; stdcall;
  end;
 
implementation
 
end.
unit Unit1;
 
interface
 
uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
  MMDevApi, ActiveX, ComObj, Vcl.ComCtrls, Vcl.StdCtrls;
 
type
  TEndpointVolumeCallback = class(TInterfacedObject, IAudioEndpointVolumeCallback)
    function OnNotify(pNotify: PAUDIO_VOLUME_NOTIFICATION_DATA): HRESULT; stdcall;
  end;
 
  TForm1 = class(TForm)
    trackVolumeLevel: TTrackBar;
    spdMute: TCheckBox;
    Edit1: TEdit;
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    endpointVolume: IAudioEndpointVolume;
  public
    { Public declarations }
    procedure doMasterVolumeMute(bMute: Boolean);
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.dfm}
 
procedure TForm1.doMasterVolumeMute(bMute: Boolean);
var
  MMDeviceCollection: IMMDeviceCollection;
  MMDeviceEnumerator: IMMDeviceEnumerator;
  device :IMMDevice ;
  hr: HRESULT;
  deviceCount : UINT;
  i : integer;
begin
  hr := CoCreateInstance(CLSID_MMDeviceEnumerator, nil, CLSCTX_ALL, IID_IMMDeviceEnumerator, MMDeviceEnumerator);
  if hr <> ERROR_SUCCESS then ShowMessage(SysErrorMessage(hr));
 
  MMDeviceCollection := nil; // wegen dem OUT-Parameter *1
  hr := MMDeviceEnumerator.EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, MMDeviceCollection);
  if hr <> ERROR_SUCCESS then ShowMessage(SysErrorMessage(hr));
 
  hr := MMDeviceCollection.GetCount(deviceCount);
  if hr <> ERROR_SUCCESS then ShowMessage(SysErrorMessage(hr));
 
  for i:=0 to deviceCount-1 do begin
    MMDeviceCollection.Item(i, device);
    endpointVolume:=nil;
    device.Activate(IID_IAudioEndpointVolume, CLSCTX_INPROC_SERVER, nil, endpointVolume);
    endpointVolume.SetMute(bMute,nil);
  end;
end;
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  doMasterVolumeMute(true);
end;
 
end.
0

Masz więcej niż 1 kartę dźwiękową w kompie? Bo tego co widzę kod wycisza wszystkie urządzenia.
Na przyszłość nie pisze się "nie działa" bo nikt z fusów nie wywróży jaki masz błąd, co jest nie tak. Chyba, że błąd się nie pojawia ale nie ma pożądanego efektu (w tym wypadku wyciszenia) to podaje się taka informację.

0

Przepraszam ze niezbyt jasno się wyraziłem. ! Moja wina
Okazuje się że mam dwie karty dźwiękowe , przyznam się ze nawet nie zdawałem sobie z tego sprawy.

Mój problem rozwiązał kod który ostatni umieściłem,
jezeli chodzi o przykład "by kAzek" to u mnie nie działa (nie wycisza dźwięku)
a dodatkowo w "Event log" mam Debug Output:

avcore\audiocore\client\audioclient\audioclientvolume.cpp(880)\AUDIOSES.DLL!63B5D73D: (caller: 63B5ECB6) ReturnHr(1) tid(4174) 80070057 The parameter is incorrect.
1

Od czego masz debugger po prostu sprawdź na czym się wywala. Dziwna sprawa, bo u mnie to działa bez problemu. Niby może "nie wyciszać", bo jak wspomniałeś masz 2 karty dźwiękowe więc po prostu mogłoby wyciszać ale nie to urządzenie (wiec efektu nie widać a raczej nie słychać). Skąd błąd parametr jest nieprawidłowy to nie wiem. W czym to kompilujesz? Jakaś zabytkowa wersja Delphi czy coś?

0

Testowałem Twój kod na Windows 10 1903 , Delphi 2010 oraz 10.1 , target win32
I w takiej konfiguracji mam "The parameter is incorrect."

Ale eksperymentalnie zrobiłem tez wersje x64 i tutaj działa bezproblemowo Twój kod.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.