SmartAudio/package/allwinner/tina_multimedia/libcedarx/demo/demoAdecoder/tinyplaydemo.c

578 lines
17 KiB
C
Executable File

/*
* Copyright (c) 2008-2017 Allwinner Technology Co. Ltd.
* All rights reserved.
*
* File : tinyplaydemo.c
* Description : demoAdecoder
* History :
*
*/
#include "tinyplaydemo.h"
#include "demo_utils.h"
#include <fcntl.h>
#ifdef LOG_TAG
#undef LOG_TAG
#define LOG_TAG "Tinyplaydemo"
#endif
#define DEMO_DEBUG 1
#define ID_RIFF 0x46464952
#define ID_WAVE 0x45564157
#define ID_FMT 0x20746d66
#define ID_DATA 0x61746164
typedef struct name_map_t
{
char name_linux[32];
char name_android[32];
}name_map;
#define AUDIO_MAP_CNT 16
#define AUDIO_NAME_CODEC "AUDIO_CODEC"
#define AUDIO_NAME_HDMI "AUDIO_HDMI"
#define AUDIO_NAME_SPDIF "AUDIO_SPDIF"
#define AUDIO_NAME_I2S "AUDIO_I2S"
#define AUDIO_NAME_RT3261 "AUDIO_CODEC_RT"
#define AUDIO_NAME_RT3261_RAW "RT3261_RAW"
#define AUDIO_NAME_MIX "AUDIO_MIX"
#define AUDIO_NAME_BT "AUDIO_BT"
static name_map audio_name_map[AUDIO_MAP_CNT] =
{
{"snddaudio", AUDIO_NAME_CODEC},//A80
{"audiocodec", AUDIO_NAME_CODEC},//A31,A20
{"sndacx00codec", AUDIO_NAME_CODEC},//H6
{"sndhdmi", AUDIO_NAME_HDMI},
{"rt3261aif2", AUDIO_NAME_RT3261_RAW},
{"sndspdif", AUDIO_NAME_SPDIF},
{"rt3261", AUDIO_NAME_RT3261},
{"snddaudio2", AUDIO_NAME_BT},
{"sndahub", AUDIO_NAME_MIX},
};
enum SND_AUIDO_RAW_DATA_TYPE
{
SND_AUDIO_RAW_DATA_UNKOWN = 0,
SND_AUDIO_RAW_DATA_PCM = 1,
SND_AUDIO_RAW_DATA_AC3 = 2,
SND_AUDIO_RAW_DATA_MPEG1 = 3,
SND_AUDIO_RAW_DATA_MP3 = 4,
SND_AUDIO_RAW_DATA_MPEG2 = 5,
SND_AUDIO_RAW_DATA_AAC = 6,
SND_AUDIO_RAW_DATA_DTS = 7,
SND_AUDIO_RAW_DATA_ATRAC = 8,
SND_AUDIO_RAW_DATA_ONE_BIT_AUDIO = 9,
SND_AUDIO_RAW_DATA_DOLBY_DIGITAL_PLUS = 10,
SND_AUDIO_RAW_DATA_DTS_HD = 11,
SND_AUDIO_RAW_DATA_MAT = 12,
SND_AUDIO_RAW_DATA_DST = 13,
SND_AUDIO_RAW_DATA_WMAPRO = 14
};
struct riff_wave_header {
uint32_t riff_id;
uint32_t riff_sz;
uint32_t wave_id;
};
struct chunk_header {
uint32_t id;
uint32_t sz;
};
struct chunk_fmt {
uint16_t audio_format;
uint16_t num_channels;
uint32_t sample_rate;
uint32_t byte_rate;
uint16_t block_align;
uint16_t bits_per_sample;
};
static int find_name_map(AudioDsp *adev, char * in, char * out)
{
int index = 0;
CDX_UNUSE(adev);
if (in == 0 || out == 0)
{
demo_loge("error params");
return -1;
}
for (; index < AUDIO_MAP_CNT; index++)
{
if (strlen(audio_name_map[index].name_linux) == 0)
{
//sprintf(out, "AUDIO_USB%d", adev->usb_audio_cnt++);
sprintf(out, "AUDIO_USB_%s", in);
strcpy(audio_name_map[index].name_linux, in);
strcpy(audio_name_map[index].name_android, out);
demo_logd("linux name = %s, android name = %s",
audio_name_map[index].name_linux,
audio_name_map[index].name_android);
return 0;
}
if (!strcmp(in, audio_name_map[index].name_linux))
{
strcpy(out, audio_name_map[index].name_android);
demo_logd("linux name = %s, android name = %s",
audio_name_map[index].name_linux,
audio_name_map[index].name_android);
return 0;
}
}
return 0;
}
static int do_init_audio_card(AudioDsp *adev, int card)
{
int ret = -1;
int fd = 0;
char * snd_path = "/sys/class/sound";
char snd_card[128], snd_node[128];
char snd_id[32], snd_name[32];
memset(snd_card, 0, sizeof(snd_card));
memset(snd_node, 0, sizeof(snd_node));
memset(snd_id, 0, sizeof(snd_id));
memset(snd_name, 0, sizeof(snd_name));
sprintf(snd_card, "%s/card%d", snd_path, card);
ret = access(snd_card, F_OK);
if(ret == 0)
{
// id / name
sprintf(snd_node, "%s/card%d/id", snd_path, card);
demo_logd("1... read card %s/card%d/id",snd_path, card);
fd = open(snd_node, O_RDONLY);
if (fd > 0)
{
ret = read(fd, snd_id, sizeof(snd_id));
if (ret > 0)
{
snd_id[ret - 1] = '\0';
demo_logd("2.... %s, %s, card: %d", snd_node, snd_id, card);
}
close(fd);
}
else
{
demo_logd("3.... fd fail ....%s, %s, len: %d", snd_node, snd_id, card);
return -1;
}
strcpy(adev->dev_manager[card].card_id, snd_id);
find_name_map(adev, snd_id, snd_name);
strcpy(adev->dev_manager[card].name, snd_name);
adev->dev_manager[card].card = card;
adev->dev_manager[card].device = 0;
adev->dev_manager[card].flag_exist = true;
// playback device
sprintf(snd_node, "%s/card%d/pcmC%dD0p", snd_path, card, card);
ret = access(snd_node, F_OK);
if(ret == 0)
{
// there is a playback device
adev->dev_manager[card].flag_out = AUDIO_OUT;
adev->dev_manager[card].flag_out_active = 0;
}
// capture device
sprintf(snd_node, "%s/card%d/pcmC%dD0c", snd_path, card, card);
ret = access(snd_node, F_OK);
if(ret == 0)
{
// there is a capture device
adev->dev_manager[card].flag_in = AUDIO_IN;
adev->dev_manager[card].flag_in_active = 0;
}
}
else
{
return -1;
}
return 0;
}
static void init_audio_devices(AudioDsp *adev)
{
int card = 0;
memset(adev->dev_manager, 0, sizeof(adev->dev_manager));
for (card = 0; card < MAX_AUDIO_DEVICES; card++)
{
if (do_init_audio_card(adev, card) == 0)
{
// break;
demo_logd("card: %d, name: %s, capture: %d, playback: %d",
card, adev->dev_manager[card].name,
adev->dev_manager[card].flag_in == AUDIO_IN,
adev->dev_manager[card].flag_out == AUDIO_OUT);
}
}
}
static void getCardNumbyName(AudioDsp *adev, char *name, int *card)
{
int index;
for (index = 0; index < MAX_AUDIO_DEVICES; index++) {
if (!strcmp(adev->dev_manager[index].name, name)) {
*card = index;
demo_logd("getCardNumbyName: name = %s , card = %d",name, index);
demo_logd("NAME = %s",adev->dev_manager[index].name);
return;
}
}
for (index = 0; index < MAX_AUDIO_DEVICES; index++) {
if (!strncmp(adev->dev_manager[index].name, "AUDIO_USB", 9)
&& !strncmp(name, "AUDIO_USB", 9)
&& adev->dev_manager[index].flag_exist) {
*card = index;
demo_logd("USBNAME = %s",adev->dev_manager[index].name);
demo_logd("getCardNumbyName: name = %s , card = %d",name, index);
break;
}
}
demo_logd("card 0 name = %s",adev->dev_manager[0].name);
if (index == MAX_AUDIO_DEVICES) {
demo_logd("BT");
*card = -1;
demo_loge("%s card does not exist",name);
}
}
#ifdef H6_AUDIO_HUB
void enble_hub_hdmi(struct mixer *mixer)
{
demo_logd("enble_hub_hdmi");
struct mixer_ctl *ctl;
//i2s1->APBIF_TXDIF0
ctl = mixer_get_ctl_by_name(mixer, "I2S1 Src Select");
mixer_ctl_set_value(ctl, 0, 1);
//enble i2s1
ctl = mixer_get_ctl_by_name(mixer, "I2S1OUT Switch");
mixer_ctl_set_value(ctl, 0, 1);
}
void close_hub_hdmi(struct mixer *mixer)
{
demo_logd("close_hub_hdmi");
struct mixer_ctl *ctl;
//i2s1->APBIF_TXDIF0
ctl = mixer_get_ctl_by_name(mixer, "I2S1 Src Select");
mixer_ctl_set_value(ctl, 0, 0);
//close i2s1
ctl = mixer_get_ctl_by_name(mixer, "I2S1OUT Switch");
mixer_ctl_set_value(ctl, 0, 0);
}
static int set_ahub_rontiue(int ahub_card_id, const char* name, int on_off)
{
struct mixer *audio_hub_mixer = mixer_open(ahub_card_id);
if(!audio_hub_mixer)
{
demo_loge("Unable to open the audio_hub_mixer, aborting...");
return -1;
}
//Now only fix the HDMI scenoris
if(on_off != 0)//enable...
{
if(!strcmp(name, AUDIO_NAME_HDMI))
{
demo_logi("ahub enable hdmi hub...");
enble_hub_hdmi(audio_hub_mixer);
}
}
else//shut down...
{
if(!strcmp(name, AUDIO_NAME_HDMI))
{
demo_logi("ahub shut down hdmi hub...");
close_hub_hdmi(audio_hub_mixer);
}
}
mixer_close(audio_hub_mixer);
audio_hub_mixer = NULL;
return 0;
}
#endif
static int set_raw_flag(AudioDsp* dsp, int card, int raw_flag)
{
demo_logi("set_raw_flag(card=%d, raw_flag=%d)", card, raw_flag);
struct mixer *mixer = mixer_open(card);
if (!mixer) {
demo_loge("Unable to open the mixer, aborting...");
return -1;
}
const char *control_name = (card == dsp->cardHDMI) ? "hdmi audio format Function":
(card == dsp->cardMIX) ? "ahub audio format Function":
"spdif audio format Function";
demo_logi("control_name : %s, card : %d", control_name, card);
const char *control_value = (raw_flag==SND_AUDIO_RAW_DATA_AC3) ? "AC3" :
(raw_flag==SND_AUDIO_RAW_DATA_DOLBY_DIGITAL_PLUS) ? "DOLBY_DIGITAL_PLUS":
(raw_flag==SND_AUDIO_RAW_DATA_MAT) ? "MAT":
(raw_flag==SND_AUDIO_RAW_DATA_DTS) ? "DTS" : "pcm";
struct mixer_ctl *audio_format = mixer_get_ctl_by_name(mixer, control_name);
if (audio_format)
mixer_ctl_set_enum_by_string(audio_format, control_value);
mixer_close(mixer);
return 0;
}
int check_param(struct pcm_params *params, unsigned int param, unsigned int value,
char *param_name, char *param_unit)
{
unsigned int min;
unsigned int max;
int is_within_bounds = 1;
min = pcm_params_get_min(params, param);
if (value < min) {
demo_loge("%s is %u%s, device only supports >= %u%s", param_name, value,
param_unit, min, param_unit);
is_within_bounds = 0;
}
max = pcm_params_get_max(params, param);
if (value > max) {
demo_loge("%s is %u%s, device only supports <= %u%s", param_name, value,
param_unit, max, param_unit);
is_within_bounds = 0;
}
return is_within_bounds;
}
static int sample_is_playable(unsigned int card, unsigned int device, unsigned int channels,
unsigned int rate, unsigned int bits, unsigned int period_size,
unsigned int period_count)
{
struct pcm_params *params;
int can_play;
demo_loge("line : %d, card:%u, device:%u",__LINE__, card, device);
params = pcm_params_get(card, device, PCM_OUT);
if (params == NULL) {
demo_loge("Unable to open PCM device %u", device);
return 0;
}
demo_loge("line : %d, card:%u, device:%u",__LINE__, card, device);
can_play = check_param(params, PCM_PARAM_RATE, rate, "Sample rate", "Hz");
can_play &= check_param(params, PCM_PARAM_CHANNELS, channels, "Sample", " channels");
can_play &= check_param(params, PCM_PARAM_SAMPLE_BITS, bits, "Bitrate", " bits");
can_play &= check_param(params, PCM_PARAM_PERIOD_SIZE, period_size, "Period size", "Hz");
can_play &= check_param(params, PCM_PARAM_PERIODS, period_count, "Period count", "Hz");
pcm_params_free(params);
return can_play;
}
int DspWrite(AudioDsp* dsp, void *pPcmData, int nPcmDataLen)
{
void* buf_conv = NULL;
int buf_conv_len = 0;
int samples = 0;
if(!dsp)
return -1;
if(!dsp->start)
{
dsp->config.channels = dsp->ch;
dsp->config.rate = dsp->spr;
dsp->config.period_size = dsp->period_size;
dsp->config.period_count = dsp->period_count;
dsp->config.raw_flag = dsp->raw_flag;
if (dsp->bps == 32)
dsp->config.format = PCM_FORMAT_S32_LE;
else if (dsp->bps == 24)
dsp->config.format = PCM_FORMAT_S24_LE;
else
dsp->config.format = PCM_FORMAT_S16_LE;
demo_logi("dsp->bps : %d", dsp->bps);
dsp->config.start_threshold = 0;
dsp->config.stop_threshold = 0;
dsp->config.silence_threshold = 0;
if(set_raw_flag(dsp, dsp->cardHDMI, dsp->raw_flag) < 0){
demo_loge("can not set raw flag...");
return -1;
}
demo_logi("hdmi , raw_flag : %d, ch : %d, spr : %d, period_size : %d, period_count : %d",
dsp->config.raw_flag, dsp->config.channels , dsp->config.rate, dsp->config.period_size,
dsp->config.period_count);
#ifdef H6_AUDIO_HUB
dsp->hubconfig = dsp->config;
if(set_raw_flag(dsp, dsp->cardMIX, dsp->raw_flag) < 0){
demo_loge("can not set raw flag...");
return -1;
}
demo_logi("ahub , raw_flag : %d, ch : %d, spr : %d, period_size : %d, period_count : %d",
dsp->hubconfig.raw_flag, dsp->hubconfig.channels , dsp->hubconfig.rate,
dsp->hubconfig.period_size, dsp->hubconfig.period_count);
set_ahub_rontiue(dsp->cardMIX, AUDIO_NAME_HDMI, 1);
dsp->pcmhub = pcm_open(dsp->cardMIX, dsp->device, PCM_OUT, &dsp->hubconfig);
if (!dsp->pcmhub || !pcm_is_ready(dsp->pcmhub)) {
demo_loge("Unable to open PCM device %d (%s)\n",
dsp->device, pcm_get_error(dsp->pcmhub));
return -1;
}
#else
dsp->pcm = pcm_open(dsp->cardHDMI, dsp->device, PCM_OUT, &dsp->config);
if (!dsp->pcm || !pcm_is_ready(dsp->pcm)) {
demo_loge("Unable to open PCM device %u (%s)\n",
dsp->device, pcm_get_error(dsp->pcm));
return -1;
}
#endif
dsp->start = 1;
}
if(nPcmDataLen > 0)
{
if (dsp->bps == 24)
{
int idx = 0, jdx = 0;
char* dst = NULL;
char* src = NULL;
samples = nPcmDataLen * 8/ dsp->ch / dsp->bps;
buf_conv_len = nPcmDataLen*4/3;
DEMO_VERBOS_SAFE_MALLOC(buf_conv, buf_conv_len,
demo_loge("Error no mem for conventer buffer...");\
return -1;
)
dst = (char*)buf_conv;
for(idx = 0; idx < dsp->ch; idx++)
{
dst = ((char*)buf_conv) + 4*idx;
src = ((char*)pPcmData) + 3*idx;
for(jdx = 0; jdx < samples; jdx++){
dst[0] = src[0]&0xff;
dst[1] = src[1]&0xff;
dst[2] = src[2]&0xff;
dst[3] = (dst[2]&0x80)?0xff:0x00;
dst += 4*dsp->ch;
src += 3*dsp->ch;
}
}
#ifdef H6_AUDIO_HUB
if (pcm_write(dsp->pcmhub, buf_conv, buf_conv_len) < 0)
#else
if (pcm_write(dsp->pcm, buf_conv, buf_conv_len) < 0)
#endif
{
demo_loge("Error playing sample...");
DEMO_SAFE_FREE(buf_conv, "buf_conv", 0)
return -1;
}
DEMO_SAFE_FREE(buf_conv, "buf_conv", 0)
}
else
{
#ifdef H6_AUDIO_HUB
if (pcm_write(dsp->pcmhub, pPcmData, nPcmDataLen) < 0)
#else
if (pcm_write(dsp->pcm, pPcmData, nPcmDataLen) < 0)
#endif
{
demo_loge("Error playing sample...");
return -1;
}
}
}
else
demo_loge("Invaild write len : %d", nPcmDataLen);
return nPcmDataLen;
}
int DspStop(AudioDsp* dsp)
{
if(!dsp)
return -1;
if(dsp->start)
{
#ifdef H6_AUDIO_HUB
if(dsp->pcmhub)
{
pcm_close(dsp->pcmhub);
dsp->pcmhub = NULL;
set_ahub_rontiue(dsp->cardMIX, AUDIO_NAME_HDMI, 0);
demo_logi("Dsp pcmhub device closed ...");
}
#else
if(dsp->pcm)
{
pcm_close(dsp->pcm);
dsp->pcm = NULL;
demo_logi("Dsp pcm device closed ...");
}
#endif
dsp->start = 0;
}
else
{
demo_logd("dsp stop while unactive...");
}
return 0;
}
void DspWaitForDevConsume(int waitms)
{
usleep(waitms * 1000);
}
extern void NotifyHalDirect(int on_off);
AudioDsp* CreateAudioDsp()
{
AudioDsp* pMem = NULL;
DEMO_VERBOS_SAFE_MALLOC(pMem, sizeof(AudioDsp),
demo_loge("CreateAudioDsp fail for no mem...");\
return NULL;
);
NotifyHalDirect(1);
init_audio_devices(pMem);
getCardNumbyName(pMem, AUDIO_NAME_CODEC, &pMem->cardCODEC);
getCardNumbyName(pMem, AUDIO_NAME_HDMI, &pMem->cardHDMI);
getCardNumbyName(pMem, AUDIO_NAME_SPDIF, &pMem->cardSPDIF);
getCardNumbyName(pMem, AUDIO_NAME_BT, &pMem->cardBT);
getCardNumbyName(pMem, AUDIO_NAME_MIX, &pMem->cardMIX);
demo_logi("cardCODEC : %d, cardHDMI: %d, cardSPDIF: %d, cardBT: %d, cardMIX: %d",
pMem->cardCODEC, pMem->cardHDMI, pMem->cardSPDIF, pMem->cardBT, pMem->cardMIX);
return pMem;
}
void DeleteAudioDsp(AudioDsp* dsp)
{
AudioDsp* pMem = NULL;
pMem = dsp;
if(!pMem)
{
demo_loge("DeleteAudioDsp strange for null ptr...");
return;
}
DspStop(pMem);
NotifyHalDirect(0);
DEMO_SAFE_FREE(pMem, "AudioDsp", 1)
}