486 lines
10 KiB
C
486 lines
10 KiB
C
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "ql_rtos.h"
|
|
#include "ql_application.h"
|
|
#include "ql_audio.h"
|
|
#include "ql_iic.h"
|
|
#include "ql_gpio.h"
|
|
#include "ql_fs.h"
|
|
|
|
#include "webclient.h"
|
|
#include <netdb.h>
|
|
#include "sockets.h"
|
|
#include "mp3dec.h"
|
|
#include "test_mp3.h"
|
|
|
|
#define RLOGD printf
|
|
struct webclient_session *session = NULL;
|
|
static int pos_length,total_length = 0;
|
|
|
|
static Mp3PlaybackHandle mp3_handle;
|
|
static Mp3PlayConfigInfo mp3_configInfo;
|
|
static unsigned char mp3_player_status = 0;
|
|
QFILE *local_mp3_file_fd=NULL;
|
|
|
|
static int mp3_player_end_frame = 0;
|
|
|
|
int current_sample_rate = 0;
|
|
static audio_track_handle track_hd;
|
|
|
|
static unsigned short pcm_buff[1152*2]={0x00};
|
|
|
|
struct mp3_decoder
|
|
{
|
|
/* mp3 information */
|
|
HMP3Decoder decoder;
|
|
MP3FrameInfo frame_info;
|
|
// rt_uint32_t frames;
|
|
|
|
/* mp3 read session */
|
|
uint8_t *read_buffer, *read_ptr;
|
|
u32 bytes_left;
|
|
|
|
};
|
|
|
|
static void mp3_decoder_track_callback(acm_audio_track_handle handle, acm_audio_track_event_t event)
|
|
{
|
|
if(mp3_player_status==1 && mp3_player_end_frame==1){
|
|
if(event == AUDIO_TRACK_EVENT_UNDERRUN){
|
|
printf("AUDIO_TRACK_EVENT_UNDERRUN\r\n");
|
|
mp3_player_status = 2;//
|
|
}
|
|
}
|
|
|
|
if(mp3_player_status==2){
|
|
if(event == AUDIO_TRACK_EVENT_DRAINING){
|
|
printf("AUDIO_TRACK_EVENT_DRAINING\r\n");
|
|
mp3_player_status = 3;//
|
|
}
|
|
}
|
|
}
|
|
|
|
void mp3_decoder_init(struct mp3_decoder* decoder)
|
|
{
|
|
/* init read session */
|
|
decoder->read_ptr = NULL;
|
|
decoder->bytes_left = 0;
|
|
|
|
decoder->decoder = MP3InitDecoder();
|
|
}
|
|
|
|
void mp3_decoder_detach(struct mp3_decoder* decoder)
|
|
{
|
|
/* release mp3 decoder */
|
|
MP3FreeDecoder(decoder->decoder);
|
|
}
|
|
|
|
struct mp3_decoder* mp3_decoder_create()
|
|
{
|
|
struct mp3_decoder* decoder;
|
|
|
|
/* allocate object */
|
|
decoder = (struct mp3_decoder*) malloc(sizeof(struct mp3_decoder));
|
|
if (decoder != NULL)
|
|
{
|
|
mp3_decoder_init(decoder);
|
|
}
|
|
|
|
return decoder;
|
|
}
|
|
|
|
void mp3_decoder_delete(struct mp3_decoder* decoder)
|
|
{
|
|
/* de-init mp3 decoder object */
|
|
mp3_decoder_detach(decoder);
|
|
/* release this object */
|
|
free(decoder);
|
|
decoder = NULL;
|
|
}
|
|
|
|
|
|
static int check_mp3_sync_word(struct mp3_decoder *codec)
|
|
{
|
|
int err;
|
|
|
|
memset(&codec->frame_info, 0, sizeof(MP3FrameInfo));
|
|
|
|
err = MP3GetNextFrameInfo(codec->decoder, &codec->frame_info, codec->read_ptr);
|
|
if (err == ERR_MP3_INVALID_FRAMEHEADER)
|
|
{
|
|
goto __err;
|
|
}
|
|
else if (err != ERR_MP3_NONE)
|
|
{
|
|
goto __err;
|
|
}
|
|
else if (codec->frame_info.nChans != 1 && codec->frame_info.nChans != 2)
|
|
{
|
|
goto __err;
|
|
}
|
|
else if (codec->frame_info.bitsPerSample != 16 && codec->frame_info.bitsPerSample != 8)
|
|
{
|
|
goto __err;
|
|
}
|
|
|
|
return 0;
|
|
|
|
__err:
|
|
return -1;
|
|
}
|
|
|
|
int mp3_decoder_run(struct mp3_decoder* decoder)
|
|
{
|
|
int err;
|
|
int read_offset = 0;;
|
|
|
|
// rt_kprintf("decoder->bytes_left:%d,mp3_player_end_frame:%d\n", decoder->bytes_left,mp3_player_end_frame);
|
|
extern int tts_playing;
|
|
if(tts_playing==2){
|
|
return -1;
|
|
}
|
|
|
|
if ((decoder->read_ptr == NULL) || decoder->bytes_left < 2 * MAINBUF_SIZE)
|
|
{
|
|
mp3_player_end_frame = 1;
|
|
}
|
|
|
|
// printf("mp3_player_end_frame:%d,decoder->bytes_left:%d\n", mp3_player_end_frame, decoder->bytes_left);
|
|
|
|
if(mp3_player_end_frame&& (decoder->bytes_left==0)){
|
|
//mp3_player_end_frame = 0;
|
|
return -1;
|
|
}
|
|
|
|
//loop_find:
|
|
// rt_kprintf("read offset: 0x%08x\n", decoder->read_ptr - decoder->read_buffer);
|
|
read_offset = MP3FindSyncWord(decoder->read_ptr, decoder->bytes_left);
|
|
if (read_offset < 0)
|
|
{
|
|
//if(mp3_decoder_fill_buffer(decoder) == 0) goto loop_find;
|
|
|
|
/* discard this data */
|
|
RLOGD("outof sync, byte left: %d\n", decoder->bytes_left);
|
|
|
|
decoder->bytes_left = 0;
|
|
return 0;
|
|
}
|
|
|
|
if(read_offset > decoder->bytes_left)
|
|
{
|
|
RLOGD("find sync exception: %d:%d.", read_offset, decoder->bytes_left);
|
|
decoder->read_ptr += decoder->bytes_left;
|
|
decoder->bytes_left = 0;
|
|
}
|
|
else
|
|
{
|
|
decoder->read_ptr += read_offset;
|
|
decoder->bytes_left -= read_offset;
|
|
}
|
|
|
|
|
|
if (check_mp3_sync_word(decoder) == -1)
|
|
{
|
|
if (decoder->bytes_left > 0)
|
|
{
|
|
decoder->bytes_left --;
|
|
decoder->read_ptr ++;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
if (decoder->bytes_left < 1024)
|
|
{
|
|
mp3_player_end_frame = 1;
|
|
if(decoder->bytes_left==0) return -1;
|
|
}
|
|
|
|
err = MP3Decode(decoder->decoder, &decoder->read_ptr,
|
|
(int*)&decoder->bytes_left, (short*)pcm_buff, 0);
|
|
|
|
if (err != ERR_MP3_NONE)
|
|
{
|
|
switch (err)
|
|
{
|
|
case ERR_MP3_INDATA_UNDERFLOW:
|
|
RLOGD("ERR_MP3_INDATA_UNDERFLOW\n");
|
|
//decoder->bytes_left = 0;
|
|
if(mp3_player_end_frame == 1)
|
|
{
|
|
/* release this memory block */
|
|
if(decoder->bytes_left==0){
|
|
return -1;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ERR_MP3_MAINDATA_UNDERFLOW:
|
|
/* do nothing - next call to decode will provide more mainData */
|
|
RLOGD("ERR_MP3_MAINDATA_UNDERFLOW\n");
|
|
break;
|
|
|
|
default:
|
|
RLOGD("unknown error: %d, left: %d\n", err, decoder->bytes_left);
|
|
|
|
// skip this frame
|
|
if (decoder->bytes_left > 0)
|
|
{
|
|
decoder->bytes_left --;
|
|
decoder->read_ptr ++;
|
|
}
|
|
else
|
|
{
|
|
// TODO
|
|
//RT_ASSERT(0);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int outputSamps;
|
|
/* no error */
|
|
MP3GetLastFrameInfo(decoder->decoder, &decoder->frame_info);
|
|
|
|
/* set sample rate */
|
|
if (decoder->frame_info.samprate != current_sample_rate)
|
|
{
|
|
current_sample_rate = decoder->frame_info.samprate;
|
|
}
|
|
|
|
ql_audio_track_write(track_hd, (char*)pcm_buff, 1152);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
u32 local_mp3_data_fetch(const char *uri, uint8_t *buffer, u32 length)
|
|
{
|
|
int read_bytes;
|
|
|
|
if(local_mp3_file_fd==NULL){
|
|
local_mp3_file_fd= ql_fopen(uri, "r");
|
|
|
|
if (local_mp3_file_fd==NULL){
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
read_bytes = ql_fread(buffer, 1, length, local_mp3_file_fd);
|
|
|
|
if (read_bytes <= 0) return 0;
|
|
|
|
return read_bytes;
|
|
}
|
|
|
|
size_t url_mp3_data_fetch(const char *uri, uint8_t *buffer, size_t length)
|
|
{
|
|
int resp_status = -1;
|
|
uint32_t nw = length;
|
|
uint32_t page_pos = 0;
|
|
int error_cnt = 0;
|
|
|
|
//printf("fd_fetch start\n");
|
|
session = webclient_session_create(1024);
|
|
if (!session)
|
|
{
|
|
printf("open uri failed.");
|
|
goto __exit;
|
|
}
|
|
|
|
resp_status = webclient_get(session, uri);
|
|
if (resp_status == 304)
|
|
{
|
|
printf("file download failed! Server http response : 304 not modified!");
|
|
goto __exit;
|
|
}
|
|
|
|
if (resp_status != 200)
|
|
{
|
|
printf("file download failed! Server http response : %d,%s !", resp_status, uri);
|
|
goto __exit;
|
|
}
|
|
|
|
if (session->content_length == 0)
|
|
{
|
|
printf("Request file size is 0!");
|
|
goto __exit;
|
|
}
|
|
|
|
printf("start read\n");
|
|
if(total_length < session->content_length)
|
|
{
|
|
if ((nw + total_length) > session->content_length)
|
|
{
|
|
nw = session->content_length - total_length;
|
|
//log_i("last page, content_length:%d, total_length:%d, nw:%d\n", session->content_length, total_length, nw);
|
|
}
|
|
|
|
/* read */
|
|
page_pos = 0;
|
|
do
|
|
{
|
|
if(vad_audio_is_recording()) {
|
|
break;
|
|
}
|
|
|
|
pos_length = webclient_read(session, buffer + page_pos, nw - page_pos);
|
|
if(pos_length<0){
|
|
if(error_cnt++<3){
|
|
continue;
|
|
}else{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pos_length == 0)
|
|
{
|
|
printf("read error: %d, content_pos:%d, page_pos:%d\n", pos_length, total_length, page_pos);
|
|
break;
|
|
}
|
|
//LOG_I("webclient_read %d\n", length);
|
|
page_pos += pos_length;
|
|
}
|
|
while (page_pos < nw); /* read */
|
|
|
|
total_length += page_pos;
|
|
}
|
|
|
|
printf("end read:%d, %d\n", total_length, session->content_length);
|
|
|
|
__exit:
|
|
|
|
//printf("fd_fetch end\n");
|
|
if (session != NULL){
|
|
webclient_close(session);
|
|
session = NULL;
|
|
}
|
|
|
|
if(total_length<session->content_length){
|
|
total_length = 0;
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
struct mp3_decoder* aofei_mp3_decoder = NULL;
|
|
|
|
int aofei_mp3_player_init(void)
|
|
{
|
|
if(aofei_mp3_decoder==NULL){
|
|
aofei_mp3_decoder = mp3_decoder_create();
|
|
if (aofei_mp3_decoder == NULL){
|
|
RLOGD("mp3_decoder_create error\n");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void aofei_mp3_player(char *file_name)
|
|
{
|
|
int ret = 0;
|
|
uint8_t *mp3_buff = malloc(100*1024);
|
|
|
|
memset(mp3_buff, 0, 100*1024);
|
|
//直接下载到一个100k的buffer
|
|
if(strstr(file_name, "http:")){//播放url
|
|
ret = url_mp3_data_fetch(file_name, mp3_buff, 100*1024);
|
|
}else if(strstr(file_name, "test.mp3")){//播放本地音频
|
|
total_length = test_data_size;
|
|
memcpy(mp3_buff, test_data, total_length);
|
|
}else{//播放本地音频
|
|
total_length = local_mp3_data_fetch(file_name, mp3_buff, 100*1024);
|
|
}
|
|
|
|
mp3_player_end_frame = 0;
|
|
|
|
|
|
if(aofei_mp3_player_init()==-1)return;
|
|
|
|
if(ret>=0){
|
|
aofei_mp3_decoder->read_ptr = mp3_buff;
|
|
aofei_mp3_decoder->bytes_left = total_length;
|
|
|
|
track_hd = ql_audio_track_open(16000, 1, 0, mp3_decoder_track_callback);
|
|
|
|
app_codec_pa_open();
|
|
|
|
mp3_player_status = 1;
|
|
|
|
RLOGD("aofei_mp3_player0\n");
|
|
|
|
while(mp3_decoder_run(aofei_mp3_decoder)!=-1){
|
|
if(vad_audio_is_recording()||tts_playing_ret()==2){
|
|
mp3_player_status = 0;
|
|
break;
|
|
}
|
|
ql_rtos_task_sleep_ms(35);
|
|
}
|
|
|
|
|
|
|
|
while(mp3_player_status!=2){
|
|
if(vad_audio_is_recording() || tts_playing_ret()==2){
|
|
mp3_player_status = 0;
|
|
break;
|
|
}
|
|
ql_rtos_task_sleep_ms(30);
|
|
}
|
|
|
|
RLOGD("aofei_mp3_player1\n");
|
|
|
|
ql_audio_track_close(track_hd, 1);
|
|
|
|
while(mp3_player_status!=3){
|
|
if(vad_audio_is_recording()||tts_playing_ret()==2){
|
|
mp3_player_status = 0;
|
|
break;
|
|
}
|
|
ql_rtos_task_sleep_ms(30);
|
|
}
|
|
|
|
if(!vad_audio_is_recording()){
|
|
ql_rtos_task_sleep_ms(200);
|
|
}
|
|
RLOGD("aofei_mp3_player2\n");
|
|
app_codec_pa_close();
|
|
}
|
|
|
|
if(aofei_mp3_decoder!=NULL){
|
|
mp3_decoder_delete(aofei_mp3_decoder);
|
|
aofei_mp3_decoder = NULL;
|
|
}
|
|
|
|
if(local_mp3_file_fd!=NULL){
|
|
ql_fclose(local_mp3_file_fd);
|
|
local_mp3_file_fd = NULL;
|
|
}
|
|
|
|
if (session != NULL){
|
|
webclient_close(session);
|
|
session = NULL;
|
|
}
|
|
|
|
if(mp3_buff!=NULL){
|
|
free(mp3_buff);
|
|
mp3_buff = NULL;
|
|
}
|
|
|
|
total_length = 0;
|
|
mp3_player_end_frame = 0;
|
|
mp3_player_status = 0;
|
|
}
|
|
|
|
|
|
|
|
|