second commit

This commit is contained in:
mojingtao 2024-11-05 09:52:55 +08:00
parent 3444880293
commit 5a4277dfad
9 changed files with 0 additions and 2857 deletions

View File

@ -1,405 +0,0 @@
#include "server/audio_server.h"
#include "server/server_core.h"
#include "system/app_core.h"
#include "generic/circular_buf.h"
#include "os/os_api.h"
#include "app_config.h"
#include "system/includes.h"
#include "wifi/wifi_connect.h"
#include "syscfg/syscfg_id.h"
#include "storage_device.h"
#include "fs/fs.h"
#include <time.h>
#include "aduio_record.h"
#include "device/device.h"
#include "asm/clock.h"
//#define RECORD
#ifdef RECORD
//全局变量
OS_SEM voice_start_sem;
OS_SEM voice_msg_sem;
struct record_message record_msg;
//静态全局变量
static struct timer_hdl timer4_hal;
static const u32 timer_div[] = {
/*0000*/ 1,
/*0001*/ 4,
/*0010*/ 16,
/*0011*/ 64,
/*0100*/ 2,
/*0101*/ 8,
/*0110*/ 32,
/*0111*/ 128,
/*1000*/ 256,
/*1001*/ 4 * 256,
/*1010*/ 16 * 256,
/*1011*/ 64 * 256,
/*1100*/ 2 * 256,
/*1101*/ 8 * 256,
/*1110*/ 32 * 256,
/*1111*/ 128 * 256,
};
//静态函数
static struct record_hdl record_handler;
#define __this (&record_handler)
static SEC_USED(.volatile_ram) JL_TIMER_TypeDef *TMR = JL_TIMER4;//选择定时器4
static SEC_USED(.volatile_ram) u8 timer_irq = IRQ_TIMER4_IDX;//选择定时器4
static SEC_USED(.volatile_ram) u32 timer_clk = 0;
static AWINLINE TSEC void timer_cfg(u32 freq, u32 us)
{
u8 timer_index[16] = {0, 4, 1, 5, 2, 6, 3, 7, 8, 12, 9, 13, 10, 14, 11, 15};
u32 timer_table[16] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768};
u32 clock = timer_clk;
u8 psc = 0;
u8 tmp = 0;
u32 prd = 0;
u32 ts = us / (1000 * 1000);//计算秒
u32 tu = us % (1000 * 1000);//计算秒剩余us
u8 i;
float tp = 0;
if (freq >= clock) {
freq = clock;
} else if (freq <= 1) {
freq = 1;
if (ts) {
tp = (float)tu / (1000 * 1000);
}
}
/*求prd值*/
prd = clock / freq;
if (prd > 65535) {
for (psc = 0; psc < 16; psc++) {
prd = (u32)(clock / (timer_table[psc]) / freq);
if (prd <= 65535) {
break;
} else if (psc == 15) {
prd = 65535;
break;
}
}
}
prd = ts ? (prd * ts + tp * prd) : prd;
psc = timer_index[psc];
TMR->CON = 0;
TMR->CNT = 0;
TMR->CON |= BIT(14);
TMR->PRD = prd;
TMR->CON |= psc << 4; //lsb_clk分频
TMR->CON |= BIT(0);
}
static void TSEC timer_set(u32 us)//设置时间,该函数可以在中断调用重新设置定时器值
{
u32 freq = 1000000 / us;
timer_cfg(freq, us);
}
extern void timer4_stop(void);
static ___interrupt TSEC void timer_isr(void)//中断
{
if (TMR->CON & BIT(15)) {
TMR->CON |= BIT(14);
//todo,中断函数执行程序...
if(!__this->start_flag){
__this->end_flag = 1;
printf("---->end\r\n");
timer4_stop();
}
}
}
static void timer4_resume(void) //定时器继续
{
if (timer4_hal.run == 0) {
return;
}
u32 prd_cnt;
u8 index;
//precesion = PRD * index / CLK
for (index = 0; index < (sizeof(timer_div) / sizeof(timer_div[0])); index++) {
prd_cnt = timer4_hal.precesion * (APP_TIMER_CLK / 1000) / timer_div[index];
if (prd_cnt > MIN_TIME_CNT && prd_cnt < MAX_TIME_CNT) {
break;
}
}
timer4_hal.index = index;
timer4_hal.prd = prd_cnt;
JL_TIMER4->CNT = timer4_hal.ticks;
JL_TIMER4->PRD = prd_cnt;
JL_TIMER4->CON = (index << 4) | BIT(0) | BIT(3);
}
void timer4_stop(void) //定时器停止
{
printf("--->Stop\r\n");
JL_TIMER4->CON = BIT(14);
timer4_hal.run = 0;
timer4_hal.precesion = 0;
}
void timer4_run(u32 precesion) //定时器开始
{
if (timer4_hal.precesion == precesion) {
return;
}
printf("-->Run %d\r\n", precesion);
JL_TIMER4->CON = BIT(14);
timer4_hal.precesion = precesion;
timer4_hal.run = 1;
timer4_hal.ticks = 0;
timer4_resume();
}
//编码器输出MP3数据
static int record_vfs_fwrite(void *file, void *data, u32 len)
{
static u8 *recognition_buffer = NULL;
static u32 buffer_filled = 0;
if (!recognition_buffer) {
recognition_buffer = malloc(SPEECH_RECOGNITION_BUFFER_SIZE);
if (!recognition_buffer) {
log_e("Failed to allocate recognition buffer\n");
return 0;
}
}
// 将新数据添加到缓冲区
if (buffer_filled + len <= SPEECH_RECOGNITION_BUFFER_SIZE) {
memcpy(recognition_buffer + buffer_filled, data, len);
buffer_filled += len;
} else {
// 改变全局变量,发送信号量
record_msg.msg = recognition_buffer;
record_msg.msg_size = buffer_filled;
if(__this->end_flag){
__this->end_flag = 0;
record_msg.end = 1;
os_sem_post(&__this->stop_sem);
}
else
record_msg.end = 0;
//发送信号量
if(__this->start_flag||record_msg.end){
os_sem_post(&voice_msg_sem);
}
if(__this->stop_flag){
__this->start_flag = 0;
__this->stop_flag = 0;
}
// 重置缓冲区
buffer_filled = 0;
memcpy(recognition_buffer, data, len);
buffer_filled = len;
}
return len;
}
//解码器读取MP3数据
static int record_vfs_fread(void *file, void *data, u32 len)
{
return len;
}
static int record_vfs_fclose(void *file)
{
return 0;
}
static int record_vfs_flen(void *file)
{
return 0;
}
static const struct audio_vfs_ops record_vfs_ops = {
.fwrite = record_vfs_fwrite,
.fread = record_vfs_fread,
.fclose = record_vfs_fclose,
.flen = record_vfs_flen,
};
static int record_close(void)
{
union audio_req req = {0};
log_d("----------record close----------\n");
if (__this->enc_server) {
req.enc.cmd = AUDIO_ENC_CLOSE;
server_request(__this->enc_server, AUDIO_REQ_ENC, &req);
}
return 0;
}
static void enc_server_event_handler(void *priv, int argc, int *argv)
{
switch (argv[0]) {
case AUDIO_SERVER_EVENT_ERR:
case AUDIO_SERVER_EVENT_END:
record_close();
break;
case AUDIO_SERVER_EVENT_SPEAK_START:
log_i("speak start ! \n");
__this->start_flag = 1;
__this->end_flag = 0;
os_sem_post(&voice_start_sem);
timer_set(2000 * 1000);
timer4_stop();
break;
case AUDIO_SERVER_EVENT_SPEAK_STOP:
log_i("speak stop ! \n");
__this->stop_flag = 1;
timer4_run(2000);
break;
default:
break;
}
}
static int encoder_init(int sample_rate, u8 channel)
{
int err;
union audio_req req = {0};
log_d("----------encoder_init----------\n");
if (channel > 2) {
channel = 2;
}
os_sem_create(&__this->stop_sem, 0);
os_sem_create(&voice_msg_sem, 0);
os_sem_create(&voice_start_sem, 0);
__this->start_flag = 0;
__this->stop_flag = 0;
__this->end_flag = 0;
/****************初始化编码器*******************/
memset(&req, 0, sizeof(union audio_req));
//BIT(x)用来区分上层需要获取哪个通道的数据
if (channel == 2) {
req.enc.channel_bit_map = BIT(CONFIG_AUDIO_ADC_CHANNEL_L) | BIT(CONFIG_AUDIO_ADC_CHANNEL_R);
} else {
req.enc.channel_bit_map = BIT(CONFIG_AUDIO_ADC_CHANNEL_L);
}
req.enc.frame_size = sample_rate / 100 * 4 * channel; //收集够多少字节MP3数据就回调一次fwrite
req.enc.output_buf_len = req.enc.frame_size * 3; //底层缓冲buf至少设成3倍frame_size
req.enc.cmd = AUDIO_ENC_OPEN;
req.enc.channel = channel;
req.enc.volume = __this->gain;
req.enc.sample_rate = sample_rate;
req.enc.format = "mp3";
req.enc.sample_source = __this->sample_source;
req.enc.vfs_ops = &record_vfs_ops;
req.enc.file = NULL;
if (channel == 1 && !strcmp(__this->sample_source, "mic") && (sample_rate == 8000 || sample_rate == 16000)) {
req.enc.use_vad = 1; //打开VAD断句功能
req.enc.dns_enable = 1; //打开降噪功能
req.enc.vad_auto_refresh = 1; //VAD自动刷新
}
err = server_request(__this->enc_server, AUDIO_REQ_ENC, &req);
if (err) {
return -1;
}
return 0;
}
static int record_mode_init(void)
{
log_i("record_play_main\n");
memset(__this, 0, sizeof(struct record_hdl));
#ifdef CONFIG_STORE_VOLUME
if (syscfg_read(CFG_MUSIC_VOL, &__this->volume, sizeof(__this->volume)) < 0 ||
__this->volume < MIN_VOLUME_VALUE || __this->volume > MAX_VOLUME_VALUE) {
__this->volume = INIT_VOLUME_VALUE;
}
#else
__this->volume = INIT_VOLUME_VALUE;
#endif
if (__this->volume < 0 || __this->volume > MAX_VOLUME_VALUE) {
__this->volume = INIT_VOLUME_VALUE;
}
__this->sample_source = "mic";
__this->channel = CONFIG_AUDIO_RECORDER_CHANNEL;
__this->gain = CONFIG_AUDIO_ADC_GAIN;
__this->sample_rate = CONFIG_AUDIO_RECORDER_SAMPLERATE;
__this->enc_server = server_open("audio_server", "enc");
server_register_event_handler_to_task(__this->enc_server, NULL, enc_server_event_handler, "app_core");
return encoder_init(__this->sample_rate, __this->channel);
}
static void record_run_task(void){
union audio_req req = {0};
record_mode_init();
timer_clk = clk_get("timer");//先获取定时器的时钟源
request_irq(timer_irq, 3, timer_isr, 0);//注册中断函数定和中断优先级
while(1){
//等待信号量
os_sem_pend(&__this->stop_sem, 0);
//os_time_dly(1000);
req.enc.cmd = AUDIO_ENC_PP;
server_request(__this->enc_server, AUDIO_REQ_ENC, &req);
}
}
static void record_run_task_create(void)
{
thread_fork("record_run_task", 15, 1024 * 3 , 0, NULL, record_run_task, NULL);
}
static void record_start(void *priv)
{
enum wifi_sta_connect_state state;
while (1) {
printf("Connecting to the network...\n");
state = wifi_get_sta_connect_state();
if (WIFI_STA_NETWORK_STACK_DHCP_SUCC == state) {
printf("Network connection is successful!\n");
break;
}
os_time_dly(500);
}
record_run_task_create();
}
static int record_init_task(void)
{
if (thread_fork("record_start", 10, 512, 0, NULL, record_start, NULL) != OS_NO_ERR) {
printf("thread fork fail\n");
}
}
late_initcall(record_init_task);
#endif //RECORD

View File

@ -1,385 +0,0 @@
#include "aduio_record.h"
//#define RECORD
#ifdef RECORD
//全局变量
OS_SEM voice_start_sem;
//静态全局变量
static struct timer_hdl timer4_hal;
static const u32 timer_div[] = {
/*0000*/ 1,
/*0001*/ 4,
/*0010*/ 16,
/*0011*/ 64,
/*0100*/ 2,
/*0101*/ 8,
/*0110*/ 32,
/*0111*/ 128,
/*1000*/ 256,
/*1001*/ 4 * 256,
/*1010*/ 16 * 256,
/*1011*/ 64 * 256,
/*1100*/ 2 * 256,
/*1101*/ 8 * 256,
/*1110*/ 32 * 256,
/*1111*/ 128 * 256,
};
//静态函数
static struct record_hdl record_handler;
#define __this (&record_handler)
static SEC_USED(.volatile_ram) JL_TIMER_TypeDef *TMR = JL_TIMER4;//选择定时器4
static SEC_USED(.volatile_ram) u8 timer_irq = IRQ_TIMER4_IDX;//选择定时器4
static SEC_USED(.volatile_ram) u32 timer_clk = 0;
static AWINLINE TSEC void timer_cfg(u32 freq, u32 us)
{
u8 timer_index[16] = {0, 4, 1, 5, 2, 6, 3, 7, 8, 12, 9, 13, 10, 14, 11, 15};
u32 timer_table[16] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768};
u32 clock = timer_clk;
u8 psc = 0;
u8 tmp = 0;
u32 prd = 0;
u32 ts = us / (1000 * 1000);//计算秒
u32 tu = us % (1000 * 1000);//计算秒剩余us
u8 i;
float tp = 0;
if (freq >= clock) {
freq = clock;
} else if (freq <= 1) {
freq = 1;
if (ts) {
tp = (float)tu / (1000 * 1000);
}
}
/*求prd值*/
prd = clock / freq;
if (prd > 65535) {
for (psc = 0; psc < 16; psc++) {
prd = (u32)(clock / (timer_table[psc]) / freq);
if (prd <= 65535) {
break;
} else if (psc == 15) {
prd = 65535;
break;
}
}
}
prd = ts ? (prd * ts + tp * prd) : prd;
psc = timer_index[psc];
TMR->CON = 0;
TMR->CNT = 0;
TMR->CON |= BIT(14);
TMR->PRD = prd;
TMR->CON |= psc << 4; //lsb_clk分频
TMR->CON |= BIT(0);
}
static void TSEC timer_set(u32 us)//设置时间,该函数可以在中断调用重新设置定时器值
{
u32 freq = 1000000 / us;
timer_cfg(freq, us);
}
extern void timer4_stop(void);
static ___interrupt TSEC void timer_isr(void)//中断
{
if (TMR->CON & BIT(15)) {
TMR->CON |= BIT(14);
//todo,中断函数执行程序...
if(!__this->start_flag){
__this->end_flag = 1;
printf("---->end\r\n");
timer4_stop();
}
}
}
static void timer4_resume(void) //定时器继续
{
if (timer4_hal.run == 0) {
return;
}
u32 prd_cnt;
u8 index;
//precesion = PRD * index / CLK
for (index = 0; index < (sizeof(timer_div) / sizeof(timer_div[0])); index++) {
prd_cnt = timer4_hal.precesion * (APP_TIMER_CLK / 1000) / timer_div[index];
if (prd_cnt > MIN_TIME_CNT && prd_cnt < MAX_TIME_CNT) {
break;
}
}
timer4_hal.index = index;
timer4_hal.prd = prd_cnt;
JL_TIMER4->CNT = timer4_hal.ticks;
JL_TIMER4->PRD = prd_cnt;
JL_TIMER4->CON = (index << 4) | BIT(0) | BIT(3);
}
static void timer4_stop(void) //定时器停止
{
printf("--->Stop\r\n");
JL_TIMER4->CON = BIT(14);
timer4_hal.run = 0;
timer4_hal.precesion = 0;
}
static void timer4_run(u32 precesion) //定时器开始
{
if (timer4_hal.precesion == precesion) {
return;
}
printf("-->Run %d\r\n", precesion);
JL_TIMER4->CON = BIT(14);
timer4_hal.precesion = precesion;
timer4_hal.run = 1;
timer4_hal.ticks = 0;
timer4_resume();
}
//编码器输出MP3数据
static int record_vfs_fwrite(void *file, void *data, u32 len)
{
static u8 *recognition_buffer = NULL;
static u32 buffer_filled = 0;
int argv[4];
int err;
if (!recognition_buffer) {
recognition_buffer = malloc(SPEECH_RECOGNITION_BUFFER_SIZE);
if (!recognition_buffer) {
log_e("Failed to allocate recognition buffer\n");
return 0;
}
}
// 将新数据添加到缓冲区
if (buffer_filled + len <= SPEECH_RECOGNITION_BUFFER_SIZE) {
memcpy(recognition_buffer + buffer_filled, data, len);
buffer_filled += len;
} else {
rec_msg *qmsg = calloc(1,sizeof(rec_msg));
memcpy(qmsg->msg,recognition_buffer,buffer_filled);
qmsg->msg_size = buffer_filled;
if(__this->end_flag){
__this->end_flag = 0;
qmsg->end = 1;
os_sem_post(&__this->stop_sem);
}
else
qmsg->end = 0;
//发送消息队列
if(__this->start_flag||qmsg->end){
argv[0]=(int)qmsg;
err = os_taskq_post_type("websockets_stt_client_main_thread", Q_USER, 4, argv);
if (err == OS_Q_FULL) {
return len;
}
}
if(__this->stop_flag){
__this->start_flag = 0;
__this->stop_flag = 0;
}
// 重置缓冲区
buffer_filled = 0;
memcpy(recognition_buffer, data, len);
buffer_filled = len;
}
return len;
}
//解码器读取MP3数据
static int record_vfs_fread(void *file, void *data, u32 len)
{
return len;
}
static int record_vfs_fclose(void *file)
{
return 0;
}
static int record_vfs_flen(void *file)
{
return 0;
}
static const struct audio_vfs_ops record_vfs_ops = {
.fwrite = record_vfs_fwrite,
.fread = record_vfs_fread,
.fclose = record_vfs_fclose,
.flen = record_vfs_flen,
};
static int record_close(void)
{
union audio_req req = {0};
log_d("----------record close----------\n");
if (__this->enc_server) {
req.enc.cmd = AUDIO_ENC_CLOSE;
server_request(__this->enc_server, AUDIO_REQ_ENC, &req);
}
return 0;
}
static void enc_server_event_handler(void *priv, int argc, int *argv)
{
switch (argv[0]) {
case AUDIO_SERVER_EVENT_ERR:
case AUDIO_SERVER_EVENT_END:
record_close();
break;
case AUDIO_SERVER_EVENT_SPEAK_START:
log_i("speak start ! \n");
__this->start_flag = 1;
__this->end_flag = 0;
os_sem_set(&voice_start_sem,0);
os_sem_post(&voice_start_sem);
timer_set(2000 * 1000);
timer4_stop();
break;
case AUDIO_SERVER_EVENT_SPEAK_STOP:
log_i("speak stop ! \n");
__this->stop_flag = 1;
timer4_run(2000);
break;
default:
break;
}
}
static int encoder_init(int sample_rate, u8 channel)
{
int err;
union audio_req req = {0};
log_d("----------encoder_init----------\n");
if (channel > 2) {
channel = 2;
}
os_sem_create(&__this->stop_sem, 0);
os_sem_create(&voice_start_sem, 0);
__this->start_flag = 0;
__this->stop_flag = 0;
__this->end_flag = 0;
/****************初始化编码器*******************/
memset(&req, 0, sizeof(union audio_req));
//BIT(x)用来区分上层需要获取哪个通道的数据
if (channel == 2) {
req.enc.channel_bit_map = BIT(CONFIG_AUDIO_ADC_CHANNEL_L) | BIT(CONFIG_AUDIO_ADC_CHANNEL_R);
} else {
req.enc.channel_bit_map = BIT(CONFIG_AUDIO_ADC_CHANNEL_L);
}
req.enc.frame_size = sample_rate / 100 * 4 * channel; //收集够多少字节MP3数据就回调一次fwrite
req.enc.output_buf_len = req.enc.frame_size * 3; //底层缓冲buf至少设成3倍frame_size
req.enc.cmd = AUDIO_ENC_OPEN;
req.enc.channel = channel;
req.enc.volume = __this->gain;
req.enc.sample_rate = sample_rate;
req.enc.format = "mp3";
req.enc.sample_source = __this->sample_source;
req.enc.vfs_ops = &record_vfs_ops;
req.enc.file = NULL;
if (channel == 1 && !strcmp(__this->sample_source, "mic") && (sample_rate == 8000 || sample_rate == 16000)) {
req.enc.use_vad = 1; //打开VAD断句功能
req.enc.dns_enable = 1; //打开降噪功能
req.enc.vad_auto_refresh = 1; //VAD自动刷新
}
err = server_request(__this->enc_server, AUDIO_REQ_ENC, &req);
if (err) {
return -1;
}
return 0;
}
static int record_mode_init(void)
{
log_i("record_play_main\n");
memset(__this, 0, sizeof(struct record_hdl));
__this->sample_source = "mic";
__this->channel = CONFIG_AUDIO_RECORDER_CHANNEL;
__this->gain = CONFIG_AUDIO_ADC_GAIN;
__this->sample_rate = CONFIG_AUDIO_RECORDER_SAMPLERATE;
__this->enc_server = server_open("audio_server", "enc");
server_register_event_handler_to_task(__this->enc_server, NULL, enc_server_event_handler, "app_core");
return encoder_init(__this->sample_rate, __this->channel);
}
static void record_run_task(void){
union audio_req req = {0};
record_mode_init();
timer_clk = clk_get("timer");//先获取定时器的时钟源
request_irq(timer_irq, 3, timer_isr, 0);//注册中断函数定和中断优先级
while(1){
//等待信号量
os_sem_pend(&__this->stop_sem, 0);
//os_time_dly(1000);
req.enc.cmd = AUDIO_ENC_PP;
server_request(__this->enc_server, AUDIO_REQ_ENC, &req);
}
}
static void record_run_task_create(void)
{
thread_fork("record_run_task", 15, 1024 * 3 , 0, NULL, record_run_task, NULL);
}
static void record_start(void *priv)
{
enum wifi_sta_connect_state state;
while (1) {
printf("Connecting to the network...\n");
state = wifi_get_sta_connect_state();
if (WIFI_STA_NETWORK_STACK_DHCP_SUCC == state) {
printf("Network connection is successful!\n");
break;
}
os_time_dly(500);
}
record_run_task_create();
}
//程序入口
static int record_init_task(void)
{
if (thread_fork("record_start", 10, 512, 0, NULL, record_start, NULL) != OS_NO_ERR) {
printf("thread fork fail\n");
}
}
late_initcall(record_init_task);
#endif //RECORD

View File

@ -1,175 +0,0 @@
/*
主要问题是如何接收处理传过来的文字
*/
#include "system/includes.h"
#include "wifi/wifi_connect.h"
#include "http/http_cli.h"
#include "app_config.h"
//#define CHAT
#ifdef CHAT
//选择其中一种进行测试
//#define HTTP_GET_TEST
#define HTTP_POST_TEST
//#define HTTP_PUT_TEST
#define HTTP_DEMO_URL "https://ark.cn-beijing.volces.com/api/v3/chat/completions"
//#define HTTP_DEMO_URL "https://www.baidu.com/search/error.html"
//#define HTTP_DEMO_URL "https://jsonplaceholder.typicode.com/posts"
#define HTTP_DEMO_DATA "{\"model\":\"ep-20241010174456-nhgs5\", \"messages\":[{\"role\":\"user\", \"content\":\"我爱你豆包\"}]}"
//#define HTTP_DEMO_DATA "{\"name\":\"xiao ming\", \"age\":12}"
//#define HTTP_DEMO_DATA "{\"title\": \"foo\", \"body\": \"bar\", \"userId\": 1}"
#define LOG_HTTP_HEAD_OPTION \
"POST /api/v3/chat/completions HTTP/1.1\r\n"\
"Host: ark.cn-beijing.volces.com\r\n"\
"Content-type: application/json\r\n"\
"Content-length: %d\r\n"\
"Authorization: Bearer f311cc81-1c5b-42c3-bb8a-1b10d1348080\r\n\r\n"
//#define LOG_HTTP_HEAD_OPTION \
// "POST /search/error.html HTTP/1.1\r\n"\
// "Host: www.baidu.com\r\n"\
// "Connection: close\r\n"\
// "Cache-Control: no-store\r\n"\
// "Content-type: application/json\r\n"\
// "Content-length: 30\r\n"\
// "Accept: */*\r\n"\
// "Accept-Language: zh-CN,zh,q=0.8\r\n"\
// "Cookie: loginType=hardware; appId=1000000001; deviceSN=A4W0H02B000001; credential=56fb1f8df901f13fea8bf12ac2109c58; randNum=2dcf4629\r\n\r\n"
//#define LOG_HTTP_HEAD_OPTION \
// "POST /post HTTP/1.1\r\n"\
// "Host: jsonplaceholder.typicode.com\r\n"\
// "Connection: close\r\n"\
// "Cache-Control: no-store\r\n"\
// "Content-type: application/json\r\n"\
// "Content-length: 44\r\n"\
// "Accept: */*\r\n"\
// "Accept-Language: zh-CN,zh,q=0.8\r\n\r\n"\
#define USER_HEADER_BUF_SIZE 2 * 1024
httpin_error httpcli_put(httpcli_ctx *ctx)
{
return httpcli_post(ctx);
}
static void http_test_task(void *priv)
{
int ret = 0;
http_body_obj http_body_buf;
char *user_header_buf = NULL;
user_header_buf = calloc(1, USER_HEADER_BUF_SIZE);
if (!user_header_buf) {
printf("calloc faile\n");
return;
}
sprintf(user_header_buf, LOG_HTTP_HEAD_OPTION, strlen(HTTP_DEMO_DATA));
printf(" . user_header_buf :\r\n%s\r\n",user_header_buf);
httpcli_ctx *ctx = (httpcli_ctx *)calloc(1, sizeof(httpcli_ctx));
if (!ctx) {
printf("calloc faile\n");
return;
}
memset(&http_body_buf, 0x0, sizeof(http_body_obj));
http_body_buf.recv_len = 0;
http_body_buf.buf_len = 4 * 1024;
http_body_buf.buf_count = 1;
http_body_buf.p = (char *) malloc(http_body_buf.buf_len * http_body_buf.buf_count);
if (!http_body_buf.p) {
free(ctx);
return;
}
ctx->url = HTTP_DEMO_URL;
ctx->timeout_millsec = 5000;
ctx->priv = &http_body_buf;
ctx->connection = "close";
// ctx->mode = MODE_HTTPS;
#if (defined HTTP_POST_TEST)
printf("http post test start\n\n");
ctx->data_format = "application/json";
ctx->post_data = HTTP_DEMO_DATA;
ctx->data_len = strlen(HTTP_DEMO_DATA);
// ctx->user_http_header = LOG_HTTP_HEAD_OPTION; //添加该参数, 则自定义申请头部内容
ctx->user_http_header = user_header_buf; //添加该参数, 则自定义申请头部内容
ret = httpcli_post(ctx);
#elif (defined HTTP_GET_TEST)
printf("http get test start\n\n");
ret = httpcli_get(ctx);
#elif (defined HTTP_PUT_TEST)
printf("http put test start\n\n");
ret = httpcli_put(ctx);
#endif
if (ret != HERROR_OK) {
printf("http client test faile\n");
} else {
if (http_body_buf.recv_len > 0) {
printf("\nReceive %d Bytes from (%s)\n", http_body_buf.recv_len, HTTP_DEMO_URL);
printf("%s\n", http_body_buf.p);
}
}
//关闭连接
httpcli_close(ctx);
if (http_body_buf.p) {
free(http_body_buf.p);
http_body_buf.p = NULL;
}
if (ctx) {
free(ctx);
ctx = NULL;
}
}
static void http_test_start(void *priv)
{
enum wifi_sta_connect_state state;
while (1) {
printf("Connecting to the network...\n");
state = wifi_get_sta_connect_state();
if (WIFI_STA_NETWORK_STACK_DHCP_SUCC == state) {
printf("Network connection is successful!\n");
break;
}
os_time_dly(1000);
}
if (thread_fork("http_test_task", 10, 1024 * 10, 0, NULL, http_test_task, NULL) != OS_NO_ERR) {
printf("thread fork fail\n");
}
}
//应用程序入口,需要运行在STA模式下
void c_main(void *priv)
{
if (thread_fork("http_test_start", 10, 512, 0, NULL, http_test_start, NULL) != OS_NO_ERR) {
printf("thread fork fail\n");
}
}
late_initcall(c_main);
#endif //CHAT

View File

@ -1,117 +0,0 @@
/*
主要问题是如何接收处理传过来的文字
*/
#include "system/includes.h"
#include "wifi/wifi_connect.h"
#include "http/http_cli.h"
#include "app_config.h"
#define CHAT
#ifdef CHAT
//选择其中一种进行测试
//#define HTTP_GET_TEST
#define HTTP_POST_TEST
//#define HTTP_PUT_TEST
#define HTTP_POST_TEST
#define HTTP_DEMO_URL "http://ark.cn-beijing.volces.com/api/v3/chat/completions"
#define HTTP_DEMO_DATA "{\"model\": \"ep-20240807114601-mvhsx\", \"messages\": [{\"role\": \"system\",\"content\": \"你是豆包,是由字节跳动开发的 AI 人工智能助手.\"},{\"role\": \"user\",\"content\": \"常见的十字花科植物有哪些?\"}]}"
#define LOG_HTTP_HEAD_OPTION \
"POST /api/v3/chat/completions HTTP/1.1\r\n"\
"Host: ark.cn-beijing.volces.com\r\n"\
"Connection: close\r\n"\
"Content-Type: application/json\r\n"\
"Authorization: Bearer 0b559a45-023b-4453-98bd-637daabe257a\r\n"\
"Content-Length: 256\r\n"\
"Accept: */*\r\n\r\n"
static void http_test_task(void *priv)
{
int ret = 0;
http_body_obj http_body_buf;
httpcli_ctx *ctx = (httpcli_ctx *)calloc(1, sizeof(httpcli_ctx));
if (!ctx) {
printf("calloc faile\n");
return;
}
memset(&http_body_buf, 0x0, sizeof(http_body_obj));
http_body_buf.recv_len = 0;
http_body_buf.buf_len = 4 * 1024;
http_body_buf.buf_count = 1;
http_body_buf.p = (char *) malloc(http_body_buf.buf_len * http_body_buf.buf_count);
if (!http_body_buf.p) {
free(ctx);
return;
}
ctx->url = HTTP_DEMO_URL;
ctx->timeout_millsec = 5000;
ctx->priv = &http_body_buf;
ctx->connection = "close";
printf("http post test start\n\n");
ctx->data_format = "application/json";
ctx->post_data = HTTP_DEMO_DATA;
ctx->data_len = strlen(HTTP_DEMO_DATA);
ctx->user_http_header = LOG_HTTP_HEAD_OPTION; // 添加自定义头部内容
ret = httpcli_post(ctx);
if (ret != HERROR_OK) {
printf("http client test faile\n");
} else {
if (http_body_buf.recv_len > 0) {
printf("\nReceive %d Bytes from (%s)\n", http_body_buf.recv_len, HTTP_DEMO_URL);
printf("%s\n", http_body_buf.p);
}
}
//关闭连接
httpcli_close(ctx);
if (http_body_buf.p) {
free(http_body_buf.p);
http_body_buf.p = NULL;
}
if (ctx) {
free(ctx);
ctx = NULL;
}
}
static void http_test_start(void *priv)
{
enum wifi_sta_connect_state state;
while (1) {
printf("Connecting to the network...\n");
state = wifi_get_sta_connect_state();
if (WIFI_STA_NETWORK_STACK_DHCP_SUCC == state) {
printf("Network connection is successful!\n");
break;
}
os_time_dly(1000);
}
if (thread_fork("http_test_task", 10, 1024 * 10, 0, NULL, http_test_task, NULL) != OS_NO_ERR) {
printf("thread fork fail\n");
}
}
//应用程序入口,需要运行在STA模式下
void c_main(void *priv)
{
if (thread_fork("http_test_start", 10, 512, 0, NULL, http_test_start, NULL) != OS_NO_ERR) {
printf("thread fork fail\n");
}
}
late_initcall(c_main);
#endif //CHAT

View File

@ -1,173 +0,0 @@
#include "system/includes.h"
#include "wifi/wifi_connect.h"
#include "apps/http_client.h"
#include "app_config.h"
#include "cJSON.h"
//#define chat_lwip
#ifdef chat_lwip
#define HTTP_DEMO_URL "https://ark.cn-beijing.volces.com/api/v3/chat/completions"
#define HTTP_DEMO_DATA "{\"model\":\"ep-20241018142738-n7wv9\", \"messages\":[{\"role\":\"user\", \"content\":\"豆包,介绍一下上甘岭战役\"}]}"
#define AUTHORIZATION "Bearer f311cc81-1c5b-42c3-bb8a-1b10d1348080"
#define BUFFER_SIZE 4096 * 3
static char buffer[BUFFER_SIZE]={0};
static uint16_t total_received = 0;
extern unsigned char chat_msg[4 * 1024];
extern OS_SEM chat_sem;
static bool is_json_complete(const char *buffer)
{
// 尝试解析 JSON
cJSON *json = cJSON_Parse(buffer);
if (json) {
cJSON_Delete(json);
return true;
}
return false;
}
static void process_json(cJSON *json)
{
// 处理 JSON 数据
cJSON *choices = cJSON_GetObjectItem(json, "choices");
if (cJSON_IsArray(choices)) {
int array_size = cJSON_GetArraySize(choices);
for (int i = 0; i < array_size; i++) {
cJSON *choice = cJSON_GetArrayItem(choices, i);
if (cJSON_IsObject(choice)) {
cJSON *message = cJSON_GetObjectItem(choice, "message");
if (cJSON_IsObject(message)) {
cJSON *content = cJSON_GetObjectItem(message, "content");
if (cJSON_IsString(content) && content->valuestring != NULL) {
printf("content: %s \r\n", content->valuestring);
}
}
}
}
}
}
static err_t http_rev_func(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{
LWIP_PLATFORM_DIAG(("this is http_rev_func\r\n"));
if (err != ERR_OK || p == NULL) {
LWIP_DEBUGF(LWIP_DEBUG, ("http_rev_func: ERR_OK=%d, p=%p\n", err, p));
return err;
}
// 将接收到的数据复制到静态缓冲区
uint16_t len = p->len;
memcpy(buffer + total_received, p->payload, len);
total_received += len;
printf("payload: %s\r\n",(char *)p->payload);
// 检查是否接收完整条消息
if (is_json_complete(buffer)) {
// 处理完整的消息
cJSON *json = cJSON_Parse(buffer);
if (json) {
process_json(json);
cJSON_Delete(json);
} else {
LWIP_DEBUGF(LWIP_DEBUG, ("Failed to parse JSON\n"));
}
// 重置状态
total_received = 0;
memset(buffer,0,sizeof(buffer));
}
tcp_recved(tpcb, p->len);//通知 lwIP 应用程序已处理了 len 字节的数据,增加接收窗口
pbuf_free(p);
return ERR_OK;
}
static void http_chat_task(void *priv)
{
const char *server_name = "ark.cn-beijing.volces.com"; // 服务器名称
u16_t port = 80; // 端口
const char *uri = "/api/v3/chat/completions"; // 请求的 URI
cJSON *root = cJSON_CreateObject();
cJSON_AddStringToObject(root, "model", "ep-20241010174456-nhgs5");
cJSON *messages = cJSON_AddArrayToObject(root, "messages");
httpc_connection_t setting = { .use_proxy = 0,
.result_fn = NULL,
.headers_done_fn = NULL,
.use_post = 1,
.authorization =AUTHORIZATION,
.arglen = strlen(HTTP_DEMO_DATA),
.args = HTTP_DEMO_DATA
};
while(1){
os_sem_pend(&chat_sem, 0);
cJSON *session = cJSON_CreateObject();
cJSON_AddStringToObject(session, "role", "user");
cJSON_AddStringToObject(session, "content", chat_msg);
cJSON_AddItemToArray(messages, session);
char *http_data = cJSON_Print(root);
cJSON_Delete(root);
setting.arglen = strlen(http_data);
setting.args = http_data;
httpc_get_file_dns(server_name, port, uri, &setting,http_rev_func, NULL, NULL);
free(http_data);
}
}
static void http_chat_start(void *priv)
{
enum wifi_sta_connect_state state;
while (1) {
printf("Connecting to the network...\n");
state = wifi_get_sta_connect_state();
if (WIFI_STA_NETWORK_STACK_DHCP_SUCC == state) {
printf("Network connection is successful!\n");
break;
}
os_time_dly(1000);
}
if (thread_fork("http_chat_task", 10, 1024 * 10, 0, NULL, http_chat_task, NULL) != OS_NO_ERR) {
printf("thread fork fail\n");
}
}
//应用程序入口,需要运行在STA模式下
static int chat_lwip_http(void)
{
if (thread_fork("http_chat_start", 15, 512, 0, NULL, http_chat_start, NULL) != OS_NO_ERR) {
printf("thread fork fail\n");
}
}
late_initcall(chat_lwip_http);
#endif //CHAT

View File

@ -1,164 +0,0 @@
#include "system/includes.h"
#include "wifi/wifi_connect.h"
#include "apps/http_client.h"
#include "app_config.h"
#include "cJSON.h"
//#define chat_lwip
#ifdef chat_lwip
#define HTTP_DEMO_URL "https://ark.cn-beijing.volces.com/api/v3/chat/completions"
#define HTTP_DEMO_DATA "{\"model\":\"ep-20241018142738-n7wv9\", \"messages\":[{\"role\":\"user\", \"content\":\"讲一个简短的故事\"}]}"
#define AUTHORIZATION "Bearer f311cc81-1c5b-42c3-bb8a-1b10d1348080"
#define BUFFER_SIZE 4096 * 3
static char buffer[BUFFER_SIZE]={0};
static uint16_t total_received = 0;
char *chat_req = NULL;
OS_SEM tts_sem;
static OS_SEM demo_sem;
static bool is_json_complete(const char *buffer)
{
// 尝试解析 JSON
cJSON *json = cJSON_Parse(buffer);
if (json) {
cJSON_Delete(json);
return true;
}
return false;
}
static void process_json(cJSON *json)
{
// 处理 JSON 数据
cJSON *choices = cJSON_GetObjectItem(json, "choices");
if (cJSON_IsArray(choices)) {
int array_size = cJSON_GetArraySize(choices);
for (int i = 0; i < array_size; i++) {
cJSON *choice = cJSON_GetArrayItem(choices, i);
if (cJSON_IsObject(choice)) {
cJSON *message = cJSON_GetObjectItem(choice, "message");
if (cJSON_IsObject(message)) {
cJSON *content = cJSON_GetObjectItem(message, "content");
if (cJSON_IsString(content) && content->valuestring != NULL) {
printf("content: %s \r\n", content->valuestring);
int content_len=strlen(content->valuestring);
chat_req = calloc(1,content_len);
memcpy(chat_req,content->valuestring,content_len);
if(chat_req!=NULL){
os_sem_post(&tts_sem);
}
}
}
}
}
}
}
static err_t http_rev_func(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{
LWIP_PLATFORM_DIAG(("this is http_rev_func\r\n"));
if (err != ERR_OK || p == NULL) {
LWIP_DEBUGF(LWIP_DEBUG, ("http_rev_func: ERR_OK=%d, p=%p\n", err, p));
return err;
}
// 将接收到的数据复制到静态缓冲区
uint16_t len = p->len;
memcpy(buffer + total_received, p->payload, len);
total_received += len;
printf("payload: %s\r\n",(char *)p->payload);
// 检查是否接收完整条消息
if (is_json_complete(buffer)) {
// 处理完整的消息
cJSON *json = cJSON_Parse(buffer);
if (json) {
process_json(json);
cJSON_Delete(json);
} else {
LWIP_DEBUGF(LWIP_DEBUG, ("Failed to parse JSON\n"));
}
// 重置状态
total_received = 0;
memset(buffer,0,sizeof(buffer));
}
tcp_recved(tpcb, p->len);//通知 lwIP 应用程序已处理了 len 字节的数据,增加接收窗口
pbuf_free(p);
return ERR_OK;
}
static void http_chat_task(void *priv)
{
const char *server_name = "ark.cn-beijing.volces.com"; // 服务器名称
u16_t port = 80; // 端口
const char *uri = "/api/v3/chat/completions"; // 请求的 URI
cJSON *root = cJSON_CreateObject();
cJSON_AddStringToObject(root, "model", "ep-20241010174456-nhgs5");
cJSON *messages = cJSON_AddArrayToObject(root, "messages");
httpc_connection_t setting = { .use_proxy = 0,
.result_fn = NULL,
.headers_done_fn = NULL,
.use_post = 1,
.authorization =AUTHORIZATION,
.arglen = strlen(HTTP_DEMO_DATA),
.args = HTTP_DEMO_DATA
};
while(1){
os_sem_pend(&demo_sem,0);
httpc_get_file_dns(server_name, port, uri, &setting,http_rev_func, NULL, NULL);
}
}
static void http_chat_start(void *priv)
{
enum wifi_sta_connect_state state;
os_sem_create(&tts_sem,0);
os_sem_create(&demo_sem,1);
while (1) {
printf("Connecting to the network...\n");
state = wifi_get_sta_connect_state();
if (WIFI_STA_NETWORK_STACK_DHCP_SUCC == state) {
printf("Network connection is successful!\n");
break;
}
os_time_dly(1000);
}
if (thread_fork("http_chat_task", 10, 1024 * 10, 0, NULL, http_chat_task, NULL) != OS_NO_ERR) {
printf("thread fork fail\n");
}
}
//应用程序入口,需要运行在STA模式下
static int chat_lwip_http(void)
{
if (thread_fork("http_chat_start", 15, 512, 0, NULL, http_chat_start, NULL) != OS_NO_ERR) {
printf("thread fork fail\n");
}
}
late_initcall(chat_lwip_http);
#endif //CHAT

View File

@ -1,179 +0,0 @@
#include "system/includes.h"
#include "wifi/wifi_connect.h"
#include "apps/http_client.h"
#include "app_config.h"
#include "cJSON.h"
//#define chat_lwip_stream
#ifdef chat_lwip_stream
#define HTTP_DEMO_URL "https://ark.cn-beijing.volces.com/api/v3/chat/completions"
#define HTTP_DEMO_DATA "{\"model\":\"ep-20241018142738-n7wv9\",\"stream\": true,\"messages\":[{\"role\":\"user\", \"content\":\"写一篇六百字的作文\"}]}"
#define AUTHORIZATION "Bearer f311cc81-1c5b-42c3-bb8a-1b10d1348080"
static char buffer[2*1024] = {0}; // 用于存储不完整数据块的缓冲区
static size_t buffer_len = 0;
char accumulated_content[10*1024] = {0};
static size_t accumulated_length = 0;
static size_t add_length = 0;
static OS_SEM csem;
OS_SEM tts_sem;
static void process_sse_chunk(const char *chunk)
{
int argv[4];
const char *data_start = strstr(chunk, "data:");
if (!data_start) {
return;
}
data_start += 5;
while (isspace(*data_start)) data_start++;
if (strcmp(data_start, "[DONE]") == 0) {
printf("SSE stream ended\r\n");
printf("answer: %s\r\n",accumulated_content);
} else {
cJSON *json = cJSON_Parse(data_start);
if (json) {
cJSON *choices = cJSON_GetObjectItem(json, "choices");
if (cJSON_IsArray(choices)) {
cJSON *choice = cJSON_GetArrayItem(choices, 0);
if (cJSON_IsObject(choice)) {
cJSON *delta = cJSON_GetObjectItem(choice, "delta");
if (cJSON_IsObject(delta)) {
cJSON *content = cJSON_GetObjectItem(delta, "content");
if (cJSON_IsString(content) && content->valuestring) {
size_t new_content_length = strlen(content->valuestring);
//printf("Chunk content: %s", content->valuestring);
if (accumulated_length + new_content_length < 10*1024) {
strcat(accumulated_content, content->valuestring);
accumulated_length += new_content_length;
}
add_length+=new_content_length;
if(strcmp(content->valuestring,",")==0||strcmp(content->valuestring,":")==0||strcmp(content->valuestring,":")==0||
strcmp(content->valuestring,"。")==0||strcmp(content->valuestring,"!")==0||strcmp(content->valuestring,"?")==0||
strcmp(content->valuestring,";")==0){
printf("sentence:%s\r\n",accumulated_content+(accumulated_length-add_length));
argv[0]=accumulated_length;
argv[1]=add_length;
os_sem_set(&tts_sem,0);
os_sem_post(&tts_sem);
os_taskq_post_type("websockets_tts_client_main_thread", Q_USER, 20, argv);
add_length = 0;
}
}
}
}
}
cJSON_Delete(json);
}
}
}
static err_t http_rev_func(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{
//LWIP_PLATFORM_DIAG(("this is http_rev_func\r\n"));
if (p == NULL) {
// 连接关闭
LWIP_PLATFORM_DIAG(("this is http_rev_func close\r\n"));
return ERR_OK;
}
// 将新数据追加到缓冲区
if (buffer_len + p->len < sizeof(buffer)) {
memcpy(buffer + buffer_len, p->payload, p->len);
buffer_len += p->len;
buffer[buffer_len] = '\0';
} else {
printf("缓冲区溢出,丢弃数据\r\n");
}
// printf("buffer: %.*s\r\n", buffer_len, buffer);
//
// printf("buffer_len: %d\r\n",buffer_len);
// 处理完整的数据块
char *start = buffer;
char *end;
while ((end = strstr(start, "\n\n")) != NULL) {
*end = '\0';
process_sse_chunk(start);
start = end + 2;
}
// 将剩余的不完整数据块移到缓冲区开头
if (start != buffer) {
buffer_len = strlen(start);
memmove(buffer, start, buffer_len + 1);
}
tcp_recved(tpcb, p->len);//通知 lwIP 应用程序已处理了 len 字节的数据,增加接收窗口
pbuf_free(p);
return ERR_OK;
}
static void http_chat_task(void *priv)
{
const char *server_name = "ark.cn-beijing.volces.com"; // 服务器名称
u16_t port = 80; // 端口
const char *uri = "/api/v3/chat/completions"; // 请求的 URI
httpc_connection_t setting = { .use_proxy = 0,
.result_fn = NULL,
.headers_done_fn = NULL,
.use_post = 1,
.authorization =AUTHORIZATION,
.arglen = strlen(HTTP_DEMO_DATA),
.args = HTTP_DEMO_DATA
};
while(1){
os_sem_pend(&csem,0);
add_length = 0;
httpc_get_file_dns(server_name, port, uri, &setting,http_rev_func, NULL, NULL);
}
}
static void http_chat_start(void *priv)
{
enum wifi_sta_connect_state state;
os_sem_create(&csem,1);
os_sem_create(&tts_sem,0);
while (1) {
printf("Connecting to the network...\n");
state = wifi_get_sta_connect_state();
if (WIFI_STA_NETWORK_STACK_DHCP_SUCC == state) {
printf("Network connection is successful!\n");
break;
}
os_time_dly(1000);
}
if (thread_fork("http_chat_task", 10, 1024 * 10, 0, NULL, http_chat_task, NULL) != OS_NO_ERR) {
printf("thread fork fail\n");
}
}
//应用程序入口,需要运行在STA模式下
static int chat_lwip_http(void)
{
if (thread_fork("http_chat_start", 15, 512, 0, NULL, http_chat_start, NULL) != OS_NO_ERR) {
printf("thread fork fail\n");
}
}
late_initcall(chat_lwip_http);
#endif //CHAT

View File

@ -1,595 +0,0 @@
#include "web_socket/websocket_api.h"
#include "wifi/wifi_connect.h"
#include "system/includes.h"
#include "fs/fs.h"
#include "asm/sfc_norflash_api.h"
#include "cJSON.h"
#include "aduio_record.h"
#ifdef WEBSOCKET_MEMHEAP_DEBUG
#include "mem_leak_test.h"
#endif
#include "app_config.h"
//#define stt
#ifdef stt
// 定义消息类型常量
#define SERVER_FULL_RESPONSE 0b1001
#define SERVER_ACK 0b1011
#define SERVER_ERROR_RESPONSE 0b1111
// 定义压缩和序列化方法常量
#define GZIP 1
#define JSON 1
#define NO_SERIALIZATION 0
// 定义响应结构体,用于存储原始响应数据
typedef struct {
uint8_t protocol_version;
uint8_t header_size;
uint8_t message_type;
uint8_t message_type_specific_flags;
uint8_t serialization_method;
uint8_t message_compression;
uint8_t reserved;
uint8_t* header_extensions;
uint8_t* payload;
size_t payload_size;
} Response;
// 定义解析后的响应结构体,用于存储处理后的数据
typedef struct {
unsigned char* payload_msg;
size_t payload_size;
} ParsedResponse;
typedef struct {
char* appid;
char* cluster;
char* token;
char* uid;
int nbest;
char* workflow;
int show_language;
int show_utterances;
char* result_type;
char* format;
int rate;
char* language;
int bits;
int channel;
char* codec;
} AsrWsClient;
#define STT_DEFAULT_VERSION 0b0001
#define STT_DEFAULT_MESSAGE_TYPE 0b0001
#define STT_DEFAULT_MESSAGE_TYPE_SPECIFIC_FLAGS 0b0000
#define STT_DEFAULT_SERIAL_METHOD 0b0001
#define STT_DEFAULT_COMPRESSION_TYPE 0b0000
#define STT_DEFAULT_RESERVED_DATA 0
#define STT_DEFAULT_EXTENSION_HEADER NULL
#define STT_DEFAULT_EXTENSION_HEADER_LENGTH 0
#define DEFAULT_HEADR STT_DEFAULT_VERSION,STT_DEFAULT_MESSAGE_TYPE,STT_DEFAULT_MESSAGE_TYPE_SPECIFIC_FLAGS,\
STT_DEFAULT_SERIAL_METHOD,STT_DEFAULT_COMPRESSION_TYPE,STT_DEFAULT_RESERVED_DATA,\
STT_DEFAULT_EXTENSION_HEADER,STT_DEFAULT_EXTENSION_HEADER_LENGTH
#define OBJ_URL "wss://openspeech.bytedance.com/api/v2/asr"
extern OS_SEM voice_msg_sem;
extern OS_SEM voice_start_sem;
OS_SEM chat_sem;
unsigned char chat_msg[4 * 1024];
extern struct record_message record_msg;
static void websockets_callback(u8 *buf, u32 len, u8 type)
{
if(buf!=NULL&&type!=0x89){
ParsedResponse *req=NULL;
printf(" . len: %d, . type: %x \r\n",len,type);
extern ParsedResponse* parse_response(const uint8_t* res, size_t res_size);
req=parse_response(buf, len);
printf(" . msg: %s\r\n",req->payload_msg);
cJSON* json = cJSON_Parse(req->payload_msg);
if(json!=NULL){
cJSON *sequence = cJSON_GetObjectItem(json, "sequence");
if(cJSON_IsNumber(sequence)){
if(sequence->valueint<0){
cJSON *results = cJSON_GetObjectItem(json, "result");
if (cJSON_IsArray(results)) {
int array_size = cJSON_GetArraySize(results);
for (int i = 0; i < array_size; i++) {
cJSON *result = cJSON_GetArrayItem(results, i);
cJSON *text = cJSON_GetObjectItem(result,"text");
if (cJSON_IsString(text) && (text->valuestring != NULL)) {
printf("text: %s\r\n", (unsigned char*)text->valuestring);
sprintf(chat_msg,"%s",text->valuestring);
os_sem_post(&chat_sem);
}
}
}
}
}
}
free(req);
}
}
/*******************************************************************************
* Websocket Client api
*******************************************************************************/
static void websockets_client_reg(struct websocket_struct *websockets_info, char mode)
{
memset(websockets_info, 0, sizeof(struct websocket_struct));
websockets_info->_init = websockets_client_socket_init;
websockets_info->_exit = websockets_client_socket_exit;
websockets_info->_handshack = webcockets_client_socket_handshack;
websockets_info->_send = websockets_client_socket_send;
websockets_info->_recv_thread = websockets_client_socket_recv_thread;
websockets_info->_heart_thread = websockets_client_socket_heart_thread;
websockets_info->_recv_cb = websockets_callback;
websockets_info->_recv = NULL;
websockets_info->websocket_mode = mode;
#if 0
//应用层指定申请接收内存大小(申请即可,不用释放,内部会释放),默认不使用
websockets_info->recv_buf_size = 30 * 1024;
websockets_info->recv_buf = malloc(websockets_info->recv_buf_size);
#endif
}
static int websockets_client_init(struct websocket_struct *websockets_info, u8 *url, const char *origin_str, const char *user_agent_str)
{
websockets_info->ip_or_url = url;
websockets_info->origin_str = origin_str;
websockets_info->user_agent_str = user_agent_str;
websockets_info->recv_time_out = 5000;
//应用层和库的版本检测,结构体不一样则返回出错
int err = websockets_struct_check(sizeof(struct websocket_struct));
if (err == FALSE) {
return err;
}
return websockets_info->_init(websockets_info);
}
static int websockets_client_handshack(struct websocket_struct *websockets_info)
{
return websockets_info->_handshack(websockets_info);
}
static int websockets_client_send(struct websocket_struct *websockets_info, u8 *buf, int len, char type)
{
//SSL加密时一次发送数据不能超过16K,用户需要自己分包
return websockets_info->_send(websockets_info, buf, len, type);
}
static void websockets_client_exit(struct websocket_struct *websockets_info)
{
websockets_info->_exit(websockets_info);
}
static uint8_t* generate_header(
uint8_t version,
uint8_t message_type,
uint8_t message_type_specific_flags,
uint8_t serial_method,
uint8_t compression_type,
uint8_t reserved_data,
const uint8_t* extension_header,
size_t extension_header_length
) {
size_t header_size = (extension_header_length / 4) + 1;
size_t total_size = header_size * 4;
uint8_t* header = (uint8_t*)malloc(total_size);
if (header == NULL) {
return NULL;
}
// 设置基本头部(4字节)
header[0] = (version << 4) | (header_size & 0x0F);
printf(" .header[0]: %x \r\n",header[0]);
header[1] = (message_type << 4) | (message_type_specific_flags & 0x0F);
printf(" .header[1]: %x \r\n",header[1]);
header[2] = (serial_method << 4) | (compression_type & 0x0F);
printf(" .header[2]: %x \r\n",header[2]);
header[3] = reserved_data;
printf(" .header[3]: %x \r\n",header[3]);
// 复制扩展头部(如果有的话)
if (extension_header_length > 0 && extension_header != NULL) {
memcpy(header + 4, extension_header, extension_header_length);
}
return header;
}
static char* construct_request(AsrWsClient* client, const char* reqid) {
cJSON* root = cJSON_CreateObject();
if (root == NULL) {
goto fail;
}
// App object
cJSON* app = cJSON_AddObjectToObject(root, "app");
if (app == NULL ||
!cJSON_AddStringToObject(app, "appid", client->appid) ||
!cJSON_AddStringToObject(app, "cluster", client->cluster) ||
!cJSON_AddStringToObject(app, "token", client->token)) {
goto fail;
}
// User object
cJSON* user = cJSON_AddObjectToObject(root, "user");
if (user == NULL ||
!cJSON_AddStringToObject(user, "uid", client->uid)) {
goto fail;
}
// Audio object
cJSON* audio = cJSON_AddObjectToObject(root, "audio");
if (audio == NULL ||
!cJSON_AddStringToObject(audio, "format", client->format)||
!cJSON_AddNumberToObject(audio, "rate", client->rate) ||
!cJSON_AddStringToObject(audio, "language", client->language) ||
!cJSON_AddNumberToObject(audio, "bits", client->bits) ||
!cJSON_AddNumberToObject(audio, "channel", client->channel) ||
!cJSON_AddStringToObject(audio, "codec", client->codec)) {
goto fail;
}
// Request object
cJSON* request = cJSON_AddObjectToObject(root, "request");
if (request == NULL ||
!cJSON_AddStringToObject(request, "reqid", reqid) ||
!cJSON_AddNumberToObject(request, "nbest", client->nbest) ||
!cJSON_AddStringToObject(request, "workflow", client->workflow) ||
!cJSON_AddBoolToObject(request, "show_utterances", client->show_utterances) ||
!cJSON_AddStringToObject(request, "result_type", client->result_type) ||
!cJSON_AddNumberToObject(request, "sequence", 1)) {
goto fail;
}
char* json_string = cJSON_Print(root);
cJSON_Delete(root);
return json_string;
fail:
if (root != NULL) {
cJSON_Delete(root);
}
return NULL;
}
static ParsedResponse* parse_response(const uint8_t* res, size_t res_size) {
// 检查响应大小是否足够
if (res_size < 4) return NULL;
// 解析响应头部
Response response = {
.protocol_version = res[0] >> 4,
.header_size = res[0] & 0x0f,
.message_type = res[1] >> 4,
.message_type_specific_flags = res[1] & 0x0f,
.serialization_method = res[2] >> 4,
.message_compression = res[2] & 0x0f,
.reserved = res[3]
};
// 提取头部扩展
size_t header_extensions_size = 4 * (response.header_size - 1);
response.header_extensions = (uint8_t*)malloc(header_extensions_size);
memcpy(response.header_extensions, res + 4, header_extensions_size);
// 设置payload指针和大小
response.payload = (uint8_t*)res + response.header_size * 4;
response.payload_size = res_size - response.header_size * 4;
// 分配ParsedResponse结构体内存
ParsedResponse* result = (ParsedResponse*)malloc(sizeof(ParsedResponse));
memset(result, 0, sizeof(ParsedResponse));
// 根据消息类型处理payload
switch (response.message_type) {
case SERVER_FULL_RESPONSE:
// 解析payload大小(前4字节)
result->payload_size = ntohl(*(int32_t*)response.payload);
response.payload += 4;
response.payload_size -= 4;
break;
case SERVER_ACK:
if (response.payload_size >= 8) {
// 如果有额外的payload,解析其大小(接下来的4字节)
result->payload_size = ntohl(*(uint32_t*)(response.payload + 4));
response.payload += 8;
response.payload_size -= 8;
}
break;
case SERVER_ERROR_RESPONSE:
result->payload_size = ntohl(*(uint32_t*)(response.payload + 4));
response.payload += 8;
response.payload_size -= 8;
break;
}
// 处理payload(如果存在)
if (response.payload_size > 0) {
// 根据序列化方法处理payload
if (response.serialization_method == JSON) {
// 解析JSON
cJSON* json = cJSON_Parse((char*)response.payload);
if (json) {
result->payload_msg = cJSON_Print(json);
cJSON_Delete(json);
}
} else if (response.serialization_method != NO_SERIALIZATION) {
// 如果不是JSON也不是NO_SERIALIZATION,则直接复制字符串
result->payload_msg = strdup((char*)response.payload);
}
}
// 清理临时分配的内存
free(response.header_extensions);
return result;
}
static void generate_uuid(char *uuid_out)
{
const char *c = "89ab";
char *p = uuid_out;
for (int n = 0; n < 16; ++n) {
int b = rand() % 255;
switch (n) {
case 6:
sprintf(p, "4%x", b % 15);
break;
case 8:
sprintf(p, "%c%x", c[rand() % strlen(c)], b % 15);
break;
default:
sprintf(p, "%02x", b);
break;
}
p += 2;
switch (n) {
case 3:
case 5:
case 7:
case 9:
*p++='-';
break;
}
}
*p = 0;
}
/*******************************************************************************
* Websocket Client.c
*******************************************************************************/
static void websockets_stt_client_main_thread(void *priv)
{
int err;
char mode = WEBSOCKET_MODE;
u8 url[256] = OBJ_URL;
const char *origin_str = "wss://openspeech.bytedance.com/api/v2/asr";
const char *user_agent_str = "Authorization: Bearer; BNA-XBIrEisvMczcmc-Sm4B3H-PmfqlL";
char *websocket_header = NULL;
char *payload = NULL;
uint32_t payloadsize;
size_t total_length;
size_t header_length;
size_t payload_length;
char *full_client_request=NULL;
u8 uuid[16] = {0};
char *aduio_client_request=NULL;
AsrWsClient STTPayload={
.appid="8571950639",
.cluster="volcengine_streaming_common",
.token="BNA-XBIrEisvMczcmc-Sm4B3H-PmfqlL",
.uid="388808088185088",
.nbest=1,
.workflow="audio_in,resample,partition,vad,fe,decode,itn,nlu_punctuate",
.show_language=false,
.show_utterances=false,
.result_type="full",
.format="mp3",
.rate=16000,
.language="zh-CN",
.bits=16,
.channel=1,
.codec="raw",
};
os_sem_create(&chat_sem,0);
printf(" . ----------------- stt Client Websocket ------------------\r\n");
/* 0 . malloc buffer */
struct websocket_struct *websockets_info = malloc(sizeof(struct websocket_struct));
if (!websockets_info) {
return;
}
/* 1 . register */
websockets_client_reg(websockets_info, mode);
/* 2 . init */
err = websockets_client_init(websockets_info, url, origin_str, user_agent_str);
if (FALSE == err) {
printf(" . ! Cilent websocket init error !!!\r\n");
goto exit_ws;
}
/* 3 . hanshack */
err = websockets_client_handshack(websockets_info);
if (FALSE == err) {
printf(" . ! Handshake error !!!\r\n");
goto exit_ws;
}
printf(" . Handshake success \r\n");
/* 4 . CreateThread */
thread_fork("websocket_client_heart", 19, 512, 0,
&websockets_info->ping_thread_id,
websockets_info->_heart_thread,
websockets_info);
thread_fork("websocket_client_recv", 18, 512, 0,
&websockets_info->recv_thread_id,
websockets_info->_recv_thread,
websockets_info);
websockets_sleep(1000);
/* 5 . recv or send data */
while (1) {
//接收信号量0
os_sem_pend(&voice_start_sem, 0); //获取信号量
websocket_header=generate_header(DEFAULT_HEADR);
header_length=4+STT_DEFAULT_EXTENSION_HEADER_LENGTH;
generate_uuid(uuid);
payload=construct_request(&STTPayload, uuid);
printf(" . Payload :%s \r\n",payload);
payload_length=strlen(payload);
payloadsize=htonl(payload_length);
total_length=header_length+4+payload_length;
full_client_request=(char *)malloc(total_length+1);
if (full_client_request == NULL) {
printf(" . ! malloc err !!!\r\n");
goto exit_ws;
}
memcpy(full_client_request, websocket_header, header_length);
memcpy(full_client_request + header_length, &payloadsize, 4);
memcpy(full_client_request + 4 + header_length,payload,payload_length+1);
err = websockets_client_send(websockets_info, (u8 *)full_client_request, total_length, WCT_TXTDATA);
if (FALSE == err) {
printf(" . ! send err !!!\r\n");
goto exit_ws;
}
free(full_client_request);
//websockets_sleep(1000);
while(1){
os_sem_pend(&voice_msg_sem, 0);
if(record_msg.end){
websocket_header=generate_header(STT_DEFAULT_VERSION,0b0010,0b0010,0b0000,\
STT_DEFAULT_COMPRESSION_TYPE,STT_DEFAULT_RESERVED_DATA,\
STT_DEFAULT_EXTENSION_HEADER,STT_DEFAULT_EXTENSION_HEADER_LENGTH);
}else{
websocket_header=generate_header(STT_DEFAULT_VERSION,0b0010,0b0000,0b0000,\
STT_DEFAULT_COMPRESSION_TYPE,STT_DEFAULT_RESERVED_DATA,\
STT_DEFAULT_EXTENSION_HEADER,STT_DEFAULT_EXTENSION_HEADER_LENGTH);
}
payloadsize=htonl(record_msg.msg_size);
total_length=header_length+4+record_msg.msg_size;
aduio_client_request=(char *)malloc(total_length+1);
if (aduio_client_request == NULL) {
printf(" . ! malloc err !!!\r\n");
goto exit_ws;
}
memcpy(aduio_client_request, websocket_header, header_length);
memcpy(aduio_client_request + header_length, &payloadsize, 4);
memcpy(aduio_client_request + 4 + header_length,record_msg.msg,record_msg.msg_size+1);
err = websockets_client_send(websockets_info, (u8 *)aduio_client_request, total_length, WCT_TXTDATA);
if (FALSE == err) {
printf(" . ! send err !!!\r\n");
goto exit_ws;
}
free(aduio_client_request);
}
}
exit_ws:
/* 6 . exit */
if (websockets_info->ping_thread_id) {
thread_kill(&websockets_info->ping_thread_id, KILL_REQ);
}
if (websockets_info->recv_thread_id) {
thread_kill(&websockets_info->recv_thread_id, KILL_REQ);
}
websockets_client_exit(websockets_info);
free(websockets_info);
}
static void websocket_client_thread_create(void)
{
thread_fork("websockets_stt_client_main_thread", 15, 1024 * 250, 0, 0, websockets_stt_client_main_thread, NULL);
}
static void http_websocket_start(void *priv)
{
enum wifi_sta_connect_state state;
while (1) {
printf("Connecting to the network...\n");
state = wifi_get_sta_connect_state();
if (WIFI_STA_NETWORK_STACK_DHCP_SUCC == state) {
printf("Network connection is successful!\n");
break;
}
os_time_dly(500);
}
websocket_client_thread_create();
}
//应用程序入口,需要运行在STA模式下
static int stt_websocket_init(void)
{
if (thread_fork("http_websocket_start", 10, 512, 0, NULL, http_websocket_start, NULL) != OS_NO_ERR) {
printf("thread fork fail\n");
}
}
late_initcall(stt_websocket_init);
#endif // stt

View File

@ -1,664 +0,0 @@
#include "web_socket/websocket_api.h"
#include "wifi/wifi_connect.h"
#include "system/includes.h"
#include "fs/fs.h"
#include "asm/sfc_norflash_api.h"
#include "cJSON.h"
#include "aduio_record.h"
#ifdef WEBSOCKET_MEMHEAP_DEBUG
#include "mem_leak_test.h"
#endif
#include "app_config.h"
//#define stt_local
#ifdef stt_local
// 定义消息类型常量
#define SERVER_FULL_RESPONSE 0b1001
#define SERVER_ACK 0b1011
#define SERVER_ERROR_RESPONSE 0b1111
// 定义压缩和序列化方法常量
#define GZIP 1
#define JSON 1
#define NO_SERIALIZATION 0
// 定义响应结构体,用于存储原始响应数据
typedef struct {
uint8_t protocol_version;
uint8_t header_size;
uint8_t message_type;
uint8_t message_type_specific_flags;
uint8_t serialization_method;
uint8_t message_compression;
uint8_t reserved;
uint8_t* header_extensions;
uint8_t* payload;
size_t payload_size;
} Response;
// 定义解析后的响应结构体,用于存储处理后的数据
typedef struct {
unsigned char* payload_msg;
size_t payload_size;
} ParsedResponse;
typedef struct {
char* appid;
char* cluster;
char* token;
char* uid;
int nbest;
char* workflow;
int show_language;
int show_utterances;
char* result_type;
char* format;
int rate;
char* language;
int bits;
int channel;
char* codec;
} AsrWsClient;
typedef struct {
unsigned char* data;
size_t size;
bool is_last;
} DataSegment;
typedef struct {
unsigned char* data;
size_t data_len;
size_t chunk_size;
size_t current_offset;
} DataSlicer;
#define STT_DEFAULT_VERSION 0b0001
#define STT_DEFAULT_MESSAGE_TYPE 0b0001
#define STT_DEFAULT_MESSAGE_TYPE_SPECIFIC_FLAGS 0b0000
#define STT_DEFAULT_SERIAL_METHOD 0b0001
#define STT_DEFAULT_COMPRESSION_TYPE 0b0000
#define STT_DEFAULT_RESERVED_DATA 0
#define STT_DEFAULT_EXTENSION_HEADER NULL
#define STT_DEFAULT_EXTENSION_HEADER_LENGTH 0
#define DEFAULT_HEADR STT_DEFAULT_VERSION,STT_DEFAULT_MESSAGE_TYPE,STT_DEFAULT_MESSAGE_TYPE_SPECIFIC_FLAGS,\
STT_DEFAULT_SERIAL_METHOD,STT_DEFAULT_COMPRESSION_TYPE,STT_DEFAULT_RESERVED_DATA,\
STT_DEFAULT_EXTENSION_HEADER,STT_DEFAULT_EXTENSION_HEADER_LENGTH
#define OBJ_URL "wss://openspeech.bytedance.com/api/v2/asr"
static OS_SEM x_sem;
OS_SEM chat_sem;
unsigned char chat_msg[4 * 1024];
static void websockets_callback(u8 *buf, u32 len, u8 type)
{
if(buf!=NULL&&type!=0x89){
ParsedResponse *req=NULL;
printf(" . len: %d, . type: %x \r\n",len,type);
extern ParsedResponse* parse_response(const uint8_t* res, size_t res_size);
req=parse_response(buf, len);
printf(" . msg: %s\r\n",req->payload_msg);
cJSON* json = cJSON_Parse(req->payload_msg);
free(req);
if(json!=NULL){
cJSON *sequence = cJSON_GetObjectItem(json, "sequence");
if(cJSON_IsNumber(sequence)){
if(sequence->valueint<0){
cJSON *results = cJSON_GetObjectItem(json, "result");
if (cJSON_IsArray(results)) {
int array_size = cJSON_GetArraySize(results);
for (int i = 0; i < array_size; i++) {
cJSON *result = cJSON_GetArrayItem(results, i);
cJSON *text = cJSON_GetObjectItem(result,"text");
if (cJSON_IsString(text) && (text->valuestring != NULL)) {
printf("text: %s\r\n", (unsigned char*)text->valuestring);
sprintf(chat_msg,"%s",text->valuestring);
os_sem_post(&chat_sem);
}
}
}
}
}
}
}
}
/*******************************************************************************
* Websocket Client api
*******************************************************************************/
static void websockets_client_reg(struct websocket_struct *websockets_info, char mode)
{
memset(websockets_info, 0, sizeof(struct websocket_struct));
websockets_info->_init = websockets_client_socket_init;
websockets_info->_exit = websockets_client_socket_exit;
websockets_info->_handshack = webcockets_client_socket_handshack;
websockets_info->_send = websockets_client_socket_send;
websockets_info->_recv_thread = websockets_client_socket_recv_thread;
websockets_info->_heart_thread = websockets_client_socket_heart_thread;
websockets_info->_recv_cb = websockets_callback;
websockets_info->_recv = NULL;
websockets_info->websocket_mode = mode;
#if 0
//应用层指定申请接收内存大小(申请即可,不用释放,内部会释放),默认不使用
websockets_info->recv_buf_size = 30 * 1024;
websockets_info->recv_buf = malloc(websockets_info->recv_buf_size);
#endif
}
static int websockets_client_init(struct websocket_struct *websockets_info, u8 *url, const char *origin_str, const char *user_agent_str)
{
websockets_info->ip_or_url = url;
websockets_info->origin_str = origin_str;
websockets_info->user_agent_str = user_agent_str;
websockets_info->recv_time_out = 5000;
//应用层和库的版本检测,结构体不一样则返回出错
int err = websockets_struct_check(sizeof(struct websocket_struct));
if (err == FALSE) {
return err;
}
return websockets_info->_init(websockets_info);
}
static int websockets_client_handshack(struct websocket_struct *websockets_info)
{
return websockets_info->_handshack(websockets_info);
}
static int websockets_client_send(struct websocket_struct *websockets_info, u8 *buf, int len, char type)
{
//SSL加密时一次发送数据不能超过16K,用户需要自己分包
return websockets_info->_send(websockets_info, buf, len, type);
}
static void websockets_client_exit(struct websocket_struct *websockets_info)
{
websockets_info->_exit(websockets_info);
}
static uint8_t* generate_header(
uint8_t version,
uint8_t message_type,
uint8_t message_type_specific_flags,
uint8_t serial_method,
uint8_t compression_type,
uint8_t reserved_data,
const uint8_t* extension_header,
size_t extension_header_length
) {
size_t header_size = (extension_header_length / 4) + 1;
size_t total_size = header_size * 4;
uint8_t* header = (uint8_t*)malloc(total_size);
if (header == NULL) {
return NULL;
}
// 设置基本头部(4字节)
header[0] = (version << 4) | (header_size & 0x0F);
printf(" .header[0]: %x \r\n",header[0]);
header[1] = (message_type << 4) | (message_type_specific_flags & 0x0F);
printf(" .header[1]: %x \r\n",header[1]);
header[2] = (serial_method << 4) | (compression_type & 0x0F);
printf(" .header[2]: %x \r\n",header[2]);
header[3] = reserved_data;
printf(" .header[3]: %x \r\n",header[3]);
// 复制扩展头部(如果有的话)
if (extension_header_length > 0 && extension_header != NULL) {
memcpy(header + 4, extension_header, extension_header_length);
}
return header;
}
static char* construct_request(AsrWsClient* client, const char* reqid) {
cJSON* root = cJSON_CreateObject();
if (root == NULL) {
goto fail;
}
// App object
cJSON* app = cJSON_AddObjectToObject(root, "app");
if (app == NULL ||
!cJSON_AddStringToObject(app, "appid", client->appid) ||
!cJSON_AddStringToObject(app, "cluster", client->cluster) ||
!cJSON_AddStringToObject(app, "token", client->token)) {
goto fail;
}
// User object
cJSON* user = cJSON_AddObjectToObject(root, "user");
if (user == NULL ||
!cJSON_AddStringToObject(user, "uid", client->uid)) {
goto fail;
}
// Audio object
cJSON* audio = cJSON_AddObjectToObject(root, "audio");
if (audio == NULL ||
!cJSON_AddStringToObject(audio, "format", client->format)||
!cJSON_AddNumberToObject(audio, "rate", client->rate) ||
!cJSON_AddStringToObject(audio, "language", client->language) ||
!cJSON_AddNumberToObject(audio, "bits", client->bits) ||
!cJSON_AddNumberToObject(audio, "channel", client->channel) ||
!cJSON_AddStringToObject(audio, "codec", client->codec)) {
goto fail;
}
// Request object
cJSON* request = cJSON_AddObjectToObject(root, "request");
if (request == NULL ||
!cJSON_AddStringToObject(request, "reqid", reqid) ||
!cJSON_AddNumberToObject(request, "nbest", client->nbest) ||
!cJSON_AddStringToObject(request, "workflow", client->workflow) ||
!cJSON_AddBoolToObject(request, "show_utterances", client->show_utterances) ||
!cJSON_AddStringToObject(request, "result_type", client->result_type) ||
!cJSON_AddNumberToObject(request, "sequence", 1)) {
goto fail;
}
char* json_string = cJSON_Print(root);
cJSON_Delete(root);
return json_string;
fail:
if (root != NULL) {
cJSON_Delete(root);
}
return NULL;
}
static ParsedResponse* parse_response(const uint8_t* res, size_t res_size) {
// 检查响应大小是否足够
if (res_size < 4) return NULL;
// 解析响应头部
Response response = {
.protocol_version = res[0] >> 4,
.header_size = res[0] & 0x0f,
.message_type = res[1] >> 4,
.message_type_specific_flags = res[1] & 0x0f,
.serialization_method = res[2] >> 4,
.message_compression = res[2] & 0x0f,
.reserved = res[3]
};
// 提取头部扩展
size_t header_extensions_size = 4 * (response.header_size - 1);
response.header_extensions = (uint8_t*)malloc(header_extensions_size);
memcpy(response.header_extensions, res + 4, header_extensions_size);
// 设置payload指针和大小
response.payload = (uint8_t*)res + response.header_size * 4;
response.payload_size = res_size - response.header_size * 4;
// 分配ParsedResponse结构体内存
ParsedResponse* result = (ParsedResponse*)malloc(sizeof(ParsedResponse));
memset(result, 0, sizeof(ParsedResponse));
// 根据消息类型处理payload
switch (response.message_type) {
case SERVER_FULL_RESPONSE:
// 解析payload大小(前4字节)
result->payload_size = ntohl(*(int32_t*)response.payload);
response.payload += 4;
response.payload_size -= 4;
break;
case SERVER_ACK:
if (response.payload_size >= 8) {
// 如果有额外的payload,解析其大小(接下来的4字节)
result->payload_size = ntohl(*(uint32_t*)(response.payload + 4));
response.payload += 8;
response.payload_size -= 8;
}
break;
case SERVER_ERROR_RESPONSE:
result->payload_size = ntohl(*(uint32_t*)(response.payload + 4));
response.payload += 8;
response.payload_size -= 8;
break;
}
// 处理payload(如果存在)
if (response.payload_size > 0) {
// 根据序列化方法处理payload
if (response.serialization_method == JSON) {
// 解析JSON
cJSON* json = cJSON_Parse((char*)response.payload);
if (json) {
result->payload_msg = cJSON_Print(json);
cJSON_Delete(json);
}
} else if (response.serialization_method != NO_SERIALIZATION) {
// 如果不是JSON也不是NO_SERIALIZATION,则直接复制字符串
result->payload_msg = strdup((char*)response.payload);
}
}
// 清理临时分配的内存
free(response.header_extensions);
return result;
}
static void generate_uuid(char *uuid_out)
{
const char *c = "89ab";
char *p = uuid_out;
for (int n = 0; n < 16; ++n) {
int b = rand() % 255;
switch (n) {
case 6:
sprintf(p, "4%x", b % 15);
break;
case 8:
sprintf(p, "%c%x", c[rand() % strlen(c)], b % 15);
break;
default:
sprintf(p, "%02x", b);
break;
}
p += 2;
switch (n) {
case 3:
case 5:
case 7:
case 9:
*p++='-';
break;
}
}
*p = 0;
}
DataSlicer* create_data_slicer(unsigned char* data, size_t data_len, size_t chunk_size) {
DataSlicer* slicer = (DataSlicer*)malloc(sizeof(DataSlicer));
slicer->data = data;
slicer->data_len = data_len;
slicer->chunk_size = chunk_size;
slicer->current_offset = 0;
return slicer;
}
DataSegment* slice_data(DataSlicer* slicer) {
if (slicer->current_offset >= slicer->data_len) {
return NULL;
}
DataSegment* segment = (DataSegment*)malloc(sizeof(DataSegment));
size_t remaining = slicer->data_len - slicer->current_offset;
size_t segment_size = (remaining < slicer->chunk_size) ? remaining : slicer->chunk_size;
segment->data = (unsigned char*)malloc(segment_size);
memcpy(segment->data, slicer->data + slicer->current_offset, segment_size);
segment->size = segment_size;
segment->is_last = (slicer->current_offset + segment_size >= slicer->data_len);
slicer->current_offset += segment_size;
return segment;
}
/*******************************************************************************
* Websocket Client.c
*******************************************************************************/
static void websockets_stt_client_main_thread(void *priv)
{
int err;
char mode = WEBSOCKET_MODE;
u8 url[256] = OBJ_URL;
const char *origin_str = "wss://openspeech.bytedance.com/api/v2/asr";
const char *user_agent_str = "Authorization: Bearer; BNA-XBIrEisvMczcmc-Sm4B3H-PmfqlL";
char *websocket_header = NULL;
char *payload = NULL;
uint32_t payloadsize;
size_t total_length;
size_t header_length;
size_t payload_length;
char *full_client_request=NULL;
u8 uuid[16] = {0};
char *aduio_client_request=NULL;
AsrWsClient STTPayload={
.appid="8571950639",
.cluster="volcengine_streaming_common",
.token="BNA-XBIrEisvMczcmc-Sm4B3H-PmfqlL",
.uid="388808088185088",
.nbest=1,
.workflow="audio_in,resample,partition,vad,fe,decode,itn,nlu_punctuate",
.show_language=false,
.show_utterances=false,
.result_type="full",
.format="mp3",
.rate=16000,
.language="zh-CN",
.bits=16,
.channel=1,
.codec="raw",
};
char name[128];
char aduio[100*1024]={0};
int aduio_len;
FILE *f = fopen("mnt/sdfile/res/demo/story.mp3", "r");
if (!f) {
printf("fopen err!\n");
}else{
fget_name(f, name, sizeof(name));
printf("file_name: %s\n", name);
aduio_len = fread(aduio, 1, sizeof(aduio), f);
if(aduio_len > 0)
{
printf("aduio_len:%d\r\n",aduio_len);
}
}
DataSlicer* slicer = create_data_slicer((unsigned char*)aduio, aduio_len, 10*1024);
DataSegment* segment;
os_sem_create(&chat_sem,0);
printf(" . ----------------- stt Client Websocket ------------------\r\n");
/* 0 . malloc buffer */
struct websocket_struct *websockets_info = malloc(sizeof(struct websocket_struct));
if (!websockets_info) {
return;
}
/* 1 . register */
websockets_client_reg(websockets_info, mode);
/* 2 . init */
err = websockets_client_init(websockets_info, url, origin_str, user_agent_str);
if (FALSE == err) {
printf(" . ! Cilent websocket init error !!!\r\n");
goto exit_ws;
}
/* 3 . hanshack */
err = websockets_client_handshack(websockets_info);
if (FALSE == err) {
printf(" . ! Handshake error !!!\r\n");
goto exit_ws;
}
printf(" . Handshake success \r\n");
/* 4 . CreateThread */
thread_fork("websocket_client_heart", 19, 512, 0,
&websockets_info->ping_thread_id,
websockets_info->_heart_thread,
websockets_info);
thread_fork("websocket_client_recv", 18, 512, 0,
&websockets_info->recv_thread_id,
websockets_info->_recv_thread,
websockets_info);
websockets_sleep(1000);
/* 5 . recv or send data */
while (1) {
//接收信号量0
os_sem_pend(&x_sem, 0); //获取信号量
websocket_header=generate_header(DEFAULT_HEADR);
header_length=4+STT_DEFAULT_EXTENSION_HEADER_LENGTH;
generate_uuid(uuid);
payload=construct_request(&STTPayload, uuid);
printf(" . Payload :%s \r\n",payload);
payload_length=strlen(payload);
payloadsize=htonl(payload_length);
total_length=header_length+4+payload_length;
full_client_request=(char *)malloc(total_length+1);
if (full_client_request == NULL) {
printf(" . ! malloc err !!!\r\n");
goto exit_ws;
}
memcpy(full_client_request, websocket_header, header_length);
memcpy(full_client_request + header_length, &payloadsize, 4);
memcpy(full_client_request + 4 + header_length,payload,payload_length+1);
err = websockets_client_send(websockets_info, (u8 *)full_client_request, total_length, WCT_TXTDATA);
if (FALSE == err) {
printf(" . ! send err !!!\r\n");
goto exit_ws;
}
free(payload);
free(full_client_request);
websockets_sleep(1000);
while(1){
segment = slice_data(slicer);
if(segment!=NULL){
if(segment->is_last){
websocket_header=generate_header(STT_DEFAULT_VERSION,0b0010,0b0010,0b0000,\
STT_DEFAULT_COMPRESSION_TYPE,STT_DEFAULT_RESERVED_DATA,\
STT_DEFAULT_EXTENSION_HEADER,STT_DEFAULT_EXTENSION_HEADER_LENGTH);
}else{
websocket_header=generate_header(STT_DEFAULT_VERSION,0b0010,0b0000,0b0000,\
STT_DEFAULT_COMPRESSION_TYPE,STT_DEFAULT_RESERVED_DATA,\
STT_DEFAULT_EXTENSION_HEADER,STT_DEFAULT_EXTENSION_HEADER_LENGTH);
}
payloadsize=htonl(segment->size);
total_length=header_length+4+segment->size;
aduio_client_request=(char *)malloc(total_length+1);
if (aduio_client_request == NULL) {
printf(" . ! malloc err !!!\r\n");
goto exit_ws;
}
memcpy(aduio_client_request, websocket_header, header_length);
memcpy(aduio_client_request + header_length, &payloadsize, 4);
memcpy(aduio_client_request + 4 + header_length,segment->data,segment->size+1);
err = websockets_client_send(websockets_info, (u8 *)aduio_client_request, total_length, WCT_TXTDATA);
if (FALSE == err) {
printf(" . ! send err !!!\r\n");
goto exit_ws;
}
free(aduio_client_request);
}else{
break;
}
free(segment);
websockets_sleep(1000);
}
}
exit_ws:
/* 6 . exit */
if (websockets_info->ping_thread_id) {
thread_kill(&websockets_info->ping_thread_id, KILL_REQ);
}
if (websockets_info->recv_thread_id) {
thread_kill(&websockets_info->recv_thread_id, KILL_REQ);
}
websockets_client_exit(websockets_info);
free(slicer);
free(websockets_info);
}
static void websocket_client_thread_create(void)
{
thread_fork("websockets_stt_client_main_thread", 15, 1024 * 250, 0, 0, websockets_stt_client_main_thread, NULL);
}
static void http_websocket_start(void *priv)
{
enum wifi_sta_connect_state state;
os_sem_create(&x_sem,1);
while (1) {
printf("Connecting to the network...\n");
state = wifi_get_sta_connect_state();
if (WIFI_STA_NETWORK_STACK_DHCP_SUCC == state) {
printf("Network connection is successful!\n");
break;
}
os_time_dly(500);
}
websocket_client_thread_create();
}
//应用程序入口,需要运行在STA模式下
static int stt_websocket_init(void)
{
if (thread_fork("http_websocket_start", 10, 512, 0, NULL, http_websocket_start, NULL) != OS_NO_ERR) {
printf("thread fork fail\n");
}
}
late_initcall(stt_websocket_init);
#endif // stt