Blame server/Windows/wf_directsound.c

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
}