~ubuntu-branches/ubuntu/quantal/openal-soft/quantal

« back to all changes in this revision

Viewing changes to Alc/backends/oss.c

  • Committer: Package Import Robot
  • Author(s): Michael Terry
  • Date: 2012-05-22 10:14:53 UTC
  • mfrom: (7.1.9 sid)
  • Revision ID: package-import@ubuntu.com-20120522101453-knsv1m1m8vl5ccfp
Tags: 1:1.14-3ubuntu1
* Merge from Debian testing.  Remaining changes:
  - Add a symbols file for libopenal1
* debian/libopenal1.symbols:
  - Update for 1.14

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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.
 
8
 *
 
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.
 
13
 *
 
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
 
19
 */
 
20
 
 
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
#include "alMain.h"
 
34
#include "AL/al.h"
 
35
#include "AL/alc.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 *pDevice = (ALCdevice*)ptr;
 
83
    oss_data *data = (oss_data*)pDevice->ExtraData;
 
84
    ALint frameSize;
 
85
    ssize_t wrote;
 
86
 
 
87
    SetRTPriority();
 
88
 
 
89
    frameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);
 
90
 
 
91
    while(!data->killNow && pDevice->Connected)
 
92
    {
 
93
        ALint len = data->data_size;
 
94
        ALubyte *WritePtr = data->mix_data;
 
95
 
 
96
        aluMixData(pDevice, 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
                    aluHandleDisconnect(pDevice);
 
106
                    break;
 
107
                }
 
108
 
 
109
                Sleep(1);
 
110
                continue;
 
111
            }
 
112
 
 
113
            len -= wrote;
 
114
            WritePtr += wrote;
 
115
        }
 
116
    }
 
117
 
 
118
    return 0;
 
119
}
 
120
 
 
121
static ALuint OSSCaptureProc(ALvoid *ptr)
 
122
{
 
123
    ALCdevice *pDevice = (ALCdevice*)ptr;
 
124
    oss_data *data = (oss_data*)pDevice->ExtraData;
 
125
    int frameSize;
 
126
    int amt;
 
127
 
 
128
    SetRTPriority();
 
129
 
 
130
    frameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);
 
131
 
 
132
    while(!data->killNow)
 
133
    {
 
134
        amt = read(data->fd, data->mix_data, data->data_size);
 
135
        if(amt < 0)
 
136
        {
 
137
            ERR("read failed: %s\n", strerror(errno));
 
138
            aluHandleDisconnect(pDevice);
 
139
            break;
 
140
        }
 
141
        if(amt == 0)
 
142
        {
 
143
            Sleep(1);
 
144
            continue;
 
145
        }
 
146
        if(data->doCapture)
 
147
            WriteRingBuffer(data->ring, data->mix_data, amt/frameSize);
 
148
    }
 
149
 
 
150
    return 0;
 
151
}
 
152
 
 
153
static ALCenum oss_open_playback(ALCdevice *device, const ALCchar *deviceName)
 
154
{
 
155
    oss_data *data;
 
156
 
 
157
    if(!deviceName)
 
158
        deviceName = oss_device;
 
159
    else if(strcmp(deviceName, oss_device) != 0)
 
160
        return ALC_INVALID_VALUE;
 
161
 
 
162
    data = (oss_data*)calloc(1, sizeof(oss_data));
 
163
    data->killNow = 0;
 
164
 
 
165
    data->fd = open(oss_driver, O_WRONLY);
 
166
    if(data->fd == -1)
 
167
    {
 
168
        free(data);
 
169
        ERR("Could not open %s: %s\n", oss_driver, strerror(errno));
 
170
        return ALC_INVALID_VALUE;
 
171
    }
 
172
 
 
173
    device->szDeviceName = strdup(deviceName);
 
174
    device->ExtraData = data;
 
175
    return ALC_NO_ERROR;
 
176
}
 
177
 
 
178
static void oss_close_playback(ALCdevice *device)
 
179
{
 
180
    oss_data *data = (oss_data*)device->ExtraData;
 
181
 
 
182
    close(data->fd);
 
183
    free(data);
 
184
    device->ExtraData = NULL;
 
185
}
 
186
 
 
187
static ALCboolean oss_reset_playback(ALCdevice *device)
 
188
{
 
189
    oss_data *data = (oss_data*)device->ExtraData;
 
190
    int numFragmentsLogSize;
 
191
    int log2FragmentSize;
 
192
    unsigned int periods;
 
193
    audio_buf_info info;
 
194
    ALuint frameSize;
 
195
    int numChannels;
 
196
    int ossFormat;
 
197
    int ossSpeed;
 
198
    char *err;
 
199
 
 
200
    switch(device->FmtType)
 
201
    {
 
202
        case DevFmtByte:
 
203
            ossFormat = AFMT_S8;
 
204
            break;
 
205
        case DevFmtUByte:
 
206
            ossFormat = AFMT_U8;
 
207
            break;
 
208
        case DevFmtUShort:
 
209
        case DevFmtInt:
 
210
        case DevFmtUInt:
 
211
        case DevFmtFloat:
 
212
            device->FmtType = DevFmtShort;
 
213
            /* fall-through */
 
214
        case DevFmtShort:
 
215
            ossFormat = AFMT_S16_NE;
 
216
            break;
 
217
    }
 
218
 
 
219
    periods = device->NumUpdates;
 
220
    numChannels = ChannelsFromDevFmt(device->FmtChans);
 
221
    frameSize = numChannels * BytesFromDevFmt(device->FmtType);
 
222
 
 
223
    ossSpeed = device->Frequency;
 
224
    log2FragmentSize = log2i(device->UpdateSize * frameSize);
 
225
 
 
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;
 
233
 
 
234
#define CHECKERR(func) if((func) < 0) {                                       \
 
235
    err = #func;                                                              \
 
236
    goto err;                                                                 \
 
237
}
 
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));
 
245
    if(0)
 
246
    {
 
247
    err:
 
248
        ERR("%s failed: %s\n", err, strerror(errno));
 
249
        return ALC_FALSE;
 
250
    }
 
251
#undef CHECKERR
 
252
 
 
253
    if((int)ChannelsFromDevFmt(device->FmtChans) != numChannels)
 
254
    {
 
255
        ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device->FmtChans), numChannels);
 
256
        return ALC_FALSE;
 
257
    }
 
258
 
 
259
    if(!((ossFormat == AFMT_S8 && device->FmtType == DevFmtByte) ||
 
260
         (ossFormat == AFMT_U8 && device->FmtType == DevFmtUByte) ||
 
261
         (ossFormat == AFMT_S16_NE && device->FmtType == DevFmtShort)))
 
262
    {
 
263
        ERR("Failed to set %s samples, got OSS format %#x\n", DevFmtTypeString(device->FmtType), ossFormat);
 
264
        return ALC_FALSE;
 
265
    }
 
266
 
 
267
    device->Frequency = ossSpeed;
 
268
    device->UpdateSize = info.fragsize / frameSize;
 
269
    device->NumUpdates = info.fragments + 1;
 
270
 
 
271
    SetDefaultChannelOrder(device);
 
272
 
 
273
    return ALC_TRUE;
 
274
}
 
275
 
 
276
static ALCboolean oss_start_playback(ALCdevice *device)
 
277
{
 
278
    oss_data *data = (oss_data*)device->ExtraData;
 
279
 
 
280
    data->data_size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
 
281
    data->mix_data = calloc(1, data->data_size);
 
282
 
 
283
    data->thread = StartThread(OSSProc, device);
 
284
    if(data->thread == NULL)
 
285
    {
 
286
        free(data->mix_data);
 
287
        data->mix_data = NULL;
 
288
        return ALC_FALSE;
 
289
    }
 
290
 
 
291
    return ALC_TRUE;
 
292
}
 
293
 
 
294
static void oss_stop_playback(ALCdevice *device)
 
295
{
 
296
    oss_data *data = (oss_data*)device->ExtraData;
 
297
 
 
298
    if(!data->thread)
 
299
        return;
 
300
 
 
301
    data->killNow = 1;
 
302
    StopThread(data->thread);
 
303
    data->thread = NULL;
 
304
 
 
305
    data->killNow = 0;
 
306
    if(ioctl(data->fd, SNDCTL_DSP_RESET) != 0)
 
307
        ERR("Error resetting device: %s\n", strerror(errno));
 
308
 
 
309
    free(data->mix_data);
 
310
    data->mix_data = NULL;
 
311
}
 
312
 
 
313
 
 
314
static ALCenum oss_open_capture(ALCdevice *device, const ALCchar *deviceName)
 
315
{
 
316
    int numFragmentsLogSize;
 
317
    int log2FragmentSize;
 
318
    unsigned int periods;
 
319
    audio_buf_info info;
 
320
    ALuint frameSize;
 
321
    int numChannels;
 
322
    oss_data *data;
 
323
    int ossFormat;
 
324
    int ossSpeed;
 
325
    char *err;
 
326
 
 
327
    if(!deviceName)
 
328
        deviceName = oss_device;
 
329
    else if(strcmp(deviceName, oss_device) != 0)
 
330
        return ALC_INVALID_VALUE;
 
331
 
 
332
    data = (oss_data*)calloc(1, sizeof(oss_data));
 
333
    data->killNow = 0;
 
334
 
 
335
    data->fd = open(oss_capture, O_RDONLY);
 
336
    if(data->fd == -1)
 
337
    {
 
338
        free(data);
 
339
        ERR("Could not open %s: %s\n", oss_capture, strerror(errno));
 
340
        return ALC_INVALID_VALUE;
 
341
    }
 
342
 
 
343
    switch(device->FmtType)
 
344
    {
 
345
        case DevFmtByte:
 
346
            ossFormat = AFMT_S8;
 
347
            break;
 
348
        case DevFmtUByte:
 
349
            ossFormat = AFMT_U8;
 
350
            break;
 
351
        case DevFmtShort:
 
352
            ossFormat = AFMT_S16_NE;
 
353
            break;
 
354
        case DevFmtUShort:
 
355
        case DevFmtInt:
 
356
        case DevFmtUInt:
 
357
        case DevFmtFloat:
 
358
            free(data);
 
359
            ERR("%s capture samples not supported\n", DevFmtTypeString(device->FmtType));
 
360
            return ALC_INVALID_VALUE;
 
361
    }
 
362
 
 
363
    periods = 4;
 
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);
 
369
 
 
370
    /* according to the OSS spec, 16 bytes are the minimum */
 
371
    if (log2FragmentSize < 4)
 
372
        log2FragmentSize = 4;
 
373
    numFragmentsLogSize = (periods << 16) | log2FragmentSize;
 
374
 
 
375
#define CHECKERR(func) if((func) < 0) {                                       \
 
376
    err = #func;                                                              \
 
377
    goto err;                                                                 \
 
378
}
 
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));
 
384
    if(0)
 
385
    {
 
386
    err:
 
387
        ERR("%s failed: %s\n", err, strerror(errno));
 
388
        close(data->fd);
 
389
        free(data);
 
390
        return ALC_INVALID_VALUE;
 
391
    }
 
392
#undef CHECKERR
 
393
 
 
394
    if((int)ChannelsFromDevFmt(device->FmtChans) != numChannels)
 
395
    {
 
396
        ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device->FmtChans), numChannels);
 
397
        close(data->fd);
 
398
        free(data);
 
399
        return ALC_INVALID_VALUE;
 
400
    }
 
401
 
 
402
    if(!((ossFormat == AFMT_S8 && device->FmtType == DevFmtByte) ||
 
403
         (ossFormat == AFMT_U8 && device->FmtType == DevFmtUByte) ||
 
404
         (ossFormat == AFMT_S16_NE && device->FmtType == DevFmtShort)))
 
405
    {
 
406
        ERR("Failed to set %s samples, got OSS format %#x\n", DevFmtTypeString(device->FmtType), ossFormat);
 
407
        close(data->fd);
 
408
        free(data);
 
409
        return ALC_INVALID_VALUE;
 
410
    }
 
411
 
 
412
    data->ring = CreateRingBuffer(frameSize, device->UpdateSize * device->NumUpdates);
 
413
    if(!data->ring)
 
414
    {
 
415
        ERR("Ring buffer create failed\n");
 
416
        close(data->fd);
 
417
        free(data);
 
418
        return ALC_OUT_OF_MEMORY;
 
419
    }
 
420
 
 
421
    data->data_size = info.fragsize;
 
422
    data->mix_data = calloc(1, data->data_size);
 
423
 
 
424
    device->ExtraData = data;
 
425
    data->thread = StartThread(OSSCaptureProc, device);
 
426
    if(data->thread == NULL)
 
427
    {
 
428
        device->ExtraData = NULL;
 
429
        free(data->mix_data);
 
430
        free(data);
 
431
        return ALC_OUT_OF_MEMORY;
 
432
    }
 
433
 
 
434
    device->szDeviceName = strdup(deviceName);
 
435
    return ALC_NO_ERROR;
 
436
}
 
437
 
 
438
static void oss_close_capture(ALCdevice *device)
 
439
{
 
440
    oss_data *data = (oss_data*)device->ExtraData;
 
441
    data->killNow = 1;
 
442
    StopThread(data->thread);
 
443
 
 
444
    close(data->fd);
 
445
 
 
446
    DestroyRingBuffer(data->ring);
 
447
 
 
448
    free(data->mix_data);
 
449
    free(data);
 
450
    device->ExtraData = NULL;
 
451
}
 
452
 
 
453
static void oss_start_capture(ALCdevice *pDevice)
 
454
{
 
455
    oss_data *data = (oss_data*)pDevice->ExtraData;
 
456
    data->doCapture = 1;
 
457
}
 
458
 
 
459
static void oss_stop_capture(ALCdevice *pDevice)
 
460
{
 
461
    oss_data *data = (oss_data*)pDevice->ExtraData;
 
462
    data->doCapture = 0;
 
463
}
 
464
 
 
465
static ALCenum oss_capture_samples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples)
 
466
{
 
467
    oss_data *data = (oss_data*)pDevice->ExtraData;
 
468
    ReadRingBuffer(data->ring, pBuffer, lSamples);
 
469
    return ALC_NO_ERROR;
 
470
}
 
471
 
 
472
static ALCuint oss_available_samples(ALCdevice *pDevice)
 
473
{
 
474
    oss_data *data = (oss_data*)pDevice->ExtraData;
 
475
    return RingBufferSize(data->ring);
 
476
}
 
477
 
 
478
 
 
479
static const BackendFuncs oss_funcs = {
 
480
    oss_open_playback,
 
481
    oss_close_playback,
 
482
    oss_reset_playback,
 
483
    oss_start_playback,
 
484
    oss_stop_playback,
 
485
    oss_open_capture,
 
486
    oss_close_capture,
 
487
    oss_start_capture,
 
488
    oss_stop_capture,
 
489
    oss_capture_samples,
 
490
    oss_available_samples
 
491
};
 
492
 
 
493
ALCboolean alc_oss_init(BackendFuncs *func_list)
 
494
{
 
495
    ConfigValueStr("oss", "device", &oss_driver);
 
496
    ConfigValueStr("oss", "capture", &oss_capture);
 
497
 
 
498
    *func_list = oss_funcs;
 
499
    return ALC_TRUE;
 
500
}
 
501
 
 
502
void alc_oss_deinit(void)
 
503
{
 
504
}
 
505
 
 
506
void alc_oss_probe(enum DevProbe type)
 
507
{
 
508
    switch(type)
 
509
    {
 
510
        case ALL_DEVICE_PROBE:
 
511
        {
 
512
#ifdef HAVE_STAT
 
513
            struct stat buf;
 
514
            if(stat(oss_device, &buf) == 0)
 
515
#endif
 
516
                AppendAllDeviceList(oss_device);
 
517
        }
 
518
        break;
 
519
 
 
520
        case CAPTURE_DEVICE_PROBE:
 
521
        {
 
522
#ifdef HAVE_STAT
 
523
            struct stat buf;
 
524
            if(stat(oss_capture, &buf) == 0)
 
525
#endif
 
526
                AppendCaptureDeviceList(oss_device);
 
527
        }
 
528
        break;
 
529
    }
 
530
}