winaudio.cpp

来自「symbian 下的helix player源代码」· C++ 代码 · 共 1,396 行 · 第 1/3 页

CPP
1,396
字号
/* ***** BEGIN LICENSE BLOCK *****
 * Source last modified: $Id: winaudio.cpp,v 1.4.8.2 2004/07/09 02:01:47 hubbe Exp $
 * 
 * Portions Copyright (c) 1995-2004 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 (the "RPSL") available at
 * http://www.helixcommunity.org/content/rpsl unless you have licensed
 * the file under the current version of the RealNetworks Community
 * Source License (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.
 * 
 * Alternatively, the contents of this file may be used under the
 * terms of the GNU General Public License Version 2 or later (the
 * "GPL") in which case the provisions of the GPL are applicable
 * instead of those above. If you wish to allow use of your version of
 * this file only under the terms of the GPL, and not to allow others
 * to use your version of this file under the terms of either the RPSL
 * or RCSL, indicate your decision by deleting the provisions above
 * and replace them with the notice and other provisions required by
 * the GPL. If you do not delete the provisions above, a recipient may
 * use your version of this file under the terms of any one of the
 * RPSL, the RCSL or the GPL.
 * 
 * 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"

#include "hlxclib/windows.h"
#include <mmsystem.h>
#include <tchar.h> 
#include <stdio.h>

#ifdef _TESTING
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

#if defined (_WINDOWS) || defined (_WIN32)

#include <io.h>

#endif

#endif

#include "hxresult.h"

#include "hxcom.h"
#include "hxausvc.h"
#include "auderrs.h"
#include "ihxpckts.h"
#include "hxengin.h"

#include "timeval.h"

#include "hxaudev.h"
#include "hxslist.h"
#include "hxtick.h"

//#include "hxaudses.h"

#include "cbqueue.h"
#include "cpqueue.h"
#include "hxthread.h"

#include "winaudio.h"

#ifdef WIN32_PLATFORM_PSPC
#define WM_NCCREATE WM_CREATE
#define WM_NCDESTROY WM_DESTROY
#endif

struct IHXCallback;

extern HINSTANCE g_hInstance;
#define	OFFSET_THIS		0

#ifdef _TESTING
int m_audfile = -1;
#endif

BOOL	CAudioOutWindows::zm_bVolSupport = FALSE;
BOOL	CAudioOutWindows::zm_bLRVolSupport = FALSE;
WORD	CAudioOutWindows::zm_uMaxVolume = 100;
BOOL	CAudioOutWindows::zm_bMixerVolSupport = FALSE;
BOOL	CAudioOutWindows::zm_bMixerVolSupportChecked = FALSE;
UINT	CAudioOutWindows::zm_uDestroyMessage = 0;
BOOL	CAudioOutWindows::zm_bClosed = TRUE;
CAudioOutWindows* zm_pCurrentAudioDevice = NULL;

// BAD drivers which need to call waveOutSetVolume directly
const UINT16	g_nBadDrivers = 1;
const TCHAR*	g_badDrivers[] = { _T("Crystal Audio System") };
audioDevice	CAudioOutWindows::zm_audioDevice = HXAUDIO_UNKNOWN;

//CRITICAL_SECTION CAudioOutWindows::zm_AudioCritSection;

#define MAX_REASONABLE_BUFFS 40

#define PUSH_DOWN_TIME		400    /* push down 400 ms  */
#define LIKELY_PUSH_COUNT	10

CAudioOutWindows::CAudioOutWindows()
    : m_hWave(NULL)
    , m_unAllocedBufferCnt(0)
    , m_unAllocedBuffSize(0)
    , m_ppAllocedBuffers(NULL)
    , m_pWaveHdrs(NULL)
    , m_rAvailBuffers(MAX_REASONABLE_BUFFS)
    , m_bInitialized(FALSE)
    , m_bResetting(FALSE)
    , m_bIsFirstPacket(TRUE)
    , m_hWnd(NULL)
    , m_bClassRegistered(FALSE)
    , m_ulDevPosRollOver(0)
    , m_ulLastDeviceBytesPlayed(0)
    , m_ulLastDeviceSamplesPlayed(0)
    , m_llDeviceBytesPlayed(0)
    , m_llDeviceSamplesPlayed(0)
#if defined(_WIN32)
    , m_ulOriginalThreadId(0)
#endif /*_WIN32*/
{
    zm_bClosed = TRUE;    
    zm_pCurrentAudioDevice = this;

#if defined(_WIN32) && !defined(_WINCE)
    m_hMixer = NULL;  
    memset(&m_VolumeControlDetails, 0 , sizeof(MIXERCONTROLDETAILS));
#endif // _WIN32

    // Create a unique message for destroying the audio window
    if (!zm_uDestroyMessage)
    {
	zm_uDestroyMessage = RegisterWindowMessage(_T("HX_DestroyAudioServicesInternal"));
    }
    
#ifdef THREADS_SUPPORTED
    HXMutex::MakeMutex(m_pMutex);
#else
    HXMutex::MakeStubMutex(m_pMutex);
#endif
}		   


CAudioOutWindows::~CAudioOutWindows()
{
//    OutputDebugString("BEFORE CALL TO:CAudioOutWindows::~CAudioOutWindows\r\n");
    // this gives us one last chance to recover packets that are still in the device
    Reset();

    // We might as well consider the device closed!
    zm_bClosed = TRUE;

#if defined(_WIN32) && !defined(_WINCE)

    /* This sleep is added to fix a hang bug that ONLY happens on
     * Darren's machine if you adjust audio volume. His machine
     * has a really old audio driver
     * 
     * I have no clue what this bug is and how this Sleep(0)
     * fixes it. Obviously, there was some race condition.
     *
     * Sound Driver Info:
     *
     * Version 2.03.0 Build 1
     * Creative Sound Blaster 16 Driver (Windows NT)
     * 
     */
    Sleep(0);

    if(m_hMixer)
    {
        mixerClose(m_hMixer);
    }
#endif // _WIN32

    _Imp_Close();

    zm_pCurrentAudioDevice = NULL;
    HX_DELETE(m_pMutex);
}

UINT16 CAudioOutWindows::_Imp_GetVolume()
{
    DWORD dwVol	    = 0;                          
    BOOL bSuccess   = FALSE;

#if defined(_WIN32) && !defined(_WINCE)
    if (!zm_bMixerVolSupportChecked)
    {
	CheckForVolumeSupport();
    }

    if(zm_bMixerVolSupport)
    {
	if (!m_hMixer)
	{
	    CheckForVolumeSupport();
	}

        PMIXERCONTROLDETAILS_UNSIGNED pmxVolume;
        UINT16 nItems = 1;
        if(m_VolumeControlDetails.cMultipleItems)
            nItems = (UINT16)m_VolumeControlDetails.cMultipleItems;
        pmxVolume = new MIXERCONTROLDETAILS_UNSIGNED[nItems];
        m_VolumeControlDetails.cbDetails = nItems * sizeof(MIXERCONTROLDETAILS_UNSIGNED);
        m_VolumeControlDetails.paDetails = pmxVolume;
        if(mixerGetControlDetails((HMIXEROBJ)m_hMixer, &m_VolumeControlDetails, 
           MIXER_GETCONTROLDETAILSF_VALUE | MIXER_OBJECTF_HMIXER) == MMSYSERR_NOERROR)
        {
            dwVol = pmxVolume[0].dwValue;
            bSuccess = TRUE;
        }
        delete[] pmxVolume;
    }
#endif

    if (!bSuccess)
    {
	if (!zm_bVolSupport)
	{
	    return 0;
	}

	MMRESULT hResult = waveOutGetVolume( m_hWave, &dwVol );

	if (hResult != MMSYSERR_NOERROR && m_hWave != NULL)
	{
	    hResult = waveOutGetVolume( NULL, &dwVol );
	}

	if (hResult != MMSYSERR_NOERROR)
	{
	    return 0;
	}
    }

    return ( (UINT16)((DWORD)LOWORD( dwVol ) * zm_uMaxVolume / 0xFFFF ) );
}

HX_RESULT CAudioOutWindows::_Imp_SetVolume
( 
    const UINT16 uVolume
)
{
    DWORD dwVol = 0;
    BOOL bSuccess = FALSE;

    if (uVolume > zm_uMaxVolume)
    {
        return HXR_OK;
    }

#if defined(_WINCE) && (_WIN32_WCE >= 400) && defined(_X86_)
	//Windows CE 4.2 Emulator (testing platform) does not seem to support waveOut
	//set volume functionality (on speakers). In some sense it does but only the
	//high volume value work, other values just mute the speakers
	dwVol = (DWORD) 0xFFFF;
#else
    dwVol = (DWORD)uVolume * 0xFFFF / zm_uMaxVolume;
#endif

    // Here we are avoiding rounding error
    if(dwVol * zm_uMaxVolume / 0xFFFF < uVolume)
	dwVol += 0xFFFF / zm_uMaxVolume;

    if (zm_audioDevice == HXAUDIO_BADDEVICE)
    {
	goto noMixer;
    }

#if defined(_WIN32) && !defined(_WINCE)
    if (!zm_bMixerVolSupportChecked)
    {
	CheckForVolumeSupport();
    }

    if(zm_bMixerVolSupport)
    {
	if (!m_hMixer)
	{
	    CheckForVolumeSupport();
	}
        PMIXERCONTROLDETAILS_UNSIGNED pmxVolume;
        UINT16 nItems = 1;
        if(m_VolumeControlDetails.cMultipleItems)
            nItems = (UINT16)m_VolumeControlDetails.cMultipleItems;
        pmxVolume = new MIXERCONTROLDETAILS_UNSIGNED[nItems];
        for(UINT16 nIndex = 0; nIndex < nItems; nIndex++)
            pmxVolume[nIndex].dwValue = dwVol;
        m_VolumeControlDetails.cbDetails = nItems * sizeof(MIXERCONTROLDETAILS_UNSIGNED);
        m_VolumeControlDetails.paDetails = pmxVolume;
        if(mixerSetControlDetails((HMIXEROBJ)m_hMixer, &m_VolumeControlDetails, 
           MIXER_GETCONTROLDETAILSF_VALUE | MIXER_OBJECTF_HMIXER) == MMSYSERR_NOERROR)
		{
			bSuccess = TRUE;
        }
        delete[] pmxVolume;
    }
#endif

noMixer:
    if ( !bSuccess )
    {
	DWORD dwLRVol = MAKELONG(dwVol, dwVol) ;
	// fix of bug 4965, in which the balance is thrown to one side.  My speculation is that the
	// driver incorrectly reports MONO here when stereo is in use.  To fix the bug, set both
	// channels equally.  john dempsey

	/* related information: 
	"If a devicedoes not support both left and right volume control, the low-order
	 word of the dwVolume argument specifies the volume level and the
	 high-order word is ignored." -- some DEC document on waveOutSetVolume.
	*/

	HX_ASSERT(LOWORD(dwLRVol) == HIWORD(dwLRVol)) ;
	if (!zm_bVolSupport)
	{
	    return HXR_FAILED;
	}

	MMRESULT hResult    = waveOutSetVolume(m_hWave, dwLRVol);

	
	MMRESULT hResult2 = hResult;

	/* 
	 * always set the volume on NULL device. 
	 * Needed to attach volume control on win98 SE, Creative SB Live! Value sound card.
	 */
	if (m_hWave != NULL)
	{
	     hResult2 = waveOutSetVolume(NULL, dwLRVol);
	}

	if (hResult != MMSYSERR_NOERROR && hResult2 != MMSYSERR_NOERROR)
	{
	    return HXR_FAILED;
	}
    }

    return HXR_OK;
}

BOOL CAudioOutWindows::_Imp_SupportsVolume()
{
    MMRESULT wSuccess;
    WAVEOUTCAPS auxcap; 

#if defined(_WIN32) && !defined(_WINCE)
    if (!zm_bMixerVolSupportChecked)
    {
	CheckForVolumeSupport();
    }
#endif

#if defined(_WIN32) || defined(_WINCE)

	// Gonna have to make VolSupport static  
    if ( zm_bVolSupport )
    {
        return (zm_bVolSupport);
    }

    wSuccess = waveOutGetDevCaps( 0, &auxcap, sizeof(WAVEOUTCAPS) );

    if ( MMSYSERR_NOERROR == wSuccess )
    { 
        if (auxcap.dwSupport & WAVECAPS_VOLUME)
		{
		    zm_bVolSupport=TRUE;
		}

		if (auxcap.dwSupport & WAVECAPS_LRVOLUME)
		{
			zm_bLRVolSupport = TRUE;
		}
	
		zm_uMaxVolume = 100;
	}                   
    else
    {
        zm_bVolSupport = FALSE;
        zm_bLRVolSupport = FALSE;
    }

    return zm_bVolSupport;
#else
    return FALSE;
#endif /*_WIN32*/
}

HX_RESULT CAudioOutWindows:: _Imp_Open
( 
    const HXAudioFormat* pFormat
)
{

    HX_RESULT theErr = HXR_OK;
#if defined(_WIN32)
    LPWAVEFORMATEX	wavePtr;
#elif defined( _WINDOWS )
    LPWAVEFORMAT	wavePtr;
#endif

    theErr = Register();
    if (theErr)
    {
	return theErr;
    }
	
#ifdef _TESTING
    m_audfile =  open("\\auddev.raw", O_WRONLY | O_CREAT);
#endif

    m_WaveFormat.SetFormat(pFormat->ulSamplesPerSec, pFormat->uChannels, pFormat->uBitsPerSample);
    // Get the Windows style wave format!
    wavePtr = m_WaveFormat.GetWaveFormat();

    // We ain't closed now
    zm_bClosed = FALSE;

    // Open the wave driver.
#ifdef _WIN16
    MMRESULT wRet = waveOutOpen( &m_hWave, WAVE_MAPPER, wavePtr,
			(UINT16)m_hWnd, (DWORD)this, CALLBACK_WINDOW);
#else
    MMRESULT wRet = waveOutOpen( &m_hWave, WAVE_MAPPER, wavePtr,
			(DWORD)m_hWnd, (DWORD)this, CALLBACK_WINDOW);
#endif


    //	Okay, translate any error returns and get out if there was an error
    switch (wRet)
    {
	case MMSYSERR_NOERROR:	    theErr = HXR_OK;		break;
	case MMSYSERR_ALLOCATED:    theErr = HXR_AUDIO_DRIVER;	break;
	case MMSYSERR_NOMEM:	    theErr = HXR_OUTOFMEMORY;	break;
	case MMSYSERR_BADDEVICEID:  theErr = HXR_AUDIO_DRIVER;	break;
	case WAVERR_BADFORMAT:	    theErr = HXR_AUDIO_DRIVER;	break;
	case WAVERR_SYNC:	    theErr = HXR_AUDIO_DRIVER;	break;

⌨️ 快捷键说明

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