EC600U_esp32_iap_uart/audio/audio_demo.c

1651 lines
44 KiB
C
Raw Permalink Normal View History

2024-02-05 17:39:56 +08:00
/*================================================================
Copyright (c) 2020 Quectel Wireless Solution, Co., Ltd. All Rights Reserved.
Quectel Wireless Solution Proprietary and Confidential.
=================================================================*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "ql_api_osi.h"
#include "ql_log.h"
#include "audio_demo.h"
#include "ql_osi_def.h"
#include "ql_audio.h"
#include "ql_fs.h"
#include "ql_i2c.h"
#include "quec_pin_index.h"
#include "ql_gpio.h"
#define QL_AUDIO_LOG_LEVEL QL_LOG_LEVEL_INFO
#define QL_AUDIO_LOG(msg, ...) QL_LOG(QL_AUDIO_LOG_LEVEL, "ql_audio", msg, ##__VA_ARGS__)
#define QL_AUDIO_LOG_PUSH(msg, ...) QL_LOG_PUSH("ql_AUDIO", msg, ##__VA_ARGS__)
#if !defined(audio_demo_no_err)
#define audio_demo_no_err(x, action, str) \
do \
{ \
if(x != 0) \
{ \
QL_AUDIO_LOG(str); \
{action;} \
} \
} while( 1==0 )
#endif
/* for headset_det */
#ifdef QL_APP_FEATURE_HEADSET_DET
#define QL_HEADSET_DETECT_PIN QUEC_PIN_DNAME_GPIO_8
#define QL_HEADSET_DETECT_GPIO QUEC_GPIO_DNAME_GPIO_8
#define QL_HEADSET_DETECT_FUNC_GPIO 0
#define QL_HEADSET_DETECT_DEBOUNCE_TIME 300 //unit: ms
#define DEMO_HEADSET_DETECT_PLUG_IN 1
#define DEMO_HEADSET_DETECT_PLUG_OUT 0
ql_task_t headset_det_task = NULL;
ql_timer_t headset_det_debounce_timer = NULL;
#endif
// only for EC600U
ql_task_t headset_EC600U_task = NULL;
#define ID_RIFF 0x46464952
#define ID_WAVE 0x45564157
#define ID_FMT 0x20746d66
#define FORMAT_PCM 1
#define CHECK_AUDIO_CORRECT 0
#define CHECK_AUDIO_INVALID_PARAMETER 1
#define CHECK_AUDIO_WAV_ERR 2
#define CHECK_AUDIO_MP3_ERR 3
#define CHECK_AUDIO_AMR_ERR 4
struct wav_header{
unsigned int riff_id;
unsigned int riff_sz;
unsigned int riff_fmt;
unsigned int fmt_id;
unsigned int fmt_sz;
unsigned short audio_format;
unsigned short num_channels;
unsigned int sample_rate;
unsigned int byte_rate;
unsigned short block_align;
unsigned short bits_per_sample;
unsigned int data_id;
unsigned int data_sz;
};
typedef struct
{
PCM_HANDLE_T recorder;
PCM_HANDLE_T player;
}ql_demo_poc_t;
#ifdef QL_APP_FEATURE_AUDIO_RECORD
static uint8 *pcm_buffer = NULL;
static uint pcm_data_size = 0;
#endif
static bool ring_tone_start = 0;
ql_task_t ql_play_task = NULL;
static int play_callback(char *p_data, int len, enum_aud_player_state state)
{
if(state == AUD_PLAYER_START)
{
QL_AUDIO_LOG("player start run");
}
else if(state == AUD_PLAYER_FINISHED)
{
QL_AUDIO_LOG("player stop run");
}
else
{
QL_AUDIO_LOG("type is %d", state);
}
return QL_AUDIO_SUCCESS;
}
#ifdef QL_APP_FEATURE_AUDIO_RECORD
static int record_callback(char *p_data, int len, enum_aud_record_state state)
{
if(state == AUD_RECORD_START)
{
QL_AUDIO_LOG("recorder start run");
}
else if(state == AUD_RECORD_CLOSE)
{
QL_AUDIO_LOG("recorder stop run");
}
else if(state == AUD_RECORD_CALL_INT)
{
QL_AUDIO_LOG("recorder int from ring/call");
}
else if(state == AUD_RECORD_DATA)
{
if(len <= 0)
return -1;
if(pcm_data_size > RECORD_BUFFER_MAX){
return -1;
}
else{
memcpy(pcm_buffer+pcm_data_size, p_data, len);
pcm_data_size += len;
}
}
return QL_AUDIO_SUCCESS;
}
#endif
static int ringtone_callback(bool start, void *ctx)
{
if(start)
{
QL_AUDIO_LOG("ringtone start play");
if(ql_aud_get_play_state() != QL_AUDIO_STATUS_RUNNING)
{
ql_event_t event = {0};
event.id = QL_AUDIO_RINGTONE_PLAY;
ring_tone_start = (ql_rtos_event_send(ql_play_task, &event) ? FALSE:TRUE);
}
}
else
{
QL_AUDIO_LOG("ringtone stop play");
if(ring_tone_start){
ql_aud_player_stop();
ring_tone_start = FALSE;
}
}
return 0;
}
static void ql_audio_demo_thread(void *param)
{
QL_AUDIO_LOG("enter audio demo");
#ifdef QL_APP_FEATURE_EXT_CODEC
// test_codec();
#endif
// config_internal_codec_gain(); //配置内置codec的音频增益,此处不建议调整,保持默认值; 用户若要调整可参考此函数
// test_pcm();
// test_mp3();
// test_wav();
// test_amr();
// test_amr_stream();
#ifdef QL_APP_FEATURE_AUDIO_RECORD
// test_record_file();
// test_record_stream();
// test_poc_full_duplex();
// test_poc_half_duplex();
#endif
// test_ring_tone(); //the demo "ql_voice_call_app_init" must be opened
// test_tone_dtmf();
QL_AUDIO_LOG("test done, exit audio demo");
ql_rtos_task_delete(NULL);
}
static int check_wav_file(QFILE fd)
{
int ret = 0;
struct wav_header hdr;
ret = ql_fseek(fd, 0, SEEK_SET);
if(ret < 0)
{
return -1;
}
ret = ql_fread(&hdr, sizeof(hdr), 1, fd);
if(ret < sizeof(hdr))
{
ql_fseek(fd, 0, SEEK_SET);
return -1;
}
if( (hdr.riff_id != ID_RIFF) || (hdr.riff_fmt != ID_WAVE)
|| (hdr.fmt_id != ID_FMT) )
{
return -1;
}
if(hdr.audio_format != FORMAT_PCM)
{
return -1;
}
return 0;
}
static int check_mp3_file(QFILE fd)
{
int64 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(strncmp(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)
{
return 0;
}
//Whether the audio format is correct?
int check_audio_format(char *fname)
{
int err = CHECK_AUDIO_CORRECT;
if (fname == NULL)
return CHECK_AUDIO_INVALID_PARAMETER;
char *dot = strrchr(fname, '.');
if (dot == NULL)
return CHECK_AUDIO_INVALID_PARAMETER;
QFILE fd = ql_fopen(fname, "r");
if(fd<0)
{
return CHECK_AUDIO_INVALID_PARAMETER;
}
if(!check_wav_file(fd))
{
if (strcasecmp(dot, ".wav") != 0)
{
err = CHECK_AUDIO_WAV_ERR;
}
}
else if(!check_mp3_file(fd))
{
if (strcasecmp(dot, ".mp3") != 0)
{
err = CHECK_AUDIO_MP3_ERR;
}
}
else if(!check_amr_file(fd))
{
if (strcasecmp(dot, ".amr") != 0)
{
err = CHECK_AUDIO_AMR_ERR;
}
}
ql_fclose(fd);
return err;
}
static void ql_audio_play_thread(void *ctx)
{
int err = 0;
ql_event_t event = {0};
while(1)
{
err = ql_event_try_wait(&event);
if(err)
{
QL_AUDIO_LOG("wait event failed");
continue;
}
switch(event.id)
{
case QL_AUDIO_RINGTONE_PLAY:
do
{
err = ql_aud_play_file_start("ring_tone.mp3", QL_AUDIO_PLAY_TYPE_LOCAL, NULL);
if(err)
{
ring_tone_start = FALSE;
break;
}
ql_aud_wait_play_finish(QL_WAIT_FOREVER);
}while(ring_tone_start);
break;
}
}
}
void config_internal_codec_gain(void)
{
int err = 0;
//配置本地播放模式下, 喇叭输出的1级音量对应的dac增益为 -13.5db, 算法增益为0db, 且实时生效
err = ql_aud_set_icvolume_level_gain(QL_AUDIO_PLAY_TYPE_LOCAL,
QL_OUTPUT_SPEAKER,
AUDIOHAL_SPK_VOL_1,
25,
15);
audio_demo_no_err(err, return, "config volume failed");
//配置非volte通话模式下, 耳机的侧音增益为MUTE(关闭侧音),且实时生效
ql_aud_set_icsidet_gain(QL_AUD_VOICECALL_NB,
QL_OUTPUT_HEADPHONE,
QL_ICMIC_SIDET_GAIN_MUTE);
audio_demo_no_err(err, return, "config side tone gain failed");
}
void test_ring_tone(void)
{
ql_aud_set_ringtone_type(QL_AUD_RING_CUSTOMER_DEF);
ql_bind_ring_tone_cb(ringtone_callback);
}
void test_tone_dtmf(void)
{
int err=0;
ql_set_audio_path_earphone();
ql_aud_set_volume(QL_AUDIO_PLAY_TYPE_LOCAL, AUDIOHAL_SPK_VOL_11);
QL_AUDIO_LOG("test dtmf");
err = ql_aud_dtmf_tone_init();
audio_demo_no_err(err, goto exit, "init fail");
err = ql_aud_dtmf_play(AUDIOHAL_DTMF_4,1000,1000);// dtmf "4", play 1s, mute 1s
audio_demo_no_err(err, goto exit, "play fail");
ql_rtos_task_sleep_ms(200);
err = ql_aud_dtmf_play(AUDIOHAL_DTMF_5,500,500);// dtmf "5",play 0.5s, mute 0.5s
audio_demo_no_err(err, goto exit, "play fail");
ql_rtos_task_sleep_ms(200);
err = ql_aud_tone_play(300,1000,300,300); //tone freq1:300Hz freq2:1000Hz,play 0.3s, mute 0.3s
audio_demo_no_err(err, goto exit, "play fail");
exit:
ql_aud_tone_stop();
}
#ifdef QL_APP_FEATURE_AUDIO_RECORD
void test_poc_full_duplex(void)
{
QL_PCM_CONFIG_T config = {0};
int err = 0, cnt_read=0, cnt_write;
char *buffer = NULL;
static ql_demo_poc_t *demo_poc = NULL;
config.channels = 1; //单声道
config.samplerate = 16000;
ql_set_audio_path_earphone();
ql_aud_set_volume(QL_AUDIO_PLAY_TYPE_VOICE, AUDIOHAL_SPK_VOL_6); //POC mode use the param of voice call
buffer = calloc(1, 1024);
audio_demo_no_err(!buffer, return, "no memory");
demo_poc = calloc(1, sizeof(ql_demo_poc_t));
audio_demo_no_err(!demo_poc, return, "no memory");
demo_poc->recorder = ql_aud_pcm_open(&config, QL_AUDIO_FORMAT_PCM, QL_PCM_BLOCK_FLAG|QL_PCM_READ_FLAG, QL_PCM_POC);
audio_demo_no_err(!demo_poc->recorder, goto exit, "player created failed");
demo_poc->player = ql_aud_pcm_open(&config, QL_AUDIO_FORMAT_PCM, QL_PCM_BLOCK_FLAG|QL_PCM_WRITE_FLAG, QL_PCM_POC);
audio_demo_no_err(!demo_poc->player, goto exit, "player created failed");
err = ql_aud_start_poc_mode(QL_POC_TYPE_FULL_DUPLEX);
audio_demo_no_err(err, goto exit, "player created failed");
while(1)
{
memset(buffer, 0, 1024);
cnt_read = ql_pcm_read(demo_poc->recorder, buffer, 640);
audio_demo_no_err((cnt_read<=0), goto exit, "read data failed");
cnt_write = ql_pcm_write(demo_poc->player, buffer, cnt_read);
audio_demo_no_err((cnt_write!=cnt_read), goto exit, "read data failed");
}
exit:
if(buffer)
{
free(buffer);
}
ql_aud_stop_poc_mode(); //users must call "ql_aud_stop_poc_mode" then call "ql_pcm_close", otherwise may leed to some errors
if(demo_poc)
{
if(demo_poc->player)
{
ql_pcm_close(demo_poc->player);
}
if(demo_poc->recorder)
{
ql_pcm_close(demo_poc->recorder);
}
free(demo_poc);
}
}
void test_poc_half_duplex(void)
{
PCM_HANDLE_T recorder = NULL;
PCM_HANDLE_T player = NULL;
QL_PCM_CONFIG_T config;
void *data = NULL;
int size, total_size = 0, cnt=0, write_cnt=0;
int err=0;
config.channels = 1; //单声道
config.samplerate = 16000;
config.amrwb_param.amrwb_mode = AMRWB_MODE_2385;
data = calloc(1, 200*1024);
if(data == NULL)
{
goto exit;
}
ql_set_audio_path_earphone();
ql_aud_set_volume(QL_AUDIO_PLAY_TYPE_VOICE, AUDIOHAL_SPK_VOL_6); //POC mode use the param of voice call
recorder = ql_aud_pcm_open(&config, QL_AUDIO_FORMAT_PCM, QL_PCM_BLOCK_FLAG|QL_PCM_READ_FLAG, QL_PCM_POC);
audio_demo_no_err(!recorder, goto exit, "recorder created failed");
player = ql_aud_pcm_open(&config, QL_AUDIO_FORMAT_PCM, QL_PCM_BLOCK_FLAG|QL_PCM_WRITE_FLAG, QL_PCM_POC);
audio_demo_no_err(!player, goto exit, "player created failed");
err = ql_aud_start_poc_mode(QL_POC_TYPE_HALF_DUPLEX);
audio_demo_no_err(err, goto exit, "poc mode start failed");
err = ql_aud_poc_switch(QL_POC_MODE_REC);
audio_demo_no_err(err, goto exit, "poc mode switch failed");
//start record
while(total_size < 200*1024)
{
size = ql_pcm_read(recorder, data+total_size, 1024);
if(size <= 0)
{
break;
}
total_size += size;
}
err = ql_aud_poc_switch(QL_POC_MODE_PLAY);
audio_demo_no_err(err, goto exit, "poc mode switch failed");
while(write_cnt < total_size)
{
if(total_size - write_cnt > PACKET_WRITE_MAX_SIZE) //单次最多可写入 PACKET_WRITE_MAX_SIZE 字节
{
cnt = ql_pcm_write(player, data+write_cnt, PACKET_WRITE_MAX_SIZE);
}
else
{
cnt = ql_pcm_write(player, data+write_cnt, total_size - write_cnt);
}
if(cnt <= 0)
{
QL_AUDIO_LOG("write failed");
goto exit;
}
write_cnt += cnt;
}
while(ql_pcm_buffer_used(player)) //in poc mode, player will not stop if not ql_aud_stop_poc_mode called
{
ql_rtos_task_sleep_ms(20); //wait the write buffer empty
}
ql_rtos_task_sleep_ms(200);
exit:
ql_aud_stop_poc_mode(); //users must call "ql_aud_stop_poc_mode" then call "ql_pcm_close", otherwise may leed to some errors
ql_pcm_close(recorder);
ql_pcm_close(player);
if(data)
{
free(data);
}
QL_AUDIO_LOG("test done");
}
#endif
void ql_audio_app_init(void)
{
QlOSStatus err = QL_OSI_SUCCESS;
ql_task_t ql_audio_task = NULL;
QL_AUDIO_LOG("audio demo enter");
err = ql_rtos_task_create(&ql_audio_task, 4096*2, APP_PRIORITY_NORMAL, "ql_audio", ql_audio_demo_thread, NULL, 5);
if(err != QL_OSI_SUCCESS)
{
QL_AUDIO_LOG("audio task create failed");
}
err = ql_rtos_task_create(&ql_play_task, 4096, APP_PRIORITY_NORMAL, "ql_audio", ql_audio_play_thread, NULL, 2);
if(err != QL_OSI_SUCCESS)
{
QL_AUDIO_LOG("audio task create failed");
}
}
void test_amr_stream(void)
{
PCM_HANDLE_T PCM = NULL;
QL_PCM_CONFIG_T config;
void *data = NULL;
int total_size = 0, cnt=0, write_cnt=0;
config.channels = 1; //单声道
config.samplerate = 16000;
config.amrwb_param.amrwb_mode = AMRWB_MODE_2385;
#ifdef QL_APP_FEATURE_AUDIO_RECORD
int size=0;
PCM = ql_aud_pcm_open(&config, QL_AUDIO_FORMAT_AMRWB, QL_PCM_BLOCK_FLAG|QL_PCM_READ_FLAG, QL_PCM_LOCAL);
if(PCM == NULL)
{
QL_AUDIO_LOG("open pcm failed");
goto exit;
}
data = malloc(100*1024);
if(data == NULL)
{
goto exit;
}
QL_AUDIO_LOG("start read");
//start record
while(total_size < 10*1024)
{
size = ql_pcm_read(PCM, data+total_size, 41);
if(size <= 0)
{
break;
}
total_size += size;
}
QL_AUDIO_LOG("exit record");
if(total_size <= 0)
{
QL_AUDIO_LOG("read pcm failed");
goto exit;
}
QL_AUDIO_LOG("size is %d", total_size);
if(ql_pcm_close(PCM) != 0)
{
QL_AUDIO_LOG("close pcm failed");
goto exit;
}
PCM = NULL;
#endif
PCM = ql_aud_pcm_open(&config, QL_AUDIO_FORMAT_AMRWB, QL_PCM_BLOCK_FLAG|QL_PCM_WRITE_FLAG, QL_PCM_LOCAL);
if(PCM == NULL)
{
QL_AUDIO_LOG("open pcm failed");
goto exit;
}
while(write_cnt < total_size)
{
if(total_size - write_cnt > PACKET_WRITE_MAX_SIZE) //单次最多可写 PACKET_WRITE_MAX_SIZE 字节
{
cnt = ql_pcm_write(PCM, data+write_cnt, PACKET_WRITE_MAX_SIZE);
}
else
{
cnt = ql_pcm_write(PCM, data+write_cnt, total_size - write_cnt);
}
if(cnt <= 0)
{
QL_AUDIO_LOG("write failed");
goto exit;
}
write_cnt += cnt;
}
ql_aud_data_done();
ql_aud_wait_play_finish(QL_WAIT_FOREVER);
QL_AUDIO_LOG("play finish");
exit:
if(PCM != NULL)
{
ql_pcm_close(PCM);
}
if(data != NULL)
{
free(data);
data = NULL;
}
}
#ifdef QL_APP_FEATURE_AUDIO_RECORD
void test_record_stream(void)
{
ql_aud_config config = {0};
int cnt = 0, total_cnt=0, err;
config.amrwb_param.amrwb_mode = AMRWB_MODE_2385;
pcm_buffer = malloc(RECORD_BUFFER_MAX);
if(!pcm_buffer){
return;
}
/* 录音 */
if(ql_aud_record_stream_start_ex(&config, QL_REC_TYPE_MIC, QL_AUDIO_FORMAT_AMRWB, record_callback))
{
QL_AUDIO_LOG("record fail");
goto exit;
}
ql_rtos_task_sleep_s(5); //record 5s
ql_aud_record_stop();
if(pcm_data_size <= 0){
QL_AUDIO_LOG("data invalid");
goto exit;
}
/* 读取录音文件用于播放,此处也可调用 ql_aud_play_file_start,或者ql_pcm_open+ql_pcm_write去播放 */
ql_set_audio_path_speaker();
ql_set_volume(TEST_PLAY_VOLUME);
while(total_cnt < pcm_data_size)
{
if(pcm_data_size - total_cnt > PACKET_WRITE_MAX_SIZE) //单次最多可播放 PACKET_WRITE_MAX_SIZE 字节
{
cnt = PACKET_WRITE_MAX_SIZE;
err = ql_aud_play_stream_start(QL_AUDIO_FORMAT_AMRWB, pcm_buffer+total_cnt, cnt, QL_AUDIO_PLAY_TYPE_LOCAL, play_callback);
}
else
{
cnt = pcm_data_size - total_cnt;
err = ql_aud_play_stream_start(QL_AUDIO_FORMAT_AMRWB, pcm_buffer+total_cnt, cnt, QL_AUDIO_PLAY_TYPE_LOCAL, play_callback);
}
if(err < 0)
{
QL_AUDIO_LOG("start failed");
goto exit;
}
else
{
QL_AUDIO_LOG("play %d bytes, total %d", cnt, total_cnt);
total_cnt += cnt;
}
}
ql_aud_data_done();
ql_aud_wait_play_finish(QL_WAIT_FOREVER);
ql_aud_player_stop();
QL_AUDIO_LOG("test successful");
exit:
if(pcm_buffer){
free(pcm_buffer);
pcm_buffer = NULL;
pcm_data_size = 0;
}
}
void test_record_file(void)
{
ql_aud_config config = {0};
config.samplerate = 8000;
if(ql_aud_record_file_start(TEST_RECORD_WAV_NAME, &config, QL_REC_TYPE_MIC, NULL) != QL_AUDIO_SUCCESS)
{
QL_AUDIO_LOG("record failed");
return;
}
QL_AUDIO_LOG("record start");
ql_rtos_task_sleep_s(5); //record 5s
ql_aud_record_stop();
QL_AUDIO_LOG("record finish, start play");
ql_set_audio_path_speaker();
if(ql_aud_play_file_start(TEST_RECORD_WAV_NAME, QL_AUDIO_PLAY_TYPE_LOCAL, play_callback))
{
QL_AUDIO_LOG("play failed");
return;
}
ql_aud_wait_play_finish(QL_WAIT_FOREVER);
ql_aud_player_stop();
QL_AUDIO_LOG("test successful");
}
#endif
void test_mp3(void)
{
//检测MP3文件格式是否正确,防止误将其他格式的文件命名为MP3格式
//int err = check_audio_format(TEST_MP3_FILE_NAME);//路径为客户预置音频文件放置的路径
//if(err)
//{
//QL_AUDIO_LOG("err = %d",err);
//return;
//}
if(ql_aud_play_file_start(TEST_MP3_FILE_NAME, QL_AUDIO_PLAY_TYPE_LOCAL, play_callback))
{
QL_AUDIO_LOG("play failed");
return;
}
ql_aud_wait_play_finish(QL_WAIT_FOREVER);
if(ql_aud_play_file_start(TEST_MP3_FILE_NAME, QL_AUDIO_PLAY_TYPE_LOCAL, play_callback))
{
QL_AUDIO_LOG("play failed");
return;
}
ql_aud_wait_play_finish(QL_WAIT_FOREVER);
ql_aud_player_stop(); //播放结束,释放播放资源
QL_AUDIO_LOG("test mp3 successful");
}
void test_wav(void)
{
int cnt = 0;
//检测WAV文件格式是否正确,防止误将其他格式的文件命名为WAV格式
//int err = check_audio_format(TEST_WAV_FILE_NAME);//路径为客户预置音频文件放置的路径
//if(err)
//{
//QL_AUDIO_LOG("err = %d",err);
//return;
//}
if(ql_aud_play_file_start(TEST_WAV_FILE_NAME, QL_AUDIO_PLAY_TYPE_LOCAL, play_callback))
{
QL_AUDIO_LOG("play failed");
return;
}
ql_aud_wait_play_finish(QL_WAIT_FOREVER);
QL_AUDIO_LOG("play %d times ok", ++cnt);
if(ql_aud_play_file_start(TEST_WAV_FILE_NAME, QL_AUDIO_PLAY_TYPE_LOCAL, play_callback))
{
QL_AUDIO_LOG("play failed");
return;
}
ql_aud_wait_play_finish(QL_WAIT_FOREVER);
QL_AUDIO_LOG("play %d times ok", ++cnt);
ql_aud_player_stop(); //播放结束,释放播放资源
QL_AUDIO_LOG("test wav successful");
}
void test_amr(void)
{
int cnt = 0;
//检测AMR文件格式是否正确,防止误将其他格式的文件命名为AMR格式
//int err = check_audio_format(TEST_AMR_FILE_NAME);//路径为客户预置音频文件放置的路径
//if(err)
//{
//QL_AUDIO_LOG("err = %d",err);
//return;
//}
if(ql_aud_play_file_start(TEST_AMR_FILE_NAME, QL_AUDIO_PLAY_TYPE_LOCAL, play_callback))
{
QL_AUDIO_LOG("play failed");
}
ql_aud_wait_play_finish(QL_WAIT_FOREVER);
QL_AUDIO_LOG("play %d times ok", ++cnt);
if(ql_aud_play_file_start(TEST_AMR_FILE_NAME, QL_AUDIO_PLAY_TYPE_LOCAL, play_callback))
{
QL_AUDIO_LOG("play failed");
}
ql_aud_wait_play_finish(QL_WAIT_FOREVER);
QL_AUDIO_LOG("play %d times ok", ++cnt);
ql_aud_player_stop(); //播放结束,释放播放资源
QL_AUDIO_LOG("test wav successful");
}
void test_pcm(void)
{
PCM_HANDLE_T PCM = NULL;
QL_PCM_CONFIG_T config;
void *data = NULL;
int size=0, write_cnt=0, cnt=0;
config.channels = 1; //单声道
config.samplerate = 8000;
#ifdef QL_APP_FEATURE_AUDIO_RECORD
PCM = ql_pcm_open(&config, QL_PCM_BLOCK_FLAG|QL_PCM_READ_FLAG);
if(PCM == NULL)
{
QL_AUDIO_LOG("open pcm failed");
goto exit;
}
data = malloc(50*1024);
if(data == NULL)
{
goto exit;
}
QL_AUDIO_LOG("start read");
size = ql_pcm_read(PCM, data, 50*1024);
if(size <= 0)
{
QL_AUDIO_LOG("read pcm failed");
goto exit;
}
QL_AUDIO_LOG("size is %d", size);
if(ql_pcm_close(PCM) != 0)
{
QL_AUDIO_LOG("close pcm failed");
goto exit;
}
PCM = NULL;
#endif
ql_set_audio_path_speaker();
PCM = ql_pcm_open(&config, QL_PCM_BLOCK_FLAG|QL_PCM_WRITE_FLAG);
if(PCM == NULL)
{
QL_AUDIO_LOG("open pcm failed");
goto exit;
}
QL_AUDIO_LOG("start write");
while(write_cnt < size)
{
if(size - write_cnt > PACKET_WRITE_MAX_SIZE) //单次最多可播放 PACKET_WRITE_MAX_SIZE 字节
{
cnt = ql_pcm_write(PCM, data+write_cnt, PACKET_WRITE_MAX_SIZE);
}
else
{
cnt = ql_pcm_write(PCM, data+write_cnt, size - write_cnt);
}
if(cnt <= 0)
{
QL_AUDIO_LOG("write failed");
goto exit;
}
write_cnt += cnt;
}
ql_aud_data_done();
ql_aud_wait_play_finish(QL_WAIT_FOREVER);
QL_AUDIO_LOG("play done");
if(ql_pcm_close(PCM) != 0)
{
QL_AUDIO_LOG("close pcm failed");
goto exit;
}
PCM = NULL;
QL_AUDIO_LOG("play finish");
exit:
if(PCM != NULL)
{
ql_pcm_close(PCM);
}
if(data != NULL)
{
free(data);
data = NULL;
}
}
#ifdef QL_APP_FEATURE_EXT_CODEC
void test_codec(void)
{
ql_aud_codec_clk_enable();
ql_I2cInit(QL_AUDIO_IIC_CHANNEL, STANDARD_MODE);
aud_codec_init();
ql_switch_ext_codec(TRUE); //need reset, as dsp only read audio nv when start
}
void ALC5616_reg_nv_load(QL_HAL_CODEC_CFG_T *nv_cfg)
{
AUD_CODEC_REG_T init_reg[] = RT5616_NV_INIT_REG, \
close_reg[] = RT5616_NV_CLOSE_REG, \
sample_8k_reg[] = RT5616_NV_SAMPLE_8K_REG, \
sample_16k_reg[] = RT5616_NV_SAMPLE_16K_REG, \
sample_32k_reg[] = RT5616_NV_SAMPLE_32K_REG, \
sample_44_1k_reg[] = RT5616_NV_SAMPLE_44_1K_REG,\
sample_48k_reg[] = RT5616_NV_SAMPLE_48K_REG;
memset(&nv_cfg->initRegCfg[0], 0, 100*sizeof(AUD_CODEC_REG_T)); //clear codec init register nv
memset(&nv_cfg->closeRegCfg[0], 0, 50*sizeof(AUD_CODEC_REG_T)); //clear codec close register nv
memset(&nv_cfg->sampleRegCfg[0][0], 0, 120*sizeof(AUD_CODEC_REG_T)); //clear codec samprate register nv
memset(&nv_cfg->inpathRegCfg[0][0], 0, 120*sizeof(AUD_CODEC_REG_T)); //clear codec in path register nv
memset(&nv_cfg->outpathRegCfg[0][0], 0, 80*sizeof(AUD_CODEC_REG_T)); //clear codec output path register nv
memcpy(nv_cfg->initRegCfg, init_reg, sizeof(init_reg));
memcpy(nv_cfg->closeRegCfg, close_reg, sizeof(close_reg));
memcpy(&nv_cfg->sampleRegCfg[0], sample_8k_reg, sizeof(sample_8k_reg));
memcpy(&nv_cfg->sampleRegCfg[3], sample_16k_reg, sizeof(sample_16k_reg));
memcpy(&nv_cfg->sampleRegCfg[6], sample_32k_reg, sizeof(sample_32k_reg));
memcpy(&nv_cfg->sampleRegCfg[7], sample_44_1k_reg, sizeof(sample_44_1k_reg));
memcpy(&nv_cfg->sampleRegCfg[8], sample_48k_reg, sizeof(sample_48k_reg));
}
void NAU8810_reg_nv_load(QL_HAL_CODEC_CFG_T *nv_cfg)
{
AUD_CODEC_REG_T init_reg[] = NAU8810_NV_INIT_REG, \
close_reg[] = NAU8810_NV_CLOSE_REG, \
sample_8k_reg[] = NAU8810_NV_SAMPLE_8K_REG, \
sample_16k_reg[] = NAU8810_NV_SAMPLE_16K_REG, \
sample_32k_reg[] = NAU8810_NV_SAMPLE_32K_REG, \
sample_44_1k_reg[] = NAU8810_NV_SAMPLE_44_1K_REG,\
sample_48k_reg[] = NAU8810_NV_SAMPLE_48K_REG;
memset(&nv_cfg->initRegCfg[0], 0, 100*sizeof(AUD_CODEC_REG_T)); //clear codec init register nv
memset(&nv_cfg->closeRegCfg[0], 0, 50*sizeof(AUD_CODEC_REG_T)); //clear codec close register nv
memset(&nv_cfg->sampleRegCfg[0][0], 0, 120*sizeof(AUD_CODEC_REG_T)); //clear codec samprate register nv
memset(&nv_cfg->inpathRegCfg[0][0], 0, 120*sizeof(AUD_CODEC_REG_T)); //clear codec in path register nv
memset(&nv_cfg->outpathRegCfg[0][0], 0, 80*sizeof(AUD_CODEC_REG_T)); //clear codec output path register nv
memcpy(nv_cfg->initRegCfg, init_reg, sizeof(init_reg));
memcpy(nv_cfg->closeRegCfg, close_reg, sizeof(close_reg));
memcpy(&nv_cfg->sampleRegCfg[0], sample_8k_reg, sizeof(sample_8k_reg));
memcpy(&nv_cfg->sampleRegCfg[3], sample_16k_reg, sizeof(sample_16k_reg));
memcpy(&nv_cfg->sampleRegCfg[6], sample_32k_reg, sizeof(sample_32k_reg));
memcpy(&nv_cfg->sampleRegCfg[7], sample_44_1k_reg, sizeof(sample_44_1k_reg));
memcpy(&nv_cfg->sampleRegCfg[8], sample_48k_reg, sizeof(sample_48k_reg));
}
void ALC5616e_reg_nv_load(QL_HAL_CODEC_CFG_T *nv_cfg)
{
AUD_CODEC_REG_T init_reg[] = RT5616E_NV_INIT_REG, \
close_reg[] = RT5616E_NV_CLOSE_REG, \
sample_8k_reg[] = RT5616E_NV_SAMPLE_8K_REG, \
sample_16k_reg[] = RT5616E_NV_SAMPLE_16K_REG, \
sample_32k_reg[] = RT5616E_NV_SAMPLE_32K_REG;
memset(&nv_cfg->initRegCfg[0], 0, 100*sizeof(AUD_CODEC_REG_T)); //clear codec init register nv
memset(&nv_cfg->closeRegCfg[0], 0, 50*sizeof(AUD_CODEC_REG_T)); //clear codec close register nv
memset(&nv_cfg->sampleRegCfg[0][0], 0, 120*sizeof(AUD_CODEC_REG_T)); //clear codec samprate register nv
memset(&nv_cfg->inpathRegCfg[0][0], 0, 120*sizeof(AUD_CODEC_REG_T)); //clear codec in path register nv
memset(&nv_cfg->outpathRegCfg[0][0], 0, 80*sizeof(AUD_CODEC_REG_T)); //clear codec output path register nv
memcpy(nv_cfg->initRegCfg, init_reg, sizeof(init_reg));
memcpy(nv_cfg->closeRegCfg, close_reg, sizeof(close_reg));
memcpy(&nv_cfg->sampleRegCfg[0], sample_8k_reg, sizeof(sample_8k_reg));
memcpy(&nv_cfg->sampleRegCfg[3], sample_16k_reg, sizeof(sample_16k_reg));
memcpy(&nv_cfg->sampleRegCfg[6], sample_32k_reg, sizeof(sample_32k_reg));
}
//switch to ext codec ,need reset
ql_audio_errcode_e ql_switch_ext_codec(bool enable)
{
ql_audio_errcode_e err = QL_AUDIO_SUCCESS;
uint16 codec_id;
QL_HAL_CODEC_CFG_T *halCodecCfg = NULL;
halCodecCfg = calloc(1, sizeof(QL_HAL_CODEC_CFG_T));
if(!halCodecCfg){
return QL_AUDIO_UNKNOWN_ERROR;
}
err = ql_aud_codec_read_nv(halCodecCfg);
audio_demo_no_err(err, goto exit, "read failed");
switch(enable)
{
case 1: //ext codec
err = ql_audio_iic_read(RT5616E_I2C_SLAVE_ADDR, RT5616E_VENDOR_ID_REG, 2, &codec_id); //read 5616e firstly, if is not 5616e, then read other codec id
//at_audio_no_err(err, goto exit, "read codec failed");
if(codec_id == RT5616E_VENDOR_ID) //init codec 5616e nv
{
QL_AUDIO_LOG("ext codec is ALC5616E, start config");
halCodecCfg->i2cCfg.id = (QL_AUDIO_IIC_CHANNEL == i2c_1 ? 0:1); //0 for use iic1, 1 for use iic 2, and iic 2 is default
halCodecCfg->basicCfg.iic_data_width = 3; //iic register 16bit, hsb first
halCodecCfg->basicCfg.codecAddr = RT5616E_I2C_SLAVE_ADDR; //iic addr, dsp will use it to connect codec
ALC5616e_reg_nv_load(halCodecCfg); //load 5616e register to struct
}
else
{
err = ql_audio_iic_read(RT5616_I2C_SLAVE_ADDR, RT5616_VENDOR_ID_REG, 1, &codec_id); //read 5616 firstly, if is not 5616, then read other codec id
//at_audio_no_err(err, goto exit, "read codec failed");
if(codec_id == RT5616_VENDOR_ID) //init codec 5616 nv
{
QL_AUDIO_LOG("ext codec is ALC5616, start config");
halCodecCfg->i2cCfg.id = (QL_AUDIO_IIC_CHANNEL == i2c_1 ? 0:1); //0 for use iic1, 1 for use iic 2, and iic 2 is default
halCodecCfg->basicCfg.iic_data_width = 3; //iic register 16bit, hsb first
halCodecCfg->basicCfg.codecAddr = RT5616_I2C_SLAVE_ADDR; //iic addr, dsp will use it to connect codec
ALC5616_reg_nv_load(halCodecCfg); //load 5616 register to struct
}
else
{
err = ql_audio_iic_read(NAU8810_I2C_SLAVE_ADDR, NAU8810_VENDOR_ID_REG, 1, &codec_id); //read 8810 firstly, if is not 8810, then read other codec id
audio_demo_no_err(err, goto exit, "read codec failed");
if(codec_id == NAU8810_VENDOR_ID)
{
QL_AUDIO_LOG("ext codec is NAU8810, start config");
halCodecCfg->i2cCfg.id = (QL_AUDIO_IIC_CHANNEL == i2c_1 ? 0:1); //0 for use iic1, 1 for use iic 2, and iic 2 is default
halCodecCfg->basicCfg.iic_data_width = 1; //iic register 9bit, hsb first
halCodecCfg->basicCfg.codecAddr = NAU8810_I2C_SLAVE_ADDR; //iic addr, dsp will use it to connect codec
NAU8810_reg_nv_load(halCodecCfg); //load 8810 register to struct
}
else
{
err = QL_AUDIO_OPER_NOT_SUPPORTED;
audio_demo_no_err(err, goto exit, "not support current codec");
}
}
}
halCodecCfg->basicCfg.externalCodec = 1; //switch to ext codec
err = ql_aud_codec_write_nv(halCodecCfg);
audio_demo_no_err(err, goto exit, "write nv failed");
break;
case 0: //internal codec
halCodecCfg->basicCfg.externalCodec = 0;
err = ql_aud_codec_write_nv(halCodecCfg);
audio_demo_no_err(err, goto exit, "write nv failed");
break;
}
exit:
if(halCodecCfg){
free(halCodecCfg);
}
return err;
}
ql_audio_errcode_e aud_codec_init(void)
{
int err = QL_AUDIO_SUCCESS, i=0;
uint16 codec_id;
QL_HAL_CODEC_CFG_T *halCodecCfg = NULL;
halCodecCfg = calloc(1, sizeof(QL_HAL_CODEC_CFG_T));
audio_demo_no_err(!halCodecCfg, return QL_AUDIO_UNKNOWN_ERROR, "malloc memory failed");
err = ql_aud_codec_read_nv(halCodecCfg);
audio_demo_no_err(err, goto exit, "read failed");
if(halCodecCfg->basicCfg.externalCodec) //1 for use external codec
{
QL_AUDIO_LOG("codec iic addr is %p, clk mode is %d", halCodecCfg->basicCfg.codecAddr, halCodecCfg->i2cCfg.clockMode);
ql_aud_codec_clk_enable();
err = ql_audio_iic_read(RT5616_I2C_SLAVE_ADDR, RT5616_VENDOR_ID_REG, 2, &codec_id);
// require_action(err, goto exit, "read codec failed");
if(codec_id == RT5616_VENDOR_ID) //init codec 5616
{
AUD_CODEC_REG_T reg_list[] = RT5616_INIT_REG;
for (i = 0; i < sizeof(reg_list)/sizeof(reg_list[0]); i++)
{
err = ql_audio_iic_write(RT5616_I2C_SLAVE_ADDR, reg_list[i].regAddr, 2, reg_list[i].val);
audio_demo_no_err(err, goto exit, "write codec register fail");
}
}
else //NAU8810 support now
{
err = ql_audio_iic_read(NAU8810_I2C_SLAVE_ADDR, NAU8810_VENDOR_ID_REG, 2, &codec_id);
audio_demo_no_err(err, goto exit, "read codec failed");
if(codec_id == NAU8810_VENDOR_ID) //init codec 8810
{
AUD_CODEC_REG_T reg_list[] = NAU8810_INIT_REG;
for (i = 0; i < sizeof(reg_list)/sizeof(reg_list[0]); i++)
{
err = ql_audio_iic_write(NAU8810_I2C_SLAVE_ADDR, reg_list[i].regAddr, 1, reg_list[i].val);
audio_demo_no_err(err, goto exit, "write codec register fail");
}
}
else
{
err = QL_AUDIO_UNKNOWN_ERROR;
audio_demo_no_err(err, goto exit, "codec not valid");
}
}
}
exit:
if(halCodecCfg){
free(halCodecCfg);
}
return err;
}
static ql_audio_errcode_e ql_rt5616_write_reg(uint8 RegAddr, uint16 RegData)
{
ql_audio_errcode_e status = QL_AUDIO_SUCCESS;
uint8 param_data[3] = {0x00};
uint8 retry_count = 5;
param_data[0] = (uint8)((RegData >> 8) & 0xFF);
param_data[1] = (uint8)(RegData & 0xff);
do
{
status = (ql_audio_errcode_e)ql_I2cWrite(QL_AUDIO_IIC_CHANNEL, RT5616_I2C_SLAVE_ADDR, RegAddr, param_data, 2);
if (status != QL_AUDIO_SUCCESS)
{
QL_AUDIO_LOG("Error:[%dth] device[0x%x] addr[0x%x] data[0x%x] failed", retry_count, RT5616_I2C_SLAVE_ADDR, RegAddr, RegData);
}
else
{
break;
}
} while (--retry_count);
return (status == 0 ? QL_AUDIO_SUCCESS : QL_AUDIO_CODEC_WR_FAIL);
}
static ql_audio_errcode_e ql_rt5616_read_reg(uint8 RegAddr, uint16 *p_value)
{
ql_audio_errcode_e status = QL_AUDIO_SUCCESS;
uint8 temp_buf[2];
uint8 retry_count = 5;
do
{
status = (ql_audio_errcode_e)ql_I2cRead(QL_AUDIO_IIC_CHANNEL, RT5616_I2C_SLAVE_ADDR, RegAddr, temp_buf, 2);
if (status != QL_AUDIO_SUCCESS)
{
QL_AUDIO_LOG("Error:[%dth] device[0x%x] addr[0x%x] failed", retry_count, RT5616_I2C_SLAVE_ADDR, RegAddr);
}
else
{
*p_value = (((uint16)temp_buf[0]) << 8) | temp_buf[1];
break;
}
} while (--retry_count);
return (status == 0 ? QL_AUDIO_SUCCESS : QL_AUDIO_CODEC_RD_FAIL);
}
static ql_audio_errcode_e ql_nau8810_write_reg(uint8 RegAddr, uint16 RegData)
{
ql_audio_errcode_e status = QL_AUDIO_SUCCESS;
uint8 param_data[3] = {0x00};
uint8 retry_count = 5;
param_data[0] = (uint8)((RegData >> 8) & 0xFF);
param_data[1] = (uint8)(RegData & 0xff);
RegAddr = (RegAddr << 1) & 0xFE;
RegAddr = RegAddr|((RegData>>8)&0x01);
param_data[0] = (uint8)(RegData & 0xFF);
do
{
status = (ql_audio_errcode_e)ql_I2cWrite(QL_AUDIO_IIC_CHANNEL, NAU8810_I2C_SLAVE_ADDR, RegAddr, param_data, 1);
if (status != QL_AUDIO_SUCCESS)
{
QL_AUDIO_LOG("Error:[%dth] device[0x%x] addr[0x%x] data[0x%x] failed", retry_count, NAU8810_I2C_SLAVE_ADDR, RegAddr, RegData);
}
} while (--retry_count);
return (status == 0 ? QL_AUDIO_SUCCESS : QL_AUDIO_CODEC_WR_FAIL);
}
static ql_audio_errcode_e ql_nau8810_read_reg(uint8 RegAddr, uint16 *p_value)
{
ql_audio_errcode_e status = QL_AUDIO_SUCCESS;
uint8 temp_buf[2];
uint8 retry_count = 5;
RegAddr = (RegAddr << 1) & 0xFE;
do
{
status = (ql_audio_errcode_e)ql_I2cRead(QL_AUDIO_IIC_CHANNEL, NAU8810_I2C_SLAVE_ADDR, RegAddr, temp_buf, 2);
if (status != QL_AUDIO_SUCCESS)
{
QL_AUDIO_LOG("Error:[%dth] device[0x%x] addr[0x%x] failed", retry_count, NAU8810_I2C_SLAVE_ADDR, RegAddr);
}
else
{
*p_value = (((uint16)temp_buf[0]) << 8) | temp_buf[1];
break;
}
} while (--retry_count);
return (status == 0 ? QL_AUDIO_SUCCESS : QL_AUDIO_CODEC_RD_FAIL);
}
#ifdef QL_CODEC_5616E_SUPPORT
static ql_audio_errcode_e ql_rt5616e_write_reg(uint16 RegAddr, uint16 RegData)
{
ql_audio_errcode_e status = QL_AUDIO_SUCCESS;
uint8 param_data[3] = {0x00};
uint8 retry_count = 5;
param_data[0] = (uint8)((RegData >> 8) & 0xFF);
param_data[1] = (uint8)(RegData & 0xff);
do
{
status = (ql_audio_errcode_e)ql_I2cWrite_16bit_addr(QL_AUDIO_IIC_CHANNEL, RT5616E_I2C_SLAVE_ADDR, RegAddr, param_data, 2);
if (status != QL_AUDIO_SUCCESS)
{
QL_AUDIO_LOG("Error:[%dth] device[0x%x] addr[0x%x] data[0x%x] failed", retry_count, RT5616E_I2C_SLAVE_ADDR, RegAddr, RegData);
}
} while (--retry_count);
return (status == 0 ? QL_AUDIO_SUCCESS : QL_AUDIO_CODEC_WR_FAIL);
}
static ql_audio_errcode_e ql_rt5616e_read_reg(uint16 RegAddr, uint16 *p_value)
{
ql_audio_errcode_e status = QL_AUDIO_SUCCESS;
uint8 temp_buf[2];
uint8 retry_count = 5;
do
{
status = (ql_audio_errcode_e)ql_I2cRead_16bit_addr(QL_AUDIO_IIC_CHANNEL, RT5616E_I2C_SLAVE_ADDR, RegAddr, temp_buf, 2);
if (status != QL_AUDIO_SUCCESS)
{
QL_AUDIO_LOG("Error:[%dth] device[0x%x] addr[0x%x] failed", retry_count, RT5616E_I2C_SLAVE_ADDR, RegAddr);
}
else
{
*p_value = (((uint16)temp_buf[0]) << 8) | temp_buf[1];
break;
}
} while (--retry_count);
return (status == 0 ? QL_AUDIO_SUCCESS : QL_AUDIO_CODEC_RD_FAIL);
}
#endif
ql_audio_errcode_e ql_audio_iic_read(uint8 dev_addr, uint16 reg_addr, uint8 size, uint16 *p_val)
{
ql_audio_errcode_e err = 0;
/* 5616 */
if(0x1B == dev_addr)
{
err = ql_rt5616_read_reg((uint8)reg_addr, p_val);
}
/* 8810 */
else if (0x1A == dev_addr)
{
// support now
err = ql_nau8810_read_reg((uint8)reg_addr, p_val);
}
else
{
return QL_AUDIO_INVALID_PARAM;
}
return err;
}
ql_audio_errcode_e ql_audio_iic_write(uint8 dev_addr, uint16 reg_addr, uint8 size, uint16 val)
{
ql_audio_errcode_e err = QL_AUDIO_SUCCESS;
/* 5616 */
if(0x1B == dev_addr)
{
err = ql_rt5616_write_reg((uint8)reg_addr, val);
}
/* 8810 */
else if (0x1A == dev_addr)
{
// support now
err = ql_nau8810_write_reg((uint8)reg_addr, val);
}
else
{
return QL_AUDIO_INVALID_PARAM;
}
return err;
}
#endif
#ifdef QL_APP_FEATURE_HEADSET_DET
void _ql_headset_det_debounce_callback(void *ctx)
{
if( headset_det_debounce_timer == NULL || ql_rtos_timer_is_running(headset_det_debounce_timer) )
{
return;
}
ql_rtos_timer_start(headset_det_debounce_timer, QL_HEADSET_DETECT_DEBOUNCE_TIME, 1);
QL_AUDIO_LOG("headset timer start");
}
static void _ql_headset_detect_callback(void *ctx)
{
ql_LvlMode headsetdet_value;
ql_event_t event;
ql_rtos_timer_stop(headset_det_debounce_timer);
event.id = QUEC_HEADSET_DET_EVENT_IND;
ql_gpio_get_level(QL_HEADSET_DETECT_GPIO, &headsetdet_value);
if( headsetdet_value == LVL_LOW ) //detect plug_in
{
event.param1 = DEMO_HEADSET_DETECT_PLUG_IN;
}
else/* headsetdet_value == LVL_HIGH */ //detect plug_out
{
event.param1 = DEMO_HEADSET_DETECT_PLUG_OUT;
}
ql_rtos_event_send(headset_det_task, &event);
}
int ql_headset_det_pin_init(void)
{
int err;
err = ql_pin_set_func(QL_HEADSET_DETECT_PIN, QL_HEADSET_DETECT_FUNC_GPIO);
if( err != QL_GPIO_SUCCESS )
{
QL_AUDIO_LOG("headset_det err = %d", err);
return err;
}
return 0;
}
int ql_headset_det_interrupt_init(void)
{
int err;
err = ql_int_register(QL_HEADSET_DETECT_GPIO, EDGE_TRIGGER, DEBOUNCE_EN, EDGE_BOTH, PULL_UP, _ql_headset_det_debounce_callback, NULL);
if( err != QL_GPIO_SUCCESS )
{
QL_AUDIO_LOG("headset_det err = %d", err);
return err;
}
ql_int_enable(QL_HEADSET_DETECT_GPIO);
return 0;
}
static void ql_headset_det_demo_thread(void *param)
{
QL_AUDIO_LOG("headset_det demo thread enter, param 0x%x", param);
ql_event_t event;
if( ql_headset_det_pin_init() != 0 )
{
QL_AUDIO_LOG("headset_det pin init failed");
ql_rtos_task_delete(NULL);
}
if( ql_headset_det_interrupt_init() != 0 )
{
QL_AUDIO_LOG("headset_det interrupt init failed");
ql_rtos_task_delete(NULL);
}
ql_LvlMode headsetdet_value;
ql_gpio_get_level(QL_HEADSET_DETECT_GPIO, &headsetdet_value);
if( headsetdet_value == LVL_LOW ) //detect plug_in
{
QL_AUDIO_LOG("start up headset plug_in");
ql_set_audio_path_earphone();
}
else/* headsetdet_value == LVL_HIGH */ //detect plug_out
{
QL_AUDIO_LOG("start up headset plug_out");
ql_set_audio_path_speaker();
}
while(1)
{
if( ql_event_try_wait(&event) != 0 )
{
continue;
}
if( event.id == QUEC_HEADSET_DET_EVENT_IND )
{
if( event.param1 == DEMO_HEADSET_DETECT_PLUG_IN )
{
QL_AUDIO_LOG("headset_det detect plug_in");
ql_aud_player_pause();
ql_set_audio_path_earphone();
ql_aud_player_resume();
}
else if( event.param1 == DEMO_HEADSET_DETECT_PLUG_OUT )
{
QL_AUDIO_LOG("headset_det detect plug_out");
ql_aud_player_pause();
ql_set_audio_path_speaker();
ql_aud_player_resume();
}
}
}
ql_rtos_task_delete(NULL);
}
void ql_headset_det_app_init(void)
{
QlOSStatus err = QL_OSI_SUCCESS;
err = ql_rtos_task_create(&headset_det_task, 1024, APP_PRIORITY_NORMAL, "ql_headset_demo", ql_headset_det_demo_thread, NULL, 1);
if( err != QL_OSI_SUCCESS )
{
QL_AUDIO_LOG("headset_det demo task created failed");
}
err = ql_rtos_timer_create(&headset_det_debounce_timer, headset_det_task, _ql_headset_detect_callback, NULL);
if( err != QL_OSI_SUCCESS )
{
QL_AUDIO_LOG("headset_det demo timer created failed");
}
}
#endif
// only for EC600U
static void _headset_EC600U_callback(QL_HEADSET_CBTYPE_E cb_type, uint32_t param)
{
ql_event_t event;
switch(cb_type)
{
case QL_HEADSET_CBTYPE_PLUG_IN:
event.id = QUEC_HEADSET_PLUG_IN_IND;
break;
case QL_HEADSET_CBTYPE_PLUG_OUT:
event.id = QUEC_HEADSET_PLUG_OUT_IND;
break;
case QL_HEADSET_CBTYPE_BTN_DOWN:
event.id = QUEC_HEADSET_BTN_DOWN_IND;
break;
case QL_HEADSET_CBTYPE_BTN_UP:
event.id = QUEC_HEADSET_BTN_UP_IND;
break;
default:
break;
}
event.param1 = param;
ql_rtos_event_send(headset_EC600U_task, &event);
}
static void ql_headset_EC600U_demo_thread(void *param)
{
QL_AUDIO_LOG("headset_btn demo thread enter, param 0x%x", param);
ql_event_t event;
// needed callback type with [or] operation
ql_headset_info_t headset_info = { _headset_EC600U_callback, QL_HEADSET_CBTYPE_PLUG_IN|QL_HEADSET_CBTYPE_PLUG_OUT|QL_HEADSET_CBTYPE_BTN_DOWN|QL_HEADSET_CBTYPE_BTN_UP };
ql_headset_cb_register(headset_info);
/* audio path init */
QL_HEADSET_PLUGSTATUS_E plug_status = QL_HEADSET_PLUGSTATUS_OUT;
ql_headset_plug_status_get(&plug_status);
if( plug_status == QL_HEADSET_PLUGSTATUS_OUT )
{
ql_set_audio_path_speaker(); // change to speaker
}
else
{
ql_set_audio_path_earphone(); // change to headset
}
/* get current audio path */
int in_path = -1;
int out_path = -1;
in_path = ql_aud_get_input_type();
out_path = ql_aud_get_output_type();
QL_AUDIO_LOG("headset_btn demo start in_path[%d] out_path[%d]", in_path, out_path);
while(1)
{
if( ql_event_try_wait(&event) != 0 )
{
continue;
}
switch(event.id)
{
case QUEC_HEADSET_PLUG_IN_IND:
QL_AUDIO_LOG("headset plug in type [%d]", event.param1);
/* do something */
in_path = ql_aud_get_input_type();
out_path = ql_aud_get_output_type();
QL_AUDIO_LOG("headset_btn before plug in in_path[%d] out_path[%d]", in_path, out_path);
ql_set_audio_path_earphone(); // change to headset
in_path = ql_aud_get_input_type();
out_path = ql_aud_get_output_type();
QL_AUDIO_LOG("headset_btn after plug in in_path[%d] out_path[%d]", in_path, out_path);
break;
case QUEC_HEADSET_PLUG_OUT_IND:
QL_AUDIO_LOG("headset plug out type [%d]", event.param1);
/* do something */
in_path = ql_aud_get_input_type();
out_path = ql_aud_get_output_type();
QL_AUDIO_LOG("headset_btn before plug out in_path[%d] out_path[%d]", in_path, out_path);
ql_set_audio_path_speaker(); // change to speaker
in_path = ql_aud_get_input_type();
out_path = ql_aud_get_output_type();
QL_AUDIO_LOG("headset_btn after plug in in_path[%d] out_path[%d]", in_path, out_path);
break;
case QUEC_HEADSET_BTN_DOWN_IND:
QL_AUDIO_LOG("headset button down adc_value [%d]", event.param1);
/* do something */
out_path = ql_aud_get_output_type();
QL_AUDIO_LOG("headset_btn demo button down out_path[%d]", out_path);
break;
case QUEC_HEADSET_BTN_UP_IND:
QL_AUDIO_LOG("headset button up adc_value [%d]", event.param1);
/* do something */
out_path = ql_aud_get_output_type();
QL_AUDIO_LOG("headset_btn demo button up out_path[%d]", out_path);
break;
default:
break;
}
}
ql_rtos_task_delete(NULL);
}
void ql_headset_EC600U_app_init(void)
{
QlOSStatus err = QL_OSI_SUCCESS;
err = ql_rtos_task_create(&headset_EC600U_task, 1024, APP_PRIORITY_NORMAL, "600hs_demo", ql_headset_EC600U_demo_thread, NULL, 1);
if( err != QL_OSI_SUCCESS )
{
QL_AUDIO_LOG("headset_btn demo task created failed");
}
}
// only for EC600U