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

167 lines
11 KiB
Plaintext
Raw Normal View History

/* Synthetic-only SDK/RTOS boundaries. No device, network or captured speech. */
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdatomic.h>
#include <string.h>
#include <stdarg.h>
static void host_log(const char *fmt, ...) {(void)fmt;}
#define LOGI(...) host_log(__VA_ARGS__)
#define ESP_LOGI(tag,...) host_log(__VA_ARGS__)
#define pdFALSE 0
#define eInvalid 0
#define eDeleted 1
#define ESP_PLATFORM 1
typedef unsigned UBaseType_t;
typedef struct {unsigned number, priority, base; int core;} host_task_t;
typedef host_task_t *TaskHandle_t;
typedef struct {unsigned xTaskNumber,uxBasePriority;int eCurrentState;} TaskStatus_t;
static host_task_t rtc_task={42,4,4,1}, conv_task={43,5,5,1};
static bool rtc_present=true, conv_present;
static bool engine_ready=true, publish_fail;
static const char *current_name="VolcRTCMain";
static unsigned priority_writes, start_events, tts_sends, audio_sends, creates;
static bool authorized=true, rtc_mode=true, create_fail;
static int tts_result;
static TaskHandle_t xTaskGetHandle(const char *name) {
if(!strcmp(name,"VolcRTCMain")) return rtc_present?&rtc_task:NULL;
if(!strcmp(name,"conv_ai")) return conv_present?&conv_task:NULL;
assert(0);return NULL;
}
static void vTaskGetInfo(TaskHandle_t task,TaskStatus_t *s,int a,int b) {assert(!task);(void)a;(void)b;s->xTaskNumber=rtc_task.number;s->uxBasePriority=rtc_task.base;s->eCurrentState=eInvalid;}
static unsigned uxTaskPriorityGet(TaskHandle_t task) {assert(!task);return rtc_task.priority;}
static void vTaskPrioritySet(TaskHandle_t task,unsigned priority) {
assert(!task);
bool inherited=rtc_task.priority>rtc_task.base;
rtc_task.base=priority;
if(!inherited || rtc_task.priority<priority) rtc_task.priority=priority;
priority_writes++;
}
static int xTaskGetCoreID(TaskHandle_t task) {assert(!task);return rtc_task.core;}
static TaskHandle_t xTaskGetCurrentTaskHandle(void) {return &rtc_task;}
static const char *pcTaskGetName(TaskHandle_t task) {assert(!task);return current_name;}
static uint64_t esp_timer_get_time(void) {return 987654321;}
enum {VOLC_SERVICE_AI_CONVERSATION=1,VOLC_SERVICE_AI_CONVERSATION_START,VOLC_SERVICE_AI_CONVERSATION_INTERRUPT,
VOLC_SERVICE_AI_CONVERSATION_QUIT,VOLC_SERVICE_AI_CONVERSATION_OVER,VOLC_SERVICE_AI_CONVERSATION_TOGGLE};
static int aios_event_pub(int event,void *a,void *b) {assert(event==VOLC_SERVICE_AI_CONVERSATION);assert(!a&&!b);start_events++;return publish_fail?-1:0;}
static bool call_client_is_engine_ready(void) {return engine_ready;}
bool conv_ai_service_diagnostic_active(void);
typedef void *volc_hal_capture_t;
typedef struct {int data_type;} volc_hal_frame_info_t;
typedef struct {bool commit;int data_type;} volc_audio_frame_info_t;
enum {VOLC_AUDIO_DATA_TYPE_PCM=11,VOLC_AGENT_TYPE_TTS=12};
static struct {void *engine;int wait_time;} conv_service={(void*)1,0};
static atomic_bool is_stop,stop_requested;
static bool platform_conversation_audio_authorized(void) {return authorized;}
bool platform_runtime_rtc(void) {return rtc_mode;}
static uint64_t host_now_ms=1234;
static uint64_t volc_osal_get_time_ms(void) {return host_now_ms;}
typedef struct {int type;} esp_gmf_afe_evt_t;
enum {ESP_GMF_AFE_EVT_VAD_START=1,ESP_GMF_AFE_EVT_VAD_END};
static int get_rssi(void) {return -10;}
static int volc_send_audio_data(void *engine,const void *data,int len,volc_audio_frame_info_t *info) {
assert(engine==conv_service.engine&&data&&len>0&&!info->commit);audio_sends++;return 0;
}
static int volc_send_text_to_agent(void *engine,const char *text,int type,int interrupt) {
assert(engine==conv_service.engine&&type==VOLC_AGENT_TYPE_TTS&&interrupt==1);
assert(strstr(text,"这是连续语音播放测试。")&&strstr(text,"平稳地读完。"));tts_sends++;return tts_result;
}
typedef int aios_ret_t;
typedef struct {int id;} aios_event_t;
typedef struct {void *conv_thread_id;} volc_conv_service_manager_t;
typedef struct {void *display_handle;} volc_hal_context_t;
typedef void *volc_hal_display_t;
static volc_hal_context_t hal_context={NULL};
static volc_hal_context_t *volc_get_global_hal_context(void) {return &hal_context;}
enum {AIOS_Ret_NotHandled,AIOS_Ret_Handled,VOLC_DISPLAY_OBJ_STATUS,VOLC_DISPLAY_TEXT};
typedef struct {char name[32];int stack_size,priority,stack_in_ext;} volc_osal_thread_param_t;
static void volc_hal_display_set_content(void *h,int obj,int kind,const char *text) {(void)h;(void)obj;(void)kind;(void)text;}
static void diagnostic_prepare(void);
static void conv_ai_service_prepare_task(void) {diagnostic_prepare();}
static void conv_ai_service_task(void *arg) {(void)arg;}
void conv_ai_service_diagnostic_reset(void);
static void volc_osal_thread_destroy(void *handle) {(void)handle;}
static void vTaskDeleteWithCaps(TaskHandle_t handle) {assert(handle==&conv_task);conv_present=false;}
static void conv_ai_service_task_stop(void) {conv_ai_service_diagnostic_reset();}
static int volc_osal_thread_create(void **handle,volc_osal_thread_param_t *p,void (*f)(void*),void *arg) {
(void)p;(void)f;(void)arg;creates++;if(create_fail)return -1;*handle=&conv_task;conv_present=true;return 0;
}
/* @PRODUCTION@ */
static void capture(void) {
int16_t pcm[8]={1,2,3,4,5,6,7,8};volc_hal_frame_info_t info={VOLC_AUDIO_DATA_TYPE_PCM};
__audio_capture_cb(NULL,pcm,sizeof(pcm),&info);
}
int main(void) {
// Execute the real VAD + PCM callback: silence does not postpone idle,
// continuous detected speech does, and its end starts a fresh minute.
is_stop=false;stop_requested=false;call_idle_activity();
host_now_ms+=59000;capture();assert(!call_idle_expired());
host_now_ms+=1000;capture();assert(call_idle_expired());
esp_gmf_afe_evt_t vad={ESP_GMF_AFE_EVT_VAD_START};
call_idle_capture_event(&vad,NULL);
for(int tick=0;tick<180;tick++){host_now_ms+=1000;capture();assert(!call_idle_expired());}
vad.type=ESP_GMF_AFE_EVT_VAD_END;call_idle_capture_event(&vad,NULL);
host_now_ms+=60000;capture();assert(call_idle_expired());
audio_sends=0;
rtc_task.priority=rtc_task.base=3;
current_name="worker";__rtc_diagnostic_priority_apply();assert(priority_writes==0&&rtc_task.base==3);
diagnostic_rtc_priority(false);diagnostic_rtc_priority(true);assert(priority_writes==0);
current_name="VolcRTCMain";__rtc_diagnostic_priority_apply();
assert(rtc_task.priority==6&&rtc_task.base==6&&priority_writes==1&&!conv_ai_service_diagnostic_active());
unsigned writes=priority_writes;__rtc_diagnostic_priority_apply();assert(priority_writes==writes);
rtc_task.priority=rtc_task.base=7;__rtc_diagnostic_priority_apply();assert(rtc_task.base==7&&priority_writes==writes);
rtc_task.priority=8;rtc_task.base=3; // inherited effective priority is not the configured base
__rtc_diagnostic_priority_apply();assert(rtc_task.base==6&&rtc_task.priority==8);
rtc_task.priority=rtc_task.base;__rtc_diagnostic_priority_apply();assert(rtc_task.priority==6);
rtc_task.number++;rtc_task.priority=rtc_task.base=3; // a new same-name task must receive the floor too
__rtc_diagnostic_priority_apply();assert(rtc_task.base==6);
rtc_task.priority=rtc_task.base=4;__rtc_diagnostic_priority_apply();assert(rtc_task.base==6);
writes=priority_writes;diagnostic_rtc_priority(false);diagnostic_rtc_priority(true);
conv_ai_service_diagnostic_reset();diagnostic_close();diagnostic_prepare();
__rtc_diagnostic_priority_apply();assert(rtc_task.base==6&&priority_writes==writes);
volc_rtc_diagnostic_snapshot();assert(atomic_load(&diagnostic_rtc_seen));
assert(atomic_load(&diagnostic_rtc_base)==6&&priority_writes==writes);
puts("PASS normal-call self-only floor, higher base, inherited effective priority, new task, no diagnostic override");
capture();assert(audio_sends==1);
conv_ai_service_diagnostic_tts();assert(start_events==1&&diagnostic_uplink_suppressed());
capture();assert(audio_sends==1);
assert(diagnostic_take_pending()==DIAGNOSTIC_TTS&&diagnostic_uplink_suppressed());
diagnostic_send_tts();assert(tts_sends==1&&diagnostic_uplink_suppressed());
conv_present=true;conv_ai_service_diagnostic_tts();assert(start_events==1);
assert(diagnostic_take_pending()==DIAGNOSTIC_TTS);diagnostic_send_tts();assert(tts_sends==2);
assert(diagnostic_take_pending()==DIAGNOSTIC_NONE);capture();assert(audio_sends==1);
conv_ai_service_diagnostic_say();assert(start_events==1&&!diagnostic_uplink_suppressed());
assert(diagnostic_take_pending()==DIAGNOSTIC_SAY);capture();assert(audio_sends==2);
conv_ai_service_diagnostic_tts();diagnostic_rtc_priority(true);conv_ai_service_diagnostic_reset();__rtc_diagnostic_priority_apply();
assert(diagnostic_take_pending()==DIAGNOSTIC_NONE&&!diagnostic_uplink_suppressed()&&rtc_task.priority==6);
capture();assert(audio_sends==3);
puts("PASS fixed TTS bypass, same-room repetition, mic-only gate, say/reset restores uplink");
conv_ai_service_diagnostic_tts();tts_result=-1;diagnostic_send_tts();assert(!diagnostic_uplink_suppressed());
assert(diagnostic_take_pending()==DIAGNOSTIC_NONE);
rtc_mode=false;conv_ai_service_diagnostic_tts();unsigned sends=tts_sends;diagnostic_send_tts();
assert(tts_sends==sends&&!diagnostic_uplink_suppressed());rtc_mode=true;tts_result=0;
conv_present=false;create_fail=true;volc_conv_service_manager_t manager={0};
aios_event_t event={VOLC_SERVICE_AI_CONVERSATION_START};
conv_ai_service_diagnostic_tts();diagnostic_rtc_priority(true);
assert(__state_conversation(&manager,&event)==AIOS_Ret_Handled&&creates==1&&!manager.conv_thread_id);
assert(!diagnostic_uplink_suppressed()&&diagnostic_take_pending()==DIAGNOSTIC_NONE&&rtc_task.priority==6);
authorized=false;capture();assert(audio_sends==3);
puts("PASS send failure, unsupported transport and actual task-create failure restore diagnostics");
conv_present=true;conv_ai_service_diagnostic_tts();diagnostic_close();
conv_ai_service_diagnostic_tts();assert(!diagnostic_uplink_suppressed()&&!conv_ai_service_diagnostic_active());
assert(diagnostic_take_pending()==DIAGNOSTIC_NONE);
diagnostic_rtc_priority(true);assert(rtc_task.priority==6);
conv_ai_service_diagnostic_reset();conv_ai_service_diagnostic_tts(); // reset must preserve closing gate
assert(!diagnostic_uplink_suppressed());
conv_present=false;publish_fail=true;conv_ai_service_diagnostic_tts();
assert(!diagnostic_uplink_suppressed()&&!conv_ai_service_diagnostic_active());publish_fail=false;
conv_ai_service_diagnostic_tts();assert(diagnostic_uplink_suppressed());diagnostic_prepare();
assert(diagnostic_take_pending()==DIAGNOSTIC_TTS);diagnostic_close();diagnostic_prepare();
assert(!diagnostic_uplink_suppressed()&&!conv_ai_service_diagnostic_active());
puts("PASS closing request rejection, no priority pollution, event failure and next-call reset");
puts("voice diagnostic host PASS");return 0;
}