70 lines
4.3 KiB
JavaScript
70 lines
4.3 KiB
JavaScript
// Execute the actual PCM worker and quiet check with synthetic RTOS/codec I/O.
|
|||
|
|
const fs=require('node:fs'),path=require('node:path');
|
||
|
|
const src=fs.readFileSync(path.join(__dirname,'../components/application/platform/src/espressif/volc_hal_player.c'),'utf8');
|
||
|
|
const section=(a,b)=>{const x=src.indexOf(a),y=src.indexOf(b,x+a.length);if(x<0||y<0)throw new Error(a);return src.slice(x,y);};
|
||
|
|
process.stdout.write(String.raw`
|
||
|
|
#include <assert.h>
|
||
|
|
#include <stdbool.h>
|
||
|
|
#include <stdint.h>
|
||
|
|
#include <stddef.h>
|
||
|
|
#include <stdio.h>
|
||
|
|
#include <stdatomic.h>
|
||
|
|
#include <string.h>
|
||
|
|
typedef void *volc_hal_player_t;
|
||
|
|
typedef struct {uint8_t data[65536];size_t used;} stream_t;
|
||
|
|
typedef struct {
|
||
|
|
atomic_bool is_started,write_in_progress;
|
||
|
|
atomic_uint last_voice_write_ms;
|
||
|
|
stream_t *pcm_stream;void *worker_stopped;
|
||
|
|
bool discard_pending,segment_complete;
|
||
|
|
bool (*authorization_gate)(void);
|
||
|
|
} volc_player_impl_t;
|
||
|
|
#define LOGI(...) do { if (0) printf(__VA_ARGS__); } while (0)
|
||
|
|
#define LOGE(...) do { if (0) printf(__VA_ARGS__); } while (0)
|
||
|
|
#define ESP_OK 0
|
||
|
|
#define PCM_PREBUFFER_BYTES 24000
|
||
|
|
#define PCM_PREBUFFER_WAIT_MS 1500
|
||
|
|
#define PCM_REPRIME_IDLE_MS 600
|
||
|
|
#define pdMS_TO_TICKS(x) (x)
|
||
|
|
static uint64_t now_ms,limit_ms;
|
||
|
|
static unsigned written,stops;
|
||
|
|
static bool feed_fail;
|
||
|
|
static volc_player_impl_t *running;
|
||
|
|
static uint64_t volc_osal_get_time_ms(void){return now_ms;}
|
||
|
|
static size_t xStreamBufferBytesAvailable(stream_t *s){return s->used;}
|
||
|
|
static size_t xStreamBufferReceive(stream_t *s,void *out,size_t n,unsigned wait){assert(wait==0);if(n>s->used)n=s->used;memcpy(out,s->data,n);memmove(s->data,s->data+n,s->used-n);s->used-=n;return n;}
|
||
|
|
static int stop_feeder_once(volc_player_impl_t *p){(void)p;stops++;return 0;}
|
||
|
|
static bool volc_hal_player_voice_quiet(volc_hal_player_t,unsigned);
|
||
|
|
static int audio_feeder_feed_data_timeout(const void *data,size_t count,unsigned timeout){
|
||
|
|
assert(data&&count&&timeout==50);
|
||
|
|
/* A dequeued last chunk is still in flight and cannot permit hangup. */
|
||
|
|
assert(atomic_load(&running->write_in_progress));assert(!volc_hal_player_voice_quiet(running,600));
|
||
|
|
now_ms+=count/32;written+=count;return feed_fail?-1:0;
|
||
|
|
}
|
||
|
|
static void vTaskDelay(unsigned ms){now_ms+=ms;if(now_ms>=limit_ms)atomic_store(&running->is_started,false);}
|
||
|
|
static void xSemaphoreGive(void *s){(void)s;}
|
||
|
|
static void vTaskDelete(void *t){assert(!t);}
|
||
|
|
`+section('static void pcm_playback_task(', '\nvolc_hal_player_t volc_hal_player_create(')+
|
||
|
|
section('bool volc_hal_player_voice_quiet(', '\nvoid volc_hal_player_set_authorization_gate(')+String.raw`
|
||
|
|
static bool deny(void){return false;}
|
||
|
|
int main(void){
|
||
|
|
stream_t stream={0};volc_player_impl_t player={.pcm_stream=&stream,.segment_complete=true};
|
||
|
|
running=&player;now_ms=1000;atomic_store(&player.is_started,true);atomic_store(&player.last_voice_write_ms,1000);
|
||
|
|
assert(!volc_hal_player_voice_quiet(&player,600));
|
||
|
|
for(size_t i=0;i<4096;i+=2){int16_t s=(i&2)?-500:500;memcpy(stream.data+i,&s,2);}stream.used=4096;
|
||
|
|
now_ms=3000;assert(!volc_hal_player_voice_quiet(&player,600));limit_ms=3400;
|
||
|
|
pcm_playback_task(&player);assert(written==4096&&stream.used==0);
|
||
|
|
uint32_t last=atomic_load(&player.last_voice_write_ms);assert(last>=3128&&last<3400);
|
||
|
|
atomic_store(&player.is_started,true);now_ms=last+599;assert(!volc_hal_player_voice_quiet(&player,600));now_ms++;assert(volc_hal_player_voice_quiet(&player,600));
|
||
|
|
memset(stream.data,0,640);stream.used=640;written=0;limit_ms=now_ms+200;
|
||
|
|
pcm_playback_task(&player);assert(written==640&&atomic_load(&player.last_voice_write_ms)==last);
|
||
|
|
atomic_store(&player.is_started,true);now_ms+=1000;assert(volc_hal_player_voice_quiet(&player,600));
|
||
|
|
stream.used=640;player.authorization_gate=deny;limit_ms=now_ms+100;pcm_playback_task(&player);assert(stops==1&&stream.used==0);
|
||
|
|
atomic_store(&player.is_started,true);player.authorization_gate=NULL;player.discard_pending=true;stream.used=640;limit_ms=now_ms+100;written=0;
|
||
|
|
pcm_playback_task(&player);assert(!player.discard_pending&&stream.used==0&&written==0);
|
||
|
|
atomic_store(&player.is_started,true);atomic_store(&player.last_voice_write_ms,UINT32_MAX-500u);now_ms=(uint64_t)UINT32_MAX+100;assert(volc_hal_player_voice_quiet(&player,600));
|
||
|
|
assert(!volc_hal_player_voice_quiet(NULL,600));
|
||
|
|
puts("PASS voice playback: actual PCM worker, queued/in-flight audio, audible tail grace, continuous silent PCM, authorization/discard, monotonic clock wrap");
|
||
|
|
}
|
||
|
|
`);
|