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
32 #include "ringbuffer.h"
35 #include "backends/base.h"
37 #ifndef WAVE_FORMAT_IEEE_FLOAT
38 #define WAVE_FORMAT_IEEE_FLOAT 0x0003
41 #define DEVNAME_HEAD "OpenAL Soft on "
44 static vector_al_string PlaybackDevices
;
45 static vector_al_string CaptureDevices
;
47 static void clear_devlist(vector_al_string
*list
)
49 VECTOR_FOR_EACH(al_string
, *list
, alstr_reset
);
50 VECTOR_RESIZE(*list
, 0, 0);
54 static void ProbePlaybackDevices(void)
59 clear_devlist(&PlaybackDevices
);
61 numdevs
= waveOutGetNumDevs();
62 VECTOR_RESIZE(PlaybackDevices
, 0, numdevs
);
63 for(i
= 0;i
< numdevs
;i
++)
65 WAVEOUTCAPSW WaveCaps
;
66 const al_string
*iter
;
69 AL_STRING_INIT(dname
);
70 if(waveOutGetDevCapsW(i
, &WaveCaps
, sizeof(WaveCaps
)) == MMSYSERR_NOERROR
)
75 alstr_copy_cstr(&dname
, DEVNAME_HEAD
);
76 alstr_append_wcstr(&dname
, WaveCaps
.szPname
);
80 snprintf(str
, sizeof(str
), " #%d", count
+1);
81 alstr_append_cstr(&dname
, str
);
85 #define MATCH_ENTRY(i) (alstr_cmp(dname, *(i)) == 0)
86 VECTOR_FIND_IF(iter
, const al_string
, PlaybackDevices
, MATCH_ENTRY
);
87 if(iter
== VECTOR_END(PlaybackDevices
)) break;
91 TRACE("Got device \"%s\", ID %u\n", alstr_get_cstr(dname
), i
);
93 VECTOR_PUSH_BACK(PlaybackDevices
, dname
);
97 static void ProbeCaptureDevices(void)
102 clear_devlist(&CaptureDevices
);
104 numdevs
= waveInGetNumDevs();
105 VECTOR_RESIZE(CaptureDevices
, 0, numdevs
);
106 for(i
= 0;i
< numdevs
;i
++)
108 WAVEINCAPSW WaveCaps
;
109 const al_string
*iter
;
112 AL_STRING_INIT(dname
);
113 if(waveInGetDevCapsW(i
, &WaveCaps
, sizeof(WaveCaps
)) == MMSYSERR_NOERROR
)
118 alstr_copy_cstr(&dname
, DEVNAME_HEAD
);
119 alstr_append_wcstr(&dname
, WaveCaps
.szPname
);
123 snprintf(str
, sizeof(str
), " #%d", count
+1);
124 alstr_append_cstr(&dname
, str
);
128 #define MATCH_ENTRY(i) (alstr_cmp(dname, *(i)) == 0)
129 VECTOR_FIND_IF(iter
, const al_string
, CaptureDevices
, MATCH_ENTRY
);
130 if(iter
== VECTOR_END(CaptureDevices
)) break;
134 TRACE("Got device \"%s\", ID %u\n", alstr_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];
151 ATOMIC(ALenum
) killNow
;
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 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 ATOMIC_INIT(&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
)
227 if(ATOMIC_LOAD(&self
->killNow
, almemory_order_acquire
))
229 if(ReadRef(&self
->WaveBuffersCommitted
) == 0)
234 WaveHdr
= ((WAVEHDR
*)msg
.lParam
);
235 ALCwinmmPlayback_lock(self
);
236 aluMixData(device
, WaveHdr
->lpData
, WaveHdr
->dwBufferLength
/
237 self
->Format
.nBlockAlign
);
238 ALCwinmmPlayback_unlock(self
);
240 // Send buffer back to play more data
241 waveOutWrite(self
->OutHdl
, WaveHdr
, sizeof(WAVEHDR
));
242 IncrementRef(&self
->WaveBuffersCommitted
);
249 static ALCenum
ALCwinmmPlayback_open(ALCwinmmPlayback
*self
, const ALCchar
*deviceName
)
251 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
252 const al_string
*iter
;
256 if(VECTOR_SIZE(PlaybackDevices
) == 0)
257 ProbePlaybackDevices();
259 // Find the Device ID matching the deviceName if valid
260 #define MATCH_DEVNAME(iter) (!alstr_empty(*(iter)) && \
261 (!deviceName || alstr_cmp_cstr(*(iter), deviceName) == 0))
262 VECTOR_FIND_IF(iter
, const al_string
, PlaybackDevices
, MATCH_DEVNAME
);
263 if(iter
== VECTOR_END(PlaybackDevices
))
264 return ALC_INVALID_VALUE
;
267 DeviceID
= (UINT
)(iter
- VECTOR_BEGIN(PlaybackDevices
));
270 memset(&self
->Format
, 0, sizeof(WAVEFORMATEX
));
271 if(device
->FmtType
== DevFmtFloat
)
273 self
->Format
.wFormatTag
= WAVE_FORMAT_IEEE_FLOAT
;
274 self
->Format
.wBitsPerSample
= 32;
278 self
->Format
.wFormatTag
= WAVE_FORMAT_PCM
;
279 if(device
->FmtType
== DevFmtUByte
|| device
->FmtType
== DevFmtByte
)
280 self
->Format
.wBitsPerSample
= 8;
282 self
->Format
.wBitsPerSample
= 16;
284 self
->Format
.nChannels
= ((device
->FmtChans
== DevFmtMono
) ? 1 : 2);
285 self
->Format
.nBlockAlign
= self
->Format
.wBitsPerSample
*
286 self
->Format
.nChannels
/ 8;
287 self
->Format
.nSamplesPerSec
= device
->Frequency
;
288 self
->Format
.nAvgBytesPerSec
= self
->Format
.nSamplesPerSec
*
289 self
->Format
.nBlockAlign
;
290 self
->Format
.cbSize
= 0;
292 if((res
=waveOutOpen(&self
->OutHdl
, DeviceID
, &self
->Format
, (DWORD_PTR
)&ALCwinmmPlayback_waveOutProc
, (DWORD_PTR
)self
, CALLBACK_FUNCTION
)) != MMSYSERR_NOERROR
)
294 if(device
->FmtType
== DevFmtFloat
)
296 device
->FmtType
= DevFmtShort
;
299 ERR("waveOutOpen failed: %u\n", res
);
303 alstr_copy(&device
->DeviceName
, VECTOR_ELEM(PlaybackDevices
, DeviceID
));
308 waveOutClose(self
->OutHdl
);
311 return ALC_INVALID_VALUE
;
314 static ALCboolean
ALCwinmmPlayback_reset(ALCwinmmPlayback
*self
)
316 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
318 device
->UpdateSize
= (ALuint
)((ALuint64
)device
->UpdateSize
*
319 self
->Format
.nSamplesPerSec
/
321 device
->UpdateSize
= (device
->UpdateSize
*device
->NumUpdates
+ 3) / 4;
322 device
->NumUpdates
= 4;
323 device
->Frequency
= self
->Format
.nSamplesPerSec
;
325 if(self
->Format
.wFormatTag
== WAVE_FORMAT_IEEE_FLOAT
)
327 if(self
->Format
.wBitsPerSample
== 32)
328 device
->FmtType
= DevFmtFloat
;
331 ERR("Unhandled IEEE float sample depth: %d\n", self
->Format
.wBitsPerSample
);
335 else if(self
->Format
.wFormatTag
== WAVE_FORMAT_PCM
)
337 if(self
->Format
.wBitsPerSample
== 16)
338 device
->FmtType
= DevFmtShort
;
339 else if(self
->Format
.wBitsPerSample
== 8)
340 device
->FmtType
= DevFmtUByte
;
343 ERR("Unhandled PCM sample depth: %d\n", self
->Format
.wBitsPerSample
);
349 ERR("Unhandled format tag: 0x%04x\n", self
->Format
.wFormatTag
);
353 if(self
->Format
.nChannels
== 2)
354 device
->FmtChans
= DevFmtStereo
;
355 else if(self
->Format
.nChannels
== 1)
356 device
->FmtChans
= DevFmtMono
;
359 ERR("Unhandled channel count: %d\n", self
->Format
.nChannels
);
362 SetDefaultWFXChannelOrder(device
);
367 static ALCboolean
ALCwinmmPlayback_start(ALCwinmmPlayback
*self
)
369 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
374 ATOMIC_STORE(&self
->killNow
, AL_FALSE
, almemory_order_release
);
375 if(althrd_create(&self
->thread
, ALCwinmmPlayback_mixerProc
, self
) != althrd_success
)
378 InitRef(&self
->WaveBuffersCommitted
, 0);
381 BufferSize
= device
->UpdateSize
*device
->NumUpdates
/ 4;
382 BufferSize
*= FrameSizeFromDevFmt(device
->FmtChans
, device
->FmtType
, device
->AmbiOrder
);
384 BufferData
= calloc(4, BufferSize
);
387 memset(&self
->WaveBuffer
[i
], 0, sizeof(WAVEHDR
));
388 self
->WaveBuffer
[i
].dwBufferLength
= BufferSize
;
389 self
->WaveBuffer
[i
].lpData
= ((i
==0) ? (CHAR
*)BufferData
:
390 (self
->WaveBuffer
[i
-1].lpData
+
391 self
->WaveBuffer
[i
-1].dwBufferLength
));
392 waveOutPrepareHeader(self
->OutHdl
, &self
->WaveBuffer
[i
], sizeof(WAVEHDR
));
393 waveOutWrite(self
->OutHdl
, &self
->WaveBuffer
[i
], sizeof(WAVEHDR
));
394 IncrementRef(&self
->WaveBuffersCommitted
);
400 static void ALCwinmmPlayback_stop(ALCwinmmPlayback
*self
)
405 if(ATOMIC_EXCHANGE(&self
->killNow
, AL_TRUE
, almemory_order_acq_rel
))
407 althrd_join(self
->thread
, &i
);
409 // Release the wave buffers
412 waveOutUnprepareHeader(self
->OutHdl
, &self
->WaveBuffer
[i
], sizeof(WAVEHDR
));
413 if(i
== 0) buffer
= self
->WaveBuffer
[i
].lpData
;
414 self
->WaveBuffer
[i
].lpData
= NULL
;
421 typedef struct ALCwinmmCapture
{
422 DERIVE_FROM_TYPE(ALCbackend
);
424 RefCount WaveBuffersCommitted
;
425 WAVEHDR WaveBuffer
[4];
429 ll_ringbuffer_t
*Ring
;
433 ATOMIC(ALenum
) killNow
;
437 static void ALCwinmmCapture_Construct(ALCwinmmCapture
*self
, ALCdevice
*device
);
438 static void ALCwinmmCapture_Destruct(ALCwinmmCapture
*self
);
440 static void CALLBACK
ALCwinmmCapture_waveInProc(HWAVEIN device
, UINT msg
, DWORD_PTR instance
, DWORD_PTR param1
, DWORD_PTR param2
);
441 static int ALCwinmmCapture_captureProc(void *arg
);
443 static ALCenum
ALCwinmmCapture_open(ALCwinmmCapture
*self
, const ALCchar
*name
);
444 static DECLARE_FORWARD(ALCwinmmCapture
, ALCbackend
, ALCboolean
, reset
)
445 static ALCboolean
ALCwinmmCapture_start(ALCwinmmCapture
*self
);
446 static void ALCwinmmCapture_stop(ALCwinmmCapture
*self
);
447 static ALCenum
ALCwinmmCapture_captureSamples(ALCwinmmCapture
*self
, ALCvoid
*buffer
, ALCuint samples
);
448 static ALCuint
ALCwinmmCapture_availableSamples(ALCwinmmCapture
*self
);
449 static DECLARE_FORWARD(ALCwinmmCapture
, ALCbackend
, ClockLatency
, getClockLatency
)
450 static DECLARE_FORWARD(ALCwinmmCapture
, ALCbackend
, void, lock
)
451 static DECLARE_FORWARD(ALCwinmmCapture
, ALCbackend
, void, unlock
)
452 DECLARE_DEFAULT_ALLOCATORS(ALCwinmmCapture
)
454 DEFINE_ALCBACKEND_VTABLE(ALCwinmmCapture
);
457 static void ALCwinmmCapture_Construct(ALCwinmmCapture
*self
, ALCdevice
*device
)
459 ALCbackend_Construct(STATIC_CAST(ALCbackend
, self
), device
);
460 SET_VTABLE2(ALCwinmmCapture
, ALCbackend
, self
);
462 InitRef(&self
->WaveBuffersCommitted
, 0);
465 ATOMIC_INIT(&self
->killNow
, AL_TRUE
);
468 static void ALCwinmmCapture_Destruct(ALCwinmmCapture
*self
)
473 /* Tell the processing thread to quit and wait for it to do so. */
474 if(!ATOMIC_EXCHANGE(&self
->killNow
, AL_TRUE
, almemory_order_acq_rel
))
476 PostThreadMessage(self
->thread
, WM_QUIT
, 0, 0);
478 althrd_join(self
->thread
, &i
);
480 /* Make sure capture is stopped and all pending buffers are flushed. */
481 waveInReset(self
->InHdl
);
483 // Release the wave buffers
486 waveInUnprepareHeader(self
->InHdl
, &self
->WaveBuffer
[i
], sizeof(WAVEHDR
));
487 if(i
== 0) buffer
= self
->WaveBuffer
[i
].lpData
;
488 self
->WaveBuffer
[i
].lpData
= NULL
;
493 ll_ringbuffer_free(self
->Ring
);
496 // Close the Wave device
498 waveInClose(self
->InHdl
);
501 ALCbackend_Destruct(STATIC_CAST(ALCbackend
, self
));
505 /* ALCwinmmCapture_waveInProc
507 * Posts a message to 'ALCwinmmCapture_captureProc' everytime a WaveIn Buffer
508 * is completed and returns to the application (with more data).
510 static void CALLBACK
ALCwinmmCapture_waveInProc(HWAVEIN
UNUSED(device
), UINT msg
, DWORD_PTR instance
, DWORD_PTR param1
, DWORD_PTR
UNUSED(param2
))
512 ALCwinmmCapture
*self
= (ALCwinmmCapture
*)instance
;
517 DecrementRef(&self
->WaveBuffersCommitted
);
518 PostThreadMessage(self
->thread
, msg
, 0, param1
);
521 static int ALCwinmmCapture_captureProc(void *arg
)
523 ALCwinmmCapture
*self
= arg
;
527 althrd_setname(althrd_current(), RECORD_THREAD_NAME
);
529 while(GetMessage(&msg
, NULL
, 0, 0))
531 if(msg
.message
!= WIM_DATA
)
533 /* Don't wait for other buffers to finish before quitting. We're
534 * closing so we don't need them. */
535 if(ATOMIC_LOAD(&self
->killNow
, almemory_order_acquire
))
538 WaveHdr
= ((WAVEHDR
*)msg
.lParam
);
539 ll_ringbuffer_write(self
->Ring
, WaveHdr
->lpData
,
540 WaveHdr
->dwBytesRecorded
/ self
->Format
.nBlockAlign
543 // Send buffer back to capture more data
544 waveInAddBuffer(self
->InHdl
, WaveHdr
, sizeof(WAVEHDR
));
545 IncrementRef(&self
->WaveBuffersCommitted
);
552 static ALCenum
ALCwinmmCapture_open(ALCwinmmCapture
*self
, const ALCchar
*name
)
554 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
555 const al_string
*iter
;
556 ALbyte
*BufferData
= NULL
;
557 DWORD CapturedDataSize
;
563 if(VECTOR_SIZE(CaptureDevices
) == 0)
564 ProbeCaptureDevices();
566 // Find the Device ID matching the deviceName if valid
567 #define MATCH_DEVNAME(iter) (!alstr_empty(*(iter)) && (!name || alstr_cmp_cstr(*iter, name) == 0))
568 VECTOR_FIND_IF(iter
, const al_string
, CaptureDevices
, MATCH_DEVNAME
);
569 if(iter
== VECTOR_END(CaptureDevices
))
570 return ALC_INVALID_VALUE
;
573 DeviceID
= (UINT
)(iter
- VECTOR_BEGIN(CaptureDevices
));
575 switch(device
->FmtChans
)
587 return ALC_INVALID_ENUM
;
590 switch(device
->FmtType
)
601 return ALC_INVALID_ENUM
;
604 memset(&self
->Format
, 0, sizeof(WAVEFORMATEX
));
605 self
->Format
.wFormatTag
= ((device
->FmtType
== DevFmtFloat
) ?
606 WAVE_FORMAT_IEEE_FLOAT
: WAVE_FORMAT_PCM
);
607 self
->Format
.nChannels
= ChannelsFromDevFmt(device
->FmtChans
, device
->AmbiOrder
);
608 self
->Format
.wBitsPerSample
= BytesFromDevFmt(device
->FmtType
) * 8;
609 self
->Format
.nBlockAlign
= self
->Format
.wBitsPerSample
*
610 self
->Format
.nChannels
/ 8;
611 self
->Format
.nSamplesPerSec
= device
->Frequency
;
612 self
->Format
.nAvgBytesPerSec
= self
->Format
.nSamplesPerSec
*
613 self
->Format
.nBlockAlign
;
614 self
->Format
.cbSize
= 0;
616 if((res
=waveInOpen(&self
->InHdl
, DeviceID
, &self
->Format
, (DWORD_PTR
)&ALCwinmmCapture_waveInProc
, (DWORD_PTR
)self
, CALLBACK_FUNCTION
)) != MMSYSERR_NOERROR
)
618 ERR("waveInOpen failed: %u\n", res
);
622 // Allocate circular memory buffer for the captured audio
623 CapturedDataSize
= device
->UpdateSize
*device
->NumUpdates
;
625 // Make sure circular buffer is at least 100ms in size
626 if(CapturedDataSize
< (self
->Format
.nSamplesPerSec
/ 10))
627 CapturedDataSize
= self
->Format
.nSamplesPerSec
/ 10;
629 self
->Ring
= ll_ringbuffer_create(CapturedDataSize
, self
->Format
.nBlockAlign
, false);
630 if(!self
->Ring
) goto failure
;
632 InitRef(&self
->WaveBuffersCommitted
, 0);
634 // Create 4 Buffers of 50ms each
635 BufferSize
= self
->Format
.nAvgBytesPerSec
/ 20;
636 BufferSize
-= (BufferSize
% self
->Format
.nBlockAlign
);
638 BufferData
= calloc(4, BufferSize
);
639 if(!BufferData
) goto failure
;
643 memset(&self
->WaveBuffer
[i
], 0, sizeof(WAVEHDR
));
644 self
->WaveBuffer
[i
].dwBufferLength
= BufferSize
;
645 self
->WaveBuffer
[i
].lpData
= ((i
==0) ? (CHAR
*)BufferData
:
646 (self
->WaveBuffer
[i
-1].lpData
+
647 self
->WaveBuffer
[i
-1].dwBufferLength
));
648 self
->WaveBuffer
[i
].dwFlags
= 0;
649 self
->WaveBuffer
[i
].dwLoops
= 0;
650 waveInPrepareHeader(self
->InHdl
, &self
->WaveBuffer
[i
], sizeof(WAVEHDR
));
651 waveInAddBuffer(self
->InHdl
, &self
->WaveBuffer
[i
], sizeof(WAVEHDR
));
652 IncrementRef(&self
->WaveBuffersCommitted
);
655 ATOMIC_STORE(&self
->killNow
, AL_FALSE
, almemory_order_release
);
656 if(althrd_create(&self
->thread
, ALCwinmmCapture_captureProc
, self
) != althrd_success
)
659 alstr_copy(&device
->DeviceName
, VECTOR_ELEM(CaptureDevices
, DeviceID
));
666 waveInUnprepareHeader(self
->InHdl
, &self
->WaveBuffer
[i
], sizeof(WAVEHDR
));
670 ll_ringbuffer_free(self
->Ring
);
674 waveInClose(self
->InHdl
);
677 return ALC_INVALID_VALUE
;
680 static ALCboolean
ALCwinmmCapture_start(ALCwinmmCapture
*self
)
682 waveInStart(self
->InHdl
);
686 static void ALCwinmmCapture_stop(ALCwinmmCapture
*self
)
688 waveInStop(self
->InHdl
);
691 static ALCenum
ALCwinmmCapture_captureSamples(ALCwinmmCapture
*self
, ALCvoid
*buffer
, ALCuint samples
)
693 ll_ringbuffer_read(self
->Ring
, buffer
, samples
);
697 static ALCuint
ALCwinmmCapture_availableSamples(ALCwinmmCapture
*self
)
699 return (ALCuint
)ll_ringbuffer_read_space(self
->Ring
);
703 static inline void AppendAllDevicesList2(const al_string
*name
)
705 if(!alstr_empty(*name
))
706 AppendAllDevicesList(alstr_get_cstr(*name
));
708 static inline void AppendCaptureDeviceList2(const al_string
*name
)
710 if(!alstr_empty(*name
))
711 AppendCaptureDeviceList(alstr_get_cstr(*name
));
714 typedef struct ALCwinmmBackendFactory
{
715 DERIVE_FROM_TYPE(ALCbackendFactory
);
716 } ALCwinmmBackendFactory
;
717 #define ALCWINMMBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCwinmmBackendFactory, ALCbackendFactory) } }
719 static ALCboolean
ALCwinmmBackendFactory_init(ALCwinmmBackendFactory
*self
);
720 static void ALCwinmmBackendFactory_deinit(ALCwinmmBackendFactory
*self
);
721 static ALCboolean
ALCwinmmBackendFactory_querySupport(ALCwinmmBackendFactory
*self
, ALCbackend_Type type
);
722 static void ALCwinmmBackendFactory_probe(ALCwinmmBackendFactory
*self
, enum DevProbe type
);
723 static ALCbackend
* ALCwinmmBackendFactory_createBackend(ALCwinmmBackendFactory
*self
, ALCdevice
*device
, ALCbackend_Type type
);
725 DEFINE_ALCBACKENDFACTORY_VTABLE(ALCwinmmBackendFactory
);
728 static ALCboolean
ALCwinmmBackendFactory_init(ALCwinmmBackendFactory
* UNUSED(self
))
730 VECTOR_INIT(PlaybackDevices
);
731 VECTOR_INIT(CaptureDevices
);
736 static void ALCwinmmBackendFactory_deinit(ALCwinmmBackendFactory
* UNUSED(self
))
738 clear_devlist(&PlaybackDevices
);
739 VECTOR_DEINIT(PlaybackDevices
);
741 clear_devlist(&CaptureDevices
);
742 VECTOR_DEINIT(CaptureDevices
);
745 static ALCboolean
ALCwinmmBackendFactory_querySupport(ALCwinmmBackendFactory
* UNUSED(self
), ALCbackend_Type type
)
747 if(type
== ALCbackend_Playback
|| type
== ALCbackend_Capture
)
752 static void ALCwinmmBackendFactory_probe(ALCwinmmBackendFactory
* UNUSED(self
), enum DevProbe type
)
756 case ALL_DEVICE_PROBE
:
757 ProbePlaybackDevices();
758 VECTOR_FOR_EACH(const al_string
, PlaybackDevices
, AppendAllDevicesList2
);
761 case CAPTURE_DEVICE_PROBE
:
762 ProbeCaptureDevices();
763 VECTOR_FOR_EACH(const al_string
, CaptureDevices
, AppendCaptureDeviceList2
);
768 static ALCbackend
* ALCwinmmBackendFactory_createBackend(ALCwinmmBackendFactory
* UNUSED(self
), ALCdevice
*device
, ALCbackend_Type type
)
770 if(type
== ALCbackend_Playback
)
772 ALCwinmmPlayback
*backend
;
773 NEW_OBJ(backend
, ALCwinmmPlayback
)(device
);
774 if(!backend
) return NULL
;
775 return STATIC_CAST(ALCbackend
, backend
);
777 if(type
== ALCbackend_Capture
)
779 ALCwinmmCapture
*backend
;
780 NEW_OBJ(backend
, ALCwinmmCapture
)(device
);
781 if(!backend
) return NULL
;
782 return STATIC_CAST(ALCbackend
, backend
);
788 ALCbackendFactory
*ALCwinmmBackendFactory_getFactory(void)
790 static ALCwinmmBackendFactory factory
= ALCWINMMBACKENDFACTORY_INITIALIZER
;
791 return STATIC_CAST(ALCbackendFactory
, &factory
);