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
, alstr_reset
);
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 alstr_copy_cstr(&dname
, DEVNAME_HEAD
);
75 alstr_append_wcstr(&dname
, WaveCaps
.szPname
);
79 snprintf(str
, sizeof(str
), " #%d", count
+1);
80 alstr_append_cstr(&dname
, str
);
84 #define MATCH_ENTRY(i) (alstr_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", alstr_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 alstr_copy_cstr(&dname
, DEVNAME_HEAD
);
118 alstr_append_wcstr(&dname
, WaveCaps
.szPname
);
122 snprintf(str
, sizeof(str
), " #%d", count
+1);
123 alstr_append_cstr(&dname
, str
);
127 #define MATCH_ENTRY(i) (alstr_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", alstr_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) (!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 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
, device
->AmbiOrder
);
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) (!alstr_empty(*(iter)) && (!name || alstr_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
)
567 return ALC_INVALID_ENUM
;
570 switch(device
->FmtType
)
581 return ALC_INVALID_ENUM
;
584 memset(&self
->Format
, 0, sizeof(WAVEFORMATEX
));
585 self
->Format
.wFormatTag
= ((device
->FmtType
== DevFmtFloat
) ?
586 WAVE_FORMAT_IEEE_FLOAT
: WAVE_FORMAT_PCM
);
587 self
->Format
.nChannels
= ChannelsFromDevFmt(device
->FmtChans
, device
->AmbiOrder
);
588 self
->Format
.wBitsPerSample
= BytesFromDevFmt(device
->FmtType
) * 8;
589 self
->Format
.nBlockAlign
= self
->Format
.wBitsPerSample
*
590 self
->Format
.nChannels
/ 8;
591 self
->Format
.nSamplesPerSec
= device
->Frequency
;
592 self
->Format
.nAvgBytesPerSec
= self
->Format
.nSamplesPerSec
*
593 self
->Format
.nBlockAlign
;
594 self
->Format
.cbSize
= 0;
596 if((res
=waveInOpen(&self
->InHdl
, DeviceID
, &self
->Format
, (DWORD_PTR
)&ALCwinmmCapture_waveInProc
, (DWORD_PTR
)self
, CALLBACK_FUNCTION
)) != MMSYSERR_NOERROR
)
598 ERR("waveInOpen failed: %u\n", res
);
602 // Allocate circular memory buffer for the captured audio
603 CapturedDataSize
= device
->UpdateSize
*device
->NumUpdates
;
605 // Make sure circular buffer is at least 100ms in size
606 if(CapturedDataSize
< (self
->Format
.nSamplesPerSec
/ 10))
607 CapturedDataSize
= self
->Format
.nSamplesPerSec
/ 10;
609 self
->Ring
= ll_ringbuffer_create(CapturedDataSize
+1, self
->Format
.nBlockAlign
);
610 if(!self
->Ring
) goto failure
;
612 InitRef(&self
->WaveBuffersCommitted
, 0);
614 // Create 4 Buffers of 50ms each
615 BufferSize
= self
->Format
.nAvgBytesPerSec
/ 20;
616 BufferSize
-= (BufferSize
% self
->Format
.nBlockAlign
);
618 BufferData
= calloc(4, BufferSize
);
619 if(!BufferData
) goto failure
;
623 memset(&self
->WaveBuffer
[i
], 0, sizeof(WAVEHDR
));
624 self
->WaveBuffer
[i
].dwBufferLength
= BufferSize
;
625 self
->WaveBuffer
[i
].lpData
= ((i
==0) ? (CHAR
*)BufferData
:
626 (self
->WaveBuffer
[i
-1].lpData
+
627 self
->WaveBuffer
[i
-1].dwBufferLength
));
628 self
->WaveBuffer
[i
].dwFlags
= 0;
629 self
->WaveBuffer
[i
].dwLoops
= 0;
630 waveInPrepareHeader(self
->InHdl
, &self
->WaveBuffer
[i
], sizeof(WAVEHDR
));
631 waveInAddBuffer(self
->InHdl
, &self
->WaveBuffer
[i
], sizeof(WAVEHDR
));
632 IncrementRef(&self
->WaveBuffersCommitted
);
635 self
->killNow
= AL_FALSE
;
636 if(althrd_create(&self
->thread
, ALCwinmmCapture_captureProc
, self
) != althrd_success
)
639 alstr_copy(&device
->DeviceName
, VECTOR_ELEM(CaptureDevices
, DeviceID
));
646 waveInUnprepareHeader(self
->InHdl
, &self
->WaveBuffer
[i
], sizeof(WAVEHDR
));
650 ll_ringbuffer_free(self
->Ring
);
654 waveInClose(self
->InHdl
);
657 return ALC_INVALID_VALUE
;
660 static void ALCwinmmCapture_close(ALCwinmmCapture
*self
)
665 /* Tell the processing thread to quit and wait for it to do so. */
666 self
->killNow
= AL_TRUE
;
667 PostThreadMessage(self
->thread
, WM_QUIT
, 0, 0);
669 althrd_join(self
->thread
, &i
);
671 /* Make sure capture is stopped and all pending buffers are flushed. */
672 waveInReset(self
->InHdl
);
674 // Release the wave buffers
677 waveInUnprepareHeader(self
->InHdl
, &self
->WaveBuffer
[i
], sizeof(WAVEHDR
));
678 if(i
== 0) buffer
= self
->WaveBuffer
[i
].lpData
;
679 self
->WaveBuffer
[i
].lpData
= NULL
;
683 ll_ringbuffer_free(self
->Ring
);
686 // Close the Wave device
687 waveInClose(self
->InHdl
);
691 static ALCboolean
ALCwinmmCapture_start(ALCwinmmCapture
*self
)
693 waveInStart(self
->InHdl
);
697 static void ALCwinmmCapture_stop(ALCwinmmCapture
*self
)
699 waveInStop(self
->InHdl
);
702 static ALCenum
ALCwinmmCapture_captureSamples(ALCwinmmCapture
*self
, ALCvoid
*buffer
, ALCuint samples
)
704 ll_ringbuffer_read(self
->Ring
, buffer
, samples
);
708 static ALCuint
ALCwinmmCapture_availableSamples(ALCwinmmCapture
*self
)
710 return ll_ringbuffer_read_space(self
->Ring
);
714 static inline void AppendAllDevicesList2(const al_string
*name
)
716 if(!alstr_empty(*name
))
717 AppendAllDevicesList(alstr_get_cstr(*name
));
719 static inline void AppendCaptureDeviceList2(const al_string
*name
)
721 if(!alstr_empty(*name
))
722 AppendCaptureDeviceList(alstr_get_cstr(*name
));
725 typedef struct ALCwinmmBackendFactory
{
726 DERIVE_FROM_TYPE(ALCbackendFactory
);
727 } ALCwinmmBackendFactory
;
728 #define ALCWINMMBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCwinmmBackendFactory, ALCbackendFactory) } }
730 static ALCboolean
ALCwinmmBackendFactory_init(ALCwinmmBackendFactory
*self
);
731 static void ALCwinmmBackendFactory_deinit(ALCwinmmBackendFactory
*self
);
732 static ALCboolean
ALCwinmmBackendFactory_querySupport(ALCwinmmBackendFactory
*self
, ALCbackend_Type type
);
733 static void ALCwinmmBackendFactory_probe(ALCwinmmBackendFactory
*self
, enum DevProbe type
);
734 static ALCbackend
* ALCwinmmBackendFactory_createBackend(ALCwinmmBackendFactory
*self
, ALCdevice
*device
, ALCbackend_Type type
);
736 DEFINE_ALCBACKENDFACTORY_VTABLE(ALCwinmmBackendFactory
);
739 static ALCboolean
ALCwinmmBackendFactory_init(ALCwinmmBackendFactory
* UNUSED(self
))
741 VECTOR_INIT(PlaybackDevices
);
742 VECTOR_INIT(CaptureDevices
);
747 static void ALCwinmmBackendFactory_deinit(ALCwinmmBackendFactory
* UNUSED(self
))
749 clear_devlist(&PlaybackDevices
);
750 VECTOR_DEINIT(PlaybackDevices
);
752 clear_devlist(&CaptureDevices
);
753 VECTOR_DEINIT(CaptureDevices
);
756 static ALCboolean
ALCwinmmBackendFactory_querySupport(ALCwinmmBackendFactory
* UNUSED(self
), ALCbackend_Type type
)
758 if(type
== ALCbackend_Playback
|| type
== ALCbackend_Capture
)
763 static void ALCwinmmBackendFactory_probe(ALCwinmmBackendFactory
* UNUSED(self
), enum DevProbe type
)
767 case ALL_DEVICE_PROBE
:
768 ProbePlaybackDevices();
769 VECTOR_FOR_EACH(const al_string
, PlaybackDevices
, AppendAllDevicesList2
);
772 case CAPTURE_DEVICE_PROBE
:
773 ProbeCaptureDevices();
774 VECTOR_FOR_EACH(const al_string
, CaptureDevices
, AppendCaptureDeviceList2
);
779 static ALCbackend
* ALCwinmmBackendFactory_createBackend(ALCwinmmBackendFactory
* UNUSED(self
), ALCdevice
*device
, ALCbackend_Type type
)
781 if(type
== ALCbackend_Playback
)
783 ALCwinmmPlayback
*backend
;
784 NEW_OBJ(backend
, ALCwinmmPlayback
)(device
);
785 if(!backend
) return NULL
;
786 return STATIC_CAST(ALCbackend
, backend
);
788 if(type
== ALCbackend_Capture
)
790 ALCwinmmCapture
*backend
;
791 NEW_OBJ(backend
, ALCwinmmCapture
)(device
);
792 if(!backend
) return NULL
;
793 return STATIC_CAST(ALCbackend
, backend
);
799 ALCbackendFactory
*ALCwinmmBackendFactory_getFactory(void)
801 static ALCwinmmBackendFactory factory
= ALCWINMMBACKENDFACTORY_INITIALIZER
;
802 return STATIC_CAST(ALCbackendFactory
, &factory
);