2
* $Id: plat_linux_audio.c,v 1.4 2000/08/30 04:40:36 dfoerste Exp $
4
* This file is part of WorkMan, the civilized CD player library
5
* (c) 1991-1997 by Steven Grimm (original author)
6
* (c) by Dirk Fļæ½rsterling (current 'author' = maintainer)
7
* The maintainer can be contacted by his e-mail address:
8
* milliByte@DeathsDoor.com
10
* This library is free software; you can redistribute it and/or
11
* modify it under the terms of the GNU Library General Public
12
* License as published by the Free Software Foundation; either
13
* version 2 of the License, or (at your option) any later version.
15
* This library is distributed in the hope that it will be useful,
16
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18
* Library General Public License for more details.
20
* You should have received a copy of the GNU Library General Public
21
* License along with this library; if not, write to the Free
22
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25
* Linux digital audio functions.
28
#include "include/wm_config.h"
30
static char plat_linux_audio_id[] = "$Id: plat_linux_audio.c,v 1.4 2000/08/30 04:40:36 dfoerste Exp $";
32
#if defined(__linux__) && defined(BUILD_CDDA) /* { */
34
#include "include/wm_cdda.h"
36
/* types.h included by wm_cdda.h */
40
#include <sys/ioctl.h>
41
#include <sys/audioio.h>
42
#include <sys/stropts.h>
48
#define WM_MSG_CLASS WM_MSG_CLASS_PLATFORM
51
* Since there's a lag time between writing audio to the audio device and
52
* hearing it, we need to make sure the status indicators correlate to what's
53
* playing out the speaker. Luckily, Solaris gives us some audio
54
* synchronization facilities that make this pretty easy.
56
* We maintain a circular queue of status information. When we write some
57
* sound to the audio device, we put its status info into the queue. We write
58
* a marker into the audio stream; when the audio device driver encounters the
59
* marker, it increments a field in a status structure. When we see that
60
* field go up, we grab the next status structure from the queue and send it
61
* to the parent process.
63
* The minimum size of the queue depends on the latency of the audio stream.
67
struct cdda_block queue[QSIZE];
72
* We only send WMCDDA_PLAYED status messages upstream when the CD is supposed
73
* to be playing; this is used to keep track.
77
static int aufd, aucfd;
78
static int raw_audio = 1; /* Can /dev/audio take 44.1KHz stereo? */
81
* For fast linear-to-ulaw mapping, we use a lookup table that's generated
84
unsigned char *ulawmap, linear_to_ulaw();
89
* Dummy signal handler so writes to /dev/audio will interrupt.
94
signal(SIGALRM, dummy);
98
* Initialize the audio device.
104
char *audiodev, *acdev;
107
audiodev = getenv("AUDIODEV");
108
if (audiodev == NULL)
109
audiodev = "/dev/audio";
111
acdev = malloc(strlen(audiodev) + 4);
114
perror("Can't allocate audio control filename");
117
strcpy(acdev, audiodev);
118
strcat(acdev, "ctl");
120
aucfd = open(acdev, O_WRONLY, 0);
128
aufd = open(audiodev, O_WRONLY, 0);
135
signal(SIGALRM, dummy);
138
* Try to set the device to CD-style audio; we can process it
139
* with the least CPU overhead.
141
AUDIO_INITINFO(&info);
142
info.play.sample_rate = 44100;
143
info.play.channels = 2;
144
info.play.precision = 16;
145
info.play.encoding = AUDIO_ENCODING_LINEAR;
147
info.record.pause = 0;
148
info.monitor_gain = 0;
150
if (ioctl(aufd, AUDIO_SETINFO, &info) < 0)
154
* Oh well, so much for that idea.
156
AUDIO_INITINFO(&info);
157
info.play.sample_rate = 8000;
158
info.play.channels = 1;
159
info.play.precision = 8;
160
info.play.encoding = AUDIO_ENCODING_ULAW;
162
info.record.pause = 0;
163
info.monitor_gain = 0;
164
if (ioctl(aufd, AUDIO_SETINFO, &info) < 0)
166
perror("Can't set up audio device");
171
* Initialize the linear-to-ulaw mapping table.
174
ulawmap = malloc(65536);
180
for (linval = 0; linval < 65536; linval++)
181
ulawmap[linval] = linear_to_ulaw(linval-32768);
193
* Get ready to play some sound.
196
wmaudio_ready( void )
201
* Start at the correct queue position.
203
if (ioctl(aucfd, AUDIO_GETINFO, &info) < 0) perror("AUDIO_GETINFO");
204
qtail = info.play.eof % QSIZE;
207
queue[qtail].status = WMCDDA_OK;
211
* Stop the audio immediately.
216
if (ioctl(aufd, I_FLUSH, FLUSHRW) < 0)
221
* Close the audio device.
224
wmaudio_close( void )
232
* Set the volume level.
235
wmaudio_volume(int level)
239
AUDIO_INITINFO(&info);
240
if (ioctl(aucfd, AUDIO_GETINFO, &info) < 0) perror("AUDIO_GETINFO");
241
info.play.gain = level;
242
if (ioctl(aucfd, AUDIO_SETINFO, &info) < 0) perror("AUDIO_SETINFO");
246
* Set the balance level.
249
wmaudio_balance(int level)
253
AUDIO_INITINFO(&info);
254
if (ioctl(aucfd, AUDIO_GETINFO, &info) < 0) perror("AUDIO_GETINFO");
255
level *= AUDIO_RIGHT_BALANCE;
256
info.play.balance = level / 255;
257
if (ioctl(aucfd, AUDIO_SETINFO, &info) < 0) perror("AUDIO_SETINFO");
261
* Mark the most recent audio block on the queue as the last one.
264
wmaudio_mark_last( void )
266
queue[qtail].status = WMCDDA_DONE;
270
* Figure out the most recent status information and send it upstream.
273
wmaudio_send_status( void )
279
* Now send the most current status information to our parent.
281
if (ioctl(aucfd, AUDIO_GETINFO, &info) < 0)
282
perror("AUDIO_GETINFO");
283
qhead = info.play.eof % QSIZE;
285
if (qhead != qstart && playing)
289
if (queue[qhead].status != WMCDDA_DONE)
290
queue[qhead].status = WMCDDA_PLAYED;
291
queue[qhead].volume = info.play.gain;
292
queue[qhead].balance = (info.play.balance * 255) /
295
send_status(queue + qhead);
299
return (queue[qhead].status == WMCDDA_DONE);
303
* Play some audio and pass a status message upstream, if applicable.
304
* Returns 0 on success.
307
wmaudio_play(unsigned char *rawbuf, long buflen, struct cdda_block *blk)
316
while (write(aufd, rawbuf, buflen) <= 0)
319
if (! raw_audio && alarmcount++ < 5)
322
* 8KHz /dev/audio blocks for several seconds
323
* waiting for its queue to drop below a low
326
wmaudio_send_status();
327
timerclear(&it.it_interval);
328
timerclear(&it.it_value);
329
it.it_value.tv_usec = 500000;
330
setitimer(ITIMER_REAL, &it, NULL);
337
*/ wmaudio_stop( void );
343
blk->status = WMCDDA_ERROR;
349
* Mark this spot in the audio stream.
351
* Marks don't always succeed (if the audio buffer is empty
352
* this call will block forever) so do it asynchronously.
354
fcntl(aufd, F_SETFL, O_NONBLOCK);
355
if (write(aufd, rawbuf, 0) < 0)
358
perror("audio mark");
361
qtail = (qtail + 1) % QSIZE;
363
fcntl(aufd, F_SETFL, 0);
367
if (wmaudio_send_status() < 0)
374
* Get the current audio state.
377
wmaudio_state(struct cdda_block *blk)
382
if (ioctl(aucfd, AUDIO_GETINFO, &info) < 0)
383
perror("AUDIO_GETINFO");
384
blk->volume = info.play.gain;
385
blk->balance = (info.play.balance * 255) / AUDIO_RIGHT_BALANCE;
389
** This routine converts from linear to ulaw.
391
** Craig Reese: IDA/Supercomputing Research Center
392
** Joe Campbell: Department of Defense
396
** 1) CCITT Recommendation G.711 (very difficult to follow)
397
** 2) "A New Digital Technique for Implementation of Any
398
** Continuous PCM Companding Law," Villeret, Michel,
399
** et al. 1973 IEEE Int. Conf. on Communications, Vol 1,
400
** 1973, pg. 11.12-11.17
401
** 3) MIL-STD-188-113,"Interoperability and Performance Standards
402
** for Analog-to_Digital Conversion Techniques,"
405
** Input: Signed 16 bit linear sample
406
** Output: 8 bit ulaw sample
408
#define ZEROTRAP /* turn on the trap as per the MIL-STD */
409
#define BIAS 0x84 /* define the add-in bias for 16 bit samples */
413
linear_to_ulaw( sample )
416
static int exp_lut[256] = {0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
417
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
418
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
419
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
420
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
421
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
422
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
423
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
424
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
425
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
426
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
427
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
428
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
429
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
430
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
431
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7};
432
int sign, exponent, mantissa;
433
unsigned char ulawbyte;
435
/* Get the sample into sign-magnitude. */
436
sign = (sample >> 8) & 0x80; /* set aside the sign */
437
if ( sign != 0 ) sample = -sample; /* get magnitude */
438
if ( sample > CLIP ) sample = CLIP; /* clip the magnitude */
440
/* Convert from 16 bit linear to ulaw. */
441
sample = sample + BIAS;
442
exponent = exp_lut[( sample >> 7 ) & 0xFF];
443
mantissa = ( sample >> ( exponent + 3 ) ) & 0x0F;
444
ulawbyte = ~ ( sign | ( exponent << 4 ) | mantissa );
446
if ( ulawbyte == 0 ) ulawbyte = 0x02; /* optional CCITT trap */
453
* Downsample a block of CDDA data, if necessary, for playing out an old-style
457
wmaudio_convert(unsigned char *rawbuf, long buflen, struct cdda_block *blk)
459
short *buf16 = (short *)rawbuf;
462
unsigned char *rbend = rawbuf + buflen;
464
/* Don't do anything if the audio device can take the raw values. */
468
for (i = 0; buf16 < (short *)(rbend); i++)
470
/* Downsampling to 8KHz is a little irregular. */
471
samples = (i & 1) ? ((i % 20) ? 10 : 12) : 12;
473
/* And unfortunately, we don't always end on a nice boundary. */
474
if (buf16 + samples > (short *)(rbend))
475
samples = ((short *)rbend) - buf16;
478
* No need to average all the values; taking the first one
479
* is sufficient and less CPU-intensive. But we do need to
482
mono_value = (buf16[0] + buf16[1]) / 2;
484
rawbuf[i] = ulawmap[mono_value];
490
#endif /* ... && BUILD_CDDA */