audlinux_oss.cpp
上传用户:dangjiwu
上传日期:2013-07-19
资源大小:42019k
文件大小:22k
源码类别:

Symbian

开发平台:

Visual C++

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Source last modified: $Id: audlinux_oss.cpp,v 1.6.18.1 2004/07/09 02:01:42 hubbe Exp $
  3.  * 
  4.  * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
  5.  * 
  6.  * The contents of this file, and the files included with this file,
  7.  * are subject to the current version of the RealNetworks Public
  8.  * Source License (the "RPSL") available at
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed
  10.  * the file under the current version of the RealNetworks Community
  11.  * Source License (the "RCSL") available at
  12.  * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
  13.  * will apply. You may also obtain the license terms directly from
  14.  * RealNetworks.  You may not use this file except in compliance with
  15.  * the RPSL or, if you have a valid RCSL with RealNetworks applicable
  16.  * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
  17.  * the rights, obligations and limitations governing use of the
  18.  * contents of the file.
  19.  * 
  20.  * Alternatively, the contents of this file may be used under the
  21.  * terms of the GNU General Public License Version 2 or later (the
  22.  * "GPL") in which case the provisions of the GPL are applicable
  23.  * instead of those above. If you wish to allow use of your version of
  24.  * this file only under the terms of the GPL, and not to allow others
  25.  * to use your version of this file under the terms of either the RPSL
  26.  * or RCSL, indicate your decision by deleting the provisions above
  27.  * and replace them with the notice and other provisions required by
  28.  * the GPL. If you do not delete the provisions above, a recipient may
  29.  * use your version of this file under the terms of any one of the
  30.  * RPSL, the RCSL or the GPL.
  31.  * 
  32.  * This file is part of the Helix DNA Technology. RealNetworks is the
  33.  * developer of the Original Code and owns the copyrights in the
  34.  * portions it created.
  35.  * 
  36.  * This file, and the files included with this file, is distributed
  37.  * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
  38.  * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
  39.  * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
  40.  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
  41.  * ENJOYMENT OR NON-INFRINGEMENT.
  42.  * 
  43.  * Technology Compatibility Kit Test Suite(s) Location:
  44.  *    http://www.helixcommunity.org/content/tck
  45.  * 
  46.  * Contributor(s):
  47.  * 
  48.  * ***** END LICENSE BLOCK ***** */
  49. #include <unistd.h>
  50. #include <fcntl.h>
  51. #include <stdlib.h>
  52. #include <errno.h>
  53. #include <sys/ioctl.h>
  54. #include <stdio.h> 
  55. #include <math.h> 
  56. #include "ihxpckts.h"
  57. #include "hxtick.h"
  58. #include "hxprefs.h"
  59. #include "timeval.h"
  60. #include "hxthread.h"
  61. #include "audlinux_oss.h"
  62. #include "hxstrutl.h"
  63. #include "hxprefutil.h"
  64. //we can't set the PCM volume on the PowerPC. The sound driver
  65. //only lets up set the master volume.
  66. #ifdef __powerpc__
  67. #   define HX_VOLUME  SOUND_MIXER_VOLUME
  68. #else
  69. #   define HX_VOLUME  SOUND_MIXER_PCM
  70. #endif
  71. //------------------------------------------
  72. // Ctors and Dtors.
  73. //------------------------------------------
  74. CAudioOutLinux::CAudioOutLinux() :
  75.     CAudioOutUNIX(),
  76.     m_ulTickCount(0),
  77.     m_ulLastBytesPlayed(0),
  78.     m_ulLastTimeStamp(0),
  79.     m_ulPausePosition(0),
  80.     m_nDevID(NO_FILE_DESCRIPTOR),
  81.     m_nMixerID(NO_FILE_DESCRIPTOR),
  82.     m_bGetODelayFailed(TRUE),
  83.     m_bGetOSpaceFailed(FALSE),
  84.     m_bTestGetODelay(TRUE)
  85. {
  86. };
  87. CAudioOutLinux::~CAudioOutLinux()
  88. {
  89.     //The mixer is opened independently of the audio device. Make sure 
  90.     //it is closed.
  91.     _CloseMixer();
  92. };
  93. //-------------------------------------------------------
  94. // These Device Specific methods must be implemented 
  95. // by the platform specific sub-classes.
  96. //-------------------------------------------------------
  97. INT16 CAudioOutLinux::_Imp_GetAudioFd(void)
  98. {
  99.     return m_nDevID;
  100. }
  101. //Devic specific method to set the audio device characteristics. Sample rate,
  102. //bits-per-sample, etc.
  103. //Method *must* set member vars. m_unSampleRate and m_unNumChannels.
  104. HX_RESULT CAudioOutLinux::_SetDeviceConfig( const HXAudioFormat* pFormat )
  105. {
  106.     if ( m_nDevID < 0 )
  107.         return RA_AOE_DEVNOTOPEN;
  108.     m_wBlockSize = m_ulBytesPerGran;
  109.     //First, we want to determine the fragment size of the device buffer.
  110.     //We will let the device determine the number of fragments after we
  111.     //make sure that each fragment is no bigger than our block size.
  112.     //The minimum block size for OSS is 16 bytes and the max is 2^0xf.
  113.     //Basically, Log-base-two(m_wBlockSize)+1.
  114.     int nPower = 0x4;
  115.     while( (1<<nPower)<m_wBlockSize && nPower<0xf )
  116.     { 
  117.         nPower++;
  118.     }
  119.     if( nPower > 4 )
  120.         nPower--;
  121.     
  122.     //Frag info is 0xMMMMSSSS. Where
  123.     //
  124.     // MMMM is the total number of fragments. Set this to 7fff if you want
  125.     //      OSS to figure it out.
  126.     // SSSS is the size of each fragment. The size is 2^0xSSSS.
  127.     int nFragInfo = 0x7fff0000 | nPower;
  128.     //Now set the fragment size.
  129.     if (ioctl(m_nDevID, SNDCTL_DSP_SETFRAGMENT, &nFragInfo) == -1)
  130.     {
  131.         return (m_wLastError = RA_AOE_NOTENABLED);
  132.     }
  133.     //Now set the format. Either 8-bit or 16-bit audio is supported.
  134.     int      nSampleWidth  = pFormat->uBitsPerSample;
  135.     ULONG32  nSampleRate   = pFormat->ulSamplesPerSec;
  136.     int      numChannels   = pFormat->uChannels;
  137.     int      nFormat1      = 0;
  138.     int      nFormat2      = 0;
  139.     
  140.     if( nSampleWidth == 16)
  141.     {
  142.         nFormat1 = nFormat2 = AFMT_S16_NE;
  143.     }
  144.     else
  145.     {
  146.         nFormat1 = nFormat2 = AFMT_U8;
  147.     }
  148.     
  149.     if(ioctl(m_nDevID, SNDCTL_DSP_SETFMT, &nFormat1) == -1)
  150.     {
  151.         return (  m_wLastError = RA_AOE_NOTENABLED );
  152.     }
  153.     //Check and see if the device supports the format we tried to set.
  154.     //If it didn't take our only other option is unsigned 8 bit. So, if
  155.     //that is what the device returned just use it.
  156.     if(nFormat1!=nFormat2 && nFormat1 != AFMT_U8 )
  157.     {
  158.         //Just try to set AFMT_U8.
  159.         nFormat1 = AFMT_U8;
  160.         if(ioctl(m_nDevID, SNDCTL_DSP_SETFMT, &nFormat1) == -1)
  161.         {
  162.             return (  m_wLastError = RA_AOE_NOTENABLED );
  163.         }
  164.         if( nFormat1 != AFMT_U8 )
  165.         {
  166.             //No know format is supported.
  167.             return (  m_wLastError = RA_AOE_NOTENABLED ); 
  168.         }
  169.     }
  170.     //If we went to 8-bit then 
  171.     if( nFormat1 == AFMT_U8 )
  172.     {
  173.         //AFMT_U8 is set.
  174.         nSampleWidth = 8;
  175.     }
  176.     m_uSampFrameSize = nSampleWidth/8;
  177.     if ( nSampleWidth != pFormat->uBitsPerSample )
  178.     {
  179.         ((HXAudioFormat*)pFormat)->uBitsPerSample = nSampleWidth;
  180.     }
  181.     
  182.     
  183.     // Set sampling rate, sample width, #channels.
  184.     //
  185.     // Make sure you set num channels before rate. If you don't it will
  186.     // screw up SBPro  devices. Your rate will actually be 1/2 of what
  187.     // you think it is.
  188.     //Set number of channels. Stereo or mono.
  189.     if (ioctl(m_nDevID, SOUND_PCM_WRITE_CHANNELS, &numChannels) == -1)
  190.     {
  191.         return ( m_wLastError = RA_AOE_NOTENABLED );
  192.     }
  193.     m_unNumChannels = numChannels;
  194.     if ( numChannels != pFormat->uChannels )
  195.     {
  196.         ((HXAudioFormat*)pFormat)->uChannels = numChannels;
  197.     }
  198.     //Set the sample rate.
  199.     if (ioctl(m_nDevID, SOUND_PCM_WRITE_RATE, &nSampleRate) == -1)
  200.     {
  201.         return ( m_wLastError = RA_AOE_NOTENABLED );
  202.     }
  203.     if (nSampleRate == 0)
  204.     {
  205. /* 
  206.  * Some drivers actually set the sample rate on the device, but
  207.  * return 0 for the sample rate. On these platforms we just ignore
  208.  * the return value and assume the sample rate is set to what was
  209.  * requested.
  210.  */
  211. nSampleRate = pFormat->ulSamplesPerSec;
  212.     }
  213.     m_unSampleRate = nSampleRate;
  214.     if ( nSampleRate != pFormat->ulSamplesPerSec )
  215.     {
  216.         ((HXAudioFormat*)pFormat)->ulSamplesPerSec = nSampleRate;
  217.     }
  218.     //Find out if the user wants to support old OSS drivers that don't have,
  219.     //or support well, the iocls needed for good syncing.  SNDCTL_DSP_GETOSPACE and
  220.     //SNDCTL_DSP_GETODELAY.
  221.     IHXPreferences* pPreferences = NULL;
  222.     if( m_pContext && HXR_OK == m_pContext->QueryInterface( IID_IHXPreferences, (void **) &pPreferences))
  223.     {
  224. UINT32 nOldOSS = 0;
  225. if (HXR_OK == ReadPrefINT32(pPreferences, "SoundDriver", nOldOSS) &&
  226.     (nOldOSS == 1))
  227. {
  228.     m_bGetODelayFailed = TRUE;
  229.     m_bGetOSpaceFailed = TRUE;
  230.     m_bTestGetODelay = FALSE;
  231. }
  232.         HX_RELEASE( pPreferences );
  233.     }
  234. //for now, PowerPC linux doesn't support the following ioctl call
  235. //So, I will just make up some buffer size and live with it for
  236. //now. You won't be able to tell the difference until you turn
  237. //off threaded audio, then it will be block city!
  238. #ifndef __powerpc__  
  239.     audio_buf_info getYourInfoHere;
  240.     if( !m_bGetOSpaceFailed )
  241.     {
  242.         //This call is to get how the device is set up after we have
  243.         //set the sample rate etc. We use this to set up the buffers
  244.         //we use for the fake pause/resume features.
  245.         if (ioctl(m_nDevID, SNDCTL_DSP_GETOSPACE, &getYourInfoHere) == -1) 
  246.         {
  247.             m_wLastError = RA_AOE_NOTENABLED;
  248.             return m_wLastError;
  249.         }
  250.         m_ulDeviceBufferSize = getYourInfoHere.fragsize*getYourInfoHere.fragstotal;
  251.     }
  252.     else
  253.     {
  254.         //We don't have anyway to determine how big the buffer is.
  255.         //just guess I guess.
  256.         m_ulDeviceBufferSize = 8192*4;
  257.     }
  258. #else
  259.     m_ulDeviceBufferSize = 8192*4;
  260. #endif
  261. #ifdef _DEBUG
  262.     fprintf( stderr, "Device Configured:n");
  263.     fprintf( stderr, "         Sample Rate: %dn",  m_unSampleRate);
  264.     fprintf( stderr, "        Sample Width: %dn",  nSampleWidth);
  265.     fprintf( stderr, "        Num channels: %dn",  m_unNumChannels);
  266.     fprintf( stderr, "          Block size: %dn",  m_wBlockSize);
  267.     fprintf( stderr, "  Device buffer size: %lun", m_ulDeviceBufferSize);
  268.     fprintf( stderr, "  Supports GETOSPACE: %dn",  !m_bGetOSpaceFailed);
  269.     fprintf( stderr, "  Supports GETODELAY: %dn",  !m_bGetODelayFailed);
  270. #endif
  271.     return RA_AOE_NOERR;
  272. }
  273. void CAudioOutLinux::_SyncUpTimeStamps(ULONG32 lCount)
  274. {
  275.     int bytes2  = 0;
  276.     int theErr = -1;
  277.     if( m_bTestGetODelay || !m_bGetODelayFailed )
  278.     {
  279.         HX_ASSERT(m_nDevID );
  280.         theErr = ::ioctl(m_nDevID, SNDCTL_DSP_GETODELAY, &bytes2);
  281.     }
  282.     if( theErr != -1)
  283.     {
  284. if (m_bTestGetODelay && (bytes2 != 0))
  285. {
  286.     // We've now seen SNDCTL_DSP_GETODELAY return
  287.     // a non-zero value so we know it is working
  288.     m_bTestGetODelay = FALSE;
  289.             m_bGetODelayFailed = FALSE;
  290. }
  291. if (!m_bTestGetODelay)
  292. {
  293.     m_ulLastBytesPlayed = (UINT64)(m_ulTotalWritten+lCount-bytes2);
  294.     m_ulLastTimeStamp   = GetTickCount();
  295. }
  296.     }
  297.     else
  298.     {
  299.         //so we don't try it again.
  300.         m_bGetODelayFailed = TRUE;
  301. m_bTestGetODelay = FALSE;
  302.     }
  303. }
  304. //Device specific method to write bytes out to the audiodevice and return a
  305. //count of bytes written. 
  306. HX_RESULT CAudioOutLinux::_WriteBytes( UCHAR* buffer, ULONG32 ulBuffLength, LONG32& lCount )
  307. {
  308.     HX_RESULT retCode = RA_AOE_NOERR;
  309.     if( m_nDevID < 0 )
  310.     {
  311.         retCode = RA_AOE_DEVNOTOPEN;
  312.     }
  313.     else
  314.     {
  315.         if( m_ulTickCount == 0 )
  316.             m_ulTickCount = GetTickCount();
  317.         lCount = ::write( m_nDevID, buffer, ulBuffLength);
  318.         if( lCount < 0 )
  319.         {
  320.             //Error occurred.
  321.             if( errno == EAGAIN )
  322.                 retCode = RA_AOE_NOERR;
  323.             if( errno == EINTR )
  324.                 retCode = RA_AOE_DEVBUSY;
  325.         }
  326.         else
  327.         {
  328.             _SyncUpTimeStamps(lCount);
  329.         }
  330.     }
  331.     return retCode;
  332. }
  333. //Device specific methods to open/close the mixer and audio devices.
  334. HX_RESULT CAudioOutLinux::_OpenAudio()
  335. {
  336.     HX_RESULT retCode = RA_AOE_NOERR;
  337.     //Set the tick count to zero
  338.     m_ulTickCount       = 0;
  339.     m_ulLastTimeStamp   = 0;
  340.     m_ulLastBytesPlayed = 0;
  341.     m_ulPausePosition   = 0;
  342.     //Check the environmental variable to let user overide default device.
  343.     char *pszOverrideName = getenv( "AUDIO" ); /* Flawfinder: ignore */
  344.     char szDevName[MAX_DEV_NAME]; /* Flawfinder: ignore */
  345.     
  346.     // Use defaults if no environment variable is set.
  347.     if ( pszOverrideName && strlen(pszOverrideName)>0 )
  348.     {
  349.         SafeStrCpy( szDevName, pszOverrideName, MAX_DEV_NAME );
  350.     }
  351.     else
  352.     {
  353.         SafeStrCpy( szDevName, "/dev/dsp", MAX_DEV_NAME );
  354.     }
  355.     
  356.     // Open the audio device if it isn't already open
  357.     if ( m_nDevID < 0 )
  358.     {
  359.         m_nDevID = ::open( szDevName, O_WRONLY );
  360.     }
  361.     
  362.     if ( m_nDevID < 0 )
  363.     {
  364. #ifdef _DEBUG        
  365.         fprintf( stderr, "Failed to open audio(%s)!!!!!!! Code is: %d  errno: %dn",
  366.                  szDevName, m_nDevID, errno );
  367. #endif        
  368.         
  369.         //Error opening device.
  370.         retCode = RA_AOE_BADOPEN;
  371.     }
  372.     
  373.     m_wLastError = retCode;
  374.     return m_wLastError;
  375. }
  376. HX_RESULT CAudioOutLinux::_CloseAudio()
  377. {
  378.     HX_RESULT retCode = RA_AOE_NOERR;
  379.     
  380.     if( m_nDevID >= 0 )
  381.     {
  382.         ::close( m_nDevID );
  383.         m_nDevID = NO_FILE_DESCRIPTOR;
  384.     }
  385.     else
  386.     {
  387.         retCode = RA_AOE_DEVNOTOPEN;
  388.     }
  389.     m_wLastError = retCode;
  390.     return m_wLastError;
  391. }
  392. HX_RESULT CAudioOutLinux::_OpenMixer()
  393. {
  394.     HX_RESULT retCode = RA_AOE_NOERR;
  395.     if(!m_bMixerPresent)
  396.     {
  397.         //Let user override default device with environ variable.
  398.         char *pszOverrideName = getenv( "MIXER" ); /* Flawfinder: ignore */
  399.         char szDevCtlName[MAX_DEV_NAME]; /* Flawfinder: ignore */
  400.         
  401.         if (pszOverrideName && strlen(pszOverrideName)>0 )
  402. {
  403.             SafeStrCpy( szDevCtlName , pszOverrideName, MAX_DEV_NAME );
  404. }
  405.         else
  406. {
  407.             SafeStrCpy( szDevCtlName , "/dev/mixer", MAX_DEV_NAME ); // default for volume
  408. }
  409.         
  410.         m_nMixerID = ::open( szDevCtlName, O_RDWR );
  411.         
  412.         if (m_nMixerID > 0)
  413.         {
  414.             m_bMixerPresent = 1;
  415.             _Imp_GetVolume();
  416.         }
  417.         else
  418.         {
  419.             m_nMixerID = NO_FILE_DESCRIPTOR;
  420.             m_bMixerPresent = 0;
  421.         }
  422.     }
  423.     m_wLastError = retCode;
  424.     return m_wLastError;
  425. }
  426. HX_RESULT CAudioOutLinux::_CloseMixer()
  427. {
  428.     HX_RESULT retCode = RA_AOE_NOERR;
  429.     if( m_nMixerID >= 0 )
  430.     {
  431.         ::close( m_nMixerID );
  432.         m_nMixerID = NO_FILE_DESCRIPTOR;
  433.     }
  434.     
  435.     m_wLastError = retCode;
  436.     return m_wLastError;
  437. }
  438. //Device specific method to reset device and return it to a state that it 
  439. //can accept new sample rates, num channels, etc.
  440. HX_RESULT CAudioOutLinux::_Reset()
  441. {
  442.     HX_RESULT retCode = RA_AOE_NOERR;
  443.     m_ulPausePosition = 0;
  444.     
  445.     if ( m_nDevID < 0 )
  446.     {
  447.         retCode = RA_AOE_DEVNOTOPEN;
  448.     }
  449.     else if( ::ioctl (m_nDevID, SOUND_PCM_RESET, 0) == -1 )
  450.     {
  451.         retCode = RA_AOE_GENERAL;
  452.     }
  453.     m_wLastError = retCode;
  454.     return m_wLastError;
  455. }
  456. //Device specific method to get/set the devices current volume.
  457. UINT16 CAudioOutLinux::_GetVolume() const
  458. {
  459.     int nVolume      = 0;
  460.     int nRetVolume   = 0;
  461.     int nLeftVolume  = 0;
  462.     int nRightVolume = 0;
  463.     
  464.     if (::ioctl( m_nMixerID, MIXER_READ(HX_VOLUME), &nVolume) < 0)
  465.     {
  466.         nRetVolume = 0;
  467.     }
  468.     nLeftVolume  = (nVolume & 0x000000ff); 
  469.     nRightVolume = (nVolume & 0x0000ff00) >> 8;
  470.     //Which one to use? Average them?
  471.     nRetVolume = nLeftVolume ;
  472.     return nRetVolume; 
  473. }
  474. HX_RESULT CAudioOutLinux::_SetVolume(UINT16 unVolume)
  475. {
  476.     HX_RESULT retCode = RA_AOE_NOERR;
  477.     
  478.     int nNewVolume=0;
  479.     //Set both left and right volumes.
  480.     nNewVolume = (unVolume & 0xff) | ((unVolume &0xff) << 8);
  481.     
  482.     if (::ioctl( m_nMixerID, MIXER_WRITE(HX_VOLUME), &nNewVolume) < 0)
  483.     {
  484.         retCode = RA_AOE_NOTSUPPORTED;
  485.     }
  486.     m_wLastError = retCode;
  487.     return m_wLastError;
  488. }
  489. //Device specific method to drain a device. This should play the remaining
  490. //bytes in the devices buffer and then return.
  491. HX_RESULT CAudioOutLinux::_Drain()
  492. {
  493.     HX_RESULT retCode = RA_AOE_NOERR;
  494.     
  495.     if ( m_nDevID < 0 )
  496.     {
  497.         retCode = RA_AOE_DEVNOTOPEN;
  498.     }
  499.     else if( ::ioctl (m_nDevID, SNDCTL_DSP_SYNC, 0) == -1 )
  500.     {
  501.         retCode = RA_AOE_GENERAL;
  502.     }
  503.     m_wLastError = retCode;
  504.     return m_wLastError;
  505. }
  506. UINT64 CAudioOutLinux::_GetBytesActualyPlayed(void) const
  507. {
  508.     /* Get current playback position in device DMA. */
  509.     int     bytes2 = 0;
  510.     UINT64  ulTheAnswer = 0;
  511.     //What versions of the linux kernel do we want to support?
  512.     if( !m_bGetODelayFailed )
  513.     {
  514.         if( m_ulTotalWritten > 0 )
  515.         {
  516.             HX_ASSERT( m_unSampleRate!=0 && m_uSampFrameSize!=0 );
  517.             ULONG32 ulTick = GetTickCount();
  518.             //We need to update the timestamps every so often.
  519.             //This make sure that if the XServer was blocked, and
  520.             //we ran dry, that we re-sync up.
  521.             if( (ulTick-m_ulLastTimeStamp)>200 )
  522.             {
  523.                 ((CAudioOutLinux*)this)->_SyncUpTimeStamps();
  524.                 ulTick = GetTickCount();
  525.             }
  526.             
  527.             ulTheAnswer = (UINT64)(m_ulLastBytesPlayed+
  528.             ((float)(ulTick-m_ulLastTimeStamp)*
  529.              (float)m_unNumChannels/1000.0*
  530.              m_unSampleRate*m_uSampFrameSize) +0.5 );
  531.         }
  532.     }
  533.     else
  534.     {
  535.         //We will assume that the error is because of an incomplete 
  536.         //implementation of the oss compatible driver. So, just 
  537.         //fake it with time stamps.
  538.         if( m_ulTotalWritten > 0 )
  539.         {
  540.             ulTheAnswer = (UINT64)((float)(GetTickCount()-m_ulTickCount)*(float)m_unNumChannels/1000.0*m_unSampleRate*m_uSampFrameSize);
  541.             ulTheAnswer += m_ulPausePosition;
  542.         }
  543.     }
  544.     return  ulTheAnswer;
  545. }
  546. //this must return the number of bytes that can be written without blocking.
  547. //Don't use SNDCTL_DSP_GETODELAY here as it can't compute that amount
  548. //correctly.
  549. HX_RESULT CAudioOutLinux::_GetRoomOnDevice(ULONG32& ulBytes) const
  550. {
  551.     HX_RESULT      retCode = RA_AOE_NOERR;
  552.     audio_buf_info stBuffInfo;
  553.     int            theErr=0;
  554.     //What versions of the linux kernel do we want to support?
  555.     if( m_bGetOSpaceFailed )
  556.     {
  557.         theErr = -1;
  558.     }
  559.     else
  560.     {
  561.         theErr = ::ioctl(m_nDevID, SNDCTL_DSP_GETOSPACE, &stBuffInfo);
  562.     }
  563.     if ( theErr != -1 )
  564.     {
  565.         ulBytes = stBuffInfo.bytes;
  566.     }
  567.     else
  568.     {
  569.         //So we just try it once.
  570.         m_bGetOSpaceFailed = TRUE;
  571.         ulBytes = m_ulDeviceBufferSize-(m_ulTotalWritten-_GetBytesActualyPlayed() );
  572.     }
  573.     m_wLastError = retCode;
  574.     return m_wLastError;
  575. }
  576. HX_RESULT CAudioOutLinux::_CheckFormat( const HXAudioFormat* pFormat )
  577. {
  578.     int   nBitsPerSample = pFormat->uBitsPerSample;
  579.     int   ulTmp          = pFormat->ulSamplesPerSec;    
  580.     int   nNumChannels   = pFormat->uChannels;
  581.     float fTmp           = 0.0;
  582.     HX_RESULT retCode = RA_AOE_NOERR;
  583.     
  584.     //Is the device already open?
  585.     if( m_nDevID > 0 || RA_AOE_NOERR != _OpenAudio() )
  586.     {
  587.         retCode = RA_AOE_DEVBUSY;
  588.         return retCode;
  589.     }
  590.     //See if the sample rate is supported.
  591.     if (ioctl(m_nDevID, SOUND_PCM_WRITE_RATE, &ulTmp) == -1)
  592.     {
  593.         //Not quite the real error, but it is what we need to return.
  594.         retCode = RA_AOE_DEVBUSY;
  595.         goto donechecking;
  596.     }
  597.     if (ulTmp == 0)
  598.     {
  599. /* 
  600.  * Some drivers actually set the sample rate on the device, but
  601.  * return 0 for the sample rate. On these platforms we just ignore
  602.  * the return value and assume the sample rate is set to what was
  603.  * requested.
  604.  */
  605. ulTmp = pFormat->ulSamplesPerSec;
  606.     }
  607.     //The ESS 1688 Sound card (not the ESS Solo-1) will return sample
  608.     //rates that are close but not quite the ones we asked for (the
  609.     //ESS Solo-1 doesn't play mono). I have see freqs like 44194
  610.     //instead of 44100 (.2%) and 7984 instead of 8000 (.6%).
  611.     //So, if we are close enough just say it is OK. 
  612.     //How about 1%?
  613.     fTmp = (float)ulTmp/(float)pFormat->ulSamplesPerSec;
  614.     if( fabs(1.0-fTmp) > .01 )
  615.     {
  616.         //It is NOT supported
  617.         retCode = RA_AOE_BADFORMAT;
  618.         goto donechecking;
  619.     }
  620.     //Check num channels.
  621.     if (ioctl(m_nDevID, SOUND_PCM_WRITE_CHANNELS, &nNumChannels) == -1)
  622.     {
  623.         retCode = RA_AOE_DEVBUSY;
  624.         goto donechecking;
  625.     }
  626.     else if ( nNumChannels != pFormat->uChannels )
  627.     {
  628.         retCode = RA_AOE_BADFORMAT;
  629.         goto donechecking;
  630.     }
  631.     //Check the frame size.
  632.     if (ioctl(m_nDevID, SNDCTL_DSP_SETFMT, &nBitsPerSample) == -1)
  633.     {
  634.        retCode = RA_AOE_DEVBUSY;
  635.        goto donechecking;
  636.     }
  637.     else if ( nBitsPerSample != pFormat->uBitsPerSample )
  638.     {
  639.         retCode = RA_AOE_BADFORMAT;
  640.         goto donechecking;
  641.     }
  642.     //Close the audio device.
  643.   donechecking:
  644.     _CloseAudio();
  645.     m_wLastError = retCode;
  646.     return retCode;
  647. }
  648. HX_RESULT CAudioOutLinux::_CheckSampleRate( ULONG32 ulSampleRate )
  649. {
  650.     ULONG32 ulTmp = ulSampleRate;
  651.     m_wLastError = RA_AOE_NOERR;
  652.     
  653.     //Is the device already open?
  654.     if( m_nDevID > 0 || RA_AOE_NOERR != _OpenAudio() )
  655.     {
  656.         m_wLastError = RA_AOE_DEVBUSY;
  657.     }
  658.     else
  659.     {   
  660.         //See if the sample rate is supported.
  661.         if (ioctl(m_nDevID, SOUND_PCM_WRITE_RATE, &ulTmp) == -1)
  662.         {
  663.             //Not quite the real error, but it is what we need to return.
  664.             m_wLastError = RA_AOE_DEVBUSY;
  665.         }
  666.         else if( ulSampleRate != ulTmp )
  667.         {
  668.             //It is NOT supported
  669.             m_wLastError = RA_AOE_BADFORMAT;
  670.         }
  671.         
  672.         _CloseAudio();
  673.     }
  674.     
  675.     return m_wLastError;
  676. }
  677. HX_RESULT CAudioOutLinux::_Pause() 
  678. {
  679.     m_wLastError = HXR_OK;
  680.     m_ulPausePosition = m_ulTotalWritten;
  681.     m_ulTickCount = 0;
  682.     m_ulLastTimeStamp   = 0;
  683.     return m_wLastError;
  684. }
  685. HX_RESULT CAudioOutLinux::_Resume()
  686. {
  687.     m_wLastError = HXR_OK;
  688.     if( m_ulTotalWritten > 0 )
  689.     {
  690.         m_ulTickCount = GetTickCount();
  691.         m_ulLastTimeStamp = m_ulTickCount;
  692.     }
  693.     return m_wLastError;
  694. }