1 // Copyright 2005-2019 The Mumble Developers. All rights reserved.
2 // Use of this source code is governed by a BSD-style license
3 // that can be found in the LICENSE file at the root of the
4 // Mumble source tree or at <https://www.mumble.info/LICENSE>.
5
6 #include "mumble_pch.hpp"
7
8 #define DIRECTSOUND_VERSION 0x1000
9
10 #include <mmsystem.h>
11 #include <dsound.h>
12 #include <ks.h>
13 #include <ksmedia.h>
14
15 #include "DirectSound.h"
16
17 #include "MainWindow.h"
18 #include "Plugins.h"
19 #include "User.h"
20 #include "Global.h"
21
22 // from os_win.cpp
23 extern HWND mumble_mw_hwnd;
24
25 #undef FAILED
26 #define FAILED(Status) (static_cast<HRESULT>(Status)<0)
27
28 // #define MY_DEFERRED DS3D_DEFERRED
29 #define MY_DEFERRED DS3D_IMMEDIATE
30
31 #define NBLOCKS 50
32
33 class DXAudioOutputRegistrar : public AudioOutputRegistrar {
34 public:
35 DXAudioOutputRegistrar();
36 virtual AudioOutput *create();
37 virtual const QList<audioDevice> getDeviceChoices();
38 virtual void setDeviceChoice(const QVariant &, Settings &);
39
40 };
41
42 class DXAudioInputRegistrar : public AudioInputRegistrar {
43 public:
44 DXAudioInputRegistrar();
45 virtual AudioInput *create();
46 virtual const QList<audioDevice> getDeviceChoices();
47 virtual void setDeviceChoice(const QVariant &, Settings &);
48 virtual bool canEcho(const QString &) const;
49
50 };
51
52 class DirectSoundInit : public DeferInit {
53 DXAudioInputRegistrar *airReg;
54 DXAudioOutputRegistrar *aorReg;
55 public:
DirectSoundInit()56 DirectSoundInit() : airReg(NULL), aorReg(NULL) {}
57 void initialize();
58 void destroy();
59 };
60
61 static DirectSoundInit dsinit;
62
initialize()63 void DirectSoundInit::initialize() {
64 airReg = NULL;
65 aorReg = NULL;
66
67 #ifdef USE_WASAPI
68 OSVERSIONINFOEXW ovi;
69 memset(&ovi, 0, sizeof(ovi));
70
71 ovi.dwOSVersionInfoSize=sizeof(ovi);
72 GetVersionEx(reinterpret_cast<OSVERSIONINFOW *>(&ovi));
73
74 #ifdef QT_NO_DEBUG
75 if ((ovi.dwMajorVersion > 6) || ((ovi.dwMajorVersion == 6) && (ovi.dwBuildNumber >= 6001))) {
76 HMODULE hLib = LoadLibrary(L"AVRT.DLL");
77 if (hLib != NULL) {
78 FreeLibrary(hLib);
79 qWarning("DirectSound: Disabled as WASAPI is available");
80 return;
81 }
82 }
83 #endif
84 #endif
85
86 airReg = new DXAudioInputRegistrar();
87 aorReg = new DXAudioOutputRegistrar();
88 }
89
destroy()90 void DirectSoundInit::destroy() {
91 delete airReg;
92 delete aorReg;
93 }
94
95
DXAudioOutputRegistrar()96 DXAudioOutputRegistrar::DXAudioOutputRegistrar() : AudioOutputRegistrar(QLatin1String("DirectSound")) {
97 }
98
create()99 AudioOutput *DXAudioOutputRegistrar::create() {
100 return new DXAudioOutput();
101 }
102
103 typedef QPair<QString, GUID> dsDevice;
104
DSEnumProc(LPGUID lpGUID,const WCHAR * lpszDesc,const WCHAR *,void * ctx)105 static BOOL CALLBACK DSEnumProc(LPGUID lpGUID, const WCHAR* lpszDesc,
106 const WCHAR*, void *ctx) {
107 if (lpGUID) {
108 QList<dsDevice> *l =reinterpret_cast<QList<dsDevice> *>(ctx);
109 *l << dsDevice(QString::fromUtf16(reinterpret_cast<const ushort*>(lpszDesc)), *lpGUID);
110 }
111
112 return(true);
113 }
114
getDeviceChoices()115 const QList<audioDevice> DXAudioOutputRegistrar::getDeviceChoices() {
116 QList<dsDevice> qlOutput;
117
118 qlOutput << dsDevice(DXAudioOutput::tr("Default DirectSound Voice Output"), DSDEVID_DefaultVoicePlayback);
119 DirectSoundEnumerate(DSEnumProc, reinterpret_cast<void *>(&qlOutput));
120
121 QList<audioDevice> qlReturn;
122
123 const GUID *lpguid = NULL;
124
125 if (! g.s.qbaDXOutput.isEmpty()) {
126 lpguid = reinterpret_cast<LPGUID>(g.s.qbaDXOutput.data());
127 } else {
128 lpguid = &DSDEVID_DefaultVoicePlayback;
129 }
130
131 foreach(dsDevice d, qlOutput) {
132 if (d.second == *lpguid) {
133 qlReturn << audioDevice(d.first, QByteArray(reinterpret_cast<const char *>(&d.second), sizeof(GUID)));
134 }
135 }
136 foreach(dsDevice d, qlOutput) {
137 if (d.second != *lpguid) {
138 qlReturn << audioDevice(d.first, QByteArray(reinterpret_cast<const char *>(&d.second), sizeof(GUID)));
139 }
140 }
141 return qlReturn;
142 }
143
setDeviceChoice(const QVariant & choice,Settings & s)144 void DXAudioOutputRegistrar::setDeviceChoice(const QVariant &choice, Settings &s) {
145 s.qbaDXOutput = choice.toByteArray();
146 }
147
DXAudioInputRegistrar()148 DXAudioInputRegistrar::DXAudioInputRegistrar() : AudioInputRegistrar(QLatin1String("DirectSound")) {
149 }
150
create()151 AudioInput *DXAudioInputRegistrar::create() {
152 return new DXAudioInput();
153 }
154
getDeviceChoices()155 const QList<audioDevice> DXAudioInputRegistrar::getDeviceChoices() {
156 QList<dsDevice> qlInput;
157
158 qlInput << dsDevice(DXAudioInput::tr("Default DirectSound Voice Input"), DSDEVID_DefaultVoiceCapture);
159 DirectSoundCaptureEnumerate(DSEnumProc, reinterpret_cast<void *>(&qlInput));
160
161 QList<audioDevice> qlReturn;
162
163 const GUID *lpguid = NULL;
164
165 if (! g.s.qbaDXInput.isEmpty()) {
166 lpguid = reinterpret_cast<LPGUID>(g.s.qbaDXInput.data());
167 } else {
168 lpguid = &DSDEVID_DefaultVoiceCapture;
169 }
170
171 foreach(dsDevice d, qlInput) {
172 if (d.second == *lpguid) {
173 qlReturn << audioDevice(d.first, QByteArray(reinterpret_cast<const char *>(&d.second), sizeof(GUID)));
174 }
175 }
176 foreach(dsDevice d, qlInput) {
177 if (d.second != *lpguid) {
178 qlReturn << audioDevice(d.first, QByteArray(reinterpret_cast<const char *>(&d.second), sizeof(GUID)));
179 }
180 }
181 return qlReturn;
182 }
183
setDeviceChoice(const QVariant & choice,Settings & s)184 void DXAudioInputRegistrar::setDeviceChoice(const QVariant &choice, Settings &s) {
185 s.qbaDXInput = choice.toByteArray();
186 }
187
canEcho(const QString &) const188 bool DXAudioInputRegistrar::canEcho(const QString &) const {
189 return false;
190 }
191
DXAudioOutput()192 DXAudioOutput::DXAudioOutput() {
193 }
194
~DXAudioOutput()195 DXAudioOutput::~DXAudioOutput() {
196 bRunning = false;
197 wait();
198 }
199
run()200 void DXAudioOutput::run() {
201 HRESULT hr;
202 DSBUFFERDESC dsbdesc;
203 WAVEFORMATEXTENSIBLE wfx;
204 WAVEFORMATEXTENSIBLE wfxSet;
205 int ns = 0;
206 unsigned int chanmasks[32];
207
208 LPDIRECTSOUND8 pDS = NULL;
209 LPDIRECTSOUNDBUFFER pDSBPrimary = NULL;
210 LPDIRECTSOUNDBUFFER pDSBOutput = NULL;
211 LPDIRECTSOUNDNOTIFY pDSNotify = NULL;
212
213 int iLastwriteblock;
214 LPVOID aptr1, aptr2;
215 DWORD nbytes1, nbytes2;
216
217 int playblock;
218 int nowriteblock;
219 DWORD dwPlayPosition, dwWritePosition;
220
221 unsigned int iByteSize;
222
223 bool bOk;
224 DWORD dwSpeakerConfig;
225
226 bool failed = false;
227
228 bOk = false;
229 DWORD dwMask = 0;
230 bool bHead = false;
231
232 ZeroMemory(&dsbdesc, sizeof(DSBUFFERDESC));
233 dsbdesc.dwSize = sizeof(DSBUFFERDESC);
234 dsbdesc.dwFlags = DSBCAPS_PRIMARYBUFFER;
235
236 if (! g.s.qbaDXOutput.isEmpty()) {
237 LPGUID lpguid = reinterpret_cast<LPGUID>(g.s.qbaDXOutput.data());
238 if (FAILED(hr = DirectSoundCreate8(lpguid, &pDS, NULL))) {
239 failed = true;
240 }
241 }
242
243 if (! pDS && FAILED(hr = DirectSoundCreate8(&DSDEVID_DefaultVoicePlayback, &pDS, NULL))) {
244 qWarning("DXAudioOutput: DirectSoundCreate failed: hr=0x%08lx", hr);
245 goto cleanup;
246 } else if (FAILED(hr = pDS->SetCooperativeLevel(mumble_mw_hwnd, DSSCL_PRIORITY))) {
247 qWarning("DXAudioOutput: SetCooperativeLevel failed: hr=0x%08lx", hr);
248 goto cleanup;
249 } else if (FAILED(hr = pDS->CreateSoundBuffer(&dsbdesc, &pDSBPrimary, NULL))) {
250 qWarning("DXAudioOutput: CreateSoundBuffer (Primary) failed: hr=0x%08lx", hr);
251 goto cleanup;
252 }
253
254 pDS->GetSpeakerConfig(&dwSpeakerConfig);
255
256
257 switch (DSSPEAKER_CONFIG(dwSpeakerConfig)) {
258 case DSSPEAKER_HEADPHONE:
259 dwMask = KSAUDIO_SPEAKER_STEREO;
260 bHead = true;
261 break;
262 case DSSPEAKER_MONO:
263 dwMask = KSAUDIO_SPEAKER_MONO;
264 break;
265 case DSSPEAKER_QUAD:
266 dwMask = KSAUDIO_SPEAKER_QUAD;
267 break;
268 case DSSPEAKER_STEREO:
269 dwMask = KSAUDIO_SPEAKER_STEREO;
270 break;
271 case DSSPEAKER_SURROUND:
272 dwMask = KSAUDIO_SPEAKER_SURROUND;
273 break;
274 case DSSPEAKER_5POINT1:
275 dwMask = KSAUDIO_SPEAKER_5POINT1;
276 break;
277 case DSSPEAKER_7POINT1:
278 dwMask = KSAUDIO_SPEAKER_7POINT1;
279 break;
280 case DSSPEAKER_7POINT1_SURROUND:
281 dwMask = KSAUDIO_SPEAKER_7POINT1_SURROUND;
282 break;
283 case DSSPEAKER_5POINT1_SURROUND:
284 dwMask = KSAUDIO_SPEAKER_5POINT1_SURROUND;
285 break;
286 default:
287 dwMask = 0;
288 break;
289 }
290
291 if (! g.s.doPositionalAudio())
292 dwMask = KSAUDIO_SPEAKER_STEREO;
293
294 for (int i=0;i<32;i++) {
295 if (dwMask & (1 << i)) {
296 chanmasks[ns++] = 1 << i;
297 }
298 }
299
300 iMixerFreq = SAMPLE_RATE;
301 iChannels = ns;
302 eSampleFormat = SampleShort;
303
304 iByteSize = iFrameSize * sizeof(short) * ns;
305
306 ZeroMemory(&wfxSet, sizeof(wfxSet));
307 wfxSet.Format.wFormatTag = WAVE_FORMAT_PCM;
308
309 ZeroMemory(&wfx, sizeof(wfx));
310 wfx.Format.wFormatTag = WAVE_FORMAT_PCM;
311 wfx.Format.nChannels = qMax(ns, 2);
312 wfx.Format.nSamplesPerSec = SAMPLE_RATE;
313 wfx.Format.nBlockAlign = sizeof(short) * wfx.Format.nChannels;
314 wfx.Format.nAvgBytesPerSec = wfx.Format.nSamplesPerSec * wfx.Format.nBlockAlign;
315 wfx.Format.wBitsPerSample = 16;
316
317 if (FAILED(hr = pDSBPrimary->SetFormat(reinterpret_cast<WAVEFORMATEX *>(&wfx)))) {
318 qWarning("DXAudioOutput: SetFormat failed: hr=0x%08lx", hr);
319 goto cleanup;
320 }
321 if (FAILED(hr = pDSBPrimary->GetFormat(reinterpret_cast<WAVEFORMATEX *>(&wfxSet), sizeof(wfxSet), NULL))) {
322 qWarning("DXAudioOutput: GetFormat failed: hr=0x%08lx", hr);
323 goto cleanup;
324 }
325
326 qWarning("DXAudioOutput: Primary buffer of %ld Hz, %d channels, %d bits",wfxSet.Format.nSamplesPerSec,wfxSet.Format.nChannels,wfxSet.Format.wBitsPerSample);
327
328 ZeroMemory(&wfx, sizeof(wfx));
329 wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
330 wfx.Format.nChannels = qMax(ns, 2);
331 wfx.Format.nSamplesPerSec = SAMPLE_RATE;
332 wfx.Format.nBlockAlign = sizeof(short) * wfx.Format.nChannels;
333 wfx.Format.nAvgBytesPerSec = wfx.Format.nSamplesPerSec * wfx.Format.nBlockAlign;
334 wfx.Format.wBitsPerSample = 16;
335 wfx.Format.cbSize = 32;
336 wfx.Samples.wValidBitsPerSample = wfx.Format.wBitsPerSample;
337 wfx.dwChannelMask = dwMask;
338 wfx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
339
340 ZeroMemory(&dsbdesc, sizeof(DSBUFFERDESC));
341 dsbdesc.dwSize = sizeof(DSBUFFERDESC);
342 dsbdesc.dwFlags = DSBCAPS_GLOBALFOCUS|DSBCAPS_GETCURRENTPOSITION2;
343 dsbdesc.dwFlags |= DSBCAPS_CTRLPOSITIONNOTIFY;
344 dsbdesc.dwBufferBytes = wfx.Format.nChannels * iFrameSize * sizeof(short) * NBLOCKS;
345 dsbdesc.lpwfxFormat = reinterpret_cast<WAVEFORMATEX *>(&wfx);
346
347 if (FAILED(hr = pDS->CreateSoundBuffer(&dsbdesc, &pDSBOutput, NULL))) {
348 qWarning("DXAudioOutputUser: CreateSoundBuffer (Secondary) failed: hr=0x%08lx", hr);
349 goto cleanup;
350 }
351
352
353 if (FAILED(hr = pDSBOutput->QueryInterface(IID_IDirectSoundNotify, reinterpret_cast<void **>(&pDSNotify)))) {
354 qWarning("DXAudioOutputUser: QueryInterface (Notify) failed: hr=0x%08lx", hr);
355 goto cleanup;
356 }
357
358 qWarning("DXAudioOutputUser: New %dHz output buffer of %ld bytes", SAMPLE_RATE, dsbdesc.dwBufferBytes);
359
360 if (failed)
361 g.mw->msgBox(tr("Opening chosen DirectSound Output failed. Default device will be used."));
362
363 initializeMixer(chanmasks, bHead);
364
365 if (FAILED(hr = pDSBOutput->Lock(0, 0, &aptr1, &nbytes1, &aptr2, &nbytes2, DSBLOCK_ENTIREBUFFER))) {
366 qWarning("DXAudioOutputUser: Initial Lock failed: hr=0x%08lx", hr);
367 goto cleanup;
368 }
369
370 if (aptr1)
371 ZeroMemory(aptr1, nbytes1);
372 if (aptr2)
373 ZeroMemory(aptr2, nbytes2);
374
375 if (FAILED(hr = pDSBOutput->Unlock(aptr1, nbytes1, aptr2, nbytes2))) {
376 qWarning("DXAudioOutputUser: Initial Unlock failed: hr=0x%08lx", hr);
377 goto cleanup;
378 }
379
380 if (FAILED(hr = pDSBOutput->Play(0, 0, DSBPLAY_LOOPING))) {
381 qWarning("DXAudioOutputUser: Play failed: hr=0x%08lx", hr);
382 goto cleanup;
383 }
384
385 iLastwriteblock = (NBLOCKS - 1 + g.s.iOutputDelay) % NBLOCKS;
386
387 bOk = true;
388
389 while (bRunning && ! FAILED(hr)) {
390 if (FAILED(hr = pDSBOutput->GetCurrentPosition(&dwPlayPosition, &dwWritePosition))) {
391 qWarning("DXAudioOutputUser: GetCurrentPosition failed: hr=0x%08lx", hr);
392 break;
393 }
394
395 playblock = dwWritePosition / iByteSize;
396 nowriteblock = (playblock + g.s.iOutputDelay + 1) % NBLOCKS;
397
398 for (int block=(iLastwriteblock + 1) % NBLOCKS;(!FAILED(hr)) && (block!=nowriteblock);block=(block + 1) % NBLOCKS) {
399 iLastwriteblock = block;
400
401 if (FAILED(hr = pDSBOutput->Lock(block * iByteSize, iByteSize, &aptr1, &nbytes1, &aptr2, &nbytes2, 0))) {
402 qWarning("DXAudioOutput: Lock block %u (%d bytes) failed: hr=0x%08lx",block, iByteSize, hr);
403 break;
404 }
405 if (aptr2 || nbytes2) {
406 qWarning("DXAudioOutput: Split buffer");
407 break;
408 }
409 if (!aptr1 || ! nbytes1) {
410 qWarning("DXAudioOutput: Zerolock");
411 break;
412 }
413 if (! mix(reinterpret_cast<short *>(aptr1), iFrameSize))
414 ZeroMemory(aptr1, iByteSize);
415
416 if (FAILED(hr = pDSBOutput->Unlock(aptr1, nbytes1, aptr2, nbytes2))) {
417 qWarning("DXAudioOutput: Unlock %p(%lu) %p(%lu) failed: hr=0x%08lx",aptr1,nbytes1,aptr2,nbytes2,hr);
418 break;
419 }
420
421 if (FAILED(hr = pDSBOutput->GetCurrentPosition(&dwPlayPosition, &dwWritePosition))) {
422 qWarning("DXAudioOutputUser: GetCurrentPosition failed: hr=0x%08lx", hr);
423 break;
424 }
425
426 playblock = dwWritePosition / iByteSize;
427 nowriteblock = (playblock + g.s.iOutputDelay + 1) % NBLOCKS;
428 }
429 if (! FAILED(hr))
430 msleep(19);
431 }
432
433 if (FAILED(hr)) {
434 g.mw->msgBox(tr("Lost DirectSound output device."));
435 }
436 cleanup:
437 if (! bOk) {
438 g.mw->msgBox(tr("Opening chosen DirectSound Output failed. No audio will be heard."));
439 return;
440 }
441
442 if (pDSNotify)
443 pDSNotify->Release();
444 if (pDSBOutput) {
445 pDSBOutput->Stop();
446 pDSBOutput->Release();
447 }
448 if (pDSBPrimary)
449 pDSBPrimary->Release();
450 if (pDS)
451 pDS->Release();
452 }
453
454 #define NBUFFBLOCKS 50
455
DXAudioInput()456 DXAudioInput::DXAudioInput() {
457 }
458
~DXAudioInput()459 DXAudioInput::~DXAudioInput() {
460 bRunning = false;
461 wait();
462 }
463
run()464 void DXAudioInput::run() {
465 LPDIRECTSOUNDCAPTURE8 pDSCapture;
466 LPDIRECTSOUNDCAPTUREBUFFER pDSCaptureBuffer;
467 LPDIRECTSOUNDNOTIFY pDSNotify;
468
469 DWORD dwBufferSize;
470 bool bOk;
471 DWORD dwReadPosition;
472 DWORD dwCapturePosition;
473
474 LPVOID aptr1, aptr2;
475 DWORD nbytes1, nbytes2;
476
477 HRESULT hr;
478 WAVEFORMATEX wfx;
479 DSCBUFFERDESC dscbd;
480
481 pDSCapture = NULL;
482 pDSCaptureBuffer = NULL;
483 pDSNotify = NULL;
484
485 bOk = false;
486
487 bool failed = false;
488
489 Timer t;
490
491 ZeroMemory(&wfx, sizeof(wfx));
492 wfx.wFormatTag = WAVE_FORMAT_PCM;
493
494 ZeroMemory(&dscbd, sizeof(dscbd));
495 dscbd.dwSize = sizeof(dscbd);
496
497 dscbd.dwBufferBytes = dwBufferSize = iFrameSize * sizeof(short) * NBUFFBLOCKS;
498 dscbd.lpwfxFormat = &wfx;
499
500 wfx.nChannels = 1;
501 wfx.nSamplesPerSec = iSampleRate;
502 wfx.nBlockAlign = 2;
503 wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
504 wfx.wBitsPerSample = 16;
505
506 // Create IDirectSoundCapture using the preferred capture device
507 if (! g.s.qbaDXInput.isEmpty()) {
508 LPGUID lpguid = reinterpret_cast<LPGUID>(g.s.qbaDXInput.data());
509 if (FAILED(hr = DirectSoundCaptureCreate8(lpguid, &pDSCapture, NULL))) {
510 failed = true;
511 }
512 }
513
514 if (! pDSCapture && FAILED(hr = DirectSoundCaptureCreate8(&DSDEVID_DefaultVoiceCapture, &pDSCapture, NULL)))
515 qWarning("DXAudioInput: DirectSoundCaptureCreate failed: hr=0x%08lx", hr);
516 else if (FAILED(hr = pDSCapture->CreateCaptureBuffer(&dscbd, &pDSCaptureBuffer, NULL)))
517 qWarning("DXAudioInput: CreateCaptureBuffer failed: hr=0x%08lx", hr);
518 else if (FAILED(hr = pDSCaptureBuffer->QueryInterface(IID_IDirectSoundNotify, reinterpret_cast<void **>(&pDSNotify))))
519 qWarning("DXAudioInput: QueryInterface (Notify) failed: hr=0x%08lx", hr);
520 else
521 bOk = true;
522
523
524
525 if (failed)
526 g.mw->msgBox(tr("Opening chosen DirectSound Input failed. Default device will be used."));
527
528 qWarning("DXAudioInput: Initialized");
529
530 if (! bOk)
531 goto cleanup;
532
533 if (FAILED(hr = pDSCaptureBuffer->Start(DSCBSTART_LOOPING))) {
534 qWarning("DXAudioInput: Start failed: hr=0x%08lx", hr);
535 } else {
536 DWORD dwReadyBytes = 0;
537 DWORD dwLastReadPos = 0;
538 float safety = 2.0f;
539
540 while (bRunning) {
541 bool firstsleep = true;
542 bool didsleep = false;
543
544 do {
545 if (FAILED(hr = pDSCaptureBuffer->GetCurrentPosition(&dwCapturePosition, &dwReadPosition))) {
546 qWarning("DXAudioInput: GetCurrentPosition failed: hr=0x%08lx", hr);
547 bRunning = false;
548 break;
549 }
550 if (dwReadPosition < dwLastReadPos)
551 dwReadyBytes = (dwBufferSize - dwLastReadPos) + dwReadPosition;
552 else
553 dwReadyBytes = dwReadPosition - dwLastReadPos;
554
555 if (static_cast<size_t>(dwReadyBytes) < sizeof(short) * iFrameSize) {
556 double msecleft = 20.0 - (dwReadyBytes * 20.0) / (sizeof(short) * iFrameSize);
557
558 if (didsleep)
559 safety *= 1.1f;
560 else if (firstsleep)
561 safety *= 0.998f;
562
563 int msec = static_cast<int>(msecleft + (firstsleep ? safety : 0.0));
564
565 msleep(msec);
566
567 didsleep = true;
568 firstsleep = false;
569 }
570 } while (static_cast<size_t>(dwReadyBytes) < sizeof(short) * iFrameSize);
571
572 // Desynchonized?
573 if (dwReadyBytes > (dwBufferSize / 2)) {
574 qWarning("DXAudioInput: Lost synchronization");
575 dwLastReadPos = dwReadPosition;
576 } else if (bRunning) {
577 if (FAILED(hr = pDSCaptureBuffer->Lock(dwLastReadPos, sizeof(short) * iFrameSize, &aptr1, &nbytes1, &aptr2, &nbytes2, 0))) {
578 qWarning("DXAudioInput: Lock from %lu (%zu bytes) failed: hr=0x%08lx", static_cast<unsigned long>(dwLastReadPos), sizeof(short) * iFrameSize, hr);
579 bRunning = false;
580 break;
581 }
582
583 if (aptr1 && nbytes1)
584 CopyMemory(psMic, aptr1, nbytes1);
585
586 if (aptr2 && nbytes2)
587 CopyMemory(psMic+nbytes1/2, aptr2, nbytes2);
588
589 if (FAILED(hr = pDSCaptureBuffer->Unlock(aptr1, nbytes1, aptr2, nbytes2))) {
590 qWarning("DXAudioInput: Unlock failed: hr=0x%08lx", hr);
591 bRunning = false;
592 break;
593 }
594
595 dwLastReadPos = (dwLastReadPos + sizeof(short) * iFrameSize) % dwBufferSize;
596
597 encodeAudioFrame();
598 }
599 }
600 if (! FAILED(hr))
601 pDSCaptureBuffer->Stop();
602 }
603 if (FAILED(hr)) {
604 g.mw->msgBox(tr("Lost DirectSound input device."));
605 }
606
607 cleanup:
608 if (! bOk) {
609 g.mw->msgBox(tr("Opening chosen DirectSound Input device failed. No microphone capture will be done."));
610 }
611 if (pDSNotify)
612 pDSNotify->Release();
613 if (pDSCaptureBuffer)
614 pDSCaptureBuffer->Release();
615 if (pDSCapture)
616 pDSCapture->Release();
617 }
618