2009-04-09 86 views
6

我想通过Windows 7的IAudioSessionManager2 COM接口(加上IAudioSessionNotification)来监视新的音频会话。目前,IAudioSessionNotification :: OnSessionCreated()永远不会被调用,我已经没有想到为什么。IAudioSessionManager2通知没有发送

代码注册自定义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刚刚发布消息,以每当暂时创建一个会话窗口;这从未发生过。为了防止我的假设完全脱离基础,我预计每当尚未播放音频的应用程序开始时都会发出通知;所以使用视频文件启动VLC应立即生成通知,而通过网络浏览器访问Pandora也会触发此通知。

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

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

+0

CustomAudioNotifications :: QueryInterface是否被调用?它是否返回S_OK? – sharptooth 2009-04-10 09:34:57

+0

通过其工厂构建对象之外;不,QueryInterface不被调用。至少,断点不会被触发。 – 2009-04-10 14:53:44

回答

15

这是一个比你需要做更多的工作。

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

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

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

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

我也假设你已经在程式码之前进行初始化COM。

更新:凯文给我发了他的申请,有一对夫妇与他的应用程序,它是更基本的(我的工作得到了文档的API的改进,以防止在未来的任何混淆)

等问题

第一个是他的应用程序没有检索到当前的会话列表。这是会话枚举API非常微妙的事情之一。为了防止在使用会话API的应用程序启动时会话通知到达时可能发生的争用情况,会话枚举API会放弃新的会话通知,直到应用程序首次检索到现有会话列表。

预期的使用模式是:

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

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

应用程序根据自己的条件管理会话的生命周期 - 只要应用程序对会话控制有引用,会话控制对象就会有效。音频会话控制对象没有到期机制。

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