📄 audaix.cpp
字号:
INT32 newRefCount = 0; if( pBuffer ) newRefCount = pBuffer->Release(); HX_ASSERT(newRefCount == 0); pBuffer = NULL; 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::HXPlaybackCountCbCAudioOutAIX::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 + -