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