/*========================================================================== * * Copyright (C) 1999 - 1999 Microsoft Corporation. All Rights Reserved. * * File: vplayer.h * Content: Voice Player Entry * * History: * Date By Reason * ==== == ====== * 03/26/00 rodtoll Created * 07/09/2000 rodtoll Added signature bytes * 09/05/2001 simonpow Bug #463972. Added constuct/destruct methods to enable * allocations and de-allocations via CFixedPool objects * 02/21/2002 simonpow Bug #549974. Added rate control for incoming speech pkts ***************************************************************************/ #include "dxvoicepch.h" #undef DPF_MODNAME #define DPF_MODNAME "CVoicePlayer::Construct" BOOL CVoicePlayer::PoolAllocFunction(void * pvItem, void * ) { CVoicePlayer * pNewPlayer=(CVoicePlayer * ) pvItem; pNewPlayer->CVoicePlayer::CVoicePlayer(); pNewPlayer->Reset(); return TRUE; } #undef DPF_MODNAME #define DPF_MODNAME "CVoicePlayer::Destruct" void CVoicePlayer::PoolDeallocFunction(void * pvItem) { ((CVoicePlayer * ) pvItem)->CVoicePlayer::~CVoicePlayer(); } CVoicePlayer::CVoicePlayer() { m_dwSignature = VSIG_VOICEPLAYER; } CVoicePlayer::~CVoicePlayer() { if (IsInitialized()) DeInitialize(); m_dwSignature = VSIG_VOICEPLAYER_FREE; } void CVoicePlayer::Reset() { m_dwFlags = 0; m_dvidPlayer = 0; m_lRefCount = 0; m_lpInBoundAudioConverter = NULL; m_lpInputQueue = NULL; m_dwLastData = 0; m_dwHostOrderID = 0xFFFFFFFF; m_bLastPeak = 0; m_dwLastPlayback = 0; m_dwNumSilentFrames = 0; m_dwTransportFlags = 0; m_dwNumLostFrames = 0; m_dwNumSpeechFrames = 0; m_dwNumReceivedFrames = 0; m_pvPlayerContext = NULL; m_blNotifyList.Initialize(); m_blPlayList.Initialize(); m_dwNumTargets = 0; m_pdvidTargets = NULL; m_lSpeechPktsInCurrentBucket=0; m_lCurrentSpeechPktBucket=0; } #undef DPF_MODNAME #define DPF_MODNAME "CVoicePlayer::SetPlayerTargets" // // Assumes the array has been checked for validity // HRESULT CVoicePlayer::SetPlayerTargets( PDVID pdvidTargets, DWORD dwNumTargets ) { Lock(); delete [] m_pdvidTargets; if( dwNumTargets == 0 ) { m_pdvidTargets = NULL; } else { m_pdvidTargets = new DVID[dwNumTargets]; if( m_pdvidTargets == NULL ) { m_pdvidTargets = NULL; m_dwNumTargets = 0; DPFX(DPFPREP, DVF_ERRORLEVEL, "Error allocating memory" ); UnLock(); return DVERR_OUTOFMEMORY; } memcpy( m_pdvidTargets, pdvidTargets, sizeof(DVID)*dwNumTargets ); } m_dwNumTargets = dwNumTargets; UnLock(); return DV_OK; } HRESULT CVoicePlayer::Initialize( const DVID dvidPlayer, const DWORD dwHostOrder, DWORD dwFlags, PVOID pvContext, CFixedPool *pOwner ) { Reset(); if (!DNInitializeCriticalSection( &m_csLock )) { return DVERR_OUTOFMEMORY; } m_lRefCount = 1; m_pOwner = pOwner; m_dvidPlayer = dvidPlayer; m_dwHostOrderID = dwHostOrder; m_dwLastData = GetTickCount(); m_dwLastPlayback = 0; m_dwTransportFlags = dwFlags; m_pvPlayerContext = pvContext; m_lSpeechPktsInCurrentBucket=0; m_lCurrentSpeechPktBucket=0; m_dwFlags |= VOICEPLAYER_FLAGS_INITIALIZED; return DV_OK; } void CVoicePlayer::GetStatistics( PVOICEPLAYER_STATISTICS pStats ) { memset( pStats, 0x00, sizeof( VOICEPLAYER_STATISTICS ) ); // Get queue statistics if( m_lpInputQueue != NULL ) { Lock(); m_lpInputQueue->GetStatistics( &pStats->queueStats ); UnLock(); } pStats->dwNumLostFrames = m_dwNumLostFrames; pStats->dwNumSilentFrames = m_dwNumSilentFrames; pStats->dwNumSpeechFrames = m_dwNumSpeechFrames; pStats->dwNumReceivedFrames = m_dwNumReceivedFrames; return; } HRESULT CVoicePlayer::CreateQueue( PQUEUE_PARAMS pQueueParams ) { HRESULT hr; DNEnterCriticalSection( &CDirectVoiceEngine::s_csSTLLock ); m_lpInputQueue = new CInputQueue2(); if( m_lpInputQueue == NULL ) { DPFX(DPFPREP, 0, "Error allocating memory" ); return DVERR_OUTOFMEMORY; } hr = m_lpInputQueue->Initialize( pQueueParams ); if( FAILED( hr ) ) { DPFX(DPFPREP, 0, "Failed initializing queue hr=0x%x", hr ); delete m_lpInputQueue; m_lpInputQueue = NULL; return hr; } DNLeaveCriticalSection( &CDirectVoiceEngine::s_csSTLLock ); return hr; } HRESULT CVoicePlayer::CreateInBoundConverter( const GUID &guidCT, PWAVEFORMATEX pwfxTargetFormat ) { HRESULT hr; hr = DVCDB_CreateConverter( guidCT, pwfxTargetFormat, &m_lpInBoundAudioConverter ); if( FAILED( hr ) ) { DPFX(DPFPREP, 0, "Error creating audio converter hr=0x%x" , hr ); return hr; } if( pwfxTargetFormat->wBitsPerSample == 8) { m_dwFlags |= VOICEPLAYER_FLAGS_TARGETIS8BIT; } return hr; } HRESULT CVoicePlayer::DeInitialize() { FreeResources(); m_pOwner->Release( this ); return DV_OK; } HRESULT CVoicePlayer::HandleReceive( PDVPROTOCOLMSG_SPEECHHEADER pdvSpeechHeader, PBYTE pbData, DWORD dwSize ) { CFrame tmpFrame; tmpFrame.SetSeqNum( pdvSpeechHeader->bSeqNum ); tmpFrame.SetMsgNum( pdvSpeechHeader->bMsgNum ); tmpFrame.SetIsSilence( FALSE ); tmpFrame.SetFrameLength( dwSize ); tmpFrame.UserOwn_SetData( pbData, dwSize ); Lock(); DPFX(DPFPREP, DVF_CLIENT_SEQNUM_DEBUG_LEVEL, "SEQ: Receive: Msg [%d] Seq [%d]", pdvSpeechHeader->bMsgNum, pdvSpeechHeader->bSeqNum ); // STATSBLOCK: Begin //m_stats.m_dwPRESpeech++; // STATSBLOCK: End m_lpInputQueue->Enqueue( tmpFrame ); m_dwLastData = GetTickCount(); DPFX(DPFPREP, DVF_INFOLEVEL, "Received speech is buffered!" ); m_dwNumReceivedFrames++; UnLock(); return DV_OK; } CFrame *CVoicePlayer::Dequeue(BOOL *pfLost, BOOL *pfSilence) { CFrame *frTmpFrame; Lock(); frTmpFrame = m_lpInputQueue->Dequeue(); UnLock(); if( !frTmpFrame->GetIsSilence() ) { *pfSilence = FALSE; m_dwLastPlayback = GetTickCount(); m_dwNumSpeechFrames++; } else { m_dwNumSilentFrames++; *pfSilence = TRUE; } if( frTmpFrame->GetIsLost() ) { *pfLost = TRUE; m_dwNumLostFrames++; } else { *pfLost = FALSE; } return frTmpFrame; } HRESULT CVoicePlayer::DeCompressInBound( CFrame *frCurrentFrame, PVOID pvBuffer, PDWORD pdwBufferSize ) { HRESULT hr; hr = m_lpInBoundAudioConverter->Convert( frCurrentFrame->GetDataPointer(), frCurrentFrame->GetFrameLength(), pvBuffer, pdwBufferSize, frCurrentFrame->GetIsSilence() ); if( FAILED( hr ) ) { DPFX(DPFPREP, 0, "Failed converting audio hr=0x%x", hr ); return hr; } return hr; } HRESULT CVoicePlayer::GetNextFrameAndDecompress( PVOID pvBuffer, PDWORD pdwBufferSize, BOOL *pfLost, BOOL *pfSilence, DWORD *pdwSeqNum, DWORD *pdwMsgNum ) { CFrame *frTmpFrame; BYTE bLastPeak; HRESULT hr; frTmpFrame = Dequeue(pfLost,pfSilence ); *pdwSeqNum = frTmpFrame->GetSeqNum(); *pdwMsgNum = frTmpFrame->GetMsgNum(); hr = DeCompressInBound( frTmpFrame, pvBuffer, pdwBufferSize ); frTmpFrame->Return(); if( FAILED( hr ) ) { DPFX(DPFPREP, 0, "Failed converting audio hr=0x%x", hr ); return hr; } if( *pfSilence ) { m_bLastPeak = 0; } else { m_bLastPeak = FindPeak( (PBYTE) pvBuffer, *pdwBufferSize, Is8BitUnCompressed() ); } return hr; } void CVoicePlayer::FreeResources() { DNDeleteCriticalSection( &m_csLock ); DNEnterCriticalSection( &CDirectVoiceEngine::s_csSTLLock ); if( m_lpInputQueue != NULL ) { delete m_lpInputQueue; m_lpInputQueue = NULL; } DNLeaveCriticalSection( &CDirectVoiceEngine::s_csSTLLock ); if( m_lpInBoundAudioConverter != NULL ) { m_lpInBoundAudioConverter->Release(); m_lpInBoundAudioConverter = NULL; } if( m_pdvidTargets != NULL ) { delete [] m_pdvidTargets; m_pdvidTargets = NULL; } Reset(); } #undef DPF_MODNAME #define DPF_MODNAME "CVoicePlayer::FindAndRemovePlayerTarget" // // FindAndRemovePlayerTarget // // Searches the list of targets for this player and removes the specified player if it is part // of the list. The pfFound variable is set to TRUE if the player specfied was in the target // list, false otherwise. // BOOL CVoicePlayer::FindAndRemovePlayerTarget( DVID dvidTargetToRemove ) { BOOL fFound = FALSE; Lock(); for( DWORD dwTargetIndex = 0; dwTargetIndex < m_dwNumTargets; dwTargetIndex++ ) { if( m_pdvidTargets[dwTargetIndex] == dvidTargetToRemove ) { if( m_dwNumTargets == 1 ) { delete [] m_pdvidTargets; m_pdvidTargets = NULL; } // Shortcut, move last element into the current element // prevents re-allocation. (However, it wastes an element of // target space) *Shrug*. If this is the last element in the list // we're removing this will simply provide an unessessary duplication // of the last element. (But num targets is correct so that's ok). else { m_pdvidTargets[dwTargetIndex] = m_pdvidTargets[m_dwNumTargets-1]; } m_dwNumTargets--; fFound = TRUE; break; } } UnLock(); return fFound; }