Make sure OSS device files exist before adding them
[openal-soft.git] / Alc / backends / oss.c
blobf99ca0d2c8f85153bbd1af2073d88810026a7c34
1 /**
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
21 #include "config.h"
23 #include <sys/ioctl.h>
24 #include <sys/types.h>
25 #include <sys/time.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <memory.h>
32 #include <unistd.h>
33 #include <errno.h>
34 #include <math.h>
36 #include "alMain.h"
37 #include "alu.h"
38 #include "threads.h"
39 #include "compat.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
51 #endif
52 #ifndef SOUND_MIXER_WRITE
53 #define SOUND_MIXER_WRITE MIXER_WRITE
54 #endif
56 #if defined(SOUND_VERSION) && (SOUND_VERSION < 0x040000)
57 #define ALC_OSS_COMPAT
58 #endif
59 #ifndef SNDCTL_AUDIOINFO
60 #define ALC_OSS_COMPAT
61 #endif
64 * FreeBSD strongly discourages the use of specific devices,
65 * such as those returned in oss_audioinfo.devnode
67 #ifdef __FreeBSD__
68 #define ALC_OSS_DEVNODE_TRUC
69 #endif
71 struct oss_device {
72 const ALCchar *handle;
73 const char *path;
74 struct oss_device *next;
77 static struct oss_device oss_playback = {
78 "OSS Default",
79 "/dev/dsp",
80 NULL
83 static struct oss_device oss_capture = {
84 "OSS Default",
85 "/dev/dsp",
86 NULL
89 #ifdef ALC_OSS_COMPAT
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))
97 #else
99 #ifndef HAVE_STRNLEN
100 static size_t strnlen(const char *str, size_t maxlen)
102 const char *end = memchr(str, 0, maxlen);
103 if(!end) return maxlen;
104 return end - str;
106 #endif
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;
112 size_t i;
114 /* skip the first item "OSS Default" */
115 last = list;
116 next = list->next;
117 #ifdef ALC_OSS_DEVNODE_TRUC
118 for(i = 0;i < plen;i++)
120 if(path[i] == '.')
122 if(strncmp(path + i, handle + hlen + i - plen, plen - i) == 0)
123 hlen = hlen + i - plen;
124 plen = i;
127 #else
128 (void)i;
129 #endif
130 if(handle[0] == '\0')
132 handle = path;
133 hlen = plen;
136 while(next != NULL)
138 if(strncmp(next->path, path, plen) == 0)
139 return;
140 last = next;
141 next = next->next;
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;
147 next->next = NULL;
148 last->next = next;
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;
162 int fd, i;
164 if((fd=open("/dev/mixer", O_RDONLY)) < 0)
166 ERR("Could not open /dev/mixer\n");
167 return;
169 if(ioctl(fd, SNDCTL_SYSINFO, &si) == -1)
171 ERR("SNDCTL_SYSINFO failed: %s\n", strerror(errno));
172 goto done;
174 for(i = 0;i < si.numaudios;i++)
176 const char *handle;
177 size_t len;
179 ai.dev = i;
180 if(ioctl(fd, SNDCTL_AUDIOINFO, &ai) == -1)
182 ERR("SNDCTL_AUDIOINFO (%d) failed: %s\n", i, strerror(errno));
183 continue;
185 if(ai.devnode[0] == '\0')
186 continue;
188 if(ai.handle[0] != '\0')
190 len = strnlen(ai.handle, sizeof(ai.handle));
191 handle = ai.handle;
193 else
195 len = strnlen(ai.name, sizeof(ai.name));
196 handle = ai.name;
198 if((ai.caps&type_flag))
199 ALCossListAppend(devlist, handle, len, ai.devnode,
200 strnlen(ai.devnode, sizeof(ai.devnode)));
203 done:
204 close(fd);
207 #endif
209 static void ALCossListFree(struct oss_device *list)
211 struct oss_device *cur;
212 if(list == NULL)
213 return;
215 /* skip the first item "OSS Default" */
216 cur = list->next;
217 list->next = NULL;
219 while(cur != NULL)
221 struct oss_device *next = cur->next;
222 free(cur);
223 cur = next;
227 static int log2i(ALCuint x)
229 int y = 0;
230 while (x > 1)
232 x >>= 1;
233 y++;
235 return y;
238 typedef struct ALCplaybackOSS {
239 DERIVE_FROM_TYPE(ALCbackend);
241 int fd;
243 ALubyte *mix_data;
244 int data_size;
246 ATOMIC(ALenum) killNow;
247 althrd_t thread;
248 } ALCplaybackOSS;
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;
273 ALubyte *write_ptr;
274 ALint frame_size;
275 ALint to_write;
276 ssize_t wrote;
277 fd_set wfds;
278 int sret;
280 SetRTPriority();
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)
288 FD_ZERO(&wfds);
289 FD_SET(self->fd, &wfds);
290 timeout.tv_sec = 1;
291 timeout.tv_usec = 0;
293 ALCplaybackOSS_unlock(self);
294 sret = select(self->fd+1, NULL, &wfds, NULL, &timeout);
295 ALCplaybackOSS_lock(self);
296 if(sret < 0)
298 if(errno == EINTR)
299 continue;
300 ERR("select failed: %s\n", strerror(errno));
301 aluHandleDisconnect(device);
302 break;
304 else if(sret == 0)
306 WARN("select timeout\n");
307 continue;
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);
316 if(wrote < 0)
318 if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
319 continue;
320 ERR("write failed: %s\n", strerror(errno));
321 aluHandleDisconnect(device);
322 break;
325 to_write -= wrote;
326 write_ptr += wrote;
329 ALCplaybackOSS_unlock(self);
331 return 0;
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)
349 name = dev->handle;
350 else
352 if(!dev->next)
354 ALCossListPopulate(&oss_playback, DSP_CAP_OUTPUT);
355 dev = &oss_playback;
357 while(dev != NULL)
359 if (strcmp(dev->handle, name) == 0)
360 break;
361 dev = dev->next;
363 if(dev == NULL)
365 WARN("Could not find \"%s\" in device list\n", name);
366 return ALC_INVALID_VALUE;
370 self->fd = open(dev->path, O_WRONLY);
371 if(self->fd == -1)
373 ERR("Could not open %s: %s\n", dev->path, strerror(errno));
374 return ALC_INVALID_VALUE;
377 alstr_copy_cstr(&device->DeviceName, name);
379 return ALC_NO_ERROR;
382 static void ALCplaybackOSS_close(ALCplaybackOSS *self)
384 close(self->fd);
385 self->fd = -1;
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;
394 audio_buf_info info;
395 ALuint frameSize;
396 int numChannels;
397 int ossFormat;
398 int ossSpeed;
399 char *err;
401 switch(device->FmtType)
403 case DevFmtByte:
404 ossFormat = AFMT_S8;
405 break;
406 case DevFmtUByte:
407 ossFormat = AFMT_U8;
408 break;
409 case DevFmtUShort:
410 case DevFmtInt:
411 case DevFmtUInt:
412 case DevFmtFloat:
413 device->FmtType = DevFmtShort;
414 /* fall-through */
415 case DevFmtShort:
416 ossFormat = AFMT_S16_NE;
417 break;
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) { \
429 err = #func; \
430 goto err; \
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));
439 if(0)
441 err:
442 ERR("%s failed: %s\n", err, strerror(errno));
443 return ALC_FALSE;
445 #undef CHECKERR
447 if((int)ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder) != numChannels)
449 ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device->FmtChans), numChannels);
450 return ALC_FALSE;
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);
458 return ALC_FALSE;
461 device->Frequency = ossSpeed;
462 device->UpdateSize = info.fragsize / frameSize;
463 device->NumUpdates = info.fragments;
465 SetDefaultChannelOrder(device);
467 return ALC_TRUE;
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;
484 return ALC_FALSE;
487 return ALC_TRUE;
490 static void ALCplaybackOSS_stop(ALCplaybackOSS *self)
492 int res;
494 if(ATOMIC_EXCHANGE_SEQ(&self->killNow, AL_TRUE))
495 return;
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);
509 int fd;
511 ll_ringbuffer_t *ring;
513 ATOMIC(ALenum) killNow;
514 althrd_t thread;
515 } ALCcaptureOSS;
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;
540 int frame_size;
541 fd_set rfds;
542 ssize_t amt;
543 int sret;
545 SetRTPriority();
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];
554 FD_ZERO(&rfds);
555 FD_SET(self->fd, &rfds);
556 timeout.tv_sec = 1;
557 timeout.tv_usec = 0;
559 sret = select(self->fd+1, &rfds, NULL, NULL, &timeout);
560 if(sret < 0)
562 if(errno == EINTR)
563 continue;
564 ERR("select failed: %s\n", strerror(errno));
565 aluHandleDisconnect(device);
566 break;
568 else if(sret == 0)
570 WARN("select timeout\n");
571 continue;
574 ll_ringbuffer_get_write_vector(self->ring, vec);
575 if(vec[0].len > 0)
577 amt = read(self->fd, vec[0].buf, vec[0].len*frame_size);
578 if(amt < 0)
580 ERR("read failed: %s\n", strerror(errno));
581 ALCcaptureOSS_lock(self);
582 aluHandleDisconnect(device);
583 ALCcaptureOSS_unlock(self);
584 break;
586 ll_ringbuffer_write_advance(self->ring, amt/frame_size);
590 return 0;
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;
609 audio_buf_info info;
610 ALuint frameSize;
611 int numChannels;
612 int ossFormat;
613 int ossSpeed;
614 char *err;
616 if(!name || strcmp(name, dev->handle) == 0)
617 name = dev->handle;
618 else
620 if(!dev->next)
622 ALCossListPopulate(&oss_capture, DSP_CAP_INPUT);
623 dev = &oss_capture;
625 while(dev != NULL)
627 if (strcmp(dev->handle, name) == 0)
628 break;
629 dev = dev->next;
631 if(dev == NULL)
633 WARN("Could not find \"%s\" in device list\n", name);
634 return ALC_INVALID_VALUE;
638 self->fd = open(dev->path, O_RDONLY);
639 if(self->fd == -1)
641 ERR("Could not open %s: %s\n", dev->path, strerror(errno));
642 return ALC_INVALID_VALUE;
645 switch(device->FmtType)
647 case DevFmtByte:
648 ossFormat = AFMT_S8;
649 break;
650 case DevFmtUByte:
651 ossFormat = AFMT_U8;
652 break;
653 case DevFmtShort:
654 ossFormat = AFMT_S16_NE;
655 break;
656 case DevFmtUShort:
657 case DevFmtInt:
658 case DevFmtUInt:
659 case DevFmtFloat:
660 ERR("%s capture samples not supported\n", DevFmtTypeString(device->FmtType));
661 return ALC_INVALID_VALUE;
664 periods = 4;
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) { \
677 err = #func; \
678 goto err; \
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));
685 if(0)
687 err:
688 ERR("%s failed: %s\n", err, strerror(errno));
689 close(self->fd);
690 self->fd = -1;
691 return ALC_INVALID_VALUE;
693 #undef CHECKERR
695 if((int)ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder) != numChannels)
697 ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device->FmtChans), numChannels);
698 close(self->fd);
699 self->fd = -1;
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);
708 close(self->fd);
709 self->fd = -1;
710 return ALC_INVALID_VALUE;
713 self->ring = ll_ringbuffer_create(device->UpdateSize*device->NumUpdates + 1, frameSize);
714 if(!self->ring)
716 ERR("Ring buffer create failed\n");
717 close(self->fd);
718 self->fd = -1;
719 return ALC_OUT_OF_MEMORY;
722 alstr_copy_cstr(&device->DeviceName, name);
724 return ALC_NO_ERROR;
727 static void ALCcaptureOSS_close(ALCcaptureOSS *self)
729 close(self->fd);
730 self->fd = -1;
732 ll_ringbuffer_free(self->ring);
733 self->ring = NULL;
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)
740 return ALC_FALSE;
741 return ALC_TRUE;
744 static void ALCcaptureOSS_stop(ALCcaptureOSS *self)
746 int res;
748 if(ATOMIC_EXCHANGE_SEQ(&self->killNow, AL_TRUE))
749 return;
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);
760 return ALC_NO_ERROR;
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);
796 return ALC_TRUE;
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)
809 return ALC_TRUE;
810 return ALC_FALSE;
813 void ALCossBackendFactory_probe(ALCossBackendFactory* UNUSED(self), enum DevProbe type)
815 struct oss_device *cur;
816 switch(type)
818 case ALL_DEVICE_PROBE:
819 ALCossListFree(&oss_playback);
820 ALCossListPopulate(&oss_playback, DSP_CAP_OUTPUT);
821 cur = &oss_playback;
822 while(cur != NULL)
824 #ifdef HAVE_STAT
825 struct stat buf;
826 if(stat(cur->path, &buf) == 0)
827 #endif
828 AppendAllDevicesList(cur->handle);
829 cur = cur->next;
831 break;
833 case CAPTURE_DEVICE_PROBE:
834 ALCossListFree(&oss_capture);
835 ALCossListPopulate(&oss_capture, DSP_CAP_INPUT);
836 cur = &oss_capture;
837 while(cur != NULL)
839 #ifdef HAVE_STAT
840 struct stat buf;
841 if(stat(cur->path, &buf) == 0)
842 #endif
843 AppendCaptureDeviceList(cur->handle);
844 cur = cur->next;
846 break;
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);
867 return NULL;