zenilib  0.5.3.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
oss.c
Go to the documentation of this file.
1 
21 #include "config.h"
22 
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>
33 
34 #include "alMain.h"
35 #include "alu.h"
36 
37 #include <sys/soundcard.h>
38 
39 /*
40  * The OSS documentation talks about SOUND_MIXER_READ, but the header
41  * only contains MIXER_READ. Play safe. Same for WRITE.
42  */
43 #ifndef SOUND_MIXER_READ
44 #define SOUND_MIXER_READ MIXER_READ
45 #endif
46 #ifndef SOUND_MIXER_WRITE
47 #define SOUND_MIXER_WRITE MIXER_WRITE
48 #endif
49 
50 static const ALCchar oss_device[] = "OSS Default";
51 
52 static const char *oss_driver = "/dev/dsp";
53 static const char *oss_capture = "/dev/dsp";
54 
55 typedef struct {
56  int fd;
57  volatile int killNow;
58  ALvoid *thread;
59 
60  ALubyte *mix_data;
61  int data_size;
62 
63  RingBuffer *ring;
64  int doCapture;
65 } oss_data;
66 
67 
68 static int log2i(ALCuint x)
69 {
70  int y = 0;
71  while (x > 1)
72  {
73  x >>= 1;
74  y++;
75  }
76  return y;
77 }
78 
79 
80 static ALuint OSSProc(ALvoid *ptr)
81 {
82  ALCdevice *Device = (ALCdevice*)ptr;
83  oss_data *data = (oss_data*)Device->ExtraData;
84  ALint frameSize;
85  ssize_t wrote;
86 
87  SetRTPriority();
88 
89  frameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType);
90 
91  while(!data->killNow && Device->Connected)
92  {
93  ALint len = data->data_size;
94  ALubyte *WritePtr = data->mix_data;
95 
96  aluMixData(Device, WritePtr, len/frameSize);
97  while(len > 0 && !data->killNow)
98  {
99  wrote = write(data->fd, WritePtr, len);
100  if(wrote < 0)
101  {
102  if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR)
103  {
104  ERR("write failed: %s\n", strerror(errno));
105  ALCdevice_Lock(Device);
106  aluHandleDisconnect(Device);
107  ALCdevice_Unlock(Device);
108  break;
109  }
110 
111  Sleep(1);
112  continue;
113  }
114 
115  len -= wrote;
116  WritePtr += wrote;
117  }
118  }
119 
120  return 0;
121 }
122 
124 {
125  ALCdevice *Device = (ALCdevice*)ptr;
126  oss_data *data = (oss_data*)Device->ExtraData;
127  int frameSize;
128  int amt;
129 
130  SetRTPriority();
131 
132  frameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType);
133 
134  while(!data->killNow)
135  {
136  amt = read(data->fd, data->mix_data, data->data_size);
137  if(amt < 0)
138  {
139  ERR("read failed: %s\n", strerror(errno));
140  ALCdevice_Lock(Device);
141  aluHandleDisconnect(Device);
142  ALCdevice_Unlock(Device);
143  break;
144  }
145  if(amt == 0)
146  {
147  Sleep(1);
148  continue;
149  }
150  if(data->doCapture)
151  WriteRingBuffer(data->ring, data->mix_data, amt/frameSize);
152  }
153 
154  return 0;
155 }
156 
157 static ALCenum oss_open_playback(ALCdevice *device, const ALCchar *deviceName)
158 {
159  oss_data *data;
160 
161  if(!deviceName)
162  deviceName = oss_device;
163  else if(strcmp(deviceName, oss_device) != 0)
164  return ALC_INVALID_VALUE;
165 
166  data = (oss_data*)calloc(1, sizeof(oss_data));
167  data->killNow = 0;
168 
169  data->fd = open(oss_driver, O_WRONLY);
170  if(data->fd == -1)
171  {
172  free(data);
173  ERR("Could not open %s: %s\n", oss_driver, strerror(errno));
174  return ALC_INVALID_VALUE;
175  }
176 
177  device->DeviceName = strdup(deviceName);
178  device->ExtraData = data;
179  return ALC_NO_ERROR;
180 }
181 
182 static void oss_close_playback(ALCdevice *device)
183 {
184  oss_data *data = (oss_data*)device->ExtraData;
185 
186  close(data->fd);
187  free(data);
188  device->ExtraData = NULL;
189 }
190 
192 {
193  oss_data *data = (oss_data*)device->ExtraData;
194  int numFragmentsLogSize;
195  int log2FragmentSize;
196  unsigned int periods;
197  audio_buf_info info;
198  ALuint frameSize;
199  int numChannels;
200  int ossFormat;
201  int ossSpeed;
202  char *err;
203 
204  switch(device->FmtType)
205  {
206  case DevFmtByte:
207  ossFormat = AFMT_S8;
208  break;
209  case DevFmtUByte:
210  ossFormat = AFMT_U8;
211  break;
212  case DevFmtUShort:
213  case DevFmtInt:
214  case DevFmtUInt:
215  case DevFmtFloat:
216  device->FmtType = DevFmtShort;
217  /* fall-through */
218  case DevFmtShort:
219  ossFormat = AFMT_S16_NE;
220  break;
221  }
222 
223  periods = device->NumUpdates;
224  numChannels = ChannelsFromDevFmt(device->FmtChans);
225  frameSize = numChannels * BytesFromDevFmt(device->FmtType);
226 
227  ossSpeed = device->Frequency;
228  log2FragmentSize = log2i(device->UpdateSize * frameSize);
229 
230  /* according to the OSS spec, 16 bytes are the minimum */
231  if (log2FragmentSize < 4)
232  log2FragmentSize = 4;
233  /* Subtract one period since the temp mixing buffer counts as one. Still
234  * need at least two on the card, though. */
235  if(periods > 2) periods--;
236  numFragmentsLogSize = (periods << 16) | log2FragmentSize;
237 
238 #define CHECKERR(func) if((func) < 0) { \
239  err = #func; \
240  goto err; \
241 }
242  /* Don't fail if SETFRAGMENT fails. We can handle just about anything
243  * that's reported back via GETOSPACE */
244  ioctl(data->fd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize);
245  CHECKERR(ioctl(data->fd, SNDCTL_DSP_SETFMT, &ossFormat));
246  CHECKERR(ioctl(data->fd, SNDCTL_DSP_CHANNELS, &numChannels));
247  CHECKERR(ioctl(data->fd, SNDCTL_DSP_SPEED, &ossSpeed));
248  CHECKERR(ioctl(data->fd, SNDCTL_DSP_GETOSPACE, &info));
249  if(0)
250  {
251  err:
252  ERR("%s failed: %s\n", err, strerror(errno));
253  return ALC_FALSE;
254  }
255 #undef CHECKERR
256 
257  if((int)ChannelsFromDevFmt(device->FmtChans) != numChannels)
258  {
259  ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device->FmtChans), numChannels);
260  return ALC_FALSE;
261  }
262 
263  if(!((ossFormat == AFMT_S8 && device->FmtType == DevFmtByte) ||
264  (ossFormat == AFMT_U8 && device->FmtType == DevFmtUByte) ||
265  (ossFormat == AFMT_S16_NE && device->FmtType == DevFmtShort)))
266  {
267  ERR("Failed to set %s samples, got OSS format %#x\n", DevFmtTypeString(device->FmtType), ossFormat);
268  return ALC_FALSE;
269  }
270 
271  device->Frequency = ossSpeed;
272  device->UpdateSize = info.fragsize / frameSize;
273  device->NumUpdates = info.fragments + 1;
274 
275  SetDefaultChannelOrder(device);
276 
277  return ALC_TRUE;
278 }
279 
281 {
282  oss_data *data = (oss_data*)device->ExtraData;
283 
284  data->data_size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
285  data->mix_data = calloc(1, data->data_size);
286 
287  data->thread = StartThread(OSSProc, device);
288  if(data->thread == NULL)
289  {
290  free(data->mix_data);
291  data->mix_data = NULL;
292  return ALC_FALSE;
293  }
294 
295  return ALC_TRUE;
296 }
297 
298 static void oss_stop_playback(ALCdevice *device)
299 {
300  oss_data *data = (oss_data*)device->ExtraData;
301 
302  if(!data->thread)
303  return;
304 
305  data->killNow = 1;
306  StopThread(data->thread);
307  data->thread = NULL;
308 
309  data->killNow = 0;
310  if(ioctl(data->fd, SNDCTL_DSP_RESET) != 0)
311  ERR("Error resetting device: %s\n", strerror(errno));
312 
313  free(data->mix_data);
314  data->mix_data = NULL;
315 }
316 
317 
318 static ALCenum oss_open_capture(ALCdevice *device, const ALCchar *deviceName)
319 {
320  int numFragmentsLogSize;
321  int log2FragmentSize;
322  unsigned int periods;
323  audio_buf_info info;
324  ALuint frameSize;
325  int numChannels;
326  oss_data *data;
327  int ossFormat;
328  int ossSpeed;
329  char *err;
330 
331  if(!deviceName)
332  deviceName = oss_device;
333  else if(strcmp(deviceName, oss_device) != 0)
334  return ALC_INVALID_VALUE;
335 
336  data = (oss_data*)calloc(1, sizeof(oss_data));
337  data->killNow = 0;
338 
339  data->fd = open(oss_capture, O_RDONLY);
340  if(data->fd == -1)
341  {
342  free(data);
343  ERR("Could not open %s: %s\n", oss_capture, strerror(errno));
344  return ALC_INVALID_VALUE;
345  }
346 
347  switch(device->FmtType)
348  {
349  case DevFmtByte:
350  ossFormat = AFMT_S8;
351  break;
352  case DevFmtUByte:
353  ossFormat = AFMT_U8;
354  break;
355  case DevFmtShort:
356  ossFormat = AFMT_S16_NE;
357  break;
358  case DevFmtUShort:
359  case DevFmtInt:
360  case DevFmtUInt:
361  case DevFmtFloat:
362  free(data);
363  ERR("%s capture samples not supported\n", DevFmtTypeString(device->FmtType));
364  return ALC_INVALID_VALUE;
365  }
366 
367  periods = 4;
368  numChannels = ChannelsFromDevFmt(device->FmtChans);
369  frameSize = numChannels * BytesFromDevFmt(device->FmtType);
370  ossSpeed = device->Frequency;
371  log2FragmentSize = log2i(device->UpdateSize * device->NumUpdates *
372  frameSize / periods);
373 
374  /* according to the OSS spec, 16 bytes are the minimum */
375  if (log2FragmentSize < 4)
376  log2FragmentSize = 4;
377  numFragmentsLogSize = (periods << 16) | log2FragmentSize;
378 
379 #define CHECKERR(func) if((func) < 0) { \
380  err = #func; \
381  goto err; \
382 }
383  CHECKERR(ioctl(data->fd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize));
384  CHECKERR(ioctl(data->fd, SNDCTL_DSP_SETFMT, &ossFormat));
385  CHECKERR(ioctl(data->fd, SNDCTL_DSP_CHANNELS, &numChannels));
386  CHECKERR(ioctl(data->fd, SNDCTL_DSP_SPEED, &ossSpeed));
387  CHECKERR(ioctl(data->fd, SNDCTL_DSP_GETISPACE, &info));
388  if(0)
389  {
390  err:
391  ERR("%s failed: %s\n", err, strerror(errno));
392  close(data->fd);
393  free(data);
394  return ALC_INVALID_VALUE;
395  }
396 #undef CHECKERR
397 
398  if((int)ChannelsFromDevFmt(device->FmtChans) != numChannels)
399  {
400  ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device->FmtChans), numChannels);
401  close(data->fd);
402  free(data);
403  return ALC_INVALID_VALUE;
404  }
405 
406  if(!((ossFormat == AFMT_S8 && device->FmtType == DevFmtByte) ||
407  (ossFormat == AFMT_U8 && device->FmtType == DevFmtUByte) ||
408  (ossFormat == AFMT_S16_NE && device->FmtType == DevFmtShort)))
409  {
410  ERR("Failed to set %s samples, got OSS format %#x\n", DevFmtTypeString(device->FmtType), ossFormat);
411  close(data->fd);
412  free(data);
413  return ALC_INVALID_VALUE;
414  }
415 
416  data->ring = CreateRingBuffer(frameSize, device->UpdateSize * device->NumUpdates);
417  if(!data->ring)
418  {
419  ERR("Ring buffer create failed\n");
420  close(data->fd);
421  free(data);
422  return ALC_OUT_OF_MEMORY;
423  }
424 
425  data->data_size = info.fragsize;
426  data->mix_data = calloc(1, data->data_size);
427 
428  device->ExtraData = data;
429  data->thread = StartThread(OSSCaptureProc, device);
430  if(data->thread == NULL)
431  {
432  device->ExtraData = NULL;
433  free(data->mix_data);
434  free(data);
435  return ALC_OUT_OF_MEMORY;
436  }
437 
438  device->DeviceName = strdup(deviceName);
439  return ALC_NO_ERROR;
440 }
441 
442 static void oss_close_capture(ALCdevice *device)
443 {
444  oss_data *data = (oss_data*)device->ExtraData;
445  data->killNow = 1;
446  StopThread(data->thread);
447 
448  close(data->fd);
449 
450  DestroyRingBuffer(data->ring);
451 
452  free(data->mix_data);
453  free(data);
454  device->ExtraData = NULL;
455 }
456 
457 static void oss_start_capture(ALCdevice *Device)
458 {
459  oss_data *data = (oss_data*)Device->ExtraData;
460  data->doCapture = 1;
461 }
462 
463 static void oss_stop_capture(ALCdevice *Device)
464 {
465  oss_data *data = (oss_data*)Device->ExtraData;
466  data->doCapture = 0;
467 }
468 
469 static ALCenum oss_capture_samples(ALCdevice *Device, ALCvoid *pBuffer, ALCuint lSamples)
470 {
471  oss_data *data = (oss_data*)Device->ExtraData;
472  ReadRingBuffer(data->ring, pBuffer, lSamples);
473  return ALC_NO_ERROR;
474 }
475 
477 {
478  oss_data *data = (oss_data*)Device->ExtraData;
479  return RingBufferSize(data->ring);
480 }
481 
482 
483 static const BackendFuncs oss_funcs = {
498 };
499 
501 {
502  ConfigValueStr("oss", "device", &oss_driver);
503  ConfigValueStr("oss", "capture", &oss_capture);
504 
505  *func_list = oss_funcs;
506  return ALC_TRUE;
507 }
508 
509 void alc_oss_deinit(void)
510 {
511 }
512 
514 {
515  switch(type)
516  {
517  case ALL_DEVICE_PROBE:
518  {
519 #ifdef HAVE_STAT
520  struct stat buf;
521  if(stat(oss_driver, &buf) == 0)
522 #endif
524  }
525  break;
526 
528  {
529 #ifdef HAVE_STAT
530  struct stat buf;
531  if(stat(oss_capture, &buf) == 0)
532 #endif
534  }
535  break;
536  }
537 }
static const BackendFuncs oss_funcs
Definition: oss.c:483
int ConfigValueStr(const char *blockName, const char *keyName, const char **ret)
Definition: alcConfig.c:316
unsigned char ALubyte
Definition: al.h:47
ALCboolean Connected
Definition: alMain.h:564
static ALCboolean oss_start_playback(ALCdevice *device)
Definition: oss.c:280
void ALvoid
Definition: al.h:74
#define ALC_TRUE
Definition: alc.h:84
GLint GLenum GLsizei GLsizei GLsizei GLint GLenum GLenum type
Definition: gl2ext.h:845
char * strdup(const char *inStr)
Definition: strdup.c:6
static ALuint OSSCaptureProc(ALvoid *ptr)
Definition: oss.c:123
#define NULL
Definition: ftobjs.h:61
const ALCchar * DevFmtChannelsString(enum DevFmtChannels chans)
Definition: ALc.c:1150
EGLSurface EGLint x
Definition: eglext.h:293
SDL_EventEntry * free
Definition: SDL_events.c:80
ALuint Frequency
Definition: alMain.h:569
void alc_oss_probe(enum DevProbe type)
Definition: oss.c:513
int ALint
Definition: al.h:56
ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
Definition: ALu.c:970
ALint64 ALCdevice_GetLatencyDefault(ALCdevice *device)
Definition: ALc.c:1285
static ALCenum oss_open_capture(ALCdevice *device, const ALCchar *deviceName)
Definition: oss.c:318
static ALuint OSSProc(ALvoid *ptr)
Definition: oss.c:80
static int log2i(ALCuint x)
Definition: oss.c:68
GLenum GLsizei len
Definition: glew.h:7035
ALsizei RingBufferSize(RingBuffer *ring)
Definition: alcRing.c:67
void SetDefaultChannelOrder(ALCdevice *device)
Definition: ALc.c:1352
void AppendCaptureDeviceList(const ALCchar *name)
unsigned int ALCuint
Definition: alc.h:60
#define calloc
Definition: SDL_malloc.c:636
ALvoid aluHandleDisconnect(ALCdevice *device)
Definition: ALu.c:1176
char ALCchar
Definition: alc.h:42
#define Sleep(x)
Definition: allatency.c:34
#define ALCdevice_Unlock(a)
Definition: alMain.h:647
struct RingBuffer RingBuffer
Definition: alMain.h:750
void * ExtraData
Definition: alMain.h:630
#define ALC_FALSE
Definition: alc.h:81
ALuint StopThread(ALvoid *thread)
Definition: alcThread.c:131
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl2ext.h:848
static void oss_stop_playback(ALCdevice *device)
Definition: oss.c:298
RingBuffer * CreateRingBuffer(ALsizei frame_size, ALsizei length)
Definition: alcRing.c:41
void alc_oss_deinit(void)
Definition: oss.c:509
static const char * oss_driver
Definition: oss.c:52
unsigned int ALuint
Definition: al.h:59
void SetRTPriority(void)
Definition: helpers.c:470
#define CHECKERR(func)
enum DevFmtChannels FmtChans
Definition: alMain.h:572
static void oss_close_playback(ALCdevice *device)
Definition: oss.c:182
static SDL_Thread * thread
static const char * oss_capture
Definition: oss.c:53
EGLSurface EGLint EGLint y
Definition: eglext.h:293
#define ALC_NO_ERROR
Definition: alc.h:102
void ALCdevice_LockDefault(ALCdevice *device)
Definition: ALc.c:1277
ALCboolean alc_oss_init(BackendFuncs *func_list)
Definition: oss.c:500
char ALCboolean
Definition: alc.h:39
static const ALCchar oss_device[]
Definition: oss.c:50
void ALCvoid
Definition: alc.h:75
#define ERR(...)
Definition: alMain.h:816
static void oss_stop_capture(ALCdevice *Device)
Definition: oss.c:463
ALuint UpdateSize
Definition: alMain.h:570
ALuint NumUpdates
Definition: alMain.h:571
enum DevFmtType FmtType
Definition: alMain.h:573
ALCchar * DeviceName
Definition: alMain.h:575
#define ALC_INVALID_VALUE
Definition: alc.h:114
#define ALC_OUT_OF_MEMORY
Definition: alc.h:117
void ReadRingBuffer(RingBuffer *ring, ALubyte *data, ALsizei len)
Definition: alcRing.c:108
static ALCenum oss_open_playback(ALCdevice *device, const ALCchar *deviceName)
Definition: oss.c:157
static ALCboolean oss_reset_playback(ALCdevice *device)
Definition: oss.c:191
int ALCenum
Definition: alc.h:66
const ALCchar * DevFmtTypeString(enum DevFmtType type)
Definition: ALc.c:1136
ALuint BytesFromDevFmt(enum DevFmtType type)
Definition: ALc.c:1165
static void oss_start_capture(ALCdevice *Device)
Definition: oss.c:457
static void oss_close_capture(ALCdevice *device)
Definition: oss.c:442
void DestroyRingBuffer(RingBuffer *ring)
Definition: alcRing.c:58
void ALCdevice_UnlockDefault(ALCdevice *device)
Definition: ALc.c:1281
void WriteRingBuffer(RingBuffer *ring, const ALubyte *data, ALsizei len)
Definition: alcRing.c:78
ALuint ChannelsFromDevFmt(enum DevFmtChannels chans)
Definition: ALc.c:1179
static ALCenum oss_capture_samples(ALCdevice *Device, ALCvoid *pBuffer, ALCuint lSamples)
Definition: oss.c:469
#define ALCdevice_Lock(a)
Definition: alMain.h:646
static ALCuint oss_available_samples(ALCdevice *Device)
Definition: oss.c:476
void AppendAllDevicesList(const ALCchar *name)
ALvoid * StartThread(ALuint(*func)(ALvoid *), ALvoid *ptr)
Definition: alcThread.c:100
DevProbe
Definition: alMain.h:383
static __inline ALuint FrameSizeFromDevFmt(enum DevFmtChannels chans, enum DevFmtType type)
Definition: alMain.h:523