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
23 #include <sys/ioctl.h>
24 #include <sys/types.h>
41 #include "backends/base.h"
43 #include <sys/soundcard.h>
46 * The OSS documentation talks about SOUND_MIXER_READ, but the header
47 * only contains MIXER_READ. Play safe. Same for WRITE.
49 #ifndef SOUND_MIXER_READ
50 #define SOUND_MIXER_READ MIXER_READ
52 #ifndef SOUND_MIXER_WRITE
53 #define SOUND_MIXER_WRITE MIXER_WRITE
56 #if defined(SOUND_VERSION) && (SOUND_VERSION < 0x040000)
57 #define ALC_OSS_COMPAT
59 #ifndef SNDCTL_AUDIOINFO
60 #define ALC_OSS_COMPAT
64 * FreeBSD strongly discourages the use of specific devices,
65 * such as those returned in oss_audioinfo.devnode
68 #define ALC_OSS_DEVNODE_TRUC
72 const ALCchar
*handle
;
74 struct oss_device
*next
;
77 static struct oss_device oss_playback
= {
83 static struct oss_device oss_capture
= {
91 #define DSP_CAP_OUTPUT 0x00020000
92 #define DSP_CAP_INPUT 0x00010000
93 static void ALCossListPopulate(struct oss_device
*UNUSED(devlist
), int UNUSED(type_flag
))
100 static size_t strnlen(const char *str
, size_t maxlen
)
102 const char *end
= memchr(str
, 0, maxlen
);
103 if(!end
) return maxlen
;
108 static void ALCossListAppend(struct oss_device
*list
, const char *handle
, size_t hlen
, const char *path
, size_t plen
)
110 struct oss_device
*next
;
111 struct oss_device
*last
;
114 /* skip the first item "OSS Default" */
117 #ifdef ALC_OSS_DEVNODE_TRUC
118 for(i
= 0;i
< plen
;i
++)
122 if(strncmp(path
+ i
, handle
+ hlen
+ i
- plen
, plen
- i
) == 0)
123 hlen
= hlen
+ i
- plen
;
130 if(handle
[0] == '\0')
138 if(strncmp(next
->path
, path
, plen
) == 0)
144 next
= (struct oss_device
*)malloc(sizeof(struct oss_device
) + hlen
+ plen
+ 2);
145 next
->handle
= (char*)(next
+ 1);
146 next
->path
= next
->handle
+ hlen
+ 1;
150 strncpy((char*)next
->handle
, handle
, hlen
);
151 ((char*)next
->handle
)[hlen
] = '\0';
152 strncpy((char*)next
->path
, path
, plen
);
153 ((char*)next
->path
)[plen
] = '\0';
155 TRACE("Got device \"%s\", \"%s\"\n", next
->handle
, next
->path
);
158 static void ALCossListPopulate(struct oss_device
*devlist
, int type_flag
)
160 struct oss_sysinfo si
;
161 struct oss_audioinfo ai
;
164 if((fd
=open("/dev/mixer", O_RDONLY
)) < 0)
166 ERR("Could not open /dev/mixer\n");
169 if(ioctl(fd
, SNDCTL_SYSINFO
, &si
) == -1)
171 ERR("SNDCTL_SYSINFO failed: %s\n", strerror(errno
));
174 for(i
= 0;i
< si
.numaudios
;i
++)
180 if(ioctl(fd
, SNDCTL_AUDIOINFO
, &ai
) == -1)
182 ERR("SNDCTL_AUDIOINFO (%d) failed: %s\n", i
, strerror(errno
));
185 if(ai
.devnode
[0] == '\0')
188 if(ai
.handle
[0] != '\0')
190 len
= strnlen(ai
.handle
, sizeof(ai
.handle
));
195 len
= strnlen(ai
.name
, sizeof(ai
.name
));
198 if((ai
.caps
&type_flag
))
199 ALCossListAppend(devlist
, handle
, len
, ai
.devnode
,
200 strnlen(ai
.devnode
, sizeof(ai
.devnode
)));
209 static void ALCossListFree(struct oss_device
*list
)
211 struct oss_device
*cur
;
215 /* skip the first item "OSS Default" */
221 struct oss_device
*next
= cur
->next
;
227 static int log2i(ALCuint x
)
238 typedef struct ALCplaybackOSS
{
239 DERIVE_FROM_TYPE(ALCbackend
);
246 ATOMIC(ALenum
) killNow
;
250 static int ALCplaybackOSS_mixerProc(void *ptr
);
252 static void ALCplaybackOSS_Construct(ALCplaybackOSS
*self
, ALCdevice
*device
);
253 static DECLARE_FORWARD(ALCplaybackOSS
, ALCbackend
, void, Destruct
)
254 static ALCenum
ALCplaybackOSS_open(ALCplaybackOSS
*self
, const ALCchar
*name
);
255 static void ALCplaybackOSS_close(ALCplaybackOSS
*self
);
256 static ALCboolean
ALCplaybackOSS_reset(ALCplaybackOSS
*self
);
257 static ALCboolean
ALCplaybackOSS_start(ALCplaybackOSS
*self
);
258 static void ALCplaybackOSS_stop(ALCplaybackOSS
*self
);
259 static DECLARE_FORWARD2(ALCplaybackOSS
, ALCbackend
, ALCenum
, captureSamples
, ALCvoid
*, ALCuint
)
260 static DECLARE_FORWARD(ALCplaybackOSS
, ALCbackend
, ALCuint
, availableSamples
)
261 static DECLARE_FORWARD(ALCplaybackOSS
, ALCbackend
, ClockLatency
, getClockLatency
)
262 static DECLARE_FORWARD(ALCplaybackOSS
, ALCbackend
, void, lock
)
263 static DECLARE_FORWARD(ALCplaybackOSS
, ALCbackend
, void, unlock
)
264 DECLARE_DEFAULT_ALLOCATORS(ALCplaybackOSS
)
265 DEFINE_ALCBACKEND_VTABLE(ALCplaybackOSS
);
268 static int ALCplaybackOSS_mixerProc(void *ptr
)
270 ALCplaybackOSS
*self
= (ALCplaybackOSS
*)ptr
;
271 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
272 struct timeval timeout
;
281 althrd_setname(althrd_current(), MIXER_THREAD_NAME
);
283 frame_size
= FrameSizeFromDevFmt(device
->FmtChans
, device
->FmtType
, device
->AmbiOrder
);
285 ALCplaybackOSS_lock(self
);
286 while(!ATOMIC_LOAD_SEQ(&self
->killNow
) && device
->Connected
)
289 FD_SET(self
->fd
, &wfds
);
293 ALCplaybackOSS_unlock(self
);
294 sret
= select(self
->fd
+1, NULL
, &wfds
, NULL
, &timeout
);
295 ALCplaybackOSS_lock(self
);
300 ERR("select failed: %s\n", strerror(errno
));
301 aluHandleDisconnect(device
);
306 WARN("select timeout\n");
310 write_ptr
= self
->mix_data
;
311 to_write
= self
->data_size
;
312 aluMixData(device
, write_ptr
, to_write
/frame_size
);
313 while(to_write
> 0 && !ATOMIC_LOAD_SEQ(&self
->killNow
))
315 wrote
= write(self
->fd
, write_ptr
, to_write
);
318 if(errno
== EAGAIN
|| errno
== EWOULDBLOCK
|| errno
== EINTR
)
320 ERR("write failed: %s\n", strerror(errno
));
321 aluHandleDisconnect(device
);
329 ALCplaybackOSS_unlock(self
);
335 static void ALCplaybackOSS_Construct(ALCplaybackOSS
*self
, ALCdevice
*device
)
337 ALCbackend_Construct(STATIC_CAST(ALCbackend
, self
), device
);
338 SET_VTABLE2(ALCplaybackOSS
, ALCbackend
, self
);
340 ATOMIC_INIT(&self
->killNow
, AL_FALSE
);
343 static ALCenum
ALCplaybackOSS_open(ALCplaybackOSS
*self
, const ALCchar
*name
)
345 struct oss_device
*dev
= &oss_playback
;
346 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
348 if(!name
|| strcmp(name
, dev
->handle
) == 0)
354 ALCossListPopulate(&oss_playback
, DSP_CAP_OUTPUT
);
359 if (strcmp(dev
->handle
, name
) == 0)
365 WARN("Could not find \"%s\" in device list\n", name
);
366 return ALC_INVALID_VALUE
;
370 self
->fd
= open(dev
->path
, O_WRONLY
);
373 ERR("Could not open %s: %s\n", dev
->path
, strerror(errno
));
374 return ALC_INVALID_VALUE
;
377 alstr_copy_cstr(&device
->DeviceName
, name
);
382 static void ALCplaybackOSS_close(ALCplaybackOSS
*self
)
388 static ALCboolean
ALCplaybackOSS_reset(ALCplaybackOSS
*self
)
390 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
391 int numFragmentsLogSize
;
392 int log2FragmentSize
;
393 unsigned int periods
;
401 switch(device
->FmtType
)
413 device
->FmtType
= DevFmtShort
;
416 ossFormat
= AFMT_S16_NE
;
420 periods
= device
->NumUpdates
;
421 numChannels
= ChannelsFromDevFmt(device
->FmtChans
, device
->AmbiOrder
);
422 ossSpeed
= device
->Frequency
;
423 frameSize
= numChannels
* BytesFromDevFmt(device
->FmtType
);
424 /* According to the OSS spec, 16 bytes (log2(16)) is the minimum. */
425 log2FragmentSize
= maxi(log2i(device
->UpdateSize
*frameSize
), 4);
426 numFragmentsLogSize
= (periods
<< 16) | log2FragmentSize
;
428 #define CHECKERR(func) if((func) < 0) { \
432 /* Don't fail if SETFRAGMENT fails. We can handle just about anything
433 * that's reported back via GETOSPACE */
434 ioctl(self
->fd
, SNDCTL_DSP_SETFRAGMENT
, &numFragmentsLogSize
);
435 CHECKERR(ioctl(self
->fd
, SNDCTL_DSP_SETFMT
, &ossFormat
));
436 CHECKERR(ioctl(self
->fd
, SNDCTL_DSP_CHANNELS
, &numChannels
));
437 CHECKERR(ioctl(self
->fd
, SNDCTL_DSP_SPEED
, &ossSpeed
));
438 CHECKERR(ioctl(self
->fd
, SNDCTL_DSP_GETOSPACE
, &info
));
442 ERR("%s failed: %s\n", err
, strerror(errno
));
447 if((int)ChannelsFromDevFmt(device
->FmtChans
, device
->AmbiOrder
) != numChannels
)
449 ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device
->FmtChans
), numChannels
);
453 if(!((ossFormat
== AFMT_S8
&& device
->FmtType
== DevFmtByte
) ||
454 (ossFormat
== AFMT_U8
&& device
->FmtType
== DevFmtUByte
) ||
455 (ossFormat
== AFMT_S16_NE
&& device
->FmtType
== DevFmtShort
)))
457 ERR("Failed to set %s samples, got OSS format %#x\n", DevFmtTypeString(device
->FmtType
), ossFormat
);
461 device
->Frequency
= ossSpeed
;
462 device
->UpdateSize
= info
.fragsize
/ frameSize
;
463 device
->NumUpdates
= info
.fragments
;
465 SetDefaultChannelOrder(device
);
470 static ALCboolean
ALCplaybackOSS_start(ALCplaybackOSS
*self
)
472 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
474 self
->data_size
= device
->UpdateSize
* FrameSizeFromDevFmt(
475 device
->FmtChans
, device
->FmtType
, device
->AmbiOrder
477 self
->mix_data
= calloc(1, self
->data_size
);
479 ATOMIC_STORE_SEQ(&self
->killNow
, AL_FALSE
);
480 if(althrd_create(&self
->thread
, ALCplaybackOSS_mixerProc
, self
) != althrd_success
)
482 free(self
->mix_data
);
483 self
->mix_data
= NULL
;
490 static void ALCplaybackOSS_stop(ALCplaybackOSS
*self
)
494 if(ATOMIC_EXCHANGE_SEQ(&self
->killNow
, AL_TRUE
))
496 althrd_join(self
->thread
, &res
);
498 if(ioctl(self
->fd
, SNDCTL_DSP_RESET
) != 0)
499 ERR("Error resetting device: %s\n", strerror(errno
));
501 free(self
->mix_data
);
502 self
->mix_data
= NULL
;
506 typedef struct ALCcaptureOSS
{
507 DERIVE_FROM_TYPE(ALCbackend
);
511 ll_ringbuffer_t
*ring
;
513 ATOMIC(ALenum
) killNow
;
517 static int ALCcaptureOSS_recordProc(void *ptr
);
519 static void ALCcaptureOSS_Construct(ALCcaptureOSS
*self
, ALCdevice
*device
);
520 static DECLARE_FORWARD(ALCcaptureOSS
, ALCbackend
, void, Destruct
)
521 static ALCenum
ALCcaptureOSS_open(ALCcaptureOSS
*self
, const ALCchar
*name
);
522 static void ALCcaptureOSS_close(ALCcaptureOSS
*self
);
523 static DECLARE_FORWARD(ALCcaptureOSS
, ALCbackend
, ALCboolean
, reset
)
524 static ALCboolean
ALCcaptureOSS_start(ALCcaptureOSS
*self
);
525 static void ALCcaptureOSS_stop(ALCcaptureOSS
*self
);
526 static ALCenum
ALCcaptureOSS_captureSamples(ALCcaptureOSS
*self
, ALCvoid
*buffer
, ALCuint samples
);
527 static ALCuint
ALCcaptureOSS_availableSamples(ALCcaptureOSS
*self
);
528 static DECLARE_FORWARD(ALCcaptureOSS
, ALCbackend
, ClockLatency
, getClockLatency
)
529 static DECLARE_FORWARD(ALCcaptureOSS
, ALCbackend
, void, lock
)
530 static DECLARE_FORWARD(ALCcaptureOSS
, ALCbackend
, void, unlock
)
531 DECLARE_DEFAULT_ALLOCATORS(ALCcaptureOSS
)
532 DEFINE_ALCBACKEND_VTABLE(ALCcaptureOSS
);
535 static int ALCcaptureOSS_recordProc(void *ptr
)
537 ALCcaptureOSS
*self
= (ALCcaptureOSS
*)ptr
;
538 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
539 struct timeval timeout
;
546 althrd_setname(althrd_current(), RECORD_THREAD_NAME
);
548 frame_size
= FrameSizeFromDevFmt(device
->FmtChans
, device
->FmtType
, device
->AmbiOrder
);
550 while(!ATOMIC_LOAD_SEQ(&self
->killNow
))
552 ll_ringbuffer_data_t vec
[2];
555 FD_SET(self
->fd
, &rfds
);
559 sret
= select(self
->fd
+1, &rfds
, NULL
, NULL
, &timeout
);
564 ERR("select failed: %s\n", strerror(errno
));
565 aluHandleDisconnect(device
);
570 WARN("select timeout\n");
574 ll_ringbuffer_get_write_vector(self
->ring
, vec
);
577 amt
= read(self
->fd
, vec
[0].buf
, vec
[0].len
*frame_size
);
580 ERR("read failed: %s\n", strerror(errno
));
581 ALCcaptureOSS_lock(self
);
582 aluHandleDisconnect(device
);
583 ALCcaptureOSS_unlock(self
);
586 ll_ringbuffer_write_advance(self
->ring
, amt
/frame_size
);
594 static void ALCcaptureOSS_Construct(ALCcaptureOSS
*self
, ALCdevice
*device
)
596 ALCbackend_Construct(STATIC_CAST(ALCbackend
, self
), device
);
597 SET_VTABLE2(ALCcaptureOSS
, ALCbackend
, self
);
599 ATOMIC_INIT(&self
->killNow
, AL_FALSE
);
602 static ALCenum
ALCcaptureOSS_open(ALCcaptureOSS
*self
, const ALCchar
*name
)
604 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
605 struct oss_device
*dev
= &oss_capture
;
606 int numFragmentsLogSize
;
607 int log2FragmentSize
;
608 unsigned int periods
;
616 if(!name
|| strcmp(name
, dev
->handle
) == 0)
622 ALCossListPopulate(&oss_capture
, DSP_CAP_INPUT
);
627 if (strcmp(dev
->handle
, name
) == 0)
633 WARN("Could not find \"%s\" in device list\n", name
);
634 return ALC_INVALID_VALUE
;
638 self
->fd
= open(dev
->path
, O_RDONLY
);
641 ERR("Could not open %s: %s\n", dev
->path
, strerror(errno
));
642 return ALC_INVALID_VALUE
;
645 switch(device
->FmtType
)
654 ossFormat
= AFMT_S16_NE
;
660 ERR("%s capture samples not supported\n", DevFmtTypeString(device
->FmtType
));
661 return ALC_INVALID_VALUE
;
665 numChannels
= ChannelsFromDevFmt(device
->FmtChans
, device
->AmbiOrder
);
666 frameSize
= numChannels
* BytesFromDevFmt(device
->FmtType
);
667 ossSpeed
= device
->Frequency
;
668 log2FragmentSize
= log2i(device
->UpdateSize
* device
->NumUpdates
*
669 frameSize
/ periods
);
671 /* according to the OSS spec, 16 bytes are the minimum */
672 if (log2FragmentSize
< 4)
673 log2FragmentSize
= 4;
674 numFragmentsLogSize
= (periods
<< 16) | log2FragmentSize
;
676 #define CHECKERR(func) if((func) < 0) { \
680 CHECKERR(ioctl(self
->fd
, SNDCTL_DSP_SETFRAGMENT
, &numFragmentsLogSize
));
681 CHECKERR(ioctl(self
->fd
, SNDCTL_DSP_SETFMT
, &ossFormat
));
682 CHECKERR(ioctl(self
->fd
, SNDCTL_DSP_CHANNELS
, &numChannels
));
683 CHECKERR(ioctl(self
->fd
, SNDCTL_DSP_SPEED
, &ossSpeed
));
684 CHECKERR(ioctl(self
->fd
, SNDCTL_DSP_GETISPACE
, &info
));
688 ERR("%s failed: %s\n", err
, strerror(errno
));
691 return ALC_INVALID_VALUE
;
695 if((int)ChannelsFromDevFmt(device
->FmtChans
, device
->AmbiOrder
) != numChannels
)
697 ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device
->FmtChans
), numChannels
);
700 return ALC_INVALID_VALUE
;
703 if(!((ossFormat
== AFMT_S8
&& device
->FmtType
== DevFmtByte
) ||
704 (ossFormat
== AFMT_U8
&& device
->FmtType
== DevFmtUByte
) ||
705 (ossFormat
== AFMT_S16_NE
&& device
->FmtType
== DevFmtShort
)))
707 ERR("Failed to set %s samples, got OSS format %#x\n", DevFmtTypeString(device
->FmtType
), ossFormat
);
710 return ALC_INVALID_VALUE
;
713 self
->ring
= ll_ringbuffer_create(device
->UpdateSize
*device
->NumUpdates
+ 1, frameSize
);
716 ERR("Ring buffer create failed\n");
719 return ALC_OUT_OF_MEMORY
;
722 alstr_copy_cstr(&device
->DeviceName
, name
);
727 static void ALCcaptureOSS_close(ALCcaptureOSS
*self
)
732 ll_ringbuffer_free(self
->ring
);
736 static ALCboolean
ALCcaptureOSS_start(ALCcaptureOSS
*self
)
738 ATOMIC_STORE_SEQ(&self
->killNow
, AL_FALSE
);
739 if(althrd_create(&self
->thread
, ALCcaptureOSS_recordProc
, self
) != althrd_success
)
744 static void ALCcaptureOSS_stop(ALCcaptureOSS
*self
)
748 if(ATOMIC_EXCHANGE_SEQ(&self
->killNow
, AL_TRUE
))
751 althrd_join(self
->thread
, &res
);
753 if(ioctl(self
->fd
, SNDCTL_DSP_RESET
) != 0)
754 ERR("Error resetting device: %s\n", strerror(errno
));
757 static ALCenum
ALCcaptureOSS_captureSamples(ALCcaptureOSS
*self
, ALCvoid
*buffer
, ALCuint samples
)
759 ll_ringbuffer_read(self
->ring
, buffer
, samples
);
763 static ALCuint
ALCcaptureOSS_availableSamples(ALCcaptureOSS
*self
)
765 return ll_ringbuffer_read_space(self
->ring
);
769 typedef struct ALCossBackendFactory
{
770 DERIVE_FROM_TYPE(ALCbackendFactory
);
771 } ALCossBackendFactory
;
772 #define ALCOSSBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCossBackendFactory, ALCbackendFactory) } }
774 ALCbackendFactory
*ALCossBackendFactory_getFactory(void);
776 static ALCboolean
ALCossBackendFactory_init(ALCossBackendFactory
*self
);
777 static void ALCossBackendFactory_deinit(ALCossBackendFactory
*self
);
778 static ALCboolean
ALCossBackendFactory_querySupport(ALCossBackendFactory
*self
, ALCbackend_Type type
);
779 static void ALCossBackendFactory_probe(ALCossBackendFactory
*self
, enum DevProbe type
);
780 static ALCbackend
* ALCossBackendFactory_createBackend(ALCossBackendFactory
*self
, ALCdevice
*device
, ALCbackend_Type type
);
781 DEFINE_ALCBACKENDFACTORY_VTABLE(ALCossBackendFactory
);
784 ALCbackendFactory
*ALCossBackendFactory_getFactory(void)
786 static ALCossBackendFactory factory
= ALCOSSBACKENDFACTORY_INITIALIZER
;
787 return STATIC_CAST(ALCbackendFactory
, &factory
);
791 ALCboolean
ALCossBackendFactory_init(ALCossBackendFactory
* UNUSED(self
))
793 ConfigValueStr(NULL
, "oss", "device", &oss_playback
.path
);
794 ConfigValueStr(NULL
, "oss", "capture", &oss_capture
.path
);
799 void ALCossBackendFactory_deinit(ALCossBackendFactory
* UNUSED(self
))
801 ALCossListFree(&oss_playback
);
802 ALCossListFree(&oss_capture
);
806 ALCboolean
ALCossBackendFactory_querySupport(ALCossBackendFactory
* UNUSED(self
), ALCbackend_Type type
)
808 if(type
== ALCbackend_Playback
|| type
== ALCbackend_Capture
)
813 void ALCossBackendFactory_probe(ALCossBackendFactory
* UNUSED(self
), enum DevProbe type
)
815 struct oss_device
*cur
;
818 case ALL_DEVICE_PROBE
:
819 ALCossListFree(&oss_playback
);
820 ALCossListPopulate(&oss_playback
, DSP_CAP_OUTPUT
);
826 if(stat(cur
->path
, &buf
) == 0)
828 AppendAllDevicesList(cur
->handle
);
833 case CAPTURE_DEVICE_PROBE
:
834 ALCossListFree(&oss_capture
);
835 ALCossListPopulate(&oss_capture
, DSP_CAP_INPUT
);
841 if(stat(cur
->path
, &buf
) == 0)
843 AppendCaptureDeviceList(cur
->handle
);
850 ALCbackend
* ALCossBackendFactory_createBackend(ALCossBackendFactory
* UNUSED(self
), ALCdevice
*device
, ALCbackend_Type type
)
852 if(type
== ALCbackend_Playback
)
854 ALCplaybackOSS
*backend
;
855 NEW_OBJ(backend
, ALCplaybackOSS
)(device
);
856 if(!backend
) return NULL
;
857 return STATIC_CAST(ALCbackend
, backend
);
859 if(type
== ALCbackend_Capture
)
861 ALCcaptureOSS
*backend
;
862 NEW_OBJ(backend
, ALCcaptureOSS
)(device
);
863 if(!backend
) return NULL
;
864 return STATIC_CAST(ALCbackend
, backend
);