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
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
;
58 clear_devlist(&PlaybackDevices
);
60 numdevs
= waveOutGetNumDevs();
61 VECTOR_RESERVE(PlaybackDevices
, numdevs
);
62 for(i
= 0;i
< numdevs
;i
++)
64 WAVEOUTCAPSW WaveCaps
;
67 AL_STRING_INIT(dname
);
68 if(waveOutGetDevCapsW(i
, &WaveCaps
, sizeof(WaveCaps
)) == MMSYSERR_NOERROR
)
72 al_string_copy_wcstr(&dname
, WaveCaps
.szPname
);
76 snprintf(str
, sizeof(str
), " #%d", count
+1);
77 al_string_append_cstr(&dname
, str
);
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)
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
;
102 clear_devlist(&CaptureDevices
);
104 numdevs
= waveInGetNumDevs();
105 VECTOR_RESERVE(CaptureDevices
, numdevs
);
106 for(i
= 0;i
< numdevs
;i
++)
108 WAVEINCAPSW WaveCaps
;
111 AL_STRING_INIT(dname
);
112 if(waveInGetDevCapsW(i
, &WaveCaps
, sizeof(WaveCaps
)) == MMSYSERR_NOERROR
)
116 al_string_copy_wcstr(&dname
, WaveCaps
.szPname
);
120 snprintf(str
, sizeof(str
), " #%d", count
+1);
121 al_string_append_cstr(&dname
, str
);
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)
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];
151 volatile ALboolean 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 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);
184 self
->killNow
= AL_TRUE
;
187 static void ALCwinmmPlayback_Destruct(ALCwinmmPlayback
*self
)
190 waveOutClose(self
->OutHdl
);
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
;
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
;
221 althrd_setname(althrd_current(), MIXER_THREAD_NAME
);
223 while(GetMessage(&msg
, NULL
, 0, 0))
225 if(msg
.message
!= WOM_DONE
)
230 if(ReadRef(&self
->WaveBuffersCommitted
) == 0)
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
);
248 static ALCenum
ALCwinmmPlayback_open(ALCwinmmPlayback
*self
, const ALCchar
*deviceName
)
250 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
251 const al_string
*iter
;
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
;
266 DeviceID
= (UINT
)(iter
- VECTOR_ITER_BEGIN(PlaybackDevices
));
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;
277 self
->Format
.wFormatTag
= WAVE_FORMAT_PCM
;
278 if(device
->FmtType
== DevFmtUByte
|| device
->FmtType
== DevFmtByte
)
279 self
->Format
.wBitsPerSample
= 8;
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
;
298 ERR("waveOutOpen failed: %u\n", res
);
302 al_string_copy(&device
->DeviceName
, VECTOR_ELEM(PlaybackDevices
, DeviceID
));
307 waveOutClose(self
->OutHdl
);
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
/
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
;
333 ERR("Unhandled IEEE float sample depth: %d\n", self
->Format
.wBitsPerSample
);
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
;
345 ERR("Unhandled PCM sample depth: %d\n", self
->Format
.wBitsPerSample
);
351 ERR("Unhandled format tag: 0x%04x\n", self
->Format
.wFormatTag
);
355 if(self
->Format
.nChannels
== 2)
356 device
->FmtChans
= DevFmtStereo
;
357 else if(self
->Format
.nChannels
== 1)
358 device
->FmtChans
= DevFmtMono
;
361 ERR("Unhandled channel count: %d\n", self
->Format
.nChannels
);
364 SetDefaultWFXChannelOrder(device
);
369 static ALCboolean
ALCwinmmPlayback_start(ALCwinmmPlayback
*self
)
371 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
376 self
->killNow
= AL_FALSE
;
377 if(althrd_create(&self
->thread
, ALCwinmmPlayback_mixerProc
, self
) != althrd_success
)
380 InitRef(&self
->WaveBuffersCommitted
, 0);
383 BufferSize
= device
->UpdateSize
*device
->NumUpdates
/ 4;
384 BufferSize
*= FrameSizeFromDevFmt(device
->FmtChans
, device
->FmtType
);
386 BufferData
= calloc(4, BufferSize
);
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
);
402 static void ALCwinmmPlayback_stop(ALCwinmmPlayback
*self
)
410 // Set flag to stop processing headers
411 self
->killNow
= AL_TRUE
;
412 althrd_join(self
->thread
, &i
);
414 // Release the wave buffers
417 waveOutUnprepareHeader(self
->OutHdl
, &self
->WaveBuffer
[i
], sizeof(WAVEHDR
));
418 if(i
== 0) buffer
= self
->WaveBuffer
[i
].lpData
;
419 self
->WaveBuffer
[i
].lpData
= NULL
;
426 typedef struct ALCwinmmCapture
{
427 DERIVE_FROM_TYPE(ALCbackend
);
429 RefCount WaveBuffersCommitted
;
430 WAVEHDR WaveBuffer
[4];
438 volatile ALboolean killNow
;
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);
471 self
->killNow
= AL_TRUE
;
474 static void ALCwinmmCapture_Destruct(ALCwinmmCapture
*self
)
477 waveInClose(self
->InHdl
);
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
;
496 DecrementRef(&self
->WaveBuffersCommitted
);
497 PostThreadMessage(self
->thread
, msg
, 0, param1
);
500 static int ALCwinmmCapture_captureProc(void *arg
)
502 ALCwinmmCapture
*self
= arg
;
506 althrd_setname(althrd_current(), RECORD_THREAD_NAME
);
508 while(GetMessage(&msg
, NULL
, 0, 0))
510 if(msg
.message
!= WIM_DATA
)
512 /* Don't wait for other buffers to finish before quitting. We're
513 * closing so we don't need them. */
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
);
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_ITER_END(CaptureDevices
))
548 return ALC_INVALID_VALUE
;
551 DeviceID
= (UINT
)(iter
- VECTOR_ITER_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
= 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
;
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
));
649 DestroyRingBuffer(self
->Ring
);
653 waveInClose(self
->InHdl
);
656 return ALC_INVALID_VALUE
;
659 static void ALCwinmmCapture_close(ALCwinmmCapture
*self
)
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
676 waveInUnprepareHeader(self
->InHdl
, &self
->WaveBuffer
[i
], sizeof(WAVEHDR
));
677 if(i
== 0) buffer
= self
->WaveBuffer
[i
].lpData
;
678 self
->WaveBuffer
[i
].lpData
= NULL
;
682 DestroyRingBuffer(self
->Ring
);
685 // Close the Wave device
686 waveInClose(self
->InHdl
);
690 static ALCboolean
ALCwinmmCapture_start(ALCwinmmCapture
*self
)
692 waveInStart(self
->InHdl
);
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
);
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
);
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
)
762 static void ALCwinmmBackendFactory_probe(ALCwinmmBackendFactory
* UNUSED(self
), enum DevProbe type
)
766 case ALL_DEVICE_PROBE
:
767 ProbePlaybackDevices();
768 VECTOR_FOR_EACH(const al_string
, PlaybackDevices
, AppendAllDevicesList2
);
771 case CAPTURE_DEVICE_PROBE
:
772 ProbeCaptureDevices();
773 VECTOR_FOR_EACH(const al_string
, CaptureDevices
, AppendCaptureDeviceList2
);
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
);
808 ALCbackendFactory
*ALCwinmmBackendFactory_getFactory(void)
810 static ALCwinmmBackendFactory factory
= ALCWINMMBACKENDFACTORY_INITIALIZER
;
811 return STATIC_CAST(ALCbackendFactory
, &factory
);