FreeRDP
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Modules Pages
wf_directsound.c
1#include "wf_directsound.h"
2#include "wf_interface.h"
3#include "wf_info.h"
4#include "wf_rdpsnd.h"
5
6#include <winpr/windows.h>
7
8#define INITGUID
9#include <initguid.h>
10#include <objbase.h>
11
12#define CINTERFACE 1
13#include <mmsystem.h>
14#include <dsound.h>
15
16#include <freerdp/log.h>
17#define TAG SERVER_TAG("windows")
18
19IDirectSoundCapture8* cap;
20IDirectSoundCaptureBuffer8* capBuf;
21DSCBUFFERDESC dscbd;
22DWORD lastPos;
23wfPeerContext* latestPeer;
24
25int wf_rdpsnd_set_latest_peer(wfPeerContext* peer)
26{
27 latestPeer = peer;
28 return 0;
29}
30
31int wf_directsound_activate(RdpsndServerContext* context)
32{
33 HRESULT hr;
34 wfInfo* wfi;
35 HANDLE hThread;
36
37 LPDIRECTSOUNDCAPTUREBUFFER pDSCB;
38
39 wfi = wf_info_get_instance();
40 if (!wfi)
41 {
42 WLog_ERR(TAG, "Failed to wfi instance");
43 return 1;
44 }
45 WLog_DBG(TAG, "RDPSND (direct sound) Activated");
46 hr = DirectSoundCaptureCreate8(NULL, &cap, NULL);
47
48 if (FAILED(hr))
49 {
50 WLog_ERR(TAG, "Failed to create sound capture device");
51 return 1;
52 }
53
54 WLog_INFO(TAG, "Created sound capture device");
55 dscbd.dwSize = sizeof(DSCBUFFERDESC);
56 dscbd.dwFlags = 0;
57 dscbd.dwBufferBytes = wfi->agreed_format->nAvgBytesPerSec;
58 dscbd.dwReserved = 0;
59 dscbd.lpwfxFormat = wfi->agreed_format;
60 dscbd.dwFXCount = 0;
61 dscbd.lpDSCFXDesc = NULL;
62
63 hr = cap->lpVtbl->CreateCaptureBuffer(cap, &dscbd, &pDSCB, NULL);
64
65 if (FAILED(hr))
66 {
67 WLog_ERR(TAG, "Failed to create capture buffer");
68 }
69
70 WLog_INFO(TAG, "Created capture buffer");
71 hr = pDSCB->lpVtbl->QueryInterface(pDSCB, &IID_IDirectSoundCaptureBuffer8, (LPVOID*)&capBuf);
72 if (FAILED(hr))
73 {
74 WLog_ERR(TAG, "Failed to QI capture buffer");
75 }
76 WLog_INFO(TAG, "Created IDirectSoundCaptureBuffer8");
77 pDSCB->lpVtbl->Release(pDSCB);
78 lastPos = 0;
79
80 if (!(hThread = CreateThread(NULL, 0, wf_rdpsnd_directsound_thread, latestPeer, 0, NULL)))
81 {
82 WLog_ERR(TAG, "Failed to create direct sound thread");
83 return 1;
84 }
85 (void)CloseHandle(hThread);
86
87 return 0;
88}
89
90static DWORD WINAPI wf_rdpsnd_directsound_thread(LPVOID lpParam)
91{
92 HRESULT hr;
93 DWORD beg = 0;
94 DWORD end = 0;
95 DWORD diff, rate;
96 wfPeerContext* context;
97 wfInfo* wfi;
98
99 VOID* pbCaptureData = NULL;
100 DWORD dwCaptureLength = 0;
101 VOID* pbCaptureData2 = NULL;
102 DWORD dwCaptureLength2 = 0;
103 VOID* pbPlayData = NULL;
104 DWORD dwReadPos = 0;
105 LONG lLockSize = 0;
106
107 wfi = wf_info_get_instance();
108 if (!wfi)
109 {
110 WLog_ERR(TAG, "Failed get instance");
111 return 1;
112 }
113
114 context = (wfPeerContext*)lpParam;
115 rate = 1000 / 24;
116 WLog_INFO(TAG, "Trying to start capture");
117 hr = capBuf->lpVtbl->Start(capBuf, DSCBSTART_LOOPING);
118 if (FAILED(hr))
119 {
120 WLog_ERR(TAG, "Failed to start capture");
121 }
122 WLog_INFO(TAG, "Capture started");
123
124 while (1)
125 {
126
127 end = GetTickCount();
128 diff = end - beg;
129
130 if (diff < rate)
131 {
132 Sleep(rate - diff);
133 }
134
135 beg = GetTickCount();
136
137 if (wf_rdpsnd_lock() > 0)
138 {
139 // check for main exit condition
140 if (wfi->snd_stop == TRUE)
141 {
142 wf_rdpsnd_unlock();
143 break;
144 }
145
146 hr = capBuf->lpVtbl->GetCurrentPosition(capBuf, NULL, &dwReadPos);
147 if (FAILED(hr))
148 {
149 WLog_ERR(TAG, "Failed to get read pos");
150 wf_rdpsnd_unlock();
151 break;
152 }
153
154 lLockSize = dwReadPos - lastPos; // dscbd.dwBufferBytes;
155 if (lLockSize < 0)
156 lLockSize += dscbd.dwBufferBytes;
157
158 // WLog_DBG(TAG, "Last, read, lock = [%"PRIu32", %"PRIu32", %"PRId32"]\n", lastPos,
159 // dwReadPos, lLockSize);
160
161 if (lLockSize == 0)
162 {
163 wf_rdpsnd_unlock();
164 continue;
165 }
166
167 hr = capBuf->lpVtbl->Lock(capBuf, lastPos, lLockSize, &pbCaptureData, &dwCaptureLength,
168 &pbCaptureData2, &dwCaptureLength2, 0L);
169 if (FAILED(hr))
170 {
171 WLog_ERR(TAG, "Failed to lock sound capture buffer");
172 wf_rdpsnd_unlock();
173 break;
174 }
175
176 // fwrite(pbCaptureData, 1, dwCaptureLength, pFile);
177 // fwrite(pbCaptureData2, 1, dwCaptureLength2, pFile);
178
179 // FIXME: frames = bytes/(bytespersample * channels)
180
181 context->rdpsnd->SendSamples(context->rdpsnd, pbCaptureData, dwCaptureLength / 4,
182 (UINT16)(beg & 0xffff));
183 context->rdpsnd->SendSamples(context->rdpsnd, pbCaptureData2, dwCaptureLength2 / 4,
184 (UINT16)(beg & 0xffff));
185
186 hr = capBuf->lpVtbl->Unlock(capBuf, pbCaptureData, dwCaptureLength, pbCaptureData2,
187 dwCaptureLength2);
188 if (FAILED(hr))
189 {
190 WLog_ERR(TAG, "Failed to unlock sound capture buffer");
191 wf_rdpsnd_unlock();
192 return 0;
193 }
194
195 // TODO keep track of location in buffer
196 lastPos += dwCaptureLength;
197 lastPos %= dscbd.dwBufferBytes;
198 lastPos += dwCaptureLength2;
199 lastPos %= dscbd.dwBufferBytes;
200
201 wf_rdpsnd_unlock();
202 }
203 }
204
205 WLog_INFO(TAG, "Trying to stop sound capture");
206 hr = capBuf->lpVtbl->Stop(capBuf);
207 if (FAILED(hr))
208 {
209 WLog_ERR(TAG, "Failed to stop capture");
210 }
211
212 WLog_INFO(TAG, "Capture stopped");
213 capBuf->lpVtbl->Release(capBuf);
214 cap->lpVtbl->Release(cap);
215
216 lastPos = 0;
217
218 return 0;
219}