其他:线程严禁不加阻塞
线程严禁空转
线程严禁在做一些简单的判断标志位的操作同时,去在其他的线程改变标志位
信号量同步数据,实现d40的speark提示音和播放数据流同步
注意信号量初始化应该为0,这样子在awi_audio2_speaker_proc准备好可以开始awi_alsa_play2_write的时候,在给出满信号量,实现数据的开始同步
#include "awi_audio2_speaker.h"
#include "awi_audio2_tips.h"
#include "awi_audio2_module.h"
typedef enum {
/*1*/AWI_AUDIO2_SPEAKER_MSG_EVENT_TIPS_START,
/*2*/AWI_AUDIO2_SPEAKER_MSG_EVENT_TIPS_DATA,
/*3*/AWI_AUDIO2_SPEAKER_MSG_EVENT_TIPS_STOP,
}awi_audio2_speaker_msg_event_t;
typedef void(*_msg_callback_func)(void *ths);
typedef struct {
awi_queue_node_t hoard_n;
awi_queue_node_t q_n;
uint8_t buffer[AWI_AUDIO2_SPEAKER_PLAY_BUFFER_SIZE];
void *cb_ths;
_msg_callback_func cb_func;
awi_audio2_speaker_msg_event_t event;
}awi_audio2_speaker_msg_t;
static awi_alsa_play2_params_t speaker_params = {
.sample_rate = AWI_AUDIO2_SPEAKER_PLAY_SAMPLE_RATE,
.channel = AWI_AUDIO2_SPEAKER_PLAY_CHANNEL,
.format = SND_PCM_FORMAT_S16_LE,
.period_time = AWI_AUDIO2_SPEAKER_PLAY_STEP_MS * 1000,
.buffer_time = AWI_AUDIO2_SPEAKER_PLAY_STEP_MS * 4 * 1000,
.dev_name = AWI_AUDIO2_SPEAKER_PLAY_DEV_NAME,
};
static uint8_t algo_buffer[AWI_AUDIO2_SPEAKER_PLAY_BUFFER_SIZE];
static uint8_t date_buffer[AWI_AUDIO2_SPEAKER_PLAY_BUFFER_SIZE];
static awi_audio2_module_t *audio2;
static awi_audio2_speaker_msg_t* awi_audio2_speaker_msg_new(awi_audio2_speaker_t *speaker)
{
return (awi_audio2_speaker_msg_t*)awi_malloc(sizeof(awi_audio2_speaker_msg_t));
}
static void awi_audio2_speaker_msg_del(awi_audio2_speaker_msg_t *msg)
{
if(NULL != msg) {
awi_free(msg);
}
}
static awi_audio2_speaker_msg_t* awi_audio2_speaker_pop_msg(awi_audio2_speaker_t *speaker)
{
awi_audio2_speaker_msg_t *msg;
msg = (awi_audio2_speaker_msg_t*)awi_lockhoard_pop(&speaker->msg_hoard);
if(NULL != msg) {
msg->cb_func = NULL;
msg->cb_ths = NULL;
}
return msg;
}
static void awi_audio2_speaker_push_msg(awi_audio2_speaker_t *speaker, awi_audio2_speaker_msg_t *msg)
{
awi_lockhoard_push(&speaker->msg_hoard, msg);
}
static void awi_to_tip(const short* pv_src, short *pv_dst, int frames)
{
float ratio = AWI_AUDIO2_MODULE_AUDIO_IN_TIPS_GAIN * audio2->tips_volume / AWI_AUDIO2_MODULE_PLAY_VOLUME_MAX;
for(int i = 0; i < frames; ++i) {
pv_dst[i] = ratio * pv_src[i];
}
}
static void awi_to_mix(const short* pv_src, const short* pv_tip_src, short *pv_dst, int frames)
{
float ratio = AWI_AUDIO2_MODULE_AUDIO_IN_TIPS_GAIN * audio2->tips_volume / AWI_AUDIO2_MODULE_PLAY_VOLUME_MAX;
for(int i = 0; i < frames; ++i) {
pv_dst[i] = pv_src[i] + ratio * pv_tip_src[i];
}
}
static void d40_awi_arrange_speaker_data_to_one(const short *src_buff, short *dst_buff, int len)
{
for(int i = 0, j = 0; i < len; i += 1, j +=2)
{
dst_buff[i] = src_buff[j];
}
}
static void d40_awi_arrange_speaker_data_to_two(const short *src_buff, short *dst_buff, int len)
{
for(int i = 0, j = 0; i < len; i += 2, j +=1)
{
dst_buff[i] = src_buff[j];
dst_buff[i+1] = src_buff[j];
}
}
static void awi_audio2_speaker_clean_cache_q(awi_audio2_speaker_t *speaker, awi_lockqueue_t *q)
{
while(1) {
awi_queue_node_t *qn = awi_lockqueue_pop(q);
if(NULL == qn) {
break;
}
awi_audio2_speaker_msg_t *msg = awi_offset(qn, awi_audio2_speaker_msg_t, q_n);
if(NULL != msg->cb_func) {
msg->cb_func(msg->cb_ths);
}
awi_audio2_speaker_push_msg(speaker, msg);
}
}
static void awi_audio2_speaker_on_tips(awi_audio2_speaker_t *speaker, awi_audio2_tips_event_t event, const uint8_t *buffer, int bytes,
void *cb_ths, awi_audio2_tips_cb_func cb_func)
{
awi_audio2_speaker_msg_t *msg;
switch(event) {
case AWI_AUDIO2_TIPS_EVENT_START:
msg = awi_audio2_speaker_pop_msg(speaker);
if(NULL != msg) {
msg->event = AWI_AUDIO2_SPEAKER_MSG_EVENT_TIPS_START;
msg->cb_func = cb_func;
msg->cb_ths = cb_ths;
awi_blockqueue_push(&speaker->msg_tip_bq, &msg->q_n);
} else if(cb_func != NULL) {
cb_func(cb_ths);
}
break;
case AWI_AUDIO2_TIPS_EVENT_DATA:
msg = awi_audio2_speaker_pop_msg(speaker);
if(NULL != msg) {
msg->event = AWI_AUDIO2_SPEAKER_MSG_EVENT_TIPS_DATA;
memcpy(msg->buffer, buffer, bytes);
msg->cb_func = cb_func;
msg->cb_ths = cb_ths;
awi_blockqueue_push(&speaker->msg_tip_bq, &msg->q_n);
} else if(cb_func != NULL) {
cb_func(cb_ths);
}
break;
case AWI_AUDIO2_TIPS_EVENT_STOP:
msg = awi_audio2_speaker_pop_msg(speaker);
if(NULL != msg) {
msg->event = AWI_AUDIO2_SPEAKER_MSG_EVENT_TIPS_STOP;
msg->cb_func = cb_func;
msg->cb_ths = cb_ths;
awi_blockqueue_push(&speaker->msg_tip_bq, &msg->q_n);
} else if(cb_func != NULL) {
cb_func(cb_ths);
}
break;
}
}
static void* awi_audio2_speaker_for_tip_proc(void *arg)
{
awi_audio2_speaker_t *speaker;
awi_queue_node_t *qn;
awi_audio2_speaker_msg_t *msg;
speaker = (awi_audio2_speaker_t*)arg;
while(speaker->runing) {
qn = awi_blockqueue_pop(&speaker->msg_tip_bq, -1);
if(NULL == qn) {
continue;
}
msg = awi_offset(qn, awi_audio2_speaker_msg_t, q_n);
switch(msg->event) {
case AWI_AUDIO2_SPEAKER_MSG_EVENT_TIPS_START:
// aw_print("AWI_AUDIO2_SPEAKER_MSG_EVENT_TIPS_START");
awi_audio2_speaker_start(speaker);
if(audio2->is_tipsing == false) {
audio2->is_tipsing = true;
}
break;
case AWI_AUDIO2_SPEAKER_MSG_EVENT_TIPS_STOP:
// aw_print("AWI_speaker_MODULE_MSG_EVENT_TIPS_STOP");
if(audio2->is_tipsing == true) {
audio2->is_tipsing = false;
awi_audio2_speaker_clean_cache_q(speaker, &speaker->msg_tip_q);
}
if(audio2->bt_ining == false && audio2->uac_outing == false &&
audio2->is_tipsing == false) {
awi_audio2_speaker_stop(speaker);
}
break;
case AWI_AUDIO2_SPEAKER_MSG_EVENT_TIPS_DATA:
if(audio2->is_tipsing == true) {
awi_lockqueue_push(&speaker->msg_tip_q, &msg->q_n);
msg = NULL;
}
default:
break;
}
if(NULL != msg) {
if(NULL != msg->cb_func) {
msg->cb_func(msg->cb_ths);
}
awi_audio2_speaker_push_msg(speaker, msg);
}
}
awi_audio2_speaker_clean_cache_q(speaker, &speaker->msg_tip_q);
return NULL;
}
static void* awi_audio2_speaker_date_proc(void *arg)
{
awi_audio2_speaker_t *speaker;
// uint8_t buffer[AWI_AUDIO2_SPEAKER_PLAY_BUFFER_SIZE];
awi_audio2_speaker_msg_t *msg = NULL;
awi_audio2_speaker_msg_t *tip_msg = NULL;
speaker = (awi_audio2_speaker_t*)arg;
while(speaker->runing == true) {
// if(speaker->playing == true) {
awi_queue_node_t *qn;
awi_queue_node_t *qn_tip;
qn = awi_lockqueue_pop(&speaker->msg_q);
qn_tip = awi_lockqueue_pop(&speaker->msg_tip_q);
if(NULL == qn && NULL == qn_tip) {
memset(date_buffer, 0x00, AWI_AUDIO2_SPEAKER_PLAY_BUFFER_SIZE);
//aw_print("-20");//debug
} else if(NULL != qn && NULL == qn_tip){
msg = awi_offset(qn, awi_audio2_speaker_msg_t, q_n);
memcpy(date_buffer, msg->buffer, AWI_AUDIO2_SPEAKER_PLAY_BUFFER_SIZE);
//aw_print("-21");//debug
}else if(NULL == qn && NULL != qn_tip){
tip_msg = awi_offset(qn_tip, awi_audio2_speaker_msg_t, q_n);
awi_to_tip((const short*)tip_msg->buffer, (short*)date_buffer, AWI_AUDIO2_SPEAKER_PLAY_BUFFER_SIZE/2);
//aw_print("-22");//debug
}else if(NULL != qn && NULL != qn_tip){
msg = awi_offset(qn, awi_audio2_speaker_msg_t, q_n);
tip_msg = awi_offset(qn_tip, awi_audio2_speaker_msg_t, q_n);
awi_to_mix((const short*)msg->buffer, (const short*)tip_msg->buffer, (short*)date_buffer, AWI_AUDIO2_SPEAKER_PLAY_BUFFER_SIZE/2);
//aw_print("-23");//debug
}
// } else {
// memset(date_buffer, 0x00, AWI_AUDIO2_SPEAKER_PLAY_BUFFER_SIZE);
// //aw_print("-24");//debug
// }
if(NULL != tip_msg){
if(NULL != tip_msg->cb_func) {
tip_msg->cb_func(tip_msg->cb_ths);
}
awi_audio2_speaker_push_msg(speaker, tip_msg);
tip_msg = NULL;
}
if(NULL != msg){
awi_audio2_speaker_push_msg(speaker, msg);
msg = NULL;
}
if (speaker->is_record){
d40_awi_arrange_speaker_data_to_one((const short*)date_buffer, (short*)algo_buffer, AWI_AUDIO2_SPEAKER_PLAY_BUFFER_SIZE / 2);
audioAlg_playDataPreProcess(speaker->algo, (short *)algo_buffer);
d40_awi_arrange_speaker_data_to_two((const short*)algo_buffer, (short*)date_buffer, AWI_AUDIO2_SPEAKER_PLAY_BUFFER_SIZE / 2);
//aw_print("-25");//debug
}
// if(speaker->init_ok){
awi_sem_require(&speaker->cache_sem, AWI_TIME_INFINITE);
awi_audio2_speaker_msg_t *date_msg;
date_msg = awi_audio2_speaker_pop_msg(speaker);
if(NULL == date_msg) {
aw_print("failed to pop msg");
return NULL;
}
memcpy(date_msg->buffer, date_buffer, AWI_AUDIO2_SPEAKER_PLAY_BUFFER_SIZE);
awi_lockqueue_push(&speaker->msg_date_q, &date_msg->q_n);
//aw_print("-26");//debug
while(true) {
if(speaker->msg_date_q.length > AWI_AUDIO2_SPEAKER_MAX_QUEUE_LENGTH) {
awi_queue_node_t *qn = awi_lockqueue_pop(&speaker->msg_date_q);
//aw_print("-27");//debug
if(NULL == qn) {
break;
}
date_msg = awi_offset(qn, awi_audio2_speaker_msg_t, hoard_n);
if (date_msg != NULL){
awi_audio2_speaker_push_msg(speaker, date_msg);
}
} else {
break;
}
}
// }
}
return NULL;
}
static void* awi_audio2_speaker_proc(void *arg)
{
int write;
int first_run_sem = 0;
awi_audio2_speaker_t *speaker;
awi_alsa_play2_t *ap = NULL;
awi_alsa_play2_params_t *ap_params;
snd_pcm_uframes_t frames;
speaker = (awi_audio2_speaker_t*)arg;
ap_params = &speaker_params;
frames = ap_params->period_time * ap_params->sample_rate / (1000 * 1000);
ap = awi_alsa_play2_new(ap_params);
if(NULL == ap) {
aw_print("failed to new alsa play");
goto fail;
}
awi_alsa_play2_set_tag(ap, "speaker");
while(speaker->runing == true) {
if(speaker->playing == true) {
awi_queue_node_t *qn;
qn = awi_lockqueue_pop(&speaker->msg_date_q);
//aw_print("-11");//debug
if(NULL == qn) {
memset(speaker->buffer, 0x00, AWI_AUDIO2_SPEAKER_PLAY_BUFFER_SIZE);
//aw_print("-12");//debug
} else {
awi_audio2_speaker_msg_t *date_msg = awi_offset(qn, awi_audio2_speaker_msg_t, q_n);
if (date_msg != NULL){
memcpy(speaker->buffer, date_msg->buffer, AWI_AUDIO2_SPEAKER_PLAY_BUFFER_SIZE);
awi_audio2_speaker_push_msg(speaker, date_msg);
awi_sem_release(&speaker->cache_sem, 1);
//aw_print("-13");//debug
}
}
} else {
memset(speaker->buffer, 0x00, AWI_AUDIO2_SPEAKER_PLAY_BUFFER_SIZE);
// usleep(1000);
//aw_print("-14");//debug
}
if(speaker->init_ok){
//aw_print("-15");//debug
if(first_run_sem == 0){
awi_sem_release(&speaker->cache_sem, AWI_AUDIO2_SPEAKER_CACHE_NUM);//注意信号量初始化应该为0,这样子在awi_audio2_speaker_proc准备好可以开始awi_alsa_play2_write的时候,在给出满信号量,实现数据的开始同步
first_run_sem = 1;
//aw_print("-30");//debug
}
write = awi_alsa_play2_write(ap, (uint8_t*)speaker->buffer, AWI_AUDIO2_SPEAKER_PLAY_FRAMES);
//aw_print("-16");//debug
if (write != frames){
aw_print("unexpect writed %d/%ld", write, frames);
if(NULL != ap) {
awi_alsa_play2_del(ap);
}
ap = awi_alsa_play2_new(ap_params);
if(NULL == ap) {
aw_print("failed to new alsa write");
}
awi_alsa_play2_set_tag(ap, "speark");
}
}
}
awi_alsa_play2_del(ap);
return NULL;
fail:
if(NULL != ap) {
awi_alsa_play2_del(ap);
}
return NULL;
}
awi_audio2_speaker_t* awi_audio2_speaker_new(void *_audio2)
{
awi_audio2_speaker_t *speaker;
audio2 = _audio2;
speaker = (awi_audio2_speaker_t*)awi_malloc(sizeof(awi_audio2_speaker_t));
if(NULL == speaker) {
aw_print("failed to malloc speaker");
goto fail;
}
memset(speaker, 0, sizeof(awi_audio2_speaker_t));
speaker->algo = audio2->algo;
awi_lockqueue_init(&speaker->msg_q);
awi_lockqueue_init(&speaker->msg_tip_q);
awi_lockqueue_init(&speaker->msg_date_q);
awi_blockqueue_init(&speaker->msg_tip_bq);
awi_lockhoard_init(&speaker->msg_hoard, offsetof(awi_audio2_speaker_msg_t, hoard_n), 15,
(awi_hoard_new_handler)awi_audio2_speaker_msg_new,
(awi_hoard_del_handler)awi_audio2_speaker_msg_del,
speaker);
awi_sem_init(&speaker->cache_sem, 0);//注意信号量初始化应该为0,这样子在awi_audio2_speaker_proc准备好可以开始awi_alsa_play2_write的时候,在给出满信号量,实现数据的开始同步
speaker->runing = true;
speaker->init_ok = false;
audio2->tips = awi_audio2_tips_new(audio2->is_abroad);
if(NULL == audio2->tips) {
aw_print("failed to new tips");
goto fail;
}
awi_audio2_tips_set_notify_func(audio2->tips, speaker, (awi_audio2_tips_notify_func)awi_audio2_speaker_on_tips);
pthread_create(&speaker->proc_tid, NULL, awi_audio2_speaker_proc, speaker);
pthread_create(&speaker->tip_tid, NULL, awi_audio2_speaker_for_tip_proc, speaker);
pthread_create(&speaker->date_tid, NULL, awi_audio2_speaker_date_proc, speaker);
return speaker;
fail:
if(NULL != speaker) {
awi_free(speaker);
}
return NULL;
}
/***********************test**************************/
static void* awi_audio2_speaker_for_test_proc(void *arg)
{
awi_audio2_speaker_t *speaker;
awi_alsa_play2_t *ap = NULL;
awi_alsa_play2_params_t *ap_params;
// uint8_t buffer[AWI_AUDIO2_SPEAKER_PLAY_BUFFER_SIZE];
speaker = (awi_audio2_speaker_t*)arg;
ap_params = &speaker_params;
ap = awi_alsa_play2_new(ap_params);
if(NULL == ap) {
aw_print("failed to new alsa play");
goto fail;
}
awi_alsa_play2_set_tag(ap, "speaker");
while(speaker->runing == true) {
if(speaker->playing == true) {
awi_queue_node_t *qn;
qn = awi_lockqueue_pop(&speaker->msg_q);
if(NULL == qn) {
memset(speaker->buffer, 0x00, AWI_AUDIO2_SPEAKER_PLAY_BUFFER_SIZE);
} else {
awi_audio2_speaker_msg_t *msg = awi_offset(qn, awi_audio2_speaker_msg_t, q_n);
memcpy(speaker->buffer, msg->buffer, AWI_AUDIO2_SPEAKER_PLAY_BUFFER_SIZE);
awi_audio2_speaker_push_msg(speaker, msg);
}
} else {
memset(speaker->buffer, 0x00, AWI_AUDIO2_SPEAKER_PLAY_BUFFER_SIZE);
}
if (speaker->is_record){
d40_awi_arrange_speaker_data_to_one((const short*)speaker->buffer, (short*)algo_buffer, AWI_AUDIO2_SPEAKER_PLAY_BUFFER_SIZE / 2);
audioAlg_playDataPreProcess(speaker->algo, (short *)algo_buffer);
d40_awi_arrange_speaker_data_to_two((const short*)algo_buffer, (short*)speaker->buffer, AWI_AUDIO2_SPEAKER_PLAY_BUFFER_SIZE / 2);
}
if(speaker->init_ok){
awi_alsa_play2_write(ap, (uint8_t*)speaker->buffer, AWI_AUDIO2_SPEAKER_PLAY_FRAMES);
}
}
awi_alsa_play2_del(ap);
return NULL;
fail:
if(NULL != ap) {
awi_alsa_play2_del(ap);
}
return NULL;
}
awi_audio2_speaker_t* awi_audio2_speaker_new_for_test(void *algo)
{
awi_audio2_speaker_t *speaker;
speaker = (awi_audio2_speaker_t*)awi_malloc(sizeof(awi_audio2_speaker_t));
if(NULL == speaker) {
aw_print("failed to malloc speaker");
goto fail;
}
memset(speaker, 0, sizeof(awi_audio2_speaker_t));
speaker->algo = algo;
awi_lockqueue_init(&speaker->msg_q);
awi_lockhoard_init(&speaker->msg_hoard, offsetof(awi_audio2_speaker_msg_t, hoard_n), 10,
(awi_hoard_new_handler)awi_audio2_speaker_msg_new,
(awi_hoard_del_handler)awi_audio2_speaker_msg_del,
speaker);
speaker->runing = true;
pthread_create(&speaker->proc_tid, NULL, awi_audio2_speaker_for_test_proc, speaker);
return speaker;
fail:
if(NULL != speaker) {
awi_free(speaker);
}
return NULL;
}
/***********************test**************************/
int awi_audio2_speaker_del(awi_audio2_speaker_t *speaker)
{
if(NULL != speaker) {
speaker->runing = false;
awi_blockqueue_wake(&speaker->msg_tip_bq);
pthread_join(speaker->proc_tid, NULL);
pthread_join(speaker->tip_tid, NULL);
awi_lockqueue_clean(&speaker->msg_q);
awi_lockqueue_clean(&speaker->msg_tip_q);
awi_blockqueue_clean(&speaker->msg_tip_bq);
awi_lockhoard_clean(&speaker->msg_hoard);
awi_free(speaker);
}
return 0;
}
int awi_audio2_speaker_start(awi_audio2_speaker_t *speaker)
{
awi_queue_node_t *qn;
awi_queue_node_t *qn_tip;
if(speaker->playing == false) {
while(true) {
qn = awi_lockqueue_pop(&speaker->msg_q);
qn_tip = awi_lockqueue_pop(&speaker->msg_tip_q);
if(NULL != qn) {
awi_audio2_speaker_msg_t *msg = awi_offset(qn, awi_audio2_speaker_msg_t, q_n);
awi_audio2_speaker_push_msg(speaker, msg);
}
if(NULL != qn_tip) {
awi_audio2_speaker_msg_t *tip_msg = awi_offset(qn_tip, awi_audio2_speaker_msg_t, q_n);
awi_audio2_speaker_push_msg(speaker, tip_msg);
}
if(NULL == qn_tip && NULL == qn) {
break;
}
}
}
speaker->playing = true;
return 0;
}
int awi_audio2_speaker_data(awi_audio2_speaker_t *speaker, const uint8_t *data, int bytes)
{
if(speaker->playing == true) {
awi_audio2_speaker_msg_t *msg;
msg = awi_audio2_speaker_pop_msg(speaker);
if(NULL == msg) {
aw_print("failed to pop msg");
return -1;
}
memcpy(msg->buffer, data, bytes);
awi_lockqueue_push(&speaker->msg_q, &msg->q_n);
while(true) {
if(speaker->msg_q.length > AWI_AUDIO2_SPEAKER_MAX_QUEUE_LENGTH) {
awi_queue_node_t *qn = awi_lockqueue_pop(&speaker->msg_q);
if(NULL == qn) {
break;
}
msg = awi_offset(qn, awi_audio2_speaker_msg_t, hoard_n);
awi_audio2_speaker_push_msg(speaker, msg);
} else {
break;
}
}
}
return 0;
}
int awi_audio2_speaker_stop(awi_audio2_speaker_t *speaker)
{
speaker->playing = false;
return 0;
}
int awi_audio2_speaker_record_start(awi_audio2_speaker_t *speaker)
{
speaker->is_record = true;
return 0;
}
int awi_audio2_speaker_record_stop(awi_audio2_speaker_t *speaker)
{
speaker->is_record = false;
return 0;
}
int awi_audio2_speaker_init_ok(awi_audio2_speaker_t *speaker)
{
speaker->init_ok = true;
return 0;
}