IAudioSessionManager2通知不会发送 [英] IAudioSessionManager2 notifications not sent

查看:276
本文介绍了IAudioSessionManager2通知不会发送的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想通过监视Windows 7的IAudioSessionManager2 COM接口(加上IAudioSessionNotification)新的音频会话。目前,IAudioSessionNotification :: OnSessionCreated()不会被调用,我已经江郎才尽了,为什么。

code注册自定义IAudioSessionNotification:

 的#define SAFE_RELEASE(comObj)\\
如果(comObj!= NULL)\\
{(comObj) - GT;发行(); comObj = NULL; }BOOL成功= FALSE;HRESULT资源;
IClassFactory的* pFactory;
IMMDevice * pDevice;
IMMDeviceEnumerator * pEnumerator;SESSION_LISTENER = NULL;
SESSION = NULL;RES = CoInitialize的(NULL);如果(RES = S_OK和放大器;!&安培;!解析度= S_FALSE)
返回false;RES = CoGetClassObject(CLSID_CustomAudioFactory,CLSCTX_ALL,NULL,__uuidof(ICla​​ssFactory的),(无效**)及pFactory);
如果(RES = S_OK!)转到退出;RES = pFactory->的CreateInstance(NULL,CLSID_CustomAudioNotifications,(无效**)及SESSION_LISTENER);
如果(RES = S_OK!)转到退出;RES = CoCreateInstance的(__ uuidof(MMDeviceEnumerator),NULL,CLSCTX_ALL,__uuidof(IMMDeviceEnumerator),(无效**)及pEnumerator);
如果(RES = S_OK!)转到退出;RES = pEnumerator-> GetDefaultAudioEndpoint(eRender,eMultimedia,&安培; pDevice);
如果(RES = S_OK!)转到退出;RES = pDevice->激活(__ uuidof(IAudioSessionManager2),CLSCTX_ALL,NULL,(无效**)及会议);
如果(RES = S_OK!)转到退出;RES =会话级> RegisterSessionNotification(SESSION_LISTENER);
如果(RES = S_OK!)转到退出;成功= TRUE;出口:
SAFE_RELEASE(pFactory);
SAFE_RELEASE(pEnumerator);
SAFE_RELEASE(pDevice);
如果(!成功)
{
SAFE_RELEASE(SESSION_LISTENER);
SAFE_RELEASE(会话);
}

CustomAudioNotifications声明:

 类CustomAudioNotifications:公共IAudioSessionNotification
{
上市:
//构造函数
CustomAudioNotifications(){InterlockedIncrement(安培; g_notifyCount); m_listener = NULL; }
〜CustomAudioNotifications(){InterlockedDecrement(安培; g_notifyCount); SAFE_RELEASE(m_listener); }// IUnknown接口
HRESULT __stdcall的QueryInterface(
                            REFIID RIID,
                            无效** ppObj);
ULONG __stdcall的AddRef();
ULONG __stdcall发行();//通知
HRESULT __stdcall OnSessionCreated(IAudioSessionControl * newsession的);私人的:
LONG m_nRefCount;
};

OnSessionCreated刚刚发布消息,以每当暂时创建一个会话的窗口;这从未发生过。万一我的假设是完全关闭基地,我期待一个通知,每当一个尚未播放音频开始这样做的一个应用程序;因此与视频文件启动VLC应立即导致的通知,同时通过Web浏览器访问潘多拉也会引发这样的通知。

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

我的COM的经验是pretty limitted,所以指出一般的WTFs?也将是AP preciated。


解决方案

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

您只需编写从IAudioSessionNotifications派生的类 - 你不需要实际编写整个COM对象,并将其注册

您还应该使用eMultimedia作用eConsole作用来代替。它并不能有效没关系(如果你只有一个音频设备),但它更正确。

对于CustomAudioNotification类的析构函数应该是私有的 - 这样你prevent意外破坏。所以我会写:


  

CustomAudioNotification
  * customNotification =新CustomAudioNotification();
  会话级> RegisterSessionNotification(customNotification);


我也假设你已经你的code段之前初始化COM。

更新:凯文给我发了他的申请,有一对夫妇与他的应用程序,它是更基本的(我的工作得到了文档的API的提高prevent在未来的任何混淆)等问题

第一,他的申请尚未检索到会话当前列表。这是关于会话枚举的API真正微妙的事情之一。为了prevent会话时通知到达时使用会话API的应用程序启动时可能发生的竞争条件,会话枚举API丢弃新的会话通知,直到应用程序检索第一现有会话列表。

预期的使用模式是:

应用程序启动一个会话manager2。
应用寄存器会议通知。
应用检索终点当前会话的列表和会话控制的对象存储到一个列表(不要忘记的AddRef会话)。

当创建一个新的会话,应用程序需要参照新创建的会话控制对象,并将其插入到列表中,如果它不是已经present。请注意,当会话通知返回传递到通知会话控制对象将被破坏 - 如果你在​​这一点上它可能不会举行新创建会话调用GetSessionEnumerator(可能,这一切都取决于时机)

应用程序管理基于自己的标准的会话的生存期 - 只要应用程序的会话控制的参考会话控制对象将是有效的。有音频会话控制对象没有到期机制。

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

I'm trying to monitor new audio sessions via Windows 7's IAudioSessionManager2 COM interface (coupled with IAudioSessionNotification). Currently, IAudioSessionNotification::OnSessionCreated() is never called and I've run out of ideas as to why.

Code registering custom 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 declaration:

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 just posts a message to a window whenever a session is created for the time being; which never happens. Just in case my assumptions are totally off base, I'm expecting a notification whenever an application that has yet to play audio starts to do so; so launching VLC with a video file should immediately result in a notice, while visiting Pandora via a web browser would also trigger such a notice.

Debugging shows all returned values are S_OK.

My COM experience is pretty limitted, so pointing out general "WTFs?" would also be appreciated.

解决方案

That's a TON more work than you need to do.

You just need to write a class that derives from IAudioSessionNotifications - you don't need to actually write a whole COM object and register it.

You should also use the eConsole role instead of the eMultimedia role. It doesn't effectively matter (if you have only one audio device) but it's more correct.

The destructor for the CustomAudioNotification class should be private - that way you prevent accidental destruction. So I'd write:

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

I'm also assuming that you've initialized COM before your code snippet.

UPDATED: Kevin sent me his application and there are a couple of other issues with his application that are more fundamental (I'm working to get the documentation for the APIs improve to prevent any confusion in the future)

The first is that his application hasn't retrieved the current list of sessions. This is one of the really subtle things about the session enumeration APIs. In order to prevent a race condition that can occur when a session notification arrives while the application using the session APIs is starting up, the session enumeration API discards new session notifications until the application has first retrieved the list of existing sessions.

The expected usage pattern is:

Application activates a session manager2. Application registers for session notifications. Application retrieves the current list of sessions for the endpoint and stores the session control objects into a list (don't forget to addref the session).

When a new session is created, the application takes a reference to the newly created session control object and inserts it into the list if it's not already present. Note that the session control object passed into the notification will be destroyed when the session notification returns - if you call GetSessionEnumerator at this point it will probably NOT hold the newly created session (it might, it all depends on timing).

The application manages the lifetime of the session based on its own criteria - as long as the application has a reference to the session control the session control object will be valid. There is no expiration mechanism for audio session control objects.

In addition, the session APIs require that the MTA be initialized - this is unfortunate but because we create COM objects (which implement IAudioSessionControl) on a worker thread the API requires that the MTA be created before the notification is received.

这篇关于IAudioSessionManager2通知不会发送的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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