跳转至
MIGRATED

Xisound 运行时模式(PC/DSP)切换规范 v1.0

文档定位

  • 产生背景:2026-05-08 Source/Sink 重构发现智能体遗漏 PC/DSP 切换开关(Bug #7)· 现有所有文档 0 次提及此功能 · 本文档首次定义产品需求 + 实施规范
  • 权威性:所有 apps(XiStudio / XiTune / XiTest / XiProbe)涉及运行时模式的 UI/数据流必须遵守本文档
  • 上游D3-FE-ARCH-001 顶层架构 · D3-FE-ARCH-007 模块 UI 实现规范 · Source/Sink Review v7.0
  • 下游:各 app tech-arch 的 TopBar 设计 · WS 协议契约 · 后端 Runtime Mode Service

1. 为什么需要 PC/DSP 切换

1.1 用户场景

场景 运行时模式 用户意图
开发/调试算法 PC 模拟 修改参数看效果 · 迭代快 · 无硬件也可运行
声学调音 PC 模拟(桌面) 用声卡模拟车载环境 · 方便 A/B 对比
量产测试 DSP 硬件 真实 XiDSP + XiAmp + 车载声学环境 · 验证算法 AEC-Q100 合规
灯塔现场 DSP 硬件 车辆交付前验收 · 不容许模拟

核心诉求同一个工程文件(link.json)在 PC 和 DSP 两种运行模式下可切换执行,结果可对比。

1.2 三种运行模式

┌─────────────────────────────────────────────────────┐
│ PC 模式 (默认 · 开发态)                              │
│ ├── 前端 → C# 后端 → DSPAlgo.dll → WASAPI → 声卡     │
│ └── 特点:跨平台 · 开发友好 · 调音师桌面用           │
├─────────────────────────────────────────────────────┤
│ DSP 模式 (生产/测试)                                 │
│ ├── 前端 → C# 后端 → 调试协议 → 真实 XiDSP → XiAmp → 车载 │
│ └── 特点:真实实时性 · AEC-Q100 合规 · 灯塔现场必需  │
├─────────────────────────────────────────────────────┤
│ 混合模式 (Y2+ · 可选)                                │
│ ├── 部分模块走 PC 模拟 + 部分走 DSP 硬件            │
│ └── 特点:前端实现成本高 · 暂缓到 Y2+                │
└─────────────────────────────────────────────────────┘

2. UI 位置与视觉规范(强制)

2.1 Shell 顶部栏位置

每个 app(主要是 XiStudio / XiTune)的 TopBar 必须在右侧用户头像左边放置一个运行时模式下拉

┌─────────────────────────────────────────────────────────────────┐
│ Xisound Studio    [工程名 · UnitTest v1.0]                      │
│                           [▼ PC 模式]  [👤 userA]  [⚙]         │ ← TopBar
└─────────────────────────────────────────────────────────────────┘
                      运行时模式下拉(必须在此位置)

2.2 下拉内部结构

┌──────────────────────────────────┐
│ ● PC 模式(当前)               │
│    本地声卡 · 跨平台             │
├──────────────────────────────────┤
│ ○ DSP 硬件模式                   │
│    真实 XiDSP · 需连接硬件       │
│    [🔍 检测硬件] → 已连 XiDSP-D2 │
└──────────────────────────────────┘
   [切换模式]         [关闭]

必须元素

元素 强制 说明
当前模式指示(下拉按钮文案) "PC 模式" / "DSP 硬件模式" · 带颜色 badge(PC=info-blue · DSP=warning-orange)
两个选项的描述 每个模式下方写一行不同点("本地声卡 · 跨平台" / "真实 XiDSP · 需连接硬件")
硬件检测按钮(DSP 选项) 点击后后端扫描 · 显示检测结果("已连 XiDSP-D2" / "未检测到硬件")
切换按钮(底部) 点击才真正切换 · 单选选项只是预选
加载中状态(切换时) 整个下拉变 disabled · 显示 spinner + "切换中..."

2.3 切换时的视觉反馈

用户点"切换模式"后的视觉流程:

t=0ms:  [▼ PC 模式] 点击
t+10ms: [▼ PC 模式 → 切换中...(spinner)]
t+1s:   [▼ DSP 硬件模式(新状态)] · 右上角 Toast "已切换到 DSP 硬件模式"
         · 如果切换失败 → Toast "切换失败:未检测到硬件" + 恢复原模式

3. 数据模型与状态机

3.1 useRuntimeModeStore

// stores/useRuntimeModeStore.ts
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import { useAudioEngineStore } from './audioEngineStore'

export type RuntimeMode = 'pc' | 'dsp' | 'hybrid'  // hybrid 留 Y2+
export type ModeSwitchStatus = 'idle' | 'detecting' | 'switching' | 'error'

export const useRuntimeModeStore = defineStore('runtime-mode', () => {
  // 状态
  const mode = ref<RuntimeMode>('pc')             // 当前模式(默认 PC)
  const switchStatus = ref<ModeSwitchStatus>('idle')
  const lastError = ref<string | null>(null)
  const hardwareDetected = ref<HardwareInfo | null>(null)
  const supportedModes = ref<RuntimeMode[]>(['pc'])  // 初始化后填充

  // Getters
  const isPC = computed(() => mode.value === 'pc')
  const isDSP = computed(() => mode.value === 'dsp')
  const canSwitchToDSP = computed(() => hardwareDetected.value !== null)

  // Actions
  async function detectHardware(): Promise<HardwareInfo | null> {
    switchStatus.value = 'detecting'
    try {
      const info = await api.detectDSPHardware()
      hardwareDetected.value = info
      if (info) supportedModes.value.push('dsp')
      return info
    } catch (e) {
      lastError.value = e.message
      return null
    } finally {
      switchStatus.value = 'idle'
    }
  }

  async function switchMode(targetMode: RuntimeMode): Promise<boolean> {
    if (!supportedModes.value.includes(targetMode)) {
      lastError.value = `模式 ${targetMode} 不受支持`
      return false
    }
    if (mode.value === targetMode) return true   // 同模式不切

    switchStatus.value = 'switching'
    try {
      // 1. 暂停当前运行的链路(如果有)
      const audioEngine = useAudioEngineStore()
      await audioEngine.pauseLink()

      // 2. 发送切换 WS 命令
      await api.switchRuntimeMode(targetMode)

      // 3. 重新 apply 当前 link(后端会根据 mode 路由到 PC DSP.dll 或真实硬件)
      await audioEngine.applyLink()

      // 4. 更新前端状态
      mode.value = targetMode
      lastError.value = null
      return true
    } catch (e) {
      lastError.value = e.message
      switchStatus.value = 'error'
      return false
    } finally {
      if (switchStatus.value !== 'error') switchStatus.value = 'idle'
    }
  }

  // 从 localStorage 恢复用户偏好
  function restorePreference(): void {
    const saved = localStorage.getItem('xi-runtime-mode')
    if (saved === 'pc' || saved === 'dsp') mode.value = saved as RuntimeMode
  }

  // 持久化(模式改变时自动调用)
  watch(mode, (v) => localStorage.setItem('xi-runtime-mode', v))

  return { mode, switchStatus, lastError, hardwareDetected, supportedModes, isPC, isDSP, canSwitchToDSP, detectHardware, switchMode, restorePreference }
})

export interface HardwareInfo {
  deviceType: 'XiDSP-D1' | 'XiDSP-D2' | 'XiDSP-D3' | 'XiDSP-D4' | 'XiDSP-A1'
  serialNumber: string
  firmwareVersion: string
  sampleRate: number
  channels: number
  connectionType: 'usb' | 'uart' | 'network'
  connectedAt: number
}

3.2 切换状态机

stateDiagram-v2
    [*] --> PC_idle: 默认启动
    PC_idle --> PC_detecting: 点击"检测硬件"
    PC_detecting --> PC_idle: 未检测到
    PC_detecting --> PC_ready_to_switch: 检测到硬件
    PC_ready_to_switch --> PC_idle: 取消
    PC_ready_to_switch --> Switching_to_DSP: 点击"切换模式"
    Switching_to_DSP --> DSP_idle: 切换成功
    Switching_to_DSP --> PC_idle: 切换失败 + Toast 错误

    DSP_idle --> Switching_to_PC: 点击"切换模式" (选 PC)
    Switching_to_PC --> PC_idle: 切换成功
    Switching_to_PC --> DSP_idle: 切换失败

    note right of Switching_to_DSP
        1. 暂停当前链路
        2. WS switch-runtime-mode
        3. 后端 re-apply link
        4. 前端刷新 audioEngine 状态
    end note

4. 模式下的功能差异矩阵(产品必读)

4.1 关键差异

功能 PC 模式 DSP 硬件模式 备注
实时延迟 ~10-30ms(WASAPI block=512) < 2ms(XiDSP block=64/48kHz) DSP 模式更接近车端
声卡/输出 本地 WASAPI 声卡(任意) XiAmp + 车载音响 / 或外接 XiDSP 开发板 DSP 不支持任意声卡
source_wav ✅ 完整支持 ⚠️ 仅 AOT 编译后的 wav DSP 不支持运行时换 wav
source_device ✅ 任意 WASAPI 输入 ✅ XiMic / XiCal 硬件直连 DSP 模式下 source_device 对应硬件麦
参数热更新 ✅ 无限制 ✅ 但需受 DSP 内存限制 DSP 有 MIPS/内存预算
模块数上限 无限(受 PC CPU) 受 XiDSP 型号(D1:10 模块 / D4:100+) DSP 模式会预警
CPU 监控 前端显示 DSP 侧采集回传 Phase 8 §14
烧录功能 ❌ 不适用 ✅ 可进入烧录流程 仅 DSP 模式
Signal Flow(CAN 信号) ⚠️ 模拟信号 ✅ 真实 CAN 总线 DSP 模式对接真实车

4.2 切换时的用户提示

PC → DSP

Toast (info): "已切换到 DSP 硬件模式"
- 硬件: XiDSP-D2 (v1.3.0)
- 采样率: 48000 Hz
- 当前链路: 8 模块 (预估 12% DSP 负载)

⚠️ 如果模块数超过硬件容量,会弹 Modal:
   "当前链路 45 模块超过 XiDSP-D2 容量(30 模块)"
   [查看详情] [返回 PC 模式]

DSP → PC

Toast (info): "已切换到 PC 模式"
- 输出设备: [ASUS Xonar AE (当前默认)]
- 采样率: 48000 Hz
- source_device 模块数: 3(自动映射到本地麦)

5. WS 协议契约(@xi/protocol 新增)

5.1 消息 Schema

// packages/protocol/src/websocket/runtime-mode.ts
import { z } from 'zod'

// 前端 → 后端:切换模式
export const SwitchRuntimeModeCommandSchema = z.object({
  type: z.literal('switch-runtime-mode'),
  payload: z.object({
    targetMode: z.enum(['pc', 'dsp', 'hybrid']),
    preserveLink: z.boolean().default(true),  // 是否保留当前 link
  }),
})

// 前端 → 后端:检测硬件
export const DetectHardwareCommandSchema = z.object({
  type: z.literal('detect-dsp-hardware'),
})

// 后端 → 前端:硬件检测结果
export const HardwareDetectedEventSchema = z.object({
  type: z.literal('dsp-hardware-detected'),
  payload: z.object({
    detected: z.boolean(),
    info: z.object({
      deviceType: z.enum(['XiDSP-D1', 'XiDSP-D2', 'XiDSP-D3', 'XiDSP-D4', 'XiDSP-A1']),
      serialNumber: z.string(),
      firmwareVersion: z.string(),
      sampleRate: z.number(),
      channels: z.number(),
      connectionType: z.enum(['usb', 'uart', 'network']),
    }).nullable(),
  }),
})

// 后端 → 前端:模式切换结果
export const RuntimeModeSwitchedEventSchema = z.object({
  type: z.literal('runtime-mode-switched'),
  payload: z.object({
    success: z.boolean(),
    newMode: z.enum(['pc', 'dsp']),
    errorMessage: z.string().optional(),
    linkStatus: z.object({
      reapplied: z.boolean(),
      moduleCount: z.number(),
      estimatedLoad: z.number().optional(),  // DSP 模式下 CPU 负载预估
    }),
  }),
})

5.2 HTTP API(辅助)

端点 方法 用途
/api/runtime/modes GET 列出支持的运行时模式(基于当前硬件检测)
/api/runtime/hardware GET 查询当前硬件信息(缓存的)
/api/runtime/mode GET 查询当前运行时模式
/api/runtime/mode/switch POST 切换模式(替代 WS,用于非实时场景)

6. 与其他文档的集成

6.1 与 Source/Sink Review v7 的关系

  • Source/Sink v7 描述了单一运行模式下的 DSP 实现细节(wav 解码器 / WASAPI capture / apply_link 等)
  • 本规范补充:wav/device 在 PC 和 DSP 两种模式下的不同行为(§4.1)
  • 不冲突:v7 仍然权威 · 本文档是前端 UI + 模式切换层的补充

6.2 与 ModuleNode 规范的关系

  • D3-FE-ARCH-007 §2 规定 ModuleNode 的 7 个强制元素
  • 本规范扩展:status 指示(§2.4)在 DSP 模式下额外支持 dsp-overload(红色闪烁)状态
  • ModuleNode 可选显示 DSP 资源占用(右下角小字 3% CPU / 8KB)· Phase 8 后

6.3 与 Phase 8 Plan 的关系

  • Phase 8 Plan 未体现 PC/DSP 切换(Phase 8 只聚焦后端+DSP 单路径)
  • Phase 9 必须加入 PC/DSP 切换实施(前端 1 天 · 后端 Runtime Mode Service 3 天 · 测试 1 天 · 共 5 天)

7. 实施 checklist(给智能体)

7.1 前端实施(XiStudio)

  • 新增 useRuntimeModeStore(§3.1 完整实现)
  • TopBar 加入运行时模式下拉(§2.1 位置)
  • 下拉内部按 §2.2 渲染(两个选项 + 描述 + 检测按钮 + 切换按钮)
  • 切换时的视觉反馈(§2.3 · spinner + disabled + Toast)
  • localStorage 持久化用户偏好
  • 切换失败时的 Toast + 恢复原状态
  • 初始化时调用 restorePreference() + detectHardware()

7.2 后端实施(C# ASP.NET Core)

  • 新增 RuntimeModeService(管理当前模式 + 硬件检测)
  • 实现 /api/runtime/* HTTP 端点
  • WS handler 支持 switch-runtime-mode / detect-dsp-hardware 命令
  • 切换模式时:调用 DSPAlgo.ChangeRuntimeTarget(pc / dsp-device) · 重新 apply_link
  • 发送 dsp-hardware-detectedruntime-mode-switched 事件

7.3 DSP 侧实施

  • XiDSP 固件支持硬件握手协议(USB/UART)
  • 固件返回型号 + firmware 版本
  • DSP 端 apply_link 协议与 PC 端一致(通过调试端口)

7.4 测试

  • e2e:切换 PC → DSP → PC · 验证 3 模块链路无爆音
  • e2e:DSP 模式下链路超载 · 验证 UI 提示
  • e2e:切换失败时的 UI 恢复
  • 单测:useRuntimeModeStore 状态机所有转换
  • 压测:10 次快速切换 · 验证后端资源释放正确

8. DQ 清单

DQ 编号 问题 建议
DQ-MODE-01 是否所有 apps(XiTune / XiTest / XiProbe)都需要切换开关? XiStudio / XiTune 必须 · XiTest 继承 · XiProbe 特殊(硬件测试本来就连 DSP)
DQ-MODE-02 混合模式(hybrid · 部分模块 PC + 部分 DSP)何时实现? Y2+ · 需要更复杂的路由 · 留做 PLAN-012
DQ-MODE-03 切换时是否保留 preset 状态? ✅ 保留 · preset 是 param 集合 · 两种模式下 param schema 相同
DQ-MODE-04 切换是否影响 Signal Flow 画布 bindings? 不影响 · bindings 在两种模式下都生效 · 只是 DSP 模式下用真实 CAN
DQ-MODE-05 XiDSP 硬件离线如何处理? 前端保持 DSP 模式 · 底栏显示"硬件已离线 · 请检查连接" · 禁止应用新 link

9. 版本与变更记录

版本 日期 作者 说明
v1.0 2026-05-09 work-cline 初稿 · 首次定义 PC/DSP 切换产品需求 · TopBar 位置 · useRuntimeModeStore · WS 协议 · 模式差异矩阵 · 实施 checklist

附录 A · 引用

上游: - D3-FE-ARCH-001 顶层架构 - D3-FE-ARCH-007 模块 UI 实现规范 - Source/Sink Review v7.0

同级: - D3-FE-ARCH-009 Preset 全链路规范(preset 跨模式保留)

下游: - D2-P1 XiStudio tech-arch:TopBar 实施应用本规范 - Phase 9 实施计划:PC/DSP 切换作为独立 plan 列入 D3-FE-PLAN-012