예제 #1
0
/* Open the audio device and initalize it. */
static void
open_audio(void)
{
	int		err;
	double		vol;

	/* Return if already open */
	if (Audio_fd >= 0)
		return;

	/* Try opening without waiting, first */
	Audio_fd = open(Audio_dev, O_WRONLY | O_NONBLOCK);
	if ((Audio_fd < 0) && (errno == EBUSY)) {
		if (Immediate) {
			Error(stderr, MGET("%s: %s is busy\n"),
			    prog, Audio_dev);
			exit(1);
		}
		if (Verbose) {
			Error(stderr, MGET("%s: waiting for %s..."),
			    prog, Audio_dev);
			(void) fflush(stderr);
		}
		/* Now hang until it's open */
		Audio_fd = open(Audio_dev, O_WRONLY);
		if (Verbose)
			Error(stderr, (Audio_fd < 0) ? "\n" : MGET("open\n"));
	}
	if (Audio_fd < 0) {
		Error(stderr, MGET("%s: error opening "), prog);
		perror(Audio_dev);
		exit(1);
	}

	/* Clear the non-blocking flag (in System V it persists after open) */
	(void) fcntl(Audio_fd, F_SETFL,
	    (fcntl(Audio_fd, F_GETFL, 0) & ~(O_NDELAY | O_NONBLOCK)));

	/* Get the device output encoding configuration */
	if (audio_get_play_config(Audio_fd, &Dev_hdr) != AUDIO_SUCCESS) {
		Error(stderr, MGET("%s: %s is not an audio device\n"),
		    prog, Audio_dev);
		exit(1);
	}

	/* If -v flag, set the output volume now */
	if (Volume != INT_MAX) {
		vol = (double)Volume / (double)MAX_GAIN;
		(void) audio_get_play_gain(Audio_fd, &Savevol);
		err = audio_set_play_gain(Audio_fd, &vol);
		if (err != AUDIO_SUCCESS) {
			Error(stderr,
			    MGET("%s: could not set output volume for %s\n"),
			    prog, Audio_dev);
			exit(1);
		}
	}
}
예제 #2
0
static int
init_device (int volume, unsigned char *data, int fd,
	     unsigned int *header_length)
{
#ifdef SUNOS4_0_3
  if (header_length) *header_length = 0;
  return 0;
#else
  Audio_hdr file_hdr;

  reset_volume_p = 0;
  reset_device_p = 0;

  if (data && fd) ABORT (); /* one or the other */

  if (AUDIO_SUCCESS != audio_get_play_config (audio_fd, &dev_hdr))
    {
      perror ("Not a valid audio device");
      return 1;
    }

  if (AUDIO_SUCCESS != (data
			? audio_decode_filehdr (data, &file_hdr, header_length)
			: audio_read_filehdr (fd, &file_hdr, 0, 0)))
    {
      if (data)
	perror ("invalid audio data");
      else
	perror ("invalid audio file");
      return 1;
    }

  audio_flush_play (audio_fd);

  if (!initialized_device_p || (0 != audio_cmp_hdr (&dev_hdr, &file_hdr)))
    {
      Audio_hdr new_hdr;
      new_hdr = file_hdr;
      reset_device_p = 1;
      initialized_device_p = 1;
      if (AUDIO_SUCCESS != audio_set_play_config (audio_fd, &new_hdr))
	{
	  char buf1 [100], buf2 [100], buf3 [250];
	  audio_enc_to_str (&file_hdr, buf1);
	  audio_enc_to_str (&new_hdr, buf2);
	  sprintf (buf3, "wanted %s, got %s", buf1, buf2);
	  warn (buf3);
	  return 1;
	}
    }

  if (volume < 0 || volume > 100)
    {
      char buf [255];
      sprintf (buf, "volume must be between 0 and 100 (not %d)", volume);
      warn (buf);
      return 1;
    }
  {
    /* set the volume; scale it to 0.0 - 1.0 */
    double V = (volume / 100.0);
    audio_get_play_gain (audio_fd, &old_volume);
    reset_volume_p = 1;
    audio_set_play_gain (audio_fd, &V);
  }

  return 0;
#endif
}
예제 #3
0
/* Play a list of audio files. */
int
main(int argc, char **argv) {
	int		errorStatus = 0;
	int		i;
	int		c;
	int		cnt;
	int		file_type;
	int		rem;
	int		outsiz;
	int		tsize;
	int		len;
	int		err;
	int		ifd;
	int		stdinseen;
	int		regular;
	int		swapBytes;
	int		frame;
	char		*outbuf;
	caddr_t		mapaddr;
	struct stat	st;
	char		*cp;
	char		ctldev[MAXPATHLEN];

	(void) setlocale(LC_ALL, "");
	(void) textdomain(TEXT_DOMAIN);

	/* Get the program name */
	prog = strrchr(argv[0], '/');
	if (prog == NULL)
		prog = argv[0];
	else
		prog++;
	Stdin = MGET("(stdin)");

	/* Check AUDIODEV environment for audio device name */
	if (cp = getenv("AUDIODEV")) {
		Audio_dev = cp;
	}

	/* Parse the command line arguments */
	err = 0;
	while ((i = getopt(argc, argv, prog_opts)) != EOF) {
		switch (i) {
			case 'v':
				if (parse_unsigned(optarg, &Volume, "-v")) {
					err++;
				} else if (Volume > MAX_GAIN) {
					Error(stderr, MGET("%s: invalid value "
					    "for -v\n"), prog);
					err++;
				}
				break;
			case 'd':
				Audio_dev = optarg;
				break;
			case 'V':
				Verbose = TRUE;
				break;
			case 'E':
				Errdetect = TRUE;
				break;
			case 'i':
				Immediate = TRUE;
				break;
			case '?':
				usage();
		/*NOTREACHED*/
		}
	}
	if (err > 0)
		exit(1);

	argc -= optind;		/* update arg pointers */
	argv += optind;

	/* Validate and open the audio device */
	err = stat(Audio_dev, &st);
	if (err < 0) {
		Error(stderr, MGET("%s: cannot stat "), prog);
		perror(Audio_dev);
		exit(1);
	}
	if (!S_ISCHR(st.st_mode)) {
		Error(stderr, MGET("%s: %s is not an audio device\n"), prog,
		    Audio_dev);
		exit(1);
	}

	/* This should probably use audio_cntl instead of open_audio */
	if ((argc <= 0) && isatty(fileno(stdin))) {
		Error(stderr, MGET("%s: No files and stdin is a tty.\n"), prog);
		exit(1);
	}

	/* Check on the -i status now. */
	Audio_fd = open(Audio_dev, O_WRONLY | O_NONBLOCK);
	if ((Audio_fd < 0) && (errno == EBUSY)) {
		if (Immediate) {
			Error(stderr, MGET("%s: %s is busy\n"), prog,
			    Audio_dev);
			exit(1);
		}
	}
	(void) close(Audio_fd);
	Audio_fd = -1;

	/* Try to open the control device and save the current format */
	(void) snprintf(ctldev, sizeof (ctldev), "%sctl", Audio_dev);
	Audio_ctlfd = open(ctldev, O_RDWR);
	if (Audio_ctlfd >= 0) {
		/*
		 * wait for the device to become available then get the
		 * controls. We want to save the format that is left when the
		 * device is in a quiescent state. So wait until then.
		 */
		Audio_fd = open(Audio_dev, O_WRONLY);
		(void) close(Audio_fd);
		Audio_fd = -1;
		if (audio_get_play_config(Audio_ctlfd, &Save_hdr)
		    != AUDIO_SUCCESS) {
			(void) close(Audio_ctlfd);
			Audio_ctlfd = -1;
		}
	}

	/* store AUDIOPATH so we don't keep doing getenv() */
	Audio_path = getenv("AUDIOPATH");

	/* Set up SIGINT handler to flush output */
	(void) signal(SIGINT, sigint);

	/* Set the endian nature of the machine. */
	if ((ulong_t)1 != htonl((ulong_t)1)) {
		NetEndian = FALSE;
	}

	/* If no filenames, read stdin */
	stdinseen = FALSE;
	if (argc <= 0) {
		Ifile = Stdin;
	} else {
		Ifile = *argv++;
		argc--;
	}

	/* Loop through all filenames */
	do {
		/* Interpret "-" filename to mean stdin */
		if (strcmp(Ifile, "-") == 0)
			Ifile = Stdin;

		if (Ifile == Stdin) {
			if (stdinseen) {
				Error(stderr,
				    MGET("%s: stdin already processed\n"),
				    prog);
				goto nextfile;
			}
			stdinseen = TRUE;
			ifd = fileno(stdin);
		} else {
			if ((ifd = path_open(Ifile, O_RDONLY, 0, Audio_path))
			    < 0) {
				Error(stderr, MGET("%s: cannot open "), prog);
				perror(Ifile);
				errorStatus++;
				goto nextfile;
			}
		}

		/* Check to make sure this is an audio file */
		err = audio_read_filehdr(ifd, &File_hdr, &file_type,
		    (char *)NULL, 0);
		if (err != AUDIO_SUCCESS) {
			Error(stderr,
			    MGET("%s: %s is not a valid audio file\n"),
			    prog, Ifile);
			errorStatus++;
			goto closeinput;
		}

		/* If G.72X adpcm, set flags for conversion */
		if ((File_hdr.encoding == AUDIO_ENCODING_G721) &&
		    (File_hdr.samples_per_unit == 2) &&
		    (File_hdr.bytes_per_unit == 1)) {
			Decode = AUDIO_ENCODING_G721;
			File_hdr.encoding = AUDIO_ENCODING_ULAW;
			File_hdr.samples_per_unit = 1;
			File_hdr.bytes_per_unit = 1;
			adpcm_state = (struct audio_g72x_state *)malloc
			    (sizeof (*adpcm_state) * File_hdr.channels);
			for (i = 0; i < File_hdr.channels; i++) {
				g721_init_state(&adpcm_state[i]);
			}
		} else if ((File_hdr.encoding == AUDIO_ENCODING_G723) &&
		    (File_hdr.samples_per_unit == 8) &&
		    (File_hdr.bytes_per_unit == 3)) {
			Decode = AUDIO_ENCODING_G723;
			File_hdr.encoding = AUDIO_ENCODING_ULAW;
			File_hdr.samples_per_unit = 1;
			File_hdr.bytes_per_unit = 1;
			adpcm_state = (struct audio_g72x_state *)malloc
			    (sizeof (*adpcm_state) * File_hdr.channels);
			for (i = 0; i < File_hdr.channels; i++) {
				g723_init_state(&adpcm_state[i]);
			}
		} else {
			Decode = AUDIO_ENCODING_NONE;
		}

		/* Check the device configuration */
		open_audio();
		if (audio_cmp_hdr(&Dev_hdr, &File_hdr) != 0) {
			/*
			 * The device does not match the input file.
			 * Wait for any old output to drain, then attempt
			 * to reconfigure the audio device to match the
			 * input data.
			 */
			if (audio_drain(Audio_fd, FALSE) != AUDIO_SUCCESS) {
				/* Flush any remaining audio */
				(void) ioctl(Audio_fd, I_FLUSH, FLUSHW);

				Error(stderr, MGET("%s: "), prog);
				perror(MGET("AUDIO_DRAIN error"));
				exit(1);
			}

			/* Flush any remaining audio */
			(void) ioctl(Audio_fd, I_FLUSH, FLUSHW);

			if (!reconfig()) {
				errorStatus++;
				goto closeinput;
			}
		}


		/* try to do the mmaping - for regular files only ... */
		err = fstat(ifd, &st);
		if (err < 0) {
			Error(stderr, MGET("%s: cannot stat "), prog);
			perror(Ifile);
			exit(1);
		}
		regular = (S_ISREG(st.st_mode));


		/* If regular file, map it.  Else, allocate a buffer */
		mapaddr = 0;

		/*
		 * This should compare to MAP_FAILED not -1, can't
		 * find MAP_FAILED
		 */
		if (regular && ((mapaddr = mmap(0, st.st_size, PROT_READ,
		    MAP_SHARED, ifd, 0)) != MAP_FAILED)) {

			(void) madvise(mapaddr, st.st_size, MADV_SEQUENTIAL);

			/* Skip the file header and set the proper size */
			cnt = lseek(ifd, 0, SEEK_CUR);
			if (cnt < 0) {
			    perror("lseek");
			    exit(1);
			}
			inbuf = (unsigned char *) mapaddr + cnt;
			len = cnt = st.st_size - cnt;
		} else {		/* Not a regular file, or map failed */

			/* mark is so. */
			mapaddr = 0;

			/* Allocate buffer to hold 10 seconds of data */
			cnt = BUFFER_LEN * File_hdr.sample_rate *
			    File_hdr.bytes_per_unit * File_hdr.channels;
			if (bufsiz != cnt) {
				if (buf != NULL) {
					(void) free(buf);
				}
				buf = (unsigned char *) malloc(cnt);
				if (buf == NULL) {
					Error(stderr,
					    MGET("%s: couldn't allocate %dK "
					    "buf\n"), prog, bufsiz / 1000);
					exit(1);
				}
				inbuf = buf;
				bufsiz = cnt;
			}
		}

		/* Set buffer sizes and pointers for conversion, if any */
		switch (Decode) {
		default:
		case AUDIO_ENCODING_NONE:
			insiz = bufsiz;
			outbuf = (char *)buf;
			break;
		case AUDIO_ENCODING_G721:
			insiz = ADPCM_SIZE / 2;
			outbuf = (char *)adpcm_buf;
			initmux(1, 2);
			break;
		case AUDIO_ENCODING_G723:
			insiz = (ADPCM_SIZE * 3) / 8;
			outbuf = (char *)adpcm_buf;
			initmux(3, 8);
			break;
		}

		/*
		 * 8-bit audio isn't a problem, however 16-bit audio is.
		 * If the file is an endian that is different from the machine
		 * then the bytes will need to be swapped.
		 *
		 * Note: Because the G.72X conversions produce 8bit output,
		 * they don't require a byte swap before display and so
		 * this scheme works just fine. If a conversion is added
		 * that produces a 16 bit result and therefore requires
		 * byte swapping before output, then a mechanism
		 * for chaining the two conversions will have to be built.
		 *
		 * Note: The following if() could be simplified, but then
		 * it gets to be very hard to read. So it's left as is.
		 */

		if (File_hdr.bytes_per_unit == 2 &&
		    ((!NetEndian && file_type == FILE_AIFF) ||
		    (!NetEndian && file_type == FILE_AU) ||
		    (NetEndian && file_type == FILE_WAV))) {
			swapBytes = TRUE;
		} else {
			swapBytes = FALSE;
		}

		if (swapBytes) {
			/* Read in interal number of sample frames. */
			frame = File_hdr.bytes_per_unit * File_hdr.channels;
			insiz = (SWAP_SIZE / frame) * frame;
			/* make the output buffer  the swap buffer. */
			outbuf = (char *)swap_buf;
		}

		/*
		 * At this point, we're all ready to copy the data.
		 */
		if (mapaddr == 0) { /* Not mmapped, do it a buffer at a time. */
			inbuf = buf;
			frame = File_hdr.bytes_per_unit * File_hdr.channels;
			rem = 0;
			while ((cnt = read(ifd, inbuf+rem, insiz-rem)) >= 0) {
				/*
				 * We need to ensure only an integral number of
				 * samples is ever written to the audio device.
				 */
				cnt = cnt + rem;
				rem = cnt % frame;
				cnt = cnt - rem;

				/*
				 * If decoding adpcm, or swapping bytes do it
				 * now.
				 *
				 * We treat the swapping like a separate
				 * encoding here because the G.72X encodings
				 * decode to single byte output samples. If
				 * another encoding is added and it produces
				 * multi-byte output samples this will have to
				 * be changed.
				 */
				if (Decode == AUDIO_ENCODING_G721) {
				    outsiz = 0;
				    demux(1, cnt / File_hdr.channels);
				    for (c = 0; c < File_hdr.channels; c++) {
					err = g721_decode(in_ch_data[c],
					    cnt / File_hdr.channels,
					    &File_hdr,
					    (void*)out_ch_data[c],
					    &tsize,
					    &adpcm_state[c]);
					outsiz = outsiz + tsize;
					if (err != AUDIO_SUCCESS) {
					    Error(stderr, MGET(
						"%s: error decoding g721\n"),
						prog);
						errorStatus++;
						break;
					}
				    }
				    mux(outbuf);
				    cnt = outsiz;
				} else if (Decode == AUDIO_ENCODING_G723) {
				    outsiz = 0;
				    demux(3, cnt / File_hdr.channels);
				    for (c = 0; c < File_hdr.channels; c++) {
					err = g723_decode(in_ch_data[c],
					    cnt / File_hdr.channels,
					    &File_hdr,
					    (void*)out_ch_data[c],
					    &tsize,
					    &adpcm_state[c]);
					outsiz = outsiz + tsize;
					if (err != AUDIO_SUCCESS) {
					    Error(stderr, MGET(
						"%s: error decoding g723\n"),
						prog);
					    errorStatus++;
					    break;
					}
				    }
				    mux(outbuf);
				    cnt = outsiz;
				} else if (swapBytes) {
					swab((char *)inbuf, outbuf, cnt);
				}

				/* If input EOF, write an eof marker */
				err = write(Audio_fd, outbuf, cnt);

				if (err < 0) {
					perror("write");
					errorStatus++;
					break;
				} else if (err != cnt) {
					Error(stderr,
					    MGET("%s: output error: "), prog);
					perror("");
					errorStatus++;
					break;
				}
				if (cnt == 0) {
					break;
				}
				/* Move remainder to the front of the buffer */
				if (rem != 0) {
					(void *)memcpy(inbuf, inbuf + cnt, rem);
				}

			}
			if (cnt < 0) {
				Error(stderr, MGET("%s: error reading "), prog);
				perror(Ifile);
				errorStatus++;
			}
		} else {	/* We're mmaped */
			if ((Decode != AUDIO_ENCODING_NONE) || swapBytes) {

				/* Transform data if we have to. */
				for (i = 0; i <= len; i += cnt) {
					cnt = insiz;
					if ((i + cnt) > len) {
						cnt = len - i;
					}
					if (Decode == AUDIO_ENCODING_G721) {
					    outsiz = 0;
					    demux(1, cnt / File_hdr.channels);
					    for (c = 0; c < File_hdr.channels;
						c++) {
						err = g721_decode(
						    in_ch_data[c],
						    cnt / File_hdr.channels,
						    &File_hdr,
						    (void*)out_ch_data[c],
						    &tsize,
						    &adpcm_state[c]);
						outsiz = outsiz + tsize;
						if (err != AUDIO_SUCCESS) {
						    Error(stderr, MGET(
							"%s: error decoding "
							"g721\n"), prog);
						    errorStatus++;
						    break;
						}
					    }
					    mux(outbuf);
					} else if
					    (Decode == AUDIO_ENCODING_G723) {
						outsiz = 0;
						demux(3,
						    cnt / File_hdr.channels);
						for (c = 0;
							c < File_hdr.channels;
							c++) {
						    err = g723_decode(
							in_ch_data[c],
							cnt /
							    File_hdr.channels,
							&File_hdr,
							(void*)out_ch_data[c],
							&tsize,
							&adpcm_state[c]);
						    outsiz = outsiz + tsize;
						    if (err != AUDIO_SUCCESS) {
							Error(stderr, MGET(
							    "%s: error "
							    "decoding g723\n"),
							    prog);
							errorStatus++;
							break;
						    }
						}
						mux(outbuf);
					} else if (swapBytes) {
						swab((char *)inbuf, outbuf,
						    cnt);
						outsiz = cnt;
					}
					inbuf += cnt;

					/* If input EOF, write an eof marker */
					err = write(Audio_fd, (char *)outbuf,
					    outsiz);
					if (err < 0) {
						perror("write");
						errorStatus++;
					} else if (outsiz == 0) {
						break;
					}

				}
			} else {
				/* write the whole thing at once!  */
				err = write(Audio_fd, inbuf, len);
				if (err < 0) {
					perror("write");
					errorStatus++;
				}
				if (err != len) {
					Error(stderr,
					    MGET("%s: output error: "), prog);
					perror("");
					errorStatus++;
				}
				err = write(Audio_fd, inbuf, 0);
				if (err < 0) {
					perror("write");
					errorStatus++;
				}
			}
		}

		/* Free memory if decoding ADPCM */
		switch (Decode) {
		case AUDIO_ENCODING_G721:
		case AUDIO_ENCODING_G723:
			freemux();
			break;
		default:
			break;
		}

closeinput:;
		if (mapaddr != 0)
			(void) munmap(mapaddr, st.st_size);
		(void) close(ifd);		/* close input file */
		if (Errdetect) {
			cnt = 0;
			audio_set_play_error(Audio_fd, (unsigned int *)&cnt);
			if (cnt) {
				Error(stderr,
				    MGET("%s: output underflow in %s\n"),
				    Ifile, prog);
				errorStatus++;
			}
		}
nextfile:;
	} while ((argc > 0) && (argc--, (Ifile = *argv++) != NULL));

	/*
	 * Though drain is implicit on close(), it's performed here
	 * to ensure that the volume is reset after all output is complete.
	 */
	(void) audio_drain(Audio_fd, FALSE);

	/* Flush any remaining audio */
	(void) ioctl(Audio_fd, I_FLUSH, FLUSHW);

	if (Volume != INT_MAX)
		(void) audio_set_play_gain(Audio_fd, &Savevol);
	if ((Audio_ctlfd >= 0) && (audio_cmp_hdr(&Save_hdr, &Dev_hdr) != 0)) {
		(void) audio_set_play_config(Audio_fd, &Save_hdr);
	}
	(void) close(Audio_fd);			/* close output */
	return (errorStatus);
}