Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions .github/workflows/client.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
name: Client platforms
on:
push:
branches: [master, 'codex/**']
pull_request:
workflow_dispatch:
permissions:
contents: read
jobs:
client:
strategy:
fail-fast: false
matrix:
include:
- runner: windows-latest
target: win32-x64
- runner: macos-15-intel
target: darwin-x64
- runner: macos-15
target: darwin-arm64
- runner: ubuntu-24.04
target: linux-x64
runs-on: ${{ matrix.runner }}
timeout-minutes: 35
env:
EXPECTED_TARGET: ${{ matrix.target }}
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
with:
node-version: '22'
cache: npm
- run: node -e "require('assert').equal(process.platform+'-'+process.arch, process.env.EXPECTED_TARGET)"
- if: runner.os == 'Linux'
run: sudo apt-get update && sudo apt-get install -y libasound2-dev libfuse2 xvfb
- run: npm ci
- run: npm run release:verify
- run: npm run test:release
- run: npm run native:test
- run: node native/tools/check-linkage.cjs
- if: runner.os == 'Windows'
run: npm run native:compare
- run: npm run test:audio
- run: npm run test:audio:integration
- run: npm run electron:build -- --dir
- if: runner.os != 'Linux'
run: npm run test:app && node tests/app/startup-failures.mjs
- if: runner.os == 'Linux'
run: xvfb-run -a npm run test:app && xvfb-run -a node tests/app/startup-failures.mjs
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
if: always()
with:
name: client-smoke-${{ matrix.target }}
path: |
artifacts/app-smoke/**/result.json
artifacts/app-smoke/**/main-window.png
native/build/Testing/Temporary/*.log
if-no-files-found: warn
retention-days: 7
28 changes: 28 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Publish accepted release
on:
push:
branches: [master]
paths: ['releases/acceptance/v*.json']
permissions:
contents: read
concurrency:
group: release-lifecycle
cancel-in-progress: false
jobs:
publish:
runs-on: ubuntu-24.04
permissions:
contents: write
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
with:
fetch-depth: 0
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
with:
node-version: '22'
- run: npm ci --ignore-scripts
- name: Publish only newly accepted exact artifacts
run: node scripts/release/publish-accepted.cjs
env:
GH_TOKEN: ${{ github.token }}
BEFORE_SHA: ${{ github.event.before }}
114 changes: 114 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
name: Release installers
on:
push:
tags: ['v*']
branches: ['codex/multiplatform-release', 'codex/release-*']
workflow_dispatch:
permissions:
contents: read
concurrency:
group: release-lifecycle
cancel-in-progress: false
jobs:
build:
strategy:
fail-fast: false
matrix:
include:
- runner: windows-latest
target: win32-x64
- runner: macos-15-intel
target: darwin-x64
- runner: macos-15
target: darwin-arm64
- runner: ubuntu-24.04
target: linux-x64
runs-on: ${{ matrix.runner }}
timeout-minutes: 45
env:
EXPECTED_TARGET: ${{ matrix.target }}
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
with:
fetch-depth: 0
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
with:
node-version: '22'
cache: npm
- run: node -e "require('assert').equal(process.platform+'-'+process.arch, process.env.EXPECTED_TARGET)"
- if: runner.os == 'Linux'
run: sudo apt-get update && sudo apt-get install -y libasound2-dev libfuse2 xvfb
- run: npm ci
- run: npm run release:verify
env:
RELEASE_TAG: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && github.ref_name || '' }}
RELEASE_MASTER: refs/remotes/origin/master
- run: npm run test:release
- run: npm run native:test
- run: node native/tools/check-linkage.cjs
- if: runner.os == 'Windows'
run: npm run native:compare
- run: npm run test:audio
- run: npm run test:audio:integration
- run: npm run electron:build
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
if: runner.os == 'Windows'
with:
ref: a7f938151321cc7346512e8aab30c9993c931d54
path: .cache/upgrade-baseline
- name: Build original 1.1.4 upgrade baseline
if: runner.os == 'Windows'
working-directory: .cache/upgrade-baseline
run: npm ci && npm run electron:build -- --publish never
- if: runner.os != 'Linux'
run: npm run test:app && node tests/app/startup-failures.mjs && npm run test:installers
- if: runner.os == 'Linux'
run: xvfb-run -a npm run test:app && xvfb-run -a node tests/app/startup-failures.mjs && xvfb-run -a npm run test:installers
- run: node scripts/release/artifacts.cjs record
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with:
name: installers-${{ matrix.target }}
path: artifacts/release/*
if-no-files-found: error
retention-days: 7
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
if: always()
with:
name: release-diagnostics-${{ matrix.target }}
path: |
artifacts/app-smoke/**/result.json
artifacts/app-smoke/**/main-window.png
artifacts/installer-smoke/result.json
native/build/Testing/Temporary/*.log
dist/builder-debug.yml
retention-days: 7
draft:
needs: build
runs-on: ubuntu-24.04
permissions:
contents: write
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
with:
fetch-depth: 0
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
with:
node-version: '22'
- run: npm ci --ignore-scripts
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
with:
pattern: installers-*
path: collected
merge-multiple: true
- run: node scripts/release/artifacts.cjs aggregate collected release-assets
- if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
run: node scripts/release/github.cjs draft "$RELEASE_TAG" release-assets
env:
RELEASE_TAG: ${{ github.ref_name }}
GH_TOKEN: ${{ github.token }}
- if: github.event_name == 'workflow_dispatch' || !startsWith(github.ref, 'refs/tags/')
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with:
name: release-dry-run
path: release-assets/*
retention-days: 7
25 changes: 25 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# 更新日志

## 1.1.4

### 功能变化

- 现有 Windows 客户端基线;多平台发布流程正在验证。

### 修复

- FFmpeg 资源固定版本和散列校验;统一试听与串口发送的 PCM 解码生命周期。

### 兼容性

- 保持应用标识、产品名、工程修订号和串口协议。

### 已知问题

- 本条目记录历史基线,不表示历史版本已完成当前发布验收。
- 不提供在线更新;实机音频与兼容设备验收需单独记录。

### 平台状态

- Windows x64:历史开发基线。
- macOS x64、macOS arm64、Linux x64:待多平台发布验收。
28 changes: 18 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,19 +45,27 @@ LSAudio 将音效参数编辑、曲线展示、音频试听和设备通信集中

| 组件 | Windows x64 | macOS x64 / arm64 | Linux x64 |
| --- | --- | --- | --- |
| 桌面客户端 | 当前运行与打包目标 | 适配中 | 适配中 |
| 桌面客户端 | 待发布验收 | 待发布验收 | 待发布验收 |
| FFmpeg 与独立音频服务 | CI 验证 | CI 验证 | CI 验证 |
| C 算法替代实现 | 已通过原 DLL 对照测试 | 待运行验证 | 待运行验证 |
| C 算法替代实现 | 原 DLL 现场对照 | 原生 runner 回归 | 原生 runner 回归 |

**当前请在 Windows x64 上运行完整客户端。** 音频 CI 覆盖资源校验、解码、流式处理与资源打包,不代表完整应用已经支持所有平台。桌面运行时仍使用原 Windows DLL,C 替代实现的接入工作正在推进。
客户端默认使用项目维护的三个 C 动态库,原厂 DLL 仅用于 Windows 对照测试,不随安装包分发。四个平台的发布必须全部通过 CI 和验收;单项测试成功不代表正式支持。

## 快速开始

当前提供源码运行与本地打包方式。
安装包入口:[GitHub Releases](https://github.com/LISTENAI/equalizer/releases)(需要仓库访问权限)。首个预览版计划为 `1.2.0-beta.1`,验收完成前不会标为已发布。源码运行与本地打包仍可使用。

### 安装应用

- Windows x64:下载 `-windows-x64-setup.exe`,运行 NSIS 安装程序。未签名版本可能出现 SmartScreen 提示,请核对来源和 SHA-256。
- macOS:按 Intel / Apple Silicon 选择 x64 / arm64 DMG,挂载后将 LSAudio 拖入应用程序。仅使用 ad-hoc 签名,未公证;如系统阻止启动,在核验来源后通过系统设置的“隐私与安全性”允许打开。
- Linux x64:AppImage 执行 `chmod +x` 后运行;Debian/Ubuntu 可用 `sudo apt install ./LSAudio-<version>-linux-x64.deb` 安装。串口访问需要系统授予相应设备权限。

每次发布提供 `SHA256SUMS.txt` 和构建清单。应用内置 FFmpeg,无需单独安装;升级通过下载安装包完成,不提供在线更新。

### 开发环境

- Windows x64。
- Windows x64、macOS x64/arm64 或 Linux x64;正式支持状态见上表。
- Git、Node.js **22.12 或更高的 22.x 版本**及 npm,与音频 CI 使用的 Node.js 主版本一致。
- 首次安装依赖与准备 FFmpeg 时需要联网。
- 连接设备时,需要兼容固件和可用的串口;设备采样率应与调参界面保持一致。
Expand All @@ -69,9 +77,9 @@ npm ci
npm run dev
```

开发启动前会自动准备并校验本机的 FFmpeg。正式应用随包内置 FFmpeg,无需用户另行安装。离线准备、本地可执行文件覆盖和目标架构选择见 [FFmpeg 维护说明](ffmpeg/README.md)。
开发启动前会自动编译本机 C 库并准备、校验 FFmpeg。正式应用随包内置 FFmpeg,无需用户另行安装。离线准备、本地可执行文件覆盖和目标架构选择见 [FFmpeg 维护说明](ffmpeg/README.md)。

如需编译 C 算法替代实现,另需 **CMake 3.20+** 与 C11 编译器;Windows 推荐安装 Visual Studio 2022 的“使用 C++ 的桌面开发”组件。完整步骤见 [Native 开发指南](native/README.md)。
开发与打包需要 **CMake 3.20+** 与 C11 编译器;Windows 推荐安装 Visual Studio 2022 的“使用 C++ 的桌面开发”组件。完整步骤见 [Native 开发指南](native/README.md)。

### 第一次调音

Expand All @@ -88,11 +96,11 @@ npm run dev
# 编译 Electron 主进程、预加载脚本与前端
npm run build

# 在 Windows x64 上构建客户端安装包
# 在目标平台的本机架构上构建客户端安装包
npm run electron:build
```

Windows 默认生成 NSIS 安装程序,产物位置以构建日志为准。打包时会按目标平台准备 FFmpeg,并附带对应的许可证与来源说明。
产物位于 `dist/`:Windows 为 NSIS,macOS 为 DMG,Linux 为 AppImage 和 deb。打包内置 FFmpeg、C 库及第三方许可资料。版本、草稿、验收与发布操作见 [发布维护指南](docs/RELEASING.md)。

## 开发与测试

Expand Down Expand Up @@ -130,7 +138,7 @@ C 模块包括参数文件与曲线计算、绘图结果包装、实际音效处
- **提交改动**:尽量围绕一个问题组织提交,说明行为变化,并运行与改动相关的测试。界面改动可附截图;协议或算法改动请补充回归用例。
- **维护资源**:FFmpeg 版本更新应包含来源、散列与各平台验证结果;原 DLL 对照基准应从原库重新采集并审查差异。

当前跨平台工作的重点是接入 C 算法替代实现,并完成 macOS/Linux 完整客户端的运行与打包验证。
发布门槛包含四平台回归和实际安装产物测试;实际试听与兼容设备验收结果单独记录。参见 [更新日志](CHANGELOG.md) 和 [发布验收记录](releases/acceptance/README.md)。

## 许可证与第三方组件

Expand Down
51 changes: 51 additions & 0 deletions docs/RELEASING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# LSAudio 发布维护

仓库保持私有;Release 仅供有仓库权限的成员下载。产品标识 `listenai.com`、名称 `LSAudio` 和 Electron 用户数据目录保持不变。不接入在线更新。

## 工作流

1. 功能 PR:四个平台原生 runner 执行 C 回归、音频测试、应用目录启动测试。Windows 额外与原 DLL 现场对照。测试失败不可通过放宽数值容差绕过。
2. 版本 PR:在干净工作区运行 `npm run release:prepare -- 1.2.0-beta.1`,填写中文 `CHANGELOG.md`,运行 `npm run release:verify`。提交 package.json、package-lock.json 和更新日志。请维护者审查并合并到 master。
3. 合并检查通过后,发布执行者(本任务已授权的代理或维护者)检出最新 master,运行 `npm run release:tag -- 1.2.0-beta.1`。工具核对 master HEAD、四平台检查、已审查版本 PR,然后创建并推送不可移动的 `v1.2.0-beta.1` 标签到 **github** 远端。保留原 origin;不向 origin 发布。
4. 标签触发 `Release installers`,重新测试、构建和验证全部五个安装器。构建使用 `--publish never`、只读 token。全部目标成功后,汇总任务才创建草稿;附带五个安装器、`SHA256SUMS.txt`、`build-manifest.json`。
5. 从草稿下载实际附件,完成[验收记录](../releases/acceptance/README.md)。验收绑定标签提交和构建清单散列;实机未验证必须保持 pending。审查验收记录并合并到 master 后,`Publish accepted release` 自动发布草稿。beta 为 prerelease 且不设 Latest;稳定版设 Latest。

初次版本为 `1.2.0-beta.1`。完成预览版验收后,用同一流程准备 `1.2.0`,不复用 beta 标签。

标签步骤使用 GitHub CLI 登录凭据对应的 Git 推送,不使用 Actions 的 GITHUB_TOKEN 推送标签,避免 GitHub 的递归触发保护导致发布工作流不启动。代理会在版本 PR 审查、合并、检查门槛满足后执行,不需要再次确认标签/发布权限。

## 版本边界

- `package.json` 是产品版本唯一来源,lockfile 根版本必须一致。界面版本由构建工具注入 preload;安装器和产物名由 builder 注入版本。
- `.lsaudio` 中的 `manifestJson.version` 是工程修订计数,不随产品发版重置。
- C ABI/模块版本在 native 中管理;FFmpeg 的实际版本按目标记录在 `ffmpeg/manifest.json`,不能把资源合集的 b6.1.1 当成全部平台实际版本。
- 接受标签 `vX.Y.Z` 或 `vX.Y.Z-beta.N`,保留历史标签。不覆盖已发布附件,不移动标签。修复用新版本。

## 平台和产物

| 原生 runner | 文件后缀 | 签名状态 |
| --- | --- | --- |
| Windows x64 | `-windows-x64-setup.exe` | 未签名 |
| macOS x64 | `-macos-x64.dmg` | ad-hoc;无 Developer ID、无公证 |
| macOS arm64 | `-macos-arm64.dmg` | ad-hoc;无 Developer ID、无公证 |
| Linux x64 | `-linux-x64.AppImage`、`-linux-x64.deb` | 未签名 |

文件名前缀为 `LSAudio-<version>`。构建清单包括提交、Actions run、Node/Electron/builder/CMake、FFmpeg 版本来源、散列、签名状态。macOS 签名会改变 dylib 字节,签名后重新生成 native 清单,再签外层应用并验证。

## 演练与排错

在 Actions 手动运行 `Release installers`(可选择分支),仅产生构建产物,不创建标签或 Release。实现分支与 `codex/release-*` 版本分支的 push 也执行演练,便于在合并前验证安装器;均不创建 Release。

本机 `npm run electron:build` 使用本机平台/架构,C 库禁止跨宿主误用;输出在 dist。`npm run electron:build -- --dir` 后运行 `npm run test:app`。`test:installers` 仅允许在可丢弃的 CI runner 执行,避免改动开发机安装。Linux 使用 `xvfb-run -a`。

任一目标失败均不创建 Release。保留失败日志/截图 7 天;Actions 存储配额不足会明确失败,不能跳过上传宣称发布验证完成。资源缺失、架构错误在启动时给出明确提示。

同标签重跑仅允许同提交的草稿,重新汇总完整附件。草稿附件变动意味着必须重新取得验收散列;已发布版本一律拒绝更新。

安装器测试涵盖 NSIS 安装/卸载、DMG 挂载复制后启动、AppImage 提取运行和 deb 安装后运行。AppImage 在容器中通过自解压方式启动,FUSE 桌面使用和系统安装提示仍须验收。Windows 真实 1.1.4 升级基线、听感、设备参数和串口音频收发不可用单元测试代替。

## 首次发布跟踪

- 自动测试结果以功能 PR 的最新提交 CI 为准,不以旧提交成功状态放行。
- 尚未取得物理设备和完整安装验收结果前,平台表保持“待发布验收”。
- 首次发布需要仓库成员审查合并版本 PR;代理不会自行冒充审查者。
7 changes: 7 additions & 0 deletions docs/THIRD_PARTY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# 随包第三方资料

- Electron:应用目录包含 Electron 的 LICENSE / LICENSES.chromium.html。
- FFmpeg:`resources/ffmpeg` 中包含当前平台的许可证、上游 README 和来源记录;实际版本与 SHA-256 见仓库 `ffmpeg/manifest.json`。
- CMSIS-DSP FFT 子集:`resources/licenses/CMSIS-DSP-LICENSE.txt` 与 `CMSIS-DSP-SOURCE.md`,Apache-2.0。
- JavaScript 与 Node 原生依赖:安装包中的依赖目录保留各包许可文件。包括 Koffi、serialport、@echogarden/audio-io(MIT);具体依赖版本见 package-lock.json。
- LSAudio C 模块为本仓库维护的兼容实现;原厂 Windows DLL 仅为测试输入,不包含在安装包内。项目级许可状态以仓库声明为准,不因使用第三方开源组件而改变。
10 changes: 10 additions & 0 deletions native/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
cmake_minimum_required(VERSION 3.20)
cmake_policy(SET CMP0091 NEW)
project(lsaudio_native VERSION 0.1.0 LANGUAGES C)

set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
set(CMAKE_BUILD_WITH_INSTALL_RPATH ON)
if(APPLE)
set(CMAKE_INSTALL_RPATH "@loader_path")
set(CMAKE_INSTALL_NAME_DIR "@rpath")
elseif(UNIX)
set(CMAKE_INSTALL_RPATH "$ORIGIN")
endif()

set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS OFF)
Expand Down
Loading
Loading