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

Symbian

开发平台:

Visual C++

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Source last modified: $Id: audhpux.cpp,v 1.3.42.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 "audhpux.h"
  50. #include "ihxpckts.h"
  51. #include "hxtick.h"
  52. #include "hxprefs.h"
  53. #include "hxstrutl.h"
  54. #include <unistd.h>
  55. #include <fcntl.h>
  56. #include <stdlib.h>
  57. #include <errno.h>
  58. #include <sys/ioctl.h>
  59. #include <stdio.h> 
  60. #include <math.h> 
  61. #include <sys/audio.h>
  62. #define MAX_DEV_NAME 256
  63. //------------------------------------------
  64. // Ctors and Dtors.
  65. //------------------------------------------
  66. CAudioOutHPUX::CAudioOutHPUX() :
  67.     CAudioOutUNIX(),
  68.     m_ulTickCount(0),
  69.     m_ulLastBytesPlayed(0),
  70.     m_ulLastTimeStamp(0),
  71.     m_ulPausePosition(0),
  72.     m_nDevID(NO_FILE_DESCRIPTOR),
  73.     m_nMixerID(NO_FILE_DESCRIPTOR),
  74.     m_bGetODelayFailed(FALSE),
  75.     m_bGetOSpaceFailed(FALSE),
  76.     m_nLastVolume(0),
  77.     m_nMinVolume(0),
  78.     m_nMaxVolume(0)
  79. {
  80. };
  81. CAudioOutHPUX::~CAudioOutHPUX()
  82. {
  83.     //The mixer is opened independently of the audio device. Make sure 
  84.     //it is celosed.
  85.   _CloseAudio();
  86. };
  87. //-------------------------------------------------------
  88. // These Device Specific methods must be implemented 
  89. // by the platform specific sub-classes.
  90. //-------------------------------------------------------
  91. INT16 CAudioOutHPUX::_Imp_GetAudioFd(void)
  92. {
  93.     return m_nDevID;
  94. }
  95. //Devic specific method to set the audio device characteristics. Sample rate,
  96. //bits-per-sample, etc.
  97. //Method *must* set member vars. m_unSampleRate and m_unNumChannels.
  98. HX_RESULT CAudioOutHPUX::_SetDeviceConfig( const HXAudioFormat* pFormat )
  99. {
  100.     if ( !pFormat )
  101.     {
  102.       pFormat = &m_lastFormat;
  103.     }
  104.     else
  105.       {
  106. m_lastFormat = *pFormat;
  107.       }
  108.     m_lastFormat = *pFormat;
  109.     if ( m_nDevID < 0 )
  110.         return RA_AOE_DEVNOTOPEN;
  111.     int nFragSize = 8192;
  112.     while (-1 != ioctl(m_nDevID, AUDIO_SET_TXBUFSIZE, nFragSize))
  113.     {
  114. nFragSize <<= 1;
  115.     }
  116.     ioctl(m_nDevID, AUDIO_GET_TXBUFSIZE, &m_ulDeviceBufferSize);
  117.     //Now set the format. Either 8-bit or 16-bit audio is supported.
  118.     int      nSampleWidth  = pFormat->uBitsPerSample;
  119.     ULONG32  nSampleRate   = pFormat->ulSamplesPerSec;
  120.     int      numChannels   = pFormat->uChannels;
  121.     int      nFormat1      = 0;
  122.     int      nFormat2      = 0;
  123.     
  124.     if( nSampleWidth == 16)
  125.     {
  126.         nFormat1 = nFormat2 = AUDIO_FORMAT_LINEAR16BIT;
  127.     }
  128.     else
  129.     {
  130.         nFormat1 = nFormat2 = AUDIO_FORMAT_LINEAR8BIT;
  131.     }
  132.     
  133.     if(ioctl(m_nDevID, AUDIO_SET_DATA_FORMAT, nFormat1) == -1)
  134.     {
  135.         return (  m_wLastError = RA_AOE_NOTENABLED );
  136.     }
  137.     m_uSampFrameSize = nSampleWidth/8;
  138.     if ( nSampleWidth != pFormat->uBitsPerSample )
  139.     {
  140.         ((HXAudioFormat*)pFormat)->uBitsPerSample = nSampleWidth;
  141.     }
  142.     //Set number of channels. Stereo or mono.
  143.     if (ioctl(m_nDevID, AUDIO_SET_CHANNELS, numChannels) == -1)
  144.     {
  145.         return ( m_wLastError = RA_AOE_NOTENABLED );
  146.     }
  147.     m_unNumChannels = numChannels;
  148.     if ( numChannels != pFormat->uChannels )
  149.     {
  150.         ((HXAudioFormat*)pFormat)->uChannels = numChannels;
  151.     }
  152.     //Set the sample rate.
  153.     if (ioctl(m_nDevID, AUDIO_SET_SAMPLE_RATE, nSampleRate) == -1)
  154.     {
  155.         return ( m_wLastError = RA_AOE_NOTENABLED );
  156.     }
  157.     m_unSampleRate = nSampleRate;
  158.     if ( nSampleRate != pFormat->ulSamplesPerSec )
  159.     {
  160.         ((HXAudioFormat*)pFormat)->ulSamplesPerSec = nSampleRate;
  161.     }
  162. #ifdef _DEBUG
  163.     fprintf( stderr, "Device Configured:n");
  164.     fprintf( stderr, "         Sample Rate: %dn",  m_unSampleRate);
  165.     fprintf( stderr, "        Sample Width: %dn",  nSampleWidth);
  166.     fprintf( stderr, "        Num channels: %dn",  m_unNumChannels);
  167.     fprintf( stderr, "          Block size: %dn",  m_wBlockSize);
  168.     fprintf( stderr, "  Device buffer size: %lun", m_ulDeviceBufferSize);
  169.     fprintf( stderr, " Support for old OSS: %dn",  m_bGetOSpaceFailed);
  170. #endif
  171.     return RA_AOE_NOERR;
  172. }
  173. void CAudioOutHPUX::_SyncUpTimeStamps(ULONG32 lCount)
  174. {
  175.     int bytes2  = 0;
  176.     int theErr = -1;
  177.     audio_status astatus;
  178.     if( !m_bGetODelayFailed )
  179.     {
  180. theErr = ::ioctl(m_nDevID, AUDIO_GET_STATUS, &astatus);
  181.     }
  182.     if( theErr != -1)
  183.     {
  184.         m_ulLastBytesPlayed = (ULONG32)(m_ulTotalWritten+lCount-astatus.transmit_buffer_count);
  185.         m_ulLastTimeStamp   = GetTickCount();
  186.     }
  187.     else
  188.     {
  189.         //so we don't try it again.
  190.         m_bGetODelayFailed = TRUE;
  191.     }
  192. }
  193. //Device specific method to write bytes out to the audiodevice and return a
  194. //count of bytes written. 
  195. HX_RESULT CAudioOutHPUX::_WriteBytes( UCHAR* buffer, ULONG32 ulBuffLength, LONG32& lCount )
  196. {
  197.     HX_RESULT retCode = RA_AOE_NOERR;
  198.     if( m_nDevID < 0 )
  199.     {
  200.         retCode = RA_AOE_DEVNOTOPEN;
  201.     }
  202.     else
  203.     {
  204.         if( m_ulTickCount == 0 )
  205.             m_ulTickCount = GetTickCount();
  206.         lCount = ::write( m_nDevID, buffer, ulBuffLength);
  207.         if( lCount < 0 )
  208.         {
  209.             //Error occurred.
  210.             if( errno == EAGAIN )
  211.                 retCode = RA_AOE_NOERR;
  212.             if( errno == EINTR )
  213.                 retCode = RA_AOE_DEVBUSY;
  214.         }
  215.         else
  216.         {
  217.             _SyncUpTimeStamps(lCount);
  218.         }
  219.     }
  220.     return retCode;
  221. }
  222. //Device specific methods to open/close the mixer and audio devices.
  223. HX_RESULT CAudioOutHPUX::_OpenAudio()
  224. {
  225.     HX_RESULT retCode = RA_AOE_NOERR;
  226.     // Open the audio device if it isn't already open
  227.     if ( -1 == m_nDevID )
  228.     {
  229. //Check the environmental variable to let user overide default device.
  230. char *pszOverrideName = getenv( "AUDIO" ); /* Flawfinder: ignore */
  231. char szDevName[MAX_DEV_NAME]; /* Flawfinder: ignore */
  232. // Use defaults if no environment variable is set.
  233. if ( pszOverrideName && strlen(pszOverrideName)>0 )
  234. {
  235.     SafeStrCpy( szDevName, pszOverrideName, MAX_DEV_NAME );
  236. }
  237. else
  238. {
  239.     SafeStrCpy( szDevName, "/dev/audio", MAX_DEV_NAME );
  240. }
  241. //Set the tick count to zero
  242. m_ulTickCount       = 0;
  243. m_ulLastTimeStamp   = 0;
  244. m_ulLastBytesPlayed = 0;
  245. m_ulPausePosition   = 0;
  246.         m_nDevID = ::open( szDevName, O_WRONLY );
  247.     }
  248.     
  249.     if ( m_nDevID < 0 )
  250.     {
  251. #ifdef _DEBUG        
  252.         fprintf( stderr, "Failed to open audio!!!!!!! Code is: %d  errno: %dn",
  253.                  m_nDevID, errno );
  254. #endif        
  255.         
  256.         //Error opening device.
  257.         retCode = RA_AOE_BADOPEN;
  258.     }
  259.     
  260.     m_wLastError = retCode;
  261.     return m_wLastError;
  262. }
  263. HX_RESULT CAudioOutHPUX::_CloseAudio()
  264. {
  265.     HX_RESULT retCode = RA_AOE_NOERR;
  266.     
  267.     if( m_nDevID >= 0 )
  268.     {
  269.         ::close( m_nDevID );
  270.         m_nDevID = NO_FILE_DESCRIPTOR;
  271.     }
  272.     else
  273.     {
  274.         retCode = RA_AOE_DEVNOTOPEN;
  275.     }
  276.     m_wLastError = retCode;
  277.     return m_wLastError;
  278. }
  279. HX_RESULT CAudioOutHPUX::_OpenMixer()
  280. {
  281.     if (-1 == m_nDevID)
  282. _OpenAudio(); // control the level through the audio device
  283.     // get and store the current volume
  284.     struct audio_describe adescribe;
  285.     if (-1 != ioctl(m_nDevID, AUDIO_DESCRIBE, &adescribe)) {
  286. m_nMinVolume = adescribe.min_transmit_gain;
  287. m_nMaxVolume = adescribe.max_transmit_gain;
  288.     }
  289.     
  290.     struct audio_gain gainsettings;
  291.     if (-1 != ioctl(m_nDevID, AUDIO_GET_GAINS, &gainsettings))
  292.     {
  293. m_nLastVolume = (gainsettings.cgain[0].transmit_gain - 
  294.  m_nMinVolume) * 100 / 
  295.     (m_nMaxVolume - m_nMinVolume);
  296.     }
  297.     
  298.     m_bMixerPresent=TRUE;
  299.     
  300.     return RA_AOE_NOERR;
  301. }
  302. HX_RESULT CAudioOutHPUX::_CloseMixer()
  303. {
  304.     HX_RESULT retCode = RA_AOE_NOERR;
  305.     m_wLastError = retCode;
  306.     m_bMixerPresent = FALSE;
  307.     return m_wLastError;
  308. }
  309. //Device specific method to reset device and return it to a state that it 
  310. //can accept new sample rates, num channels, etc.
  311. HX_RESULT CAudioOutHPUX::_Reset()
  312. {
  313.     ioctl(m_nDevID, AUDIO_RESET, RESET_TX_BUF);
  314.   
  315.     _CloseAudio();
  316.     UINT32 ulTickCount = m_ulTickCount;
  317.     UINT32 ulLastTimeStamp = m_ulLastTimeStamp;
  318.     UINT32 ulLastBytesPlayed = m_ulLastBytesPlayed;
  319.     UINT32 ulPausePosition = m_ulPausePosition;
  320.     _OpenAudio();
  321.     m_ulTickCount = ulTickCount;
  322.     m_ulLastTimeStamp = ulLastTimeStamp;
  323.     m_ulLastBytesPlayed = ulLastBytesPlayed;
  324.     m_ulPausePosition = ulPausePosition;
  325.     _SetDeviceConfig(NULL);
  326.     m_ulPausePosition = 0;
  327.     HX_RESULT retCode = RA_AOE_NOERR;
  328.     m_wLastError = retCode;
  329.     
  330.     // verify that this worked
  331.     audio_status astatus;
  332.     ioctl(m_nDevID, AUDIO_GET_STATUS, &astatus);
  333.     
  334.     return m_wLastError;
  335. }
  336. //Device specific method to get/set the devices current volume.
  337. UINT16 CAudioOutHPUX::_GetVolume() const
  338. {
  339.     _OpenMixer();
  340.     
  341.     return m_nLastVolume; 
  342. }
  343. HX_RESULT CAudioOutHPUX::_SetVolume(UINT16 unVolume)
  344. {
  345.     m_nLastVolume = unVolume;
  346.     HX_RESULT retCode = RA_AOE_NOERR;
  347.     struct audio_gain gainsettings;
  348.     memset(&gainsettings, 0, sizeof(audio_gain));
  349.     gainsettings.channel_mask = AUDIO_CHANNEL_LEFT | AUDIO_CHANNEL_RIGHT;
  350.     gainsettings.cgain[0].transmit_gain = (INT32)unVolume * (m_nMaxVolume - m_nMinVolume) / 100 + m_nMinVolume;
  351.     gainsettings.cgain[1].transmit_gain = (INT32)unVolume * (m_nMaxVolume - m_nMinVolume) / 100 + m_nMinVolume;
  352.     
  353.     if (::ioctl( m_nDevID, AUDIO_SET_GAINS, &gainsettings) < 0)
  354.       {
  355.    retCode = RA_AOE_NOTENABLED;
  356.       }
  357.     m_wLastError = retCode;
  358.     return m_wLastError;
  359. }
  360. //Device specific method to drain a device. This should play the remaining
  361. //bytes in the devices buffer and then return.
  362. HX_RESULT CAudioOutHPUX::_Drain()
  363. {
  364.     HX_RESULT retCode = RA_AOE_NOERR;
  365.     
  366.     m_wLastError = retCode;
  367.     return m_wLastError;
  368. }
  369. ULONG32 CAudioOutHPUX::_GetBytesActualyPlayed(void) const
  370. {
  371.     /* Get current playback position in device DMA. */
  372.     int     bytes2 = 0;
  373.     ULONG32 ulTheAnswer = 0;
  374.     //What versions of the linux kernel do we want to support?
  375.     if( !m_bGetODelayFailed )
  376.     {
  377.         if( m_ulTotalWritten > 0 )
  378.         {
  379.             HX_ASSERT( m_unSampleRate!=0 && m_uSampFrameSize!=0 );
  380.             ULONG32 ulTick = GetTickCount();
  381.             //We need to update the timestamps every so often.
  382.             //This make sure that if the XServer was blocked, and
  383.             //we ran dry, that we re-sync up.
  384.             if( (ulTick-m_ulLastTimeStamp)>200 )
  385.             {
  386.                 ((CAudioOutHPUX*)this)->_SyncUpTimeStamps(); // ug... constness of method prohibits this call somtimes
  387.                 ulTick = GetTickCount();
  388.             }
  389.             
  390.             ulTheAnswer = (ULONG32)(m_ulLastBytesPlayed+
  391.             ((float)(ulTick-m_ulLastTimeStamp)*
  392.              (float)m_unNumChannels/1000.0*
  393.              m_unSampleRate*m_uSampFrameSize) +0.5 );
  394.         }
  395.     }
  396.     else
  397.     {
  398.         //We will assume that the error is because of an incomplete 
  399.         //implementation of the oss compatible driver. So, just 
  400.         //fake it with time stamps.
  401.         if( m_ulTotalWritten > 0 )
  402.         {
  403.             ulTheAnswer = (ULONG32)((float)(GetTickCount()-m_ulTickCount)*(float)m_unNumChannels/1000.0*m_unSampleRate*m_uSampFrameSize);
  404.             ulTheAnswer += m_ulPausePosition;
  405.         }
  406.     }
  407.     return  ulTheAnswer;
  408. }
  409. //this must return the number of bytes that can be written without blocking.
  410. //Don't use SNDCTL_DSP_GETODELAY here as it can't compute that amount
  411. //correctly.
  412. HX_RESULT CAudioOutHPUX::_GetRoomOnDevice(ULONG32& ulBytes) const
  413. {
  414.     audio_status astatus;
  415.     int theErr;
  416.     
  417.     theErr = ioctl(m_nDevID, AUDIO_GET_STATUS, &astatus);
  418.     
  419.     if( theErr != -1)
  420.     {
  421. ulBytes = m_ulDeviceBufferSize - astatus.transmit_buffer_count;
  422.     }
  423.     return RA_AOE_NOERR;
  424. }
  425. HX_RESULT CAudioOutHPUX::_CheckFormat( const HXAudioFormat* pFormat )
  426. {
  427.     return RA_AOE_NOERR;
  428. }
  429. HX_RESULT CAudioOutHPUX::_CheckSampleRate( ULONG32 ulSampleRate )
  430. {
  431.     return m_wLastError = RA_AOE_NOERR;
  432. }
  433. HX_RESULT CAudioOutHPUX::_Pause() 
  434. {
  435.   //  ioctl(m_nDevID, AUDIO_PAUSE, AUDIO_TRANSMIT);
  436.   
  437.     m_wLastError = HXR_OK;
  438.       m_ulPausePosition = m_ulTotalWritten;
  439.       m_ulTickCount = 0;
  440.       m_ulLastTimeStamp   = 0;
  441.     return m_wLastError;
  442. }
  443. HX_RESULT CAudioOutHPUX::_Resume()
  444. {
  445.   //  ioctl(m_nDevID, AUDIO_RESUME, AUDIO_TRANSMIT);
  446.     m_wLastError = HXR_OK;
  447.     
  448.     if( m_ulTotalWritten > 0 )
  449.     {
  450. m_ulTickCount = GetTickCount();
  451. m_ulLastTimeStamp = m_ulTickCount;
  452.     }
  453.     return m_wLastError;
  454. }