📄 winaudio.cpp
字号:
/* ***** 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#endifstruct IHXCallback;extern HINSTANCE g_hInstance;#define OFFSET_THIS 0#ifdef _TESTINGint m_audfile = -1;#endifBOOL 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 directlyconst 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 10CAudioOutWindows::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; }#endifnoMixer: 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 + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -