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

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. //===================================================================================
  36. // 
  37. //    audESound.cpp
  38. // 
  39. //    CLASS: CAudioOutESound
  40. // 
  41. //    Implements the sound subsystem for the Enlightenment Sound
  42. //      Deamon.
  43. //
  44. //===================================================================================
  45. #include <unistd.h>
  46. #include <fcntl.h>
  47. #include <stdlib.h>
  48. #include <errno.h>
  49. #include <sys/ioctl.h>
  50. #include <stdio.h> 
  51. #include <dlfcn.h>
  52. #include "audlinux_esound.h"
  53. #include "ihxpckts.h"
  54. #include "hxtick.h"
  55. //------------------------------------------
  56. // Ctors and Dtors.
  57. //------------------------------------------
  58. CAudioOutESound::CAudioOutESound() :
  59.     CAudioOutUNIX(),
  60.     m_nDevID(NO_FILE_DESCRIPTOR),
  61.     m_nESoundServerID(NO_FILE_DESCRIPTOR),
  62.     m_nESoundPlayerID(NO_FILE_DESCRIPTOR),
  63.     m_ulTickCount(0),
  64.     m_ulPausePosition(0),
  65.     m_strRealplayerName(""),
  66.     m_pESDLib(NULL),
  67.     m_fpESDPlayStream(NULL),
  68.     m_fpESDGetAllInfo(NULL),
  69.     m_fpESDFreeAllInfo(NULL),
  70.     m_fpESDClose(NULL),
  71.     m_fpESDSetStreamPan(NULL),
  72.     m_fpESDAudioFlush(NULL),
  73.     m_fpESDOpenSound(NULL)
  74. {
  75.     //Construct a proccess specific name to register with ESD.
  76.     m_strRealplayerName.Format( "%s-%d", "realplayer", getpid() );
  77. };
  78. CAudioOutESound::~CAudioOutESound()
  79. {
  80.     HX_DELETE( m_pESDLib );
  81. };
  82. //-------------------------------------------------------
  83. // These Device Specific methods must be implemented 
  84. // by the platform specific sub-classes.
  85. //-------------------------------------------------------
  86. INT16 CAudioOutESound::_Imp_GetAudioFd(void)
  87. {
  88.     return m_nDevID;
  89. }
  90. //Devic specific method to set the audio device characteristics. Sample rate,
  91. //bits-per-sample, etc.
  92. //Method *must* set member vars. m_unSampleRate and m_unNumChannels.
  93. HX_RESULT CAudioOutESound::_SetDeviceConfig( const HXAudioFormat* pFormat )
  94. {
  95.     if ( m_nESoundServerID < 0 )
  96.         return RA_AOE_DEVNOTOPEN;
  97.     //We can only do this once after opening the audio device.
  98.     if( m_nDevID != NO_FILE_DESCRIPTOR )
  99.         return RA_AOE_DEVBUSY;
  100.     
  101.     // Open the audio device if it isn't already open
  102.     esd_format_t format = ESD_STREAM | ESD_PLAY;
  103.     //Set steareo or mono
  104.     if( 2 == pFormat->uChannels )
  105.     {
  106.         format |= ESD_STEREO;
  107.     }
  108.     else
  109.     {
  110.         format |= ESD_MONO;
  111.     }
  112.     
  113.     //Now set the format. Either 8-bit or 16-bit audio is supported.
  114.     if( pFormat->uBitsPerSample == 16)
  115.     {
  116.         format |= ESD_BITS16;
  117.     }
  118.     else
  119.     {
  120.         format |= ESD_BITS8;
  121.     }
  122.     //Now open our connection with ESD on the local host.
  123.     m_nDevID = m_fpESDPlayStream( format, pFormat->ulSamplesPerSec, NULL, (const char *)m_strRealplayerName);
  124.     
  125.     if ( m_nDevID < 0 )
  126.     {
  127. #ifdef _DEBUG        
  128.         fprintf( stderr, "Failed to open audio!!!!!!! Code is: %d  errno: %dn",
  129.                  m_nDevID, errno );
  130. #endif        
  131.         
  132.         //Error opening device.
  133.         return RA_AOE_DEVNOTOPEN;
  134.     }
  135.     m_wBlockSize         = m_ulBytesPerGran;
  136.     m_unNumChannels      = pFormat->uChannels;
  137.     m_unSampleRate       = pFormat->ulSamplesPerSec;
  138.     m_ulDeviceBufferSize = ESD_BUF_SIZE*4;
  139.     m_uSampFrameSize     = pFormat->uBitsPerSample/8;
  140.     //Now, here is the tricky part. We must get a list of players from
  141.     //the esd deamon and interate through them until we find our self.
  142.     //Was we find us we need to store the ID for later use in setting
  143.     //the volume (panning).
  144.     //n
  145.     // From esd.h:
  146.     //
  147.     //      typedef struct esd_info {
  148.     //        
  149.     //          esd_server_info_t *server;
  150.     //          esd_player_info_t *player_list;
  151.     //          esd_sample_info_t *sample_list;
  152.     //
  153.     //      } esd_info_t;
  154.     //
  155.     //  typedef struct esd_player_info {
  156.     //      struct esd_player_info *next; /* point to next entry in list */
  157.     //      esd_server_info_t *server; /* the server that contains this stream */
  158.     //      int source_id; /* either a stream fd or sample id */
  159.     //      char name[ ESD_NAME_MAX ]; /* name of stream for remote control */
  160.     //      int rate; /* sample rate */
  161.     //      int left_vol_scale; /* volume scaling */
  162.     //      int right_vol_scale;
  163.     //      esd_format_t format; /* magic int with the format info */
  164.     //  } esd_player_info_t;
  165.     esd_player_info_t *pPlayerInfo = _GetPlayerInfo();
  166.     if( NULL == pPlayerInfo )
  167.     {
  168.         return RA_AOE_GENERAL;
  169.     }
  170.     m_nESoundPlayerID = pPlayerInfo->source_id;
  171.     HX_DELETE( pPlayerInfo );
  172.     if( m_nESoundPlayerID == NO_FILE_DESCRIPTOR )
  173.     {
  174. #ifdef _DEBUG        
  175.         fprintf( stderr, "Can't find the realaudio stream in the ESD server list.n");
  176. #endif
  177.         return RA_AOE_GENERAL;
  178.     }
  179. #ifdef _DEBUG
  180.     fprintf( stderr, "Device Configured:n");
  181.     fprintf( stderr, "        Sample Rate: %dn", m_unSampleRate);
  182.     fprintf( stderr, "       Sample Width: %dn", m_uSampFrameSize);
  183.     fprintf( stderr, "       Num channels: %dn", m_unNumChannels);
  184.     fprintf( stderr, "         Block size: %dn", m_wBlockSize);
  185.     fprintf( stderr, "  Device buffer size: %lun", m_ulDeviceBufferSize);
  186. #endif
  187.     return RA_AOE_NOERR;
  188. }
  189. //FREE THE RETURNED POINTER!!!!!!!!!!!!!!!
  190. esd_player_info_t* CAudioOutESound::_GetPlayerInfo() const
  191. {
  192.     
  193.     esd_info_t       *pServerInfo  = NULL;
  194.     esd_player_info_t *pPlayerInfo = NULL;
  195.     esd_player_info_t *pRetVal     = NULL;
  196.     pServerInfo = m_fpESDGetAllInfo(m_nESoundServerID);
  197.     if( pServerInfo == NULL )
  198.     {
  199. #ifdef _DEBUG        
  200.         fprintf( stderr, "Can't get server info from ESD.n");
  201. #endif
  202.         return NULL;
  203.     }
  204.     if( pServerInfo->player_list == NULL )
  205.     {
  206. #ifdef _DEBUG        
  207.         fprintf( stderr, "There seem to be no players connected to esd server.n");
  208. #endif
  209.         m_fpESDFreeAllInfo( pServerInfo );
  210.         return NULL;
  211.     }
  212.     pPlayerInfo = pServerInfo->player_list;
  213.     while( pPlayerInfo )
  214.     {
  215.         if( strcmp( pPlayerInfo->name, (const char *)m_strRealplayerName ) == 0 )
  216.         {
  217.             //found it.
  218.             break;
  219.         }
  220.         pPlayerInfo = pPlayerInfo->next;
  221.     }
  222.     //We found it. Make a new one and copy.
  223.     pRetVal = new esd_player_info_t(*pPlayerInfo);
  224.     if( NULL == pRetVal )
  225.     {
  226.         //OOps.
  227.         return NULL;
  228.     }
  229.     
  230.     pRetVal->next    = NULL; //Don't even think about it.
  231.     pRetVal->server  = NULL;
  232. //      pRetVal->source_id = pPlayerInfo->source_id;
  233. //      strcpy(pRetVal->name, pPlayerInfo->name );
  234. //      pRetVal->rate = pPlayerInfo->rate;
  235. //      pRetVal->left_vol_scale = pPlayerInfo->left_vol_scale;
  236. //      pRetVal->right_vol_scale = pPlayerInfo->right_vol_scale
  237. //      pRetVal->format = pPlayerInfo->format;
  238.     
  239.     //Free the info struct.
  240.     m_fpESDFreeAllInfo( pServerInfo );
  241.     return pRetVal;
  242. }
  243. //Device specific method to write bytes out to the audiodevice and return a
  244. //count of bytes written. 
  245. HX_RESULT CAudioOutESound::_WriteBytes( UCHAR* buffer, ULONG32 ulBuffLength, LONG32& lCount )
  246. {
  247.     
  248.     HX_RESULT retCode = RA_AOE_NOERR;
  249.     if( m_nDevID < 0 )
  250.     {
  251.         retCode = RA_AOE_DEVNOTOPEN;
  252.     }
  253.     else
  254.     {
  255.         if( m_ulTickCount == 0 )
  256.             m_ulTickCount = GetTickCount();
  257.         
  258.         lCount = ::write( m_nDevID, buffer, ulBuffLength);
  259.         
  260.         if( lCount < 0 )
  261.         {
  262.             //Error occurred.
  263.             if( errno == EAGAIN )
  264.                 retCode = RA_AOE_NOERR;
  265.             if( errno == EINTR )
  266.                 retCode = RA_AOE_DEVBUSY;
  267.         }
  268.         
  269.     }
  270.     return retCode;
  271. }
  272. //XXXgfw, since we have to open the audio device in ESD with
  273. //all the format information (no way to change it once open)
  274. //we will just return OK here and do the actual open in 
  275. //SetDeviceConfig() call. In this call we will just open
  276. //our connectin to the ESD server that we use for changing
  277. //the volume of our stream (panning).
  278. HX_RESULT CAudioOutESound::_OpenAudio()
  279. {
  280.     
  281.     HX_RESULT retCode = RA_AOE_NOERR;
  282.     
  283.     //Set the tick count to zero
  284.     m_ulTickCount = 0;
  285.     m_ulPausePosition = 0;
  286.     // create DLLAccess object
  287.     m_pESDLib = new DLLAccess();
  288.     if((DLLAccess::DLL_OK==m_pESDLib->open("libesd.so", DLLTYPE_NOT_DEFINED))||
  289.        (DLLAccess::DLL_OK==m_pESDLib->open("libesd.so.0", DLLTYPE_NOT_DEFINED)))
  290.     {
  291.         m_fpESDPlayStream = (ESDPlayStreamType)m_pESDLib->getSymbol("esd_play_stream");
  292.         if( dlerror() != NULL )
  293.             retCode = RA_AOE_DEVNOTOPEN;
  294.         m_fpESDGetAllInfo = (ESDGetAllInfoType)m_pESDLib->getSymbol("esd_get_all_info");
  295.         if( dlerror() != NULL )
  296.             retCode = RA_AOE_DEVNOTOPEN;
  297.         m_fpESDFreeAllInfo = (ESDFreeAllInfoType)m_pESDLib->getSymbol("esd_free_all_info");
  298.         if( dlerror() != NULL )
  299.             retCode = RA_AOE_DEVNOTOPEN;
  300.         m_fpESDClose = (ESDCloseType)m_pESDLib->getSymbol("esd_close");
  301.         if( dlerror() != NULL )
  302.             retCode = RA_AOE_DEVNOTOPEN;
  303.         m_fpESDSetStreamPan = (ESDSetStreamPanType)m_pESDLib->getSymbol("esd_set_stream_pan");
  304.         if( dlerror() != NULL )
  305.             retCode = RA_AOE_DEVNOTOPEN;
  306.         m_fpESDAudioFlush = (ESDAudioFlushType)m_pESDLib->getSymbol("esd_audio_flush");
  307.         if( dlerror() != NULL )
  308.             retCode = RA_AOE_DEVNOTOPEN;
  309.         m_fpESDOpenSound = (ESDOpenSoundType)m_pESDLib->getSymbol("esd_open_sound");
  310.         if( dlerror() != NULL )
  311.             retCode = RA_AOE_DEVNOTOPEN;
  312.     }
  313.     else
  314.     {
  315. #ifdef _DEBUG        
  316.         //Can't load the ESD shared lib. Tell the user.
  317.         fprintf( stderr, "The ESD library, libesd.so, could not be loaded.n");
  318.         fprintf( stderr, "Please install ESD, disable ESD support or locaten" );
  319.         fprintf( stderr, "the missing library.n");
  320. #endif
  321.         retCode = RA_AOE_DEVNOTOPEN;
  322.     }
  323.     
  324.     //Open the ESD server on the localhost.
  325.     if( RA_AOE_NOERR == retCode )
  326.     {
  327.         m_nESoundServerID = m_fpESDOpenSound( NULL );
  328.         if( m_nESoundServerID == -1 )
  329.         {
  330. #ifdef _DEBUG        
  331.             fprintf( stderr, "The ESD server could not be located on localhost.n");
  332.             fprintf( stderr, "Either disable ESD support or start the esd daemon.n");
  333. #endif        
  334.             retCode = RA_AOE_DEVNOTOPEN;
  335.         }
  336.     }
  337.     
  338.     m_wLastError = retCode;
  339.     return m_wLastError;
  340. }
  341. HX_RESULT CAudioOutESound::_CloseAudio()
  342. {
  343.     HX_RESULT retCode = RA_AOE_NOERR;
  344.     
  345.     if( m_nDevID >= 0 )
  346.     {
  347.         //close the esd server
  348.         m_fpESDClose( m_nESoundServerID );
  349.         m_nESoundServerID = NO_FILE_DESCRIPTOR;
  350.         //Close the esd player FD.
  351.         ::close( m_nDevID );
  352.         m_nDevID = NO_FILE_DESCRIPTOR;
  353.     }
  354.     else
  355.     {
  356.         retCode = RA_AOE_DEVNOTOPEN;
  357.     }
  358.     m_ulPausePosition = 0;
  359.     m_ulTickCount     = 0;
  360.     
  361.     m_wLastError = retCode;
  362.     return m_wLastError;
  363. }
  364. HX_RESULT CAudioOutESound::_OpenMixer()
  365. {
  366.     HX_RESULT retCode = RA_AOE_NOERR;
  367.     //ESD always has volume support.
  368.     m_bMixerPresent = 1;
  369.     _Imp_GetVolume();
  370.     
  371.     m_wLastError = retCode;
  372.     return m_wLastError;
  373. }
  374. //Do nothing under ESD.
  375. HX_RESULT CAudioOutESound::_CloseMixer()
  376. {
  377.     HX_RESULT retCode = RA_AOE_NOERR;
  378.     
  379.     m_wLastError = retCode;
  380.     return m_wLastError;
  381. }
  382. //Device specific method to reset device and return it to a state that it 
  383. //can accept new sample rates, num channels, etc.
  384. //Can't really do anything here under ESD.
  385. HX_RESULT CAudioOutESound::_Reset()
  386. {
  387.     HX_RESULT retCode = RA_AOE_NOERR;
  388.     if ( m_nDevID < 0 )
  389.     {
  390.         retCode = RA_AOE_DEVNOTOPEN;
  391.     }
  392.     m_ulPausePosition = 0;
  393.     
  394.     m_wLastError = retCode;
  395.     return m_wLastError;
  396. }
  397. //Device specific method to get/set the devices current volume.
  398. UINT16 CAudioOutESound::_GetVolume() const
  399. {
  400.     int nRetVolume   = 0;
  401.     if( m_nESoundPlayerID > 0 )
  402.     {
  403.         //We have been added to the esd server list and can report
  404.         //volume.
  405.         esd_player_info_t *pPlayer = _GetPlayerInfo();
  406.         if( NULL != pPlayer )
  407.         {
  408.             //Choose either the left or right?
  409.             nRetVolume = pPlayer->left_vol_scale;
  410.             HX_DELETE( pPlayer );
  411.         }
  412.     }
  413.     else
  414.     {
  415.         //ESD always starts out an app at 256. ESD_VOLUME_BASE.
  416.         nRetVolume = ESD_VOLUME_BASE;
  417.     }
  418.     //Map device specific volume levels to [0,100]. 
  419.     nRetVolume = (int) ((float)nRetVolume/256.0*100.0+0.5);
  420.     return nRetVolume; 
  421. }
  422. HX_RESULT CAudioOutESound::_SetVolume(UINT16 unVolume)
  423. {
  424.     HX_RESULT retCode = RA_AOE_NOERR;
  425.     //Map incoming [0..100] volume to ESD_VOLUME_BASE.
  426.     unVolume = (int)((float)unVolume/100.0 * (float)ESD_VOLUME_BASE + 0.5 );
  427.     if( m_nESoundPlayerID > 0 )
  428.     {
  429.         //We have been added to the esd server list and can set
  430.         //volumes.
  431.         m_fpESDSetStreamPan( m_nESoundServerID, m_nESoundPlayerID, unVolume, unVolume);
  432.     }
  433.     else
  434.     {
  435.         //Just do nothing here for now....
  436.     }
  437.     m_wLastError = retCode;
  438.     return m_wLastError;
  439. }
  440. //Device specific method to drain a device. This should play the remaining
  441. //bytes in the devices buffer and then return.
  442. HX_RESULT CAudioOutESound::_Drain()
  443. {
  444.     HX_RESULT retCode = RA_AOE_NOERR;
  445.     
  446.     if ( m_nDevID < 0 )
  447.     {
  448.         retCode = RA_AOE_DEVNOTOPEN;
  449.     }
  450.     m_fpESDAudioFlush();
  451.     
  452.     m_wLastError = retCode;
  453.     return m_wLastError;
  454. }
  455. UINT64 CAudioOutESound::_GetBytesActualyPlayed(void) const
  456. {
  457.     UINT64 ulBytes2 = 0;
  458.     if( m_ulTotalWritten > 0 )
  459.     {
  460.         ulBytes2 = ((double)((GetTickCount()-m_ulTickCount)*m_unNumChannels)/(double)1000*m_unSampleRate*m_uSampFrameSize);
  461.         ulBytes2 += m_ulPausePosition;
  462.     }
  463.     return  ulBytes2;
  464. }
  465. //this must return the number of bytes that can be written without blocking.
  466. //Don't use SNDCTL_DSP_GETODELAY here as it can't compute that amount
  467. //correctly.
  468. HX_RESULT CAudioOutESound::_GetRoomOnDevice(ULONG32& ulBytes) const
  469. {
  470.     HX_RESULT retCode     = RA_AOE_NOERR;
  471.     //XXXgfw :-( This is going to suck if they don't use threads...
  472.     ulBytes = m_wBlockSize;
  473. //    ulBytes = m_ulDeviceBufferSize-(m_ulTotalWritten-_GetBytesActualyPlayed() );
  474.     m_wLastError = retCode;
  475.     return m_wLastError;
  476. }
  477. HX_RESULT CAudioOutESound::_CheckFormat( const HXAudioFormat* pFormat )
  478. {
  479.     m_wLastError = RA_AOE_NOERR;
  480.     return m_wLastError;
  481. }
  482. HX_RESULT CAudioOutESound::_CheckSampleRate( ULONG32 ulSampleRate )
  483. {
  484.     //ESD supposidly converts any format to one the matches the 
  485.     //installed hardware the best. ESD does the conversion for
  486.     //us. So, Just return OK.
  487.     m_wLastError = RA_AOE_NOERR;
  488.     return m_wLastError;
  489. }
  490.  
  491. HX_RESULT CAudioOutESound::_Pause() 
  492. {
  493.     m_wLastError = HXR_OK;
  494.     m_ulPausePosition = m_ulTotalWritten;
  495.     m_ulTickCount = 0;
  496.     return m_wLastError;
  497. }
  498. HX_RESULT CAudioOutESound::_Resume()
  499. {
  500.     m_wLastError = HXR_OK;
  501.     if( m_ulTotalWritten > 0 )
  502.         m_ulTickCount = GetTickCount();
  503.     
  504.     return m_wLastError;
  505. }
  506. BOOL CAudioOutESound::_IsSelectable() const
  507. {
  508.     return TRUE;
  509. }
  510. BOOL CAudioOutESound::_HardwarePauseSupported() const
  511. {
  512.     return TRUE;
  513. }