SetChannelVolumeLevelScalar会产生访问冲突吗?

时间:2014-09-03 20:26:39

标签: delphi core-audio

来自How to check if the system master volume is mute or unmute?的代码示例,但有一些更改。

function GetChannelVolumeLevel(nChannel: Integer; out fLevelDB: double): HRESULT; stdcall;
function GetChannelVolumeLevelScalar(nChannel: Integer; out fLevel: double): HRESULT; stdcall;

fLevelDB从double到single。双结果总是0。 而对于

function SetMute(bMute: Boolean; pguidEventContext: PGUID): HRESULT; stdcall;
function GetMute(out bMute: Boolean): HRESULT; stdcall;

从布尔到整数(0-false 1-true)

无法使SetChannelVolumeLevelScalar / SetChannelVolumeLevel工作,这个函数首先让我陷入困境。

演示代码

unit MasterVolumeControl;
interface
uses
  SysUtils,
  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}';
  DEVICE_STATE_ACTIVE              = $00000001;
  DEVICE_STATE_UNPLUGGED           = $00000002;
  DEVICE_STATE_NOTPRESENT          = $00000004;
  DEVICE_STATEMASK_ALL             = $00000007;

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)
    ['{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: uint; fLevelDB: double; pguidEventContext: PGUID): HRESULT; stdcall;
    function SetChannelVolumeLevelScalar(nChannel: uint; fLevelDB: double; pguidEventContext: PGUID): HRESULT; stdcall;
    function GetChannelVolumeLevel(nChannel: Integer; out fLevelDB: double): HRESULT; stdcall;
    function GetChannelVolumeLevelScalar(nChannel: Integer; out fLevel: single): HRESULT; stdcall;
    function SetMute(bMute: Integer; pguidEventContext: PGUID): HRESULT; stdcall;
    function GetMute(out bMute: Integer): 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: EDataFlow; ER: SYSUINT; out Dev: IMMDevice): HRESULT; stdcall;
    function GetDevice(pwstrId: pointer; out Dev: IMMDevice): HRESULT; stdcall;
    function RegisterEndpointNotificationCallback(pClient: IMMNotificationClient): HRESULT; stdcall;
  end;

var
  pEndpointVolume  : IAudioEndpointVolume;
  LDeviceEnumerator: IMMDeviceEnumerator;
  Dev              : IMMDevice;
procedure SetMasterVolume(fLevelDB: single);
function GetMasterVolume(): single;
function GetNumberOfChannels: Integer;
function GetChannelVolume(Channel: DWORD): single;
procedure SetVolumeChannel(fLevelDB: single; Channel: uint);
procedure SetMute(mute: Boolean);
function GetMute(): Boolean;

implementation


procedure SetMasterVolume(fLevelDB: single);
begin
  if not Succeeded(pEndpointVolume.SetMasterVolumeLevelScalar(fLevelDB, @GUID_NULL)) then
    RaiseLastOSError;
end;

function GetMasterVolume(): single;
begin
  if not Succeeded(pEndpointVolume.GetMasterVolumeLevelScaler(result)) then
    RaiseLastOSError;
end;

function GetChannelVolume(Channel: DWORD): single;
begin
  if not Succeeded(pEndpointVolume.GetChannelVolumeLevelScalar(Channel, result)) then
    RaiseLastOSError;
end;

procedure SetVolumeChannel(fLevelDB: single; Channel: uint);
begin
  if not Succeeded(pEndpointVolume.SetChannelVolumeLevelScalar(Channel, fLevelDB, @GUID_NULL)) then
    RaiseLastOSError;
end;

procedure SetMute(mute: Boolean);
var
  iMute: Integer;
begin
  iMute := 0;
  if mute then
    iMute := 1;
  if not Succeeded(pEndpointVolume.SetMute(iMute, nil)) then
    RaiseLastOSError;
end;

function GetMute(): Boolean;
var
  mute: Integer;
begin
  if not Succeeded(pEndpointVolume.GetMute(mute)) then
    RaiseLastOSError;
  result := true;
  if mute = 0 then
    result := false;
end;

function GetNumberOfChannels: Integer;
begin
  if not Succeeded(pEndpointVolume.GetChannelCount(result)) then
    RaiseLastOSError;
end;

initialization

if not Succeeded(CoCreateInstance(CLASS_IMMDeviceEnumerator, nil, CLSCTX_INPROC_SERVER, IID_IMMDeviceEnumerator, LDeviceEnumerator)) then
  RaiseLastOSError;
if not Succeeded(LDeviceEnumerator.GetDefaultAudioEndpoint(eRender, eConsole, Dev)) then
  RaiseLastOSError;
if not Succeeded(Dev.Activate(IID_IAudioEndpointVolume, CLSCTX_INPROC_SERVER, nil, pEndpointVolume)) then
  RaiseLastOSError;

end.

并形成:

unit uVolumeControlExample;

interface

uses
  MasterVolumeControl,
  Vcl.ComCtrls,
  System.Classes,
  Vcl.Controls,
  Vcl.StdCtrls,
  Vcl.Forms,
  sysutils;

type
  TForm8 = class(TForm)
    chkMute: TCheckBox;
    masterVolume: TTrackBar;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure chkMuteClick(Sender: TObject);
    procedure FormResize(Sender: TObject);

    private
      noOfChannels: integer;
      channels    : TStringList;
      procedure TrackBarChange(Sender: TObject);
      procedure RefreshChannels;

    public
    { Public declarations }
  end;

var
  Form8: TForm8;

implementation

{$R *.dfm}

procedure TForm8.chkMuteClick(Sender: TObject);
begin
  SetMute(chkMute.Checked);
end;

procedure TForm8.FormCreate(Sender: TObject);
var
  I: integer;
begin
  channels := TStringList.Create;
  noOfChannels := GetNumberOfChannels;
  for I := 0 to noOfChannels - 1 do begin
    channels.AddObject('Channel_' + IntToStr(I), TTrackBar.Create(self));
    with TTrackBar(channels.Objects[I]) do begin
      Visible := false;
      Parent := self;
      Tag := I;
      Left := 8;
      Top := 8 + I * 45;
      Width := 345;
      Height := 45;
      OnChange := TrackBarChange;
      Max := 100;
      Name := 'Channel_' + IntToStr(I);
      Visible := true;
    end;
  end;
  with masterVolume do begin
    Visible := false;
    Tag := noOfChannels;
    Left := 8;
    Top := 8 + noOfChannels * 45;
    Width := 345;
    Height := 45;
    OnChange := TrackBarChange;
    Max := 100;
    Visible := true;
  end;
  RefreshChannels;
end;

procedure TForm8.FormDestroy(Sender: TObject);
begin
  channels.Free;
end;

procedure TForm8.FormResize(Sender: TObject);
begin
  RefreshChannels;
end;

procedure TForm8.RefreshChannels;
var
  I: integer;
begin
  for I := 0 to noOfChannels - 1 do begin
    with TTrackBar(channels.Objects[I]) do begin
      OnChange := nil;
      Position := round(GetChannelVolume(I) * 100);
      OnChange := TrackBarChange;
    end;
  end;
  if GetMute then
    chkMute.Checked := true
  else
    chkMute.Checked := false;
  masterVolume.OnChange := nil;
  masterVolume.Position := round(GetMasterVolume() * 100);
  masterVolume.OnChange := TrackBarChange;
end;

procedure TForm8.TrackBarChange(Sender: TObject);
begin
  if TTrackBar(Sender).Tag = noOfChannels then begin
    SetMasterVolume(TTrackBar(Sender).Position / 100);
    exit;
  end;
  SetVolumeChannel(TTrackBar(Sender).Position / 100, TTrackBar(Sender).Tag);
end;

end.

1 个答案:

答案 0 :(得分:3)

您的代码显而易见的问题是,您使用Double作为浮点参数,而实际上它们是Single。您无法决定在那里使用哪些类型。这是一个二进制接口,由接口的作者做出决定。将这些参数类型更改回Single

对于GetMute方法,其参数应为BOOL而不是BooleanInteger