捕捉音频会议活动(Catch audio sessions events)

2019-09-21 08:18发布

我试着写一些应用程序,将监视音频会话(如SndVol一样)。 我激活IAudioSessionManager2,打通IAudioSessionEnumerator当前的音频会议,使用RegisterSessionNotification方法在音频会话管理器通知登记的名单。 然而,我的应用程序将不会收到通知OnSessionCreated()。 当然,我在这里读了类似的主题: 通知不发送 , IAudioSessionNotification人有工作代码

我仔细看了所有的答案,但我找不到什么,我做错了。 这里是我的代码(德尔福):

TDNAudioSessionManager = class(TDNUnknownObject, IAudioSessionNotification)
private
  FManager: IAudioSessionManager2;
  FList: TDNAudioSessionList;
  function IsManagerValid: Boolean;
protected
  procedure ActivateSessionManager(out AManager: IAudioSessionManager2);
  procedure GetCurrentSessions;
  // IAudioSessionNotification
  function OnSessionCreated(ANewSession: IAudioSessionControl): HRESULT; stdcall;
public
  constructor Create;
  destructor Destroy; override;
end;

constructor TDNAudioSessionManager.Create;
begin
  inherited Create;
  ActivateSessionManager(FManager);
  if IsManagerValid then
  begin
    FList := TDNAudioSessionList.Create;
    FManager.RegisterSessionNotification(Self);
    GetCurrentSessions;
   end;
 end;

destructor TDNAudioSessionManager.Destroy;
begin
  if IsManagerValid then
  begin
    FManager.UnregisterSessionNotification(Self);
    FManager := nil;
  end;
  FreeAndNil(FList);
  inherited Destroy;
 end;

function TDNAudioSessionManager.IsManagerValid: Boolean;
begin
  Result := Assigned(FManager);
end;

procedure TDNAudioSessionManager.GetCurrentSessions;
var
  AEnumerator: IAudioSessionEnumerator;
  ASession: IAudioSessionControl;
  ACount: Integer;
  I: Integer;
begin
  if IsManagerValid then
    if FManager.GetSessionEnumerator(AEnumerator) = S_OK then
    try
      AEnumerator.GetCount(ACount);
      for I := 0 to ACount - 1 do
      begin
        AEnumerator.GetSession(I, ASession);
        FList.Add(ASession);
      end;
    finally
      AEnumerator := nil;
    end;
end;

function TDNAudioSessionManager.OnSessionCreated(ANewSession: IAudioSessionControl): HRESULT;
begin
  FList.Add(ANewSession);
  Result := S_OK;
end;

procedure TDNAudioSessionManager.ActivateSessionManager(out AManager: IAudioSessionManager2);
var
  AEnumerator: IMMDeviceEnumerator;
  ADefault: IMMDevice;
  ARes: HRESULT;
begin
  AManager := nil;
  ARes := CoCreateInstance(CLSID_MMDeviceEnumerator, nil, CLSCTX_INPROC_SERVER, IID_IMMDeviceEnumerator, AEnumerator);
  if not ARes = S_OK then Exit;
  if AEnumerator.GetDefaultAudioEndpoint(eRender, eConsole,  ADefault) = S_OK then
  try
    ADefault.Activate(IID_IAudioSessionManager2, CLSCTX_INPROC_SERVER, nil, AManager);
  finally
    ADefault := nil;
  end;
end;

initialization
  CoInitializeEx(nil, COINIT_MULTITHREADED);
end.

注:TDNUnknownObject是类实现IUnknown方法。

还有一个问题:什么情况下不音频会议时发送应用程序关闭? (在SndVol它是从列表中删除)。 我试过OnSessionDisconnected,OnStateChanged(与国家AudioSessionExpired),但我的应用程序一直没有收到他们。

提前致谢!

TDNUnknownObject:

TDNUnknownObject = class(TObject, IUnknown)
protected
  // IUnknown
  function _AddRef: Integer; stdcall;
  function _Release: Integer; stdcall;
  function QueryInterface(const IID: TGUID; out Obj): HRESULT; virtual; stdcall;
end;

function TDNUnknownObject._AddRef: Integer; stdcall;
begin
  Result := -1;
end;

function TDNUnknownObject._Release: Integer; stdcall;
begin
  Result := -1;
end;

function TDNUnknownObject.QueryInterface(const IID: TGUID; out Obj): HRESULT; stdcall;
begin
  if GetInterface(IID, Obj) then
    Result := S_OK
  else
    Result := E_NOINTERFACE;
end;

Answer 1:

嗯,我抓我的头这个..第一个问题来了:为什么不使用TInterfacedObject? 节省了大量的工作,被证明能够正常工作。 这个对象从IUnknown的衍生和别名IInterface,并且不正是你试图在这里做什么。 当然,你可以尝试写自己的版本,但要注意:德尔福编译器将会更加严格,所以你会喜欢双的实现和名称冲突陷阱很容易confrontated。 编译器,连接器和调试器可以表现,因为这些奇怪的。

好吧,从MS简短说明:请确保应用程序在非UI线程调用的CoInitializeEx(无,COINIT_MULTITHREADED)初始化与多线程单元(MTA)模型COM。 如果MTA没有初始化,应用程序不会从会话管理器接收会议通知。 运行应用程序的用户界面线程应该初始化公寓线程模型。

你去那里:你的初始化部分是不正确的。 它应该是:

initialization
  CoInitializeEx(Nil,
                 COINIT_APARTMENTTHREADED);


文章来源: Catch audio sessions events