Files

43 lines
3.6 KiB
JavaScript
Raw Permalink Normal View History

// Compile actual PCM packetizer and runtime JSON with ASan/UBSan on a C host.
const fs=require('node:fs'),path=require('node:path');
const root=path.resolve(__dirname,'..');
const read=p=>fs.readFileSync(path.join(root,p),'utf8');
const src=read('components/volc_conv_ai/src/transports/high_quality/src/volc_rtc.c');
const fn=src.slice(src.indexOf('static int __rtc_send_pcm('),src.indexOf('\nint volc_rtc_send('));
const conv=read('components/application/service/conv_service/src/volc_conv.c');
const config=conv.slice(conv.indexOf('#define CONV_AI_CONFIG_FORMAT'),conv.indexOf('#define CONV_SERVICE_TIMEOUT'));
const jsonDir=path.join(process.env.IDF_PATH||'E:/Codex/toolchains/esp-idf-v5.5.1','components/json/cJSON');
process.stdout.write(fs.readFileSync(path.join(jsonDir,'cJSON.h'),'utf8')+'\n'+fs.readFileSync(path.join(jsonDir,'cJSON.c'),'utf8').replace('#include "cJSON.h"','')+`
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#define ESP_PLATFORM 1
#define ESP_AUDIO_ERR_OK 0
#define AUDIO_DATA_TYPE_PCM 5
#define AUDIO_DATA_TYPE_OPUS 1
typedef struct {int data_type;} audio_frame_info_t;
typedef struct {uint8_t *buffer;uint32_t len;} esp_audio_enc_in_frame_t;
typedef struct {uint8_t *buffer;uint32_t len,encoded_bytes;} esp_audio_enc_out_frame_t;
typedef struct {void *rtc; const char *p_channel_name; uint8_t pcm_frame[640]; size_t pcm_used;void *opus_encoder;uint8_t *opus_packet;int opus_packet_size;} rtc_impl_t;
static uint8_t received[64000]; static size_t used; static int fail;
static int esp_opus_enc_process(void *h,esp_audio_enc_in_frame_t *in,esp_audio_enc_out_frame_t *out){assert(in->len==640 && out->len==640);memcpy(out->buffer,in->buffer,640);out->encoded_bytes=640;return 0;}
static int byte_rtc_send_audio_data(void *r,const char *ch,const void *p,size_t n,audio_frame_info_t *info) {
assert(n==640 && (info->data_type==AUDIO_DATA_TYPE_PCM || info->data_type==AUDIO_DATA_TYPE_OPUS)); if(fail)return -7;
assert(used+n<=sizeof(received)); memcpy(received+used,p,n); used+=n; return 0;
}
`+fn+'\n'+config+`
int main(void) {
uint8_t input[64000]; for(size_t i=0;i<sizeof(input);i++)input[i]=(uint8_t)i;
for(int encoded=0;encoded<2;encoded++)for(size_t chunk=1;chunk<=4097;chunk+=137) {
uint8_t packet[640];rtc_impl_t rtc={.opus_encoder=encoded?(void*)1:NULL,.opus_packet=packet,.opus_packet_size=sizeof(packet)}; used=0;
for(size_t pos=0;pos<sizeof(input);) {size_t n=sizeof(input)-pos;if(n>chunk)n=chunk;assert(__rtc_send_pcm(&rtc,input+pos,n)==0);pos+=n;}
assert(rtc.pcm_used==0 && used==sizeof(input));assert(!memcmp(input,received,sizeof(input)));
}
rtc_impl_t rtc={0};fail=1;assert(__rtc_send_pcm(&rtc,input,1920)==-7);assert(rtc.pcm_used==0);fail=0;
char buf[1024];int n=snprintf(buf,sizeof(buf),CONV_AI_CONFIG_FORMAT,"instance","product","secret","device");assert(n>0 && (size_t)n<sizeof(buf));
cJSON *cfg=cJSON_Parse(buf);assert(cfg);cJSON *params=cJSON_GetObjectItem(cJSON_GetObjectItem(cfg,"rtc"),"params");assert(cJSON_IsArray(params));
int opus=0;cJSON *p; cJSON_ArrayForEach(p,params) {cJSON *j=cJSON_Parse(cJSON_GetStringValue(p));assert(j);cJSON *a=cJSON_GetObjectItem(cJSON_GetObjectItem(cJSON_GetObjectItem(j,"audio"),"codec"),"opus");if(a){opus++;assert(cJSON_GetNumberValue(cJSON_GetObjectItem(a,"s_sample_rate"))==48000);assert(cJSON_GetNumberValue(cJSON_GetObjectItem(a,"s_samples_per_frame"))==960);assert(cJSON_GetNumberValue(cJSON_GetObjectItem(a,"r_sample_rate"))==48000);assert(cJSON_GetNumberValue(cJSON_GetObjectItem(a,"r_samples_per_frame"))==960);}cJSON_Delete(j);}
assert(opus==1);cJSON_Delete(cfg);puts("RTC PCM packetizer and runtime JSON: PASS");return 0;
}
`);