1/* 2 * Copyright (C) 1997-2004 Kare Sjolander <kare@speech.kth.se> 3 * 4 * This file is part of the Snack Sound Toolkit. 5 * The latest version can be found at http://www.speech.kth.se/snack/ 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 */ 21 22#include "tcl.h" 23#include "jkAudIO.h" 24#include "jkSound.h" 25#include <stdio.h> 26#include <fcntl.h> 27#include <unistd.h> 28#include <sys/ioctl.h> 29#include <alsa/asoundlib.h> 30#include <string.h> 31#include <ctype.h> 32#include <stdlib.h> 33#define DEVICE_NAME "default" 34 35static char *defaultDeviceName = DEVICE_NAME; 36extern void Snack_WriteLog(char *s); 37extern void Snack_WriteLogInt(char *s, int n); 38 39#ifndef min 40#define min(a,b) ((a)<(b)?(a):(b)) 41#define max(a,b) ((a)>(b)?(a):(b)) 42#endif 43 44static int mfd = 0; 45/* 46static struct MixerLink mixerLinks[SOUND_MIXER_NRDEVICES][2]; 47*/ 48static int littleEndian = 0; 49 50static int minNumChan = 1; 51 52int 53SnackAudioOpen(ADesc *A, Tcl_Interp *interp, char *device, int mode, int freq, 54 int nchannels, int encoding) 55{ 56 int format; 57 int nformat; 58 int channels; 59 int speed; 60 int mask; 61 62 snd_pcm_hw_params_t *hw_params; 63 64 if (A->debug > 1) Snack_WriteLog(" Enter SnackAudioOpen\n"); 65 66 if (device == NULL) { 67 device = defaultDeviceName; 68 } 69 if (strlen(device) == 0) { 70 device = defaultDeviceName; 71 } 72 73 A->mode = mode; 74 switch (mode) { 75 case RECORD: 76 if (snd_pcm_open(&A->handle, device, SND_PCM_STREAM_CAPTURE, 0) < 0) { 77 Tcl_AppendResult(interp, "Could not open ", device, " for read.", 78 NULL); 79 return TCL_ERROR; 80 } 81 break; 82 case PLAY: 83 if (snd_pcm_open(&A->handle, device, SND_PCM_STREAM_PLAYBACK, 0) < 0) { 84 Tcl_AppendResult(interp, "Could not open ", device, " for write.", 85 NULL); 86 return TCL_ERROR; 87 } 88 break; 89 } 90 91 switch (encoding) { 92 case LIN16: 93 if (littleEndian) { 94 format = SND_PCM_FORMAT_S16_LE; 95 } else { 96 format = SND_PCM_FORMAT_S16_BE; 97 } 98 A->bytesPerSample = sizeof(short); 99 break; 100 case LIN24: 101 if (littleEndian) { 102 format = SND_PCM_FORMAT_S32_LE; 103 } else { 104 format = SND_PCM_FORMAT_S32_BE; 105 } 106 A->bytesPerSample = sizeof(int); 107 break; 108 case ALAW: 109 format = SND_PCM_FORMAT_A_LAW; 110 A->bytesPerSample = sizeof(char); 111 break; 112 case MULAW: 113 format = SND_PCM_FORMAT_MU_LAW; 114 A->bytesPerSample = sizeof(char); 115 break; 116 case LIN8OFFSET: 117 format = SND_PCM_FORMAT_U8; 118 A->bytesPerSample = sizeof(char); 119 break; 120 case LIN8: 121 format = SND_PCM_FORMAT_S8; 122 A->bytesPerSample = sizeof(char); 123 break; 124 } 125 126 snd_pcm_hw_params_malloc(&hw_params); 127 snd_pcm_hw_params_any(A->handle, hw_params); 128 snd_pcm_hw_params_set_access(A->handle, hw_params, 129 SND_PCM_ACCESS_RW_INTERLEAVED); 130 snd_pcm_hw_params_set_format(A->handle, hw_params, format); 131 snd_pcm_hw_params_set_rate_near(A->handle, hw_params, &freq, 0); 132 snd_pcm_hw_params_set_channels(A->handle, hw_params, nchannels); 133 134 if (snd_pcm_hw_params(A->handle, hw_params) < 0) { 135 Tcl_AppendResult(interp, "Failed setting HW params.", NULL); 136 return TCL_ERROR; 137 } 138 snd_pcm_hw_params_free(hw_params); 139 snd_pcm_prepare(A->handle); 140 if (A->mode == RECORD) { 141 snd_pcm_start(A->handle); 142 } 143 144 A->freq = freq; 145 A->nWritten = 0; 146 A->nPlayed = 0; 147 148 if (A->debug > 1) Snack_WriteLogInt(" Exit SnackAudioOpen", A->debug); 149 150 return TCL_OK; 151} 152 153int 154SnackAudioClose(ADesc *A) 155{ 156 if (A->debug > 1) Snack_WriteLog(" Enter SnackAudioClose\n"); 157 158 snd_pcm_drop(A->handle); 159 snd_pcm_close(A->handle); 160 161 if (A->debug > 1) Snack_WriteLog(" Exit SnackAudioClose\n"); 162 163 return(0); 164} 165 166long 167SnackAudioPause(ADesc *A) 168{ 169 if (A->mode == RECORD) { 170 snd_pcm_drop(A->handle); 171 return(-1); 172 } else { 173 long res = SnackAudioPlayed(A); 174 A->nPlayed = res; 175 snd_pcm_drop(A->handle); 176 return(res); 177 } 178} 179 180void 181SnackAudioResume(ADesc *A) 182{ 183 if (A->mode == RECORD) { 184 } else { 185 snd_pcm_prepare(A->handle); 186 } 187} 188 189void 190SnackAudioFlush(ADesc *A) 191{ 192 if (A->mode == RECORD) { 193 } else { 194 snd_pcm_drop(A->handle); 195 snd_pcm_prepare(A->handle); 196 } 197} 198 199void 200SnackAudioPost(ADesc *A) 201{ 202 int i; 203 static char buf[64]; 204 205 if (A->debug > 1) Snack_WriteLog(" Enter SnackAudioPost\n"); 206 207 for (i = 0; i < 1000; i++) { 208 snd_pcm_writei(A->handle, &buf, 1); 209 } 210 211 if (A->debug > 1) Snack_WriteLog(" Enter SnackAudioPost\n"); 212} 213 214int 215SnackAudioRead(ADesc *A, void *buf, int nFrames) 216{ 217 int n; 218 219 if (A->debug > 1) Snack_WriteLogInt(" Enter SnackAudioRead", nFrames); 220 221 n = snd_pcm_readi(A->handle, buf, nFrames); 222 223 if (A->debug > 1) Snack_WriteLogInt(" Exit SnackAudioRead", n); 224 225 return(n); 226} 227 228int 229SnackAudioWrite(ADesc *A, void *buf, int nFrames) 230{ 231 int n; 232 233 n = snd_pcm_writei(A->handle, buf, nFrames); 234 A->nWritten += n; 235 236 return(n); 237} 238 239int 240SnackAudioReadable(ADesc *A) 241{ 242 int avail; 243 244 if (A->debug > 1) Snack_WriteLog(" Enter SnackAudioReadable\n"); 245 246 avail = snd_pcm_avail_update(A->handle); 247 248 if (A->debug > 1) Snack_WriteLogInt(" Exit SnackAudioReadable",avail); 249 250 if (avail < 0) 251 avail = 0; 252 253 return (avail); 254} 255 256int 257SnackAudioWriteable(ADesc *A) 258{ 259 int avail = snd_pcm_avail_update(A->handle); 260 261 if (avail < 0) 262 avail = 0; 263 264 return (avail); 265} 266 267long 268SnackAudioPlayed(ADesc *A) 269{ 270 long avail = _snd_pcm_mmap_hw_ptr(A->handle); 271 272 if (avail < 0) 273 avail = 0; 274 275 return (avail+A->nPlayed); 276} 277 278void 279SnackAudioInit() 280{ 281 union { 282 char c[sizeof(short)]; 283 short s; 284 } order; 285 int afd, format, channels, nchannels; 286 /* 287 int i, n; 288 char *arr[MAX_NUM_DEVICES]; 289 */ 290 291 /* Compute the byte order of this machine. */ 292 293 order.s = 1; 294 if (order.c[0] == 1) { 295 littleEndian = 1; 296 } 297} 298 299void 300SnackAudioFree() 301{ 302 int i, j; 303 /* 304 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 305 for (j = 0; j < 2; j++) { 306 if (mixerLinks[i][j].mixer != NULL) { 307 ckfree(mixerLinks[i][j].mixer); 308 } 309 if (mixerLinks[i][j].mixerVar != NULL) { 310 ckfree(mixerLinks[i][j].mixerVar); 311 } 312 } 313 if (mixerLinks[i][0].jack != NULL) { 314 ckfree(mixerLinks[i][0].jack); 315 } 316 if (mixerLinks[i][0].jackVar != NULL) { 317 ckfree(mixerLinks[i][0].jackVar); 318 } 319 } 320 */ 321} 322 323void 324ASetRecGain(int gain) 325{ 326 int g = min(max(gain, 0), 100); 327 int recsrc = 0; 328 /* 329 g = g * 256 + g; 330 ioctl(mfd, SOUND_MIXER_READ_RECSRC, &recsrc); 331 if (recsrc & SOUND_MASK_LINE) { 332 ioctl(mfd, SOUND_MIXER_WRITE_LINE, &g); 333 } else { 334 ioctl(mfd, SOUND_MIXER_WRITE_MIC, &g); 335 } 336 */ 337} 338 339void 340ASetPlayGain(int gain) 341{ 342 int g = min(max(gain, 0), 100); 343 int pcm_gain = 25700; 344 /* 345 g = g * 256 + g; 346 ioctl(mfd, SOUND_MIXER_WRITE_VOLUME, &g); 347 ioctl(mfd, SOUND_MIXER_WRITE_PCM, &pcm_gain); 348 */ 349} 350 351int 352AGetRecGain() 353{ 354 int g = 0, left, right, recsrc = 0; 355/* 356 ioctl(mfd, SOUND_MIXER_READ_RECSRC, &recsrc); 357 if (recsrc & SOUND_MASK_LINE) { 358 ioctl(mfd, SOUND_MIXER_READ_LINE, &g); 359 } else { 360 ioctl(mfd, SOUND_MIXER_READ_MIC, &g); 361 } 362 left = g & 0xff; 363 right = (g & 0xff00) / 256; 364 g = (left + right) / 2; 365*/ 366 return(g); 367} 368 369int 370AGetPlayGain() 371{ 372 int g = 0, left, right; 373 /* 374 ioctl(mfd, SOUND_MIXER_READ_VOLUME, &g); 375 left = g & 0xff; 376 right = (g & 0xff00) / 256; 377 g = (left + right) / 2; 378 */ 379 return(g); 380} 381 382int 383SnackAudioGetEncodings(char *device) 384{ 385 int afd, mask; 386 /* 387 if ((afd = open(DEVICE_NAME, O_WRONLY, 0)) == -1) { 388 return(0); 389 } 390 if (ioctl(afd, SNDCTL_DSP_GETFMTS, &mask) == -1) { 391 return(0); 392 } 393 close(afd); 394 395 if (mask & AFMT_S16_LE || mask & AFMT_S16_BE) {*/ 396 return(LIN16); 397 /* } else { 398 return(0); 399 }*/ 400} 401 402void 403SnackAudioGetRates(char *device, char *buf, int n) 404{ 405 strncpy(buf, "8000 11025 16000 22050 32000 44100 48000", n); 406 buf[n-1] = '\0'; 407} 408 409int 410SnackAudioMaxNumberChannels(char *device) 411{ 412 return(2); 413} 414 415int 416SnackAudioMinNumberChannels(char *device) 417{ 418 return(minNumChan); 419} 420 421void 422SnackMixerGetInputJackLabels(char *buf, int n) 423{/* 424 char *jackLabels[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_LABELS; 425 int i, recMask, pos = 0; 426 427 if (mfd != -1) { 428 ioctl(mfd, SOUND_MIXER_READ_RECMASK, &recMask); 429 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 430 if ((1 << i) & recMask) { 431 pos += sprintf(&buf[pos], "%s", jackLabels[i]); 432 pos += sprintf(&buf[pos], " "); 433 } 434 } 435 } else { 436 buf[0] = '\0'; 437 } 438 buf[n-1] = '\0';*/ 439} 440 441void 442SnackMixerGetOutputJackLabels(char *buf, int n) 443{ 444 buf[0] = '\0'; 445} 446 447void 448SnackMixerGetInputJack(char *buf, int n) 449{/* 450 char *jackLabels[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_LABELS; 451 int i, recSrc = 0, pos = 0; 452 453 ioctl(mfd, SOUND_MIXER_READ_RECSRC, &recSrc); 454 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 455 if ((1 << i) & recSrc) { 456 pos += sprintf(&buf[pos], "%s", jackLabels[i]); 457 while (isspace(buf[pos-1])) pos--; 458 pos += sprintf(&buf[pos], " "); 459 } 460 } 461 if(isspace(buf[pos-1])) pos--; 462 buf[pos] = '\0';*/ 463 /*printf("SnackMixerGetInputJack %x, %s\n", recSrc, buf);*/ 464} 465 466int 467SnackMixerSetInputJack(Tcl_Interp *interp, char *jack, CONST84 char *status) 468{/* 469 char *jackLabels[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_LABELS; 470 int i, recSrc = 0, currSrc; 471 472 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 473 if (strncasecmp(jack, jackLabels[i], strlen(jack)) == 0) { 474 recSrc = 1 << i; 475 break; 476 } 477 } 478 479 ioctl(mfd, SOUND_MIXER_READ_RECSRC, &currSrc); 480 */ 481/* printf("SnackMixerSetInputJack1 %x %s %s\n", currSrc, jack, status);*/ 482 /* 483 if (strcmp(status, "1") == 0) { 484 recSrc |= currSrc; 485 } else { 486 recSrc = (currSrc & ~recSrc); 487 }*/ 488/* printf("SnackMixerSetInputJack2 %x\n", recSrc);*/ 489 /* 490 if (ioctl(mfd, SOUND_MIXER_WRITE_RECSRC, &recSrc) == -1) { 491 return 1; 492 } else { 493 ioctl(mfd, SOUND_MIXER_READ_RECSRC, &recSrc);*/ 494/* printf("SnackMixerSetInputJack3 %x\n", recSrc);*/ 495 /* return 0; 496 }*/ 497 return 1; 498} 499 500void 501SnackMixerGetOutputJack(char *buf, int n) 502{ 503 buf[0] = '\0'; 504} 505 506void 507SnackMixerSetOutputJack(char *jack, char *status) 508{ 509} 510 511static int dontTrace = 0; 512 513static char * 514JackVarProc(ClientData clientData, Tcl_Interp *interp, CONST84 char *name1, 515 CONST84 char *name2, int flags) 516{/* 517 MixerLink *mixLink = (MixerLink *) clientData; 518 char *jackLabels[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_LABELS; 519 int i, recSrc = 0, status = 0; 520 CONST84 char *stringValue; 521 Tcl_Obj *obj, *var; 522 523 if (dontTrace) return (char *) NULL; 524 525 ioctl(mfd, SOUND_MIXER_READ_RECSRC, &recSrc);*/ 526/*printf("JackVarProc %x %s %s\n", recSrc, name1, name2);*/ 527 /* if (flags & TCL_TRACE_UNSETS) { 528 if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) { 529 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 530 if (strncasecmp(mixLink->jack, jackLabels[i], strlen(mixLink->jack)) 531 == 0) { 532 if ((1 << i) & recSrc) { 533 status = 1; 534 } else { 535 status = 0; 536 } 537 break; 538 } 539 } 540 obj = Tcl_NewIntObj(status); 541 var = Tcl_NewStringObj(mixLink->jackVar, -1); 542 Tcl_ObjSetVar2(interp, var, NULL, obj, TCL_GLOBAL_ONLY | TCL_PARSE_PART1); 543 Tcl_TraceVar(interp, mixLink->jackVar, 544 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, 545 JackVarProc, mixLink); 546 } 547 return (char *) NULL; 548 } 549 550 stringValue = Tcl_GetVar(interp, mixLink->jackVar, TCL_GLOBAL_ONLY); 551 if (stringValue != NULL) { 552 SnackMixerSetInputJack(interp, mixLink->jack, stringValue); 553 } 554 555 ioctl(mfd, SOUND_MIXER_READ_RECSRC, &recSrc);*/ 556 /*printf("JackVarProc2 %x\n", recSrc);*//* 557 dontTrace = 1; 558 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 559 if (mixerLinks[i][0].jackVar != NULL) { 560 if ((1 << i) & recSrc) { 561 status = 1; 562 } else { 563 status = 0; 564 } 565 obj = Tcl_NewIntObj(status); 566 var = Tcl_NewStringObj(mixerLinks[i][0].jackVar, -1); 567 Tcl_ObjSetVar2(interp, var, NULL, obj, TCL_GLOBAL_ONLY |TCL_PARSE_PART1); 568 } 569 } 570 dontTrace = 0; 571 */ 572 return (char *) NULL; 573} 574 575void 576SnackMixerLinkJacks(Tcl_Interp *interp, char *jack, Tcl_Obj *var) 577{/* 578 char *jackLabels[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_LABELS; 579 int i, recSrc = 0, status; 580 CONST84 char *value; 581 582 ioctl(mfd, SOUND_MIXER_READ_RECSRC, &recSrc); 583 584 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 585 if (strncasecmp(jack, jackLabels[i], strlen(jack)) == 0) { 586 if ((1 << i) & recSrc) { 587 status = 1; 588 } else { 589 status = 0; 590 } 591 mixerLinks[i][0].jack = SnackStrDup(jack); 592 mixerLinks[i][0].jackVar = SnackStrDup(Tcl_GetStringFromObj(var, NULL)); 593 value = Tcl_GetVar(interp, mixerLinks[i][0].jackVar, TCL_GLOBAL_ONLY); 594 if (value != NULL) { 595 SnackMixerSetInputJack(interp, mixerLinks[i][0].jack, value); 596 } else { 597 Tcl_Obj *obj = Tcl_NewIntObj(status); 598 Tcl_ObjSetVar2(interp, var, NULL, obj, 599 TCL_GLOBAL_ONLY | TCL_PARSE_PART1); 600 601 } 602 Tcl_TraceVar(interp, mixerLinks[i][0].jackVar, 603 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, 604 JackVarProc, (ClientData) &mixerLinks[i][0]); 605 break; 606 } 607 }*/ 608} 609 610void 611SnackMixerGetChannelLabels(char *line, char *buf, int n) 612{/* 613 char *mixLabels[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_LABELS; 614 int i, devMask; 615 616 ioctl(mfd, SOUND_MIXER_READ_STEREODEVS, &devMask); 617 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 618 if (strncasecmp(line, mixLabels[i], strlen(line)) == 0) { 619 if (devMask & (1 << i)) { 620 sprintf(buf, "Left Right"); 621 } else { 622 sprintf(buf, "Mono"); 623 } 624 break; 625 } 626 }*/ 627} 628 629void 630SnackMixerGetVolume(char *line, int channel, char *buf, int n) 631{/* 632 char *mixLabels[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_LABELS; 633 int i, vol = 0, devMask, isStereo = 0, left, right; 634 635 buf[0] = '\0'; 636 637 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 638 if (strncasecmp(line, mixLabels[i], strlen(line)) == 0) { 639 ioctl(mfd, MIXER_READ(i), &vol); 640 ioctl(mfd, SOUND_MIXER_READ_STEREODEVS, &devMask); 641 if (devMask & (1 << i)) { 642 isStereo = 1; 643 } 644 break; 645 } 646 } 647 left = vol & 0xff; 648 right = (vol & 0xff00) >> 8; 649 if (isStereo) { 650 if (channel == 0) { 651 sprintf(buf, "%d", left); 652 } else if (channel == 1) { 653 sprintf(buf, "%d", right); 654 } else if (channel == -1) { 655 sprintf(buf, "%d", (left + right)/2); 656 } 657 } else { 658 sprintf(buf, "%d", left); 659 }*/ 660} 661 662void 663SnackMixerSetVolume(char *line, int channel, int volume) 664{/* 665 char *mixLabels[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_LABELS; 666 int tmp = min(max(volume, 0), 100), i, oldVol = 0; 667 int vol = (tmp << 8) + tmp; 668 669 if (channel == 0) { 670 vol = tmp; 671 } 672 if (channel == 1) { 673 vol = tmp << 8; 674 } 675 676 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 677 if (strncasecmp(line, mixLabels[i], strlen(line)) == 0) { 678 ioctl(mfd, MIXER_READ(i), &oldVol); 679 if (channel == 0) { 680 vol = (oldVol & 0xff00) | (vol & 0x00ff); 681 } 682 if (channel == 1) { 683 vol = (vol & 0xff00) | (oldVol & 0x00ff); 684 } 685 ioctl(mfd, MIXER_WRITE(i), &vol); 686 break; 687 } 688 }*/ 689} 690 691static char * 692VolumeVarProc(ClientData clientData, Tcl_Interp *interp, CONST84 char *name1, 693 CONST84 char *name2, int flags) 694{/* 695 MixerLink *mixLink = (MixerLink *) clientData; 696 CONST84 char *stringValue; 697 698 if (flags & TCL_TRACE_UNSETS) { 699 if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) { 700 Tcl_Obj *obj, *var; 701 char tmp[VOLBUFSIZE]; 702 703 SnackMixerGetVolume(mixLink->mixer, mixLink->channel, tmp, VOLBUFSIZE); 704 obj = Tcl_NewIntObj(atoi(tmp)); 705 var = Tcl_NewStringObj(mixLink->mixerVar, -1); 706 Tcl_ObjSetVar2(interp, var, NULL, obj, TCL_GLOBAL_ONLY | TCL_PARSE_PART1); 707 Tcl_TraceVar(interp, mixLink->mixerVar, 708 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, 709 VolumeVarProc, mixLink); 710 } 711 return (char *) NULL; 712 } 713 714 stringValue = Tcl_GetVar(interp, mixLink->mixerVar, TCL_GLOBAL_ONLY); 715 if (stringValue != NULL) { 716 SnackMixerSetVolume(mixLink->mixer, mixLink->channel, atoi(stringValue)); 717 } 718 */ 719 return (char *) NULL; 720} 721 722void 723SnackMixerLinkVolume(Tcl_Interp *interp, char *line, int n, 724 Tcl_Obj *CONST objv[]) 725{/* 726 char *mixLabels[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_LABELS; 727 int i, j, channel; 728 CONST84 char *value; 729 char tmp[VOLBUFSIZE]; 730 731 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 732 if (strncasecmp(line, mixLabels[i], strlen(line)) == 0) { 733 for (j = 0; j < n; j++) { 734 if (n == 1) { 735 channel = -1; 736 } else { 737 channel = j; 738 } 739 mixerLinks[i][j].mixer = SnackStrDup(line); 740 mixerLinks[i][j].mixerVar = SnackStrDup(Tcl_GetStringFromObj(objv[j+3],NULL)); 741 mixerLinks[i][j].channel = j; 742 value = Tcl_GetVar(interp, mixerLinks[i][j].mixerVar, TCL_GLOBAL_ONLY); 743 if (value != NULL) { 744 SnackMixerSetVolume(line, channel, atoi(value)); 745 } else { 746 Tcl_Obj *obj; 747 SnackMixerGetVolume(line, channel, tmp, VOLBUFSIZE); 748 obj = Tcl_NewIntObj(atoi(tmp)); 749 Tcl_ObjSetVar2(interp, objv[j+3], NULL, obj, 750 TCL_GLOBAL_ONLY | TCL_PARSE_PART1); 751 } 752 Tcl_TraceVar(interp, mixerLinks[i][j].mixerVar, 753 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, 754 VolumeVarProc, (ClientData) &mixerLinks[i][j]); 755 } 756 } 757 }*/ 758} 759 760void 761SnackMixerUpdateVars(Tcl_Interp *interp) 762{/* 763 int i, j, recSrc, status; 764 char tmp[VOLBUFSIZE]; 765 Tcl_Obj *obj, *var; 766 767 ioctl(mfd, SOUND_MIXER_READ_RECSRC, &recSrc); 768 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 769 for (j = 0; j < 2; j++) { 770 if (mixerLinks[i][j].mixerVar != NULL) { 771 SnackMixerGetVolume(mixerLinks[i][j].mixer, mixerLinks[i][j].channel, 772 tmp, VOLBUFSIZE); 773 obj = Tcl_NewIntObj(atoi(tmp)); 774 var = Tcl_NewStringObj(mixerLinks[i][j].mixerVar, -1); 775 Tcl_ObjSetVar2(interp, var, NULL, obj, TCL_GLOBAL_ONLY|TCL_PARSE_PART1); 776 } 777 } 778 if (mixerLinks[i][0].jackVar != NULL) { 779 if ((1 << i) & recSrc) { 780 status = 1; 781 } else { 782 status = 0; 783 } 784 obj = Tcl_NewIntObj(status); 785 var = Tcl_NewStringObj(mixerLinks[i][0].jackVar, -1); 786 Tcl_ObjSetVar2(interp, var, NULL, obj, TCL_GLOBAL_ONLY | TCL_PARSE_PART1); 787 } 788 }*/ 789} 790 791void 792SnackMixerGetLineLabels(char *buf, int n) 793{/* 794 char *mixLabels[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_LABELS; 795 int i, devMask, pos = 0; 796 797 if (mfd != -1) { 798 ioctl(mfd, SOUND_MIXER_READ_DEVMASK, &devMask); 799 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 800 if ((1 << i) & devMask && pos < n-8) { 801 pos += sprintf(&buf[pos], "%s", mixLabels[i]); 802 pos += sprintf(&buf[pos], " "); 803 } 804 } 805 } else { 806 buf[0] = '\0'; 807 }*/ 808 buf[n-1] = '\0'; 809} 810 811int 812SnackGetOutputDevices(char **arr, int n) 813{ 814 return SnackGetInputDevices(arr, n); 815} 816 817int 818SnackGetInputDevices(char **arr, int n) 819{ 820 int i = -1, j = 0; 821 char devicename[20]; 822 823 arr[j++] = (char *) SnackStrDup("default"); 824 while (snd_card_next(&i) == 0 && i > -1) { 825 if (j < n) { 826 snprintf(devicename, 20, "plughw:%d", i); 827 arr[j++] = (char *) SnackStrDup(devicename); 828 } else { 829 break; 830 } 831 } 832 return(j); 833} 834 835int 836SnackGetMixerDevices(char **arr, int n) 837{ 838 int i = -1, j = 0; 839 char devicename[20]; 840 841 while (snd_card_next(&i) == 0 && i > -1) { 842 snprintf(devicename, 20, "hw:%d", i); 843 if (j < n) { 844 arr[j++] = (char *) SnackStrDup(devicename); 845 } else { 846 break; 847 } 848 } 849 return(j); 850} 851