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
23
#include <sys/ioctl.h>
24
#include <sys/types.h>
37
#include <sys/soundcard.h>
40
* The OSS documentation talks about SOUND_MIXER_READ, but the header
41
* only contains MIXER_READ. Play safe. Same for WRITE.
43
#ifndef SOUND_MIXER_READ
44
#define SOUND_MIXER_READ MIXER_READ
46
#ifndef SOUND_MIXER_WRITE
47
#define SOUND_MIXER_WRITE MIXER_WRITE
50
static const ALCchar oss_device[] = "OSS Default";
52
static const char *oss_driver = "/dev/dsp";
53
static const char *oss_capture = "/dev/dsp";
68
static int log2i(ALCuint x)
80
static ALuint OSSProc(ALvoid *ptr)
82
ALCdevice *pDevice = (ALCdevice*)ptr;
83
oss_data *data = (oss_data*)pDevice->ExtraData;
89
frameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);
91
while(!data->killNow && pDevice->Connected)
93
ALint len = data->data_size;
94
ALubyte *WritePtr = data->mix_data;
96
aluMixData(pDevice, WritePtr, len/frameSize);
97
while(len > 0 && !data->killNow)
99
wrote = write(data->fd, WritePtr, len);
102
if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR)
104
ERR("write failed: %s\n", strerror(errno));
105
aluHandleDisconnect(pDevice);
121
static ALuint OSSCaptureProc(ALvoid *ptr)
123
ALCdevice *pDevice = (ALCdevice*)ptr;
124
oss_data *data = (oss_data*)pDevice->ExtraData;
130
frameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);
132
while(!data->killNow)
134
amt = read(data->fd, data->mix_data, data->data_size);
137
ERR("read failed: %s\n", strerror(errno));
138
aluHandleDisconnect(pDevice);
147
WriteRingBuffer(data->ring, data->mix_data, amt/frameSize);
153
static ALCenum oss_open_playback(ALCdevice *device, const ALCchar *deviceName)
158
deviceName = oss_device;
159
else if(strcmp(deviceName, oss_device) != 0)
160
return ALC_INVALID_VALUE;
162
data = (oss_data*)calloc(1, sizeof(oss_data));
165
data->fd = open(oss_driver, O_WRONLY);
169
ERR("Could not open %s: %s\n", oss_driver, strerror(errno));
170
return ALC_INVALID_VALUE;
173
device->szDeviceName = strdup(deviceName);
174
device->ExtraData = data;
178
static void oss_close_playback(ALCdevice *device)
180
oss_data *data = (oss_data*)device->ExtraData;
184
device->ExtraData = NULL;
187
static ALCboolean oss_reset_playback(ALCdevice *device)
189
oss_data *data = (oss_data*)device->ExtraData;
190
int numFragmentsLogSize;
191
int log2FragmentSize;
192
unsigned int periods;
200
switch(device->FmtType)
212
device->FmtType = DevFmtShort;
215
ossFormat = AFMT_S16_NE;
219
periods = device->NumUpdates;
220
numChannels = ChannelsFromDevFmt(device->FmtChans);
221
frameSize = numChannels * BytesFromDevFmt(device->FmtType);
223
ossSpeed = device->Frequency;
224
log2FragmentSize = log2i(device->UpdateSize * frameSize);
226
/* according to the OSS spec, 16 bytes are the minimum */
227
if (log2FragmentSize < 4)
228
log2FragmentSize = 4;
229
/* Subtract one period since the temp mixing buffer counts as one. Still
230
* need at least two on the card, though. */
231
if(periods > 2) periods--;
232
numFragmentsLogSize = (periods << 16) | log2FragmentSize;
234
#define CHECKERR(func) if((func) < 0) { \
238
/* Don't fail if SETFRAGMENT fails. We can handle just about anything
239
* that's reported back via GETOSPACE */
240
ioctl(data->fd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize);
241
CHECKERR(ioctl(data->fd, SNDCTL_DSP_SETFMT, &ossFormat));
242
CHECKERR(ioctl(data->fd, SNDCTL_DSP_CHANNELS, &numChannels));
243
CHECKERR(ioctl(data->fd, SNDCTL_DSP_SPEED, &ossSpeed));
244
CHECKERR(ioctl(data->fd, SNDCTL_DSP_GETOSPACE, &info));
248
ERR("%s failed: %s\n", err, strerror(errno));
253
if((int)ChannelsFromDevFmt(device->FmtChans) != numChannels)
255
ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device->FmtChans), numChannels);
259
if(!((ossFormat == AFMT_S8 && device->FmtType == DevFmtByte) ||
260
(ossFormat == AFMT_U8 && device->FmtType == DevFmtUByte) ||
261
(ossFormat == AFMT_S16_NE && device->FmtType == DevFmtShort)))
263
ERR("Failed to set %s samples, got OSS format %#x\n", DevFmtTypeString(device->FmtType), ossFormat);
267
device->Frequency = ossSpeed;
268
device->UpdateSize = info.fragsize / frameSize;
269
device->NumUpdates = info.fragments + 1;
271
SetDefaultChannelOrder(device);
276
static ALCboolean oss_start_playback(ALCdevice *device)
278
oss_data *data = (oss_data*)device->ExtraData;
280
data->data_size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
281
data->mix_data = calloc(1, data->data_size);
283
data->thread = StartThread(OSSProc, device);
284
if(data->thread == NULL)
286
free(data->mix_data);
287
data->mix_data = NULL;
294
static void oss_stop_playback(ALCdevice *device)
296
oss_data *data = (oss_data*)device->ExtraData;
302
StopThread(data->thread);
306
if(ioctl(data->fd, SNDCTL_DSP_RESET) != 0)
307
ERR("Error resetting device: %s\n", strerror(errno));
309
free(data->mix_data);
310
data->mix_data = NULL;
314
static ALCenum oss_open_capture(ALCdevice *device, const ALCchar *deviceName)
316
int numFragmentsLogSize;
317
int log2FragmentSize;
318
unsigned int periods;
328
deviceName = oss_device;
329
else if(strcmp(deviceName, oss_device) != 0)
330
return ALC_INVALID_VALUE;
332
data = (oss_data*)calloc(1, sizeof(oss_data));
335
data->fd = open(oss_capture, O_RDONLY);
339
ERR("Could not open %s: %s\n", oss_capture, strerror(errno));
340
return ALC_INVALID_VALUE;
343
switch(device->FmtType)
352
ossFormat = AFMT_S16_NE;
359
ERR("%s capture samples not supported\n", DevFmtTypeString(device->FmtType));
360
return ALC_INVALID_VALUE;
364
numChannels = ChannelsFromDevFmt(device->FmtChans);
365
frameSize = numChannels * BytesFromDevFmt(device->FmtType);
366
ossSpeed = device->Frequency;
367
log2FragmentSize = log2i(device->UpdateSize * device->NumUpdates *
368
frameSize / periods);
370
/* according to the OSS spec, 16 bytes are the minimum */
371
if (log2FragmentSize < 4)
372
log2FragmentSize = 4;
373
numFragmentsLogSize = (periods << 16) | log2FragmentSize;
375
#define CHECKERR(func) if((func) < 0) { \
379
CHECKERR(ioctl(data->fd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize));
380
CHECKERR(ioctl(data->fd, SNDCTL_DSP_SETFMT, &ossFormat));
381
CHECKERR(ioctl(data->fd, SNDCTL_DSP_CHANNELS, &numChannels));
382
CHECKERR(ioctl(data->fd, SNDCTL_DSP_SPEED, &ossSpeed));
383
CHECKERR(ioctl(data->fd, SNDCTL_DSP_GETISPACE, &info));
387
ERR("%s failed: %s\n", err, strerror(errno));
390
return ALC_INVALID_VALUE;
394
if((int)ChannelsFromDevFmt(device->FmtChans) != numChannels)
396
ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device->FmtChans), numChannels);
399
return ALC_INVALID_VALUE;
402
if(!((ossFormat == AFMT_S8 && device->FmtType == DevFmtByte) ||
403
(ossFormat == AFMT_U8 && device->FmtType == DevFmtUByte) ||
404
(ossFormat == AFMT_S16_NE && device->FmtType == DevFmtShort)))
406
ERR("Failed to set %s samples, got OSS format %#x\n", DevFmtTypeString(device->FmtType), ossFormat);
409
return ALC_INVALID_VALUE;
412
data->ring = CreateRingBuffer(frameSize, device->UpdateSize * device->NumUpdates);
415
ERR("Ring buffer create failed\n");
418
return ALC_OUT_OF_MEMORY;
421
data->data_size = info.fragsize;
422
data->mix_data = calloc(1, data->data_size);
424
device->ExtraData = data;
425
data->thread = StartThread(OSSCaptureProc, device);
426
if(data->thread == NULL)
428
device->ExtraData = NULL;
429
free(data->mix_data);
431
return ALC_OUT_OF_MEMORY;
434
device->szDeviceName = strdup(deviceName);
438
static void oss_close_capture(ALCdevice *device)
440
oss_data *data = (oss_data*)device->ExtraData;
442
StopThread(data->thread);
446
DestroyRingBuffer(data->ring);
448
free(data->mix_data);
450
device->ExtraData = NULL;
453
static void oss_start_capture(ALCdevice *pDevice)
455
oss_data *data = (oss_data*)pDevice->ExtraData;
459
static void oss_stop_capture(ALCdevice *pDevice)
461
oss_data *data = (oss_data*)pDevice->ExtraData;
465
static ALCenum oss_capture_samples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples)
467
oss_data *data = (oss_data*)pDevice->ExtraData;
468
ReadRingBuffer(data->ring, pBuffer, lSamples);
472
static ALCuint oss_available_samples(ALCdevice *pDevice)
474
oss_data *data = (oss_data*)pDevice->ExtraData;
475
return RingBufferSize(data->ring);
479
static const BackendFuncs oss_funcs = {
490
oss_available_samples
493
ALCboolean alc_oss_init(BackendFuncs *func_list)
495
ConfigValueStr("oss", "device", &oss_driver);
496
ConfigValueStr("oss", "capture", &oss_capture);
498
*func_list = oss_funcs;
502
void alc_oss_deinit(void)
506
void alc_oss_probe(enum DevProbe type)
510
case ALL_DEVICE_PROBE:
514
if(stat(oss_device, &buf) == 0)
516
AppendAllDeviceList(oss_device);
520
case CAPTURE_DEVICE_PROBE:
524
if(stat(oss_capture, &buf) == 0)
526
AppendCaptureDeviceList(oss_device);