|
Packit |
1fb8d4 |
#include "wf_directsound.h"
|
|
Packit |
1fb8d4 |
#include "wf_interface.h"
|
|
Packit |
1fb8d4 |
#include "wf_info.h"
|
|
Packit |
1fb8d4 |
#include "wf_rdpsnd.h"
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#include <winpr/windows.h>
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#define INITGUID
|
|
Packit |
1fb8d4 |
#include <initguid.h>
|
|
Packit |
1fb8d4 |
#include <objbase.h>
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#define CINTERFACE 1
|
|
Packit |
1fb8d4 |
#include <mmsystem.h>
|
|
Packit |
1fb8d4 |
#include <dsound.h>
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#include <freerdp/log.h>
|
|
Packit |
1fb8d4 |
#define TAG SERVER_TAG("windows")
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
IDirectSoundCapture8* cap;
|
|
Packit |
1fb8d4 |
IDirectSoundCaptureBuffer8* capBuf;
|
|
Packit |
1fb8d4 |
DSCBUFFERDESC dscbd;
|
|
Packit |
1fb8d4 |
DWORD lastPos;
|
|
Packit |
1fb8d4 |
wfPeerContext* latestPeer;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
int wf_rdpsnd_set_latest_peer(wfPeerContext* peer)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
latestPeer = peer;
|
|
Packit |
1fb8d4 |
return 0;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
int wf_directsound_activate(RdpsndServerContext* context)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
HRESULT hr;
|
|
Packit |
1fb8d4 |
wfInfo* wfi;
|
|
Packit |
1fb8d4 |
HANDLE hThread;
|
|
Packit Service |
5a9772 |
|
|
Packit Service |
5a9772 |
LPDIRECTSOUNDCAPTUREBUFFER pDSCB;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
wfi = wf_info_get_instance();
|
|
Packit |
1fb8d4 |
if (!wfi)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "Failed to wfi instance");
|
|
Packit |
1fb8d4 |
return 1;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
WLog_DBG(TAG, "RDPSND (direct sound) Activated");
|
|
Packit |
1fb8d4 |
hr = DirectSoundCaptureCreate8(NULL, &cap, NULL);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (FAILED(hr))
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "Failed to create sound capture device");
|
|
Packit |
1fb8d4 |
return 1;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
WLog_INFO(TAG, "Created sound capture device");
|
|
Packit |
1fb8d4 |
dscbd.dwSize = sizeof(DSCBUFFERDESC);
|
|
Packit |
1fb8d4 |
dscbd.dwFlags = 0;
|
|
Packit |
1fb8d4 |
dscbd.dwBufferBytes = wfi->agreed_format->nAvgBytesPerSec;
|
|
Packit |
1fb8d4 |
dscbd.dwReserved = 0;
|
|
Packit |
1fb8d4 |
dscbd.lpwfxFormat = wfi->agreed_format;
|
|
Packit |
1fb8d4 |
dscbd.dwFXCount = 0;
|
|
Packit |
1fb8d4 |
dscbd.lpDSCFXDesc = NULL;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
hr = cap->lpVtbl->CreateCaptureBuffer(cap, &dscbd, &pDSCB, NULL);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (FAILED(hr))
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "Failed to create capture buffer");
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
WLog_INFO(TAG, "Created capture buffer");
|
|
Packit |
1fb8d4 |
hr = pDSCB->lpVtbl->QueryInterface(pDSCB, &IID_IDirectSoundCaptureBuffer8, (LPVOID*)&capBuf);
|
|
Packit |
1fb8d4 |
if (FAILED(hr))
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "Failed to QI capture buffer");
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
WLog_INFO(TAG, "Created IDirectSoundCaptureBuffer8");
|
|
Packit |
1fb8d4 |
pDSCB->lpVtbl->Release(pDSCB);
|
|
Packit |
1fb8d4 |
lastPos = 0;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!(hThread = CreateThread(NULL, 0, wf_rdpsnd_directsound_thread, latestPeer, 0, NULL)))
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "Failed to create direct sound thread");
|
|
Packit |
1fb8d4 |
return 1;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
CloseHandle(hThread);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
return 0;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
static DWORD WINAPI wf_rdpsnd_directsound_thread(LPVOID lpParam)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
HRESULT hr;
|
|
Packit |
1fb8d4 |
DWORD beg = 0;
|
|
Packit |
1fb8d4 |
DWORD end = 0;
|
|
Packit |
1fb8d4 |
DWORD diff, rate;
|
|
Packit |
1fb8d4 |
wfPeerContext* context;
|
|
Packit |
1fb8d4 |
wfInfo* wfi;
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
VOID* pbCaptureData = NULL;
|
|
Packit |
1fb8d4 |
DWORD dwCaptureLength = 0;
|
|
Packit |
1fb8d4 |
VOID* pbCaptureData2 = NULL;
|
|
Packit |
1fb8d4 |
DWORD dwCaptureLength2 = 0;
|
|
Packit Service |
5a9772 |
VOID* pbPlayData = NULL;
|
|
Packit |
1fb8d4 |
DWORD dwReadPos = 0;
|
|
Packit |
1fb8d4 |
LONG lLockSize = 0;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
wfi = wf_info_get_instance();
|
|
Packit |
1fb8d4 |
if (!wfi)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "Failed get instance");
|
|
Packit |
1fb8d4 |
return 1;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
context = (wfPeerContext*)lpParam;
|
|
Packit |
1fb8d4 |
rate = 1000 / 24;
|
|
Packit |
1fb8d4 |
WLog_INFO(TAG, "Trying to start capture");
|
|
Packit |
1fb8d4 |
hr = capBuf->lpVtbl->Start(capBuf, DSCBSTART_LOOPING);
|
|
Packit |
1fb8d4 |
if (FAILED(hr))
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "Failed to start capture");
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
WLog_INFO(TAG, "Capture started");
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
while (1)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
end = GetTickCount();
|
|
Packit |
1fb8d4 |
diff = end - beg;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (diff < rate)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
Sleep(rate - diff);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
beg = GetTickCount();
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (wf_rdpsnd_lock() > 0)
|
|
Packit |
1fb8d4 |
{
|
|
Packit Service |
5a9772 |
// check for main exit condition
|
|
Packit |
1fb8d4 |
if (wfi->snd_stop == TRUE)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
wf_rdpsnd_unlock();
|
|
Packit |
1fb8d4 |
break;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
hr = capBuf->lpVtbl->GetCurrentPosition(capBuf, NULL, &dwReadPos);
|
|
Packit |
1fb8d4 |
if (FAILED(hr))
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "Failed to get read pos");
|
|
Packit |
1fb8d4 |
wf_rdpsnd_unlock();
|
|
Packit |
1fb8d4 |
break;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
lLockSize = dwReadPos - lastPos; // dscbd.dwBufferBytes;
|
|
Packit Service |
5a9772 |
if (lLockSize < 0)
|
|
Packit Service |
5a9772 |
lLockSize += dscbd.dwBufferBytes;
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
// WLog_DBG(TAG, "Last, read, lock = [%"PRIu32", %"PRIu32", %"PRId32"]\n", lastPos,
|
|
Packit Service |
5a9772 |
// dwReadPos, lLockSize);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (lLockSize == 0)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
wf_rdpsnd_unlock();
|
|
Packit |
1fb8d4 |
continue;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
hr = capBuf->lpVtbl->Lock(capBuf, lastPos, lLockSize, &pbCaptureData, &dwCaptureLength,
|
|
Packit Service |
5a9772 |
&pbCaptureData2, &dwCaptureLength2, 0L);
|
|
Packit |
1fb8d4 |
if (FAILED(hr))
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "Failed to lock sound capture buffer");
|
|
Packit |
1fb8d4 |
wf_rdpsnd_unlock();
|
|
Packit |
1fb8d4 |
break;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
// fwrite(pbCaptureData, 1, dwCaptureLength, pFile);
|
|
Packit Service |
5a9772 |
// fwrite(pbCaptureData2, 1, dwCaptureLength2, pFile);
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
// FIXME: frames = bytes/(bytespersample * channels)
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
context->rdpsnd->SendSamples(context->rdpsnd, pbCaptureData, dwCaptureLength / 4,
|
|
Packit Service |
5a9772 |
(UINT16)(beg & 0xffff));
|
|
Packit Service |
5a9772 |
context->rdpsnd->SendSamples(context->rdpsnd, pbCaptureData2, dwCaptureLength2 / 4,
|
|
Packit Service |
5a9772 |
(UINT16)(beg & 0xffff));
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
hr = capBuf->lpVtbl->Unlock(capBuf, pbCaptureData, dwCaptureLength, pbCaptureData2,
|
|
Packit Service |
5a9772 |
dwCaptureLength2);
|
|
Packit |
1fb8d4 |
if (FAILED(hr))
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "Failed to unlock sound capture buffer");
|
|
Packit |
1fb8d4 |
wf_rdpsnd_unlock();
|
|
Packit |
1fb8d4 |
return 0;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
// TODO keep track of location in buffer
|
|
Packit |
1fb8d4 |
lastPos += dwCaptureLength;
|
|
Packit |
1fb8d4 |
lastPos %= dscbd.dwBufferBytes;
|
|
Packit |
1fb8d4 |
lastPos += dwCaptureLength2;
|
|
Packit |
1fb8d4 |
lastPos %= dscbd.dwBufferBytes;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
wf_rdpsnd_unlock();
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
WLog_INFO(TAG, "Trying to stop sound capture");
|
|
Packit |
1fb8d4 |
hr = capBuf->lpVtbl->Stop(capBuf);
|
|
Packit |
1fb8d4 |
if (FAILED(hr))
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "Failed to stop capture");
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
WLog_INFO(TAG, "Capture stopped");
|
|
Packit |
1fb8d4 |
capBuf->lpVtbl->Release(capBuf);
|
|
Packit |
1fb8d4 |
cap->lpVtbl->Release(cap);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
lastPos = 0;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
return 0;
|
|
Packit |
1fb8d4 |
}
|