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

📄 audaix.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 ***** */ 

/*******************************************************************
 *	audaix.cpp
 *
 *	CLASS: CAudioOutAIX
 *	
 *	DESCRIPTION: AIX & UMS specific audio class implementation
 *   
 *******************************************************************/

#include <signal.h>		// for  getenv()

#include <stdio.h>
#include <stdlib.h>		// for  getenv()
#include <math.h>
#include <sys/types.h>
#include <stropts.h>		// for I_FLUSH ioctl
#include <sys/conf.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/audio.h>

#include "hxcom.h"

#include "hxresult.h"
#include "hxengin.h"
#include "ihxpckts.h"   // for IHXBuffer 
#include "hxslist.h"

#include "timeval.h"

#include "audaix.h"

#include "hxaudses.h"
#include "hxtick.h"
#include "chxpckts.h"

#include "debug.h"
#include "hxstrutl.h"

#include <UMSBAUDDevice.xh>
#include <UMSAudioDevice.xh>
#include <UMSAudioTypes.xh>

struct IHXCallback;  // forward declaration needed for callback.

// One and ONLY one of the following must be uncommented.  They determine the
// strategy used to determine the elaped time. The first is the preferred.
#define AIX_TIME_BYTES_WRITTEN         // function of bytes written vrs bytes in buffer.


//**********************************************************************
//  constants.
//

// in UMS, balance is really an initial pan setting. 
// -100 = hard left, 0 is centered, 100 = hard right

static const LONG32   lDefaultBalance = 0;   
static const LONG32   lDefaultVolume = 50;   // UMS range is 0..100
static LONG32   zlCurrentVolume = 50;   // UMS range is 0..100
// this is sufficient for PCI devices, for microchannel devices, set the
// envar AUDIODEV to "/dev/maud0".
static const char *   szDefaultPortFilename = "/dev/paud0";
static const char *   moduleName = "CAudioOutAIX"; 

// this will point to the SOM environment needed by the UMS subsystem
static Environment*   gpSomEnvironment                  = NULL;


// static local routines, used to translate UMS message code to RMA types.
static const char *   getUMSAudioDeviceError( UMSAudioDevice_ReturnCode );
static audio_error    UMSErrorCodeToRACode( UMSAudioDevice_ReturnCode ); 

CAudioOutAIX::CAudioOutAIX() 
  : mixm_wID( -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(NULL),
    m_PendingCallbackID (0),
    m_bCallbackPending(FALSE),
    m_paused(FALSE),
    m_pWriteList(NULL),
    m_lLeftGain(100),
    m_lRightGain(100)
{
  
    // set up UMS environment.
    gpSomEnvironment = somGetGlobalEnvironment();
    HX_ASSERT( gpSomEnvironment );
    m_pAudioDevice   = new UMSBAUDDevice();
    
    // 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.
    m_DevName[26]    = NULL;
    m_DevCtlName[26] = NULL;

    if (adev && strlen(adev) > 0)
        SafeStrCpy(m_DevName, adev, 26);
    else
        SafeStrCpy(m_DevName, szDefaultPortFilename, 26);

    m_pPlaybackCountCBTime = new Timeval;

    if (mdev && strlen(mdev) > 0)
        SafeStrCpy(m_DevCtlName, mdev, 26);
    else
        SafeStrCpy(m_DevCtlName, szDefaultPortFilename, 26);
    
    m_pWriteList = new CHXSimpleList();

    // now configure our device.
    m_pAudioDevice->set_audio_format_type  ( gpSomEnvironment, "PCM" );
    m_pAudioDevice->set_number_format      ( gpSomEnvironment, 
					     "TWOS_COMPLEMENT" );
    m_pAudioDevice->set_byte_order         ( gpSomEnvironment, "MSB" ); 
    m_pAudioDevice->set_time_format        ( gpSomEnvironment, 
					     UMSAudioTypes_Msecs ); 
    
    m_pAudioDevice->set_balance   ( gpSomEnvironment, lDefaultBalance );  
    m_pAudioDevice->set_volume    ( gpSomEnvironment, zlCurrentVolume );
    m_pAudioDevice->enable_output ( gpSomEnvironment, "LINE_OUT", 
				    &m_lLeftGain, &m_lRightGain  );
}


CAudioOutAIX::~CAudioOutAIX()
{
    if ( m_wState != RA_AOS_CLOSED ) 
      {
	_Imp_Close();
	m_wState = RA_AOS_CLOSED;
      }
    
    mixm_wID = -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;
    
    if (m_pScheduler) 
      m_pScheduler->Release();
    
    m_PendingCallbackID = 0;
    m_bCallbackPending = TRUE; 
    
    while(!m_pWriteList->IsEmpty())
      {
	IHXBuffer* pBuffer = (IHXBuffer*)m_pWriteList->RemoveHead();
	HX_RELEASE(pBuffer);
      }

    HX_DELETE(m_pWriteList);
    
    delete m_pAudioDevice;
}


/*
 *    I do not open /dev/mixer to control volume, the volume is scaled
 *    by the UMS device.
 *    The device's volume has a range of 0..100.
 */
UINT16 CAudioOutAIX::_Imp_GetVolume()
{
    long volume;
    m_pAudioDevice->get_volume( gpSomEnvironment, &volume );
    return zlCurrentVolume;
    return (UINT16)volume;
}


HX_RESULT CAudioOutAIX::_Imp_SetVolume( const UINT16 uVolume )
{
    m_pAudioDevice->set_volume( gpSomEnvironment, (long)uVolume );
    zlCurrentVolume = uVolume;
    return RA_AOE_NOERR;
}


/*
 *  All UMS audio devices support volume.
 */
BOOL CAudioOutAIX::_Imp_SupportsVolume()
{
    return TRUE;
}

HX_RESULT CAudioOutAIX:: _Imp_Open( const HXAudioFormat* pFormatSupplied )
{
    if( pFormatSupplied != NULL )
      m_pAudioFormat = pFormatSupplied;
    
    HX_ASSERT( m_pAudioFormat != NULL ); 
    
    // 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 );
    }

    // 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;
    
    m_ulBlocksProcessed = 0;
    UMSAudioDevice_ReturnCode retCode =  
      m_pAudioDevice->open( gpSomEnvironment, m_DevName, "PLAY", 0 ); 
    
    if( retCode != UMSAudioDevice_Success ) 
      {
        return HXR_FAILED;
      }
    
    m_wBlockSize = m_ulBytesPerGran;  //m_pAudioFormat->uMaxBlockSize;
    m_uSampFrameSize = m_pAudioFormat->uBitsPerSample / 8;
    
    // Set device state
    m_wState = RA_AOS_OPENING;
    
    // Configure the audio device.
    AUDIOERROR iVal = SetDeviceConfig( m_pAudioFormat );
    
    return RA_AOE_NOERR;
}



HX_RESULT CAudioOutAIX::_Imp_Close()
{
    m_wState = RA_AOS_CLOSED;
    
    // this will force the player to play all remaining data.  If passed TRUE, 
    // the call will block until finished playing. Do we want to call this?
    // m_pAudioDevice->play_remaining_data( gpSomEnvironment, TRUE );
    _Imp_Write(NULL);
    
    m_pAudioDevice->stop( gpSomEnvironment );
    m_pAudioDevice->close( gpSomEnvironment );
    
    // Remove callback from scheduler
    if (m_bCallbackPending)
      {
	m_pScheduler->Remove(m_PendingCallbackID);
	m_bCallbackPending = FALSE;
    }
    
    return RA_AOE_NOERR;
}




HX_RESULT CAudioOutAIX::_Imp_Write( const HXAudioData* pAudioOutHdr )
{
    IHXBuffer* pBuffer = NULL;
    UCHAR* pData = NULL;
    UMSAudioTypes_Buffer adBuffer;
    UINT32* pTimeStamp = NULL;
    
    if ( m_bFirstWrite && pAudioOutHdr)
    {
        /*  Initialize the playback callback time. */
        HXTimeval lTime = m_pScheduler->GetCurrentSchedulerTime();
        m_pPlaybackCountCBTime->tv_sec = lTime.tv_sec;
        m_pPlaybackCountCBTime->tv_usec = lTime.tv_usec;

	m_bFirstWrite = FALSE;
	ReschedPlaybackCheck();
    }

    if (pAudioOutHdr)
      {
        ++m_ulBlocksProcessed ; 
	
	DPRINTF(D_INFO, ("_Imp_Write: buf len in milli-seconds: %lu\n",
			 ((ULONG32) (( 1000.0
				       / (m_num_channels * m_uSampFrameSize * m_sample_rate))
				     *  pAudioOutHdr->pData->GetSize()))));
      }
    
    // If we are paused, just add the block to the end of the WriteList.
    if (m_paused)
    {
	if (!pAudioOutHdr)
	    return m_wLastError = 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;
    do {
        bWroteSomething = FALSE;
	if(m_pWriteList->GetCount() <= 0)
	{
	    if(!pAudioOutHdr)
		return  RA_AOE_NOERR;
	    
	    pData = (UCHAR*)pAudioOutHdr->pData->GetBuffer();
	    adBuffer._length = pAudioOutHdr->pData->GetSize();
	}
	else
	{
	    if (pAudioOutHdr)
	    {
		IHXBuffer* pNewBuffer = new CHXBuffer();
		pNewBuffer->AddRef();
		pNewBuffer->Set(pAudioOutHdr->pData->GetBuffer(),
				pAudioOutHdr->pData->GetSize());
		m_pWriteList->AddTail(pNewBuffer);
	    }
	    pBuffer = (IHXBuffer*)m_pWriteList->RemoveHead();
	    HX_ASSERT(pBuffer);
	    pData = pBuffer->GetBuffer();
	    adBuffer._length  = pBuffer->GetSize();
	}
    
        // Write audio data to device.
        long	count = 0;
        int         wrote;
    
        adBuffer._buffer = pData;
        adBuffer._maximum = adBuffer._length;
    
        int     nBytesPerSample = (m_bits_per_sample/8)* m_num_channels;
        long    lSamplesToWrite = adBuffer._length / nBytesPerSample;
        long    lSamplesWritten =0;    
    
        int     transferredCount = adBuffer._length;

        m_wLastError = RA_AOE_NOERR;  // less work this way.

        UMSAudioDevice_ReturnCode retCode = 
            m_pAudioDevice->write( gpSomEnvironment, 
				 &adBuffer,
				 lSamplesToWrite,
				 &lSamplesWritten );

        switch(retCode)
        {
            case UMSAudioDevice_Success :    
	    {
	        int nBytesWritten = lSamplesWritten * nBytesPerSample;
	        m_ulTotalWritten += nBytesWritten;
	      
  	  	HX_ASSERT(lSamplesWritten <= lSamplesToWrite);
	        if( lSamplesWritten == lSamplesToWrite ) 
	        {
  		    bWroteSomething = TRUE;
	        }
	        else 
                {  
	    	    /* requeue the balance. */
		    long lSamplesToRequeue = lSamplesToWrite - lSamplesWritten;
		    IHXBuffer* pNewBuffer = new CHXBuffer();
		    pNewBuffer->AddRef();
		    pNewBuffer->Set( adBuffer._buffer + nBytesWritten,
				 adBuffer._length - nBytesWritten );
		    m_pWriteList->AddHead(pNewBuffer);
	        }
	    }
	    break;
	    
	    case UMSAudioDevice_DeviceError : // indicates EWOULDBLOCK
	    case UMSAudioDevice_Preempted :
	    case UMSAudioDevice_Interrupted :
            {
	        // just requeue the data
	        IHXBuffer* pNewBuffer = new CHXBuffer();
	        pNewBuffer->AddRef();
	        pNewBuffer->Set( adBuffer._buffer, adBuffer._length );
	        m_pWriteList->AddHead(pNewBuffer);
	        break;
            }
	    
	    default :  // failure!
	        HX_ASSERT(FALSE);
	        m_wLastError = UMSErrorCodeToRACode( retCode );
        }  
    
       INT32 newRefCount = 0;
       if( pBuffer ) 
           newRefCount = pBuffer->Release();

	HX_ASSERT(newRefCount == 0);
	pBuffer = NULL;

⌨️ 快捷键说明

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