Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Path: blob/next/external/cache/sources/tinyalsa/tinyplay.c
Views: 3959
/* tinyplay.c1**2** Copyright 2011, The Android Open Source Project3**4** Redistribution and use in source and binary forms, with or without5** modification, are permitted provided that the following conditions are met:6** * Redistributions of source code must retain the above copyright7** notice, this list of conditions and the following disclaimer.8** * Redistributions in binary form must reproduce the above copyright9** notice, this list of conditions and the following disclaimer in the10** documentation and/or other materials provided with the distribution.11** * Neither the name of The Android Open Source Project nor the names of12** its contributors may be used to endorse or promote products derived13** from this software without specific prior written permission.14**15** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND16** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE17** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE18** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE19** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL20** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR21** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER22** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT23** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY24** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH25** DAMAGE.26*/2728#include <tinyalsa/asoundlib.h>29#include <stdio.h>30#include <stdlib.h>31#include <stdint.h>32#include <string.h>33#include <signal.h>34#include <sys/time.h>3536#define ID_RIFF 0x4646495237#define ID_WAVE 0x4556415738#define ID_FMT 0x20746d6639#define ID_DATA 0x617461644041struct riff_wave_header {42uint32_t riff_id;43uint32_t riff_sz;44uint32_t wave_id;45};4647struct chunk_header {48uint32_t id;49uint32_t sz;50};5152struct chunk_fmt {53uint16_t audio_format;54uint16_t num_channels;55uint32_t sample_rate;56uint32_t byte_rate;57uint16_t block_align;58uint16_t bits_per_sample;59};6061static int close = 0;62static unsigned int loop_num = 1;63static unsigned int loop_minutes = 0;6465void play_sample(FILE *file, unsigned int card, unsigned int device, unsigned int channels,66unsigned int rate, unsigned int bits, unsigned int period_size,67unsigned int period_count);6869void stream_close(int sig)70{71/* allow the stream to be closed gracefully */72signal(sig, SIG_IGN);73close = 1;74}7576int main(int argc, char **argv)77{78FILE *file;79struct riff_wave_header riff_wave_header;80struct chunk_header chunk_header;81struct chunk_fmt chunk_fmt;82unsigned int device = 0;83unsigned int card = 0;84unsigned int period_size = 1024;85unsigned int period_count = 4;86char *filename;87int more_chunks = 1;8889if (argc < 2) {90fprintf(stderr, "Usage: %s file.wav [-D card] [-d device] "91"[-m loop_minutes] [-i loop_num] "92"[-p period_size] [-n period_count] \n", argv[0]);93return 1;94}9596filename = argv[1];97file = fopen(filename, "rb");98if (!file) {99fprintf(stderr, "Unable to open file '%s'\n", filename);100return 1;101}102103fread(&riff_wave_header, sizeof(riff_wave_header), 1, file);104if ((riff_wave_header.riff_id != ID_RIFF) ||105(riff_wave_header.wave_id != ID_WAVE)) {106fprintf(stderr, "Error: '%s' is not a riff/wave file\n", filename);107fclose(file);108return 1;109}110111do {112fread(&chunk_header, sizeof(chunk_header), 1, file);113114switch (chunk_header.id) {115case ID_FMT:116fread(&chunk_fmt, sizeof(chunk_fmt), 1, file);117/* If the format header is larger, skip the rest */118if (chunk_header.sz > sizeof(chunk_fmt))119fseek(file, chunk_header.sz - sizeof(chunk_fmt), SEEK_CUR);120break;121case ID_DATA:122/* Stop looking for chunks */123more_chunks = 0;124break;125default:126/* Unknown chunk, skip bytes */127fseek(file, chunk_header.sz, SEEK_CUR);128}129} while (more_chunks);130131/* parse command line arguments */132argv += 2;133while (*argv) {134if (strcmp(*argv, "-d") == 0) {135argv++;136if (*argv)137device = atoi(*argv);138}139if (strcmp(*argv, "-p") == 0) {140argv++;141if (*argv)142period_size = atoi(*argv);143}144if (strcmp(*argv, "-n") == 0) {145argv++;146if (*argv)147period_count = atoi(*argv);148}149if (strcmp(*argv, "-D") == 0) {150argv++;151if (*argv)152card = atoi(*argv);153}154if (strcmp(*argv, "-m") == 0) {155argv++;156if (*argv)157loop_minutes = atoi(*argv);158}159if (strcmp(*argv, "-i") == 0) {160argv++;161if (*argv)162loop_num = atoi(*argv);163}164if (*argv)165argv++;166}167168play_sample(file, card, device, chunk_fmt.num_channels, chunk_fmt.sample_rate,169chunk_fmt.bits_per_sample, period_size, period_count);170171fclose(file);172173return 0;174}175176int check_param(struct pcm_params *params, unsigned int param, unsigned int value,177char *param_name, char *param_unit)178{179unsigned int min;180unsigned int max;181int is_within_bounds = 1;182183min = pcm_params_get_min(params, param);184if (value < min) {185fprintf(stderr, "%s is %u%s, device only supports >= %u%s\n", param_name, value,186param_unit, min, param_unit);187is_within_bounds = 0;188}189190max = pcm_params_get_max(params, param);191if (value > max) {192fprintf(stderr, "%s is %u%s, device only supports <= %u%s\n", param_name, value,193param_unit, max, param_unit);194is_within_bounds = 0;195}196197return is_within_bounds;198}199200int sample_is_playable(unsigned int card, unsigned int device, unsigned int channels,201unsigned int rate, unsigned int bits, unsigned int period_size,202unsigned int period_count)203{204struct pcm_params *params;205int can_play;206207params = pcm_params_get(card, device, PCM_OUT);208if (params == NULL) {209fprintf(stderr, "Unable to open PCM device %u.\n", device);210return 0;211}212213can_play = check_param(params, PCM_PARAM_RATE, rate, "Sample rate", "Hz");214can_play &= check_param(params, PCM_PARAM_CHANNELS, channels, "Sample", " channels");215can_play &= check_param(params, PCM_PARAM_SAMPLE_BITS, bits, "Bitrate", " bits");216can_play &= check_param(params, PCM_PARAM_PERIOD_SIZE, period_size, "Period size", "Hz");217can_play &= check_param(params, PCM_PARAM_PERIODS, period_count, "Period count", "Hz");218219pcm_params_free(params);220221return can_play;222}223224void play_sample(FILE *file, unsigned int card, unsigned int device, unsigned int channels,225unsigned int rate, unsigned int bits, unsigned int period_size,226unsigned int period_count)227{228struct pcm_config config;229struct pcm *pcm;230char *buffer;231int size;232int num_read;233struct timeval tv;234struct timezone tz;235long sec_start = 0;236long sec_end = 0;237int loop_count = 0;238239config.channels = channels;240config.rate = rate;241config.period_size = period_size;242config.period_count = period_count;243if (bits == 32)244config.format = PCM_FORMAT_S32_LE;245else if (bits == 16)246config.format = PCM_FORMAT_S16_LE;247else if (bits == 24)248config.format = PCM_FORMAT_S24_LE;249config.start_threshold = 0;250config.stop_threshold = 0;251config.silence_threshold = 0;252253if (!sample_is_playable(card, device, channels, rate, bits, period_size, period_count)) {254return;255}256257pcm = pcm_open(card, device, PCM_OUT, &config);258if (!pcm || !pcm_is_ready(pcm)) {259fprintf(stderr, "Unable to open PCM device %u (%s)\n",260device, pcm_get_error(pcm));261return;262}263264size = pcm_frames_to_bytes(pcm, pcm_get_buffer_size(pcm));265buffer = malloc(size);266if (!buffer) {267fprintf(stderr, "Unable to allocate %d bytes\n", size);268free(buffer);269pcm_close(pcm);270return;271}272273printf("Playing sample: %u ch, %u hz, %u bit\n", channels, rate, bits);274275/* catch ctrl-c to shutdown cleanly */276signal(SIGINT, stream_close);277278gettimeofday(&tv, &tz);279sec_start = tv.tv_sec;280281printf("start --> loop_minutes = %d; loop_num = %d\n",282loop_minutes, loop_num);283284do {285num_read = fread(buffer, 1, size, file);286if (num_read > 0) {287if (pcm_write(pcm, buffer, num_read)) {288fprintf(stderr, "Error playing sample\n");289break;290}291if (feof(file)) {292printf("--> loop_count = %d\n", ++loop_count);293fseek(file, 0L, SEEK_SET);294}295if (loop_minutes == 0) {296if (loop_count >= loop_num)297break;298} else {299gettimeofday(&tv, &tz);300sec_end = tv.tv_sec;301if ((sec_end - sec_start) > (loop_minutes * 60)) {302printf("End loop_minutes: %ld\n", (sec_end - sec_start)/60);303break;304}305}306}307} while (!close && num_read > 0);308309free(buffer);310pcm_close(pcm);311}312313314315