📄 hxaudses.cpp
字号:
/* If the audio device is busy, check if we have
* anything other than audio in the presentation.
* If TRUE, play silence so that the rest of the
* presentation can be played.
*/
if (theErr == HXR_AUDIO_DRIVER && !m_bDisableWrite)
{
if (!IsAudioOnlyTrue())
{
m_bDisableWrite = TRUE;
m_pAudioDev = 0;
theErr = HXR_OK;
}
}
}
m_bInited = (!theErr) ? TRUE : FALSE;
if (!theErr && m_pAudioDev && m_pHookList)
{
InitHooks();
}
if (!theErr && m_pAudioDev && m_pFinalHook)
{
ProcessAudioHook(ACTION_ADD, m_pFinalHook);
}
if(m_pContext)
{
HX_RELEASE(m_pMPPSupport);
m_pContext->QueryInterface(IID_IHXMultiPlayPauseSupport, (void**)&m_pMPPSupport);
}
return theErr;
}
HX_RESULT
CHXAudioSession::OpenDevice()
{
HX_RESULT theErr = HXR_OK;
HXAudioFormat audioFormat;
if (m_pFinalHook)
{
m_bUseFinalHook = TRUE;
if (HXR_OK != ProcessAudioHook(ACTION_CHECK, m_pFinalHook))
{
m_bUseFinalHook = FALSE;
}
if (m_bUseFinalHook)
{
memcpy( &audioFormat, &m_ActualDeviceFmt, sizeof(HXAudioFormat));
theErr = m_pFinalHook->OnInit(&audioFormat);
}
}
if (!theErr && m_pFinalHook && m_bUseFinalHook)
{
m_bUseFinalHook = TRUE;
/* Did the hook change the data format? */
if( 0!=memcmp(&audioFormat, &m_ActualDeviceFmt, sizeof(HXAudioFormat)))
{
memcpy( &m_BeforeHookDeviceFmt, &m_ActualDeviceFmt, sizeof(HXAudioFormat));
memcpy( &m_ActualDeviceFmt, &audioFormat, sizeof(HXAudioFormat));
}
}
else
{
m_bUseFinalHook = FALSE;
}
theErr = OpenAudio();
if (theErr && m_pFinalHook && m_bUseFinalHook)
{
/* Looks like the audio device does not support the format
* specified by the final Hook
* Revert back to the original format and try again
*/
memcpy( &m_ActualDeviceFmt, &m_BeforeHookDeviceFmt, sizeof(HXAudioFormat));
m_bUseFinalHook = FALSE;
theErr = OpenAudio();
}
return theErr;
}
/* ***********************************************************************
* Method:
* CHXAudioSession::GetDeviceFormat
* Purpose:
* Determine the device format for this session.
* The session object needs to resolve the device format
* among multiple players.
*/
HX_RESULT CHXAudioSession::GetDeviceFormat()
{
HX_RESULT theErr = HXR_OK;
UINT16 uOrigSampleRate = 0;
CHXAudioPlayer* p = NULL;
UINT16 bAutoUpsampling = FALSE;
HXAudioFormat audioFmt;
// We no longer force audio device in stereo mode. However we
// still try to open it in 16-bit mode since all of our processing
// is done in 16 bit.
m_DeviceFmt.uBitsPerSample = 16;
//Just grab the first players stats to use as maximums.
LISTPOSITION lp = m_pPlayerList->GetHeadPosition();
while(lp)
{
p = (CHXAudioPlayer*) m_pPlayerList->GetNext(lp);
if(0!=p->GetStreamCount())
{
p->GetFormat( &audioFmt );
m_DeviceFmt.uChannels = audioFmt.uChannels;
m_DeviceFmt.ulSamplesPerSec = audioFmt.ulSamplesPerSec;
m_DeviceFmt.uMaxBlockSize = audioFmt.uMaxBlockSize;
break;
}
}
//Now loop through the rest of the players and find all the
//maximums.
while(lp)
{
p = (CHXAudioPlayer*) m_pPlayerList->GetNext(lp);
if( 0 != p->GetStreamCount() )
{
p->GetFormat( &audioFmt );
m_DeviceFmt.uChannels = max(m_DeviceFmt.uChannels,
audioFmt.uChannels);
m_DeviceFmt.ulSamplesPerSec = max(m_DeviceFmt.ulSamplesPerSec,
audioFmt.ulSamplesPerSec);
m_DeviceFmt.uMaxBlockSize = max(m_DeviceFmt.uMaxBlockSize,
audioFmt.uMaxBlockSize);
}
}
// turn on the default upsampling to 44K only on IX86 platforms
// which support MMX
// XXXgfw this also uses more memory for each block we push down
// XXXgfw to the audio device. You might not want it on MIN_HEAP
// XXXgfw kind of MMX devices, if there are any.
#if defined(_M_IX86)
ReadPrefINT16(m_pPreferences, "AutoAudioUpsampling", bAutoUpsampling );
#endif
if(bAutoUpsampling)
{
//force 44khz as our first attempt to open audio device
uOrigSampleRate = (UINT16)m_DeviceFmt.ulSamplesPerSec;
m_DeviceFmt.ulSamplesPerSec = 44100;
}
#if defined(HELIX_FEATURE_PREFERENCES)
else
{
UINT16 ulSamplesPerSecPreference = 0;
ReadPrefINT16(m_pPreferences, "AudioDeviceSamplesPerSec", ulSamplesPerSecPreference );
if(ulSamplesPerSecPreference)
{
uOrigSampleRate = (UINT16)m_DeviceFmt.ulSamplesPerSec;
m_DeviceFmt.ulSamplesPerSec = ulSamplesPerSecPreference;
}
}
#endif /* HELIX_FEATURE_PREFERENCES */
//Start negotiating with the device. Generate a table that will
//drive the different formats we want to try. Start with the
//native rate (and any mods from the pref stuff above) and go up
//in samplerate. If that fails, go down in sample rate.
const int nNumberOfRates = sizeof(z_anValidSampleRates)/sizeof(z_anValidSampleRates[0]);
//Total number of table entries per sample rate will be:
//nNumberOfRates*4 (mono/16, mono/8, stereo/16, stereo/8) plus
//native format + user defined samplerate entry.
const int nTmp = nNumberOfRates*4+2;
unsigned short nTableSize = 0;
tableEntry* table = new tableEntry[nTmp];
HX_ASSERT(table);
if( NULL == table )
return HXR_OUTOFMEMORY;
//First entry is always our native format from above with any
//samplerate changes the user made via prefs.
table[nTableSize++].set( (UINT16)m_DeviceFmt.ulSamplesPerSec,
(UINT8)m_DeviceFmt.uChannels,
(UINT8)m_DeviceFmt.uBitsPerSample
);
//Second entry is always the above with the clip's original
//sample rate, if we changed it.
if( uOrigSampleRate )
table[nTableSize++].set(uOrigSampleRate,
(UINT8)m_DeviceFmt.uChannels,
(UINT8)m_DeviceFmt.uBitsPerSample
);
//Now generate the rest of the format table....
const UINT8 usNativeChannel = (UINT8)m_DeviceFmt.uChannels;
const UINT8 usAltChannel = (2==m_DeviceFmt.uChannels)?1:2;
const UINT8 usNativeBits = (UINT8)m_DeviceFmt.uBitsPerSample;
const UINT8 usAltBits = (8==m_DeviceFmt.uBitsPerSample)?16:8;
//First use all equal or higher sample rates.
short nIdx = 0;
while( nIdx<nNumberOfRates )
{
UINT16 usRate = z_anValidSampleRates[nIdx];
if( usRate >= m_DeviceFmt.ulSamplesPerSec )
{
table[nTableSize++].set(usRate, usNativeChannel, usNativeBits );
table[nTableSize++].set(usRate, usAltChannel, usNativeBits );
table[nTableSize++].set(usRate, usNativeChannel, usAltBits );
table[nTableSize++].set(usRate, usAltChannel, usAltBits );
}
nIdx++;
}
//Now all the samle rates lower then the native rate.
nIdx = nNumberOfRates-1;
while( nIdx>=0)
{
UINT16 usRate = z_anValidSampleRates[nIdx];
if( usRate < m_DeviceFmt.ulSamplesPerSec )
{
table[nTableSize++].set(usRate, usNativeChannel, usNativeBits );
table[nTableSize++].set(usRate, usAltChannel, usNativeBits );
table[nTableSize++].set(usRate, usNativeChannel, usAltBits );
table[nTableSize++].set(usRate, usAltChannel, usAltBits );
}
nIdx--;
}
//Now loop through our table and find a supported format.
nIdx = 0;
theErr = HXR_FAIL;
while( FAILED(theErr) && nIdx<nTableSize)
{
m_DeviceFmt.ulSamplesPerSec = table[nIdx].usSampleRate;
m_DeviceFmt.uChannels = table[nIdx].usChannels;
m_DeviceFmt.uBitsPerSample = table[nIdx].usBits;
theErr = CheckAudioFormat(&m_DeviceFmt);
nIdx++;
}
//We still need to create playback buffers since we will use the
//fake timeline if the presentation has atleast one media type
//other than audio
//XXXgfw this code below needs to be looked at. I Don't want to
//touch it now for fear of breaking something that will take
//a long time to fix.
if (!theErr || theErr == HXR_AUDIO_DRIVER)
{
m_ActualDeviceFmt = m_DeviceFmt;
//All the calculations are done for 16 bit stereo. There are
//VERY FEW sound cards out there which do not support 16 bit
//stereo. They will incur a high performace hit because of
//possible unnecessary up/down conversion. For now we will
//live with that.
//XXXgfw wrong. lots of handhelds/phones don't do 16bit-2
//channel output.
m_DeviceFmt.uBitsPerSample = 16;
m_BeforeHookDeviceFmt = m_ActualDeviceFmt;
}
HX_VECTOR_DELETE(table);
return theErr;
}
/************************************************************************
* Method:
* CHXAudioSession::CheckAudioFormat
* Purpose:
* The audio player calls this to check its audio format with the
* the audio device.
*/
HX_RESULT CHXAudioSession::CheckAudioFormat
(
HXAudioFormat* pAudioFormat
)
{
HX_RESULT theErr = HXR_OK;
if (!m_pAudioDev)
{
CreateAudioDevice();
m_pAudioDev = m_pCurrentAudioDev;
}
if (m_pAudioDev)
{
theErr = m_pAudioDev->CheckFormat(pAudioFormat);
/* Any error from audio device other than memory error is
* returned as HXR_AUDIO_DRIVER
*/
if (theErr != HXR_OK && theErr != HXR_OUTOFMEMORY)
{
theErr = HXR_AUDIO_DRIVER;
}
}
return theErr;
}
/************************************************************************
* Method:
* CHXAudioSession::PlayAudio
* Purpose:
* The player object call this to play audio. This method is called
* again in the playback response function.
*/
HX_RESULT CHXAudioSession::PlayAudio(UINT16 uNumBlocks)
{
HX_RESULT theErr = HXR_OK;
BOOL bDisableWrite = FALSE;
if ( !m_bInited )
return theErr;
if (m_bInPlayAudio)
{
return HXR_OK;
}
m_pMutex->Lock();
if (m_bToBeRewound)
{
theErr = Rewind();
goto exit;
}
m_bInPlayAudio = TRUE;
if (m_pAuxiliaryAudioBuffers &&
m_pAuxiliaryAudioBuffers->GetCount() > 0 && m_pAudioDev && !m_bDisableWrite)
{
if (HXR_OK == ProcessAudioDevice(ACTION_CHECK, m_pAudioDev))
{
/* Try to stuff in as much backlog as possible */
while (!theErr && m_pAuxiliaryAudioBuffers->GetCount() > 0)
{
HXAudioData* pAudioData =
(HXAudioData*) m_pAuxiliaryAudioBuffers->GetHead();
// Write session audio data to device.
theErr = m_pAudioDev->Write(pAudioData);
if( theErr == HXR_OUTOFMEMORY )
{
goto exit;
}
if (!theErr)
{
m_ulBlocksWritten++;
m_dNumBytesWritten += pAudioData->pData->GetSize();
m_pAuxiliaryAudioBuffers->RemoveHead();
pAudioData->pData->Release();
delete pAudioData;
}
/*All other error codes are translated into audio driver error*/
else if (theErr != HXR_OUTOFMEMORY && theErr != HXR_WOULD_BLOCK)
{
theErr = HXR_AUDIO_DRIVER;
}
}
}
}
// If we have audio streams then play audio.
if (!theErr && m_bHasStreams)
{
// Push down at least 3 secs of audio.
UINT16 uPush = uNumBlocks;
if (m_bFirstPlayAudio)
{
uPush = (UINT16) m_ulMinBlocksTobeQueued;
}
HXAudioData audioData;
CHXAudioPlayer* pPlayer = 0;
CHXAudioStream* pStream = 0;
CHXSimpleList* pStreamList = 0;
#if defined(HELIX_FEATURE_VOLUME) || defined(HELIX_FEATURE_MIXER)
UINT16 uPlayerVolume = HX_INIT_VOLUME;
#endif
UCHAR* pMixBuffer = 0;
UCHAR* pPlayerBuf = NULL;
UCHAR* pSessionBuf = NULL;
IHXBuffer* pMixIHXBuffer = NULL;
BufType bufType = BUFFER_NONE;
for (UINT16 i = 0; !theErr && i < uPush; i++ )
{
m_uNumToBePushed = uPush - i;
m_bSessionBufferDirty = FALSE; // only used for multi-player case
UINT32 ulNumBytesWritten = m_ulBytesPerGran;
BOOL bAtLeastOnePlayerActive = FALSE;
theErr = m_pSessionBuf->SetSize(m_ulBytesPerGran);
if( theErr == HXR_OUTOFMEMORY )
{
theErr = HXR_OUTOFMEMORY;
goto exit;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -