/*==========================================================================; * * Copyright (C) 1999 Microsoft Corporation. All Rights Reserved. * * File: dvcsplay.cpp * Content: Implementation of CDVCSPlayer class * History: * Date By Reason * ============ * 07/22/99 rodtoll created * 10/05/99 rodtoll Added comments, dpf's. * 10/29/99 rodtoll Bug #113726 - Integrate Voxware Codecs, updating to use new * pluggable codec architecture. * 01/14/2000 rodtoll Updated to support multiple targets * 03/28/2000 rodtoll Updated to use new player class as base * rodtoll Moved a bunch of logic out of server into this class * 11/16/2000 rodtoll Bug #40587 - DPVOICE: Mixing server needs to use multi-processors ***************************************************************************/ #include "dxvoicepch.h" #define IsEmpty(x) (x.next == x.prev && x.next == &x) #define CONVERTTORECORD(x,y,z) ((y *)(x->pvObject))->z #undef DPF_MODNAME #define DPF_MODNAME "CDVCSPlayer::CDVCSPlayer" CDVCSPlayer::CDVCSPlayer( ): m_lpOutBoundAudioConverter(NULL), m_bLastSent(NULL), m_bMsgNum((BYTE)-1), m_bSeqNum(0), m_targetSize(0), m_pblMixingActivePlayers(NULL), m_pblMixingSpeakingPlayers(NULL), m_pblMixingHearingPlayers(NULL), m_pdwHearCount(NULL), m_pfDecompressed(NULL), m_pfSilence(NULL), m_pfNeedsDecompression(NULL), m_pppCanHear(NULL), m_pdwMaxCanHear(NULL), m_pSourceFrame(NULL), m_sourceUnCompressed(NULL), m_targetCompressed(NULL), m_pfMixed(NULL), m_dwNumMixingThreads(0), m_pbMsgNumToSend(NULL), m_pbSeqNumToSend(NULL), m_pdwResultLength(NULL), m_pfMixToBeReused(NULL) { } #undef DPF_MODNAME #define DPF_MODNAME "CDVCSPlayer::~CDVCSPlayer" CDVCSPlayer::~CDVCSPlayer() { } #undef DPF_MODNAME #define DPF_MODNAME "CDVCSPlayer::ComparePlayerMix" // // ComparePlayerMix // // Compares the mix of one player to the mix of another. // BOOL CDVCSPlayer::ComparePlayerMix( DWORD dwThreadIndex, CDVCSPlayer *lpdvPlayer ) { DNASSERT( lpdvPlayer != NULL ); if( lpdvPlayer->m_pdwHearCount[dwThreadIndex] != m_pdwHearCount[dwThreadIndex] ) { return FALSE; } for( int index = 0; index < m_pdwHearCount[dwThreadIndex]; index++ ) { if( lpdvPlayer->m_pppCanHear[dwThreadIndex][index] != m_pppCanHear[dwThreadIndex][index] ) { return FALSE; } } return TRUE; } void CDVCSPlayer::CompleteRun( DWORD dwThreadIndex ) { if( m_pSourceFrame[dwThreadIndex] ) { m_pSourceFrame[dwThreadIndex]->Return(); m_pSourceFrame[dwThreadIndex] = NULL; } } void CDVCSPlayer::ResetForNextRun( DWORD dwThreadIndex, BOOL fDequeue ) { BOOL fLostFrame; m_pdwHearCount[dwThreadIndex] = 0; m_pfSilence[dwThreadIndex] = FALSE; m_pReuseMixFromThisPlayer[dwThreadIndex] = NULL; if( !fDequeue ) { m_pSourceFrame[dwThreadIndex] = NULL; } else { DNASSERT( !m_pSourceFrame[dwThreadIndex] ); m_pSourceFrame[dwThreadIndex] = Dequeue(&fLostFrame, &m_pfSilence[dwThreadIndex]); } m_pfMixed[dwThreadIndex] = FALSE; m_pfNeedsDecompression[dwThreadIndex] = FALSE; m_pfDecompressed[dwThreadIndex] = FALSE; m_pfMixToBeReused[dwThreadIndex] = FALSE; m_pdwResultLength[dwThreadIndex] = NULL; } HRESULT CDVCSPlayer::Initialize( const DVID dvidPlayer, const DWORD dwHostOrder, DWORD dwFlags, PVOID pvContext, DWORD dwCompressedSize, DWORD dwUnCompressedSize, CLockedFixedPool *pCSOwner, DWORD dwNumMixingThreads ) { HRESULT hr; DWORD dwIndex; m_pCSOwner = pCSOwner; hr = CVoicePlayer::Initialize( dvidPlayer, dwHostOrder, dwFlags, pvContext, NULL ); if( FAILED( hr ) ) { DPFX(DPFPREP, 0, "Initialize failed on player hr=0x%x", hr ); return hr; } m_pdwHearCount = new DWORD[dwNumMixingThreads]; m_pfSilence = new BOOL[dwNumMixingThreads]; m_pdwMaxCanHear = new DWORD[dwNumMixingThreads]; m_pSourceFrame = new CFrame*[dwNumMixingThreads]; m_pfMixed = new BOOL[dwNumMixingThreads]; m_pblMixingActivePlayers = new BILINK[dwNumMixingThreads]; m_pblMixingHearingPlayers = new BILINK[dwNumMixingThreads]; m_pblMixingSpeakingPlayers = new BILINK[dwNumMixingThreads]; m_sourceUnCompressed = new BYTE[dwNumMixingThreads*dwUnCompressedSize]; m_targetCompressed = new BYTE[dwNumMixingThreads*dwCompressedSize]; m_pfNeedsDecompression = new BOOL[dwNumMixingThreads]; m_pfDecompressed = new BOOL[dwNumMixingThreads]; m_dwNumMixingThreads = dwNumMixingThreads; m_pbMsgNumToSend = new BYTE[dwNumMixingThreads]; m_pbSeqNumToSend = new BYTE[dwNumMixingThreads]; m_pdwUnCompressedBufferOffset = new DWORD[dwNumMixingThreads]; m_pdwCompressedBufferOffset = new DWORD[dwNumMixingThreads]; m_pReuseMixFromThisPlayer = new CDVCSPlayer*[dwNumMixingThreads]; m_pdwResultLength = new DWORD[dwNumMixingThreads]; m_pfMixToBeReused = new BOOL[dwNumMixingThreads]; if( !m_pblMixingActivePlayers || !m_pdwHearCount || !m_pfSilence || !m_pdwMaxCanHear || !m_pSourceFrame || !m_sourceUnCompressed || !m_targetCompressed || !m_pfMixed || !m_pfNeedsDecompression || !m_pfDecompressed || !m_pbMsgNumToSend || !m_pbSeqNumToSend || !m_pdwUnCompressedBufferOffset || !m_pdwCompressedBufferOffset || !m_pReuseMixFromThisPlayer || !m_pdwResultLength || !m_pfMixToBeReused || !m_pblMixingHearingPlayers || !m_pblMixingSpeakingPlayers ) { DPFX(DPFPREP, 0, "Memory alloc failure" ); hr = DVERR_OUTOFMEMORY; goto INITIALIZE_FAILURE; } // Create the Can Hear arrays m_pppCanHear = new CDVCSPlayer**[dwNumMixingThreads]; ZeroMemory( m_pppCanHear, sizeof(CDVCSPlayer*)*dwNumMixingThreads ); // Resize canhear arrays and setup compressed/uncompressed offsets for( dwIndex = 0; dwIndex < dwNumMixingThreads; dwIndex++ ) { m_pdwUnCompressedBufferOffset[dwIndex] = dwIndex * dwUnCompressedSize; m_pdwCompressedBufferOffset[dwIndex] = dwIndex * dwCompressedSize; m_pSourceFrame[dwIndex] = 0; m_pdwMaxCanHear[dwIndex] = 0; InitBilink( &m_pblMixingActivePlayers[dwIndex], this ); InitBilink( &m_pblMixingSpeakingPlayers[dwIndex], this ); InitBilink( &m_pblMixingHearingPlayers[dwIndex], this ); ResetForNextRun(dwIndex,FALSE); hr = ResizeIfRequired(dwIndex,1); if( FAILED( hr ) ) { DPFX(DPFPREP, 0, "Error resizing target array hr=0x%x", hr ); goto INITIALIZE_FAILURE; } } return hr; INITIALIZE_FAILURE: DeInitialize(); return hr; } HRESULT CDVCSPlayer::DeInitialize() { DWORD dwIndex; if( m_pblMixingActivePlayers ) { #ifdef DEBUG for( dwIndex = 0; dwIndex < m_dwNumMixingThreads; dwIndex++ ) { DNASSERT( (IsEmpty( m_pblMixingActivePlayers[dwIndex] )) ); DNASSERT( !m_pSourceFrame[dwIndex] ); } #endif delete [] m_pblMixingActivePlayers; m_pblMixingActivePlayers = NULL; } if( m_pblMixingSpeakingPlayers ) { delete [] m_pblMixingSpeakingPlayers; m_pblMixingSpeakingPlayers = NULL; } if( m_pblMixingHearingPlayers ) { delete [] m_pblMixingHearingPlayers; m_pblMixingHearingPlayers = NULL; } if( m_lpOutBoundAudioConverter ) { m_lpOutBoundAudioConverter->Release(); m_lpOutBoundAudioConverter = NULL; } if( m_pppCanHear ) { for( dwIndex = 0; dwIndex < m_dwNumMixingThreads; dwIndex++ ) { if( m_pppCanHear[dwIndex] ) { delete [] m_pppCanHear[dwIndex]; m_pppCanHear[dwIndex] = NULL; } } delete [] m_pppCanHear; m_pppCanHear = NULL; } if( m_pdwHearCount ) { delete [] m_pdwHearCount; m_pdwHearCount = NULL; } if( m_pdwResultLength ) { delete [] m_pdwResultLength; m_pdwResultLength = NULL; } if( m_pfSilence ) { delete [] m_pfSilence; m_pfSilence = NULL; } if( m_pdwUnCompressedBufferOffset ) { delete [] m_pdwUnCompressedBufferOffset; m_pdwUnCompressedBufferOffset = NULL; } if( m_pReuseMixFromThisPlayer ) { delete [] m_pReuseMixFromThisPlayer; m_pReuseMixFromThisPlayer = NULL; } if( m_pdwCompressedBufferOffset ) { delete [] m_pdwCompressedBufferOffset; m_pdwCompressedBufferOffset = NULL; } if( m_pdwMaxCanHear ) { delete [] m_pdwMaxCanHear; m_pdwMaxCanHear = NULL; } if( m_sourceUnCompressed ) { delete [] m_sourceUnCompressed; m_sourceUnCompressed = NULL; } if( m_pfMixToBeReused ) { delete [] m_pfMixToBeReused; m_pfMixToBeReused = NULL; } if( m_pbMsgNumToSend ) { delete [] m_pbMsgNumToSend; m_pbMsgNumToSend = NULL; } if( m_pbSeqNumToSend ) { delete [] m_pbSeqNumToSend; m_pbSeqNumToSend = NULL; } if( m_targetCompressed ) { delete [] m_targetCompressed; m_targetCompressed = NULL; } if( m_pfMixed ) { delete [] m_pfMixed; m_pfMixed = NULL; } if( m_pfNeedsDecompression ) { delete [] m_pfNeedsDecompression; m_pfNeedsDecompression = NULL; } if( m_pfDecompressed ) { delete [] m_pfDecompressed; m_pfDecompressed = NULL; } if( m_pSourceFrame ) { delete [] m_pSourceFrame; m_pSourceFrame = NULL; } FreeResources(); m_pCSOwner->Release( this ); return DV_OK; } HRESULT CDVCSPlayer::HandleMixingReceive( PDVPROTOCOLMSG_SPEECHHEADER pdvSpeechHeader, PBYTE pbData, DWORD dwSize, PDVID pdvidTargets, DWORD dwNumTargets ) { CFrame tmpFrame; tmpFrame.SetSeqNum( pdvSpeechHeader->bSeqNum ); tmpFrame.SetMsgNum( pdvSpeechHeader->bMsgNum ); tmpFrame.SetIsSilence( FALSE ); tmpFrame.SetFrameLength( dwSize ); tmpFrame.UserOwn_SetData( pbData, dwSize ); tmpFrame.UserOwn_SetTargets( pdvidTargets, dwNumTargets ); Lock(); // STATSBLOCK: Begin //m_pStatsBlob->m_dwPRESpeech++; // STATSBLOCK: End m_lpInputQueue->Enqueue( tmpFrame ); m_dwLastData = GetTickCount(); DPFX(DPFPREP, DVF_MIXER_DEBUG_LEVEL, "Received speech is buffered!" ); m_dwNumReceivedFrames++; UnLock(); return DV_OK; } HRESULT CDVCSPlayer::CompressOutBound( PVOID pvInputBuffer, DWORD dwInputBufferSize, PVOID pvOutputBuffer, DWORD *pdwOutputSize ) { HRESULT hr; hr = m_lpOutBoundAudioConverter->Convert( pvInputBuffer, dwInputBufferSize, pvOutputBuffer, pdwOutputSize, FALSE ); if( FAILED( hr ) ) { DPFX(DPFPREP, 0, "Failed converting audio hr=0x%x", hr ); return hr; } return hr; }