com - IAudioSessionManager2 通知未发送

标签 com windows-7 audio

我正在尝试通过 Windows 7 的 IAudioSessionManager2 COM 接口(interface)(与 IAudioSessionNotification 结合)监视新的 Audio Session 。目前, IAudioSessionNotification::OnSessionCreated() 从未被调用过,我已经想不出为什么了。

注册自定义 IAudioSessionNotification 的代码:

#define SAFE_RELEASE(comObj) \
if(comObj != NULL) \
    { (comObj)->Release(); comObj = NULL; }

BOOL success = false;

HRESULT res;
IClassFactory* pFactory;
IMMDevice* pDevice;
IMMDeviceEnumerator* pEnumerator;

SESSION_LISTENER = NULL;
SESSION = NULL;

res = CoInitialize(NULL);

if(res != S_OK && res != S_FALSE)
    return false;

res = CoGetClassObject(CLSID_CustomAudioFactory, CLSCTX_ALL, NULL, __uuidof(IClassFactory), (void**)&pFactory);
if(res != S_OK)  goto Exit;

res = pFactory->CreateInstance(NULL, CLSID_CustomAudioNotifications, (void**)&SESSION_LISTENER);
if(res != S_OK)  goto Exit;

res = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&pEnumerator);
if(res != S_OK)  goto Exit;

res = pEnumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, &pDevice);
if(res != S_OK)  goto Exit;

res = pDevice->Activate(__uuidof(IAudioSessionManager2), CLSCTX_ALL, NULL, (void**)&SESSION);
if(res != S_OK)  goto Exit;

res = SESSION->RegisterSessionNotification(SESSION_LISTENER);
if(res != S_OK)  goto Exit;

success = true;

Exit:
SAFE_RELEASE(pFactory);
SAFE_RELEASE(pEnumerator);
SAFE_RELEASE(pDevice);
if(!success)
{
    SAFE_RELEASE(SESSION_LISTENER);
    SAFE_RELEASE(SESSION);
}

CustomAudioNotifications 声明:
class CustomAudioNotifications : public IAudioSessionNotification
{
public:
//Constructors
CustomAudioNotifications()  { InterlockedIncrement(&g_notifyCount); m_listener = NULL; }
~CustomAudioNotifications() { InterlockedDecrement(&g_notifyCount); SAFE_RELEASE(m_listener); }

//IUnknown interface
HRESULT __stdcall QueryInterface(
                            REFIID riid ,
                            void **ppObj);
ULONG   __stdcall AddRef();
ULONG   __stdcall Release();

//Notification
HRESULT __stdcall OnSessionCreated(IAudioSessionControl *NewSession);

private:
LONG m_nRefCount;
};

OnSessionCreated 只是暂时在创建 session 时向窗口发布消息;这永远不会发生。以防万一我的假设完全不成立,我希望在尚未播放音频的应用程序开始播放时收到通知;因此启动带有视频文件的 VLC 应该会立即产生通知,而通过 Web 浏览器访问 Pandora 也会触发这样的通知。

调试显示所有返回值都是 S_OK。

我的 COM 经验非常有限,所以指出一般的“WTF”?也将不胜感激。

最佳答案

这比您需要做的工作多 TON。

您只需要编写一个派生自 IAudioSessionNotifications 的类 - 您不需要实际编写整个 COM 对象并注册它。

您还应该使用 eConsole 角色而不是 eMultimedia 角色。这实际上并不重要(如果您只有一个音频设备),但它更正确。

CustomAudioNotification 类的析构函数应该是私有(private)的——这样可以防止意外破坏。所以我会写:

CustomAudioNotification *customNotification = new CustomAudioNotification(); SESSION->RegisterSessionNotification(customNotification);



我还假设您已经在代码片段之前初始化了 COM。

更新:Kevin 向我发送了他的应用程序,他的应用程序还有一些其他更基本的问题(我正在努力改进 API 的文档以防止将来出现任何混淆)

首先是他的应用程序没有检索到当前的 session 列表。这是关于 session 枚举 API 的真正微妙之处之一。为了防止在使用 session API 的应用程序启动时 session 通知到达时可能发生的竞争条件, session 枚举 API 会丢弃新的 session 通知,直到应用程序首先检索到现有 session 的列表。

预期的使用模式是:

应用程序激活 session 管理器2。
应用程序注册 session 通知。
应用程序检索端点的当前 session 列表并将 session 控制对象存储到列表中(不要忘记添加 session )。

创建新 session 时,应用程序获取对新创建的 session 控制对象的引用,如果它不存在,则将其插入到列表中。请注意,当 session 通知返回时,传递到通知中的 session 控制对象将被销毁 - 如果此时调用 GetSessionEnumerator 它可能不会保留新创建的 session (它可能,这完全取决于时间)。

应用程序根据自己的标准管理 session 的生命周期——只要应用程序引用了 session 控制, session 控制对象就有效。 Audio Session 控制对象没有过期机制。

此外, session API 要求初始化 MTA - 这很不幸,但是因为我们在工作线程上创建 COM 对象(实现 IAudioSessionControl),所以 API 要求在收到通知之前创建 MTA。

关于com - IAudioSessionManager2 通知未发送,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/736084/

相关文章:

iphone - 您如何循环播放iPhone的声音?

c# - 尝试为 SxS C#.NET COM DLL 调用 CoCreateInstance 时出现 HRESULT 0x80070002 (FILE_NOT_FOUND)

c# COM 对象 & "The value of ESP was not properly saved across a function call..."

C# 在 COM 重应用中的使用

windows - bat/cmd 文件不返回

c - Win7中通过pid获取进程信息

windows-7 - 如何在 Windows 7 中使用 C++ 保存文件

android - Media Player同步播放音频和视频

javascript - 如果正在使用屏幕阅读器,我想禁用音频事件

c# - 通过 C# 访问远程 COM 对象