📄 audqnx.cpp
字号:
// Make sure we only deal with full samples. Bytes-per-sample*num-channels. int nRem = ulNumBytesToRewind % (m_uSampFrameSize * m_num_channels); ulNumBytesToRewind -= nRem; pNewBuffer->Set( m_pRollbackBuffer+m_ulDeviceBufferSize-ulNumBytesToRewind, ulNumBytesToRewind ); m_pWriteList->AddHead(pNewBuffer); 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::HXPlaybackCountCbCAudioOutQNX::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 + -