Use a macro for the record thread name
[openal-soft.git] / Alc / backends / winmm.c
blob03805ab818d70d5534615f66826b8e76ef4cf2f9
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include "config.h"
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <memory.h>
27 #include <windows.h>
28 #include <mmsystem.h>
30 #include "alMain.h"
31 #include "alu.h"
32 #include "threads.h"
34 #include "backends/base.h"
36 #ifndef WAVE_FORMAT_IEEE_FLOAT
37 #define WAVE_FORMAT_IEEE_FLOAT 0x0003
38 #endif
41 TYPEDEF_VECTOR(al_string, vector_al_string)
42 static vector_al_string PlaybackDevices;
43 static vector_al_string CaptureDevices;
45 static void clear_devlist(vector_al_string *list)
47 VECTOR_FOR_EACH(al_string, *list, al_string_deinit);
48 VECTOR_RESIZE(*list, 0);
52 static void ProbePlaybackDevices(void)
54 al_string *iter, *end;
55 ALuint numdevs;
56 ALuint i;
58 clear_devlist(&PlaybackDevices);
60 numdevs = waveOutGetNumDevs();
61 VECTOR_RESERVE(PlaybackDevices, numdevs);
62 for(i = 0;i < numdevs;i++)
64 WAVEOUTCAPSW WaveCaps;
65 al_string dname;
67 AL_STRING_INIT(dname);
68 if(waveOutGetDevCapsW(i, &WaveCaps, sizeof(WaveCaps)) == MMSYSERR_NOERROR)
70 ALuint count = 0;
71 do {
72 al_string_copy_wcstr(&dname, WaveCaps.szPname);
73 if(count != 0)
75 char str[64];
76 snprintf(str, sizeof(str), " #%d", count+1);
77 al_string_append_cstr(&dname, str);
79 count++;
81 iter = VECTOR_ITER_BEGIN(PlaybackDevices);
82 end = VECTOR_ITER_END(PlaybackDevices);
83 for(;iter != end;iter++)
85 if(al_string_cmp(*iter, dname) == 0)
86 break;
88 } while(iter != end);
90 TRACE("Got device \"%s\", ID %u\n", al_string_get_cstr(dname), i);
92 VECTOR_PUSH_BACK(PlaybackDevices, dname);
96 static void ProbeCaptureDevices(void)
98 al_string *iter, *end;
99 ALuint numdevs;
100 ALuint i;
102 clear_devlist(&CaptureDevices);
104 numdevs = waveInGetNumDevs();
105 VECTOR_RESERVE(CaptureDevices, numdevs);
106 for(i = 0;i < numdevs;i++)
108 WAVEINCAPSW WaveCaps;
109 al_string dname;
111 AL_STRING_INIT(dname);
112 if(waveInGetDevCapsW(i, &WaveCaps, sizeof(WaveCaps)) == MMSYSERR_NOERROR)
114 ALuint count = 0;
115 do {
116 al_string_copy_wcstr(&dname, WaveCaps.szPname);
117 if(count != 0)
119 char str[64];
120 snprintf(str, sizeof(str), " #%d", count+1);
121 al_string_append_cstr(&dname, str);
123 count++;
125 iter = VECTOR_ITER_BEGIN(CaptureDevices);
126 end = VECTOR_ITER_END(CaptureDevices);
127 for(;iter != end;iter++)
129 if(al_string_cmp(*iter, dname) == 0)
130 break;
132 } while(iter != end);
134 TRACE("Got device \"%s\", ID %u\n", al_string_get_cstr(dname), i);
136 VECTOR_PUSH_BACK(CaptureDevices, dname);
141 typedef struct ALCwinmmPlayback {
142 DERIVE_FROM_TYPE(ALCbackend);
144 RefCount WaveBuffersCommitted;
145 WAVEHDR WaveBuffer[4];
147 HWAVEOUT OutHdl;
149 WAVEFORMATEX Format;
151 volatile ALboolean killNow;
152 althrd_t thread;
153 } ALCwinmmPlayback;
155 static void ALCwinmmPlayback_Construct(ALCwinmmPlayback *self, ALCdevice *device);
156 static void ALCwinmmPlayback_Destruct(ALCwinmmPlayback *self);
158 static void CALLBACK ALCwinmmPlayback_waveOutProc(HWAVEOUT device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2);
159 static int ALCwinmmPlayback_mixerProc(void *arg);
161 static ALCenum ALCwinmmPlayback_open(ALCwinmmPlayback *self, const ALCchar *name);
162 static void ALCwinmmPlayback_close(ALCwinmmPlayback *self);
163 static ALCboolean ALCwinmmPlayback_reset(ALCwinmmPlayback *self);
164 static ALCboolean ALCwinmmPlayback_start(ALCwinmmPlayback *self);
165 static void ALCwinmmPlayback_stop(ALCwinmmPlayback *self);
166 static DECLARE_FORWARD2(ALCwinmmPlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint)
167 static DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, ALCuint, availableSamples)
168 static DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, ALint64, getLatency)
169 static DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, void, lock)
170 static DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, void, unlock)
171 DECLARE_DEFAULT_ALLOCATORS(ALCwinmmPlayback)
173 DEFINE_ALCBACKEND_VTABLE(ALCwinmmPlayback);
176 static void ALCwinmmPlayback_Construct(ALCwinmmPlayback *self, ALCdevice *device)
178 ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
179 SET_VTABLE2(ALCwinmmPlayback, ALCbackend, self);
181 InitRef(&self->WaveBuffersCommitted, 0);
182 self->OutHdl = NULL;
184 self->killNow = AL_TRUE;
187 static void ALCwinmmPlayback_Destruct(ALCwinmmPlayback *self)
189 if(self->OutHdl)
190 waveOutClose(self->OutHdl);
191 self->OutHdl = 0;
193 ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
197 /* ALCwinmmPlayback_waveOutProc
199 * Posts a message to 'ALCwinmmPlayback_mixerProc' everytime a WaveOut Buffer
200 * is completed and returns to the application (for more data)
202 static void CALLBACK ALCwinmmPlayback_waveOutProc(HWAVEOUT UNUSED(device), UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR UNUSED(param2))
204 ALCwinmmPlayback *self = (ALCwinmmPlayback*)instance;
206 if(msg != WOM_DONE)
207 return;
209 DecrementRef(&self->WaveBuffersCommitted);
210 PostThreadMessage(self->thread, msg, 0, param1);
213 FORCE_ALIGN static int ALCwinmmPlayback_mixerProc(void *arg)
215 ALCwinmmPlayback *self = arg;
216 ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
217 WAVEHDR *WaveHdr;
218 MSG msg;
220 SetRTPriority();
221 althrd_setname(althrd_current(), MIXER_THREAD_NAME);
223 while(GetMessage(&msg, NULL, 0, 0))
225 if(msg.message != WOM_DONE)
226 continue;
228 if(self->killNow)
230 if(ReadRef(&self->WaveBuffersCommitted) == 0)
231 break;
232 continue;
235 WaveHdr = ((WAVEHDR*)msg.lParam);
236 aluMixData(device, WaveHdr->lpData, WaveHdr->dwBufferLength /
237 self->Format.nBlockAlign);
239 // Send buffer back to play more data
240 waveOutWrite(self->OutHdl, WaveHdr, sizeof(WAVEHDR));
241 IncrementRef(&self->WaveBuffersCommitted);
244 return 0;
248 static ALCenum ALCwinmmPlayback_open(ALCwinmmPlayback *self, const ALCchar *deviceName)
250 ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
251 const al_string *iter;
252 UINT DeviceID;
253 MMRESULT res;
255 if(VECTOR_SIZE(PlaybackDevices) == 0)
256 ProbePlaybackDevices();
258 // Find the Device ID matching the deviceName if valid
259 #define MATCH_DEVNAME(iter) (!al_string_empty(*(iter)) && \
260 (!deviceName || al_string_cmp_cstr(*(iter), deviceName) == 0))
261 VECTOR_FIND_IF(iter, const al_string, PlaybackDevices, MATCH_DEVNAME);
262 if(iter == VECTOR_ITER_END(PlaybackDevices))
263 return ALC_INVALID_VALUE;
264 #undef MATCH_DEVNAME
266 DeviceID = (UINT)(iter - VECTOR_ITER_BEGIN(PlaybackDevices));
268 retry_open:
269 memset(&self->Format, 0, sizeof(WAVEFORMATEX));
270 if(device->FmtType == DevFmtFloat)
272 self->Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
273 self->Format.wBitsPerSample = 32;
275 else
277 self->Format.wFormatTag = WAVE_FORMAT_PCM;
278 if(device->FmtType == DevFmtUByte || device->FmtType == DevFmtByte)
279 self->Format.wBitsPerSample = 8;
280 else
281 self->Format.wBitsPerSample = 16;
283 self->Format.nChannels = ((device->FmtChans == DevFmtMono) ? 1 : 2);
284 self->Format.nBlockAlign = self->Format.wBitsPerSample *
285 self->Format.nChannels / 8;
286 self->Format.nSamplesPerSec = device->Frequency;
287 self->Format.nAvgBytesPerSec = self->Format.nSamplesPerSec *
288 self->Format.nBlockAlign;
289 self->Format.cbSize = 0;
291 if((res=waveOutOpen(&self->OutHdl, DeviceID, &self->Format, (DWORD_PTR)&ALCwinmmPlayback_waveOutProc, (DWORD_PTR)self, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR)
293 if(device->FmtType == DevFmtFloat)
295 device->FmtType = DevFmtShort;
296 goto retry_open;
298 ERR("waveOutOpen failed: %u\n", res);
299 goto failure;
302 al_string_copy(&device->DeviceName, VECTOR_ELEM(PlaybackDevices, DeviceID));
303 return ALC_NO_ERROR;
305 failure:
306 if(self->OutHdl)
307 waveOutClose(self->OutHdl);
308 self->OutHdl = NULL;
310 return ALC_INVALID_VALUE;
313 static void ALCwinmmPlayback_close(ALCwinmmPlayback* UNUSED(self))
316 static ALCboolean ALCwinmmPlayback_reset(ALCwinmmPlayback *self)
318 ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
320 device->UpdateSize = (ALuint)((ALuint64)device->UpdateSize *
321 self->Format.nSamplesPerSec /
322 device->Frequency);
323 device->UpdateSize = (device->UpdateSize*device->NumUpdates + 3) / 4;
324 device->NumUpdates = 4;
325 device->Frequency = self->Format.nSamplesPerSec;
327 if(self->Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
329 if(self->Format.wBitsPerSample == 32)
330 device->FmtType = DevFmtFloat;
331 else
333 ERR("Unhandled IEEE float sample depth: %d\n", self->Format.wBitsPerSample);
334 return ALC_FALSE;
337 else if(self->Format.wFormatTag == WAVE_FORMAT_PCM)
339 if(self->Format.wBitsPerSample == 16)
340 device->FmtType = DevFmtShort;
341 else if(self->Format.wBitsPerSample == 8)
342 device->FmtType = DevFmtUByte;
343 else
345 ERR("Unhandled PCM sample depth: %d\n", self->Format.wBitsPerSample);
346 return ALC_FALSE;
349 else
351 ERR("Unhandled format tag: 0x%04x\n", self->Format.wFormatTag);
352 return ALC_FALSE;
355 if(self->Format.nChannels == 2)
356 device->FmtChans = DevFmtStereo;
357 else if(self->Format.nChannels == 1)
358 device->FmtChans = DevFmtMono;
359 else
361 ERR("Unhandled channel count: %d\n", self->Format.nChannels);
362 return ALC_FALSE;
364 SetDefaultWFXChannelOrder(device);
366 return ALC_TRUE;
369 static ALCboolean ALCwinmmPlayback_start(ALCwinmmPlayback *self)
371 ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
372 ALbyte *BufferData;
373 ALint BufferSize;
374 ALuint i;
376 self->killNow = AL_FALSE;
377 if(althrd_create(&self->thread, ALCwinmmPlayback_mixerProc, self) != althrd_success)
378 return ALC_FALSE;
380 InitRef(&self->WaveBuffersCommitted, 0);
382 // Create 4 Buffers
383 BufferSize = device->UpdateSize*device->NumUpdates / 4;
384 BufferSize *= FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
386 BufferData = calloc(4, BufferSize);
387 for(i = 0;i < 4;i++)
389 memset(&self->WaveBuffer[i], 0, sizeof(WAVEHDR));
390 self->WaveBuffer[i].dwBufferLength = BufferSize;
391 self->WaveBuffer[i].lpData = ((i==0) ? (CHAR*)BufferData :
392 (self->WaveBuffer[i-1].lpData +
393 self->WaveBuffer[i-1].dwBufferLength));
394 waveOutPrepareHeader(self->OutHdl, &self->WaveBuffer[i], sizeof(WAVEHDR));
395 waveOutWrite(self->OutHdl, &self->WaveBuffer[i], sizeof(WAVEHDR));
396 IncrementRef(&self->WaveBuffersCommitted);
399 return ALC_TRUE;
402 static void ALCwinmmPlayback_stop(ALCwinmmPlayback *self)
404 void *buffer = NULL;
405 int i;
407 if(self->killNow)
408 return;
410 // Set flag to stop processing headers
411 self->killNow = AL_TRUE;
412 althrd_join(self->thread, &i);
414 // Release the wave buffers
415 for(i = 0;i < 4;i++)
417 waveOutUnprepareHeader(self->OutHdl, &self->WaveBuffer[i], sizeof(WAVEHDR));
418 if(i == 0) buffer = self->WaveBuffer[i].lpData;
419 self->WaveBuffer[i].lpData = NULL;
421 free(buffer);
426 typedef struct ALCwinmmCapture {
427 DERIVE_FROM_TYPE(ALCbackend);
429 RefCount WaveBuffersCommitted;
430 WAVEHDR WaveBuffer[4];
432 HWAVEIN InHdl;
434 RingBuffer *Ring;
436 WAVEFORMATEX Format;
438 volatile ALboolean killNow;
439 althrd_t thread;
440 } ALCwinmmCapture;
442 static void ALCwinmmCapture_Construct(ALCwinmmCapture *self, ALCdevice *device);
443 static void ALCwinmmCapture_Destruct(ALCwinmmCapture *self);
445 static void CALLBACK ALCwinmmCapture_waveInProc(HWAVEIN device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2);
446 static int ALCwinmmCapture_captureProc(void *arg);
448 static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *name);
449 static void ALCwinmmCapture_close(ALCwinmmCapture *self);
450 static DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, ALCboolean, reset)
451 static ALCboolean ALCwinmmCapture_start(ALCwinmmCapture *self);
452 static void ALCwinmmCapture_stop(ALCwinmmCapture *self);
453 static ALCenum ALCwinmmCapture_captureSamples(ALCwinmmCapture *self, ALCvoid *buffer, ALCuint samples);
454 static ALCuint ALCwinmmCapture_availableSamples(ALCwinmmCapture *self);
455 static DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, ALint64, getLatency)
456 static DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, void, lock)
457 static DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, void, unlock)
458 DECLARE_DEFAULT_ALLOCATORS(ALCwinmmCapture)
460 DEFINE_ALCBACKEND_VTABLE(ALCwinmmCapture);
463 static void ALCwinmmCapture_Construct(ALCwinmmCapture *self, ALCdevice *device)
465 ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
466 SET_VTABLE2(ALCwinmmCapture, ALCbackend, self);
468 InitRef(&self->WaveBuffersCommitted, 0);
469 self->InHdl = NULL;
471 self->killNow = AL_TRUE;
474 static void ALCwinmmCapture_Destruct(ALCwinmmCapture *self)
476 if(self->InHdl)
477 waveInClose(self->InHdl);
478 self->InHdl = 0;
480 ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
484 /* ALCwinmmCapture_waveInProc
486 * Posts a message to 'ALCwinmmCapture_captureProc' everytime a WaveIn Buffer
487 * is completed and returns to the application (with more data).
489 static void CALLBACK ALCwinmmCapture_waveInProc(HWAVEIN UNUSED(device), UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR UNUSED(param2))
491 ALCwinmmCapture *self = (ALCwinmmCapture*)instance;
493 if(msg != WIM_DATA)
494 return;
496 DecrementRef(&self->WaveBuffersCommitted);
497 PostThreadMessage(self->thread, msg, 0, param1);
500 static int ALCwinmmCapture_captureProc(void *arg)
502 ALCwinmmCapture *self = arg;
503 WAVEHDR *WaveHdr;
504 MSG msg;
506 althrd_setname(althrd_current(), RECORD_THREAD_NAME);
508 while(GetMessage(&msg, NULL, 0, 0))
510 if(msg.message != WIM_DATA)
511 continue;
512 /* Don't wait for other buffers to finish before quitting. We're
513 * closing so we don't need them. */
514 if(self->killNow)
515 break;
517 WaveHdr = ((WAVEHDR*)msg.lParam);
518 WriteRingBuffer(self->Ring, (ALubyte*)WaveHdr->lpData,
519 WaveHdr->dwBytesRecorded/self->Format.nBlockAlign);
521 // Send buffer back to capture more data
522 waveInAddBuffer(self->InHdl, WaveHdr, sizeof(WAVEHDR));
523 IncrementRef(&self->WaveBuffersCommitted);
526 return 0;
530 static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *name)
532 ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
533 const al_string *iter;
534 ALbyte *BufferData = NULL;
535 DWORD CapturedDataSize;
536 ALint BufferSize;
537 UINT DeviceID;
538 MMRESULT res;
539 ALuint i;
541 if(VECTOR_SIZE(CaptureDevices) == 0)
542 ProbeCaptureDevices();
544 // Find the Device ID matching the deviceName if valid
545 #define MATCH_DEVNAME(iter) (!al_string_empty(*(iter)) && (!name || al_string_cmp_cstr(*iter, name) == 0))
546 VECTOR_FIND_IF(iter, const al_string, CaptureDevices, MATCH_DEVNAME);
547 if(iter == VECTOR_ITER_END(CaptureDevices))
548 return ALC_INVALID_VALUE;
549 #undef MATCH_DEVNAME
551 DeviceID = (UINT)(iter - VECTOR_ITER_BEGIN(CaptureDevices));
553 switch(device->FmtChans)
555 case DevFmtMono:
556 case DevFmtStereo:
557 break;
559 case DevFmtQuad:
560 case DevFmtX51:
561 case DevFmtX51Rear:
562 case DevFmtX61:
563 case DevFmtX71:
564 case DevFmtBFormat3D:
565 return ALC_INVALID_ENUM;
568 switch(device->FmtType)
570 case DevFmtUByte:
571 case DevFmtShort:
572 case DevFmtInt:
573 case DevFmtFloat:
574 break;
576 case DevFmtByte:
577 case DevFmtUShort:
578 case DevFmtUInt:
579 return ALC_INVALID_ENUM;
582 memset(&self->Format, 0, sizeof(WAVEFORMATEX));
583 self->Format.wFormatTag = ((device->FmtType == DevFmtFloat) ?
584 WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM);
585 self->Format.nChannels = ChannelsFromDevFmt(device->FmtChans);
586 self->Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8;
587 self->Format.nBlockAlign = self->Format.wBitsPerSample *
588 self->Format.nChannels / 8;
589 self->Format.nSamplesPerSec = device->Frequency;
590 self->Format.nAvgBytesPerSec = self->Format.nSamplesPerSec *
591 self->Format.nBlockAlign;
592 self->Format.cbSize = 0;
594 if((res=waveInOpen(&self->InHdl, DeviceID, &self->Format, (DWORD_PTR)&ALCwinmmCapture_waveInProc, (DWORD_PTR)self, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR)
596 ERR("waveInOpen failed: %u\n", res);
597 goto failure;
600 // Allocate circular memory buffer for the captured audio
601 CapturedDataSize = device->UpdateSize*device->NumUpdates;
603 // Make sure circular buffer is at least 100ms in size
604 if(CapturedDataSize < (self->Format.nSamplesPerSec / 10))
605 CapturedDataSize = self->Format.nSamplesPerSec / 10;
607 self->Ring = CreateRingBuffer(self->Format.nBlockAlign, CapturedDataSize);
608 if(!self->Ring) goto failure;
610 InitRef(&self->WaveBuffersCommitted, 0);
612 // Create 4 Buffers of 50ms each
613 BufferSize = self->Format.nAvgBytesPerSec / 20;
614 BufferSize -= (BufferSize % self->Format.nBlockAlign);
616 BufferData = calloc(4, BufferSize);
617 if(!BufferData) goto failure;
619 for(i = 0;i < 4;i++)
621 memset(&self->WaveBuffer[i], 0, sizeof(WAVEHDR));
622 self->WaveBuffer[i].dwBufferLength = BufferSize;
623 self->WaveBuffer[i].lpData = ((i==0) ? (CHAR*)BufferData :
624 (self->WaveBuffer[i-1].lpData +
625 self->WaveBuffer[i-1].dwBufferLength));
626 self->WaveBuffer[i].dwFlags = 0;
627 self->WaveBuffer[i].dwLoops = 0;
628 waveInPrepareHeader(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR));
629 waveInAddBuffer(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR));
630 IncrementRef(&self->WaveBuffersCommitted);
633 self->killNow = AL_FALSE;
634 if(althrd_create(&self->thread, ALCwinmmCapture_captureProc, self) != althrd_success)
635 goto failure;
637 al_string_copy(&device->DeviceName, VECTOR_ELEM(CaptureDevices, DeviceID));
638 return ALC_NO_ERROR;
640 failure:
641 if(BufferData)
643 for(i = 0;i < 4;i++)
644 waveInUnprepareHeader(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR));
645 free(BufferData);
648 if(self->Ring)
649 DestroyRingBuffer(self->Ring);
650 self->Ring = NULL;
652 if(self->InHdl)
653 waveInClose(self->InHdl);
654 self->InHdl = NULL;
656 return ALC_INVALID_VALUE;
659 static void ALCwinmmCapture_close(ALCwinmmCapture *self)
661 void *buffer = NULL;
662 int i;
664 /* Tell the processing thread to quit and wait for it to do so. */
665 self->killNow = AL_TRUE;
666 PostThreadMessage(self->thread, WM_QUIT, 0, 0);
668 althrd_join(self->thread, &i);
670 /* Make sure capture is stopped and all pending buffers are flushed. */
671 waveInReset(self->InHdl);
673 // Release the wave buffers
674 for(i = 0;i < 4;i++)
676 waveInUnprepareHeader(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR));
677 if(i == 0) buffer = self->WaveBuffer[i].lpData;
678 self->WaveBuffer[i].lpData = NULL;
680 free(buffer);
682 DestroyRingBuffer(self->Ring);
683 self->Ring = NULL;
685 // Close the Wave device
686 waveInClose(self->InHdl);
687 self->InHdl = NULL;
690 static ALCboolean ALCwinmmCapture_start(ALCwinmmCapture *self)
692 waveInStart(self->InHdl);
693 return ALC_TRUE;
696 static void ALCwinmmCapture_stop(ALCwinmmCapture *self)
698 waveInStop(self->InHdl);
701 static ALCenum ALCwinmmCapture_captureSamples(ALCwinmmCapture *self, ALCvoid *buffer, ALCuint samples)
703 ReadRingBuffer(self->Ring, buffer, samples);
704 return ALC_NO_ERROR;
707 static ALCuint ALCwinmmCapture_availableSamples(ALCwinmmCapture *self)
709 return RingBufferSize(self->Ring);
713 static inline void AppendAllDevicesList2(const al_string *name)
715 if(!al_string_empty(*name))
716 AppendAllDevicesList(al_string_get_cstr(*name));
718 static inline void AppendCaptureDeviceList2(const al_string *name)
720 if(!al_string_empty(*name))
721 AppendCaptureDeviceList(al_string_get_cstr(*name));
724 typedef struct ALCwinmmBackendFactory {
725 DERIVE_FROM_TYPE(ALCbackendFactory);
726 } ALCwinmmBackendFactory;
727 #define ALCWINMMBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCwinmmBackendFactory, ALCbackendFactory) } }
729 static ALCboolean ALCwinmmBackendFactory_init(ALCwinmmBackendFactory *self);
730 static void ALCwinmmBackendFactory_deinit(ALCwinmmBackendFactory *self);
731 static ALCboolean ALCwinmmBackendFactory_querySupport(ALCwinmmBackendFactory *self, ALCbackend_Type type);
732 static void ALCwinmmBackendFactory_probe(ALCwinmmBackendFactory *self, enum DevProbe type);
733 static ALCbackend* ALCwinmmBackendFactory_createBackend(ALCwinmmBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
735 DEFINE_ALCBACKENDFACTORY_VTABLE(ALCwinmmBackendFactory);
738 static ALCboolean ALCwinmmBackendFactory_init(ALCwinmmBackendFactory* UNUSED(self))
740 VECTOR_INIT(PlaybackDevices);
741 VECTOR_INIT(CaptureDevices);
743 return ALC_TRUE;
746 static void ALCwinmmBackendFactory_deinit(ALCwinmmBackendFactory* UNUSED(self))
748 clear_devlist(&PlaybackDevices);
749 VECTOR_DEINIT(PlaybackDevices);
751 clear_devlist(&CaptureDevices);
752 VECTOR_DEINIT(CaptureDevices);
755 static ALCboolean ALCwinmmBackendFactory_querySupport(ALCwinmmBackendFactory* UNUSED(self), ALCbackend_Type type)
757 if(type == ALCbackend_Playback || type == ALCbackend_Capture)
758 return ALC_TRUE;
759 return ALC_FALSE;
762 static void ALCwinmmBackendFactory_probe(ALCwinmmBackendFactory* UNUSED(self), enum DevProbe type)
764 switch(type)
766 case ALL_DEVICE_PROBE:
767 ProbePlaybackDevices();
768 VECTOR_FOR_EACH(const al_string, PlaybackDevices, AppendAllDevicesList2);
769 break;
771 case CAPTURE_DEVICE_PROBE:
772 ProbeCaptureDevices();
773 VECTOR_FOR_EACH(const al_string, CaptureDevices, AppendCaptureDeviceList2);
774 break;
778 static ALCbackend* ALCwinmmBackendFactory_createBackend(ALCwinmmBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
780 if(type == ALCbackend_Playback)
782 ALCwinmmPlayback *backend;
784 backend = ALCwinmmPlayback_New(sizeof(*backend));
785 if(!backend) return NULL;
786 memset(backend, 0, sizeof(*backend));
788 ALCwinmmPlayback_Construct(backend, device);
790 return STATIC_CAST(ALCbackend, backend);
792 if(type == ALCbackend_Capture)
794 ALCwinmmCapture *backend;
796 backend = ALCwinmmCapture_New(sizeof(*backend));
797 if(!backend) return NULL;
798 memset(backend, 0, sizeof(*backend));
800 ALCwinmmCapture_Construct(backend, device);
802 return STATIC_CAST(ALCbackend, backend);
805 return NULL;
808 ALCbackendFactory *ALCwinmmBackendFactory_getFactory(void)
810 static ALCwinmmBackendFactory factory = ALCWINMMBACKENDFACTORY_INITIALIZER;
811 return STATIC_CAST(ALCbackendFactory, &factory);