1/* 2 * BSD LICENSE 3 * 4 * tinyplay command line player for compress audio offload in alsa 5 * Copyright (c) 2011-2012, Intel Corporation 6 * All rights reserved. 7 * 8 * Author: Vinod Koul <vinod.koul@linux.intel.com> 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions are met: 12 * 13 * Redistributions of source code must retain the above copyright notice, 14 * this list of conditions and the following disclaimer. 15 * Redistributions in binary form must reproduce the above copyright notice, 16 * this list of conditions and the following disclaimer in the documentation 17 * and/or other materials provided with the distribution. 18 * Neither the name of Intel Corporation nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 32 * THE POSSIBILITY OF SUCH DAMAGE. 33 * 34 * LGPL LICENSE 35 * 36 * tinyplay command line player for compress audio offload in alsa 37 * Copyright (c) 2011-2012, Intel Corporation. 38 * 39 * This program is free software; you can redistribute it and/or modify it 40 * under the terms and conditions of the GNU Lesser General Public License, 41 * version 2.1, as published by the Free Software Foundation. 42 * 43 * This program is distributed in the hope it will be useful, but WITHOUT 44 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 45 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 46 * License for more details. 47 * 48 * You should have received a copy of the GNU Lesser General Public License 49 * along with this program; if not, write to 50 * the Free Software Foundation, Inc., 51 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 52 */ 53 54#include <stdint.h> 55#include <linux/types.h> 56#include <fcntl.h> 57#include <errno.h> 58#include <unistd.h> 59#include <stdio.h> 60#include <stdlib.h> 61#include <string.h> 62#include <signal.h> 63#include <stdbool.h> 64#include <getopt.h> 65#include <sys/time.h> 66#define __force 67#define __bitwise 68#define __user 69#include "sound/compress_params.h" 70#include "tinycompress/tinycompress.h" 71#include "tinycompress/tinymp3.h" 72 73static int verbose; 74 75static void usage(void) 76{ 77 fprintf(stderr, "usage: cplay [OPTIONS] filename\n" 78 "-c\tcard number\n" 79 "-d\tdevice node\n" 80 "-b\tbuffer size\n" 81 "-f\tfragments\n\n" 82 "-v\tverbose mode\n" 83 "-h\tPrints this help list\n\n" 84 "Example:\n" 85 "\tcplay -c 1 -d 2 test.mp3\n" 86 "\tcplay -f 5 test.mp3\n"); 87 88 exit(EXIT_FAILURE); 89} 90 91void play_samples(char *name, unsigned int card, unsigned int device, 92 unsigned long buffer_size, unsigned int frag); 93 94struct mp3_header { 95 uint16_t sync; 96 uint8_t format1; 97 uint8_t format2; 98}; 99 100int parse_mp3_header(struct mp3_header *header, unsigned int *num_channels, 101 unsigned int *sample_rate, unsigned int *bit_rate) 102{ 103 int ver_idx, mp3_version, layer, bit_rate_idx, sample_rate_idx, channel_idx; 104 105 /* check sync bits */ 106 if ((header->sync & MP3_SYNC) != MP3_SYNC) { 107 fprintf(stderr, "Error: Can't find sync word\n"); 108 return -1; 109 } 110 ver_idx = (header->sync >> 11) & 0x03; 111 mp3_version = ver_idx == 0 ? MPEG25 : ((ver_idx & 0x1) ? MPEG1 : MPEG2); 112 layer = 4 - ((header->sync >> 9) & 0x03); 113 bit_rate_idx = ((header->format1 >> 4) & 0x0f); 114 sample_rate_idx = ((header->format1 >> 2) & 0x03); 115 channel_idx = ((header->format2 >> 6) & 0x03); 116 117 if (sample_rate_idx == 3 || layer == 4 || bit_rate_idx == 15) { 118 fprintf(stderr, "Error: Can't find valid header\n"); 119 return -1; 120 } 121 *num_channels = (channel_idx == MONO ? 1 : 2); 122 *sample_rate = mp3_sample_rates[mp3_version][sample_rate_idx]; 123 *bit_rate = (mp3_bit_rates[mp3_version][layer - 1][bit_rate_idx]) * 1000; 124 if (verbose) 125 printf("%s: exit\n", __func__); 126 return 0; 127} 128 129int check_codec_format_supported(unsigned int card, unsigned int device, struct snd_codec *codec) 130{ 131 if (is_codec_supported(card, device, COMPRESS_IN, codec) == false) { 132 fprintf(stderr, "Error: This codec or format is not supported by DSP\n"); 133 return -1; 134 } 135 return 0; 136} 137 138static int print_time(struct compress *compress) 139{ 140 unsigned int avail; 141 struct timespec tstamp; 142 143 if (compress_get_hpointer(compress, &avail, &tstamp) != 0) { 144 fprintf(stderr, "Error querying timestamp\n"); 145 fprintf(stderr, "ERR: %s\n", compress_get_error(compress)); 146 return -1; 147 } else 148 fprintf(stderr, "DSP played %jd.%jd\n", (intmax_t)tstamp.tv_sec, (intmax_t)tstamp.tv_nsec*1000); 149 return 0; 150} 151 152int main(int argc, char **argv) 153{ 154 char *file; 155 unsigned long buffer_size = 0; 156 int c; 157 unsigned int card = 0, device = 0, frag = 0; 158 159 160 if (argc < 2) 161 usage(); 162 163 verbose = 0; 164 while ((c = getopt(argc, argv, "hvb:f:c:d:")) != -1) { 165 switch (c) { 166 case 'h': 167 usage(); 168 break; 169 case 'b': 170 buffer_size = strtol(optarg, NULL, 0); 171 break; 172 case 'f': 173 frag = strtol(optarg, NULL, 10); 174 break; 175 case 'c': 176 card = strtol(optarg, NULL, 10); 177 break; 178 case 'd': 179 device = strtol(optarg, NULL, 10); 180 break; 181 case 'v': 182 verbose = 1; 183 break; 184 default: 185 exit(EXIT_FAILURE); 186 } 187 } 188 if (optind >= argc) 189 usage(); 190 191 file = argv[optind]; 192 193 play_samples(file, card, device, buffer_size, frag); 194 195 fprintf(stderr, "Finish Playing.... Close Normally\n"); 196 exit(EXIT_SUCCESS); 197} 198 199void play_samples(char *name, unsigned int card, unsigned int device, 200 unsigned long buffer_size, unsigned int frag) 201{ 202 struct compr_config config; 203 struct snd_codec codec; 204 struct compress *compress; 205 struct mp3_header header; 206 FILE *file; 207 char *buffer; 208 int size, num_read, wrote; 209 unsigned int channels, rate, bits; 210 211 if (verbose) 212 printf("%s: entry\n", __func__); 213 file = fopen(name, "rb"); 214 if (!file) { 215 fprintf(stderr, "Unable to open file '%s'\n", name); 216 exit(EXIT_FAILURE); 217 } 218 219 fread(&header, sizeof(header), 1, file); 220 221 if (parse_mp3_header(&header, &channels, &rate, &bits) == -1) { 222 fclose(file); 223 exit(EXIT_FAILURE); 224 } 225 226 codec.id = SND_AUDIOCODEC_MP3; 227 codec.ch_in = channels; 228 codec.ch_out = channels; 229 codec.sample_rate = rate; 230 if (!codec.sample_rate) { 231 fprintf(stderr, "invalid sample rate %d\n", rate); 232 fclose(file); 233 exit(EXIT_FAILURE); 234 } 235 codec.bit_rate = bits; 236 codec.rate_control = 0; 237 codec.profile = 0; 238 codec.level = 0; 239 codec.ch_mode = 0; 240 codec.format = 0; 241 if ((buffer_size != 0) && (frag != 0)) { 242 config.fragment_size = buffer_size/frag; 243 config.fragments = frag; 244 } else { 245 /* use driver defaults */ 246 config.fragment_size = 0; 247 config.fragments = 0; 248 } 249 config.codec = &codec; 250 251 compress = compress_open(card, device, COMPRESS_IN, &config); 252 if (!compress || !is_compress_ready(compress)) { 253 fprintf(stderr, "Unable to open Compress device %d:%d\n", 254 card, device); 255 fprintf(stderr, "ERR: %s\n", compress_get_error(compress)); 256 goto FILE_EXIT; 257 }; 258 if (verbose) 259 printf("%s: Opened compress device\n", __func__); 260 size = config.fragment_size; 261 buffer = malloc(size * config.fragments); 262 if (!buffer) { 263 fprintf(stderr, "Unable to allocate %d bytes\n", size); 264 goto COMP_EXIT; 265 } 266 267 /* we will write frag fragment_size and then start */ 268 num_read = fread(buffer, 1, size * config.fragments, file); 269 if (num_read > 0) { 270 if (verbose) 271 printf("%s: Doing first buffer write of %d\n", __func__, num_read); 272 wrote = compress_write(compress, buffer, num_read); 273 if (wrote < 0) { 274 fprintf(stderr, "Error %d playing sample\n", wrote); 275 fprintf(stderr, "ERR: %s\n", compress_get_error(compress)); 276 goto BUF_EXIT; 277 } 278 if (wrote != num_read) { 279 /* TODO: Buufer pointer needs to be set here */ 280 fprintf(stderr, "We wrote %d, DSP accepted %d\n", num_read, wrote); 281 } 282 } 283 printf("Playing file %s On Card %u device %u, with buffer of %lu bytes\n", 284 name, card, device, buffer_size); 285 printf("Format %u Channels %u, %u Hz, Bit Rate %d\n", 286 SND_AUDIOCODEC_MP3, channels, rate, bits); 287 288 compress_start(compress); 289 if (verbose) 290 printf("%s: You should hear audio NOW!!!\n", __func__); 291 292 do { 293 num_read = fread(buffer, 1, size, file); 294 if (num_read > 0) { 295 wrote = compress_write(compress, buffer, num_read); 296 if (wrote < 0) { 297 fprintf(stderr, "Error playing sample\n"); 298 fprintf(stderr, "ERR: %s\n", compress_get_error(compress)); 299 goto BUF_EXIT; 300 } 301 if (wrote != num_read) { 302 /* TODO: Buffer pointer needs to be set here */ 303 fprintf(stderr, "We wrote %d, DSP accepted %d\n", num_read, wrote); 304 } 305 if (verbose) { 306 print_time(compress); 307 printf("%s: wrote %d\n", __func__, wrote); 308 } 309 } 310 } while (num_read > 0); 311 312 if (verbose) 313 printf("%s: exit success\n", __func__); 314 /* issue drain if it supports */ 315 compress_drain(compress); 316 free(buffer); 317 fclose(file); 318 compress_close(compress); 319 return; 320BUF_EXIT: 321 free(buffer); 322COMP_EXIT: 323 compress_close(compress); 324FILE_EXIT: 325 fclose(file); 326 if (verbose) 327 printf("%s: exit failure\n", __func__); 328 exit(EXIT_FAILURE); 329} 330 331