Rename al_string_* functions to alstr_*
[openal-soft.git] / Alc / backends / oss.c
blob6706405d52f6ef8c2204d6530a1953a1b46088d8
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);
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);
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) != 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(device->FmtChans, device->FmtType);
475 self->mix_data = calloc(1, self->data_size);
477 ATOMIC_STORE_SEQ(&self->killNow, AL_FALSE);
478 if(althrd_create(&self->thread, ALCplaybackOSS_mixerProc, self) != althrd_success)
480 free(self->mix_data);
481 self->mix_data = NULL;
482 return ALC_FALSE;
485 return ALC_TRUE;
488 static void ALCplaybackOSS_stop(ALCplaybackOSS *self)
490 int res;
492 if(ATOMIC_EXCHANGE_SEQ(ALenum, &self->killNow, AL_TRUE))
493 return;
494 althrd_join(self->thread, &res);
496 if(ioctl(self->fd, SNDCTL_DSP_RESET) != 0)
497 ERR("Error resetting device: %s\n", strerror(errno));
499 free(self->mix_data);
500 self->mix_data = NULL;
504 typedef struct ALCcaptureOSS {
505 DERIVE_FROM_TYPE(ALCbackend);
507 int fd;
509 ll_ringbuffer_t *ring;
511 ATOMIC(ALenum) killNow;
512 althrd_t thread;
513 } ALCcaptureOSS;
515 static int ALCcaptureOSS_recordProc(void *ptr);
517 static void ALCcaptureOSS_Construct(ALCcaptureOSS *self, ALCdevice *device);
518 static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, void, Destruct)
519 static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name);
520 static void ALCcaptureOSS_close(ALCcaptureOSS *self);
521 static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, ALCboolean, reset)
522 static ALCboolean ALCcaptureOSS_start(ALCcaptureOSS *self);
523 static void ALCcaptureOSS_stop(ALCcaptureOSS *self);
524 static ALCenum ALCcaptureOSS_captureSamples(ALCcaptureOSS *self, ALCvoid *buffer, ALCuint samples);
525 static ALCuint ALCcaptureOSS_availableSamples(ALCcaptureOSS *self);
526 static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, ClockLatency, getClockLatency)
527 static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, void, lock)
528 static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, void, unlock)
529 DECLARE_DEFAULT_ALLOCATORS(ALCcaptureOSS)
530 DEFINE_ALCBACKEND_VTABLE(ALCcaptureOSS);
533 static int ALCcaptureOSS_recordProc(void *ptr)
535 ALCcaptureOSS *self = (ALCcaptureOSS*)ptr;
536 ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
537 struct timeval timeout;
538 int frame_size;
539 fd_set rfds;
540 ssize_t amt;
541 int sret;
543 SetRTPriority();
544 althrd_setname(althrd_current(), RECORD_THREAD_NAME);
546 frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
548 while(!ATOMIC_LOAD_SEQ(&self->killNow))
550 ll_ringbuffer_data_t vec[2];
552 FD_ZERO(&rfds);
553 FD_SET(self->fd, &rfds);
554 timeout.tv_sec = 1;
555 timeout.tv_usec = 0;
557 sret = select(self->fd+1, &rfds, NULL, NULL, &timeout);
558 if(sret < 0)
560 if(errno == EINTR)
561 continue;
562 ERR("select failed: %s\n", strerror(errno));
563 aluHandleDisconnect(device);
564 break;
566 else if(sret == 0)
568 WARN("select timeout\n");
569 continue;
572 ll_ringbuffer_get_write_vector(self->ring, vec);
573 if(vec[0].len > 0)
575 amt = read(self->fd, vec[0].buf, vec[0].len*frame_size);
576 if(amt < 0)
578 ERR("read failed: %s\n", strerror(errno));
579 ALCcaptureOSS_lock(self);
580 aluHandleDisconnect(device);
581 ALCcaptureOSS_unlock(self);
582 break;
584 ll_ringbuffer_write_advance(self->ring, amt/frame_size);
588 return 0;
592 static void ALCcaptureOSS_Construct(ALCcaptureOSS *self, ALCdevice *device)
594 ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
595 SET_VTABLE2(ALCcaptureOSS, ALCbackend, self);
597 ATOMIC_INIT(&self->killNow, AL_FALSE);
600 static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name)
602 ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
603 struct oss_device *dev = &oss_capture;
604 int numFragmentsLogSize;
605 int log2FragmentSize;
606 unsigned int periods;
607 audio_buf_info info;
608 ALuint frameSize;
609 int numChannels;
610 int ossFormat;
611 int ossSpeed;
612 char *err;
614 if(!name || strcmp(name, dev->handle) == 0)
615 name = dev->handle;
616 else
618 if(!dev->next)
620 ALCossListPopulate(&oss_capture, DSP_CAP_INPUT);
621 dev = &oss_capture;
623 while(dev != NULL)
625 if (strcmp(dev->handle, name) == 0)
626 break;
627 dev = dev->next;
629 if(dev == NULL)
631 WARN("Could not find \"%s\" in device list\n", name);
632 return ALC_INVALID_VALUE;
636 self->fd = open(dev->path, O_RDONLY);
637 if(self->fd == -1)
639 ERR("Could not open %s: %s\n", dev->path, strerror(errno));
640 return ALC_INVALID_VALUE;
643 switch(device->FmtType)
645 case DevFmtByte:
646 ossFormat = AFMT_S8;
647 break;
648 case DevFmtUByte:
649 ossFormat = AFMT_U8;
650 break;
651 case DevFmtShort:
652 ossFormat = AFMT_S16_NE;
653 break;
654 case DevFmtUShort:
655 case DevFmtInt:
656 case DevFmtUInt:
657 case DevFmtFloat:
658 ERR("%s capture samples not supported\n", DevFmtTypeString(device->FmtType));
659 return ALC_INVALID_VALUE;
662 periods = 4;
663 numChannels = ChannelsFromDevFmt(device->FmtChans);
664 frameSize = numChannels * BytesFromDevFmt(device->FmtType);
665 ossSpeed = device->Frequency;
666 log2FragmentSize = log2i(device->UpdateSize * device->NumUpdates *
667 frameSize / periods);
669 /* according to the OSS spec, 16 bytes are the minimum */
670 if (log2FragmentSize < 4)
671 log2FragmentSize = 4;
672 numFragmentsLogSize = (periods << 16) | log2FragmentSize;
674 #define CHECKERR(func) if((func) < 0) { \
675 err = #func; \
676 goto err; \
678 CHECKERR(ioctl(self->fd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize));
679 CHECKERR(ioctl(self->fd, SNDCTL_DSP_SETFMT, &ossFormat));
680 CHECKERR(ioctl(self->fd, SNDCTL_DSP_CHANNELS, &numChannels));
681 CHECKERR(ioctl(self->fd, SNDCTL_DSP_SPEED, &ossSpeed));
682 CHECKERR(ioctl(self->fd, SNDCTL_DSP_GETISPACE, &info));
683 if(0)
685 err:
686 ERR("%s failed: %s\n", err, strerror(errno));
687 close(self->fd);
688 self->fd = -1;
689 return ALC_INVALID_VALUE;
691 #undef CHECKERR
693 if((int)ChannelsFromDevFmt(device->FmtChans) != numChannels)
695 ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device->FmtChans), numChannels);
696 close(self->fd);
697 self->fd = -1;
698 return ALC_INVALID_VALUE;
701 if(!((ossFormat == AFMT_S8 && device->FmtType == DevFmtByte) ||
702 (ossFormat == AFMT_U8 && device->FmtType == DevFmtUByte) ||
703 (ossFormat == AFMT_S16_NE && device->FmtType == DevFmtShort)))
705 ERR("Failed to set %s samples, got OSS format %#x\n", DevFmtTypeString(device->FmtType), ossFormat);
706 close(self->fd);
707 self->fd = -1;
708 return ALC_INVALID_VALUE;
711 self->ring = ll_ringbuffer_create(device->UpdateSize*device->NumUpdates + 1, frameSize);
712 if(!self->ring)
714 ERR("Ring buffer create failed\n");
715 close(self->fd);
716 self->fd = -1;
717 return ALC_OUT_OF_MEMORY;
720 alstr_copy_cstr(&device->DeviceName, name);
722 return ALC_NO_ERROR;
725 static void ALCcaptureOSS_close(ALCcaptureOSS *self)
727 close(self->fd);
728 self->fd = -1;
730 ll_ringbuffer_free(self->ring);
731 self->ring = NULL;
734 static ALCboolean ALCcaptureOSS_start(ALCcaptureOSS *self)
736 ATOMIC_STORE_SEQ(&self->killNow, AL_FALSE);
737 if(althrd_create(&self->thread, ALCcaptureOSS_recordProc, self) != althrd_success)
738 return ALC_FALSE;
739 return ALC_TRUE;
742 static void ALCcaptureOSS_stop(ALCcaptureOSS *self)
744 int res;
746 if(ATOMIC_EXCHANGE_SEQ(ALenum, &self->killNow, AL_TRUE))
747 return;
749 althrd_join(self->thread, &res);
751 if(ioctl(self->fd, SNDCTL_DSP_RESET) != 0)
752 ERR("Error resetting device: %s\n", strerror(errno));
755 static ALCenum ALCcaptureOSS_captureSamples(ALCcaptureOSS *self, ALCvoid *buffer, ALCuint samples)
757 ll_ringbuffer_read(self->ring, buffer, samples);
758 return ALC_NO_ERROR;
761 static ALCuint ALCcaptureOSS_availableSamples(ALCcaptureOSS *self)
763 return ll_ringbuffer_read_space(self->ring);
767 typedef struct ALCossBackendFactory {
768 DERIVE_FROM_TYPE(ALCbackendFactory);
769 } ALCossBackendFactory;
770 #define ALCOSSBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCossBackendFactory, ALCbackendFactory) } }
772 ALCbackendFactory *ALCossBackendFactory_getFactory(void);
774 static ALCboolean ALCossBackendFactory_init(ALCossBackendFactory *self);
775 static void ALCossBackendFactory_deinit(ALCossBackendFactory *self);
776 static ALCboolean ALCossBackendFactory_querySupport(ALCossBackendFactory *self, ALCbackend_Type type);
777 static void ALCossBackendFactory_probe(ALCossBackendFactory *self, enum DevProbe type);
778 static ALCbackend* ALCossBackendFactory_createBackend(ALCossBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
779 DEFINE_ALCBACKENDFACTORY_VTABLE(ALCossBackendFactory);
782 ALCbackendFactory *ALCossBackendFactory_getFactory(void)
784 static ALCossBackendFactory factory = ALCOSSBACKENDFACTORY_INITIALIZER;
785 return STATIC_CAST(ALCbackendFactory, &factory);
789 ALCboolean ALCossBackendFactory_init(ALCossBackendFactory* UNUSED(self))
791 ConfigValueStr(NULL, "oss", "device", &oss_playback.path);
792 ConfigValueStr(NULL, "oss", "capture", &oss_capture.path);
794 return ALC_TRUE;
797 void ALCossBackendFactory_deinit(ALCossBackendFactory* UNUSED(self))
799 ALCossListFree(&oss_playback);
800 ALCossListFree(&oss_capture);
804 ALCboolean ALCossBackendFactory_querySupport(ALCossBackendFactory* UNUSED(self), ALCbackend_Type type)
806 if(type == ALCbackend_Playback || type == ALCbackend_Capture)
807 return ALC_TRUE;
808 return ALC_FALSE;
811 void ALCossBackendFactory_probe(ALCossBackendFactory* UNUSED(self), enum DevProbe type)
813 struct oss_device *cur;
814 switch(type)
816 case ALL_DEVICE_PROBE:
817 ALCossListFree(&oss_playback);
818 ALCossListPopulate(&oss_playback, DSP_CAP_OUTPUT);
819 cur = &oss_playback;
820 while(cur != NULL)
822 AppendAllDevicesList(cur->handle);
823 cur = cur->next;
825 break;
827 case CAPTURE_DEVICE_PROBE:
828 ALCossListFree(&oss_capture);
829 ALCossListPopulate(&oss_capture, DSP_CAP_INPUT);
830 cur = &oss_capture;
831 while(cur != NULL)
833 AppendCaptureDeviceList(cur->handle);
834 cur = cur->next;
836 break;
840 ALCbackend* ALCossBackendFactory_createBackend(ALCossBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
842 if(type == ALCbackend_Playback)
844 ALCplaybackOSS *backend;
845 NEW_OBJ(backend, ALCplaybackOSS)(device);
846 if(!backend) return NULL;
847 return STATIC_CAST(ALCbackend, backend);
849 if(type == ALCbackend_Capture)
851 ALCcaptureOSS *backend;
852 NEW_OBJ(backend, ALCcaptureOSS)(device);
853 if(!backend) return NULL;
854 return STATIC_CAST(ALCbackend, backend);
857 return NULL;