⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 audqnx.cpp

📁 著名的 helix realplayer 基于手机 symbian 系统的 播放器全套源代码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/* ***** 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 ***** */ 

/*******************************************************************
 *
 *	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();

	// Make sure we only deal with full samples. Bytes-per-sample*num-channels.
	int nRem = ulNumBytesToRewind % (m_uSampFrameSize * m_num_channels);

	ulNumBytesToRewind -= nRem;

	pNewBuffer->Set( m_pRollbackBuffer+m_ulDeviceBufferSize-ulNumBytesToRewind, ulNumBytesToRewind );
	m_pWriteList->AddHead(pNewBuffer);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -