[Feature]add MT2731_MP2_MR2_SVN388 baseline version

Change-Id: Ief04314834b31e27effab435d3ca8ba33b499059
diff --git a/meta/meta-mediatek/recipes-multimedia/tinycompress/tinycompress.bb b/meta/meta-mediatek/recipes-multimedia/tinycompress/tinycompress.bb
new file mode 100644
index 0000000..ab512b1
--- /dev/null
+++ b/meta/meta-mediatek/recipes-multimedia/tinycompress/tinycompress.bb
@@ -0,0 +1,21 @@
+DESCRIPTION = "tinycompress"
+LICENSE = "BSD|LGPLv2.1"
+LIC_FILES_CHKSUM = "file://COPYING;md5=cf9105c1a2d4405cbe04bbe3367373a0"
+
+inherit autotools
+
+SRC_URI = "git://git.alsa-project.org/http/tinycompress.git;protocol=http \
+           file://0001-compress-fix-uncertain-no_wake_mode-setting.patch \
+           file://0002-cplay-add-aac-playback-support.patch \
+           file://0003-cplay-add-sbc-playback-support.patch \
+           file://0004-compress-add-api-to-get-fragment-size-and-fragments.patch \
+           file://0005-cplay-support-low-power-playback.patch \
+           file://0006-compress-fix-the-return-value-of-is_codec_supported.patch \
+           file://0007-comrpess-add-api-to-query-aac-mode-support.patch \
+           file://0008-cplay-add-hostless-mode-support.patch \
+           file://0009-cplay-add-xrun-recovery-support.patch \
+"
+
+SRCREV = "d99dc2875843327feb658d674c8f4d710e8bd432"
+
+S = "${WORKDIR}/git"
diff --git a/meta/meta-mediatek/recipes-multimedia/tinycompress/tinycompress/0001-compress-fix-uncertain-no_wake_mode-setting.patch b/meta/meta-mediatek/recipes-multimedia/tinycompress/tinycompress/0001-compress-fix-uncertain-no_wake_mode-setting.patch
new file mode 100644
index 0000000..d50659c
--- /dev/null
+++ b/meta/meta-mediatek/recipes-multimedia/tinycompress/tinycompress/0001-compress-fix-uncertain-no_wake_mode-setting.patch
@@ -0,0 +1,27 @@
+From fe9df9ce4270926a7bf1caf62f14573aeb173411 Mon Sep 17 00:00:00 2001
+From: Hidalgo Huang <hidalgo.huang@mediatek.com>
+Date: Tue, 18 Dec 2018 17:22:14 +0800
+Subject: [PATCH 1/9] compress: fix uncertain no_wake_mode setting
+
+Initialize struct snd_compr_param explicitly.
+
+Signed-off-by: Hidalgo Huang <hidalgo.huang@mediatek.com>
+---
+ src/lib/compress.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/src/lib/compress.c b/src/lib/compress.c
+index bba4fcf..d8d2ffc 100644
+--- a/src/lib/compress.c
++++ b/src/lib/compress.c
+@@ -228,6 +228,7 @@ struct compress *compress_open(unsigned int card, unsigned int device,
+ 		config->fragments = caps.max_fragments;
+ 	}
+ 
++	memset(&params, 0, sizeof(struct snd_compr_params));
+ 	memcpy(compress->config, config, sizeof(*compress->config));
+ 	fill_compress_params(config, &params);
+ 
+-- 
+2.18.0
+
diff --git a/meta/meta-mediatek/recipes-multimedia/tinycompress/tinycompress/0002-cplay-add-aac-playback-support.patch b/meta/meta-mediatek/recipes-multimedia/tinycompress/tinycompress/0002-cplay-add-aac-playback-support.patch
new file mode 100644
index 0000000..4b63ed9
--- /dev/null
+++ b/meta/meta-mediatek/recipes-multimedia/tinycompress/tinycompress/0002-cplay-add-aac-playback-support.patch
@@ -0,0 +1,361 @@
+From 5e87cad41e7762ee5a097b4be451a3415b763229 Mon Sep 17 00:00:00 2001
+From: Hidalgo Huang <hidalgo.huang@mediatek.com>
+Date: Wed, 19 Dec 2018 16:34:31 +0800
+Subject: [PATCH 2/9] cplay: add aac playback support
+
+Support ADTS/ADIF/LOAS/LATM/RAW files.
+
+Signed-off-by: Hidalgo Huang <hidalgo.huang@mediatek.com>
+---
+ include/tinycompress/tinyaac.h |  77 ++++++++++++++
+ src/utils/cplay.c              | 187 ++++++++++++++++++++++++++++++++-
+ 2 files changed, 260 insertions(+), 4 deletions(-)
+ create mode 100644 include/tinycompress/tinyaac.h
+
+diff --git a/include/tinycompress/tinyaac.h b/include/tinycompress/tinyaac.h
+new file mode 100644
+index 0000000..c5ee94e
+--- /dev/null
++++ b/include/tinycompress/tinyaac.h
+@@ -0,0 +1,77 @@
++/*
++ * This file is provided under a dual BSD/LGPLv2.1 license.  When using or
++ * redistributing this file, you may do so under either license.
++ *
++ * BSD LICENSE
++ *
++ * aac header and prasing
++ * Copyright (c) 2018, MediaTek Inc.
++ * All rights reserved.
++ *
++ * Author: Hidalgo Huang <hidalgo.huang@mediatek.com>
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *
++ * Redistributions of source code must retain the above copyright notice,
++ * this list of conditions and the following disclaimer.
++ * Redistributions in binary form must reproduce the above copyright notice,
++ * this list of conditions and the following disclaimer in the documentation
++ * and/or other materials provided with the distribution.
++ * Neither the name of Intel Corporation nor the names of its contributors
++ * may be used to endorse or promote products derived from this software
++ * without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
++ * THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * LGPL LICENSE
++ *
++ * aac header and parsing
++ * Copyright (c) 2018, MediaTek inc.
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU Lesser General Public License,
++ * version 2.1, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
++ * License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * along with this program; if not, write to
++ * the Free Software Foundation, Inc.,
++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++ */
++
++
++#ifndef __TINYAAC_H
++#define __TINYAAC_H
++
++#if defined(__cplusplus)
++extern "C" {
++#endif
++
++#define ADTS_HEADER_PARSE_SIZE (4)
++#define LOAS_HEADER_PARSE_SIZE (2)
++#define ADIF_HEADER_PARSE_SIZE (4)
++
++static const int aac_sample_rates[16] = {
++	96000, 88200, 64000, 48000,
++	44100, 32000, 24000, 22050,
++	16000, 12000, 11025, 8000,
++	73500, 0, 0, 0,
++};
++
++#endif
+diff --git a/src/utils/cplay.c b/src/utils/cplay.c
+index 3e9fcac..8cb86c6 100644
+--- a/src/utils/cplay.c
++++ b/src/utils/cplay.c
+@@ -72,6 +72,7 @@
+ #include "sound/compress_params.h"
+ #include "tinycompress/tinycompress.h"
+ #include "tinycompress/tinymp3.h"
++#include "tinycompress/tinyaac.h"
+ 
+ static int verbose;
+ static const unsigned int DEFAULT_CODEC_ID = SND_AUDIOCODEC_PCM;
+@@ -112,6 +113,8 @@ static void usage(void)
+ 		"-f\tfragments\n\n"
+ 		"-v\tverbose mode\n"
+ 		"-h\tPrints this help list\n\n"
++		"-R\tspecify sample rate\n\n"
++		"-C\tspecify channel count\n\n"
+ 		"Example:\n"
+ 		"\tcplay -c 1 -d 2 test.mp3\n"
+ 		"\tcplay -f 5 test.mp3\n\n"
+@@ -128,7 +131,8 @@ static void usage(void)
+ 
+ void play_samples(char *name, unsigned int card, unsigned int device,
+ 		unsigned long buffer_size, unsigned int frag,
+-		unsigned long codec_id);
++		unsigned long codec_id, unsigned int rate,
++		unsigned int channels);
+ 
+ struct mp3_header {
+ 	uint16_t sync;
+@@ -165,6 +169,143 @@ static int parse_mp3_header(struct mp3_header *header, unsigned int *num_channel
+ 	return 0;
+ }
+ 
++static int check_aac_adts_frame(FILE *file, unsigned int *num_channels,
++	unsigned int *sample_rate, unsigned int *format, char *file_name)
++{
++	size_t read;
++	unsigned char data[ADTS_HEADER_PARSE_SIZE];
++	unsigned int freq_index;
++
++	read = fread(&data, 1, sizeof(data), file);
++	if (read != sizeof(data))
++		return -1;
++
++	// check syncword
++	if ((data[0] == 0xff) && ((data[1] & 0xf6) == 0xf0)) {
++		*format = (data[1] & 0x8) ? SND_AUDIOSTREAMFORMAT_MP2ADTS :
++		                            SND_AUDIOSTREAMFORMAT_MP4ADTS;
++		freq_index = (data[2] >> 2) & 0xf;
++		*sample_rate = aac_sample_rates[freq_index];
++		*num_channels = (data[2] & 0x1) << 2 | (data[3] >> 6);
++		return 0;
++	}
++
++	return -1;
++}
++
++static int check_aac_loas_frame(FILE *file, unsigned int *num_channels,
++	unsigned int *sample_rate, unsigned int *format, char *file_name)
++{
++	size_t read;
++	unsigned char data[LOAS_HEADER_PARSE_SIZE];
++
++	read = fread(&data, 1, sizeof(data), file);
++	if (read != sizeof(data))
++		return -1;
++
++	// check AudioSyncStream syncword 0x2b7 (11bits)
++	if ((data[0] == 0x56) && ((data[1] & 0xe0) == 0xe0)) {
++		*format = SND_AUDIOSTREAMFORMAT_MP4LOAS;
++		*num_channels = 2;
++		if (*sample_rate == 0)
++			*sample_rate = 44100;
++		if (*num_channels == 0)
++			*num_channels = 2;
++		return 0;
++	}
++
++	return -1;
++}
++
++static int check_aac_adif_frame(FILE *file, unsigned int *num_channels,
++	unsigned int *sample_rate, unsigned int *format, char *file_name)
++{
++	size_t read;
++	unsigned char data[ADIF_HEADER_PARSE_SIZE];
++
++	read = fread(&data, 1, sizeof(data), file);
++	if (read != sizeof(data))
++		return -1;
++
++	// check syncword
++	if ((data[0] == 'A') && (data[1] == 'D') &&
++	    (data[2] == 'I') && (data[3] == 'F') ) {
++		*format = SND_AUDIOSTREAMFORMAT_ADIF;
++		if (*sample_rate == 0)
++			*sample_rate = 44100;
++		if (*num_channels == 0)
++			*num_channels = 2;
++		return 0;
++	}
++
++	return -1;
++}
++
++static int check_aac_latm_frame(FILE *file, unsigned int *num_channels,
++	unsigned int *sample_rate, unsigned int *format, char *file_name)
++{
++	if (strstr(file_name, ".latm")) {
++		*format = SND_AUDIOSTREAMFORMAT_MP4LATM;
++		if (*sample_rate == 0)
++			*sample_rate = 44100;
++		if (*num_channels == 0)
++			*num_channels = 2;
++		return 0;
++	}
++
++	return -1;
++}
++
++static int check_aac_raw_frame(FILE *file, unsigned int *num_channels,
++	unsigned int *sample_rate, unsigned int *format, char *file_name)
++{
++	if (strstr(file_name, ".aac")) {
++		*format = SND_AUDIOSTREAMFORMAT_RAW;
++		if (*sample_rate == 0)
++			*sample_rate = 44100;
++		if (*num_channels == 0)
++			*num_channels = 2;
++		return 0;
++	}
++
++	return -1;
++}
++
++static int parse_aac_header(FILE *file, unsigned int *num_channels,
++		unsigned int *sample_rate, unsigned int *format, char *file_name)
++{
++	int i;
++	fpos_t init_pos;
++	static int (*aac_parsers[])(FILE *,
++	                            unsigned int *,
++	                            unsigned int *,
++	                            unsigned int *,
++	                            char *) = {
++	    check_aac_adts_frame,
++	    check_aac_loas_frame,
++	    check_aac_adif_frame,
++	    check_aac_latm_frame,
++	    check_aac_raw_frame,
++	};
++	int parser_num = sizeof(aac_parsers) / sizeof(aac_parsers[0]);
++
++	fgetpos(file, &init_pos);
++
++	for (i = 0; i < parser_num; i++) {
++		fsetpos(file, &init_pos);
++
++		if (aac_parsers[i](file, num_channels, sample_rate, format, file_name) == 0)
++			goto aac_parsed;
++	}
++
++aac_err:
++	return -1;
++
++aac_parsed:
++	fsetpos(file, &init_pos);
++	return 0;
++}
++
+ static int print_time(struct compress *compress)
+ {
+ 	unsigned int avail;
+@@ -186,12 +327,13 @@ int main(int argc, char **argv)
+ 	int c, i;
+ 	unsigned int card = 0, device = 0, frag = 0;
+ 	unsigned int codec_id = SND_AUDIOCODEC_MP3;
++	unsigned int rate = 0, channels = 0;
+ 
+ 	if (argc < 2)
+ 		usage();
+ 
+ 	verbose = 0;
+-	while ((c = getopt(argc, argv, "hvb:f:c:d:I:")) != -1) {
++	while ((c = getopt(argc, argv, "hvb:f:c:d:I:R:C:")) != -1) {
+ 		switch (c) {
+ 		case 'h':
+ 			usage();
+@@ -230,6 +372,12 @@ int main(int argc, char **argv)
+ 		case 'v':
+ 			verbose = 1;
+ 			break;
++		case 'R':
++			rate = strtol(optarg, NULL, 10);
++			break;
++		case 'C':
++			channels = strtol(optarg, NULL, 10);
++			break;
+ 		default:
+ 			exit(EXIT_FAILURE);
+ 		}
+@@ -239,7 +387,7 @@ int main(int argc, char **argv)
+ 
+ 	file = argv[optind];
+ 
+-	play_samples(file, card, device, buffer_size, frag, codec_id);
++	play_samples(file, card, device, buffer_size, frag, codec_id, rate, channels);
+ 
+ 	fprintf(stderr, "Finish Playing.... Close Normally\n");
+ 	exit(EXIT_SUCCESS);
+@@ -297,9 +445,37 @@ void get_codec_iec(FILE *file, struct compr_config *config,
+ 	codec->format = 0;
+ }
+ 
++void get_codec_aac(FILE *file, struct compr_config *config,
++		struct snd_codec *codec, char *file_name,
++		unsigned int specified_rate,
++		unsigned int specified_channels)
++{
++	unsigned int channels, rate, format;
++
++	rate = specified_rate;
++	channels = specified_channels;
++
++	if (parse_aac_header(file, &channels, &rate, &format, file_name) == -1) {
++		fclose(file);
++		exit(EXIT_FAILURE);
++	}
++
++	codec->id = SND_AUDIOCODEC_AAC;
++	codec->ch_in = channels;
++	codec->ch_out = channels;
++	codec->sample_rate = rate;
++	codec->bit_rate = 0;
++	codec->rate_control = 0;
++	codec->profile = SND_AUDIOPROFILE_AAC;
++	codec->level = 0;
++	codec->ch_mode = 0;
++	codec->format = format;
++}
++
+ void play_samples(char *name, unsigned int card, unsigned int device,
+ 		unsigned long buffer_size, unsigned int frag,
+-		unsigned long codec_id)
++		unsigned long codec_id, unsigned int rate,
++		unsigned int channels)
+ {
+ 	struct compr_config config;
+ 	struct snd_codec codec;
+@@ -323,6 +499,9 @@ void play_samples(char *name, unsigned int card, unsigned int device,
+ 	case SND_AUDIOCODEC_IEC61937:
+ 		get_codec_iec(file, &config, &codec);
+ 		break;
++	case SND_AUDIOCODEC_AAC:
++		get_codec_aac(file, &config, &codec, name, rate, channels);
++		break;
+ 	default:
+ 		fprintf(stderr, "codec ID %ld is not supported\n", codec_id);
+ 		exit(EXIT_FAILURE);
+-- 
+2.18.0
+
diff --git a/meta/meta-mediatek/recipes-multimedia/tinycompress/tinycompress/0003-cplay-add-sbc-playback-support.patch b/meta/meta-mediatek/recipes-multimedia/tinycompress/tinycompress/0003-cplay-add-sbc-playback-support.patch
new file mode 100644
index 0000000..a47ab02
--- /dev/null
+++ b/meta/meta-mediatek/recipes-multimedia/tinycompress/tinycompress/0003-cplay-add-sbc-playback-support.patch
@@ -0,0 +1,253 @@
+From 73e54158d4b9e5d7b2c38f528ae9cf261a7cfe45 Mon Sep 17 00:00:00 2001
+From: Hidalgo Huang <hidalgo.huang@mediatek.com>
+Date: Tue, 25 Dec 2018 15:33:50 +0800
+Subject: [PATCH 3/9] cplay: add sbc playback support
+
+Support .sbc files.
+
+Signed-off-by: Hidalgo Huang <hidalgo.huang@mediatek.com>
+---
+ include/sound/compress_params.h | 21 ++++++++-
+ include/tinycompress/tinysbc.h  | 76 +++++++++++++++++++++++++++++++++
+ src/utils/cplay.c               | 61 ++++++++++++++++++++++++++
+ 3 files changed, 157 insertions(+), 1 deletion(-)
+ create mode 100644 include/tinycompress/tinysbc.h
+
+diff --git a/include/sound/compress_params.h b/include/sound/compress_params.h
+index 7286556..6f3aa33 100644
+--- a/include/sound/compress_params.h
++++ b/include/sound/compress_params.h
+@@ -39,8 +39,9 @@
+ #define SND_AUDIOCODEC_G723_1 ((__u32) 0x0000000C)
+ #define SND_AUDIOCODEC_G729 ((__u32) 0x0000000D)
+ #define SND_AUDIOCODEC_BESPOKE ((__u32) 0x0000000E)
++#define SND_AUDIOCODEC_SBC ((__u32) 0x0000000F)
+ 
+-#define SND_AUDIOCODEC_MAX SND_AUDIOCODEC_BESPOKE
++#define SND_AUDIOCODEC_MAX SND_AUDIOCODEC_SBC
+ #define SND_AUDIOPROFILE_PCM ((__u32) 0x00000001)
+ 
+ #define SND_AUDIOCHANMODE_MP3_MONO ((__u32) 0x00000001)
+@@ -170,6 +171,16 @@
+ #define SND_AUDIOMODE_G729_ANNEX_A ((__u32) 0x00000001)
+ #define SND_AUDIOMODE_G729_ANNEX_B ((__u32) 0x00000002)
+ 
++#define SND_AUDIOPROFILE_SBC ((__u32) 0x00000001)
++
++#define SND_AUDIOCHANMODE_SBC_MONO ((__u32) 0x00000001)
++#define SND_AUDIOCHANMODE_SBC_STEREO ((__u32) 0x00000002)
++#define SND_AUDIOCHANMODE_SBC_JOINTSTEREO ((__u32) 0x00000004)
++#define SND_AUDIOCHANMODE_SBC_DUAL ((__u32) 0x00000008)
++
++#define SND_BIT_ALLOC_SBC_LOUDNESS ((__u32) 0x00000001)
++#define SND_BIT_ALLOC_SBC_SNR ((__u32) 0x00000002)
++
+ #define SND_RATECONTROLMODE_CONSTANTBITRATE ((__u32) 0x00000001)
+ #define SND_RATECONTROLMODE_VARIABLEBITRATE ((__u32) 0x00000002)
+ 
+@@ -201,12 +212,20 @@ struct snd_enc_generic {
+  __s32 reserved[15];
+ }__attribute__((packed, aligned(4)));
+ 
++struct snd_enc_sbc {
++ __u32 bitpool;
++ __u32 num_subbands;
++ __u32 num_blocks;
++ __u32 bit_alloc;
++} __attribute__((packed, aligned(4)));
++
+ union snd_codec_options {
+  struct snd_enc_wma wma;
+  struct snd_enc_vorbis vorbis;
+  struct snd_enc_real real;
+  struct snd_enc_flac flac;
+  struct snd_enc_generic generic;
++ struct snd_enc_sbc sbc;
+ }__attribute__((packed, aligned(4)));
+ 
+ struct snd_codec_desc {
+diff --git a/include/tinycompress/tinysbc.h b/include/tinycompress/tinysbc.h
+new file mode 100644
+index 0000000..f579ca7
+--- /dev/null
++++ b/include/tinycompress/tinysbc.h
+@@ -0,0 +1,76 @@
++/*
++ * This file is provided under a dual BSD/LGPLv2.1 license.  When using or
++ * redistributing this file, you may do so under either license.
++ *
++ * BSD LICENSE
++ *
++ * aac header and prasing
++ * Copyright (c) 2018, MediaTek Inc.
++ * All rights reserved.
++ *
++ * Author: Hidalgo Huang <hidalgo.huang@mediatek.com>
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *
++ * Redistributions of source code must retain the above copyright notice,
++ * this list of conditions and the following disclaimer.
++ * Redistributions in binary form must reproduce the above copyright notice,
++ * this list of conditions and the following disclaimer in the documentation
++ * and/or other materials provided with the distribution.
++ * Neither the name of Intel Corporation nor the names of its contributors
++ * may be used to endorse or promote products derived from this software
++ * without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
++ * THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * LGPL LICENSE
++ *
++ * aac header and parsing
++ * Copyright (c) 2018, MediaTek inc.
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU Lesser General Public License,
++ * version 2.1, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
++ * License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * along with this program; if not, write to
++ * the Free Software Foundation, Inc.,
++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++ */
++
++
++#ifndef __TINYSBC_H
++#define __TINYSBC_H
++
++#if defined(__cplusplus)
++extern "C" {
++#endif
++
++#define SBC_HEADER_PARSE_SIZE (4)
++
++static const int sbc_sample_rates[4] = {
++	16000, 32000, 44100, 48000,
++};
++
++static const int sbc_channels[4] = {
++	1, 2, 2, 2,
++};
++
++#endif
+diff --git a/src/utils/cplay.c b/src/utils/cplay.c
+index 8cb86c6..e5d2a9d 100644
+--- a/src/utils/cplay.c
++++ b/src/utils/cplay.c
+@@ -73,6 +73,7 @@
+ #include "tinycompress/tinycompress.h"
+ #include "tinycompress/tinymp3.h"
+ #include "tinycompress/tinyaac.h"
++#include "tinycompress/tinysbc.h"
+ 
+ static int verbose;
+ static const unsigned int DEFAULT_CODEC_ID = SND_AUDIOCODEC_PCM;
+@@ -98,6 +99,7 @@ static const struct {
+ #ifdef SND_AUDIOCODEC_BESPOKE
+ 	{ "BESPOKE", SND_AUDIOCODEC_BESPOKE },
+ #endif
++	{ "SBC", SND_AUDIOCODEC_SBC },
+ };
+ #define CPLAY_NUM_CODEC_IDS (sizeof(codec_ids) / sizeof(codec_ids[0]))
+ 
+@@ -306,6 +308,35 @@ aac_parsed:
+ 	return 0;
+ }
+ 
++static int parse_sbc_header(FILE *file, unsigned int *num_channels,
++		unsigned int *sample_rate)
++{
++	int i;
++	fpos_t init_pos;
++	size_t read;
++	unsigned char data[SBC_HEADER_PARSE_SIZE];
++	int ret = 0;
++
++	fgetpos(file, &init_pos);
++
++	read = fread(&data, 1, sizeof(data), file);
++	if (read != sizeof(data))
++		goto sbc_err;
++
++	if (data[0] != 0x9c)
++		goto sbc_err;
++
++	*num_channels = sbc_channels[(data[1] >> 2) & 0x3];
++	*sample_rate = sbc_sample_rates[(data[1] >> 6) & 0x3];
++
++	fsetpos(file, &init_pos);
++	return 0;
++
++sbc_err:
++	fsetpos(file, &init_pos);
++	return -1;
++}
++
+ static int print_time(struct compress *compress)
+ {
+ 	unsigned int avail;
+@@ -472,6 +503,33 @@ void get_codec_aac(FILE *file, struct compr_config *config,
+ 	codec->format = format;
+ }
+ 
++void get_codec_sbc(FILE *file, struct compr_config *config,
++        struct snd_codec *codec)
++{
++    unsigned int channels, rate;
++
++    if (parse_sbc_header(file, &channels, &rate) == -1) {
++        fclose(file);
++        exit(EXIT_FAILURE);
++    }
++
++    codec->id = SND_AUDIOCODEC_SBC;
++    codec->ch_in = channels;
++    codec->ch_out = channels;
++    codec->sample_rate = rate;
++    if (!codec->sample_rate) {
++        fprintf(stderr, "invalid sample rate %d\n", rate);
++        fclose(file);
++        exit(EXIT_FAILURE);
++    }
++    codec->bit_rate = 0;
++    codec->rate_control = 0;
++    codec->profile = SND_AUDIOPROFILE_SBC;
++    codec->level = 0;
++    codec->ch_mode = 0;
++    codec->format = 0;
++}
++
+ void play_samples(char *name, unsigned int card, unsigned int device,
+ 		unsigned long buffer_size, unsigned int frag,
+ 		unsigned long codec_id, unsigned int rate,
+@@ -502,6 +560,9 @@ void play_samples(char *name, unsigned int card, unsigned int device,
+ 	case SND_AUDIOCODEC_AAC:
+ 		get_codec_aac(file, &config, &codec, name, rate, channels);
+ 		break;
++	case SND_AUDIOCODEC_SBC:
++		get_codec_sbc(file, &config, &codec);
++		break;
+ 	default:
+ 		fprintf(stderr, "codec ID %ld is not supported\n", codec_id);
+ 		exit(EXIT_FAILURE);
+-- 
+2.18.0
+
diff --git a/meta/meta-mediatek/recipes-multimedia/tinycompress/tinycompress/0004-compress-add-api-to-get-fragment-size-and-fragments.patch b/meta/meta-mediatek/recipes-multimedia/tinycompress/tinycompress/0004-compress-add-api-to-get-fragment-size-and-fragments.patch
new file mode 100644
index 0000000..3922471
--- /dev/null
+++ b/meta/meta-mediatek/recipes-multimedia/tinycompress/tinycompress/0004-compress-add-api-to-get-fragment-size-and-fragments.patch
@@ -0,0 +1,100 @@
+From f17496d78a75fbc7c2b9eab8e83e8eda25789632 Mon Sep 17 00:00:00 2001
+From: Hidalgo Huang <hidalgo.huang@mediatek.com>
+Date: Mon, 21 Jan 2019 10:09:13 +0800
+Subject: [PATCH 4/9] compress: add api to get fragment size and fragments
+
+Implement get_fragment_config().
+
+Signed-off-by: Hidalgo Huang <hidalgo.huang@mediatek.com>
+---
+ include/tinycompress/tinycompress.h | 10 +++++++
+ src/lib/compress.c                  | 41 +++++++++++++++++++++++++++++
+ 2 files changed, 51 insertions(+)
+
+diff --git a/include/tinycompress/tinycompress.h b/include/tinycompress/tinycompress.h
+index f0fae30..c3ef6b8 100644
+--- a/include/tinycompress/tinycompress.h
++++ b/include/tinycompress/tinycompress.h
+@@ -82,6 +82,13 @@ struct compr_gapless_mdata {
+ 	__u32 encoder_padding;
+ };
+ 
++struct compr_fragment_config {
++	__u32 min_fragment_size;
++	__u32 max_fragment_size;
++	__u32 min_fragments;
++	__u32 max_fragments;
++};
++
+ #define COMPRESS_OUT        0x20000000
+ #define COMPRESS_IN         0x10000000
+ 
+@@ -276,6 +283,9 @@ int is_compress_ready(struct compress *compress);
+ /* Returns a human readable reason for the last error */
+ const char *compress_get_error(struct compress *compress);
+ 
++int get_fragment_config(unsigned int card, unsigned int device,
++	unsigned int flags, struct compr_fragment_config *fragment_config);
++
+ #if defined(__cplusplus)
+ } // extern "C"
+ #endif
+diff --git a/src/lib/compress.c b/src/lib/compress.c
+index d8d2ffc..67cab2b 100644
+--- a/src/lib/compress.c
++++ b/src/lib/compress.c
+@@ -172,6 +172,23 @@ fill_compress_params(struct compr_config *config, struct snd_compr_params *param
+ 	memcpy(&params->codec, config->codec, sizeof(params->codec));
+ }
+ 
++static int _get_fragment_config(int fd, struct compr_fragment_config *fragment_config)
++{
++	struct snd_compr_caps caps;
++
++	if (ioctl(fd, SNDRV_COMPRESS_GET_CAPS, &caps)) {
++		oops(&bad_compress, errno, "cannot get device caps");
++		return -1;
++	}
++
++	fragment_config->min_fragment_size = caps.min_fragment_size;
++	fragment_config->max_fragment_size = caps.max_fragment_size;
++	fragment_config->min_fragments = caps.min_fragments;
++	fragment_config->max_fragments = caps.max_fragments;
++
++	return 0;
++}
++
+ struct compress *compress_open(unsigned int card, unsigned int device,
+ 		unsigned int flags, struct compr_config *config)
+ {
+@@ -583,3 +600,27 @@ int compress_wait(struct compress *compress, int timeout_ms)
+ 	return oops(compress, EIO, "poll signalled unhandled event");
+ }
+ 
++int get_fragment_config(unsigned int card, unsigned int device,
++	unsigned int flags, struct compr_fragment_config *fragment_config)
++{
++	unsigned int dev_flag;
++	int ret;
++	int fd;
++	char fn[256];
++
++	snprintf(fn, sizeof(fn), "/dev/snd/comprC%uD%u", card, device);
++
++	if (flags & COMPRESS_OUT)
++		dev_flag = O_RDONLY;
++	else
++		dev_flag = O_WRONLY;
++
++	fd = open(fn, dev_flag);
++	if (fd < 0)
++		return oops(&bad_compress, errno, "cannot open device '%s'", fn);
++
++	ret = _get_fragment_config(fd, fragment_config);
++
++	close(fd);
++	return ret;
++}
+-- 
+2.18.0
+
diff --git a/meta/meta-mediatek/recipes-multimedia/tinycompress/tinycompress/0005-cplay-support-low-power-playback.patch b/meta/meta-mediatek/recipes-multimedia/tinycompress/tinycompress/0005-cplay-support-low-power-playback.patch
new file mode 100644
index 0000000..7954d73
--- /dev/null
+++ b/meta/meta-mediatek/recipes-multimedia/tinycompress/tinycompress/0005-cplay-support-low-power-playback.patch
@@ -0,0 +1,68 @@
+From abf3dfe62b2ab7fefd65069d6fbce911b238862b Mon Sep 17 00:00:00 2001
+From: Hidalgo Huang <hidalgo.huang@mediatek.com>
+Date: Mon, 21 Jan 2019 10:12:48 +0800
+Subject: [PATCH 5/9] cplay: support low power playback
+
+Use max fragment size for low power playback.
+
+Signed-off-by: Hidalgo Huang <hidalgo.huang@mediatek.com>
+---
+ src/utils/cplay.c | 16 +++++++++++++++-
+ 1 file changed, 15 insertions(+), 1 deletion(-)
+
+diff --git a/src/utils/cplay.c b/src/utils/cplay.c
+index e5d2a9d..6dc3096 100644
+--- a/src/utils/cplay.c
++++ b/src/utils/cplay.c
+@@ -117,6 +117,7 @@ static void usage(void)
+ 		"-h\tPrints this help list\n\n"
+ 		"-R\tspecify sample rate\n\n"
+ 		"-C\tspecify channel count\n\n"
++		"-L\tlow power mode\n\n"
+ 		"Example:\n"
+ 		"\tcplay -c 1 -d 2 test.mp3\n"
+ 		"\tcplay -f 5 test.mp3\n\n"
+@@ -359,12 +360,13 @@ int main(int argc, char **argv)
+ 	unsigned int card = 0, device = 0, frag = 0;
+ 	unsigned int codec_id = SND_AUDIOCODEC_MP3;
+ 	unsigned int rate = 0, channels = 0;
++	int low_power = 0;
+ 
+ 	if (argc < 2)
+ 		usage();
+ 
+ 	verbose = 0;
+-	while ((c = getopt(argc, argv, "hvb:f:c:d:I:R:C:")) != -1) {
++	while ((c = getopt(argc, argv, "hvb:f:c:d:I:R:C:L")) != -1) {
+ 		switch (c) {
+ 		case 'h':
+ 			usage();
+@@ -409,6 +411,9 @@ int main(int argc, char **argv)
+ 		case 'C':
+ 			channels = strtol(optarg, NULL, 10);
+ 			break;
++		case 'L':
++			low_power = 1;
++			break;
+ 		default:
+ 			exit(EXIT_FAILURE);
+ 		}
+@@ -418,6 +423,15 @@ int main(int argc, char **argv)
+ 
+ 	file = argv[optind];
+ 
++	if (low_power) {
++		struct compr_fragment_config fragment_config;
++
++		if (get_fragment_config(card, device, COMPRESS_IN, &fragment_config) == 0) {
++			frag = fragment_config.min_fragments;
++			buffer_size = fragment_config.max_fragment_size * frag;
++		}
++	}
++
+ 	play_samples(file, card, device, buffer_size, frag, codec_id, rate, channels);
+ 
+ 	fprintf(stderr, "Finish Playing.... Close Normally\n");
+-- 
+2.18.0
+
diff --git a/meta/meta-mediatek/recipes-multimedia/tinycompress/tinycompress/0006-compress-fix-the-return-value-of-is_codec_supported.patch b/meta/meta-mediatek/recipes-multimedia/tinycompress/tinycompress/0006-compress-fix-the-return-value-of-is_codec_supported.patch
new file mode 100644
index 0000000..7193ccc
--- /dev/null
+++ b/meta/meta-mediatek/recipes-multimedia/tinycompress/tinycompress/0006-compress-fix-the-return-value-of-is_codec_supported.patch
@@ -0,0 +1,32 @@
+From feaa0588eadaed43a82dcf3b763f3bd059685e33 Mon Sep 17 00:00:00 2001
+From: Hidalgo Huang <hidalgo.huang@mediatek.com>
+Date: Thu, 21 Feb 2019 14:58:24 +0800
+Subject: [PATCH 6/9] compress: fix the return value of is_codec_supported()
+
+Return false when failed to open device node.
+
+Signed-off-by: Hidalgo Huang <hidalgo.huang@mediatek.com>
+---
+ src/lib/compress.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/src/lib/compress.c b/src/lib/compress.c
+index 67cab2b..5cb29e4 100644
+--- a/src/lib/compress.c
++++ b/src/lib/compress.c
+@@ -558,8 +558,10 @@ bool is_codec_supported(unsigned int card, unsigned int device,
+ 		dev_flag = O_WRONLY;
+ 
+ 	fd = open(fn, dev_flag);
+-	if (fd < 0)
+-		return oops(&bad_compress, errno, "cannot open device '%s'", fn);
++	if (fd < 0) {
++		oops(&bad_compress, errno, "cannot open device '%s'", fn);
++		return false;
++	}
+ 
+ 	ret = _is_codec_type_supported(fd, codec);
+ 
+-- 
+2.18.0
+
diff --git a/meta/meta-mediatek/recipes-multimedia/tinycompress/tinycompress/0007-comrpess-add-api-to-query-aac-mode-support.patch b/meta/meta-mediatek/recipes-multimedia/tinycompress/tinycompress/0007-comrpess-add-api-to-query-aac-mode-support.patch
new file mode 100644
index 0000000..d00d7d3
--- /dev/null
+++ b/meta/meta-mediatek/recipes-multimedia/tinycompress/tinycompress/0007-comrpess-add-api-to-query-aac-mode-support.patch
@@ -0,0 +1,95 @@
+From f6b42b5bffb1783905d7f3869b73c1228b3471d2 Mon Sep 17 00:00:00 2001
+From: Hidalgo Huang <hidalgo.huang@mediatek.com>
+Date: Mon, 18 Mar 2019 14:56:45 +0800
+Subject: [PATCH 7/9] comrpess: add api to query aac mode support
+
+Implement is_acc_mode_supported().
+
+Signed-off-by: Hidalgo Huang <hidalgo.huang@mediatek.com>
+---
+ include/tinycompress/tinycompress.h |  3 ++
+ src/lib/compress.c                  | 50 +++++++++++++++++++++++++++++
+ 2 files changed, 53 insertions(+)
+
+diff --git a/include/tinycompress/tinycompress.h b/include/tinycompress/tinycompress.h
+index c3ef6b8..a087a85 100644
+--- a/include/tinycompress/tinycompress.h
++++ b/include/tinycompress/tinycompress.h
+@@ -286,6 +286,9 @@ const char *compress_get_error(struct compress *compress);
+ int get_fragment_config(unsigned int card, unsigned int device,
+ 	unsigned int flags, struct compr_fragment_config *fragment_config);
+ 
++bool is_aac_mode_supported(unsigned int card, unsigned int device,
++	unsigned int flags, unsigned int mode);
++
+ #if defined(__cplusplus)
+ } // extern "C"
+ #endif
+diff --git a/src/lib/compress.c b/src/lib/compress.c
+index 5cb29e4..e2644ea 100644
+--- a/src/lib/compress.c
++++ b/src/lib/compress.c
+@@ -189,6 +189,16 @@ static int _get_fragment_config(int fd, struct compr_fragment_config *fragment_c
+ 	return 0;
+ }
+ 
++static int _get_codec_caps(int fd, struct snd_compr_codec_caps *caps)
++{
++	if (ioctl(fd, SNDRV_COMPRESS_GET_CODEC_CAPS, caps)) {
++		oops(&bad_compress, errno, "cannot get codec caps");
++		return -1;
++	}
++
++	return 0;
++}
++
+ struct compress *compress_open(unsigned int card, unsigned int device,
+ 		unsigned int flags, struct compr_config *config)
+ {
+@@ -626,3 +636,43 @@ int get_fragment_config(unsigned int card, unsigned int device,
+ 	close(fd);
+ 	return ret;
+ }
++
++bool is_aac_mode_supported(unsigned int card, unsigned int device,
++	unsigned int flags, unsigned int mode)
++{
++	unsigned int dev_flag;
++	bool ret = false;
++	int fd;
++	char fn[256];
++	struct snd_compr_codec_caps codec_caps;
++	unsigned int i;
++
++	snprintf(fn, sizeof(fn), "/dev/snd/comprC%uD%u", card, device);
++
++	if (flags & COMPRESS_OUT)
++		dev_flag = O_RDONLY;
++	else
++		dev_flag = O_WRONLY;
++
++	fd = open(fn, dev_flag);
++	if (fd < 0) {
++		oops(&bad_compress, errno, "cannot open device '%s'", fn);
++		return false;
++	}
++
++	codec_caps.codec = SND_AUDIOCODEC_AAC;
++
++	if (_get_codec_caps(fd, &codec_caps) < 0)
++		goto endofsupport;
++
++	for (i = 0; i < codec_caps.num_descriptors; i++) {
++		if (codec_caps.descriptor[i].modes & mode) {
++			ret = true;
++			goto endofsupport;
++		}
++	}
++
++endofsupport:
++	close(fd);
++	return ret;
++}
+-- 
+2.18.0
+
diff --git a/meta/meta-mediatek/recipes-multimedia/tinycompress/tinycompress/0008-cplay-add-hostless-mode-support.patch b/meta/meta-mediatek/recipes-multimedia/tinycompress/tinycompress/0008-cplay-add-hostless-mode-support.patch
new file mode 100644
index 0000000..198810b
--- /dev/null
+++ b/meta/meta-mediatek/recipes-multimedia/tinycompress/tinycompress/0008-cplay-add-hostless-mode-support.patch
@@ -0,0 +1,122 @@
+From 2d15d53d4e6775edddcf3980e98a88bc53552fff Mon Sep 17 00:00:00 2001
+From: Hidalgo Huang <hidalgo.huang@mediatek.com>
+Date: Mon, 23 Dec 2019 16:45:26 +0800
+Subject: [PATCH 8/9] cplay: add hostless mode support
+
+E.g. cplay -c 0 -d 27 -H -T 1000 /data/misc/mtk-audio-patterns/sample.mp3
+
+Signed-off-by: Hidalgo Huang <hidalgo.huang@mediatek.com>
+---
+ src/utils/cplay.c | 36 ++++++++++++++++++++++++++++++++----
+ 1 file changed, 32 insertions(+), 4 deletions(-)
+
+diff --git a/src/utils/cplay.c b/src/utils/cplay.c
+index 6dc3096..2198409 100644
+--- a/src/utils/cplay.c
++++ b/src/utils/cplay.c
+@@ -118,6 +118,8 @@ static void usage(void)
+ 		"-R\tspecify sample rate\n\n"
+ 		"-C\tspecify channel count\n\n"
+ 		"-L\tlow power mode\n\n"
++		"-H\thostless mode\n\n"
++		"-T\thostless play time in seconds\n\n"
+ 		"Example:\n"
+ 		"\tcplay -c 1 -d 2 test.mp3\n"
+ 		"\tcplay -f 5 test.mp3\n\n"
+@@ -135,7 +137,7 @@ static void usage(void)
+ void play_samples(char *name, unsigned int card, unsigned int device,
+ 		unsigned long buffer_size, unsigned int frag,
+ 		unsigned long codec_id, unsigned int rate,
+-		unsigned int channels);
++		unsigned int channels, int hostless, unsigned int play_time);
+ 
+ struct mp3_header {
+ 	uint16_t sync;
+@@ -361,12 +363,14 @@ int main(int argc, char **argv)
+ 	unsigned int codec_id = SND_AUDIOCODEC_MP3;
+ 	unsigned int rate = 0, channels = 0;
+ 	int low_power = 0;
++	int hostless = 0;
++	unsigned int play_time = 10;
+ 
+ 	if (argc < 2)
+ 		usage();
+ 
+ 	verbose = 0;
+-	while ((c = getopt(argc, argv, "hvb:f:c:d:I:R:C:L")) != -1) {
++	while ((c = getopt(argc, argv, "hvb:f:c:d:I:R:C:LHT:")) != -1) {
+ 		switch (c) {
+ 		case 'h':
+ 			usage();
+@@ -414,6 +418,12 @@ int main(int argc, char **argv)
+ 		case 'L':
+ 			low_power = 1;
+ 			break;
++		case 'H':
++			hostless = 1;
++			break;
++		case 'T':
++			play_time = strtol(optarg, NULL, 10);
++			break;
+ 		default:
+ 			exit(EXIT_FAILURE);
+ 		}
+@@ -432,7 +442,7 @@ int main(int argc, char **argv)
+ 		}
+ 	}
+ 
+-	play_samples(file, card, device, buffer_size, frag, codec_id, rate, channels);
++	play_samples(file, card, device, buffer_size, frag, codec_id, rate, channels, hostless, play_time);
+ 
+ 	fprintf(stderr, "Finish Playing.... Close Normally\n");
+ 	exit(EXIT_SUCCESS);
+@@ -547,7 +557,7 @@ void get_codec_sbc(FILE *file, struct compr_config *config,
+ void play_samples(char *name, unsigned int card, unsigned int device,
+ 		unsigned long buffer_size, unsigned int frag,
+ 		unsigned long codec_id, unsigned int rate,
+-		unsigned int channels)
++		unsigned int channels, int hostless, unsigned int play_time)
+ {
+ 	struct compr_config config;
+ 	struct snd_codec codec;
+@@ -592,6 +602,11 @@ void play_samples(char *name, unsigned int card, unsigned int device,
+ 	}
+ 	config.codec = &codec;
+ 
++	if (hostless) {
++		codec.reserved[2] &= 0xffff0000;
++		codec.reserved[2] |= 0x6c68;
++	}
++
+ 	compress = compress_open(card, device, COMPRESS_IN, &config);
+ 	if (!compress || !is_compress_ready(compress)) {
+ 		fprintf(stderr, "Unable to open Compress device %d:%d\n",
+@@ -601,6 +616,13 @@ void play_samples(char *name, unsigned int card, unsigned int device,
+ 	};
+ 	if (verbose)
+ 		printf("%s: Opened compress device\n", __func__);
++
++	if (hostless) {
++		compress_start(compress);
++		sleep(play_time);
++		goto HOSTLESS_EXIT;
++	}
++
+ 	size = config.fragments * config.fragment_size;
+ 	buffer = malloc(size);
+ 	if (!buffer) {
+@@ -670,5 +692,11 @@ FILE_EXIT:
+ 	if (verbose)
+ 		printf("%s: exit failure\n", __func__);
+ 	exit(EXIT_FAILURE);
++HOSTLESS_EXIT:
++	if (verbose)
++		printf("%s: hostless exit success\n", __func__);
++	compress_drain(compress);
++	fclose(file);
++	compress_close(compress);
+ }
+ 
+-- 
+2.18.0
+
diff --git a/meta/meta-mediatek/recipes-multimedia/tinycompress/tinycompress/0009-cplay-add-xrun-recovery-support.patch b/meta/meta-mediatek/recipes-multimedia/tinycompress/tinycompress/0009-cplay-add-xrun-recovery-support.patch
new file mode 100644
index 0000000..102e241
--- /dev/null
+++ b/meta/meta-mediatek/recipes-multimedia/tinycompress/tinycompress/0009-cplay-add-xrun-recovery-support.patch
@@ -0,0 +1,161 @@
+From a9cd8f898d032098921b7ee8baee7e407bea7ab2 Mon Sep 17 00:00:00 2001
+From: Hidalgo Huang <hidalgo.huang@mediatek.com>
+Date: Tue, 23 Jun 2020 19:54:58 +0800
+Subject: [PATCH 9/9] cplay: add xrun recovery support
+
+E.g. cplay -c 0 -d 24 -L -x /data/misc/mtk-audio-patterns/sample.mp3
+
+Signed-off-by: Hidalgo Huang <hidalgo.huang@mediatek.com>
+---
+ src/lib/compress.c | 12 ++++++++++--
+ src/utils/cplay.c  | 33 ++++++++++++++++++++++++++++-----
+ 2 files changed, 38 insertions(+), 7 deletions(-)
+
+diff --git a/src/lib/compress.c b/src/lib/compress.c
+index e2644ea..a268b26 100644
+--- a/src/lib/compress.c
++++ b/src/lib/compress.c
+@@ -110,6 +110,9 @@ static int oops(struct compress *compress, int e, const char *fmt, ...)
+ 		": %s", strerror(e));
+ 	errno = e;
+ 
++	if (e == EPIPE)
++		return -e;
++
+ 	return -1;
+ }
+ 
+@@ -340,7 +343,7 @@ int compress_write(struct compress *compress, const void *buf, unsigned int size
+ 	if (!is_compress_ready(compress))
+ 		return oops(compress, ENODEV, "device not ready");
+ 	fds.fd = compress->fd;
+-	fds.events = POLLOUT;
++	fds.events = POLLOUT | POLLNVAL;
+ 
+ 	/*TODO: treat auto start here first */
+ 	while (size) {
+@@ -356,6 +359,9 @@ int compress_write(struct compress *compress, const void *buf, unsigned int size
+ 				return total;
+ 
+ 			ret = poll(&fds, 1, compress->max_poll_wait_ms);
++			if (fds.revents & POLLNVAL) {
++				return oops(compress, EPIPE, "poll returned nval!");
++			}
+ 			if (fds.revents & POLLERR) {
+ 				return oops(compress, EIO, "poll returned error!");
+ 			}
+@@ -595,10 +601,12 @@ int compress_wait(struct compress *compress, int timeout_ms)
+ 	int ret;
+ 
+ 	fds.fd = compress->fd;
+-	fds.events = POLLOUT | POLLIN;
++	fds.events = POLLOUT | POLLIN | POLLNVAL;
+ 
+ 	ret = poll(&fds, 1, timeout_ms);
+ 	if (ret > 0) {
++		if (fds.revents & POLLNVAL)
++			return oops(compress, EIO, "poll returned nval!");
+ 		if (fds.revents & POLLERR)
+ 			return oops(compress, EIO, "poll returned error!");
+ 		if (fds.revents & (POLLOUT | POLLIN))
+diff --git a/src/utils/cplay.c b/src/utils/cplay.c
+index 2198409..85c12c2 100644
+--- a/src/utils/cplay.c
++++ b/src/utils/cplay.c
+@@ -120,6 +120,7 @@ static void usage(void)
+ 		"-L\tlow power mode\n\n"
+ 		"-H\thostless mode\n\n"
+ 		"-T\thostless play time in seconds\n\n"
++		"-x\tdo xrun recovery\n\n"
+ 		"Example:\n"
+ 		"\tcplay -c 1 -d 2 test.mp3\n"
+ 		"\tcplay -f 5 test.mp3\n\n"
+@@ -137,7 +138,8 @@ static void usage(void)
+ void play_samples(char *name, unsigned int card, unsigned int device,
+ 		unsigned long buffer_size, unsigned int frag,
+ 		unsigned long codec_id, unsigned int rate,
+-		unsigned int channels, int hostless, unsigned int play_time);
++		unsigned int channels, int hostless, unsigned int play_time,
++		int xrun_recovery);
+ 
+ struct mp3_header {
+ 	uint16_t sync;
+@@ -365,12 +367,13 @@ int main(int argc, char **argv)
+ 	int low_power = 0;
+ 	int hostless = 0;
+ 	unsigned int play_time = 10;
++	int xrun_recovery = 0;
+ 
+ 	if (argc < 2)
+ 		usage();
+ 
+ 	verbose = 0;
+-	while ((c = getopt(argc, argv, "hvb:f:c:d:I:R:C:LHT:")) != -1) {
++	while ((c = getopt(argc, argv, "hvb:f:c:d:I:R:C:LHT:x")) != -1) {
+ 		switch (c) {
+ 		case 'h':
+ 			usage();
+@@ -424,6 +427,9 @@ int main(int argc, char **argv)
+ 		case 'T':
+ 			play_time = strtol(optarg, NULL, 10);
+ 			break;
++		case 'x':
++			xrun_recovery = 1;
++			break;
+ 		default:
+ 			exit(EXIT_FAILURE);
+ 		}
+@@ -442,7 +448,7 @@ int main(int argc, char **argv)
+ 		}
+ 	}
+ 
+-	play_samples(file, card, device, buffer_size, frag, codec_id, rate, channels, hostless, play_time);
++	play_samples(file, card, device, buffer_size, frag, codec_id, rate, channels, hostless, play_time, xrun_recovery);
+ 
+ 	fprintf(stderr, "Finish Playing.... Close Normally\n");
+ 	exit(EXIT_SUCCESS);
+@@ -557,7 +563,8 @@ void get_codec_sbc(FILE *file, struct compr_config *config,
+ void play_samples(char *name, unsigned int card, unsigned int device,
+ 		unsigned long buffer_size, unsigned int frag,
+ 		unsigned long codec_id, unsigned int rate,
+-		unsigned int channels, int hostless, unsigned int play_time)
++		unsigned int channels, int hostless, unsigned int play_time,
++		int xrun_recovery)
+ {
+ 	struct compr_config config;
+ 	struct snd_codec codec;
+@@ -659,6 +666,21 @@ void play_samples(char *name, unsigned int card, unsigned int device,
+ 		num_read = fread(buffer, 1, size, file);
+ 		if (num_read > 0) {
+ 			wrote = compress_write(compress, buffer, num_read);
++			if (wrote == -EPIPE) {
++				fprintf(stderr, "Try to recover %s ...\n", compress_get_error(compress));
++				compress_close(compress);
++				compress = 0;
++				compress = compress_open(card, device, COMPRESS_IN, &config);
++				if (!compress || !is_compress_ready(compress)) {
++					fprintf(stderr, "Unable to recover Compress device %d:%d\n",
++						card, device);
++					fprintf(stderr, "ERR: %s\n", compress_get_error(compress));
++					goto BUF_EXIT;
++				}
++				wrote = compress_write(compress, buffer, num_read);
++				if (wrote > 0)
++					compress_start(compress);
++			}
+ 			if (wrote < 0) {
+ 				fprintf(stderr, "Error playing sample\n");
+ 				fprintf(stderr, "ERR: %s\n", compress_get_error(compress));
+@@ -686,7 +708,8 @@ void play_samples(char *name, unsigned int card, unsigned int device,
+ BUF_EXIT:
+ 	free(buffer);
+ COMP_EXIT:
+-	compress_close(compress);
++	if (compress)
++		compress_close(compress);
+ FILE_EXIT:
+ 	fclose(file);
+ 	if (verbose)
+-- 
+2.18.0
+