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., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include <sys/ioctl.h>
22 #include <sys/types.h>
35 #include <sys/soundcard.h>
38 * The OSS documentation talks about SOUND_MIXER_READ, but the header
39 * only contains MIXER_READ. Play safe. Same for WRITE.
41 #ifndef SOUND_MIXER_READ
42 #define SOUND_MIXER_READ MIXER_READ
44 #ifndef SOUND_MIXER_WRITE
45 #define SOUND_MIXER_WRITE MIXER_WRITE
48 static char *oss_device
;
49 static char *oss_device_capture
;
65 static int log2i(ALCuint x
)
77 static ALuint
OSSProc(ALvoid
*ptr
)
79 ALCdevice
*pDevice
= (ALCdevice
*)ptr
;
80 oss_data
*data
= (oss_data
*)pDevice
->ExtraData
;
87 aluMixData(pDevice
->Context
,data
->mix_data
,data
->data_size
,pDevice
->Format
);
90 remaining
= data
->data_size
;
93 wrote
= write(data
->fd
, data
->mix_data
+data
->data_size
-remaining
, remaining
);
96 AL_PRINT("write failed: %s\n", strerror(errno
));
111 static ALuint
OSSCaptureProc(ALvoid
*ptr
)
113 ALCdevice
*pDevice
= (ALCdevice
*)ptr
;
114 oss_data
*data
= (oss_data
*)pDevice
->ExtraData
;
118 frameSize
= aluBytesFromFormat(pDevice
->Format
);
119 frameSize
*= aluChannelsFromFormat(pDevice
->Format
);
121 while(!data
->killNow
)
123 amt
= read(data
->fd
, data
->mix_data
, data
->data_size
);
126 AL_PRINT("read failed: %s\n", strerror(errno
));
135 WriteRingBuffer(data
->ring
, data
->mix_data
, amt
/frameSize
);
141 static ALCboolean
oss_open_playback(ALCdevice
*device
, const ALCchar
*deviceName
)
143 int numFragmentsLogSize
;
144 int log2FragmentSize
;
145 unsigned int periods
;
155 strncpy(driver
, GetConfigValue("oss", "device", "/dev/dsp"), sizeof(driver
)-1);
156 driver
[sizeof(driver
)-1] = 0;
159 if(strcmp(deviceName
, oss_device
))
161 device
->szDeviceName
= oss_device
;
164 device
->szDeviceName
= oss_device
;
166 data
= (oss_data
*)calloc(1, sizeof(oss_data
));
169 data
->fd
= open(driver
, O_WRONLY
);
173 AL_PRINT("Could not open %s: %s\n", driver
, strerror(errno
));
177 switch(device
->Format
)
179 case AL_FORMAT_MONO8
:
180 case AL_FORMAT_STEREO8
:
181 case AL_FORMAT_QUAD8
:
182 data
->silence
= 0x80;
185 case AL_FORMAT_MONO16
:
186 case AL_FORMAT_STEREO16
:
187 case AL_FORMAT_QUAD16
:
189 ossFormat
= AFMT_S16_NE
;
193 AL_PRINT("Unknown format?! %x\n", device
->Format
);
196 periods
= GetConfigValueInt("oss", "periods", 4);
199 numChannels
= device
->Channels
;
200 ossSpeed
= device
->Frequency
;
201 log2FragmentSize
= log2i(device
->UpdateFreq
* device
->FrameSize
/ periods
);
203 /* according to the OSS spec, 16 bytes are the minimum */
204 if (log2FragmentSize
< 4)
205 log2FragmentSize
= 4;
206 numFragmentsLogSize
= (periods
<< 16) | log2FragmentSize
;
208 #define ok(func, str) (i=(func),((i<0)?(err=(str)),0:1))
209 if (!(ok(ioctl(data
->fd
, SNDCTL_DSP_SETFRAGMENT
, &numFragmentsLogSize
), "set fragment") &&
210 ok(ioctl(data
->fd
, SNDCTL_DSP_SETFMT
, &ossFormat
), "set format") &&
211 ok(ioctl(data
->fd
, SNDCTL_DSP_CHANNELS
, &numChannels
), "set channels") &&
212 ok(ioctl(data
->fd
, SNDCTL_DSP_SPEED
, &ossSpeed
), "set speed") &&
213 ok(ioctl(data
->fd
, SNDCTL_DSP_GETOSPACE
, &info
), "get space")))
215 AL_PRINT("%s failed: %s\n", err
, strerror(errno
));
222 device
->Channels
= numChannels
;
223 device
->Frequency
= ossSpeed
;
225 if(ossFormat
== AFMT_U8
)
227 if(device
->Channels
== 1)
229 device
->Format
= AL_FORMAT_MONO8
;
230 device
->FrameSize
= 1;
232 else if(device
->Channels
== 2)
234 device
->Format
= AL_FORMAT_STEREO8
;
235 device
->FrameSize
= 2;
237 else if(device
->Channels
== 4)
239 device
->Format
= AL_FORMAT_QUAD8
;
240 device
->FrameSize
= 4;
243 else if(ossFormat
== AFMT_S16_NE
)
245 if(device
->Channels
== 1)
247 device
->Format
= AL_FORMAT_MONO16
;
248 device
->FrameSize
= 2;
250 else if(device
->Channels
== 2)
252 device
->Format
= AL_FORMAT_STEREO16
;
253 device
->FrameSize
= 4;
255 else if(device
->Channels
== 4)
257 device
->Format
= AL_FORMAT_QUAD16
;
258 device
->FrameSize
= 8;
264 AL_PRINT("returned unknown format: %#x %d!\n", ossFormat
, numChannels
);
270 device
->UpdateFreq
= info
.fragsize
/ device
->FrameSize
;
272 data
->data_size
= device
->UpdateFreq
* device
->FrameSize
;
273 data
->mix_data
= calloc(1, data
->data_size
);
275 device
->MaxNoOfSources
= 256;
277 device
->ExtraData
= data
;
278 data
->thread
= StartThread(OSSProc
, device
);
279 if(data
->thread
== NULL
)
281 device
->ExtraData
= NULL
;
282 free(data
->mix_data
);
290 static void oss_close_playback(ALCdevice
*device
)
292 oss_data
*data
= (oss_data
*)device
->ExtraData
;
294 StopThread(data
->thread
);
298 free(data
->mix_data
);
300 device
->ExtraData
= NULL
;
304 static ALCboolean
oss_open_capture(ALCdevice
*device
, const ALCchar
*deviceName
, ALCuint frequency
, ALCenum format
, ALCsizei SampleSize
)
306 int numFragmentsLogSize
;
307 int log2FragmentSize
;
308 unsigned int periods
;
318 strncpy(driver
, GetConfigValue("oss", "capture", "/dev/dsp"), sizeof(driver
)-1);
319 driver
[sizeof(driver
)-1] = 0;
322 if(strcmp(deviceName
, oss_device_capture
))
324 device
->szDeviceName
= oss_device_capture
;
327 device
->szDeviceName
= oss_device_capture
;
329 data
= (oss_data
*)calloc(1, sizeof(oss_data
));
332 data
->fd
= open(driver
, O_RDONLY
);
336 AL_PRINT("Could not open %s: %s\n", driver
, strerror(errno
));
342 case AL_FORMAT_MONO8
:
343 case AL_FORMAT_STEREO8
:
344 case AL_FORMAT_QUAD8
:
345 data
->silence
= 0x80;
348 case AL_FORMAT_MONO16
:
349 case AL_FORMAT_STEREO16
:
350 case AL_FORMAT_QUAD16
:
352 ossFormat
= AFMT_S16_NE
;
356 AL_PRINT("Unknown format?! %x\n", device
->Format
);
360 numChannels
= device
->Channels
;
361 ossSpeed
= frequency
;
362 log2FragmentSize
= log2i(device
->UpdateFreq
* device
->FrameSize
/ periods
);
364 /* according to the OSS spec, 16 bytes are the minimum */
365 if (log2FragmentSize
< 4)
366 log2FragmentSize
= 4;
367 numFragmentsLogSize
= (periods
<< 16) | log2FragmentSize
;
369 #define ok(func, str) (i=(func),((i<0)?(err=(str)),0:1))
370 if (!(ok(ioctl(data
->fd
, SNDCTL_DSP_SETFRAGMENT
, &numFragmentsLogSize
), "set fragment") &&
371 ok(ioctl(data
->fd
, SNDCTL_DSP_SETFMT
, &ossFormat
), "set format") &&
372 ok(ioctl(data
->fd
, SNDCTL_DSP_CHANNELS
, &numChannels
), "set channels") &&
373 ok(ioctl(data
->fd
, SNDCTL_DSP_SPEED
, &ossSpeed
), "set speed") &&
374 ok(ioctl(data
->fd
, SNDCTL_DSP_GETISPACE
, &info
), "get space")))
376 AL_PRINT("%s failed: %s\n", err
, strerror(errno
));
383 device
->Channels
= numChannels
;
384 device
->Frequency
= ossSpeed
;
386 if(ossFormat
== AFMT_U8
)
388 if(device
->Channels
== 1)
390 device
->Format
= AL_FORMAT_MONO8
;
391 device
->FrameSize
= 1;
393 else if(device
->Channels
== 2)
395 device
->Format
= AL_FORMAT_STEREO8
;
396 device
->FrameSize
= 2;
398 else if(device
->Channels
== 4)
400 device
->Format
= AL_FORMAT_QUAD8
;
401 device
->FrameSize
= 4;
404 else if(ossFormat
== AFMT_S16_NE
)
406 if(device
->Channels
== 1)
408 device
->Format
= AL_FORMAT_MONO16
;
409 device
->FrameSize
= 2;
411 else if(device
->Channels
== 2)
413 device
->Format
= AL_FORMAT_STEREO16
;
414 device
->FrameSize
= 4;
416 else if(device
->Channels
== 4)
418 device
->Format
= AL_FORMAT_QUAD16
;
419 device
->FrameSize
= 8;
425 AL_PRINT("returned unknown format: %#x %d!\n", ossFormat
, numChannels
);
431 data
->ring
= CreateRingBuffer(device
->FrameSize
, SampleSize
);
434 AL_PRINT("ring buffer create failed\n");
440 device
->UpdateFreq
= info
.fragsize
/ device
->FrameSize
;
442 data
->data_size
= device
->UpdateFreq
* device
->FrameSize
;
443 data
->mix_data
= calloc(1, data
->data_size
);
445 device
->ExtraData
= data
;
446 data
->thread
= StartThread(OSSCaptureProc
, device
);
447 if(data
->thread
== NULL
)
449 device
->ExtraData
= NULL
;
450 free(data
->mix_data
);
458 static void oss_close_capture(ALCdevice
*device
)
460 oss_data
*data
= (oss_data
*)device
->ExtraData
;
462 StopThread(data
->thread
);
466 DestroyRingBuffer(data
->ring
);
468 free(data
->mix_data
);
470 device
->ExtraData
= NULL
;
473 static void oss_start_capture(ALCdevice
*pDevice
)
475 oss_data
*data
= (oss_data
*)pDevice
->ExtraData
;
479 static void oss_stop_capture(ALCdevice
*pDevice
)
481 oss_data
*data
= (oss_data
*)pDevice
->ExtraData
;
485 static void oss_capture_samples(ALCdevice
*pDevice
, ALCvoid
*pBuffer
, ALCuint lSamples
)
487 oss_data
*data
= (oss_data
*)pDevice
->ExtraData
;
488 if(lSamples
<= (ALCuint
)RingBufferSize(data
->ring
))
489 ReadRingBuffer(data
->ring
, pBuffer
, lSamples
);
491 SetALCError(ALC_INVALID_VALUE
);
494 static ALCuint
oss_available_samples(ALCdevice
*pDevice
)
496 oss_data
*data
= (oss_data
*)pDevice
->ExtraData
;
497 return RingBufferSize(data
->ring
);
501 BackendFuncs oss_funcs
= {
509 oss_available_samples
512 void alc_oss_init(BackendFuncs
*func_list
)
514 *func_list
= oss_funcs
;
516 oss_device
= AppendDeviceList("OSS Software");
517 AppendAllDeviceList(oss_device
);
519 oss_device_capture
= AppendCaptureDeviceList("OSS Capture");