957 lines
23 KiB
C
957 lines
23 KiB
C
|
|
/*兼容旧同步接口*/
|
|
/*这些接口灵活性很低不建议客户使用*/
|
|
/*在kernel使用接口请自行移植到kernel*/
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#ifndef NO_AUDIO
|
|
#include "ql_audio.h"
|
|
#include "ql_audio_old_api.h"
|
|
#include "ql_rtos.h"
|
|
#include "ql_fs.h"
|
|
|
|
#define true 1
|
|
#define false 0
|
|
#define SEEK_SET 0
|
|
#define ID_RIFF 0x46464952
|
|
#define ID_WAVE 0x45564157
|
|
#define ID_FMT 0x20746d66
|
|
#define ID_DATA 0x61746164
|
|
#define ID_IOS 0x524c4c46//wav data id by IOS
|
|
#define QUEC_PCM_BLOCK_FLAG (0x01)
|
|
#define QUEC_PCM_NONBLOCK_FLAG (0x02)
|
|
#define QUEC_PCM_READ_FLAG (0x04)
|
|
#define QUEC_PCM_WRITE_FLAG (0x08)
|
|
#define AUDIO_PLAY 1
|
|
#define AUDIO_RECORD 2
|
|
|
|
#ifndef QL_MP3_FUNC
|
|
int ql_play_mp3(char *file_name,Mp3PlaybackHandle* handle,Mp3PlayConfigInfo* mp3_configInfo)
|
|
{
|
|
return -1;
|
|
}
|
|
int ql_play_mp3_stream_buffer(Mp3PlaybackHandle handle,unsigned char *mp3_buff, int mp3_size)
|
|
{
|
|
return -1;
|
|
}
|
|
int ql_stop_mp3_play(Mp3PlaybackHandle handle,int drain)
|
|
{
|
|
return -1;
|
|
}
|
|
int ql_mp3_get_pcm_handle(Mp3PlaybackHandle handle, unsigned int* pcm_handle)
|
|
{
|
|
return -1;
|
|
}
|
|
#endif
|
|
#ifndef QL_AMR_FUNC
|
|
int ql_play_amr(char *file_name,AmrPlaybackHandle* handle,AmrPlaybackConfigInfo* amr_configInfo)
|
|
{
|
|
return -1;
|
|
}
|
|
int ql_play_amr_stream_buffer(AmrPlaybackHandle handle,unsigned char *amr_buff, int amr_size)
|
|
{
|
|
return -1;
|
|
}
|
|
int ql_stop_amr_play(AmrPlaybackHandle handle,int drain)
|
|
{
|
|
return -1;
|
|
}
|
|
int ql_amr_get_pcm_handle(AmrPlaybackHandle handle, unsigned int* track_handle)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
int ql_record_amr(char *file_name,AmrEncodeHandle* handle,AmrEncConfigInfo* amr_configInfo)
|
|
{
|
|
return -1;
|
|
}
|
|
int ql_record_amr_stop(AmrEncodeHandle handle)
|
|
{
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
long long QUEC_2_ASR_AUDIO_TRACK_OPTION(unsigned int flags)
|
|
{
|
|
AUDIO_PLAY_OPTION option ;
|
|
long long option1;
|
|
memset(&option,0,sizeof(long long));
|
|
if(QUEC_PCM_BLOCK_FLAG&flags)
|
|
{
|
|
option.write_mode = 1;
|
|
}
|
|
else if(QUEC_PCM_NONBLOCK_FLAG&flags)
|
|
{
|
|
option.write_mode = 0;
|
|
}
|
|
option.active_point = 1;
|
|
memcpy(&option1,&option,sizeof(long long));
|
|
return option1;
|
|
}
|
|
static char is_support_samplerate(unsigned int rate)
|
|
{
|
|
switch(rate) {
|
|
case 8000:
|
|
case 16000:
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static int check_wav_file(QFILE *fd, aud_input_para_t *para)
|
|
{
|
|
int ret = 0,i = 0;
|
|
struct riff_chunk riff_hdr;
|
|
struct format_chunk format_hdr;
|
|
struct data_chunk data_hdr;
|
|
unsigned int chunk_id = 0,chunk_size = 0,chunk_len = 0;
|
|
unsigned int data = 0,data_size = 0;
|
|
|
|
if(!para)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
ret = ql_fseek(fd, 0, SEEK_SET);
|
|
if(ret < 0)
|
|
{
|
|
return -1;
|
|
}
|
|
ret = ql_fread(&riff_hdr, sizeof(riff_hdr),1,fd); //riff
|
|
if(ret < sizeof(riff_hdr))
|
|
{
|
|
ql_fseek(fd, 0, SEEK_SET);
|
|
return -1;
|
|
}
|
|
if( (riff_hdr.riff != ID_RIFF) || (riff_hdr.wave!= ID_WAVE))
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
for(i = 0;i < riff_hdr.file_size;){ //format
|
|
ql_fread(&chunk_id, sizeof(chunk_id),1,fd);
|
|
if(chunk_id == ID_FMT){
|
|
ql_fread(&format_hdr.format_size, sizeof(unsigned int),1,fd);
|
|
format_hdr.format = chunk_id;
|
|
break;
|
|
}else{
|
|
ql_fread(&chunk_size, sizeof(chunk_size),1,fd);
|
|
i += (chunk_size + 8);
|
|
if(i > riff_hdr.file_size)
|
|
return -1;
|
|
ret = ql_fseek(fd, chunk_size, 1);
|
|
if(ret < chunk_size)
|
|
return -1;
|
|
chunk_len = i;
|
|
}
|
|
|
|
}
|
|
ql_fread(&format_hdr.aud_fmt, format_hdr.format_size,1,fd);
|
|
if(is_support_samplerate(format_hdr.sample) == false){
|
|
return -1;
|
|
}
|
|
|
|
|
|
for(i = 0;i < (riff_hdr.file_size-chunk_len-format_hdr.format_size);){ //data
|
|
ql_fread(&data, sizeof(data),1,fd);
|
|
if(data == ID_DATA){
|
|
ql_fread(&data_hdr.data_size, sizeof(unsigned int),1,fd);
|
|
data_hdr.data = data;
|
|
break;
|
|
}else{
|
|
ql_fread(&data_size, sizeof(data_size),1,fd);
|
|
i += (data_size + 8);
|
|
if(i > riff_hdr.file_size-chunk_len-format_hdr.format_size)
|
|
return -1;
|
|
ret = ql_fseek(fd, data_size, 1);
|
|
if(ret < data_size)
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
switch (format_hdr.bits_sample)
|
|
{
|
|
case 8:
|
|
para->format = QUEC_PCM_FORMAT_S8;
|
|
break;
|
|
case 16:
|
|
para->format = QUEC_PCM_FORMAT_S16_LE;
|
|
break;
|
|
case 24:
|
|
para->format = QUEC_PCM_FORMAT_S24_LE;
|
|
break;
|
|
case 32:
|
|
para->format = QUEC_PCM_FORMAT_S32_LE;
|
|
break;
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
para->rate = format_hdr.sample;
|
|
para->channels = format_hdr.channel;
|
|
para->hsize = 4;
|
|
para->type = AUD_STREAM_FORMAT_PCM;
|
|
para->file_size = data_hdr.data_size;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int check_mp3_file(QFILE *fd)
|
|
{
|
|
int ret = 0;
|
|
char head[10] = {0};
|
|
|
|
ret = ql_fseek(fd, 0, SEEK_SET);
|
|
if(ret < 0)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
ret = ql_fread(head, sizeof(head),1,fd);
|
|
if(ret < sizeof(head))
|
|
{
|
|
ql_fseek(fd, 0, SEEK_SET);
|
|
return -1;
|
|
}
|
|
|
|
if(memcmp(head, "ID3", 3) == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
else if( (head[0] == 0xFF) && (head[1] & 0xF0) == 0xF0 )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int check_amr_file(QFILE *fd, aud_input_para_t *para)
|
|
{
|
|
int bytesRead = 0;
|
|
int ret = 0;
|
|
char header[6] = {0};
|
|
ret = ql_fseek(fd, 0, SEEK_SET);
|
|
if(ret < 0)
|
|
{
|
|
return -1;
|
|
}
|
|
// Validate the input AMR file
|
|
bytesRead = ql_fread(header, 6,1,fd);
|
|
if (bytesRead != 6 || memcmp(header, "#!AMR\n", 6)) {
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int check_audio_format(QFILE *fd, aud_input_para_t *para)
|
|
{
|
|
|
|
if(!check_wav_file(fd, para))
|
|
{
|
|
return AUD_STREAM_FORMAT_PCM;
|
|
}
|
|
else if(!check_mp3_file(fd))
|
|
{
|
|
return AUD_STREAM_FORMAT_MP3;
|
|
}
|
|
else if(!check_amr_file(fd, para))
|
|
{
|
|
return AUD_STREAM_FORMAT_AMR;
|
|
}else{
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Name: ql_audio_file_play
|
|
*
|
|
* Description: 播放音频文件 ,文件类型可以是mp3,pcm ,wav 异步接口
|
|
*
|
|
* Parameters:
|
|
*
|
|
* Returns:
|
|
*
|
|
* Notes:
|
|
*
|
|
***********************************************************************/
|
|
static cb_on_player aud_play_cb = NULL;
|
|
|
|
static Mp3PlaybackHandle mp3_handle;
|
|
static Mp3PlayConfigInfo mp3_configInfo;
|
|
static unsigned char is_mp3_playing = 0;
|
|
static audio_track_handle wav_handle;
|
|
static AmrPlaybackHandle amr_handle;
|
|
static AmrPlaybackConfigInfo amr_config;
|
|
static struct audio_track_config wav_config;
|
|
static unsigned char is_wav_file_playing;
|
|
static unsigned char is_amr_file_playing;
|
|
|
|
static AmrPlaybackHandle amr_stream_handle;
|
|
static AmrPlaybackConfigInfo amr_stream_config;
|
|
static unsigned char is_amr_stream_playing = 0;
|
|
|
|
int ql_audio_play_init(cb_on_player aud_cb)
|
|
{
|
|
aud_play_cb = aud_cb;
|
|
return 0;
|
|
}
|
|
|
|
static void wav_play_callback(acm_audio_track_handle handle, acm_audio_track_event_t event)
|
|
{
|
|
if(handle == wav_handle)
|
|
{
|
|
if(event == AUDIO_TRACK_EVENT_STARTED)
|
|
{
|
|
is_wav_file_playing = 1;
|
|
if(aud_play_cb)
|
|
{
|
|
aud_play_cb(NULL, 0, AUD_PLAYER_START);
|
|
}
|
|
}
|
|
if(event == AUDIO_TRACK_EVENT_UNDERRUN)
|
|
{
|
|
is_wav_file_playing = 0;
|
|
if(aud_play_cb)
|
|
{
|
|
aud_play_cb(NULL, 0, AUD_PLAYER_FINISHED);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
static void ql_Mp3PlaybackEvent(Mp3PlayEventType event, int val)
|
|
{
|
|
if(event == MP3_PLAYBACK_EVENT_STATUS){
|
|
if(val == MP3_PLAYBACK_STATUS_STARTED)
|
|
{
|
|
is_mp3_playing = 1;
|
|
if(aud_play_cb)
|
|
{
|
|
aud_play_cb(NULL, 0, AUD_PLAYER_START);
|
|
}
|
|
}
|
|
if(val == MP3_PLAYBACK_STATUS_ENDED)
|
|
{
|
|
is_mp3_playing = 0;
|
|
if(aud_play_cb)
|
|
{
|
|
aud_play_cb(NULL, 0, AUD_PLAYER_FINISHED);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void ql_amr_palyback_event(AmrPlaybackEventType event, int val)
|
|
{
|
|
if(event == AMR_PLAYBACK_EVENT_STATUS){
|
|
if(val == AMR_PLAYBACK_STATUS_STARTED)
|
|
{
|
|
is_amr_file_playing = 1;
|
|
if(aud_play_cb)
|
|
{
|
|
aud_play_cb(NULL, 0, AUD_PLAYER_START);
|
|
}
|
|
}
|
|
if(val == AMR_PLAYBACK_STATUS_ENDED)
|
|
{
|
|
is_amr_stream_playing = 0;
|
|
is_amr_file_playing = 0;
|
|
if(aud_play_cb)
|
|
{
|
|
aud_play_cb(NULL, 0, AUD_PLAYER_FINISHED);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
int ql_audio_file_play(char *file_name)
|
|
{
|
|
int rc = 0,ret=0;
|
|
QFILE * fd = NULL;
|
|
aud_input_para_t para;
|
|
rc = ql_access(file_name,0);
|
|
if(rc == 0)
|
|
{
|
|
fd = ql_fopen(file_name, "rb");
|
|
if(fd == NULL)
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return -1;
|
|
}
|
|
ret = check_audio_format(fd, ¶);
|
|
ql_fclose(fd);
|
|
if(AUD_STREAM_FORMAT_MP3 == ret)
|
|
{
|
|
if(is_mp3_playing == 1) {
|
|
return -2;
|
|
}
|
|
mp3_configInfo.listener = ql_Mp3PlaybackEvent;
|
|
ql_play_mp3(file_name,&mp3_handle,&mp3_configInfo);
|
|
}
|
|
else if(AUD_STREAM_FORMAT_PCM == ret)
|
|
{
|
|
if(is_wav_file_playing == 1)
|
|
{
|
|
return -2;
|
|
}
|
|
wav_config.event_cb = wav_play_callback;
|
|
ql_wav_play(file_name,&wav_config,&wav_handle);
|
|
}
|
|
else if(AUD_STREAM_FORMAT_AMR == ret)
|
|
{
|
|
if(is_amr_file_playing == 1)
|
|
{
|
|
return -2;
|
|
}
|
|
amr_config.listener = ql_amr_palyback_event;
|
|
ret = ql_play_amr(file_name,&amr_handle,&amr_config);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ql_audio_file_stop(void)
|
|
{
|
|
return 0;
|
|
}
|
|
/***********************************************************************
|
|
*
|
|
* Name: ql_play_file_start
|
|
*
|
|
* Description: 播放音频文件 ,文件类型可以是mp3,pcm ,wav ,,同步接口
|
|
*
|
|
* Parameters:
|
|
*
|
|
* Returns:
|
|
*
|
|
* Notes:
|
|
*
|
|
***********************************************************************/
|
|
static Mp3PlaybackHandle mp3_handle_sync;
|
|
static Mp3PlayConfigInfo mp3_configInfo_sync;
|
|
static unsigned char mp3_sync_playing = 0;
|
|
|
|
static audio_track_handle wav_handle_sync;
|
|
static struct audio_track_config wav_config_sync;
|
|
static unsigned char wav_sync_playing = 0;
|
|
|
|
static AmrPlaybackHandle amr_handle_sync;
|
|
static AmrPlaybackConfigInfo amr_config_sync;
|
|
static unsigned char amr_sync_playing = 0;
|
|
|
|
static void wav_sync_play_callback(acm_audio_track_handle handle, acm_audio_track_event_t event)
|
|
{
|
|
if(handle == wav_handle)
|
|
{
|
|
if(event == AUDIO_TRACK_EVENT_STARTED)
|
|
{
|
|
wav_sync_playing = 1;
|
|
if(aud_play_cb)
|
|
{
|
|
aud_play_cb(NULL, 0, AUD_PLAYER_START);
|
|
}
|
|
}
|
|
if(event == AUDIO_TRACK_EVENT_UNDERRUN)
|
|
{
|
|
wav_sync_playing = 0;
|
|
if(aud_play_cb)
|
|
{
|
|
aud_play_cb(NULL, 0, AUD_PLAYER_FINISHED);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
static void mp3_sync_play_callback(Mp3PlayEventType event, int val)
|
|
{
|
|
if(event == MP3_PLAYBACK_EVENT_STATUS){
|
|
if(val == MP3_PLAYBACK_STATUS_STARTED)
|
|
{
|
|
mp3_sync_playing = 1;
|
|
if(aud_play_cb)
|
|
{
|
|
aud_play_cb(NULL, 0, AUD_PLAYER_START);
|
|
}
|
|
}
|
|
if(val == MP3_PLAYBACK_STATUS_ENDED)
|
|
{
|
|
mp3_sync_playing = 0;
|
|
if(aud_play_cb)
|
|
{
|
|
aud_play_cb(NULL, 0, AUD_PLAYER_FINISHED);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void amr_sync_play_callback(AmrPlaybackEventType event, int val)
|
|
{
|
|
if(event == AMR_PLAYBACK_EVENT_STATUS){
|
|
if(val == AMR_PLAYBACK_STATUS_STARTED)
|
|
{
|
|
amr_sync_playing = 1;
|
|
if(aud_play_cb)
|
|
{
|
|
aud_play_cb(NULL, 0, AUD_PLAYER_START);
|
|
}
|
|
}
|
|
if(val == AMR_PLAYBACK_STATUS_ENDED)
|
|
{
|
|
amr_sync_playing = 0;
|
|
if(aud_play_cb)
|
|
{
|
|
aud_play_cb(NULL, 0, AUD_PLAYER_FINISHED);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
int ql_play_file_start(char *file_name)
|
|
{
|
|
int rc = 0,ret=0;
|
|
QFILE * fd = NULL;
|
|
aud_input_para_t para;
|
|
rc = ql_access(file_name,0);
|
|
if(rc == 0)
|
|
{
|
|
fd = ql_fopen(file_name, "rb");
|
|
if(fd == NULL)
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return -1;
|
|
}
|
|
ret = check_audio_format(fd, ¶);
|
|
ql_fclose(fd);
|
|
if(AUD_STREAM_FORMAT_MP3 == ret)
|
|
{
|
|
if(mp3_sync_playing == 1) {
|
|
return -2;
|
|
}
|
|
mp3_configInfo_sync.listener = mp3_sync_play_callback;
|
|
ret = ql_play_mp3(file_name,&mp3_handle_sync,&mp3_configInfo_sync);
|
|
do
|
|
{
|
|
ql_rtos_task_sleep_ms(50);
|
|
} while (mp3_sync_playing);
|
|
}
|
|
else if(AUD_STREAM_FORMAT_PCM == ret)
|
|
{
|
|
if(wav_sync_playing == 1)
|
|
{
|
|
return -2;
|
|
}
|
|
wav_config_sync.event_cb = wav_sync_play_callback;
|
|
ret = ql_wav_play(file_name,&wav_config_sync,&wav_handle_sync);
|
|
do
|
|
{
|
|
ql_rtos_task_sleep_ms(50);
|
|
} while (wav_sync_playing);
|
|
}
|
|
else if(AUD_STREAM_FORMAT_AMR == ret)
|
|
{
|
|
if(amr_sync_playing == 1)
|
|
{
|
|
return -2;
|
|
}
|
|
amr_config_sync.listener = amr_sync_play_callback;
|
|
ret = ql_play_amr(file_name,&amr_handle_sync,&amr_config_sync);
|
|
do
|
|
{
|
|
ql_rtos_task_sleep_ms(50);
|
|
} while (amr_sync_playing);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ql_play_file_stop(void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int ql_wav_file_play(char *file_name)
|
|
{
|
|
if(!file_name){
|
|
return -1;
|
|
}
|
|
if(is_wav_file_playing == 1)
|
|
{
|
|
return -2;
|
|
}
|
|
wav_config.event_cb = wav_play_callback;
|
|
wav_config.prepare_threshold = 64;
|
|
return ql_wav_play(file_name,&wav_config,&wav_handle);
|
|
}
|
|
|
|
void ql_wav_file_stop(void)
|
|
{
|
|
ql_wav_play_stop(wav_handle,1);
|
|
}
|
|
|
|
int ql_mp3_file_play(char *file_name)
|
|
{
|
|
if(!file_name){
|
|
return -1;
|
|
}
|
|
|
|
if(is_mp3_playing == 1) {
|
|
return -2;
|
|
}
|
|
mp3_configInfo.listener = ql_Mp3PlaybackEvent;
|
|
return ql_play_mp3(file_name,&mp3_handle,&mp3_configInfo);
|
|
}
|
|
|
|
void ql_mp3_file_stop(void)
|
|
{
|
|
ql_stop_mp3_play(mp3_handle,0);
|
|
}
|
|
|
|
|
|
static int ql_amr_file_play_type = 0;
|
|
int ql_amr_file_play(char *file_name)
|
|
{
|
|
if(!file_name){
|
|
return -1;
|
|
}
|
|
|
|
if(is_amr_file_playing == 1) {
|
|
return -2;
|
|
}
|
|
ql_amr_file_play_type = 0;
|
|
amr_config.listener = ql_amr_palyback_event;
|
|
return ql_play_amr(file_name,&amr_handle,&amr_config);
|
|
}
|
|
|
|
int ql_amr_file_play2(const char *data, unsigned int size)
|
|
{
|
|
int ret = -1;
|
|
if(is_amr_stream_playing == 0)
|
|
{
|
|
amr_config.listener = ql_amr_palyback_event;
|
|
ql_play_amr(NULL,&amr_stream_handle,&amr_stream_config);
|
|
is_amr_stream_playing = 1;
|
|
ql_amr_file_play_type = 1;
|
|
ret = ql_play_amr_stream_buffer(amr_stream_handle,(unsigned char *)data, size);
|
|
if (ret == 0)
|
|
{
|
|
ret = ql_stop_amr_play(amr_stream_handle,1);//播缓存,等待结束事件
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void ql_amr_file_stop(void)
|
|
{
|
|
if (ql_amr_file_play_type == 0)//文件播放调用播文件句柄
|
|
{
|
|
ql_stop_amr_play(amr_handle,0);
|
|
}
|
|
else
|
|
{
|
|
ql_amr_file_play_type = 0;
|
|
if (is_amr_stream_playing)
|
|
{
|
|
is_amr_stream_playing = 0;
|
|
ql_stop_amr_play(amr_stream_handle,0);
|
|
}
|
|
}
|
|
}
|
|
|
|
static AmrEncodeHandle record_amr_handle;
|
|
static AmrEncConfigInfo record_amr_config;
|
|
int ql_record_amr_file_start(char *file_name)
|
|
{
|
|
if(!file_name){
|
|
return -1;
|
|
}
|
|
return ql_record_amr(file_name, &record_amr_handle , &record_amr_config);
|
|
}
|
|
|
|
void ql_record_amr_file_stop(void)
|
|
{
|
|
ql_record_amr_stop(record_amr_handle);
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Name:
|
|
*
|
|
* Description: 播放音频文件 ,文件类型可以是mp3,pcm ,wav
|
|
*
|
|
* Parameters:
|
|
*
|
|
* Returns:
|
|
*
|
|
* Notes:
|
|
*
|
|
***********************************************************************/
|
|
/*尾插单链表*/
|
|
typedef struct Node {
|
|
unsigned int data;
|
|
struct Node* next;
|
|
} Node;
|
|
// 初始化一个空链表
|
|
Node* initializeList() {
|
|
return NULL;
|
|
}
|
|
// 在链表末尾插入一个新节点
|
|
Node* insertNode(Node* head, unsigned int data) {
|
|
Node* newNode = (Node*)malloc(sizeof(Node));
|
|
newNode->data = data;
|
|
newNode->next = NULL;
|
|
|
|
if (head == NULL) {
|
|
return newNode;
|
|
}
|
|
|
|
Node* current = head;
|
|
while (current->next != NULL) {
|
|
current = current->next;
|
|
}
|
|
|
|
current->next = newNode;
|
|
return head;
|
|
}
|
|
|
|
// 删除链表中第一个匹配给定数据的节点
|
|
Node* deleteNode(Node* head, unsigned int data) {
|
|
if (head == NULL) {
|
|
return NULL; // 空链表,无需删除
|
|
}
|
|
|
|
if (head->data == data) {
|
|
Node* temp = head;
|
|
head = head->next;
|
|
free(temp);
|
|
return head;
|
|
}
|
|
|
|
Node* current = head;
|
|
while (current->next != NULL && current->next->data != data) {
|
|
current = current->next;
|
|
}
|
|
|
|
if (current->next != NULL) {
|
|
Node* temp = current->next;
|
|
current->next = current->next->next;
|
|
free(temp);
|
|
}
|
|
|
|
return head;
|
|
}
|
|
|
|
PCM_HANDLE_T findList(Node* head , unsigned int handle) {
|
|
Node* current = head;
|
|
PCM_HANDLE_T quec_audio_handle = NULL;
|
|
while (current != NULL) {
|
|
quec_audio_handle = (PCM_HANDLE_T)current->data;
|
|
if(quec_audio_handle->handle == handle)
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
quec_audio_handle = NULL;
|
|
}
|
|
current = current->next;
|
|
}
|
|
return quec_audio_handle;
|
|
}
|
|
|
|
// 释放链表内存
|
|
void freeList(Node* head) {
|
|
Node* current = head;
|
|
Node* next;
|
|
while (current != NULL) {
|
|
next = current->next;
|
|
free(current);
|
|
current = next;
|
|
}
|
|
}
|
|
Node* pcm_hadle_list;
|
|
#define PCM_END_FLAG 0x1
|
|
char record_work_mode=0;
|
|
char list_created = 0;
|
|
void OLD_pcm_play_callback(acm_audio_track_handle handle, acm_audio_track_event_t event)
|
|
{
|
|
PCM_HANDLE_T quec_audio_handle = findList(pcm_hadle_list , (unsigned int)handle);
|
|
if(quec_audio_handle){
|
|
if(event == AUDIO_TRACK_EVENT_CLOSED)
|
|
ql_rtos_flag_release(quec_audio_handle->pcm_stream_flag,PCM_END_FLAG, QL_FLAG_OR);
|
|
}
|
|
|
|
}
|
|
|
|
PCM_HANDLE_T ql_pcm_open(QL_PCM_CONFIG_T *config, unsigned int flags)
|
|
{
|
|
PCM_HANDLE_T quec_audio_handle = malloc(sizeof(ql_pcm_hadle_t));
|
|
long long option = 0;
|
|
if (flags&QUEC_PCM_WRITE_FLAG)
|
|
{
|
|
if(list_created)
|
|
{
|
|
list_created=1;
|
|
pcm_hadle_list=initializeList();
|
|
}
|
|
pcm_hadle_list = insertNode(pcm_hadle_list, (unsigned int)quec_audio_handle);
|
|
ql_rtos_flag_create(&(quec_audio_handle->pcm_stream_flag));
|
|
quec_audio_handle->record_or_play = AUDIO_PLAY;
|
|
option = QUEC_2_ASR_AUDIO_TRACK_OPTION(flags);
|
|
quec_audio_handle->handle = ql_audio_track_open(config->samplerate, config->channels,option, OLD_pcm_play_callback);
|
|
}
|
|
else if(flags&QUEC_PCM_READ_FLAG)
|
|
{
|
|
if(flags&QUEC_PCM_BLOCK_FLAG)
|
|
record_work_mode = 1;
|
|
else
|
|
record_work_mode = 0;
|
|
quec_audio_handle->record_or_play = AUDIO_RECORD;
|
|
quec_audio_handle->handle = ql_audio_record_open(config->samplerate, config->channels, option,NULL);
|
|
}
|
|
return (PCM_HANDLE_T)quec_audio_handle;
|
|
}
|
|
|
|
int ql_pcm_read(PCM_HANDLE_T handle, void *data, unsigned int count)
|
|
{
|
|
ql_pcm_hadle_t *quec_audio_handle = handle;
|
|
int ret = -1,CNT=0;
|
|
unsigned int count1=0;
|
|
if(count == 0 || data == NULL)
|
|
return ret;
|
|
count1 = count;
|
|
if(record_work_mode == 1)/*由于asr的录音不带阻塞模式,故在此增加阻塞*/
|
|
{
|
|
while(ret&&CNT<10){
|
|
count1 = count;
|
|
ret = ql_audio_record_read(quec_audio_handle->handle, data, &count1);
|
|
ql_rtos_task_sleep_ms(5);
|
|
CNT++;
|
|
}
|
|
if(ret<0)
|
|
count1 = 0;
|
|
}
|
|
else
|
|
{
|
|
ret = ql_audio_record_read(quec_audio_handle->handle, data, &count1);
|
|
if(ret<0)
|
|
count1 = 0;
|
|
}
|
|
|
|
return count1;
|
|
}
|
|
|
|
int ql_pcm_write(PCM_HANDLE_T handle, void *data, unsigned int count)
|
|
{
|
|
int ret = 0;
|
|
int temp_cnt = 0;
|
|
|
|
temp_cnt = count;
|
|
ql_pcm_hadle_t *quec_audio_handle = handle;
|
|
ret = ql_audio_track_write(quec_audio_handle->handle, data, count);
|
|
if (ret == 0)
|
|
{
|
|
return temp_cnt;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int ql_pcm_close(PCM_HANDLE_T handle)
|
|
{
|
|
ql_pcm_hadle_t *quec_audio_handle = handle;
|
|
int ret = 0;
|
|
u32 flags = 0;
|
|
if(quec_audio_handle->record_or_play==AUDIO_PLAY)
|
|
{
|
|
ret = ql_audio_track_close(quec_audio_handle->handle,1);
|
|
ql_rtos_task_sleep_ms(20);
|
|
// ql_rtos_flag_wait(quec_audio_handle->pcm_stream_flag, PCM_END_FLAG, QL_FLAG_OR_CLEAR, &flags, 0xFFFFFFFF);
|
|
pcm_hadle_list = deleteNode(pcm_hadle_list, (unsigned int)quec_audio_handle);
|
|
ql_rtos_flag_delete(quec_audio_handle->pcm_stream_flag);
|
|
}
|
|
else if(quec_audio_handle->record_or_play==AUDIO_RECORD)
|
|
{
|
|
ret = ql_audio_record_close(quec_audio_handle->handle,1);
|
|
}
|
|
else
|
|
{
|
|
ret = -1;
|
|
}
|
|
|
|
free(quec_audio_handle);
|
|
return ret;
|
|
}
|
|
cb_on_player ql_pcm_play_cb;
|
|
audio_track_handle track_handle = 0;
|
|
|
|
static void pcm_play_callback(acm_audio_track_handle handle, acm_audio_track_event_t event)
|
|
{
|
|
enum_aud_player_state ql_aug_event = AUD_PLAYER_ERROR;
|
|
if(handle == track_handle)
|
|
{
|
|
if(event == AUDIO_TRACK_EVENT_STARTED)
|
|
{
|
|
if(ql_pcm_play_cb)
|
|
ql_pcm_play_cb(NULL,0,AUD_PLAYER_START);
|
|
}
|
|
if(event == AUDIO_TRACK_EVENT_UNDERRUN)
|
|
{
|
|
if(ql_pcm_play_cb)
|
|
ql_pcm_play_cb(NULL,0,AUD_PLAYER_NODATA);
|
|
}
|
|
if(event == AUDIO_TRACK_EVENT_NEARLY_OVERRUN)
|
|
{
|
|
if(ql_pcm_play_cb)
|
|
ql_pcm_play_cb(NULL,0,AUD_PLAYER_MOREDATA);
|
|
}
|
|
if(event == AUDIO_TRACK_EVENT_NEARLY_UNDERRUN)
|
|
{
|
|
if(ql_pcm_play_cb)
|
|
ql_pcm_play_cb(NULL,0,AUD_PLAYER_LESSDATA);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
int ql_pcm_play_init(cb_on_player play_cb)
|
|
{
|
|
ql_pcm_play_cb=play_cb;
|
|
return 0;
|
|
}
|
|
int ql_pcm_play(int hdl, unsigned char *buffer, int wav_size)
|
|
{
|
|
track_handle = ql_audio_track_open(8000, 1,0, pcm_play_callback);
|
|
return ql_audio_track_write(track_handle, buffer, wav_size);
|
|
}
|
|
|
|
int ql_pcm_play_stop(int hdl)
|
|
{
|
|
return ql_audio_track_close(track_handle,0);
|
|
}
|
|
|
|
int ql_pcm_play_deinit(int hdl)
|
|
{
|
|
ql_pcm_play_cb=0;
|
|
return 0;
|
|
}
|
|
|
|
|
|
#endif |