/* tinyplay.c ** ** Copyright 2011, The Android Open Source Project ** ** Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in the ** documentation and/or other materials provided with the distribution. ** * Neither the name of The Android Open Source Project nor the names of ** its contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ** DAMAGE. */ #include #include #include #include #define ID_RIFF 0x46464952 #define ID_WAVE 0x45564157 #define ID_FMT 0x20746d66 #define ID_DATA 0x61746164 #define FORMAT_PCM 1 struct wav_header { uint32_t riff_id; uint32_t riff_sz; uint32_t riff_fmt; uint32_t fmt_id; uint32_t fmt_sz; uint16_t audio_format; uint16_t num_channels; uint32_t sample_rate; uint32_t byte_rate; uint16_t block_align; uint16_t bits_per_sample; uint32_t data_id; uint32_t data_sz; }; void play_sample(FILE *file, unsigned int channels, unsigned int rate, unsigned int bits); int main(int argc, char **argv) { FILE *file; struct wav_header header; if (argc != 2) { fprintf(stderr, "Usage: %s \n", argv[0]); return 1; } file = fopen(argv[1], "rb"); if (!file) { fprintf(stderr, "Unable to open file '%s'\n", argv[1]); return 1; } fread(&header, sizeof(struct wav_header), 1, file); if ((header.riff_id != ID_RIFF) || (header.riff_fmt != ID_WAVE) || (header.fmt_id != ID_FMT) || (header.audio_format != FORMAT_PCM) || (header.fmt_sz != 16)) { fprintf(stderr, "Error: '%s' is not a PCM riff/wave file\n", argv[1]); fclose(file); return 1; } play_sample(file, header.num_channels, header.sample_rate, header.bits_per_sample); fclose(file); return 0; } void play_sample(FILE *file, unsigned int channels, unsigned int rate, unsigned int bits) { struct pcm_config config; struct pcm *pcm; char *buffer; int size; int num_read; config.channels = channels; config.rate = rate; config.period_size = 1024; config.period_count = 4; if (bits == 32) config.format = PCM_FORMAT_S32_LE; else if (bits == 16) config.format = PCM_FORMAT_S16_LE; pcm = pcm_open(0, 0, PCM_OUT, &config); if (!pcm || !pcm_is_ready(pcm)) { fprintf(stderr, "Unable to open PCM device (%s)\n", pcm_get_error(pcm)); return; } size = pcm_get_buffer_size(pcm); buffer = malloc(size); if (!buffer) { fprintf(stderr, "Unable to allocate %d bytes\n", size); free(buffer); pcm_close(pcm); return; } printf("Playing sample: %u ch, %u hz, %u bit\n", channels, rate, bits); do { num_read = fread(buffer, 1, size, file); if (num_read > 0) { if (pcm_write(pcm, buffer, num_read)) { fprintf(stderr, "Error playing sample\n"); break; } } } while (num_read > 0); free(buffer); pcm_close(pcm); }