/** * Play */ void *playback_alsa(struct bat *bat) { int err = 0; struct snd_pcm_container sndpcm; int size, offset, count; printf("Entering playback thread (ALSA).\n"); memset(&sndpcm, 0, sizeof(sndpcm)); if (NULL != bat->playback.device) { err = snd_pcm_open(&sndpcm.handle, bat->playback.device, SND_PCM_STREAM_PLAYBACK, 0); if (err < 0) { loge(E_OPENPCMP, "%s(%d)", snd_strerror(err), err); goto fail_exit; } } else { loge(E_NOPCMP, "exit"); goto fail_exit; } err = set_snd_pcm_params(bat, &sndpcm); if (err != 0) goto fail_exit; if (bat->playback.file == NULL) { printf("Playing generated audio sine wave"); bat->sinus_duration == 0 ? printf(" endlessly\n") : printf("\n"); } else { printf("Playing input audio file: %s\n", bat->playback.file); bat->fp = fopen(bat->playback.file, "rb"); if (bat->fp == NULL) { loge(E_OPENFILEC, "%s", bat->playback.file); goto fail_exit; } } count = sndpcm.period_bytes; /* playback buffer size */ #ifdef DEBUG FILE *sin_file; sin_file = fopen("/tmp/sin.wav", "wb"); #endif while (1) { offset = 0; size = count * 8 / sndpcm.frame_bits; err = generate_input_data(sndpcm, count, bat); if (err < 0) goto fail_exit; else if (err > 0) break; #ifdef DEBUG fwrite(sndpcm.buffer, count * 8 / sndpcm.frame_bits, 4, sin_file); #endif if (bat->period_limit && bat->periods_played >= bat->periods_total) break; err = write_to_pcm(size, &sndpcm, offset); if (err == -1) goto fail_exit; } #ifdef DEBUG fclose(sin_file); #endif snd_pcm_drain(sndpcm.handle); if (bat->fp) fclose(bat->fp); free(sndpcm.buffer); snd_pcm_close(sndpcm.handle); retval_play = 0; pthread_exit(&retval_play); fail_exit: if (bat->fp) fclose(bat->fp); if (sndpcm.buffer) free(sndpcm.buffer); if (sndpcm.handle) snd_pcm_close(sndpcm.handle); retval_play = 1; pthread_exit(&retval_play); }
static int write_to_pcm_loop(struct pcm_container *sndpcm, struct bat *bat) { int err; int bytes = sndpcm->period_bytes; /* playback buffer size */ int frames = bytes * 8 / sndpcm->frame_bits; /* frame count */ FILE *fp = NULL; struct wav_container wav; int bytes_total = 0; if (bat->debugplay) { fp = fopen(bat->debugplay, "wb"); if (fp == NULL) { fprintf(bat->err, _("Cannot open file for capture: ")); fprintf(bat->err, _("%s %d\n"), bat->debugplay, -errno); return -errno; } /* leave space for wav header */ err = fseek(fp, sizeof(wav), SEEK_SET); if (err != 0) { fprintf(bat->err, _("Seek file error: %d %d\n"), err, -errno); return -errno; } } while (1) { err = generate_input_data(sndpcm, bytes, bat); if (err < 0) return err; else if (err > 0) break; if (bat->debugplay) { err = fwrite(sndpcm->buffer, 1, bytes, fp); if (err != bytes) { fprintf(bat->err, _("Write file error: ")); fprintf(bat->err, _("%s(%d)\n"), snd_strerror(err), err); return -EIO; } bytes_total += bytes; } bat->periods_played++; if (bat->period_is_limited && bat->periods_played >= bat->periods_total) break; err = write_to_pcm(sndpcm, frames, bat); if (err != 0) return err; } if (bat->debugplay) { /* update wav header */ prepare_wav_info(&wav, bat); wav.chunk.length = bytes_total; wav.header.length = (wav.chunk.length) + sizeof(wav.chunk) + sizeof(wav.format) + sizeof(wav.header) - 8; rewind(fp); err = write_wav_header(fp, &wav, bat); if (err != 0) { fprintf(bat->err, _("Write file error: %s %s(%d)\n"), bat->debugplay, snd_strerror(err), err); return err; } fclose(fp); } snd_pcm_drain(sndpcm->handle); return 0; }