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

📄 audunix.cpp

📁 著名的 helix realplayer 基于手机 symbian 系统的 播放器全套源代码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
/* ***** 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 "hxcom.h"
#include "hxresult.h"
#include "hxengin.h"
#include "ihxpckts.h"   // for IHXBuffer 
#include "hxslist.h"
#include "timeval.h"
#include "hxausvc.h"
#include "auderrs.h"
#include "hxaudev.h"
#include "hxaudses.h"
#include "hxtick.h"
#include "chxpckts.h"
#include "debug.h"

#include "microsleep.h"
//me.
#include "audUnix.h"

#include <errno.h>

#if defined(_THREADED_AUDIO) && defined(_UNIX_THREADS_SUPPORTED)
#include "hxprefs.h"
#endif 



//-1 is usually considered to be no file descriptor.
const int CAudioOutUNIX::NO_FILE_DESCRIPTOR = -1;

const int CAudioOutUNIX::MAX_VOLUME = 100;
    
//XXXgfw We need to clean up the return values. We need to return only PN result codes
//XXXgfw and not RA_AOE codes from interface methods.
CAudioOutUNIX::CAudioOutUNIX() :
    m_pCallback(NULL),
    m_wState( RA_AOS_CLOSED ),
    m_wLastError( RA_AOE_NOERR ),
    m_bMixerPresent(FALSE),
    m_wBlockSize(0),
    m_ulLastNumBytes (0),
    m_ulTotalWritten(0),
    m_bFirstWrite (TRUE),
    m_pPlaybackCountCBTime(0),
    m_PendingCallbackID (0),
    m_bCallbackPending(FALSE),
    m_pWriteList(NULL),
    m_ulDeviceBufferSize(0),
#if defined(_THREADED_AUDIO) && defined(_UNIX_THREADS_SUPPORTED)
    m_mtxWriteListPlayStateLock(NULL),
    m_mtxDeviceStateLock(NULL),
    m_audioThread(NULL),
    m_bUserWantsThreads(TRUE),
    m_ulSleepTime(0),
#endif
    m_pRollbackBuffer(NULL)
{

    //Alloc a Timeval for use with the timer callback.
    m_pPlaybackCountCBTime = new Timeval;
    m_pCallback = new HXPlaybackCountCB(this);
    m_pCallback->AddRef();
    
    //Allco our write buffer list. Want to throw from here? You will, like
    //it or not.
    m_pWriteList = new CHXSimpleList();
    
}

void CAudioOutUNIX::_initAfterContext()
{
#if defined(_THREADED_AUDIO) && defined(_UNIX_THREADS_SUPPORTED)
    HX_ASSERT( m_pContext );
    
    //Find out if the user wants to use threads or not.
    IHXPreferences* pPreferences = NULL;   
    if( m_pContext && HXR_OK == m_pContext->QueryInterface( IID_IHXPreferences, (void **) &pPreferences))
    {
        IHXBuffer *pBuffer = NULL;
        pPreferences->ReadPref("ThreadedAudio", pBuffer);
        if (pBuffer)
        {
            m_bUserWantsThreads = (::atoi((const char*)pBuffer->GetBuffer()) == 1);
            HX_RELEASE(pBuffer);
        }
        HX_RELEASE( pPreferences );
    }    

    if( m_bUserWantsThreads )
    {
        //Initialize the write list and playstate mutex.
        HXMutex::MakeMutex(m_mtxWriteListPlayStateLock );
        HXMutex::MakeMutex( m_mtxDeviceStateLock );
        HXThread::MakeThread( m_audioThread );
    }
#endif    

}

CAudioOutUNIX::~CAudioOutUNIX()
{
    //We must assume that _Imp_Close has already been called. If not, we are 
    //in big trouble.
    if ( m_wState != RA_AOS_CLOSED ) 
    {
        HX_ASSERT( "Device not closed in dtor." == NULL );
    }

    
#if defined(_THREADED_AUDIO) && defined(_UNIX_THREADS_SUPPORTED)
    //Sanity check that the audio thread has exited.
    //XXXgfw ADD a thread join to HXThread and use it instead
    //       of the cond var below in _close and we won't have
    //       to check here at all.
#ifdef _DEBUG    
    UINT32 unThreadID = 0;
    if( m_audioThread )
    {
        m_audioThread->GetThreadId(unThreadID);
        HX_ASSERT( unThreadID == 0 );
    }
#endif    
#endif

    //Clean up the scheduler.
    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_pPlaybackCountCBTime);
    HX_RELEASE(m_pCallback);
    HX_DELETE(m_pWriteList);

    HX_VECTOR_DELETE(m_pRollbackBuffer);
    
#if defined(_THREADED_AUDIO) && defined(_UNIX_THREADS_SUPPORTED)
    if( m_bUserWantsThreads )
    {
        HX_DELETE( m_mtxWriteListPlayStateLock );
        HX_DELETE( m_mtxDeviceStateLock );
        HX_DELETE( m_audioThread );
    }
#endif    

}

UINT16 CAudioOutUNIX::_Imp_GetVolume()
{
    if (!m_bMixerPresent)
        _OpenMixer();

    if ( m_bMixerPresent ) 
    {
        m_uCurVolume = _GetVolume();
    }
    return m_uCurVolume;
}

HX_RESULT CAudioOutUNIX::_Imp_SetVolume( const UINT16 uVolume )
{
    HX_RESULT retCode = RA_AOE_NOERR;
    
    //Mixer methods can be called before _Imp_Open
    if( !m_bMixerPresent )
        _OpenMixer();

    //m_uCurVolume is set up at the pnaudev level.
    if( m_bMixerPresent )
    {
        retCode =_SetVolume( uVolume );
    }

    m_wLastError = retCode;
    return m_wLastError;
}


BOOL CAudioOutUNIX::_Imp_SupportsVolume()
{
    return TRUE;
}


HX_RESULT CAudioOutUNIX::_Imp_Open( const HXAudioFormat* pFormat )
{
    HX_RESULT retCode = RA_AOE_NOERR;
    
    //Schedule the timer callback...
    if(m_pContext && !m_pScheduler)
    {
        m_pContext->QueryInterface(IID_IHXScheduler, (void**) &m_pScheduler );
    }

    // Check state. Could already be opened.
    if( !IsOpen() && m_wState != RA_AOS_OPENING )
    {
        retCode = _OpenAudio();
        if( retCode == RA_AOE_NOERR ) 
        {
            m_wBlockSize     = m_ulBytesPerGran;
            m_uSampFrameSize
                = pFormat->uBitsPerSample / 8;
            
            //Set device state
            LOCK(m_mtxWriteListPlayStateLock);
            m_wState = RA_AOS_OPENING;
            UNLOCK(m_mtxWriteListPlayStateLock);

            //Configure the audio device.
            retCode = _SetDeviceConfig( pFormat );

            if (retCode != RA_AOE_NOERR) 
            {
                _CloseAudio();
                m_wState=RA_AOS_CLOSED;
            }
            else
            {
#if defined(_THREADED_AUDIO) && defined(_UNIX_THREADS_SUPPORTED)
                //We want to sleep as a function of device buffer size.
                //If we have a small m_ulDeviceBufferSize we can only 
                //afford to sleep just a little while.
                HX_ASSERT( m_ulDeviceBufferSize != 0 );
                m_ulSleepTime = (((float)m_ulDeviceBufferSize/(float)m_uSampFrameSize)/
                                 (float)m_unSampleRate) * 1000 / (float)m_unNumChannels;
#endif
                if (!m_bMixerPresent)
                    _OpenMixer();   

                if( _IsSelectable() )
                {
                    IHXAsyncIOSelection* pAsyncIO = NULL;
                    if( m_pContext && HXR_OK == m_pContext->QueryInterface( IID_IHXAsyncIOSelection, (void**)&pAsyncIO))
                    {
                        pAsyncIO->Add( new HXPlaybackCountCB(this, FALSE), _Imp_GetAudioFd() , PNAIO_WRITE);
                        HX_RELEASE( pAsyncIO );
                    }
                }
            }
        }
        else
        {
            //Couldn't open the audio device.
            //Just pass through and return the error.
            m_wState=RA_AOS_CLOSED;
        }
        
    }

    // If we're optimizing/minimizing heap, we don't want to do this malloc
    // yet, because we're going to change/minize the value of 
    // m_ulDeviceBufferSize later on.
#ifndef HELIX_CONFIG_MIN_ROLLBACK_BUFFER
    //_SetDeviceConfig should have set the m_ulDeviceBufferSize var.
    if( RA_AOE_NOERR == retCode && !_HardwarePauseSupported() )
    {
        HX_ASSERT( m_ulDeviceBufferSize != 0 );
        if( NULL == m_pRollbackBuffer)
        {
            m_pRollbackBuffer = new UCHAR[m_ulDeviceBufferSize];
            memset( m_pRollbackBuffer, '0', m_ulDeviceBufferSize );
        }
    }
#endif // HELIX_CONFIG_MIN_ROLLBACK_BUFFER


#if defined(_THREADED_AUDIO) && defined(_UNIX_THREADS_SUPPORTED)
    //Start up the audio thread if it isn't going allready from a previous open
    //which sometimes happens.
    
    //Make sure we only have one thread going at a time.
    if( m_bUserWantsThreads && RA_AOE_NOERR==retCode )
    {
        UINT32 unThreadID = 0;
        m_audioThread->GetThreadId(unThreadID);
        
        if( unThreadID == 0 )
            m_audioThread->CreateThread( CAudioOutUNIX::AudioThread, this, 0 );
        
        m_audioThread->GetThreadId(unThreadID);
    }
#endif
    m_wLastError = retCode;
    return m_wLastError;
}

HX_RESULT CAudioOutUNIX::_Imp_Close()
{
    HX_RESULT retCode = RA_AOE_NOERR;

    LOCK(m_mtxWriteListPlayStateLock);
    m_wState = RA_AOS_CLOSING;
    UNLOCK(m_mtxWriteListPlayStateLock);


#if defined(_THREADED_AUDIO) && defined(_UNIX_THREADS_SUPPORTED)
    //The audio thread should exit when the state changes to closed.
    //Wait for it to do so and clean up.
    if( m_bUserWantsThreads )
    {
        m_audioThread->Exit(0);
    }
    
#endif    


    //Reset the device and empty the write buffer.
    //Don't protect this reset with a lock as the audio thread
    //has alread exited.
    retCode = _Imp_Reset();
    
    if( retCode != RA_AOE_DEVNOTOPEN )
    {
        if( _IsSelectable() )
        {
            IHXAsyncIOSelection* pAsyncIO = NULL;
            

⌨️ 快捷键说明

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