📄 hxaudply.cpp
字号:
// Create the Stream response list.
m_pStreamList = new CHXSimpleList;
#if defined(HELIX_FEATURE_AUDIO_POSTMIXHOOK)
m_pPMixHookList = new CHXSimpleList;
#endif /* HELIX_FEATURE_AUDIO_POSTMIXHOOK */
m_pStreamRespList = new CHXSimpleList;
if ( !m_pStreamList || !m_pStreamList->IsPtrListValid())
theErr = HXR_OUTOFMEMORY;
#if defined(HELIX_FEATURE_AUDIO_POSTMIXHOOK)
if ( !m_pPMixHookList || !m_pPMixHookList->IsPtrListValid())
theErr = HXR_OUTOFMEMORY;
#endif /* HELIX_FEATURE_AUDIO_POSTMIXHOOK */
if ( !m_pStreamRespList || !m_pStreamRespList->IsPtrListValid())
theErr = HXR_OUTOFMEMORY;
#if defined(HELIX_FEATURE_VOLUME)
if( !theErr )
{
m_pPlayerVolume = (IHXVolume*)new CHXVolume;
if( m_pPlayerVolume )
{
m_pPlayerVolume->AddRef();
m_pPlayerVolume->AddAdviseSink(this);
//Start off with the volume at max.
m_pPlayerVolume->SetVolume(HX_MAX_VOLUME);
}
else
{
theErr = HXR_OUTOFMEMORY;
}
}
#endif /* HELIX_FEATURE_VOLUME */
return ( theErr );
}
/************************************************************************
* Method:
* CHXAudioPlayer::GetFormat
* Purpose:
* Return the player's device format which was determined in
* InitPlayer() and is based on all the streams.
*/
void CHXAudioPlayer::GetFormat
(
HXAudioFormat* pAudioFormat
)
{
memcpy(pAudioFormat, &m_PlayerFmt, sizeof( HXAudioFormat) );
}
/* ***********************************************************************
* Method:
* CHXAudioPlayer::GetAudioPrefs
* Purpose:
* Get audio related preferences.
*/
HX_RESULT CHXAudioPlayer::GetAudioPrefs()
{
IHXBuffer* pBuffer = NULL;
IHXPreferences* pPreferences = 0;
#if defined(HELIX_FEATURE_PREFERENCES)
/* Reason we query for Preferences here and not at Init() is because
* Preferences may have been overwritten in HXPlayer by SetupClient()
* call by upper level client and this happens AFTER CHXAudioPlayer::Init()
* is called
*/
if (!m_pContext)
{
return HXR_INVALID_PARAMETER;
}
m_pContext->QueryInterface(IID_IHXPreferences, (void**) &pPreferences);
// What is the pref for this?
if( pPreferences )
{
if (pPreferences->ReadPref("SamplingRate", pBuffer) == HXR_OK)
{
m_bPrefUse11khz = (11025 == ::atol((const char*) pBuffer->GetBuffer()));
pBuffer->Release();
pBuffer = 0;
}
ReadPrefINT16(pPreferences, "BitsPerSample", m_uPrefBitsPerSample);
ReadPrefINT16(pPreferences, "Quality", m_uPrefAudioQuality);
/* hmmm... Looks like the client override default Preferences implementation*/
if (m_pPreferences != pPreferences)
{
if (m_pPreferences)
{
m_pPreferences->Release();
}
m_pPreferences = pPreferences;
m_pPreferences->AddRef();
}
pPreferences->Release();
}
#endif /* HELIX_FEATURE_PREFERENCES */
return HXR_OK;
}
/************************************************************************
* Method:
* IHXAudioPlay::CreateAudioStream
* Purpose:
* The renderer calls this to create a unique audio stream with its
* unique audio format.
*/
STDMETHODIMP CHXAudioPlayer::CreateAudioStream
(
IHXAudioStream** pAudioStream
)
{
HX_RESULT theErr = HXR_OK;
// Create a new IRMA audio stream
*pAudioStream = 0;
*pAudioStream = (IHXAudioStream*) new CHXAudioStream(this, m_pContext);
if ( !*pAudioStream )
{
theErr = HXR_OUTOFMEMORY;
}
// Add audio stream to my list
if (!theErr)
{
theErr = _CreateAudioStream(pAudioStream);
}
return theErr;
}
HX_RESULT
CHXAudioPlayer::_CreateAudioStream(IHXAudioStream** pAudioStream)
{
(*pAudioStream)->AddRef(); // once for user
(*pAudioStream)->AddRef(); // once for me
// Add to the stream list.
m_pStreamList->AddTail((void*) *pAudioStream);
((CHXAudioStream*)(*pAudioStream))->SetLive(m_bIsLive);
m_Owner->CheckIfLastNMilliSecsToBeStored();
/* Already initialized with no streams?*/
if (m_bInited && !m_bHasStreams)
{
/* If we are already initialized and there were no audio streams before
* initialization, we must be using our fake timer to send time syncs
* This needs to change now to get time syncs from the audio device
*/
((CHXAudioStream*)(*pAudioStream))->SetupToBeDone();
return HXR_OK;
}
m_bHasStreams = TRUE;
/* If we are already initialized, it means CreateAudioStream was
* called in the midst of the presentation. In this case, we already know
* the granularity and the Device format and thus call Setup right away
*/
if ((*pAudioStream) && m_bInited)
{
((CHXAudioStream*)(*pAudioStream))->Setup( &m_DeviceFmt, m_ulGranularity );
}
return HXR_OK;
}
HX_RESULT
CHXAudioPlayer::SetSoundLevel(CHXSimpleList* pAudioStreamList, UINT16 uSoundLevel, BOOL bReflushAudioDevice)
{
HX_RESULT rc = HXR_OK;
IHXVolume* pStreamVolume = NULL;
if (pAudioStreamList && !pAudioStreamList->IsEmpty())
{
CHXSimpleList::Iterator lIter = pAudioStreamList->Begin();
for (; lIter != pAudioStreamList->End(); ++lIter)
{
CHXAudioStream* pAudioStream = (CHXAudioStream*) (*lIter);
pStreamVolume = pAudioStream->GetAudioVolume();
if (pStreamVolume)
{
pStreamVolume->SetVolume(uSoundLevel);
}
HX_RELEASE(pStreamVolume);
}
if (bReflushAudioDevice)
{
AudioStreamStateChanged(E_PLAYING);
}
}
return rc;
}
HX_RESULT CHXAudioPlayer::ManageAudioStreams( CHXSimpleList* pStreamList,
STREAM_ACTION what,
UINT32 ulTime )
{
HX_RESULT rc = HXR_OK;
LISTPOSITION pos = 0;
if(pStreamList && !pStreamList->IsEmpty())
{
CHXSimpleList::Iterator it = pStreamList->Begin();
while( it != pStreamList->End() )
{
CHXAudioStream* pAudioStream = (CHXAudioStream*) (*it);
switch(what)
{
case STR_STOP:
pAudioStream->Stop();
break;
case STR_SEEK:
pAudioStream->Seek(ulTime);
break;
case STR_RESUME:
pAudioStream->Resume(FALSE);
break;
case STR_PAUSE:
pAudioStream->Pause(FALSE);
break;
case STR_SETHINT:
pAudioStream->SetAudioDeviceReflushHint(TRUE);
break;
case STR_REMOVE:
pos = m_pStreamList->Find(pAudioStream);
if (pos)
m_pStreamList->RemoveAt(pos);
pAudioStream->Stop();
HX_RELEASE(pAudioStream);
break;
default:
HX_ASSERT("bad stream action taken"==NULL);
}
++it;
}
//Post stream iteration actions.
switch(what)
{
case STR_STOP:
AudioStreamStateChanged(E_STOPPED);
break;
case STR_PAUSE:
AudioStreamStateChanged(E_PAUSED);
break;
case STR_SETHINT:
m_Owner->CheckIfLastNMilliSecsToBeStored();
break;
case STR_REMOVE:
if( 0 == m_pStreamList->GetCount())
{
m_bHasStreams = FALSE;
m_Owner->Stop(this, TRUE);
m_bInited = FALSE;
if(HXR_OK != (rc=Setup(m_ulGranularity)))
{
IHXErrorMessages* pErrorMessage = NULL;
m_pContext->QueryInterface(IID_IHXErrorMessages, (void**) &pErrorMessage);
if (pErrorMessage)
{
pErrorMessage->Report(HXLOG_ERR, rc, 0, NULL, NULL);
pErrorMessage->Release();
}
rc = HXR_OK;
}
else
{
rc = ResumeFakeTimeline();
}
}
else
{
AudioStreamStateChanged(E_STOPPED);
}
break;
default:
HX_ASSERT("bad stream action taken"==NULL );
}
}
return rc;
}
HX_RESULT
CHXAudioPlayer::AudioStreamStateChanged(EPlayerState eState)
{
if(!m_Owner->GetDisableMultiPlayPauseSupport())
{
// we only concern about the state change of audio stream
// while its parent audio player is in playing mode
if (m_eState == E_PLAYING)
{
switch (eState)
{
case E_PLAYING:
m_Owner->RewindSession();
m_Owner->ActualResume();
break;
case E_PAUSED:
case E_STOPPED:
m_Owner->RewindSession();
if (NumberOfResumedStreams() > 0 ||
m_Owner->NumberOfResumedPlayers() > 0)
{
m_Owner->ActualResume();
}
break;
default:
break;
}
}
}
return HXR_OK;
}
CHXAudioStream*
CHXAudioPlayer::GetCHXAudioStream(UINT16 uIndex)
{
LISTPOSITION lp = 0;
lp = m_pStreamList->FindIndex( (int) uIndex );
if ( lp )
{
return (CHXAudioStream*)m_pStreamList->GetAt(lp);
}
else
{
return NULL;
}
}
BOOL
CHXAudioPlayer::IsLastNMilliSecsToBeStored()
{
BOOL bResult = FALSE;
if (m_bHasStreams)
{
CHXAudioStream* s = 0;
CHXSimpleList::Iterator lIter = m_pStreamList->Begin();
for (; lIter != m_pStreamList->End(); ++lIter)
{
s = (CHXAudioStream*) (*lIter);
if (s->IsAudioDeviceReflushHint())
{
bResult = TRUE;
break;
}
}
}
return bResult;
}
HX_RESULT
CHXAudioPlayer::ActualAddPostMixHook(IHXAudioHook* pHook,
const BOOL bDisableWrite,
const BOOL bFinal)
{
if (!m_pPMixHookList || !pHook)
{
return HXR_FAILED;
}
#if defined(HELIX_FEATURE_AUDIO_POSTMIXHOOK)
/* Check if this one already exists */
HXAudioHookInfo* h = 0;
LISTPOSITION lp = 0;
lp = m_pPMixHookList->GetHeadPosition();
while( lp )
{
h = (HXAudioHookInfo*) m_pPMixHookList->GetNext(lp);
if (pHook == h->pHook)
{
return HXR_FAILED;
}
}
h = (HXAudioHookInfo*) new HXAudioHookInfo;
h->pHook = pHook;
h->bDisableWrite = bDisableWrite;
h->bFinal = bFinal;
h->bIgnoreAudioData = FALSE;
h->bMultiChannelSupport = FALSE;
IHXValues* pValues = NULL;
if (pHook && pHook->QueryInterface(IID_IHXValues, (void**) &pValues) == HXR_OK)
{
UINT32 ulValue = 0;
pValues->GetPropertyULONG32("IgnoreAudioData", ulValue);
h->bIgnoreAudioData = (ulValue == 1);
HX_RELEASE(pValues);
}
IHXAudioMultiChannel* pMultiChannel = NULL;
if (pHook && HXR_OK == pHook->QueryInterface(IID_IHXAudioMultiChannel, (void**) &pMultiChannel))
{
h->bMultiChannelSupport = pMultiChannel->GetMultiChannelSupport();
}
HX_RELEASE(pMultiChannel);
if (bDisableWrite)
{
m_bDisableWrite = bDisableWrite;
}
pHook->AddRef();
// Order list by putting all bFinal == TRUE at end of list.
if ( m_pPMixHookList->IsEmpty() || !bFinal )
{
m_pPMixHookList->AddHead((void*) h);
}
else
{
m_pPMixHookList->AddTail((void*) h);
}
m_Owner->PostMixHooksUpdated();
ProcessAudioHook(ACTION_ADD, pHook);
/* If we are already initialized, send the device format to the
* post hook
*/
if (m_bInited)
{
if (h->bIgnoreAudioData ||
HXR_OK == ProcessAudioHook(ACTION_CHECK, pHook))
{
HXAudioFormat audioFmt;
m_Owner->GetFormat( &audioFmt );
pHook->OnInit( &audioFmt );
}
}
#endif /* HELIX_FEATURE_AUDIO_POSTMIXHOOK */
return HXR_OK;
}
HX_RESULT
CHXAudioPlayer::ActualRemovePostMixHook(IHXAudioHook* pHook)
{
if (!m_pPMixHookList || !pHook)
{
return HXR_FAILED;
}
#if defined(HELIX_FEATURE_AUDIO_POSTMIXHOOK)
BOOL bCheckForDisableWrite = FALSE;
BOOL bFound = FALSE;
HXAudioHookInfo* h = 0;
LISTPOSITION lp, lastlp;
lp = lastlp = 0;
lp = m_pPMixHookList->GetHeadPosition();
while( lp )
{
lastlp = lp;
h = (HXAudioHookInfo*) m_pPMixHookList->GetNext(lp);
if ( pHook == h->pHook )
{
if (h->bDisableWrite)
{
m_bDisableWrite = FALSE;
bCheckForDisableWrite = TRUE;
}
ProcessAudioHook(ACTION_REMOVE, pHook);
h->pHook->Release();
delete h;
h = 0;
m_pPMixHookList->RemoveAt(lastlp);
bFound = TRUE;
break;
}
}
if (!bFound)
{
return HXR_FAILED;
}
m_Owner->PostMixHooksUpdated();
if ( m_pPMixHookList && bCheckForDisableWrite && m_pPMixHookList->GetCount() > 0)
{
HXAudioHookInfo* h = 0;
LISTPOSITION lp, lastlp;
lp = lastlp = 0;
lp = m_pPMixHookList->GetHeadPosition();
while( lp )
{
h = (HXAudioHookInfo*) m_pPMixHookList->GetNext(lp);
if (h->bDisableWrite)
{
m_bDisableWrite = TRUE;
break;
}
}
}
#endif /* HELIX_FEATURE_AUDIO_POSTMIXHOOK */
return HXR_OK;
}
/************************************************************************
* Method:
* CHXAudioPlayer::SetGranularity
* Purpose:
* The HELIX player object calls this BEFORE starting audio playback
* and AFTER all audio streams are created for the renderers.
*/
void CHXAudioPlayer::SetGranularity
(
const ULONG32 ulGranularity
)
{
m_ulGranularity = ulGranularity;
return;
}
/************************************************************************
* Method:
* CHXAudioPlayer::Resume
* Purpose:
* Resume audio playback by writing data to the audio device.
* Open the audio device if it is not opened already.
*/
HX_RESULT CHXAudioPlayer::Resume()
{
HX_RESULT theErr = HXR_OK;
if (!m_bInited)
return HXR_NOT_INITIALIZED;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -