File indexing completed on 2024-04-28 08:46:53
0001 /* This file is part of the KDE project 0002 0003 Copyright (C) 1991-1997 by Steven Grimm <koreth@midwinter.com> 0004 Copyright (C) by Dirk Försterling <milliByte@DeathsDoor.com> 0005 Copyright (C) 2006 Alexander Kern <alex.kern@gmx.de> 0006 0007 This library is free software; you can redistribute it and/or 0008 modify it under the terms of the GNU Library General Public 0009 License version 2 as published by the Free Software Foundation. 0010 0011 This library is distributed in the hope that it will be useful, 0012 but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0014 Library General Public License for more details. 0015 0016 You should have received a copy of the GNU Library General Public License 0017 along with this library; see the file COPYING.LIB. If not, write to 0018 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0019 Boston, MA 02110-1301, USA. 0020 0021 Sun (really Solaris) digital audio functions. 0022 */ 0023 0024 #if defined(sun) || defined(__sun__) 0025 0026 #include "audio.h" 0027 0028 #include <stdio.h> 0029 #include <malloc.h> 0030 #include <sys/ioctl.h> 0031 #include <sys/audioio.h> 0032 #include <sys/stropts.h> 0033 #include <sys/time.h> 0034 #include <errno.h> 0035 #include <fcntl.h> 0036 #include <signal.h> 0037 0038 #define WM_MSG_CLASS WM_MSG_CLASS_PLATFORM 0039 0040 /* 0041 * Since there's a lag time between writing audio to the audio device and 0042 * hearing it, we need to make sure the status indicators correlate to what's 0043 * playing out the speaker. Luckily, Solaris gives us some audio 0044 * synchronization facilities that make this pretty easy. 0045 * 0046 * We maintain a circular queue of status information. When we write some 0047 * sound to the audio device, we put its status info into the queue. We write 0048 * a marker into the audio stream; when the audio device driver encounters the 0049 * marker, it increments a field in a status structure. When we see that 0050 * field go up, we grab the next status structure from the queue and send it 0051 * to the parent process. 0052 * 0053 * The minimum size of the queue depends on the latency of the audio stream. 0054 */ 0055 #define QSIZE 500 0056 0057 struct cdda_block queue[QSIZE]; 0058 int qtail; 0059 int qstart; 0060 0061 /* 0062 * We only send WM_CDM_PLAYING status messages upstream when the CD is supposed 0063 * to be playing; this is used to keep track. 0064 */ 0065 extern int playing; 0066 0067 static int aufd, aucfd; 0068 static int raw_audio = 1; /* Can /dev/audio take 44.1KHz stereo? */ 0069 0070 /* 0071 * For fast linear-to-ulaw mapping, we use a lookup table that's generated 0072 * at startup. 0073 */ 0074 unsigned char *ulawmap, linear_to_ulaw(); 0075 0076 char *getenv(); 0077 0078 /* 0079 * Dummy signal handler so writes to /dev/audio will interrupt. 0080 */ 0081 static void 0082 dummy( void ) 0083 { 0084 signal(SIGALRM, dummy); 0085 } 0086 0087 /* 0088 * Initialize the audio device. 0089 */ 0090 void 0091 sun_audio_init( void ) 0092 { 0093 audio_info_t info; 0094 char *audiodev, *acdev; 0095 int linval; 0096 0097 audiodev = getenv("AUDIODEV"); 0098 if (audiodev == NULL || 0099 strncmp("/dev/", audiodev, 5) || 0100 strstr(audiodev, "/../") ) 0101 audiodev = "/dev/audio"; 0102 0103 acdev = malloc(strlen(audiodev) + 4); 0104 if (acdev == NULL) 0105 { 0106 perror("Cannot allocate audio control filename"); 0107 exit(1); 0108 } 0109 strcpy(acdev, audiodev); 0110 strcat(acdev, "ctl"); 0111 0112 aucfd = open(acdev, O_WRONLY, 0); 0113 if (aucfd < 0) 0114 { 0115 perror(acdev); 0116 exit(1); 0117 } 0118 free(acdev); 0119 0120 aufd = open(audiodev, O_WRONLY, 0); 0121 if (aufd < 0) 0122 { 0123 perror(audiodev); 0124 exit(1); 0125 } 0126 0127 signal(SIGALRM, dummy); 0128 0129 /* 0130 * Try to set the device to CD-style audio; we can process it 0131 * with the least CPU overhead. 0132 */ 0133 AUDIO_INITINFO(&info); 0134 info.play.sample_rate = 44100; 0135 info.play.channels = 2; 0136 info.play.precision = 16; 0137 info.play.encoding = AUDIO_ENCODING_LINEAR; 0138 info.play.pause = 0; 0139 info.record.pause = 0; 0140 info.monitor_gain = 0; 0141 0142 if (ioctl(aufd, AUDIO_SETINFO, &info) < 0) 0143 if (errno == EINVAL) 0144 { 0145 /* 0146 * Oh well, so much for that idea. 0147 */ 0148 AUDIO_INITINFO(&info); 0149 info.play.sample_rate = 8000; 0150 info.play.channels = 1; 0151 info.play.precision = 8; 0152 info.play.encoding = AUDIO_ENCODING_ULAW; 0153 info.play.pause = 0; 0154 info.record.pause = 0; 0155 info.monitor_gain = 0; 0156 if (ioctl(aufd, AUDIO_SETINFO, &info) < 0) 0157 { 0158 perror("Can't set up audio device"); 0159 exit(1); 0160 } 0161 0162 /* 0163 * Initialize the linear-to-ulaw mapping table. 0164 */ 0165 if (ulawmap == NULL) 0166 ulawmap = malloc(65536); 0167 if (ulawmap == NULL) 0168 { 0169 perror("malloc"); 0170 exit(1); 0171 } 0172 for (linval = 0; linval < 65536; linval++) 0173 ulawmap[linval] = linear_to_ulaw(linval-32768); 0174 ulawmap += 32768; 0175 raw_audio = 0; 0176 } 0177 else 0178 { 0179 perror(audiodev); 0180 exit(1); 0181 } 0182 } 0183 0184 /* 0185 * Get ready to play some sound. 0186 */ 0187 void 0188 sun_audio_ready( void ) 0189 { 0190 audio_info_t info; 0191 0192 /* 0193 * Start at the correct queue position. 0194 */ 0195 if (ioctl(aucfd, AUDIO_GETINFO, &info) < 0) perror("AUDIO_GETINFO"); 0196 qtail = info.play.eof % QSIZE; 0197 qstart = qtail; 0198 0199 queue[qtail].status = WM_CDM_PLAYING; 0200 } 0201 0202 /* 0203 * Stop the audio immediately. 0204 */ 0205 int 0206 sun_audio_stop( void ) 0207 { 0208 if (ioctl(aufd, I_FLUSH, FLUSHRW) < 0) 0209 perror("flush"); 0210 return 0; 0211 } 0212 0213 /* 0214 * Close the audio device. 0215 */ 0216 int 0217 sun_audio_close( void ) 0218 { 0219 wmaudio_stop(); 0220 close(aufd); 0221 close(aucfd); 0222 return 0; 0223 } 0224 0225 /* 0226 * Set/get the balance and volume level. 0227 */ 0228 int 0229 sun_audio_balvol(int setget, unsigned char *balance, unsigned char *volume) 0230 { 0231 audio_info_t info; 0232 AUDIO_INITINFO(&info); 0233 if (ioctl(aucfd, AUDIO_GETINFO, &info) < 0) { 0234 perror("AUDIO_GETINFO"); 0235 return -1; 0236 } 0237 0238 if(setget) { 0239 balance *= AUDIO_RIGHT_BALANCE; 0240 info.play.balance = *balance / 255; 0241 info.play.gain = *volume; 0242 if (ioctl(aucfd, AUDIO_SETINFO, &info) < 0) { 0243 perror("AUDIO_SETINFO"); 0244 return -1; 0245 } 0246 } else { 0247 *volume = info.play.gain; 0248 *balance = (info.play.balance * 255) / AUDIO_RIGHT_BALANCE; 0249 } 0250 return 0; 0251 } 0252 0253 /* 0254 * Mark the most recent audio block on the queue as the last one. 0255 */ 0256 void 0257 sun_audio_mark_last( void ) 0258 { 0259 queue[qtail].status = WM_CDM_TRACK_DONE; 0260 } 0261 0262 /* 0263 * Figure out the most recent status information and send it upstream. 0264 */ 0265 int 0266 sun_audio_send_status( void ) 0267 { 0268 audio_info_t info; 0269 int qhead; 0270 0271 /* 0272 * Now send the most current status information to our parent. 0273 */ 0274 if (ioctl(aucfd, AUDIO_GETINFO, &info) < 0) 0275 perror("AUDIO_GETINFO"); 0276 qhead = info.play.eof % QSIZE; 0277 0278 if (qhead != qstart && playing) 0279 { 0280 int balance; 0281 0282 if (queue[qhead].status != WM_CDM_TRACK_DONE) 0283 queue[qhead].status = WM_CDM_PLAYING; 0284 queue[qhead].volume = info.play.gain; 0285 queue[qhead].balance = (info.play.balance * 255) / 0286 AUDIO_RIGHT_BALANCE; 0287 0288 send_status(queue + qhead); 0289 qstart = -1; 0290 } 0291 0292 return (queue[qhead].status == WM_CDM_TRACK_DONE); 0293 } 0294 0295 /* 0296 * Play some audio and pass a status message upstream, if applicable. 0297 * Returns 0 on success. 0298 */ 0299 int 0300 sun_audio_play(unsigned char *rawbuf, long buflen, struct cdda_block *blk) 0301 { 0302 int i; 0303 short *buf16; 0304 int alarmcount = 0; 0305 struct itimerval it; 0306 long playablelen; 0307 0308 alarm(1); 0309 playablelen = dev_audio_convert(rawbuf, buflen, blk); 0310 while (write(aufd, rawbuf, playablelen) <= 0) 0311 if (errno == EINTR) 0312 { 0313 if (! raw_audio && alarmcount++ < 5) 0314 { 0315 /* 0316 * 8KHz /dev/audio blocks for several seconds 0317 * waiting for its queue to drop below a low 0318 * water mark. 0319 */ 0320 wmaudio_send_status(); 0321 timerclear(&it.it_interval); 0322 timerclear(&it.it_value); 0323 it.it_value.tv_usec = 500000; 0324 setitimer(ITIMER_REAL, &it, NULL); 0325 continue; 0326 } 0327 0328 /* close(aufd); 0329 close(aucfd); 0330 wmaudio_init(); 0331 */ sun_audio_stop(); 0332 alarm(2); 0333 continue; 0334 } 0335 else 0336 { 0337 blk->status = WM_CDM_CDDAERROR; 0338 return (-1); 0339 } 0340 alarm(0); 0341 0342 /* 0343 * Mark this spot in the audio stream. 0344 * 0345 * Marks don't always succeed (if the audio buffer is empty 0346 * this call will block forever) so do it asynchronously. 0347 */ 0348 fcntl(aufd, F_SETFL, O_NONBLOCK); 0349 if (write(aufd, rawbuf, 0) < 0) 0350 { 0351 if (errno != EAGAIN) 0352 perror("audio mark"); 0353 } 0354 else 0355 qtail = (qtail + 1) % QSIZE; 0356 0357 fcntl(aufd, F_SETFL, 0); 0358 0359 queue[qtail] = *blk; 0360 0361 if (wmaudio_send_status() < 0) 0362 return (-1); 0363 else 0364 return (0); 0365 } 0366 0367 /* 0368 ** This routine converts from linear to ulaw. 0369 ** 0370 ** Craig Reese: IDA/Supercomputing Research Center 0371 ** Joe Campbell: Department of Defense 0372 ** 29 September 1989 0373 ** 0374 ** References: 0375 ** 1) CCITT Recommendation G.711 (very difficult to follow) 0376 ** 2) "A New Digital Technique for Implementation of Any 0377 ** Continuous PCM Companding Law," Villeret, Michel, 0378 ** et al. 1973 IEEE Int. Conf. on Communications, Vol 1, 0379 ** 1973, pg. 11.12-11.17 0380 ** 3) MIL-STD-188-113,"Interoperability and Performance Standards 0381 ** for Analog-to_Digital Conversion Techniques," 0382 ** 17 February 1987 0383 ** 0384 ** Input: Signed 16 bit linear sample 0385 ** Output: 8 bit ulaw sample 0386 */ 0387 #define ZEROTRAP /* turn on the trap as per the MIL-STD */ 0388 #define BIAS 0x84 /* define the add-in bias for 16 bit samples */ 0389 #define CLIP 32635 0390 0391 unsigned char 0392 linear_to_ulaw( sample ) 0393 int sample; 0394 { 0395 static int exp_lut[256] = {0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3, 0396 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 0397 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 0398 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 0399 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 0400 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 0401 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 0402 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 0403 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 0404 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 0405 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 0406 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 0407 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 0408 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 0409 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 0410 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7}; 0411 int sign, exponent, mantissa; 0412 unsigned char ulawbyte; 0413 0414 /* Get the sample into sign-magnitude. */ 0415 sign = (sample >> 8) & 0x80; /* set aside the sign */ 0416 if ( sign != 0 ) sample = -sample; /* get magnitude */ 0417 if ( sample > CLIP ) sample = CLIP; /* clip the magnitude */ 0418 0419 /* Convert from 16 bit linear to ulaw. */ 0420 sample = sample + BIAS; 0421 exponent = exp_lut[( sample >> 7 ) & 0xFF]; 0422 mantissa = ( sample >> ( exponent + 3 ) ) & 0x0F; 0423 ulawbyte = ~ ( sign | ( exponent << 4 ) | mantissa ); 0424 #ifdef ZEROTRAP 0425 if ( ulawbyte == 0 ) ulawbyte = 0x02; /* optional CCITT trap */ 0426 #endif 0427 0428 return ulawbyte; 0429 } 0430 0431 /* 0432 * Downsample a block of CDDA data, if necessary, for playing out an old-style 0433 * audio device. 0434 */ 0435 long 0436 dev_audio_convert(unsigned char *rawbuf, long buflen, struct cdda_block *blk) 0437 { 0438 short *buf16 = (short *)rawbuf; 0439 int i, j, samples; 0440 int mono_value; 0441 unsigned char *rbend = rawbuf + buflen; 0442 0443 /* Don't do anything if the audio device can take the raw values. */ 0444 if (raw_audio) 0445 return (buflen); 0446 0447 for (i = 0; buf16 < (short *)(rbend); i++) 0448 { 0449 /* Downsampling to 8KHz is a little irregular. */ 0450 samples = (i & 1) ? ((i % 20) ? 10 : 12) : 12; 0451 0452 /* And unfortunately, we don't always end on a nice boundary. */ 0453 if (buf16 + samples > (short *)(rbend)) 0454 samples = ((short *)rbend) - buf16; 0455 0456 /* 0457 * No need to average all the values; taking the first one 0458 * is sufficient and less CPU-intensive. But we do need to 0459 * do both channels. 0460 */ 0461 mono_value = (buf16[0] + buf16[1]) / 2; 0462 buf16 += samples; 0463 rawbuf[i] = ulawmap[mono_value]; 0464 } 0465 0466 return (i); 0467 } 0468 0469 static struct audio_oops sun_audio_oops = { 0470 .wmaudio_open = sun_audio_open, 0471 .wmaudio_close = sun_audio_close, 0472 .wmaudio_play = sun_audio_play, 0473 .wmaudio_stop = sun_audio_stop, 0474 .wmaudio_state = NULL, 0475 .wmaudio_balvol = sun_audio_balvol 0476 }; 0477 0478 struct audio_oops* 0479 setup_sun_audio(const char *dev, const char *ctl) 0480 { 0481 int err; 0482 0483 if((err = sun_audio_init())) { 0484 ERRORLOG("cannot initialize SUN /dev/audio subsystem \n"); 0485 return NULL; 0486 } 0487 0488 sun_audio_open(); 0489 0490 return &sun_audio_oops; 0491 } 0492 0493 #endif