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

Symbian

开发平台:

Visual C++

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Source last modified: $Id: audqnx.cpp,v 1.3.42.1 2004/07/09 02:01:43 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. /*******************************************************************
  50.  *
  51.  * audqnx.cpp
  52.  *
  53.  * CLASS: CAudioOutQNX
  54.  *
  55.  * DESCRIPTION: Class implementation for QNX-specific audio devices 
  56.  *
  57.  *******************************************************************/
  58. #include <signal.h>
  59. #include <stdio.h>
  60. #include <stdlib.h>
  61. #include <math.h>
  62. #include <sys/types.h>
  63. #include <sys/stat.h>
  64. #include <sys/file.h>
  65. #include <sys/ioctl.h>
  66. #include <errno.h>
  67. #include <fcntl.h>
  68. #include <unistd.h>
  69. #include <errno.h>
  70. #include <string.h>
  71. #include <sys/asound.h>
  72. #include "hxcom.h"
  73. #include "hxresult.h"
  74. #include "hxengin.h"
  75. #include "ihxpckts.h"
  76. #include "hxslist.h"
  77. #include "hxstrutl.h"
  78. #include "timeval.h"
  79. #include "audqnx.h"
  80. #include "hxaudses.h"
  81. #include "hxtick.h"
  82. #include "chxpckts.h"
  83. #include "debug.h"
  84. struct IHXCallback;
  85. CAudioOutQNX::CAudioOutQNX() :
  86. m_wID( -1 ),
  87. mixm_wID( -1 ),
  88. m_wPCMChannel( -1 ),
  89. m_wState( RA_AOS_CLOSED ),
  90. m_wLastError( RA_AOE_NOERR ),
  91. m_bMixerPresent(FALSE),
  92. m_wBlockSize(0),
  93. m_ulLastNumBytes (0),
  94. m_ulBytesRemaining(0),
  95. m_ulTotalWritten(0),
  96. m_bFirstWrite (TRUE),
  97. m_pPlaybackCountCBTime(0),
  98. m_PendingCallbackID (0),
  99. m_bCallbackPending(FALSE),
  100. m_paused(FALSE),
  101. m_pWriteList(NULL),
  102. m_last_audio_time(0),
  103. m_ulPauseBytes(0),
  104.     m_ulDeviceBufferSize(0),
  105.     m_pRollbackBuffer(NULL)
  106. {
  107. // Use Photon registry later 
  108. // Get AUDIODEV environment var to find audio device of choice
  109. char *adev = (char*)getenv( "AUDIODEV" ); /* Flawfinder: ignore */
  110. char *mdev = (char*)getenv( "MIXERDEV" ); /* Flawfinder: ignore */
  111. // Use defaults if no environment variable is set.
  112. if ( adev )
  113. {
  114.     SafeStrCpy( m_DevName, adev, DEVICE_NAME_SIZE );
  115. }
  116. else
  117. {
  118.     SafeStrCpy( m_DevName, "/dev/pcm00", DEVICE_NAME_SIZE ); // default
  119. }
  120. if ( mdev )
  121. {
  122.     SafeStrCpy( m_DevCtlName, mdev, DEVICE_NAME_SIZE );
  123. }
  124. else
  125. {
  126.     SafeStrCpy( m_DevCtlName, "/dev/mixer00", DEVICE_NAME_SIZE );   // default for volume
  127. }
  128. m_pPlaybackCountCBTime = new Timeval;
  129. m_pWriteList = new CHXSimpleList();
  130. }
  131. CAudioOutQNX::~CAudioOutQNX()
  132. {
  133.     // Check to make sure device is closed
  134.     if ( m_wState != RA_AOS_CLOSED ) 
  135.     {
  136.         HX_ASSERT( "Device not closed in dtor." == NULL );
  137. _Imp_Close();
  138.     }
  139.  
  140. HX_RELEASE( m_pScheduler );
  141.     //Just in case it isn't empty at this point.
  142.     while( m_pWriteList && !m_pWriteList->IsEmpty() )
  143.     {
  144.         IHXBuffer* pBuffer = (IHXBuffer *)(m_pWriteList->RemoveHead());
  145.         HX_RELEASE( pBuffer );
  146.     }
  147. HX_DELETE( m_pWriteList );
  148. HX_VECTOR_DELETE( m_pRollbackBuffer );
  149. }
  150. UINT16 CAudioOutQNX::_Imp_GetVolume()
  151. {
  152. struct snd_mixer_channel_direction_t cdata;
  153.     if (!m_bMixerPresent)
  154. OpenMixer();
  155.     if ( !m_bMixerPresent ) 
  156. return m_uCurVolume;
  157. cdata.channel = m_wPCMChannel;
  158. if ( ioctl( mixm_wID, SND_MIXER_IOCTL_CHANNEL_OREAD, &cdata ) == -1 )
  159. return (0);
  160. m_uCurVolume = cdata.volume ; 
  161. return m_uCurVolume;
  162. }
  163. HX_RESULT CAudioOutQNX::_Imp_SetVolume( UINT16 uVolume )
  164. {
  165. struct snd_mixer_channel_direction_t cdata;
  166.     if (!m_bMixerPresent)
  167. OpenMixer();
  168.     
  169. if ( !m_bMixerPresent ) 
  170. return RA_AOE_NOERR;
  171. cdata.channel = m_wPCMChannel;
  172. if ( ioctl( mixm_wID, SND_MIXER_IOCTL_CHANNEL_OREAD, &cdata ) == -1 )
  173. return ( m_wLastError = RA_AOE_NOTSUPPORTED );
  174. cdata.volume  = uVolume;
  175. if ( ioctl( mixm_wID, SND_MIXER_IOCTL_CHANNEL_OWRITE, &cdata ) == -1 )
  176. return ( m_wLastError = RA_AOE_NOTSUPPORTED );
  177. return RA_AOE_NOERR;
  178. }
  179. BOOL CAudioOutQNX::_Imp_SupportsVolume()
  180. {
  181. return TRUE;
  182. }
  183. HX_RESULT CAudioOutQNX:: _Imp_Open ( const HXAudioFormat* pFormat )
  184. {
  185. printf( "_imp_openn" );
  186. m_ulLastTimeChecked = (UINT32) -1;
  187. m_ulLastTimeReturned = 0;
  188. // Get the core scheduler interface; Use this to schedule polling
  189. // the audio device for number of bytes played.
  190. #if 0
  191. if ( m_pOwner )
  192. {
  193. m_pOwner->GetScheduler( &m_pScheduler );
  194. m_pScheduler->AddRef();
  195. }
  196. #else
  197.     // Get the core scheduler interface; Use this to schedule polling
  198.     // the audio device for number of bytes played.
  199.     if ( m_pContext )
  200.     {
  201. m_pContext->QueryInterface(IID_IHXScheduler, (void**) &m_pScheduler );
  202.     }
  203. #endif
  204. // Check state. Could already be opened.
  205. if ( m_wState == RA_AOS_OPEN_PAUSED || m_wState == RA_AOS_OPEN_PLAYING ||
  206. m_wState == RA_AOS_OPENING )
  207. return RA_AOE_NOERR;
  208. // Open audio device.
  209. if ( m_wID < 0 )
  210. m_wID = open ( m_DevName, O_WRONLY | O_NONBLOCK );
  211. if ( m_wID < 0 )
  212. return ( m_wLastError = RA_AOE_BADOPEN );
  213. m_wBlockSize = m_ulBytesPerGran;  //pFormat->uMaxBlockSize;
  214. m_uSampFrameSize = pFormat->uBitsPerSample / 8;
  215. // Set device state
  216. m_wState = RA_AOS_OPENING;
  217. // Configure the audio device.
  218. AUDIOERROR iVal = SetDeviceConfig( pFormat );
  219. if (iVal != RA_AOE_NOERR) 
  220. {
  221. close ( m_wID );
  222. m_wID = -1;
  223. return iVal;
  224. }
  225. // Find out if mixer is there.. the mixer controls volume.
  226. // If there is no mixer device, then we handle volume manually by
  227. // multiplying the samples by the volume level in the Write() method.
  228. if (!m_bMixerPresent)
  229. OpenMixer();
  230. IHXAsyncIOSelection* pAsyncIO = NULL;
  231. if( HXR_OK == m_pContext->QueryInterface(IID_IHXAsyncIOSelection, (void**)&pAsyncIO))
  232. {
  233.     pAsyncIO->Add(new HXPlaybackCountCb(FALSE), m_wID, PNAIO_WRITE);
  234. HX_RELEASE( pAsyncIO );
  235. }
  236.      
  237. HX_ASSERT( m_ulDeviceBufferSize != 0 );
  238. if( NULL == m_pRollbackBuffer)
  239. {
  240. m_pRollbackBuffer = new UCHAR[m_ulDeviceBufferSize];
  241. memset( m_pRollbackBuffer, '0', m_ulDeviceBufferSize );
  242. }
  243. return RA_AOE_NOERR;
  244. }
  245. HX_RESULT CAudioOutQNX::_Imp_Close()
  246. {
  247. printf( "_imp_closen" );
  248. m_wState = RA_AOS_CLOSING;
  249. /* reset pause offset */
  250. m_ulPauseBytes = 0;
  251. _Imp_Reset( );
  252. // Close the audio device.
  253. if ( m_wID >= 0 ) 
  254. {
  255. close ( m_wID );
  256. IHXAsyncIOSelection* pAsyncIO;
  257. if( HXR_OK == m_pContext->QueryInterface(IID_IHXAsyncIOSelection, (void**)&pAsyncIO))
  258.         {
  259.      pAsyncIO->Remove(m_wID, PNAIO_WRITE);
  260.      pAsyncIO->Release();
  261. }
  262. m_wID = -1;
  263. }
  264.     CloseMixer();
  265. m_wState = RA_AOS_CLOSED;
  266. // Remove callback from scheduler
  267. if (m_bCallbackPending)
  268. {
  269.     m_pScheduler->Remove(m_PendingCallbackID);
  270.     m_bCallbackPending = FALSE;
  271. }
  272. HX_VECTOR_DELETE( m_pRollbackBuffer );
  273. return RA_AOE_NOERR;
  274. }
  275. HX_RESULT CAudioOutQNX::_Imp_Write ( const HXAudioData* pAudioOutHdr )
  276. {
  277.     IHXBuffer* pBuffer = NULL;
  278. UCHAR* pData = 0;
  279. ULONG32 ulBufLen = 0;
  280. // Schedule callbacks
  281. if ( m_bFirstWrite && pAudioOutHdr)
  282. {
  283.        m_bFirstWrite = FALSE;
  284.     /*  Initialize the playback callback time. */
  285.     HXTimeval lTime = m_pScheduler->GetCurrentSchedulerTime();
  286.     m_pPlaybackCountCBTime->tv_sec = lTime.tv_sec;
  287.     m_pPlaybackCountCBTime->tv_usec = lTime.tv_usec;
  288.     /*  Scheduler playback callback. */
  289.      ReschedPlaybackCheck();
  290. }
  291.     if ( m_paused )
  292. {
  293. if ( !pAudioOutHdr )
  294. return RA_AOE_NOERR;
  295. IHXBuffer* pNewBuffer = new CHXBuffer();
  296. pNewBuffer->Set(pAudioOutHdr->pData->GetBuffer(),
  297. pAudioOutHdr->pData->GetSize());
  298. pNewBuffer->AddRef();
  299. m_pWriteList->AddTail(pNewBuffer);
  300.     return RA_AOE_NOERR;
  301. }
  302. BOOL bWroteSomething = TRUE;
  303. do 
  304. {
  305. bWroteSomething = FALSE;
  306.     if(m_pWriteList->GetCount() <= 0)
  307.     {
  308. if(!pAudioOutHdr)
  309.     return RA_AOE_NOERR;
  310. pData = (UCHAR*)pAudioOutHdr->pData->GetBuffer();
  311. ulBufLen = pAudioOutHdr->pData->GetSize();
  312.     }
  313.     else
  314.     {
  315. if(pAudioOutHdr)
  316. {
  317.     IHXBuffer* pNewBuffer = new CHXBuffer();
  318.     pNewBuffer->Set(pAudioOutHdr->pData->GetBuffer(),
  319.     pAudioOutHdr->pData->GetSize());
  320.     m_pWriteList->AddTail(pNewBuffer);
  321.     pNewBuffer->AddRef();
  322. }
  323. pBuffer = (IHXBuffer*)m_pWriteList->RemoveHead();
  324. pData = pBuffer->GetBuffer();
  325. ulBufLen = pBuffer->GetSize();
  326.     }
  327. // Write audio data to device.
  328. int count = 0;
  329. count = write(m_wID, pData, ulBufLen);
  330. if ( count == -1 )
  331. {
  332. // Rebuffer the data
  333. IHXBuffer* pNewBuffer = new CHXBuffer( );
  334.             pNewBuffer->AddRef( );
  335. pNewBuffer->Set( pData, ulBufLen );
  336. m_pWriteList->AddHead( pNewBuffer );
  337. }
  338. // anything that is left over must be added to the write list at 
  339. // the beginning
  340. if (count != -1 && count != ulBufLen) 
  341. // replace the extra data in the writelist
  342. IHXBuffer* pNewBuffer = new CHXBuffer();
  343. pNewBuffer->Set(pData + count, ulBufLen - count);
  344. m_pWriteList->AddHead(pNewBuffer);
  345. pNewBuffer->AddRef();
  346. }
  347. if (count != -1)
  348. {
  349. bWroteSomething = TRUE;
  350. m_ulTotalWritten += count;
  351.             // If we wrote to the device we need to keep a copy of the 
  352.             // data our device buffer. We use this to 'rewind' the data
  353.             // in case we get paused.
  354.             // If we could write ulCount without blocking then there was at 
  355.             // least that much room in the device and since m_pRollbackBuffer
  356.             // is as large as the devices buffer, we can safely shift and copy.
  357.             // Add the new stuff to the end pushing the rest of the data forward.
  358.                         
  359.                         // Throw an assert here
  360.                         HX_ASSERT(count <= m_ulDeviceBufferSize);
  361.                         // Now protect against a crash
  362.                         if (count > m_ulDeviceBufferSize) count = m_ulDeviceBufferSize;
  363.             memmove( m_pRollbackBuffer, m_pRollbackBuffer+count, m_ulDeviceBufferSize-count);
  364.             memcpy( m_pRollbackBuffer+m_ulDeviceBufferSize-count, pData, count ); /* Flawfinder: ignore */
  365. }
  366. HX_RELEASE( pBuffer );
  367. pBuffer = NULL;
  368. pAudioOutHdr = NULL; // Don't add the same buffer again
  369. } while( bWroteSomething );
  370. return RA_AOE_NOERR;
  371. }
  372. HX_RESULT CAudioOutQNX::_Imp_Seek(ULONG32 ulSeekTime)
  373. {
  374.     return HXR_OK;
  375. }
  376. HX_RESULT CAudioOutQNX::_Imp_Pause()
  377. {
  378.     m_paused = TRUE;
  379. // Find out how much we have left in the device's buffer.
  380. int pause_bytes = GetPlaybackBytes( );
  381. ULONG32 ulNumBytesToRewind = m_ulTotalWritten - pause_bytes;
  382. // Reset player and discard all the data in the device's buffer
  383. if( _Imp_Reset() != RA_AOE_NOERR )
  384. {
  385.     //We will just ignore it. That means the buffer will just drain
  386.     //and we will hear it again when they unpause.
  387. }
  388. // Add it to the front of the write buffer.
  389. IHXBuffer* pNewBuffer = new CHXBuffer();
  390. // Make sure we only deal with full samples. Bytes-per-sample*num-channels.
  391. int nRem = ulNumBytesToRewind % (m_uSampFrameSize * m_num_channels);
  392. ulNumBytesToRewind -= nRem;
  393. pNewBuffer->Set( m_pRollbackBuffer+m_ulDeviceBufferSize-ulNumBytesToRewind, ulNumBytesToRewind );
  394. m_pWriteList->AddHead(pNewBuffer);
  395. pNewBuffer->AddRef();
  396. // Update total pause bytes offset for time/video sync
  397. m_ulPauseBytes += pause_bytes;
  398. return RA_AOE_NOERR;
  399. }
  400. HX_RESULT CAudioOutQNX::_Imp_Resume()
  401. {
  402. m_paused = FALSE;
  403. _Imp_Write( NULL );
  404. return RA_AOE_NOERR;
  405. }
  406. HX_RESULT CAudioOutQNX::_Imp_Reset()
  407. {
  408. m_ulLastTimeChecked = (UINT32) -1;
  409. m_ulLastTimeReturned = 0;
  410. if ( m_wState == RA_AOS_CLOSED )
  411. return RA_AOE_NOERR;
  412. if ( m_wID < 0 )
  413. return RA_AOE_DEVNOTOPEN;
  414. // Temporary FLUSH <--> DRAIN
  415. if ( ioctl (m_wID, SND_PCM_IOCTL_DRAIN_PLAYBACK, 0) == -1 )
  416. return RA_AOE_GENERAL;
  417. while (m_pWriteList && m_pWriteList->GetCount() > 0)
  418. {
  419.     IHXBuffer* pBuffer = (IHXBuffer *)(m_pWriteList->RemoveHead());
  420.     pBuffer->Release();
  421. }
  422. m_ulTotalWritten    = 0;
  423. m_bFirstWrite     = TRUE;
  424. m_ulLastNumBytes    = 0;
  425. return RA_AOE_NOERR;
  426. }
  427. HX_RESULT CAudioOutQNX::_Imp_Drain()
  428. {
  429. if ( m_wID < 0 )
  430. return RA_AOE_DEVNOTOPEN;
  431. // Temporary FLUSH <--> DRAIN
  432. if ( ioctl (m_wID, SND_PCM_IOCTL_FLUSH_PLAYBACK, 0) == -1 )
  433. return RA_AOE_GENERAL;
  434. return RA_AOE_NOERR;
  435. }
  436. AUDIOERROR CAudioOutQNX::SetDeviceConfig
  437. const HXAudioFormat* pFormat 
  438. )
  439. {
  440. if ( m_wID < 0 ) 
  441. return RA_AOE_NOTENABLED;
  442. int sampleWidth      = pFormat->uBitsPerSample;
  443. ULONG32 sampleRate   = pFormat->ulSamplesPerSec;
  444. int numChannels      = pFormat->uChannels;
  445. m_wBlockSize         = m_ulBytesPerGran;  //pFormat->uMaxBlockSize;
  446. ULONG32 bufSize = 128;
  447. ULONG32 bytesPerBlock = m_wBlockSize; 
  448. while ( bufSize < 4096 )
  449. {
  450. bufSize *= 2;
  451. }
  452. m_ulFragSize = bufSize;
  453. snd_pcm_playback_params_t playback_params;
  454. memset( &playback_params, 0, sizeof(playback_params) );
  455. playback_params.fragment_size  = m_ulFragSize;
  456. playback_params.fragments_max  = -1;
  457. playback_params.fragments_room =  1;
  458. /* it's okay to fail, card may not handle fragment size */
  459. ioctl(m_wID, SND_PCM_IOCTL_PLAYBACK_PARAMS, &playback_params );
  460. snd_pcm_format_t format;
  461. memset( &format, 0, sizeof(format));
  462. if( sampleWidth == 16 )
  463. {
  464.     format.format = SND_PCM_SFMT_S16_LE;
  465. }
  466. else 
  467. {
  468.     format.format = SND_PCM_SFMT_U8;
  469.     m_uSampFrameSize /= 2;
  470. }
  471. format.channels = numChannels;
  472. format.rate = sampleRate;
  473. m_sample_rate = sampleRate;
  474. m_num_channels = numChannels;
  475. m_uSampFrameSize = sampleWidth / 8;
  476. if(ioctl(m_wID, SND_PCM_IOCTL_PLAYBACK_FORMAT, &format) == -1)
  477. {
  478.     return (  m_wLastError = RA_AOE_NOTENABLED );
  479. }
  480. numChannels = format.channels;
  481. sampleRate  = format.rate;
  482. //
  483. // Verify that requested format was accepted by the audio device.
  484. //
  485. if ( numChannels != pFormat->uChannels )
  486. ((HXAudioFormat*)pFormat)->uChannels = numChannels;
  487. if ( sampleRate != pFormat->ulSamplesPerSec )
  488. ((HXAudioFormat*)pFormat)->ulSamplesPerSec = sampleRate;
  489. // Get the audio driver's buffer size for our rollback buffer
  490.     snd_pcm_playback_info_t pinfo;
  491. memset( &pinfo, 0, sizeof( pinfo ) );
  492. if(ioctl(m_wID, SND_PCM_IOCTL_PLAYBACK_INFO, &pinfo) != -1)
  493. m_ulDeviceBufferSize = pinfo.buffer_size;
  494. return RA_AOE_NOERR;
  495. }
  496. HX_RESULT CAudioOutQNX::_Imp_CheckFormat
  497. const HXAudioFormat* pFormat 
  498. )
  499. {
  500. // QNX audio driver can do all formats that we our
  501. // currently interested in. However, we should check
  502. // for valid inputs.
  503. if ( pFormat->uChannels != 1 && pFormat->uChannels != 2 )
  504. return HXR_FAILED;
  505. if ( pFormat->uBitsPerSample != 8 && pFormat->uBitsPerSample != 16 )
  506. return HXR_FAILED;
  507. // Ask driver later
  508. #if 0
  509.   /*No reason why the driver won't accept other sampling rates...*/
  510. if ( pFormat->ulSamplesPerSec != 8000 && pFormat->ulSamplesPerSec != 9600  &&
  511.      pFormat->ulSamplesPerSec != 11025 && pFormat->ulSamplesPerSec != 16000  &&
  512.      pFormat->ulSamplesPerSec != 18900 && pFormat->ulSamplesPerSec != 22050  &&
  513.      pFormat->ulSamplesPerSec != 32000 && pFormat->ulSamplesPerSec != 44100  &&
  514.      pFormat->ulSamplesPerSec != 48000 )
  515. return HXR_FAILED;
  516. #endif
  517. return HXR_OK;
  518. }
  519. /************************************************************************
  520.  *  Method:
  521.  *              CAudioOutQNX::_Imp_GetCurrentTime
  522.  *      Purpose:
  523.  *              Get the current time from the audio device.
  524.  * We added this to support the clock available in the
  525.  * Window's audio driver.
  526.  */
  527. HX_RESULT CAudioOutQNX::_Imp_GetCurrentTime ( ULONG32& ulCurrentTime )
  528. {
  529.     ULONG32 ulTime   = 0;
  530.     ULONG32 ulBytes  = GetPlaybackBytes();
  531. ulBytes += m_ulPauseBytes;
  532.     
  533.     ulTime = (UINT32)((  (double)(ulBytes/m_uSampFrameSize)/(double)m_sample_rate) * 1000 / m_num_channels);
  534.     
  535.     //Not used anywhere but belongs to CHXAudioDevice so we must set it.
  536.     m_ulCurrentTime  = ulTime;
  537.     //Set the answer.
  538.     ulCurrentTime = ulTime;
  539.     return HXR_OK;
  540. }
  541. /************************************************************************
  542.  *  Method:
  543.  *              CAudioOutQNX::_Imp_GetAudioFd
  544.  *      Purpose:
  545.  */
  546. INT16 CAudioOutQNX::_Imp_GetAudioFd()
  547. {
  548.     return m_wID;
  549. }
  550. /************************************************************************
  551.  *  Method:
  552.  *              CAudioOutQNX::DoTimeSyncs
  553.  *      Purpose:
  554.  * Manual time syncs! Fork!
  555.  */
  556. void CAudioOutQNX::DoTimeSyncs()
  557. {
  558.     ReschedPlaybackCheck();
  559. OnTimeSync();
  560.     return;
  561. }
  562. /************************************************************************
  563.  *  Method:
  564.  *              CAudioOutQNX::GetPlaybackBytes
  565.  *      Purpose:
  566.  * Get the number of bytes played since last open() was
  567.  * called. This ioctl() returns funky values sometimes?!@%
  568.  */
  569. ULONG32 CAudioOutQNX::GetPlaybackBytes()
  570. {
  571. snd_pcm_playback_status_t info;
  572. memset( &info,0, sizeof(info));
  573. if ( ioctl (m_wID, SND_PCM_IOCTL_PLAYBACK_STATUS, &info) != -1 )
  574. return info.scount;
  575. // If ioctl failed, just guess the value
  576.     int bytes = m_ulTotalWritten - m_ulGranularity / 2;
  577.     if (bytes < 0) 
  578. bytes = 0;
  579. return (ULONG32) bytes; 
  580. }
  581. ULONG32 CAudioOutQNX::_GetPlaybackBuffer( )
  582. {
  583. return( m_ulTotalWritten - GetPlaybackBytes( ) );
  584. }
  585. /************************************************************************
  586.  *  Method:
  587.  *              CAudioOutQNX::ReschedPlaybackCheck()
  588.  *      Purpose:
  589.  * Reschedule playback callback.
  590.  */
  591. HX_RESULT CAudioOutQNX::ReschedPlaybackCheck()
  592. {
  593.     HX_RESULT theErr = HXR_OK;
  594.     if (m_bCallbackPending)
  595. return theErr;
  596.     /* Put this back in the scheduler.
  597.      */
  598.     HXPlaybackCountCb* pCallback = 0;
  599.     pCallback = new HXPlaybackCountCb;
  600.     if (pCallback)
  601.     {
  602.         *m_pPlaybackCountCBTime += (int) (1000 * m_ulGranularity);
  603.         pCallback->m_pAudioDeviceObject = this;
  604.         m_bCallbackPending = TRUE;
  605.         m_PendingCallbackID = m_pScheduler->AbsoluteEnter(pCallback,
  606.                         *((HXTimeval*) m_pPlaybackCountCBTime));
  607.     }
  608.     else
  609.     {
  610.         theErr = HXR_OUTOFMEMORY;
  611.     }
  612.     return HXR_OK;
  613. }
  614. UINT16 CAudioOutQNX::_NumberOfBlocksRemainingToPlay(void)
  615. {
  616.     UINT32  bytesBuffered = 0;
  617.     LISTPOSITION i = m_pWriteList->GetHeadPosition();
  618.     while (i)
  619.     {
  620. bytesBuffered += ((IHXBuffer *)m_pWriteList->GetAt(i)) -> GetSize();
  621. m_pWriteList->GetNext(i);
  622.     }
  623.     
  624.     bytesBuffered += (m_ulTotalWritten - GetPlaybackBytes());
  625.     return bytesBuffered / m_wBlockSize + 1;
  626. }
  627. // CAudioOutQNX::HXPlaybackCountCb
  628. CAudioOutQNX::HXPlaybackCountCb::HXPlaybackCountCb(BOOL timed) :
  629.      m_lRefCount (0)
  630.     ,m_pAudioDeviceObject (0)
  631.     ,m_timed(timed)
  632. {
  633. }
  634. CAudioOutQNX::HXPlaybackCountCb::~HXPlaybackCountCb()
  635. {
  636. }
  637. /*
  638.  * IUnknown methods
  639.  */
  640. /////////////////////////////////////////////////////////////////////////
  641. //      Method:
  642. //              IUnknown::QueryInterface
  643. //      Purpose:
  644. //              Implement this to export the interfaces supported by your 
  645. //              object.
  646. //
  647. STDMETHODIMP CAudioOutQNX::HXPlaybackCountCb::QueryInterface
  648. ( REFIID riid, void** ppvObj )
  649. {
  650.     if (IsEqualIID(riid, IID_IHXCallback))
  651.     {
  652.         AddRef();
  653.         *ppvObj = (IHXCallback*)this;
  654.         return HXR_OK;
  655.     }
  656.     else if (IsEqualIID(riid, IID_IUnknown))
  657.     {
  658.         AddRef();
  659.         *ppvObj = this;
  660.         return HXR_OK;
  661.     }
  662.     *ppvObj = NULL;
  663.     return HXR_NOINTERFACE;
  664. }
  665. /////////////////////////////////////////////////////////////////////////
  666. //      Method:
  667. //              IUnknown::AddRef
  668. //      Purpose:
  669. //              Everyone usually implements this the same... feel free to use
  670. //              this implementation.
  671. //
  672. STDMETHODIMP_(ULONG32) CAudioOutQNX::HXPlaybackCountCb::AddRef()
  673. {
  674.     return InterlockedIncrement(&m_lRefCount);
  675. }
  676. /////////////////////////////////////////////////////////////////////////
  677. //      Method:
  678. //              IUnknown::Release
  679. //      Purpose:
  680. //              Everyone usually implements this the same... feel free to use
  681. //              this implementation.
  682. //
  683. STDMETHODIMP_(ULONG32) CAudioOutQNX::HXPlaybackCountCb::Release()
  684. {
  685.     if (InterlockedDecrement(&m_lRefCount) > 0)
  686.     {
  687.         return m_lRefCount;
  688.     }
  689.     delete this;
  690.     return 0;
  691. }
  692. /*
  693.  *      IHXPlaybackCountCb methods
  694.  */
  695. STDMETHODIMP CAudioOutQNX::HXPlaybackCountCb::Func(void)
  696. {
  697.     if (m_pAudioDeviceObject)
  698.     {
  699. if(!m_timed)
  700. {
  701.     m_pAudioDeviceObject->_Imp_Write(NULL);
  702. }
  703. else
  704. {
  705.     m_pAudioDeviceObject->m_bCallbackPending  = FALSE;
  706.     m_pAudioDeviceObject->_Imp_Write(NULL);
  707.     m_pAudioDeviceObject->DoTimeSyncs();
  708. }
  709.     }
  710.     return HXR_OK;
  711. }
  712. /************************************************************************
  713.  *  Method:
  714.  *              CAudioOutQNX::BuffersEmpty
  715.  *      Purpose:
  716.  */
  717. BOOL CAudioOutQNX::BuffersEmpty()
  718. {
  719.     snd_pcm_playback_status_t info;
  720.     if ( -1 == ioctl(m_wID, SND_PCM_IOCTL_PLAYBACK_STATUS, &info) )
  721. return FALSE;
  722.     if ( info.queue )
  723. return FALSE;
  724.     return TRUE;
  725. }
  726. void CAudioOutQNX::OpenMixer()
  727. {
  728. int i;
  729. struct snd_mixer_info_t  info;
  730. struct snd_mixer_channel_info_t cinfo;
  731.     //
  732.     // return if the mixer is already opened
  733.     //
  734.     if (m_bMixerPresent)
  735. return;
  736.     mixm_wID = open ( m_DevCtlName, O_RDWR );
  737. if ( -1 == ioctl( mixm_wID, SND_MIXER_IOCTL_INFO, &info ) )
  738. {
  739. CloseMixer( );
  740. return;
  741. }
  742.     
  743.     if (mixm_wID > 0)
  744.     {
  745. /* find pcm channel */
  746. memset( &cinfo, 0, sizeof( cinfo ) );
  747. for ( i = 0; i < info.channels; i++ )
  748. {
  749. cinfo.channel = i;
  750. if ( -1 == ioctl( mixm_wID, SND_MIXER_IOCTL_CHANNEL_INFO, &cinfo ) )
  751. {
  752. continue;
  753. }
  754. if ( 0 == strcmp( (char *)cinfo.name, SND_MIXER_ID_PCM ) ) 
  755. {
  756. m_wPCMChannel = i;
  757. break;
  758. }
  759. }
  760. }
  761. if ( m_wPCMChannel > 0 )
  762. {
  763. m_bMixerPresent = 1;
  764.     }
  765.     else
  766.     {
  767. CloseMixer( );
  768. m_bMixerPresent = 0;
  769.     }
  770. }
  771. void CAudioOutQNX::CloseMixer()
  772. {
  773.     // Close the mixer device.
  774.     if ( mixm_wID >= 0 ) 
  775.     {
  776. close ( mixm_wID );
  777. mixm_wID = -1;
  778.     }
  779. }