Only pass nano seconds to al_nssleep
[openal-soft.git] / Alc / backends / oss.c
blob631a496e28e9a6b9e705f285227a871168c76715
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/stat.h>
26 #include <fcntl.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <memory.h>
30 #include <unistd.h>
31 #include <errno.h>
32 #include <math.h>
34 #include "alMain.h"
35 #include "alu.h"
36 #include "threads.h"
37 #include "compat.h"
39 #include "backends/base.h"
41 #include <sys/soundcard.h>
44 * The OSS documentation talks about SOUND_MIXER_READ, but the header
45 * only contains MIXER_READ. Play safe. Same for WRITE.
47 #ifndef SOUND_MIXER_READ
48 #define SOUND_MIXER_READ MIXER_READ
49 #endif
50 #ifndef SOUND_MIXER_WRITE
51 #define SOUND_MIXER_WRITE MIXER_WRITE
52 #endif
55 static const ALCchar oss_device[] = "OSS Default";
57 static const char *oss_driver = "/dev/dsp";
58 static const char *oss_capture = "/dev/dsp";
60 static int log2i(ALCuint x)
62 int y = 0;
63 while (x > 1)
65 x >>= 1;
66 y++;
68 return y;
72 typedef struct ALCplaybackOSS {
73 DERIVE_FROM_TYPE(ALCbackend);
75 int fd;
77 ALubyte *mix_data;
78 int data_size;
80 volatile int killNow;
81 althrd_t thread;
82 } ALCplaybackOSS;
84 static int ALCplaybackOSS_mixerProc(void *ptr);
86 static void ALCplaybackOSS_Construct(ALCplaybackOSS *self, ALCdevice *device);
87 static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, void, Destruct)
88 static ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name);
89 static void ALCplaybackOSS_close(ALCplaybackOSS *self);
90 static ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self);
91 static ALCboolean ALCplaybackOSS_start(ALCplaybackOSS *self);
92 static void ALCplaybackOSS_stop(ALCplaybackOSS *self);
93 static DECLARE_FORWARD2(ALCplaybackOSS, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint)
94 static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, ALCuint, availableSamples)
95 static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, ALint64, getLatency)
96 static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, void, lock)
97 static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, void, unlock)
98 DECLARE_DEFAULT_ALLOCATORS(ALCplaybackOSS)
99 DEFINE_ALCBACKEND_VTABLE(ALCplaybackOSS);
102 static int ALCplaybackOSS_mixerProc(void *ptr)
104 ALCplaybackOSS *self = (ALCplaybackOSS*)ptr;
105 ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
106 ALint frameSize;
107 ssize_t wrote;
109 SetRTPriority();
110 althrd_setname(althrd_current(), MIXER_THREAD_NAME);
112 frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
114 while(!self->killNow && device->Connected)
116 ALint len = self->data_size;
117 ALubyte *WritePtr = self->mix_data;
119 aluMixData(device, WritePtr, len/frameSize);
120 while(len > 0 && !self->killNow)
122 wrote = write(self->fd, WritePtr, len);
123 if(wrote < 0)
125 if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR)
127 ERR("write failed: %s\n", strerror(errno));
128 ALCplaybackOSS_lock(self);
129 aluHandleDisconnect(device);
130 ALCplaybackOSS_unlock(self);
131 break;
134 al_nssleep(1000000);
135 continue;
138 len -= wrote;
139 WritePtr += wrote;
143 return 0;
147 static void ALCplaybackOSS_Construct(ALCplaybackOSS *self, ALCdevice *device)
149 ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
150 SET_VTABLE2(ALCplaybackOSS, ALCbackend, self);
153 static ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name)
155 ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
157 if(!name)
158 name = oss_device;
159 else if(strcmp(name, oss_device) != 0)
160 return ALC_INVALID_VALUE;
162 self->killNow = 0;
164 self->fd = open(oss_driver, O_WRONLY);
165 if(self->fd == -1)
167 ERR("Could not open %s: %s\n", oss_driver, strerror(errno));
168 return ALC_INVALID_VALUE;
171 al_string_copy_cstr(&device->DeviceName, name);
173 return ALC_NO_ERROR;
176 static void ALCplaybackOSS_close(ALCplaybackOSS *self)
178 close(self->fd);
179 self->fd = -1;
182 static ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self)
184 ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
185 int numFragmentsLogSize;
186 int log2FragmentSize;
187 unsigned int periods;
188 audio_buf_info info;
189 ALuint frameSize;
190 int numChannels;
191 int ossFormat;
192 int ossSpeed;
193 char *err;
195 switch(device->FmtType)
197 case DevFmtByte:
198 ossFormat = AFMT_S8;
199 break;
200 case DevFmtUByte:
201 ossFormat = AFMT_U8;
202 break;
203 case DevFmtUShort:
204 case DevFmtInt:
205 case DevFmtUInt:
206 case DevFmtFloat:
207 device->FmtType = DevFmtShort;
208 /* fall-through */
209 case DevFmtShort:
210 ossFormat = AFMT_S16_NE;
211 break;
214 periods = device->NumUpdates;
215 numChannels = ChannelsFromDevFmt(device->FmtChans);
216 frameSize = numChannels * BytesFromDevFmt(device->FmtType);
218 ossSpeed = device->Frequency;
219 log2FragmentSize = log2i(device->UpdateSize * frameSize);
221 /* according to the OSS spec, 16 bytes are the minimum */
222 if (log2FragmentSize < 4)
223 log2FragmentSize = 4;
224 /* Subtract one period since the temp mixing buffer counts as one. Still
225 * need at least two on the card, though. */
226 if(periods > 2) periods--;
227 numFragmentsLogSize = (periods << 16) | log2FragmentSize;
229 #define CHECKERR(func) if((func) < 0) { \
230 err = #func; \
231 goto err; \
233 /* Don't fail if SETFRAGMENT fails. We can handle just about anything
234 * that's reported back via GETOSPACE */
235 ioctl(self->fd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize);
236 CHECKERR(ioctl(self->fd, SNDCTL_DSP_SETFMT, &ossFormat));
237 CHECKERR(ioctl(self->fd, SNDCTL_DSP_CHANNELS, &numChannels));
238 CHECKERR(ioctl(self->fd, SNDCTL_DSP_SPEED, &ossSpeed));
239 CHECKERR(ioctl(self->fd, SNDCTL_DSP_GETOSPACE, &info));
240 if(0)
242 err:
243 ERR("%s failed: %s\n", err, strerror(errno));
244 return ALC_FALSE;
246 #undef CHECKERR
248 if((int)ChannelsFromDevFmt(device->FmtChans) != numChannels)
250 ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device->FmtChans), numChannels);
251 return ALC_FALSE;
254 if(!((ossFormat == AFMT_S8 && device->FmtType == DevFmtByte) ||
255 (ossFormat == AFMT_U8 && device->FmtType == DevFmtUByte) ||
256 (ossFormat == AFMT_S16_NE && device->FmtType == DevFmtShort)))
258 ERR("Failed to set %s samples, got OSS format %#x\n", DevFmtTypeString(device->FmtType), ossFormat);
259 return ALC_FALSE;
262 device->Frequency = ossSpeed;
263 device->UpdateSize = info.fragsize / frameSize;
264 device->NumUpdates = info.fragments + 1;
266 SetDefaultChannelOrder(device);
268 return ALC_TRUE;
271 static ALCboolean ALCplaybackOSS_start(ALCplaybackOSS *self)
273 ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
275 self->data_size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
276 self->mix_data = calloc(1, self->data_size);
278 self->killNow = 0;
279 if(althrd_create(&self->thread, ALCplaybackOSS_mixerProc, self) != althrd_success)
281 free(self->mix_data);
282 self->mix_data = NULL;
283 return ALC_FALSE;
286 return ALC_TRUE;
289 static void ALCplaybackOSS_stop(ALCplaybackOSS *self)
291 int res;
293 if(self->killNow)
294 return;
296 self->killNow = 1;
297 althrd_join(self->thread, &res);
299 if(ioctl(self->fd, SNDCTL_DSP_RESET) != 0)
300 ERR("Error resetting device: %s\n", strerror(errno));
302 free(self->mix_data);
303 self->mix_data = NULL;
307 typedef struct ALCcaptureOSS {
308 DERIVE_FROM_TYPE(ALCbackend);
310 int fd;
312 ALubyte *read_data;
313 int data_size;
315 RingBuffer *ring;
316 int doCapture;
318 volatile int killNow;
319 althrd_t thread;
320 } ALCcaptureOSS;
322 static int ALCcaptureOSS_recordProc(void *ptr);
324 static void ALCcaptureOSS_Construct(ALCcaptureOSS *self, ALCdevice *device);
325 static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, void, Destruct)
326 static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name);
327 static void ALCcaptureOSS_close(ALCcaptureOSS *self);
328 static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, ALCboolean, reset)
329 static ALCboolean ALCcaptureOSS_start(ALCcaptureOSS *self);
330 static void ALCcaptureOSS_stop(ALCcaptureOSS *self);
331 static ALCenum ALCcaptureOSS_captureSamples(ALCcaptureOSS *self, ALCvoid *buffer, ALCuint samples);
332 static ALCuint ALCcaptureOSS_availableSamples(ALCcaptureOSS *self);
333 static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, ALint64, getLatency)
334 static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, void, lock)
335 static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, void, unlock)
336 DECLARE_DEFAULT_ALLOCATORS(ALCcaptureOSS)
337 DEFINE_ALCBACKEND_VTABLE(ALCcaptureOSS);
340 static int ALCcaptureOSS_recordProc(void *ptr)
342 ALCcaptureOSS *self = (ALCcaptureOSS*)ptr;
343 ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
344 int frameSize;
345 int amt;
347 SetRTPriority();
348 althrd_setname(althrd_current(), "alsoft-record");
350 frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
352 while(!self->killNow)
354 amt = read(self->fd, self->read_data, self->data_size);
355 if(amt < 0)
357 ERR("read failed: %s\n", strerror(errno));
358 ALCcaptureOSS_lock(self);
359 aluHandleDisconnect(device);
360 ALCcaptureOSS_unlock(self);
361 break;
363 if(amt == 0)
365 al_nssleep(1000000);
366 continue;
368 if(self->doCapture)
369 WriteRingBuffer(self->ring, self->read_data, amt/frameSize);
372 return 0;
376 static void ALCcaptureOSS_Construct(ALCcaptureOSS *self, ALCdevice *device)
378 ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
379 SET_VTABLE2(ALCcaptureOSS, ALCbackend, self);
382 static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name)
384 ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
385 int numFragmentsLogSize;
386 int log2FragmentSize;
387 unsigned int periods;
388 audio_buf_info info;
389 ALuint frameSize;
390 int numChannels;
391 int ossFormat;
392 int ossSpeed;
393 char *err;
395 if(!name)
396 name = oss_device;
397 else if(strcmp(name, oss_device) != 0)
398 return ALC_INVALID_VALUE;
400 self->fd = open(oss_capture, O_RDONLY);
401 if(self->fd == -1)
403 ERR("Could not open %s: %s\n", oss_capture, strerror(errno));
404 return ALC_INVALID_VALUE;
407 switch(device->FmtType)
409 case DevFmtByte:
410 ossFormat = AFMT_S8;
411 break;
412 case DevFmtUByte:
413 ossFormat = AFMT_U8;
414 break;
415 case DevFmtShort:
416 ossFormat = AFMT_S16_NE;
417 break;
418 case DevFmtUShort:
419 case DevFmtInt:
420 case DevFmtUInt:
421 case DevFmtFloat:
422 ERR("%s capture samples not supported\n", DevFmtTypeString(device->FmtType));
423 return ALC_INVALID_VALUE;
426 periods = 4;
427 numChannels = ChannelsFromDevFmt(device->FmtChans);
428 frameSize = numChannels * BytesFromDevFmt(device->FmtType);
429 ossSpeed = device->Frequency;
430 log2FragmentSize = log2i(device->UpdateSize * device->NumUpdates *
431 frameSize / periods);
433 /* according to the OSS spec, 16 bytes are the minimum */
434 if (log2FragmentSize < 4)
435 log2FragmentSize = 4;
436 numFragmentsLogSize = (periods << 16) | log2FragmentSize;
438 #define CHECKERR(func) if((func) < 0) { \
439 err = #func; \
440 goto err; \
442 CHECKERR(ioctl(self->fd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize));
443 CHECKERR(ioctl(self->fd, SNDCTL_DSP_SETFMT, &ossFormat));
444 CHECKERR(ioctl(self->fd, SNDCTL_DSP_CHANNELS, &numChannels));
445 CHECKERR(ioctl(self->fd, SNDCTL_DSP_SPEED, &ossSpeed));
446 CHECKERR(ioctl(self->fd, SNDCTL_DSP_GETISPACE, &info));
447 if(0)
449 err:
450 ERR("%s failed: %s\n", err, strerror(errno));
451 close(self->fd);
452 self->fd = -1;
453 return ALC_INVALID_VALUE;
455 #undef CHECKERR
457 if((int)ChannelsFromDevFmt(device->FmtChans) != numChannels)
459 ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device->FmtChans), numChannels);
460 close(self->fd);
461 self->fd = -1;
462 return ALC_INVALID_VALUE;
465 if(!((ossFormat == AFMT_S8 && device->FmtType == DevFmtByte) ||
466 (ossFormat == AFMT_U8 && device->FmtType == DevFmtUByte) ||
467 (ossFormat == AFMT_S16_NE && device->FmtType == DevFmtShort)))
469 ERR("Failed to set %s samples, got OSS format %#x\n", DevFmtTypeString(device->FmtType), ossFormat);
470 close(self->fd);
471 self->fd = -1;
472 return ALC_INVALID_VALUE;
475 self->ring = CreateRingBuffer(frameSize, device->UpdateSize * device->NumUpdates);
476 if(!self->ring)
478 ERR("Ring buffer create failed\n");
479 close(self->fd);
480 self->fd = -1;
481 return ALC_OUT_OF_MEMORY;
484 self->data_size = info.fragsize;
485 self->read_data = calloc(1, self->data_size);
487 self->killNow = 0;
488 if(althrd_create(&self->thread, ALCcaptureOSS_recordProc, self) != althrd_success)
490 device->ExtraData = NULL;
491 close(self->fd);
492 self->fd = -1;
493 return ALC_OUT_OF_MEMORY;
496 al_string_copy_cstr(&device->DeviceName, name);
498 return ALC_NO_ERROR;
501 static void ALCcaptureOSS_close(ALCcaptureOSS *self)
503 int res;
505 self->killNow = 1;
506 althrd_join(self->thread, &res);
508 close(self->fd);
509 self->fd = -1;
511 DestroyRingBuffer(self->ring);
512 self->ring = NULL;
514 free(self->read_data);
515 self->read_data = NULL;
518 static ALCboolean ALCcaptureOSS_start(ALCcaptureOSS *self)
520 self->doCapture = 1;
521 return ALC_TRUE;
524 static void ALCcaptureOSS_stop(ALCcaptureOSS *self)
526 self->doCapture = 0;
529 static ALCenum ALCcaptureOSS_captureSamples(ALCcaptureOSS *self, ALCvoid *buffer, ALCuint samples)
531 ReadRingBuffer(self->ring, buffer, samples);
532 return ALC_NO_ERROR;
535 static ALCuint ALCcaptureOSS_availableSamples(ALCcaptureOSS *self)
537 return RingBufferSize(self->ring);
541 typedef struct ALCossBackendFactory {
542 DERIVE_FROM_TYPE(ALCbackendFactory);
543 } ALCossBackendFactory;
544 #define ALCOSSBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCossBackendFactory, ALCbackendFactory) } }
546 ALCbackendFactory *ALCossBackendFactory_getFactory(void);
548 static ALCboolean ALCossBackendFactory_init(ALCossBackendFactory *self);
549 static DECLARE_FORWARD(ALCossBackendFactory, ALCbackendFactory, void, deinit)
550 static ALCboolean ALCossBackendFactory_querySupport(ALCossBackendFactory *self, ALCbackend_Type type);
551 static void ALCossBackendFactory_probe(ALCossBackendFactory *self, enum DevProbe type);
552 static ALCbackend* ALCossBackendFactory_createBackend(ALCossBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
553 DEFINE_ALCBACKENDFACTORY_VTABLE(ALCossBackendFactory);
556 ALCbackendFactory *ALCossBackendFactory_getFactory(void)
558 static ALCossBackendFactory factory = ALCOSSBACKENDFACTORY_INITIALIZER;
559 return STATIC_CAST(ALCbackendFactory, &factory);
563 ALCboolean ALCossBackendFactory_init(ALCossBackendFactory* UNUSED(self))
565 ConfigValueStr("oss", "device", &oss_driver);
566 ConfigValueStr("oss", "capture", &oss_capture);
568 return ALC_TRUE;
571 ALCboolean ALCossBackendFactory_querySupport(ALCossBackendFactory* UNUSED(self), ALCbackend_Type type)
573 if(type == ALCbackend_Playback || type == ALCbackend_Capture)
574 return ALC_TRUE;
575 return ALC_FALSE;
578 void ALCossBackendFactory_probe(ALCossBackendFactory* UNUSED(self), enum DevProbe type)
580 switch(type)
582 case ALL_DEVICE_PROBE:
584 #ifdef HAVE_STAT
585 struct stat buf;
586 if(stat(oss_driver, &buf) == 0)
587 #endif
588 AppendAllDevicesList(oss_device);
590 break;
592 case CAPTURE_DEVICE_PROBE:
594 #ifdef HAVE_STAT
595 struct stat buf;
596 if(stat(oss_capture, &buf) == 0)
597 #endif
598 AppendCaptureDeviceList(oss_device);
600 break;
604 ALCbackend* ALCossBackendFactory_createBackend(ALCossBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
606 if(type == ALCbackend_Playback)
608 ALCplaybackOSS *backend;
610 backend = ALCplaybackOSS_New(sizeof(*backend));
611 if(!backend) return NULL;
612 memset(backend, 0, sizeof(*backend));
614 ALCplaybackOSS_Construct(backend, device);
616 return STATIC_CAST(ALCbackend, backend);
618 if(type == ALCbackend_Capture)
620 ALCcaptureOSS *backend;
622 backend = ALCcaptureOSS_New(sizeof(*backend));
623 if(!backend) return NULL;
624 memset(backend, 0, sizeof(*backend));
626 ALCcaptureOSS_Construct(backend, device);
628 return STATIC_CAST(ALCbackend, backend);
631 return NULL;