tarina

git clone https://git.tarina.org/tarina
Log | Files | Refs | README | LICENSE

iecset.c (10997B)


      1 /*
      2    iecset - change IEC958 status bits on ALSA
      3    Copyright (C) 2003 by Takashi Iwai <tiwai@suse.de>
      4 
      5    This program is free software; you can redistribute it and/or
      6    modify it under the terms of the GNU General Public License
      7    as published by the Free Software Foundation; either version 2
      8    of the License, or (at your option) any later version.
      9    
     10    This program is distributed in the hope that it will be useful,
     11    but WITHOUT ANY WARRANTY; without even the implied warranty of
     12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13    GNU General Public License for more details.
     14    
     15    You should have received a copy of the GNU General Public License
     16    along with this program; if not, write to the Free Software
     17    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
     18  */
     19 
     20 #include <stdio.h>
     21 #include <ctype.h>
     22 #include <alsa/asoundlib.h>
     23 
     24 void dump_iec958(snd_aes_iec958_t *iec);
     25 
     26 static int get_bool(const char *str)
     27 {
     28 	if (strncmp(str, "yes", 3) == 0 ||
     29 	    strncmp(str, "YES", 3) == 0 ||
     30 	    strncmp(str, "on", 2) == 0 ||
     31 	    strncmp(str, "ON", 2) == 0 ||
     32 	    strncmp(str, "true", 4) == 0 ||
     33 	    strncmp(str, "TRUE", 4) == 0 ||
     34 	    *str == '1')
     35 		return 1;
     36 	return 0;
     37 }
     38 
     39 enum {
     40 	CMD_BOOL, CMD_BOOL_INV, CMD_INT
     41 };
     42 
     43 enum {
     44 	IDX_PRO, IDX_NOAUDIO, IDX_RATE, IDX_UNLOCK, IDX_SBITS, IDX_WORD, IDX_EMP, IDX_CAT, IDX_NOCOPY, IDX_ORIG,
     45 	IDX_LAST
     46 };
     47 
     48 struct cmdtbl {
     49 	const char *name;
     50 	int idx;
     51 	int type;
     52 	const char *desc;
     53 };
     54 
     55 static const struct cmdtbl cmds[] = {
     56 	{ "pro", IDX_PRO, CMD_BOOL,
     57 	  "professional (common)\n\toff = consumer mode, on = professional mode" },
     58 	{ "aud", IDX_NOAUDIO, CMD_BOOL_INV,
     59 	  "audio (common)\n\ton = audio mode, off = non-audio mode" },
     60 	{ "rat", IDX_RATE, CMD_INT,
     61 	  "rate (common)\n\tsample rate in Hz (0 = not indicated)" },
     62 	{ "emp", IDX_EMP, CMD_INT,
     63 	  "emphasis (common)\n\t0 = none, 1 = 50/15us, 2 = CCITT" },
     64 	{ "loc", IDX_UNLOCK, CMD_BOOL_INV,
     65 	  "lock (prof.)\n\toff = rate unlocked, on = rate locked" },
     66 	{ "sbi", IDX_SBITS, CMD_INT,
     67 	  "sbits (prof.)\n\tsample bits 2 = 20bit, 4 = 24bit, 6 = undef" },
     68 	{ "wor", IDX_WORD, CMD_INT,
     69 	  "wordlength (prof.)\n\t0=no, 2=22-18bit, 4=23-19bit, 5=24-20bit, 6=20-16bit" },
     70 	{ "cat", IDX_CAT, CMD_INT,
     71 	  "category (consumer)\n\t0-0x7f" },
     72 	{ "cop", IDX_NOCOPY, CMD_BOOL_INV,
     73 	  "copyright (consumer)\n\toff = non-copyright, on = copyright" },
     74 	{ "ori", IDX_ORIG, CMD_BOOL,
     75 	  "original (consumer)\n\toff = 1st-gen, on = original" },
     76 };
     77 
     78 
     79 static void error(const char *s, int err)
     80 {
     81 	fprintf(stderr, "%s: %s\n", s, snd_strerror(err));
     82 }
     83 
     84 
     85 static void usage(void)
     86 {
     87 	int i;
     88 
     89 	printf("Usage: iecset [options] [cmd arg...]\n");
     90 	printf("Options:\n");
     91 	printf("    -D device   specifies the control device to use\n");
     92 	printf("    -c card     specifies the card number to use (equiv. with -Dhw:#)\n");
     93 	printf("    -n number   specifies the control index number (default = 0)\n");
     94 	printf("    -x          dump the dump the AESx hex code for IEC958 PCM parameters\n");
     95 	printf("    -i          read commands from stdin\n");
     96 	printf("Commands:\n");
     97 	for (i = 0; i < (int)(sizeof(cmds)/sizeof(cmds[0])); i++) {
     98 		printf("    %s\n", cmds[i].desc);
     99 	}
    100 }
    101 
    102 
    103 /*
    104  * parse iecset commands
    105  */
    106 static void parse_command(int *parms, const char *c, const char *arg)
    107 {
    108 	int i;
    109 
    110 	for (i = 0; i < (int)(sizeof(cmds)/sizeof(cmds[0])); i++) {
    111 		if (strncmp(c, cmds[i].name, strlen(cmds[i].name)) == 0) {
    112 			int val;
    113 			switch (cmds[i].type) {
    114 			case CMD_BOOL:
    115 				val = get_bool(arg);
    116 				break;
    117 			case CMD_BOOL_INV:
    118 				val = !get_bool(arg);
    119 				break;
    120 			case CMD_INT:
    121 			default:
    122 				val = (int)strtol(arg, NULL, 0);
    123 				break;
    124 			}
    125 			parms[cmds[i].idx] = val;
    126 			return;
    127 		}
    128 	}
    129 }
    130 
    131 static char *skipspace(char *line)
    132 {
    133 	char *p;
    134 	for (p = line; *p && isspace(*p); p++)
    135 		;
    136 	return p;
    137 }
    138 
    139 /*
    140  * parse iecset commands from the file
    141  */
    142 static void parse_file(int *parms, FILE *fp)
    143 {
    144 	char line[1024], *cmd, *arg;
    145 	while (fgets(line, sizeof(line), fp) != NULL) {
    146 		cmd = skipspace(line);
    147 		if (*cmd == '#' || ! *cmd)
    148 			continue;
    149 		for (arg = cmd; *arg && !isspace(*arg); arg++)
    150 			;
    151 		if (! *arg)
    152 			continue;
    153 		*arg++ = 0;
    154 		arg = skipspace(arg);
    155 		if (! *arg)
    156 			continue;
    157 		parse_command(parms, cmd, arg);
    158 	}
    159 }
    160 
    161 /* update iec958 status values
    162  * return non-zero if the values are modified
    163  */
    164 static int update_iec958_status(snd_aes_iec958_t *iec958, int *parms)
    165 {
    166 	int changed = 0;
    167 	if (parms[IDX_PRO] >= 0) {
    168 		if (parms[IDX_PRO])
    169 			iec958->status[0] |= IEC958_AES0_PROFESSIONAL;
    170 		else
    171 			iec958->status[0] &= ~IEC958_AES0_PROFESSIONAL;
    172 		changed = 1;
    173 	}
    174 	if (parms[IDX_NOAUDIO] >= 0) {
    175 		if (parms[IDX_NOAUDIO])
    176 			iec958->status[0] |= IEC958_AES0_NONAUDIO;
    177 		else
    178 			iec958->status[0] &= ~IEC958_AES0_NONAUDIO;
    179 		changed = 1;
    180 	}
    181 	if (parms[IDX_RATE] >= 0) {
    182 		if (iec958->status[0] & IEC958_AES0_PROFESSIONAL) {
    183 			iec958->status[0] &= ~IEC958_AES0_PRO_FS;
    184 			switch (parms[IDX_RATE]) {
    185 			case 44100:
    186 				iec958->status[0] |= IEC958_AES0_PRO_FS_44100;
    187 				break;
    188 			case 48000:
    189 				iec958->status[0] |= IEC958_AES0_PRO_FS_48000;
    190 				break;
    191 			case 32000:
    192 				iec958->status[0] |= IEC958_AES0_PRO_FS_32000;
    193 				break;
    194 			}
    195 		} else {
    196 			iec958->status[3] &= ~IEC958_AES3_CON_FS;
    197 			switch (parms[IDX_RATE]) {
    198 			case 22050:
    199 				iec958->status[3] |= IEC958_AES3_CON_FS_22050;
    200 				break;
    201 			case 24000:
    202 				iec958->status[3] |= IEC958_AES3_CON_FS_24000;
    203 				break;
    204 			case 32000:
    205 				iec958->status[3] |= IEC958_AES3_CON_FS_32000;
    206 				break;
    207 			case 44100:
    208 				iec958->status[3] |= IEC958_AES3_CON_FS_44100;
    209 				break;
    210 			case 48000:
    211 				iec958->status[3] |= IEC958_AES3_CON_FS_48000;
    212 				break;
    213 			case 88200:
    214 				iec958->status[3] |= IEC958_AES3_CON_FS_88200;;
    215 				break;
    216 			case 96000:
    217 				iec958->status[3] |= IEC958_AES3_CON_FS_96000;
    218 				break;
    219 			case 176400:
    220 				iec958->status[3] |= IEC958_AES3_CON_FS_176400;
    221 				break;
    222 			case 192000:
    223 				iec958->status[3] |= IEC958_AES3_CON_FS_192000;
    224 				break;
    225 			case 768000:
    226 				iec958->status[3] |= IEC958_AES3_CON_FS_768000;
    227 				break;
    228 			default:
    229 				iec958->status[3] |= IEC958_AES3_CON_FS_NOTID;
    230 				break;
    231 			}
    232 		}
    233 		changed = 1;
    234 	}
    235 	if (parms[IDX_NOCOPY] >= 0) {
    236 		if (! (iec958->status[0] & IEC958_AES0_PROFESSIONAL)) {
    237 			if (parms[IDX_NOCOPY])
    238 				iec958->status[0] |= IEC958_AES0_CON_NOT_COPYRIGHT;
    239 			else
    240 				iec958->status[0] &= ~IEC958_AES0_CON_NOT_COPYRIGHT;
    241 		}
    242 		changed = 1;
    243 	}
    244 	if (parms[IDX_ORIG] >= 0) {
    245 		if (! (iec958->status[0] & IEC958_AES0_PROFESSIONAL)) {
    246 			if (parms[IDX_ORIG])
    247 				iec958->status[1] |= IEC958_AES1_CON_ORIGINAL;
    248 			else
    249 				iec958->status[1] &= ~IEC958_AES1_CON_ORIGINAL;
    250 		}
    251 		changed = 1;
    252 	}
    253 	if (parms[IDX_EMP] >= 0) {
    254 		if (iec958->status[0] & IEC958_AES0_PROFESSIONAL) {
    255 			iec958->status[0] &= ~IEC958_AES0_PRO_EMPHASIS;
    256 			switch (parms[IDX_EMP]) {
    257 			case 0:
    258 				iec958->status[0] |= IEC958_AES0_PRO_EMPHASIS_NONE;
    259 				break;
    260 			case 1:
    261 				iec958->status[0] |= IEC958_AES0_PRO_EMPHASIS_5015;
    262 				break;
    263 			case 2:
    264 				iec958->status[0] |= IEC958_AES0_PRO_EMPHASIS_CCITT;
    265 				break;
    266 			}
    267 		} else {
    268 			if (parms[IDX_EMP])
    269 				iec958->status[0] |= IEC958_AES0_CON_EMPHASIS_5015;
    270 			else
    271 				iec958->status[0] &= ~IEC958_AES0_CON_EMPHASIS_5015;
    272 		}
    273 		changed = 1;
    274 	}
    275 	if (parms[IDX_UNLOCK] >= 0) {
    276 		if (iec958->status[0] & IEC958_AES0_PROFESSIONAL) {
    277 			if (parms[IDX_UNLOCK])
    278 				iec958->status[0] |= IEC958_AES0_PRO_FREQ_UNLOCKED;
    279 			else
    280 				iec958->status[0] &= ~IEC958_AES0_PRO_FREQ_UNLOCKED;
    281 		}
    282 		changed = 1;
    283 	}
    284 	if (parms[IDX_SBITS] >= 0) {
    285 		if (iec958->status[0] & IEC958_AES0_PROFESSIONAL) {
    286 			iec958->status[2] &= ~IEC958_AES2_PRO_SBITS;
    287 			iec958->status[2] |= parms[IDX_SBITS] & 7;
    288 		}
    289 		changed = 1;
    290 	}
    291 	if (parms[IDX_WORD] >= 0) {
    292 		if (iec958->status[0] & IEC958_AES0_PROFESSIONAL) {
    293 			iec958->status[2] &= ~IEC958_AES2_PRO_WORDLEN;
    294 			iec958->status[2] |= (parms[IDX_WORD] & 7) << 3;
    295 		}
    296 		changed = 1;
    297 	}
    298 	if (parms[IDX_CAT] >= 0) {
    299 		if (! (iec958->status[0] & IEC958_AES0_PROFESSIONAL)) {
    300 			iec958->status[1] &= ~IEC958_AES1_CON_CATEGORY;
    301 			iec958->status[1] |= parms[IDX_CAT] & 0x7f;
    302 		}
    303 		changed = 1;
    304 	}
    305 
    306 	return changed;
    307 }
    308 		
    309 
    310 int main(int argc, char **argv)
    311 {
    312 	const char *dev = "default";
    313 	const char *spdif_str = SND_CTL_NAME_IEC958("", PLAYBACK, DEFAULT);
    314 	int spdif_index = -1;
    315 	snd_ctl_t *ctl;
    316 	snd_ctl_elem_list_t *clist;
    317 	snd_ctl_elem_id_t *cid;
    318 	snd_ctl_elem_value_t *cval;
    319 	snd_aes_iec958_t iec958;
    320 	int from_stdin = 0;
    321 	int dumphex = 0;
    322 	int i, c, err;
    323 	unsigned int controls, cidx;
    324 	char tmpname[32];
    325 	int parms[IDX_LAST];
    326 
    327 	for (i = 0; i < IDX_LAST; i++)
    328 		parms[i] = -1; /* not set */
    329 
    330 	while ((c = getopt(argc, argv, "D:c:n:xhi")) != -1) {
    331 		switch (c) {
    332 		case 'D':
    333 			dev = optarg;
    334 			break;
    335 		case 'c':
    336 			i = atoi(optarg);
    337 			if (i < 0 || i >= 32) {
    338 				fprintf(stderr, "invalid card index %d\n", i);
    339 				return 1;
    340 			}
    341 			sprintf(tmpname, "hw:%d", i);
    342 			dev = tmpname;
    343 			break;
    344 		case 'n':
    345 			spdif_index = atoi(optarg);
    346 			break;
    347 		case 'x':
    348 			dumphex = 1;
    349 			break;
    350 		case 'i':
    351 			from_stdin = 1;
    352 			break;
    353 		default:
    354 			usage();
    355 			return 1;
    356 		}
    357 	}
    358 
    359 	if ((err = snd_ctl_open(&ctl, dev, 0)) < 0) {
    360 		error("snd_ctl_open", err);
    361 		return 1;
    362 	}
    363 
    364 	snd_ctl_elem_list_alloca(&clist);
    365 	if ((err = snd_ctl_elem_list(ctl, clist)) < 0) {
    366 		error("snd_ctl_elem_list", err);
    367 		return 1;
    368 	}
    369 	if ((err = snd_ctl_elem_list_alloc_space(clist, snd_ctl_elem_list_get_count(clist))) < 0) {
    370 		error("snd_ctl_elem_list_alloc_space", err);
    371 		return 1;
    372 	}
    373 	if ((err = snd_ctl_elem_list(ctl, clist)) < 0) {
    374 		error("snd_ctl_elem_list", err);
    375 		return 1;
    376 	}
    377 
    378 	controls = snd_ctl_elem_list_get_used(clist);
    379 	for (cidx = 0; cidx < controls; cidx++) {
    380 		if (!strcmp(snd_ctl_elem_list_get_name(clist, cidx), spdif_str))
    381 			if (spdif_index < 0 ||
    382 			    snd_ctl_elem_list_get_index(clist, cidx) == spdif_index)
    383 				break;
    384 	}
    385 	if (cidx >= controls) {
    386 		fprintf(stderr, "control \"%s\" (index %d) not found\n",
    387 			spdif_str, spdif_index);
    388 		return 1;
    389 	}
    390 
    391 	snd_ctl_elem_id_alloca(&cid);
    392 	snd_ctl_elem_list_get_id(clist, cidx, cid);
    393 	snd_ctl_elem_value_alloca(&cval);
    394 	snd_ctl_elem_value_set_id(cval, cid);
    395 	if ((err = snd_ctl_elem_read(ctl, cval)) < 0) {
    396 		error("snd_ctl_elem_read", err);
    397 		return 1;
    398 	}
    399 
    400 	snd_ctl_elem_value_get_iec958(cval, &iec958);
    401 
    402 	/* parse from stdin */
    403 	if (from_stdin)
    404 		parse_file(parms, stdin);
    405 
    406 	/* parse commands */
    407 	for (c = optind; c < argc - 1; c += 2)
    408 		parse_command(parms, argv[c], argv[c + 1]);
    409 
    410 	if (update_iec958_status(&iec958, parms)) {
    411 		/* store the values */
    412 		snd_ctl_elem_value_set_iec958(cval, &iec958);
    413 		if ((err = snd_ctl_elem_write(ctl, cval)) < 0) {
    414 			error("snd_ctl_elem_write", err);
    415 			return 1;
    416 		}
    417 		if ((err = snd_ctl_elem_read(ctl, cval)) < 0) {
    418 			error("snd_ctl_elem_write", err);
    419 			return 1;
    420 		}
    421 		snd_ctl_elem_value_get_iec958(cval, &iec958);
    422 	}
    423 
    424 	if (dumphex)
    425 		printf("AES0=0x%02x,AES1=0x%02x,AES2=0x%02x,AES3=0x%02x\n",
    426 		       iec958.status[0], iec958.status[1], iec958.status[2], iec958.status[3]);
    427 	else
    428 		dump_iec958(&iec958);
    429 
    430 	snd_ctl_close(ctl);
    431 	return 0;
    432 }