📄 audqnx.cpp
字号:
pNewBuffer->AddRef();
// Update total pause bytes offset for time/video sync
m_ulPauseBytes += pause_bytes;
return RA_AOE_NOERR;
}
HX_RESULT CAudioOutQNX::_Imp_Resume()
{
m_paused = FALSE;
_Imp_Write( NULL );
return RA_AOE_NOERR;
}
HX_RESULT CAudioOutQNX::_Imp_Reset()
{
m_ulLastTimeChecked = (UINT32) -1;
m_ulLastTimeReturned = 0;
if ( m_wState == RA_AOS_CLOSED )
return RA_AOE_NOERR;
if ( m_wID < 0 )
return RA_AOE_DEVNOTOPEN;
// Temporary FLUSH <--> DRAIN
if ( ioctl (m_wID, SND_PCM_IOCTL_DRAIN_PLAYBACK, 0) == -1 )
return RA_AOE_GENERAL;
while (m_pWriteList && m_pWriteList->GetCount() > 0)
{
IHXBuffer* pBuffer = (IHXBuffer *)(m_pWriteList->RemoveHead());
pBuffer->Release();
}
m_ulTotalWritten = 0;
m_bFirstWrite = TRUE;
m_ulLastNumBytes = 0;
return RA_AOE_NOERR;
}
HX_RESULT CAudioOutQNX::_Imp_Drain()
{
if ( m_wID < 0 )
return RA_AOE_DEVNOTOPEN;
// Temporary FLUSH <--> DRAIN
if ( ioctl (m_wID, SND_PCM_IOCTL_FLUSH_PLAYBACK, 0) == -1 )
return RA_AOE_GENERAL;
return RA_AOE_NOERR;
}
AUDIOERROR CAudioOutQNX::SetDeviceConfig
(
const HXAudioFormat* pFormat
)
{
if ( m_wID < 0 )
return RA_AOE_NOTENABLED;
int sampleWidth = pFormat->uBitsPerSample;
ULONG32 sampleRate = pFormat->ulSamplesPerSec;
int numChannels = pFormat->uChannels;
m_wBlockSize = m_ulBytesPerGran; //pFormat->uMaxBlockSize;
ULONG32 bufSize = 128;
ULONG32 bytesPerBlock = m_wBlockSize;
while ( bufSize < 4096 )
{
bufSize *= 2;
}
m_ulFragSize = bufSize;
snd_pcm_playback_params_t playback_params;
memset( &playback_params, 0, sizeof(playback_params) );
playback_params.fragment_size = m_ulFragSize;
playback_params.fragments_max = -1;
playback_params.fragments_room = 1;
/* it's okay to fail, card may not handle fragment size */
ioctl(m_wID, SND_PCM_IOCTL_PLAYBACK_PARAMS, &playback_params );
snd_pcm_format_t format;
memset( &format, 0, sizeof(format));
if( sampleWidth == 16 )
{
format.format = SND_PCM_SFMT_S16_LE;
}
else
{
format.format = SND_PCM_SFMT_U8;
m_uSampFrameSize /= 2;
}
format.channels = numChannels;
format.rate = sampleRate;
m_sample_rate = sampleRate;
m_num_channels = numChannels;
m_uSampFrameSize = sampleWidth / 8;
if(ioctl(m_wID, SND_PCM_IOCTL_PLAYBACK_FORMAT, &format) == -1)
{
return ( m_wLastError = RA_AOE_NOTENABLED );
}
numChannels = format.channels;
sampleRate = format.rate;
//
// Verify that requested format was accepted by the audio device.
//
if ( numChannels != pFormat->uChannels )
((HXAudioFormat*)pFormat)->uChannels = numChannels;
if ( sampleRate != pFormat->ulSamplesPerSec )
((HXAudioFormat*)pFormat)->ulSamplesPerSec = sampleRate;
// Get the audio driver's buffer size for our rollback buffer
snd_pcm_playback_info_t pinfo;
memset( &pinfo, 0, sizeof( pinfo ) );
if(ioctl(m_wID, SND_PCM_IOCTL_PLAYBACK_INFO, &pinfo) != -1)
m_ulDeviceBufferSize = pinfo.buffer_size;
return RA_AOE_NOERR;
}
HX_RESULT CAudioOutQNX::_Imp_CheckFormat
(
const HXAudioFormat* pFormat
)
{
// QNX audio driver can do all formats that we our
// currently interested in. However, we should check
// for valid inputs.
if ( pFormat->uChannels != 1 && pFormat->uChannels != 2 )
return HXR_FAILED;
if ( pFormat->uBitsPerSample != 8 && pFormat->uBitsPerSample != 16 )
return HXR_FAILED;
// Ask driver later
#if 0
/*No reason why the driver won't accept other sampling rates...*/
if ( pFormat->ulSamplesPerSec != 8000 && pFormat->ulSamplesPerSec != 9600 &&
pFormat->ulSamplesPerSec != 11025 && pFormat->ulSamplesPerSec != 16000 &&
pFormat->ulSamplesPerSec != 18900 && pFormat->ulSamplesPerSec != 22050 &&
pFormat->ulSamplesPerSec != 32000 && pFormat->ulSamplesPerSec != 44100 &&
pFormat->ulSamplesPerSec != 48000 )
return HXR_FAILED;
#endif
return HXR_OK;
}
/************************************************************************
* Method:
* CAudioOutQNX::_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.
*/
HX_RESULT CAudioOutQNX::_Imp_GetCurrentTime ( ULONG32& ulCurrentTime )
{
ULONG32 ulTime = 0;
ULONG32 ulBytes = GetPlaybackBytes();
ulBytes += m_ulPauseBytes;
ulTime = (UINT32)(( (double)(ulBytes/m_uSampFrameSize)/(double)m_sample_rate) * 1000 / m_num_channels);
//Not used anywhere but belongs to CHXAudioDevice so we must set it.
m_ulCurrentTime = ulTime;
//Set the answer.
ulCurrentTime = ulTime;
return HXR_OK;
}
/************************************************************************
* Method:
* CAudioOutQNX::_Imp_GetAudioFd
* Purpose:
*/
INT16 CAudioOutQNX::_Imp_GetAudioFd()
{
return m_wID;
}
/************************************************************************
* Method:
* CAudioOutQNX::DoTimeSyncs
* Purpose:
* Manual time syncs! Fork!
*/
void CAudioOutQNX::DoTimeSyncs()
{
ReschedPlaybackCheck();
OnTimeSync();
return;
}
/************************************************************************
* Method:
* CAudioOutQNX::GetPlaybackBytes
* Purpose:
* Get the number of bytes played since last open() was
* called. This ioctl() returns funky values sometimes?!@%
*/
ULONG32 CAudioOutQNX::GetPlaybackBytes()
{
snd_pcm_playback_status_t info;
memset( &info,0, sizeof(info));
if ( ioctl (m_wID, SND_PCM_IOCTL_PLAYBACK_STATUS, &info) != -1 )
return info.scount;
// If ioctl failed, just guess the value
int bytes = m_ulTotalWritten - m_ulGranularity / 2;
if (bytes < 0)
bytes = 0;
return (ULONG32) bytes;
}
ULONG32 CAudioOutQNX::_GetPlaybackBuffer( )
{
return( m_ulTotalWritten - GetPlaybackBytes( ) );
}
/************************************************************************
* Method:
* CAudioOutQNX::ReschedPlaybackCheck()
* Purpose:
* Reschedule playback callback.
*/
HX_RESULT CAudioOutQNX::ReschedPlaybackCheck()
{
HX_RESULT theErr = HXR_OK;
if (m_bCallbackPending)
return theErr;
/* Put this back in the scheduler.
*/
HXPlaybackCountCb* pCallback = 0;
pCallback = new HXPlaybackCountCb;
if (pCallback)
{
*m_pPlaybackCountCBTime += (int) (1000 * m_ulGranularity);
pCallback->m_pAudioDeviceObject = this;
m_bCallbackPending = TRUE;
m_PendingCallbackID = m_pScheduler->AbsoluteEnter(pCallback,
*((HXTimeval*) m_pPlaybackCountCBTime));
}
else
{
theErr = HXR_OUTOFMEMORY;
}
return HXR_OK;
}
UINT16 CAudioOutQNX::_NumberOfBlocksRemainingToPlay(void)
{
UINT32 bytesBuffered = 0;
LISTPOSITION i = m_pWriteList->GetHeadPosition();
while (i)
{
bytesBuffered += ((IHXBuffer *)m_pWriteList->GetAt(i)) -> GetSize();
m_pWriteList->GetNext(i);
}
bytesBuffered += (m_ulTotalWritten - GetPlaybackBytes());
return bytesBuffered / m_wBlockSize + 1;
}
// CAudioOutQNX::HXPlaybackCountCb
CAudioOutQNX::HXPlaybackCountCb::HXPlaybackCountCb(BOOL timed) :
m_lRefCount (0)
,m_pAudioDeviceObject (0)
,m_timed(timed)
{
}
CAudioOutQNX::HXPlaybackCountCb::~HXPlaybackCountCb()
{
}
/*
* IUnknown methods
*/
/////////////////////////////////////////////////////////////////////////
// Method:
// IUnknown::QueryInterface
// Purpose:
// Implement this to export the interfaces supported by your
// object.
//
STDMETHODIMP CAudioOutQNX::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) CAudioOutQNX::HXPlaybackCountCb::AddRef()
{
return InterlockedIncrement(&m_lRefCount);
}
/////////////////////////////////////////////////////////////////////////
// Method:
// IUnknown::Release
// Purpose:
// Everyone usually implements this the same... feel free to use
// this implementation.
//
STDMETHODIMP_(ULONG32) CAudioOutQNX::HXPlaybackCountCb::Release()
{
if (InterlockedDecrement(&m_lRefCount) > 0)
{
return m_lRefCount;
}
delete this;
return 0;
}
/*
* IHXPlaybackCountCb methods
*/
STDMETHODIMP CAudioOutQNX::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;
}
/************************************************************************
* Method:
* CAudioOutQNX::BuffersEmpty
* Purpose:
*/
BOOL CAudioOutQNX::BuffersEmpty()
{
snd_pcm_playback_status_t info;
if ( -1 == ioctl(m_wID, SND_PCM_IOCTL_PLAYBACK_STATUS, &info) )
return FALSE;
if ( info.queue )
return FALSE;
return TRUE;
}
void CAudioOutQNX::OpenMixer()
{
int i;
struct snd_mixer_info_t info;
struct snd_mixer_channel_info_t cinfo;
//
// return if the mixer is already opened
//
if (m_bMixerPresent)
return;
mixm_wID = open ( m_DevCtlName, O_RDWR );
if ( -1 == ioctl( mixm_wID, SND_MIXER_IOCTL_INFO, &info ) )
{
CloseMixer( );
return;
}
if (mixm_wID > 0)
{
/* find pcm channel */
memset( &cinfo, 0, sizeof( cinfo ) );
for ( i = 0; i < info.channels; i++ )
{
cinfo.channel = i;
if ( -1 == ioctl( mixm_wID, SND_MIXER_IOCTL_CHANNEL_INFO, &cinfo ) )
{
continue;
}
if ( 0 == strcmp( (char *)cinfo.name, SND_MIXER_ID_PCM ) )
{
m_wPCMChannel = i;
break;
}
}
}
if ( m_wPCMChannel > 0 )
{
m_bMixerPresent = 1;
}
else
{
CloseMixer( );
m_bMixerPresent = 0;
}
}
void CAudioOutQNX::CloseMixer()
{
// Close the mixer device.
if ( mixm_wID >= 0 )
{
close ( mixm_wID );
mixm_wID = -1;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -