📄 audqnx.cpp
字号:
/* ***** BEGIN LICENSE BLOCK ***** * Source last modified: $Id: audqnx.cpp,v 1.3.42.1 2004/07/09 02:01:43 hubbe Exp $ * * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved. * * The contents of this file, and the files included with this file, * are subject to the current version of the RealNetworks Public * Source License (the "RPSL") available at * http://www.helixcommunity.org/content/rpsl unless you have licensed * the file under the current version of the RealNetworks Community * Source License (the "RCSL") available at * http://www.helixcommunity.org/content/rcsl, in which case the RCSL * will apply. You may also obtain the license terms directly from * RealNetworks. You may not use this file except in compliance with * the RPSL or, if you have a valid RCSL with RealNetworks applicable * to this file, the RCSL. Please see the applicable RPSL or RCSL for * the rights, obligations and limitations governing use of the * contents of the file. * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL") in which case the provisions of the GPL are applicable * instead of those above. If you wish to allow use of your version of * this file only under the terms of the GPL, and not to allow others * to use your version of this file under the terms of either the RPSL * or RCSL, indicate your decision by deleting the provisions above * and replace them with the notice and other provisions required by * the GPL. If you do not delete the provisions above, a recipient may * use your version of this file under the terms of any one of the * RPSL, the RCSL or the GPL. * * This file is part of the Helix DNA Technology. RealNetworks is the * developer of the Original Code and owns the copyrights in the * portions it created. * * This file, and the files included with this file, is distributed * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET * ENJOYMENT OR NON-INFRINGEMENT. * * Technology Compatibility Kit Test Suite(s) Location: * http://www.helixcommunity.org/content/tck * * Contributor(s): * * ***** END LICENSE BLOCK ***** *//******************************************************************* * * audqnx.cpp * * CLASS: CAudioOutQNX * * DESCRIPTION: Class implementation for QNX-specific audio devices * *******************************************************************/#include <signal.h>#include <stdio.h>#include <stdlib.h>#include <math.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/file.h>#include <sys/ioctl.h>#include <errno.h>#include <fcntl.h>#include <unistd.h>#include <errno.h>#include <string.h>#include <sys/asound.h>#include "hxcom.h"#include "hxresult.h"#include "hxengin.h"#include "ihxpckts.h"#include "hxslist.h"#include "hxstrutl.h"#include "timeval.h"#include "audqnx.h"#include "hxaudses.h"#include "hxtick.h"#include "chxpckts.h"#include "debug.h"struct IHXCallback;CAudioOutQNX::CAudioOutQNX() : m_wID( -1 ), mixm_wID( -1 ), m_wPCMChannel( -1 ), m_wState( RA_AOS_CLOSED ), m_wLastError( RA_AOE_NOERR ), m_bMixerPresent(FALSE), m_wBlockSize(0), m_ulLastNumBytes (0), m_ulBytesRemaining(0), m_ulTotalWritten(0), m_bFirstWrite (TRUE), m_pPlaybackCountCBTime(0), m_PendingCallbackID (0), m_bCallbackPending(FALSE), m_paused(FALSE), m_pWriteList(NULL), m_last_audio_time(0), m_ulPauseBytes(0), m_ulDeviceBufferSize(0), m_pRollbackBuffer(NULL){ // Use Photon registry later // Get AUDIODEV environment var to find audio device of choice char *adev = (char*)getenv( "AUDIODEV" ); /* Flawfinder: ignore */ char *mdev = (char*)getenv( "MIXERDEV" ); /* Flawfinder: ignore */ // Use defaults if no environment variable is set. if ( adev ) { SafeStrCpy( m_DevName, adev, DEVICE_NAME_SIZE ); } else { SafeStrCpy( m_DevName, "/dev/pcm00", DEVICE_NAME_SIZE ); // default } if ( mdev ) { SafeStrCpy( m_DevCtlName, mdev, DEVICE_NAME_SIZE ); } else { SafeStrCpy( m_DevCtlName, "/dev/mixer00", DEVICE_NAME_SIZE ); // default for volume } m_pPlaybackCountCBTime = new Timeval; m_pWriteList = new CHXSimpleList();}CAudioOutQNX::~CAudioOutQNX(){ // Check to make sure device is closed if ( m_wState != RA_AOS_CLOSED ) { HX_ASSERT( "Device not closed in dtor." == NULL ); _Imp_Close(); } HX_RELEASE( m_pScheduler ); //Just in case it isn't empty at this point. while( m_pWriteList && !m_pWriteList->IsEmpty() ) { IHXBuffer* pBuffer = (IHXBuffer *)(m_pWriteList->RemoveHead()); HX_RELEASE( pBuffer ); } HX_DELETE( m_pWriteList ); HX_VECTOR_DELETE( m_pRollbackBuffer );}UINT16 CAudioOutQNX::_Imp_GetVolume(){ struct snd_mixer_channel_direction_t cdata; if (!m_bMixerPresent) OpenMixer(); if ( !m_bMixerPresent ) return m_uCurVolume; cdata.channel = m_wPCMChannel; if ( ioctl( mixm_wID, SND_MIXER_IOCTL_CHANNEL_OREAD, &cdata ) == -1 ) return (0); m_uCurVolume = cdata.volume ; return m_uCurVolume;}HX_RESULT CAudioOutQNX::_Imp_SetVolume( UINT16 uVolume ){ struct snd_mixer_channel_direction_t cdata; if (!m_bMixerPresent) OpenMixer(); if ( !m_bMixerPresent ) return RA_AOE_NOERR; cdata.channel = m_wPCMChannel; if ( ioctl( mixm_wID, SND_MIXER_IOCTL_CHANNEL_OREAD, &cdata ) == -1 ) return ( m_wLastError = RA_AOE_NOTSUPPORTED ); cdata.volume = uVolume; if ( ioctl( mixm_wID, SND_MIXER_IOCTL_CHANNEL_OWRITE, &cdata ) == -1 ) return ( m_wLastError = RA_AOE_NOTSUPPORTED ); return RA_AOE_NOERR;}BOOL CAudioOutQNX::_Imp_SupportsVolume(){ return TRUE;}HX_RESULT CAudioOutQNX:: _Imp_Open ( const HXAudioFormat* pFormat ){printf( "_imp_open\n" ); m_ulLastTimeChecked = (UINT32) -1; m_ulLastTimeReturned = 0; // Get the core scheduler interface; Use this to schedule polling // the audio device for number of bytes played.#if 0 if ( m_pOwner ) { m_pOwner->GetScheduler( &m_pScheduler ); m_pScheduler->AddRef(); }#else // Get the core scheduler interface; Use this to schedule polling // the audio device for number of bytes played. if ( m_pContext ) { m_pContext->QueryInterface(IID_IHXScheduler, (void**) &m_pScheduler ); }#endif // Check state. Could already be opened. if ( m_wState == RA_AOS_OPEN_PAUSED || m_wState == RA_AOS_OPEN_PLAYING || m_wState == RA_AOS_OPENING ) return RA_AOE_NOERR; // Open audio device. if ( m_wID < 0 ) m_wID = open ( m_DevName, O_WRONLY | O_NONBLOCK ); if ( m_wID < 0 ) return ( m_wLastError = RA_AOE_BADOPEN ); m_wBlockSize = m_ulBytesPerGran; //pFormat->uMaxBlockSize; m_uSampFrameSize = pFormat->uBitsPerSample / 8; // Set device state m_wState = RA_AOS_OPENING; // Configure the audio device. AUDIOERROR iVal = SetDeviceConfig( pFormat ); if (iVal != RA_AOE_NOERR) { close ( m_wID ); m_wID = -1; return iVal; } // Find out if mixer is there.. the mixer controls volume. // If there is no mixer device, then we handle volume manually by // multiplying the samples by the volume level in the Write() method. if (!m_bMixerPresent) OpenMixer(); IHXAsyncIOSelection* pAsyncIO = NULL; if( HXR_OK == m_pContext->QueryInterface(IID_IHXAsyncIOSelection, (void**)&pAsyncIO)) { pAsyncIO->Add(new HXPlaybackCountCb(FALSE), m_wID, PNAIO_WRITE); HX_RELEASE( pAsyncIO ); } HX_ASSERT( m_ulDeviceBufferSize != 0 ); if( NULL == m_pRollbackBuffer) { m_pRollbackBuffer = new UCHAR[m_ulDeviceBufferSize]; memset( m_pRollbackBuffer, '0', m_ulDeviceBufferSize ); } return RA_AOE_NOERR;}HX_RESULT CAudioOutQNX::_Imp_Close(){printf( "_imp_close\n" ); m_wState = RA_AOS_CLOSING; /* reset pause offset */ m_ulPauseBytes = 0; _Imp_Reset( ); // Close the audio device. if ( m_wID >= 0 ) { close ( m_wID ); IHXAsyncIOSelection* pAsyncIO; if( HXR_OK == m_pContext->QueryInterface(IID_IHXAsyncIOSelection, (void**)&pAsyncIO)) { pAsyncIO->Remove(m_wID, PNAIO_WRITE); pAsyncIO->Release(); } m_wID = -1; } CloseMixer(); m_wState = RA_AOS_CLOSED; // Remove callback from scheduler if (m_bCallbackPending) { m_pScheduler->Remove(m_PendingCallbackID); m_bCallbackPending = FALSE; } HX_VECTOR_DELETE( m_pRollbackBuffer ); return RA_AOE_NOERR;}HX_RESULT CAudioOutQNX::_Imp_Write ( const HXAudioData* pAudioOutHdr ){ IHXBuffer* pBuffer = NULL; UCHAR* pData = 0; ULONG32 ulBufLen = 0; // Schedule callbacks if ( m_bFirstWrite && pAudioOutHdr) { m_bFirstWrite = FALSE; /* Initialize the playback callback time. */ HXTimeval lTime = m_pScheduler->GetCurrentSchedulerTime(); m_pPlaybackCountCBTime->tv_sec = lTime.tv_sec; m_pPlaybackCountCBTime->tv_usec = lTime.tv_usec; /* Scheduler playback callback. */ ReschedPlaybackCheck(); } if ( m_paused ) { if ( !pAudioOutHdr ) return RA_AOE_NOERR; IHXBuffer* pNewBuffer = new CHXBuffer(); pNewBuffer->Set(pAudioOutHdr->pData->GetBuffer(), pAudioOutHdr->pData->GetSize()); pNewBuffer->AddRef(); m_pWriteList->AddTail(pNewBuffer); return RA_AOE_NOERR; } BOOL bWroteSomething = TRUE; do { bWroteSomething = FALSE; if(m_pWriteList->GetCount() <= 0) { if(!pAudioOutHdr) return RA_AOE_NOERR; pData = (UCHAR*)pAudioOutHdr->pData->GetBuffer(); ulBufLen = pAudioOutHdr->pData->GetSize(); } else { if(pAudioOutHdr) { IHXBuffer* pNewBuffer = new CHXBuffer(); pNewBuffer->Set(pAudioOutHdr->pData->GetBuffer(), pAudioOutHdr->pData->GetSize()); m_pWriteList->AddTail(pNewBuffer); pNewBuffer->AddRef(); } pBuffer = (IHXBuffer*)m_pWriteList->RemoveHead(); pData = pBuffer->GetBuffer(); ulBufLen = pBuffer->GetSize(); } // Write audio data to device. int count = 0; count = write(m_wID, pData, ulBufLen); if ( count == -1 ) { // Rebuffer the data IHXBuffer* pNewBuffer = new CHXBuffer( ); pNewBuffer->AddRef( ); pNewBuffer->Set( pData, ulBufLen ); m_pWriteList->AddHead( pNewBuffer ); } // anything that is left over must be added to the write list at // the beginning if (count != -1 && count != ulBufLen) { // replace the extra data in the writelist IHXBuffer* pNewBuffer = new CHXBuffer(); pNewBuffer->Set(pData + count, ulBufLen - count); m_pWriteList->AddHead(pNewBuffer); pNewBuffer->AddRef(); } if (count != -1) { bWroteSomething = TRUE; m_ulTotalWritten += count; // If we wrote to the device we need to keep a copy of the // data our device buffer. We use this to 'rewind' the data // in case we get paused. // If we could write ulCount without blocking then there was at // least that much room in the device and since m_pRollbackBuffer // is as large as the devices buffer, we can safely shift and copy. // Add the new stuff to the end pushing the rest of the data forward. // Throw an assert here HX_ASSERT(count <= m_ulDeviceBufferSize); // Now protect against a crash if (count > m_ulDeviceBufferSize) count = m_ulDeviceBufferSize; memmove( m_pRollbackBuffer, m_pRollbackBuffer+count, m_ulDeviceBufferSize-count); memcpy( m_pRollbackBuffer+m_ulDeviceBufferSize-count, pData, count ); /* Flawfinder: ignore */ } HX_RELEASE( pBuffer ); pBuffer = NULL; pAudioOutHdr = NULL; // Don't add the same buffer again } while( bWroteSomething ); return RA_AOE_NOERR;}HX_RESULT CAudioOutQNX::_Imp_Seek(ULONG32 ulSeekTime){ return HXR_OK;}HX_RESULT CAudioOutQNX::_Imp_Pause(){ m_paused = TRUE; // Find out how much we have left in the device's buffer. int pause_bytes = GetPlaybackBytes( ); ULONG32 ulNumBytesToRewind = m_ulTotalWritten - pause_bytes; // Reset player and discard all the data in the device's buffer if( _Imp_Reset() != RA_AOE_NOERR ) { //We will just ignore it. That means the buffer will just drain //and we will hear it again when they unpause. } // Add it to the front of the write buffer. IHXBuffer* pNewBuffer = new CHXBuffer();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -