diff options
Diffstat (limited to 'Alc/backends/oss.c')
-rw-r--r-- | Alc/backends/oss.c | 541 |
1 files changed, 394 insertions, 147 deletions
diff --git a/Alc/backends/oss.c b/Alc/backends/oss.c index dce42e21..71faad25 100644 --- a/Alc/backends/oss.c +++ b/Alc/backends/oss.c @@ -22,10 +22,12 @@ #include <sys/ioctl.h> #include <sys/types.h> +#include <sys/time.h> #include <sys/stat.h> #include <fcntl.h> #include <stdlib.h> #include <stdio.h> +#include <string.h> #include <memory.h> #include <unistd.h> #include <errno.h> @@ -33,6 +35,8 @@ #include "alMain.h" #include "alu.h" +#include "alconfig.h" +#include "ringbuffer.h" #include "threads.h" #include "compat.h" @@ -51,11 +55,176 @@ #define SOUND_MIXER_WRITE MIXER_WRITE #endif +#if defined(SOUND_VERSION) && (SOUND_VERSION < 0x040000) +#define ALC_OSS_COMPAT +#endif +#ifndef SNDCTL_AUDIOINFO +#define ALC_OSS_COMPAT +#endif + +/* + * FreeBSD strongly discourages the use of specific devices, + * such as those returned in oss_audioinfo.devnode + */ +#ifdef __FreeBSD__ +#define ALC_OSS_DEVNODE_TRUC +#endif + +struct oss_device { + const ALCchar *handle; + const char *path; + struct oss_device *next; +}; + +static struct oss_device oss_playback = { + "OSS Default", + "/dev/dsp", + NULL +}; + +static struct oss_device oss_capture = { + "OSS Default", + "/dev/dsp", + NULL +}; + +#ifdef ALC_OSS_COMPAT + +#define DSP_CAP_OUTPUT 0x00020000 +#define DSP_CAP_INPUT 0x00010000 +static void ALCossListPopulate(struct oss_device *UNUSED(devlist), int UNUSED(type_flag)) +{ +} + +#else + +#ifndef HAVE_STRNLEN +static size_t strnlen(const char *str, size_t maxlen) +{ + const char *end = memchr(str, 0, maxlen); + if(!end) return maxlen; + return end - str; +} +#endif + +static void ALCossListAppend(struct oss_device *list, const char *handle, size_t hlen, const char *path, size_t plen) +{ + struct oss_device *next; + struct oss_device *last; + size_t i; + + /* skip the first item "OSS Default" */ + last = list; + next = list->next; +#ifdef ALC_OSS_DEVNODE_TRUC + for(i = 0;i < plen;i++) + { + if(path[i] == '.') + { + if(strncmp(path + i, handle + hlen + i - plen, plen - i) == 0) + hlen = hlen + i - plen; + plen = i; + } + } +#else + (void)i; +#endif + if(handle[0] == '\0') + { + handle = path; + hlen = plen; + } + + while(next != NULL) + { + if(strncmp(next->path, path, plen) == 0) + return; + last = next; + next = next->next; + } + + next = (struct oss_device*)malloc(sizeof(struct oss_device) + hlen + plen + 2); + next->handle = (char*)(next + 1); + next->path = next->handle + hlen + 1; + next->next = NULL; + last->next = next; + + strncpy((char*)next->handle, handle, hlen); + ((char*)next->handle)[hlen] = '\0'; + strncpy((char*)next->path, path, plen); + ((char*)next->path)[plen] = '\0'; -static const ALCchar oss_device[] = "OSS Default"; + TRACE("Got device \"%s\", \"%s\"\n", next->handle, next->path); +} + +static void ALCossListPopulate(struct oss_device *devlist, int type_flag) +{ + struct oss_sysinfo si; + struct oss_audioinfo ai; + int fd, i; + + if((fd=open("/dev/mixer", O_RDONLY)) < 0) + { + TRACE("Could not open /dev/mixer: %s\n", strerror(errno)); + return; + } + if(ioctl(fd, SNDCTL_SYSINFO, &si) == -1) + { + TRACE("SNDCTL_SYSINFO failed: %s\n", strerror(errno)); + goto done; + } + for(i = 0;i < si.numaudios;i++) + { + const char *handle; + size_t len; -static const char *oss_driver = "/dev/dsp"; -static const char *oss_capture = "/dev/dsp"; + ai.dev = i; + if(ioctl(fd, SNDCTL_AUDIOINFO, &ai) == -1) + { + ERR("SNDCTL_AUDIOINFO (%d) failed: %s\n", i, strerror(errno)); + continue; + } + if(ai.devnode[0] == '\0') + continue; + + if(ai.handle[0] != '\0') + { + len = strnlen(ai.handle, sizeof(ai.handle)); + handle = ai.handle; + } + else + { + len = strnlen(ai.name, sizeof(ai.name)); + handle = ai.name; + } + if((ai.caps&type_flag)) + ALCossListAppend(devlist, handle, len, ai.devnode, + strnlen(ai.devnode, sizeof(ai.devnode))); + } + +done: + close(fd); +} + +#endif + +static void ALCossListFree(struct oss_device *list) +{ + struct oss_device *cur; + if(list == NULL) + return; + + /* skip the first item "OSS Default" */ + cur = list->next; + list->next = NULL; + + while(cur != NULL) + { + struct oss_device *next = cur->next; + free(cur); + cur = next; + } +} static int log2i(ALCuint x) { @@ -68,7 +237,6 @@ static int log2i(ALCuint x) return y; } - typedef struct ALCplaybackOSS { DERIVE_FROM_TYPE(ALCbackend); @@ -77,22 +245,21 @@ typedef struct ALCplaybackOSS { ALubyte *mix_data; int data_size; - volatile int killNow; + ATOMIC(ALenum) killNow; althrd_t thread; } ALCplaybackOSS; static int ALCplaybackOSS_mixerProc(void *ptr); static void ALCplaybackOSS_Construct(ALCplaybackOSS *self, ALCdevice *device); -static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, void, Destruct) +static void ALCplaybackOSS_Destruct(ALCplaybackOSS *self); static ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name); -static void ALCplaybackOSS_close(ALCplaybackOSS *self); static ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self); static ALCboolean ALCplaybackOSS_start(ALCplaybackOSS *self); static void ALCplaybackOSS_stop(ALCplaybackOSS *self); static DECLARE_FORWARD2(ALCplaybackOSS, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, ALCuint, availableSamples) -static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, ALint64, getLatency) +static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, ClockLatency, getClockLatency) static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, void, lock) static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, void, unlock) DECLARE_DEFAULT_ALLOCATORS(ALCplaybackOSS) @@ -103,42 +270,66 @@ static int ALCplaybackOSS_mixerProc(void *ptr) { ALCplaybackOSS *self = (ALCplaybackOSS*)ptr; ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - ALint frameSize; + struct timeval timeout; + ALubyte *write_ptr; + ALint frame_size; + ALint to_write; ssize_t wrote; + fd_set wfds; + int sret; SetRTPriority(); althrd_setname(althrd_current(), MIXER_THREAD_NAME); - frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); - while(!self->killNow && device->Connected) + ALCplaybackOSS_lock(self); + while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && + ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) { - ALint len = self->data_size; - ALubyte *WritePtr = self->mix_data; + FD_ZERO(&wfds); + FD_SET(self->fd, &wfds); + timeout.tv_sec = 1; + timeout.tv_usec = 0; + + ALCplaybackOSS_unlock(self); + sret = select(self->fd+1, NULL, &wfds, NULL, &timeout); + ALCplaybackOSS_lock(self); + if(sret < 0) + { + if(errno == EINTR) + continue; + ERR("select failed: %s\n", strerror(errno)); + aluHandleDisconnect(device, "Failed waiting for playback buffer: %s", strerror(errno)); + break; + } + else if(sret == 0) + { + WARN("select timeout\n"); + continue; + } - aluMixData(device, WritePtr, len/frameSize); - while(len > 0 && !self->killNow) + write_ptr = self->mix_data; + to_write = self->data_size; + aluMixData(device, write_ptr, to_write/frame_size); + while(to_write > 0 && !ATOMIC_LOAD_SEQ(&self->killNow)) { - wrote = write(self->fd, WritePtr, len); + wrote = write(self->fd, write_ptr, to_write); if(wrote < 0) { - if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) - { - ERR("write failed: %s\n", strerror(errno)); - ALCplaybackOSS_lock(self); - aluHandleDisconnect(device); - ALCplaybackOSS_unlock(self); - break; - } - - al_nssleep(1000000); - continue; + if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) + continue; + ERR("write failed: %s\n", strerror(errno)); + aluHandleDisconnect(device, "Failed writing playback samples: %s", + strerror(errno)); + break; } - len -= wrote; - WritePtr += wrote; + to_write -= wrote; + write_ptr += wrote; } } + ALCplaybackOSS_unlock(self); return 0; } @@ -148,37 +339,59 @@ static void ALCplaybackOSS_Construct(ALCplaybackOSS *self, ALCdevice *device) { ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCplaybackOSS, ALCbackend, self); + + self->fd = -1; + ATOMIC_INIT(&self->killNow, AL_FALSE); +} + +static void ALCplaybackOSS_Destruct(ALCplaybackOSS *self) +{ + if(self->fd != -1) + close(self->fd); + self->fd = -1; + + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); } static ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name) { + struct oss_device *dev = &oss_playback; ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - if(!name) - name = oss_device; - else if(strcmp(name, oss_device) != 0) - return ALC_INVALID_VALUE; - - self->killNow = 0; + if(!name || strcmp(name, dev->handle) == 0) + name = dev->handle; + else + { + if(!dev->next) + { + ALCossListPopulate(&oss_playback, DSP_CAP_OUTPUT); + dev = &oss_playback; + } + while(dev != NULL) + { + if (strcmp(dev->handle, name) == 0) + break; + dev = dev->next; + } + if(dev == NULL) + { + WARN("Could not find \"%s\" in device list\n", name); + return ALC_INVALID_VALUE; + } + } - self->fd = open(oss_driver, O_WRONLY); + self->fd = open(dev->path, O_WRONLY); if(self->fd == -1) { - ERR("Could not open %s: %s\n", oss_driver, strerror(errno)); + ERR("Could not open %s: %s\n", dev->path, strerror(errno)); return ALC_INVALID_VALUE; } - al_string_copy_cstr(&device->DeviceName, name); + alstr_copy_cstr(&device->DeviceName, name); return ALC_NO_ERROR; } -static void ALCplaybackOSS_close(ALCplaybackOSS *self) -{ - close(self->fd); - self->fd = -1; -} - static ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; @@ -212,18 +425,11 @@ static ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self) } periods = device->NumUpdates; - numChannels = ChannelsFromDevFmt(device->FmtChans); - frameSize = numChannels * BytesFromDevFmt(device->FmtType); - + numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); ossSpeed = device->Frequency; - log2FragmentSize = log2i(device->UpdateSize * frameSize); - - /* according to the OSS spec, 16 bytes are the minimum */ - if (log2FragmentSize < 4) - log2FragmentSize = 4; - /* Subtract one period since the temp mixing buffer counts as one. Still - * need at least two on the card, though. */ - if(periods > 2) periods--; + frameSize = numChannels * BytesFromDevFmt(device->FmtType); + /* According to the OSS spec, 16 bytes (log2(16)) is the minimum. */ + log2FragmentSize = maxi(log2i(device->UpdateSize*frameSize), 4); numFragmentsLogSize = (periods << 16) | log2FragmentSize; #define CHECKERR(func) if((func) < 0) { \ @@ -245,7 +451,7 @@ static ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self) } #undef CHECKERR - if((int)ChannelsFromDevFmt(device->FmtChans) != numChannels) + if((int)ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder) != numChannels) { ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device->FmtChans), numChannels); return ALC_FALSE; @@ -261,7 +467,7 @@ static ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self) device->Frequency = ossSpeed; device->UpdateSize = info.fragsize / frameSize; - device->NumUpdates = info.fragments + 1; + device->NumUpdates = info.fragments; SetDefaultChannelOrder(device); @@ -272,10 +478,12 @@ static ALCboolean ALCplaybackOSS_start(ALCplaybackOSS *self) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - self->data_size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + self->data_size = device->UpdateSize * FrameSizeFromDevFmt( + device->FmtChans, device->FmtType, device->AmbiOrder + ); self->mix_data = calloc(1, self->data_size); - self->killNow = 0; + ATOMIC_STORE_SEQ(&self->killNow, AL_FALSE); if(althrd_create(&self->thread, ALCplaybackOSS_mixerProc, self) != althrd_success) { free(self->mix_data); @@ -290,10 +498,8 @@ static void ALCplaybackOSS_stop(ALCplaybackOSS *self) { int res; - if(self->killNow) + if(ATOMIC_EXCHANGE_SEQ(&self->killNow, AL_TRUE)) return; - - self->killNow = 1; althrd_join(self->thread, &res); if(ioctl(self->fd, SNDCTL_DSP_RESET) != 0) @@ -309,28 +515,23 @@ typedef struct ALCcaptureOSS { int fd; - ALubyte *read_data; - int data_size; - - RingBuffer *ring; - int doCapture; + ll_ringbuffer_t *ring; - volatile int killNow; + ATOMIC(ALenum) killNow; althrd_t thread; } ALCcaptureOSS; static int ALCcaptureOSS_recordProc(void *ptr); static void ALCcaptureOSS_Construct(ALCcaptureOSS *self, ALCdevice *device); -static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, void, Destruct) +static void ALCcaptureOSS_Destruct(ALCcaptureOSS *self); static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name); -static void ALCcaptureOSS_close(ALCcaptureOSS *self); static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, ALCboolean, reset) static ALCboolean ALCcaptureOSS_start(ALCcaptureOSS *self); static void ALCcaptureOSS_stop(ALCcaptureOSS *self); static ALCenum ALCcaptureOSS_captureSamples(ALCcaptureOSS *self, ALCvoid *buffer, ALCuint samples); static ALCuint ALCcaptureOSS_availableSamples(ALCcaptureOSS *self); -static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, ALint64, getLatency) +static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, ClockLatency, getClockLatency) static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, void, lock) static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, void, unlock) DECLARE_DEFAULT_ALLOCATORS(ALCcaptureOSS) @@ -341,32 +542,55 @@ static int ALCcaptureOSS_recordProc(void *ptr) { ALCcaptureOSS *self = (ALCcaptureOSS*)ptr; ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - int frameSize; - int amt; + struct timeval timeout; + int frame_size; + fd_set rfds; + ssize_t amt; + int sret; SetRTPriority(); althrd_setname(althrd_current(), RECORD_THREAD_NAME); - frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); - while(!self->killNow) + while(!ATOMIC_LOAD_SEQ(&self->killNow)) { - amt = read(self->fd, self->read_data, self->data_size); - if(amt < 0) + ll_ringbuffer_data_t vec[2]; + + FD_ZERO(&rfds); + FD_SET(self->fd, &rfds); + timeout.tv_sec = 1; + timeout.tv_usec = 0; + + sret = select(self->fd+1, &rfds, NULL, NULL, &timeout); + if(sret < 0) { - ERR("read failed: %s\n", strerror(errno)); - ALCcaptureOSS_lock(self); - aluHandleDisconnect(device); - ALCcaptureOSS_unlock(self); + if(errno == EINTR) + continue; + ERR("select failed: %s\n", strerror(errno)); + aluHandleDisconnect(device, "Failed to check capture samples: %s", strerror(errno)); break; } - if(amt == 0) + else if(sret == 0) { - al_nssleep(1000000); + WARN("select timeout\n"); continue; } - if(self->doCapture) - WriteRingBuffer(self->ring, self->read_data, amt/frameSize); + + ll_ringbuffer_get_write_vector(self->ring, vec); + if(vec[0].len > 0) + { + amt = read(self->fd, vec[0].buf, vec[0].len*frame_size); + if(amt < 0) + { + ERR("read failed: %s\n", strerror(errno)); + ALCcaptureOSS_lock(self); + aluHandleDisconnect(device, "Failed reading capture samples: %s", strerror(errno)); + ALCcaptureOSS_unlock(self); + break; + } + ll_ringbuffer_write_advance(self->ring, amt/frame_size); + } } return 0; @@ -377,11 +601,27 @@ static void ALCcaptureOSS_Construct(ALCcaptureOSS *self, ALCdevice *device) { ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCcaptureOSS, ALCbackend, self); + + self->fd = -1; + self->ring = NULL; + ATOMIC_INIT(&self->killNow, AL_FALSE); +} + +static void ALCcaptureOSS_Destruct(ALCcaptureOSS *self) +{ + if(self->fd != -1) + close(self->fd); + self->fd = -1; + + ll_ringbuffer_free(self->ring); + self->ring = NULL; + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); } static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + struct oss_device *dev = &oss_capture; int numFragmentsLogSize; int log2FragmentSize; unsigned int periods; @@ -392,15 +632,32 @@ static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) int ossSpeed; char *err; - if(!name) - name = oss_device; - else if(strcmp(name, oss_device) != 0) - return ALC_INVALID_VALUE; + if(!name || strcmp(name, dev->handle) == 0) + name = dev->handle; + else + { + if(!dev->next) + { + ALCossListPopulate(&oss_capture, DSP_CAP_INPUT); + dev = &oss_capture; + } + while(dev != NULL) + { + if (strcmp(dev->handle, name) == 0) + break; + dev = dev->next; + } + if(dev == NULL) + { + WARN("Could not find \"%s\" in device list\n", name); + return ALC_INVALID_VALUE; + } + } - self->fd = open(oss_capture, O_RDONLY); + self->fd = open(dev->path, O_RDONLY); if(self->fd == -1) { - ERR("Could not open %s: %s\n", oss_capture, strerror(errno)); + ERR("Could not open %s: %s\n", dev->path, strerror(errno)); return ALC_INVALID_VALUE; } @@ -424,7 +681,7 @@ static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) } periods = 4; - numChannels = ChannelsFromDevFmt(device->FmtChans); + numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); frameSize = numChannels * BytesFromDevFmt(device->FmtType); ossSpeed = device->Frequency; log2FragmentSize = log2i(device->UpdateSize * device->NumUpdates * @@ -454,7 +711,7 @@ static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) } #undef CHECKERR - if((int)ChannelsFromDevFmt(device->FmtChans) != numChannels) + if((int)ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder) != numChannels) { ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device->FmtChans), numChannels); close(self->fd); @@ -472,7 +729,7 @@ static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) return ALC_INVALID_VALUE; } - self->ring = CreateRingBuffer(frameSize, device->UpdateSize * device->NumUpdates); + self->ring = ll_ringbuffer_create(device->UpdateSize*device->NumUpdates, frameSize, false); if(!self->ring) { ERR("Ring buffer create failed\n"); @@ -481,60 +738,41 @@ static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) return ALC_OUT_OF_MEMORY; } - self->data_size = info.fragsize; - self->read_data = calloc(1, self->data_size); - - self->killNow = 0; - if(althrd_create(&self->thread, ALCcaptureOSS_recordProc, self) != althrd_success) - { - device->ExtraData = NULL; - close(self->fd); - self->fd = -1; - return ALC_OUT_OF_MEMORY; - } - - al_string_copy_cstr(&device->DeviceName, name); + alstr_copy_cstr(&device->DeviceName, name); return ALC_NO_ERROR; } -static void ALCcaptureOSS_close(ALCcaptureOSS *self) -{ - int res; - - self->killNow = 1; - althrd_join(self->thread, &res); - - close(self->fd); - self->fd = -1; - - DestroyRingBuffer(self->ring); - self->ring = NULL; - - free(self->read_data); - self->read_data = NULL; -} - static ALCboolean ALCcaptureOSS_start(ALCcaptureOSS *self) { - self->doCapture = 1; + ATOMIC_STORE_SEQ(&self->killNow, AL_FALSE); + if(althrd_create(&self->thread, ALCcaptureOSS_recordProc, self) != althrd_success) + return ALC_FALSE; return ALC_TRUE; } static void ALCcaptureOSS_stop(ALCcaptureOSS *self) { - self->doCapture = 0; + int res; + + if(ATOMIC_EXCHANGE_SEQ(&self->killNow, AL_TRUE)) + return; + + althrd_join(self->thread, &res); + + if(ioctl(self->fd, SNDCTL_DSP_RESET) != 0) + ERR("Error resetting device: %s\n", strerror(errno)); } static ALCenum ALCcaptureOSS_captureSamples(ALCcaptureOSS *self, ALCvoid *buffer, ALCuint samples) { - ReadRingBuffer(self->ring, buffer, samples); + ll_ringbuffer_read(self->ring, buffer, samples); return ALC_NO_ERROR; } static ALCuint ALCcaptureOSS_availableSamples(ALCcaptureOSS *self) { - return RingBufferSize(self->ring); + return ll_ringbuffer_read_space(self->ring); } @@ -546,9 +784,9 @@ typedef struct ALCossBackendFactory { ALCbackendFactory *ALCossBackendFactory_getFactory(void); static ALCboolean ALCossBackendFactory_init(ALCossBackendFactory *self); -static DECLARE_FORWARD(ALCossBackendFactory, ALCbackendFactory, void, deinit) +static void ALCossBackendFactory_deinit(ALCossBackendFactory *self); static ALCboolean ALCossBackendFactory_querySupport(ALCossBackendFactory *self, ALCbackend_Type type); -static void ALCossBackendFactory_probe(ALCossBackendFactory *self, enum DevProbe type); +static void ALCossBackendFactory_probe(ALCossBackendFactory *self, enum DevProbe type, al_string *outnames); static ALCbackend* ALCossBackendFactory_createBackend(ALCossBackendFactory *self, ALCdevice *device, ALCbackend_Type type); DEFINE_ALCBACKENDFACTORY_VTABLE(ALCossBackendFactory); @@ -562,12 +800,19 @@ ALCbackendFactory *ALCossBackendFactory_getFactory(void) ALCboolean ALCossBackendFactory_init(ALCossBackendFactory* UNUSED(self)) { - ConfigValueStr(NULL, "oss", "device", &oss_driver); - ConfigValueStr(NULL, "oss", "capture", &oss_capture); + ConfigValueStr(NULL, "oss", "device", &oss_playback.path); + ConfigValueStr(NULL, "oss", "capture", &oss_capture.path); return ALC_TRUE; } +void ALCossBackendFactory_deinit(ALCossBackendFactory* UNUSED(self)) +{ + ALCossListFree(&oss_playback); + ALCossListFree(&oss_capture); +} + + ALCboolean ALCossBackendFactory_querySupport(ALCossBackendFactory* UNUSED(self), ALCbackend_Type type) { if(type == ALCbackend_Playback || type == ALCbackend_Capture) @@ -575,29 +820,31 @@ ALCboolean ALCossBackendFactory_querySupport(ALCossBackendFactory* UNUSED(self), return ALC_FALSE; } -void ALCossBackendFactory_probe(ALCossBackendFactory* UNUSED(self), enum DevProbe type) +void ALCossBackendFactory_probe(ALCossBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) { + struct oss_device *cur = NULL; switch(type) { case ALL_DEVICE_PROBE: - { -#ifdef HAVE_STAT - struct stat buf; - if(stat(oss_driver, &buf) == 0) -#endif - AppendAllDevicesList(oss_device); - } - break; + ALCossListFree(&oss_playback); + ALCossListPopulate(&oss_playback, DSP_CAP_OUTPUT); + cur = &oss_playback; + break; case CAPTURE_DEVICE_PROBE: - { + ALCossListFree(&oss_capture); + ALCossListPopulate(&oss_capture, DSP_CAP_INPUT); + cur = &oss_capture; + break; + } + while(cur != NULL) + { #ifdef HAVE_STAT - struct stat buf; - if(stat(oss_capture, &buf) == 0) + struct stat buf; + if(stat(cur->path, &buf) == 0) #endif - AppendCaptureDeviceList(oss_device); - } - break; + alstr_append_range(outnames, cur->handle, cur->handle+strlen(cur->handle)+1); + cur = cur->next; } } |