Files
story/firmware/echoear-platform-agent/tools/test_voice_diagnostic_host.mjs
T

46 lines
2.9 KiB
JavaScript
Raw Normal View History

// Extract actual USB diagnostic, microphone callback and manager failure path.
import fs from 'node:fs';
import path from 'node:path';
import crypto from 'node:crypto';
import {fileURLToPath} from 'node:url';
const here = path.dirname(fileURLToPath(import.meta.url));
const root = path.resolve(here, '..');
const names = ['main/conv_ai_embedded_kit.c',
'components/application/service/conv_service/src/volc_conv.c',
'components/application/service/conv_service/src/volc_conv_service.c',
'components/volc_conv_ai/src/transports/high_quality/src/volc_rtc.c'];
const sha = b => crypto.createHash('sha256').update(b).digest('hex');
const raw = names.map(p => fs.readFileSync(path.join(root,p)));
const texts = raw.map(b => b.toString('utf8').replaceAll('\r\n','\n'));
function between(text,start,end) {
const a=text.indexOf(start), b=text.indexOf(end,a);
if(a<0 || b<0) throw new Error('Missing source marker '+start);
return text.slice(a,b+end.length);
}
const production = [
'#define CONV_SERVICE_TIMEOUT 60\n' + between(texts[1],'/* CALL_IDLE_BEGIN:', '/* CALL_IDLE_END */'),
between(texts[0],'/* RTC_PRIORITY_DIAGNOSTIC_BEGIN:', '/* RTC_PRIORITY_DIAGNOSTIC_END */'),
between(texts[1],'/* VOICE_DIAGNOSTIC_BEGIN:', '/* VOICE_DIAGNOSTIC_END */'),
between(texts[3],'/* RTC_SELF_PRIORITY_BEGIN:', '/* RTC_SELF_PRIORITY_END */'),
// Existing capture callback accepts a positive int length; the cast retains
// its loop bound and makes that conversion explicit for host -Wsign-compare.
between(texts[1],'static void __audio_capture_cb(', '\n}').replace('i < len / sizeof(int16_t)', 'i < (int)(len / sizeof(int16_t))'),
between(texts[2],'static aios_ret_t __state_conversation(', '\n}'),
].join('\n\n');
// Verify real end/error paths still route through the tested reset function.
for (const start of ['CONV_AI_QUIT:', 'void conv_ai_service_task_stop(']) {
const tail=texts[1].slice(texts[1].indexOf(start));
if(!tail.slice(0,1500).includes('diagnostic_close();')) throw new Error('Missing reset '+start);
}
if(!between(texts[1],'void conv_ai_service_prepare_task(', '\n}').includes('diagnostic_prepare();')) throw new Error('Missing prepare gate');
const template=fs.readFileSync(path.join(here,'test_voice_diagnostic_host.c.in'),'utf8');
if(template.split('/* @PRODUCTION@ */').length!==2) throw new Error('Invalid template');
const output=path.resolve(process.argv[2] ?? path.join(here,'voice-diagnostic-host.c'));
fs.mkdirSync(path.dirname(output),{recursive:true});
fs.writeFileSync(output,template.replace('/* @PRODUCTION@ */',production));
const manifest={source_rows:names.map((p,i)=>({path:path.join(root,p),sha256:sha(raw[i])})),
output,host_sha256:sha(fs.readFileSync(output)),
build:'clang -std=c11 -g -O1 -fsanitize=undefined -fno-omit-frame-pointer voice-diagnostic-host.c -o voice-diagnostic-host'};
fs.writeFileSync(output+'.json',JSON.stringify(manifest,null,2)+'\n');
console.log(JSON.stringify(manifest));