[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(¶ms, 0, sizeof(struct snd_compr_params));
+ memcpy(compress->config, config, sizeof(*compress->config));
+ fill_compress_params(config, ¶ms);
+
+--
+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(¶ms->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
+