捕获音频会话事件

2024-01-24

我尝试编写一些应用程序来监视音频会话(如 SndVol 所做的那样)。我激活了 IAudioSessionManager2,通过 IAudioSessionEnumerator 获取当前音频会话列表,使用音频会话管理器中的 RegisterSessionNotification 方法注册通知。但是,我的应用程序从未收到 OnSessionCreated() 通知。当然,我在这里读到了类似的主题:通知未发送 https://stackoverflow.com/questions/736084/iaudiosessionmanager2-notifications-not-sent, IAudioSessionNotification 任何人都有工作代码 https://stackoverflow.com/questions/858974/iaudiosessionnotification-anyone-have-working-code

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

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),但我的应用程序也从未收到它们。

提前致谢!

TDN 未知对象:

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 编译器将更加严格,因此您将很容易遇到双重实现和名称冲突等陷阱。因此,编译器、链接器和调试器的行为可能会很奇怪。

好的,来自 MS 的简短说明: 确保应用程序通过在非 UI 线程中调用 CoInitializeEx(Nil, COINIT_MULTITHREADED) 使用多线程单元 (MTA) 模型初始化 COM。如果 MTA 未初始化,应用程序不会从会话管理器接收会话通知。运行应用程序用户界面的线程应该初始化单元线程模型。

就是这样:您的初始化部分不正确。 它应该是:

initialization
  CoInitializeEx(Nil,
                 COINIT_APARTMENTTHREADED);
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

捕获音频会话事件 的相关文章

随机推荐

  • 为什么我们需要添加

    为什么我们需要在 Facebook 应用程序中添加这对标签 这对标签有什么用呢 我创建了一个使用 apprequest 的应用程序 即使我没有在脚本前面添加这些标签 它也能正常工作 所以我真的很想知道为什么我们需要添加它们 谢谢 它是 Fa
  • 什么是影根

    在 Google Chrome 的开发者工具中 我看到 shadow root就在下面标签 它有什么作用以及用途是什么 我在 Firefox 和 IE 中都没有看到它 仅在 Chrome 中 这是一个特殊功能吗 如果我打开它 它会显示 an
  • Logback 依赖性阻止 SBT 离线运行

    这是一个细化的上一个问题 https stackoverflow com questions 23014492 sbt 0 13 1 offline更密切地归因于问题 我正在尝试确认我可以离线运行我的 SBT 项目 我可以 除非 logba
  • python 2.7中的karger最小切割算法

    这是我的 karger min cut 算法的代码 据我所知 我实现的算法是正确的 但我没有得到正确的答案 如果有人可以检查出了什么问题 我将不胜感激 import random from random import randint loa
  • Plaid 快速入门 - 无法获取 link_token (Python)

    按照以下说明进行操作后https dashboard plaid com overview sandbox https dashboard plaid com overview sandbox 我得到了以下消息在前端 https i sta
  • 如何对值为数组引用的 Perl 哈希进行排序?

    嘿 我只是想知道是否有一个很酷的 单行 可以对保存数组引用的哈希进行排序 所以我的哈希中有一堆键 值 例如 DataBase key value 但是我想按以下方式对哈希进行排序array 0 元素 然后循环遍历它们 我一开始是这样的 fo
  • C++ 模板函数参数推导和函数解析

    今天我只想提出一个关于C 模板函数参数推导和C 11中模板函数重载解析的问题 我使用的是vs2010 sp1 我定义了两个模板函数 如下所示 功能 1 template
  • 在 Angular 应用程序中处理过滤值的更优雅的方式

    我在 Angular 2 应用程序中多次重新加载表格显示中的数据时遇到了一些问题 我认为主要问题与以下事实有关 在初始组件加载时 我将数据作为网络请求发送给一系列过滤器 基本上 我们利用 Mongo Mongoose 功能 让我们在 pos
  • APN 重复令牌

    我们有一个推送通知服务器 它保存多个不同应用程序的数据 设备令牌 由于 Apple 希望阻止人们使用 UDID 作为标识符 我正在考虑更改此服务器 以便它不再依赖 UDID 来识别设备 据我所知 APN 返回的令牌不是全局唯一的 而是每个设
  • 我如何编写一个 mt4 指标,在前 6 小时的每小时蜡烛图上绘制矩形和水平线

    我是 mql4 编码的新手 我想知道如何根据下图编写一个执行以下操作的指标 在当天的小时图上绘制一个矩形 覆盖前 6 小时的最高和最低价格点 蜡烛 沿着找到的最高点和最低点画两条水平线 1 请注意 1 和 2 应严格基于每小时时间段 并且不
  • 如何在 Spring Data REST 中禁止 PUT 而允许 POST 和 PATCH?

    是否可以在 Spring Data REST 中完全禁止对存储库进行 PUT 同时仍然可以对集合进行 POST 并对项目进行 PATCH 这背后的基本原理是 PUT 通常允许替换语义 但在我们的例子中 资源只能通过集合上的 POST 创建
  • 您可以使用 TortoiseGit 与索引/暂存区域进行交互吗?

    我的任务是向我的同事做关于 Git 的演示 他们几乎都是习惯使用 TortoiseCVS 的 Windows 用户 我已经使用 Git 大约一年了 但我几乎只使用 Unix 命令行界面 所以我一直在尝试熟悉 Windows GUI Git
  • 如何解析 React Js 中的最小和最大日期输入?

    我创建了一个函数 该函数返回当前日期的减法或加法 并将结果设置为日期输入的最小值或最大值 我的职能 SubDate subDay gt let tgDate new Date tgDate setDate tgDate getDate su
  • 如何获取流星智能包中的当前目录

    我正在为要在 Atmosphere 上发布的流星构建一个包 我需要获取该包安装的当前目录 我努力了process cwd 在包中包含的文件中 但它获取我的应用程序的当前目录 该软件包已安装并正常工作 似乎该软件包与应用程序在同一进程中运行
  • Eclipse LogCat - 不工作

    这是有史以来最令人沮丧的事情 LogCat 不断停用 断开连接 运行 eclipse 后 LogCat 记录第一次运行 之后 它变为空白 我必须重新启动 Eclipse 才能使其再次运行 然后同样的事情再次发生 这有什么关系呢 它曾经工作得
  • 如何在 Sublime 中将“一行 html”格式化为漂亮的文档? [复制]

    这个问题在这里已经有答案了 我有一个 html 源文件 仅包含一行 如下所示 testwow 我想将其格式化如下 test wow 我使用了命令 编辑 gt 行 gt 重新缩进 但它不起作用 在 Sublime Text 中试试这个 突出显
  • 如何配置Automapper注入Ninject 2.0?

    Structure Map 和 Windsor 有配置示例 http www cprieto com index php 2009 08 20 using automapper with castle windsor http www cp
  • thread_guard 与scoped_thread

    在书里 Anthony Williams 的 C 并发实践 你可以找到以下两段代码 我做了一些细微的修改 片段 1 class thread guard std thread t public explicit thread guard s
  • 仅授予对 Amazon 别名密钥的访问权限的 IAM 策略

    In KMS http docs aws amazon com kms latest developerguide overview html有亚马逊别名键 例如 alias aws s3 and 客户主密钥 http docs aws a
  • 捕获音频会话事件

    我尝试编写一些应用程序来监视音频会话 如 SndVol 所做的那样 我激活了 IAudioSessionManager2 通过 IAudioSessionEnumerator 获取当前音频会话列表 使用音频会话管理器中的 RegisterS