// 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 #include #include #include #include #include #include #include #include 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; } `);