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
34 #include "backends/base.h"
36 #ifndef WAVE_FORMAT_IEEE_FLOAT
37 #define WAVE_FORMAT_IEEE_FLOAT 0x0003
40 #define DEVNAME_HEAD "OpenAL Soft on "
43 static vector_al_string PlaybackDevices
;
44 static vector_al_string CaptureDevices
;
46 static void clear_devlist(vector_al_string
*list
)
48 VECTOR_FOR_EACH(al_string
, *list
, al_string_deinit
);
49 VECTOR_RESIZE(*list
, 0);
53 static void ProbePlaybackDevices(void)
58 clear_devlist(&PlaybackDevices
);
60 numdevs
= waveOutGetNumDevs();
61 VECTOR_RESERVE(PlaybackDevices
, numdevs
);
62 for(i
= 0;i
< numdevs
;i
++)
64 WAVEOUTCAPSW WaveCaps
;
65 const al_string
*iter
;
68 AL_STRING_INIT(dname
);
69 if(waveOutGetDevCapsW(i
, &WaveCaps
, sizeof(WaveCaps
)) == MMSYSERR_NOERROR
)
74 al_string_copy_cstr(&dname
, DEVNAME_HEAD
);
75 al_string_append_wcstr(&dname
, WaveCaps
.szPname
);
79 snprintf(str
, sizeof(str
), " #%d", count
+1);
80 al_string_append_cstr(&dname
, str
);
84 #define MATCH_ENTRY(i) (al_string_cmp(dname, *(i)) == 0)
85 VECTOR_FIND_IF(iter
, const al_string
, PlaybackDevices
, MATCH_ENTRY
);
86 if(iter
== VECTOR_END(PlaybackDevices
)) break;
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)
101 clear_devlist(&CaptureDevices
);
103 numdevs
= waveInGetNumDevs();
104 VECTOR_RESERVE(CaptureDevices
, numdevs
);
105 for(i
= 0;i
< numdevs
;i
++)
107 WAVEINCAPSW WaveCaps
;
108 const al_string
*iter
;
111 AL_STRING_INIT(dname
);
112 if(waveInGetDevCapsW(i
, &WaveCaps
, sizeof(WaveCaps
)) == MMSYSERR_NOERROR
)
117 al_string_copy_cstr(&dname
, DEVNAME_HEAD
);
118 al_string_append_wcstr(&dname
, WaveCaps
.szPname
);
122 snprintf(str
, sizeof(str
), " #%d", count
+1);
123 al_string_append_cstr(&dname
, str
);
127 #define MATCH_ENTRY(i) (al_string_cmp(dname, *(i)) == 0)
128 VECTOR_FIND_IF(iter
, const al_string
, CaptureDevices
, MATCH_ENTRY
);
129 if(iter
== VECTOR_END(CaptureDevices
)) break;
133 TRACE("Got device \"%s\", ID %u\n", al_string_get_cstr(dname
), i
);
135 VECTOR_PUSH_BACK(CaptureDevices
, dname
);
140 typedef struct ALCwinmmPlayback
{
141 DERIVE_FROM_TYPE(ALCbackend
);
143 RefCount WaveBuffersCommitted
;
144 WAVEHDR WaveBuffer
[4];
150 volatile ALboolean killNow
;
154 static void ALCwinmmPlayback_Construct(ALCwinmmPlayback
*self
, ALCdevice
*device
);
155 static void ALCwinmmPlayback_Destruct(ALCwinmmPlayback
*self
);
157 static void CALLBACK
ALCwinmmPlayback_waveOutProc(HWAVEOUT device
, UINT msg
, DWORD_PTR instance
, DWORD_PTR param1
, DWORD_PTR param2
);
158 static int ALCwinmmPlayback_mixerProc(void *arg
);
160 static ALCenum
ALCwinmmPlayback_open(ALCwinmmPlayback
*self
, const ALCchar
*name
);
161 static void ALCwinmmPlayback_close(ALCwinmmPlayback
*self
);
162 static ALCboolean
ALCwinmmPlayback_reset(ALCwinmmPlayback
*self
);
163 static ALCboolean
ALCwinmmPlayback_start(ALCwinmmPlayback
*self
);
164 static void ALCwinmmPlayback_stop(ALCwinmmPlayback
*self
);
165 static DECLARE_FORWARD2(ALCwinmmPlayback
, ALCbackend
, ALCenum
, captureSamples
, ALCvoid
*, ALCuint
)
166 static DECLARE_FORWARD(ALCwinmmPlayback
, ALCbackend
, ALCuint
, availableSamples
)
167 static DECLARE_FORWARD(ALCwinmmPlayback
, ALCbackend
, ClockLatency
, getClockLatency
)
168 static DECLARE_FORWARD(ALCwinmmPlayback
, ALCbackend
, void, lock
)
169 static DECLARE_FORWARD(ALCwinmmPlayback
, ALCbackend
, void, unlock
)
170 DECLARE_DEFAULT_ALLOCATORS(ALCwinmmPlayback
)
172 DEFINE_ALCBACKEND_VTABLE(ALCwinmmPlayback
);
175 static void ALCwinmmPlayback_Construct(ALCwinmmPlayback
*self
, ALCdevice
*device
)
177 ALCbackend_Construct(STATIC_CAST(ALCbackend
, self
), device
);
178 SET_VTABLE2(ALCwinmmPlayback
, ALCbackend
, self
);
180 InitRef(&self
->WaveBuffersCommitted
, 0);
183 self
->killNow
= AL_TRUE
;
186 static void ALCwinmmPlayback_Destruct(ALCwinmmPlayback
*self
)
189 waveOutClose(self
->OutHdl
);
192 ALCbackend_Destruct(STATIC_CAST(ALCbackend
, self
));
196 /* ALCwinmmPlayback_waveOutProc
198 * Posts a message to 'ALCwinmmPlayback_mixerProc' everytime a WaveOut Buffer
199 * is completed and returns to the application (for more data)
201 static void CALLBACK
ALCwinmmPlayback_waveOutProc(HWAVEOUT
UNUSED(device
), UINT msg
, DWORD_PTR instance
, DWORD_PTR param1
, DWORD_PTR
UNUSED(param2
))
203 ALCwinmmPlayback
*self
= (ALCwinmmPlayback
*)instance
;
208 DecrementRef(&self
->WaveBuffersCommitted
);
209 PostThreadMessage(self
->thread
, msg
, 0, param1
);
212 FORCE_ALIGN
static int ALCwinmmPlayback_mixerProc(void *arg
)
214 ALCwinmmPlayback
*self
= arg
;
215 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
220 althrd_setname(althrd_current(), MIXER_THREAD_NAME
);
222 while(GetMessage(&msg
, NULL
, 0, 0))
224 if(msg
.message
!= WOM_DONE
)
229 if(ReadRef(&self
->WaveBuffersCommitted
) == 0)
234 WaveHdr
= ((WAVEHDR
*)msg
.lParam
);
235 aluMixData(device
, WaveHdr
->lpData
, WaveHdr
->dwBufferLength
/
236 self
->Format
.nBlockAlign
);
238 // Send buffer back to play more data
239 waveOutWrite(self
->OutHdl
, WaveHdr
, sizeof(WAVEHDR
));
240 IncrementRef(&self
->WaveBuffersCommitted
);
247 static ALCenum
ALCwinmmPlayback_open(ALCwinmmPlayback
*self
, const ALCchar
*deviceName
)
249 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
250 const al_string
*iter
;
254 if(VECTOR_SIZE(PlaybackDevices
) == 0)
255 ProbePlaybackDevices();
257 // Find the Device ID matching the deviceName if valid
258 #define MATCH_DEVNAME(iter) (!al_string_empty(*(iter)) && \
259 (!deviceName || al_string_cmp_cstr(*(iter), deviceName) == 0))
260 VECTOR_FIND_IF(iter
, const al_string
, PlaybackDevices
, MATCH_DEVNAME
);
261 if(iter
== VECTOR_END(PlaybackDevices
))
262 return ALC_INVALID_VALUE
;
265 DeviceID
= (UINT
)(iter
- VECTOR_BEGIN(PlaybackDevices
));
268 memset(&self
->Format
, 0, sizeof(WAVEFORMATEX
));
269 if(device
->FmtType
== DevFmtFloat
)
271 self
->Format
.wFormatTag
= WAVE_FORMAT_IEEE_FLOAT
;
272 self
->Format
.wBitsPerSample
= 32;
276 self
->Format
.wFormatTag
= WAVE_FORMAT_PCM
;
277 if(device
->FmtType
== DevFmtUByte
|| device
->FmtType
== DevFmtByte
)
278 self
->Format
.wBitsPerSample
= 8;
280 self
->Format
.wBitsPerSample
= 16;
282 self
->Format
.nChannels
= ((device
->FmtChans
== DevFmtMono
) ? 1 : 2);
283 self
->Format
.nBlockAlign
= self
->Format
.wBitsPerSample
*
284 self
->Format
.nChannels
/ 8;
285 self
->Format
.nSamplesPerSec
= device
->Frequency
;
286 self
->Format
.nAvgBytesPerSec
= self
->Format
.nSamplesPerSec
*
287 self
->Format
.nBlockAlign
;
288 self
->Format
.cbSize
= 0;
290 if((res
=waveOutOpen(&self
->OutHdl
, DeviceID
, &self
->Format
, (DWORD_PTR
)&ALCwinmmPlayback_waveOutProc
, (DWORD_PTR
)self
, CALLBACK_FUNCTION
)) != MMSYSERR_NOERROR
)
292 if(device
->FmtType
== DevFmtFloat
)
294 device
->FmtType
= DevFmtShort
;
297 ERR("waveOutOpen failed: %u\n", res
);
301 al_string_copy(&device
->DeviceName
, VECTOR_ELEM(PlaybackDevices
, DeviceID
));
306 waveOutClose(self
->OutHdl
);
309 return ALC_INVALID_VALUE
;
312 static void ALCwinmmPlayback_close(ALCwinmmPlayback
* UNUSED(self
))
315 static ALCboolean
ALCwinmmPlayback_reset(ALCwinmmPlayback
*self
)
317 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
319 device
->UpdateSize
= (ALuint
)((ALuint64
)device
->UpdateSize
*
320 self
->Format
.nSamplesPerSec
/
322 device
->UpdateSize
= (device
->UpdateSize
*device
->NumUpdates
+ 3) / 4;
323 device
->NumUpdates
= 4;
324 device
->Frequency
= self
->Format
.nSamplesPerSec
;
326 if(self
->Format
.wFormatTag
== WAVE_FORMAT_IEEE_FLOAT
)
328 if(self
->Format
.wBitsPerSample
== 32)
329 device
->FmtType
= DevFmtFloat
;
332 ERR("Unhandled IEEE float sample depth: %d\n", self
->Format
.wBitsPerSample
);
336 else if(self
->Format
.wFormatTag
== WAVE_FORMAT_PCM
)
338 if(self
->Format
.wBitsPerSample
== 16)
339 device
->FmtType
= DevFmtShort
;
340 else if(self
->Format
.wBitsPerSample
== 8)
341 device
->FmtType
= DevFmtUByte
;
344 ERR("Unhandled PCM sample depth: %d\n", self
->Format
.wBitsPerSample
);
350 ERR("Unhandled format tag: 0x%04x\n", self
->Format
.wFormatTag
);
354 if(self
->Format
.nChannels
== 2)
355 device
->FmtChans
= DevFmtStereo
;
356 else if(self
->Format
.nChannels
== 1)
357 device
->FmtChans
= DevFmtMono
;
360 ERR("Unhandled channel count: %d\n", self
->Format
.nChannels
);
363 SetDefaultWFXChannelOrder(device
);
368 static ALCboolean
ALCwinmmPlayback_start(ALCwinmmPlayback
*self
)
370 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
375 self
->killNow
= AL_FALSE
;
376 if(althrd_create(&self
->thread
, ALCwinmmPlayback_mixerProc
, self
) != althrd_success
)
379 InitRef(&self
->WaveBuffersCommitted
, 0);
382 BufferSize
= device
->UpdateSize
*device
->NumUpdates
/ 4;
383 BufferSize
*= FrameSizeFromDevFmt(device
->FmtChans
, device
->FmtType
);
385 BufferData
= calloc(4, BufferSize
);
388 memset(&self
->WaveBuffer
[i
], 0, sizeof(WAVEHDR
));
389 self
->WaveBuffer
[i
].dwBufferLength
= BufferSize
;
390 self
->WaveBuffer
[i
].lpData
= ((i
==0) ? (CHAR
*)BufferData
:
391 (self
->WaveBuffer
[i
-1].lpData
+
392 self
->WaveBuffer
[i
-1].dwBufferLength
));
393 waveOutPrepareHeader(self
->OutHdl
, &self
->WaveBuffer
[i
], sizeof(WAVEHDR
));
394 waveOutWrite(self
->OutHdl
, &self
->WaveBuffer
[i
], sizeof(WAVEHDR
));
395 IncrementRef(&self
->WaveBuffersCommitted
);
401 static void ALCwinmmPlayback_stop(ALCwinmmPlayback
*self
)
409 // Set flag to stop processing headers
410 self
->killNow
= AL_TRUE
;
411 althrd_join(self
->thread
, &i
);
413 // Release the wave buffers
416 waveOutUnprepareHeader(self
->OutHdl
, &self
->WaveBuffer
[i
], sizeof(WAVEHDR
));
417 if(i
== 0) buffer
= self
->WaveBuffer
[i
].lpData
;
418 self
->WaveBuffer
[i
].lpData
= NULL
;
425 typedef struct ALCwinmmCapture
{
426 DERIVE_FROM_TYPE(ALCbackend
);
428 RefCount WaveBuffersCommitted
;
429 WAVEHDR WaveBuffer
[4];
433 ll_ringbuffer_t
*Ring
;
437 volatile ALboolean killNow
;
441 static void ALCwinmmCapture_Construct(ALCwinmmCapture
*self
, ALCdevice
*device
);
442 static void ALCwinmmCapture_Destruct(ALCwinmmCapture
*self
);
444 static void CALLBACK
ALCwinmmCapture_waveInProc(HWAVEIN device
, UINT msg
, DWORD_PTR instance
, DWORD_PTR param1
, DWORD_PTR param2
);
445 static int ALCwinmmCapture_captureProc(void *arg
);
447 static ALCenum
ALCwinmmCapture_open(ALCwinmmCapture
*self
, const ALCchar
*name
);
448 static void ALCwinmmCapture_close(ALCwinmmCapture
*self
);
449 static DECLARE_FORWARD(ALCwinmmCapture
, ALCbackend
, ALCboolean
, reset
)
450 static ALCboolean
ALCwinmmCapture_start(ALCwinmmCapture
*self
);
451 static void ALCwinmmCapture_stop(ALCwinmmCapture
*self
);
452 static ALCenum
ALCwinmmCapture_captureSamples(ALCwinmmCapture
*self
, ALCvoid
*buffer
, ALCuint samples
);
453 static ALCuint
ALCwinmmCapture_availableSamples(ALCwinmmCapture
*self
);
454 static DECLARE_FORWARD(ALCwinmmCapture
, ALCbackend
, ClockLatency
, getClockLatency
)
455 static DECLARE_FORWARD(ALCwinmmCapture
, ALCbackend
, void, lock
)
456 static DECLARE_FORWARD(ALCwinmmCapture
, ALCbackend
, void, unlock
)
457 DECLARE_DEFAULT_ALLOCATORS(ALCwinmmCapture
)
459 DEFINE_ALCBACKEND_VTABLE(ALCwinmmCapture
);
462 static void ALCwinmmCapture_Construct(ALCwinmmCapture
*self
, ALCdevice
*device
)
464 ALCbackend_Construct(STATIC_CAST(ALCbackend
, self
), device
);
465 SET_VTABLE2(ALCwinmmCapture
, ALCbackend
, self
);
467 InitRef(&self
->WaveBuffersCommitted
, 0);
470 self
->killNow
= AL_TRUE
;
473 static void ALCwinmmCapture_Destruct(ALCwinmmCapture
*self
)
476 waveInClose(self
->InHdl
);
479 ALCbackend_Destruct(STATIC_CAST(ALCbackend
, self
));
483 /* ALCwinmmCapture_waveInProc
485 * Posts a message to 'ALCwinmmCapture_captureProc' everytime a WaveIn Buffer
486 * is completed and returns to the application (with more data).
488 static void CALLBACK
ALCwinmmCapture_waveInProc(HWAVEIN
UNUSED(device
), UINT msg
, DWORD_PTR instance
, DWORD_PTR param1
, DWORD_PTR
UNUSED(param2
))
490 ALCwinmmCapture
*self
= (ALCwinmmCapture
*)instance
;
495 DecrementRef(&self
->WaveBuffersCommitted
);
496 PostThreadMessage(self
->thread
, msg
, 0, param1
);
499 static int ALCwinmmCapture_captureProc(void *arg
)
501 ALCwinmmCapture
*self
= arg
;
505 althrd_setname(althrd_current(), RECORD_THREAD_NAME
);
507 while(GetMessage(&msg
, NULL
, 0, 0))
509 if(msg
.message
!= WIM_DATA
)
511 /* Don't wait for other buffers to finish before quitting. We're
512 * closing so we don't need them. */
516 WaveHdr
= ((WAVEHDR
*)msg
.lParam
);
517 ll_ringbuffer_write(self
->Ring
, WaveHdr
->lpData
,
518 WaveHdr
->dwBytesRecorded
/ self
->Format
.nBlockAlign
521 // Send buffer back to capture more data
522 waveInAddBuffer(self
->InHdl
, WaveHdr
, sizeof(WAVEHDR
));
523 IncrementRef(&self
->WaveBuffersCommitted
);
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
;
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_END(CaptureDevices
))
548 return ALC_INVALID_VALUE
;
551 DeviceID
= (UINT
)(iter
- VECTOR_BEGIN(CaptureDevices
));
553 switch(device
->FmtChans
)
564 case DevFmtBFormat3D
:
565 return ALC_INVALID_ENUM
;
568 switch(device
->FmtType
)
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
);
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
= ll_ringbuffer_create(CapturedDataSize
+1, self
->Format
.nBlockAlign
);
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
;
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
)
637 al_string_copy(&device
->DeviceName
, VECTOR_ELEM(CaptureDevices
, DeviceID
));
644 waveInUnprepareHeader(self
->InHdl
, &self
->WaveBuffer
[i
], sizeof(WAVEHDR
));
648 ll_ringbuffer_free(self
->Ring
);
652 waveInClose(self
->InHdl
);
655 return ALC_INVALID_VALUE
;
658 static void ALCwinmmCapture_close(ALCwinmmCapture
*self
)
663 /* Tell the processing thread to quit and wait for it to do so. */
664 self
->killNow
= AL_TRUE
;
665 PostThreadMessage(self
->thread
, WM_QUIT
, 0, 0);
667 althrd_join(self
->thread
, &i
);
669 /* Make sure capture is stopped and all pending buffers are flushed. */
670 waveInReset(self
->InHdl
);
672 // Release the wave buffers
675 waveInUnprepareHeader(self
->InHdl
, &self
->WaveBuffer
[i
], sizeof(WAVEHDR
));
676 if(i
== 0) buffer
= self
->WaveBuffer
[i
].lpData
;
677 self
->WaveBuffer
[i
].lpData
= NULL
;
681 ll_ringbuffer_free(self
->Ring
);
684 // Close the Wave device
685 waveInClose(self
->InHdl
);
689 static ALCboolean
ALCwinmmCapture_start(ALCwinmmCapture
*self
)
691 waveInStart(self
->InHdl
);
695 static void ALCwinmmCapture_stop(ALCwinmmCapture
*self
)
697 waveInStop(self
->InHdl
);
700 static ALCenum
ALCwinmmCapture_captureSamples(ALCwinmmCapture
*self
, ALCvoid
*buffer
, ALCuint samples
)
702 ll_ringbuffer_read(self
->Ring
, buffer
, samples
);
706 static ALCuint
ALCwinmmCapture_availableSamples(ALCwinmmCapture
*self
)
708 return ll_ringbuffer_read_space(self
->Ring
);
712 static inline void AppendAllDevicesList2(const al_string
*name
)
714 if(!al_string_empty(*name
))
715 AppendAllDevicesList(al_string_get_cstr(*name
));
717 static inline void AppendCaptureDeviceList2(const al_string
*name
)
719 if(!al_string_empty(*name
))
720 AppendCaptureDeviceList(al_string_get_cstr(*name
));
723 typedef struct ALCwinmmBackendFactory
{
724 DERIVE_FROM_TYPE(ALCbackendFactory
);
725 } ALCwinmmBackendFactory
;
726 #define ALCWINMMBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCwinmmBackendFactory, ALCbackendFactory) } }
728 static ALCboolean
ALCwinmmBackendFactory_init(ALCwinmmBackendFactory
*self
);
729 static void ALCwinmmBackendFactory_deinit(ALCwinmmBackendFactory
*self
);
730 static ALCboolean
ALCwinmmBackendFactory_querySupport(ALCwinmmBackendFactory
*self
, ALCbackend_Type type
);
731 static void ALCwinmmBackendFactory_probe(ALCwinmmBackendFactory
*self
, enum DevProbe type
);
732 static ALCbackend
* ALCwinmmBackendFactory_createBackend(ALCwinmmBackendFactory
*self
, ALCdevice
*device
, ALCbackend_Type type
);
734 DEFINE_ALCBACKENDFACTORY_VTABLE(ALCwinmmBackendFactory
);
737 static ALCboolean
ALCwinmmBackendFactory_init(ALCwinmmBackendFactory
* UNUSED(self
))
739 VECTOR_INIT(PlaybackDevices
);
740 VECTOR_INIT(CaptureDevices
);
745 static void ALCwinmmBackendFactory_deinit(ALCwinmmBackendFactory
* UNUSED(self
))
747 clear_devlist(&PlaybackDevices
);
748 VECTOR_DEINIT(PlaybackDevices
);
750 clear_devlist(&CaptureDevices
);
751 VECTOR_DEINIT(CaptureDevices
);
754 static ALCboolean
ALCwinmmBackendFactory_querySupport(ALCwinmmBackendFactory
* UNUSED(self
), ALCbackend_Type type
)
756 if(type
== ALCbackend_Playback
|| type
== ALCbackend_Capture
)
761 static void ALCwinmmBackendFactory_probe(ALCwinmmBackendFactory
* UNUSED(self
), enum DevProbe type
)
765 case ALL_DEVICE_PROBE
:
766 ProbePlaybackDevices();
767 VECTOR_FOR_EACH(const al_string
, PlaybackDevices
, AppendAllDevicesList2
);
770 case CAPTURE_DEVICE_PROBE
:
771 ProbeCaptureDevices();
772 VECTOR_FOR_EACH(const al_string
, CaptureDevices
, AppendCaptureDeviceList2
);
777 static ALCbackend
* ALCwinmmBackendFactory_createBackend(ALCwinmmBackendFactory
* UNUSED(self
), ALCdevice
*device
, ALCbackend_Type type
)
779 if(type
== ALCbackend_Playback
)
781 ALCwinmmPlayback
*backend
;
782 NEW_OBJ(backend
, ALCwinmmPlayback
)(device
);
783 if(!backend
) return NULL
;
784 return STATIC_CAST(ALCbackend
, backend
);
786 if(type
== ALCbackend_Capture
)
788 ALCwinmmCapture
*backend
;
789 NEW_OBJ(backend
, ALCwinmmCapture
)(device
);
790 if(!backend
) return NULL
;
791 return STATIC_CAST(ALCbackend
, backend
);
797 ALCbackendFactory
*ALCwinmmBackendFactory_getFactory(void)
799 static ALCwinmmBackendFactory factory
= ALCWINMMBACKENDFACTORY_INITIALIZER
;
800 return STATIC_CAST(ALCbackendFactory
, &factory
);