捕获音频会话事件 [英] Catch audio sessions events

查看:843
本文介绍了捕获音频会话事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试写一些将监控音频会话的应用程序(如SndVol)。我激活IAudioSessionManager2,通过IAudioSessionEnumerator获得当前音频会话的列表,使用音频会话管理器中的RegisterSessionNotification方法注册通知。但是,我的应用程序从未收到通知OnSessionCreated()。当然,我在这里读到类似的主题:
通知未发送
IAudioSessionNotification任何人都有工作代码

I try to write some application that will monitor audio sessions (like SndVol does). I activated IAudioSessionManager2, got list of current audio sessions through IAudioSessionEnumerator, registered for the notification using RegisterSessionNotification method in audio session manager. However, my application never receives notification OnSessionCreated(). Of course, I read the similar topics here: Notifications not sent, IAudioSessionNotification anyone have working code

我仔细阅读所有的答案,但我找不到我做错了。这是我的代码(Delphi):

I read carefully all the answers but I couldn't find what I am doing wrong. Here is my code (Delphi):

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方法的类。

Note: TDNUnknownObject is class that implements IUnknown methods.

还有一个问题:当应用程序关闭时,音频会话发送什么事件? (在SndVol中,它从列表中删除)。我尝试OnSessionDisconnected,OnStateChanged(与状态AudioSessionExpired),但我的应用程序从来没有收到他们。

And one more question: what event does audio session send when application is closed? (in SndVol it is removed from list). I tried OnSessionDisconnected, OnStateChanged (with state AudioSessionExpired) but my app never receive them too.

提前感谢!

TDNUnknownObject:

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;


推荐答案

第一个问题出来:为什么不使用TInterfacedObject?节省大量的工作,并证明能够正常工作。此对象派生自IUnknown并别名为IInterface,并且完全按照您在此尝试做的。当然你可以尝试编写自己的版本,但要注意:Delphi编译器会更严格,所以你会很容易遇到像双重实现和名称冲突这样的陷阱。编译器,链接器和调试器可能会出现奇怪的行为。

Well I'm scratching my head about this.. The first question comes up: Why not using the TInterfacedObject? Saves a lot of work and is proven to work correctly. This object is derived from IUnknown and aliased to IInterface, and does exactly what you try to do here. Of course you could try to write your own version, but beware: Delphi compilers are going to be more strict and so you will be easily confrontated with pitfalls like double implementations and name clashes. The compiler, linker and debugger can behave strangely because of those.

确定MS的简短注释:
确保应用程序使用Multithreaded Apartment MTA)模型,通过在非UI线程中调用CoInitializeEx(Nil,COINIT_MULTITHREADED)。如果MTA未初始化,则应用程序不从会话管理器接收会话通知。运行应用程序的用户界面的线程应该是初始化的公寓线程模型。

Ok a short note from MS: Make sure that the application initializes COM with Multithreaded Apartment (MTA) model by calling CoInitializeEx(Nil, COINIT_MULTITHREADED) in a non-UI thread. If MTA is not initialized, the application does not receive session notifications from the session manager. Threads that run the user interface of an application should be initialized apartment threading model.

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

There you go: Your initialization section is not correct. It should be:

initialization
  CoInitializeEx(Nil,
                 COINIT_APARTMENTTHREADED);

这篇关于捕获音频会话事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆