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, 0);
53 static void ProbePlaybackDevices(void)
58 clear_devlist(&PlaybackDevices
);
60 numdevs
= waveOutGetNumDevs();
61 VECTOR_RESIZE(PlaybackDevices
, 0, 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_RESIZE(CaptureDevices
, 0, 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 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) (!al_string_empty(*(iter)) && \
261 (!deviceName || al_string_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 al_string_copy(&device
->DeviceName
, VECTOR_ELEM(PlaybackDevices
, DeviceID
));
308 waveOutClose(self
->OutHdl
);
311 return ALC_INVALID_VALUE
;
314 static void ALCwinmmPlayback_close(ALCwinmmPlayback
* UNUSED(self
))
317 static ALCboolean
ALCwinmmPlayback_reset(ALCwinmmPlayback
*self
)
319 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
321 device
->UpdateSize
= (ALuint
)((ALuint64
)device
->UpdateSize
*
322 self
->Format
.nSamplesPerSec
/
324 device
->UpdateSize
= (device
->UpdateSize
*device
->NumUpdates
+ 3) / 4;
325 device
->NumUpdates
= 4;
326 device
->Frequency
= self
->Format
.nSamplesPerSec
;
328 if(self
->Format
.wFormatTag
== WAVE_FORMAT_IEEE_FLOAT
)
330 if(self
->Format
.wBitsPerSample
== 32)
331 device
->FmtType
= DevFmtFloat
;
334 ERR("Unhandled IEEE float sample depth: %d\n", self
->Format
.wBitsPerSample
);
338 else if(self
->Format
.wFormatTag
== WAVE_FORMAT_PCM
)
340 if(self
->Format
.wBitsPerSample
== 16)
341 device
->FmtType
= DevFmtShort
;
342 else if(self
->Format
.wBitsPerSample
== 8)
343 device
->FmtType
= DevFmtUByte
;
346 ERR("Unhandled PCM sample depth: %d\n", self
->Format
.wBitsPerSample
);
352 ERR("Unhandled format tag: 0x%04x\n", self
->Format
.wFormatTag
);
356 if(self
->Format
.nChannels
== 2)
357 device
->FmtChans
= DevFmtStereo
;
358 else if(self
->Format
.nChannels
== 1)
359 device
->FmtChans
= DevFmtMono
;
362 ERR("Unhandled channel count: %d\n", self
->Format
.nChannels
);
365 SetDefaultWFXChannelOrder(device
);
370 static ALCboolean
ALCwinmmPlayback_start(ALCwinmmPlayback
*self
)
372 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
377 self
->killNow
= AL_FALSE
;
378 if(althrd_create(&self
->thread
, ALCwinmmPlayback_mixerProc
, self
) != althrd_success
)
381 InitRef(&self
->WaveBuffersCommitted
, 0);
384 BufferSize
= device
->UpdateSize
*device
->NumUpdates
/ 4;
385 BufferSize
*= FrameSizeFromDevFmt(device
->FmtChans
, device
->FmtType
);
387 BufferData
= calloc(4, BufferSize
);
390 memset(&self
->WaveBuffer
[i
], 0, sizeof(WAVEHDR
));
391 self
->WaveBuffer
[i
].dwBufferLength
= BufferSize
;
392 self
->WaveBuffer
[i
].lpData
= ((i
==0) ? (CHAR
*)BufferData
:
393 (self
->WaveBuffer
[i
-1].lpData
+
394 self
->WaveBuffer
[i
-1].dwBufferLength
));
395 waveOutPrepareHeader(self
->OutHdl
, &self
->WaveBuffer
[i
], sizeof(WAVEHDR
));
396 waveOutWrite(self
->OutHdl
, &self
->WaveBuffer
[i
], sizeof(WAVEHDR
));
397 IncrementRef(&self
->WaveBuffersCommitted
);
403 static void ALCwinmmPlayback_stop(ALCwinmmPlayback
*self
)
411 // Set flag to stop processing headers
412 self
->killNow
= AL_TRUE
;
413 althrd_join(self
->thread
, &i
);
415 // Release the wave buffers
418 waveOutUnprepareHeader(self
->OutHdl
, &self
->WaveBuffer
[i
], sizeof(WAVEHDR
));
419 if(i
== 0) buffer
= self
->WaveBuffer
[i
].lpData
;
420 self
->WaveBuffer
[i
].lpData
= NULL
;
427 typedef struct ALCwinmmCapture
{
428 DERIVE_FROM_TYPE(ALCbackend
);
430 RefCount WaveBuffersCommitted
;
431 WAVEHDR WaveBuffer
[4];
435 ll_ringbuffer_t
*Ring
;
439 volatile ALboolean killNow
;
443 static void ALCwinmmCapture_Construct(ALCwinmmCapture
*self
, ALCdevice
*device
);
444 static void ALCwinmmCapture_Destruct(ALCwinmmCapture
*self
);
446 static void CALLBACK
ALCwinmmCapture_waveInProc(HWAVEIN device
, UINT msg
, DWORD_PTR instance
, DWORD_PTR param1
, DWORD_PTR param2
);
447 static int ALCwinmmCapture_captureProc(void *arg
);
449 static ALCenum
ALCwinmmCapture_open(ALCwinmmCapture
*self
, const ALCchar
*name
);
450 static void ALCwinmmCapture_close(ALCwinmmCapture
*self
);
451 static DECLARE_FORWARD(ALCwinmmCapture
, ALCbackend
, ALCboolean
, reset
)
452 static ALCboolean
ALCwinmmCapture_start(ALCwinmmCapture
*self
);
453 static void ALCwinmmCapture_stop(ALCwinmmCapture
*self
);
454 static ALCenum
ALCwinmmCapture_captureSamples(ALCwinmmCapture
*self
, ALCvoid
*buffer
, ALCuint samples
);
455 static ALCuint
ALCwinmmCapture_availableSamples(ALCwinmmCapture
*self
);
456 static DECLARE_FORWARD(ALCwinmmCapture
, ALCbackend
, ClockLatency
, getClockLatency
)
457 static DECLARE_FORWARD(ALCwinmmCapture
, ALCbackend
, void, lock
)
458 static DECLARE_FORWARD(ALCwinmmCapture
, ALCbackend
, void, unlock
)
459 DECLARE_DEFAULT_ALLOCATORS(ALCwinmmCapture
)
461 DEFINE_ALCBACKEND_VTABLE(ALCwinmmCapture
);
464 static void ALCwinmmCapture_Construct(ALCwinmmCapture
*self
, ALCdevice
*device
)
466 ALCbackend_Construct(STATIC_CAST(ALCbackend
, self
), device
);
467 SET_VTABLE2(ALCwinmmCapture
, ALCbackend
, self
);
469 InitRef(&self
->WaveBuffersCommitted
, 0);
472 self
->killNow
= AL_TRUE
;
475 static void ALCwinmmCapture_Destruct(ALCwinmmCapture
*self
)
478 waveInClose(self
->InHdl
);
481 ALCbackend_Destruct(STATIC_CAST(ALCbackend
, self
));
485 /* ALCwinmmCapture_waveInProc
487 * Posts a message to 'ALCwinmmCapture_captureProc' everytime a WaveIn Buffer
488 * is completed and returns to the application (with more data).
490 static void CALLBACK
ALCwinmmCapture_waveInProc(HWAVEIN
UNUSED(device
), UINT msg
, DWORD_PTR instance
, DWORD_PTR param1
, DWORD_PTR
UNUSED(param2
))
492 ALCwinmmCapture
*self
= (ALCwinmmCapture
*)instance
;
497 DecrementRef(&self
->WaveBuffersCommitted
);
498 PostThreadMessage(self
->thread
, msg
, 0, param1
);
501 static int ALCwinmmCapture_captureProc(void *arg
)
503 ALCwinmmCapture
*self
= arg
;
507 althrd_setname(althrd_current(), RECORD_THREAD_NAME
);
509 while(GetMessage(&msg
, NULL
, 0, 0))
511 if(msg
.message
!= WIM_DATA
)
513 /* Don't wait for other buffers to finish before quitting. We're
514 * closing so we don't need them. */
518 WaveHdr
= ((WAVEHDR
*)msg
.lParam
);
519 ll_ringbuffer_write(self
->Ring
, WaveHdr
->lpData
,
520 WaveHdr
->dwBytesRecorded
/ self
->Format
.nBlockAlign
523 // Send buffer back to capture more data
524 waveInAddBuffer(self
->InHdl
, WaveHdr
, sizeof(WAVEHDR
));
525 IncrementRef(&self
->WaveBuffersCommitted
);
532 static ALCenum
ALCwinmmCapture_open(ALCwinmmCapture
*self
, const ALCchar
*name
)
534 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
535 const al_string
*iter
;
536 ALbyte
*BufferData
= NULL
;
537 DWORD CapturedDataSize
;
543 if(VECTOR_SIZE(CaptureDevices
) == 0)
544 ProbeCaptureDevices();
546 // Find the Device ID matching the deviceName if valid
547 #define MATCH_DEVNAME(iter) (!al_string_empty(*(iter)) && (!name || al_string_cmp_cstr(*iter, name) == 0))
548 VECTOR_FIND_IF(iter
, const al_string
, CaptureDevices
, MATCH_DEVNAME
);
549 if(iter
== VECTOR_END(CaptureDevices
))
550 return ALC_INVALID_VALUE
;
553 DeviceID
= (UINT
)(iter
- VECTOR_BEGIN(CaptureDevices
));
555 switch(device
->FmtChans
)
569 return ALC_INVALID_ENUM
;
572 switch(device
->FmtType
)
583 return ALC_INVALID_ENUM
;
586 memset(&self
->Format
, 0, sizeof(WAVEFORMATEX
));
587 self
->Format
.wFormatTag
= ((device
->FmtType
== DevFmtFloat
) ?
588 WAVE_FORMAT_IEEE_FLOAT
: WAVE_FORMAT_PCM
);
589 self
->Format
.nChannels
= ChannelsFromDevFmt(device
->FmtChans
);
590 self
->Format
.wBitsPerSample
= BytesFromDevFmt(device
->FmtType
) * 8;
591 self
->Format
.nBlockAlign
= self
->Format
.wBitsPerSample
*
592 self
->Format
.nChannels
/ 8;
593 self
->Format
.nSamplesPerSec
= device
->Frequency
;
594 self
->Format
.nAvgBytesPerSec
= self
->Format
.nSamplesPerSec
*
595 self
->Format
.nBlockAlign
;
596 self
->Format
.cbSize
= 0;
598 if((res
=waveInOpen(&self
->InHdl
, DeviceID
, &self
->Format
, (DWORD_PTR
)&ALCwinmmCapture_waveInProc
, (DWORD_PTR
)self
, CALLBACK_FUNCTION
)) != MMSYSERR_NOERROR
)
600 ERR("waveInOpen failed: %u\n", res
);
604 // Allocate circular memory buffer for the captured audio
605 CapturedDataSize
= device
->UpdateSize
*device
->NumUpdates
;
607 // Make sure circular buffer is at least 100ms in size
608 if(CapturedDataSize
< (self
->Format
.nSamplesPerSec
/ 10))
609 CapturedDataSize
= self
->Format
.nSamplesPerSec
/ 10;
611 self
->Ring
= ll_ringbuffer_create(CapturedDataSize
+1, self
->Format
.nBlockAlign
);
612 if(!self
->Ring
) goto failure
;
614 InitRef(&self
->WaveBuffersCommitted
, 0);
616 // Create 4 Buffers of 50ms each
617 BufferSize
= self
->Format
.nAvgBytesPerSec
/ 20;
618 BufferSize
-= (BufferSize
% self
->Format
.nBlockAlign
);
620 BufferData
= calloc(4, BufferSize
);
621 if(!BufferData
) goto failure
;
625 memset(&self
->WaveBuffer
[i
], 0, sizeof(WAVEHDR
));
626 self
->WaveBuffer
[i
].dwBufferLength
= BufferSize
;
627 self
->WaveBuffer
[i
].lpData
= ((i
==0) ? (CHAR
*)BufferData
:
628 (self
->WaveBuffer
[i
-1].lpData
+
629 self
->WaveBuffer
[i
-1].dwBufferLength
));
630 self
->WaveBuffer
[i
].dwFlags
= 0;
631 self
->WaveBuffer
[i
].dwLoops
= 0;
632 waveInPrepareHeader(self
->InHdl
, &self
->WaveBuffer
[i
], sizeof(WAVEHDR
));
633 waveInAddBuffer(self
->InHdl
, &self
->WaveBuffer
[i
], sizeof(WAVEHDR
));
634 IncrementRef(&self
->WaveBuffersCommitted
);
637 self
->killNow
= AL_FALSE
;
638 if(althrd_create(&self
->thread
, ALCwinmmCapture_captureProc
, self
) != althrd_success
)
641 al_string_copy(&device
->DeviceName
, VECTOR_ELEM(CaptureDevices
, DeviceID
));
648 waveInUnprepareHeader(self
->InHdl
, &self
->WaveBuffer
[i
], sizeof(WAVEHDR
));
652 ll_ringbuffer_free(self
->Ring
);
656 waveInClose(self
->InHdl
);
659 return ALC_INVALID_VALUE
;
662 static void ALCwinmmCapture_close(ALCwinmmCapture
*self
)
667 /* Tell the processing thread to quit and wait for it to do so. */
668 self
->killNow
= AL_TRUE
;
669 PostThreadMessage(self
->thread
, WM_QUIT
, 0, 0);
671 althrd_join(self
->thread
, &i
);
673 /* Make sure capture is stopped and all pending buffers are flushed. */
674 waveInReset(self
->InHdl
);
676 // Release the wave buffers
679 waveInUnprepareHeader(self
->InHdl
, &self
->WaveBuffer
[i
], sizeof(WAVEHDR
));
680 if(i
== 0) buffer
= self
->WaveBuffer
[i
].lpData
;
681 self
->WaveBuffer
[i
].lpData
= NULL
;
685 ll_ringbuffer_free(self
->Ring
);
688 // Close the Wave device
689 waveInClose(self
->InHdl
);
693 static ALCboolean
ALCwinmmCapture_start(ALCwinmmCapture
*self
)
695 waveInStart(self
->InHdl
);
699 static void ALCwinmmCapture_stop(ALCwinmmCapture
*self
)
701 waveInStop(self
->InHdl
);
704 static ALCenum
ALCwinmmCapture_captureSamples(ALCwinmmCapture
*self
, ALCvoid
*buffer
, ALCuint samples
)
706 ll_ringbuffer_read(self
->Ring
, buffer
, samples
);
710 static ALCuint
ALCwinmmCapture_availableSamples(ALCwinmmCapture
*self
)
712 return ll_ringbuffer_read_space(self
->Ring
);
716 static inline void AppendAllDevicesList2(const al_string
*name
)
718 if(!al_string_empty(*name
))
719 AppendAllDevicesList(al_string_get_cstr(*name
));
721 static inline void AppendCaptureDeviceList2(const al_string
*name
)
723 if(!al_string_empty(*name
))
724 AppendCaptureDeviceList(al_string_get_cstr(*name
));
727 typedef struct ALCwinmmBackendFactory
{
728 DERIVE_FROM_TYPE(ALCbackendFactory
);
729 } ALCwinmmBackendFactory
;
730 #define ALCWINMMBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCwinmmBackendFactory, ALCbackendFactory) } }
732 static ALCboolean
ALCwinmmBackendFactory_init(ALCwinmmBackendFactory
*self
);
733 static void ALCwinmmBackendFactory_deinit(ALCwinmmBackendFactory
*self
);
734 static ALCboolean
ALCwinmmBackendFactory_querySupport(ALCwinmmBackendFactory
*self
, ALCbackend_Type type
);
735 static void ALCwinmmBackendFactory_probe(ALCwinmmBackendFactory
*self
, enum DevProbe type
);
736 static ALCbackend
* ALCwinmmBackendFactory_createBackend(ALCwinmmBackendFactory
*self
, ALCdevice
*device
, ALCbackend_Type type
);
738 DEFINE_ALCBACKENDFACTORY_VTABLE(ALCwinmmBackendFactory
);
741 static ALCboolean
ALCwinmmBackendFactory_init(ALCwinmmBackendFactory
* UNUSED(self
))
743 VECTOR_INIT(PlaybackDevices
);
744 VECTOR_INIT(CaptureDevices
);
749 static void ALCwinmmBackendFactory_deinit(ALCwinmmBackendFactory
* UNUSED(self
))
751 clear_devlist(&PlaybackDevices
);
752 VECTOR_DEINIT(PlaybackDevices
);
754 clear_devlist(&CaptureDevices
);
755 VECTOR_DEINIT(CaptureDevices
);
758 static ALCboolean
ALCwinmmBackendFactory_querySupport(ALCwinmmBackendFactory
* UNUSED(self
), ALCbackend_Type type
)
760 if(type
== ALCbackend_Playback
|| type
== ALCbackend_Capture
)
765 static void ALCwinmmBackendFactory_probe(ALCwinmmBackendFactory
* UNUSED(self
), enum DevProbe type
)
769 case ALL_DEVICE_PROBE
:
770 ProbePlaybackDevices();
771 VECTOR_FOR_EACH(const al_string
, PlaybackDevices
, AppendAllDevicesList2
);
774 case CAPTURE_DEVICE_PROBE
:
775 ProbeCaptureDevices();
776 VECTOR_FOR_EACH(const al_string
, CaptureDevices
, AppendCaptureDeviceList2
);
781 static ALCbackend
* ALCwinmmBackendFactory_createBackend(ALCwinmmBackendFactory
* UNUSED(self
), ALCdevice
*device
, ALCbackend_Type type
)
783 if(type
== ALCbackend_Playback
)
785 ALCwinmmPlayback
*backend
;
786 NEW_OBJ(backend
, ALCwinmmPlayback
)(device
);
787 if(!backend
) return NULL
;
788 return STATIC_CAST(ALCbackend
, backend
);
790 if(type
== ALCbackend_Capture
)
792 ALCwinmmCapture
*backend
;
793 NEW_OBJ(backend
, ALCwinmmCapture
)(device
);
794 if(!backend
) return NULL
;
795 return STATIC_CAST(ALCbackend
, backend
);
801 ALCbackendFactory
*ALCwinmmBackendFactory_getFactory(void)
803 static ALCwinmmBackendFactory factory
= ALCWINMMBACKENDFACTORY_INITIALIZER
;
804 return STATIC_CAST(ALCbackendFactory
, &factory
);