compress: Extend cplay with support to offload path

Extend cplay with support to offload path (16 & 24 bit S_LE)

CRs-Fixed: 671678
Change-Id: Ib13e063422f82bbfdd3a6d1ea8eba8ae8eff6a44
diff --git a/cplay.c b/cplay.c
index c46577a..b10df43 100644
--- a/cplay.c
+++ b/cplay.c
@@ -67,8 +67,10 @@
 #define __bitwise
 #define __user
 #include "sound/compress_params.h"
+#include "sound/asound.h"
 #include "tinycompress/tinycompress.h"
 #include "tinycompress/tinymp3.h"
+#include <string.h>
 
 static int verbose;
 
@@ -80,6 +82,7 @@
 		"-b\tbuffer size\n"
 		"-f\tfragments\n\n"
 		"-v\tverbose mode\n"
+                "-p\tpcm input\n"
 		"-h\tPrints this help list\n\n"
 		"Example:\n"
 		"\tcplay -c 1 -d 2 test.mp3\n"
@@ -90,7 +93,8 @@
 
 void play_samples(char *name, unsigned int card, unsigned int device,
 		unsigned long buffer_size, unsigned int frag);
-
+void play_pcm_samples(char *name, unsigned int card, unsigned int device,
+		unsigned long buffer_size, unsigned int frag);
 struct mp3_header {
 	uint16_t sync;
 	uint8_t format1;
@@ -126,6 +130,63 @@
 	return 0;
 }
 
+int parse_pcm_header(FILE **file, uint16_t *num_channels,
+		     unsigned int *sample_rate, uint16_t *bit_rate)
+{
+	char title[5] = "    ";
+	int size = 0;
+	fread(title, 4, 1, *file);
+	if (strcmp(title, "RIFF") != 0) {
+		fprintf(stderr, "invalid file\n");
+		return -1;
+	}
+
+	//skip total file size
+	fseek(*file, 4, SEEK_CUR);
+
+	char format[5] = "    ";
+	fread(format, 4, 1, *file);
+	if (strcmp(format, "WAVE") != 0) {
+		fprintf(stderr, "invalid format\n");
+		return -1;
+	}
+
+	fread(title, 4, 1, *file);
+	fread(&size, 4, 1, *file);
+	while (strcmp(title, "fmt ") != 0){
+		fseek(*file, size, SEEK_CUR);
+		fread(title, 4, 1, *file);
+		fread(&size, 4, 1, *file);
+		if (feof(*file)) {
+			fprintf(stderr, "missing format information\n");
+			return -1;
+		}
+	}
+
+	uint16_t audioformat, blockalign;
+	unsigned int byterate;
+	fread(&audioformat, 2, 1, *file);
+	fread(num_channels, 2, 1, *file);
+	fread(sample_rate, 4, 1, *file);
+	fread(&byterate, 4, 1, *file);
+	fread(&blockalign, 2, 1, *file);
+	fread(bit_rate, 2, 1, *file);
+	fseek(*file, size - 16, SEEK_CUR);
+
+	fread(title, 4, 1, *file);
+	fread(&size, 4, 1, *file);
+	while (strcmp(title, "data") != 0){
+		fseek(*file, size, SEEK_CUR);
+		fread(title, 4, 1, *file);
+		fread(&size, 4, 1, *file);
+		if (feof(*file)) {
+			fprintf(stderr, "missing data\n");
+			return -1;
+		}
+	}
+	return 0;
+}
+
 int check_codec_format_supported(unsigned int card, unsigned int device, struct snd_codec *codec)
 {
 	if (is_codec_supported(card, device, COMPRESS_IN, codec) == false) {
@@ -149,19 +210,38 @@
 	return 0;
 }
 
+static int readFromFile2Buffer(char *buffer, FILE** file, int size, uint16_t bits){
+        int num_read = 0;
+        if (bits == 24){
+		int i;
+		int pos = 0;
+		for (i = 0; i < size; i = i + 4) {
+			*(buffer + pos) = 0;
+			pos += 1;
+			num_read += 3 * fread(buffer + pos, 3, 1, *file);
+			pos += 3;
+			num_read += 1;
+		}
+	} else {
+		num_read = fread(buffer, 1, size, *file);
+	}
+
+	return num_read;
+}
+
 int main(int argc, char **argv)
 {
-	char *file;
+        char *file;
 	unsigned long buffer_size = 0;
 	int c;
 	unsigned int card = 0, device = 0, frag = 0;
+        bool pcm = false;
 
-
-	if (argc < 2)
+        if (argc < 2)
 		usage();
 
-	verbose = 0;
-	while ((c = getopt(argc, argv, "hvb:f:c:d:")) != -1) {
+        verbose = 0;
+        while ((c = getopt(argc, argv, "hvpb:f:c:d:")) != -1) {
 		switch (c) {
 		case 'h':
 			usage();
@@ -181,16 +261,23 @@
 		case 'v':
 			verbose = 1;
 			break;
+		case 'p':
+			pcm = true;
+			break;
 		default:
 			exit(EXIT_FAILURE);
 		}
-	}
+        }
 	if (optind >= argc)
 		usage();
 
 	file = argv[optind];
-
-	play_samples(file, card, device, buffer_size, frag);
+	if (!pcm) {
+		play_samples(file, card, device, buffer_size, frag);
+	} else if (pcm) {
+		fprintf(stderr, "Playing pcm samples\n");
+		play_pcm_samples(file, card, device, buffer_size, frag);
+	}
 
 	fprintf(stderr, "Finish Playing.... Close Normally\n");
 	exit(EXIT_SUCCESS);
@@ -328,3 +415,160 @@
 	exit(EXIT_FAILURE);
 }
 
+void play_pcm_samples(char *name, unsigned int card, unsigned int device,
+		      unsigned long buffer_size, unsigned int frag)
+{
+	struct compr_config config;
+	struct snd_codec codec;
+	struct compress *compress;
+	struct mp3_header header;
+	FILE *file;
+	char *buffer;
+	int frag_size, num_read, wrote;
+	unsigned int rate, byterate;
+	uint16_t channels, bits;
+
+	if (verbose)
+		printf("%s: entry\n", __func__);
+	file = fopen(name, "rb");
+	if (!file) {
+		fprintf(stderr, "Unable to open file '%s'\n", name);
+		exit(EXIT_FAILURE);
+	}
+
+	if (parse_pcm_header(&file, &channels, &rate, &bits) == -1){
+		fprintf(stderr, "invalid header\n");
+		exit(EXIT_FAILURE);
+	}
+
+	codec.id = SND_AUDIOCODEC_PCM;
+	codec.ch_in = channels;
+	codec.ch_out = channels;
+	codec.sample_rate = compress_get_alsa_rate(rate);
+	if (!codec.sample_rate) {
+		fprintf(stderr, "invalid sample rate %d\n", rate);
+		fclose(file);
+		exit(EXIT_FAILURE);
+	}
+	codec.bit_rate = bits;
+	codec.rate_control = 0;
+	codec.profile = 0;
+	codec.level = 0;
+	codec.ch_mode = 0;
+	if (bits == 16) {
+		codec.format = SNDRV_PCM_FORMAT_S16_LE;
+	} else if (bits == 24) {
+		codec.format = SNDRV_PCM_FORMAT_S24_LE;
+	} else {
+		fprintf(stderr, "invalid bit rate %d\n", bits);
+		fclose(file);
+		exit(EXIT_FAILURE);
+	}
+
+	if ((buffer_size != 0) && (frag != 0)) {
+		/* Make sure the buffer size and fragments are multiple of 2, or 24 for multi channel*/
+		unsigned int temp_size = (channels > 2)? 24 : 2;
+		while (temp_size < buffer_size)
+			temp_size *= 2;
+		buffer_size = temp_size;
+
+		unsigned int temp_frag = 1;
+		while (temp_frag < frag)
+			temp_frag *= 2;
+
+		config.fragment_size = temp_size/temp_frag;
+		config.fragments = temp_frag;
+	} else {
+		/* Now set to suggested value. set to 0 for using driver defaults */
+		config.fragment_size = (channels > 2)? 12288 : 8192;
+		config.fragments = 4;
+	}
+	if (verbose)
+		printf("%s: Buffer size: %d Fragment size: %d Fragments: %d\n",
+		       __func__, config.fragment_size * config.fragments,
+		       config.fragment_size, config.fragments);
+
+	config.codec = &codec;
+
+	compress = compress_open(card, device, COMPRESS_IN, &config);
+	if (!compress || !is_compress_ready(compress)) {
+		fprintf(stderr, "Unable to open Compress device %d:%d\n",
+			card, device);
+		fprintf(stderr, "ERR: %s\n", compress_get_error(compress));
+		goto FILE_EXIT;
+	};
+	if (verbose)
+		printf("%s: Opened compress device\n", __func__);
+	frag_size = config.fragment_size;
+	printf("frag_size %d frags %d", frag_size, config.fragments);
+	buffer = malloc(frag_size * config.fragments);
+	if (!buffer) {
+		fprintf(stderr, "Unable to allocate %d bytes\n", frag_size);
+		goto COMP_EXIT;
+	}
+
+	/* we will write frag fragment_size and then start */
+	num_read = readFromFile2Buffer(buffer, &file, frag_size * config.fragments, bits);
+	/*Zero padded each 3 byte into 4 byte, the number read must be greater than size / 4 */
+	if (num_read > ((bits == 16)? 0 : frag_size * (int)config.fragments / 4)) {
+		if (verbose)
+			printf("%s: Doing first buffer write of %d\n", __func__, num_read);
+		wrote = compress_write(compress, buffer, num_read);
+		if (wrote < 0) {
+			fprintf(stderr, "Error %d playing sample\n", wrote);
+			fprintf(stderr, "ERR: %s\n", compress_get_error(compress));
+			goto BUF_EXIT;
+		}
+		if (wrote != num_read) {
+			/* TODO: Buufer pointer needs to be set here */
+			fprintf(stderr, "We wrote %d, DSP accepted %d\n", num_read, wrote);
+		}
+	}
+	printf("Playing file %s On Card %u device %u, with buffer of %lu bytes\n",
+	       name, card, device, buffer_size);
+	printf("Format %u Channels %u, %u Hz, Bit Rate %d\n",
+	       SND_AUDIOCODEC_MP3, channels, rate, bits);
+
+	compress_start(compress);
+	if (verbose)
+		printf("%s: You should hear audio NOW!!!\n", __func__);
+
+	do {
+		num_read = readFromFile2Buffer(buffer, &file, frag_size, bits);
+		if (num_read > ((bits == 16)? 0 : frag_size / 4)) {
+			wrote = compress_write(compress, buffer, num_read);
+			if (wrote < 0) {
+				fprintf(stderr, "Error playing sample\n");
+				fprintf(stderr, "ERR: %s\n", compress_get_error(compress));
+				goto BUF_EXIT;
+			}
+			if (wrote != num_read) {
+				/* TODO: Buffer pointer needs to be set here */
+				fprintf(stderr, "We wrote %d, DSP accepted %d\n", num_read, wrote);
+			}
+			if (verbose) {
+				print_time(compress);
+				printf("%s: wrote %d\n", __func__, wrote);
+			}
+		}
+	} while ((!feof(file)));
+
+	if (verbose)
+		printf("%s: exit success\n", __func__);
+	/* issue drain if it supports */
+	compress_drain(compress);
+	free(buffer);
+	fclose(file);
+	compress_close(compress);
+	return;
+BUF_EXIT:
+	free(buffer);
+COMP_EXIT:
+	compress_close(compress);
+FILE_EXIT:
+	fclose(file);
+	if (verbose)
+		printf("%s: exit failure\n", __func__);
+	exit(EXIT_FAILURE);
+}
+