1edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson/* tinyplay.c 2edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson** 3edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson** Copyright 2011, The Android Open Source Project 4edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson** 5edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson** Redistribution and use in source and binary forms, with or without 6edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson** modification, are permitted provided that the following conditions are met: 7edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson** * Redistributions of source code must retain the above copyright 8edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson** notice, this list of conditions and the following disclaimer. 9edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson** * Redistributions in binary form must reproduce the above copyright 10edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson** notice, this list of conditions and the following disclaimer in the 11edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson** documentation and/or other materials provided with the distribution. 12edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson** * Neither the name of The Android Open Source Project nor the names of 13edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson** its contributors may be used to endorse or promote products derived 14edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson** from this software without specific prior written permission. 15edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson** 16edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND 17edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE 20edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 26edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson** DAMAGE. 27edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson*/ 28edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson 29edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson#include <tinyalsa/asoundlib.h> 30edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson#include <stdio.h> 31edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson#include <stdlib.h> 32edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson#include <stdint.h> 33edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson 34edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson#define ID_RIFF 0x46464952 35edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson#define ID_WAVE 0x45564157 36edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson#define ID_FMT 0x20746d66 37edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson#define ID_DATA 0x61746164 38edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson 3985dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilsonstruct riff_wave_header { 40edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson uint32_t riff_id; 41edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson uint32_t riff_sz; 4285dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson uint32_t wave_id; 4385dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson}; 4485dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson 4585dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilsonstruct chunk_header { 4685dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson uint32_t id; 4785dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson uint32_t sz; 4885dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson}; 4985dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson 5085dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilsonstruct chunk_fmt { 51edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson uint16_t audio_format; 52edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson uint16_t num_channels; 53edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson uint32_t sample_rate; 54edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson uint32_t byte_rate; 55edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson uint16_t block_align; 56edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson uint16_t bits_per_sample; 57edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson}; 58edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson 59daa83291944318d8face12c780dfb69ae96b0723Simon Wilsonvoid play_sample(FILE *file, unsigned int card, unsigned int device, unsigned int channels, 60daa83291944318d8face12c780dfb69ae96b0723Simon Wilson unsigned int rate, unsigned int bits, unsigned int period_size, 61daa83291944318d8face12c780dfb69ae96b0723Simon Wilson unsigned int period_count); 62edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson 63edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilsonint main(int argc, char **argv) 64edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson{ 65edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson FILE *file; 6685dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson struct riff_wave_header riff_wave_header; 6785dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson struct chunk_header chunk_header; 6885dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson struct chunk_fmt chunk_fmt; 69621047309242d04a6186230e7a337de8642ec754Simon Wilson unsigned int device = 0; 70daa83291944318d8face12c780dfb69ae96b0723Simon Wilson unsigned int card = 0; 71daa83291944318d8face12c780dfb69ae96b0723Simon Wilson unsigned int period_size = 1024; 72daa83291944318d8face12c780dfb69ae96b0723Simon Wilson unsigned int period_count = 4; 7385dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson char *filename; 7485dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson int more_chunks = 1; 75edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson 76621047309242d04a6186230e7a337de8642ec754Simon Wilson if (argc < 2) { 77daa83291944318d8face12c780dfb69ae96b0723Simon Wilson fprintf(stderr, "Usage: %s file.wav [-D card] [-d device] [-p period_size]" 78daa83291944318d8face12c780dfb69ae96b0723Simon Wilson " [-n n_periods] \n", argv[0]); 79edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson return 1; 80edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson } 81edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson 8285dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson filename = argv[1]; 8385dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson file = fopen(filename, "rb"); 84edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson if (!file) { 8585dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson fprintf(stderr, "Unable to open file '%s'\n", filename); 8685dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson return 1; 8785dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson } 8885dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson 8985dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson fread(&riff_wave_header, sizeof(riff_wave_header), 1, file); 9085dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson if ((riff_wave_header.riff_id != ID_RIFF) || 9185dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson (riff_wave_header.wave_id != ID_WAVE)) { 9285dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson fprintf(stderr, "Error: '%s' is not a riff/wave file\n", filename); 9385dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson fclose(file); 94edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson return 1; 95edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson } 96edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson 9785dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson do { 9885dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson fread(&chunk_header, sizeof(chunk_header), 1, file); 9985dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson 10085dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson switch (chunk_header.id) { 10185dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson case ID_FMT: 10285dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson fread(&chunk_fmt, sizeof(chunk_fmt), 1, file); 10385dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson /* If the format header is larger, skip the rest */ 10485dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson if (chunk_header.sz > sizeof(chunk_fmt)) 10585dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson fseek(file, chunk_header.sz - sizeof(chunk_fmt), SEEK_CUR); 10685dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson break; 10785dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson case ID_DATA: 10885dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson /* Stop looking for chunks */ 10985dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson more_chunks = 0; 11085dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson break; 11185dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson default: 11285dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson /* Unknown chunk, skip bytes */ 11385dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson fseek(file, chunk_header.sz, SEEK_CUR); 11485dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson } 11585dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson } while (more_chunks); 11685dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson 117621047309242d04a6186230e7a337de8642ec754Simon Wilson /* parse command line arguments */ 118621047309242d04a6186230e7a337de8642ec754Simon Wilson argv += 2; 119e9942c8b1fab1cea4836b5af2dd59a1bf0ad411dSimon Wilson while (*argv) { 120e9942c8b1fab1cea4836b5af2dd59a1bf0ad411dSimon Wilson if (strcmp(*argv, "-d") == 0) { 121e9942c8b1fab1cea4836b5af2dd59a1bf0ad411dSimon Wilson argv++; 122daa83291944318d8face12c780dfb69ae96b0723Simon Wilson if (*argv) 123daa83291944318d8face12c780dfb69ae96b0723Simon Wilson device = atoi(*argv); 124e9942c8b1fab1cea4836b5af2dd59a1bf0ad411dSimon Wilson } 125daa83291944318d8face12c780dfb69ae96b0723Simon Wilson if (strcmp(*argv, "-p") == 0) { 126daa83291944318d8face12c780dfb69ae96b0723Simon Wilson argv++; 127daa83291944318d8face12c780dfb69ae96b0723Simon Wilson if (*argv) 128daa83291944318d8face12c780dfb69ae96b0723Simon Wilson period_size = atoi(*argv); 129daa83291944318d8face12c780dfb69ae96b0723Simon Wilson } 130daa83291944318d8face12c780dfb69ae96b0723Simon Wilson if (strcmp(*argv, "-n") == 0) { 131daa83291944318d8face12c780dfb69ae96b0723Simon Wilson argv++; 132daa83291944318d8face12c780dfb69ae96b0723Simon Wilson if (*argv) 133daa83291944318d8face12c780dfb69ae96b0723Simon Wilson period_count = atoi(*argv); 134daa83291944318d8face12c780dfb69ae96b0723Simon Wilson } 135daa83291944318d8face12c780dfb69ae96b0723Simon Wilson if (strcmp(*argv, "-D") == 0) { 136daa83291944318d8face12c780dfb69ae96b0723Simon Wilson argv++; 137daa83291944318d8face12c780dfb69ae96b0723Simon Wilson if (*argv) 138daa83291944318d8face12c780dfb69ae96b0723Simon Wilson card = atoi(*argv); 139daa83291944318d8face12c780dfb69ae96b0723Simon Wilson } 140daa83291944318d8face12c780dfb69ae96b0723Simon Wilson if (*argv) 141daa83291944318d8face12c780dfb69ae96b0723Simon Wilson argv++; 142621047309242d04a6186230e7a337de8642ec754Simon Wilson } 143621047309242d04a6186230e7a337de8642ec754Simon Wilson 14485dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson play_sample(file, card, device, chunk_fmt.num_channels, chunk_fmt.sample_rate, 14585dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson chunk_fmt.bits_per_sample, period_size, period_count); 146edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson 147edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson fclose(file); 148edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson 149edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson return 0; 150edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson} 151edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson 152daa83291944318d8face12c780dfb69ae96b0723Simon Wilsonvoid play_sample(FILE *file, unsigned int card, unsigned int device, unsigned int channels, 153daa83291944318d8face12c780dfb69ae96b0723Simon Wilson unsigned int rate, unsigned int bits, unsigned int period_size, 154daa83291944318d8face12c780dfb69ae96b0723Simon Wilson unsigned int period_count) 155edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson{ 156edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson struct pcm_config config; 157edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson struct pcm *pcm; 158edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson char *buffer; 159edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson int size; 160edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson int num_read; 161edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson 162edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson config.channels = channels; 163edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson config.rate = rate; 164daa83291944318d8face12c780dfb69ae96b0723Simon Wilson config.period_size = period_size; 165daa83291944318d8face12c780dfb69ae96b0723Simon Wilson config.period_count = period_count; 166edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson if (bits == 32) 167edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson config.format = PCM_FORMAT_S32_LE; 168edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson else if (bits == 16) 169edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson config.format = PCM_FORMAT_S16_LE; 170621047309242d04a6186230e7a337de8642ec754Simon Wilson config.start_threshold = 0; 171621047309242d04a6186230e7a337de8642ec754Simon Wilson config.stop_threshold = 0; 172621047309242d04a6186230e7a337de8642ec754Simon Wilson config.silence_threshold = 0; 173edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson 174daa83291944318d8face12c780dfb69ae96b0723Simon Wilson pcm = pcm_open(card, device, PCM_OUT, &config); 175edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson if (!pcm || !pcm_is_ready(pcm)) { 176621047309242d04a6186230e7a337de8642ec754Simon Wilson fprintf(stderr, "Unable to open PCM device %u (%s)\n", 177621047309242d04a6186230e7a337de8642ec754Simon Wilson device, pcm_get_error(pcm)); 178edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson return; 179edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson } 180edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson 181daa83291944318d8face12c780dfb69ae96b0723Simon Wilson size = pcm_frames_to_bytes(pcm, pcm_get_buffer_size(pcm)); 182edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson buffer = malloc(size); 183edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson if (!buffer) { 184edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson fprintf(stderr, "Unable to allocate %d bytes\n", size); 185edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson free(buffer); 186edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson pcm_close(pcm); 187edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson return; 188edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson } 189edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson 190edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson printf("Playing sample: %u ch, %u hz, %u bit\n", channels, rate, bits); 191edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson 192edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson do { 193edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson num_read = fread(buffer, 1, size, file); 194edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson if (num_read > 0) { 195edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson if (pcm_write(pcm, buffer, num_read)) { 196edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson fprintf(stderr, "Error playing sample\n"); 197edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson break; 198edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson } 199edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson } 200edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson } while (num_read > 0); 201edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson 202edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson free(buffer); 203edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson pcm_close(pcm); 204edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson} 205edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson 206