www.pudn.com > helix.src.0812.rar > hxaudev.cpp
/* ***** BEGIN LICENSE BLOCK ***** * Version: RCSL 1.0/RPSL 1.0 * * Portions Copyright (c) 1995-2002 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 * Version 1.0 (the "RPSL") available at * http://www.helixcommunity.org/content/rpsl unless you have licensed * the file under the RealNetworks Community Source License Version 1.0 * (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. * * 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 ***** */ #include "hxtypes.h" #if defined( _WINDOWS ) || defined( _WIN32 ) #include#include #endif /*defined( _WINDOWS ) || defined( _WIN32 )*/ #ifdef _UNIX #include #endif #include "hlxclib/stdio.h" #include "hlxclib/string.h" #include "hxresult.h" #include "cbqueue.h" #include "cpqueue.h" #include "hxslist.h" #include "hxcom.h" #include "hxausvc.h" #include "hxengin.h" #include "ihxpckts.h" #include "timeval.h" #include "hxaudev.h" #ifdef _UNIX #include "hxprefs.h" extern IHXPreferences* z_pIHXPrefs; #endif #if defined( _WINDOWS ) || defined( _WIN32 ) #include "winaudio.h" #if defined (HELIX_FEATURE_DIRECT_SOUND) #include "hxaudevds.h" #endif #endif #if defined( _LINUX ) || defined ( _FREEBSD ) #include "audlinux_oss.h" #if defined(HELIX_FEATURE_ESOUND) #include "audlinux_esound.h" #endif #if defined(HELIX_FEATURE_ALSA) #include "audlinux_alsa.h" #endif #endif #if defined( __QNXNTO__ ) #include "audqnx.h" #endif #if defined( _IRIX ) #include "audirix.h" #endif #if defined( _SUN ) && !defined( _SOLARIS ) #include "audsunos.h" #endif #if defined( _AIX ) #include "audaix.h" #endif #if defined( _SOLARIS ) #include "audSolaris.h" #endif #if defined( _MACINTOSH ) || defined( _MAC_UNIX ) #include "macaudio.h" #endif #if defined( _BEOS ) #include "audbeos.h" #endif #if defined( _HPUX ) #include "audhpux.h" #endif #if defined(_SYMBIAN) #include "audsymbian.h" #endif #if defined(_OPENWAVE) #include "audopwave.h" #endif #include "hxheap.h" #ifdef _DEBUG #undef HX_THIS_FILE static const char HX_THIS_FILE[] = __FILE__; #endif /************************************************************************ * Method: * IHXAudioDevice::~CHXAudioDevice() * Purpose: * Destructor. Clean up and set free. */ CHXAudioDevice::~CHXAudioDevice() { HX_RELEASE(m_pDeviceResponse); HX_RELEASE(m_pScheduler); HX_RELEASE(m_pContext); m_uMinVolume = 0; m_uMaxVolume = 0; m_uCurVolume = 0; m_uSampFrameSize = 0; m_ulCurrentTime = 0; m_ulLastSysTime = 0; m_ulGranularity = 0; m_pdevName = 0; } ///////////////////////////////////////////////////////////////////////// // Method: // IUnknown::QueryInterface // Purpose: // Implement this to export the interfaces supported by your // object. // STDMETHODIMP CHXAudioDevice::QueryInterface(REFIID riid, void** ppvObj) { QInterfaceList qiList[] = { { GET_IIDHANDLE(IID_IHXAudioDevice), (IHXAudioDevice*)this }, { GET_IIDHANDLE(IID_IUnknown), (IUnknown*)(IHXAudioDevice*)this }, }; return ::QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj); } ///////////////////////////////////////////////////////////////////////// // Method: // IUnknown::AddRef // Purpose: // Everyone usually implements this the same... feel free to use // this implementation. // STDMETHODIMP_(ULONG32) CHXAudioDevice::AddRef() { return InterlockedIncrement(&m_lRefCount); } ///////////////////////////////////////////////////////////////////////// // Method: // IUnknown::Release // Purpose: // Everyone usually implements this the same... feel free to use // this implementation. // STDMETHODIMP_(ULONG32) CHXAudioDevice::Release() { if (InterlockedDecrement(&m_lRefCount) > 0) { return m_lRefCount; } delete this; return 0; } /* * IHXAudioDevice methods */ /************************************************************************ * Method: * IHXAudioDevice::Create * Purpose: * Create the audio device. */ CHXAudioDevice* CHXAudioDevice::Create(IHXPreferences* pPrefs) { CHXAudioDevice* pAudioDevice = NULL; /* * The Mac compiler has trouble w/ overly complicated expressions to the * preprocessor (that's why the #if... #endif... #if... #endif blocks). */ #if defined( _SUN ) && !defined( _SOLARIS ) pAudioDevice = new CAudioOutSun; #endif #if defined( _AIX) pAudioDevice = new CAudioOutAIX; #endif #if defined( _SOLARIS ) pAudioDevice = new CAudioOutSolaris(); #endif #if defined( _LINUX ) || defined( _FREEBSD ) || defined ( _NETBSD) const int kOSS = 1; const int kESound = 2; const int kALSA = 3; int nSoundDriver = kOSS; int nSoundDriverRequested; IHXBuffer* pBuffer = NULL; HX_ASSERT( z_pIHXPrefs ); if( z_pIHXPrefs ) { z_pIHXPrefs->ReadPref("SoundDriver", pBuffer); if (pBuffer) { nSoundDriverRequested = atoi((const char*)pBuffer->GetBuffer()); if(nSoundDriverRequested == kOSS) { nSoundDriver = kOSS; } else if(nSoundDriverRequested == kESound) { #ifdef HELIX_FEATURE_ESOUND nSoundDriver = kESound; #endif } else if(nSoundDriverRequested == kALSA) { #ifdef HELIX_FEATURE_ALSA nSoundDriver = kALSA; #endif } else { //Unknown sound driver -- maybe our config file was generated //by a future version of this driver. Use OSS as a fall-back. printf("Unknown sound driver in preferences. Falling back to OSS.\n"); nSoundDriver = kOSS; } HX_RELEASE(pBuffer); } } #if defined(HELIX_FEATURE_ESOUND) if( nSoundDriver == kESound ) { pAudioDevice = new CAudioOutESound(); } #endif #if defined(HELIX_FEATURE_ALSA) if( nSoundDriver == kALSA ) { pAudioDevice = new CAudioOutLinuxAlsa(); } #endif if( nSoundDriver == kOSS || !pAudioDevice ) { pAudioDevice = new CAudioOutLinux(); } #endif #if defined( __QNXNTO__ ) pAudioDevice = new CAudioOutQNX; #endif #if defined( _IRIX ) pAudioDevice = new CAudioOutIrix; #endif #if defined( _BEOS ) pAudioDevice = new CAudioOutBeOS; #endif #if defined(_SYMBIAN) pAudioDevice = CAudioOutSymbian::NewL(); #endif #if defined(_OPENWAVE) // currently, audio unsupported for arm #ifndef _OPENWAVE_ARMULATOR pAudioDevice = new CAudioOutOpenwave; #endif #endif #if defined( _WINDOWS ) #if defined (HELIX_FEATURE_DIRECT_SOUND) BOOL bUseDS = FALSE; if(pPrefs) { IHXBuffer* pBuff = NULL; pPrefs->ReadPref("UseDirectSound", pBuff); if (pBuff) { bUseDS = (::atoi((const char*)pBuff->GetBuffer()) == 1); HX_RELEASE(pBuff); } } if(bUseDS) pAudioDevice = new CHXAudioDeviceDS; else pAudioDevice = new CAudioOutWindows; #else pAudioDevice = new CAudioOutWindows; #endif //HELIX_FEATURE_DIRECT_SOUND #endif #if defined( _MACINTOSH ) || defined( _MAC_UNIX ) pAudioDevice = new CAudioOutMac; #endif #if defined _HPUX pAudioDevice = new CAudioOutHPUX; #endif return( pAudioDevice ); } void CHXAudioDevice::Init(IUnknown* pContext) { HX_ASSERT(m_pContext == NULL && pContext != NULL); HX_RELEASE(m_pContext); m_pContext = pContext; if (m_pContext) { m_pContext->AddRef(); _initAfterContext(); } } void CHXAudioDevice::_initAfterContext() {} /************************************************************************ * Method: * IHXAudioDevice::Open * Purpose: * Open the audio device using the given format. */ STDMETHODIMP CHXAudioDevice::Open ( const HXAudioFormat* pAudioFormat, IHXAudioDeviceResponse* pDeviceResponse ) { HX_RESULT theErr = HXR_OK; m_pDeviceResponse = pDeviceResponse; if (m_pDeviceResponse) { m_pDeviceResponse->AddRef(); } memcpy( &m_AudioFmt, pAudioFormat, sizeof(HXAudioFormat) ); /* Flawfinder: ignore */ theErr = _Imp_Open( pAudioFormat ); if (!theErr) { m_eState = E_DEV_OPENED; } return theErr; } /************************************************************************ * Method: * IHXAudioDevice::Close * Purpose: * Close the audio device. */ STDMETHODIMP CHXAudioDevice::Close ( const BOOL bFlush ) { HX_RESULT theErr = HXR_OK; if ( bFlush ) { theErr = Reset(); } else { theErr = Drain(); } if ( !theErr ) theErr = _Imp_Close(); m_eState = E_DEV_CLOSED; return HXR_OK; } HX_RESULT CHXAudioDevice::Seek( UINT32 ulSeekTime) { _Imp_Seek(ulSeekTime); return HXR_OK; } /************************************************************************ * Method: * IHXAudioDevice::Pause * Purpose: * Pause the audio device. */ STDMETHODIMP CHXAudioDevice::Pause ( ) { HX_RESULT theErr = HXR_OK; m_bPaused = TRUE; theErr = _Imp_Pause(); m_eState = E_DEV_PAUSED; return HXR_OK; } /************************************************************************ * Method: * IHXAudioDevice::Resume * Purpose: * Resume the audio device. */ STDMETHODIMP CHXAudioDevice::Resume ( ) { HX_RESULT theErr = HXR_OK; m_bPaused = FALSE; theErr = _Imp_Resume(); m_eState = E_DEV_RESUMED; return HXR_OK; } /************************************************************************ * Method: * IHXAudioDevice::Write * Purpose: * Write data to the audio device. */ STDMETHODIMP CHXAudioDevice::Write ( const HXAudioData* pAudioHdr ) { HX_RESULT theErr = _Imp_Write( pAudioHdr ); return theErr; } /************************************************************************ * Method: * IHXAudioDevice::SetCallback * Purpose: */ /* STDMETHODIMP CHXAudioDevice::SetCallback ( ) { return HXR_OK; } */ /************************************************************************ * Method: * IHXAudioDevice::SetBuffering * Purpose: * Let the Audio Device manage the audio buffers. */ STDMETHODIMP CHXAudioDevice::SetBuffering ( const BOOL bSetBuffering ) { m_bBuffer = bSetBuffering; return HXR_OK; } /************************************************************************ * Method: * IHXAudioDevice::InitVolume * Purpose: * Initialize the volume. Return TRUE if device supports volume. */ STDMETHODIMP_(BOOL) CHXAudioDevice::InitVolume ( const UINT16 uMinVolume, const UINT16 uMaxVolume ) { m_uMinVolume = uMinVolume; m_uMaxVolume = uMaxVolume; return (_Imp_SupportsVolume()); } /************************************************************************ * Method: * IHXAudioDevice::SetVolume * Purpose: * Set the volume. */ STDMETHODIMP CHXAudioDevice::SetVolume ( const UINT16 uVolume ) { m_uCurVolume = uVolume; return _Imp_SetVolume( uVolume ); } /************************************************************************ * Method: * IHXAudioDevice::GetVolume * Purpose: * Get the volume. */ STDMETHODIMP_(UINT16) CHXAudioDevice::GetVolume() { return _Imp_GetVolume(); } /************************************************************************ * Method: * IHXAudioDevice::Reset * Purpose: * Reset audio. Stop playback and flush all buffers. */ STDMETHODIMP CHXAudioDevice::Reset () { return( _Imp_Reset() ); } /************************************************************************ * Method: * IHXAudioDevice::Drain * Purpose: * Drain remaining audio with playback. */ STDMETHODIMP CHXAudioDevice::Drain() { return( _Imp_Drain() ); } /************************************************************************ * Method: * IHXAudioDevice::CheckFormat * Purpose: * Check to see if the audio device will accept this audio * format. */ STDMETHODIMP CHXAudioDevice::CheckFormat( const HXAudioFormat* pFormat ) { return( _Imp_CheckFormat( pFormat ) ); } /************************************************************************ * Method: * IHXAudioDevice::GetCurrentAudioTime * Purpose: * Get the current time from the audio device. * We added this to support the clock available in the * Window's audio driver. */ STDMETHODIMP CHXAudioDevice::GetCurrentAudioTime ( ULONG32& ulCurrentTime ) { return _Imp_GetCurrentTime( ulCurrentTime ); } /************************************************************************ * Method: * CHXAudioDevice::GetAudioFd * Purpose: */ STDMETHODIMP CHXAudioDevice::GetAudioFd() { return _Imp_GetAudioFd(); } /************************************************************************ * Method: * CHXAudioDevice::OnTimeSync * Purpose: * Get the audio time from the platform specific function * GetCurrentAudioTime() and pass this up to the audio * session. */ HX_RESULT CHXAudioDevice::OnTimeSync() { HX_RESULT theErr = HXR_OK; // Ignore this if we're paused! if (!m_bPaused) { ULONG32 ulAudioTime = 0; theErr = _Imp_GetCurrentTime( ulAudioTime ); if (m_pDeviceResponse) { theErr = m_pDeviceResponse->OnTimeSync(ulAudioTime); } } return theErr; } UINT16 CHXAudioDevice::NumberOfBlocksRemainingToPlay() { return _NumberOfBlocksRemainingToPlay(); } BOOL CHXAudioDevice::IsWaveOutDevice() { return _IsWaveOutDevice(); } BOOL CHXAudioDevice::_IsWaveOutDevice() { return TRUE; } /************************************************************************* * Test code.. * */ #ifdef _TESTING_STR #include #ifndef _WINDOWS #include // for getopt() #else #include // for open() #define O_NONBLOCK 0 #endif #include // for atoi() #include // for open() #include // for open() #include // for open() #define INITGUID 1 #include "hxcom.h" #include "hxausvc.h" #include "hxaudev.h" int opt_debug = 0xff; int process_id(void) { return 10; } #define BLOCK_SIZE 3176 void main( int argc, char **argv ) { CHXAudioDevice* mydev = 0; HX_RESULT theErr = HXR_OK; mydev = CHXAudioDevice::Create(); printf("main: created: %x\n", mydev); HXAudioFormat audioFmt; audioFmt.uChannels = 1; audioFmt.uBitsPerSample= 16; audioFmt.ulSamplesPerSec= 11025; //44100; // 22050; //11025; audioFmt.uMaxBlockSize = BLOCK_SIZE; printf("main: Format:\n"); printf("main: Channels: %d\n", audioFmt.uChannels ); printf("main: Bits Per Sample %d\n", audioFmt.uBitsPerSample); printf("main: SamplesPerSec %d\n", audioFmt.ulSamplesPerSec); printf("main: MaxBlockSize %d\n", audioFmt.uMaxBlockSize); printf("main: Check Format: err: %d\n", theErr); theErr = mydev->CheckFormat( &audioFmt ); if ( !theErr ) { IHXAudioDeviceResponse* playerResponse = 0; theErr = mydev->Open( &audioFmt, playerResponse ); } if ( !theErr ) { theErr = mydev->Pause(); theErr = mydev->Resume(); } HXAudioData audioHdr; if ( !theErr ) { audioHdr.ulAudioTime = 66; // Initialize the volume to 0,100 if ( mydev->InitVolume( HX_MIN_VOLUME, HX_MAX_VOLUME ) ) printf("main: SupportsVolume is TRUE\n"); else printf("main: SupportsVolume is FALSE\n"); UINT16 curVol = 0; theErr = mydev->GetVolume( curVol ); printf("main: GetVolume: %d\n", curVol); UINT16 newVol = HX_INIT_VOLUME; theErr = mydev->SetVolume( newVol ); printf("main: SetVolume: %d\n", newVol); curVol = 0; theErr = mydev->GetVolume( curVol ); printf("main: GetVolume: %d\n", curVol); } // Write some PCM to the device... if ( !theErr ) { int cnt = 0; unsigned char buf[BLOCK_SIZE]; /* Flawfinder: ignore */ if ( argc > 1 ) { int fd; *argv++; printf("main: Playing: %s \n", *argv); fd = open( *argv,O_RDONLY | O_NONBLOCK ); /* Flawfinder: ignore */ if ( fd > 0 ) { int nbytes = 0; audioHdr.pData = (UCHAR*) new char [BLOCK_SIZE ]; while( (nbytes = read( fd, buf, BLOCK_SIZE)) > 0 ) /* Flawfinder: ignore */ { memcpy(audioHdr.pData,buf, nbytes); /* Flawfinder: ignore */ // play silence memset(audioHdr.pData, 0, nbytes); audioHdr.ulBufLen = nbytes; theErr = mydev->Write( &audioHdr ); cnt++; } } } printf("Played %d blocks of %d bytes = %d\n", cnt, BLOCK_SIZE, cnt * BLOCK_SIZE); for (int i = 0; i<6; i++) { memset(buf,0,BLOCK_SIZE); memcpy(audioHdr.pData,buf, BLOCK_SIZE); /* Flawfinder: ignore */ audioHdr.ulBufLen = BLOCK_SIZE; theErr = mydev->Write( &audioHdr ); } } if ( !theErr ) theErr = mydev->Close(TRUE); } #endif // _TESTING