audlinux_oss.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:21k
源码类别:

Symbian

开发平台:

C/C++

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