#include #include #include #include #include #include #include #include #include #include #include #include "config.h" #include "engine.h" #include "utils.h" struct _channel devs[SOUND_MIXER_NRDEVICES + 1]; int mixer_fd; const char ret[10][151]; int recmask; int devmask; int recscr; int stereomask; void initMixer() { mixer_fd = open("/dev/mixer", O_RDWR); if(mixer_fd == ERROR) err_quit("Unable to open /dev/mixer(are you root?)\n"); } int initMask() { if((ioctl(mixer_fd, SOUND_MIXER_READ_RECSRC, &recscr)) == ERROR) return ERROR; if((ioctl(mixer_fd, SOUND_MIXER_READ_RECMASK, &recmask)) == ERROR) return ERROR; if((ioctl(mixer_fd, SOUND_MIXER_READ_DEVMASK, &devmask)) == ERROR) return ERROR; if((ioctl(mixer_fd, SOUND_MIXER_READ_STEREODEVS, &stereomask)) == ERROR) return ERROR; return SUCCESS; } int *readFromDevice(const int device) { int value = 0, *result = NULL, left = 0, right = 0; value = left | (right << 8); if((ioctl(mixer_fd, MIXER_READ(device), &value)) == -1) return NULL; result = malloc(sizeof(int) * 2); if(result == NULL) return NULL; result[0] = value & 0xff; result[1] = (value >> 8) & 0xff; return result; } int writeToDevice(const int device, const int left, const int right) { int value = 0; value = left | (right << 8); if((ioctl(mixer_fd, MIXER_WRITE(device), &value)) == -1) return ERROR; return SUCCESS; } int searchDevice(const char *nameOfDevice) { const char *names[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES; int x = 0; for(x = 0; x < SOUND_MIXER_NRDEVICES; x++) { if(!strncasecmp(names[x], nameOfDevice, strlen(names[x]))) return x; } return ERROR; } int checkSpace(const char *buf) { DIR *profile; struct dirent *prv; int x = 0; profile = opendir(buf); if(!profile) return ERROR; while((prv = readdir(profile))) { if(x > 10) { closedir(profile); return ERROR; } x++; } closedir(profile); return SUCCESS; } int writeFile(const char *name) { FILE *conf; char *buf = NULL, pathname[PATH_MAX + 1]; int x = 0; buf = returnPathdir(); if(checkSpace(buf) == ERROR) return NOSPACE; snprintf(pathname, PATH_MAX, "%s%s.profile", buf, name); free(buf); conf = fopen(pathname, "w"); if(!conf) return ERROR; fprintf(conf, "# Generated by ermixer\n"); fprintf(conf, "# Legend:\n"); fprintf(conf, "# Name: Name_of_Device (Read include/soundcard.h)\n"); fprintf(conf, "# Type: 1(MONO) or 2(STEREO)\n"); fprintf(conf, "# State: 3(PLAY), 4(MUTE), 5(RECORDING) or 6(RECORDABLE)\n"); fprintf(conf, "# Value: Left and right value of channel (in the mono's device right value was ignored\n"); fprintf(conf, "# Done.\n"); while((devs[x].chan) < SOUND_MIXER_NRDEVICES) { if((devs[x].chan) == -1) break; fprintf(conf, "\n[newdevice]\n"); fprintf(conf, "Name=%d\n", devs[x].chan); fprintf(conf, "Type=%d\n", devs[x].type); fprintf(conf, "State=%d\n", devs[x].state); fprintf(conf, "Value=%d:%d\n", devs[x].left, devs[x].right); fprintf(conf, "[endevice]\n"); x++; } fclose(conf); return SUCCESS; } int parseFile(const char *filename) { FILE *parsed; char opt[150], *c = NULL, *buf = NULL, pathname[PATH_MAX + 1]; int x = 0, y = 0; buf = returnPathdir(); snprintf(pathname, PATH_MAX, "%s%s.profile", buf, filename); free(buf); parsed = fopen(pathname, "r"); if(!parsed) return ERROR; memset(devs, 0, sizeof(struct _channel)*(SOUND_MIXER_NRDEVICES + 1)); while(fgets(opt, 150, parsed)) { if(opt[0] == '#') /* it's a comment, go on */ continue; if(!strncmp(opt, "[newdevice]", 11)) { x = 1; continue; } if(!strncmp(opt, "[endevice]", 10)) { x = 0; y++; } if(x) { c = strtok(opt, "="); if(!c) continue; if(!strncmp(opt, "Name", 4)) { c = strtok(NULL, "\n"); if(c) devs[y].chan = atoi(c); } else if(!strncmp(opt, "State", 5)) { c = strtok(NULL, "\n"); if(c) devs[y].state = atoi(c); } else if(!strncmp(opt, "Value", 5)) { c = strtok(NULL, ":"); if(c) { devs[y].left = atoi(c); c = strtok(NULL, "\n"); if(c) devs[y].right = atoi(c); } } else if(!strncmp(opt, "Type", 4)) { c = strtok(NULL, "\n"); if(c) devs[y].type = atoi(c); } } } devs[y].chan = -1; for(x = 0; devs[x].chan < SOUND_MIXER_NRDEVICES; x++) { if(devs[x].chan == -1) break; switch(devs[x].state) { case REC: modifySrc(devs[x].chan, REC); writeToDevice(devs[x].chan, devs[x].left, devs[x].right); break; case MUTE: writeToDevice(devs[x].chan, 0, 0); break; default: writeToDevice(devs[x].chan, devs[x].left, devs[x].right); } } return SUCCESS; } int deleteFile(const char *name) { char *buf = NULL, pathname[PATH_MAX + 1]; buf = returnPathdir(); snprintf(pathname, PATH_MAX, "%s%s.profile", buf, name); free(buf); if(remove(pathname) == -1) return ERROR; return SUCCESS; } int isRecordable(const int device) { if((1 << device) & recmask) return SUCCESS; return ERROR; } int isRecording(const int device) { if((1 << device) & recscr) return SUCCESS; return ERROR; } int modifySrc(const int device, const int caso) { int currentRecmask = 0, newrecmask = 0; if((ioctl(mixer_fd, SOUND_MIXER_READ_RECMASK, ¤tRecmask)) == ERROR) return ERROR; if(!((1 << device) & currentRecmask)) return ERROR; if(caso == REC) newrecmask |= (1 << device); else newrecmask &= ~(1 << device); if (ioctl(mixer_fd, SOUND_MIXER_WRITE_RECSRC, &newrecmask) == -1) return ERROR; if((initMask()) == ERROR) return ERROR; return SUCCESS; } void getChannels() { int *value, device = 0, y = 0; memset(devs, 0, sizeof(struct _channel)*(SOUND_MIXER_NRDEVICES + 1)); for(device = 0; device < SOUND_MIXER_NRDEVICES; device++) { if(!((1 << device) & devmask)) continue; if((1 << device) & stereomask) devs[y].type = STEREO; else devs[y].type = MONO; value = readFromDevice(device); if(!value) continue; devs[y].chan = device; devs[y].left = value[0]; devs[y].right = value[1]; devs[y].state = getState(device, value); free(value); y++; } devs[y].chan = -1; } int getState(const int device, const int *vol) { if((isRecordable(device)) == SUCCESS) { if((isRecording(device)) == SUCCESS) return REC; else return PREC; } if(vol[0] == 0 && vol[1] == 0) return MUTE; return PLAY; } int getProfiles() { DIR *profiles; char *buf = NULL; struct dirent *prv = NULL; int i = 0; buf = returnPathdir(); profiles = opendir(buf); if(!profiles) return ERROR; free(buf); memset(ret, 0, sizeof(char) * 1500); while((prv = readdir(profiles))) { if(i == 10) break; if(prv -> d_name[0] == '.') continue; buf = strtok(prv -> d_name, "."); if(!buf) continue; strncpy((char *)ret[i++], buf, 150); } return SUCCESS; } void err_quit(const char *msg) { perror(msg); exit(EXIT_FAILURE); }