package com.lila.wakeup import android.media.AudioFormat /** * KWS APK 全局配置常量。 * * 协议版本:v2.1(详见 KWS唤醒协议-V2.md) * 涵盖三类常量: * - 协议常量(Action 名、对端包名、字段键) * - 引擎参数(阈值、平滑、超时、采样率) * - 模型路径(assets 内相对路径) */ object Config { // ============================================================ // 一、协议常量 // ============================================================ /** 本 APK 包名(自身) */ const val SELF_PACKAGE = "com.lila.wakeup" /** 数字人 APP 包名(已确认 v2.1) */ const val APP_PACKAGE = "com.qy.lila" /** 唤醒事件广播 Action(本 → APP) */ const val ACTION_WAKEUP = "com.lila.intent.action.WAKEUP" /** 暂停 KWS 广播 Action(APP → 本) */ const val ACTION_KWS_PAUSE = "com.lila.intent.action.KWS_PAUSE" /** 恢复 KWS 广播 Action(APP → 本) */ const val ACTION_KWS_RESUME = "com.lila.intent.action.KWS_RESUME" /** WAKEUP Extras: 命中的唤醒词文本 */ const val EXTRA_KEYWORD = "keyword" /** WAKEUP Extras: 命中时间戳(毫秒) */ const val EXTRA_TIMESTAMP = "timestamp" /** WAKEUP Extras: 置信度 [0,1] */ const val EXTRA_CONFIDENCE = "confidence" /** PAUSE Extras: 静默期毫秒数 */ const val EXTRA_SILENCE_MS = "silence_ms" /** PAUSE/RESUME Extras: 调用原因(透传日志) */ const val EXTRA_REASON = "reason" /** * 内部广播 Action(仅本 APP 自己接收,用于 MainActivity UI 实时显示命中)。 * 与对外协议 [ACTION_WAKEUP] 隔离,避免外部 APP 干扰内部 UI 状态。 */ const val ACTION_INTERNAL_WAKEUP = "com.lila.wakeup.action.INTERNAL_WAKEUP" // ============================================================ // 二、引擎参数 // ============================================================ /** PAUSE 默认静默期(v2.1 微调:3000ms 覆盖 RTC 远端音频回灌 + AI TTS 触发延迟) */ const val DEFAULT_SILENCE_MS = 3000L /** APP 漏发 RESUME 时的兜底超时(2 分钟) */ const val PAUSE_TIMEOUT_MS = 2 * 60 * 1000L // 注:KWS_THRESHOLD / SMOOTH_FRAMES 已移除,使用 sherpa-onnx 默认值 // - keywordsThreshold 默认 0.25 (KeywordSpotterConfig) // - 不做外部后验平滑(sherpa-onnx 内部 numTrailingBlanks 已平滑) // 原因见 KwsEngine.kt / KwsStateMachine.kt 注释 // ============================================================ // 三、AudioRecord 配置 // ============================================================ /** 采样率(sherpa-onnx 模型固定 16kHz) */ const val SAMPLE_RATE = 16_000 /** 单声道 */ const val CHANNEL_CONFIG = AudioFormat.CHANNEL_IN_MONO /** 16-bit PCM */ const val ENCODING = AudioFormat.ENCODING_PCM_16BIT /** * 单帧采样点数(100ms 帧 @ 16kHz = 1600 samples)。 * * ⚠️ 必须与 sherpa-onnx 官方 demo 一致(用 100ms 帧)。 * 之前用 10ms 帧(160 sample)第一次能识别,之后再无命中——sherpa-onnx * 内部 chunk 累积/边界处理对小帧不友好。改用 100ms 后稳定。 */ const val FRAME_SAMPLES = SAMPLE_RATE / 10 // ============================================================ // 四、模型路径(assets 内) // ============================================================ /** * 架构演进历史: * - v0: KWS wenetspeech 3.3M (2024) —— 默认 keywords 命中率 30-40% * - v1: KWS zh-en 双语 3M —— 英文 Lila 0% 命中 * - v2: ASR (SenseVoice 228MB) + 拼音替换 —— 板载 mic 全部 empty(模型对短词不敏感) * - v3: KWS Zipformer wenetspeech-3.3M + 自定义谐音 keywords.txt 流式架构(当前) * * v3 关键改动: * keywords.txt 用多个谐音变体覆盖("你好丽啦/咪啦/丽拉/lai啦"等) * 流式实时识别,不再切 segment,不再依赖 VAD/能量门 * 模型 5MB(vs SenseVoice 228MB),推理快 10x */ const val KWS_MODEL_DIR = "kws" const val KWS_ENCODER = "kws/encoder.int8.onnx" const val KWS_DECODER = "kws/decoder.onnx" const val KWS_JOINER = "kws/joiner.int8.onnx" const val KWS_TOKENS = "kws/tokens.txt" const val KWS_KEYWORDS_FILE = "kws/keywords.txt" /** KWS 推理线程数 */ const val KWS_NUM_THREADS = 2 /** * 关键词命中阈值(0~1 之间),越低越容易触发。 * 板载 mic 弱信号 + Lila 非训练词,激进降到 0.05。 * 误触发风险:需要观察 listening 待机时是否被环境噪声误唤醒。 */ const val KWS_THRESHOLD = 0.05f /** * 关键词命中加分,越大越容易触发。弱信号场景拉到 3.0。 */ const val KWS_SCORE = 3.0f /** * AudioCapture 软件预增益(在喂 KWS 之前)。 * 板载 mic 信号偏弱,1.5x 增益让说话峰值更接近满量程,KWS 神经网络 * 看到的特征对比度更高。clamp 到 [-32768, 32767] 防止溢出失真。 */ const val AUDIO_CAPTURE_GAIN = 1.5f /** * 调试: 命中前后 dump 一段 PCM 到 WAV 文件,辅助调试。 * 路径: /sdcard/Android/data/com.lila.wakeup/files/lila_kws/ * 拉回: adb pull /sdcard/Android/data/com.lila.wakeup/files/lila_kws/ ./ * 上线前关掉。 */ const val DUMP_HIT_WAV = true // ============================================================ // 五、通知栏 // ============================================================ const val NOTIF_CHANNEL_ID = "lila_wakeup_kws" const val NOTIF_CHANNEL_NAME = "Lila 语音唤醒" const val NOTIF_ID = 1 }