/* test/test_decode.c — 播放解码链路验证(宿主):minimp3 解码 mp3 → audio_out(FILE sink) 写 WAV。 * 不依赖网络/登录(输入本地 mp3)。验证:解码无错、WAV 非空、时长合理、RT 因子。 * 运行:NCM_AUDIO_SINK=file NCM_AUDIO_OUT=/tmp/ncm_decode.wav ./test_decode */ #include #include #include #include #include "../ncm_app_internal.h" /* 引 audio_out / minimp3 声明 */ #include "minimp3_ex.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; 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"; mp3dec_ex_t dec; memset(&dec, 0, sizeof dec); if (mp3dec_ex_open(&dec, path, MP3D_SEEK_TO_BYTE) != 0) { fprintf(stderr, "open failed\n"); return 1; } static mp3d_sample_t pcm[8192 * 2]; /* 读首帧确定采样率/声道(read 会填 dec.info)*/ size_t got = mp3dec_ex_read(&dec, pcm, 8192 * 2); int sr = dec.info.hz; int ch = dec.info.channels; if (sr <= 0 || ch <= 0) { fprintf(stderr, "bad stream\n"); return 1; } printf("mp3: %s %dHz x%d detected_samples=%lld bitrate=%dkbps\n", path, sr, ch, (long long)dec.samples, dec.info.bitrate_kbps); if (audio_out_open(sr, ch, 16) != 0) { fprintf(stderr, "audio_out open failed\n"); return 1; } long long frames = 0; double t0 = now_s(); if (got > 0) { int fr = (int)(got / (size_t)ch); if (audio_out_write(pcm, fr) != fr) { fprintf(stderr, "write failed\n"); return 1; } frames += fr; } for (;;) { if (g_app_quit) break; got = mp3dec_ex_read(&dec, pcm, 8192 * 2); if (got == 0) break; int fr = (int)(got / (size_t)ch); if (audio_out_write(pcm, fr) != fr) { fprintf(stderr, "write failed\n"); break; } frames += fr; } double dt = now_s() - t0; audio_out_close(); mp3dec_ex_close(&dec); double secs = (double)frames / (double)sr; double rt = (dt > 0) ? secs / dt : 0; printf("decoded %lld frames = %.2f s audio (%d Hz) in %.3f s => %.1fx RT\n", frames, secs, sr, dt, rt); printf("OK: %s\n", (frames > 0) ? "decode chain works" : "EMPTY"); return (frames > 0) ? 0 : 1; }