-#if API_ALSA
-static void log_params(snd_pcm_hw_params_t *hwparams,
- snd_pcm_sw_params_t *swparams) {
- snd_pcm_uframes_t f;
- unsigned u;
-
- return; /* too verbose */
- if(hwparams) {
- /* TODO */
- }
- if(swparams) {
- snd_pcm_sw_params_get_silence_size(swparams, &f);
- info("sw silence_size=%lu", (unsigned long)f);
- snd_pcm_sw_params_get_silence_threshold(swparams, &f);
- info("sw silence_threshold=%lu", (unsigned long)f);
- snd_pcm_sw_params_get_sleep_min(swparams, &u);
- info("sw sleep_min=%lu", (unsigned long)u);
- snd_pcm_sw_params_get_start_threshold(swparams, &f);
- info("sw start_threshold=%lu", (unsigned long)f);
- snd_pcm_sw_params_get_stop_threshold(swparams, &f);
- info("sw stop_threshold=%lu", (unsigned long)f);
- snd_pcm_sw_params_get_xfer_align(swparams, &f);
- info("sw xfer_align=%lu", (unsigned long)f);
- }
-}
-#endif
-
-static void soxargs(const char ***pp, char **qq, ao_sample_format *ao) {
- int n;
-
- *(*pp)++ = "-t.raw";
- *(*pp)++ = "-s";
- *(*pp)++ = *qq; n = sprintf(*qq, "-r%d", ao->rate); *qq += n + 1;
- *(*pp)++ = *qq; n = sprintf(*qq, "-c%d", ao->channels); *qq += n + 1;
- /* sox 12.17.9 insists on -b etc; CVS sox insists on -<n> etc; both are
- * deployed! */
- switch(config->sox_generation) {
- case 0:
- if(ao->bits != 8
- && ao->byte_format != AO_FMT_NATIVE
- && ao->byte_format != MACHINE_AO_FMT) {
- *(*pp)++ = "-x";
- }
- switch(ao->bits) {
- case 8: *(*pp)++ = "-b"; break;
- case 16: *(*pp)++ = "-w"; break;
- case 32: *(*pp)++ = "-l"; break;
- case 64: *(*pp)++ = "-d"; break;
- default: fatal(0, "cannot handle sample size %d", (int)ao->bits);
- }
- break;
- case 1:
- switch(ao->byte_format) {
- case AO_FMT_NATIVE: break;
- case AO_FMT_BIG: *(*pp)++ = "-B"; break;
- case AO_FMT_LITTLE: *(*pp)++ = "-L"; break;
- }
- *(*pp)++ = *qq; n = sprintf(*qq, "-%d", ao->bits/8); *qq += n + 1;
- break;
- }
-}
-
-/* Make sure the sound device is open and has the right sample format. Return
- * 0 on success and -1 on error. */
-static int activate(void) {
- /* If we don't know the format yet we cannot start. */
- if(!playing->got_format) {
- D((" - not got format for %s", playing->id));
- return -1;
- }
- if(kidfd >= 0) {
- if(!formats_equal(&playing->format, &config->sample_format)) {
- char argbuf[1024], *q = argbuf;
- const char *av[18], **pp = av;
- int soxpipe[2];
- pid_t soxkid;
- *pp++ = "sox";
- soxargs(&pp, &q, &playing->format);
- *pp++ = "-";
- soxargs(&pp, &q, &config->sample_format);
- *pp++ = "-";
- *pp++ = 0;
- if(debugging) {
- for(pp = av; *pp; pp++)
- D(("sox arg[%d] = %s", pp - av, *pp));
- D(("end args"));
- }
- xpipe(soxpipe);
- soxkid = xfork();
- if(soxkid == 0) {
- xdup2(playing->fd, 0);
- xdup2(soxpipe[1], 1);
- fcntl(0, F_SETFL, fcntl(0, F_GETFL) & ~O_NONBLOCK);
- close(soxpipe[0]);
- close(soxpipe[1]);
- close(playing->fd);
- execvp("sox", (char **)av);
- _exit(1);
- }
- D(("forking sox for format conversion (kid = %d)", soxkid));
- close(playing->fd);
- close(soxpipe[1]);
- playing->fd = soxpipe[0];
- playing->format = config->sample_format;
- ready = 0;
- }
- if(!ready) {
- pcm_format = config->sample_format;
- bufsize = 3 * FRAMES;
- bpf = bytes_per_frame(&config->sample_format);
- D(("acquired audio device"));
- ready = 1;
- }
- return 0;
- }
- if(config->speaker_command)
- return -1;
-#if API_ALSA
- /* If we need to change format then close the current device. */
- if(pcm && !formats_equal(&playing->format, &pcm_format))
- idle();
- if(!pcm) {
- snd_pcm_hw_params_t *hwparams;
- snd_pcm_sw_params_t *swparams;
- snd_pcm_uframes_t pcm_bufsize;
- int err;
- int sample_format = 0;
- unsigned rate;
-
- D(("snd_pcm_open"));
- if((err = snd_pcm_open(&pcm,
- config->device,
- SND_PCM_STREAM_PLAYBACK,
- SND_PCM_NONBLOCK))) {
- error(0, "error from snd_pcm_open: %d", err);
- goto error;
- }
- snd_pcm_hw_params_alloca(&hwparams);
- D(("set up hw params"));
- if((err = snd_pcm_hw_params_any(pcm, hwparams)) < 0)
- fatal(0, "error from snd_pcm_hw_params_any: %d", err);
- if((err = snd_pcm_hw_params_set_access(pcm, hwparams,
- SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
- fatal(0, "error from snd_pcm_hw_params_set_access: %d", err);
- switch(playing->format.bits) {
- case 8:
- sample_format = SND_PCM_FORMAT_S8;
- break;
- case 16:
- switch(playing->format.byte_format) {
- case AO_FMT_NATIVE: sample_format = SND_PCM_FORMAT_S16; break;
- case AO_FMT_LITTLE: sample_format = SND_PCM_FORMAT_S16_LE; break;
- case AO_FMT_BIG: sample_format = SND_PCM_FORMAT_S16_BE; break;
- error(0, "unrecognized byte format %d", playing->format.byte_format);
- goto fatal;
- }
- break;
- default:
- error(0, "unsupported sample size %d", playing->format.bits);
- goto fatal;
- }
- if((err = snd_pcm_hw_params_set_format(pcm, hwparams,
- sample_format)) < 0) {
- error(0, "error from snd_pcm_hw_params_set_format (%d): %d",
- sample_format, err);
- goto fatal;
- }
- rate = playing->format.rate;
- if((err = snd_pcm_hw_params_set_rate_near(pcm, hwparams, &rate, 0)) < 0) {
- error(0, "error from snd_pcm_hw_params_set_rate (%d): %d",
- playing->format.rate, err);
- goto fatal;
- }
- if(rate != (unsigned)playing->format.rate)
- info("want rate %d, got %u", playing->format.rate, rate);
- if((err = snd_pcm_hw_params_set_channels(pcm, hwparams,
- playing->format.channels)) < 0) {
- error(0, "error from snd_pcm_hw_params_set_channels (%d): %d",
- playing->format.channels, err);
- goto fatal;
- }
- bufsize = 3 * FRAMES;
- pcm_bufsize = bufsize;
- if((err = snd_pcm_hw_params_set_buffer_size_near(pcm, hwparams,
- &pcm_bufsize)) < 0)
- fatal(0, "error from snd_pcm_hw_params_set_buffer_size (%d): %d",
- 3 * FRAMES, err);
- if(pcm_bufsize != 3 * FRAMES && pcm_bufsize != last_pcm_bufsize)
- info("asked for PCM buffer of %d frames, got %d",
- 3 * FRAMES, (int)pcm_bufsize);
- last_pcm_bufsize = pcm_bufsize;
- if((err = snd_pcm_hw_params(pcm, hwparams)) < 0)
- fatal(0, "error calling snd_pcm_hw_params: %d", err);
- D(("set up sw params"));
- snd_pcm_sw_params_alloca(&swparams);
- if((err = snd_pcm_sw_params_current(pcm, swparams)) < 0)
- fatal(0, "error calling snd_pcm_sw_params_current: %d", err);
- if((err = snd_pcm_sw_params_set_avail_min(pcm, swparams, FRAMES)) < 0)
- fatal(0, "error calling snd_pcm_sw_params_set_avail_min %d: %d",
- FRAMES, err);
- if((err = snd_pcm_sw_params(pcm, swparams)) < 0)
- fatal(0, "error calling snd_pcm_sw_params: %d", err);
- pcm_format = playing->format;
- bpf = bytes_per_frame(&pcm_format);
- D(("acquired audio device"));
- log_params(hwparams, swparams);
- ready = 1;
- }
- return 0;
-fatal:
- abandon();
-error:
- /* We assume the error is temporary and that we'll retry in a bit. */
- if(pcm) {
- snd_pcm_close(pcm);
- pcm = 0;
- }
-#endif
- return -1;