📄 audlinux_oss.cpp
字号:
SafeStrCpy( szDevName, "/dev/dsp", MAX_DEV_NAME ); } // Open the audio device if it isn't already open if ( m_nDevID < 0 ) { m_nDevID = ::open( szDevName, O_WRONLY ); } if ( m_nDevID < 0 ) {#ifdef _DEBUG fprintf( stderr, "Failed to open audio(%s)!!!!!!! Code is: %d errno: %d\n", szDevName, m_nDevID, errno );#endif //Error opening device. retCode = RA_AOE_BADOPEN; } m_wLastError = retCode; return m_wLastError;}HX_RESULT CAudioOutLinux::_CloseAudio(){ HX_RESULT retCode = RA_AOE_NOERR; if( m_nDevID >= 0 ) { ::close( m_nDevID ); m_nDevID = NO_FILE_DESCRIPTOR; } else { retCode = RA_AOE_DEVNOTOPEN; } m_wLastError = retCode; return m_wLastError;}HX_RESULT CAudioOutLinux::_OpenMixer(){ HX_RESULT retCode = RA_AOE_NOERR; if(!m_bMixerPresent) { //Let user override default device with environ variable. char *pszOverrideName = getenv( "MIXER" ); /* Flawfinder: ignore */ char szDevCtlName[MAX_DEV_NAME]; /* Flawfinder: ignore */ if (pszOverrideName && strlen(pszOverrideName)>0 ) { SafeStrCpy( szDevCtlName , pszOverrideName, MAX_DEV_NAME ); } else { SafeStrCpy( szDevCtlName , "/dev/mixer", MAX_DEV_NAME ); // default for volume } m_nMixerID = ::open( szDevCtlName, O_RDWR ); if (m_nMixerID > 0) { m_bMixerPresent = 1; _Imp_GetVolume(); } else { m_nMixerID = NO_FILE_DESCRIPTOR; m_bMixerPresent = 0; } } m_wLastError = retCode; return m_wLastError;}HX_RESULT CAudioOutLinux::_CloseMixer(){ HX_RESULT retCode = RA_AOE_NOERR; if( m_nMixerID >= 0 ) { ::close( m_nMixerID ); m_nMixerID = NO_FILE_DESCRIPTOR; } m_wLastError = retCode; return m_wLastError;}//Device specific method to reset device and return it to a state that it //can accept new sample rates, num channels, etc.HX_RESULT CAudioOutLinux::_Reset(){ HX_RESULT retCode = RA_AOE_NOERR; m_ulPausePosition = 0; if ( m_nDevID < 0 ) { retCode = RA_AOE_DEVNOTOPEN; } else if( ::ioctl (m_nDevID, SOUND_PCM_RESET, 0) == -1 ) { retCode = RA_AOE_GENERAL; } m_wLastError = retCode; return m_wLastError;}//Device specific method to get/set the devices current volume.UINT16 CAudioOutLinux::_GetVolume() const{ int nVolume = 0; int nRetVolume = 0; int nLeftVolume = 0; int nRightVolume = 0; if (::ioctl( m_nMixerID, MIXER_READ(HX_VOLUME), &nVolume) < 0) { nRetVolume = 0; } nLeftVolume = (nVolume & 0x000000ff); nRightVolume = (nVolume & 0x0000ff00) >> 8; //Which one to use? Average them? nRetVolume = nLeftVolume ; return nRetVolume; }HX_RESULT CAudioOutLinux::_SetVolume(UINT16 unVolume){ HX_RESULT retCode = RA_AOE_NOERR; int nNewVolume=0; //Set both left and right volumes. nNewVolume = (unVolume & 0xff) | ((unVolume &0xff) << 8); if (::ioctl( m_nMixerID, MIXER_WRITE(HX_VOLUME), &nNewVolume) < 0) { retCode = RA_AOE_NOTSUPPORTED; } m_wLastError = retCode; return m_wLastError;}//Device specific method to drain a device. This should play the remaining//bytes in the devices buffer and then return.HX_RESULT CAudioOutLinux::_Drain(){ HX_RESULT retCode = RA_AOE_NOERR; if ( m_nDevID < 0 ) { retCode = RA_AOE_DEVNOTOPEN; } else if( ::ioctl (m_nDevID, SNDCTL_DSP_SYNC, 0) == -1 ) { retCode = RA_AOE_GENERAL; } m_wLastError = retCode; return m_wLastError;}UINT64 CAudioOutLinux::_GetBytesActualyPlayed(void) const{ /* Get current playback position in device DMA. */ int bytes2 = 0; UINT64 ulTheAnswer = 0; //What versions of the linux kernel do we want to support? if( !m_bGetODelayFailed ) { if( m_ulTotalWritten > 0 ) { HX_ASSERT( m_unSampleRate!=0 && m_uSampFrameSize!=0 ); ULONG32 ulTick = GetTickCount(); //We need to update the timestamps every so often. //This make sure that if the XServer was blocked, and //we ran dry, that we re-sync up. if( (ulTick-m_ulLastTimeStamp)>200 ) { ((CAudioOutLinux*)this)->_SyncUpTimeStamps(); ulTick = GetTickCount(); } ulTheAnswer = (UINT64)(m_ulLastBytesPlayed+ ((float)(ulTick-m_ulLastTimeStamp)* (float)m_unNumChannels/1000.0* m_unSampleRate*m_uSampFrameSize) +0.5 ); } } else { //We will assume that the error is because of an incomplete //implementation of the oss compatible driver. So, just //fake it with time stamps. if( m_ulTotalWritten > 0 ) { ulTheAnswer = (UINT64)((float)(GetTickCount()-m_ulTickCount)*(float)m_unNumChannels/1000.0*m_unSampleRate*m_uSampFrameSize); ulTheAnswer += m_ulPausePosition; } } return ulTheAnswer;}//this must return the number of bytes that can be written without blocking.//Don't use SNDCTL_DSP_GETODELAY here as it can't compute that amount//correctly.HX_RESULT CAudioOutLinux::_GetRoomOnDevice(ULONG32& ulBytes) const{ HX_RESULT retCode = RA_AOE_NOERR; audio_buf_info stBuffInfo; int theErr=0; //What versions of the linux kernel do we want to support? if( m_bGetOSpaceFailed ) { theErr = -1; } else { theErr = ::ioctl(m_nDevID, SNDCTL_DSP_GETOSPACE, &stBuffInfo); } if ( theErr != -1 ) { ulBytes = stBuffInfo.bytes; } else { //So we just try it once. m_bGetOSpaceFailed = TRUE; ulBytes = m_ulDeviceBufferSize-(m_ulTotalWritten-_GetBytesActualyPlayed() ); } m_wLastError = retCode; return m_wLastError;}HX_RESULT CAudioOutLinux::_CheckFormat( const HXAudioFormat* pFormat ){ int nBitsPerSample = pFormat->uBitsPerSample; int ulTmp = pFormat->ulSamplesPerSec; int nNumChannels = pFormat->uChannels; float fTmp = 0.0; HX_RESULT retCode = RA_AOE_NOERR; //Is the device already open? if( m_nDevID > 0 || RA_AOE_NOERR != _OpenAudio() ) { retCode = RA_AOE_DEVBUSY; return retCode; } //See if the sample rate is supported. if (ioctl(m_nDevID, SOUND_PCM_WRITE_RATE, &ulTmp) == -1) { //Not quite the real error, but it is what we need to return. retCode = RA_AOE_DEVBUSY; goto donechecking; } if (ulTmp == 0) { /* * Some drivers actually set the sample rate on the device, but * return 0 for the sample rate. On these platforms we just ignore * the return value and assume the sample rate is set to what was * requested. */ ulTmp = pFormat->ulSamplesPerSec; } //The ESS 1688 Sound card (not the ESS Solo-1) will return sample //rates that are close but not quite the ones we asked for (the //ESS Solo-1 doesn't play mono). I have see freqs like 44194 //instead of 44100 (.2%) and 7984 instead of 8000 (.6%). //So, if we are close enough just say it is OK. //How about 1%? fTmp = (float)ulTmp/(float)pFormat->ulSamplesPerSec; if( fabs(1.0-fTmp) > .01 ) { //It is NOT supported retCode = RA_AOE_BADFORMAT; goto donechecking; } //Check num channels. if (ioctl(m_nDevID, SOUND_PCM_WRITE_CHANNELS, &nNumChannels) == -1) { retCode = RA_AOE_DEVBUSY; goto donechecking; } else if ( nNumChannels != pFormat->uChannels ) { retCode = RA_AOE_BADFORMAT; goto donechecking; } //Check the frame size. if (ioctl(m_nDevID, SNDCTL_DSP_SETFMT, &nBitsPerSample) == -1) { retCode = RA_AOE_DEVBUSY; goto donechecking; } else if ( nBitsPerSample != pFormat->uBitsPerSample ) { retCode = RA_AOE_BADFORMAT; goto donechecking; } //Close the audio device. donechecking: _CloseAudio(); m_wLastError = retCode; return retCode;}HX_RESULT CAudioOutLinux::_CheckSampleRate( ULONG32 ulSampleRate ){ ULONG32 ulTmp = ulSampleRate; m_wLastError = RA_AOE_NOERR; //Is the device already open? if( m_nDevID > 0 || RA_AOE_NOERR != _OpenAudio() ) { m_wLastError = RA_AOE_DEVBUSY; } else { //See if the sample rate is supported. if (ioctl(m_nDevID, SOUND_PCM_WRITE_RATE, &ulTmp) == -1) { //Not quite the real error, but it is what we need to return. m_wLastError = RA_AOE_DEVBUSY; } else if( ulSampleRate != ulTmp ) { //It is NOT supported m_wLastError = RA_AOE_BADFORMAT; } _CloseAudio(); } return m_wLastError;}HX_RESULT CAudioOutLinux::_Pause() { m_wLastError = HXR_OK; m_ulPausePosition = m_ulTotalWritten; m_ulTickCount = 0; m_ulLastTimeStamp = 0; return m_wLastError;}HX_RESULT CAudioOutLinux::_Resume(){ m_wLastError = HXR_OK; if( m_ulTotalWritten > 0 ) { m_ulTickCount = GetTickCount(); m_ulLastTimeStamp = m_ulTickCount; } return m_wLastError;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -