#include "CEchoGals.h"
Functions for opening and closing pipes
******************************************************************************/
ECHOSTATUS CEchoGals::OpenAudio
(
PECHOGALS_OPENAUDIOPARAMETERS pOpenParameters,
PWORD pwPipeIndex,
BOOL fCheckHardware,
CDaffyDuck *pDuck
)
{
CChannelMask cmMask;
WORD wPipeMax, wPipe, wPipeIndex, i, wWidth;
ECHOSTATUS Status;
ECHO_DEBUGPRINTF( ("CEchoGals::OpenAudio: %s %u "
"PipeWidth %d "
"Cyclic %u \n",
( pOpenParameters->Pipe.bIsInput ) ? "Input" : "Output",
pOpenParameters->Pipe.nPipe,
pOpenParameters->Pipe.wInterleave,
pOpenParameters->bIsCyclic) );
*pwPipeIndex = (WORD) -1;
if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() )
{
ECHO_DEBUGPRINTF( ("\tECHOSTATUS_DSP_DEAD\n") );
return ECHOSTATUS_DSP_DEAD;
}
if (fCheckHardware)
{
Status = GetDspCommObject()->LoadFirmware();
if ( ECHOSTATUS_OK != Status )
return Status;
}
wPipe = pOpenParameters->Pipe.nPipe;
wWidth = pOpenParameters->Pipe.wInterleave;
if ( pOpenParameters->Pipe.bIsInput )
{
wPipeIndex = wPipe + GetNumPipesOut();
wPipeMax = GetNumPipesIn();
}
else
{
wPipeIndex = wPipe;
wPipeMax = GetNumPipesOut();
}
if ( ( wPipe + wWidth ) > wPipeMax )
{
ECHO_DEBUGPRINTF( ("\tECHOSTATUS_INVALID_CHANNEL\n") );
return ECHOSTATUS_INVALID_CHANNEL;
}
if ( (0 == (m_wFlags & ECHOGALS_ROFLAG_SUPER_INTERLEAVE_OK)) &&
(wWidth > 2)
)
{
ECHO_DEBUGPRINTF( ("\tECHOSTATUS_NO_SUPER_INTERLEAVE\n") );
return ECHOSTATUS_NO_SUPER_INTERLEAVE;
}
for ( i = 0; i < pOpenParameters->Pipe.wInterleave; i++ )
{
cmMask.SetIndexInMask( wPipeIndex + i );
}
if ( m_cmAudioOpen.Test( &cmMask ) )
{
ECHO_DEBUGPRINTF( ("OpenAudio - ECHOSTATUS_CHANNEL_ALREADY_OPEN - m_cmAudioOpen 0x%x cmMask 0x%x\n",
m_cmAudioOpen.GetMask(),cmMask.GetMask()) );
return ECHOSTATUS_CHANNEL_ALREADY_OPEN;
}
#ifdef AUTO_DUCK_ALLOCATE
if (NULL == pDuck)
{
pDuck = CDaffyDuck::MakeDaffyDuck(m_pOsSupport);
if (NULL == pDuck)
return ECHOSTATUS_NO_MEM;
}
SetDaffyDuck( wPipeIndex, pDuck );
#else
if (NULL != pDuck)
SetDaffyDuck( wPipeIndex, pDuck );
#endif
ResetDmaPos(wPipeIndex);
GetDspCommObject()->ResetPipePosition(wPipeIndex);
m_cmAudioOpen += cmMask;
if ( pOpenParameters->bIsCyclic )
m_cmAudioCyclic += cmMask;
m_Pipes[ wPipeIndex ] = pOpenParameters->Pipe;
*pwPipeIndex = wPipeIndex;
m_ProcessId[ wPipeIndex ] = pOpenParameters->ProcessId;
Reset( wPipeIndex );
ECHO_DEBUGPRINTF( ("OpenAudio - ECHOSTATUS_OK - m_cmAudioOpen 0x%x\n",m_cmAudioOpen.GetMask()) );
return ECHOSTATUS_OK;
}
ECHOSTATUS CEchoGals::CloseAudio
(
PECHOGALS_CLOSEAUDIOPARAMETERS pCloseParameters,
BOOL fFreeDuck
)
{
CChannelMask cmMask;
ECHOSTATUS Status;
WORD i;
WORD wPipeIndex;
wPipeIndex = pCloseParameters->wPipeIndex;
ECHO_DEBUGPRINTF( ("CEchoGals::CloseAudio: Pipe %u ",
wPipeIndex) );
Status = VerifyAudioOpen( wPipeIndex );
if ( ECHOSTATUS_OK != Status )
return Status;
for ( i = 0;
i < m_Pipes[ wPipeIndex ].wInterleave;
i++ )
{
cmMask.SetIndexInMask( wPipeIndex + i );
}
Reset( wPipeIndex );
if (NULL != m_DaffyDucks[wPipeIndex])
{
if (fFreeDuck)
delete m_DaffyDucks[wPipeIndex];
m_DaffyDucks[wPipeIndex] = NULL;
}
m_cmAudioOpen -= cmMask;
m_cmAudioCyclic -= cmMask;
m_ProcessId[ wPipeIndex ] = NULL;
m_Pipes[ wPipeIndex ].wInterleave = 0;
ECHO_DEBUGPRINTF( ("CloseAudio - ECHOSTATUS_OK - m_cmAudioOpen 0x%x\n",m_cmAudioOpen.GetMask()) );
return ECHOSTATUS_OK;
}
ECHOSTATUS CEchoGals::VerifyAudioOpen
(
WORD wPipeIndex
)
{
CChannelMask cmMask;
if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() )
{
ECHO_DEBUGPRINTF( ("\tECHOSTATUS_DSP_DEAD\n") );
return ECHOSTATUS_DSP_DEAD;
}
cmMask.SetIndexInMask( wPipeIndex );
if ( !( m_cmAudioOpen.Test( &cmMask ) ) )
{
ECHO_DEBUGPRINTF( ("VerifyAudioOpen - ECHOSTATUS_CHANNEL_NOT_OPEN - wPipeIndex %d - m_cmAudioOpen 0x%x - cmMask 0x%x\n",
wPipeIndex,m_cmAudioOpen.GetMask(),cmMask.GetMask()) );
return ECHOSTATUS_CHANNEL_NOT_OPEN;
}
return ECHOSTATUS_OK;
}
ECHOSTATUS CEchoGals::GetActivePipes
(
PCChannelMask pChannelMask
)
{
if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() )
return ECHOSTATUS_DSP_DEAD;
GetDspCommObject()->GetActivePipes( pChannelMask );
return ECHOSTATUS_OK;
}
ECHOSTATUS CEchoGals::GetOpenPipes
(
PCChannelMask pChannelMask
)
{
if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() )
return ECHOSTATUS_DSP_DEAD;
*pChannelMask = m_cmAudioOpen;
return ECHOSTATUS_OK;
}
Functions for setting audio formats and the sample rate
******************************************************************************/
ECHOSTATUS CEchoGals::QueryAudioFormat
(
WORD wPipeIndex,
PECHOGALS_AUDIOFORMAT pAudioFormat
)
{
ECHOSTATUS Status = ECHOSTATUS_OK;
ECHO_DEBUGPRINTF( ("CEchoGals::QueryAudioFormat:\n") );
WORD wInterleave = pAudioFormat->wDataInterleave;
WORD wStoredPipeWidth = m_Pipes[ wPipeIndex ].wInterleave;
if (0 != wStoredPipeWidth)
{
if (wInterleave > wStoredPipeWidth)
{
ECHO_DEBUGPRINTF(("CEchoGals::QueryAudioFormat - pipe was opened "
"with a width of %d; interleave of %d invalid.\n",
wStoredPipeWidth,
pAudioFormat->wDataInterleave));
return ECHOSTATUS_BAD_FORMAT;
}
}
if (wInterleave > 2)
{
if (0 == (m_wFlags & ECHOGALS_ROFLAG_SUPER_INTERLEAVE_OK))
return ECHOSTATUS_NO_SUPER_INTERLEAVE;
if ( (0 != pAudioFormat->byDataAreBigEndian) ||
(0 != (wInterleave & 1) )
)
return ECHOSTATUS_BAD_FORMAT;
if ( (32 != pAudioFormat->wBitsPerSample) &&
(24 != pAudioFormat->wBitsPerSample) &&
(16 != pAudioFormat->wBitsPerSample) )
return ECHOSTATUS_BAD_FORMAT;
WORD wMaxPipe;
if (wPipeIndex >= GetNumPipesOut())
{
wMaxPipe = GetNumPipesIn();
wPipeIndex = wPipeIndex - GetNumPipesOut();
}
else
{
wMaxPipe = GetNumPipesOut();
}
if ( (wPipeIndex + wInterleave) > wMaxPipe)
return ECHOSTATUS_BAD_FORMAT;
return ECHOSTATUS_OK;
}
if ( (1 != pAudioFormat->wDataInterleave) &&
(2 != pAudioFormat->wDataInterleave) )
{
ECHO_DEBUGPRINTF( ("CEchoGals::QueryAudioFormat - interleave %d not allowed\n",
pAudioFormat->wDataInterleave));
return ECHOSTATUS_BAD_FORMAT;
}
if (pAudioFormat->byDataAreBigEndian)
{
if (pAudioFormat->wBitsPerSample != 32)
{
ECHO_DEBUGPRINTF(("CEchoGals::QueryAudioFormat - Only 32 bits per"
" sample supported for big-endian data\n"));
return ECHOSTATUS_BAD_FORMAT;
}
switch (pAudioFormat->wDataInterleave)
{
#ifdef STEREO_BIG_ENDIAN32_SUPPORT
case 1 :
case 2 :
break;
#else
case 1 :
break;
#endif
default :
ECHO_DEBUGPRINTF(("CEchoGals::QueryAudioFormat - Interleave of %d"
" not allowed for big-endian data\n",
pAudioFormat->wDataInterleave));
return ECHOSTATUS_BAD_FORMAT;
}
return ECHOSTATUS_OK;
}
switch ( pAudioFormat->wBitsPerSample )
{
case 8 :
case 16 :
case 24 :
case 32 :
break;
default :
ECHO_DEBUGPRINTF(
("CEchoGals::QueryAudioFormat: No valid format "
"specified, bits per sample %d\n",
pAudioFormat->wBitsPerSample) );
Status = ECHOSTATUS_BAD_FORMAT;
break;
}
return Status;
}
ECHOSTATUS CEchoGals::SetAudioFormat
(
WORD wPipeIndex,
PECHOGALS_AUDIOFORMAT pAudioFormat
)
{
ECHOSTATUS Status;
ECHO_DEBUGPRINTF( ("CEchoGals::SetAudioFormat: "
"for pipe %d\n",
wPipeIndex) );
Status = VerifyAudioOpen( wPipeIndex );
if ( ECHOSTATUS_OK != Status )
return Status;
Status = QueryAudioFormat( wPipeIndex, pAudioFormat );
if ( ECHOSTATUS_OK != Status )
return Status;
Status = GetDspCommObject()->SetAudioFormat( wPipeIndex, pAudioFormat );
return Status;
}
ECHOSTATUS CEchoGals::SetAudioFormat
(
PCChannelMask pChannelMask,
PECHOGALS_AUDIOFORMAT pAudioFormat
)
{
WORD wPipeIndex = 0xffff;
ECHOSTATUS Status;
if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() )
{
ECHO_DEBUGPRINTF( ("\tECHOSTATUS_DSP_DEAD\n") );
return ECHOSTATUS_DSP_DEAD;
}
for ( ; ; )
{
wPipeIndex = pChannelMask->GetIndexFromMask( ++wPipeIndex );
if ( (WORD) ECHO_INVALID_CHANNEL == wPipeIndex )
break;
if ( !( m_cmAudioOpen.TestIndexInMask( wPipeIndex ) ) )
{
ECHO_DEBUGPRINTF( ("CEchoGals::SetAudioFormat: "
"for pipe %d failed, pipe not open\n",
wPipeIndex) );
return ECHOSTATUS_CHANNEL_NOT_OPEN;
}
ECHO_DEBUGPRINTF( ("CEchoGals::SetAudioFormat: "
"for pipe %d\n",
wPipeIndex) );
Status = QueryAudioFormat( wPipeIndex, pAudioFormat );
if ( ECHOSTATUS_OK != Status )
return Status;
Status = GetDspCommObject()->SetAudioFormat( wPipeIndex, pAudioFormat );
if ( ECHOSTATUS_OK != Status )
return Status;
}
return ECHOSTATUS_OK;
}
ECHOSTATUS CEchoGals::GetAudioFormat
(
WORD wPipeIndex,
PECHOGALS_AUDIOFORMAT pAudioFormat
)
{
ECHO_DEBUGPRINTF( ("CEchoGals::GetAudioFormat: "
"for pipe %d\n",
wPipeIndex) );
GetDspCommObject()->GetAudioFormat( wPipeIndex, pAudioFormat );
return ECHOSTATUS_OK;
}
ECHOSTATUS CEchoGals::SetAudioSampleRate
(
DWORD dwSampleRate
)
{
ECHOSTATUS Status;
ECHO_DEBUGPRINTF( ("CEchoGals::SetAudioSampleRate: "
"to %ld Hz\n",
dwSampleRate) );
if ( 0 != (m_wFlags & ECHOGALS_FLAG_SAMPLE_RATE_LOCKED))
{
return ECHOSTATUS_OK;
}
else
{
Status = QueryAudioSampleRate( dwSampleRate );
if ( ECHOSTATUS_OK != Status )
return Status;
if ( dwSampleRate == GetDspCommObject()->SetSampleRate( dwSampleRate ) )
{
m_dwSampleRate = dwSampleRate;
return ECHOSTATUS_OK;
}
}
return ECHOSTATUS_BAD_FORMAT;
}
ECHOSTATUS CEchoGals::GetAudioSampleRate
(
PDWORD pdwSampleRate
)
{
ECHO_DEBUGPRINTF( ("CEchoGals::GetAudioSampleRate\n"));
*pdwSampleRate = m_dwSampleRate;
return ECHOSTATUS_OK;
}
Functions related to the scatter-gather list
******************************************************************************/
ECHOSTATUS CEchoGals::SetDaffyDuck(WORD wPipeIndex, CDaffyDuck *pDuck)
{
m_DaffyDucks[wPipeIndex] = pDuck;
return ECHOSTATUS_OK;
}
CDaffyDuck *CEchoGals::GetDaffyDuck(WORD wPipeIndex)
{
ECHO_DEBUGPRINTF(("CEchoGals::GetDaffyDuck for pipe index %d\n",wPipeIndex));
if (wPipeIndex >= GetNumPipes())
return NULL;
return m_DaffyDucks[wPipeIndex];
}
Functions for starting and stopping transport
******************************************************************************/
ECHOSTATUS CEchoGals::Start
(
WORD wPipeIndex
)
{
CChannelMask cmMask;
cmMask.SetIndexInMask( wPipeIndex );
return Start( &cmMask );
}
ECHOSTATUS CEchoGals::Start
(
PCChannelMask pChannelMask
)
{
WORD wPipe;
DWORD dwPhysStartAddr;
CChannelMask cmStart;
PVOID ProcessId = NULL;
CDspCommObject *pDCO;
pDCO = GetDspCommObject();
if ( NULL == pDCO || pDCO->IsBoardBad() )
return ECHOSTATUS_DSP_DEAD;
if ( GetFlags() & ECHOGALS_FLAG_SYNCH_WAVE )
{
wPipe = pChannelMask->GetIndexFromMask( 0 );
ProcessId = m_ProcessId[ wPipe ];
}
for (wPipe = 0; wPipe < GetNumPipes(); wPipe++)
{
PDWORD pdwDspCommPositions;
if (!pChannelMask->TestIndexInMask(wPipe))
continue;
if (NULL == m_DaffyDucks[ wPipe ])
{
ECHO_DEBUGPRINTF(("CDaffyDuck::Start - trying to start pipe index %d "
"but there is no CDaffyDuck!\n",wPipe));
return ECHOSTATUS_CHANNEL_NOT_OPEN;
}
if ( (0 != m_cmAudioCyclic.TestIndexInMask( wPipe ) ) &&
(FALSE == m_DaffyDucks[wPipe]->Wrapped())
)
{
ECHO_DEBUGPRINTF(("CEchoGals::Start called for pipe index %d - "
"pipe was opened in cyclic mode, but the duck "
"has not been wrapped\n",wPipe));
return ECHOSTATUS_DUCK_NOT_WRAPPED;
}
dwPhysStartAddr = m_DaffyDucks[wPipe]->GetPhysStartAddr();
pDCO->SetAudioDuckListPhys( wPipe, dwPhysStartAddr );
switch (m_byPipeState[wPipe])
{
case PIPE_STATE_RESET :
pdwDspCommPositions = pDCO->GetAudioPositionPtr();
pdwDspCommPositions[ wPipe ] = 0;
if (NULL == ProcessId)
{
m_byPipeState[ wPipe ] = PIPE_STATE_STARTED;
cmStart.SetIndexInMask( wPipe );
}
else
{
m_byPipeState[ wPipe ] = PIPE_STATE_PENDING;
}
break;
case PIPE_STATE_STOPPED :
if (NULL == ProcessId)
{
m_byPipeState[ wPipe ] = PIPE_STATE_STARTED;
cmStart.SetIndexInMask( wPipe );
}
else
{
m_byPipeState[ wPipe ] = PIPE_STATE_PENDING;
}
break;
case PIPE_STATE_PENDING :
case PIPE_STATE_STARTED :
break;
}
}
BOOL fAllReady = TRUE;
for ( wPipe = 0; wPipe < GetNumPipes(); wPipe++ )
{
if ( ( ProcessId == m_ProcessId[ wPipe ] ) &&
( PIPE_STATE_STOPPED == m_byPipeState[wPipe]))
{
ECHO_DEBUGPRINTF(("CEchoGals::Start - can't start; pipe %d "
"still set to state %d\n",
wPipe,
m_byPipeState[wPipe]));
fAllReady = FALSE;
}
}
if (fAllReady)
{
for (wPipe = 0; wPipe < GetNumPipes(); wPipe++)
{
if ( (ProcessId == m_ProcessId[ wPipe ]) &&
(PIPE_STATE_PENDING == m_byPipeState[ wPipe ]))
{
m_byPipeState[wPipe] = PIPE_STATE_STARTED;
cmStart.SetIndexInMask( wPipe );
ECHO_DEBUGPRINTF(("CEchoGals::Start - setting pipe %d to start\n",
wPipe));
}
}
}
if ( cmStart.IsEmpty() )
return ECHOSTATUS_OK;
return pDCO->StartTransport( &cmStart );
}
ECHOSTATUS CEchoGals::Stop
(
WORD wPipeIndex
)
{
CChannelMask cmMask;
cmMask.SetIndexInMask( wPipeIndex );
return( Stop( &cmMask ) );
}
ECHOSTATUS CEchoGals::Stop
(
PCChannelMask pChannelMask
)
{
INT32 i;
ECHOSTATUS Status;
if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() )
return ECHOSTATUS_DSP_DEAD;
Status = GetDspCommObject()->StopTransport( pChannelMask );
if ( ECHOSTATUS_OK != Status )
return Status;
for ( i = 0; i < GetNumPipes(); i++ )
{
if ( !pChannelMask->TestIndexInMask( (WORD) i ) )
continue;
if ( PIPE_STATE_STOPPED == m_byPipeState[ i ] )
continue;
UpdateDmaPos( (WORD) i );
m_byPipeState[ i ] = PIPE_STATE_STOPPED;
}
return Status;
}
ECHOSTATUS CEchoGals::Reset
(
WORD wPipeIndex
)
{
CChannelMask cmMask;
cmMask.SetIndexInMask( wPipeIndex );
return Reset( &cmMask );
}
ECHOSTATUS CEchoGals::Reset
(
PCChannelMask pChannelMask
)
{
WORD i;
ECHOSTATUS Status;
if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() )
return ECHOSTATUS_DSP_DEAD;
Status = GetDspCommObject()->ResetTransport( pChannelMask );
if ( ECHOSTATUS_OK != Status )
return Status;
for ( i = 0; i < GetNumPipes(); i++ )
{
if ( !pChannelMask->TestIndexInMask( (WORD) i ) )
continue;
if ( PIPE_STATE_RESET == m_byPipeState[ i ] )
continue;
UpdateDmaPos( i );
m_dwLastDspPos[ i ] = 0;
GetDspCommObject()->ResetPipePosition(i);
m_byPipeState[ i ] = PIPE_STATE_RESET;
}
return Status;
}
Functions for handling the current DMA position for pipes; the DMA position
is the number of bytes transported by a pipe.
******************************************************************************/
void CEchoGals::UpdateDmaPos( WORD wPipeIndex )
{
DWORD dwDspPos;
DWORD dwDelta;
dwDspPos = GetDspCommObject()->GetAudioPosition( wPipeIndex );
dwDelta = dwDspPos - m_dwLastDspPos[ wPipeIndex ];
m_ullDmaPos[ wPipeIndex ] += dwDelta;
m_dwLastDspPos[ wPipeIndex ] = dwDspPos;
}
void CEchoGals::ResetDmaPos(WORD wPipe)
{
m_ullDmaPos[ wPipe ] = 0;
m_dwLastDspPos[ wPipe ] = 0;
if (NULL != m_DaffyDucks[wPipe])
m_DaffyDucks[wPipe]->ResetStartPos();
}
ECHOSTATUS CEchoGals::GetAudioPositionPtr
(
WORD wPipeIndex,
PDWORD & pdwPosition
)
{
if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() )
return ECHOSTATUS_DSP_DEAD;
if (wPipeIndex >= GetNumPipes())
{
pdwPosition = NULL;
return ECHOSTATUS_INVALID_CHANNEL;
}
PDWORD pdwDspCommPos = GetDspCommObject()->GetAudioPositionPtr();
pdwPosition = pdwDspCommPos + wPipeIndex;
return ECHOSTATUS_OK;
}