代码注册自定义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),__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),(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应立即发出通知,而通过Web浏览器访问Pandora也会触发此类通知.
调试显示所有返回的值都是S_OK.
我的COM体验非常有限,所以指出一般的“WTF”?也将不胜感激.
您只需要编写一个派生自IAudioSessionNotifications的类 – 您不需要实际编写整个COM对象并注册它.
您还应该使用eConsole角色而不是eMultimedia角色.它没有实际意义(如果你只有一个音频设备),但它更正确.
CustomAudioNotification类的析构函数应该是私有的 – 这样可以防止意外破坏.所以我写道:
CustomAudioNotification
*customNotification = new CustomAudioNotification();
SESSION->RegisterSessionNotification(customNotification);
我还假设您已经在代码片段之前初始化了COM.
更新:Kevin发给我他的应用程序,他的应用程序还有一些其他问题更为基础(我正在努力改进API的文档,以防止将来出现任何混淆)
首先是他的应用程序没有检索当前的会话列表.这是会话枚举API的一个非常微妙的事情.为了防止在使用会话API的应用程序启动时会话通知到达时可能发生的竞争条件,会话枚举API会丢弃新的会话通知,直到应用程序首次检索到现有会话的列表.
预期的使用模式是:
应用程序激活会话管理器2.
应用程序注册会话通知.
应用程序检索端点的当前会话列表,并将会话控制对象存储到列表中(不要忘记添加会话).
创建新会话时,应用程序将引用新创建的会话控制对象,并将其插入列表(如果尚未存在).请注意,当会话通知返回时,传递给通知的会话控制对象将被销毁 – 如果此时调用GetSessionEnumerator,它可能不会保留新创建的会话(可能,这一切都取决于时间).
应用程序根据自己的标准管理会话的生命周期 – 只要应用程序具有对会话控制的引用,会话控制对象就是有效的.音频会话控制对象没有到期机制.
此外,会话API要求初始化MTA – 这是不幸的,但是因为我们在工作线程上创建COM对象(实现IAudioSessionControl),API要求在收到通知之前创建MTA.