📄 hwctxt.cpp
字号:
//-----------------------------------------------------------------------------
//
// Function: GetInterruptThreadPriority
//
// This function attempts to retrieve the thread priority for the audio
// IST from the registry and supplies a default priority if one is not
// found.
//
// Parameters:
// None.
//
// Returns:
// Returns thread priority for the audio IST.
//
//-----------------------------------------------------------------------------
DWORD HardwareContext::GetInterruptThreadPriority()
{
HKEY hDevKey;
DWORD dwValType;
DWORD dwValLen;
DWORD dwPrio = INTR_PRIORITY; // Default IST priority
hDevKey = OpenDeviceKey((LPWSTR)m_DriverIndex);
if (hDevKey)
{
dwValLen = sizeof(DWORD);
RegQueryValueEx(
hDevKey,
INTR_PRIORITY_REGKEY,
NULL,
&dwValType,
(PUCHAR)&dwPrio,
&dwValLen);
RegCloseKey(hDevKey);
}
return dwPrio;
}
//-----------------------------------------------------------------------------
//
// Function: InitInterruptThread
//
// This function initializes the IST for handling DMA interrupts.
//
// Parameters:
// None.
//
// Returns:
// Returns TRUE if successful, otherwise returns FALSE.
//
//-----------------------------------------------------------------------------
BOOL HardwareContext::InitInterruptThread()
{
DEBUGMSG(ZONE_FUNCTION,(_T("+HardwareContext::InitInterruptThread\n")));
// Create an automatic reset, unsignaled, and unnamed event for IST
// signaling.
m_hAudioInterrupt = CreateEvent(NULL, FALSE, FALSE, NULL);
// Check if event creation suceeded
if (!m_hAudioInterrupt)
{
ERRMSG("Unable to create audio interrupt event");
return(FALSE);
}
// Register the audio driver interrupts.
if (m_pSSI1)
{
if (! InterruptInitialize(m_dwSysintrSSI1, m_hAudioInterrupt, NULL, 0))
{
ERRMSG("Unable to initialize audio input interrupt for SSI1");
return FALSE;
}
// Mask SSI1 interrupts. SDMA transfer interrupts are used to signal
// the Interrupt Service Thread (IST).
InterruptMask(m_dwSysintrSSI1, TRUE);
}
if (m_pSSI2)
{
if (! InterruptInitialize(m_dwSysintrSSI2, m_hAudioInterrupt, NULL, 0))
{
ERRMSG("Unable to initialize audio output interrupt for SSI2");
return FALSE;
}
// Mask SSI2 interrupts. SDMA transfer interrupts are used to signal
// the Interrupt Service Thread (IST).
InterruptMask(m_dwSysintrSSI2, TRUE);
}
// Create the Interrupt Service Thread (IST).
m_hAudioInterruptThread =
CreateThread((LPSECURITY_ATTRIBUTES)NULL,
0,
(LPTHREAD_START_ROUTINE)CallInterruptThread,
this,
0,
NULL);
if (!m_hAudioInterruptThread)
{
ERRMSG("Unable to create audio interrupt event handling thread");
return FALSE;
}
// Bump up the priority since the interrupt must be serviced immediately.
CeSetThreadPriority(m_hAudioInterruptThread, GetInterruptThreadPriority());
DEBUGMSG(ZONE_FUNCTION,(_T("-HardwareContext::InitInterruptThread\n")));
return(TRUE);
}
//-----------------------------------------------------------------------------
//
// Function: PowerUp
//
// This function powers up the audio codec chip. Note that the audio CODEC
// chip is ONLY powered up when the user wishes to play or record.
//
// Parameters:
// None.
//
// Returns:
// Returns TRUE if successful, otherwise returns FALSE.
//
//-----------------------------------------------------------------------------
void HardwareContext::PowerUp()
{
BSPAudioPowerUp(TRUE);
// Restart the audio I/O operations that were suspended when PowerDown()
// was called.
if (g_saveOutputDMARunning)
{
StartOutputDMA();
}
#ifdef AUDIO_RECORDING_ENABLED
if (g_saveInputDMARunning)
{
StartInputDMA();
}
#endif
BSPAudioPowerUp(FALSE);
m_audioPowerdown = FALSE;
}
//-----------------------------------------------------------------------------
//
// Function: PowerDown
//
// This function powers down the audio codec chip. If the input/output
// channels are muted, then this function powers down the appropriate
// components of the audio codec chip in order to conserve battery power.
//
// The PowerDown() method will power down the entire audio chip while the
// PowerDown(const DWORD channel) allows for the independent powerdown of
// the input and/or output components to allow a finer degree of control.
//
// Parameters:
// None.
//
// Returns:
// None.
//
//-----------------------------------------------------------------------------
void HardwareContext::PowerDown()
{
// Note that for this special case, we do not need to grab the critical
// section via Lock() and Unlock() before calling StopOutputDMA() and
// StopInputDMA(). The powerdown thread runs at a high enough priority
// that all other threads will be blocked while it runs. Having the
// Lock() and Unlock() calls here may actually cause potential race
// condition problems during the shutdown process.
//
// Furthermore, we will not resume operation until the hardware is powered
// up again. At that point the hardware and audio driver state will be
// reinitialized again. So at this point, we can just go ahead and shut
// everything down.
// Manually set the timed delay disable events. This will explicitly
// trigger any in-progress delays to immediately terminate.
if (m_hAudioDelayDisableEvent[0] != NULL)
{
PulseEvent(m_hAudioDelayDisableEvent[0]);
}
#ifdef AUDIO_RECORDING_ENABLED
if (m_hAudioDelayDisableEvent[1] != NULL)
{
PulseEvent(m_hAudioDelayDisableEvent[1]);
}
#endif
// This tells the low-level PMIC driver to immediately terminate any
// pending timer delays.
BSPAudioPowerDown(FALSE);
// Set this flag to allow special handling for the powerdown procedure.
// The most important thing we want to avoid when powering down is using
// any sort of timer or other type of delay mechanism. We need to bypass
// anything like that and simply shutdown the hardware components when
// performing a powerdown operation.
m_audioPowerdown = TRUE;
// Save state for correct powerup handling.
g_saveOutputDMARunning = m_OutputDMARunning;
#ifdef AUDIO_RECORDING_ENABLED
g_saveInputDMARunning = m_InputDMARunning;
#endif
// Request all active audio-related DMA channels to stop.
StopOutputDMA();
#ifdef AUDIO_RECORDING_ENABLED
StopInputDMA();
#endif
// Request audio devices to power down.
BSPAudioPowerDown(TRUE);
}
//-----------------------------------------------------------------------------
//----------------------------- Helper Functions ------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//
// Function: TransferOutputBuffer
//
// This function retrieves the next "mixed" audio buffer of data to DMA into
// the output channel.
//
// Parameters:
// NumBuf
// [in] Output DMA page to be filled.
//
// Returns:
// Returns number of bytes placed into output buffer.
//
//-----------------------------------------------------------------------------
ULONG HardwareContext::TransferOutputBuffer(const PBYTE pBufferStart,
const PBYTE pBufferEnd)
{
ULONG BytesTransferred = 0;
PBYTE pBufferLast;
__try
{
pBufferLast = m_OutputDeviceContext.TransferBuffer(pBufferStart,
pBufferEnd,
NULL);
BytesTransferred = pBufferLast - pBufferStart;
// Only mark the DMA buffer as being in use if some data was actually
// transferred.
if (BytesTransferred > 0)
{
// Enable if you need to clear the rest of the DMA buffer
// TODO:
// Probably want to do something better than clearing out remaining
// buffer samples. DC output by replicating last sample or
// some type of fade out would be better.
StreamContext::ClearBuffer(pBufferLast, pBufferEnd);
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
DEBUGMSG(ZONE_ERROR, (TEXT("WAVDEV2.DLL:TransferOutputBuffer() - ")
TEXT("EXCEPTION: %d"), GetExceptionCode()));
}
return BytesTransferred;
}
//-----------------------------------------------------------------------------
//
// Function: TransferOutputBuffers
//
// This function determines which output buffer (A or B) needs to be filled
// with sound data. The correct buffer is then populated with data and ready
// to DMA to the output channel.
//
// Parameters:
// dwDCSR
// [in] Current status of the output DMA.
//
// Returns:
// Returns number of bytes placed into the output buffers.
//
//-----------------------------------------------------------------------------
ULONG HardwareContext::TransferOutputBuffers(DWORD dwDCSR)
{
ULONG BytesTransferred_A = 0;
ULONG BytesTransferred_B = 0;
if (dwDCSR & DMA_DONEA)
{
// DMA buffer A is free, try to refill it.
BytesTransferred_A =
TransferOutputBuffer(m_Output_pbDMA_PAGES[OUT_BUFFER_A],
m_Output_pbDMA_PAGES[OUT_BUFFER_A] +
AUDIO_DMA_PAGE_SIZE);
if (BytesTransferred_A > 0)
{
m_OutputDMAStatus &= ~DMA_DONEA;
}
}
if (dwDCSR & DMA_DONEB)
{
// DMA buffer B is free, try to refill it.
//
// Note that we can refill both DMA buffers at once if both DMA
// buffers are free and there is sufficient data.
//
BytesTransferred_B =
TransferOutputBuffer(m_Output_pbDMA_PAGES[OUT_BUFFER_B],
m_Output_pbDMA_PAGES[OUT_BUFFER_B] +
AUDIO_DMA_PAGE_SIZE);
if (BytesTransferred_B > 0)
{
m_OutputDMAStatus &= ~DMA_DONEB;
}
}
return BytesTransferred_A + BytesTransferred_B;
}
#ifdef AUDIO_RECORDING_ENABLED
//-----------------------------------------------------------------------------
//
// Function: TransferInputBuffer
//
// This function retrieves the chunk of recorded sound data and inputs
// it into an audio buffer for potential "mixing".
//
// Parameters:
// NumBuf
// [in] Input DMA page to be filled.
//
// Returns:
// Returns number of bytes placed into input buffer.
//
//-----------------------------------------------------------------------------
ULONG HardwareContext::TransferInputBuffer(ULONG NumBuf)
{
ULONG BytesTransferred = 0;
PBYTE pBufferStart = m_Input_pbDMA_PAGES[NumBuf];
PBYTE pBufferEnd = pBufferStart + AUDIO_DMA_PAGE_SIZE;
PBYTE pBufferLast;
__try
{
pBufferLast = m_InputDeviceContext.TransferBuffer(pBufferStart,
pBufferEnd,NULL);
BytesTransferred = pBufferLast - pBufferStart;
// We will mark the input DMA buffer as being in use again regardless
// of whether or not the data was completely copied out to an
// application-supplied data buffer. The input DMA buffer must be
// immediately reused because the audio recording operation is still
// running.
if(NumBuf == IN_BUFFER_A)
{
m_InputDMAStatus &= ~DMA_DONEA;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -