// File: ichnlaud.cpp #include "precomp.h" #include "ichnlaud.h" static const IID * g_apiidCP[] = { {&IID_INmChannelNotify}, {&IID_INmChannelAudioNotify} }; CNmChannelAudio::CNmChannelAudio(BOOL fIncoming) : CConnectionPointContainer(g_apiidCP, ARRAY_ELEMENTS(g_apiidCP)), m_cMembers (0), m_dwFlags(0), m_pAudioChannel(NULL), m_pAudioDevice(NULL), m_pCommChannel(NULL), m_fIncoming(fIncoming), m_AudioControl(!fIncoming /* fLocal */), m_MediaFormat(INVALID_MEDIA_FORMAT) { IMediaChannel *pMC = NULL; HRESULT hr; if (NULL != g_pH323UI) { IMediaChannelBuilder * pMCProvider = g_pH323UI->GetStreamProvider(); ASSERT(NULL != pMCProvider); // create the channel, and get the device interface pMCProvider->CreateMediaChannel(MCF_AUDIO | (fIncoming ? MCF_RECV : MCF_SEND), &pMC); if (NULL != pMC) { pMCProvider->QueryInterface(IID_IAudioDevice, (void**)&m_pAudioDevice); pMC->QueryInterface(IID_IAudioChannel, (void**)&m_pAudioChannel); ASSERT(m_pAudioChannel); ASSERT(m_pAudioDevice); pMC->Release(); } else { WARNING_OUT(("CreateMediaChannel failed")); } pMCProvider->Release(); } DbgMsg(iZONE_OBJECTS, "Obj: %08X created CNmChannelAudio", this); } CNmChannelAudio::~CNmChannelAudio() { if (NULL != m_pCommChannel) { m_pCommChannel->Release(); } if (NULL != m_pAudioChannel) { m_pAudioChannel->Release(); } if (NULL != m_pAudioDevice) { m_pAudioDevice->Release(); } DbgMsg(iZONE_OBJECTS, "Obj: %08X destroyed CNmChannelAudio", this); } VOID CNmChannelAudio::CommChannelOpened(ICommChannel *pCommChannel) { ASSERT(NULL == m_pCommChannel); m_pCommChannel = pCommChannel; pCommChannel->AddRef(); } VOID CNmChannelAudio::CommChannelActive(ICommChannel *pCommChannel) { ASSERT(m_pCommChannel == pCommChannel); } VOID CNmChannelAudio::CommChannelClosed() { if (NULL != m_pCommChannel) { m_pCommChannel->Release(); m_pCommChannel = NULL; } } VOID CNmChannelAudio::OnMemberAdded(CNmMember *pMember) { // Don't add to the channel if we already belong. if (0 != (pMember->GetNmchCaps() & NMCH_AUDIO)) { return; } ++m_cMembers; pMember->AddNmchCaps(NMCH_AUDIO); CConfObject *pco = ::GetConfObject(); pco->OnMemberUpdated(pMember); NotifySink((INmMember *) pMember, OnNotifyChannelMemberAdded); } VOID CNmChannelAudio::OnMemberRemoved(CNmMember *pMember) { // If member does not belong to this channel, don't remove it. if (0 == (pMember->GetNmchCaps() & NMCH_AUDIO)) { return; } --m_cMembers; pMember->RemoveNmchCaps(NMCH_AUDIO); CConfObject *pco = ::GetConfObject(); pco->OnMemberUpdated(pMember); NotifySink((INmMember *) pMember, OnNotifyChannelMemberRemoved); } VOID CNmChannelAudio::OnMemberUpdated(CNmMember *pMember) { NotifySink((INmMember *) pMember, OnNotifyChannelMemberUpdated); } DWORD CNmChannelAudio::GetLevel() { UINT uLevel = 0; if (NULL != m_pAudioChannel) { m_pAudioChannel->GetSignalLevel(&uLevel); } return uLevel; } BOOL CNmChannelAudio::IsAutoMixing() { BOOL bOn=FALSE; if ((NULL != m_pAudioChannel) && (!m_fIncoming)) { m_pAudioDevice->GetAutoMix(&bOn); } return bOn; } BOOL CNmChannelAudio::IsPaused() { BOOL fPaused = TRUE; if (NULL != m_pCommChannel) { DWORD dwOn = FALSE; UINT uSize = sizeof(dwOn); DWORD dwPropID = m_fIncoming ? PROP_PLAY_ON : PROP_RECORD_ON; m_pCommChannel->GetProperty(dwPropID, &dwOn, &uSize); fPaused = (0 == dwOn); } return fPaused; } VOID CNmChannelAudio::Open() { ASSERT(m_MediaFormat != INVALID_MEDIA_FORMAT); m_AudioControl.Open(m_MediaFormat); } VOID CNmChannelAudio::Close() { m_AudioControl.Close(); } STDMETHODIMP_(ULONG) CNmChannelAudio::AddRef(void) { return RefCount::AddRef(); } STDMETHODIMP_(ULONG) CNmChannelAudio::Release(void) { return RefCount::Release(); } STDMETHODIMP CNmChannelAudio::QueryInterface(REFIID riid, PVOID *ppv) { HRESULT hr = S_OK; if ((riid == IID_INmChannelAudio) || (riid == IID_INmChannel) || (riid == IID_IUnknown)) { *ppv = (INmChannel *)this; DbgMsgApi("CNmChannelAudio::QueryInterface()"); } else if (riid == IID_IConnectionPointContainer) { *ppv = (IConnectionPointContainer *) this; DbgMsgApi("CNmChannelAudio::QueryInterface(): Returning IConnectionPointContainer."); } else { hr = E_NOINTERFACE; *ppv = NULL; DbgMsgApi("CNmChannelAudio::QueryInterface(): Called on unknown interface."); } if (S_OK == hr) { AddRef(); } return hr; } STDMETHODIMP CNmChannelAudio::IsSameAs(INmChannel *pChannel) { return (((INmChannel *) this) == pChannel) ? S_OK : S_FALSE; } STDMETHODIMP CNmChannelAudio::IsActive() { return (NULL != m_pCommChannel) ? S_OK : S_FALSE; } STDMETHODIMP CNmChannelAudio::SetActive(BOOL fActive) { return E_FAIL; } STDMETHODIMP CNmChannelAudio::GetConference(INmConference **ppConference) { return ::GetConference(ppConference); } STDMETHODIMP CNmChannelAudio::GetInterface(IID *piid) { HRESULT hr = E_POINTER; if (NULL != piid) { *piid = IID_INmChannelAudio; hr = S_OK; } return hr; } STDMETHODIMP CNmChannelAudio::GetNmch(ULONG *puCh) { HRESULT hr = E_POINTER; if (NULL != puCh) { *puCh = NMCH_AUDIO; hr = S_OK; } return hr; } STDMETHODIMP CNmChannelAudio::EnumMember(IEnumNmMember **ppEnum) { HRESULT hr = E_POINTER; if (NULL != ppEnum) { int cMembers = 0; COBLIST MemberList; COBLIST* pPartList = ::GetMemberList(); if (NULL != pPartList) { POSITION pos = pPartList->GetHeadPosition(); while (pos) { CNmMember * pMember = (CNmMember *) pPartList->GetNext(pos); ASSERT(NULL != pMember); if (NMCH_AUDIO & pMember->GetNmchCaps()) { MemberList.AddTail(pMember); pMember->AddRef(); cMembers++; } } } *ppEnum = new CEnumNmMember(&MemberList, cMembers); while (!MemberList.IsEmpty()) { INmMember *pMember = (INmMember *) (CNmMember *) MemberList.RemoveHead(); pMember->Release(); } hr = (NULL != *ppEnum)? S_OK : E_OUTOFMEMORY; } return hr; } STDMETHODIMP CNmChannelAudio::GetMemberCount(ULONG * puCount) { HRESULT hr = E_POINTER; if (NULL != puCount) { *puCount = m_cMembers; hr = S_OK; } return hr; } STDMETHODIMP CNmChannelAudio::IsIncoming(void) { return m_fIncoming ? S_OK : S_FALSE; } STDMETHODIMP CNmChannelAudio::GetState(NM_AUDIO_STATE *puState) { HRESULT hr = E_POINTER; if (NULL != puState) { if (NULL != m_pCommChannel) { if (IsPaused()) { *puState = NM_AUDIO_LOCAL_PAUSED; } else { *puState = NM_AUDIO_TRANSFERRING; } } else { *puState = NM_AUDIO_IDLE; } hr = S_OK; } return hr; } IMediaChannel* CNmChannelAudio::GetMediaChannelInterface(void) { IMediaChannel *pMC=NULL; if (m_pAudioChannel) { m_pAudioChannel->QueryInterface(IID_IMediaChannel, (void**)&pMC); } return pMC; } STDMETHODIMP CNmChannelAudio::GetProperty(NM_AUDPROP uID, ULONG_PTR *puValue) { HRESULT hr = E_POINTER; if (NULL != puValue) { switch (uID) { case NM_AUDPROP_LEVEL: *puValue = GetLevel(); hr = S_OK; break; case NM_AUDPROP_PAUSE: *puValue = IsPaused(); hr = S_OK; break; case NM_AUDPROP_AUTOMIX: *puValue = IsAutoMixing(); hr = S_OK; break; default: hr = E_FAIL; break; } } return hr; } HRESULT OnNotifyPropertyChanged(IUnknown *pAudioChannelNotify, PVOID pv, REFIID riid) { ASSERT(NULL != pAudioChannelNotify); ((INmChannelAudioNotify*)pAudioChannelNotify)->PropertyChanged((DWORD)((DWORD_PTR)pv)); return S_OK; } HRESULT OnNotifyStateChanged(IUnknown *pAudioChannelNotify, PVOID pv, REFIID riid) { ASSERT(NULL != pAudioChannelNotify); ((INmChannelAudioNotify*)pAudioChannelNotify)->StateChanged(static_cast((DWORD)((DWORD_PTR)pv))); return S_OK; } STDMETHODIMP CNmChannelAudio::SetProperty(NM_AUDPROP uID, ULONG_PTR uValue) { HRESULT hr = E_FAIL; if ((NULL != m_pAudioDevice) && (NULL != m_pAudioChannel)) { switch (uID) { case NM_AUDPROP_PAUSE: { DWORD dwOn = (0 == uValue); DWORD dwPropID = m_fIncoming ? PROP_PLAY_ON : PROP_RECORD_ON; if (m_pCommChannel) { hr = m_pCommChannel->SetProperty(dwPropID, &dwOn, sizeof(dwOn)); if(S_OK == hr) { // The Mute state has changed NotifySink((void*)NM_AUDPROP_PAUSE, OnNotifyPropertyChanged); // The Channel state has changed NM_AUDIO_STATE uState; if(SUCCEEDED(GetState(&uState))) { NotifySink((void*)uState, OnNotifyStateChanged); } } } break; } case NM_AUDPROP_LEVEL: { hr = m_pAudioDevice->SetSilenceLevel(uValue); break; } case NM_AUDPROP_FULL_DUPLEX: { DWORD dwDuplex = uValue; hr = m_pAudioDevice->SetDuplex((BOOL)uValue); break; } case NM_AUDPROP_WAVE_DEVICE: { if (m_fIncoming) { hr = m_pAudioDevice->SetPlaybackID(uValue); } else { hr = m_pAudioDevice->SetRecordID(uValue); } break; } case NM_AUDPROP_AUTOMIX: { hr = m_pAudioDevice->SetAutoMix((BOOL)uValue); break; } case NM_AUDPROP_DTMF_DIGIT: { IDTMFSend *pDTMF=NULL; if (!m_fIncoming) { hr = m_pAudioChannel->QueryInterface(IID_IDTMFSend, (void**)&pDTMF); if (SUCCEEDED(hr)) { hr = pDTMF->AddDigit((int)uValue); pDTMF->Release(); } } } default: break; } } return hr; }