Windows2003-3790/termsrv/newclient/rdpdr/rdpsndc.cpp
2020-09-30 16:53:55 +02:00

2977 lines
74 KiB
C++

/////////////////////////////////////////////////////////////////////
//
// Module: rdpsndc.c
//
// Purpose: Client-side audio redirection
//
// Copyright(C) Microsoft Corporation 2000
//
// History: 4-10-2000 vladimis [created]
//
/////////////////////////////////////////////////////////////////////
#include "precom.h"
#include <sha.h>
#include <rc4.h>
#include "rdpsndc.h"
#undef ASSERT
#ifdef DBG
#undef TRC
#define TRC _DbgPrintMessage
#define ASSERT(Cond) if (!(Cond)) \
{ \
::_DbgPrintMessage( \
FATAL, \
_T("ASSERT in file: %s, line %d\n"), \
_T(__FILE__), \
__LINE__); \
DebugBreak(); \
}
#else // !DBG
#define TRC
#define ASSERT
#endif // !DBG
#ifdef UNICODE
#define _NAMEOFCLAS L"RDPSoundWnd"
#else // !UNICODE
#define _NAMEOFCLAS "RDPSoundWnd"
#endif
#define WM_WSOCK WM_USER
#define WM_RESAMPLE (WM_USER + 1)
#define WAVE_CLOSE_TIMEOUT 3000
//
// WMA codec description
//
#define WMAUDIO_DEC_KEY "1A0F78F0-EC8A-11d2-BBBE-006008320064"
#define WAVE_FORMAT_WMAUDIO2 0x161
#ifdef _WIN32
#include <pshpack1.h>
#else
#ifndef RC_INVOKED
#pragma pack(1)
#endif
#endif
typedef struct wmaudio2waveformat_tag {
WAVEFORMATEX wfx;
DWORD dwSamplesPerBlock;
WORD wEncodeOptions;
DWORD dwSuperBlockAlign;
} WMAUDIO2WAVEFORMAT;
#ifdef _WIN32
#include <poppack.h>
#else
#ifndef RC_INVOKED
#pragma pack()
#endif
#endif
// Trace levels
//
const TCHAR *ALV = _T("TSSNDC - ALV:");
const TCHAR *INF = _T("TSSNDC - INF:");
const TCHAR *WRN = _T("TSSNDC - WRN:");
const TCHAR *ERR = _T("TSSNDC - ERR:");
const TCHAR *FATAL = _T("TSSNDC - !FATAL!:");
/*
* Function declarations
*
*/
VOID
VCAPITYPE
OpenEventFnEx(
IN PVOID lpUserParam,
IN DWORD OpenHandle,
IN UINT event,
IN PVOID pData,
IN UINT32 dataLength,
IN UINT32 totalLength,
IN UINT32 dataFlags
);
INT
WSInit(
VOID
);
LRESULT
CALLBACK
MsgWndProc(
HWND hwnd,
UINT uiMessage,
WPARAM wParam,
LPARAM lParam
);
VOID
_cdecl
_DbgPrintMessage(
LPCTSTR level,
LPCTSTR format,
...
);
//////////////////////////////////////////////////////////////////////////
/*
* Function:
* OpenEventFn
*
* Description:
* Called by the TS client on channel read/write ready
*
* Parameters:
* lpUserParam - parameter passed from VirtualChannelEntryEx
* OpenaHandle - Channel handle, returned by VirtualChanneOpen
* event - event type
* pData - meaning depends on event type
* dataLength - size of pData
* dataFlags - information about the received data
*
*/
VOID
VCAPITYPE
OpenEventFnEx(
IN PVOID lpUserParam,
IN DWORD OpenHandle,
IN UINT event,
IN PVOID pData,
IN UINT32 dataLength,
IN UINT32 totalLength,
IN UINT32 dataFlags
)
{
CRDPSound *pSnd;
ASSERT( NULL != lpUserParam );
if ( NULL != lpUserParam )
{
pSnd = ((VCManager*)lpUserParam)->GetSound();
ASSERT( NULL != pSnd );
if ( NULL != pSnd )
pSnd->OpenEventFn(
OpenHandle,
event,
pData,
dataLength,
totalLength,
dataFlags
);
}
}
LRESULT
CALLBACK
MsgWndProc(
HWND hwnd,
UINT uiMessage,
WPARAM wParam,
LPARAM lParam
)
{
LRESULT rv = 0;
CRDPSound *pSnd;
pSnd = (CRDPSound *)
#ifndef OS_WINCE
GetWindowLongPtr( hwnd, GWLP_USERDATA );
#else // OS_WINCE
GetWindowLong( hwnd, GWL_USERDATA );
#endif
switch (uiMessage)
{
case MM_WOM_OPEN:
ASSERT( NULL != pSnd );
if ( NULL != pSnd )
pSnd->vcwaveCallback( (HWAVEOUT)wParam, WOM_OPEN, NULL );
break;
case MM_WOM_CLOSE:
ASSERT( NULL != pSnd );
if ( NULL != pSnd )
pSnd->vcwaveCallback( (HWAVEOUT)wParam, WOM_CLOSE, NULL );
break;
case MM_WOM_DONE:
ASSERT( NULL != pSnd );
if ( NULL != pSnd )
pSnd->vcwaveCallback((HWAVEOUT)wParam, WOM_DONE, (LPWAVEHDR)lParam);
break;
case WM_RESAMPLE:
ASSERT( NULL != pSnd );
if ( NULL != pSnd )
pSnd->vcwaveResample();
break;
case WM_WSOCK:
ASSERT( NULL != pSnd );
pSnd->DGramSocketMessage(wParam, lParam);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
rv = DefWindowProc(hwnd, uiMessage, wParam, lParam);
}
return rv;
}
/*
* Function:
* InitEventFn
*
* Description:
* Called by InitEventFn
*
* Parameters:
* pInitHandle - connection handle
* event - Event id
* pData - Data, meaning depends on event id
* dataLength - Length of data
* (see MSDN: VirtualChannelInitEvent)
*
*/
VOID
CRDPSound::InitEventFn(
PVOID pInitHandle,
UINT event,
PVOID pData,
UINT dataLength
)
{
UINT rc;
UNREFERENCED_PARAMETER(dataLength);
ASSERT( pInitHandle == m_pInitHandle );
switch(event)
{
case CHANNEL_EVENT_INITIALIZED:
TRC(ALV, _T("InitEventFnEx: CHANNEL_EVENT_INITILIZED\n"));
::WSInit();
/*
#ifdef OS_WINCE
#error create single instance
::WSAStartAsyncThread();
#endif // OS_WINCE
*/
CreateMsgWindow(m_hInst);
break;
case CHANNEL_EVENT_CONNECTED:
TRC(ALV, _T("InitEventFnEx: CHANNEL_EVENT_CONNECTED to %s\n"), pData);
ASSERT(m_ChannelEntries.pVirtualChannelOpenEx);
rc = (m_ChannelEntries.pVirtualChannelOpenEx)(
pInitHandle,
&m_dwChannel,
_SNDVC_NAME,
OpenEventFnEx
);
if (rc != CHANNEL_RC_OK)
{
TRC(WRN, _T("InitEventFnEx: VirtualChannelOpen returned %d\n"), rc);
m_dwChannel = INVALID_CHANNELID;
} else {
// All's OK, check the channel handle
//
ASSERT(m_dwChannel != INVALID_CHANNELID);
}
// Prepare for connectionless data
//
DGramInit();
break;
case CHANNEL_EVENT_DISCONNECTED:
TRC(ALV, _T("InitEventFnEx: CHANNEL_EVENT_DISCONNECTED\n"));
ASSERT(m_ChannelEntries.pVirtualChannelCloseEx);
if (m_dwChannel != INVALID_CHANNELID)
{
rc = m_ChannelEntries.pVirtualChannelCloseEx(
m_pInitHandle,
m_dwChannel
);
if (rc != CHANNEL_RC_OK)
{
TRC(WRN, _T("InitEventFnEx: VirtualChannelClose returned %d\n"), rc);
}
m_dwChannel = INVALID_CHANNELID;
if (NULL != m_hWave)
{
waveOutReset(m_hWave);
vcwaveClose();
}
}
// destroy the UDP socket
//
DGramDone();
m_bPrologReceived = FALSE;
m_dwBytesInProlog = 0;
m_dwBytesInBody = 0;
//
// dispose the cache format
//
vcwaveCleanSoundFormats();
vcwaveFreeAllWaves();
_FragSlotFreeAll();
break;
case CHANNEL_EVENT_V1_CONNECTED:
TRC(ALV, _T("InitEventFnEx: CHANNEL_EVENT_V1_CONNECTED\n"));
break;
case CHANNEL_EVENT_TERMINATED:
TRC(ALV, _T("InitEventFnEx: CHANNEL_EVENT_TERMINATED\n"));
WSACleanup();
if (NULL != m_hWave)
{
waveOutReset(m_hWave);
vcwaveClose();
}
DGramDone();
/*
#ifdef OS_WINCE
#error see previous error
::WSACloseAsyncThread();
#endif // OS_WINCE
*/
if ( NULL != m_pProlog )
{
free( m_pProlog );
m_pProlog = NULL;
}
if ( NULL != m_pMsgBody )
{
free( m_pMsgBody );
m_pMsgBody = NULL;
}
vcwaveCleanSoundFormats();
vcwaveFreeAllWaves();
_FragSlotFreeAll();
DestroyMsgWindow();
break;
default:
TRC(ALV, _T("Unhandled event in InitEventFnEx: %d\n"), event);
}
}
/*
* Function:
* OpenEventFn
*
* Description:
* Called by OpenEventFnEx
*
* Parameters:
* OpenaHandle - Channel handle, returned by VirtualChanneOpen
* event - event type
* pData - meaning depends on event type
* dataLength - size of pData
* dataFlags - information about the received data
*
*/
VOID
CRDPSound::OpenEventFn(
DWORD OpenHandle,
UINT event,
PVOID pData,
UINT32 dataLength,
UINT32 totalLength,
UINT32 dataFlags
)
{
UNREFERENCED_PARAMETER(OpenHandle);
switch (event)
{
case CHANNEL_EVENT_DATA_RECEIVED:
#if _IO_DBG
TRC(ALV,
"OpenEventFn: CHANNEL_EVENT_DATA_RECEIVED, dataSize=0x%x, total=0x%x\n",
dataLength,
totalLength);
#endif
//
// save the data in global buffers
//
if (!m_bPrologReceived)
{
//
// receive the prolog (1st message)
//
if ( 0 != ( dataFlags & CHANNEL_FLAG_FIRST ))
m_dwBytesInProlog = 0;
if ( NULL == m_pProlog )
{
ASSERT( 0 != ( dataFlags & CHANNEL_FLAG_FIRST ));
m_pProlog = malloc( totalLength );
if ( NULL == m_pProlog )
{
TRC( FATAL, _T("OpenEventFn: failed to allocate %d bytes\n"),
totalLength);
break;
}
m_dwPrologAllocated = totalLength;
}
if ( totalLength > m_dwPrologAllocated )
{
PVOID pNewProlog;
ASSERT( 0 != ( dataFlags & CHANNEL_FLAG_FIRST ));
pNewProlog = realloc( m_pProlog, totalLength );
if ( NULL == pNewProlog )
{
TRC( FATAL, _T("OpenEventFn: failed to allocate %d bytes\n"),
totalLength);
free ( m_pProlog );
m_pProlog = NULL;
m_dwPrologAllocated = 0;
break;
}
m_pProlog = pNewProlog;
m_dwPrologAllocated = totalLength;
}
if ( m_dwBytesInProlog + dataLength > m_dwPrologAllocated )
{
TRC( ERR, _T("An invalid VC packet received. Ignoring\n" ));
break;
}
memcpy( ((LPSTR)m_pProlog) + m_dwBytesInProlog, pData, dataLength );
m_dwBytesInProlog += dataLength;
ASSERT( m_dwBytesInProlog <= totalLength );
if ( 0 != ( dataFlags & CHANNEL_FLAG_LAST ))
{
m_bPrologReceived = TRUE;
ASSERT( sizeof(SNDPROLOG) <= m_dwBytesInProlog );
//
// check if we expect a body
//
ASSERT( m_dwBytesInProlog - sizeof(SNDPROLOG) <=
((PSNDPROLOG)m_pProlog)->BodySize);
if ( m_dwBytesInProlog - sizeof(SNDPROLOG) ==
((PSNDPROLOG)m_pProlog)->BodySize )
{
// no, proceed the message
//
DataArrived(
(PSNDPROLOG)m_pProlog,
((PSNDPROLOG)m_pProlog) + 1
);
m_bPrologReceived = FALSE;
m_dwBytesInProlog = 0;
m_dwBytesInBody = 0;
}
}
} else {
//
// receive the body (2nd message)
//
if ( 0 != ( dataFlags & CHANNEL_FLAG_FIRST ))
m_dwBytesInBody = 0;
if ( NULL == m_pMsgBody )
{
ASSERT( 0 != ( dataFlags & CHANNEL_FLAG_FIRST ));
m_pMsgBody = malloc( totalLength );
if ( NULL == m_pMsgBody )
{
TRC( FATAL, _T("OpenEventFn: failed to allocate %d bytes\n"),
totalLength);
break;
}
m_dwBodyAllocated = totalLength;
}
if ( totalLength > m_dwBodyAllocated )
{
PVOID pNewBody;
ASSERT( 0 != ( dataFlags & CHANNEL_FLAG_FIRST ));
pNewBody = realloc( m_pMsgBody, totalLength );
if ( NULL == pNewBody )
{
TRC( FATAL, _T("OpenEventFn: failed to allocate %d bytes\n"),
totalLength);
free ( m_pMsgBody );
m_pMsgBody = NULL;
m_dwBodyAllocated = 0;
break;
}
m_pMsgBody = pNewBody;
m_dwBodyAllocated = totalLength;
}
if ( m_dwBytesInBody + dataLength > m_dwBodyAllocated )
{
TRC( ERR, _T("An invalid VC packet received. Ignoring\n" ));
break;
}
memcpy( ((LPSTR)m_pMsgBody) + m_dwBytesInBody, pData, dataLength );
m_dwBytesInBody += dataLength;
ASSERT( m_dwBytesInBody <= totalLength );
if ( 0 != ( dataFlags & CHANNEL_FLAG_LAST ))
{
UINT32 *pdw;
//
// here comes the magic
// the server sends two packets, but it is possible
// in case of switching between sessions (or shadowing ?!)
// that the client can receive first packet from one session
// and the second from another
// that's why we have a valid message type for each packet
// by replacing the first word of the second message
// this word is kept in the end of the first message
//
if ( NULL != m_pMsgBody &&
SNDC_NONE != *((UINT32 *)m_pMsgBody) )
{
LPVOID pSwap;
DWORD dwSwap;
TRC(ERR, _T("OpenEventFn: messages not synchronized. ")
_T("Trying to fix it\n"));
pSwap = m_pProlog;
m_pProlog = m_pMsgBody;
m_pMsgBody = pSwap;
dwSwap = m_dwPrologAllocated;
m_dwPrologAllocated = m_dwBodyAllocated;
m_dwBodyAllocated = dwSwap;
m_dwBytesInProlog = m_dwBytesInBody;
m_dwBytesInBody = 0;
// we swapped the body and the prolog
// now, wait for the actual body
//
break;
}
//
// from the end of the prolog message, remove
// UINT32 word and place it at the begining of the body
//
ASSERT( sizeof(SNDPROLOG) + sizeof(UINT32) <= m_dwBytesInProlog);
if ( sizeof(SNDPROLOG) + sizeof(UINT32) > m_dwBytesInProlog )
{
TRC( ERR, _T("An invalid VC packet received. Ignoring\n" ));
break;
}
pdw = (UINT32 *)(((LPSTR)m_pProlog) +
m_dwBytesInProlog - sizeof(UINT32));
*((UINT32 *)m_pMsgBody) = *pdw;
//
// cut the prolog length by UINT32 size
//
m_dwBytesInProlog -= sizeof(UINT32);
DataArrived(
(PSNDPROLOG)m_pProlog,
m_pMsgBody
);
m_bPrologReceived = FALSE;
m_dwBytesInProlog = 0;
m_dwBytesInBody = 0;
}
}
break;
case CHANNEL_EVENT_WRITE_COMPLETE:
{
TRC(ALV, _T("OpenEventFn: CHANNEL_EVENT_WRITE_COMPLETE, ptr=0x%p\n"),
pData);
free(pData);
}
break;
case CHANNEL_EVENT_WRITE_CANCELLED:
{
TRC(WRN, _T("OpenEventFn: CHANNEL_EVENT_WRITE_CANCELED. Cleaning up\n"));
free(pData);
}
break;
default:
TRC(ALV, _T("Unhandled event in OpenEventFn: %d\n"), event);
}
}
/*
* Function:
* ChannelWriteNCopy
*
* Description:
* Allocates a chunk of memory and sends it using ChannelWrite
* Allows the caller to free or reuse the buffer
*
* Parameters:
* pBuffer - Chunk pointer
* uiSize - Chunk size
*
* Returns:
* TRUE on success
*
*/
BOOL
CRDPSound::ChannelWriteNCopy(
LPVOID pBuffer,
UINT32 uiSize
)
{
BOOL rv = FALSE;
LPVOID pSendBuffer = NULL;
if ( INVALID_CHANNELID == m_dwChannel )
{
TRC(ERR, _T("ChannelWriteNCopy: invalid handle\n"));
goto exitpt;
}
if (NULL == pBuffer)
{
TRC(ERR, _T("ChannelWriteNCopy: buffer is NULL\n"));
goto exitpt;
}
pSendBuffer = malloc(uiSize);
if (pSendBuffer)
{
memcpy(pSendBuffer, pBuffer, uiSize);
rv = ChannelWrite( pSendBuffer, uiSize );
}
exitpt:
if (!rv)
{
if (pSendBuffer)
free(pSendBuffer);
}
return rv;
}
/*
* Function:
* DataArrived
*
* Description:
* Processes a message arrived from the channel
*
* Parameters:
* pProlog - the message prolog, type and body size
* pBody - pointer to the message body
*
*/
VOID
CRDPSound::DataArrived(
PSNDPROLOG pProlog,
LPVOID pBody
)
{
ASSERT(pProlog);
ASSERT(pBody);
switch(pProlog->Type)
{
case SNDC_CLOSE:
TRC(ALV, _T("DataArrived: SNDC_CLOSE\n"));
if (m_hWave)
{
vcwaveClose();
}
break;
case SNDC_SETVOLUME:
{
PSNDSETVOLUME pSetVolume;
TRC(ALV, _T("DataArrived: SNDC_SETVOLUME\n"));
if ( pProlog->BodySize < sizeof( *pSetVolume ) - sizeof( *pProlog ))
{
TRC( ERR, _T("DataArrived: Invalid SNDC_SETVOLUME message\n" ));
break;
}
pSetVolume = (PSNDSETVOLUME)
(((LPSTR)pBody) - sizeof(*pProlog));
ASSERT(pProlog->BodySize == sizeof(*pSetVolume) - sizeof(*pProlog));
if (m_hWave)
waveOutSetVolume(m_hWave, pSetVolume->dwVolume);
}
break;
case SNDC_WAVE:
{
PSNDWAVE pWave;
//
// disable dgram response
//
m_dwRemoteDGramPort = 0;
m_ulRemoteDGramAddress = 0;
pWave = (PSNDWAVE)pProlog;
TRC(ALV, _T("DataArrived: SNDC_WAVE, block no: %d\n"),
pWave->cBlockNo);
if ( pProlog->BodySize < sizeof( *pWave ) - sizeof( *pProlog ))
{
TRC( ERR, _T("DataArrived: Invalid SNDC_WAVE message\n" ));
break;
}
vcwaveWrite(pWave->cBlockNo,
pWave->wFormatNo,
pWave->wTimeStamp,
pWave->Prolog.BodySize - sizeof(SNDWAVE) + sizeof(SNDPROLOG),
pBody);
}
break;
case SNDC_TRAINING:
{
SNDTRAINING SndTraining;
PSNDTRAINING pRecvTraining;
if ( pProlog->BodySize < sizeof( *pRecvTraining ) - sizeof( *pProlog ))
{
TRC( ERR, _T("DataArrived: Invalid SNDC_TRAINING message\n" ));
break;
}
//
// disable dgram response
//
m_dwRemoteDGramPort = 0;
m_ulRemoteDGramAddress = 0;
pRecvTraining = (PSNDTRAINING)
(((LPSTR)pBody) - sizeof(*pProlog));
TRC(ALV, _T("DataArrived: training, sending a response\n"));
SndTraining.Prolog.Type = SNDC_TRAINING;
SndTraining.Prolog.BodySize = sizeof(SndTraining) -
sizeof(SndTraining.Prolog);
SndTraining.wTimeStamp = pRecvTraining->wTimeStamp;
SndTraining.wPackSize = pRecvTraining->wPackSize;
//
// send the response immediatly
//
ChannelWriteNCopy( &SndTraining, sizeof(SndTraining) );
}
break;
case SNDC_FORMATS:
{
PSNDFORMATMSG pSndFormats;
PSNDFORMATMSG pSndFormatsResp;
PSNDFORMATITEM pSndSuppFormats = NULL;
DWORD dwRespSize;
DWORD dwListSize;
DWORD dwNumFormats;
BOOL bSuccess;
DWORD dwPacketSize;
DWORD count;
PSNDFORMATITEM pFmt;
pSndFormats = (PSNDFORMATMSG)
(((LPSTR)pBody) - sizeof(*pProlog));
TRC(ALV, _T("DataArrived: SNDC_FORMATS, number of formats: %d\n"),
pSndFormats->wNumberOfFormats);
if ( pProlog->BodySize < sizeof( *pSndFormats ) - sizeof( *pProlog ))
{
TRC( ERR, _T("DataArrived: Invalid SNDC_FORMATS message\n" ));
break;
}
//
// validate the packet length
//
dwPacketSize = pProlog->BodySize - sizeof( *pSndFormats ) + sizeof( *pProlog );
pFmt = (PSNDFORMATITEM) (pSndFormats + 1);
for( count = 0; count < pSndFormats->wNumberOfFormats; count ++ )
{
DWORD adv = sizeof( *pFmt ) + pFmt->cbSize;
if ( adv > dwPacketSize )
{
TRC( ERR, _T("DataArrived: Invalid SNDC_FORMATS, invalid format list\n" ));
goto break_sndformat;
}
pFmt = (PSNDFORMATITEM)((LPSTR)pFmt + adv);
dwPacketSize -= adv;
}
ASSERT( 0 == dwPacketSize );
m_cLastReceivedBlock = pSndFormats->cLastBlockConfirmed;
vcwaveCleanSoundFormats();
bSuccess = vcwaveChooseSoundFormat(
pSndFormats->wNumberOfFormats,
(PSNDFORMATITEM) (pSndFormats + 1),
&pSndSuppFormats,
&dwListSize,
&dwNumFormats
);
if (bSuccess)
{
ASSERT( NULL != pSndSuppFormats );
ASSERT( 0 != dwListSize );
ASSERT( 0 != dwNumFormats );
bSuccess = vcwaveSaveSoundFormats(
pSndSuppFormats,
dwNumFormats);
if (!bSuccess)
{
free(pSndSuppFormats);
pSndSuppFormats = NULL;
dwNumFormats = 0;
dwListSize = 0;
}
} else {
ASSERT( NULL == pSndSuppFormats );
ASSERT( 0 == dwListSize );
ASSERT( 0 == dwNumFormats );
}
dwRespSize = sizeof( *pSndFormatsResp ) + dwListSize;
__try {
pSndFormatsResp = (PSNDFORMATMSG)alloca( dwRespSize );
}
__except((EXCEPTION_STACK_OVERFLOW == GetExceptionCode()) ?
EXCEPTION_EXECUTE_HANDLER :
EXCEPTION_CONTINUE_SEARCH)
{
_resetstkoflw();
pSndFormatsResp = NULL;
TRC(ERR, _T("alloca threw exception: 0x%x\n"),
GetExceptionCode());
}
if ( NULL == pSndFormatsResp )
goto break_sndformat;
pSndFormatsResp->Prolog.Type = SNDC_FORMATS;
pSndFormatsResp->Prolog.BodySize = (UINT16)(
dwRespSize -
sizeof( pSndFormatsResp->Prolog ));
pSndFormatsResp->wNumberOfFormats = (WORD)dwNumFormats;
vcwaveGetDevCaps( pSndFormatsResp );
//
// Beta 1 compatability, fake we are version 1 if the server is version 1
//
m_wServerVersion = pSndFormats->wVersion;
if ( 1 == pSndFormats->wVersion )
pSndFormatsResp->wVersion = 1;
else
pSndFormatsResp->wVersion = RDPSND_PROTOCOL_VERSION;
//
// copy the format list
//
memcpy( (PSNDFORMATITEM) ( pSndFormatsResp + 1 ),
pSndSuppFormats,
dwListSize );
ChannelWriteNCopy( pSndFormatsResp, dwRespSize );
break_sndformat:
if ( NULL != pSndSuppFormats )
free ( pSndSuppFormats );
}
break;
case SNDC_CRYPTKEY:
{
PSNDCRYPTKEY pKey = (PSNDCRYPTKEY)(((LPSTR)pBody) - sizeof(*pProlog));
if ( pProlog->BodySize < sizeof( *pKey ) - sizeof( *pProlog ))
{
TRC( ERR, _T("DataArrived: Invalid SNDC_CRYPTKEY message\n"));
break;
}
memcpy( m_EncryptKey, pKey->Seed, RANDOM_KEY_LENGTH );
}
break;
default:
TRC(ERR, _T("DataArrived: Invalid message type received: %d\n"), pProlog->Type);
}
}
/*
* Function:
* vcwaveResample
*
* Description:
* Reopens the device with new codec
*
*/
VOID
CRDPSound::vcwaveResample(
VOID
)
{
if ( 0 != m_dwWavesPlaying || NULL == m_pFirstWave )
goto exitpt;
if ( NULL == m_hWave ||
m_dwCurrentFormat != (DWORD)PtrToLong((PVOID)m_pFirstWave->reserved))
{
TRC(INF, _T("vcwaveResample: Resampling\n"));
m_dwCurrentFormat = (DWORD)PtrToLong((PVOID)m_pFirstWave->reserved);
if ( m_dwCurrentFormat >= m_dwNumFormats )
{
TRC(ERR, _T("vcwaveResample: invalid format no\n"));
vcwaveFreeAllWaves();
goto exitpt;
}
vcwaveOpen( (LPWAVEFORMATEX)m_ppFormats[ m_dwCurrentFormat ] );
}
//
// stuff all pending blocks
//
while ( NULL != m_pFirstWave &&
m_dwCurrentFormat == (DWORD)PtrToLong( (PVOID)m_pFirstWave->reserved ))
{
LPWAVEHDR lpNext = m_pFirstWave->lpNext;
MMRESULT mmres;
mmres = vcwaveOutWrite( m_pFirstWave );
if ( MMSYSERR_NOERROR != mmres )
{
vcwaveFreeAllWaves();
} else {
m_pFirstWave = lpNext;
if ( NULL == m_pFirstWave )
m_pLastWave = NULL;
}
}
exitpt:
;
}
/*
* Function:
* DGramSocketMessage
*
* Description:
* Callback from UDP
*
*/
VOID
CRDPSound::DGramSocketMessage(
WPARAM wParam,
LPARAM lParam
)
{
if (WSAGETSELECTERROR(lParam))
{
TRC(ERR, _T("WM_WSOCK: Winsock error: %d\n"),
WSAGETSELECTERROR(lParam));
goto exitpt;
}
if (m_hDGramSocket != (SOCKET)wParam)
{
TRC(WRN, _T("WM_WSOCK: message for unknown socket\n"));
goto exitpt;
}
if (WSAGETSELECTEVENT(lParam) == FD_CLOSE)
{
TRC(ERR, _T("WM_WSOCK: socket closed\n"));
DGramDone();
goto exitpt;
}
if (WSAGETSELECTEVENT(lParam) != FD_READ)
{
TRC(WRN, _T("WM_WSOCK: unknown event received\n"));
goto exitpt;
}
TRC(ALV, _T("WM_WSOCK: data available\n"));
{
BOOL bSuccess;
PSNDWAVE pSndWave;
UINT structsize;
structsize = sizeof(*pSndWave) + TSSND_BLOCKSIZE + RDPSND_SIGNATURE_SIZE;
__try
{
pSndWave = (PSNDWAVE)alloca(structsize);
}
__except((EXCEPTION_STACK_OVERFLOW == GetExceptionCode()) ?
EXCEPTION_EXECUTE_HANDLER :
EXCEPTION_CONTINUE_SEARCH)
{
_resetstkoflw();
pSndWave = NULL;
TRC(ERR, _T("WM_SOCK: alloca threw exception: 0x%x\n"),
GetExceptionCode());
}
if (NULL == pSndWave)
goto exitpt;
bSuccess = DGramRecvWave(
pSndWave,
structsize
);
if (bSuccess)
{
PBYTE pWave = (PBYTE)(pSndWave+1);
UINT uiWaveSize = pSndWave->Prolog.BodySize -
sizeof(SNDWAVE) + sizeof(SNDPROLOG);
if ( IsDGramWaveSigned( m_wServerVersion ))
{
DWORD dw;
BYTE Signature[ RDPSND_SIGNATURE_SIZE ];
//
// wave starts with signature
//
if ( uiWaveSize < RDPSND_SIGNATURE_SIZE )
{
TRC( ERR, _T("Insufficient data for signature\n" ));
goto exitpt;
}
if ( !IsDGramWaveAudioSigned( m_wServerVersion ))
{
SL_Signature( Signature, pSndWave->dwBlockNo );
} else {
SL_AudioSignature( Signature,
pSndWave->dwBlockNo,
pWave + RDPSND_SIGNATURE_SIZE,
uiWaveSize - RDPSND_SIGNATURE_SIZE );
}
dw = memcmp( pWave, Signature, RDPSND_SIGNATURE_SIZE );
if ( 0 != dw )
{
TRC( ERR, _T("Invalid signature\n" ));
goto exitpt;
}
pWave += RDPSND_SIGNATURE_SIZE;
uiWaveSize -= RDPSND_SIGNATURE_SIZE;
}
vcwaveWrite(pSndWave->cBlockNo,
pSndWave->wFormatNo,
pSndWave->wTimeStamp,
uiWaveSize,
pWave);
}
}
exitpt:
;
}
/*
* Function:
* CreateMsgWindow
*
* Description:
* Creates a window
*
*/
BOOL
CRDPSound::CreateMsgWindow(
HINSTANCE hInstance
)
{
WNDCLASS wc;
BOOL rv = FALSE;
DWORD dwLastErr;
LONG_PTR dwUser;
memset(&wc, 0, sizeof(wc));
wc.lpfnWndProc = MsgWndProc;
wc.hInstance = hInstance;
wc.lpszClassName = _NAMEOFCLAS;
if (!RegisterClass (&wc))
{
dwLastErr = GetLastError();
if(dwLastErr != ERROR_CLASS_ALREADY_EXISTS)
{
TRC(ERR,
_T("CreateMsgWindow: Can't register class. GetLastError=%d\n"),
GetLastError());
goto exitpt;
}
}
m_hMsgWindow = CreateWindow(
_NAMEOFCLAS,
NULL, // Window name
0, // dwStyle
0, // x
0, // y
0, // nWidth
0, // nHeight
NULL, // hWndParent
NULL, // hMenu
hInstance,
NULL); // lpParam
if (!m_hMsgWindow)
{
TRC(ERR, _T("CreateMsgWindow: Failed to create message window. GetLastError=%d\n"),
GetLastError());
goto exitpt;
}
//
// safe the class pointer in the window structure
//
#ifndef OS_WINCE
dwUser = SetWindowLongPtr(
m_hMsgWindow,
GWLP_USERDATA,
(LONG_PTR)this
);
#else
dwUser = SetWindowLong(
m_hMsgWindow,
GWL_USERDATA,
(LONG)this
);
#endif
ASSERT( 0 == dwUser );
rv = TRUE;
exitpt:
return rv;
}
/*
* Function:
* DestroyMsgWindow
*
* Description:
* Destroy our window
*
*/
VOID
CRDPSound::DestroyMsgWindow(
VOID
)
{
if (NULL != m_hMsgWindow)
DestroyWindow(m_hMsgWindow);
UnregisterClass(_NAMEOFCLAS, m_hInst);
}
/*
* Function:
* ChannelWrite
*
* Description:
* Sends or queues a chunk of data to the virtual channel
*
* Parameters:
* hGlobMem - handle to a HGLOBAL
* uiBlockSize - size of the chunk
*
* Returns:
* TRUE on success
*
*/
BOOL
CRDPSound::ChannelWrite(
LPVOID pData,
UINT32 uiBlockSize
)
{
BOOL rv = FALSE;
DWORD Handle = m_dwChannel;
UINT rc;
ASSERT(Handle != INVALID_CHANNELID);
ASSERT(m_ChannelEntries.pVirtualChannelWriteEx);
// parameters check
//
if (INVALID_CHANNELID == Handle)
{
TRC(ERR, _T("ChannelWrite: invalid handle\n"));
goto exitpt;
}
TRC(ALV, _T("Sending ptr=%p, Size=%d\n"), pData, uiBlockSize);
rc = m_ChannelEntries.pVirtualChannelWriteEx(
m_pInitHandle,
Handle,
pData,
uiBlockSize,
pData);
if (rc != CHANNEL_RC_OK)
{
TRC(INF, _T("VirtualChannelWrite failed rv=%d"), rc);
goto exitpt;
}
rv = TRUE;
exitpt:
if (!rv)
{
TRC(ERR, _T("ChannelWrite: Failed to send data\n"));
}
return rv;
}
/*
* Function:
* vcwaveCallbacl
*
* Description:
* WaveOut callbacks
*
*/
VOID
CRDPSound::vcwaveCallback(
HWAVEOUT hWave,
UINT uMsg,
LPWAVEHDR lpWaveHdr
)
{
switch (uMsg)
{
case WOM_OPEN:
TRC(ALV, _T("vcwaveCallback: WOM_OPEN\n"));
break;
case WOM_CLOSE:
TRC(ALV, _T("vcwaveCallback: WOM_CLOSE\n"));
break;
case WOM_DONE:
{
SNDWAVECONFIRM WaveConfirm;
ASSERT( 0 != ( lpWaveHdr->dwFlags & WHDR_PREPARED ));
if ( 0 == ( lpWaveHdr->dwFlags & WHDR_PREPARED ))
{
TRC( ERR, _T("vcwaveCallback: buffer already unprepared\n") );
} else if ( m_hWave != hWave )
{
TRC( ERR, _T("vcwaveCallback: can't unprepare header, beacuse ")
_T("the stream is already closed\n"));
} else {
MMRESULT mmres;
mmres = waveOutUnprepareHeader(
hWave,
lpWaveHdr,
sizeof(*lpWaveHdr)
);
ASSERT( mmres == MMSYSERR_NOERROR );
#if DBG
m_lPrepdBlocks --;
#endif // DBG
}
if (lpWaveHdr)
{
DWORD dw = PtrToLong((PVOID)lpWaveHdr->dwUser);
WaveConfirm.cConfirmedBlockNo = (BYTE)(dw >> 16);
//
// adjust completly the time stamp
// see vcwaveWrite
//
WaveConfirm.wTimeStamp = (WORD)
((dw & 0xffff) + GetTickCount());
#if _STAT_DBG
TRC(INF, _T("blockno=%d, adjusted time stamp=%x\n"),
WaveConfirm.cConfirmedBlockNo, WaveConfirm.wTimeStamp);
#endif
TRC(ALV, _T("vcwaveCallback: WOM_DONE, block no %d\n"),
WaveConfirm.cConfirmedBlockNo);
if (lpWaveHdr->lpData)
{
#ifdef OS_WINCE
lpWaveHdr->lpData = (char *)UnMapPtr(lpWaveHdr->lpData);
if (lpWaveHdr->lpData)
#endif
free(lpWaveHdr->lpData);
}
else
TRC(ERR, _T("vcwaveCallback: WOM_DONE: lpWaveHdr->lpData is NULL\n"));
free(lpWaveHdr);
} else
TRC(ERR, _T("vcwaveCallback: WOM_DONE: lpWaveHdr is NULL\n"));
// Send the confirmation
//
WaveConfirm.Prolog.Type = SNDC_WAVECONFIRM;
WaveConfirm.Prolog.BodySize = sizeof(WaveConfirm) -
sizeof(WaveConfirm.Prolog);
if ( 0 != m_ulRemoteDGramAddress )
DGramSend( &WaveConfirm, sizeof(WaveConfirm));
else
ChannelWriteNCopy( &WaveConfirm, sizeof( WaveConfirm ));
m_dwWavesPlaying --;
ASSERT( -1 != m_dwWavesPlaying );
if ( 0 == m_dwWavesPlaying && NULL != m_pFirstWave )
{
TRC(INF, _T("vcwaveCallback: WOM_DONE: attempt to resample\n"));
PostMessage( m_hMsgWindow, WM_RESAMPLE, 0, 0 );
}
}
break;
}
}
/*
* Function:
* vcwaveGetDevCaps
*
* Description:
* Queries for device capabilities
*
*/
VOID
CRDPSound::vcwaveGetDevCaps(
PSNDFORMATMSG pFmtMsg
)
{
WAVEFORMATEX Format;
MMRESULT mmres;
DWORD dw;
ASSERT( NULL != pFmtMsg );
pFmtMsg->dwFlags = 0;
pFmtMsg->dwVolume = 0;
pFmtMsg->dwPitch = 0;
pFmtMsg->wDGramPort = 0;
Format.wFormatTag = WAVE_FORMAT_PCM;
Format.nChannels = TSSND_NATIVE_CHANNELS;
Format.nSamplesPerSec = TSSND_NATIVE_SAMPLERATE;
Format.nAvgBytesPerSec = TSSND_NATIVE_AVGBYTESPERSEC;
Format.nBlockAlign = TSSND_NATIVE_BLOCKALIGN;
Format.wBitsPerSample = TSSND_NATIVE_BITSPERSAMPLE;
Format.cbSize = 0;
if (!vcwaveOpen(&Format))
{
TRC(ERR, _T("vcwaveGetDevCaps: can't open device\n"));
goto exitpt;
}
ASSERT( NULL != m_hWave );
pFmtMsg->dwFlags = TSSNDCAPS_ALIVE;
pFmtMsg->wDGramPort = DGramGetLocalPort();
mmres = waveOutGetVolume(m_hWave, &dw);
if (MMSYSERR_NOERROR == mmres)
{
pFmtMsg->dwFlags |= TSSNDCAPS_VOLUME;
pFmtMsg->dwVolume = dw;
}
else
TRC(ERR, _T("vcwaveGetDevCaps: device doesn't support volume control\n"));
mmres = waveOutGetPitch(m_hWave, &dw);
if (MMSYSERR_NOERROR == mmres)
{
pFmtMsg->dwFlags |= TSSNDCAPS_PITCH;
pFmtMsg->dwPitch = dw;
}
else
TRC(INF, _T("vcwaveGetDevCaps: device doesn't support pitch control\n"));
vcwaveClose();
exitpt:
;
}
/*
* Function:
* vcwaveChooseSoundFormat
*
* Description:
* Queries the local device for different formats
*
*/
BOOL
CRDPSound::vcwaveChooseSoundFormat(
DWORD dwNumberOfFormats,
PSNDFORMATITEM pSndFormats,
PSNDFORMATITEM *ppSndFormatFound,
DWORD *pdwListSize,
DWORD *pdwNumFormats
)
{
PSNDFORMATITEM pSndFormat;
//
// query the waveout device with different wave formats
// returns the list of successfull formats in pSndFormatFound
// FALSE in any other case
// the caller takes responsibility for freeing the data in
// *ppSndFormatFound
//
BOOL rv = FALSE;
DWORD i;
PSNDFORMATITEM pSndFormatFound = NULL;
LPSTR pFmtCopy;
DWORD dwListSize = 0;
DWORD dwNumFormats = 0;
ASSERT( NULL != pSndFormats );
ASSERT( NULL != ppSndFormatFound );
ASSERT( NULL != pdwListSize );
ASSERT( NULL != pdwNumFormats );
for ( i = 0, pSndFormat = pSndFormats;
i < dwNumberOfFormats;
i++, pSndFormat = (PSNDFORMATITEM)
(((LPSTR)pSndFormat) + sizeof( *pSndFormat ) + pSndFormat->cbSize)
)
{
MMRESULT mmres;
PSNDFORMATITEM pFmtToOpen = pSndFormat;
PSNDFORMATITEM pFixedFormat = NULL;
//
// fix the format for WMA audio
// copy and modify it in another structure, so we don't disrupt
// the original
//
if ( WAVE_FORMAT_WMAUDIO2 == pSndFormat->wFormatTag )
{
DWORD dwTotalSize = sizeof( WMAUDIO2WAVEFORMAT ) -
sizeof( WAVEFORMATEX ) + sizeof( WMAUDIO_DEC_KEY );
ASSERT( pSndFormat->cbSize == dwTotalSize );
if ( pSndFormat->cbSize == dwTotalSize )
{
pFixedFormat = (PSNDFORMATITEM)malloc( sizeof( WMAUDIO2WAVEFORMAT ) +
sizeof( WMAUDIO_DEC_KEY ));
if ( NULL != pFixedFormat )
{
memcpy( pFixedFormat, pSndFormat, sizeof( pSndFormat ) + pSndFormat->cbSize );
strncpy((CHAR *)(((WMAUDIO2WAVEFORMAT *) pFixedFormat) + 1),
WMAUDIO_DEC_KEY, sizeof( WMAUDIO_DEC_KEY ));
pFmtToOpen = pFixedFormat;
}
}
}
mmres = waveOutOpen(
NULL,
WAVE_MAPPER,
(LPWAVEFORMATEX)pFmtToOpen,
0,
0,
WAVE_FORMAT_QUERY
);
if ( NULL != pFixedFormat )
{
free( pFixedFormat );
}
TRC(ALV, _T("FormatTag - %d\n"), pSndFormat->wFormatTag);
TRC(ALV, _T("Channels - %d\n"), pSndFormat->nChannels);
TRC(ALV, _T("SamplesPerSec - %d\n"), pSndFormat->nSamplesPerSec);
TRC(ALV, _T("AvgBytesPerSec - %d\n"), pSndFormat->nAvgBytesPerSec);
TRC(ALV, _T("BlockAlign - %d\n"), pSndFormat->nBlockAlign);
TRC(ALV, _T("BitsPerSample - %d\n"), pSndFormat->wBitsPerSample);
TRC(ALV, _T("cbSize - %d\n"), pSndFormat->cbSize);
if ( MMSYSERR_NOERROR == mmres )
{
//
// this format is supported
//
TRC(ALV, _T("vcwaveChooseSoundFormat: format found\n"));
dwListSize += sizeof( *pSndFormat ) + pSndFormat->cbSize;
dwNumFormats ++;
} else {
//
// if not supported,
// zero it's AvgBytesPerSec member
//
TRC(INF, _T("vcwaveChooseSoundFormat: format not supported\n"));
pSndFormat->nAvgBytesPerSec = 0;
}
}
if ( 0 == dwListSize )
{
TRC(WRN, _T("vcwaveChooseSoundFormat: no formats found\n"));
goto exitpt;
}
pSndFormatFound = (PSNDFORMATITEM)malloc( dwListSize );
if ( NULL == pSndFormatFound )
{
TRC( ERR, _T("vcwaveChooseSoundFormat: can't allocate %d bytes\n"),
dwListSize );
dwListSize = 0;
dwNumFormats = 0;
goto exitpt;
}
//
// copy the list of supported formats
//
for ( i = 0, pSndFormat = pSndFormats, pFmtCopy = (LPSTR)pSndFormatFound;
i < dwNumberOfFormats;
i++, pSndFormat = (PSNDFORMATITEM)
(((LPSTR)pSndFormat) + sizeof( *pSndFormat ) + pSndFormat->cbSize)
)
{
if ( 0 != pSndFormat->nAvgBytesPerSec )
{
memcpy( pFmtCopy,
pSndFormat,
sizeof( *pSndFormat ) + pSndFormat->cbSize);
pFmtCopy += sizeof( *pSndFormat ) + pSndFormat->cbSize;
}
}
rv = TRUE;
exitpt:
*ppSndFormatFound = pSndFormatFound;
*pdwListSize = dwListSize;
*pdwNumFormats = dwNumFormats;
return rv;
}
/*
* Function:
* vcwaveCleanSoundForamt
*
* Description:
* Cleans the list of negotiated formats
*
*/
VOID
CRDPSound::vcwaveCleanSoundFormats(
VOID
)
{
DWORD i;
if ( NULL == m_ppFormats )
goto exitpt;
//
// dispose the allocated structures
//
for (i = 0; i < m_dwNumFormats; i++)
{
if ( NULL != m_ppFormats[i] )
free( m_ppFormats[i] );
}
free( m_ppFormats );
m_ppFormats = NULL;
m_dwNumFormats = 0;
exitpt:
;
}
/*
* Function:
* vcwaveSafeSoundFormats
*
* Description:
* Saves the list of negotiated formats
*
*/
BOOL
CRDPSound::vcwaveSaveSoundFormats(
PSNDFORMATITEM pSndFormats,
DWORD dwNumFormats
)
{
BOOL rv = FALSE;
DWORD i;
DWORD dwAllocSize;
LPSTR p;
ASSERT( NULL != pSndFormats );
ASSERT( 0 != dwNumFormats );
if ( NULL != m_ppFormats )
{
vcwaveCleanSoundFormats();
}
ASSERT( NULL == m_ppFormats );
ASSERT( 0 == m_dwNumFormats );
dwAllocSize = sizeof( PSNDFORMATITEM ) * dwNumFormats;
m_ppFormats = (PSNDFORMATITEM *)malloc( dwAllocSize );
if ( NULL == m_ppFormats )
{
TRC(ERR, _T("Failed to allocate %d bytes\n"),
dwAllocSize );
goto exitpt;
}
memset( m_ppFormats, 0, dwAllocSize );
for (i = 0, p = (LPSTR)pSndFormats;
i < dwNumFormats;
i++, p += sizeof(SNDFORMATITEM) + ((PSNDFORMATITEM)p)->cbSize)
{
PSNDFORMATITEM pFmt;
pFmt = (PSNDFORMATITEM) p;
dwAllocSize = sizeof(SNDFORMATITEM) + pFmt->cbSize;
m_ppFormats[i] = (PSNDFORMATITEM)malloc( dwAllocSize );
if ( NULL == (PVOID)m_ppFormats[i] )
{
TRC(ERR, _T("Failed to allocate %d bytes\n"),
dwAllocSize );
goto exitpt;
}
//
// copy the format
//
memcpy( m_ppFormats[i], pFmt, dwAllocSize );
}
m_dwNumFormats = dwNumFormats;
rv = TRUE;
exitpt:
if (!rv && NULL != m_ppFormats)
{
// dispose the allocated structures
//
for (i = 0; i < dwNumFormats; i++)
{
if ( NULL != m_ppFormats[i] )
free( m_ppFormats[i] );
}
free( m_ppFormats );
m_ppFormats = NULL;
m_dwNumFormats = 0;
}
return rv;
}
/*
* Function:
* vcwaveClose
*
* Description:
* Closes the local device
*
*/
VOID
CRDPSound::vcwaveClose(
VOID
)
{
MSG msg;
UINT_PTR idTimer;
if ( NULL == m_hWave )
goto exitpt;
//
// process all MM_WOM_DONE messages
//
ASSERT( NULL != m_hMsgWindow );
//
// start a timeout timer
//
idTimer = SetTimer( m_hMsgWindow, 1, WAVE_CLOSE_TIMEOUT, NULL );
while( 0 != m_dwWavesPlaying &&
GetMessage( &msg, m_hMsgWindow, 0, 0 ))
{
if ( WM_TIMER == msg.message && msg.wParam == idTimer )
{
//
// cancel outstanding io
//
TRC( WRN, _T("TIMEDOUT waiting for the playing to complete. Resetting\n" ));
waveOutReset( m_hWave );
}
DispatchMessage(&msg);
}
if ( 0 != idTimer )
{
KillTimer( m_hMsgWindow, idTimer );
}
waveOutClose(m_hWave);
#ifdef DBG
if ( 0 != InterlockedDecrement(&m_lTimesWaveOutOpened))
{
TRC(FATAL, _T("Device was closed too many times\n"));
ASSERT(0);
}
ASSERT( 0 == m_dwWavesPlaying );
ASSERT( 0 == m_lPrepdBlocks );
#endif
m_hWave = NULL;
exitpt:
;
}
/*
* Function:
* vcwaveOpen
*
* Description:
* Opens the device in given format
*
*/
BOOL
CRDPSound::vcwaveOpen(
LPWAVEFORMATEX pFormat
)
{
BOOL rv = FALSE;
MMRESULT mmres;
if (m_hWave)
{
TRC(WRN, _T("vcwaveOpen: device is already opened. Reopening\n"));
waveOutReset(m_hWave);
vcwaveClose();
}
if (INVALID_SOCKET == m_hDGramSocket)
{
TRC(ERR, _T("vcwaveOpen: no datagram connection, falling to VC\n"));
}
// 11.025 kHz, 8 bit, mono
if (NULL == m_hMsgWindow && !CreateMsgWindow(m_hInst))
goto exitpt;
//
// fix the format for WMA audio
//
if ( WAVE_FORMAT_WMAUDIO2 == pFormat->wFormatTag )
{
DWORD dwTotalSize = sizeof( WMAUDIO2WAVEFORMAT ) -
sizeof( WAVEFORMATEX ) + sizeof( WMAUDIO_DEC_KEY );
ASSERT( pFormat->cbSize == dwTotalSize );
if ( pFormat->cbSize == dwTotalSize )
{
strncpy((CHAR *)(((WMAUDIO2WAVEFORMAT *) pFormat) + 1),
WMAUDIO_DEC_KEY, sizeof( WMAUDIO_DEC_KEY ));
}
}
mmres = waveOutOpen(
&m_hWave,
WAVE_MAPPER,
pFormat,
(DWORD_PTR)m_hMsgWindow,
0, // CallbackInstance
CALLBACK_WINDOW
);
if (MMSYSERR_NOERROR != mmres)
{
TRC(WRN, _T("vcwaveOpen: failed to open WaveOut device: MMRESULT=%d\n"),
mmres);
goto exitpt;
}
#ifdef OS_WINCE
TRC(ALV, _T("waveOutOpen succeeded with following format %d\n"), pFormat->wFormatTag);
TRC(ALV, _T("FormatTag - %d\n"), pFormat->wFormatTag);
TRC(ALV, _T("Channels - %d\n"), pFormat->nChannels);
TRC(ALV, _T("SamplesPerSec - %d\n"), pFormat->nSamplesPerSec);
TRC(ALV, _T("AvgBytesPerSec - %d\n"), pFormat->nAvgBytesPerSec);
TRC(ALV, _T("BlockAlign - %d\n"), pFormat->nBlockAlign);
TRC(ALV, _T("BitsPerSample - %d\n"), pFormat->wBitsPerSample);
TRC(ALV, _T("cbSize - %d\n"), pFormat->cbSize);
#endif
#ifdef DBG
// Win95 InterlockedIncrement() difference.
InterlockedIncrement(&m_lTimesWaveOutOpened);
if ( 1 != m_lTimesWaveOutOpened )
{
TRC(FATAL, _T("Device was opened %d times\n"),
m_lTimesWaveOutOpened);
ASSERT(0);
}
#endif
rv = TRUE;
exitpt:
return rv;
}
/*
* Function:
* vcwaveFreeAllWaves
*
* Description:
* Frees all queued data
*
*/
VOID
CRDPSound::vcwaveFreeAllWaves(
VOID
)
{
while ( NULL != m_pFirstWave )
{
LPWAVEHDR lpNext = m_pFirstWave->lpNext;
free( m_pFirstWave->lpData );
free( m_pFirstWave );
m_pFirstWave = lpNext;
}
m_pFirstWave = m_pLastWave = NULL;
}
/*
* Function:
* vcwaveOutWrite
*
* Description:
* Writes a data to the output sound device
*
*/
MMRESULT
CRDPSound::vcwaveOutWrite(
LPWAVEHDR lpWaveHdr
)
{
MMRESULT mmres;
mmres = waveOutPrepareHeader(
m_hWave,
lpWaveHdr,
sizeof(*lpWaveHdr)
);
if (MMSYSERR_NOERROR != mmres)
{
TRC(WRN, _T("vcwaveOpen: failed to prepare buffer: MMRESULT=%d\n"),
mmres);
goto exitpt;
}
m_dwWavesPlaying++;
#if DBG
m_lPrepdBlocks ++;
#endif
mmres = waveOutWrite(
m_hWave,
lpWaveHdr,
sizeof(*lpWaveHdr)
);
if (MMSYSERR_NOERROR != mmres)
{
TRC(WRN, _T("vcwaveOpen: failed to write in WaveOut device: MMRESULT=%d\n"),
mmres);
waveOutUnprepareHeader(
m_hWave,
lpWaveHdr,
sizeof(*lpWaveHdr)
);
m_dwWavesPlaying --;
#if DBG
m_lPrepdBlocks --;
#endif
goto exitpt;
}
exitpt:
return mmres;
}
/*
* Function:
* vcwaveWrite
*
* Description:
* If the format id is not changes calls vcwaveOutWrite
* otherwise queues the data for later
*
*/
BOOL
CRDPSound::vcwaveWrite(
BYTE cBlockNo,
DWORD dwFormatNo,
DWORD dwTimeStamp,
DWORD dwWaveDataLen,
LPVOID pData
)
{
BOOL rv = FALSE;
LPVOID lpWaveData = NULL;
LPWAVEHDR lpWaveHdr = NULL;
MMRESULT mmres;
BOOL bDontPlay = FALSE;
//
// put the stamp here to remove the delay of opening the device
//
DWORD dwStartStamp = GetTickCount() & 0xffff;
if ( NULL != m_hWave &&
m_dwCurrentFormat != dwFormatNo )
{
bDontPlay = TRUE;
}
if (NULL == m_hWave)
{
TRC(ALV, _T("wcwaveWrite: attempting to open the device\n"));
if (dwFormatNo >= m_dwNumFormats)
{
TRC(FATAL, _T("Invalid format no: %d\n"),
dwFormatNo);
goto exitpt;
}
if ( NULL == m_ppFormats )
{
TRC(FATAL, _T("No formats available(NULL)\n"));
goto exitpt;
}
if ( !vcwaveOpen( (LPWAVEFORMATEX)m_ppFormats[dwFormatNo] ))
TRC(ERR, _T("Can't open the device\n"));
m_dwCurrentFormat = dwFormatNo;
}
if ((BYTE)( m_cLastReceivedBlock - cBlockNo ) < TSSND_BLOCKSONTHENET)
{
TRC(WRN, _T("wcwaveWrite: received old block, ")
_T("the last one is %d, this one is %d. Discarding\n"),
m_cLastReceivedBlock,
cBlockNo);
goto exitpt;
} else
m_cLastReceivedBlock = cBlockNo;
lpWaveData = malloc(dwWaveDataLen);
if (!lpWaveData)
{
TRC(ERR, _T("vcwaveWrite: malloc failed to allocate %d bytes\n"),
dwWaveDataLen);
goto exitpt;
}
lpWaveHdr = (LPWAVEHDR)malloc(sizeof(*lpWaveHdr));
if (!lpWaveHdr)
{
TRC(ERR, _T("vcwaveWrite: malloc failed for %d bytes\n"),
sizeof(*lpWaveHdr));
goto exitpt;
}
memset(lpWaveHdr, 0, sizeof(*lpWaveHdr));
memcpy(lpWaveData, pData, dwWaveDataLen);
lpWaveHdr->lpData = (LPSTR)lpWaveData;
lpWaveHdr->dwBufferLength = dwWaveDataLen;
lpWaveHdr->dwFlags = 0;
lpWaveHdr->dwLoops = 0;
//
// here, we'll do a little magic with the time stamp
// in order to exclude the time when time packet is in the wave queue
// we'll subtract the current time now and add the time when
// confirmation is to be send
//
#if _STAT_DBG
TRC(INF, _T("blockno=%d, time stamp=%x\n"),
cBlockNo, dwTimeStamp );
#endif
lpWaveHdr->dwUser = (cBlockNo << 16) +
((dwTimeStamp - dwStartStamp ) & 0xffff);
if ( bDontPlay )
{
//
// format change
// add this wave to the list
//
lpWaveHdr->reserved = dwFormatNo;
lpWaveHdr->lpNext = NULL;
if ( NULL != m_pLastWave )
m_pLastWave->lpNext = lpWaveHdr;
else
m_pFirstWave = lpWaveHdr;
m_pLastWave = lpWaveHdr;
ASSERT( NULL != lpWaveHdr->lpData );
TRC(INF, _T("vcwaveWrite: posting WM_RESAMPLE\n"));
PostMessage( m_hMsgWindow, WM_RESAMPLE, 0, 0 );
goto leavept;
}
mmres = vcwaveOutWrite( lpWaveHdr );
if (MMSYSERR_NOERROR != mmres)
{
TRC(WRN, _T("vcwaveOpen: failed to play a buffer: MMRESULT=%d\n"),
mmres);
goto exitpt;
}
leavept:
rv = TRUE;
exitpt:
if (!rv)
{
if (lpWaveData)
free(lpWaveData);
if (lpWaveHdr)
free(lpWaveHdr);
}
return rv;
}
/*
* Function:
* DGramInit
*
* Description:
* Init our UDP socket
*
*/
BOOL
CRDPSound::DGramInit(
VOID
)
{
BOOL rv = FALSE;
#ifndef OS_WINCE
INT optval;
#endif
INT rc;
struct sockaddr_in sin;
ASSERT(INVALID_SOCKET == m_hDGramSocket);
m_hDGramSocket = socket(AF_INET, SOCK_DGRAM, 0);
if (INVALID_SOCKET == m_hDGramSocket)
{
TRC(ERR, _T("DGramInit: can't create dgram socket: %d\n"),
WSAGetLastError());
goto exitpt;
}
// bind the socket to any port/address
//
sin.sin_family = PF_INET;
sin.sin_port = htons(0); // any port between 1024 and 50000
sin.sin_addr.s_addr = INADDR_ANY;
rc = bind(m_hDGramSocket, (struct sockaddr *)(&sin), sizeof(sin));
if (SOCKET_ERROR == rc)
{
TRC(ERR, _T("DGramInit: can't bind the socket: %d\n"),
WSAGetLastError());
goto exitpt;
}
#ifndef OS_WINCE
//
// assign an appropriate buffer length
//
optval = TSSND_BLOCKSONTHENET * (sizeof(SNDWAVE) + TSSND_BLOCKSIZE);
rc = setsockopt(m_hDGramSocket,
SOL_SOCKET,
SO_RCVBUF,
(LPSTR)&optval,
sizeof(optval));
if (SOCKET_ERROR == rc)
{
TRC(ERR, _T("DGramInit: setsockopt failed: %d\n"),
WSAGetLastError());
goto exitpt;
}
#endif
// select the socket on the message window
//
if (NULL != m_hMsgWindow &&
SOCKET_ERROR ==
WSAAsyncSelect(m_hDGramSocket, m_hMsgWindow,
WM_WSOCK, FD_READ))
{
TRC(ERR, _T("DGramInit: WSAAsyncSelect failed: %d\n"),
WSAGetLastError());
goto exitpt;
}
rv = TRUE;
exitpt:
if (!rv && INVALID_SOCKET != m_hDGramSocket)
{
closesocket(m_hDGramSocket);
m_hDGramSocket = INVALID_SOCKET;
}
return rv;
}
/*
* Function:
* DGramDone
*
* Description:
* Destroy our UDP socket
*
*/
VOID
CRDPSound::DGramDone(
VOID
)
{
if (INVALID_SOCKET != m_hDGramSocket)
{
closesocket(m_hDGramSocket);
m_hDGramSocket = INVALID_SOCKET;
}
}
/*
* Function:
* DGramGetLocalPort
*
* Description:
* Retreives the local UDP port
*
*/
u_short
CRDPSound::DGramGetLocalPort(
VOID
)
{
u_short rv = 0;
struct sockaddr_in sin;
INT rc;
INT nSinSize;
if (INVALID_SOCKET == m_hDGramSocket)
{
TRC(ERR, _T("DGramGetLocalPort: invalid socket\n"));
goto exitpt;
}
nSinSize = sizeof(sin);
rc = getsockname(m_hDGramSocket,
(struct sockaddr *)&sin,
&nSinSize);
if (SOCKET_ERROR == rc)
{
TRC(ERR, _T("DGramGetLocalPort: getsockname failed: %d\n"),
WSAGetLastError());
goto exitpt;
}
ASSERT(PF_INET == sin.sin_family);
rv = sin.sin_port;
exitpt:
return rv;
}
/*
* Function:
* DGramSend
*
* Description:
* Send an UDP packet
*
*/
BOOL
CRDPSound::DGramSend(
LPVOID pData,
DWORD dwSize
)
{
INT rc = SOCKET_ERROR;
struct sockaddr_in sin;
ASSERT( 0 != m_dwRemoteDGramPort );
ASSERT( 0 != m_ulRemoteDGramAddress );
if ( INVALID_SOCKET == m_hDGramSocket )
{
TRC(ERR, _T("DGramSend: invalid socket handle\n"));
goto exitpt;
}
sin.sin_family = PF_INET;
sin.sin_port = (u_short)m_dwRemoteDGramPort;
sin.sin_addr.s_addr = m_ulRemoteDGramAddress;
rc = sendto(
m_hDGramSocket,
(LPSTR)pData,
dwSize,
0,
(struct sockaddr *)&sin,
sizeof( sin )
);
if ( SOCKET_ERROR == rc )
{
TRC(WRN, _T("DGramSend: sendto failed=%d\n"),
WSAGetLastError());
}
exitpt:
return ( rc != SOCKET_ERROR );
}
/*
* Function:
* DGramRecvWave
*
* Description:
* Recieve data from UDP
*
*/
BOOL
CRDPSound::DGramRecvWave(
PSNDWAVE pSndWave,
DWORD dwSize
)
{
BOOL rv = FALSE;
INT recvd;
struct sockaddr_in sin_from;
INT nSinFrom;
// parameters check
//
if (NULL == pSndWave)
{
TRC(ERR, _T("DGramRecvWave: pSndWave is NULL\n"));
goto exitpt;
}
if (dwSize <= sizeof(*pSndWave))
{
TRC(ERR, _T("DGramRecvWave: no enough space to get the wave\n"));
goto exitpt;
}
// receive the message
//
nSinFrom = sizeof( sin_from );
recvd = recvfrom(
m_hDGramSocket,
(LPSTR)pSndWave,
dwSize,
0,
(struct sockaddr *)&sin_from,
&nSinFrom
);
if (recvd < sizeof(pSndWave->Prolog) || ((DWORD)recvd) > dwSize)
{
if (SOCKET_ERROR == recvd)
TRC(ERR, _T("WM_WSOCK: recvfrom failed: %d\n"),
WSAGetLastError());
else
TRC(WRN,
_T("WM_WSOCK: received %d bytes instead %d. Discarding\n"),
recvd, sizeof(pSndWave->Prolog));
goto exitpt;
}
ASSERT( PF_INET == sin_from.sin_family );
if ( PF_INET != sin_from.sin_family )
{
TRC(WRN, _T("WM_WSOCK: message from invalid protocol( %x )\n"),
sin_from.sin_family );
goto exitpt;
}
if ( sizeof( sin_from ) > nSinFrom )
{
TRC(WRN, _T("WM_WSOCK: from address invalid, len=%d\n"),
nSinFrom );
goto exitpt;
}
m_dwRemoteDGramPort = sin_from.sin_port;
m_ulRemoteDGramAddress = sin_from.sin_addr.s_addr;
//
// Check for line-training request
//
if (SNDC_TRAINING == pSndWave->Prolog.Type)
{
SNDTRAINING SndTraining;
PSNDTRAINING pRecvTraining;
TRC(ALV, _T("DGramRecvWave: training, sending a response\n"));
pRecvTraining = (PSNDTRAINING)pSndWave;
SndTraining.Prolog.Type = SNDC_TRAINING;
SndTraining.Prolog.BodySize = sizeof(SndTraining) -
sizeof(SndTraining.Prolog);
SndTraining.wTimeStamp = pRecvTraining->wTimeStamp;
SndTraining.wPackSize = pRecvTraining->wPackSize;
//
// send the response immediatly
//
DGramSend( &SndTraining, sizeof(SndTraining) );
goto exitpt;
}
if ( SNDC_UDPWAVE == pSndWave->Prolog.Type)
{
rv = ConstructFromDGramFrags(
(PSNDUDPWAVE)pSndWave,
recvd,
pSndWave,
dwSize
);
goto exitpt;
} else if ( SNDC_UDPWAVELAST == pSndWave->Prolog.Type)
{
rv = ConstructFromDGramLastFrag(
(PSNDUDPWAVELAST)pSndWave,
recvd,
pSndWave,
dwSize
);
goto exitpt;
}
if (SNDC_WAVEENCRYPT == pSndWave->Prolog.Type)
{
if ( !SL_Encrypt(
(PBYTE)(pSndWave + 1),
pSndWave->dwBlockNo,
pSndWave->Prolog.BodySize - sizeof(SNDWAVE) + sizeof(SNDPROLOG) ))
goto exitpt;
}
else if (SNDC_WAVE != pSndWave->Prolog.Type)
{
TRC(ERR, _T("DGramRecvWave: invalid message type: %d\n"),
pSndWave->Prolog.Type);
goto exitpt;
}
if ( recvd < sizeof(SNDPROLOG) ||
pSndWave->Prolog.BodySize + sizeof(SNDPROLOG) != (DWORD)recvd)
{
TRC(WRN,
_T("WM_WSOCK: received %d bytes instead %d. Discarding\n"),
recvd, pSndWave->Prolog.BodySize + sizeof(SNDPROLOG) );
goto exitpt;
}
TRC(ALV, _T("DGramRecvWave: block no: %d\n"),
pSndWave->cBlockNo);
rv = TRUE;
exitpt:
return rv;
}
BOOL
CRDPSound::ConstructFromDGramFrags(
PSNDUDPWAVE pWave,
DWORD dwSize,
PSNDWAVE pReady,
DWORD dwReadySize
)
{
BOOL rv = FALSE;
PBYTE pRecvdData;
DWORD dwFragNo;
DWORD dwEstimatedSize;
DWORD dwDataSize;
PFRAGSLOT pSlot;
if ( dwSize <= sizeof( *pWave ))
{
TRC( ERR, _T("ConstructFromDGramFrags: packet too small %d\n"),
dwSize );
goto exitpt;
}
pRecvdData = (PBYTE)(pWave + 1);
dwFragNo = pWave->cFragNo & (~RDPSND_FRAGNO_EXT);
dwDataSize = dwSize - sizeof( *pWave );
if ( pWave->cFragNo & RDPSND_FRAGNO_EXT )
{
dwFragNo <<= 8;
dwFragNo += *pRecvdData;
pRecvdData++;
dwDataSize--;
}
dwEstimatedSize = ( dwFragNo + 1 ) * dwDataSize;
if ( dwEstimatedSize >= MAX_UDP_SIZE )
{
TRC( ERR, _T("ConstructFromDGramFrags: estimated size >=64K (0x%x)\n"),
dwEstimatedSize );
goto exitpt;
}
if (!_FragSlotFind( &pSlot, pWave->cBlockNo, dwEstimatedSize ))
{
goto exitpt;
}
if ( 0 != pSlot->dwFragSize && pSlot->dwFragSize != dwDataSize )
{
TRC( ERR, _T("ConstructFromDGramFrags: received frag with different size: %d, expect %d\n"),
dwDataSize, pSlot->dwFragSize );
_FragSlotClear( pSlot );
goto exitpt;
}
memcpy( pSlot->pData + dwFragNo * dwDataSize, pRecvdData, dwDataSize );
pSlot->dwFragSize = dwDataSize;
pSlot->dwTotalSize += dwDataSize;
// TRC( INF, _T("Fragment received: block#=0x%x, frag#=0x%x, total=0x%x\n"),
// pWave->cBlockNo, dwFragNo, pSlot->dwTotalSize );
if ( pSlot->dwTotalSize != pSlot->dwExpectedTotalSize )
{
goto exitpt;
}
//
// wave is ready, convert
//
if (!_FragSlotToWave( pSlot, pReady, dwReadySize ))
{
goto exitpt;
}
rv = TRUE;
exitpt:
return rv;
}
BOOL
CRDPSound::ConstructFromDGramLastFrag(
PSNDUDPWAVELAST pLast,
DWORD dwSize,
PSNDWAVE pReady,
DWORD dwReadySize
)
{
BOOL rv = FALSE;
DWORD dwDataSize;
PFRAGSLOT pSlot;
if ( dwSize < sizeof( *pLast ))
{
TRC( ERR, _T("ConstructFromDGramLastFrag: too small packet (%d)\n"), dwSize );
}
if (!_FragSlotFind( &pSlot, pLast->cBlockNo, pLast->wTotalSize ))
{
TRC( WRN, _T("ConstructFromDGramLastFrag: Failed to find a slot for last fragment\n" ));
goto exitpt;
}
pSlot->dwExpectedTotalSize = pLast->wTotalSize;
pSlot->wTimeStamp = pLast->wTimeStamp;
pSlot->wFormatNo = pLast->wFormatNo;
pSlot->dwBlockNo = pLast->dwBlockNo;
dwDataSize = dwSize - sizeof( *pLast );
memcpy( pSlot->pData + pSlot->dwExpectedTotalSize - dwDataSize, pLast + 1, dwDataSize );
pSlot->dwTotalSize += dwDataSize;
// TRC( INF, _T("Fragment LAST block#=0x%x, total=0x%x\n"),
// pLast->cBlockNo, pSlot->dwTotalSize );
if ( pSlot->dwTotalSize != pSlot->dwExpectedTotalSize )
{
goto exitpt;
}
//
// ready, set, go
//
if (!_FragSlotToWave( pSlot, pReady, dwReadySize ))
{
goto exitpt;
}
rv = TRUE;
exitpt:
return rv;
}
BOOL
CRDPSound::_FragSlotFind(
PFRAGSLOT *ppFragSlot,
BYTE cBlockNo,
DWORD dwEstimatedSize
)
{
BOOL rv = FALSE;
PFRAGSLOT pIter = m_pFragSlots;
PFRAGSLOT pLastFree = NULL;
PFRAGSLOT pFound = NULL;
DWORD dwNewSize;
while( pIter )
{
//
// check if the slot hasn't been used for a while
//
if ( pIter->bUsed &&
(BYTE)( m_cLastReceivedBlock - pIter->cBlockNo ) < TSSND_BLOCKSONTHENET)
{
TRC( WRN, _T("Old frag found id %d, last id %d\n"),
pIter->cBlockNo, m_cLastReceivedBlock );
_FragSlotClear( pIter );
}
if ( !pIter->bUsed && NULL == pLastFree )
{
pLastFree = pIter;
}
if ( pIter->bUsed && pIter->cBlockNo == cBlockNo )
{
// found a block with same number
pFound = pIter;
break;
}
pIter = pIter->pNext;
}
if ( NULL == pFound && NULL != pLastFree )
{
//
// found a free block
//
pLastFree->bUsed = TRUE;
pLastFree->cBlockNo = cBlockNo;
pFound = pLastFree;
}
if ( NULL != pFound &&
pFound->dwAllocatedSize < dwEstimatedSize )
{
dwNewSize = dwEstimatedSize * 2;
PBYTE pNewData = (PBYTE)malloc( dwEstimatedSize * 2 );
if ( NULL == pNewData )
{
//
// we can't use this slot anymore
//
_FragSlotClear( pFound );
pFound = NULL;
goto exitpt;
}
memcpy( pNewData, pFound->pData, pFound->dwAllocatedSize );
pFound->dwAllocatedSize = dwNewSize;
free( pFound->pData );
pFound->pData = pNewData;
}
if ( NULL == pFound )
{
// allocate a new block
//
pFound = (PFRAGSLOT)malloc( sizeof( *pFound ));
if ( NULL == pFound )
{
goto exitpt;
}
dwNewSize = ( dwEstimatedSize > TSSND_BLOCKSIZE + RDPSND_SIGNATURE_SIZE )
? dwEstimatedSize : TSSND_BLOCKSIZE + RDPSND_SIGNATURE_SIZE;
pFound->pData = (PBYTE)malloc( dwNewSize );
if ( NULL == pFound->pData )
{
free( pFound );
goto exitpt;
}
pFound->dwAllocatedSize = dwNewSize;
_FragSlotClear( pFound );
pFound->bUsed = TRUE;
pFound->cBlockNo = cBlockNo;
//
// add it to the list
//
pFound->pNext = m_pFragSlots;
m_pFragSlots = pFound;
}
*ppFragSlot = pFound;
rv = TRUE;
exitpt:
return rv;
}
VOID
CRDPSound::_FragSlotClear(
PFRAGSLOT pSlot
)
{
DWORD dwAllocated = pSlot->dwAllocatedSize;
PBYTE pData = pSlot->pData;
PFRAGSLOT pNext = pSlot->pNext;
memset( pSlot, 0, sizeof( *pSlot ));
pSlot->dwAllocatedSize = dwAllocated;
pSlot->pData = pData;
pSlot->pNext = pNext;
}
VOID
CRDPSound::_FragSlotFreeAll(
VOID
)
{
//
// free the fragment slots too
//
while( NULL != m_pFragSlots )
{
PFRAGSLOT pNext = m_pFragSlots->pNext;
free( m_pFragSlots->pData );
free( m_pFragSlots );
m_pFragSlots = pNext;
}
}
BOOL
CRDPSound::_FragSlotToWave(
PFRAGSLOT pSlot,
PSNDWAVE pWave,
DWORD dwWaveSize
)
{
BOOL rv = FALSE;
DWORD dwAvailDataSize;
DWORD dwBodySize;
ASSERT( pSlot->dwExpectedTotalSize == pSlot->dwTotalSize );
dwAvailDataSize = dwWaveSize - sizeof( *pWave );
if ( dwAvailDataSize < pSlot->dwTotalSize )
{
TRC( ERR, _T("_FragSlotToWave insufficient size to move the wave")
_T(" need %d, available %d\n"),
pSlot->dwTotalSize, dwAvailDataSize );
goto exitpt;
}
//
// when we support fragments, packets are encrypted
//
pWave->Prolog.Type = SNDC_WAVEENCRYPT;
dwBodySize = pSlot->dwTotalSize + sizeof( *pWave ) -
sizeof( pWave->Prolog );
ASSERT( dwBodySize < MAX_UDP_SIZE - sizeof( *pWave ));
pWave->Prolog.BodySize = (UINT16)dwBodySize;
pWave->wTimeStamp = pSlot->wTimeStamp;
pWave->wFormatNo = pSlot->wFormatNo;
pWave->dwBlockNo = pSlot->dwBlockNo;
memcpy( pWave + 1, pSlot->pData, pSlot->dwTotalSize );
//
// release the slot
//
_FragSlotClear( pSlot );
rv = TRUE;
exitpt:
return rv;
}
INT
WSInit(
VOID
)
{
WORD versionRequested;
WSADATA wsaData;
int intRC;
versionRequested = MAKEWORD(1, 1);
intRC = WSAStartup(versionRequested, &wsaData);
if (intRC != 0)
{
TRC(ERR, _T("Failed to initialize WinSock rc:%d\n"), intRC);
}
return intRC;
}
/*
* create signature bits
*/
VOID
CRDPSound::SL_Signature(
PBYTE pSig,
DWORD dwBlockNo
)
{
BYTE ShaBits[A_SHA_DIGEST_LEN];
A_SHA_CTX SHACtx;
ASSERT( A_SHA_DIGEST_LEN > RDPSND_SIGNATURE_SIZE );
A_SHAInit(&SHACtx);
*((DWORD *)(m_EncryptKey + RANDOM_KEY_LENGTH)) = dwBlockNo;
A_SHAUpdate(&SHACtx, (PBYTE)m_EncryptKey, sizeof(m_EncryptKey));
A_SHAFinal(&SHACtx, ShaBits);
memcpy( pSig, ShaBits, RDPSND_SIGNATURE_SIZE );
}
/*
* signature which verifies the audio bits
*/
VOID
CRDPSound::SL_AudioSignature(
PBYTE pSig,
DWORD dwBlockNo,
PBYTE pData,
DWORD dwDataSize
)
{
BYTE ShaBits[A_SHA_DIGEST_LEN];
A_SHA_CTX SHACtx;
A_SHAInit(&SHACtx);
*((DWORD *)(m_EncryptKey + RANDOM_KEY_LENGTH)) = dwBlockNo;
A_SHAUpdate(&SHACtx, (PBYTE)m_EncryptKey, sizeof(m_EncryptKey));
A_SHAUpdate(&SHACtx, pData, dwDataSize );
A_SHAFinal(&SHACtx, ShaBits);
memcpy( pSig, ShaBits, RDPSND_SIGNATURE_SIZE );
}
/*
* encrypt/decrypt a block of data
*
*/
BOOL
CRDPSound::SL_Encrypt( PBYTE pBits, DWORD BlockNo, DWORD dwBitsLen )
{
BYTE ShaBits[A_SHA_DIGEST_LEN];
RC4_KEYSTRUCT rc4key;
#ifndef OS_WINCE
DWORD i;
#endif
PBYTE pbBuffer;
A_SHA_CTX SHACtx;
DWORD dw;
DWORD_PTR *pdwBits;
A_SHAInit(&SHACtx);
// SHA the static bits
*((DWORD *)(m_EncryptKey + RANDOM_KEY_LENGTH)) = BlockNo;
A_SHAUpdate(&SHACtx, (PBYTE)m_EncryptKey, sizeof(m_EncryptKey));
A_SHAFinal(&SHACtx, ShaBits);
rc4_key(&rc4key, A_SHA_DIGEST_LEN, ShaBits);
rc4(&rc4key, dwBitsLen, pBits);
return TRUE;
}
/*
* Function:
* _DbgPrintMessage
*
* Description:
* A tracing function
*
* Parameters:
* level - current message trace level
* format - message format
* ... - parameters
*
*/
VOID
_cdecl
_DbgPrintMessage(LPCTSTR level, LPCTSTR format, ...)
{
TCHAR szBuffer[256];
va_list arglist;
if (ALV == level)
return;
va_start (arglist, format);
StringCchVPrintf(szBuffer, SIZE_TCHARS(szBuffer), format, arglist);
va_end (arglist);
#ifndef OS_WINCE
OutputDebugString(level);
OutputDebugString(szBuffer);
#endif // !OS_WINCE
}