2009-04-09 91 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。