/* test/test_decode.c — 播放解码链路验证(宿主/mipsel+qemu):decoder(magic 分发 * dr_flac/minimp3,§19)→ audio_out(FILE sink) 写 WAV。不依赖网络/登录(输入本地文件)。 * 验证:格式探测正确、rate/ch/bits 按实际流、解码无错、WAV 非空、帧数/时长对、RT 因子。 * * 运行:NCM_AUDIO_SINK=file NCM_AUDIO_OUT=/tmp/ncm_decode.wav \ * ./test_decode [expect_frames] [expect_rate] [expect_bits] * expect_* 给定时校验(不一致 exit 1);不给则只要求 frames>0。 * * 编译(宿主,ncm_app 目录下): * gcc -O2 -Wall -Wextra -DJSMN_HEADER -I. -Icore -I../sdk -I../meow_launcherd \ * -Ivendor/minimp3 -Ivendor/dr_flac \ * app/test/test_decode.c app/play/decoder.c app/play/audio_out.c \ * ../sdk/meow_ui_audio.c ../sdk/meow_ui_log.c -o /tmp/td.o-chain # 见下两行豁免 TU * gcc -O2 -Ivendor/minimp3 -c app/play/minimp3_impl.c -o /tmp/td_mm.o # vendor 豁免 * gcc -O2 -Ivendor/dr_flac -c app/play/dr_flac_impl.c -o /tmp/td_df.o # vendor 豁免 * (首行改为 -c 逐个或把两个豁免 .o 一并链接:gcc ... -o out/test_decode /tmp/td_mm.o /tmp/td_df.o -lpthread -lm) */ #include #include #include #include #include "../ncm_app_internal.h" /* audio_out 声明 + 全局态 */ #include "../play/decoder.h" ncm_app_state_t g_st; ncm_play_run_t g_play = { .mu = PTHREAD_MUTEX_INITIALIZER }; volatile int g_app_quit = 0; volatile int g_net_ready = 0; int g_host_mock = 1; /* SDK meow_ui_log.c 需要(本测试不链 meow_ui_sys.c,同 audiod_chain_sim 口径打桩) */ uint64_t meow_ui_time_ms(void) { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000; } static double now_s(void) { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); return (double)ts.tv_sec + ts.tv_nsec / 1e9; } int main(int argc, char **argv) { const char *path = (argc > 1) ? argv[1] : "vendor/minimp3/vectors/performance/MIPSTest.mp3"; int64_t exp_frames = (argc > 2) ? atoll(argv[2]) : -1; int exp_rate = (argc > 3) ? atoi(argv[3]) : -1; int exp_bits = (argc > 4) ? atoi(argv[4]) : -1; ncm_decoder_t *dec = NULL; int rate = 0, ch = 0, bits = 0; int64_t total_frames = 0; if (ncm_dec_open(&dec, path, &rate, &ch, &bits, &total_frames) != 0) { fprintf(stderr, "open failed\n"); return 1; } printf("%s: %s %dHz x%d %dbit total_frames=%lld\n", path, ncm_dec_format(dec), rate, ch, bits, (long long)total_frames); if (exp_rate > 0 && rate != exp_rate) { fprintf(stderr, "rate mismatch %d != %d\n", rate, exp_rate); return 1; } if (exp_bits > 0 && bits != exp_bits) { fprintf(stderr, "bits mismatch %d != %d\n", bits, exp_bits); return 1; } if (audio_out_open(rate, ch, bits) != 0) { fprintf(stderr, "audio_out open failed\n"); return 1; } static int32_t pcm[4096 * 2]; long long frames = 0; double t0 = now_s(); for (;;) { if (g_app_quit) break; int64_t got = ncm_dec_read(dec, pcm, 4096); if (got == 0) break; if (audio_out_write(pcm, (int)got) != (int)got) { fprintf(stderr, "write failed\n"); break; } frames += got; } double dt = now_s() - t0; audio_out_close(); ncm_dec_close(dec); double secs = rate > 0 ? (double)frames / (double)rate : 0; double rt = (dt > 0) ? secs / dt : 0; printf("decoded %lld frames = %.3f s audio (%d Hz) in %.3f s => %.1fx RT\n", frames, secs, rate, dt, rt); if (exp_frames >= 0 && frames != exp_frames) { fprintf(stderr, "frames mismatch %lld != %lld\n", frames, (long long)exp_frames); return 1; } printf("OK: %s\n", (frames > 0) ? "decode chain works" : "EMPTY"); return (frames > 0) ? 0 : 1; }