1 #include "dat.h" 2 #include "fns.h" 3 #include "error.h" 4 #include <fcntl.h> 5 #include <sys/ioctl.h> 6 #include <sys/filio.h> 7 #include "audio.h" 8 #include <sys/soundcard.h> 9 10 #define Audio_Mic_Val SOUND_MIXER_MIC 11 #define Audio_Linein_Val SOUND_MIXER_LINE 12 13 #define Audio_Speaker_Val SOUND_MIXER_SPEAKER 14 #define Audio_Headphone_Val SOUND_MIXER_PHONEOUT 15 #define Audio_Lineout_Val SOUND_MIXER_VOLUME 16 17 #define Audio_Pcm_Val AFMT_S16_LE 18 #define Audio_Ulaw_Val AFMT_MU_LAW 19 #define Audio_Alaw_Val AFMT_A_LAW 20 21 #include "audio-tbls.c" 22 23 #define min(a,b) ((a) < (b) ? (a) : (b)) 24 static int debug; 25 26 #define AUDIO_FILE_STRING "/dev/dsp" 27 28 enum { 29 A_Pause, 30 A_UnPause 31 }; 32 33 enum { 34 A_In, 35 A_Out 36 }; 37 38 static QLock inlock; 39 static QLock outlock; 40 41 static int audio_file = -1; /* file in/out */ 42 static int audio_file_in = -1; /* copy of above when opened O_READ/O_RDWR */ 43 static int audio_file_out = -1; /* copy of above when opened O_WRITE/O_RDWR */ 44 45 static int audio_swap_flag = 0; /* endian swap */ 46 47 static int audio_in_pause = A_UnPause; 48 49 static Audio_t av; 50 static int mixerleftvol[32]; 51 static int mixerrightvol[32]; 52 53 static int audio_enforce(Audio_t*); 54 static int audio_open(void); 55 static int audio_pause_in(int, int); 56 static int audio_flush(int, int); 57 static int audio_pause_out(int); 58 static int audio_set_blocking(int); 59 static int audio_set_info(int, Audio_d*, int); 60 static void audio_swap_endian(char*, int); 61 62 void 63 audio_file_init(void) 64 { 65 int i; 66 static ushort flag = 1; 67 68 audio_swap_flag = *((uchar*)&flag) == 0; /* big-endian? */ 69 audio_info_init(&av); 70 for (i = 0; i < 32; i++) 71 mixerleftvol[i] = mixerrightvol[i] = 100; 72 } 73 74 void 75 audio_ctl_init(void) 76 { 77 } 78 79 void 80 audio_file_open(Chan *c, int omode) 81 { 82 char ebuf[ERRMAX]; 83 84 if (debug) 85 print("audio_file_open(0x%.8lux, %d)\n", c, omode); 86 switch(omode){ 87 case OREAD: 88 qlock(&inlock); 89 if(waserror()){ 90 qunlock(&inlock); 91 nexterror(); 92 } 93 94 if(audio_file_in >= 0) 95 error(Einuse); 96 if (audio_file < 0) 97 audio_file = audio_open(); 98 audio_file_in = audio_file; 99 poperror(); 100 qunlock(&inlock); 101 break; 102 case OWRITE: 103 qlock(&outlock); 104 if(waserror()){ 105 qunlock(&outlock); 106 nexterror(); 107 } 108 if(audio_file_out >= 0) 109 error(Einuse); 110 if (audio_file < 0) 111 audio_file = audio_open(); 112 audio_file_out = audio_file; 113 poperror(); 114 qunlock(&outlock); 115 break; 116 case ORDWR: 117 qlock(&inlock); 118 qlock(&outlock); 119 if(waserror()){ 120 qunlock(&outlock); 121 qunlock(&inlock); 122 nexterror(); 123 } 124 if(audio_file_in >= 0 || audio_file_out >= 0) 125 error(Einuse); 126 if (audio_file < 0) 127 audio_file = audio_open(); 128 audio_file_in = audio_file_out = audio_file; 129 poperror(); 130 qunlock(&outlock); 131 qunlock(&inlock); 132 break; 133 } 134 if (debug) 135 print("audio_file_open: success\nin %d out %d both %d\n", 136 audio_file_out, audio_file_in, audio_file); 137 } 138 139 void 140 audio_ctl_open(Chan *c, int omode) 141 { 142 USED(c); 143 USED(omode); 144 } 145 146 void 147 audio_file_close(Chan *c) 148 { 149 switch(c->mode){ 150 case OREAD: 151 qlock(&inlock); 152 qlock(&outlock); 153 if (audio_file_out < 0) { 154 close(audio_file); 155 audio_file = -1; 156 } 157 qunlock(&outlock); 158 audio_file_in = -1; 159 qunlock(&inlock); 160 break; 161 case OWRITE: 162 qlock(&inlock); 163 qlock(&outlock); 164 if (audio_file_in < 0) { 165 close(audio_file); 166 audio_file = -1; 167 } 168 audio_file_out = -1; 169 qunlock(&outlock); 170 qunlock(&inlock); 171 break; 172 case ORDWR: 173 qlock(&inlock); 174 qlock(&outlock); 175 close(audio_file); 176 audio_file_in = audio_file_out = audio_file = -1; 177 qunlock(&outlock); 178 qunlock(&inlock); 179 break; 180 } 181 } 182 183 void 184 audio_ctl_close(Chan *c) 185 { 186 } 187 188 long 189 audio_file_read(Chan *c, void *va, long count, vlong offset) 190 { 191 struct timespec time; 192 long ba, status, chunk, total; 193 char *pva = (char *) va; 194 195 qlock(&inlock); 196 if(waserror()){ 197 qunlock(&inlock); 198 nexterror(); 199 } 200 201 if(audio_file_in < 0) 202 error(Eperm); 203 204 /* check block alignment */ 205 ba = av.in.bits * av.in.chan / Bits_Per_Byte; 206 207 if(count % ba) 208 error(Ebadarg); 209 210 if(!audio_pause_in(audio_file_in, A_UnPause)) 211 error(Eio); 212 213 total = 0; 214 while(total < count) { 215 chunk = count - total; 216 osenter(); 217 status = read(audio_file_in, pva + total, chunk); 218 osleave(); 219 if(status < 0) 220 error(Eio); 221 total += status; 222 } 223 224 if(total != count) 225 error(Eio); 226 227 if(audio_swap_flag && av.out.bits == 16) 228 audio_swap_endian(pva, count); 229 230 poperror(); 231 qunlock(&inlock); 232 233 return count; 234 } 235 236 long 237 audio_file_write(Chan *c, void *va, long count, vlong offset) 238 { 239 struct timespec time; 240 long status = -1; 241 long ba, total, chunk, bufsz; 242 243 if (debug > 1) 244 print("audio_file_write(0x%.8lux, 0x%.8lux, %ld, %uld)\n", 245 c, va, count, offset); 246 247 qlock(&outlock); 248 if(waserror()){ 249 qunlock(&outlock); 250 nexterror(); 251 } 252 253 if(audio_file_out < 0) 254 error(Eperm); 255 256 /* check block alignment */ 257 ba = av.out.bits * av.out.chan / Bits_Per_Byte; 258 259 if(count % ba) 260 error(Ebadarg); 261 262 if(audio_swap_flag && av.out.bits == 16) 263 audio_swap_endian(va, count); 264 265 total = 0; 266 bufsz = av.out.buf * Audio_Max_Buf / Audio_Max_Val; 267 268 if(bufsz == 0) 269 error(Ebadarg); 270 271 while(total < count) { 272 chunk = min(bufsz, count - total); 273 osenter(); 274 status = write(audio_file_out, va, chunk); 275 osleave(); 276 if(status <= 0) 277 error(Eio); 278 total += status; 279 } 280 281 poperror(); 282 qunlock(&outlock); 283 284 return count; 285 } 286 287 static int 288 audio_open(void) 289 { 290 int fd; 291 292 /* open non-blocking in case someone already has it open */ 293 /* otherwise we would block until they close! */ 294 fd = open(AUDIO_FILE_STRING, O_RDWR|O_NONBLOCK); 295 if(fd < 0) 296 oserror(); 297 298 /* change device to be blocking */ 299 if(!audio_set_blocking(fd)) { 300 if (debug) 301 print("audio_open: failed to set blocking\n"); 302 close(fd); 303 error("cannot set blocking mode"); 304 } 305 306 if (debug) 307 print("audio_open: blocking set\n"); 308 309 /* set audio info */ 310 av.in.flags = ~0; 311 av.out.flags = 0; 312 313 if(! audio_set_info(fd, &av.in, A_In)) { 314 close(fd); 315 error(Ebadarg); 316 } 317 318 av.in.flags = 0; 319 320 /* tada, we're open, blocking, paused and flushed */ 321 return fd; 322 } 323 324 long 325 audio_ctl_write(Chan *c, void *va, long count, vlong offset) 326 { 327 int fd; 328 int ff; 329 Audio_t tmpav = av; 330 331 tmpav.in.flags = 0; 332 tmpav.out.flags = 0; 333 334 if (!audioparse(va, count, &tmpav)) 335 error(Ebadarg); 336 337 if (!audio_enforce(&tmpav)) 338 error(Ebadarg); 339 340 qlock(&inlock); 341 if (waserror()) { 342 qunlock(&inlock); 343 nexterror(); 344 } 345 346 if (audio_file_in >= 0 && (tmpav.in.flags & AUDIO_MOD_FLAG)) { 347 if (!audio_pause_in(audio_file_in, A_Pause)) 348 error(Ebadarg); 349 if (!audio_flush(audio_file_in, A_In)) 350 error(Ebadarg); 351 if (!audio_set_info(audio_file_in, &tmpav.in, A_In)) 352 error(Ebadarg); 353 } 354 poperror(); 355 qunlock(&inlock); 356 357 qlock(&outlock); 358 if (waserror()) { 359 qunlock(&outlock); 360 nexterror(); 361 } 362 if (audio_file_out >= 0 && (tmpav.out.flags & AUDIO_MOD_FLAG)){ 363 if (!audio_pause_out(audio_file_out)) 364 error(Ebadarg); 365 if (!audio_set_info(audio_file_out, &tmpav.out, A_Out)) 366 error(Ebadarg); 367 } 368 poperror(); 369 qunlock(&outlock); 370 371 tmpav.in.flags = 0; 372 tmpav.out.flags = 0; 373 374 av = tmpav; 375 376 return count; 377 } 378 379 380 381 static int 382 audio_set_blocking(int fd) 383 { 384 int val; 385 386 if((val = fcntl(fd, F_GETFL, 0)) == -1) 387 return 0; 388 389 val &= ~O_NONBLOCK; 390 391 if(fcntl(fd, F_SETFL, val) < 0) 392 return 0; 393 394 return 1; 395 } 396 397 static int 398 doioctl(int fd, int ctl, int *info) 399 { 400 int status; 401 osenter(); 402 status = ioctl(fd, ctl, info); /* qlock and load general stuff */ 403 osleave(); 404 if (status < 0) 405 print("doioctl(0x%.8lux, 0x%.8lux) failed %d\n", ctl, *info, errno); 406 return status; 407 } 408 409 static int 410 choosefmt(Audio_d *i) 411 { 412 int newbits, newenc; 413 414 newbits = i->bits; 415 newenc = i->enc; 416 switch (newenc) { 417 case Audio_Alaw_Val: 418 if (newbits == 8) 419 return AFMT_A_LAW; 420 break; 421 case Audio_Ulaw_Val: 422 if (newbits == 8) 423 return AFMT_MU_LAW; 424 break; 425 case Audio_Pcm_Val: 426 if (newbits == 8) 427 return AFMT_U8; 428 else if (newbits == 16) 429 return AFMT_S16_LE; 430 break; 431 } 432 return -1; 433 } 434 435 static int 436 audio_set_info(int fd, Audio_d *i, int d) 437 { 438 int status; 439 int unequal_stereo = 0; 440 441 if(fd < 0) 442 return 0; 443 444 /* fmt */ 445 if(i->flags & (AUDIO_BITS_FLAG || AUDIO_ENC_FLAG)) { 446 int oldfmt, newfmt; 447 oldfmt = AFMT_QUERY; 448 if (doioctl(fd, SNDCTL_DSP_SETFMT, &oldfmt) < 0) 449 return 0; 450 if (debug) 451 print("audio_set_info: current format 0x%.8lux\n", oldfmt); 452 newfmt = choosefmt(i); 453 if (debug) 454 print("audio_set_info: new format 0x%.8lux\n", newfmt); 455 if (newfmt == -1 || newfmt != oldfmt && doioctl(fd, SNDCTL_DSP_SETFMT, &newfmt) < 0) 456 return 0; 457 } 458 459 /* channels */ 460 if(i->flags & AUDIO_CHAN_FLAG) { 461 int channels = i->chan; 462 if (debug) 463 print("audio_set_info: new channels %d\n", channels); 464 if (doioctl(fd, SNDCTL_DSP_CHANNELS, &channels) < 0 465 || channels != i->chan) 466 return 0; 467 } 468 469 /* sample rate */ 470 if(i->flags & AUDIO_RATE_FLAG) { 471 int speed = i->rate; 472 if (debug) 473 print("audio_set_info: new speed %d\n", speed); 474 if (doioctl(fd, SNDCTL_DSP_SPEED, &speed) < 0 || speed != i->rate) 475 return 0; 476 } 477 478 /* dev volume */ 479 if(i->flags & (AUDIO_LEFT_FLAG | AUDIO_VOL_FLAG | AUDIO_RIGHT_FLAG)) { 480 int val; 481 if (i->flags & (AUDIO_LEFT_FLAG | AUDIO_VOL_FLAG)) 482 mixerleftvol[i->dev] = (i->left * 100) / Audio_Max_Val; 483 if (i->flags & (AUDIO_RIGHT_FLAG | AUDIO_VOL_FLAG)) 484 mixerrightvol[i->dev] = (i->right * 100) / Audio_Max_Val; 485 val = mixerleftvol[i->dev] | (mixerrightvol[i->dev] << 8); 486 doioctl(fd, MIXER_WRITE(i->dev), &val); 487 } 488 489 if (i->flags & AUDIO_DEV_FLAG) { 490 } 491 492 return 1; 493 } 494 495 void 496 audio_swap_endian(char *p, int n) 497 { 498 int b; 499 500 while (n > 1) { 501 b = p[0]; 502 p[0] = p[1]; 503 p[1] = b; 504 p += 2; 505 n -= 2; 506 } 507 } 508 509 static int 510 audio_pause_out(int fd) 511 { 512 USED(fd); 513 return 1; 514 } 515 516 static int 517 audio_pause_in(int fd, int f) 518 { 519 USED(fd); 520 USED(f); 521 return 1; 522 } 523 524 static int 525 audio_flush(int fd, int d) 526 { 527 int x; 528 return doioctl(fd, SNDCTL_DSP_SYNC, &x) >= 0; 529 } 530 531 static int 532 audio_enforce(Audio_t *t) 533 { 534 if((t->in.enc == Audio_Ulaw_Val || t->in.enc == Audio_Alaw_Val) && 535 (t->in.rate != 8000 || t->in.chan != 1)) 536 return 0; 537 if((t->out.enc == Audio_Ulaw_Val || t->out.enc == Audio_Alaw_Val) && 538 (t->out.rate != 8000 || t->out.chan != 1)) 539 return 0; 540 return 1; 541 } 542 543 Audio_t* 544 getaudiodev(void) 545 { 546 return &av; 547 } 548