Files
story/firmware/echoear-platform-agent/tests/capture-restart-host.cjs
T
Codex Local bf1233d5df
ci / verify (push) Canceled after 0s
feat: expand companion platform, device controls, and memoir workflows
Add customer and operator login, BLE provisioning, device fleet controls, call memory, memoir generation, and refreshed family and maintenance portals. Include API contracts, migrations, firmware sources, tests, assets, and deployment documentation.
2026-10-08 10:06:44 +08:00

135 lines
9.2 KiB
JavaScript

// Compile actual capture lifecycle and recorder close/read functions with
// concurrent workers. No device, microphone or provider access.
const fs=require('node:fs'),path=require('node:path');
const root=path.resolve(__dirname,'..');
const capture=fs.readFileSync(path.join(root,'components/application/platform/src/espressif/volc_hal_capture.c'),'utf8').replace(/^#include .*$/gm,'');
const recorder=fs.readFileSync(path.join(root,'components/av_processor/audio_processor.c'),'utf8');
function section(first,last){const a=recorder.indexOf(first),b=recorder.indexOf(last,a);if(a<0||b<0)throw Error(first);return recorder.slice(a,b);}
process.stdout.write(String.raw`
#include <assert.h>
#include <stdatomic.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <time.h>
typedef int esp_err_t;
#define ESP_OK 0
#define ESP_FAIL -1
#define ESP_LOGI(...) ((void)0)
#define ESP_LOGW(...) ((void)0)
#define ESP_LOGE(...) ((void)0)
#define LOGI(...) ((void)0)
#define LOGE(...) ((void)0)
#define pdMS_TO_TICKS(x) (x)
#define portMAX_DELAY 0
#define MALLOC_CAP_SPIRAM 1
#define MALLOC_CAP_8BIT 2
#define pdPASS 1
#define VOLC_MEDIA_TYPE_AUDIO 0
#define VOLC_MEDIA_TYPE_VIDEO 1
#define VOLC_HAL_CAPTURE_AUDIO 0
#define VOLC_AUDIO_DATA_TYPE_PCM 0
#define AV_PROCESSOR_FORMAT_ID_PCM 0
typedef int volc_media_type_e;
typedef enum {VOLC_AUDIO_MODE_WAKEUP,VOLC_AUDIO_MODE_CAPTURE} volc_hal_audio_capture_mode_e;
typedef void *volc_hal_capture_t;
typedef struct {int data_type;void *user_data;} volc_hal_frame_info_t;
typedef void (*volc_hal_capture_data_cb_t)(void*,const void*,int,volc_hal_frame_info_t*);
typedef void (*volc_hal_audio_wakeup_cb_t)(void*,void*);
typedef struct {int media_type;volc_hal_capture_data_cb_t data_cb;volc_hal_audio_wakeup_cb_t audio_wakeup_cb;void *user_data;} volc_hal_capture_config_t;
typedef struct {void *capture_handle[1];} volc_hal_context_t;
static volc_hal_context_t hal;
static volc_hal_context_t *volc_get_global_hal_context(void){return &hal;}
typedef struct {void *rec_dev;} basic_board_periph_t;
basic_board_periph_t global_periph;
static void esp_codec_dev_set_in_gain(void *d,float g){(void)d;(void)g;}
typedef struct {int format;struct {struct {struct {int sample_rate,sample_bits,channels,frame_duration;} audio_info;} g711;} params;} av_processor_encoder_config_t;
typedef struct {bool ai_mode_wakeup;} av_processor_afe_config_t;
typedef struct {av_processor_encoder_config_t encoder_cfg;av_processor_afe_config_t afe_config;volc_hal_audio_wakeup_cb_t recorder_event_cb;void *recorder_ctx;} audio_recorder_config_t;
#define DEFAULT_AV_PROCESSOR_AFE_CONFIG() {0}
#define DEFAULT_AUDIO_RECORDER_CONFIG() {0}
typedef unsigned UBaseType_t;
static UBaseType_t uxTaskPriorityGet(void *t){(void)t;return 5;}
static void vTaskPrioritySet(void *t,unsigned p){(void)t;(void)p;}
static void vTaskDelay(unsigned ticks){(void)ticks;struct timespec t={0,1000000};nanosleep(&t,NULL);}
typedef struct {pthread_mutex_t mutex;pthread_cond_t cond;int value;} *SemaphoreHandle_t;
static unsigned semaphores,tasks,allocations,pipelines;
static SemaphoreHandle_t xSemaphoreCreateBinary(void){
SemaphoreHandle_t s=calloc(1,sizeof(*s));assert(s);pthread_mutex_init(&s->mutex,NULL);pthread_cond_init(&s->cond,NULL);semaphores++;return s;
}
static int xSemaphoreTake(SemaphoreHandle_t s,unsigned timeout){(void)timeout;pthread_mutex_lock(&s->mutex);while(!s->value)pthread_cond_wait(&s->cond,&s->mutex);s->value--;pthread_mutex_unlock(&s->mutex);return 1;}
static void xSemaphoreGive(SemaphoreHandle_t s){pthread_mutex_lock(&s->mutex);s->value++;pthread_cond_signal(&s->cond);pthread_mutex_unlock(&s->mutex);}
static void vSemaphoreDelete(SemaphoreHandle_t s){pthread_mutex_destroy(&s->mutex);pthread_cond_destroy(&s->cond);free(s);semaphores--;}
typedef struct {pthread_t thread;void (*fn)(void*);void *arg;} *TaskHandle_t;
static bool task_fail,open_fail,buffer_fail;
static void *worker(void *p){TaskHandle_t t=p;t->fn(t->arg);assert(0);return NULL;}
static int xTaskCreatePinnedToCoreWithCaps(void (*fn)(void*),const char *name,unsigned stack,void *arg,unsigned priority,TaskHandle_t *h,int core,unsigned caps){
(void)name;(void)stack;(void)priority;(void)core;(void)caps;if(task_fail)return 0;
TaskHandle_t t=calloc(1,sizeof(*t));assert(t);t->fn=fn;t->arg=arg;*h=t;tasks++;assert(!pthread_create(&t->thread,NULL,worker,t));return pdPASS;
}
static void vTaskSuspend(void *h){assert(!h);pthread_exit(NULL);}
static void vTaskDeleteWithCaps(TaskHandle_t t){assert(!pthread_join(t->thread,NULL));free(t);tasks--;}
static void *volc_osal_malloc(size_t n){if(buffer_fail)return NULL;void *p=malloc(n);assert(p);allocations++;return p;}
static void *volc_osal_calloc(size_t n,size_t s){void *p=calloc(n,s);assert(p);allocations++;return p;}
static void volc_osal_free(void *p){if(p){free(p);allocations--;}}
enum {AUDIO_RUN_STATE_CLOSED,AUDIO_RUN_STATE_PLAYING};
typedef struct {int valid_size;void *buf;} esp_gmf_data_bus_block_t;
typedef struct {pthread_mutex_t mutex;pthread_cond_t cond;bool aborted,supply;int borrowers;char data[1920];} fifo_t;
static struct {int state;void *pipe,*task,*afe_cfg,*afe_manager,*pool;fifo_t *fifo;void *cb,*ctx;} audio_recorder;
static atomic_bool recorder_closing;
static atomic_uint recorder_readers,frames;
static SemaphoreHandle_t control;
static SemaphoreHandle_t recorder_control_lock(void){return control;}
static atomic_uint fifo_waiters;
static int esp_gmf_fifo_acquire_read(fifo_t *f,esp_gmf_data_bus_block_t *b,int n,unsigned timeout){
(void)timeout;pthread_mutex_lock(&f->mutex);atomic_fetch_add(&fifo_waiters,1);
while(!f->aborted&&!f->supply)pthread_cond_wait(&f->cond,&f->mutex);
atomic_fetch_sub(&fifo_waiters,1);
int ret=-1;if(!f->aborted){f->supply=false;f->borrowers++;b->valid_size=n;b->buf=f->data;ret=0;}
pthread_mutex_unlock(&f->mutex);return ret;
}
static void esp_gmf_fifo_release_read(fifo_t *f,esp_gmf_data_bus_block_t *b,unsigned t){(void)b;(void)t;pthread_mutex_lock(&f->mutex);assert(f->borrowers==1);f->borrowers--;pthread_mutex_unlock(&f->mutex);}
static void esp_gmf_fifo_abort(fifo_t *f){pthread_mutex_lock(&f->mutex);f->aborted=true;pthread_cond_broadcast(&f->cond);pthread_mutex_unlock(&f->mutex);}
static void esp_gmf_pipeline_stop(void *p){assert(p);}
static void esp_gmf_pipeline_destroy(void *p){assert(p);free(p);pipelines--;}
static void esp_gmf_task_deinit(void *p){assert(p);free(p);}
static void esp_gmf_fifo_destroy(fifo_t *f){assert(!atomic_load(&recorder_readers)&&!f->borrowers);pthread_mutex_destroy(&f->mutex);pthread_cond_destroy(&f->cond);free(f);}
static void afe_config_free(void *p){free(p);}
static void esp_gmf_afe_manager_destroy(void *p){free(p);}
static void av_audio_recorder_pool_deinit(void *p){free(p);}
`+section('static void recorder_cleanup_on_error(void)','static esp_err_t recorder_configure_all_encoders(void)')+section('static esp_err_t recorder_close_internal(void)','esp_err_t audio_feeder_feed_data(uint8_t')+String.raw`
static int audio_recorder_open(audio_recorder_config_t *c){
(void)c;assert(audio_recorder.state==AUDIO_RUN_STATE_CLOSED);
audio_recorder.pipe=malloc(1);pipelines++;audio_recorder.task=malloc(1);audio_recorder.afe_cfg=malloc(1);audio_recorder.afe_manager=malloc(1);audio_recorder.pool=malloc(1);
audio_recorder.fifo=calloc(1,sizeof(fifo_t));assert(audio_recorder.fifo);pthread_mutex_init(&audio_recorder.fifo->mutex,NULL);pthread_cond_init(&audio_recorder.fifo->cond,NULL);audio_recorder.fifo->supply=true;
if(open_fail){recorder_cleanup_on_error();assert(!audio_recorder.pool&&!audio_recorder.pipe&&!audio_recorder.task&&!audio_recorder.fifo&&!audio_recorder.afe_cfg&&!audio_recorder.afe_manager);return -1;}
audio_recorder.state=AUDIO_RUN_STATE_PLAYING;return 0;
}
`+capture+String.raw`
static void captured(void *c,const void *b,int n,volc_hal_frame_info_t *f){(void)c;(void)b;(void)n;(void)f;atomic_fetch_add(&frames,1);}
int main(void){
control=xSemaphoreCreateBinary();xSemaphoreGive(control);
volc_hal_capture_config_t cfg={.media_type=VOLC_MEDIA_TYPE_AUDIO,.data_cb=captured};
volc_hal_capture_t c=volc_hal_capture_create(&cfg);assert(c);
for(unsigned i=0;i<100;i++){
assert(!volc_hal_capture_start(c,i%2?VOLC_AUDIO_MODE_CAPTURE:VOLC_AUDIO_MODE_WAKEUP));
while(!atomic_load(&fifo_waiters))vTaskDelay(1);
assert(pipelines==1&&tasks==1);
assert(!volc_hal_capture_stop(c));assert(!pipelines&&!tasks&&!recorder_readers&&!fifo_waiters);
assert(!((volc_hal_capture_impl_t*)c)->capture_thread);
assert(!volc_hal_capture_update_config(c,&cfg));assert(!volc_hal_capture_stop(c));
}
task_fail=true;assert(volc_hal_capture_start(c,VOLC_AUDIO_MODE_CAPTURE)==-1);assert(!pipelines&&!tasks);task_fail=false;
open_fail=true;assert(volc_hal_capture_start(c,VOLC_AUDIO_MODE_CAPTURE)==-1);assert(!pipelines&&!tasks);open_fail=false;
buffer_fail=true;assert(volc_hal_capture_start(c,VOLC_AUDIO_MODE_CAPTURE)==-1);buffer_fail=false;
assert(!volc_hal_capture_start(c,VOLC_AUDIO_MODE_CAPTURE));while(!fifo_waiters)vTaskDelay(1);
volc_hal_capture_destroy(c);assert(!hal.capture_handle[0]&&!pipelines&&!tasks&&!allocations);
vSemaphoreDelete(control);assert(!semaphores&&frames>=50);
puts("PASS 100 concurrent capture/wakeup restarts: blocked reader abort and join, pipeline/WithCaps/handle/buffer cleanup, duplicate stop, open/buffer/task failure recovery, destroy");
return 0;
}
`);