📄 hxaudevds.cpp
字号:
/* ***** BEGIN LICENSE BLOCK ***** * Source last modified: $Id: hxaudevds.cpp,v 1.13.2.3 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"#if defined( _WINDOWS ) || defined( _WIN32 )#include <windows.h>#include <tchar.h>#include <mmsystem.h>#include "mmreg.h"#endif /*defined( _WINDOWS ) || defined( _WIN32 )*/#include <stdio.h>#include <string.h>#include "hxresult.h"#include "cbqueue.h"#include "cpqueue.h"#include "hxslist.h"#include "hxcom.h"#include "hxengin.h"#include "ihxpckts.h" #include "hxausvc.h"#include "auderrs.h"#include "math.h" #include "hxaudev.h"#include "tsconvrt.h"#include "hxaudevds.h"extern HINSTANCE g_hInstance;#include "hxheap.h"#ifdef _DEBUG#undef HX_THIS_FILE static const char HX_THIS_FILE[] = __FILE__;#endif#include "hlxosstr.h"#ifndef TEXT#define TEXT(w) OS_STRING(w)#endif#ifndef _WINDOWS#define TCHAR char#endiftypedef HRESULT (WINAPI* FPDIRECTSOUNDCREATE)(LPGUID lpGuid, LPDIRECTSOUND * ppDS, IUnknown FAR * pUnkOuter);static LRESULT CALLBACK HXDSWndProc(HWND, UINT, WPARAM, LPARAM);UINT CHXAudioDeviceDS::zm_uDestroyMessage = 0;const UINT32 kExitThreadWaitTime = 3000; // ms#define HXMSG_TIMESYNC WM_USER+501const TCHAR* szTitle = TEXT("Helix DSWnd");const TCHAR* szWindowClass = TEXT("Helix DSWndClass");const TCHAR* kDSWaitEvent = TEXT("HelixDirectSoundNotifyWait");const TCHAR* kDSDestroyMessage = TEXT("HX_DestroyDSWindowInternal");const int BUFFER_TIME = 8;extern BOOL RMEnableLogging();extern void RMDSLog(const char* pFormatString, ...);#define RMDS_LOG RMDSLogCHXAudioDeviceDS::CHXAudioDeviceDS(): m_ulLastPlayCursor(0) , m_ulLastWriteCursor(0) , m_ulCurrPlayTime(0) , m_ulCurrLoopTime(0) , m_pDSDev(NULL) , m_pPrimaryBuffer(NULL) , m_pSecondaryBuffer(NULL) , m_hwnd(NULL) , m_pAudioPtrStart(NULL) , m_hSoundDll(NULL) , m_ulLoops(0) , m_ulLoopTime(0) , m_hDSNotifyEvent(NULL) , m_hWaitThread(NULL) , m_nBlocksPerBuffer(0) , m_bExitThread(FALSE) , m_ulOriginalThreadId(0){ // Create a unique message for destroying the audio window if (!zm_uDestroyMessage) { zm_uDestroyMessage = RegisterWindowMessage(kDSDestroyMessage); }#ifdef _WINCE WNDCLASS wcex;#else WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.hIconSm = NULL;#endif wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = (WNDPROC)HXDSWndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = g_hInstance; wcex.hIcon = NULL; wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = NULL; wcex.lpszClassName = szWindowClass;#ifdef _WINCE RegisterClass(&wcex);#else RegisterClassEx(&wcex);#endif#ifdef _WINCE m_hwnd = ::CreateWindow(szWindowClass, szTitle, WS_OVERLAPPED|WS_BORDER|WS_CAPTION|WS_SYSMENU, -5000, -5000, 1, 1, NULL, NULL, g_hInstance, NULL );#else m_hwnd = ::CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, -5000, -5000, 1, 1, NULL, NULL, g_hInstance, NULL );#endif m_ulOriginalThreadId = GetCurrentThreadId(); m_hSoundDll = ::LoadLibrary( TEXT("dsound.dll") );}CHXAudioDeviceDS::~CHXAudioDeviceDS(){ if (m_hSoundDll) { FreeLibrary(m_hSoundDll); m_hSoundDll = NULL; } if (m_hwnd) {#if defined(_WIN32) if (m_ulOriginalThreadId == GetCurrentThreadId()) { SendMessage(m_hwnd, zm_uDestroyMessage, 0, 0); } else { PostMessage(m_hwnd, zm_uDestroyMessage, 0, 0); Sleep(0); }#else SendMessage(m_hwnd, zm_uDestroyMessage, 0, 0);#endif m_hwnd = NULL; }}/* * Set the format of the primary buffer, if possible. On WDM drivers, this has * no effect -- the kernel mixer determines that format. */HX_RESULT CHXAudioDeviceDS::SetPrimaryBufferFormat(){ HX_RESULT res = HXR_OK ; DSBUFFERDESC bufferDesc; ::memset(&bufferDesc, 0, sizeof(DSBUFFERDESC)); bufferDesc.dwSize = sizeof(DSBUFFERDESC); bufferDesc.lpwfxFormat = 0 ; bufferDesc.dwBufferBytes = 0 ; bufferDesc.dwFlags = DSBCAPS_PRIMARYBUFFER ; /* close the primary buffer if we had one open before. */ HX_RELEASE(m_pPrimaryBuffer) ; /* try to open with WAVE_FORMAT_EXTENSIBLE */ res = m_pDSDev->CreateSoundBuffer(&bufferDesc, &m_pPrimaryBuffer, NULL); if (res == DS_OK) { res = !DS_OK ; if (m_WaveFormat.Format.nChannels > 2) { res = m_pPrimaryBuffer->SetFormat(&m_WaveFormat.Format) ; } if (res != DS_OK) { /* if that fails, try to open with WAVE_FORMAT_PCM */ m_WaveFormat.Format.wFormatTag = WAVE_FORMAT_PCM ; res = m_pPrimaryBuffer->SetFormat(&m_WaveFormat.Format) ; } } return res ;}/* * IHXAudioDevice override methods */HX_RESULT CHXAudioDeviceDS::_Imp_Open(const HXAudioFormat* pFormat){ HX_RESULT theErr = HXR_FAIL; if(!m_hwnd || !m_hSoundDll) return theErr; // close open resources _Imp_Close() ; /* Get the IDirectSound interface */ FPDIRECTSOUNDCREATE fpCreateDS = (FPDIRECTSOUNDCREATE) ::GetProcAddress(m_hSoundDll, TEXT("DirectSoundCreate") ); if(!fpCreateDS) return theErr; theErr = fpCreateDS(NULL, &m_pDSDev, NULL); if (FAILED(theErr)) return theErr; /* set the cooperative level. Because we want control over the format of the primary buffer (16 bit, multichannel!), we need DSSCL_PRIORITY. */ m_pDSDev->SetCooperativeLevel(m_hwnd, DSSCL_PRIORITY ); /* fill out the wave format structure */ ::memset(&m_WaveFormat, 0, sizeof(m_WaveFormat)); m_WaveFormat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; m_WaveFormat.Format.nChannels = pFormat->uChannels; m_WaveFormat.Format.nSamplesPerSec = pFormat->ulSamplesPerSec; m_WaveFormat.Format.wBitsPerSample = pFormat->uBitsPerSample; m_WaveFormat.Format.nBlockAlign = pFormat->uBitsPerSample/8 * pFormat->uChannels; m_WaveFormat.Format.nAvgBytesPerSec = m_WaveFormat.Format.nBlockAlign * pFormat->ulSamplesPerSec ; m_WaveFormat.Format.cbSize = 22; m_WaveFormat.Samples.wValidBitsPerSample = pFormat->uBitsPerSample; m_WaveFormat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM ; m_WaveFormat.dwChannelMask = defaultChannelMapping(pFormat->uChannels) ; /* set the format of the primary buffer. This will fail on WDM systems (because the kernel mixer termines the primary buffer format), but is important on non-WDM systems. This might change the m_WaveFormat structure from a WAVE_FORMAT_EXTENSIBLE to a WAVEFORMATEX. Ignore the result. */ SetPrimaryBufferFormat() ; /* Now open a secondary buffer. */ DSBUFFERDESC bufferDesc; ::memset(&bufferDesc, 0, sizeof(DSBUFFERDESC)); bufferDesc.dwSize = sizeof(DSBUFFERDESC); bufferDesc.lpwfxFormat = &m_WaveFormat.Format; // Manipulate the buffer size so that is is an exact multiple of the block size. // This will ensure that our write positions on the buffer are the same in every loop. // We need to do this so that we have fixed playback notification positions marking the end each write block. m_nBlocksPerBuffer = (m_WaveFormat.Format.nAvgBytesPerSec*BUFFER_TIME)/pFormat->uMaxBlockSize; m_ulTotalBuffer = pFormat->uMaxBlockSize*m_nBlocksPerBuffer; m_ulLoopTime = (double)m_ulTotalBuffer / (double)m_WaveFormat.Format.nAvgBytesPerSec; bufferDesc.dwBufferBytes = m_ulTotalBuffer ; bufferDesc.dwFlags = DSBCAPS_CTRLVOLUME | // so we can control the volume DSBCAPS_GETCURRENTPOSITION2 | // finer position reports DSBCAPS_CTRLPOSITIONNOTIFY | // have them reported here DSBCAPS_GLOBALFOCUS | // take control! DSBCAPS_STICKYFOCUS ; /* Again, try with WAVE_FORMAT_EXTENSIBLE first, but only if multichannel. */ theErr = !DS_OK ; if (m_WaveFormat.Format.nChannels > 2) { m_WaveFormat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; theErr = m_pDSDev->CreateSoundBuffer(&bufferDesc, &m_pSecondaryBuffer, NULL); } if (theErr != DS_OK) { /* and if that fails, try WAVEFORMATEX */ m_WaveFormat.Format.wFormatTag = WAVE_FORMAT_PCM; theErr = m_pDSDev->CreateSoundBuffer(&bufferDesc, &m_pSecondaryBuffer, NULL); } /* call it a day and count our blessings. */ switch (theErr) { case DS_OK: theErr = HXR_OK; break; case DSERR_OUTOFMEMORY: theErr = HXR_OUTOFMEMORY; break; default: theErr = HXR_FAIL; break; } if (SUCCEEDED(theErr) && m_pSecondaryBuffer) { m_eState = E_DEV_OPENED; KillThreadAndEvent(); SetWindowLong(m_hwnd, GWL_USERDATA, (LONG)this); // Create the event to be signalled on playback position notifications and the thread to wait for those events to be signalled. m_hDSNotifyEvent = CreateEvent(NULL, TRUE, FALSE, kDSWaitEvent); // now set the notification positions for direct sound playback. IDirectSoundNotify* pNotify = NULL; m_pSecondaryBuffer->QueryInterface(IID_IDirectSoundNotify, (void**)&pNotify); if(pNotify && m_hDSNotifyEvent) { DSBPOSITIONNOTIFY* aPositionNotify = new DSBPOSITIONNOTIFY[m_nBlocksPerBuffer]; if(aPositionNotify) { for(int i = 0; i < m_nBlocksPerBuffer; i++) { aPositionNotify[i].dwOffset = i * pFormat->uMaxBlockSize; aPositionNotify[i].hEventNotify = m_hDSNotifyEvent;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -