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

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