📄 audunix.cpp
字号:
if( HXR_OK == m_pContext->QueryInterface( IID_IHXAsyncIOSelection,
(void**)&pAsyncIO)
)
{
pAsyncIO->Remove(_Imp_GetAudioFd() , PNAIO_WRITE);
HX_RELEASE( pAsyncIO );
}
}
}
//Close the audio device.
retCode = _CloseAudio();
//Close the mixer device.
_CloseMixer();
//Set state.
LOCK(m_mtxWriteListPlayStateLock);
m_wState = RA_AOS_CLOSED;
UNLOCK(m_mtxWriteListPlayStateLock);
//Remove callback from scheduler
if (m_bCallbackPending)
{
m_pScheduler->Remove(m_PendingCallbackID);
m_bCallbackPending = FALSE;
}
HX_VECTOR_DELETE(m_pRollbackBuffer);
//return
m_wLastError = retCode;
return m_wLastError;
}
//So far no UN*X platforms support this.
HX_RESULT CAudioOutUNIX::_Imp_Seek(ULONG32 ulSeekTime)
{
m_wLastError = HXR_OK;
return m_wLastError;
}
HX_RESULT CAudioOutUNIX::_Imp_Pause()
{
//XXXgfw We really should be closing the device instead of keeping it open to be nice to
//other procs.
LOCK(m_mtxWriteListPlayStateLock);
m_wState = RA_AOS_OPEN_PAUSED;
UNLOCK(m_mtxWriteListPlayStateLock);
if( !_HardwarePauseSupported() )
{
// Strategy.
//--Find out how much we have left in the device's buffer.
ULONG32 ulBytesPlayed = _GetBytesActualyPlayed();
ULONG32 ulNumBytesToRewind = m_ulTotalWritten-ulBytesPlayed;
//Sometimes we can get a value for bytesPlayed that is slightly
//more then the amount we have actually written. This results
//in a huge number.
if( ulBytesPlayed > m_ulTotalWritten )
ulNumBytesToRewind = 0;
//--and reset player and discard all the data in the device's buffer
//We will just ignore an error here. That means the buffer will just drain
//and we will hear it again when they unpause.
LOCK(m_mtxDeviceStateLock);
_Reset();
UNLOCK(m_mtxDeviceStateLock);
//Make sure we only deal with full samples. Bytes-per-sample*num-channels.
int nRem = ulNumBytesToRewind%(m_uSampFrameSize*m_unNumChannels);
ulNumBytesToRewind = ulNumBytesToRewind>nRem ? ulNumBytesToRewind-nRem : 0;
// In heap-optimized mode, we accept that we're going to lose a
// little bit of data after a pause/resume because we are using as
// small a rollback buffer as we can get away with.
#ifdef HELIX_CONFIG_MIN_ROLLBACK_BUFFER
if( ulNumBytesToRewind > m_ulDeviceBufferSize )
{
ulNumBytesToRewind = m_ulDeviceBufferSize;
}
#endif // HELIX_CONFIG_MIN_ROLLBACK_BUFFER
// and add it to the front of the write buffer.
IHXBuffer* pNewBuffer = new CHXBuffer();
pNewBuffer->Set( m_pRollbackBuffer+m_ulDeviceBufferSize-ulNumBytesToRewind,
ulNumBytesToRewind );
LOCK(m_mtxWriteListPlayStateLock);
m_pWriteList->AddHead(pNewBuffer);
pNewBuffer->AddRef();
UNLOCK(m_mtxWriteListPlayStateLock);
//--Subtract that from m_ulTotalWritten.
m_ulTotalWritten -= ulNumBytesToRewind;
_Pause();
}
else
{
//The hardware device handles the Pause/Resume.
LOCK(m_mtxDeviceStateLock);
_Pause();
UNLOCK(m_mtxDeviceStateLock);
}
m_wLastError = HXR_OK;
return m_wLastError;
}
HX_RESULT CAudioOutUNIX::_Imp_Resume()
{
//XXXgfw We really should be closing and re-opening the device to be nice to other procs.
LOCK(m_mtxWriteListPlayStateLock);
m_wState = RA_AOS_OPEN_PLAYING;
UNLOCK(m_mtxWriteListPlayStateLock);
//XXXgfw If the two branches of the if are the same maybe get rid of one????
if( !_HardwarePauseSupported() )
{
_Resume();
_Imp_Write(NULL);
}
else
{
//The hardware device handles the Pause/Resume.
_Resume();
_Imp_Write(NULL);
}
m_wLastError = HXR_OK;
return m_wLastError;
}
HX_RESULT CAudioOutUNIX::_Imp_Reset()
{
HX_RESULT retCode = RA_AOE_NOERR;
if ( m_wState != RA_AOS_CLOSED )
{
LOCK(m_mtxDeviceStateLock);
retCode = _Reset();
UNLOCK(m_mtxDeviceStateLock);
LOCK(m_mtxWriteListPlayStateLock);
while (m_pWriteList && m_pWriteList->GetCount() > 0)
{
IHXBuffer* pBuffer = (IHXBuffer *)(m_pWriteList->RemoveHead());
HX_RELEASE( pBuffer );
}
UNLOCK(m_mtxWriteListPlayStateLock);
m_ulTotalWritten = 0;
m_bFirstWrite = TRUE;
m_ulLastNumBytes = 0;
}
m_wLastError = retCode;
return m_wLastError;
}
HX_RESULT CAudioOutUNIX::_Imp_Drain()
{
HX_RESULT retCode = RA_AOE_NOERR;
LOCK(m_mtxWriteListPlayStateLock);
if( m_wState != RA_AOS_CLOSED )
{
retCode = _Drain();
}
while( m_pWriteList && !m_pWriteList->IsEmpty() )
{
IHXBuffer* pBuffer = (IHXBuffer *)(m_pWriteList->RemoveHead());
HX_RELEASE( pBuffer );
}
UNLOCK(m_mtxWriteListPlayStateLock);
m_wLastError = retCode;
return m_wLastError;
}
HX_RESULT CAudioOutUNIX::_Imp_CheckFormat( const HXAudioFormat* pFormat )
{
HX_RESULT retCode = RA_AOE_NOERR;
m_wLastError = HXR_OK;
retCode = _CheckFormat( pFormat );
if( RA_AOE_NOERR != retCode && RA_AOE_DEVBUSY != retCode )
{
m_wLastError = HXR_FAILED;
}
else
{
m_wLastError = HXR_OK;
}
return m_wLastError;
}
HX_RESULT CAudioOutUNIX::_Imp_GetCurrentTime( ULONG32& ulCurrentTime )
{
ULONG32 ulTime = 0;
UINT64 ulBytes = 0;
LOCK(m_mtxWriteListPlayStateLock);
ulBytes = _GetBytesActualyPlayed();
UNLOCK(m_mtxWriteListPlayStateLock);
ulTime = (ULONG32)(( ( (double)ulBytes/(double)m_uSampFrameSize)/(double)m_unSampleRate) * 1000.0 / (double)m_unNumChannels);
//Not used anywhere but belongs to CHXAudioDevice so we must set it.
m_ulCurrentTime = ulTime;
//Set the answer.
ulCurrentTime = ulTime;
m_wLastError = HXR_OK;
return HXR_OK;
}
void CAudioOutUNIX::DoTimeSyncs()
{
ReschedPlaybackCheck();
OnTimeSync();
return;
}
HX_RESULT CAudioOutUNIX::ReschedPlaybackCheck()
{
HX_RESULT retCode = HXR_OK;
if(!m_bCallbackPending)
{
HX_ASSERT( m_pCallback );
if(m_pCallback)
{
*m_pPlaybackCountCBTime += (int)(500*m_ulGranularity);
m_bCallbackPending = TRUE;
m_PendingCallbackID = m_pScheduler->AbsoluteEnter( m_pCallback,*((HXTimeval*)m_pPlaybackCountCBTime));
}
else
{
retCode = HXR_OUTOFMEMORY;
}
}
m_wLastError = retCode;
return m_wLastError;
}
UINT16 CAudioOutUNIX::_NumberOfBlocksRemainingToPlay(void)
{
UINT32 bytesBuffered = 0;
//We have to go through all of the buffers and count the size. Even though
//we always write m_wBlockSize buffers, we can get off-sized buffs because
//of the pause/resume code. When we pause we rewind however many bytes have
//not been played yet in the buffer.
LOCK(m_mtxWriteListPlayStateLock);
if( m_pWriteList )
{
LISTPOSITION i = m_pWriteList->GetHeadPosition();
while( i )
{
bytesBuffered += ((IHXBuffer *)m_pWriteList->GetAt(i)) -> GetSize();
m_pWriteList->GetNext(i);
}
}
bytesBuffered += (m_ulTotalWritten - _GetBytesActualyPlayed());
UNLOCK(m_mtxWriteListPlayStateLock);
return bytesBuffered / m_wBlockSize + 1;
}
CAudioOutUNIX::HXPlaybackCountCB::~HXPlaybackCountCB()
{
}
STDMETHODIMP CAudioOutUNIX::HXPlaybackCountCB::QueryInterface( REFIID riid, void** ppvObj )
{
HX_RESULT retCode = HXR_OK;
if( IsEqualIID(riid, IID_IHXCallback) )
{
AddRef();
*ppvObj = (IHXCallback*)this;
}
else if (IsEqualIID(riid, IID_IUnknown))
{
AddRef();
*ppvObj = this;
}
else
{
*ppvObj = NULL;
retCode = HXR_NOINTERFACE;
}
return retCode;
}
STDMETHODIMP_(ULONG32) CAudioOutUNIX::HXPlaybackCountCB::AddRef()
{
return InterlockedIncrement(&m_lRefCount);
}
STDMETHODIMP_(ULONG32) CAudioOutUNIX::HXPlaybackCountCB::Release()
{
if (InterlockedDecrement(&m_lRefCount) > 0)
{
return m_lRefCount;
}
delete this;
return HXR_OK;
}
STDMETHODIMP CAudioOutUNIX::HXPlaybackCountCB::Func(void)
{
if (m_pAudioDeviceObject)
{
if(!m_timed)
{
//m_pAudioDeviceObject->_Imp_Write(NULL);
}
else
{
m_pAudioDeviceObject->m_bCallbackPending = FALSE;
m_pAudioDeviceObject->_Imp_Write(NULL);
m_pAudioDeviceObject->DoTimeSyncs();
}
}
return HXR_OK;
}
HX_RESULT CAudioOutUNIX::_Pause()
{
return RA_AOE_NOTSUPPORTED;
}
HX_RESULT CAudioOutUNIX::_Resume()
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -