📄 audaix.cpp
字号:
pAudioOutHdr = NULL; // don't add the same buffer again...
} while (bWroteSomething);
return m_wLastError;
}
// Seek() is never called.
HX_RESULT CAudioOutAIX::_Imp_Seek(ULONG32 ulSeekTime)
{
return HXR_OK;
}
HX_RESULT CAudioOutAIX::_Imp_Pause()
{
m_paused = TRUE;
return RA_AOE_NOERR;
}
HX_RESULT CAudioOutAIX::_Imp_Resume()
{
m_paused = FALSE;
return RA_AOE_NOERR;
}
/////////////////////////////////////////////////////////////////////////
// Imp_Reset()
// Reset the device. It is important to note that this call results
// from a seek, so we must act accordingly.
//
HX_RESULT CAudioOutAIX::_Imp_Reset()
{
_Imp_Close();
_Imp_Open(NULL);
while(!m_pWriteList->IsEmpty())
{
IHXBuffer* pBuffer = (IHXBuffer*)m_pWriteList->RemoveHead();
HX_RELEASE(pBuffer);
}
HX_ASSERT( m_pWriteList->IsEmpty() );
// these are vital! If they are not set this way, playback after a seek
// will just stop after a few frames.
m_bPaused = FALSE;
m_bFirstWrite = TRUE;
// and these are fairly obvious, but necessary after a seek. It should be
// noted here that the audio timeline after a seek is relative to the
// internal timeline of the core scheduler; all our playback is based from
// our start.
m_ulTotalWritten =0;
m_ulCurrentTime = 0;
return RA_AOE_NOERR;
}
// this will force the player to play all remaining data. The call
// will block until finished playing - if this is not what is desired,
// change the second parameter of the call to FALSE.
HX_RESULT CAudioOutAIX::_Imp_Drain()
{
// -pjg need to drain the WriteList also.
// this will force the player to play all remaining data. If passed TRUE,
// the call will block until finished playing.
while(!m_pWriteList->IsEmpty())
{
IHXBuffer* pBuffer = (IHXBuffer*)m_pWriteList->RemoveHead();
HX_RELEASE(pBuffer);
}
m_pAudioDevice->play_remaining_data( gpSomEnvironment, TRUE );
return RA_AOE_NOERR;
}
AUDIOERROR CAudioOutAIX::SetDeviceConfig( const HXAudioFormat* pFormat )
{
m_pAudioDevice->set_sample_rate ( gpSomEnvironment,
pFormat->ulSamplesPerSec,
&m_oSamples );
m_pAudioDevice->set_number_of_channels ( gpSomEnvironment,
pFormat->uChannels );
m_pAudioDevice->set_bits_per_sample ( gpSomEnvironment,
pFormat->uBitsPerSample );
m_pAudioDevice->set_audio_format_type ( gpSomEnvironment, "PCM" );
m_pAudioDevice->set_number_format ( gpSomEnvironment,
"TWOS_COMPLEMENT" );
m_pAudioDevice->set_byte_order ( gpSomEnvironment, "MSB" );
m_pAudioDevice->set_time_format ( gpSomEnvironment,
UMSAudioTypes_Msecs );
m_pAudioDevice->set_balance ( gpSomEnvironment, lDefaultBalance );
m_pAudioDevice->set_volume ( gpSomEnvironment, zlCurrentVolume );
m_pAudioDevice->enable_output ( gpSomEnvironment, "LINE_OUT",
&m_lLeftGain, &m_lRightGain );
m_pAudioDevice->initialize ( gpSomEnvironment );
m_pAudioDevice->start ( gpSomEnvironment );
m_num_channels = pFormat->uChannels;
m_sample_rate = pFormat->ulSamplesPerSec;
m_bits_per_sample = pFormat->uBitsPerSample;
return RA_AOE_NOERR;
}
HX_RESULT CAudioOutAIX::_Imp_CheckFormat( const HXAudioFormat* pFormat )
{
// Check for valid format inputs.
if ( pFormat->uChannels != 1 && pFormat->uChannels != 2 )
{
return HXR_FAIL;
}
if ( pFormat->uBitsPerSample != 8 && pFormat->uBitsPerSample != 16 )
{
return HXR_FAIL;
}
return HXR_OK;
}
/************************************************************************
* Method:
* CAudioOutAIX::_Imp_GetCurrentTime
* Purpose:
* Get the current time from the audio device.
* We added this to support the clock available in the
* Window's audio driver.
*
* Current time is simply a function of the total number of
* bytes written to the device minus the number still in
* the device queue. This is expressed as playbackbytes.
*
* Ported to Aix 4.3.1 by fhutchinson, Jan 1999.
*
* The minitimer below is a simple timer employed to avoid excessive
* calls to the UMS audio driver to get the current time, the rationale
* being that a gettimeofday call and a little arithmetic is less expensive
* than a call to the driver. The threshold value is the number of
* microseconds (1/1,000,000 sec) that must pass before the time goes off.
*/
#include <string.h> // for strerror()
HX_RESULT CAudioOutAIX::_Imp_GetCurrentTime( ULONG32& ulCurrentTime )
{
long lBytesPerSample = m_bits_per_sample/8;
long lBytesStillInDeviceBuffer;
ulCurrentTime = m_ulCurrentTime;
UMSAudioDevice_ReturnCode retCode;
// set the device to return the amount of data still in the device buffer as a
// number of bytes
retCode = m_pAudioDevice->set_time_format( gpSomEnvironment, UMSAudioTypes_Bytes );
if( retCode != UMSAudioDevice_Success )
{
m_wLastError = UMSErrorCodeToRACode( retCode );
return (m_wLastError = UMSErrorCodeToRACode( retCode ) );
}
retCode = m_pAudioDevice->write_buff_used( gpSomEnvironment, &lBytesStillInDeviceBuffer );
if( retCode != UMSAudioDevice_Success )
{
// almost certainly because the device is not opened.
return (m_wLastError = UMSErrorCodeToRACode( retCode ) );
}
long lBytesPlayed = m_ulTotalWritten - lBytesStillInDeviceBuffer;
m_ulCurrentTime = ulCurrentTime =
( (lBytesPlayed /lBytesPerSample) /
(float)m_sample_rate * 1000 / m_num_channels );
return HXR_OK;
}
/************************************************************************
* Method:
* CAudioOutAIX::_Imp_GetAudioFd
* Purpose: Intended to return the file descriptor of the device.
* However, UMS is not file descriptor-based, so we
* return a -1, generally accepted as a closed device fd.
*/
INT16 CAudioOutAIX::_Imp_GetAudioFd()
{
return -1;
}
/************************************************************************
* Method:
* CAudioOutAIX::DoTimeSyncs
* Purpose:
* Manual time syncs! Fork!
*/
void CAudioOutAIX::DoTimeSyncs()
{
ReschedPlaybackCheck();
OnTimeSync(); // XXXDMB // hxaudev.cpp::CHXAudioDevice::OnTimeSync()
return;
}
/************************************************************************
* Method:
* CAudioOutAIX::ReschedPlaybackCheck()
* Purpose:
* Reschedule playback callback.
*/
HX_RESULT CAudioOutAIX::ReschedPlaybackCheck()
{
HX_RESULT theErr = HXR_OK;
if (m_bCallbackPending)
return theErr;
*m_pPlaybackCountCBTime += (int) (m_ulGranularity*1000) / 2;
// Put this back in the scheduler.
HXPlaybackCountCb* pCallback = 0;
pCallback = new HXPlaybackCountCb(TRUE);
if (pCallback)
{
pCallback->m_pAudioDeviceObject = this;
m_bCallbackPending = TRUE;
m_PendingCallbackID =
m_pScheduler->AbsoluteEnter(pCallback,*((HXTimeval*)m_pPlaybackCountCBTime)) ;
}
else
theErr = HXR_OUTOFMEMORY; // but ignored, why?
return theErr;
}
UINT16 CAudioOutAIX::_NumberOfBlocksRemainingToPlay(void)
{
ULONG32 ulCurTime = 0;
GetCurrentAudioTime(ulCurTime);
UINT32 bytesBuffered = 0;
LISTPOSITION i = m_pWriteList->GetHeadPosition();
while (i)
{
bytesBuffered += ((IHXBuffer *)m_pWriteList->GetAt(i)) -> GetSize();
m_pWriteList->GetNext(i);
}
m_pAudioDevice->set_time_format( gpSomEnvironment, UMSAudioTypes_Bytes );
long lBytesStillInDeviceBuffer;
UINT32 tries = 100;
UMSAudioDevice_ReturnCode retCode;
while (--tries &&
(m_pAudioDevice->write_buff_used( gpSomEnvironment, &lBytesStillInDeviceBuffer )) != UMSAudioDevice_Success);
if (!tries)
{
HX_ASSERT(FALSE);
// don't know what to do!
}
UINT16 blocks =
(bytesBuffered + lBytesStillInDeviceBuffer) / m_wBlockSize + 1;
//UINT16 blocks = (int) (((double)bytesBuffered + lBytesStillInDeviceBuffer) /
// m_ulBytesPerGran) + 1;
return blocks;
}
// CAudioOutAIX::HXPlaybackCountCb
CAudioOutAIX::HXPlaybackCountCb::HXPlaybackCountCb(BOOL timed)
: m_lRefCount (0),
m_pAudioDeviceObject (0),
m_timed(timed)
{
}
CAudioOutAIX::HXPlaybackCountCb::~HXPlaybackCountCb()
{
}
/*
* IUnknown methods
*/
/////////////////////////////////////////////////////////////////////////
// Method:
// IUnknown::QueryInterface
// Purpose:
// Implement this to export the interfaces supported by your
// object.
//
STDMETHODIMP CAudioOutAIX::HXPlaybackCountCb::QueryInterface(REFIID riid, void** ppvObj)
{
if (IsEqualIID(riid, IID_IHXCallback))
{
AddRef();
*ppvObj = (IHXCallback*)this;
return HXR_OK;
}
else if (IsEqualIID(riid, IID_IUnknown))
{
AddRef();
*ppvObj = this;
return HXR_OK;
}
*ppvObj = NULL;
return HXR_NOINTERFACE;
}
/////////////////////////////////////////////////////////////////////////
// Method:
// IUnknown::AddRef
// Purpose:
// Everyone usually implements this the same... feel free to use
// this implementation.
//
STDMETHODIMP_(ULONG32) CAudioOutAIX::HXPlaybackCountCb::AddRef()
{
return InterlockedIncrement(&m_lRefCount);
}
/////////////////////////////////////////////////////////////////////////
// Method:
// IUnknown::Release
// Purpose:
// Everyone usually implements this the same... feel free to use
// this implementation.
//
STDMETHODIMP_(ULONG32) CAudioOutAIX::HXPlaybackCountCb::Release()
{
if (InterlockedDecrement(&m_lRefCount) > 0)
{
return m_lRefCount;
}
delete this;
return 0;
}
/*
* IHXPlaybackCountCb methods
*/
STDMETHODIMP CAudioOutAIX::HXPlaybackCountCb::Func(void)
{
if (m_pAudioDeviceObject)
{
if(!m_timed)
{
m_pAudioDeviceObject->_Imp_Write(NULL);
}
else
{
m_pAudioDeviceObject->_Imp_Write(NULL);
m_pAudioDeviceObject->m_bCallbackPending = FALSE;
m_pAudioDeviceObject->DoTimeSyncs();
}
}
return HXR_OK;
}
//
// getUMSAudioDeviceError()
//
// returns the string description of the given UMS error code
//
static const char * getUMSAudioDeviceError( UMSAudioDevice_ReturnCode code )
{
switch( code )
{
case UMSAudioDevice_Success : return "Success";
case UMSAudioDevice_InvalidParam : return "Invalid parameter";
case UMSAudioDevice_MemoryError : return "Success";
case UMSAudioDevice_DeviceNotAvail : return "Device is not available";
case UMSAudioDevice_Preempted : return "Preempted";
case UMSAudioDevice_Interrupted : return "Inerrupted";
case UMSAudioDevice_DeviceError : return "Device error";
// make sure this is last before default case.
case UMSAudioDevice_Failure : return "undescribed error";
default : break;
}
return "Unknown error";
}
//
// UMSErrorCodeToRACode()
//
// Converts the UMS return code to a best-guess RMA return code equivalent.
//
audio_error UMSErrorCodeToRACode( UMSAudioDevice_ReturnCode retCode )
{
switch( retCode )
{
case UMSAudioDevice_Success : return RA_AOE_NOERR;
case UMSAudioDevice_InvalidParam : return RA_AOE_INVALPARAM;
case UMSAudioDevice_DeviceNotAvail : return RA_AOE_BADDEVICEID;
case UMSAudioDevice_NoDevice : return RA_AOE_BADDEVICEID;
case UMSAudioDevice_IncompatibleSettings : return RA_AOE_BADFORMAT ;
case UMSAudioDevice_NotOpen : return RA_AOE_DEVNOTOPEN ;
case UMSAudioDevice_NotReady : return RA_AOE_DEVBUSY ;
case UMSAudioDevice_SettingsChanged : return RA_AOE_BADFORMAT ;
// this is a stretch...
case UMSAudioDevice_DeviceError : return RA_AOE_BADWRITE ;
case UMSAudioDevice_NotSupported : return RA_AOE_NOTSUPPORTED ;
// and these we will classify under general for now.
case UMSAudioDevice_Interrupted : ;
case UMSAudioDevice_Preempted : ;
case UMSAudioDevice_MemoryError : ;
case UMSAudioDevice_Failure : ;
case UMSAudioDevice_UnderRun : ;
case UMSAudioDevice_OverRun : ;
default : break;
}
return RA_AOE_GENERAL;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -