Files
TAIXIN/sdk/app/intercom/intercom.c

1702 lines
54 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "basic_include.h"
#include "csi_kernel.h"
#include "syscfg.h"
#include "lwip/sockets.h"
#include "netif/ethernetif.h"
#include "lib/umac/ieee80211.h"
#include "audio_code_ctrl.h"
#include "audio_msi/audio_adc.h"
#include "audio_msi/audio_dac.h"
#include "magic_voice/magic_voice.h"
#include "intercom.h"
#define MAX_INTERCOM_RXBUF 14
#define MAX_INTERCOM_TXBUF 4
#define CHANGE_PLAY_SPEED 1
#define PLC_PROCESS 1
#define BITRATE_ADJUST 0
#define AUDIO_ENCODER OPUS_ENC
#define AUDIO_DECODER OPUS_DEC
#define HIGH_BITRATE 16000
#define LOW_BITRATE 8000
#define FRAME_TIME 20
#define INTERCOM_PORT 5008
#define MAX_ENCODED_LEN 280
#define ENCODED_BUF_NUM 15
#define ENCODED_RINGBUF_LEN 1500
#define SUBLIST_NUM 40
#define SOFTBUF_LEN 4000
#define NODE_DATA_LEN 60
#define HEAD_RESERVE_BYTE 18
#define NUM_OF_FRAME 1
#define LOSE_STATISTICAL 1
#define TIMEOUT_COUNT 500
#ifndef MAGIC_VOICE_EN
#define MAGIC_VOICE_EN 0
#endif
#ifndef ONE_TO_MANY
#define ONE_TO_MANY 0
#endif
#ifndef INTERCOM_HALF_DUPLEX
#define INTERCOM_HALF_DUPLEX 0
#endif
#ifndef LOW_BITRATE_MODE
#define LOW_BITRATE_MODE 0
#endif
static uint16_t g_play_sort = 0;
static uint16_t g_current_sort = 1;
static uint32_t g_numofcached = 0;
static uint32_t g_s_identify_num = 0;
static uint32_t g_r_identify_num = 0;
static uint32_t cur_r_identify_num = 0;
static uint32_t g_send_enable = 1;
static uint32_t play_start_wait = 10;
static uint8_t send_start_flag = 1;
static uint8_t play_start_flag = 2; //BIT(0)是否播放BIT(1)是否接收
static AUDIO_TRACK *audac_fiter_track = NULL;
static uint32_t last_statistical_time = 0;
static uint32_t lose_total = 0;
static uint32_t max_lose_cnt = 0;
static uint32_t slow_speed_cnt = 0;
static uint32_t fast_speed_cnt = 0;
static struct msi *global_intercom_msi = NULL;
enum {
clear_useList_event = BIT(0),
clear_useList_finish_event = BIT(1),
};
void intercom_deinit();
static void intercom_task_state_init(INTERCOM_STRUCT *intercom_s)
{
intercom_s->run_state = intercom_run;
intercom_s->run_task = 0;
}
static void intercom_task_increase(INTERCOM_STRUCT *intercom_s)
{
os_mutex_lock(&intercom_s->state_mutex, osWaitForever);
intercom_s->run_task++;
os_mutex_unlock(&intercom_s->state_mutex);
}
static void intercom_task_decrease(INTERCOM_STRUCT *intercom_s)
{
os_mutex_lock(&intercom_s->state_mutex, osWaitForever);
intercom_s->run_task--;
os_mutex_unlock(&intercom_s->state_mutex);
}
static void intercom_close_socket(INTERCOM_STRUCT *intercom_s)
{
if(intercom_s->local_trans_fd >= 0) {
close(intercom_s->local_trans_fd);
}
if(intercom_s->local_ret_fd >= 0) {
close(intercom_s->local_ret_fd);
}
}
static int intercom_room_init(INTERCOM_STRUCT *intercom_s)
{
intercom_s->encoded_ringbuf = (RINGBUF*)ringbuf_Init(1, ENCODED_RINGBUF_LEN);
if(!(intercom_s->encoded_ringbuf)) {
os_printf("intercom encode_ringbuf init fail!\n");
return RET_ERR;
}
intercom_s->sort_buf = (uint8_t*)INTERCOM_MALLOC(SOFTBUF_LEN * sizeof(uint8_t));
if(!intercom_s->sort_buf) {
os_printf("intercom malloc sort_buf fail!\n");
return RET_ERR;
}
intercom_s->send_buf = (uint8_t*)INTERCOM_MALLOC(1400 * sizeof(uint8_t));
if(!intercom_s->send_buf) {
os_printf("intercom malloc send_buf fail!\n");
return RET_ERR;
}
intercom_s->recv_buf = (uint8_t*)INTERCOM_MALLOC(1400 * sizeof(uint8_t));
if(!intercom_s->recv_buf) {
os_printf("intercom malloc recv_buf fail!\n");
return RET_ERR;
}
INIT_LIST_HEAD((struct list_head *)&intercom_s->checkList_head);
INIT_LIST_HEAD((struct list_head *)&intercom_s->useList_head);
INIT_LIST_HEAD((struct list_head *)&intercom_s->nodeList_head);
INIT_LIST_HEAD((struct list_head *)&intercom_s->sublist_head);
INIT_LIST_HEAD((struct list_head *)&intercom_s->ringbuf_manage_empty);
INIT_LIST_HEAD((struct list_head *)&intercom_s->ringbuf_manage_used);
INIT_LIST_HEAD((struct list_head *)&intercom_s->device_head);
audio_node *audio_node_src = (audio_node*)INTERCOM_ZALLOC(sizeof(audio_node) * (SOFTBUF_LEN / NODE_DATA_LEN));
if(!audio_node_src) {
os_printf("intercom malloc audio_node_src fail!\n");
return RET_ERR;
}
for(uint32_t i=0; i<(SOFTBUF_LEN/NODE_DATA_LEN); i++) {
audio_node_src[i].buf_addr = (uint8_t*)(intercom_s->sort_buf+(NODE_DATA_LEN * i));
list_add_tail((struct list_head *)&(audio_node_src[i].list),(struct list_head *)&intercom_s->nodeList_head);
}
intercom_s->audio_node_src = audio_node_src;
sublist *sublist_src = (sublist*)INTERCOM_ZALLOC(sizeof(sublist) * SUBLIST_NUM);
if(!sublist_src) {
os_printf("intercom malloc sublist_src fail!\n");
return RET_ERR;
}
for(uint32_t i=0; i<SUBLIST_NUM; i++) {
sublist_src[i].node_head.next = &(sublist_src[i].node_head);
sublist_src[i].node_head.prev = &(sublist_src[i].node_head);
list_add_tail((struct list_head *)&sublist_src[i].list, (struct list_head *)&intercom_s->sublist_head);
}
intercom_s->sublist_src = sublist_src;
ringbuf_manage *ringbuf_manage_src = (ringbuf_manage*)INTERCOM_ZALLOC(sizeof(ringbuf_manage) * SUBLIST_NUM);
if(!ringbuf_manage_src) {
os_printf("intercom malloc ringbuf_manage_src fail!\n");
return RET_ERR;
}
for(uint32_t i=0; i<ENCODED_BUF_NUM; i++) {
list_add_tail((struct list_head *)&ringbuf_manage_src[i].list,(struct list_head *)&intercom_s->ringbuf_manage_empty);
}
intercom_s->ringbuf_manage_src = ringbuf_manage_src;
intercom_s->manage_cur_pop = &intercom_s->ringbuf_manage_used;
intercom_s->manage_cur_push = &intercom_s->ringbuf_manage_used;
os_printf("intercom_room_init succes\n");
return RET_OK;
}
static void intercom_room_free(INTERCOM_STRUCT *intercom_s)
{
if(intercom_s->encoded_ringbuf)
ringbuf_del(intercom_s->encoded_ringbuf);
if(intercom_s->sort_buf)
INTERCOM_FREE(intercom_s->sort_buf);
if(intercom_s->send_buf)
INTERCOM_FREE(intercom_s->send_buf);
if(intercom_s->recv_buf)
INTERCOM_FREE(intercom_s->recv_buf);
if(intercom_s->audio_node_src)
INTERCOM_FREE(intercom_s->audio_node_src);
if(intercom_s->sublist_src)
INTERCOM_FREE(intercom_s->sublist_src);
if(intercom_s->ringbuf_manage_src)
INTERCOM_FREE(intercom_s->ringbuf_manage_src);
}
static void *get_ringbuf_manage_addr(struct list_head *list)
{
ringbuf_manage *ringbuf_mana;
ringbuf_mana = list_entry((struct list_head *)list,ringbuf_manage,list);
return ringbuf_mana->buf_addr;
}
static uint32_t get_ringbuf_manage_datalen(struct list_head *list)
{
ringbuf_manage *ringbuf_mana;
ringbuf_mana = list_entry((struct list_head *)list,ringbuf_manage,list);
return (uint32_t)ringbuf_mana->data_len;
}
static int32_t get_ringbuf_manage_count(INTERCOM_STRUCT *intercom_s)
{
int count = 0;
struct list_head *list_n = (struct list_head *)intercom_s->manage_cur_pop;
struct list_head *head = (struct list_head *)intercom_s->manage_cur_push;
while(list_n != head) {
list_n = list_n->next;
count++;
if(count > ENCODED_BUF_NUM)
{
count = 0;
break;
}
}
return count;
}
static struct list_head *get_ringbuf_manage(INTERCOM_STRUCT *intercom_s, uint8_t grab)
{
if(list_empty_careful((const struct list_head *)&intercom_s->ringbuf_manage_empty)) {
if(grab) {
list_move_tail((struct list_head *)intercom_s->ringbuf_manage_used.next,
(struct list_head *)&intercom_s->ringbuf_manage_used);
}
else {
return 0;
}
}
else {
list_move_tail((struct list_head *)intercom_s->ringbuf_manage_empty.next,
(struct list_head *)&intercom_s->ringbuf_manage_used);
}
return intercom_s->ringbuf_manage_used.prev;
}
static void del_ringbuf_manage(INTERCOM_STRUCT *intercom_s)
{
list_move_tail((struct list_head *)intercom_s->ringbuf_manage_used.next,
(struct list_head*)&intercom_s->ringbuf_manage_empty);
}
static void output_sema_up(uint32_t *args)
{
INTERCOM_STRUCT *intercom_s = (INTERCOM_STRUCT*)args;
if(intercom_s->output_sema.hdl) {
os_sema_up(&intercom_s->output_sema);
}
return;
}
void losePacket_retransfer(INTERCOM_STRUCT *intercom_s, uint8_t *addr, uint32_t len)
{
int32_t slen = 0;
if((addr + len) > ((uint8_t*)(intercom_s->encoded_ringbuf->data +
intercom_s->encoded_ringbuf->elementcount))) {
uint32_t residue_len = (uint8_t*)(intercom_s->encoded_ringbuf->data +
intercom_s->encoded_ringbuf->elementcount) - addr;
os_memcpy(intercom_s->send_buf, addr, residue_len);
os_memcpy(intercom_s->send_buf + residue_len, intercom_s->encoded_ringbuf->data,
len - residue_len);
}
else {
os_memcpy(intercom_s->send_buf, addr, len);
}
slen = sendto(intercom_s->local_trans_fd, intercom_s->send_buf, len, 0,
(struct sockaddr*)&(intercom_s->remote_trans_addr), sizeof(intercom_s->remote_trans_addr));
}
static void intercom_retransfer_check(INTERCOM_STRUCT *intercom_s)
{
uint8_t *addr = NULL;
uint8_t sequence = 0;
uint8_t cnt = 0;
int32_t recv_len = 0;
uint32_t lose_packet = 0;
uint32_t send_totallen = 0;
struct list_head *manage_p = NULL;
socklen_t addrlen = sizeof(struct sockaddr_in);
struct sockaddr_in remote_ret_addr;
os_mutex_lock(&intercom_s->send_mutex, osWaitForever);
recv_len = recvfrom(intercom_s->local_ret_fd, &lose_packet, 4, 0,
(struct sockaddr*)&(remote_ret_addr), &addrlen);
if(os_memcmp(&remote_ret_addr.sin_addr, &intercom_s->remote_ret_addr.sin_addr, sizeof(struct in_addr)) != 0)
goto intercom_retransfer_check_end;
if(!send_start_flag)
goto intercom_retransfer_check_end;
if(recv_len > 0) {
manage_p = intercom_s->ringbuf_manage_used.next;
while(manage_p != &intercom_s->ringbuf_manage_used) {
cnt++;
send_totallen = 0;
addr = (uint8_t*)get_ringbuf_manage_addr(manage_p);
sequence = *addr;
if(BIT(sequence) & lose_packet) {
send_totallen = get_ringbuf_manage_datalen(manage_p);
losePacket_retransfer(intercom_s, addr, send_totallen);
os_sleep_ms(1);
}
manage_p = manage_p->next;
if(cnt >= ENCODED_BUF_NUM)
break;
}
#if BITRATE_ADJUST == ADJUST_BY_LOSS
if(lose_packet & BIT(31)) {
intercom_s->new_bitrate_mode = low_bitrate_mode;
}
else {
intercom_s->new_bitrate_mode = high_bitrate_mode;
}
#endif
}
intercom_retransfer_check_end:
os_mutex_unlock(&intercom_s->send_mutex);
}
static uint16_t calulate_sum(uint8_t * buf, uint16_t len)
{
uint16_t sum = 0;
for(uint16_t i=0; i<len; i++) {
sum += *(buf+i);
}
return sum;
}
void ringbuf_write_pre(INTERCOM_STRUCT *intercom_s, uint32_t size)
{
ringbuf_manage *ringbuf_mana_n = NULL;
struct list_head *ringbuf_mana_l = NULL;
struct list_head *manage_l_del = NULL;
ringbuf_manage *manage_n_del = NULL;
ringbuf_mana_l = get_ringbuf_manage(intercom_s, 0);
if(!ringbuf_mana_l) {
ringbuf_mana_l = intercom_s->ringbuf_manage_used.next;
ringbuf_mana_n = list_entry(ringbuf_mana_l, ringbuf_manage, list);
ringbuf_move_readptr(intercom_s->encoded_ringbuf, size);
if(intercom_s->manage_cur_pop == intercom_s->ringbuf_manage_used.next)
intercom_s->manage_cur_pop = intercom_s->manage_cur_pop->next;
ringbuf_mana_l = get_ringbuf_manage(intercom_s, 1);
}
intercom_s->manage_cur_push = ringbuf_mana_l;
ringbuf_mana_n = list_entry(ringbuf_mana_l, ringbuf_manage, list);
ringbuf_mana_n->buf_addr = (uint8_t*)intercom_s->encoded_ringbuf->data +
intercom_s->encoded_ringbuf->rear;
ringbuf_mana_n->data_len = size;
while(ringbuf_write_available(intercom_s->encoded_ringbuf) < size) {
manage_l_del = intercom_s->ringbuf_manage_used.next;
manage_n_del = list_entry(manage_l_del, ringbuf_manage, list);
ringbuf_move_readptr(intercom_s->encoded_ringbuf, size);
if(intercom_s->manage_cur_pop == intercom_s->ringbuf_manage_used.next)
intercom_s->manage_cur_pop = intercom_s->manage_cur_pop->next;
del_ringbuf_manage(intercom_s);
}
}
static void intercom_send_data(INTERCOM_STRUCT *intercom_s, uint8_t num)
{
uint8_t *addr = NULL;
int32_t slen = 0;
uint32_t send_totallen = 0;
uint32_t data_len = 0;
socklen_t addrlen = sizeof(struct sockaddr_in);
struct list_head *manage_p = NULL;
intercom_s->manage_cur_pop = intercom_s->manage_cur_pop->next;
manage_p = intercom_s->manage_cur_pop;
addr = (uint8_t*)get_ringbuf_manage_addr(manage_p);
for(uint32_t i=0; i<num; i++) {
data_len = get_ringbuf_manage_datalen(manage_p);
send_totallen += data_len;
manage_p = manage_p->next;
}
if((addr + send_totallen) > ((uint8_t*)(intercom_s->encoded_ringbuf->data +
intercom_s->encoded_ringbuf->elementcount))) {
uint32_t residue_len = (uint8_t*)(intercom_s->encoded_ringbuf->data +
intercom_s->encoded_ringbuf->elementcount) - addr;
os_memcpy(intercom_s->send_buf, addr, residue_len);
os_memcpy(intercom_s->send_buf + residue_len, intercom_s->encoded_ringbuf->data,
send_totallen - residue_len);
}
else
os_memcpy(intercom_s->send_buf, addr, send_totallen);
os_mutex_lock(&intercom_s->send_mutex, osWaitForever);
slen = sendto(intercom_s->local_trans_fd, intercom_s->send_buf, send_totallen, 0,
(struct sockaddr*)&(intercom_s->remote_trans_addr), addrlen);
os_mutex_unlock(&intercom_s->send_mutex);
}
static void intercom_send_task(void *d)
{
#if BITRATE_ADJUST == ADJUST_BY_MCS
uint8_t avg_mcs = 7;
uint8_t avg_cnt = 0;
#endif
uint8_t send_sequence = 0;
uint8_t encoded_buf[MAX_ENCODED_LEN] = {0};
uint8_t *data = NULL;
uint16_t send_sort = 0;
uint32_t data_len = 0;
uint32_t timestamp = 0;
INTERCOM_STRUCT *intercom_s = (INTERCOM_STRUCT*)d;
struct framebuff *frame_buf = NULL;
AUENC_INIT auenc_init;
#if MAGIC_VOICE_EN
magic_voice_struct *magic_voice_s = NULL;
#endif
intercom_task_increase(intercom_s);
g_s_identify_num = 0;
os_random_bytes((uint8_t*)(&g_s_identify_num), 4);
os_printf("\n**********intercom ID:%d***********\n",g_s_identify_num);
auenc_init.destroy_self = 0;
#if MAGIC_VOICE_EN
auadc_msi_add_output(AUSYS_AUAD, intercom_s->magic_voice_msi->name);
magic_voice_s = intercom_s->magic_voice_msi->priv;
auenc_init.src_msi = magic_voice_s->autpc_msi;
#else
auenc_init.src_msi = get_auadc_msi(AUSYS_AUAD);
#endif
intercom_s->encoder_msi = audio_encode_init(AUDIO_ENCODER, audio_adc_get_samplerate(AUSYS_AUAD), &auenc_init);
if(!intercom_s->encoder_msi) {
os_printf("intercom audio encoder init fail!\n");
intercom_task_decrease(intercom_s);
return;
}
#if (!BITRATE_ADJUST && LOW_BITRATE_MODE)
audio_encode_set_bitrate(intercom_s->encoder_msi, 8000);
#endif
audio_code_add_output(intercom_s->encoder_msi, intercom_s->msi->name);
intercom_s->send_stream_type = intercom_live_audio;
while(1) {
if(intercom_s->run_state == intercom_stop)
break;
intercom_retransfer_check(intercom_s);
#if BITRATE_ADJUST == ADJUST_BY_MCS
if(sys_cfgs.wifi_mode == WIFI_MODE_STA) {
avg_mcs += (ieee80211_conf_get_tx_mcs(WIFI_MODE_STA, NULL, 0) & 0x0f);
}
else {
avg_mcs += (ieee80211_conf_get_tx_mcs(WIFI_MODE_AP, NULL, 1) & 0x0f);
}
if(avg_cnt >= 20) {
avg_mcs /= 20;
avg_cnt = 0;
if(avg_mcs >= 4) {
intercom_s->new_bitrate_mode = high_bitrate_mode;
}
else {
intercom_s->new_bitrate_mode = low_bitrate_mode;
}
}
avg_cnt++;
#endif
#if BITRATE_ADJUST
if((intercom_s->cur_bitrate_mode != intercom_s->new_bitrate_mode) && (intercom_s->new_bitrate_mode == low_bitrate_mode)) {
audio_encode_set_bitrate(intercom_s->encoder_msi, 8000);
intercom_s->cur_bitrate_mode = intercom_s->new_bitrate_mode;
os_printf("audio set bitrate:8000\n");
}
else if((intercom_s->cur_bitrate_mode != intercom_s->new_bitrate_mode) && (intercom_s->new_bitrate_mode == high_bitrate_mode)) {
audio_encode_set_bitrate(intercom_s->encoder_msi, 16000);
intercom_s->cur_bitrate_mode = intercom_s->new_bitrate_mode;
os_printf("audio set bitrate:16000\n");
}
#endif
if(send_start_flag) {
if(audio_code_get_status(intercom_s->encoder_msi) == AUCODEC_PAUSE) {
audio_code_continue(intercom_s->encoder_msi);
}
frame_buf = msi_get_fb(intercom_s->msi, 0);
if(frame_buf) {
data = frame_buf->data;
data_len = frame_buf->len;
send_sequence = (send_sequence % (ENCODED_BUF_NUM*2))+1;
send_sort++;
timestamp = os_jiffies();
encoded_buf[0] = send_sequence;
if(data_len) {
if(intercom_s->send_stream_type == intercom_live_audio)
encoded_buf[1] = (intercom_live_audio << 4) | intercom_s->cur_bitrate_mode;
else if(intercom_s->send_stream_type == intercom_playback_audio)
encoded_buf[1] = (intercom_playback_audio << 4) | intercom_s->cur_bitrate_mode;
}
else
encoded_buf[1] = 0;
*((uint16_t*)(encoded_buf+2)) = send_sort;
*((uint32_t*)(encoded_buf+4)) = timestamp;
*((uint32_t*)(encoded_buf+8)) = data_len;
*((uint32_t*)(encoded_buf+12)) = g_s_identify_num;
*((uint16_t*)(encoded_buf+16)) = calulate_sum(encoded_buf,HEAD_RESERVE_BYTE-2);
if(data_len)
os_memcpy(encoded_buf + HEAD_RESERVE_BYTE, data, data_len);
data_len += HEAD_RESERVE_BYTE;
ringbuf_write_pre(intercom_s, data_len);
ringbuf_write(intercom_s->encoded_ringbuf, encoded_buf, data_len);
if(get_ringbuf_manage_count(intercom_s) >= NUM_OF_FRAME)
intercom_send_data(intercom_s, NUM_OF_FRAME);
msi_delete_fb(NULL, frame_buf);
frame_buf = NULL;
}
else
os_sleep_ms(1);
}
else {
frame_buf = msi_get_fb(intercom_s->msi, 0);
if(frame_buf) {
msi_delete_fb(NULL, frame_buf);
frame_buf = NULL;
}
if(get_ringbuf_manage_count(intercom_s) >= NUM_OF_FRAME)
intercom_send_data(intercom_s, NUM_OF_FRAME);
if(audio_code_get_status(intercom_s->encoder_msi) == AUCODEC_RUN) {
audio_code_pause(intercom_s->encoder_msi);
}
os_sleep_ms(10);
}
}
intercom_task_decrease(intercom_s);
}
static int32_t get_audio_node_count(struct list_head *head)
{
int count = 0;
struct list_head *list_n = (struct list_head *)head;
while(list_n->next != head) {
list_n = list_n->next;
count++;
if(count > (SOFTBUF_LEN / NODE_DATA_LEN)) {
count = 0;
break;
}
}
return count;
}
static void *get_audio_node_addr(struct list_head *list)
{
audio_node *audio_n;
audio_n = list_entry((struct list_head *)list,audio_node,list);
return audio_n->buf_addr;
}
static struct list_head *get_audio_node(INTERCOM_STRUCT *intercom_s, struct list_head *head, uint32_t node_num)
{
int ret = os_mutex_lock(&intercom_s->list_mutex, osWaitForever);
if(ret < 0)
return 0;
if(get_audio_node_count((struct list_head *)&intercom_s->nodeList_head) < node_num) {
os_mutex_unlock(&intercom_s->list_mutex);
os_printf("nodeList_head empty\n");
return 0;
}
for(uint32_t i=0; i<node_num; i++)
list_move_tail((struct list_head *)intercom_s->nodeList_head.next, (struct list_head *)head);
os_mutex_unlock(&intercom_s->list_mutex);
return head->next;
}
static void del_audio_node(INTERCOM_STRUCT *intercom_s, struct list_head *del)
{
del->next->prev = intercom_s->nodeList_head.prev;
del->prev->next = (struct list_head*)(&(intercom_s->nodeList_head));
intercom_s->nodeList_head.prev->next = del->next;
intercom_s->nodeList_head.prev = del->prev;
del->next = (struct list_head *)del;
del->prev = (struct list_head *)del;
}
static int32_t get_audio_sublist_count(INTERCOM_STRUCT *intercom_s, struct list_head *head)
{
int count = 0;
struct list_head *list_n = (struct list_head *)head;
int ret = os_mutex_lock(&intercom_s->list_mutex, osWaitForever);
if(ret < 0) {
return 0;
}
while(list_n->next != head) {
list_n = list_n->next;
count++;
if(count > SUBLIST_NUM) {
count = 0;
break;
}
}
os_mutex_unlock(&intercom_s->list_mutex);
return count;
}
static struct list_head *get_audio_sublist(INTERCOM_STRUCT *intercom_s, struct list_head *head)
{
int ret = os_mutex_lock(&intercom_s->list_mutex, osWaitForever);
if(ret < 0)
return 0;
if(list_empty_careful((const struct list_head *)&intercom_s->sublist_head)) {
os_mutex_unlock(&intercom_s->list_mutex);
os_printf("sublist_head empty\n");
return 0;
}
list_move_tail((struct list_head *)intercom_s->sublist_head.next,(struct list_head *)head);
os_mutex_unlock(&intercom_s->list_mutex);
return head->prev;
}
static void del_audio_sublist(INTERCOM_STRUCT *intercom_s, struct list_head *del)
{
int32_t ret = os_mutex_lock(&intercom_s->list_mutex, osWaitForever);
if(ret < 0)
return;
sublist *sublist_n = list_entry((struct list_head *)del,sublist,list);
if(sublist_n->node_cnt)
del_audio_node(intercom_s, &(sublist_n->node_head));
list_move_tail((struct list_head *)del,(struct list_head*)&intercom_s->sublist_head);
os_mutex_unlock(&intercom_s->list_mutex);
}
static void insert_into_useList(INTERCOM_STRUCT *intercom_s, struct list_head *del, volatile struct list_head *head)
{
sublist *sublist_n;
sublist *sublist_n_pos;
sublist *npos;
sublist_n = list_entry((struct list_head *)del,sublist,list);
int32_t prev_sort = 0;
uint16_t new_sort = 0;
uint16_t next_sort = 0;
int32_t ret;
new_sort = sublist_n->sort;
prev_sort = (play_start_flag&BIT(0))?g_play_sort:-1;
if((prev_sort >= new_sort) && ((prev_sort - new_sort) < 60000)) {
del_audio_sublist(intercom_s, del);
return;
}
// os_printf("insert:%d\n",new_sort);
ret = os_mutex_lock(&intercom_s->list_mutex, osWaitForever);
if(ret < 0)
return;
if(list_empty_careful((struct list_head *)head)) {
list_move((struct list_head *)del, (struct list_head *)head);
goto insert_into_useList_end;
}
list_for_each_entry_safe(sublist_n_pos, npos, (struct list_head *)head, list) {
next_sort = sublist_n_pos->sort;
if(new_sort == next_sort) {
if(sublist_n->node_cnt)
del_audio_node(intercom_s, &(sublist_n->node_head));
list_move_tail((struct list_head *)del,(struct list_head*)&intercom_s->sublist_head);
goto insert_into_useList_end;
}
else if( (prev_sort < new_sort ) && (new_sort < next_sort) && ((next_sort-new_sort) < 60000) ) {
list_move((struct list_head *)del, (struct list_head *)(sublist_n_pos->list.prev));
goto insert_into_useList_end;
}
else if( (prev_sort>60000) && ((prev_sort - new_sort)>60000) && (new_sort < next_sort) && (prev_sort - next_sort > 60000) ) {
list_move((struct list_head *)del, (struct list_head *)(sublist_n_pos->list.prev));
goto insert_into_useList_end;
}
prev_sort = next_sort;
}
list_move_tail((struct list_head *)del, (struct list_head *)head);
insert_into_useList_end:
os_mutex_unlock(&intercom_s->list_mutex);
return;
}
static int32_t recv_repeat_check(uint16_t seq, uint16_t sort)
{
static uint16_t seq_sort[ENCODED_BUF_NUM*2+1] = {0};
if(sort == seq_sort[seq]) {
return 1;
}
else {
seq_sort[seq] = sort;
return 0;
}
}
static void lose_packet_check(INTERCOM_STRUCT *intercom_s)
{
static char sequence = 0;
char temp = 0;
static uint32_t lose_packet = 0;
static char retrans_num[ENCODED_BUF_NUM*2+1] = {0};
socklen_t addrlen = sizeof(struct sockaddr_in);
uint32_t last_loop_lose = 0;
uint32_t new_loop_lose = 0;
uint8_t seq = 0;
uint16_t sort = 0;
struct list_head *sublist_l = NULL;
sublist *sublist_n = NULL;
uint32_t i = 0;
int32_t prev_sort = 0;
for(i=1; i<(ENCODED_BUF_NUM*2+1); i++)
{
if(lose_packet & BIT(i)) {
retrans_num[i] +=1;
if(retrans_num[i] >= 2) {
retrans_num[i] = 0;
lose_packet &= ~BIT(i);
}
}
}
sublist_l = intercom_s->checkList_head.next;
sublist_n = list_entry((struct list_head *)sublist_l, sublist, list);
temp = (sequence % (ENCODED_BUF_NUM*2))+1;
seq = sublist_n->seq;
if(os_abs(seq-temp) >= 8)
temp = seq;
sort = sublist_n->sort;
prev_sort = (play_start_flag&BIT(0))?g_play_sort:-1;
/*收到重复包,丢弃*/
if(recv_repeat_check(seq, sort)) {
del_audio_sublist(intercom_s, sublist_l);
}
else if((sort <= prev_sort) && ((prev_sort-sort) < 60000)) {
del_audio_sublist(intercom_s, sublist_l);
lose_packet &= ~BIT(seq);
retrans_num[seq] = 0;
}
else
{
/*收到丢包,清掉该丢包位*/
if( lose_packet & BIT(seq) ) {
lose_packet &= ~BIT(seq);
retrans_num[seq] = 0;
}
else if( temp != seq )
{
if(BIT(seq) > BIT(temp))
lose_packet |= (BIT(seq) - BIT(temp));
else {
last_loop_lose = BIT(ENCODED_BUF_NUM*2+1) - BIT(temp);
new_loop_lose = BIT(seq) - BIT(1);
lose_packet |= (last_loop_lose|new_loop_lose);
}
sequence = seq;
}
else
sequence = temp;
insert_into_useList(intercom_s, sublist_l, &intercom_s->useList_head);
}
if(intercom_s->loss_state == serious_loss) {
lose_packet |= BIT(31);
}
else {
lose_packet &= ~BIT(31);
}
if(lose_packet & 0x7FFFFFFF) {
sendto(intercom_s->local_ret_fd, &lose_packet, 4, 0, (struct sockaddr*)&(intercom_s->remote_ret_addr), addrlen);
}
#if BITRATE_ADJUST == ADJUST_BY_LOSS
else if(intercom_s->loss_state != (sublist_n->type&0xF)) {
sendto(intercom_s->local_ret_fd, &lose_packet, 4, 0, (struct sockaddr*)&(intercom_s->remote_ret_addr), addrlen);
}
#endif
}
static uint8_t is_new_device(INTERCOM_STRUCT *intercom_s, struct sockaddr_in *remote_trans_addr)
{
intercom_device *device;
intercom_device *npos;
list_for_each_entry_safe(device, npos, (struct list_head *)&(intercom_s->device_head), list) {
if(device->ip_addr == remote_trans_addr->sin_addr.s_addr) {
return 0;
}
}
os_printf("\n*****intercom find new device*****\n");
return 1;
}
static void add_new_device(INTERCOM_STRUCT *intercom_s, uint32_t new_identify_num, struct sockaddr_in *remote_trans_addr, uint8_t switch_new)
{
intercom_device *device = (intercom_device*)INTERCOM_MALLOC(sizeof(intercom_device));
if(!device) {
os_printf("intercom add new device fail\n");
return;
}
device->identify_num = new_identify_num;
device->ip_addr = remote_trans_addr->sin_addr.s_addr;
list_move_tail((struct list_head *)device, (struct list_head *)&(intercom_s->device_head));
intercom_s->connected_num++;
device->online = 1;
device->timeout_cnt = TIMEOUT_COUNT;
device->dev_id = ((remote_trans_addr->sin_addr.s_addr & 0xFF000000) >> 24) - 100;
os_printf("\n*****intercom add new device,ip:%x,id:%d*****\n",device->ip_addr,device->dev_id);
if(switch_new) {
send_start_flag = 0;
g_r_identify_num = new_identify_num;
intercom_s->remote_trans_addr.sin_addr.s_addr = remote_trans_addr->sin_addr.s_addr;
intercom_s->remote_ret_addr.sin_addr.s_addr = remote_trans_addr->sin_addr.s_addr;
send_start_flag = 1;
intercom_s->current_dev_id = device->dev_id;
}
}
static intercom_device *find_device(INTERCOM_STRUCT *intercom_s, struct sockaddr_in *remote_trans_addr)
{
intercom_device *device;
intercom_device *npos;
list_for_each_entry_safe(device, npos, (struct list_head *)&(intercom_s->device_head), list) {
if(device->ip_addr == remote_trans_addr->sin_addr.s_addr) {
return device;
}
}
return NULL;
}
static void switch_device(INTERCOM_STRUCT *intercom_s, uint32_t dev_id)
{
intercom_device *device;
intercom_device *npos;
os_mutex_lock(&intercom_s->send_mutex, osWaitForever);
list_for_each_entry_safe(device, npos, (struct list_head *)&(intercom_s->device_head), list) {
if(device->dev_id == dev_id) {
g_r_identify_num = device->identify_num;
intercom_s->remote_trans_addr.sin_addr.s_addr = device->ip_addr;
intercom_s->remote_ret_addr.sin_addr.s_addr = device->ip_addr;
intercom_s->current_dev_id = dev_id;
}
}
os_mutex_unlock(&intercom_s->send_mutex);
}
static void clear_disconnect_device(INTERCOM_STRUCT *intercom_s)
{
intercom_device *device;
intercom_device *npos;
list_for_each_entry_safe(device, npos, (struct list_head *)&(intercom_s->device_head), list) {
if(device->online) {
device->timeout_cnt = TIMEOUT_COUNT;
}
else {
device->timeout_cnt--;
}
device->online = 0;
if(device->timeout_cnt <= 0) {
intercom_s->connected_num--;
os_printf("\n*****intercom del device:%d*****\n",device->identify_num);
list_del(&device->list);
INTERCOM_FREE(device);
switch_device(intercom_s, 0);
}
}
}
static void clear_one_device(INTERCOM_STRUCT *intercom_s, uint32_t dev_id)
{
intercom_device *device;
intercom_device *npos;
if(intercom_s->connected_num) {
list_for_each_entry_safe(device, npos, (struct list_head *)&(intercom_s->device_head), list) {
if(device->dev_id == dev_id) {
list_del(&device->list);
INTERCOM_FREE(device);
intercom_s->connected_num--;
}
}
}
}
static void clear_all_device(INTERCOM_STRUCT *intercom_s)
{
intercom_device *device;
intercom_device *npos;
if(intercom_s->connected_num) {
list_for_each_entry_safe(device, npos, (struct list_head *)&(intercom_s->device_head), list) {
list_del(&device->list);
INTERCOM_FREE(device);
}
}
intercom_s->connected_num = 0;
}
static void intercom_recv_task(void *d)
{
uint8_t *node_addr = NULL;
int32_t rlen = 0;
uint16_t check_sum = 0;
uint32_t code_len = 0;
uint32_t offset = 0;
uint32_t node_num = 0;
uint32_t recv_timeout_cnt = 0;
struct sockaddr_in remote_trans_addr;
socklen_t addrlen = sizeof(struct sockaddr_in);
#if ONE_TO_MANY
uint8_t is_new = 0;
intercom_device *device;
#endif
INTERCOM_STRUCT *intercom_s = (INTERCOM_STRUCT*)d;
intercom_task_increase(intercom_s);
intercom_s->recv_stream_type = intercom_live_audio;
while(1) {
if(intercom_s->run_state == intercom_stop)
break;
recv_data_again:
rlen = recvfrom(intercom_s->local_trans_fd, intercom_s->recv_buf, 1400, 0,
(struct sockaddr*)&(remote_trans_addr), &addrlen);
if((play_start_flag&BIT(1)) == 0) {
continue;
}
// clear_disconnect_device(intercom_s);
if(rlen >= HEAD_RESERVE_BYTE) {
offset = 0;
while(rlen > offset) {
check_sum = ((uint16_t)(intercom_s->recv_buf[offset + HEAD_RESERVE_BYTE - 1]) << 8)
| intercom_s->recv_buf[offset + HEAD_RESERVE_BYTE - 2];
if(check_sum != calulate_sum(intercom_s->recv_buf + offset, HEAD_RESERVE_BYTE - 2)) {
os_printf("intercom abnormal packet\n");
goto recv_data_again;
}
recv_timeout_cnt = 0;
// os_printf("recv:%d\n",*((uint16_t*)(intercom_s->recv_buf + offset + 2)));
struct list_head *sublist_l = get_audio_sublist(intercom_s, (struct list_head*)(&intercom_s->checkList_head));
if(!sublist_l)
goto recv_data_again;
sublist *sublist_n = list_entry((struct list_head *)sublist_l, sublist, list);
os_memcpy(&(sublist_n->seq), intercom_s->recv_buf + offset, HEAD_RESERVE_BYTE - 2);
#if ONE_TO_MANY
if(intercom_s->current_dev_id != intercom_s->next_dev_id) {
switch_device(intercom_s, intercom_s->next_dev_id);
}
is_new = is_new_device(intercom_s, &remote_trans_addr);
os_mutex_lock(&intercom_s->send_mutex, osWaitForever);
if(is_new) {
add_new_device(intercom_s, sublist_n->identify_num, &remote_trans_addr, 1);
}
else {
device = find_device(intercom_s, &remote_trans_addr);
if(device) {
device->online = 1;
if((device->identify_num == g_r_identify_num) && (device->identify_num != sublist_n->identify_num)) {
g_r_identify_num = sublist_n->identify_num;
}
device->identify_num = sublist_n->identify_num;
}
}
os_mutex_unlock(&intercom_s->send_mutex);
if(cur_r_identify_num != g_r_identify_num) {
os_event_set(&intercom_s->clear_event, clear_useList_event, NULL);
os_event_wait(&intercom_s->clear_event, clear_useList_finish_event,
NULL, OS_EVENT_WMODE_CLEAR|OS_EVENT_WMODE_OR, osWaitForever);
cur_r_identify_num = g_r_identify_num;
os_printf("\n******change intercom identify_num****\n");
}
if(cur_r_identify_num != sublist_n->identify_num) {
sublist_n->node_cnt = 0;
del_audio_sublist(intercom_s, sublist_l);
goto recv_data_again;
}
#else
os_mutex_lock(&intercom_s->send_mutex, osWaitForever);
if(os_memcmp(&remote_trans_addr.sin_addr, &intercom_s->remote_trans_addr.sin_addr, sizeof(struct in_addr))) {
os_memcpy(&intercom_s->remote_trans_addr.sin_addr, &remote_trans_addr.sin_addr, sizeof(struct in_addr));
os_memcpy(&intercom_s->remote_ret_addr.sin_addr, &remote_trans_addr.sin_addr, sizeof(struct in_addr));
}
os_mutex_unlock(&intercom_s->send_mutex);
if(cur_r_identify_num != sublist_n->identify_num) {
os_event_set(&intercom_s->clear_event, clear_useList_event, NULL);
os_event_wait(&intercom_s->clear_event, clear_useList_finish_event,
NULL, OS_EVENT_WMODE_CLEAR|OS_EVENT_WMODE_OR, osWaitForever);
g_r_identify_num = sublist_n->identify_num;
cur_r_identify_num = g_r_identify_num;
os_printf("\n******change intercom identify_num****\n");
}
#endif
offset += HEAD_RESERVE_BYTE;
// if((sublist_n->type>>4) != intercom_s->recv_stream_type) {
// sublist_n->node_cnt = 0;
// del_audio_sublist(intercom_s, sublist_l);
// goto recv_data_again;
// }
code_len = sublist_n->code_len;
node_num = (code_len % NODE_DATA_LEN)?(code_len / NODE_DATA_LEN + 1):(code_len / NODE_DATA_LEN);
sublist_n->node_cnt = node_num;
// os_printf("recv:%d %d\n",sublist_n->sort,sublist_n->timestamp);
struct list_head *audio_n = get_audio_node(intercom_s, &(sublist_n->node_head), node_num);
if(audio_n) {
while(code_len > NODE_DATA_LEN) {
node_addr = (uint8_t*)get_audio_node_addr(audio_n);
os_memcpy(node_addr, intercom_s->recv_buf + offset, NODE_DATA_LEN);
audio_n = audio_n->next;
offset += NODE_DATA_LEN;
code_len -= NODE_DATA_LEN;
}
if(code_len > 0) {
node_addr = (uint8_t*)get_audio_node_addr(audio_n);
os_memcpy(node_addr, intercom_s->recv_buf + offset, code_len);
offset += code_len;
code_len = 0;
}
#if INTERCOM_HALF_DUPLEX
if((send_start_flag == 0) || (g_r_identify_num < g_s_identify_num)) {
g_send_enable = 0;
}
#endif
lose_packet_check(intercom_s);
}
else {
sublist_n->node_cnt = 0;
del_audio_sublist(intercom_s, sublist_l);
goto recv_data_again;
}
}
}
else {
recv_timeout_cnt++;
if(recv_timeout_cnt > TIMEOUT_COUNT) {
recv_timeout_cnt = TIMEOUT_COUNT;
if((play_start_flag&BIT(0)) == 1) {
os_event_set(&intercom_s->clear_event, clear_useList_event, NULL);
os_event_wait(&intercom_s->clear_event, clear_useList_finish_event,
NULL, OS_EVENT_WMODE_CLEAR|OS_EVENT_WMODE_OR, osWaitForever);
play_start_flag &= ~BIT(0);
os_printf("intercom stop\n");
}
}
}
}
intercom_task_decrease(intercom_s);
}
static void intercom_output_framebuf(INTERCOM_STRUCT *intercom_s, uint32_t cached)
{
uint8_t fade_in = 0;
uint8_t encode_data[MAX_ENCODED_LEN] = {0};
uint16_t new_sort = 0;
int32_t output_res = 0;
uint32_t timestamp = 0;
uint32_t offset = 0;
uint32_t code_len = 0;
static uint8_t play_speed_sta = 2;
static uint32_t play_speed = 100;
static uint32_t last_timestamp = 0;
static uint32_t plc_cnt = 0;
struct framebuff *frame_buf = NULL;
struct list_head *sublist_l = NULL;
sublist *sublist_n = NULL;
AUDIO_TRACK *audio_track = NULL;
output_framebuf_again:
frame_buf = fbpool_get(&intercom_s->tx_pool, 0, intercom_s->msi);
if(frame_buf) {
g_play_sort = g_current_sort;
((AUDECODER_OPERATION*)frame_buf->priv)->decode_operation = 0;
if(list_empty((struct list_head*)&intercom_s->useList_head) == 0) {
sublist_l = intercom_s->useList_head.next;
sublist_n = list_entry((struct list_head*)sublist_l, sublist, list);
new_sort = sublist_n->sort;
// os_printf("dec:%d %d %d\n",cached, g_current_sort, new_sort);
if((g_current_sort>new_sort) && ((g_current_sort-new_sort)<60000)) {
del_audio_sublist(intercom_s, sublist_l);
}
if((SUBLIST_NUM-cached<4) && (((new_sort>g_current_sort)&&(new_sort-g_current_sort<60000)) ||
((g_current_sort>new_sort)&&(g_current_sort-new_sort>=60000)))) {
g_current_sort = new_sort;
}
if(g_current_sort == new_sort) {
timestamp = sublist_n->timestamp;
last_timestamp = timestamp;
code_len = sublist_n->code_len;
struct list_head *audio_n = sublist_n->node_head.next;
uint8_t *addr = NULL;
offset = 0;
while(code_len > NODE_DATA_LEN) {
addr = (uint8_t*)get_audio_node_addr(audio_n);
os_memcpy(encode_data+offset, addr, NODE_DATA_LEN);
audio_n = audio_n->next;
offset += NODE_DATA_LEN;
code_len -= NODE_DATA_LEN;
}
if(code_len > 0) {
addr = (uint8_t*)get_audio_node_addr(audio_n);
os_memcpy(encode_data+offset, addr, code_len);
offset += code_len;
code_len = 0;
}
frame_buf->data = (uint8_t*)INTERCOM_MALLOC(sublist_n->code_len);
if(!frame_buf->data) {
os_printf("intercom malloc frame_buf fail\n");
msi_delete_fb(intercom_s->msi, frame_buf);
del_audio_sublist(intercom_s, sublist_l);
frame_buf = NULL;
g_current_sort += 1;
return;
}
os_memcpy(frame_buf->data, encode_data, sublist_n->code_len);
frame_buf->len = sublist_n->code_len;
timestamp = sublist_n->timestamp;
last_timestamp = timestamp;
del_audio_sublist(intercom_s, sublist_l);
if(fade_in)
((AUDECODER_OPERATION*)frame_buf->priv)->decode_operation = DECODE_ADD_FADE_IN;
fade_in = 0;
plc_cnt = 0;
}
else {
#if PLC_PROCESS
if(plc_cnt <= 5) {
((AUDECODER_OPERATION*)frame_buf->priv)->decode_operation = PACKET_LOSS_CONCEALMENT;
}
else {
((AUDECODER_OPERATION*)frame_buf->priv)->decode_operation = OUTPUT_MUTE_DATA;
}
#else
((AUDECODER_OPERATION*)frame_buf->priv)->decode_operation = OUTPUT_MUTE_DATA;
#endif
fade_in = 1;
timestamp = last_timestamp + FRAME_TIME;
last_timestamp = timestamp;
plc_cnt++;
lose_total++;
if(plc_cnt > max_lose_cnt)
max_lose_cnt = plc_cnt;
}
}
else {
#if PLC_PROCESS
if(plc_cnt <= 5) {
((AUDECODER_OPERATION*)frame_buf->priv)->decode_operation = PACKET_LOSS_CONCEALMENT;
}
else {
((AUDECODER_OPERATION*)frame_buf->priv)->decode_operation = OUTPUT_MUTE_DATA;
}
#else
((AUDECODER_OPERATION*)frame_buf->priv)->decode_operation = OUTPUT_MUTE_DATA;
#endif
fade_in = 1;
timestamp = last_timestamp + FRAME_TIME;
last_timestamp = timestamp;
plc_cnt++;
lose_total++;
if(plc_cnt > max_lose_cnt)
max_lose_cnt = plc_cnt;
}
#if CHANGE_PLAY_SPEED
if((cached > 0) && (cached <= (play_start_wait - 5))) {
if(play_speed_sta != 0) {
play_speed = 90;
msi_do_cmd(intercom_s->decoder_msi, MSI_CMD_AUCODER, MSI_AUCODER_SET_SPEED, play_speed);
play_speed_sta = 0;
}
}
else if(cached >= (play_start_wait + 5)) {
if(play_speed_sta != 1) {
play_speed = 110;
msi_do_cmd(intercom_s->decoder_msi, MSI_CMD_AUCODER, MSI_AUCODER_SET_SPEED, play_speed);
play_speed_sta = 1;
}
}
else if((cached == 0) || (cached == play_start_wait)) {
if(play_speed_sta != 2) {
play_speed = 100;
msi_do_cmd(intercom_s->decoder_msi, MSI_CMD_AUCODER, MSI_AUCODER_SET_SPEED, play_speed);
play_speed_sta = 2;
}
}
if(play_speed == 90)
slow_speed_cnt++;
if(play_speed == 110)
fast_speed_cnt++;
#endif
frame_buf->time = timestamp;
frame_buf->mtype = F_AUDIO;
output_res = msi_output_fb(intercom_s->msi, frame_buf);
// os_printf("out:%d %d\n",g_current_sort,(int32_t)(os_jiffies()-timestamp));
msi_cmd("R_AUDAC", MSI_CMD_AUDAC, MSI_AUDAC_GET_FILTER_TRACK, (uint32_t)(&audac_fiter_track));
audio_track = intercom_s->decoder_msi->priv;
if((audac_fiter_track==audio_track) && (cached>=1) && (cached >= (play_start_wait-2))) {
cached -= 1;
g_current_sort += 1;
os_sleep_ms(5);
goto output_framebuf_again;
}
g_current_sort += 1;
}
if(os_jiffies()-last_statistical_time > 5000) {
#if LOSE_STATISTICAL
os_printf("\r\naudio info:total loss:%d, max loss:%d\r\n",lose_total, max_lose_cnt);
#endif
if((lose_total > 50) || (lose_total>25 && max_lose_cnt>3)) {
intercom_s->loss_state = serious_loss;
}
else if((lose_total < 20) && (max_lose_cnt<=2) && (intercom_s->loss_state == serious_loss)) {
intercom_s->loss_state = mild_loss;
}
lose_total = 0;
max_lose_cnt = 0;
slow_speed_cnt = 0;
fast_speed_cnt = 0;
last_statistical_time = os_jiffies();
}
}
static void clear_useList_func(INTERCOM_STRUCT *intercom_s)
{
g_numofcached = get_audio_sublist_count(intercom_s, (struct list_head *)&intercom_s->useList_head);
for(uint8_t i=0; i<g_numofcached; i++) {
struct list_head *sublist_l = intercom_s->useList_head.next;
del_audio_sublist(intercom_s, sublist_l);
}
g_numofcached = 0;
play_start_flag &= ~BIT(0);
}
static void intercom_output_task(void *d)
{
uint8_t numofwait = 0;
uint32_t useList_clear = 0;
struct list_head *sublist_l = NULL;
sublist *sublist_n = NULL;
INTERCOM_STRUCT *intercom_s = (INTERCOM_STRUCT*)d;
struct os_semaphore *sem = &intercom_s->output_sema;
AUDEC_INIT audec_init;
intercom_task_increase(intercom_s);
audec_init.track_type = CALL_TRACK;
audec_init.priority = play_interruptible;
audec_init.direct_to_dac = 1;
audec_init.destroy_self = 0;
#if CHANGE_PLAY_SPEED
audec_init.use_tpc = 1;
#else
audec_init.use_tpc = 0;
#endif
audec_init.speed = 100;
audec_init.pitch = 100;
audec_init.src_msi = intercom_s->msi;
intercom_s->decoder_msi = audio_decode_init(AUDIO_DECODER, audio_adc_get_samplerate(AUSYS_AUAD), &audec_init);
if(!intercom_s->decoder_msi) {
os_printf("intercom audio decoder init fail!\n");
intercom_task_decrease(intercom_s);
return;
}
while(1) {
if(intercom_s->run_state == intercom_stop)
break;
os_event_wait(&intercom_s->clear_event, clear_useList_event, &useList_clear, OS_EVENT_WMODE_CLEAR|OS_EVENT_WMODE_OR, 0);
if(useList_clear & clear_useList_event) {
useList_clear = 0;
clear_useList_func(intercom_s);
os_event_set(&intercom_s->clear_event, clear_useList_finish_event, NULL);
numofwait = 0;
continue;
}
if(os_sema_down(sem, 5) == 1) {
g_numofcached = get_audio_sublist_count(intercom_s, (struct list_head *)&intercom_s->useList_head);
if(g_numofcached == 0) {
g_send_enable = 1;
}
#if INTERCOM_HALF_DUPLEX
if((send_start_flag == 1) && (g_r_identify_num > g_s_identify_num) && (g_numofcached > 0)) {
clear_useList_func(intercom_s);
numofwait = 0;
g_numofcached = 0;
}
#endif
if(((play_start_flag&BIT(0)) == 0) && ((g_numofcached > play_start_wait) || (numofwait > play_start_wait))) {
play_start_flag |= BIT(0);
numofwait = 0;
sublist_l = intercom_s->useList_head.next;
sublist_n = list_entry((struct list_head*)sublist_l, sublist, list);
g_current_sort = sublist_n->sort;
lose_total = 0;
max_lose_cnt = 0;
slow_speed_cnt = 0;
fast_speed_cnt = 0;
os_printf("intercom start\n");
}
if( ((play_start_flag&BIT(0)) == 0) && (g_numofcached > 0) )
numofwait++;
if(play_start_flag&BIT(0)) {
intercom_output_framebuf(intercom_s, g_numofcached);
}
}
}
audio_code_pause(intercom_s->decoder_msi);
audio_code_clear(intercom_s->decoder_msi);
intercom_task_decrease(intercom_s);
}
static void intercom_handel_task(void *d)
{
uint32_t ipaddr;
int32_t err = -1;
socklen_t addrlen = sizeof(struct sockaddr_in);
int32_t trans_time_out = FRAME_TIME * 2;
int32_t ret_time_out = 1;
INTERCOM_STRUCT *intercom_s = (INTERCOM_STRUCT*)d;
int32_t tos = 0xE0; //28
intercom_task_increase(intercom_s);
if(sys_cfgs.wifi_mode == WIFI_MODE_STA) {
do{
if(sys_cfgs.wifi_mode == WIFI_MODE_AP)
break;
if(intercom_s->run_state == intercom_stop) {
intercom_task_decrease(intercom_s);
return;
}
ipaddr = lwip_netif_get_ip2("w0").addr;
os_sleep_ms(100);
}while((ipaddr&0xff000000) == 0x1000000);
}
intercom_s->local_trans_fd = socket(AF_INET,SOCK_DGRAM, 0);
intercom_s->local_ret_fd = socket(AF_INET,SOCK_DGRAM, 0);
if((intercom_s->local_trans_fd==-1) || (intercom_s->local_ret_fd==-1)) {
os_printf("create intercom socket fail!\n");
goto intercom_handel_task_err;
}
if(setsockopt(intercom_s->local_trans_fd,SOL_SOCKET,SO_RCVTIMEO,&trans_time_out,sizeof(int32_t)) == -1) {
os_printf("intercom setsockopt fail!\n");
goto intercom_handel_task_err;
}
if(setsockopt(intercom_s->local_ret_fd,SOL_SOCKET,SO_RCVTIMEO,&ret_time_out,sizeof(int32_t)) == -1) {
os_printf("intercom setsockopt fail!\n");
goto intercom_handel_task_err;
}
if(setsockopt(intercom_s->local_trans_fd,IPPROTO_IP,IP_TOS,&tos,sizeof(int32_t)) == -1) {
os_printf("intercom setsockopt fail!\n");
goto intercom_handel_task_err;
}
if(setsockopt(intercom_s->local_ret_fd,IPPROTO_IP,IP_TOS,&tos,sizeof(int32_t)) == -1) {
os_printf("intercom setsockopt fail!\n");
goto intercom_handel_task_err;
}
for(uint8_t i=0; i<2; i++) {
(*((&intercom_s->local_trans_addr)+i)).sin_family = AF_INET;
(*((&intercom_s->local_trans_addr)+i)).sin_port = htons(INTERCOM_PORT + i);
(*((&intercom_s->local_trans_addr)+i)).sin_addr.s_addr = 0;
err = bind(*((&intercom_s->local_trans_fd)+i), (struct sockaddr *)((&intercom_s->local_trans_addr)+i), addrlen);
if(err == -1) {
os_printf("intercom socket bind fail!\n");
goto intercom_handel_task_err;
}
}
for(uint8_t i=0; i<2; i++) {
(*((&intercom_s->remote_trans_addr)+i)).sin_family = AF_INET;
(*((&intercom_s->remote_trans_addr)+i)).sin_port = htons(INTERCOM_PORT + i);
if(sys_cfgs.wifi_mode == WIFI_MODE_STA) {
(*((&intercom_s->remote_trans_addr)+i)).sin_addr.s_addr = inet_addr("192.168.169.1");
}
else {
#if ONE_TO_MANY
send_start_flag = 0;
#else
(*((&intercom_s->remote_trans_addr)+i)).sin_addr.s_addr = inet_addr("192.168.169.100");
#endif
}
}
err = intercom_room_init(intercom_s);
if(err == RET_ERR) {
goto intercom_handel_task_err;
}
os_mutex_init(&intercom_s->list_mutex);
os_mutex_init(&intercom_s->send_mutex);
os_event_init(&intercom_s->clear_event);
os_sema_init(&intercom_s->output_sema, 0);
os_timer_init(&intercom_s->ctl_timer, (os_timer_func_t)output_sema_up, OS_TIMER_MODE_PERIODIC, intercom_s);
if(!intercom_s->list_mutex.hdl || !intercom_s->send_mutex.hdl ||
!intercom_s->clear_event.hdl || !intercom_s->output_sema.hdl || !intercom_s->ctl_timer.hdl) {
os_printf("intercom malloc synth fail!\n");
goto intercom_handel_task_err;
}
intercom_s->recv_task_hdl = os_task_create("intercom_recv_task", intercom_recv_task, (void*)intercom_s, OS_TASK_PRIORITY_ABOVE_NORMAL-1, 0, NULL, 1024);
intercom_s->send_task_hdl = os_task_create("intercom_send_task", intercom_send_task, (void*)intercom_s, OS_TASK_PRIORITY_ABOVE_NORMAL, 0, NULL, 1024);
intercom_s->output_task_hdl = os_task_create("intercom_output_task", intercom_output_task, (void*)intercom_s, OS_TASK_PRIORITY_ABOVE_NORMAL, 0, NULL, 1024);
if(!intercom_s->recv_task_hdl || !intercom_s->send_task_hdl || !intercom_s->output_task_hdl) {
os_printf("intercom create task fail!\n");
goto intercom_handel_task_err;
}
os_timer_start(&intercom_s->ctl_timer, FRAME_TIME);
intercom_task_decrease(intercom_s);
return;
intercom_handel_task_err:
intercom_task_decrease(intercom_s);
intercom_deinit();
return;
}
static int32_t intercom_msi_action(struct msi *msi, uint32_t cmd_id, uint32_t param1, uint32_t param2)
{
int32_t ret = RET_OK;
INTERCOM_STRUCT *intercom_s = (INTERCOM_STRUCT*)msi->priv;
switch(cmd_id) {
case MSI_CMD_TRANS_FB:
{
ret = RET_OK+1;
struct framebuff *frame_buf = (struct framebuff *)param1;
if(frame_buf->mtype == F_AUDIO) {
ret = RET_OK;
}
break;
}
case MSI_CMD_FREE_FB:
{
if(intercom_s) {
struct framebuff *frame_buf = (struct framebuff *)param1;
if(frame_buf->data) {
INTERCOM_FREE(frame_buf->data);
frame_buf->data = NULL;
}
fbpool_put(&intercom_s->tx_pool, frame_buf);
}
ret = RET_OK+1;
break;
}
case MSI_CMD_POST_DESTROY:
{
if(intercom_s) {
for(uint32_t i=0; i<MAX_INTERCOM_TXBUF; i++) {
struct framebuff *frame_buf = (intercom_s->tx_pool.pool)+i;
if(frame_buf->data) {
INTERCOM_FREE(frame_buf->data);
frame_buf->data = NULL;
}
if(frame_buf->priv) {
INTERCOM_FREE(frame_buf->priv);
frame_buf->priv = NULL;
}
}
fbpool_destroy(&intercom_s->tx_pool);
INTERCOM_FREE(intercom_s);
}
ret = RET_OK;
break;
}
default:
break;
}
return ret;
}
struct msi *intercom_init(void)
{
uint8_t msi_isnew = 0;
struct framebuff *frame_buf = NULL;
struct msi *msi = NULL;
msi = msi_new("SR_INTERCOM", MAX_INTERCOM_RXBUF, &msi_isnew);
if(msi == NULL) {
os_printf("create intercom msi fail\n");
return NULL;
}
if(msi && !msi_isnew) {
os_printf("intercom has been created\n");
return NULL;
}
INTERCOM_STRUCT *intercom_s = (INTERCOM_STRUCT*)INTERCOM_ZALLOC(sizeof(INTERCOM_STRUCT));
if(intercom_s == NULL) {
msi_destroy(msi);
os_printf("malloc intercom_s fail!\n");
return NULL;
}
intercom_s->local_trans_fd = -1;
intercom_s->local_ret_fd = -1;
intercom_s->msi = msi;
intercom_s->msi->enable = 1;
intercom_s->msi->action = intercom_msi_action;
fbpool_init(&intercom_s->tx_pool, MAX_INTERCOM_TXBUF);
for(uint32_t i=0; i<MAX_INTERCOM_TXBUF; i++) {
frame_buf = (intercom_s->tx_pool.pool)+i;
frame_buf->data = NULL;
frame_buf->priv = NULL;
frame_buf->priv = (AUDECODER_OPERATION*)INTERCOM_ZALLOC(sizeof(AUDECODER_OPERATION));
if(!frame_buf->priv)
goto intercom_init_err;
}
intercom_s->msi->priv = intercom_s;
#if MAGIC_VOICE_EN
intercom_s->magic_voice_msi = magic_voice_init(audio_adc_get_samplerate(AUSYS_AUAD), FRAME_TIME*audio_adc_get_samplerate(AUSYS_AUAD)/1000);
if(intercom_s->magic_voice_msi == NULL) {
os_printf("intercom create magic voice msi fail\n");
goto intercom_init_err;
}
#endif
if(os_mutex_init(&intercom_s->state_mutex) != RET_OK)
goto intercom_init_err;
intercom_task_state_init(intercom_s);
intercom_s->init_task_hdl = os_task_create("intercom_handel_task", intercom_handel_task, (void*)intercom_s, OS_TASK_PRIORITY_NORMAL, 0, NULL, 1024);
if(!intercom_s->init_task_hdl)
goto intercom_init_err;
global_intercom_msi = intercom_s->msi;
return intercom_s->msi;
intercom_init_err:
intercom_deinit();
os_printf("intercom init fail\n");
return NULL;
}
void intercom_deinit(void)
{
global_intercom_msi = NULL;
struct msi *msi = msi_find("SR_INTERCOM", 1);
if(msi) {
msi_put(msi);
INTERCOM_STRUCT *intercom_s = (INTERCOM_STRUCT*)(msi->priv);
intercom_s->run_state = intercom_stop;
while(intercom_s->run_task > 0)
os_sleep_ms(1);
clear_all_device(intercom_s);
if(intercom_s->magic_voice_msi) {
magic_voice_deinit();
}
if(intercom_s->encoder_msi) {
audio_encode_deinit(intercom_s->encoder_msi);
}
if(intercom_s->decoder_msi)
audio_decode_deinit(intercom_s->decoder_msi);
if(intercom_s->ctl_timer.hdl) {
os_timer_stop(&intercom_s->ctl_timer);
os_timer_del(&intercom_s->ctl_timer);
}
if(intercom_s->output_sema.hdl)
os_sema_del(&intercom_s->output_sema);
if(intercom_s->state_mutex.hdl)
os_mutex_del(&intercom_s->state_mutex);
if(intercom_s->list_mutex.hdl)
os_mutex_del(&intercom_s->list_mutex);
if(intercom_s->send_mutex.hdl)
os_mutex_del(&intercom_s->send_mutex);
if(intercom_s->clear_event.hdl)
os_event_del(&intercom_s->clear_event);
intercom_close_socket(intercom_s);
intercom_room_free(intercom_s);
msi_destroy(intercom_s->msi);
g_play_sort = 0;
g_current_sort = 1;
g_numofcached = 0;
g_s_identify_num = 0;
play_start_flag = 2;
}
}
void intercom_send_enable(uint8_t state)
{
if(state == 1) {
g_s_identify_num = 0;
os_random_bytes((uint8_t*)(&g_s_identify_num), 4);
}
send_start_flag = state;
}
void intercom_recv_enable(uint8_t state)
{
if(state == 1)
play_start_flag |= BIT(1);
else if(state == 0)
play_start_flag &= ~BIT(1);
}
void intercom_encode_pause(uint8_t state, uint8_t clear)
{
if(global_intercom_msi) {
INTERCOM_STRUCT *intercom_s = (INTERCOM_STRUCT*)(global_intercom_msi->priv);
if(intercom_s->encoder_msi == NULL) {
return;
}
if(state == 1) {
audio_code_pause(intercom_s->encoder_msi);
if(clear) {
audio_code_clear(intercom_s->encoder_msi);
}
}
else if(state == 0) {
g_s_identify_num = 0;
os_random_bytes((uint8_t*)(&g_s_identify_num), 4);
audio_code_continue(intercom_s->encoder_msi);
}
}
}
void intercom_decode_pause(uint8_t state, uint8_t clear)
{
if(global_intercom_msi) {
INTERCOM_STRUCT *intercom_s = (INTERCOM_STRUCT*)(global_intercom_msi->priv);
if(intercom_s->decoder_msi == NULL) {
return;
}
if(state == 1) {
audio_code_direct_to_dac(intercom_s->decoder_msi, 0);
audio_code_pause(intercom_s->decoder_msi);
if(clear) {
audio_code_clear(intercom_s->decoder_msi);
}
}
else if(state == 0) {
audio_code_direct_to_dac(intercom_s->decoder_msi, 1);
audio_code_continue(intercom_s->decoder_msi);
}
}
}
void intercom_reset_play(void)
{
if(global_intercom_msi) {
INTERCOM_STRUCT *intercom_s = (INTERCOM_STRUCT*)(global_intercom_msi->priv);
audio_code_pause(intercom_s->decoder_msi);
audio_code_clear(intercom_s->decoder_msi);
play_start_flag &= ~BIT(1);
os_event_set(&intercom_s->clear_event, clear_useList_event, NULL);
os_event_wait(&intercom_s->clear_event, clear_useList_finish_event,
NULL, OS_EVENT_WMODE_CLEAR|OS_EVENT_WMODE_OR, osWaitForever);
play_start_flag |= BIT(1);
audio_code_continue(intercom_s->decoder_msi);
}
}
void intercom_set_stream_type(uint8_t recv_type, uint8_t send_type)
{
if(global_intercom_msi) {
INTERCOM_STRUCT *intercom_s = (INTERCOM_STRUCT*)(global_intercom_msi->priv);
intercom_s->recv_stream_type = recv_type;
intercom_s->send_stream_type = send_type;
}
}
uint32_t intercom_ctrl_key(struct key_callback_list_s *callback_list,uint32_t keyvalue,uint32_t extern_value)
{
#ifdef SYS_APP_WALKIE_TALKIE
if( (keyvalue>>8) != AD_SPEACH)
return 0;
#else
if( (keyvalue>>8) != AD_DOWN)
return 0;
#endif
uint32 key_val = (keyvalue & 0xff);
if(g_send_enable == 0) {
if(send_start_flag == 1) {
intercom_encode_pause(1, 1);
send_start_flag = 0;
}
return 0;
}
if((key_val == KEY_EVENT_DOWN) || (key_val == KEY_EVENT_LDOWN) || (key_val == KEY_EVENT_REPEAT)) {
if(send_start_flag == 0) {
intercom_encode_pause(0, 0);
g_s_identify_num = 0;
os_random_bytes((uint8_t*)(&g_s_identify_num), 4);
send_start_flag = 1;
}
}
else if((key_val == KEY_EVENT_SUP) || (key_val == KEY_EVENT_LUP)) {
if(send_start_flag == 1) {
intercom_encode_pause(1, 1);
send_start_flag = 0;
}
}
return 0;
}
void intercom_switch_device(uint32_t device_id)
{
if(global_intercom_msi) {
INTERCOM_STRUCT *intercom_s = (INTERCOM_STRUCT*)(global_intercom_msi->priv);
intercom_s->next_dev_id = device_id;
}
}
int32_t atcmd_intercom_switch_device(const char *cmd, char *argv[], uint32 argc)
{
uint8_t device = 0;
if(argv[0]) {
device = os_atoi(argv[0]);
intercom_switch_device(device);
return RET_OK;
}
return RET_ERR;
}