📄 drvrctxt.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
// -----------------------------------------------------------------------------
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// -----------------------------------------------------------------------------
#include "wavdrv.h"
/////////////////////////////////////////////////////////////////////////////
//
// CDriverContext Methods
//
/////////////////////////////////////////////////////////////////////////////
CDriverContext::CDriverContext (void)
{
MYTHIS_CONSTRUCTOR;
m_pDevice = NULL;
m_ulVolume = 0xFFFFFFFF; // volume start off at max.
m_pHead = NULL; // list of open mixer handles
m_pMxLineState = NULL;
m_pMxControlState = NULL;
}
CDriverContext::~CDriverContext ()
{
MYTHIS_CHECK;
if (m_pDevice != NULL) {
delete m_pDevice;
}
if (m_pMxLineState) {
delete [] m_pMxLineState;
}
if (m_pMxControlState) {
delete [] m_pMxControlState;
}
MYTHIS_DESTRUCTOR;
}
BOOL
CDriverContext::Initialize (PCTSTR pszActiveKey)
{
MYTHIS_CHECK;
// set up convenient access to our registry key
CRegKey regkey(pszActiveKey);
m_pDevice = new CES1371;
if (m_pDevice == NULL) {
DEBUGMSG(ZONE_ERROR, (TEXT("Unable to allocate device object\r\n")));
return FALSE;
}
if (! m_pDevice->MapDevice(®key)) {
DEBUGMSG (ZONE_ERROR, (TEXT("Error mapping device\r\n")));
return FALSE;
}
m_ulBufferSize = 16 * 1024;
regkey.QueryDword(TEXT("BufferSize"), m_ulBufferSize);
if (!m_pDevice->AudioInitialize(®key)) {
DEBUGMSG(ZONE_ERROR, (TEXT("CDriverContext::Initialize - failed to initialize device\r\n")));
return FALSE;
}
if (! InitializeMixerState ()) {
DEBUGMSG(ZONE_ERROR, (TEXT("CDriverContext::Initialize - failed to initialize mixer interface\r\n")));
return FALSE;
}
// find out what the hardware volume is set to so GetVolume returns an honest value
USHORT usVolume = m_pDevice->ReadCodecRegister(AC97_PCMOUT_VOL);
if (usVolume & 0x8000) {
m_ulVolume = 0;
}
else {
// AC97_PCMOUT_VOL has two five-bit fields, one for each stereo channel, indicating -Gain in 1.5dB steps
// 0 = zero attenuation
// 31 = 46.5 dB attenuation
ULONG ulLeft = 31 - ((usVolume & 0x1F00) >> 8);
ULONG ulRight = 31 - (usVolume & 0x001F);
// scale up from 5 to 16 bits
ulLeft <<= 11;
ulRight <<= 11;
// put into format expected by waveOutGetVolume (right high, left low)
m_ulVolume = (ulRight << 16) | ulLeft;
}
return TRUE;
}
MMRESULT
CDriverContext::GetCaps (ULONG msg, PWAVEOUTCAPS pCaps)
{
MYTHIS_CHECK;
pCaps->wMid = MM_MICROSOFT;
if (msg == WIDM_GETDEVCAPS) {
pCaps->wPid = MM_MSFT_WSS_WAVEIN; // generic in
}
else {
pCaps->wPid = MM_MSFT_WSS_WAVEOUT; // generic out...
}
pCaps->vDriverVersion = DRIVER_VERSION;
wsprintf (pCaps->szPname, DEVICE_NAME);
pCaps->dwFormats = WAVE_FORMAT_1M08 | WAVE_FORMAT_1M16 |
WAVE_FORMAT_1S08 | WAVE_FORMAT_1S16 |
WAVE_FORMAT_2M08 | WAVE_FORMAT_2M16 |
WAVE_FORMAT_2S08 | WAVE_FORMAT_2S16 |
WAVE_FORMAT_4M08 | WAVE_FORMAT_4M16 |
WAVE_FORMAT_4S08 | WAVE_FORMAT_4S16;
pCaps->wChannels = 2;
if (msg == WODM_GETDEVCAPS) {
// only fill out dwSupport for output caps
// this field is not present in the input caps
pCaps->dwSupport =
WAVECAPS_VOLUME
| WAVECAPS_LRVOLUME
| WAVECAPS_PLAYBACKRATE
| WAVECAPS_SAMPLEACCURATE
| WAVECAPS_DIRECTSOUND // supports Windows CE DirectSound Extensions
;
}
return MMSYSERR_NOERROR;
}
MMRESULT
CDriverContext::GetExtCaps (PWAVEOUTEXTCAPS pCaps)
{
pCaps->dwMaxHwStreams = 2;
pCaps->dwFreeHwStreams = m_pDevice->GetNumFreeDMAChannels(DMADIR_OUT);
pCaps->dwMinSampleRate = 100;
pCaps->dwMaxSampleRate = 48000;
// mixer stream parameters:
// The driver can specify the sample rate, buffer size and count for the mixer stream.
// This driver declines to state a preference by setting the values to zero.
pCaps->dwSwMixerSampleRate = 0;
pCaps->dwSwMixerBufferSize = 0;
pCaps->dwSwMixerBufferCount = 0;
return MMSYSERR_NOERROR;
}
MMRESULT
CDriverContext::OpenStream (ULONG msg, HSTREAM * ppStream, LPWAVEOPENDESC pWOD, DWORD dwFlags)
{
MYTHIS_CHECK;
MMRESULT mr;
if( pWOD->lpFormat->wFormatTag != WAVE_FORMAT_PCM
|| (pWOD->lpFormat->nChannels != 1 && pWOD->lpFormat->nChannels != 2)
|| (pWOD->lpFormat->wBitsPerSample != 8 && pWOD->lpFormat->wBitsPerSample != 16)
|| pWOD->lpFormat->nSamplesPerSec > 48000
|| pWOD->lpFormat->nSamplesPerSec < 100
) {
DEBUGMSG(ZONE_ERROR,(TEXT("CDriverContext::OpenStream - format not supported\r\n")));
return WAVERR_BADFORMAT;
}
if( (pWOD->lpFormat->nBlockAlign != (pWOD->lpFormat->wBitsPerSample * pWOD->lpFormat->nChannels) / 8)
|| (pWOD->lpFormat->nAvgBytesPerSec != pWOD->lpFormat->nBlockAlign * pWOD->lpFormat->nSamplesPerSec)
) {
DEBUGMSG(ZONE_ERROR,(TEXT("CDriverContext::OpenStream - ill-formed waveformat\r\n")));
return MMSYSERR_INVALPARAM;
}
if (dwFlags & WAVE_FORMAT_QUERY) {
// if this is just a query, we're done.
return MMSYSERR_NOERROR;
}
// attempt to allocate a DMA channel
ULONG ulChannelIndex;
mr = m_pDevice->AllocDMAChannel( (msg==WODM_OPEN) ? DMADIR_OUT : DMADIR_IN, m_ulBufferSize, &ulChannelIndex);
if (MMFAILED(mr)) {
DEBUGMSG(ZONE_ERROR,(TEXT("CDriverContext::OpenStream - allocate DMA channel failed\r\n")));
return mr;
}
// if that worked, allocate a stream context
HSTREAM pStream;
if (msg == WODM_OPEN) {
pStream = new COutputStreamContext;
}
else {
ASSERT(msg == WIDM_OPEN);
pStream = new CInputStreamContext;
}
if (pStream == NULL) {
DEBUGMSG(ZONE_ERROR, (TEXT("CDriverContext::OpenStream - CStreamContext::ctor failed\r\n")));
m_pDevice->FreeDMAChannel(ulChannelIndex);
return MMSYSERR_NOMEM;
}
mr = pStream->Initialize(m_pDevice, ulChannelIndex, pWOD);
if (MMFAILED(mr)) {
DEBUGMSG(ZONE_ERROR, (TEXT("CDriverContext::OpenStream - CStreamContext::Initialize failed\r\n")));
delete pStream;
return mr;
}
*ppStream = pStream;
// we're done! it all worked
return MMSYSERR_NOERROR;
}
MMRESULT
CDriverContext::GetVolume (PULONG pulVolume)
{
MYTHIS_CHECK;
*pulVolume = m_ulVolume;
return MMSYSERR_NOERROR;
}
MMRESULT
CDriverContext::SetVolume (ULONG ulVolume)
{
MYTHIS_CHECK;
// Device-level SetVolume semantics:
// Set the "global" volume that affects all other streams uniformly
// In the case of this device, that means the AC97_PCMOUT_VOL register.
m_ulVolume = ulVolume; // keep track of what the nominal volume is
USHORT usLeft = (USHORT) ((m_ulVolume & 0x0000F800) >> 11);
USHORT usRight = (USHORT) ((m_ulVolume & 0xF8000000) >> 27);
USHORT usRegVal;
if (usLeft == 0 && usRight == 0) {
// if zero, just mute the output
usRegVal = 0x8000;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -