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> 33da39e0b09eb0a1b559a96e2108160d1d8dccf314Simon Wilson#include <string.h> 34da39e0b09eb0a1b559a96e2108160d1d8dccf314Simon Wilson#include <signal.h> 35edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson 36edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson#define ID_RIFF 0x46464952 37edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson#define ID_WAVE 0x45564157 38edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson#define ID_FMT 0x20746d66 39edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson#define ID_DATA 0x61746164 40edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson 4185dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilsonstruct riff_wave_header { 42edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson uint32_t riff_id; 43edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson uint32_t riff_sz; 4485dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson uint32_t wave_id; 4585dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson}; 4685dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson 4785dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilsonstruct chunk_header { 4885dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson uint32_t id; 4985dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson uint32_t sz; 5085dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson}; 5185dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson 5285dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilsonstruct chunk_fmt { 53edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson uint16_t audio_format; 54edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson uint16_t num_channels; 55edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson uint32_t sample_rate; 56edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson uint32_t byte_rate; 57edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson uint16_t block_align; 58edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson uint16_t bits_per_sample; 59edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson}; 60edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson 61da39e0b09eb0a1b559a96e2108160d1d8dccf314Simon Wilsonstatic int close = 0; 62da39e0b09eb0a1b559a96e2108160d1d8dccf314Simon Wilson 63daa83291944318d8face12c780dfb69ae96b0723Simon Wilsonvoid play_sample(FILE *file, unsigned int card, unsigned int device, unsigned int channels, 64daa83291944318d8face12c780dfb69ae96b0723Simon Wilson unsigned int rate, unsigned int bits, unsigned int period_size, 65daa83291944318d8face12c780dfb69ae96b0723Simon Wilson unsigned int period_count); 66edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson 67da39e0b09eb0a1b559a96e2108160d1d8dccf314Simon Wilsonvoid stream_close(int sig) 68da39e0b09eb0a1b559a96e2108160d1d8dccf314Simon Wilson{ 69da39e0b09eb0a1b559a96e2108160d1d8dccf314Simon Wilson /* allow the stream to be closed gracefully */ 70da39e0b09eb0a1b559a96e2108160d1d8dccf314Simon Wilson signal(sig, SIG_IGN); 71da39e0b09eb0a1b559a96e2108160d1d8dccf314Simon Wilson close = 1; 72da39e0b09eb0a1b559a96e2108160d1d8dccf314Simon Wilson} 73da39e0b09eb0a1b559a96e2108160d1d8dccf314Simon Wilson 74edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilsonint main(int argc, char **argv) 75edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson{ 76edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson FILE *file; 7785dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson struct riff_wave_header riff_wave_header; 7885dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson struct chunk_header chunk_header; 7985dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson struct chunk_fmt chunk_fmt; 80621047309242d04a6186230e7a337de8642ec754Simon Wilson unsigned int device = 0; 81daa83291944318d8face12c780dfb69ae96b0723Simon Wilson unsigned int card = 0; 82daa83291944318d8face12c780dfb69ae96b0723Simon Wilson unsigned int period_size = 1024; 83daa83291944318d8face12c780dfb69ae96b0723Simon Wilson unsigned int period_count = 4; 8485dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson char *filename; 8585dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson int more_chunks = 1; 86edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson 87621047309242d04a6186230e7a337de8642ec754Simon Wilson if (argc < 2) { 88daa83291944318d8face12c780dfb69ae96b0723Simon Wilson fprintf(stderr, "Usage: %s file.wav [-D card] [-d device] [-p period_size]" 89daa83291944318d8face12c780dfb69ae96b0723Simon Wilson " [-n n_periods] \n", argv[0]); 90edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson return 1; 91edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson } 92edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson 9385dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson filename = argv[1]; 9485dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson file = fopen(filename, "rb"); 95edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson if (!file) { 9685dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson fprintf(stderr, "Unable to open file '%s'\n", filename); 9785dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson return 1; 9885dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson } 9985dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson 10085dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson fread(&riff_wave_header, sizeof(riff_wave_header), 1, file); 10185dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson if ((riff_wave_header.riff_id != ID_RIFF) || 10285dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson (riff_wave_header.wave_id != ID_WAVE)) { 10385dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson fprintf(stderr, "Error: '%s' is not a riff/wave file\n", filename); 10485dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson fclose(file); 105edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson return 1; 106edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson } 107edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson 10885dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson do { 10985dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson fread(&chunk_header, sizeof(chunk_header), 1, file); 11085dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson 11185dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson switch (chunk_header.id) { 11285dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson case ID_FMT: 11385dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson fread(&chunk_fmt, sizeof(chunk_fmt), 1, file); 11485dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson /* If the format header is larger, skip the rest */ 11585dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson if (chunk_header.sz > sizeof(chunk_fmt)) 11685dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson fseek(file, chunk_header.sz - sizeof(chunk_fmt), SEEK_CUR); 11785dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson break; 11885dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson case ID_DATA: 11985dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson /* Stop looking for chunks */ 12085dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson more_chunks = 0; 12185dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson break; 12285dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson default: 12385dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson /* Unknown chunk, skip bytes */ 12485dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson fseek(file, chunk_header.sz, SEEK_CUR); 12585dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson } 12685dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson } while (more_chunks); 12785dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson 128621047309242d04a6186230e7a337de8642ec754Simon Wilson /* parse command line arguments */ 129621047309242d04a6186230e7a337de8642ec754Simon Wilson argv += 2; 130e9942c8b1fab1cea4836b5af2dd59a1bf0ad411dSimon Wilson while (*argv) { 131e9942c8b1fab1cea4836b5af2dd59a1bf0ad411dSimon Wilson if (strcmp(*argv, "-d") == 0) { 132e9942c8b1fab1cea4836b5af2dd59a1bf0ad411dSimon Wilson argv++; 133daa83291944318d8face12c780dfb69ae96b0723Simon Wilson if (*argv) 134daa83291944318d8face12c780dfb69ae96b0723Simon Wilson device = atoi(*argv); 135e9942c8b1fab1cea4836b5af2dd59a1bf0ad411dSimon Wilson } 136daa83291944318d8face12c780dfb69ae96b0723Simon Wilson if (strcmp(*argv, "-p") == 0) { 137daa83291944318d8face12c780dfb69ae96b0723Simon Wilson argv++; 138daa83291944318d8face12c780dfb69ae96b0723Simon Wilson if (*argv) 139daa83291944318d8face12c780dfb69ae96b0723Simon Wilson period_size = atoi(*argv); 140daa83291944318d8face12c780dfb69ae96b0723Simon Wilson } 141daa83291944318d8face12c780dfb69ae96b0723Simon Wilson if (strcmp(*argv, "-n") == 0) { 142daa83291944318d8face12c780dfb69ae96b0723Simon Wilson argv++; 143daa83291944318d8face12c780dfb69ae96b0723Simon Wilson if (*argv) 144daa83291944318d8face12c780dfb69ae96b0723Simon Wilson period_count = atoi(*argv); 145daa83291944318d8face12c780dfb69ae96b0723Simon Wilson } 146daa83291944318d8face12c780dfb69ae96b0723Simon Wilson if (strcmp(*argv, "-D") == 0) { 147daa83291944318d8face12c780dfb69ae96b0723Simon Wilson argv++; 148daa83291944318d8face12c780dfb69ae96b0723Simon Wilson if (*argv) 149daa83291944318d8face12c780dfb69ae96b0723Simon Wilson card = atoi(*argv); 150daa83291944318d8face12c780dfb69ae96b0723Simon Wilson } 151daa83291944318d8face12c780dfb69ae96b0723Simon Wilson if (*argv) 152daa83291944318d8face12c780dfb69ae96b0723Simon Wilson argv++; 153621047309242d04a6186230e7a337de8642ec754Simon Wilson } 154621047309242d04a6186230e7a337de8642ec754Simon Wilson 15585dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson play_sample(file, card, device, chunk_fmt.num_channels, chunk_fmt.sample_rate, 15685dc38f5bee79c184260e8c665cc34143be12bd4Simon Wilson chunk_fmt.bits_per_sample, period_size, period_count); 157edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson 158edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson fclose(file); 159edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson 160edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson return 0; 161edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson} 162edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson 1639673f5717d824137d64320d0bc98a6461a9383a8Simon Wilsonint check_param(struct pcm_params *params, unsigned int param, unsigned int value, 1649673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson char *param_name, char *param_unit) 1659673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson{ 1669673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson unsigned int min; 1679673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson unsigned int max; 1689673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson int is_within_bounds = 1; 1699673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson 1709673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson min = pcm_params_get_min(params, param); 1719673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson if (value < min) { 1729673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson fprintf(stderr, "%s is %u%s, device only supports >= %u%s\n", param_name, value, 1739673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson param_unit, min, param_unit); 1749673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson is_within_bounds = 0; 1759673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson } 1769673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson 1779673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson max = pcm_params_get_max(params, param); 1789673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson if (value > max) { 1799673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson fprintf(stderr, "%s is %u%s, device only supports <= %u%s\n", param_name, value, 1809673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson param_unit, max, param_unit); 1819673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson is_within_bounds = 0; 1829673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson } 1839673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson 1849673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson return is_within_bounds; 1859673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson} 1869673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson 1879673f5717d824137d64320d0bc98a6461a9383a8Simon Wilsonint sample_is_playable(unsigned int card, unsigned int device, unsigned int channels, 1889673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson unsigned int rate, unsigned int bits, unsigned int period_size, 1899673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson unsigned int period_count) 1909673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson{ 1919673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson struct pcm_params *params; 1929673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson int can_play; 1939673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson 1949673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson params = pcm_params_get(card, device, PCM_OUT); 1959673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson if (params == NULL) { 1969673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson fprintf(stderr, "Unable to open PCM device %u.\n", device); 1979673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson return 0; 1989673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson } 1999673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson 2009673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson can_play = check_param(params, PCM_PARAM_RATE, rate, "Sample rate", "Hz"); 2019673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson can_play &= check_param(params, PCM_PARAM_CHANNELS, channels, "Sample", " channels"); 2029673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson can_play &= check_param(params, PCM_PARAM_SAMPLE_BITS, bits, "Bitrate", " bits"); 2039673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson can_play &= check_param(params, PCM_PARAM_PERIOD_SIZE, period_size, "Period size", "Hz"); 2049673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson can_play &= check_param(params, PCM_PARAM_PERIODS, period_count, "Period count", "Hz"); 2059673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson 2069673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson pcm_params_free(params); 2079673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson 2089673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson return can_play; 2099673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson} 2109673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson 211daa83291944318d8face12c780dfb69ae96b0723Simon Wilsonvoid play_sample(FILE *file, unsigned int card, unsigned int device, unsigned int channels, 212daa83291944318d8face12c780dfb69ae96b0723Simon Wilson unsigned int rate, unsigned int bits, unsigned int period_size, 213daa83291944318d8face12c780dfb69ae96b0723Simon Wilson unsigned int period_count) 214edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson{ 215edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson struct pcm_config config; 216edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson struct pcm *pcm; 217edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson char *buffer; 218edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson int size; 219edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson int num_read; 220edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson 221edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson config.channels = channels; 222edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson config.rate = rate; 223daa83291944318d8face12c780dfb69ae96b0723Simon Wilson config.period_size = period_size; 224daa83291944318d8face12c780dfb69ae96b0723Simon Wilson config.period_count = period_count; 225edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson if (bits == 32) 226edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson config.format = PCM_FORMAT_S32_LE; 227edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson else if (bits == 16) 228edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson config.format = PCM_FORMAT_S16_LE; 229621047309242d04a6186230e7a337de8642ec754Simon Wilson config.start_threshold = 0; 230621047309242d04a6186230e7a337de8642ec754Simon Wilson config.stop_threshold = 0; 231621047309242d04a6186230e7a337de8642ec754Simon Wilson config.silence_threshold = 0; 232edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson 2339673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson if (!sample_is_playable(card, device, channels, rate, bits, period_size, period_count)) { 2349673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson return; 2359673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson } 2369673f5717d824137d64320d0bc98a6461a9383a8Simon Wilson 237daa83291944318d8face12c780dfb69ae96b0723Simon Wilson pcm = pcm_open(card, device, PCM_OUT, &config); 238edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson if (!pcm || !pcm_is_ready(pcm)) { 239621047309242d04a6186230e7a337de8642ec754Simon Wilson fprintf(stderr, "Unable to open PCM device %u (%s)\n", 240621047309242d04a6186230e7a337de8642ec754Simon Wilson device, pcm_get_error(pcm)); 241edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson return; 242edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson } 243edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson 244daa83291944318d8face12c780dfb69ae96b0723Simon Wilson size = pcm_frames_to_bytes(pcm, pcm_get_buffer_size(pcm)); 245edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson buffer = malloc(size); 246edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson if (!buffer) { 247edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson fprintf(stderr, "Unable to allocate %d bytes\n", size); 248edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson free(buffer); 249edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson pcm_close(pcm); 250edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson return; 251edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson } 252edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson 253edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson printf("Playing sample: %u ch, %u hz, %u bit\n", channels, rate, bits); 254edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson 255da39e0b09eb0a1b559a96e2108160d1d8dccf314Simon Wilson /* catch ctrl-c to shutdown cleanly */ 256da39e0b09eb0a1b559a96e2108160d1d8dccf314Simon Wilson signal(SIGINT, stream_close); 257da39e0b09eb0a1b559a96e2108160d1d8dccf314Simon Wilson 258edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson do { 259edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson num_read = fread(buffer, 1, size, file); 260edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson if (num_read > 0) { 261edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson if (pcm_write(pcm, buffer, num_read)) { 262edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson fprintf(stderr, "Error playing sample\n"); 263edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson break; 264edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson } 265edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson } 266da39e0b09eb0a1b559a96e2108160d1d8dccf314Simon Wilson } while (!close && num_read > 0); 267edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson 268edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson free(buffer); 269edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson pcm_close(pcm); 270edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson} 271edff708e3129d7d8e05bbdfb624af97a3264a332Simon Wilson 272