From c98e7e61b39ec652b6928864ddb808005f8e98e2 Mon Sep 17 00:00:00 2001 From: nanako <469449812@qq.com> Date: Fri, 24 Oct 2025 18:17:58 +0800 Subject: [PATCH] init --- CMakeLists.txt | 192 ++++ build.bat | 213 ++++ build.sh | 310 +++++ cmake/build_options.cmake | 103 ++ cmake/compiler_options.cmake | 170 +++ cmake/config_macos.cmake | 41 + cmake/dependencies.cmake | 147 +++ cmake/detect_os.cmake | 161 +++ cmake/install_config.cmake | 110 ++ cmake/mingw_dll.cmake | 41 + cmake/mirage_utils.cmake | 44 + cmake/project_cpp_standard.cmake | 138 +++ cmake/retrieve_files.cmake | 545 +++++++++ conanfile.txt | 109 ++ docs/README.md | 82 ++ docs/architecture-design.md | 1256 +++++++++++++++++++++ setup_conan.bat | 4 + src/CMakeLists.txt | 63 ++ src/common/CMakeLists.txt | 98 ++ src/common/error.cpp | 297 +++++ src/common/error.h | 382 +++++++ src/common/logger.cpp | 181 +++ src/common/logger.h | 179 +++ src/communication/CMakeLists.txt | 112 ++ src/communication/README.md | 67 ++ src/communication/core/message.cpp | 135 +++ src/communication/core/message.h | 199 ++++ src/communication/core/serializer.cpp | 222 ++++ src/communication/core/serializer.h | 177 +++ src/communication/proto/audio_meta.proto | 219 ++++ src/communication/proto/common.proto | 161 +++ src/communication/proto/control.proto | 196 ++++ src/communication/proto/plugin_mgmt.proto | 299 +++++ src/communication/proto/status.proto | 348 ++++++ src/engine/CMakeLists.txt | 117 ++ src/engine/audio_buffer.cpp | 290 +++++ src/engine/audio_buffer.h | 346 ++++++ src/frontend/CMakeLists.txt | 106 ++ src/plugin_host/CMakeLists.txt | 147 +++ src/simd/CMakeLists.txt | 131 +++ src/simd/aligned_allocator.h | 305 +++++ src/simd/audio_processing.cpp | 249 ++++ src/simd/audio_processing.h | 227 ++++ src/simd/cpu_features.cpp | 513 +++++++++ src/simd/cpu_features.h | 178 +++ src/simd/function_dispatcher.cpp | 120 ++ src/simd/function_dispatcher.h | 264 +++++ tests/CMakeLists.txt | 181 +++ 48 files changed, 10175 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 build.bat create mode 100644 build.sh create mode 100644 cmake/build_options.cmake create mode 100644 cmake/compiler_options.cmake create mode 100644 cmake/config_macos.cmake create mode 100644 cmake/dependencies.cmake create mode 100644 cmake/detect_os.cmake create mode 100644 cmake/install_config.cmake create mode 100644 cmake/mingw_dll.cmake create mode 100644 cmake/mirage_utils.cmake create mode 100644 cmake/project_cpp_standard.cmake create mode 100644 cmake/retrieve_files.cmake create mode 100644 conanfile.txt create mode 100644 docs/README.md create mode 100644 docs/architecture-design.md create mode 100644 setup_conan.bat create mode 100644 src/CMakeLists.txt create mode 100644 src/common/CMakeLists.txt create mode 100644 src/common/error.cpp create mode 100644 src/common/error.h create mode 100644 src/common/logger.cpp create mode 100644 src/common/logger.h create mode 100644 src/communication/CMakeLists.txt create mode 100644 src/communication/README.md create mode 100644 src/communication/core/message.cpp create mode 100644 src/communication/core/message.h create mode 100644 src/communication/core/serializer.cpp create mode 100644 src/communication/core/serializer.h create mode 100644 src/communication/proto/audio_meta.proto create mode 100644 src/communication/proto/common.proto create mode 100644 src/communication/proto/control.proto create mode 100644 src/communication/proto/plugin_mgmt.proto create mode 100644 src/communication/proto/status.proto create mode 100644 src/engine/CMakeLists.txt create mode 100644 src/engine/audio_buffer.cpp create mode 100644 src/engine/audio_buffer.h create mode 100644 src/frontend/CMakeLists.txt create mode 100644 src/plugin_host/CMakeLists.txt create mode 100644 src/simd/CMakeLists.txt create mode 100644 src/simd/aligned_allocator.h create mode 100644 src/simd/audio_processing.cpp create mode 100644 src/simd/audio_processing.h create mode 100644 src/simd/cpu_features.cpp create mode 100644 src/simd/cpu_features.h create mode 100644 src/simd/function_dispatcher.cpp create mode 100644 src/simd/function_dispatcher.h create mode 100644 tests/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..bdf43c0 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,192 @@ +# ================================================================================================ +# C++23 跨平台音频后端系统 - 主CMake配置文件 +# ================================================================================================ +# 项目: Audio Backend Framework +# 描述: 跨平台(Windows、Linux、macOS)C++23音频后端系统 +# 架构: 多进程架构,插件沙盒隔离,ZeroMQ + Boost共享内存通信 +# ================================================================================================ + +cmake_minimum_required(VERSION 3.20) + +# ================================================================================================ +# 项目定义 +# ================================================================================================ +project(AudioBackend + VERSION 1.0.0 + DESCRIPTION "Cross-platform C++23 Audio Backend System with Plugin Sandboxing" + LANGUAGES CXX C +) + +# ================================================================================================ +# C++标准配置 +# ================================================================================================ +set(CMAKE_CXX_STANDARD 23) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +message(STATUS "") +message(STATUS "========================================") +message(STATUS " ${PROJECT_NAME} v${PROJECT_VERSION}") +message(STATUS "========================================") +message(STATUS "C++ 标准: C++${CMAKE_CXX_STANDARD}") +message(STATUS "构建系统: CMake ${CMAKE_VERSION}") +message(STATUS "编译器: ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}") +message(STATUS "操作系统: ${CMAKE_SYSTEM_NAME}") +message(STATUS "架构: ${CMAKE_SYSTEM_PROCESSOR}") + +# ================================================================================================ +# 构建输出目录配置 +# ================================================================================================ +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) + +# 多配置生成器的输出目录 +foreach(OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES}) + string(TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${CMAKE_BINARY_DIR}/bin) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${CMAKE_BINARY_DIR}/lib) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${CMAKE_BINARY_DIR}/lib) +endforeach() + +# ================================================================================================ +# CMake模块路径 +# ================================================================================================ +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) + +# ================================================================================================ +# 包含CMake模块 +# ================================================================================================ +include(detect_os) # 操作系统检测 +include(project_cpp_standard) # C++标准配置 +include(build_options) # 构建选项 +include(compiler_options) # 编译器选项 +include(dependencies) # 依赖管理 +include(install_config) # 安装配置 + +# ================================================================================================ +# 配置构建类型 +# ================================================================================================ +configure_build_type() + +# ================================================================================================ +# 定义构建选项 +# ================================================================================================ +define_feature_options() + +# ================================================================================================ +# 打印构建选项摘要 +# ================================================================================================ +print_build_options() + +# ================================================================================================ +# Conan依赖集成 +# ================================================================================================ +# 检查Conan 2.x工具链文件 +if(EXISTS "${CMAKE_BINARY_DIR}/build/generators/conan_toolchain.cmake") + include(${CMAKE_BINARY_DIR}/build/generators/conan_toolchain.cmake) + message(STATUS "使用Conan 2.x工具链: build/generators/conan_toolchain.cmake") +elseif(EXISTS "${CMAKE_BINARY_DIR}/generators/conan_toolchain.cmake") + include(${CMAKE_BINARY_DIR}/generators/conan_toolchain.cmake) + message(STATUS "使用Conan 2.x工具链: generators/conan_toolchain.cmake") +elseif(EXISTS "${CMAKE_BINARY_DIR}/conan_toolchain.cmake") + include(${CMAKE_BINARY_DIR}/conan_toolchain.cmake) + message(STATUS "使用Conan 2.x工具链: conan_toolchain.cmake") +endif() + +# ================================================================================================ +# 配置所有依赖项 +# ================================================================================================ +setup_all_dependencies() + +# ================================================================================================ +# 应用编译器配置 +# ================================================================================================ +apply_compiler_configuration() + +# ================================================================================================ +# 创建项目配置接口库 +# ================================================================================================ +setup_project_options( + STANDARD 23 + INTERFACE_TARGET audio_backend_project_options +) + +# ================================================================================================ +# 全局编译定义 +# ================================================================================================ +add_compile_definitions( + $<$:AUDIO_BACKEND_DEBUG> + $<$:AUDIO_BACKEND_RELEASE> + AUDIO_BACKEND_VERSION_MAJOR=${PROJECT_VERSION_MAJOR} + AUDIO_BACKEND_VERSION_MINOR=${PROJECT_VERSION_MINOR} + AUDIO_BACKEND_VERSION_PATCH=${PROJECT_VERSION_PATCH} +) + +# ================================================================================================ +# 平台特定配置 +# ================================================================================================ +if(WIN32) + add_compile_definitions( + NOMINMAX # 防止Windows.h定义min/max宏 + WIN32_LEAN_AND_MEAN # 减少Windows.h包含的内容 + _WIN32_WINNT=0x0A00 # Windows 10 + ) +endif() + +# ================================================================================================ +# 注意: 每个模块将有自己的CMakeLists.txt文件管理自己的包含路径 +# 不再使用全局include_directories,而是在各模块内使用target_include_directories +# ================================================================================================ + +# ================================================================================================ +# 子目录 +# ================================================================================================ +message(STATUS "") +message(STATUS "=== 配置子模块 ===") + +# 源代码目录 +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/src) + add_subdirectory(src) + message(STATUS "添加源代码目录: src/") +endif() + +# 测试目录 +if(DAW_ENABLE_TESTS AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/tests) + enable_testing() + add_subdirectory(tests) + message(STATUS "添加测试目录: tests/") +endif() + +# 示例目录 +if(DAW_ENABLE_EXAMPLES AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/examples) + add_subdirectory(examples) + message(STATUS "添加示例目录: examples/") +endif() + +# 文档目录 +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/docs) + message(STATUS "文档目录: docs/") +endif() + +# ================================================================================================ +# 安装和打包配置 +# ================================================================================================ +setup_install_and_packaging() + +# ================================================================================================ +# 构建摘要 +# ================================================================================================ +message(STATUS "") +message(STATUS "========================================") +message(STATUS " 构建配置完成") +message(STATUS "========================================") +message(STATUS "项目名称: ${PROJECT_NAME}") +message(STATUS "项目版本: ${PROJECT_VERSION}") +message(STATUS "构建类型: ${CMAKE_BUILD_TYPE}") +message(STATUS "C++标准: C++${CMAKE_CXX_STANDARD}") +message(STATUS "安装前缀: ${CMAKE_INSTALL_PREFIX}") +message(STATUS "二进制输出: ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}") +message(STATUS "库输出: ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}") +message(STATUS "========================================") +message(STATUS "") \ No newline at end of file diff --git a/build.bat b/build.bat new file mode 100644 index 0000000..ed54b65 --- /dev/null +++ b/build.bat @@ -0,0 +1,213 @@ +@echo off +REM ================================================================================================ +REM Audio Backend Framework - Windows构建脚本 +REM ================================================================================================ +REM 描述: Windows平台的自动化构建脚本 +REM 功能: Conan依赖安装、CMake配置、项目编译 +REM 用法: build.bat [Debug|Release|clean|help] +REM ================================================================================================ + +setlocal EnableDelayedExpansion + +REM 设置项目根目录 +set PROJECT_ROOT=%~dp0 +cd /d %PROJECT_ROOT% + +REM 默认构建类型 +set BUILD_TYPE=Release +set CLEAN_BUILD=0 + +REM 解析命令行参数 +if "%1"=="" goto :parse_done +if /i "%1"=="Debug" set BUILD_TYPE=Debug +if /i "%1"=="Release" set BUILD_TYPE=Release +if /i "%1"=="clean" set CLEAN_BUILD=1 +if /i "%1"=="help" goto :show_help +if /i "%1"=="-h" goto :show_help +if /i "%1"=="--help" goto :show_help + +:parse_done + +echo. +echo ======================================== +echo Audio Backend Framework 构建系统 +echo ======================================== +echo 项目目录: %PROJECT_ROOT% +echo 构建类型: %BUILD_TYPE% +echo. + +REM ================================================================================================ +REM 清理构建 +REM ================================================================================================ +if %CLEAN_BUILD%==1 ( + echo [清理] 正在清理构建目录... + if exist build ( + rmdir /s /q build + echo [清理] 已删除 build 目录 + ) + if exist CMakeCache.txt ( + del /f /q CMakeCache.txt + echo [清理] 已删除 CMakeCache.txt + ) + echo [清理] 清理完成 + goto :end +) + +REM ================================================================================================ +REM 检查必要工具 +REM ================================================================================================ +echo [检查] 验证必要工具... + +where cmake >nul 2>nul +if %ERRORLEVEL% neq 0 ( + echo [错误] 未找到 CMake,请先安装 CMake + echo 下载地址: https://cmake.org/download/ + goto :error +) + +where conan >nul 2>nul +if %ERRORLEVEL% neq 0 ( + echo [错误] 未找到 Conan,请先安装 Conan + echo 安装命令: pip install conan + goto :error +) + +echo [检查] ✓ CMake 已安装 +echo [检查] ✓ Conan 已安装 + +REM ================================================================================================ +REM 安装Conan依赖 +REM ================================================================================================ +echo. +echo [Conan] 正在安装依赖包... +echo [Conan] 构建类型: %BUILD_TYPE% +echo [Conan] C++标准: C++23 +echo. + +REM 创建build目录 +if not exist build mkdir build +cd build + +REM 执行Conan安装 +conan install .. --output-folder=. --build=missing --settings=build_type=%BUILD_TYPE% --settings=compiler.cppstd=23 + +if %ERRORLEVEL% neq 0 ( + echo [错误] Conan依赖安装失败 + cd .. + goto :error +) + +echo. +echo [Conan] ✓ 依赖安装成功 +echo. + +REM ================================================================================================ +REM 配置CMake项目 +REM ================================================================================================ +echo [CMake] 正在配置项目... +echo [CMake] 构建类型: %BUILD_TYPE% +echo. + +REM CMake配置 +cmake .. -G "Visual Studio 17 2022" ^ + -DCMAKE_BUILD_TYPE=%BUILD_TYPE% ^ + -DCMAKE_TOOLCHAIN_FILE=generators/conan_toolchain.cmake ^ + -DDAW_ENABLE_SIMD=ON ^ + -DDAW_ENABLE_AVX512=ON ^ + -DDAW_ENABLE_TESTS=ON ^ + -DDAW_ENABLE_EXAMPLES=ON + +if %ERRORLEVEL% neq 0 ( + echo [错误] CMake配置失败 + cd .. + goto :error +) + +echo. +echo [CMake] ✓ 项目配置成功 +echo. + +REM ================================================================================================ +REM 编译项目 +REM ================================================================================================ +echo [编译] 正在编译项目... +echo [编译] 配置: %BUILD_TYPE% +echo. + +cmake --build . --config %BUILD_TYPE% --parallel + +if %ERRORLEVEL% neq 0 ( + echo [错误] 项目编译失败 + cd .. + goto :error +) + +echo. +echo [编译] ✓ 项目编译成功 +echo. + +REM 返回项目根目录 +cd .. + +REM ================================================================================================ +REM 构建成功 +REM ================================================================================================ +echo. +echo ======================================== +echo 构建成功! +echo ======================================== +echo 构建类型: %BUILD_TYPE% +echo 输出目录: %PROJECT_ROOT%build\bin +echo 库目录: %PROJECT_ROOT%build\lib +echo. +echo 运行测试: cd build ^&^& ctest -C %BUILD_TYPE% +echo. + +goto :end + +REM ================================================================================================ +REM 帮助信息 +REM ================================================================================================ +:show_help +echo. +echo Audio Backend Framework - Windows 构建脚本 +echo. +echo 用法: +echo build.bat [选项] +echo. +echo 选项: +echo Debug - 构建Debug版本(包含调试符号) +echo Release - 构建Release版本(默认,优化编译) +echo clean - 清理所有构建文件 +echo help - 显示此帮助信息 +echo. +echo 示例: +echo build.bat # 构建Release版本 +echo build.bat Debug # 构建Debug版本 +echo build.bat clean # 清理构建文件 +echo. +echo 依赖要求: +echo - CMake 3.20+ +echo - Conan 2.x +echo - Visual Studio 2022 或更高版本 +echo - C++23 支持的编译器 +echo. +goto :end + +REM ================================================================================================ +REM 错误处理 +REM ================================================================================================ +:error +echo. +echo ======================================== +echo 构建失败! +echo ======================================== +echo. +exit /b 1 + +REM ================================================================================================ +REM 正常退出 +REM ================================================================================================ +:end +endlocal +exit /b 0 \ No newline at end of file diff --git a/build.sh b/build.sh new file mode 100644 index 0000000..00b49b9 --- /dev/null +++ b/build.sh @@ -0,0 +1,310 @@ +#!/bin/bash +# ================================================================================================ +# Audio Backend Framework - Linux/macOS构建脚本 +# ================================================================================================ +# 描述: Linux和macOS平台的自动化构建脚本 +# 功能: Conan依赖安装、CMake配置、项目编译 +# 用法: ./build.sh [Debug|Release|clean|help] +# ================================================================================================ + +set -e # 遇到错误立即退出 + +# 颜色定义 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# 项目配置 +PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +BUILD_TYPE="Release" +CLEAN_BUILD=0 +JOBS=$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 4) + +# 检测操作系统 +detect_os() { + if [[ "$OSTYPE" == "darwin"* ]]; then + OS="macOS" + CMAKE_GENERATOR="Unix Makefiles" + elif [[ "$OSTYPE" == "linux"* ]]; then + OS="Linux" + CMAKE_GENERATOR="Unix Makefiles" + else + echo -e "${RED}[错误] 不支持的操作系统: $OSTYPE${NC}" + exit 1 + fi +} + +# 显示帮助信息 +show_help() { + echo + echo "Audio Backend Framework - Linux/macOS 构建脚本" + echo + echo "用法:" + echo " ./build.sh [选项]" + echo + echo "选项:" + echo " Debug - 构建Debug版本(包含调试符号)" + echo " Release - 构建Release版本(默认,优化编译)" + echo " clean - 清理所有构建文件" + echo " help - 显示此帮助信息" + echo + echo "示例:" + echo " ./build.sh # 构建Release版本" + echo " ./build.sh Debug # 构建Debug版本" + echo " ./build.sh clean # 清理构建文件" + echo + echo "依赖要求:" + echo " - CMake 3.20+" + echo " - Conan 2.x" + echo " - GCC 13+ 或 Clang 17+" + echo " - C++23 支持的编译器" + echo + echo "系统包依赖 (Ubuntu/Debian):" + echo " sudo apt install build-essential cmake python3-pip" + echo " sudo apt install libasound2-dev libpulse-dev libjack-jackd2-dev" + echo + echo "系统包依赖 (macOS):" + echo " brew install cmake conan" + echo +} + +# 解析命令行参数 +parse_args() { + case "${1:-}" in + "Debug"|"debug") + BUILD_TYPE="Debug" + ;; + "Release"|"release"|"") + BUILD_TYPE="Release" + ;; + "clean") + CLEAN_BUILD=1 + ;; + "help"|"-h"|"--help") + show_help + exit 0 + ;; + *) + echo -e "${RED}[错误] 未知参数: $1${NC}" + echo "使用 './build.sh help' 查看帮助" + exit 1 + ;; + esac +} + +# 打印标题 +print_header() { + echo + echo "========================================" + echo " Audio Backend Framework 构建系统" + echo "========================================" + echo "项目目录: $PROJECT_ROOT" + echo "操作系统: $OS" + echo "构建类型: $BUILD_TYPE" + echo "并行任务: $JOBS" + echo +} + +# 清理构建 +clean_build() { + echo -e "${YELLOW}[清理] 正在清理构建目录...${NC}" + + if [ -d "build" ]; then + rm -rf build + echo -e "${GREEN}[清理] ✓ 已删除 build 目录${NC}" + fi + + if [ -f "CMakeCache.txt" ]; then + rm -f CMakeCache.txt + echo -e "${GREEN}[清理] ✓ 已删除 CMakeCache.txt${NC}" + fi + + echo -e "${GREEN}[清理] ✓ 清理完成${NC}" + exit 0 +} + +# 检查必要工具 +check_tools() { + echo -e "${BLUE}[检查] 验证必要工具...${NC}" + + # 检查CMake + if ! command -v cmake &> /dev/null; then + echo -e "${RED}[错误] 未找到 CMake,请先安装 CMake${NC}" + if [[ "$OS" == "macOS" ]]; then + echo " 安装命令: brew install cmake" + else + echo " 安装命令: sudo apt install cmake" + fi + exit 1 + fi + + # 检查Conan + if ! command -v conan &> /dev/null; then + echo -e "${RED}[错误] 未找到 Conan,请先安装 Conan${NC}" + echo " 安装命令: pip3 install conan" + exit 1 + fi + + # 检查编译器 + if [[ "$OS" == "macOS" ]]; then + if ! command -v clang++ &> /dev/null; then + echo -e "${RED}[错误] 未找到 Clang++,请安装 Xcode Command Line Tools${NC}" + echo " 安装命令: xcode-select --install" + exit 1 + fi + else + if ! command -v g++ &> /dev/null && ! command -v clang++ &> /dev/null; then + echo -e "${RED}[错误] 未找到 G++ 或 Clang++,请安装编译器${NC}" + echo " 安装令: sudo apt install build-essential" + exit 1 + fi + fi + + echo -e "${GREEN}[检查] ✓ CMake 已安装$(cmake --version | head -n1 | cut -d' ' -f3)${NC}" + echo -e "${GREEN}[检查] ✓ Conan 已安装$(conan --version 2>/dev/null | cut -d' ' -f3)${NC}" + echo -e "${GREEN}[检查] ✓ 编译器已安装${NC}" +} + +# 安装系统依赖提示 +check_system_deps() { + if [[ "$OS" == "Linux" ]]; then + echo -e "${YELLOW}[提示] 确保已安装音频开发库:${NC}" + echo " sudo apt install libasound2-dev libpulse-dev libjack-jackd2-dev" + echo " sudo apt install libfftw3-dev libsndfile1-dev libsamplerate0-dev" + echo + fi +} + +# 安装Conan依赖 +install_dependencies() { + echo + echo -e "${BLUE}[Conan] 正在安装依赖包...${NC}" + echo -e "${BLUE}[Conan] 构建类型: $BUILD_TYPE${NC}" + echo -e "${BLUE}[Conan] C++标准: C++23${NC}" + echo + + # 创建build目录 + mkdir -p build + cd build + + # 执行Conan安装 + conan install .. \ + --output-folder=. \ + --build=missing \ + --settings=build_type="$BUILD_TYPE" \ + --settings=compiler.cppstd=23 + + echo + echo -e "${GREEN}[Conan] ✓ 依赖安装成功${NC}" + echo +} + +# 配置CMake项目 +configure_cmake() { + echo -e "${BLUE}[CMake] 正在配置项目...${NC}" + echo -e "${BLUE}[CMake] 构建类型: $BUILD_TYPE${NC}" + echo -e "${BLUE}[CMake] 生成器: $CMAKE_GENERATOR${NC}" + echo + + # 设置平台特定的选项 + CMAKE_ARGS=() + CMAKE_ARGS+=("-G" "$CMAKE_GENERATOR") + CMAKE_ARGS+=("-DCMAKE_BUILD_TYPE=$BUILD_TYPE") + CMAKE_ARGS+=("-DCMAKE_TOOLCHAIN_FILE=generators/conan_toolchain.cmake") + CMAKE_ARGS+=("-DDAW_ENABLE_SIMD=ON") + CMAKE_ARGS+=("-DDAW_ENABLE_TESTS=ON") + CMAKE_ARGS+=("-DDAW_ENABLE_EXAMPLES=ON") + + # 根据系统架构设置AVX512支持 + if [[ $(uname -m) == "x86_64" ]]; then + CMAKE_ARGS+=("-DDAW_ENABLE_AVX512=ON") + else + CMAKE_ARGS+=("-DDAW_ENABLE_AVX512=OFF") + fi + + # macOS特定配置 + if [[ "$OS" == "macOS" ]]; then + CMAKE_ARGS+=("-DCMAKE_OSX_DEPLOYMENT_TARGET=11.0") + fi + + # 执行CMake配置 + cmake .. "${CMAKE_ARGS[@]}" + + echo + echo -e "${GREEN}[CMake] ✓ 项目配置成功${NC}" + echo +} + +# 编译项目 +build_project() { + echo -e "${BLUE}[编译] 正在编译项目...${NC}" + echo -e "${BLUE}[编译] 配置: $BUILD_TYPE${NC}" + echo -e "${BLUE}[编译] 并行任务: $JOBS${NC}" + echo + + # 编译项目 + cmake --build . --config "$BUILD_TYPE" --parallel "$JOBS" + + echo + echo -e "${GREEN}[编译] ✓ 项目编译成功${NC}" + echo +} + +# 显示构建结果 +show_results() { + cd "$PROJECT_ROOT" + + echo + echo "========================================" + echo " 构建成功!" + echo "========================================" + echo "构建类型: $BUILD_TYPE" + echo "输出目录: $PROJECT_ROOT/build/bin" + echo "库目录: $PROJECT_ROOT/build/lib" + echo + echo "运行测试: cd build && ctest -C $BUILD_TYPE" + echo "安装项目: cd build && make install" + echo +} + +# 主函数 +main() { + cd "$PROJECT_ROOT" + + # 检测操作系统 + detect_os + + # 解析参数 + parse_args "$1" + + # 显示标题 + print_header + + # 处理清理 + if [ $CLEAN_BUILD -eq 1 ]; then + clean_build + fi + + # 检查工具 + check_tools + + # 检查系统依赖 + check_system_deps + + # 安装依赖 + install_dependencies + + # 配置项目 + configure_cmake + + # 编译项目 + build_project + + # 显示结果 + show_results +} + +# 执行主函数 +main "$@" \ No newline at end of file diff --git a/cmake/build_options.cmake b/cmake/build_options.cmake new file mode 100644 index 0000000..b439b35 --- /dev/null +++ b/cmake/build_options.cmake @@ -0,0 +1,103 @@ +# ================================================================================================ +# DAW Backend Framework - 构建选项配置模块 +# 描述: 定义所有项目构建选项,包括功能开关、插件支持和开发工具 +# ================================================================================================ + +# ================================================================================================ +# 构建类型配置 +# ================================================================================================ +function(configure_build_type) + if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Release" CACHE STRING + "Choose build type: Debug Release RelWithDebInfo MinSizeRel" FORCE) + message(STATUS "未指定构建类型,默认使用: Release") + endif() + + message(STATUS "当前构建类型: ${CMAKE_BUILD_TYPE}") +endfunction() + +# ================================================================================================ +# 功能选项定义 +# ================================================================================================ +function(define_feature_options) + # 功能选项 + option(DAW_ENABLE_TESTS "Enable building tests" ON) + option(DAW_ENABLE_EXAMPLES "Enable building examples" ON) + option(DAW_ENABLE_TOOLS "Enable building tools" ON) + option(DAW_ENABLE_BENCHMARKS "Enable building benchmarks" ON) + + # 插件支持选项 + option(DAW_ENABLE_VST2 "Enable VST2 plugin support" ON) + option(DAW_ENABLE_VST3 "Enable VST3 plugin support" ON) + option(DAW_ENABLE_CLAP "Enable CLAP plugin support" ON) + + # 系统特性选项 + option(DAW_ENABLE_SANDBOX "Enable plugin sandboxing" ON) + option(DAW_ENABLE_NETWORK "Enable network communication" ON) + option(DAW_ENABLE_SIMD "Enable SIMD optimizations" ON) + option(DAW_ENABLE_AVX512 "Enable AVX512 optimizations" ON) + option(DAW_ENABLE_PROFILING "Enable profiling support" OFF) + + # IPC系统选项 + option(ENABLE_ENHANCED_IPC "Enable enhanced IPC system (ZeroMQ + Shared Memory)" ON) + + # 开发选项 + option(DAW_ENABLE_ASAN "Enable AddressSanitizer" OFF) + option(DAW_ENABLE_TSAN "Enable ThreadSanitizer" OFF) + option(DAW_ENABLE_UBSAN "Enable UndefinedBehaviorSanitizer" OFF) + option(DAW_ENABLE_COVERAGE "Enable code coverage" OFF) + + # 将选项提升到父作用域 + set(DAW_ENABLE_TESTS ${DAW_ENABLE_TESTS} PARENT_SCOPE) + set(DAW_ENABLE_EXAMPLES ${DAW_ENABLE_EXAMPLES} PARENT_SCOPE) + set(DAW_ENABLE_TOOLS ${DAW_ENABLE_TOOLS} PARENT_SCOPE) + set(DAW_ENABLE_BENCHMARKS ${DAW_ENABLE_BENCHMARKS} PARENT_SCOPE) + set(DAW_ENABLE_VST2 ${DAW_ENABLE_VST2} PARENT_SCOPE) + set(DAW_ENABLE_VST3 ${DAW_ENABLE_VST3} PARENT_SCOPE) + set(DAW_ENABLE_CLAP ${DAW_ENABLE_CLAP} PARENT_SCOPE) + set(DAW_ENABLE_SANDBOX ${DAW_ENABLE_SANDBOX} PARENT_SCOPE) + set(DAW_ENABLE_NETWORK ${DAW_ENABLE_NETWORK} PARENT_SCOPE) + set(DAW_ENABLE_SIMD ${DAW_ENABLE_SIMD} PARENT_SCOPE) + set(DAW_ENABLE_AVX512 ${DAW_ENABLE_AVX512} PARENT_SCOPE) + set(DAW_ENABLE_PROFILING ${DAW_ENABLE_PROFILING} PARENT_SCOPE) + set(ENABLE_ENHANCED_IPC ${ENABLE_ENHANCED_IPC} PARENT_SCOPE) + set(DAW_ENABLE_ASAN ${DAW_ENABLE_ASAN} PARENT_SCOPE) + set(DAW_ENABLE_TSAN ${DAW_ENABLE_TSAN} PARENT_SCOPE) + set(DAW_ENABLE_UBSAN ${DAW_ENABLE_UBSAN} PARENT_SCOPE) + set(DAW_ENABLE_COVERAGE ${DAW_ENABLE_COVERAGE} PARENT_SCOPE) + + message(STATUS "构建选项配置完成") +endfunction() + +# ================================================================================================ +# 打印构建选项摘要 +# ================================================================================================ +function(print_build_options) + message(STATUS "") + message(STATUS "=== 功能选项 ===") + message(STATUS " 测试: ${DAW_ENABLE_TESTS}") + message(STATUS " 示例: ${DAW_ENABLE_EXAMPLES}") + message(STATUS " 工具: ${DAW_ENABLE_TOOLS}") + message(STATUS " 基准测试: ${DAW_ENABLE_BENCHMARKS}") + message(STATUS "") + message(STATUS "=== 插件支持 ===") + message(STATUS " VST2: ${DAW_ENABLE_VST2}") + message(STATUS " VST3: ${DAW_ENABLE_VST3}") + message(STATUS " CLAP: ${DAW_ENABLE_CLAP}") + message(STATUS "") + message(STATUS "=== 系统特性 ===") + message(STATUS " 沙盒: ${DAW_ENABLE_SANDBOX}") + message(STATUS " 网络: ${DAW_ENABLE_NETWORK}") + message(STATUS " SIMD优化: ${DAW_ENABLE_SIMD}") + message(STATUS " AVX512优化: ${DAW_ENABLE_AVX512}") + message(STATUS " 性能分析: ${DAW_ENABLE_PROFILING}") + message(STATUS "") + message(STATUS "=== IPC系统 ===") + message(STATUS " 增强型IPC: ${ENABLE_ENHANCED_IPC}") + message(STATUS "") + message(STATUS "=== 开发工具 ===") + message(STATUS " ASAN: ${DAW_ENABLE_ASAN}") + message(STATUS " TSAN: ${DAW_ENABLE_TSAN}") + message(STATUS " UBSAN: ${DAW_ENABLE_UBSAN}") + message(STATUS " 覆盖率: ${DAW_ENABLE_COVERAGE}") +endfunction() \ No newline at end of file diff --git a/cmake/compiler_options.cmake b/cmake/compiler_options.cmake new file mode 100644 index 0000000..3ba8b44 --- /dev/null +++ b/cmake/compiler_options.cmake @@ -0,0 +1,170 @@ +# ================================================================================================ +# DAW Backend Framework - 编译器选项配置模块 +# 描述: 配置编译器特定选项、警告级别和优化设置 +# ================================================================================================ + +# ================================================================================================ +# 配置编译器选项 +# ================================================================================================ +function(configure_compiler_options) + # 使用生成器表达式为多配置生成器(如Visual Studio)正确配置选项 + if(MSVC) + # Debug配置特定设置 + add_compile_options( + $<$:/Zi> # 调试信息 + $<$:/Od> # 禁用优化 + $<$:/RTC1> # 运行时检查 + $<$:/W4> # 严格警告 + ) + add_compile_definitions( + $<$:DAW_DEBUG_BUILD> + ) + + # Release配置特定设置 + add_compile_options( + $<$:/O2> # 最大优化 + $<$:/Ob2> # 内联展开 + $<$:/Zi> # 调试信息(用于调试Release版本) + ) + add_compile_definitions( + $<$:DAW_RELEASE_BUILD> + $<$:NDEBUG> + ) + + # RelWithDebInfo配置 + add_compile_options( + $<$:/O2> + $<$:/Ob1> + $<$:/Zi> + ) + add_compile_definitions( + $<$:DAW_RELEASE_BUILD> + $<$:NDEBUG> + ) + + # MinSizeRel配置 + add_compile_options( + $<$:/O1> + $<$:/Ob1> + $<$:/Zi> + ) + add_compile_definitions( + $<$:DAW_RELEASE_BUILD> + $<$:NDEBUG> + ) + + message(STATUS "MSVC编译器选项已配置,支持多配置生成器") + else() + # 非MSVC编译器的传统配置 + if(CMAKE_BUILD_TYPE STREQUAL "Debug") + add_compile_definitions(DAW_DEBUG_BUILD) + add_compile_options(-g -O0 -fno-omit-frame-pointer) + add_compile_options(-Wall -Wextra -Wpedantic) + message(STATUS "Debug模式: 启用调试符号,禁用优化,启用严格警告") + else() + add_compile_definitions(DAW_RELEASE_BUILD NDEBUG) + add_compile_options(-O3 -DNDEBUG -march=native) + message(STATUS "Release模式: 启用最高级别优化") + endif() + + # 启用更好的诊断信息 + if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") + add_compile_options(-fdiagnostics-color=always) + add_compile_options(-ftemplate-backtrace-limit=0) + message(STATUS "启用彩色诊断和完整模板回溯") + endif() + endif() +endfunction() + +# ================================================================================================ +# 配置SIMD优化(扩展AVX512支持) +# ================================================================================================ +function(configure_simd_optimizations) + if(DAW_ENABLE_SIMD) + if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64") + # 检测编译器支持 + include(CheckCXXCompilerFlag) + + # AVX2支持(保持现有) + if(MSVC) + check_cxx_compiler_flag("/arch:AVX2" COMPILER_SUPPORTS_AVX2) + if(COMPILER_SUPPORTS_AVX2) + add_compile_options(/arch:AVX2) + add_compile_definitions(DAW_ENABLE_AVX2) + message(STATUS "SIMD优化: 启用AVX2指令集") + endif() + else() + check_cxx_compiler_flag("-mavx2" COMPILER_SUPPORTS_AVX2) + if(COMPILER_SUPPORTS_AVX2) + add_compile_options(-mavx2 -mfma) + add_compile_definitions(DAW_ENABLE_AVX2) + message(STATUS "SIMD优化: 启用AVX2指令集") + endif() + endif() + + # AVX512支持(新增) + if(DAW_ENABLE_AVX512) + if(MSVC) + check_cxx_compiler_flag("/arch:AVX512" COMPILER_SUPPORTS_AVX512) + if(COMPILER_SUPPORTS_AVX512) + add_compile_options(/arch:AVX512) + add_compile_definitions(DAW_ENABLE_AVX512) + message(STATUS "SIMD优化: 启用AVX512指令集") + else() + message(WARNING "编译器不支持AVX512,降级到AVX2") + endif() + else() + check_cxx_compiler_flag("-mavx512f" COMPILER_SUPPORTS_AVX512F) + check_cxx_compiler_flag("-mavx512vl" COMPILER_SUPPORTS_AVX512VL) + check_cxx_compiler_flag("-mavx512bw" COMPILER_SUPPORTS_AVX512BW) + + if(COMPILER_SUPPORTS_AVX512F AND COMPILER_SUPPORTS_AVX512VL) + add_compile_options(-mavx512f -mavx512vl) + add_compile_definitions(DAW_ENABLE_AVX512) + + if(COMPILER_SUPPORTS_AVX512BW) + add_compile_options(-mavx512bw) + add_compile_definitions(DAW_ENABLE_AVX512BW) + endif() + + message(STATUS "SIMD优化: 启用AVX512指令集") + else() + message(WARNING "编译器不支持完整AVX512,降级到AVX2") + endif() + endif() + endif() + elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm|aarch64|ARM64") + # ARM平台:检测NEON支持 + include(CheckCXXCompilerFlag) + + if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|ARM64") + # AArch64: NEON默认可用 + add_compile_definitions(DAW_ENABLE_NEON) + message(STATUS "SIMD优化: 启用ARM64 NEON指令集") + else() + # ARM32: 检测NEON支持 + check_cxx_compiler_flag("-mfpu=neon" COMPILER_SUPPORTS_NEON) + if(COMPILER_SUPPORTS_NEON) + add_compile_options(-mfpu=neon) + add_compile_definitions(DAW_ENABLE_NEON) + message(STATUS "SIMD优化: 启用ARM32 NEON指令集") + else() + message(STATUS "SIMD优化: ARM32平台不支持NEON") + endif() + endif() + else() + message(STATUS "SIMD优化: 当前架构(${CMAKE_SYSTEM_PROCESSOR})不支持SIMD优化") + endif() + else() + message(STATUS "SIMD优化: 已禁用") + endif() +endfunction() + +# ================================================================================================ +# 应用编译器配置 +# ================================================================================================ +function(apply_compiler_configuration) + configure_compiler_options() + configure_simd_optimizations() + message(STATUS "编译器配置完成") +endfunction() \ No newline at end of file diff --git a/cmake/config_macos.cmake b/cmake/config_macos.cmake new file mode 100644 index 0000000..f5b4e21 --- /dev/null +++ b/cmake/config_macos.cmake @@ -0,0 +1,41 @@ + +# 如果是Macos +if (APPLE) + # 获取 Homebrew 安装的 libomp 路径 + execute_process( + COMMAND brew --prefix libomp + OUTPUT_VARIABLE HOMEBREW_LIBOMP_PATH + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + # 设置 OpenMP 路径变量 + set(OpenMP_CXX_FLAGS "-Xpreprocessor -fopenmp -I${HOMEBREW_LIBOMP_PATH}/include") + set(OpenMP_CXX_LIB_NAMES "omp") + set(OpenMP_omp_LIBRARY "${HOMEBREW_LIBOMP_PATH}/lib/libomp.dylib") + enable_language(OBJC OBJCXX) + + # ============================================================================================ + # Apple Accelerate框架支持 (包含AMX向量指令集) + # ============================================================================================ + # 检测是否为Apple Silicon (ARM64) + if(CMAKE_SYSTEM_PROCESSOR MATCHES "arm64|aarch64") + message(STATUS "Detected Apple Silicon (${CMAKE_SYSTEM_PROCESSOR})") + + # 查找Accelerate框架(macOS系统自带) + find_library(ACCELERATE_FRAMEWORK Accelerate) + if(ACCELERATE_FRAMEWORK) + message(STATUS "Found Accelerate framework: ${ACCELERATE_FRAMEWORK}") + # 设置全局变量供其他模块使用 + set(APPLE_ACCELERATE_LIBRARY ${ACCELERATE_FRAMEWORK} PARENT_SCOPE) + set(HAS_ACCELERATE TRUE PARENT_SCOPE) + # 启用Accelerate编译选项 + add_compile_definitions(DAW_ENABLE_ACCELERATE) + else() + message(WARNING "Accelerate framework not found on macOS") + set(HAS_ACCELERATE FALSE PARENT_SCOPE) + endif() + else() + message(STATUS "Not Apple Silicon, Accelerate framework disabled") + set(HAS_ACCELERATE FALSE PARENT_SCOPE) + endif() +endif () diff --git a/cmake/dependencies.cmake b/cmake/dependencies.cmake new file mode 100644 index 0000000..628a653 --- /dev/null +++ b/cmake/dependencies.cmake @@ -0,0 +1,147 @@ +# ================================================================================================ +# DAW Backend Framework - 依赖项管理模块 +# 描述: 管理项目的系统依赖、第三方库和平台特定依赖 +# ================================================================================================ + +# ================================================================================================ +# 查找系统依赖 +# ================================================================================================ +function(find_system_dependencies) + # 查找线程库(必需) + find_package(Threads REQUIRED) + if(Threads_FOUND) + message(STATUS "找到Threads库") + endif() + + # 设置全局变量供外部使用 + set(THREADS_LIB Threads::Threads PARENT_SCOPE) +endfunction() + +# ================================================================================================ +# 配置Conan依赖管理 +# ================================================================================================ +function(configure_conan_dependencies) + # 检查是否使用CMakeDeps (Conan 2.x风格) + if(EXISTS ${CMAKE_BINARY_DIR}/generators/conan_toolchain.cmake) + message(STATUS "使用Conan 2.x CMakeDeps") + set(USING_CONAN TRUE PARENT_SCOPE) + + # 设置CMAKE_PREFIX_PATH以便CMake可以找到Conan生成的包配置文件 + list(APPEND CMAKE_PREFIX_PATH ${CMAKE_BINARY_DIR}/generators) + set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} PARENT_SCOPE) + + # 查找核心必需的Conan包 + find_package(spdlog REQUIRED) + find_package(fmt REQUIRED) + find_package(nlohmann_json REQUIRED) + find_package(GTest REQUIRED) + find_package(Boost REQUIRED) + find_package(Eigen3 REQUIRED) + find_package(Protobuf REQUIRED) + find_package(TBB REQUIRED) + find_package(ZeroMQ REQUIRED) + find_package(cppzmq REQUIRED) + if(NOT TARGET TBB::tbb) + find_package(oneTBB REQUIRED) + endif() + + # Boost组件 - 增强型IPC需要 + find_package(Boost REQUIRED COMPONENTS + system + interprocess + circular_buffer + filesystem + thread + chrono + atomic + date_time) + + # 查找可选的Conan包 + find_package(yaml-cpp QUIET) + find_package(benchmark QUIET) + + message(STATUS "Conan依赖配置完成:") + message(STATUS " - spdlog: ${spdlog_VERSION}") + message(STATUS " - fmt: ${fmt_VERSION}") + message(STATUS " - nlohmann_json: ${nlohmann_json_VERSION}") + message(STATUS " - GTest: 已配置") + message(STATUS " - Boost: ${Boost_VERSION}") + message(STATUS " - Eigen3: ${Eigen3_VERSION}") + message(STATUS " - Protobuf: ${Protobuf_VERSION}") + message(STATUS " - TBB/oneTBB: ${TBB_VERSION}") + message(STATUS " - ZeroMQ: ${zeroMQ_VERSION}") + message(STATUS " - cppzmq: ${cppzmq_VERSION}") + + if(TARGET yaml-cpp::yaml-cpp) + message(STATUS " - yaml-cpp: 已找到") + endif() + + if(TARGET benchmark::benchmark) + message(STATUS " - benchmark: 已找到") + endif() + + # 检查是否使用Conan 1.x风格 + elseif(EXISTS ${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) + include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) + conan_basic_setup(TARGETS) + message(STATUS "使用Conan 1.x依赖管理") + set(USING_CONAN TRUE PARENT_SCOPE) + else() + message(STATUS "未检测到Conan,将使用系统依赖") + set(USING_CONAN FALSE PARENT_SCOPE) + endif() +endfunction() + +# ================================================================================================ +# 配置平台特定依赖 +# ================================================================================================ +function(configure_platform_dependencies) + if(WIN32) + # Windows平台依赖 + set(PLATFORM_LIBS wsock32 ws2_32 winmm) + message(STATUS "Windows平台: 添加wsock32, ws2_32, winmm库") + + elseif(APPLE) + # macOS平台依赖 + find_library(COREFOUNDATION_LIBRARY CoreFoundation) + find_library(COREAUDIO_LIBRARY CoreAudio QUIET) + + set(PLATFORM_LIBS ${COREFOUNDATION_LIBRARY}) + if(COREAUDIO_LIBRARY) + list(APPEND PLATFORM_LIBS ${COREAUDIO_LIBRARY}) + message(STATUS "macOS平台: 找到CoreFoundation和CoreAudio框架") + else() + message(STATUS "macOS平台: 找到CoreFoundation框架") + endif() + + else() + # Linux平台依赖 + set(PLATFORM_LIBS ${CMAKE_DL_LIBS}) + message(STATUS "Linux平台: 添加动态链接库支持") + endif() + + # 将平台库设置为全局变量 + set(PLATFORM_LIBS ${PLATFORM_LIBS} PARENT_SCOPE) +endfunction() + +# ================================================================================================ +# 配置所有依赖项 +# ================================================================================================ +function(setup_all_dependencies) + message(STATUS "") + message(STATUS "=== 配置依赖项 ===") + + # 查找系统依赖 + find_system_dependencies() + set(THREADS_LIB ${THREADS_LIB} PARENT_SCOPE) + + # 配置Conan + configure_conan_dependencies() + set(USING_CONAN ${USING_CONAN} PARENT_SCOPE) + + # 配置平台特定依赖 + configure_platform_dependencies() + set(PLATFORM_LIBS ${PLATFORM_LIBS} PARENT_SCOPE) + + message(STATUS "依赖项配置完成") +endfunction() \ No newline at end of file diff --git a/cmake/detect_os.cmake b/cmake/detect_os.cmake new file mode 100644 index 0000000..33e49ae --- /dev/null +++ b/cmake/detect_os.cmake @@ -0,0 +1,161 @@ + +# 定义一个函数,为指定的目标添加操作系统和架构相关的预处理器定义 +function(add_os_definitions target) + # 检查 target 参数是否提供 + if(NOT target) + message(FATAL_ERROR "函数 add_os_definitions 需要一个 target 参数。") + return() + endif() + + # --- 阶段 1: 确定宏的值 --- + + # 初始化所有平台、架构和特性宏的值为 0 + set(alicho_def_windows 0) + set(alicho_def_macos 0) + set(alicho_def_linux 0) + set(alicho_def_freebsd 0) + set(alicho_def_ios 0) + set(alicho_def_android 0) + set(alicho_def_cygwin 0) + set(alicho_def_unix 0) + set(alicho_def_posix 0) + set(alicho_def_mobile 0) + set(alicho_def_arch_64bit 0) + set(alicho_def_arch_32bit 0) + set(alicho_def_x86 0) + set(alicho_def_arm 0) + set(alicho_def_riscv 0) + set(alicho_def_apple 0) # 用于 iOS 和 macOS 的通用定义 + set(alicho_def_debug 0) # 当前是否处于调试模式 + + if (CMAKE_BUILD_TYPE STREQUAL "Debug") + set(alicho_def_debug 1) + endif () + + # -- 操作系统检测与赋值 -- + # 注意检测顺序:优先检测更具体的平台 + if(CYGWIN) + # Cygwin 环境比较特殊,它在 Windows 上模拟 Unix + set(alicho_def_windows 1) # 基础是 Windows + set(alicho_def_cygwin 1) # 明确是 Cygwin + set(alicho_def_unix 1) # 提供 Unix API + set(alicho_def_posix 1) # 提供 POSIX API + message(STATUS "检测到 **Cygwin** 环境 (运行于 Windows)") + elseif(WIN32) + # 非 Cygwin 的 Windows 环境 (MSVC, MinGW, etc.) + set(alicho_def_windows 1) + message(STATUS "检测到 **Windows** 操作系统 (非 Cygwin)") + elseif(ANDROID) + # Android 平台 (通常需要特定工具链设置 ANDROID 变量) + set(alicho_def_android 1) + set(alicho_def_unix 1) # Android NDK 基于 Unix + set(alicho_def_posix 1) # NDK 提供 POSIX API + set(alicho_def_mobile 1) # 移动平台 + message(STATUS "检测到 **Android** 操作系统") + elseif(IOS) + # iOS 平台 (通常需要特定工具链设置 IOS 变量) + # 需要在 APPLE 之前判断,因为 iOS 下 APPLE 也为 TRUE + set(alicho_def_ios 1) + set(alicho_def_unix 1) # iOS (Darwin) 基于 Unix + set(alicho_def_posix 1) # 提供 POSIX API + set(alicho_def_mobile 1) # 移动平台 + set(alicho_def_apple 1) # iOS 是 Apple 生态的一部分 + message(STATUS "检测到 **iOS** 操作系统") + elseif(APPLE) + # 此时排除了 iOS,确定是 macOS + set(alicho_def_macos 1) + set(alicho_def_unix 1) # macOS (Darwin) 基于 Unix + set(alicho_def_posix 1) # 提供 POSIX API + set(alicho_def_apple 1) # macOS 是 Apple 生态的一部分 + message(STATUS "检测到 **macOS** 操作系统") + elseif(UNIX) + # 此时排除了 Apple, Android, Cygwin 的其他 Unix-like 系统 + set(alicho_def_unix 1) + set(alicho_def_posix 1) + if(CMAKE_SYSTEM_NAME MATCHES "Linux") + set(alicho_def_linux 1) + message(STATUS "检测到 **Linux** 操作系统") + elseif(CMAKE_SYSTEM_NAME MATCHES "FreeBSD") + set(alicho_def_freebsd 1) + message(STATUS "检测到 **FreeBSD** 操作系统") + else() + message(WARNING "检测到未知的 类Unix 操作系统: ${CMAKE_SYSTEM_NAME}") + endif() + else() + message(WARNING "检测到未知的操作系统: ${CMAKE_SYSTEM_NAME}") + endif() + + # -- 架构检测与赋值 -- + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(alicho_def_arch_64bit 1) + set(alicho_def_arch_32bit 0) # 明确设置为 0 + message(STATUS "检测到 **64-bit** 架构") + elseif(CMAKE_SIZEOF_VOID_P EQUAL 4) + set(alicho_def_arch_64bit 0) # 明确设置为 0 + set(alicho_def_arch_32bit 1) + message(STATUS "检测到 **32-bit** 架构") + else() + # 对于未知或未定义的指针大小,两者都保持 0 + message(WARNING "无法明确检测到 32-bit 或 64-bit 架构 (CMAKE_SIZEOF_VOID_P = ${CMAKE_SIZEOF_VOID_P})。将两者都设置为 0。") + endif() + + # 检测特定架构类型 + if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86|i386|i486|i586|i686|i786|x86_64|AMD64") + set(alicho_def_x86 1) + message(STATUS "检测到 **x86/x64** 架构") + elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm|aarch64|ARM64") + set(alicho_def_arm 1) + message(STATUS "检测到 **ARM** 架构") + elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "riscv|riscv64|riscv32") + set(alicho_def_riscv 1) + message(STATUS "检测到 **RISC-V** 架构") + else() + + # --- 阶段 2: 组装定义列表 --- + set(definitions_list "") # 初始化空列表 + + # 添加平台定义 + list(APPEND definitions_list "ALICHO_PLATFORM_WINDOWS=${alicho_def_windows}") + list(APPEND definitions_list "ALICHO_PLATFORM_MACOS=${alicho_def_macos}") + list(APPEND definitions_list "ALICHO_PLATFORM_LINUX=${alicho_def_linux}") + list(APPEND definitions_list "ALICHO_PLATFORM_FREEBSD=${alicho_def_freebsd}") + list(APPEND definitions_list "ALICHO_PLATFORM_IOS=${alicho_def_ios}") + list(APPEND definitions_list "ALICHO_PLATFORM_ANDROID=${alicho_def_android}") + list(APPEND definitions_list "ALICHO_PLATFORM_CYGWIN=${alicho_def_cygwin}") + list(APPEND definitions_list "ALICHO_PLATFORM_APPLE=${alicho_def_apple}") # 用于 iOS 和 macOS 的通用定义 + + # 添加架构定义 + list(APPEND definitions_list "ALICHO_PLATFORM_ARCH_64BIT=${alicho_def_arch_64bit}") + list(APPEND definitions_list "ALICHO_PLATFORM_ARCH_32BIT=${alicho_def_arch_32bit}") + + # 添加特性定义 + list(APPEND definitions_list "ALICHO_PLATFORM_UNIX=${alicho_def_unix}") + list(APPEND definitions_list "ALICHO_PLATFORM_POSIX=${alicho_def_posix}") + list(APPEND definitions_list "ALICHO_PLATFORM_IS_MOBILE=${alicho_def_mobile}") + + list(APPEND definitions_list "ALICHO_DEBUG=${alicho_def_debug}") # 当前是否处于调试模式 + + list(APPEND definitions_list "ALICHO_PLATFORM_X86=${alicho_def_x86}") + list(APPEND definitions_list "ALICHO_PLATFORM_ARM=${alicho_def_arm}") + list(APPEND definitions_list "ALICHO_PLATFORM_RISCV=${alicho_def_riscv}") + + # --- 阶段 3: 应用所有定义 --- + # **关键:使用一次调用将所有定义添加到目标** + if(definitions_list) # 确保列表非空 + target_compile_definitions(${target} PUBLIC ${definitions_list}) + endif() + + # 函数作用域结束时,alicho_def_* 变量会自动销毁,无需显式 unset + +endfunction() + +# --- 使用示例 --- +# project(MyProject) +# add_executable(my_app main.c) +# +# # 调用函数为 my_app 添加平台定义 +# add_os_definitions(my_app) +# +# # 你也可以为库调用 +# # add_library(my_lib STATIC my_lib.c) +# # add_os_definitions(my_lib) diff --git a/cmake/install_config.cmake b/cmake/install_config.cmake new file mode 100644 index 0000000..3673bd6 --- /dev/null +++ b/cmake/install_config.cmake @@ -0,0 +1,110 @@ +# ================================================================================================ +# DAW Backend Framework - 安装和打包配置模块 +# 描述: 配置项目的安装规则和跨平台打包 +# ================================================================================================ + +# ================================================================================================ +# 配置安装规则 +# ================================================================================================ +function(configure_install_rules) + include(GNUInstallDirs) + + # 安装头文件 + install(DIRECTORY ${CMAKE_SOURCE_DIR}/include/ + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + FILES_MATCHING PATTERN "*.h" PATTERN "*.hpp") + + message(STATUS "安装规则: 头文件将安装到 ${CMAKE_INSTALL_INCLUDEDIR}") + + # 安装配置文件(如果存在) + if(EXISTS ${CMAKE_SOURCE_DIR}/config) + install(DIRECTORY ${CMAKE_SOURCE_DIR}/config/ + DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/daw-backend) + message(STATUS "安装规则: 配置文件将安装到 ${CMAKE_INSTALL_SYSCONFDIR}/daw-backend") + endif() + + # 安装文档 + set(DOC_FILES + README.md + architecture_design.md + pattern_system_design.md + ) + + foreach(DOC_FILE ${DOC_FILES}) + if(EXISTS ${CMAKE_SOURCE_DIR}/${DOC_FILE}) + install(FILES ${CMAKE_SOURCE_DIR}/${DOC_FILE} + DESTINATION ${CMAKE_INSTALL_DOCDIR}) + endif() + endforeach() + + message(STATUS "安装规则: 文档将安装到 ${CMAKE_INSTALL_DOCDIR}") +endfunction() + +# ================================================================================================ +# 配置CPack打包 +# ================================================================================================ +function(configure_cpack) + # 基础包信息 + set(CPACK_PACKAGE_NAME "DAWBackend" PARENT_SCOPE) + set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION} PARENT_SCOPE) + set(CPACK_PACKAGE_DESCRIPTION ${PROJECT_DESCRIPTION} PARENT_SCOPE) + set(CPACK_PACKAGE_CONTACT "daw-backend@example.com" PARENT_SCOPE) + set(CPACK_PACKAGE_VENDOR "DAW Backend Team" PARENT_SCOPE) + + # 平台特定打包器 + if(WIN32) + set(CPACK_GENERATOR "NSIS;ZIP" PARENT_SCOPE) + set(CPACK_NSIS_DISPLAY_NAME "DAW Backend Framework" PARENT_SCOPE) + set(CPACK_NSIS_PACKAGE_NAME "DAWBackend" PARENT_SCOPE) + message(STATUS "打包配置: Windows (NSIS + ZIP)") + + elseif(APPLE) + set(CPACK_GENERATOR "DragNDrop;TGZ" PARENT_SCOPE) + set(CPACK_DMG_VOLUME_NAME "DAW Backend" PARENT_SCOPE) + message(STATUS "打包配置: macOS (DragNDrop + TGZ)") + + else() + # Linux + set(CPACK_GENERATOR "DEB;RPM;TGZ" PARENT_SCOPE) + set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6, libstdc++6" PARENT_SCOPE) + set(CPACK_RPM_PACKAGE_REQUIRES "glibc, libstdc++" PARENT_SCOPE) + message(STATUS "打包配置: Linux (DEB + RPM + TGZ)") + endif() +endfunction() + +# ================================================================================================ +# 应用安装和打包配置 +# ================================================================================================ +function(setup_install_and_packaging) + message(STATUS "") + message(STATUS "=== 配置安装和打包 ===") + + # 配置安装规则 + configure_install_rules() + + # 配置CPack + configure_cpack() + + # 导出CPack设置到父作用域 + set(CPACK_PACKAGE_NAME ${CPACK_PACKAGE_NAME} PARENT_SCOPE) + set(CPACK_PACKAGE_VERSION ${CPACK_PACKAGE_VERSION} PARENT_SCOPE) + set(CPACK_PACKAGE_DESCRIPTION ${CPACK_PACKAGE_DESCRIPTION} PARENT_SCOPE) + set(CPACK_PACKAGE_CONTACT ${CPACK_PACKAGE_CONTACT} PARENT_SCOPE) + set(CPACK_PACKAGE_VENDOR ${CPACK_PACKAGE_VENDOR} PARENT_SCOPE) + set(CPACK_GENERATOR ${CPACK_GENERATOR} PARENT_SCOPE) + + if(WIN32) + set(CPACK_NSIS_DISPLAY_NAME ${CPACK_NSIS_DISPLAY_NAME} PARENT_SCOPE) + set(CPACK_NSIS_PACKAGE_NAME ${CPACK_NSIS_PACKAGE_NAME} PARENT_SCOPE) + elseif(APPLE) + set(CPACK_DMG_VOLUME_NAME ${CPACK_DMG_VOLUME_NAME} PARENT_SCOPE) + else() + set(CPACK_DEBIAN_PACKAGE_DEPENDS ${CPACK_DEBIAN_PACKAGE_DEPENDS} PARENT_SCOPE) + set(CPACK_RPM_PACKAGE_REQUIRES ${CPACK_RPM_PACKAGE_REQUIRES} PARENT_SCOPE) + endif() + + # 包含CPack模块 + include(CPack) + + message(STATUS "安装和打包配置完成") +endfunction() \ No newline at end of file diff --git a/cmake/mingw_dll.cmake b/cmake/mingw_dll.cmake new file mode 100644 index 0000000..da09762 --- /dev/null +++ b/cmake/mingw_dll.cmake @@ -0,0 +1,41 @@ + +function(auto_copy_mingw_dll target) + if(MINGW) + # 获取MinGW目录 + get_filename_component(MINGW_DIR ${CMAKE_CXX_COMPILER} PATH) + + # 根据你的环境调整DLL列表 + set(MINGW_DLLS + "libstdc++-6.dll" +# "libgcc_s_dw2-1.dll" + "libgcc_s_seh-1.dll" + "libwinpthread-1.dll" + "libbz2-1.dll" + "libbrotlidec.dll" + "libbrotlicommon.dll" + "libharfbuzz-0.dll" + "libpng16-16.dll" + "zlib1.dll" + "libglib-2.0-0.dll" + "libfreetype-6.dll" + "libgraphite2.dll" + "libintl-8.dll" + "libpcre2-8-0.dll" + "libiconv-2.dll" + ) + + foreach(DLL ${MINGW_DLLS}) + # 检查文件是否存在 + if(EXISTS "${MINGW_DIR}/${DLL}") + add_custom_command(TARGET ${target} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${MINGW_DIR}/${DLL}" + "$" + COMMENT "Copying ${DLL} to output directory" + VERBATIM) + else() + message(WARNING "DLL not found: ${MINGW_DIR}/${DLL}") + endif() + endforeach() + endif() +endfunction() \ No newline at end of file diff --git a/cmake/mirage_utils.cmake b/cmake/mirage_utils.cmake new file mode 100644 index 0000000..4a4b4bb --- /dev/null +++ b/cmake/mirage_utils.cmake @@ -0,0 +1,44 @@ + +# 定义一个函数来配置项目的默认设置 +# 这包括设置输出目录和项目根目录变量 +function(configure_project_defaults) + # 检查是否在顶层 CMakeLists.txt 中调用 (可选但推荐) + # 确保 CMAKE_SOURCE_DIR 和 CMAKE_CURRENT_SOURCE_DIR 相同 + if(NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) + message(WARNING "configure_project_defaults() 应该在项目的根 CMakeLists.txt 中调用。") + # 如果您确实需要在子目录中设置不同的根目录,请调整此逻辑 + endif() + + # --- 配置输出目录 --- + # 使用 CMAKE_BINARY_DIR 作为基础构建目录 + # ${CMAKE_BINARY_DIR} 指向您配置 CMake 时指定的构建目录 + # 例如,在 CLion 中通常是 cmake-build-debug 或 cmake-build-release + # 如果手动运行 cmake ..,它就是您运行 cmake 命令的目录 + + # **设置可执行文件输出路径**: + # 对于单配置生成器 (如 Makefiles, Ninja), 可执行文件将位于 /bin/ + # 对于多配置生成器 (如 Visual Studio, Xcode), CMake 通常会自动在此路径下附加配置名称 + # (例如 /bin/Debug/, /bin/Release/) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin CACHE PATH "Directory for runtime executables") + message(STATUS "运行时输出目录设置为: ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}") + + # **设置库文件输出路径 (共享库和静态库)**: + # 规则同上,库文件将位于 /lib/ 或 /lib// + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib CACHE PATH "Directory for shared libraries") + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib CACHE PATH "Directory for static libraries") + message(STATUS "库输出目录设置为: ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}") + message(STATUS "存档输出目录设置为: ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}") + + # --- 提示 --- + # 这种全局设置输出目录的方法对于中小型项目是常见的。 + # 对于更复杂的项目或需要更细粒度控制的情况,可以考虑为每个目标(target)单独设置输出目录属性: + # 例如: + # add_executable(my_app main.cpp) + # set_target_properties(my_app PROPERTIES + # RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/executables" + # ) + # add_library(my_lib STATIC my_lib.cpp) + # set_target_properties(my_lib PROPERTIES + # ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/static_libs" + # ) +endfunction() \ No newline at end of file diff --git a/cmake/project_cpp_standard.cmake b/cmake/project_cpp_standard.cmake new file mode 100644 index 0000000..79f6401 --- /dev/null +++ b/cmake/project_cpp_standard.cmake @@ -0,0 +1,138 @@ +# 文件: cmake/CompilerSetup.cmake + +# ============================================================================== +# 函数:setup_project_options +# 描述:配置项目级的 C++ 标准、编译器警告、定义和依赖。 +# 此函数遵循现代 CMake 实践,将所有配置封装到一个 INTERFACE 库中。 +# +# 参数: +# standard - (必选) C++ 标准版本 (例如 17, 20, 23)。 +# INTERFACE_TARGET - (必选) 用于接收创建的 INTERFACE 库名称的变量名。 +# +# 用法: +# include(cmake/CompilerSetup.cmake) +# setup_project_options( +# STANDARD 20 +# INTERFACE_TARGET my_project_options +# ) +# # ... 定义你的可执行文件或库 +# add_executable(my_app main.cpp) +# # ... 将配置应用到目标上 +# target_link_libraries(my_app PRIVATE ${my_project_options}) +# ============================================================================== +function(setup_project_options) + # --- 参数解析 --- + set(options "") # 无单值选项 + set(oneValueArgs STANDARD INTERFACE_TARGET) # 定义接收单个值的参数 + set(multiValueArgs "") # 无多值选项 + cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + # --- 参数验证 --- + if(NOT ARG_STANDARD OR NOT ARG_INTERFACE_TARGET) + message(FATAL_ERROR "setup_project_options 必须提供 STANDARD 和 INTERFACE_TARGET 参数。") + endif() + + set(VALID_STANDARDS 11 14 17 20 23) + list(FIND VALID_STANDARDS ${ARG_STANDARD} _standard_index) + if(_standard_index EQUAL -1) + message(FATAL_ERROR "不支持的 C++ 标准: ${ARG_STANDARD}。有效值: ${VALID_STANDARDS}") + endif() + + # --- 创建 INTERFACE 库 --- + # 这是现代 CMake 的核心:创建一个虚拟目标来承载所有配置属性。 + add_library(${ARG_INTERFACE_TARGET} INTERFACE) + message(STATUS "创建配置接口库: ${ARG_INTERFACE_TARGET}") + + # --- 设置 C++ 标准 (应用到接口库) --- + target_compile_features(${ARG_INTERFACE_TARGET} INTERFACE cxx_std_${ARG_STANDARD}) + + # --- 设置通用编译定义和选项 --- + # 使用 target_compile_definitions 和 target_compile_options,并指定 INTERFACE + # 这样任何链接到此库的目标都会继承这些属性。 + + # --- 平台特定设置 --- + if(WIN32) + target_compile_definitions(${ARG_INTERFACE_TARGET} INTERFACE UNICODE _UNICODE) + message(STATUS "为 Windows 添加 UNICODE 定义") + endif() + + # --- 编译器特定设置 --- + if(MSVC) + # MSVC 特定选项 + target_compile_options(${ARG_INTERFACE_TARGET} INTERFACE + /W4 # 更高警告等级 + # /WX # 将警告视为错误 (可选,但推荐) + /EHsc + /utf-8 # 源码和执行字符集设为 UTF-8 + /Zc:__cplusplus # 修正 __cplusplus 宏 + /wd4100 # 禁用警告: 未使用的形参 + /wd4996 # 禁用警告: 使用了被标记为否决的函数 + ) + message(STATUS "为 MSVC 添加特定编译选项") + else() # GCC / Clang / AppleClang + # 通用于 GCC 和 Clang 的选项 + target_compile_options(${ARG_INTERFACE_TARGET} INTERFACE + -Wall + -Wextra + -Wpedantic # 更加严格的警告 + -Werror # 将所有警告视为错误 (可选,但推荐) + -Wno-unused-parameter + ) + + # C++17 及以上标准的额外警告 + if(${ARG_STANDARD} GREATER_EQUAL 17) + target_compile_options(${ARG_INTERFACE_TARGET} INTERFACE + -Wshadow + -Wnon-virtual-dtor + ) + endif() + + # 【核心修复】区分处理 AppleClang 和标准 Clang/GCC + # AppleClang 不支持 -finput-charset/-fexec-charset,并默认源码为 UTF-8 + if(NOT CMAKE_CXX_COMPILER_ID MATCHES "AppleClang") + target_compile_options(${ARG_INTERFACE_TARGET} INTERFACE + -finput-charset=UTF-8 + -fexec-charset=UTF-8 + ) + message(STATUS "为 GCC/Clang 添加 UTF-8 字符集选项") + else() + message(STATUS "检测到 AppleClang,源码假定为 UTF-8,跳过字符集选项") + endif() + message(STATUS "为 GCC/Clang 添加特定编译选项") + endif() + + # --- MinGW 特定设置 --- + if(MINGW) + # 为 C++17 及以上的 支持添加链接库 + if(${ARG_STANDARD} GREATER_EQUAL 17) + # 使用 target_link_libraries,这才是正确的方式 + target_link_libraries(${ARG_INTERFACE_TARGET} INTERFACE -lstdc++fs) + message(STATUS "为 MinGW C++${ARG_STANDARD} 添加 libstdc++fs 依赖 (用于 )") + endif() + endif() + + # --- 将 INTERFACE 库的名称返回给调用者 --- + set(${ARG_INTERFACE_TARGET} ${ARG_INTERFACE_TARGET} PARENT_SCOPE) + message(STATUS "C++${ARG_STANDARD} 项目配置完成,请链接到 ${ARG_INTERFACE_TARGET} 目标。") + +endfunction() + +# ============================================================================== +# 函数:set_cpp_standard +# 描述:设置全局 C++ 标准的简化包装函数 +# 参数: +# standard - (必选) C++ 标准版本 (例如 17, 20, 23) +# ============================================================================== +function(set_cpp_standard standard) + set(VALID_STANDARDS 11 14 17 20 23) + list(FIND VALID_STANDARDS ${standard} _standard_index) + if(_standard_index EQUAL -1) + message(FATAL_ERROR "不支持的 C++ 标准: ${standard}。有效值: ${VALID_STANDARDS}") + endif() + + set(CMAKE_CXX_STANDARD ${standard} PARENT_SCOPE) + set(CMAKE_CXX_STANDARD_REQUIRED ON PARENT_SCOPE) + set(CMAKE_CXX_EXTENSIONS OFF PARENT_SCOPE) + + message(STATUS "设置 C++ 标准为 C++${standard}") +endfunction() \ No newline at end of file diff --git a/cmake/retrieve_files.cmake b/cmake/retrieve_files.cmake new file mode 100644 index 0000000..b915b84 --- /dev/null +++ b/cmake/retrieve_files.cmake @@ -0,0 +1,545 @@ +#[=======================================================================[ + 平台匹配检查函数 + 参数: + platform: 平台标识符 (windows|linux|mac|mobile|desktop) + is_match: 输出变量,表示当前平台是否匹配 +#]=======================================================================] +function(is_current_platform platform is_match) + # 设置默认值为TRUE(用于未知平台) + set(matches FALSE) + + if(platform STREQUAL "windows") + if(WIN32 OR CYGWIN) + set(matches TRUE) + endif() + elseif(platform STREQUAL "linux") + if(UNIX AND NOT APPLE) + set(matches TRUE) + endif() + elseif(platform STREQUAL "macos") + if(APPLE AND NOT IOS) + set(matches TRUE) + endif() + elseif(platform STREQUAL "ios") + if(IOS) + set(matches TRUE) + endif() + elseif(platform STREQUAL "android") + if(ANDROID) + set(matches TRUE) + endif() + # 添加对unix平台的支持 + elseif(platform STREQUAL "unix") + if(UNIX) + set(matches TRUE) + endif() + elseif(platform STREQUAL "mobile") + if(ANDROID OR IOS) + set(matches TRUE) + endif() + elseif(platform STREQUAL "desktop") + if(WIN32 OR (UNIX AND NOT APPLE) OR (APPLE AND NOT IOS)) + set(matches TRUE) + endif() + elseif(platform STREQUAL "web") + if(EMSCRIPTEN) + set(matches TRUE) + endif() + else() + # 未知平台标识,默认匹配 + set(matches TRUE) + endif() + + set(${is_match} ${matches} PARENT_SCOPE) +endfunction() + +#[=======================================================================[ + 主文件检索函数 + 参数: + path: 要检索的根目录路径 + extension: 文件扩展名列表 + out_files: 输出变量名,将包含筛选后的文件列表 +#]=======================================================================] +function(retrieve_files_custom path extension out_files) + # 1. 参数验证 + if(NOT IS_DIRECTORY "${path}") + message(WARNING "错误:目录 '${path}' 不存在") + return() + endif() + + message(STATUS "正在检索目录: ${path}") + + # 2. 构建文件匹配模式 + set(file_patterns "") + foreach(ext IN LISTS extension) + list(APPEND file_patterns "${path}/*.${ext}") + endforeach() + + # 3. 递归查找所有匹配的文件 + file(GLOB_RECURSE found_files + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + CONFIGURE_DEPENDS ${file_patterns} + ) + + # 4. 处理找到的文件 + set(filtered_files "") + foreach(current_file IN LISTS found_files) + # 4.1 获取文件所在目录 + get_filename_component(file_dir "${current_file}" DIRECTORY) + string(REPLACE "/" ";" dir_components "${file_dir}") + + # 4.2 检查平台兼容性 + set(should_skip_file FALSE) + set(found_platform_dir FALSE) + + foreach(dir_name IN LISTS dir_components) + # 检查是否是平台相关目录 + if(dir_name MATCHES "^(windows|linux|mac|ios|android|unix|mobile|desktop|web)$") + set(found_platform_dir TRUE) + is_current_platform(${dir_name} platform_matches) + if(NOT platform_matches) + set(should_skip_file TRUE) + break() + endif() + endif() + endforeach() + + # 如果文件需要跳过,继续处理下一个文件 + if(should_skip_file) + continue() + endif() + + # 4.3 添加符合条件的文件 + list(APPEND filtered_files "${current_file}") + + # 4.4 设置IDE文件分组 + # 计算相对路径作为分组名称 + get_filename_component(root_abs_path "${path}" ABSOLUTE) + get_filename_component(file_dir_abs_path "${file_dir}" ABSOLUTE) + file(RELATIVE_PATH group_path "${root_abs_path}" "${file_dir_abs_path}") + + # 处理根目录的特殊情况 + if(group_path STREQUAL ".") + set(group_name "") + else() + string(REPLACE "/" "\\" group_name "${group_path}") + endif() + + # 创建IDE分组 + source_group("${group_name}" FILES "${current_file}") + endforeach() + + # 5. 设置输出变量 + set(${out_files} ${filtered_files} PARENT_SCOPE) +endfunction() + +#[=======================================================================[ + 便捷封装函数 + 自动处理常见文件扩展名,针对不同平台添加特定文件类型 +#]=======================================================================] +function(retrieve_files path out_files) + # 设置基础文件类型 + set(file_extensions + "h" # 头文件 + "hpp" # C++头文件 + "ini" # 配置文件 + "cpp" # C++源文件 + "c" # C源文件 + "cc" + "ixx" # C++20模块文件 + ) + + # 针对Mac平台添加额外文件类型 + if(APPLE) + list(APPEND file_extensions "mm") # Objective-C++源文件 + endif() + + # 执行文件检索 + set(temp_files "") + retrieve_files_custom(${path} "${file_extensions}" temp_files) + + # 合并结果到输出变量 + set(${out_files} ${${out_files}} ${temp_files} PARENT_SCOPE) +endfunction() + +#[=======================================================================[ + Proto文件编译和gRPC绑定生成函数 + 参数: + TARGET_NAME: (必需) - 要创建的库目标名称 + PROTO_PATH: (必需) - 包含.proto文件的目录路径 + OUTPUT_PATH: (可选) - 生成文件的输出目录,默认为${CMAKE_CURRENT_BINARY_DIR}/generated + GRPC_ENABLED: (可选) - 是否生成gRPC绑定,默认为TRUE + PROTO_IMPORT_DIRS:(可选) - proto文件的额外导入目录列表 + EXPORT_MACRO: (可选) - 导出宏定义(用于Windows DLL导出) + + 例子: + compile_proto_files( + TARGET_NAME my_proto_lib + PROTO_PATH ${CMAKE_CURRENT_SOURCE_DIR}/protos + OUTPUT_PATH ${CMAKE_BINARY_DIR}/proto_gen + GRPC_ENABLED TRUE + PROTO_IMPORT_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protos + ) +#]=======================================================================] +function(compile_proto_files) + # 定义预期的参数 + set(options GRPC_ENABLED) + set(oneValueArgs TARGET_NAME PROTO_PATH OUTPUT_PATH EXPORT_MACRO) + set(multiValueArgs PROTO_IMPORT_DIRS) + + # 解析传递给函数的参数 + cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + # 参数验证 + if(NOT ARG_TARGET_NAME) + message(FATAL_ERROR "**compile_proto_files**: **缺少必需参数** **TARGET_NAME**.") + endif() + if(NOT ARG_PROTO_PATH) + message(FATAL_ERROR "**compile_proto_files**: **缺少必需参数** **PROTO_PATH**.") + endif() + + # 设置默认值 + if(NOT DEFINED ARG_GRPC_ENABLED) + set(ARG_GRPC_ENABLED TRUE) + endif() + if(NOT ARG_OUTPUT_PATH) + set(ARG_OUTPUT_PATH "${CMAKE_CURRENT_BINARY_DIR}/generated") + endif() + + # 查找Protobuf和gRPC + find_package(Protobuf REQUIRED) + if(ARG_GRPC_ENABLED) + find_package(gRPC QUIET) + if(NOT gRPC_FOUND) + # 如果找不到gRPC包,尝试手动查找 + find_program(GRPC_CPP_PLUGIN grpc_cpp_plugin) + if(NOT GRPC_CPP_PLUGIN) + message(FATAL_ERROR "**compile_proto_files**: **找不到gRPC C++插件**. 请确保已安装gRPC.") + endif() + else() + set(GRPC_CPP_PLUGIN $) + endif() + endif() + + # 创建输出目录 + file(MAKE_DIRECTORY ${ARG_OUTPUT_PATH}) + + get_filename_component(PROTO_PATH "${ARG_PROTO_PATH}" ABSOLUTE) + + # 递归查找所有.proto文件 + file(GLOB_RECURSE PROTO_FILES + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + CONFIGURE_DEPENDS + "${PROTO_PATH}/*.proto" + ) + + if(NOT PROTO_FILES) + message(WARNING "**compile_proto_files**: 在 '${PROTO_PATH}' 中未找到任何.proto文件") + return() + endif() + + message(STATUS "找到 ${CMAKE_CURRENT_SOURCE_DIR} Proto文件: ${PROTO_FILES}") + + # 准备生成的文件列表 + set(PROTO_SRCS) + set(PROTO_HDRS) + set(GRPC_SRCS) + set(GRPC_HDRS) + + # 构建导入路径参数 + set(PROTO_IMPORT_ARGS) + list(APPEND PROTO_IMPORT_ARGS "-I${PROTO_PATH}") + foreach(IMPORT_DIR ${ARG_PROTO_IMPORT_DIRS}) + list(APPEND PROTO_IMPORT_ARGS "-I${IMPORT_DIR}") + endforeach() + + # 为每个proto文件生成代码 + foreach(PROTO_FILE ${PROTO_FILES}) + # 获取proto文件的绝对路径 + get_filename_component(PROTO_FILE_ABS "${PROTO_FILE}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") + get_filename_component(PROTO_NAME_WE "${PROTO_FILE}" NAME_WE) + get_filename_component(PROTO_DIR "${PROTO_FILE}" DIRECTORY) + + # 计算相对路径以保持目录结构 + if(PROTO_DIR) + file(RELATIVE_PATH REL_DIR "${PROTO_PATH}" "${CMAKE_CURRENT_SOURCE_DIR}/${PROTO_DIR}") + set(OUTPUT_SUBDIR "${ARG_OUTPUT_PATH}/${REL_DIR}") + else() + set(OUTPUT_SUBDIR "${ARG_OUTPUT_PATH}") + endif() + + # 创建输出子目录 + file(MAKE_DIRECTORY ${OUTPUT_SUBDIR}) + + # 生成的文件路径 + set(PROTO_SRC "${OUTPUT_SUBDIR}/${PROTO_NAME_WE}.pb.cc") + set(PROTO_HDR "${OUTPUT_SUBDIR}/${PROTO_NAME_WE}.pb.h") + list(APPEND PROTO_SRCS ${PROTO_SRC}) + list(APPEND PROTO_HDRS ${PROTO_HDR}) + + # 基础protobuf生成命令 + set(PROTOC_ARGS + ${PROTO_IMPORT_ARGS} + "--cpp_out=${ARG_OUTPUT_PATH}" + "${PROTO_FILE_ABS}" + ) + + if(ARG_GRPC_ENABLED) + set(GRPC_SRC "${OUTPUT_SUBDIR}/${PROTO_NAME_WE}.grpc.pb.cc") + set(GRPC_HDR "${OUTPUT_SUBDIR}/${PROTO_NAME_WE}.grpc.pb.h") + list(APPEND GRPC_SRCS ${GRPC_SRC}) + list(APPEND GRPC_HDRS ${GRPC_HDR}) + + # 添加自定义命令生成protobuf和gRPC代码 + add_custom_command( + OUTPUT ${PROTO_SRC} ${PROTO_HDR} ${GRPC_SRC} ${GRPC_HDR} + COMMAND ${Protobuf_PROTOC_EXECUTABLE} + ${PROTOC_ARGS} + COMMAND ${Protobuf_PROTOC_EXECUTABLE} + ${PROTO_IMPORT_ARGS} + "--grpc_out=${ARG_OUTPUT_PATH}" + "--plugin=protoc-gen-grpc=${GRPC_CPP_PLUGIN}" + "${PROTO_FILE_ABS}" + DEPENDS ${PROTO_FILE_ABS} + COMMENT "生成Protobuf和gRPC代码: ${PROTO_FILE}" + VERBATIM + ) + else() + # 只生成protobuf代码 + add_custom_command( + OUTPUT ${PROTO_SRC} ${PROTO_HDR} + COMMAND ${Protobuf_PROTOC_EXECUTABLE} + ${PROTOC_ARGS} + DEPENDS ${PROTO_FILE_ABS} + COMMENT "生成Protobuf代码: ${PROTO_FILE}" + VERBATIM + ) + endif() + endforeach() + + # 创建库目标 + add_library(${ARG_TARGET_NAME} STATIC + ${PROTO_SRCS} + ${PROTO_HDRS} + ${GRPC_SRCS} + ${GRPC_HDRS} + ) + + # 设置包含目录 + target_include_directories(${ARG_TARGET_NAME} + PUBLIC + $ + $ + ) + + # 链接必要的库 + target_link_libraries(${ARG_TARGET_NAME} + PUBLIC + protobuf::libprotobuf + ) + + if(ARG_GRPC_ENABLED) + if(gRPC_FOUND) + target_link_libraries(${ARG_TARGET_NAME} + PUBLIC + gRPC::grpc++ + gRPC::grpc++_reflection + ) + else() + # 手动查找并链接gRPC库 + find_library(GRPC_LIBRARY grpc++) + find_library(GRPC_REFLECTION_LIBRARY grpc++_reflection) + if(GRPC_LIBRARY AND GRPC_REFLECTION_LIBRARY) + target_link_libraries(${ARG_TARGET_NAME} + PUBLIC + ${GRPC_LIBRARY} + ${GRPC_REFLECTION_LIBRARY} + ) + else() + message(WARNING "**compile_proto_files**: 无法找到gRPC库,请手动链接") + endif() + endif() + endif() + + # 设置导出宏(如果提供) + if(ARG_EXPORT_MACRO) + target_compile_definitions(${ARG_TARGET_NAME} + PRIVATE ${ARG_EXPORT_MACRO}_EXPORTS + INTERFACE ${ARG_EXPORT_MACRO}_IMPORTS + ) + endif() + + # 设置C++标准 + target_compile_features(${ARG_TARGET_NAME} PUBLIC cxx_std_11) + + # IDE文件分组 + source_group("Proto Files" FILES ${PROTO_FILES}) + source_group("Generated Files\\Protobuf" FILES ${PROTO_SRCS} ${PROTO_HDRS}) + if(ARG_GRPC_ENABLED) + source_group("Generated Files\\gRPC" FILES ${GRPC_SRCS} ${GRPC_HDRS}) + endif() + + # 输出信息 + message(STATUS "创建Proto库目标: ${ARG_TARGET_NAME}") + message(STATUS " Proto文件数量: ${CMAKE_CURRENT_SOURCE_DIR} list length: ${PROTO_FILES}") + message(STATUS " 输出目录: ${ARG_OUTPUT_PATH}") + message(STATUS " gRPC支持: ${ARG_GRPC_ENABLED}") +endfunction() + +#[=======================================================================[ +# 用于添加资源文件并在编译后复制到最终可执行文件所在目录 +# 注意:此函数依赖于 CMAKE_RUNTIME_OUTPUT_DIRECTORY 或 EXECUTABLE_OUTPUT_PATH +# 变量的设置,以确定可执行文件的输出目录。请确保在项目中设置了其中之一。 +# +# 参数: +# TARGET_NAME: (必需) - 关联的目标 (库或可执行文件) 的名称。 +# 资源复制命令将在 TARGET_NAME 构建后执行。 +# RESOURCE_FILES: (必需) - 一个或多个要复制的资源文件的路径列表 (相对或绝对) +# OUTPUT_SUBDIR: (可选) - 相对于可执行文件输出目录的子目录路径 (例如 "assets") +# +# 例子: +# # 确保设置了可执行文件输出目录 (通常在顶层 CMakeLists.txt) +# set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) +# +# # 添加库 +# add_library(my_lib STATIC src/my_lib.cpp) +# +# # 添加资源到 my_lib,但复制到最终可执行文件的输出目录下的 'config' 子目录 +# add_resource_file( +# TARGET_NAME my_lib +# RESOURCE_FILES config/settings.json config/defaults.ini +# OUTPUT_SUBDIR config +# ) +# +# # 添加可执行文件 +# add_executable(my_app main.cpp) +# target_link_libraries(my_app PRIVATE my_lib) +# +# # 添加 my_app 的资源,复制到可执行文件输出目录的根目录 +# add_resource_file( +# TARGET_NAME my_app +# RESOURCE_FILES assets/icon.png +# ) +#]=======================================================================] +function(add_resource_file) + # 定义预期的参数 + set(options "") # 无布尔选项 + set(oneValueArgs TARGET_NAME OUTPUT_SUBDIR) + set(multiValueArgs RESOURCE_FILES) + + # 解析传递给函数的参数 + cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + # --- 参数验证 --- + if(NOT ARG_TARGET_NAME) + message(FATAL_ERROR "**add_resource_file**: **缺少必需参数** **TARGET_NAME**.") + endif() + if(NOT ARG_RESOURCE_FILES) + message(FATAL_ERROR "**add_resource_file**: **缺少必需参数** **RESOURCE_FILES**.") + endif() + if(NOT TARGET ${ARG_TARGET_NAME}) + message(WARNING "**add_resource_file**: 目标 '${ARG_TARGET_NAME}' (尚)不存在。请确保在调用 add_executable/add_library('${ARG_TARGET_NAME}') 之后调用此函数。") + # 即使目标尚不存在,仍然尝试配置命令。CMake通常能处理好依赖关系。 + endif() + + # --- 确定最终可执行文件的目标基础目录 --- + set(DESTINATION_BASE "") + if(DEFINED CMAKE_RUNTIME_OUTPUT_DIRECTORY AND CMAKE_RUNTIME_OUTPUT_DIRECTORY) + set(DESTINATION_BASE "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}") + elseif(DEFINED EXECUTABLE_OUTPUT_PATH AND EXECUTABLE_OUTPUT_PATH) + # EXECUTABLE_OUTPUT_PATH 是旧变量,但也检查一下 + set(DESTINATION_BASE "${EXECUTABLE_OUTPUT_PATH}") + else() + # 如果是多配置生成器(如 Visual Studio, Xcode),需要考虑配置类型 + get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) + if(is_multi_config) + # 对于多配置,没有单一的顶级运行时目录变量。 + # 可以考虑使用 $ 配合一个已知的可执行文件名,但这会使函数复杂化。 + # 最好的做法是要求用户设置 CMAKE_RUNTIME_OUTPUT_DIRECTORY_ + # 或者我们直接报错,强制用户设置 CMAKE_RUNTIME_OUTPUT_DIRECTORY + message(FATAL_ERROR "**add_resource_file**: **无法确定可执行文件输出目录**。请在您的项目中设置 **CMAKE_RUNTIME_OUTPUT_DIRECTORY** 变量 (例如 set(CMAKE_RUNTIME_OUTPUT_DIRECTORY \"\${CMAKE_BINARY_DIR}/bin\"))。对于多配置生成器,可能需要设置 CMAKE_RUNTIME_OUTPUT_DIRECTORY_ 变量。") + else() + # 对于单配置生成器(如 Makefiles, Ninja),可以默认到 CMAKE_BINARY_DIR + set(DESTINATION_BASE "${CMAKE_BINARY_DIR}") + message(WARNING "**add_resource_file**: **未设置 CMAKE_RUNTIME_OUTPUT_DIRECTORY**。默认将资源复制到 CMAKE_BINARY_DIR ('${CMAKE_BINARY_DIR}')。强烈建议设置 CMAKE_RUNTIME_OUTPUT_DIRECTORY 以获得可预测的行为。") + endif() + # message(FATAL_ERROR "**add_resource_file**: **无法确定可执行文件输出目录**。请在您的项目中设置 **CMAKE_RUNTIME_OUTPUT_DIRECTORY** 变量 (例如 set(CMAKE_RUNTIME_OUTPUT_DIRECTORY \"\${CMAKE_BINARY_DIR}/bin\"))。") + endif() + + # 处理子目录 + set(DESTINATION_DIR "${DESTINATION_BASE}") # 默认目标目录 + if(ARG_OUTPUT_SUBDIR) + # 清理子目录路径字符串 + string(STRIP "${ARG_OUTPUT_SUBDIR}" _subdir) + if(IS_ABSOLUTE "${_subdir}") + message(FATAL_ERROR "**add_resource_file**: **OUTPUT_SUBDIR** ('${ARG_OUTPUT_SUBDIR}') **必须是相对路径**。") + else() + # 移除可能存在的前导/后导斜杠,以便干净地拼接路径 + string(REGEX REPLACE "^[/\\\\]+" "" _subdir "${_subdir}") + string(REGEX REPLACE "[/\\\\]+$" "" _subdir "${_subdir}") + if(_subdir) # 仅当子目录清理后非空时才追加 + set(DESTINATION_DIR "${DESTINATION_BASE}/${_subdir}") + endif() + endif() + endif() + + # --- 准备源文件路径 --- + set(ABS_RESOURCE_FILES "") + foreach(RESOURCE_FILE ${ARG_RESOURCE_FILES}) + get_filename_component(RESOURCE_FILE_REALPATH "${RESOURCE_FILE}" REALPATH BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") + # if(IS_ABSOLUTE "${RESOURCE_FILE}") + # # 如果已经是绝对路径,直接使用 + # list(APPEND ABS_RESOURCE_FILES "${RESOURCE_FILE}") + # else() + # # 如果是相对路径,相对于当前源目录进行解析 + # list(APPEND ABS_RESOURCE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/${RESOURCE_FILE}") + # endif() + list(APPEND ABS_RESOURCE_FILES "${RESOURCE_FILE_REALPATH}") + + # 检查文件是否存在 (在配置时发出警告,有助于早期发现错误) + # list(GET ABS_RESOURCE_FILES -1 _current_abs_file) # 获取刚才添加的绝对路径 + if(NOT EXISTS "${RESOURCE_FILE_REALPATH}") + message(WARNING "**add_resource_file**: **资源文件** '${RESOURCE_FILE}' (解析为 '${RESOURCE_FILE_REALPATH}') **在配置时不存在**。") + endif() + endforeach() + + # --- 添加自定义命令 --- + # 使用 add_custom_command 在目标构建完成后执行复制操作 + if(ABS_RESOURCE_FILES) # 确保有文件需要复制 + # 注意:DESTINATION_DIR 可能包含特定于配置的路径(例如,如果 CMAKE_RUNTIME_OUTPUT_DIRECTORY + # 设置为 ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/bin)。 + # add_custom_command 的 COMMAND 参数在构建时执行,此时这些变量/生成器表达式已解析。 + add_custom_command( + TARGET ${ARG_TARGET_NAME} + POST_BUILD # 指定在目标构建之后执行 + # 步骤 1: 确保目标目录存在 (copy_if_different 不会创建目录) + COMMAND ${CMAKE_COMMAND} -E make_directory "${DESTINATION_DIR}" + # 步骤 2: 复制文件 + COMMAND ${CMAKE_COMMAND} -E copy_if_different # 使用CMake内置命令复制(仅当文件不同时) + ${ABS_RESOURCE_FILES} # 要复制的源文件列表(绝对路径) + "${DESTINATION_DIR}" # 最终可执行文件所在的目标目录 (带引号以处理空格) + COMMENT "为 ${ARG_TARGET_NAME} 将资源复制到可执行文件目录: ${DESTINATION_DIR}..." # 构建时显示的注释 + VERBATIM # 确保参数(尤其是路径和生成器表达式)被正确处理 + ) + else() + message(WARNING "**add_resource_file**: 没有有效的资源文件提供给目标 '${ARG_TARGET_NAME}'。") + endif() + + # --- 可选: 将资源文件添加到 IDE 项目结构中 --- + if(ABS_RESOURCE_FILES) + set(_source_group_name "Resource Files") # 基础组名 + if(ARG_OUTPUT_SUBDIR) + # 使用与目标目录结构匹配的组名 + string(STRIP "${ARG_OUTPUT_SUBDIR}" _clean_subdir) + string(REPLACE "\\" "/" _clean_subdir "${_clean_subdir}") # 统一使用正斜杠 + string(REGEX REPLACE "^[/]+" "" _clean_subdir "${_clean_subdir}") + string(REGEX REPLACE "[/]+$" "" _clean_subdir "${_clean_subdir}") + if(_clean_subdir) + set(_source_group_name "Resource Files/${_clean_subdir}") + endif() + endif() + # 使用 source_group 将文件添加到 IDE 的指定组下 + source_group(${_source_group_name} FILES ${ABS_RESOURCE_FILES}) + endif() + +endfunction() diff --git a/conanfile.txt b/conanfile.txt new file mode 100644 index 0000000..a154849 --- /dev/null +++ b/conanfile.txt @@ -0,0 +1,109 @@ +[requires] +# ================================================================================================ +# DAW Backend Framework - Conan依赖配置 (完整版本) +# ================================================================================================ + +# 核心依赖 +spdlog/1.14.1 # 高性能日志库 +fmt/10.2.1 # 格式化库 (spdlog依赖) +nlohmann_json/3.11.3 # JSON处理 + +# 序列化和数据结构 +yaml-cpp/0.8.0 # YAML配置文件支持 +protobuf/3.21.12 # 消息序列化 +flatbuffers/24.3.25 # 高性能序列化 (零拷贝) + +# 测试框架 +gtest/1.14.0 # 单元测试 +benchmark/1.8.3 # 性能测试 + +# 基础工具库 +boost/1.88.0 # 提供进程管理、IPC、共享内存等核心组件 + +# 通信组件 +zeromq/4.3.5 # 高性能异步消息库 +cppzmq/4.11.0 # ZeroMQ C++绑定 +zstd/1.5.5 # 高性能压缩库 (网络传输优化) + +# 数学和信号处理 +eigen/3.4.0 # 矩阵计算和DSP处理 +fftw/3.3.10 # 快速傅里叶变换 +libsamplerate/0.2.2 # 高质量采样率转换 + +# 线程和并发 +onetbb/2022.2.0 # Intel线程构建块 (并行处理) + +# 音频处理支持 +portaudio/19.7.0 # 跨平台音频I/O库 +libsndfile/1.2.2 # 音频文件格式读写 +rtmidi/5.0.0 # MIDI处理 + +[options] +# Boost配置 - 启用IPC和零拷贝相关组件 +boost/*:shared=False +boost/*:without_test=False +boost/*:without_filesystem=False +boost/*:without_system=False +boost/*:without_thread=False +boost/*:without_chrono=False +boost/*:without_atomic=False +boost/*:without_date_time=False +boost/*:without_regex=False +boost/*:without_context=False # 提供上下文切换支持,process依赖 +boost/*:without_coroutine=True +boost/*:without_fiber=True +boost/*:without_graph=True +boost/*:without_iostreams=False # process依赖 +boost/*:without_locale=True +boost/*:without_log=True +boost/*:without_math=True +boost/*:without_mpi=True +boost/*:without_program_options=False # 命令行参数解析 +boost/*:without_python=True +boost/*:without_random=False +boost/*:without_serialization=False # 需要序列化支持 +boost/*:without_wave=True +boost/*:without_asio=False # process依赖 + +# ZeroMQ配置 - 增强版本支持更多特性 +zeromq/*:shared=False +cppzmq/*:shared=False + +# 日志库配置 +spdlog/*:shared=False +spdlog/*:header_only=False +fmt/*:shared=False +fmt/*:header_only=False + +# 测试框架配置 +gtest/*:shared=False +gtest/*:no_main=False +benchmark/*:shared=False + +# 序列化库配置 +protobuf/*:shared=False +yaml-cpp/*:shared=False +flatbuffers/*:shared=False + +# 数学库配置 +eigen/*:shared=False +onetbb/*:shared=False +fftw/*:shared=False +fftw/*:precision=double + +# 音频库配置 +portaudio/*:shared=False +libsndfile/*:shared=False +libsndfile/*:with_external_libs=True +rtmidi/*:shared=False +libsamplerate/*:shared=False + +# 压缩库配置 +zstd/*:shared=False + +[generators] +CMakeDeps +CMakeToolchain + +[layout] +cmake_layout \ No newline at end of file diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..1a874ad --- /dev/null +++ b/docs/README.md @@ -0,0 +1,82 @@ +# AI 项目编码规范 + +为了统一项目编码风格,提高代码的可读性、可维护性和团队协作效率,特制定本规范。所有项目参与者均需严格遵守。 + +## 1. 终端命令 + +在本项目中,所有终端操作,包括但不限于编译、运行、脚本执行等,均需使用 **PowerShell** 命令。 + +- **目的**: 确保在 Windows 主开发环境下命令的一致性。 +- **要求**: 请确保你的开发环境已正确配置 PowerShell,并使用 PowerShell Core (7.x+) 以获得最佳的跨平台兼容性体验。 + +## 2. 跨平台宏定义 + +项目中所有的跨平台宏定义和操作系统判断逻辑,请统一参考和使用根目录 `cmake/detect_os.cmake` 文件中提供的宏。 + +- **目的**: 集中管理平台相关逻辑,避免在业务代码中出现分散的、重复的平台判断代码。 +- **示例**: 在 CMakeLists.txt 中需要根据操作系统执行不同操作时,应使用 `detect_os.cmake` 中定义的 `IS_WINDOWS`, `IS_LINUX` 等变量。 + +## 3. 目录结构与头文件管理 + +本项目不设立顶层的 `include` 文件夹用于存放公共头文件。每个模块所需的头文件(`.h`, `.hpp`)和源文件(`.cpp`)应全部放置在该模块自身的文件夹下。 + +- **目的**: 提高模块的内聚性,使得模块可以被轻松地移植或复用。 +- **正确结构示例**: + ``` + project/ + ├── src/ + │ ├── moduleA/ + │ │ ├── a.h + │ │ └── a.cpp + │ ├── moduleB/ + │ │ ├── b.h + │ │ └── b.cpp + │ └── common/ + │ ├── logger.h + │ └── error.h + └── cmake/ + ├── detect_os.cmake + └── retrieve_files.cmake + ``` + +## 4. 跨平台文件包含 + +当需要根据不同操作系统包含不同的源文件时,应遵循 `cmake/retrieve_files.cmake` 文件中定义的规范和函数。 + +- **目的**: 将文件包含的平台差异性逻辑收敛到 CMake 构建系统中,保持 `CMakeLists.txt` 的整洁。 +- **要求**: 请勿在业务模块的 `CMakeLists.txt` 中自行编写 `if(WIN32)` 等逻辑来添加源文件,应调用 `retrieve_files.cmake` 中提供的函数来获取平台相关的文件列表。 + +## 5. 错误码与异常处理 + +项目中所有的错误码定义和异常抛出机制,均已在 `common` 模块的 `error.h` 文件中统一规定。 + +- **目的**: 统一全项目的错误处理方式,便于问题的定位和跟踪。 +- **要求**: + - 在进行错误处理或抛出异常时,必须查阅并使用此文件中已有的定义。 + - 如需新增错误类型,也应在此文件中进行统一扩展,并附上清晰的注释说明。 + +## 6. 日志打印 + +严禁使用 `printf`、`std::cout` 等标准输出函数进行调试和日志打印。所有日志信息必须通过 `common` 模块下的 `logger.h` 提供的日志接口进行输出。 + +- **目的**: 便于统一管理日志级别(如 DEBUG, INFO, WARNING, ERROR)、输出格式和输出目标(如控制台、文件),方便在不同环境下进行调试和部署。 +- **示例**: + ```cpp + // 错误示范 + // std::cout << "加载模型失败" << std::endl; + + // 正确示范 + #include "logger.h" + ... + log_err("模型加载失败,文件路径:%s", model_path.c_str()); + ``` + +## 7. 注释与日志语言 + +为了方便团队所有成员的阅读和理解,项目所有的**代码注释**、**日志信息**以及**代码提交信息(Commit Message)** **必须全部使用中文**。 + +- **目的**: 消除语言障碍,降低沟通成本,确保信息的准确传达。 +- **要求**: + - **代码注释**: 对复杂的函数、算法或业务逻辑,必须添加清晰的中文注释。 + - **日志内容**: `logger.h` 输出的日志消息必须为中文。 + - **Git Commit**: 每次提交的说明信息都应使用中文描述本次变更的内容。 diff --git a/docs/architecture-design.md b/docs/architecture-design.md new file mode 100644 index 0000000..ce10646 --- /dev/null +++ b/docs/architecture-design.md @@ -0,0 +1,1256 @@ +# C++23跨平台音频后系统架构设计文档 + +## 文档版本 +- 版本:1.0 +- 日期:2025-10-24 +- 状态:设计完成 + +--- + +## 1. 执行摘要 + +本文档提供了一完整的跨平台(Windows、Linux、macOS)C++23音频后端系统的技术架构设计。该系统采用多进程架构,将音频引擎核心与第三方插件彻底隔离,通过Boost构建插件沙盒,使用ZeroMQ和Boost共享内存实现高效通信,支持网络通信和SIMD优化,保证性能、安全和可维护性。 + +### 1.1 核心特性 +- ✅ 多进程架构确保插件与核心引擎隔离 +- ✅ 双通道通信机制(ZeroMQ + Boost共享内存) +- ✅ 支持本地和远程网络通信 +- ✅ SIMD运行时检测和动优化 +- ✅ 全面的错误处理和容错机制 +- ✅ 企业级安全措施 +- ✅ 高度可扩展的模块化设计 + +--- + +## 2. 系统整体架构 + +### 2.1 进程模型 + +系统分为三个主要进程组: + +**音频引擎核心进** +- 角色:中央处理单元 +- 职责:音频处理调度、资源管理、通信协调 +- 特点:高优先级实时线程,零内存分配 + +**插件沙盒进程** +- 角色:隔离执行环境 +- 职责:运行第三方插件,资源限制 +- 特点:独立进程空间,严格资源配额 + +**前端进程** +- 角色:用户交互界面 +- 职责:UI显示、硬控制、用户输入 +- 特点:非实时处理,异步通信 + +### 2.2 系统架构图 + +```mermaid +graph TB + subgraph "前端进程" + UI[UI层] + HAL[硬件抽象层] + FrontAPI[前端API] + end + + subgraph "音频引擎核心进" + AudioCore[音频核心擎] + ProcessingGraph[处理管理器] + BufferManager[音频缓区管理] + SIMDEngine[SIMD优化引擎] + MixerEngine[混音引擎] + PluginManager[插件管器] + CommManager[通信管理器] + end + + subgraph "插件沙盒1" + Sandbox1[沙盒运行时] + Plugin1[插件实例1] + end + + subgraph "插件沙盒2" + Sandbox2[沙盒运行时] + Plugin2[插件实例2] + end + + subgraph "远程前端" + RemoteUI[远程UI] + RemoteAPI[远程API] + end + + FrontAPI -- ZeroMQ --> CommManager + HAL -- 硬件控制 --> FrontAPI + UI -- 用户操作 --> FrontAPI + + AudioCore -- 调度 --> ProcessingGraph + ProcessingGraph -- 使用 --> BufferManager + ProcessingGraph -- 调用 --> SIMDEngine + SIMDEngine -- 输出 --> MixerEngine + PluginManager -- 管理 --> CommManager + + CommManager -- Boost共享内存/ZeroMQ --> Sandbox1 + CommManager -- Boost共享内存/ZeroMQ --> Sandbox2 + Sandbox1 -- 加载 --> Plugin1 + Sandbox2 -- 加载 --> Plugin2 + + RemoteAPI -- 网络协议 --> CommManager + RemoteUI -- 用户操作 --> RemoteAPI +``` + +--- + +## 3. 进程间通信架构 + +### 3.1 通信策略 + +基于消息大小和延迟要求,系统采用双通道策略: + +**控制通道(ZeroMQ** +- 用途:小消息(< 4KB) +- 场景:插件状态通知、控制命令、参数更新、错误报告 +- 优势:灵活的消息模式、自动重连、跨平台 + +**数据通道(Boost享内存)** +- 用途:大数据传输(≥ 4KB) +- 场景:音频缓冲区、批量参数数据、音频流 +- 优势:零拷贝、低延迟、高吞吐量 + +### 3.2 通信架构图 + +```mermaid +graph LR + subgraph "音频引擎核心" + CoreZMQ[ZeroMQ Publisher/Subscriber] + CoreSHM[Boost共享内管理器] + CoreQueue[无锁环形列] + end + + subgraph "插件沙盒" + PluginZMQ[ZeroMQ Subscriber/Publisher] + PluginSHM[Boost共享内存访问器] + PluginQueue[无锁环形队列] + end + + subgraph "前端进程" + FrontZMQ[ZeroMQ REQ/REP] + FrontSHM[Boost共享内访问器] + end + + CoreZMQ <--> PluginZMQ + CoreSHM <--> PluginSHM + CoreQueue <--> PluginQueue + + CoreZMQ <--> FrontZMQ + CoreSHM <--> FrontSHM +``` + +### 3.3 通信模式详细设计 + +#### 3.3.1 音频缓冲区传输 +- 技术:Boost.Interprocess共享内存 +- 数据结构:无锁环形缓冲区(Lock-free Ring Buffer) +- 缓冲策略:三缓冲机制减少等待 +- 内存布局:SIMD对(64字节边界) + +#### 3.3.2 控制消息传输 +- ZeroMQ模式: + * PUB/SUB:广播状态新 + * REQ/REP:同步请求响应 +- 序列化:Protobuf +- 优先级:消息优先级队列 + +#### 3.3.3 参数同步 +- 单参数:原子操作 +- 批量参数:共享内存 +- 一致性:版本号机制 + +--- + +## 4. 网络通信协议 + +### 4.1 协议分层架构 + +**传输层** +- 本地通信:Unix Domain Socket / Named Pipes +- 局域网:TCP + UDP混合 +- 广域网:TCP + TLS 1.3 + +**会话层** +- 连接管理和心跳检测 +- 自动重连机制 +- 带宽自适应 + +**应用层** +- 音频流协议(基于RTP/RTCP) +- 控制协议(基于Protobuf) +- 发现和配对协议 + +### 4.2 网络通信架构图 + +```mermaid +graph TD + subgraph "本地网络" + LocalEngine[本地音频引擎] + LocalFront[本地前端] + LocalEngine <--> LocalFront + end + + subgraph "局域网设备" + LANEngine[局域网音引擎] + LANFront[局域网前端] + end + + subgraph "广域网设备" + WANEngine[广域网音引擎] + WANFront[广域网前端] + end + + subgraph "协议栈" + DiscoveryProtocol[设备发现协议] + AudioStreamProtocol[音流协议] + ControlProtocol[控制议] + SecurityLayer[安全层] + end + + LocalEngine --> DiscoveryProtocol + DiscoveryProtocol --> LANEngine + DiscoveryProtocol --> WANEngine + + AudioStreamProtocol --> LANEngine + AudioStreamProtocol --> WANEngine + + ControlProtocol --> LANFront + ControlProtocol --> WANFront + + SecurityLayer --> AudioStreamProtocol + SecurityLayer --> ControlProtocol +``` + +### 4.3 协议详细设计 + +#### 4.3.1 音频流传输协议 +- 传输:基于UDP的实时传输 +- 编码:OPUS/AAC可选 +- 质量控制:自适应码率 +- 可靠性:丢包检测和重传 +- 同步:时间戳同步机制 + +#### 4.3.2 控制协议 +- 传输:基于TCP的可靠传输 +- 序列化:Protobuf +- 模式:命令-响应 + 事件通知 +- 性能:连接池和多路复用 + +#### 4.3.3 安全机制 +- 加密:TLS 1.3 +- 认证:设备配对 + Token验证 +- 密钥管理:定期轮换 +- 攻击防护:防重放攻击 + +--- + +## 5. SIMD优化策略 + +### 5.1 指令集支持层次 + +系统采用多级SIMD化策略,运行时自动选择最优实现: + +**基础层** +- 标量实现(无SIMD +- 保证所有平台兼容性 + +**SSE层** +- SSE/SSE2/SSE3/SSSE3 +- SSE4.1/SSE4.2 +- 广泛的x86/x64支持 + +**AVX层** +- AVX/AVX2 +- FMA指令集 +- 现代x86/x64处理器 + +**AVX-512层** +- AVX-512F/VL/BW/DQ +- 服务器和高端桌面CPU + +**ARM层** +- NEON(32位和64位) +- 移动和嵌入式平台 + +### 5.2 运行时检测和分发机制 + +```mermaid +graph TD + Start[系统启动] --> CPUIDDetect[CPUID检测] + CPUIDDetect --> BuildCapTable[构建能表] + BuildCapTable --> RegisterImpl[注册所SIMD实现] + + RegisterImpl --> SelectBest[选择最优现] + SelectBest --> CacheResult[缓存函数指针] + + subgraph "运行时调用" + AudioCall[音频处理用] + FuncPtr[函数指针分] + SIMDImpl[SIMD实现] + end + + CacheResult --> FuncPtr + AudioCall --> FuncPtr + FuncPtr --> SIMDImpl +``` + +### 5.3 SIMD优化设计要点 + +#### 5.3.1 CPU特性检测 +- x86/x64:CPUID指令 +- ARM:/proc/cpuinfo或hwcap +- 运行时验证指令集可用性 +- 结果缓存避免重复检测 + +#### 5.3.2 函数多版本实现 +- 每个关键函数提供多个版本 +- C++23属性`[[target]]`函数多版本 +- 编译时生成所有版本 +- 函数指针表零开销分发 + +#### 5.3.3 数据对齐和布局 +- 64字节边界对齐(AVX-512) +- SoA布局优化缓存 +- 预分配对齐内存池 +- SIMD友好的数据结 + +#### 5.3.4 关键优化路径 +- 音频混音(多轨合成) +- FFT/IFFT变换 +- 卷积运算(混响、滤波器) +- 采样率转换 +- 音量和Pan计算 + +--- + +## 6. 插件沙盒隔离机制 + +### 6.1 沙盒架构 + +插件沙盒采用多层隔离策略: + +**进程级隔离** +- 每个插件在独立进程中运行 +- 使用Boost.Process管子进程 +- 进程崩溃不影响核心引擎 +- 进程池复用减少启动开销 + +**内存隔离** +- 插件无法访问核心引擎内存 +- 仅通过共享内存区域交换数据 +- 内存配额管理 +- 内存泄漏检测和限制 + +**资源访问控制** +- 文件系统访问白名单 +- 网络访问权限控制 +- 系统调用过滤 +- CPU和内存使用限制 + +### 6.2 沙盒隔离架构图 + +```mermaid +graph TB + subgraph "核心引擎进程空" + EngineCore[音频引擎心] + SandboxManager[沙盒管理器] + ResourceMonitor[资源控器] + IPCBridge[IPC桥接层] + end + + subgraph "沙盒进程1" + SandboxRuntime1[沙盒行时] + PluginLoader1[插件加器] + ResourceLimiter1[资源制器] + Plugin1[插件实例] + + SandboxRuntime1 --> PluginLoader1 + PluginLoader1 --> Plugin1 + ResourceLimiter1 --> Plugin1 + end + + subgraph "沙盒进程2" + SandboxRuntime2[沙盒行时] + PluginLoader2[插件加器] + ResourceLimiter2[资源制器] + Plugin2[插件实例] + + SandboxRuntime2 --> PluginLoader2 + PluginLoader2 --> Plugin2 + ResourceLimiter2 --> Plugin2 + end + + subgraph "共享内存区域" + AudioBufferSHM[音频缓冲区] + ControlDataSHM[控制数据] + end + + EngineCore --> SandboxManager + SandboxManager --> ResourceMonitor + SandboxManager --> IPCBridge + + IPCBridge <--> SandboxRuntime1 + IPCBridge <--> SandboxRuntime2 + + SandboxRuntime1 <--> AudioBufferSHM + SandboxRuntime2 <--> AudioBufferSHM + + ResourceMonitor --> SandboxRuntime1 + ResourceMonitor --> SandboxRuntime2 +``` + +### 6.3 沙盒设计要点 + +#### 6.3.1 进程隔离机制 + +**Windows实现** +- Job Objects限制资源 +- 降低进程权限(Low Integrity Level) +- AppContainer隔离 + +**Linux实现** +- Namespaces隔离(PID, Mount, Network) +- Cgroups资源限制 +- Seccomp系统调用过 + +**macOS实现** +- Sandbox profile限制 +- 降低权限执行 +- XPC服务隔离 + +#### 6.3.2 通信安全 +- 验证所有进程间消息 +- 输入数据边界检查 +- 防止缓冲区溢出 +- 超时保护机制 + +#### 6.3.3 资源配额管理 +- CPU使用率上限(单插件≤25%) +- 内存配额(单插件≤512MB) +- 文件描述符数量限制 +- 线程数量限制 + +#### 6.3.4 故障隔离和恢复 +- 插件崩溃自动检测 +- 静默重启失败插件 +- 降级模式(bypass崩溃插件) +- 崩溃报告收集 + +--- + +## 7. 错误处理和容错机制 + +### 7.1 错误分类体系 + +**致命错误** +- 系统崩溃、内存耗尽 +- 处理:优雅关闭、保存状态 + +**严重错误** +- 音频缓冲区欠载、插件崩溃 +- 处理:隔离故障、尝试恢复 + +**警告错误** +- 性能下降、资源不足 +- 处理:记录警告、持续监控 + +**信息错误** +- 配置变更、状态迁移 +- 处理:记录信息 + +### 7.2 错误处理流程图 + +```mermaid +graph TD + Error[错误发生] --> Detect[错误检测] + Detect --> Classify[错误分类] + + Classify --> Fatal{致命错误?} + Classify --> Severe{严重错误?} + Classify --> Warning{警告错误?} + + Fatal --> |是| GracefulShutdown[优雅闭] + Fatal --> |否| Severe + + Severe --> |是| Isolate[隔离故障组] + Isolate --> AttemptRecover[尝试恢复] + AttemptRecover --> RecoverSuccess{恢复成功?} + + RecoverSuccess --> |是| LogAndContinue[记录并继续] + RecoverSuccess --> |否| Degrade[降级模式运] + + Severe --> |否| Warning + Warning --> |是| LogWarning[记录警告] + Warning --> |否| LogInfo[记录信息] + + LogAndContinue --> Monitor[持续监控] + Degrade --> Monitor + LogWarning --> Monitor + LogInfo --> Monitor + + GracefulShutdown --> SaveState[保存状态] + SaveState --> CleanupResources[清理源] + CleanupResources --> Exit[退出] +``` + +### 7.3 容错机制详细设计 + +#### 7.3.1 插件故障处理 + +**故障检测** +- 进程崩溃监控(进程返回码) +- 心跳超时检测(ping/pong) +- 响应时间监控(超时阈值) +- 输出异常检测(NaN/Inf) + +**恢复策略** +- 第一次失败:静默重启 +- 连续失败:标记不可用,bypass +- 持久化失败:禁用插件,通知用户 +- 保持处理链完整性 + +#### 7.3.2 音频缓冲区管理 +- 预警机制(使用率监控) +- 动态调整缓区大小 +- 紧急填充静音数据 +- 丢弃最旧数据 +- 通知上层调整延迟 + +#### 7.3.3 网络通信容错 +- 连接断开自动重连(指数退避) +- 消息丢失检测和重传 +- 网络拥塞控制 +- 会话恢复机制 +- 超时保护 + +#### 7.3.4 内存管理容错 +- 预分配内存池 +- 内存使用限制和监控 +- OOM处理(降级模式) +- 内存泄漏检测 +- 强制使用智能指针 + +#### 7.3.5 日志和诊断 + +**日志策略(spdlog** +- TRACE: 详细调试信息 +- DEBUG: 调试信息 +- INFO: 一般信息 +- WARN: 警告信息 +- ERROR: 错误信息 +- CRITICAL: 致命错误 + +**日志特性** +- 异步日志(避免阻塞) +- 日志轮转 +- 性能日志 +- 崩溃转储 + +#### 7.3.6 健康监控系统 + +**监控指标** +- CPU使用率 +- 内存使用量 +- 音频延迟 +- 缓冲区使用率 +- 丢包率 +- 插件响应时间 + +**告警机制** +- 阈值告警 +- 趋势告警 +- 异常模式检测 +- 告警聚合 + +--- + +## 8. 性能优化策略 + +### 8.1 内存管理优化 + +**内存池技术** +- 预分配固定大小内存块 +- 对象池复用频繁创建的对象 +- 减少内存碎片 + +**零拷贝机制** +- 共享内存直接访问 +- 内存映射文件 +- 引用传递替代值拷贝 + +**自定义分配器** +- SIMD对齐分配 +- 缓存行对齐 +- NUMA感知分配 + +### 8.2 线程模型优化 + +```mermaid +graph TB + subgraph "线程优先级与职" + RT1[实时线程-音频调] --> |最高优先级| AudioCallback[音频数处理] + RT2[实时线程-关键件] --> |高优先级| PluginProcess[插件处] + Worker[工作线程池] --> |标准优先级| TaskDispatch[任务分] + Background[后台线程] --> |低优先级| NonRealtime[非实时任务] + end + + subgraph "任务分类与调度" + AudioCallback --> RTTasks[实时任务队] + TaskDispatch --> Compute[计算密集型务] + TaskDispatch --> IO[I/O任务] + TaskDispatch --> LowPriority[低优先级任务] + NonRealtime --> Analytics[分析和监] + end + + subgraph "资源分配策略" + RTTasks --> |预留核心| CPU1[专用CPU核心] + Compute --> |动态分配| CPU2[共享CPU核心组] + IO --> |事件驱动| IOThreads[I/O线程组] + Analytics --> |低优先级| BackgroundThreads[后台线程] + end +``` + +### 8.3 实时性能保障 + +**实时策略** +- 实时线程CPU亲和性绑定 +- 预分配所有资源 +- 避免系统调用和页面错误 +- 避免GC和阻塞操作 +- 高优先级任务优先 + +### 8.4 并发处理优化 + +**并发架构** +- 工作窃取任务调度器 +- 无锁数据结构(环形缓冲区、队列) +- 细粒度任务分解 +- 前端和后端异步解耦 +- 核心音频线程无锁设计 + +### 8.5 算法优化 + +**优化策略** +- FFT快速算法 +- 动态规划和记忆化 +- 位操作优化 +- 分支预测优化 +- SIMD向量化 + +### 8.6 I/O和磁盘优化 + +**I/O策略** +- 异步I/O +- 内存映射文件(mmap) +- 预读取和预缓存 +- 批量读写 +- 写入合并 + +### 8.7 编译优化 + +**编译策略** +- 链接时优化(LTO) +- 程序全局优化(PGO) +- 函数内联控制 +- 热点代码优化 +- 跨模块优化 + +--- + +## 9. 安全性措施 + +### 9.1 安全架构层次 + +```mermaid +graph TB + subgraph "网络安全层" + TLS[TLS 1.3加密] + Auth[身份认证] + Firewall[防火墙规则] + end + + subgraph "进程安全层" + Sandbox[沙盒隔离] + PrivSep[权限分离] + ResourceLimit[资源限] + end + + subgraph "数据安全层" + DataEncrypt[数据加密] + InputValid[输入验证] + Sanitize[数据清洗] + end + + subgraph "代码安全层" + MemSafe[内存安全] + ASLR[地址随机化] + StackProtect[栈保护] + end + + subgraph "审计和监控层" + AuditLog[审计日志] + IntrusionDetect[入侵测] + Alerting[告警系统] + end + + TLS --> Auth + Auth --> Sandbox + Sandbox --> DataEncrypt + DataEncrypt --> MemSafe + MemSafe --> AuditLog +``` + +### 9.2 网络通信安全 + +**传输安全** +- TLS 1.3强制加密 +- 证书验证和固定 +- 完美前向保密(PFS) +- 防中间人攻击 +- 防重放攻击 + +**认证和授权** +- 设备配对机制 +- 基于Token的会话管 +- 定期密钥轮换 +- 多因素认证(可选) +- 权限最小化 + +### 9.3 进程和插件安全 + +**沙盒强化** +- 最小权限原则 +- 禁用危险系统调用 +- 文件系统白名单 +- 网络访问隔离 +- 进程间通信验证 + +**插件验证** +- 插件签名验证 +- 版本和兼容性检查 +- 动态行为监控 +- 异常行为检测 +- 黑名单机制 + +### 9.4 内存安全 + +**内存保护** +- 强制使用智能指针 +- 边界检查(gsl::span) +- 栈溢出保护 +- ASLR地址随机化 +- DEP/NX数据执行保护 + +**代码审查** +- 静态分析(clang-tidy, cppcheck) +- 模糊测试(AFL, libFuzzer) +- 内存安全扫描(AddressSanitizer) +- 未定义行为检测(UBSan) + +### 9.5 输入验证和数据清洗 + +**验证策略** +- 所有外部输入严格验证 +- 白名单优于黑名单 +- 类型安全检查 +- 长度和范围限制 +- 格式验证 + +**数据清洗** +- 防止代码注入 +- 转义特殊字符 +- 规范化路径名 +- 过滤危险内容 + +### 9.6 数据保护 + +**敏感数据处理** +- 配置文件加密存储 +- 密钥安全管理 +- 临时数据安全擦除 +- 内存敏感数据最小化 +- 审计日志脱敏 + +**数据完整性** +- 消息认证码(HMAC +- 数字签名 +- 校验和验证 +- 版本控制和回滚 + +### 9.7 审计和日志安全 + +**审计策略** +- 关键操作全记录 +- 安全事件优先级分类 +- 不可篡改日志 +- 日志轮转和归档 +- 异常模式检测 + +**监控指标** +- 失败登录尝试 +- 权限提升请求 +- 异常网络流量 +- 资源异常使用 +- 进程异常行为 + +### 9.8 跨平台安全适配 + +**Windows特定** +- Code Integrity Guard +- Control Flow Guard (CFG) +- Windows Defender集成 +- UAC支持 + +**Linux特定** +- SELinux/AppArmor策略 +- Capabilities细粒度权限 +- Seccomp-BPF过滤 +- Namespaces隔离 + +**macOS特定** +- Gatekeeper和公证 +- Sandbox profiles +- Keychain集成 +- SIP兼容 + +--- + +## 10. 系统可扩展性 + +### 10.1 模块化架构 + +```mermaid +graph TB + subgraph "核心层 - 不可替换" + CoreEngine[音频核心擎] + ProcessingGraph[处理引擎] + MemoryManager[内存管器] + end + + subgraph "抽象层 - 可扩展接口" + AudioDeviceAPI[音频设备抽象] + PluginAPI[插件接口] + NetworkAPI[网络传输象] + StorageAPI[存储抽象] + SIMDAPI[SIMD抽象] + end + + subgraph "实现层 - 可替换模块" + ASIOImpl[ASIO实现] + CoreAudioImpl[CoreAudio现] + ALSAImpl[ALSA实现] + + VST3Plugin[VST3插件] + AUPlugin[AU插件] + CustomPlugin[自定义件] + + TCPTransport[TCP传输] + UDPTransport[UDP传输] + CustomTransport[自定传输] + end + + CoreEngine --> ProcessingGraph + ProcessingGraph --> MemoryManager + + CoreEngine --> AudioDeviceAPI + ProcessingGraph --> PluginAPI + CoreEngine --> NetworkAPI + + AudioDeviceAPI --> ASIOImpl + AudioDeviceAPI --> CoreAudioImpl + AudioDeviceAPI --> ALSAImpl + + PluginAPI --> VST3Plugin + PluginAPI --> AUPlugin + PluginAPI --> CustomPlugin + + NetworkAPI --> TCPTransport + NetworkAPI --> UDPTransport + NetworkAPI --> CustomTransport +``` + +### 10.2 插件系统扩展 + +**插件类型支持** +- 音频效果插件 +- 音频生成插件 +- MIDI处理插件 +- 分析和可视化插件 +- 自定义协议插件 + +**扩展机制** +- 标准插件API定义 +- 插件发现和注册机制 +- 热插拔支持 +- 版本管理和兼容性 +- 插件市场集成支持 + +### 10.3 处理图扩展 + +**图结构** +- 动态节点添加/删 +- 动态连接重路由 +- 并行处理分支 +- 子图嵌套 +- 图模板和预设 + +**节点类型** +- 音频输入/输出节 +- 效果处理节点 +- 混音节点 +- 路由节点 +- 分析节点 +- 自定义节点类型 + +### 10.4 存储和配置扩展 + +**配置管理** +- JSON/YAML配置文件 +- 配置模板系统 +- 配置继承和覆盖 +- 配置验证schema +- 配置热重载 + +**持久化** +- 项目文件格式可扩展 +- 插件状态序列化 +- 版本迁移机制 +- 数据导入/导出插 + +### 10.5 网络协议扩展 + +**协议栈** +- 可插拔传输层(TCP/UDP/QUIC等) +- 可扩展编码器(OPUS/AAC/自定义) +- 自定义应用层协议 +- 协议协商机制 +- 向后兼容性保证 + +### 10.6 用户界面扩展 + +**UI框架** +- 前端框架无关(Qt/Web/原生) +- 主题系统 +- 布局可定制 +- 组件库扩展 +- 第三方控制器集成 + +### 10.7 性能扩展 + +**水平扩展** +- 多机分布式处理 +- 负载均衡 +- 任务分片 +- 弹性计算 + +**垂直扩展** +- 自动检测硬件能力 +- 动态调整处理精度 +- 自适应缓冲区大小 +- 多核心充分利用 + +### 10.8 API版本管理 + +**版本策略** +- 语义化版本控制 +- API兼容性保证 +- 废弃警告机制 +- 平滑迁移路径 +- 多版本共存支持 + +### 10.9 扩展点清单 + +**主要扩展点** +1. 音频设备驱动接口 +2. 插件加载器接口 +3. 网络传输协议接口 +4. 音频编解码接口 +5. 存储序列化接口 +6. SIMD实现接口 +7. 错误处理钩子 +8. 日志输出接口 +9. 资源分配策略接口 +10. 用户界面组件接口 + +--- + +## 11. 跨平台兼容性 + +### 11.1 平台支持矩阵 + +| 功能 | Windows | Linux | macOS | +|------|---------|-------|-------| +| 音频设备 | ASIO, WASAPI, DirectSound | ALSA, JACK, PulseAudio | CoreAudio | +| 进程隔离 | Job Objects, AppContainer | Namespaces, Cgroups | Sandbox, XPC | +| 共享内存 | Named Shared Memory | POSIX SHM, System V SHM | POSIX SHM | +| 网络通信 | Winsock | BSD Sockets | BSD Sockets | +| 实时优先级 | SetThreadPriority | SCHED_FIFO | Thread Policy | +| SIMD | SSE/AVX/AVX-512 | SSE/AVX/AVX-512 | SSE/AVX/NEON (M系列) | + +### 11.2 平台抽象层设计 + +**音频设备抽象** +- 统一的音频设备枚举接口 +- 统一的流配置接口 +- 统一的回调机制 +- 平台特定优化保留 + +**进程管理抽象** +- 统一的进程创建接口 +- 统一的资源限制接口 +- 统一的进程监控接口 +- 平台特定安全机制适配 + +**文件系统抽象** +- 统一的路径处理 +- 统一的文件作接口 +- 平台特定权限映射 + +**网络抽象** +- 统一的socket接口 +- 统一的地址解析 +- 平台特定优化(如IOCP, epoll) + +--- + +## 12. 依赖管理和构建配置 + +### 12.1 核心依赖 + +**已配置依赖(conanfile.txt)** +- spdlog 1.14.1 - 日志系统 +- fmt 10.2.1 - 格式化库 +- nlohmann_json 3.11.3 - JSON处理 +- yaml-cpp 0.8.0 - YAML配置 +- protobuf 3.21.12 - 消息序列化 +- gtest 1.14.0 - 单元测试 +- benchmark 1.8.3 - 性能测试 +- boost 1.88.0 - 核心工具库 +- zeromq 4.3.5 - 消息队列 +- cppzmq 4.11.0 - ZeroMQ C++绑定 +- eigen 3.4.0 - 数学库 +- onetbb 2022.2.0 - 并行处理 + +### 12.2 CMake构建配置 + +**关键配置项** +- C++标准:C++23 +- 构建类型:Debug, Release, RelWithDebInfo +- SIMD优化:可选启AVX2/AVX-512 +- 跨平台检测:自动检测OS和架构 +- 编译器选项:严格警告,优化设置 + +### 12.3 编译器要求 + +**最低编译器版本** +- Windows: MSVC 2022 (19.30+) +- Linux: GCC 13+ 或 Clang 17+ +- macOS: AppleClang 15+ 或 Clang 17+ + +**推荐编译器设置** +- C++23支持完整 +- 现代标准库实现 +- 优秀的诊断信息 +- 良好的优化能力 + +--- + +## 13. 实现建议和优先级 + +### 13.1 实现路线图 + +**阶段1:核心基础(优先级:高)** +- [ ] 音频引擎核心架构 +- [ ] 基础进程间通信(ZeroMQ + 共享内存) +- [ ] 内存管理系统 +- [ ] 基础SIMD框架 + +**阶段2:插件系统(优先级:高)** +- [ ] 插件沙盒隔离机制 +- [ ] 插件加载和管理 +- [ ] 插件通信协议 +- [ ] 插件故障恢复 + +**阶段3:错误处理(优先级:中)** +- [ ] 错误分类系统 +- [ ] 容错机制实现 +- [ ] 日志系统集成 +- [ ] 健康监控系统 + +**阶段4:网络通信(优先级:中)** +- [ ] 网络协议栈 +- [ ] 本地和远程通信 +- [ ] 音频流传输 +- [ ] 设备发现机制 + +**阶段5:安全强化(优先级:中)** +- [ ] 网络加密(TLS) +- [ ] 身份认证系统 +- [ ] 输入验证框架 +- [ ] 审计日志系统 + +**阶段6:性能优化(优先级:中低)** +- [ ] 高级SIMD优化 +- [ ] 内存池优化 +- [ ] 线程模型调优 +- [ ] I/O优化 + +**阶段7:扩展功能(优先级:低)** +- [ ] 高级插件格式支持 +- [ ] UI扩展系统 +- [ ] 分布式处理 +- [ ] 云端集成 + +### 13.2 开发最佳实践 + +**代码规范** +- 遵循Modern C++最佳实践 +- 使用RAII管理资源 +- 强制使用智能指针 +- 避免裸指针和手动内存管理 +- 使用`const`和`constexpr` + +**测试策略** +- 单元测试覆盖核心功能 +- 集成测试验证组件交互 +- 性能测试确保实时性 +- 压力测试验证稳定性 +- 跨平台测试确保兼容性 + +**文档要求** +- API文档(Doxygen) +- 架构文档(本文档) +- 用户指南 +- 开发者指南 +- 示例和教程 + +--- + +## 14. 风险评估和缓解策略 + +### 14.1 技术风险 + +**风险1:实时性能要求** +- 描述:音频处理必须满足严格的实时性要求 +- 缓解: + - 预分配所有资源 + - 使用无锁数据结构 + - 实时线程优先级设置 + - 性能监控和告警 + +**风险2:跨平台兼容性** +- 描述:不同平台API差异可能导致兼容性问题 +- 缓解: + - 清晰的抽象层设计 + - 充分的跨平台测试 + - 平台特定代码隔离 + - 持续集成测试 + +**风险3:插件稳定性** +- 描述:第三方插件可能崩溃或行为异常 +- 缓解: + - 严格的沙盒隔离 + - 完善的故障恢复机制 + - 插件验证和监控 + - 降级模式支持 + +**风险4:网络延迟和不稳定** +- 描述:网络传输可能影响音频质量 +- 缓解: + - 自适应码率控制 + - 丢包检测和重传 + - 缓冲区自适应调整 + - 降级模式支持 + +### 14.2 项目风险 + +**风险5:开发复杂度高** +- 描述:系统架构复杂,开发周期可能较长 +- 缓解: + - 分阶段实施 + - 核心功能优先 + - 充分的原型验证 + - 定期review和调整 + +**风险6:第三方依赖** +- 描述:依赖第三方库可能带来版本和兼容性问题 +- 缓解: + - 使用稳定版本 + - 依赖锁定和版本控制 + - 定期更新和测试 + - 必要时考虑替代方案 + +--- + +## 15. 总结 + +本架构设计文档提供了一个完整的、企业级的C++23跨平台音频后端系统技术方案。该系统具有以下核心优势: + +**技术优势** +- ✅ 多进程架构确保稳定性和隔离性 +- ✅ 高效的双通道通信机制 +- ✅ 运行时SIMD优化保性能 +- ✅ 完善的错误处理和容错机制 +- ✅ 企业级安全措施 +- ✅ 高度模块化和可扩展设计 + +**实施建议** +- 采用分阶段实施策略 +- 核心功能优先开发 +- 持续集成和测试 +- 定期性能评估和优化 +- 充分的文档和示例 + +**后续工作** +- 详细的API设计文档 +- 具体模块实现规范 +- 性能基准和测试计划 +- 部署和运维指南 + +本架构设计为后续的具体实现提供了坚实的理论基础和技术指导。 + +--- + +## 附录A:术语表 + +- **SIMD**:Single Instruction Multiple Data,单指令多数流 +- **IPC**:Inter-Process Communication,进程通信 +- **ZeroMQ**:高性能步消息库 +- **ASIO**:Audio Stream Input/Output,专业音频接口 +- **VST**:Virtual Studio Technology,虚拟工室技术 +- **RAII**:Resource Acquisition Is Initialization,资源取即初始化 +- **TLS**:Transport Layer Security,传输层安 +- **ASLR**:Address Space Layout Randomization,地址间布局随机化 +- **DEP/NX**:Data Execution Prevention/No-Execute,数据执行保护 +- **NUMA**:Non-Uniform Memory Access,非一致性内存访问 + +--- + +## 附录B:参考资料 + +**C++23标准** +- ISO/IEC 14882:2023 Programming Language C++ + +**音频编程** +- The Audio Programming Book (MIT Press) +- Designing Audio Effect Plugins in C++ (Will Pirkle) + +**实时系统** +- Real-Time Systems Design and Analysis (Phillip A. Laplante) + +**网络编程** +- UNIX Network Programming (W. Richard Stevens) +- ZeroMQ: Messaging for Many Applications + +**安全编程** +- The Art of Software Security Assessment +- Secure Programming Cookbook for C and C++ + +--- + +**文档结束** \ No newline at end of file diff --git a/setup_conan.bat b/setup_conan.bat new file mode 100644 index 0000000..ff33399 --- /dev/null +++ b/setup_conan.bat @@ -0,0 +1,4 @@ +conan install . --build=missing --settings=build_type=Debug --settings=compiler.cppstd=23 +@REM conan install . --output-folder=build --build=missing --settings=build_type=Release --settings=compiler.cppstd=23 + +pause \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..6adedfb --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,63 @@ +# ================================================================================================ +# Audio Backend Framework - 源代码目录CMake配置 +# ================================================================================================ +# 描述: 协调管理各个音频后端模块的构建 +# 架构: 模块化设计,每个模块独立管理自己的包含路径和依赖 +# ================================================================================================ + +message(STATUS "") +message(STATUS "=== 配置源代码模块 ===") + +# ================================================================================================ +# 核心模块 - 按依赖顺序添加 +# ================================================================================================ + +# 公共组件模块 (最底层,其他模块依赖) +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/common/CMakeLists.txt) + add_subdirectory(common) + message(STATUS "✓ 添加公共组件模块: common/") +endif() + +# 通信模块 (IPC和网络通信) +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/communication/CMakeLists.txt) + add_subdirectory(communication) + message(STATUS "✓ 添加通信模块: communication/") +endif() + +# SIMD优化模块 (性能关键路径) +if(DAW_ENABLE_SIMD AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/simd/CMakeLists.txt) + add_subdirectory(simd) + message(STATUS "✓ 添加SIMD优化模块: simd/") +endif() + +# 音频引擎核心模块 +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/engine/CMakeLists.txt) + add_subdirectory(engine) + message(STATUS "✓ 添加音频引擎模块: engine/") +endif() + +# 插件沙盒宿主模块 +if(DAW_ENABLE_SANDBOX AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/plugin_host/CMakeLists.txt) + add_subdirectory(plugin_host) + message(STATUS "✓ 添加插件沙盒模块: plugin_host/") +endif() + +# 前端进程模块 +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/frontend/CMakeLists.txt) + add_subdirectory(frontend) + message(STATUS "✓ 添加前端进程模块: frontend/") +endif() + +# ================================================================================================ +# 模块配置摘要 +# ================================================================================================ +message(STATUS "") +message(STATUS "=== 源代码模块配置摘要 ===") +message(STATUS "架构设计: 模块化多进程系统") +message(STATUS "核心特性:") +message(STATUS " - 进程隔离: 音频引擎 | 插件沙盒 | 前端UI") +message(STATUS " - 双通道通信: ZeroMQ + Boost共享内存") +message(STATUS " - SIMD优化: ${DAW_ENABLE_SIMD}") +message(STATUS " - 插件沙盒: ${DAW_ENABLE_SANDBOX}") +message(STATUS " - 网络通信: ${DAW_ENABLE_NETWORK}") +message(STATUS "") \ No newline at end of file diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt new file mode 100644 index 0000000..163475c --- /dev/null +++ b/src/common/CMakeLists.txt @@ -0,0 +1,98 @@ +# ================================================================================================ +# Audio Backend - 公共组件模块 +# ================================================================================================ +# 描述: 提供基础工具类、数据结构和所有模块共享的功能 +# 依赖: Boost、spdlog、fmt、nlohmann_json +# ================================================================================================ + +# ================================================================================================ +# 自动收集源文件和头文件 +# ================================================================================================ +set(MODULE_SOURCES "") +retrieve_files(${CMAKE_CURRENT_SOURCE_DIR} MODULE_SOURCES) + +# 如果当前没有源文件,创建一个空目标占位 +if(NOT MODULE_SOURCES) + message(STATUS "Common模块: 当前无源文件,创建接口库占位") + add_library(audio_backend_common INTERFACE) + add_library(AudioBackend::Common ALIAS audio_backend_common) + + # 设置接口包含路径 + target_include_directories(audio_backend_common INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR} + ) + + # 设置接口依赖 + target_link_libraries(audio_backend_common INTERFACE + ${audio_backend_project_options} + Boost::boost + Boost::filesystem + Boost::system + Boost::thread + spdlog::spdlog + fmt::fmt + nlohmann_json::nlohmann_json + yaml-cpp::yaml-cpp + ) + + return() +endif() + +# ================================================================================================ +# 库目标定义 +# ================================================================================================ +add_library(audio_backend_common STATIC ${MODULE_SOURCES}) + +# 设置别名,使其他模块可以使用命名空间风格引用此库 +add_library(AudioBackend::Common ALIAS audio_backend_common) + +# ================================================================================================ +# 目标属性配置 +# ================================================================================================ +target_include_directories(audio_backend_common + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) + +# ================================================================================================ +# 依赖关系配置 +# ================================================================================================ +target_link_libraries(audio_backend_common + PUBLIC + ${audio_backend_project_options} + Boost::boost + Boost::filesystem + Boost::system + Boost::thread + PRIVATE + spdlog::spdlog + fmt::fmt + nlohmann_json::nlohmann_json + yaml-cpp::yaml-cpp +) + +# ================================================================================================ +# 目标编译定义 +# ================================================================================================ +target_compile_definitions(audio_backend_common + PRIVATE + AUDIO_BACKEND_COMMON_EXPORTS + PUBLIC + $<$:AUDIO_BACKEND_ENABLE_PROFILING> +) + +# ================================================================================================ +# 操作系统平台定义 +# ================================================================================================ +add_os_definitions(audio_backend_common) + +# ================================================================================================ +# 安装规则 +# ================================================================================================ +install(TARGETS audio_backend_common + EXPORT AudioBackendTargets + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} +) + +message(STATUS "Common模块: 已配置 ${MODULE_SOURCES}个文件") \ No newline at end of file diff --git a/src/common/error.cpp b/src/common/error.cpp new file mode 100644 index 0000000..5b57aff --- /dev/null +++ b/src/common/error.cpp @@ -0,0 +1,297 @@ +// ================================================================================================ +// Audio Backend - 错误处理和异常类实现 +// ================================================================================================ + +#include "error.h" +#include +#include + +#if ALICHO_PLATFORM_WINDOWS +#include +#elif ALICHO_PLATFORM_UNIX +#include +#endif + +namespace audio_backend::common { + +// ================================================================================================ +// 错误码描述映射 +// ================================================================================================ +static const std::unordered_map error_descriptions = { + // 通用错误 + {ErrorCode::SUCCESS, "操作成功"}, + {ErrorCode::UNKNOWN_ERROR, "未知错误"}, + {ErrorCode::INVALID_ARGUMENT, "无效参数"}, + {ErrorCode::INVALID_OPERATION, "无效操作"}, + {ErrorCode::NOT_IMPLEMENTED, "功能未实现"}, + {ErrorCode::OUT_OF_MEMORY, "内存不足"}, + {ErrorCode::OPERATION_TIMED_OUT, "操作超时"}, + {ErrorCode::NOT_INITIALIZED, "未初始化"}, + {ErrorCode::ALREADY_INITIALIZED, "已经初始化"}, + + // 文件和I/O错误 + {ErrorCode::FILE_NOT_FOUND, "文件未找到"}, + {ErrorCode::FILE_ACCESS_DENIED, "文件访问被拒绝"}, + {ErrorCode::FILE_READ_ERROR, "文件读取错误"}, + {ErrorCode::FILE_WRITE_ERROR, "文件写入错误"}, + {ErrorCode::FILE_FORMAT_ERROR, "文件格式错误"}, + + // 音频处理错误 + {ErrorCode::AUDIO_FORMAT_ERROR, "音频格式错误"}, + {ErrorCode::AUDIO_DEVICE_ERROR, "音频设备错误"}, + {ErrorCode::AUDIO_BUFFER_UNDERRUN, "音频缓冲区欠载"}, + {ErrorCode::AUDIO_BUFFER_OVERRUN, "音频缓冲区溢出"}, + {ErrorCode::AUDIO_SAMPLE_RATE_MISMATCH, "采样率不匹配"}, + {ErrorCode::AUDIO_CHANNEL_COUNT_MISMATCH, "声道数不匹配"}, + + // 插件错误 + {ErrorCode::PLUGIN_LOAD_ERROR, "插件加载错误"}, + {ErrorCode::PLUGIN_NOT_FOUND, "插件未找到"}, + {ErrorCode::PLUGIN_VERSION_MISMATCH, "插件版本不匹配"}, + {ErrorCode::PLUGIN_INITIALIZATION_ERROR, "插件初始化错误"}, + {ErrorCode::PLUGIN_COMMUNICATION_ERROR, "插件通信错误"}, + {ErrorCode::PLUGIN_EXECUTION_ERROR, "插件执行错误"}, + {ErrorCode::PLUGIN_TIMEOUT, "插件超时"}, + + // 通信错误 + {ErrorCode::COMMUNICATION_ERROR, "通信错误"}, + {ErrorCode::CONNECTION_ERROR, "连接错误"}, + {ErrorCode::DISCONNECTED, "连接已断开"}, + {ErrorCode::MESSAGE_FORMAT_ERROR, "消息格式错误"}, + {ErrorCode::PROTOCOL_ERROR, "协议错误"}, + {ErrorCode::TIMEOUT, "超时"}, + + // 系统错误 + {ErrorCode::SYSTEM_ERROR, "系统错误"}, + {ErrorCode::PERMISSION_DENIED, "权限被拒绝"}, + {ErrorCode::NOT_ENOUGH_RESOURCES, "资源不足"} +}; + +// ================================================================================================ +// 错误分类映射 +// ================================================================================================ +static const std::unordered_map error_categories = { + // 通用错误 + {ErrorCode::SUCCESS, ErrorCategory::GENERAL}, + {ErrorCode::UNKNOWN_ERROR, ErrorCategory::GENERAL}, + {ErrorCode::INVALID_ARGUMENT, ErrorCategory::GENERAL}, + {ErrorCode::INVALID_OPERATION, ErrorCategory::GENERAL}, + {ErrorCode::NOT_IMPLEMENTED, ErrorCategory::GENERAL}, + {ErrorCode::OUT_OF_MEMORY, ErrorCategory::GENERAL}, + {ErrorCode::OPERATION_TIMED_OUT, ErrorCategory::GENERAL}, + {ErrorCode::NOT_INITIALIZED, ErrorCategory::GENERAL}, + {ErrorCode::ALREADY_INITIALIZED, ErrorCategory::GENERAL}, + + // 文件错误 + {ErrorCode::FILE_NOT_FOUND, ErrorCategory::FILE}, + {ErrorCode::FILE_ACCESS_DENIED, ErrorCategory::FILE}, + {ErrorCode::FILE_READ_ERROR, ErrorCategory::FILE}, + {ErrorCode::FILE_WRITE_ERROR, ErrorCategory::FILE}, + {ErrorCode::FILE_FORMAT_ERROR, ErrorCategory::FILE}, + + // 音频错误 + {ErrorCode::AUDIO_FORMAT_ERROR, ErrorCategory::AUDIO}, + {ErrorCode::AUDIO_DEVICE_ERROR, ErrorCategory::AUDIO}, + {ErrorCode::AUDIO_BUFFER_UNDERRUN, ErrorCategory::AUDIO}, + {ErrorCode::AUDIO_BUFFER_OVERRUN, ErrorCategory::AUDIO}, + {ErrorCode::AUDIO_SAMPLE_RATE_MISMATCH, ErrorCategory::AUDIO}, + {ErrorCode::AUDIO_CHANNEL_COUNT_MISMATCH, ErrorCategory::AUDIO}, + + // 插件错误 + {ErrorCode::PLUGIN_LOAD_ERROR, ErrorCategory::PLUGIN}, + {ErrorCode::PLUGIN_NOT_FOUND, ErrorCategory::PLUGIN}, + {ErrorCode::PLUGIN_VERSION_MISMATCH, ErrorCategory::PLUGIN}, + {ErrorCode::PLUGIN_INITIALIZATION_ERROR, ErrorCategory::PLUGIN}, + {ErrorCode::PLUGIN_COMMUNICATION_ERROR, ErrorCategory::PLUGIN}, + {ErrorCode::PLUGIN_EXECUTION_ERROR, ErrorCategory::PLUGIN}, + {ErrorCode::PLUGIN_TIMEOUT, ErrorCategory::PLUGIN}, + + // 通信错误 + {ErrorCode::COMMUNICATION_ERROR, ErrorCategory::COMMUNICATION}, + {ErrorCode::CONNECTION_ERROR, ErrorCategory::COMMUNICATION}, + {ErrorCode::DISCONNECTED, ErrorCategory::COMMUNICATION}, + {ErrorCode::MESSAGE_FORMAT_ERROR, ErrorCategory::COMMUNICATION}, + {ErrorCode::PROTOCOL_ERROR, ErrorCategory::COMMUNICATION}, + {ErrorCode::TIMEOUT, ErrorCategory::COMMUNICATION}, + + // 系统错误 + {ErrorCode::SYSTEM_ERROR, ErrorCategory::SYSTEM}, + {ErrorCode::PERMISSION_DENIED, ErrorCategory::SYSTEM}, + {ErrorCode::NOT_ENOUGH_RESOURCES, ErrorCategory::SYSTEM} +}; + +// ================================================================================================ +// 公共函数实现 +// ================================================================================================ + +ErrorCategory get_error_category(ErrorCode code) { + auto it = error_categories.find(code); + if (it != error_categories.end()) { + return it->second; + } + return ErrorCategory::GENERAL; +} + +std::string get_error_description(ErrorCode code) { + auto it = error_descriptions.find(code); + if (it != error_descriptions.end()) { + return it->second; + } + return "未知错误代码: " + std::to_string(static_cast(code)); +} + +std::exception_ptr create_exception(ErrorCode code, + const std::string& message, + const std::string& details) { + ErrorCategory category = get_error_category(code); + + try { + switch (category) { + case ErrorCategory::FILE: + throw FileException(code, message, details); + case ErrorCategory::AUDIO: + throw AudioException(code, message, details); + case ErrorCategory::PLUGIN: + throw PluginException(code, message, details); + case ErrorCategory::COMMUNICATION: + throw CommunicationException(code, message, details); + case ErrorCategory::SYSTEM: + throw SystemException(code, message, details); + default: + throw AudioBackendException(code, message, details); + } + } catch (...) { + return std::current_exception(); + } +} + +void throw_exception(ErrorCode code, + const std::string& message, + const std::string& details) { + std::rethrow_exception(create_exception(code, message, details)); +} + +void check_error(bool condition, + ErrorCode error_code, + const std::string& message, + const std::string& details) { + if (condition) { + throw_exception(error_code, message, details); + } +} + +ErrorCode system_error_to_error_code(int system_error) { +#if ALICHO_PLATFORM_WINDOWS + switch (system_error) { + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + return ErrorCode::FILE_NOT_FOUND; + case ERROR_ACCESS_DENIED: + return ErrorCode::FILE_ACCESS_DENIED; + case ERROR_NOT_ENOUGH_MEMORY: + case ERROR_OUTOFMEMORY: + return ErrorCode::OUT_OF_MEMORY; + case ERROR_TIMEOUT: + return ErrorCode::OPERATION_TIMED_OUT; + case ERROR_INVALID_PARAMETER: + return ErrorCode::INVALID_ARGUMENT; + default: + return ErrorCode::SYSTEM_ERROR; + } +#elif ALICHO_PLATFORM_UNIX + switch (system_error) { + case ENOENT: + return ErrorCode::FILE_NOT_FOUND; + case EACCES: + case EPERM: + return ErrorCode::FILE_ACCESS_DENIED; + case ENOMEM: + return ErrorCode::OUT_OF_MEMORY; + case ETIMEDOUT: + return ErrorCode::OPERATION_TIMED_OUT; + case EINVAL: + return ErrorCode::INVALID_ARGUMENT; + default: + return ErrorCode::SYSTEM_ERROR; + } +#else + return ErrorCode::SYSTEM_ERROR; +#endif +} + +ErrorCode std_error_to_error_code(const std::error_code& ec) { + if (ec.category() == std::generic_category()) { + return system_error_to_error_code(ec.value()); + } else if (ec.category() == AudioBackendErrorCategory::instance()) { + return static_cast(ec.value()); + } else { + return ErrorCode::SYSTEM_ERROR; + } +} + +// ================================================================================================ +// ErrorHandler实现 +// ================================================================================================ + +void ErrorHandler::add_error_handler(const ErrorCallback& handler) { + handlers_.push_back(handler); +} + +void ErrorHandler::remove_error_handler(const ErrorCallback& handler) { + // 注意:这个比较可能不会按预期工作,因为std::function的比较很复杂 + // 在实际使用中,可能需要使用其他方式来管理处理器(比如返回ID) + auto it = std::find_if(handlers_.begin(), handlers_.end(), + [&handler](const ErrorCallback& h) { + // 这里的比较不太可靠,应该考虑使用其他方式 + return &h == &handler; + }); + + if (it != handlers_.end()) { + handlers_.erase(it); + } +} + +void ErrorHandler::handle_error(const AudioBackendException& exception) { + for (const auto& handler : handlers_) { + try { + handler(exception); + } catch (...) { + // 忽略错误处理器中的异常,防止无限递归 + } + } +} + +void ErrorHandler::handle_error(ErrorCode code, + const std::string& message, + const std::string& details) { + try { + AudioBackendException exception(code, message, details); + handle_error(exception); + } catch (...) { + // 忽略创建异常时的错误 + } +} + +void ErrorHandler::handle_exception(std::exception_ptr eptr) { + if (!eptr) return; + + try { + std::rethrow_exception(eptr); + } catch (const AudioBackendException& e) { + handle_error(e); + } catch (const std::exception& e) { + // 对于其他标准异常,创建一个通用的AudioBackendException + AudioBackendException wrapper(ErrorCode::UNKNOWN_ERROR, e.what()); + handle_error(wrapper); + } catch (...) { + // 对于其他异常,创建一个未知错误 + AudioBackendException wrapper(ErrorCode::UNKNOWN_ERROR, "未知异常类型"); + handle_error(wrapper); + } +} + +void ErrorHandler::clear_handlers() { + handlers_.clear(); +} + +} // namespace audio_backend::common \ No newline at end of file diff --git a/src/common/error.h b/src/common/error.h new file mode 100644 index 0000000..8563fc7 --- /dev/null +++ b/src/common/error.h @@ -0,0 +1,382 @@ +// ================================================================================================ +// Audio Backend - 错误处理和异常类 +// ================================================================================================ +// 描述: 定义自定义异常层次结构和错误处理机制 +// 功能: 提供统一的异常类型和错误码 +// ================================================================================================ + +#pragma once + +#include +#include +#include +#include +#include + +namespace audio_backend::common { + +// ================================================================================================ +// 错误码定义 +// ================================================================================================ +enum class ErrorCode { + // 通用错误 (0-999) + SUCCESS = 0, + UNKNOWN_ERROR = 1, + INVALID_ARGUMENT = 2, + INVALID_OPERATION = 3, + NOT_IMPLEMENTED = 4, + OUT_OF_MEMORY = 5, + OPERATION_TIMED_OUT = 6, + NOT_INITIALIZED = 7, + ALREADY_INITIALIZED = 8, + + // 文件和I/O错误 (1000-1999) + FILE_NOT_FOUND = 1000, + FILE_ACCESS_DENIED = 1001, + FILE_READ_ERROR = 1002, + FILE_WRITE_ERROR = 1003, + FILE_FORMAT_ERROR = 1004, + + // 音频处理错误 (2000-2999) + AUDIO_FORMAT_ERROR = 2000, + AUDIO_DEVICE_ERROR = 2001, + AUDIO_BUFFER_UNDERRUN = 2002, + AUDIO_BUFFER_OVERRUN = 2003, + AUDIO_SAMPLE_RATE_MISMATCH = 2004, + AUDIO_CHANNEL_COUNT_MISMATCH = 2005, + + // 插件错误 (3000-3999) + PLUGIN_LOAD_ERROR = 3000, + PLUGIN_NOT_FOUND = 3001, + PLUGIN_VERSION_MISMATCH = 3002, + PLUGIN_INITIALIZATION_ERROR = 3003, + PLUGIN_COMMUNICATION_ERROR = 3004, + PLUGIN_EXECUTION_ERROR = 3005, + PLUGIN_TIMEOUT = 3006, + + // 通信错误 (4000-4999) + COMMUNICATION_ERROR = 4000, + CONNECTION_ERROR = 4001, + DISCONNECTED = 4002, + MESSAGE_FORMAT_ERROR = 4003, + PROTOCOL_ERROR = 4004, + TIMEOUT = 4005, + + // 系统错误 (5000-5999) + SYSTEM_ERROR = 5000, + PERMISSION_DENIED = 5001, + NOT_ENOUGH_RESOURCES = 5002 +}; + +// ================================================================================================ +// 错误分类定义 +// ================================================================================================ +enum class ErrorCategory { + GENERAL, + FILE, + AUDIO, + PLUGIN, + COMMUNICATION, + SYSTEM +}; + +// 获取错误分类 +ErrorCategory get_error_category(ErrorCode code); + +// 获取错误码对应的描述信息 +std::string get_error_description(ErrorCode code); + +// ================================================================================================ +// 自定义错误类别(std::error_category扩展) +// ================================================================================================ +class AudioBackendErrorCategory : public std::error_category { +public: + static const AudioBackendErrorCategory& instance() { + static AudioBackendErrorCategory instance; + return instance; + } + + const char* name() const noexcept override { + return "audio_backend"; + } + + std::string message(int ev) const override { + return get_error_description(static_cast(ev)); + } + +private: + AudioBackendErrorCategory() = default; +}; + +// 创建error_code +inline std::error_code make_error_code(ErrorCode e) { + return {static_cast(e), AudioBackendErrorCategory::instance()}; +} + +// ================================================================================================ +// 基础异常类 +// ================================================================================================ +class AudioBackendException : public std::exception { +public: + explicit AudioBackendException(ErrorCode code, + const std::string& message = "", + const std::string& details = "") + : code_(code), message_(message), details_(details) { + // 如果没有提供消息,使用默认的错误描述 + if (message_.empty()) { + message_ = get_error_description(code); + } + + // 构建完整的错误消息 + if (!details_.empty()) { + full_message_ = message_ + " - " + details_; + } else { + full_message_ = message_; + } + } + + // 获取错误码 + ErrorCode code() const noexcept { + return code_; + } + + // 获取错误消息 + const std::string& message() const noexcept { + return message_; + } + + // 获取详细信息 + const std::string& details() const noexcept { + return details_; + } + + // 获取完整错误消息 + const char* what() const noexcept override { + return full_message_.c_str(); + } + + // 获取错误分类 + ErrorCategory category() const noexcept { + return get_error_category(code_); + } + + // 获取std::error_code + std::error_code error_code() const noexcept { + return make_error_code(code_); + } + + // 是否是某个错误码 + bool is(ErrorCode code) const noexcept { + return code_ == code; + } + + // 是否属于某个错误分类 + bool is_category(ErrorCategory category) const noexcept { + return category == get_error_category(code_); + } + +private: + ErrorCode code_; + std::string message_; + std::string details_; + std::string full_message_; +}; + +// ================================================================================================ +// 具体异常类 +// ================================================================================================ + +// 文件异常 +class FileException : public AudioBackendException { +public: + explicit FileException(ErrorCode code, + const std::string& message = "", + const std::string& details = "") + : AudioBackendException(code, message, details) { + if (!is_category(ErrorCategory::FILE)) { + throw std::invalid_argument("错误码不属于文件异常类别"); + } + } +}; + +// 音频异常 +class AudioException : public AudioBackendException { +public: + explicit AudioException(ErrorCode code, + const std::string& message = "", + const std::string& details = "") + : AudioBackendException(code, message, details) { + if (!is_category(ErrorCategory::AUDIO)) { + throw std::invalid_argument("错误码不属于音频异常类别"); + } + } +}; + +// 插件异常 +class PluginException : public AudioBackendException { +public: + explicit PluginException(ErrorCode code, + const std::string& message = "", + const std::string& details = "") + : AudioBackendException(code, message, details) { + if (!is_category(ErrorCategory::PLUGIN)) { + throw std::invalid_argument("错误码不属于插件异常类别"); + } + } +}; + +// 通信异常 +class CommunicationException : public AudioBackendException { +public: + explicit CommunicationException(ErrorCode code, + const std::string& message = "", + const std::string& details = "") + : AudioBackendException(code, message, details) { + if (!is_category(ErrorCategory::COMMUNICATION)) { + throw std::invalid_argument("错误码不属于通信异常类别"); + } + } +}; + +// 系统异常 +class SystemException : public AudioBackendException { +public: + explicit SystemException(ErrorCode code, + const std::string& message = "", + const std::string& details = "") + : AudioBackendException(code, message, details) { + if (!is_category(ErrorCategory::SYSTEM)) { + throw std::invalid_argument("错误码不属于系统异常类别"); + } + } +}; + +// ================================================================================================ +// 错误处理工具函数 +// ================================================================================================ + +// 根据错误码创建适当的异常 +std::exception_ptr create_exception(ErrorCode code, + const std::string& message = "", + const std::string& details = ""); + +// 根据错误码抛出异常 +[[noreturn]] void throw_exception(ErrorCode code, + const std::string& message = "", + const std::string& details = ""); + +// 错误检查函数(条件为true时抛出异常) +void check_error(bool condition, + ErrorCode error_code, + const std::string& message = "", + const std::string& details = ""); + +// 将系统错误码转换为AudioBackend错误码 +ErrorCode system_error_to_error_code(int system_error); + +// 将std::error_code转换为AudioBackend错误码 +ErrorCode std_error_to_error_code(const std::error_code& ec); + +// ================================================================================================ +// 错误处理器(用于收集和处理错误) +// ================================================================================================ +class ErrorHandler { +public: + // 错误处理回调函数类型 + using ErrorCallback = std::function; + + // 获取单例实例 + static ErrorHandler& instance() { + static ErrorHandler instance; + return instance; + } + + // 禁止拷贝和移动 + ErrorHandler(const ErrorHandler&) = delete; + ErrorHandler& operator=(const ErrorHandler&) = delete; + ErrorHandler(ErrorHandler&&) = delete; + ErrorHandler& operator=(ErrorHandler&&) = delete; + + // 添加全局错误处理回调 + void add_error_handler(const ErrorCallback& handler); + + // 移除错误处理回调 + void remove_error_handler(const ErrorCallback& handler); + + // 处理错误 + void handle_error(const AudioBackendException& exception); + + // 处理错误(从错误码创建异常) + void handle_error(ErrorCode code, + const std::string& message = "", + const std::string& details = ""); + + // 处理异常捕获 + void handle_exception(std::exception_ptr eptr); + + // 清除所有错误处理回调 + void clear_handlers(); + +private: + ErrorHandler() = default; + ~ErrorHandler() = default; + + std::vector handlers_; +}; + +// ================================================================================================ +// RAII风格的错误处理辅助类 +// ================================================================================================ +class ScopedErrorHandler { +public: + explicit ScopedErrorHandler(ErrorHandler::ErrorCallback handler) { + ErrorHandler::instance().add_error_handler(handler); + } + + ~ScopedErrorHandler() { + ErrorHandler::instance().remove_error_handler(handler_); + } + + // 禁止拷贝和移动 + ScopedErrorHandler(const ScopedErrorHandler&) = delete; + ScopedErrorHandler& operator=(const ScopedErrorHandler&) = delete; + ScopedErrorHandler(ScopedErrorHandler&&) = delete; + ScopedErrorHandler& operator=(ScopedErrorHandler&&) = delete; + +private: + ErrorHandler::ErrorCallback handler_; +}; + +// ================================================================================================ +// 宏定义 +// ================================================================================================ + +#define AUDIO_CHECK_ERROR(condition, error_code, message) \ + audio_backend::common::check_error((condition), (error_code), (message), \ + "文件: " __FILE__ ", 行: " + std::to_string(__LINE__)) + +#define AUDIO_THROW_ERROR(error_code, message) \ + audio_backend::common::throw_exception((error_code), (message), \ + "文件: " __FILE__ ", 行: " + std::to_string(__LINE__)) + +#define AUDIO_HANDLE_ERROR(error_code, message) \ + audio_backend::common::ErrorHandler::instance().handle_error((error_code), (message), \ + "文件: " __FILE__ ", 行: " + std::to_string(__LINE__)) + +#define AUDIO_TRY_CATCH_ALL() \ + try + +#define AUDIO_CATCH_ALL() \ + catch(...) { \ + audio_backend::common::ErrorHandler::instance().handle_exception(std::current_exception()); \ + } + +} // namespace audio_backend::common + +// ================================================================================================ +// 在std命名空间添加特化,允许将ErrorCode作为错误码使用 +// ================================================================================================ +namespace std { + template<> + struct is_error_code_enum : public true_type {}; +} // namespace std \ No newline at end of file diff --git a/src/common/logger.cpp b/src/common/logger.cpp new file mode 100644 index 0000000..7c4052b --- /dev/null +++ b/src/common/logger.cpp @@ -0,0 +1,181 @@ +// ================================================================================================ +// Audio Backend - 日志系统实现 +// ================================================================================================ + +#include "logger.h" +#include +#include + +#if ALICHO_PLATFORM_WINDOWS +#include +#endif + +namespace audio_backend::common { + +namespace fs = std::filesystem; + +// ================================================================================================ +// Logger实现 +// ================================================================================================ + +Logger::Logger() = default; + +Logger::~Logger() { + shutdown(); +} + +void Logger::initialize(const std::string& app_name, + LogLevel console_level, + bool file_logging, + const std::string& log_dir, + size_t max_file_size, + size_t max_files) { + if (initialized_) { + return; // 已经初始化 + } + + try { + // 创建控制台sink + console_sink_ = std::make_shared(); + console_sink_->set_level(static_cast(console_level)); + console_sink_->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%^%l%$] [%n] %v"); + + std::vector sinks; + sinks.push_back(console_sink_); + + // 如果启用文件日志,创建文件sink + if (file_logging) { + create_log_directory(log_dir); + log_directory_ = log_dir; + + // 创建日志文件路径 + fs::path log_file_path = fs::path(log_dir) / (app_name + ".log"); + + file_sink_ = std::make_shared( + log_file_path.string(), max_file_size, max_files); + file_sink_->set_level(spdlog::level::trace); // 文件记录所有级别 + file_sink_->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] [%n] [%t] %v"); + + sinks.push_back(file_sink_); + } + + // 创建主日志器 + logger_ = std::make_shared(app_name, sinks.begin(), sinks.end()); + logger_->set_level(spdlog::level::trace); // 总是记录所有级别 + logger_->flush_on(spdlog::level::err); // 错误时立即刷新 + + // 设置为默认日志器 + spdlog::set_default_logger(logger_); + + // 设置异步刷新 + spdlog::flush_every(std::chrono::seconds(3)); + + initialized_ = true; + + logger_->info("音频后端日志系统已初始化"); + logger_->info("控制台日志级别: {}", spdlog::level::to_string_view(console_sink_->level())); + if (file_logging) { + logger_->info("文件日志目录: {}", log_dir); + } + + } catch (const spdlog::spdlog_ex& ex) { + std::cerr << "日志初始化失败: " << ex.what() << std::endl; + initialized_ = false; + } +} + +void Logger::shutdown() { + if (!initialized_) { + return; + } + + if (logger_) { + logger_->info("关闭日志系统"); + logger_->flush(); + logger_.reset(); + } + + console_sink_.reset(); + file_sink_.reset(); + + spdlog::shutdown(); + initialized_ = false; +} + +void Logger::set_level(LogLevel level) { + if (logger_) { + logger_->set_level(static_cast(level)); + } +} + +void Logger::set_console_level(LogLevel level) { + if (console_sink_) { + console_sink_->set_level(static_cast(level)); + } +} + +void Logger::set_file_level(LogLevel level) { + if (file_sink_) { + file_sink_->set_level(static_cast(level)); + } +} + +LogLevel Logger::get_level() const { + if (logger_) { + return static_cast(logger_->level()); + } + return LogLevel::INFO; +} + +std::shared_ptr Logger::get_module_logger(const std::string& module_name) { + // 检查是否已存在该模块的日志器 + auto existing_logger = spdlog::get(module_name); + if (existing_logger) { + return existing_logger; + } + + // 创建新的模块日志器 + return create_logger(module_name); +} + +void Logger::flush() { + if (logger_) { + logger_->flush(); + } +} + +std::shared_ptr Logger::create_logger(const std::string& logger_name) { + std::vector sinks; + + if (console_sink_) { + sinks.push_back(console_sink_); + } + + if (file_sink_) { + sinks.push_back(file_sink_); + } + + auto new_logger = std::make_shared(logger_name, sinks.begin(), sinks.end()); + new_logger->set_level(spdlog::level::trace); + new_logger->flush_on(spdlog::level::err); + + // 注册日志器 + spdlog::register_logger(new_logger); + + return new_logger; +} + +void Logger::create_log_directory(const std::string& dir) { + try { + fs::path log_path(dir); + + if (!fs::exists(log_path)) { + fs::create_directories(log_path); + } + + } catch (const fs::filesystem_error& e) { + std::cerr << "创建日志目录失败: " << e.what() << std::endl; + } +} + +} // namespace audio_backend::common \ No newline at end of file diff --git a/src/common/logger.h b/src/common/logger.h new file mode 100644 index 0000000..2aff003 --- /dev/null +++ b/src/common/logger.h @@ -0,0 +1,179 @@ +// ================================================================================================ +// Audio Backend - 日志系统 +// ================================================================================================ +// 描述: 基于spdlog的日志系统封装 +// 功能: 提供统一的日志接口,支持多种日志级别和格式 +// ================================================================================================ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace audio_backend::common { + +// ================================================================================================ +// 日志级别枚举 +// ================================================================================================ +enum class LogLevel { + TRACE = spdlog::level::trace, + DEBUG = spdlog::level::debug, + INFO = spdlog::level::info, + WARN = spdlog::level::warn, + ERR = spdlog::level::err, + CRITICAL = spdlog::level::critical, + OFF = spdlog::level::off +}; + +// ================================================================================================ +// 日志系统封装类(单例模式) +// ================================================================================================ +class Logger { +public: + // 获取单例实例 + static Logger& instance() { + static Logger instance; + return instance; + } + + // 禁止拷贝和移动 + Logger(const Logger&) = delete; + Logger& operator=(const Logger&) = delete; + Logger(Logger&&) = delete; + Logger& operator=(Logger&&) = delete; + + // 初始化日志系统 + void initialize(const std::string& app_name = "AudioBackend", + LogLevel console_level = LogLevel::INFO, + bool file_logging = true, + const std::string& log_dir = "logs", + size_t max_file_size = 5 * 1024 * 1024, + size_t max_files = 3); + + // 关闭日志系统 + void shutdown(); + + // 设置全局日志级别 + void set_level(LogLevel level); + + // 设置控制台日志级别 + void set_console_level(LogLevel level); + + // 设置文件日志级别 + void set_file_level(LogLevel level); + + // 获取当前日志级别 + LogLevel get_level() const; + + // 获取主日志器 + std::shared_ptr get_logger() const { + return logger_; + } + + // 获取特定模块的日志器 + std::shared_ptr get_module_logger(const std::string& module_name); + + // 刷新日志缓冲区 + void flush(); + + // 便捷的日志记录方法 + template + void trace(std::string_view fmt, const Args&... args) { + if (logger_) logger_->trace(fmt, args...); + } + + template + void debug(std::string_view fmt, const Args&... args) { + if (logger_) logger_->debug(fmt, args...); + } + + template + void info(std::string_view fmt, const Args&... args) { + if (logger_) logger_->info(fmt, args...); + } + + template + void warn(std::string_view fmt, const Args&... args) { + if (logger_) logger_->warn(fmt, args...); + } + + template + void err(std::string_view fmt, const Args&... args) { + if (logger_) logger_->error(fmt, args...); + } + + template + void critical(std::string_view fmt, const Args&... args) { + if (logger_) logger_->critical(fmt, args...); + } + +private: + Logger(); + ~Logger(); + + // 创建日志器 + std::shared_ptr create_logger(const std::string& logger_name); + + // 创建日志目录 + void create_log_directory(const std::string& dir); + + std::shared_ptr logger_; + std::shared_ptr console_sink_; + std::shared_ptr file_sink_; + + std::string log_directory_; + bool initialized_ = false; +}; + +// ================================================================================================ +// 全局日志函数 +// ================================================================================================ +template +inline void log_trace(std::string_view fmt, const Args&... args) { + Logger::instance().trace(fmt, args...); +} + +template +inline void log_debug(std::string_view fmt, const Args&... args) { + Logger::instance().debug(fmt, args...); +} + +template +inline void log_info(std::string_view fmt, const Args&... args) { + Logger::instance().info(fmt, args...); +} + +template +inline void log_warn(std::string_view fmt, const Args&... args) { + Logger::instance().warn(fmt, args...); +} + +template +inline void log_err(std::string_view fmt, const Args&... args) { + Logger::instance().err(fmt, args...); +} + +template +inline void log_critical(std::string_view fmt, const Args&... args) { + Logger::instance().critical(fmt, args...); +} + +// ================================================================================================ +// 模块日志宏 +// ================================================================================================ +#define AUDIO_MODULE_LOGGER(module_name) \ + static auto logger = audio_backend::common::Logger::instance().get_module_logger(module_name) + +#define AUDIO_LOG_TRACE(...) if (logger) logger->trace(__VA_ARGS__) +#define AUDIO_LOG_DEBUG(...) if (logger) logger->debug(__VA_ARGS__) +#define AUDIO_LOG_INFO(...) if (logger) logger->info(__VA_ARGS__) +#define AUDIO_LOG_WARN(...) if (logger) logger->warn(__VA_ARGS__) +#define AUDIO_LOG_ERR(...) if (logger) logger->error(__VA_ARGS__) +#define AUDIO_LOG_CRITICAL(...) if (logger) logger->critical(__VA_ARGS__) + +} // namespace audio_backend::common \ No newline at end of file diff --git a/src/communication/CMakeLists.txt b/src/communication/CMakeLists.txt new file mode 100644 index 0000000..f886fb0 --- /dev/null +++ b/src/communication/CMakeLists.txt @@ -0,0 +1,112 @@ +# ================================================================================================ +# Audio Backend - 通信模块 +# ================================================================================================ +# 描述: 进程间通信(IPC)和网络通信实现 +# 功能: ZeroMQ消息队列、Boost共享内存、网络协议栈 +# 依赖: ZeroMQ、cppzmq、Boost::interprocess、protobuf +# ================================================================================================ + +# ================================================================================================ +# 自动收集源文件和头文件 +# ================================================================================================ +set(MODULE_SOURCES "") +retrieve_files(${CMAKE_CURRENT_SOURCE_DIR} MODULE_SOURCES) + +# 如果当前没有源文件,创建一个空目标占位 +if(NOT MODULE_SOURCES) + message(STATUS "Communication模块: 当前无源文件,创建接口库占位") + add_library(audio_backend_communication INTERFACE) + add_library(AudioBackend::Communication ALIAS audio_backend_communication) + + # 设置接口包含路径 + target_include_directories(audio_backend_communication INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR} + ) + + # 设置接口依赖 + target_link_libraries(audio_backend_communication INTERFACE + AudioBackend::Common + zeromq::zeromq + cppzmq::cppzmq + Boost::interprocess + protobuf::protobuf + ${PLATFORM_LIBS} + ) + + return() +endif() + +# ================================================================================================ +# 库目标定义 +# ================================================================================================ +add_library(audio_backend_communication STATIC ${MODULE_SOURCES}) + +# 设置别名 +add_library(AudioBackend::Communication ALIAS audio_backend_communication) + +# ================================================================================================ +# 目标属性配置 +# ================================================================================================ +target_include_directories(audio_backend_communication + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} +) + +# ================================================================================================ +# 依赖关系配置 +# ================================================================================================ +target_link_libraries(audio_backend_communication + PUBLIC + ${audio_backend_project_options} + AudioBackend::Common + zeromq::zeromq + cppzmq::cppzmq + Boost::interprocess + Boost::system + Boost::thread + PRIVATE + protobuf::protobuf + ${PLATFORM_LIBS} +) + +# ================================================================================================ +# 条件性网络支持 +# ================================================================================================ +if(DAW_ENABLE_NETWORK) + target_compile_definitions(audio_backend_communication + PUBLIC DAW_ENABLE_NETWORK + ) + + # 网络相关的平台库 + if(WIN32) + target_link_libraries(audio_backend_communication PRIVATE wsock32 ws2_32) + endif() +endif() + +# ================================================================================================ +# 目标编译定义 +# ================================================================================================ +target_compile_definitions(audio_backend_communication + PRIVATE + AUDIO_BACKEND_COMMUNICATION_EXPORTS + PUBLIC + $<$:ENHANCED_IPC_ENABLED> +) + +# ================================================================================================ +# 操作系统平台定义 +# ================================================================================================ +add_os_definitions(audio_backend_communication) + +# ================================================================================================ +# 安装规则 +# ================================================================================================ +install(TARGETS audio_backend_communication + EXPORT AudioBackendTargets + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} +) + +message(STATUS "Communication模块: 已配置 ${MODULE_SOURCES}个文件") \ No newline at end of file diff --git a/src/communication/README.md b/src/communication/README.md new file mode 100644 index 0000000..bd53412 --- /dev/null +++ b/src/communication/README.md @@ -0,0 +1,67 @@ +# 音频后端通信模块 + +## 目录结构 + +``` +src/communication/ +├── proto/ # Protobuf消息定义 +│ ├── common.proto # 公共类型和枚举 +│ ├── control.proto # 控制消息 +│ ├── audio_meta.proto # 音频元数据 +│ ├── plugin_mgmt.proto # 插件管理 +│ └── status.proto # 状态同步 +│ +├── zmq/ # ZeroMQ通信实现 +│ ├── socket.h/cpp # 套接字抽象 +│ ├── context.h/cpp # ZMQ上下文管理 +│ ├── publisher.h/cpp # 发布者实现 +│ ├── subscriber.h/cpp # 订阅者实现 +│ ├── requester.h/cpp # 请求者实现 +│ ├── responder.h/cpp # 响应者实现 +│ ├── poller.h/cpp # 事件轮询 +│ └── monitor.h/cpp # 连接监控 +│ +├── shm/ # Boost共享内存实现 +│ ├── memory_pool.h/cpp # 共享内存池 +│ ├── ring_buffer.h/cpp # 无锁环形缓冲区 +│ ├── triple_buffer.h/cpp # 三缓冲机制 +│ ├── sync.h/cpp # 跨进程同步原语 +│ └── allocator.h/cpp # 共享内存分配器 +│ +├── net/ # 网络通信功能 +│ ├── transport.h/cpp # 传输层抽象 +│ ├── discovery.h/cpp # 网络发现 +│ ├── session.h/cpp # 会话管理 +│ ├── stream.h/cpp # 音频流协议 +│ └── security.h/cpp # 安全功能 +│ +├── core/ # 核心通信组件 +│ ├── message.h/cpp # 消息抽象 +│ ├── serializer.h/cpp # 序列化器 +│ ├── router.h/cpp # 消息路由 +│ ├── endpoint.h/cpp # 通信端点 +│ └── error.h/cpp # 通信错误处理 +│ +└── manager.h/cpp # 通信管理器(统一接口) +``` + +## 通信策略 + +根据架构设计文档,系统采用双通道策略: + +1. **控制通道 (ZeroMQ)** + - 用于小消息 (<4KB) + - 用例:插件状态通知、控制命令、参数更新、错误报告 + - 特点:灵活的消息模式、自动重连、跨平台兼容性 + +2. **数据通道 (Boost共享内存)** + - 用于大数据传输 (>=4KB) + - 用例:音频缓冲区、批量参数数据、音频流 + - 特点:零拷贝、低延迟、高吞吐量 + +## 实现概述 + +- **ZeroMQ通信层**:封装ZeroMQ的不同消息模式(REQ-REP, PUB-SUB, PUSH-PULL),提供异步消息处理和回调机制 +- **Boost共享内存**:实现共享内存池、无锁环形缓冲和三缓冲机制 +- **统一通信接口**:通信管理器自动根据消息大小选择适当的传输通道 +- **网络通信**:实现TCP/UDP传输抽象和音频流协议 \ No newline at end of file diff --git a/src/communication/core/message.cpp b/src/communication/core/message.cpp new file mode 100644 index 0000000..e6822a0 --- /dev/null +++ b/src/communication/core/message.cpp @@ -0,0 +1,135 @@ +// ================================================================================================ +// Audio Backend - 消息抽象接口实现 +// ================================================================================================ + +#include "message.h" +#include "logger.h" + +#include +#include +#include +#include + +namespace audio_backend::communication { + +// ================================================================================================ +// Endpoint 实现 +// ================================================================================================ + +std::string Endpoint::to_string() const { + std::ostringstream oss; + oss << "Endpoint{id=" << id + << ", type=" << static_cast(type) + << ", address=" << address; + if (port > 0) { + oss << ", port=" << port; + } + oss << "}"; + return oss.str(); +} + +// ================================================================================================ +// IMessage 默认实现 +// ================================================================================================ + +bool IMessage::should_use_shared_memory() const { + // 默认基于消息大小判断 + return size() >= 4096; // 4KB阈值 +} + +TransportChannel IMessage::preferred_channel() const { + // 默认策略:大消息使用共享内存,小消息使用ZeroMQ + if (should_use_shared_memory()) { + return TransportChannel::SharedMemory; + } + + // 根据优先级选择通道 + if (priority() == MessagePriority::Realtime) { + return TransportChannel::SharedMemory; // 实时消息优先使用共享内存 + } + + return TransportChannel::ZmqControl; // 默认使用ZeroMQ控制通道 +} + +// ================================================================================================ +// Message 实现 +// ================================================================================================ + +Message::Message() + : message_id_(generate_message_id()) + , source_() + , destination_() + , priority_(MessagePriority::Normal) + , timestamp_(std::chrono::system_clock::now()) + , raw_data_() +{ +} + +Message::Message(const std::string& id, const Endpoint& source, const Endpoint& destination) + : message_id_(id) + , source_(source) + , destination_(destination) + , priority_(MessagePriority::Normal) + , timestamp_(std::chrono::system_clock::now()) + , raw_data_() +{ + if (message_id_.empty()) { + message_id_ = generate_message_id(); + } +} + +TransportChannel Message::preferred_channel() const { + // 基于消息大小选择通道 + if (should_use_shared_memory()) { + return TransportChannel::SharedMemory; + } + + // 实时优先级的消息优先使用共享内存以降低延迟 + if (priority_ == MessagePriority::Realtime) { + return TransportChannel::SharedMemory; + } + + // 关键消息使用可靠的ZeroMQ通道 + if (priority_ == MessagePriority::Critical) { + return TransportChannel::ZmqControl; + } + + return TransportChannel::ZmqControl; +} + +bool Message::should_use_shared_memory() const { + return raw_data_.size() >= SHARED_MEMORY_THRESHOLD; +} + +// ================================================================================================ +// 消息ID生成 +// ================================================================================================ + +std::string generate_message_id() { + // 使用原子计数器和时间戳生成唯一ID + static std::atomic counter{0}; + + auto now = std::chrono::system_clock::now(); + auto timestamp = std::chrono::duration_cast( + now.time_since_epoch()).count(); + + uint64_t count = counter.fetch_add(1, std::memory_order_relaxed); + + // 格式: timestamp-counter-random + std::ostringstream oss; + oss << std::hex << std::setfill('0'); + oss << std::setw(16) << timestamp; + oss << "-"; + oss << std::setw(8) << count; + oss << "-"; + + // 添加随机部分以进一步确保唯一性 + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution dis(0, 0xFFFFFFFF); + oss << std::setw(8) << dis(gen); + + return oss.str(); +} + +} // namespace audio_backend::communication \ No newline at end of file diff --git a/src/communication/core/message.h b/src/communication/core/message.h new file mode 100644 index 0000000..e23aa0b --- /dev/null +++ b/src/communication/core/message.h @@ -0,0 +1,199 @@ +// ================================================================================================ +// Audio Backend - 消息抽象接口 +// ================================================================================================ +// 描述: 定义通信模块消息的基础接口和结构 +// 功能: 提供统一的消息处理方式,支持不同类型的消息传输 +// ================================================================================================ + +#pragma once + +#include +#include +#include +#include +#include + +#include "error.h" + +namespace audio_backend::communication { + +// 消息优先级定义,与Proto定义保持一致 +enum class MessagePriority { + Low = 0, // 低优先级(日志、统计等) + Normal = 1, // 普通优先级(一般控制消息) + High = 2, // 高优先级(重要状态更新) + Critical = 3, // 关键优先级(错误、紧急停止) + Realtime = 4 // 实时优先级(音频处理相关) +}; + +// 传输通道类型,与Proto定义保持一致 +enum class TransportChannel { + ZmqControl = 0, // ZeroMQ控制通道 + SharedMemory = 1, // 共享内存通道 + NetworkTcp = 2, // 网络TCP通道 + NetworkUdp = 3, // 网络UDP通道 + LocalIpc = 4 // 本地IPC通道 +}; + +// 端点类型,与Proto定义保持一致 +enum class EndpointType { + Unknown = 0, + AudioEngine = 1, // 音频引擎 + PluginSandbox = 2, // 插件沙盒 + Frontend = 3, // 前端进程 + RemoteClient = 4, // 远程客户端 + NetworkNode = 5 // 网络节点 +}; + +// 通信端点定义 +struct Endpoint { + std::string id; // 端点唯一标识符 + EndpointType type; // 端点类型 + std::string address; // 端点地址 + int32_t port; // 端口号(网络通信时使用) + + Endpoint() = default; + + Endpoint(const std::string& id_, EndpointType type_, + const std::string& addr_, int32_t port_ = 0) + : id(id_), type(type_), address(addr_), port(port_) {} + + bool operator==(const Endpoint& other) const { + return id == other.id && type == other.type && + address == other.address && port == other.port; + } + + bool operator!=(const Endpoint& other) const { + return !(*this == other); + } + + // 转换为字符串表示,用于日志等 + std::string to_string() const; +}; + +// 消息接口 +class IMessage { +public: + virtual ~IMessage() = default; + + // 获取消息类型标识 + virtual std::string message_type() const = 0; + + // 获取消息唯一标识符 + virtual std::string message_id() const = 0; + + // 获取消息来源端点 + virtual Endpoint source() const = 0; + + // 获取消息目标端点(如果有) + virtual Endpoint destination() const = 0; + + // 获取消息优先级 + virtual MessagePriority priority() const = 0; + + // 获取消息创建时间戳 + virtual std::chrono::system_clock::time_point timestamp() const = 0; + + // 获取消息的原始数据 + virtual const std::vector& raw_data() const = 0; + + // 消息大小(字节数) + virtual size_t size() const = 0; + + // 克隆消息 + virtual std::unique_ptr clone() const = 0; + + // 确定此消息是否应该使用共享内存传输 + virtual bool should_use_shared_memory() const; + + // 获取首选传输通道 + virtual TransportChannel preferred_channel() const; + + // 消息转换为字符串表示,用于调试和日志 + virtual std::string to_string() const = 0; +}; + +// 基础消息类,实现通用功能 +class Message : public IMessage { +public: + Message(); + Message(const std::string& id, const Endpoint& source, + const Endpoint& destination = Endpoint()); + virtual ~Message() = default; + + // IMessage 接口实现 + std::string message_id() const override { return message_id_; } + Endpoint source() const override { return source_; } + Endpoint destination() const override { return destination_; } + MessagePriority priority() const override { return priority_; } + std::chrono::system_clock::time_point timestamp() const override { return timestamp_; } + const std::vector& raw_data() const override { return raw_data_; } + size_t size() const override { return raw_data_.size(); } + + // 设置方法 + void set_message_id(const std::string& id) { message_id_ = id; } + void set_source(const Endpoint& source) { source_ = source; } + void set_destination(const Endpoint& destination) { destination_ = destination; } + void set_priority(MessagePriority priority) { priority_ = priority; } + void set_timestamp(const std::chrono::system_clock::time_point& time) { timestamp_ = time; } + void set_raw_data(const std::vector& data) { raw_data_ = data; } + void set_raw_data(std::vector&& data) { raw_data_ = std::move(data); } + + // 默认首选通道实现 + TransportChannel preferred_channel() const override; + + // 基于消息大小确定是否使用共享内存 + bool should_use_shared_memory() const override; + +protected: + std::string message_id_; + Endpoint source_; + Endpoint destination_; + MessagePriority priority_; + std::chrono::system_clock::time_point timestamp_; + std::vector raw_data_; + + // 消息大小阈值(大于此值使用共享内存) + static constexpr size_t SHARED_MEMORY_THRESHOLD = 4 * 1024; // 4KB +}; + +// 工厂函数:创建新的消息ID +std::string generate_message_id(); + +// 消息工厂类 +class MessageFactory { +public: + // 创建消息的工厂方法 + template + static std::unique_ptr create(Args&&... args) { + auto message = std::make_unique(std::forward(args)...); + // 确保所有消息都有有效的消息ID + if (message->message_id().empty()) { + message->set_message_id(generate_message_id()); + } + return message; + } +}; + +// 消息处理结果状态 +enum class MessageHandleResult { + Success, // 成功处理 + Error, // 处理出错 + NotHandled, // 未处理(无对应处理器) + InvalidMessage, // 无效消息 + Timeout // 处理超时 +}; + +// 消息处理器接口 +class IMessageHandler { +public: + virtual ~IMessageHandler() = default; + + // 处理消息,返回处理结果 + virtual MessageHandleResult handle_message(const IMessage& message) = 0; + + // 检查处理器是否可以处理此类型的消息 + virtual bool can_handle(const IMessage& message) = 0; +}; + +} // namespace audio_backend::communication \ No newline at end of file diff --git a/src/communication/core/serializer.cpp b/src/communication/core/serializer.cpp new file mode 100644 index 0000000..b6fa703 --- /dev/null +++ b/src/communication/core/serializer.cpp @@ -0,0 +1,222 @@ +// ================================================================================================ +// Audio Backend - 消息序列化器实现 +// ================================================================================================ + +#include "serializer.h" +#include + +// 跨平台网络字节序转换 +#ifdef _WIN32 + #include + #pragma comment(lib, "ws2_32.lib") +#else + #include +#endif + +namespace audio_backend::communication { + +// 使用全局日志函数 +using audio_backend::common::log_info; +using audio_backend::common::log_warn; +using audio_backend::common::log_err; +using audio_backend::common::log_debug; + +namespace audio_backend::communication { + +// ================================================================================================ +// ProtobufSerializer 实现 +// ================================================================================================ + +ProtobufSerializer::ProtobufSerializer() { + log_info("初始化Protobuf序列化器"); +} + +SerializationError ProtobufSerializer::serialize(const IMessage& message, std::vector& output) { + const std::string& type_name = message.message_type(); + + // 查找序列化函数 + auto it = serialize_funcs_.find(type_name); + if (it == serialize_funcs_.end()) { + log_err("未找到消息类型 '%s' 的序列化函数", type_name.c_str()); + return SerializationError::UnsupportedType; + } + + // 序列化消息内容 + std::vector message_data; + SerializationError result = it->second(message, message_data); + if (result != SerializationError::Success) { + log_err("序列化消息类型 '%s' 失败: %d", type_name.c_str(), static_cast(result)); + return result; + } + + // 构建完整的消息,包含消息头 + MessageHeader header; + header.magic = htonl(HEADER_MAGIC); + header.version = htons(CURRENT_VERSION); + header.type_length = htons(static_cast(type_name.length())); + + // 计算总大小 + size_t total_size = HEADER_SIZE + type_name.length() + message_data.size(); + output.reserve(total_size); + output.clear(); + + // 写入消息头 + const uint8_t* header_bytes = reinterpret_cast(&header); + output.insert(output.end(), header_bytes, header_bytes + HEADER_SIZE); + + // 写入消息类型 + output.insert(output.end(), type_name.begin(), type_name.end()); + + // 写入消息数据 + output.insert(output.end(), message_data.begin(), message_data.end()); + + log_debug("成功序列化消息类型 '%s', 大小: %zu 字节", type_name.c_str(), output.size()); + return SerializationError::Success; +} + +SerializationError ProtobufSerializer::deserialize(const std::vector& data, std::unique_ptr& output) { + if (data.size() < HEADER_SIZE) { + log_err("数据大小不足以包含消息头: %zu < %zu", data.size(), HEADER_SIZE); + return SerializationError::InvalidInput; + } + + // 解析消息头 + MessageHeader header; + std::memcpy(&header, data.data(), HEADER_SIZE); + + // 验证魔术数字 + if (ntohl(header.magic) != HEADER_MAGIC) { + log_err("无效的消息头魔术数字: 0x%08X", ntohl(header.magic)); + return SerializationError::InvalidFormat; + } + + // 检查版本 + uint16_t version = ntohs(header.version); + if (version != CURRENT_VERSION) { + log_warn("消息版本不匹配: %d != %d", version, CURRENT_VERSION); + // 暂时继续处理,但可能需要版本兼容性处理 + } + + // 提取消息类型 + uint16_t type_length = ntohs(header.type_length); + if (data.size() < HEADER_SIZE + type_length) { + log_err("数据大小不足以包含消息类型: %zu < %zu", data.size(), HEADER_SIZE + type_length); + return SerializationError::InvalidInput; + } + + std::string message_type(data.begin() + HEADER_SIZE, data.begin() + HEADER_SIZE + type_length); + + // 查找反序列化函数 + auto it = deserialize_funcs_.find(message_type); + if (it == deserialize_funcs_.end()) { + log_err("未找到消类型 '%s' 的反序列化函数", message_type.c_str()); + return SerializationError::UnsupportedType; + } + + // 提取消息数据 + size_t message_data_offset = HEADER_SIZE + type_length; + std::vector message_data(data.begin() + message_data_offset, data.end()); + + // 反序列化消息 + SerializationError result = it->second(message_data, output); + if (result != SerializationError::Success) { + log_err("反序列化消息类型 '%s' 失败: %d", message_type.c_str(), static_cast(result)); + return result; + } + + log_debug("成功反序列化消息类型 '%s', 数据大小: %zu 字节", message_type.c_str(), message_data.size()); + return SerializationError::Success; +} + +bool ProtobufSerializer::supports_message_type(const std::string& message_type) const { + return serialize_funcs_.find(message_type) != serialize_funcs_.end() && + deserialize_funcs_.find(message_type) != deserialize_funcs_.end(); +} + +void ProtobufSerializer::register_message_type(const std::string& type_name, + const SerializeFunction& serialize_func, + const DeserializeFunction& deserialize_func) { + serialize_funcs_[type_name] = serialize_func; + deserialize_funcs_[type_name] = deserialize_func; + log_debug("注册消息类型: '%s'", type_name.c_str()); +} + +std::string ProtobufSerializer::extract_message_type(const std::vector& data) { + if (data.size() < HEADER_SIZE) { + return ""; + } + + MessageHeader header; + std::memcpy(&header, data.data(), HEADER_SIZE); + + if (ntohl(header.magic) != HEADER_MAGIC) { + return ""; + } + + uint16_t type_length = ntohs(header.type_length); + if (data.size() < HEADER_SIZE + type_length) { + return ""; + } + + return std::string(data.begin() + HEADER_SIZE, data.begin() + HEADER_SIZE + type_length); +} + +// ================================================================================================ +// SerializerFactory 实现 +// ================================================================================================ + +SerializerFactory& SerializerFactory::instance() { + static SerializerFactory instance; + return instance; +} + +void SerializerFactory::register_serializer(const std::string& name, std::unique_ptr serializer) { + if (!serializer) { + log_err("尝试注册空的序列化器: '%s'", name.c_str()); + return; + } + + serializers_[name] = std::move(serializer); + log_info("注册序列化器: '%s'", name.c_str()); +} + +ISerializer* SerializerFactory::get_serializer(const std::string& name) { + auto it = serializers_.find(name); + if (it != serializers_.end()) { + return it->second.get(); + } + + log_warn("未找到序列化器: '%s'", name.c_str()); + return nullptr; +} + +ISerializer* SerializerFactory::get_serializer_for_message_type(const std::string& message_type) { + for (const auto& pair : serializers_) { + if (pair.second->supports_message_type(message_type)) { + return pair.second.get(); + } + } + + log_warn("未找到支持消息类型 '%s' 的序列化器", message_type.c_str()); + return nullptr; +} + +ISerializer* SerializerFactory::detect_serializer(const std::vector& data) { + if (data.size() < sizeof(ProtobufSerializer::MessageHeader)) { + return nullptr; + } + + // 检查是否为Protobuf格式 + ProtobufSerializer::MessageHeader header; + std::memcpy(&header, data.data(), sizeof(header)); + + if (ntohl(header.magic) == ProtobufSerializer::HEADER_MAGIC) { + return get_serializer("protobuf"); + } + + // 可以在这里添加其他格式的检测逻辑 + log_warn("无法识别数据格式"); + return nullptr; +} + +} // namespace audio_backend::communication \ No newline at end of file diff --git a/src/communication/core/serializer.h b/src/communication/core/serializer.h new file mode 100644 index 0000000..d254545 --- /dev/null +++ b/src/communication/core/serializer.h @@ -0,0 +1,177 @@ +// ================================================================================================ +// Audio Backend - 消息序列化器 +// ================================================================================================ +// 描述: 定义消息序列化和反序列化接口 +// 功能: 提供消息与二进制数据之间的转换机制,支持Protocol Buffers格式 +// ================================================================================================ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "message.h" +#include "error.h" +#include "logger.h" + +namespace audio_backend::communication { + +// ================================================================================================ +// 序列化错误码 +// ================================================================================================ +enum class SerializationError { + Success = 0, + InvalidInput = 1, // 输入数据无效 + UnsupportedType = 2, // 不支持的消息类型 + SerializeError = 3, // 序列化错误 + DeserializeError = 4, // 反序列化错误 + BufferTooSmall = 5, // 缓冲区过小 + NotImplemented = 6, // 未实现 + VersionMismatch = 7, // 版本不匹配 + InvalidFormat = 8 // 格式无效 +}; + +// ================================================================================================ +// 序列化器接口 +// ================================================================================================ +class ISerializer { +public: + virtual ~ISerializer() = default; + + // 序列化消息为二进制数据 + virtual SerializationError serialize(const IMessage& message, std::vector& output) = 0; + + // 反序列化二进制数据为消息 + virtual SerializationError deserialize(const std::vector& data, std::unique_ptr& output) = 0; + + // 获取序列化器名称 + virtual std::string name() const = 0; + + // 检查序列化器是否支持指定的消息类型 + virtual bool supports_message_type(const std::string& message_type) const = 0; +}; + +// ================================================================================================ +// Protobuf序列化器基类 +// ================================================================================================ +class ProtobufSerializer : public ISerializer { +public: + ProtobufSerializer(); + virtual ~ProtobufSerializer() = default; + + // ISerializer接口实现 + SerializationError serialize(const IMessage& message, std::vector& output) override; + SerializationError deserialize(const std::vector& data, std::unique_ptr& output) override; + std::string name() const override { return "protobuf"; } + bool supports_message_type(const std::string& message_type) const override; + +protected: + // 消息类型与序列化/反序列化函数的映射 + using SerializeFunction = std::function&)>; + using DeserializeFunction = std::function&, std::unique_ptr&)>; + + // 消息类型注册 + void register_message_type(const std::string& type_name, + const SerializeFunction& serialize_func, + const DeserializeFunction& deserialize_func); + + // 从二进制数据中提取消息类型(消息头) + static std::string extract_message_type(const std::vector& data); + + // 消息头设计:固定格式的消息头,包含消息类型和版本信息 + struct MessageHeader { + uint32_t magic; // 魔术数字,用于标识格式 (AUDP) + uint16_t version; // 协议版本 + uint16_t type_length; // 消息类型长度 + // 后跟变长的消息类型字符串,然后是消息内容 + }; + + // 常量定义 + static constexpr uint32_t HEADER_MAGIC = 0x41554450; // 'AUDP' + static constexpr uint16_t CURRENT_VERSION = 0x0001; // 当前版本 + static constexpr size_t HEADER_SIZE = sizeof(MessageHeader); + +private: + std::unordered_map serialize_funcs_; + std::unordered_map deserialize_funcs_; +}; + +// ================================================================================================ +// 序列化器工厂 +// ================================================================================================ +class SerializerFactory { +public: + // 获取实例(单例) + static SerializerFactory& instance(); + + // 注册序列化器 + void register_serializer(const std::string& name, std::unique_ptr serializer); + + // 获取序列化器 + ISerializer* get_serializer(const std::string& name); + + // 获取支持指定消息类型的序列化器 + ISerializer* get_serializer_for_message_type(const std::string& message_type); + + // 根据数据格式自动选择序列化器 + ISerializer* detect_serializer(const std::vector& data); + +private: + SerializerFactory() = default; + ~SerializerFactory() = default; + + // 禁止拷贝和移动 + SerializerFactory(const SerializerFactory&) = delete; + SerializerFactory& operator=(const SerializerFactory&) = delete; + SerializerFactory(SerializerFactory&&) = delete; + SerializerFactory& operator=(SerializerFactory&&) = delete; + + std::unordered_map> serializers_; +}; + +// ================================================================================================ +// 序列化辅助函数 +// ================================================================================================ +// 序列化任意消息 +template +SerializationError serialize_message(const MessageType& message, std::vector& output) { + auto serializer = SerializerFactory::instance().get_serializer_for_message_type(message.message_type()); + if (!serializer) { + log_err("找不到支持消息类型 '%s' 的序列化器", message.message_type().c_str()); + return SerializationError::UnsupportedType; + } + return serializer->serialize(message, output); +} + +// 反序列化为特定类型的消息 +template +SerializationError deserialize_message(const std::vector& data, std::unique_ptr& output) { + std::unique_ptr base_message; + auto serializer = SerializerFactory::instance().detect_serializer(data); + if (!serializer) { + log_err("无法确定数据的序列化格式"); + return SerializationError::InvalidFormat; + } + + auto result = serializer->deserialize(data, base_message); + if (result != SerializationError::Success || !base_message) { + return result; + } + + // 类型转换 + auto* derived = dynamic_cast(base_message.get()); + if (!derived) { + log_err("消息类型转换失败: 期望 '%s'", typeid(MessageType).name()); + return SerializationError::UnsupportedType; + } + + output.reset(derived); + base_message.release(); // 防止双重释放 + return SerializationError::Success; +} + +} // namespace audio_backend::communication \ No newline at end of file diff --git a/src/communication/proto/audio_meta.proto b/src/communication/proto/audio_meta.proto new file mode 100644 index 0000000..e009b21 --- /dev/null +++ b/src/communication/proto/audio_meta.proto @@ -0,0 +1,219 @@ +// ================================================================================================ +// Audio Backend - 音频元数据协议定义 +// ================================================================================================ +// 描述: 定义音频处理相关的元数据和信息 +// 用途: 音频流信息、缓冲区元数据、处理链配置 +// ================================================================================================ + +syntax = "proto3"; + +package audio_backend.communication.proto; + +import "common.proto"; + +option cc_enable_arenas = true; +option optimize_for = SPEED; + +// ================================================================================================ +// 音频流信息 +// ================================================================================================ +message AudioStreamInfo { + string stream_id = 1; // 流标识符 + AudioFormat format = 2; // 音频格式 + StreamDirection direction = 3; // 流方向 + StreamState state = 4; // 流状态 + uint64 total_frames = 5; // 总帧数 + uint64 current_frame = 6; // 当前帧 + double duration_seconds = 7; // 持续时间(秒) + Timestamp start_time = 8; // 开始时间 + map metadata = 9; // 流元数据 +} + +enum StreamDirection { + STREAM_INPUT = 0; // 输入流 + STREAM_OUTPUT = 1; // 输出流 + STREAM_BIDIRECTIONAL = 2; // 双向流 +} + +enum StreamState { + STREAM_STOPPED = 0; // 停止 + STREAM_STARTING = 1; // 启动中 + STREAM_RUNNING = 2; // 运行中 + STREAM_PAUSED = 3; // 暂停 + STREAM_STOPPING = 4; // 停止中 + STREAM_ERROR = 5; // 错误状态 +} + +// ================================================================================================ +// 音频缓冲区元数据 +// ================================================================================================ +message AudioBufferMetadata { + string buffer_id = 1; // 缓冲区ID + AudioFormat format = 2; // 音频格式 + uint32 frame_count = 3; // 帧数 + uint64 timestamp_samples = 4; // 时间戳(样本为单位) + double timestamp_seconds = 5; // 时间戳(秒为单位) + BufferFlags flags = 6; // 缓冲区标志 + uint32 sequence_number = 7; // 序列号 + repeated ChannelInfo channels = 8; // 声道信息 +} + +message BufferFlags { + bool is_silent = 1; // 是否静音 + bool has_discontinuity = 2; // 是否有不连续性 + bool is_last = 3; // 是否为最后一个缓冲区 + bool needs_processing = 4; // 是否需要处理 + bool is_real_time = 5; // 是否为实时数据 +} + +message ChannelInfo { + int32 channel_index = 1; // 声道索引 + ChannelType type = 2; // 声道类型 + double peak_level = 3; // 峰值电平 + double rms_level = 4; // RMS电平 + bool is_clipping = 5; // 是否削波 +} + +enum ChannelType { + CHANNEL_UNKNOWN = 0; + CHANNEL_MONO = 1; // 单声道 + CHANNEL_LEFT = 2; // 左声道 + CHANNEL_RIGHT = 3; // 右声道 + CHANNEL_CENTER = 4; // 中央声道 + CHANNEL_LFE = 5; // 低频声道 + CHANNEL_SURROUND_LEFT = 6; // 环绕左声道 + CHANNEL_SURROUND_RIGHT = 7; // 环绕右声道 +} + +// ================================================================================================ +// 音频设备信息 +// ================================================================================================ +message AudioDeviceInfo { + string device_id = 1; // 设备ID + string name = 2; // 设备名称 + string driver_name = 3; // 驱动名称 + DeviceType type = 4; // 设备类型 + DeviceState state = 5; // 设备状态 + repeated AudioFormat supported_formats = 6; // 支持的格式 + AudioFormat current_format = 7; // 当前格式 + DeviceCapabilities capabilities = 8; // 设备能力 + PerformanceMetrics metrics = 9; // 性能指标 +} + +enum DeviceType { + DEVICE_TYPE_UNKNOWN = 0; + DEVICE_TYPE_INPUT = 1; // 输入设备 + DEVICE_TYPE_OUTPUT = 2; // 输出设备 + DEVICE_TYPE_FULL_DUPLEX = 3; // 全双工设备 + DEVICE_TYPE_LOOPBACK = 4; // 回环设备 +} + +message DeviceCapabilities { + bool supports_exclusive_mode = 1; // 支持独占模式 + bool supports_shared_mode = 2; // 支持共享模式 + bool supports_hardware_mixing = 3; // 支持硬件混音 + bool supports_sample_rate_conversion = 4; // 支持采样率转换 + int32 min_buffer_size = 5; // 最小缓冲区大小 + int32 max_buffer_size = 6; // 最大缓冲区大小 + repeated int32 supported_sample_rates = 7; // 支持的采样率 +} + +// ================================================================================================ +// 音频处理链配置 +// ================================================================================================ +message ProcessingChainConfig { + string chain_id = 1; // 处理链ID + repeated ProcessingNode nodes = 2; // 处理节点 + repeated Connection connections = 3; // 节点连接 + map global_params = 4; // 全局参数 + bool enabled = 5; // 是否启用 +} + +message ProcessingNode { + string node_id = 1; // 节点ID + string processor_type = 2; // 处理器类型 + map parameters = 3; // 节点参数 + bool enabled = 4; // 是否启用 + bool bypass = 5; // 是否旁路 + NodeType type = 6; // 节点类型 +} + +enum NodeType { + NODE_UNKNOWN = 0; + NODE_INPUT = 1; // 输入节点 + NODE_OUTPUT = 2; // 输出节点 + NODE_EFFECT = 3; // 效果节点 + NODE_GENERATOR = 4; // 生成器节点 + NODE_ANALYZER = 5; // 分析器节点 + NODE_MIXER = 6; // 混音器节点 +} + +message Connection { + string from_node = 1; // 源节点ID + int32 from_pin = 2; // 源节点引脚 + string to_node = 3; // 目标节点ID + int32 to_pin = 4; // 目标节点引脚 + double gain = 5; // 增益 + bool muted = 6; // 是否静音 +} + +// ================================================================================================ +// 音频分析数据 +// ================================================================================================ +message AudioAnalysisData { + string analysis_id = 1; // 分析ID + AnalysisType type = 2; // 分析类型 + Timestamp timestamp = 3; // 时间戳 + bytes data = 4; // 分析数据 + AnalysisParams parameters = 5; // 分析参数 +} + +enum AnalysisType { + ANALYSIS_UNKNOWN = 0; + ANALYSIS_SPECTRUM = 1; // 频谱分析 + ANALYSIS_WAVEFORM = 2; // 波形分析 + ANALYSIS_LEVEL_METER = 3; // 电平表 + ANALYSIS_PHASE_METER = 4; // 相位表 + ANALYSIS_CORRELATION = 5; // 相关性分析 +} + +message AnalysisParams { + int32 fft_size = 1; // FFT大小 + int32 overlap = 2; // 重叠率 + WindowType window_type = 3; // 窗函数类型 + double frequency_min = 4; // 最小频率 + double frequency_max = 5; // 最大频率 +} + +enum WindowType { + WINDOW_RECTANGULAR = 0; // 矩形窗 + WINDOW_HANNING = 1; // 汉宁窗 + WINDOW_HAMMING = 2; // 汉明窗 + WINDOW_BLACKMAN = 3; // 布莱克曼窗 + WINDOW_KAISER = 4; // 凯泽窗 +} + +// ================================================================================================ +// MIDI消息定义 +// ================================================================================================ +message MidiMessage { + uint32 timestamp = 1; // 时间戳 + bytes data = 2; // MIDI数据 + MidiMessageType type = 3; // 消息类型 + int32 channel = 4; // MIDI通道 + int32 note = 5; // 音符号 + int32 velocity = 6; // 力度 + int32 controller = 7; // 控制器号 + int32 value = 8; // 控制器值 +} + +enum MidiMessageType { + MIDI_UNKNOWN = 0; + MIDI_NOTE_ON = 1; // 音符开始 + MIDI_NOTE_OFF = 2; // 音符结束 + MIDI_CONTROL_CHANGE = 3; // 控制器变化 + MIDI_PROGRAM_CHANGE = 4; // 程序变化 + MIDI_PITCH_BEND = 5; // 弯音 + MIDI_AFTERTOUCH = 6; // 触后 + MIDI_SYSTEM_EXCLUSIVE = 7; // 系统独占 +} \ No newline at end of file diff --git a/src/communication/proto/common.proto b/src/communication/proto/common.proto new file mode 100644 index 0000000..84505a0 --- /dev/null +++ b/src/communication/proto/common.proto @@ -0,0 +1,161 @@ +// ================================================================================================ +// Audio Backend - 通用消息协议定义 +// ================================================================================================ +// 描述: 定义系统中通用的数据类型、枚举和结构 +// 用途: 为其他协议文件提供基础类型定义 +// ================================================================================================ + +syntax = "proto3"; + +package audio_backend.communication.proto; + +option cc_enable_arenas = true; +option optimize_for = SPEED; + +// ================================================================================================ +// 时间戳定义 +// ================================================================================================ +message Timestamp { + int64 seconds = 1; // 自1970-01-01 00:00:00 UTC以来的秒数 + int32 nanos = 2; // 秒内的纳秒数 [0-999,999,999] +} + +// ================================================================================================ +// 错误信息定义 +// ================================================================================================ +message ErrorInfo { + int32 code = 1; // 错误码(对应ErrorCode枚举) + string message = 2; // 错误描述 + string details = 3; // 详细信息 + string source = 4; // 错误来源(模块名) + Timestamp timestamp = 5; // 错误发生时间 +} + +// ================================================================================================ +// 通信端点定义 +// ================================================================================================ +message Endpoint { + string id = 1; // 端点唯一标识符 + EndpointType type = 2; // 端点类型 + string address = 3; // 端点地址 + int32 port = 4; // 端口号(网络通信时使用) + map metadata = 5; // 端点元数据 +} + +enum EndpointType { + ENDPOINT_UNKNOWN = 0; + ENDPOINT_AUDIO_ENGINE = 1; // 音频引擎 + ENDPOINT_PLUGIN_SANDBOX = 2; // 插件沙盒 + ENDPOINT_FRONTEND = 3; // 前端进程 + ENDPOINT_REMOTE_CLIENT = 4; // 远程客户端 + ENDPOINT_NETWORK_NODE = 5; // 网络节点 +} + +// ================================================================================================ +// 消息优先级定义 +// ================================================================================================ +enum MessagePriority { + PRIORITY_LOW = 0; // 低优先级(日志、统计等) + PRIORITY_NORMAL = 1; // 普通优先级(一般控制消息) + PRIORITY_HIGH = 2; // 高优先级(重要状态更新) + PRIORITY_CRITICAL = 3; // 关键优先级(错误、紧急停止) + PRIORITY_REALTIME = 4; // 实时优先级(音频处理相关) +} + +// ================================================================================================ +// 传输通道类型 +// ================================================================================================ +enum TransportChannel { + CHANNEL_ZMQ_CONTROL = 0; // ZeroMQ控制通道 + CHANNEL_SHARED_MEMORY = 1; // 共享内存通道 + CHANNEL_NETWORK_TCP = 2; // 网络TCP通道 + CHANNEL_NETWORK_UDP = 3; // 网络UDP通道 + CHANNEL_LOCAL_IPC = 4; // 本地IPC通道 +} + +// ================================================================================================ +// 音频格式定义 +// ================================================================================================ +message AudioFormat { + int32 sample_rate = 1; // 采样率 (Hz) + int32 channels = 2; // 声道数 + AudioSampleType sample_type = 3; // 采样类型 + int32 buffer_size = 4; // 缓冲区大小(样本数) + bool interleaved = 5; // 是否交错格式 +} + +enum AudioSampleType { + SAMPLE_UNKNOWN = 0; + SAMPLE_INT16 = 1; // 16位整数 + SAMPLE_INT24 = 2; // 24位整数 + SAMPLE_INT32 = 3; // 32位整数 + SAMPLE_FLOAT32 = 4; // 32位浮点 + SAMPLE_FLOAT64 = 5; // 64位浮点 +} + +// ================================================================================================ +// 设备状态枚举 +// ================================================================================================ +enum DeviceState { + DEVICE_UNKNOWN = 0; + DEVICE_DISCONNECTED = 1; // 设备断开 + DEVICE_CONNECTED = 2; // 设备连接 + DEVICE_ACTIVE = 3; // 设备活跃 + DEVICE_ERROR = 4; // 设备错误 + DEVICE_SUSPENDED = 5; // 设备挂起 +} + +// ================================================================================================ +// 进程状态枚举 +// ================================================================================================ +enum ProcessState { + PROCESS_UNKNOWN = 0; + PROCESS_STARTING = 1; // 进程启动中 + PROCESS_RUNNING = 2; // 进程运行中 + PROCESS_STOPPING = 3; // 进程停止中 + PROCESS_STOPPED = 4; // 进程已停止 + PROCESS_ERROR = 5; // 进程错误 + PROCESS_CRASHED = 6; // 进程崩溃 +} + +// ================================================================================================ +// 版本信息定义 +// ================================================================================================ +message Version { + int32 major = 1; // 主版本号 + int32 minor = 2; // 次版本号 + int32 patch = 3; // 补丁版本号 + string pre_release = 4; // 预发布标识 + string build_metadata = 5; // 构建元数据 +} + +// ================================================================================================ +// 性能统计信息 +// ================================================================================================ +message PerformanceMetrics { + double cpu_usage = 1; // CPU使用率 (0-100%) + uint64 memory_usage = 2; // 内存使用量 (字节) + double latency_ms = 3; // 延迟 (毫秒) + uint64 throughput_bps = 4; // 吞吐量 (字节/秒) + uint32 buffer_underruns = 5; // 缓冲区下溢次数 + uint32 buffer_overruns = 6; // 缓冲区溢出次数 + Timestamp last_updated = 7; // 最后更新时间 +} + +// ================================================================================================ +// 网络地址信息 +// ================================================================================================ +message NetworkAddress { + string host = 1; // 主机名或IP地址 + int32 port = 2; // 端口号 + AddressType type = 3; // 地址类型 + bool is_local = 4; // 是否为本地地址 +} + +enum AddressType { + ADDRESS_UNKNOWN = 0; + ADDRESS_IPV4 = 1; // IPv4地址 + ADDRESS_IPV6 = 2; // IPv6地址 + ADDRESS_HOSTNAME = 3; // 主机名 + ADDRESS_UNIX_SOCKET = 4; // Unix套接字 +} \ No newline at end of file diff --git a/src/communication/proto/control.proto b/src/communication/proto/control.proto new file mode 100644 index 0000000..a0600f7 --- /dev/null +++ b/src/communication/proto/control.proto @@ -0,0 +1,196 @@ +// ================================================================================================ +// Audio Backend - 控制消息协议定义 +// ================================================================================================ +// 描述: 定义系统控制消息的类型和结构 +// 用途: 进程间控制命令、配置更新、系统管理 +// ================================================================================================ + +syntax = "proto3"; + +package audio_backend.communication.proto; + +import "common.proto"; + +option cc_enable_arenas = true; +option optimize_for = SPEED; + +// ================================================================================================ +// 控制消息封装 +// ================================================================================================ +message ControlMessage { + string message_id = 1; // 消息唯一标识符 + Endpoint source = 2; // 消息来源 + Endpoint destination = 3; // 消息目的地 + MessagePriority priority = 4; // 消息优先级 + Timestamp timestamp = 5; // 消息时间戳 + + oneof payload { + CommandRequest command_request = 10; + CommandResponse command_response = 11; + ConfigUpdate config_update = 12; + ParameterChange parameter_change = 13; + SystemCommand system_command = 14; + } +} + +// ================================================================================================ +// 命令请求 +// ================================================================================================ +message CommandRequest { + string request_id = 1; // 请求ID + CommandType command_type = 2; // 命令类型 + bytes payload = 3; // 命令载荷 + map parameters = 4; // 命令参数 + int32 timeout_ms = 5; // 超时时间(毫秒) +} + +enum CommandType { + CMD_UNKNOWN = 0; + CMD_START = 1; // 启动命令 + CMD_STOP = 2; // 停止命令 + CMD_PAUSE = 3; // 暂停命令 + CMD_RESUME = 4; // 恢复命令 + CMD_RESET = 5; // 重置命令 + CMD_CONFIGURE = 6; // 配置命令 + CMD_QUERY = 7; // 查询命令 + CMD_CUSTOM = 100; // 自定义命令 +} + +// ================================================================================================ +// 命令响应 +// ================================================================================================ +message CommandResponse { + string request_id = 1; // 对应的请求ID + ResponseStatus status = 2; // 响应状态 + bytes result = 3; // 响应结果 + ErrorInfo error = 4; // 错误信息(如果有) + int32 execution_time_ms = 5; // 执行时间(毫秒) +} + +enum ResponseStatus { + STATUS_UNKNOWN = 0; + STATUS_SUCCESS = 1; // 成功 + STATUS_PENDING = 2; // 处理中 + STATUS_FAILED = 3; // 失败 + STATUS_TIMEOUT = 4; // 超时 + STATUS_REJECTED = 5; // 被拒绝 +} + +// ================================================================================================ +// 配置更新 +// ================================================================================================ +message ConfigUpdate { + string config_id = 1; // 配置标识符 + ConfigScope scope = 2; // 配置作用域 + map settings = 3; // 配置设置 + bool require_restart = 4; // 是否需要重启 + Timestamp effective_time = 5; // 生效时间 +} + +enum ConfigScope { + SCOPE_GLOBAL = 0; // 全局配置 + SCOPE_ENGINE = 1; // 引擎配置 + SCOPE_PLUGIN = 2; // 插件配置 + SCOPE_DEVICE = 3; // 设备配置 + SCOPE_NETWORK = 4; // 网络配置 +} + +// ================================================================================================ +// 参数变更 +// ================================================================================================ +message ParameterChange { + string parameter_path = 1; // 参数路径(如"plugin.id.param.name") + ParameterValue value = 2; // 参数值 + bool automated = 3; // 是否为自动化 + string automation_id = 4; // 自动化ID(如果有) +} + +message ParameterValue { + oneof value { + double float_value = 1; + int64 int_value = 2; + bool bool_value = 3; + string string_value = 4; + bytes binary_value = 5; + } + + // 元数据 + double min_value = 10; // 最小值 + double max_value = 11; // 最大值 + double default_value = 12; // 默认值 + string unit = 13; // 单位 + ParameterType type = 14; // 参数类型 +} + +enum ParameterType { + PARAM_UNKNOWN = 0; + PARAM_FLOAT = 1; // 浮点数参数 + PARAM_INT = 2; // 整数参数 + PARAM_BOOL = 3; // 布尔参数 + PARAM_STRING = 4; // 字符串参数 + PARAM_ENUM = 5; // 枚举参数 + PARAM_BINARY = 6; // 二进制参数 +} + +// ================================================================================================ +// 系统命令 +// ================================================================================================ +message SystemCommand { + SystemCommandType type = 1; // 系统命令类型 + string target_id = 2; // 目标标识符 + map arguments = 3; // 命令参数 + bool force = 4; // 是否强制执行 +} + +enum SystemCommandType { + SYS_CMD_UNKNOWN = 0; + SYS_CMD_SHUTDOWN = 1; // 关闭系统 + SYS_CMD_RESTART = 2; // 重启系统 + SYS_CMD_LOAD_PLUGIN = 3; // 加载插件 + SYS_CMD_UNLOAD_PLUGIN = 4; // 卸载插件 + SYS_CMD_ENABLE_DEVICE = 5; // 启用设备 + SYS_CMD_DISABLE_DEVICE = 6; // 禁用设备 + SYS_CMD_CLEAR_CACHE = 7; // 清除缓存 + SYS_CMD_SAVE_STATE = 8; // 保存状态 + SYS_CMD_LOAD_STATE = 9; // 加载状态 +} + +// ================================================================================================ +// 心跳消息 +// ================================================================================================ +message HeartbeatMessage { + string sender_id = 1; // 发送者ID + Timestamp timestamp = 2; // 时间戳 + ProcessState state = 3; // 进程状态 + PerformanceMetrics metrics = 4; // 性能指标 + int32 sequence_number = 5; // 序列号 +} + +// ================================================================================================ +// 连接管理消息 +// ================================================================================================ +message ConnectionMessage { + ConnectionAction action = 1; // 连接操作 + Endpoint endpoint = 2; // 端点信息 + string session_id = 3; // 会话ID + ConnectionInfo info = 4; // 连接信息 +} + +enum ConnectionAction { + CONN_UNKNOWN = 0; + CONN_CONNECT = 1; // 连接请求 + CONN_ACCEPT = 2; // 接受连接 + CONN_REJECT = 3; // 拒绝连接 + CONN_DISCONNECT = 4; // 断开连接 + CONN_RECONNECT = 5; // 重新连接 + CONN_PING = 6; // Ping + CONN_PONG = 7; // Pong +} + +message ConnectionInfo { + TransportChannel channel = 1; // 传输通道 + map properties = 2; // 连接属性 + Version protocol_version = 3; // 协议版本 + bool encrypted = 4; // 是否加密 + string encryption_method = 5; // 加密方法 +} \ No newline at end of file diff --git a/src/communication/proto/plugin_mgmt.proto b/src/communication/proto/plugin_mgmt.proto new file mode 100644 index 0000000..fbb365c --- /dev/null +++ b/src/communication/proto/plugin_mgmt.proto @@ -0,0 +1,299 @@ +// ================================================================================================ +// Audio Backend - 插件管理协议定义 +// ================================================================================================ +// 描述: 定义插件系统的管理消息和状态 +// 用途: 插件加载、卸载、通信、状态管理 +// ================================================================================================ + +syntax = "proto3"; + +package audio_backend.communication.proto; + +import "common.proto"; +import "audio_meta.proto"; + +option cc_enable_arenas = true; +option optimize_for = SPEED; + +// ================================================================================================ +// 插件管理消息 +// ================================================================================================ +message PluginManagementMessage { + string message_id = 1; // 消息ID + Endpoint source = 2; // 消息来源 + Endpoint destination = 3; // 消息目的地 + Timestamp timestamp = 4; // 时间戳 + + oneof payload { + PluginLoadRequest load_request = 10; + PluginLoadResponse load_response = 11; + PluginUnloadRequest unload_request = 12; + PluginUnloadResponse unload_response = 13; + PluginStateNotification state_notification = 14; + PluginProcessRequest process_request = 15; + PluginProcessResponse process_response = 16; + PluginParameterUpdate parameter_update = 17; + PluginPresetChange preset_change = 18; + } +} + +// ================================================================================================ +// 插件加载请求和响应 +// ================================================================================================ +message PluginLoadRequest { + string plugin_id = 1; // 插件唯一标识符 + string plugin_path = 2; // 插件文件路径 + PluginFormat format = 3; // 插件格式 + map init_params = 4; // 初始化参数 + SandboxConfig sandbox_config = 5; // 沙盒配置 + int32 timeout_ms = 6; // 加载超时时间 +} + +message PluginLoadResponse { + string plugin_id = 1; // 插件ID + PluginLoadStatus status = 2; // 加载状态 + PluginInfo plugin_info = 3; // 插件信息 + string sandbox_id = 4; // 沙盒ID + ErrorInfo error = 5; // 错误信息(如果有) + int32 load_time_ms = 6; // 加载时间 +} + +enum PluginFormat { + FORMAT_UNKNOWN = 0; + FORMAT_VST3 = 1; // VST3插件 + FORMAT_AU = 2; // Audio Unit插件 + FORMAT_LADSPA = 3; // LADSPA插件 + FORMAT_LV2 = 4; // LV2插件 + FORMAT_CLAP = 5; // CLAP插件 + FORMAT_NATIVE = 6; // 原生插件 +} + +enum PluginLoadStatus { + LOAD_UNKNOWN = 0; + LOAD_SUCCESS = 1; // 加载成功 + LOAD_FAILED = 2; // 加载失败 + LOAD_PENDING = 3; // 加载中 + LOAD_TIMEOUT = 4; // 加载超时 + LOAD_INVALID_FORMAT = 5; // 格式无效 + LOAD_MISSING_DEPENDENCIES = 6; // 缺少依赖 +} + +// ================================================================================================ +// 插件卸载请求和响应 +// ================================================================================================ +message PluginUnloadRequest { + string plugin_id = 1; // 插件ID + bool force = 2; // 强制卸载 + bool save_state = 3; // 保存状态 + int32 timeout_ms = 4; // 卸载超时时间 +} + +message PluginUnloadResponse { + string plugin_id = 1; // 插件ID + PluginUnloadStatus status = 2; // 卸载状态 + bytes saved_state = 3; // 保存的状态(如果有) + ErrorInfo error = 4; // 错误信息(如果有) + int32 unload_time_ms = 5; // 卸载时间 +} + +enum PluginUnloadStatus { + UNLOAD_UNKNOWN = 0; + UNLOAD_SUCCESS = 1; // 卸载成功 + UNLOAD_FAILED = 2; // 卸载失败 + UNLOAD_TIMEOUT = 3; // 卸载超时 + UNLOAD_FORCED = 4; // 强制卸载 +} + +// ================================================================================================ +// 插件信息定义 +// ================================================================================================ +message PluginInfo { + string plugin_id = 1; // 插件ID + string name = 2; // 插件名称 + string vendor = 3; // 供应商 + Version version = 4; // 版本 + string description = 5; // 描述 + PluginCategory category = 6; // 插件类别 + PluginType type = 7; // 插件类型 + repeated AudioFormat supported_formats = 8; // 支持的音频格式 + PluginCapabilities capabilities = 9; // 插件能力 + repeated PluginParameter parameters = 10; // 插件参数 + repeated PluginPreset presets = 11; // 预设 +} + +enum PluginCategory { + CATEGORY_UNKNOWN = 0; + CATEGORY_EFFECT = 1; // 效果器 + CATEGORY_INSTRUMENT = 2; // 乐器 + CATEGORY_ANALYZER = 3; // 分析器 + CATEGORY_GENERATOR = 4; // 生成器 + CATEGORY_UTILITY = 5; // 工具 + CATEGORY_MIXER = 6; // 混音器 +} + +enum PluginType { + TYPE_UNKNOWN = 0; + TYPE_AUDIO_EFFECT = 1; // 音频效果 + TYPE_INSTRUMENT = 2; // 乐器 + TYPE_MIDI_EFFECT = 3; // MIDI效果 + TYPE_ANALYZER = 4; // 分析器 + TYPE_GENERATOR = 5; // 生成器 +} + +message PluginCapabilities { + bool has_gui = 1; // 有GUI + bool supports_midi = 2; // 支持MIDI + bool supports_presets = 3; // 支持预设 + bool supports_automation = 4; // 支持自动化 + bool is_realtime_safe = 5; // 实时安全 + bool supports_bypass = 6; // 支持旁路 + int32 max_input_channels = 7; // 最大输入声道数 + int32 max_output_channels = 8; // 最大输出声道数 + double latency_samples = 9; // 延迟(样本) +} + +// ================================================================================================ +// 插件参数定义 +// ================================================================================================ +message PluginParameter { + string parameter_id = 1; // 参数ID + string name = 2; // 参数名称 + string label = 3; // 参数标签 + ParameterType type = 4; // 参数类型 + ParameterValue default_value = 5; // 默认值 + ParameterValue min_value = 6; // 最小值 + ParameterValue max_value = 7; // 最大值 + string unit = 8; // 单位 + bool is_automatable = 9; // 可自动化 + bool is_read_only = 10; // 只读 + repeated string enum_values = 11; // 枚举值(如果适用) +} + +// ================================================================================================ +// 插件预设定义 +// ================================================================================================ +message PluginPreset { + string preset_id = 1; // 预设ID + string name = 2; // 预设名称 + string description = 3; // 描述 + string author = 4; // 作者 + Version version = 5; // 版本 + map parameters = 6; // 参数值 + bytes binary_data = 7; // 二进制数据(如果有) + map metadata = 8; // 元数据 +} + +// ================================================================================================ +// 插件沙盒配置 +// ================================================================================================ +message SandboxConfig { + bool enabled = 1; // 启用沙盒 + SandboxType type = 2; // 沙盒类型 + ResourceLimits limits = 3; // 资源限制 + SecuritySettings security = 4; // 安全设置 + bool crash_recovery = 5; // 崩溃恢复 + int32 watchdog_timeout_ms = 6; // 看门狗超时 +} + +enum SandboxType { + SANDBOX_NONE = 0; // 无沙盒 + SANDBOX_PROCESS = 1; // 进程沙盒 + SANDBOX_CONTAINER = 2; // 容器沙盒 + SANDBOX_VM = 3; // 虚拟机沙盒 +} + +message ResourceLimits { + uint64 max_memory_bytes = 1; // 最大内存 + double max_cpu_percent = 2; // 最大CPU使用率 + uint32 max_threads = 3; // 最大线程数 + uint32 max_file_handles = 4; // 最大文件句柄数 + uint64 max_disk_usage_bytes = 5; // 最大磁盘使用量 +} + +message SecuritySettings { + bool allow_network_access = 1; // 允许网络访问 + bool allow_file_system_access = 2; // 允许文件系统访问 + repeated string allowed_paths = 3; // 允许的路径 + repeated string blocked_apis = 4; // 阻止的API + bool enable_aslr = 5; // 启用ASLR + bool enable_dep = 6; // 启用DEP +} + +// ================================================================================================ +// 插件状态通知 +// ================================================================================================ +message PluginStateNotification { + string plugin_id = 1; // 插件ID + PluginState state = 2; // 插件状态 + string message = 3; // 状态消息 + PerformanceMetrics metrics = 4; // 性能指标 + Timestamp timestamp = 5; // 时间戳 +} + +enum PluginState { + STATE_UNKNOWN = 0; + STATE_LOADING = 1; // 加载中 + STATE_LOADED = 2; // 已加载 + STATE_ACTIVE = 3; // 活跃 + STATE_INACTIVE = 4; // 非活跃 + STATE_PROCESSING = 5; // 处理中 + STATE_BYPASSED = 6; // 已旁路 + STATE_ERROR = 7; // 错误状态 + STATE_CRASHED = 8; // 已崩溃 + STATE_UNLOADING = 9; // 卸载中 +} + +// ================================================================================================ +// 插件处理请求和响应 +// ================================================================================================ +message PluginProcessRequest { + string plugin_id = 1; // 插件ID + string buffer_id = 2; // 缓冲区ID + AudioBufferMetadata metadata = 3; // 音频元数据 + repeated MidiMessage midi_events = 4; // MIDI事件 + bool bypass = 5; // 旁路处理 +} + +message PluginProcessResponse { + string plugin_id = 1; // 插件ID + string buffer_id = 2; // 缓冲区ID + ProcessingResult result = 3; // 处理结果 + repeated MidiMessage output_midi = 4; // 输出MIDI事件 + PerformanceMetrics metrics = 5; // 性能指标 + ErrorInfo error = 6; // 错误信息(如果有) +} + +enum ProcessingResult { + RESULT_SUCCESS = 0; // 处理成功 + RESULT_FAILED = 1; // 处理失败 + RESULT_BYPASS = 2; // 旁路处理 + RESULT_SILENCE = 3; // 输出静音 + RESULT_TIMEOUT = 4; // 处理超时 +} + +// ================================================================================================ +// 插件参数更新 +// ================================================================================================ +message PluginParameterUpdate { + string plugin_id = 1; // 插件ID + repeated ParameterChange changes = 2; // 参数变更 + bool immediate = 3; // 立即生效 + string automation_id = 4; // 自动化ID(如果有) +} + +// ================================================================================================ +// 插件预设变更 +// ================================================================================================ +message PluginPresetChange { + string plugin_id = 1; // 插件ID + PresetAction action = 2; // 预设操作 + PluginPreset preset = 3; // 预设数据 + bool immediate = 4; // 立即生效 +} + +enum PresetAction { + PRESET_LOAD = 0; // 加载预设 + PRESET_SAVE = 1; // 保存预设 + PRESET_DELETE = 2; // 删除预设 + PRESET_RENAME = 3; // 重命名预设 +} \ No newline at end of file diff --git a/src/communication/proto/status.proto b/src/communication/proto/status.proto new file mode 100644 index 0000000..45373f9 --- /dev/null +++ b/src/communication/proto/status.proto @@ -0,0 +1,348 @@ +// ================================================================================================ +// Audio Backend - 状态同步协议定义 +// ================================================================================================ +// 描述: 定义系统状态同步相关的消息和数据结构 +// 用途: 进程状态同步、系统监控、诊断和健康检查 +// ================================================================================================ + +syntax = "proto3"; + +package audio_backend.communication.proto; + +import "common.proto"; +import "audio_meta.proto"; + +option cc_enable_arenas = true; +option optimize_for = SPEED; + +// ================================================================================================ +// 状态同步消息 +// ================================================================================================ +message StatusMessage { + string message_id = 1; // 消息ID + Endpoint source = 2; // 消息来源 + Timestamp timestamp = 3; // 时间戳 + + oneof payload { + SystemStatus system_status = 10; + ProcessStatus process_status = 11; + EngineStatus engine_status = 12; + PluginHostStatus plugin_host_status = 13; + DeviceStatus device_status = 14; + NetworkStatus network_status = 15; + HealthCheckRequest health_check_request = 16; + HealthCheckResponse health_check_response = 17; + DiagnosticRequest diagnostic_request = 18; + DiagnosticResponse diagnostic_response = 19; + } +} + +// ================================================================================================ +// 系统状态 +// ================================================================================================ +message SystemStatus { + string system_id = 1; // 系统ID + SystemState state = 2; // 系统状态 + Version system_version = 3; // 系统版本 + SystemResources resources = 4; // 系统资源 + repeated ProcessStatus processes = 5; // 进程状态列表 + repeated ErrorInfo recent_errors = 6; // 最近错误 + Timestamp startup_time = 7; // 启动时间 + double uptime_seconds = 8; // 运行时间 +} + +enum SystemState { + SYS_STATE_UNKNOWN = 0; + SYS_STATE_STARTING = 1; // 启动中 + SYS_STATE_RUNNING = 2; // 运行中 + SYS_STATE_DEGRADED = 3; // 功能降级 + SYS_STATE_STOPPING = 4; // 停止中 + SYS_STATE_ERROR = 5; // 错误状态 + SYS_STATE_MAINTENANCE = 6; // 维护模式 +} + +message SystemResources { + double system_cpu_usage = 1; // 系统CPU使用率 + double process_cpu_usage = 2; // 进程CPU使用率 + uint64 physical_memory_bytes = 3; // 物理内存总量 + uint64 memory_usage_bytes = 4; // 内存使用量 + uint64 swap_usage_bytes = 5; // 交换空间使用量 + uint64 disk_total_bytes = 6; // 磁盘总量 + uint64 disk_used_bytes = 7; // 磁盘使用量 + uint64 network_rx_bytes = 8; // 网络接收字节数 + uint64 network_tx_bytes = 9; // 网络发送字节数 +} + +// ================================================================================================ +// 进程状态 +// ================================================================================================ +message ProcessStatus { + string process_id = 1; // 进程ID + string process_name = 2; // 进程名称 + ProcessType type = 3; // 进程类型 + ProcessState state = 4; // 进程状态 + PerformanceMetrics metrics = 5; // 性能指标 + int32 pid = 6; // 系统进程ID + int32 restart_count = 7; // 重启计数 + ErrorInfo last_error = 8; // 最近一次错误 + Timestamp start_time = 9; // 启动时间 +} + +enum ProcessType { + PROCESS_TYPE_UNKNOWN = 0; + PROCESS_TYPE_ENGINE = 1; // 音频引擎进程 + PROCESS_TYPE_PLUGIN_HOST = 2; // 插件沙盒进程 + PROCESS_TYPE_FRONTEND = 3; // 前端进程 + PROCESS_TYPE_NETWORK = 4; // 网络服务进程 + PROCESS_TYPE_UTILITY = 5; // 工具进程 +} + +// ================================================================================================ +// 音频引擎状态 +// ================================================================================================ +message EngineStatus { + string engine_id = 1; // 引擎ID + EngineState state = 2; // 引擎状态 + AudioFormat current_format = 3; // 当前音频格式 + repeated StreamStatus streams = 4; // 音频流状态 + PerformanceMetrics metrics = 5; // 性能指标 + repeated ProcessingNodeStatus nodes = 6; // 处理节点状态 + double dsp_load = 7; // DSP负载 + double latency_ms = 8; // 延迟(毫秒) + double xrun_count = 9; // 缓冲区溢出/欠载数 +} + +enum EngineState { + ENGINE_UNKNOWN = 0; + ENGINE_STOPPED = 1; // 停止 + ENGINE_STARTING = 2; // 启动中 + ENGINE_RUNNING = 3; // 运行中 + ENGINE_STOPPING = 4; // 停止中 + ENGINE_ERROR = 5; // 错误状态 +} + +message StreamStatus { + string stream_id = 1; // 流ID + StreamState state = 2; // 流状态 + AudioBufferMetadata buffer_info = 3; // 缓冲区信息 + double current_position_seconds = 4; // 当前位置(秒) + double peak_level = 5; // 峰值电平 + double rms_level = 6; // RMS电平 + bool is_clipping = 7; // 是否削波 +} + +message ProcessingNodeStatus { + string node_id = 1; // 节点ID + string node_type = 2; // 节点类型 + bool enabled = 3; // 是否启用 + bool bypassed = 4; // 是否旁路 + double processing_load = 5; // 处理负载 + double processing_time_ms = 6; // 处理时间(毫秒) + ErrorInfo error = 7; // 错误信息(如果有) +} + +// ================================================================================================ +// 插件宿主状态 +// ================================================================================================ +message PluginHostStatus { + string host_id = 1; // 宿主ID + ProcessState state = 2; // 进程状态 + repeated PluginInstanceStatus plugins = 3; // 插件实例状态 + SandboxStatus sandbox = 4; // 沙盒状态 + PerformanceMetrics metrics = 5; // 性能指标 +} + +message PluginInstanceStatus { + string plugin_id = 1; // 插件ID + string plugin_name = 2; // 插件名称 + PluginState state = 3; // 插件状态 + double cpu_usage = 4; // CPU使用率 + uint64 memory_usage = 5; // 内存使用量 + double processing_time_ms = 6; // 处理时间(毫秒) + int32 input_count = 7; // 输入数量 + int32 output_count = 8; // 输出数量 + double latency_samples = 9; // 延迟(样本) + ErrorInfo last_error = 10; // 最近一次错误 +} + +message SandboxStatus { + bool enabled = 1; // 是否启用 + SandboxType type = 2; // 沙盒类型 + SandboxState state = 3; // 沙盒状态 + ResourceUsage resource_usage = 4; // 资源使用情况 + repeated string violations = 5; // 违规操作 + ErrorInfo last_error = 6; // 最近一次错误 +} + +enum SandboxState { + SANDBOX_UNKNOWN = 0; + SANDBOX_ACTIVE = 1; // 活跃 + SANDBOX_INACTIVE = 2; // 非活跃 + SANDBOX_ERROR = 3; // 错误状态 + SANDBOX_COMPROMISED = 4; // 已被破坏 +} + +message ResourceUsage { + double cpu_percent = 1; // CPU使用率(百分比) + uint64 memory_bytes = 2; // 内存使用量(字节) + uint32 thread_count = 3; // 线程数 + uint32 file_handle_count = 4; // 文件句柄数 + uint64 disk_usage_bytes = 5; // 磁盘使用量(字节) +} + +// ================================================================================================ +// 设备状态 +// ================================================================================================ +message DeviceStatus { + string device_id = 1; // 设备ID + string device_name = 2; // 设备名称 + DeviceType type = 3; // 设备类型 + DeviceState state = 4; // 设备状态 + AudioFormat current_format = 5; // 当前格式 + double buffer_health = 6; // 缓冲区健康度(0-1) + int32 xrun_count = 7; // 溢出/欠载计数 + double latency_ms = 8; // 延迟(毫秒) + ErrorInfo last_error = 9; // 最近一次错误 +} + +// ================================================================================================ +// 网络状态 +// ================================================================================================ +message NetworkStatus { + string network_id = 1; // 网络ID + NetworkState state = 2; // 网络状态 + repeated ConnectionStatus connections = 3; // 连接状态 + int32 active_peers = 4; // 活跃对等点数量 + NetworkMetrics metrics = 5; // 网络指标 +} + +enum NetworkState { + NET_STATE_UNKNOWN = 0; + NET_STATE_DISCONNECTED = 1; // 断开连接 + NET_STATE_CONNECTING = 2; // 连接中 + NET_STATE_CONNECTED = 3; // 已连接 + NET_STATE_ERROR = 4; // 错误状态 +} + +message ConnectionStatus { + string connection_id = 1; // 连接ID + Endpoint remote_endpoint = 2; // 远程端点 + ConnectionState state = 3; // 连接状态 + double latency_ms = 4; // 延迟(毫秒) + double packet_loss = 5; // 丢包率(0-1) + uint64 bytes_sent = 6; // 已发送字节数 + uint64 bytes_received = 7; // 已接收字节数 + int32 reconnect_count = 8; // 重连次数 +} + +enum ConnectionState { + CONN_STATE_UNKNOWN = 0; + CONN_STATE_DISCONNECTED = 1; // 断开连接 + CONN_STATE_CONNECTING = 2; // 连接中 + CONN_STATE_CONNECTED = 3; // 已连接 + CONN_STATE_RECONNECTING = 4; // 重连中 + CONN_STATE_ERROR = 5; // 错误状态 +} + +message NetworkMetrics { + double download_bandwidth_bps = 1; // 下载带宽(bps) + double upload_bandwidth_bps = 2; // 上传带宽(bps) + double packet_loss = 3; // 丢包率(0-1) + double average_latency_ms = 4; // 平均延迟(毫秒) + double jitter_ms = 5; // 抖动(毫秒) + uint64 total_bytes_sent = 6; // 总发送字节数 + uint64 total_bytes_received = 7; // 总接收字节数 + uint32 packet_errors = 8; // 包错误数 +} + +// ================================================================================================ +// 健康检查 +// ================================================================================================ +message HealthCheckRequest { + string check_id = 1; // 检查ID + HealthCheckType type = 2; // 检查类型 + string target_id = 3; // 目标ID + int32 timeout_ms = 4; // 超时时间(毫秒) +} + +enum HealthCheckType { + CHECK_UNKNOWN = 0; + CHECK_PING = 1; // Ping检查 + CHECK_DEEP = 2; // 深度检查 + CHECK_RESOURCE = 3; // 资源检查 + CHECK_CONNECTIVITY = 4; // 连接性检查 +} + +message HealthCheckResponse { + string check_id = 1; // 检查ID + HealthStatus status = 2; // 健康状态 + string message = 3; // 状态消息 + map details = 4; // 详细信息 + int32 response_time_ms = 5; // 响应时间(毫秒) +} + +enum HealthStatus { + HEALTH_UNKNOWN = 0; + HEALTH_OK = 1; // 正常 + HEALTH_WARNING = 2; // 警告 + HEALTH_ERROR = 3; // 错误 + HEALTH_CRITICAL = 4; // 严重错误 + HEALTH_TIMEOUT = 5; // 超时 +} + +// ================================================================================================ +// 诊断请求和响应 +// ================================================================================================ +message DiagnosticRequest { + string request_id = 1; // 请求ID + DiagnosticType type = 2; // 诊断类型 + string target = 3; // 目标 + map parameters = 4; // 诊断参数 + int32 timeout_ms = 5; // 超时时间(毫秒) +} + +enum DiagnosticType { + DIAG_UNKNOWN = 0; + DIAG_SYSTEM = 1; // 系统诊断 + DIAG_PROCESS = 2; // 进程诊断 + DIAG_AUDIO = 3; // 音频诊断 + DIAG_PLUGIN = 4; // 插件诊断 + DIAG_NETWORK = 5; // 网络诊断 + DIAG_DEVICE = 6; // 设备诊断 +} + +message DiagnosticResponse { + string request_id = 1; // 请求ID + DiagnosticResult result = 2; // 诊断结果 + repeated DiagnosticFinding findings = 3; // 发现 + string summary = 4; // 摘要 + bytes raw_data = 5; // 原始数据 + int32 execution_time_ms = 6; // 执行时间(毫秒) +} + +enum DiagnosticResult { + RESULT_UNKNOWN = 0; + RESULT_OK = 1; // 正常 + RESULT_WARNING = 2; // 警告 + RESULT_ERROR = 3; // 错误 + RESULT_CRITICAL = 4; // 严重错误 + RESULT_TIMEOUT = 5; // 超时 +} + +message DiagnosticFinding { + string id = 1; // 发现ID + SeverityLevel severity = 2; // 严重程度 + string title = 3; // 标题 + string description = 4; // 描述 + string location = 5; // 位置 + string recommendation = 6; // 建议 + map details = 7; // 详细信息 +} + +enum SeverityLevel { + SEVERITY_INFO = 0; // 信息 + SEVERITY_LOW = 1; // 低 + SEVERITY_MEDIUM = 2; // 中 + SEVERITY_HIGH = 3; // 高 + SEVERITY_CRITICAL = 4; // 严重 +} \ No newline at end of file diff --git a/src/engine/CMakeLists.txt b/src/engine/CMakeLists.txt new file mode 100644 index 0000000..ba7d0c0 --- /dev/null +++ b/src/engine/CMakeLists.txt @@ -0,0 +1,117 @@ +# ================================================================================================ +# Audio Backend - 音频引擎核心模块 +# ================================================================================================ +# 描述: 音频处理引擎核心组件,包括音频流管理、混音、处理链 +# 功能: 音频缓冲区管理、处理图调度、混音引擎 +# 依赖: Common, Communication, SIMD +# ================================================================================================ + +# ================================================================================================ +# 自动收集源文件和头文件 +# ================================================================================================ +set(MODULE_SOURCES "") +retrieve_files(${CMAKE_CURRENT_SOURCE_DIR} MODULE_SOURCES) + +# 如果当前没有源文件,创建一个空目标占位 +if(NOT MODULE_SOURCES) + message(STATUS "Engine模块: 当前无源文件,创建接口库占位") + add_library(audio_backend_engine INTERFACE) + add_library(AudioBackend::Engine ALIAS audio_backend_engine) + + # 设置接口包含路径 + target_include_directories(audio_backend_engine INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR} + ) + + # 设置接口依赖 + target_link_libraries(audio_backend_engine INTERFACE + AudioBackend::Common + AudioBackend::Communication + AudioBackend::SIMD + ) + + return() +endif() + +# ================================================================================================ +# 库目标定义 +# ================================================================================================ +add_library(audio_backend_engine STATIC ${MODULE_SOURCES}) + +# 设置别名 +add_library(AudioBackend::Engine ALIAS audio_backend_engine) + +# ================================================================================================ +# 目标属性配置 +# ================================================================================================ +target_include_directories(audio_backend_engine + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} +) + +# ================================================================================================ +# 依赖关系配置 +# ================================================================================================ +target_link_libraries(audio_backend_engine + PUBLIC + ${audio_backend_project_options} + AudioBackend::Common + AudioBackend::Communication + PRIVATE + AudioBackend::SIMD + # 音频I/O库 + portaudio::portaudio + sndfile::sndfile + ${PLATFORM_LIBS} +) + +# 条件性依赖 +if(TARGET rtmidi::rtmidi) + target_link_libraries(audio_backend_engine PRIVATE rtmidi::rtmidi) +endif() + +if(TARGET libsamplerate::libsamplerate) + target_link_libraries(audio_backend_engine PRIVATE libsamplerate::libsamplerate) +endif() + +# ================================================================================================ +# 音频引擎特定编译选项 +# ================================================================================================ +# 高优先级线程设置 +if(WIN32) + target_compile_definitions(audio_backend_engine PRIVATE WIN32_LEAN_AND_MEAN) +elseif(UNIX) + # UNIX平台需要链接实时线程支持 + find_library(REALTIME_LIB rt) + if(REALTIME_LIB) + target_link_libraries(audio_backend_engine PRIVATE ${REALTIME_LIB}) + endif() +endif() + +# ================================================================================================ +# 目标编译定义 +# ================================================================================================ +target_compile_definitions(audio_backend_engine + PRIVATE + AUDIO_BACKEND_ENGINE_EXPORTS + PUBLIC + # 公共宏定义 +) + +# ================================================================================================ +# 操作系统平台定义 +# ================================================================================================ +add_os_definitions(audio_backend_engine) + +# ================================================================================================ +# 安装规则 +# ================================================================================================ +install(TARGETS audio_backend_engine + EXPORT AudioBackendTargets + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} +) + +message(STATUS "Engine模块: 已配置 ${MODULE_SOURCES}个文件") \ No newline at end of file diff --git a/src/engine/audio_buffer.cpp b/src/engine/audio_buffer.cpp new file mode 100644 index 0000000..8d30ccb --- /dev/null +++ b/src/engine/audio_buffer.cpp @@ -0,0 +1,290 @@ +// ================================================================================================ +// Audio Backend - 音频缓冲区管理实现 +// ================================================================================================ + +#include "audio_buffer.h" +#include "audio_processing.h" +#include +#include +#include + +namespace audio_backend::engine { + +// ================================================================================================ +// 音频格式名称 +// ================================================================================================ +const char* get_format_name(AudioFormat format) { + switch (format) { + case AudioFormat::INT16: return "INT16"; + case AudioFormat::INT24: return "INT24"; + case AudioFormat::INT32: return "INT32"; + case AudioFormat::FLOAT32: return "FLOAT32"; + case AudioFormat::FLOAT64: return "FLOAT64"; + default: return "UNKNOWN"; + } +} + +// ================================================================================================ +// AudioBuffer实现 +// ================================================================================================ + +AudioBuffer::AudioBuffer(const AudioConfig& config, bool interleaved) + : config_(config), interleaved_(interleaved) { + validate_config(); + allocate(config, interleaved); +} + +AudioBuffer::AudioBuffer(uint32_t frames, + uint16_t channels, + AudioFormat format, + bool interleaved) + : interleaved_(interleaved) { + config_.frames_per_buffer = frames; + config_.channels = channels; + config_.format = format; + validate_config(); + allocate(config_, interleaved); +} + +AudioBuffer::AudioBuffer(AudioBuffer&& other) noexcept + : config_(other.config_), + interleaved_(other.interleaved_), + channel_stride_(other.channel_stride_), + data_(std::move(other.data_)) { + other.config_ = AudioConfig{}; + other.channel_stride_ = 0; +} + +AudioBuffer& AudioBuffer::operator=(AudioBuffer&& other) noexcept { + if (this != &other) { + config_ = other.config_; + interleaved_ = other.interleaved_; + channel_stride_ = other.channel_stride_; + data_ = std::move(other.data_); + + other.config_ = AudioConfig{}; + other.channel_stride_ = 0; + } + return *this; +} + +AudioBuffer AudioBuffer::clone() const { + AudioBuffer copy; + copy.config_ = config_; + copy.interleaved_ = interleaved_; + copy.channel_stride_ = channel_stride_; + copy.data_.allocate(data_.size()); + std::memcpy(copy.data_.data(), data_.data(), data_.size()); + return copy; +} + +void AudioBuffer::allocate(const AudioConfig& config, bool interleaved) { + config_ = config; + interleaved_ = interleaved; + validate_config(); + + size_t buffer_size = calculate_buffer_size(); + data_.allocate(buffer_size); + + if (!interleaved_) { + channel_stride_ = calculate_channel_stride(); + } + + clear(); +} + +void AudioBuffer::allocate(uint32_t frames, + uint16_t channels, + AudioFormat format, + bool interleaved) { + AudioConfig config; + config.frames_per_buffer = frames; + config.channels = channels; + config.format = format; + allocate(config, interleaved); +} + +void AudioBuffer::release() { + data_.deallocate(); + config_ = AudioConfig{}; + channel_stride_ = 0; +} + +void AudioBuffer::clear() { + if (!data_.empty()) { + std::memset(data_.data(), 0, data_.size()); + } +} + +void AudioBuffer::copy_to(AudioBuffer& dest) const { + if (dest.config_ != config_ || dest.interleaved_ != interleaved_) { + dest.allocate(config_, interleaved_); + } + + std::memcpy(dest.data_.data(), data_.data(), data_.size()); +} + +void AudioBuffer::copy_from(const AudioBuffer& src) { + src.copy_to(*this); +} + +void AudioBuffer::apply_gain(float gain) { + if (format() != AudioFormat::FLOAT32) { + throw common::AudioException( + common::ErrorCode::AUDIO_FORMAT_ERROR, + "apply_gain only supports FLOAT32 format"); + } + + float* data_ptr = reinterpret_cast(data_.data()); + size_t sample_count = config_.frames_per_buffer * config_.channels; + + // 使用SIMD优化的增益应用 + simd::apply_gain_f32(data_ptr, gain, data_ptr, sample_count); +} + +bool AudioBuffer::is_aligned() const { + return data_.is_properly_aligned(); +} + +void AudioBuffer::validate_config() const { + if (!config_.is_valid()) { + throw common::AudioException( + common::ErrorCode::INVALID_ARGUMENT, + "Invalid audio configuration"); + } +} + +size_t AudioBuffer::calculate_buffer_size() const { + return config_.get_buffer_size_bytes(); +} + +size_t AudioBuffer::calculate_channel_stride() const { + return config_.frames_per_buffer * get_format_byte_size(config_.format); +} + +AudioBuffer AudioBuffer::to_interleaved() const { + if (interleaved_) { + return clone(); + } + + AudioBuffer result(config_, true); + + // 转换非交错到交错格式 + size_t format_size = get_format_byte_size(config_.format); + + for (uint32_t frame = 0; frame < config_.frames_per_buffer; ++frame) { + for (uint16_t channel = 0; channel < config_.channels; ++channel) { + const uint8_t* src = data_.data() + channel * channel_stride_ + frame * format_size; + uint8_t* dest = result.data_.data() + (frame * config_.channels + channel) * format_size; + std::memcpy(dest, src, format_size); + } + } + + return result; +} + +AudioBuffer AudioBuffer::to_non_interleaved() const { + if (!interleaved_) { + return clone(); + } + + AudioBuffer result(config_, false); + + // 转换交错到非交错格式 + size_t format_size = get_format_byte_size(config_.format); + + for (uint32_t frame = 0; frame < config_.frames_per_buffer; ++frame) { + for (uint16_t channel = 0; channel < config_.channels; ++channel) { + const uint8_t* src = data_.data() + (frame * config_.channels + channel) * format_size; + uint8_t* dest = result.data_.data() + channel * result.channel_stride_ + frame * format_size; + std::memcpy(dest, src, format_size); + } + } + + return result; +} + +AudioBuffer AudioBuffer::convert_format(AudioFormat new_format) const { + if (new_format == config_.format) { + return clone(); + } + + // 目前只实现INT16 <-> FLOAT32的转换 + if ((config_.format == AudioFormat::INT16 && new_format == AudioFormat::FLOAT32) || + (config_.format == AudioFormat::FLOAT32 && new_format == AudioFormat::INT16)) { + + AudioConfig new_config = config_; + new_config.format = new_format; + AudioBuffer result(new_config, interleaved_); + + size_t sample_count = config_.frames_per_buffer * config_.channels; + + if (config_.format == AudioFormat::INT16 && new_format == AudioFormat::FLOAT32) { + const int16_t* src = reinterpret_cast(data_.data()); + float* dest = reinterpret_cast(result.data_.data()); + simd::convert_i16_to_f32(src, dest, sample_count); + } else { + const float* src = reinterpret_cast(data_.data()); + int16_t* dest = reinterpret_cast(result.data_.data()); + simd::convert_f32_to_i16(src, dest, sample_count); + } + + return result; + } + + throw common::AudioException( + common::ErrorCode::NOT_IMPLEMENTED, + "Format conversion not implemented for this format pair"); +} + +AudioBuffer AudioBuffer::resample(uint32_t new_sample_rate) const { + if (new_sample_rate == config_.sample_rate) { + return clone(); + } + + // 简单的线性插值重采样(实际应用中应使用更高质量的算法) + double ratio = static_cast(new_sample_rate) / config_.sample_rate; + uint32_t new_frames = static_cast(config_.frames_per_buffer * ratio); + + AudioConfig new_config = config_; + new_config.sample_rate = new_sample_rate; + new_config.frames_per_buffer = new_frames; + + AudioBuffer result(new_config, interleaved_); + + // TODO: 实现高质量的重采样算法 + // 这里仅作为占位符 + + return result; +} + +void AudioBuffer::mix_from(const AudioBuffer& src, float gain) { + if (src.config_ != config_ || src.interleaved_ != interleaved_) { + throw common::AudioException( + common::ErrorCode::INVALID_ARGUMENT, + "Buffer configurations must match for mixing"); + } + + if (format() != AudioFormat::FLOAT32 || src.format() != AudioFormat::FLOAT32) { + throw common::AudioException( + common::ErrorCode::AUDIO_FORMAT_ERROR, + "mix_from only supports FLOAT32 format"); + } + + float* dest_data = reinterpret_cast(data_.data()); + const float* src_data = reinterpret_cast(src.data_.data()); + size_t sample_count = config_.frames_per_buffer * config_.channels; + + // 使用SIMD优化的混音 + if (gain == 1.0f) { + simd::mix_audio_f32(dest_data, src_data, dest_data, sample_count); + } else { + // 先应用增益再混音 + simd::AlignedBuffer temp; + temp.allocate(sample_count); + simd::apply_gain_f32(src_data, gain, temp.data(), sample_count); + simd::mix_audio_f32(dest_data, temp.data(), dest_data, sample_count); + } +} + +} // namespace audio_backend::engine \ No newline at end of file diff --git a/src/engine/audio_buffer.h b/src/engine/audio_buffer.h new file mode 100644 index 0000000..aa6d5d4 --- /dev/null +++ b/src/engine/audio_buffer.h @@ -0,0 +1,346 @@ +// ================================================================================================ +// Audio Backend - 音频缓冲区管理 +// ================================================================================================ +// 描述: 高性能音频缓冲区管理,支持多种格式和声道配置 +// 功能: SIMD对齐、零拷贝、线程安全 +// ================================================================================================ + +#pragma once + +#include "aligned_allocator.h" +#include "error.h" +#include +#include +#include +#include +#include + +namespace audio_backend::engine { + +// ================================================================================================ +// 音频格式定义 +// ================================================================================================ +enum class AudioFormat { + UNKNOWN = 0, + INT16, // 16位有符号整数 [-32768, 32767] + INT24, // 24位有符号整数(包在int32中)[-8388608, 8388607] + INT32, // 32位有符号整数 + FLOAT32, // 32位浮点数 [-1.0, 1.0] + FLOAT64 // 64位浮点数 [-1.0, 1.0] +}; + +// 获取音频格式的字节大小 +inline size_t get_format_byte_size(AudioFormat format) { + switch (format) { + case AudioFormat::INT16: return 2; + case AudioFormat::INT24: return 3; + case AudioFormat::INT32: return 4; + case AudioFormat::FLOAT32: return 4; + case AudioFormat::FLOAT64: return 8; + default: return 0; + } +} + +// 获取音频格式名称 +const char* get_format_name(AudioFormat format); + +// ================================================================================================ +// 音频配置结构 +// ================================================================================================ +struct AudioConfig { + uint32_t sample_rate = 48000; // 采样率(Hz) + uint16_t channels = 2; // 声道数 + AudioFormat format = AudioFormat::FLOAT32; // 音频格式 + uint32_t frames_per_buffer = 512; // 每个缓冲区的帧数 + + // 验证配置有效性 + bool is_valid() const { + return sample_rate > 0 && + sample_rate <= 192000 && + channels > 0 && + channels <= 32 && + format != AudioFormat::UNKNOWN && + frames_per_buffer > 0 && + frames_per_buffer <= 8192; + } + + // 计算缓冲区大小(字节) + size_t get_buffer_size_bytes() const { + return frames_per_buffer * channels * get_format_byte_size(format); + } + + // 计算缓冲区大小(样本数) + size_t get_buffer_size_samples() const { + return frames_per_buffer * channels; + } + + // 计算延迟(毫秒) + double get_latency_ms() const { + return (static_cast(frames_per_buffer) / sample_rate) * 1000.0; + } + + // 比较操作符 + bool operator==(const AudioConfig& other) const { + return sample_rate == other.sample_rate && + channels == other.channels && + format == other.format && + frames_per_buffer == other.frames_per_buffer; + } + + bool operator!=(const AudioConfig& other) const { + return !(*this == other); + } +}; + +// ================================================================================================ +// 音频缓冲区类(支持交错和非交错格式) +// ================================================================================================ +class AudioBuffer { +public: + // 构造函数 + AudioBuffer() = default; + + explicit AudioBuffer(const AudioConfig& config, bool interleaved = false); + + AudioBuffer(uint32_t frames, + uint16_t channels, + AudioFormat format, + bool interleaved = false); + + // 移动构造和赋值 + AudioBuffer(AudioBuffer&& other) noexcept; + AudioBuffer& operator=(AudioBuffer&& other) noexcept; + + // 禁止拷贝(使用clone方法显式拷贝) + AudioBuffer(const AudioBuffer&) = delete; + AudioBuffer& operator=(const AudioBuffer&) = delete; + + ~AudioBuffer() = default; + + // 显式拷贝 + AudioBuffer clone() const; + + // 重新分配缓冲区 + void allocate(const AudioConfig& config, bool interleaved = false); + + void allocate(uint32_t frames, + uint16_t channels, + AudioFormat format, + bool interleaved = false); + + // 释放缓冲区 + void release(); + + // 清空缓冲区(填充零) + void clear(); + + // 获取配置 + const AudioConfig& config() const { return config_; } + + // 访问器 + uint32_t frames() const { return config_.frames_per_buffer; } + uint16_t channels() const { return config_.channels; } + AudioFormat format() const { return config_.format; } + uint32_t sample_rate() const { return config_.sample_rate; } + bool is_interleaved() const { return interleaved_; } + + // 数据访问(非交错格式) + template + T* channel_data(uint16_t channel) { + if (interleaved_) { + throw common::AudioException( + common::ErrorCode::INVALID_OPERATION, + "Cannot access channel data in interleaved buffer"); + } + if (channel >= config_.channels) { + throw common::AudioException( + common::ErrorCode::INVALID_ARGUMENT, + "Channel index out of range"); + } + return reinterpret_cast(data_.data() + channel * channel_stride_); + } + + template + const T* channel_data(uint16_t channel) const { + return const_cast(this)->channel_data(channel); + } + + // 数据访问(交错格式) + template + T* interleaved_data() { + if (!interleaved_) { + throw common::AudioException( + common::ErrorCode::INVALID_OPERATION, + "Cannot access interleaved data in non-interleaved buffer"); + } + return reinterpret_cast(data_.data()); + } + + template + const T* interleaved_data() const { + return const_cast(this)->interleaved_data(); + } + + // 原始数据访问 + uint8_t* data() { return data_.data(); } + const uint8_t* data() const { return data_.data(); } + + size_t size_bytes() const { return data_.size(); } + bool empty() const { return data_.empty(); } + + // 转换为交错/非交错格式 + AudioBuffer to_interleaved() const; + AudioBuffer to_non_interleaved() const; + + // 格式转换 + AudioBuffer convert_format(AudioFormat new_format) const; + + // 重采样(简单的线性插值,用于格式转换) + AudioBuffer resample(uint32_t new_sample_rate) const; + + // 复制数据到另一个缓冲区 + void copy_to(AudioBuffer& dest) const; + + // 从另一个缓冲区复制数据 + void copy_from(const AudioBuffer& src); + + // 混音(加法混合) + void mix_from(const AudioBuffer& src, float gain = 1.0f); + + // 应用增益 + void apply_gain(float gain); + + // 检查缓冲区是否正确对齐 + bool is_aligned() const; + +private: + AudioConfig config_; + bool interleaved_ = false; + size_t channel_stride_ = 0; // 非交错格式中每个声道的字节偏移 + simd::AlignedBuffer data_; + + // 辅助函数 + void validate_config() const; + size_t calculate_buffer_size() const; + size_t calculate_channel_stride() const; +}; + +// ================================================================================================ +// 环形缓冲区(用于实时音频流) +// ================================================================================================ +template +class RingBuffer { +public: + explicit RingBuffer(size_t capacity = 0) + : capacity_(capacity), + read_pos_(0), + write_pos_(0), + available_(0) { + if (capacity > 0) { + buffer_.allocate(capacity); + } + } + + // 重新分配容量 + void resize(size_t new_capacity) { + std::lock_guard lock(mutex_); + capacity_ = new_capacity; + buffer_.allocate(new_capacity); + read_pos_ = 0; + write_pos_ = 0; + available_ = 0; + } + + // 写入数据 + size_t write(const T* data, size_t count) { + std::lock_guard lock(mutex_); + + size_t space = capacity_ - available_.load(std::memory_order_acquire); + size_t to_write = std::min(count, space); + + if (to_write == 0) return 0; + + size_t write_pos = write_pos_.load(std::memory_order_relaxed); + + // 分两部分写入(如果需要环绕) + size_t first_part = std::min(to_write, capacity_ - write_pos); + std::memcpy(buffer_.data() + write_pos, data, first_part * sizeof(T)); + + if (to_write > first_part) { + size_t second_part = to_write - first_part; + std::memcpy(buffer_.data(), data + first_part, second_part * sizeof(T)); + } + + write_pos_.store((write_pos + to_write) % capacity_, std::memory_order_release); + available_.fetch_add(to_write, std::memory_order_acq_rel); + + return to_write; + } + + // 读取数据 + size_t read(T* data, size_t count) { + std::lock_guard lock(mutex_); + + size_t avail = available_.load(std::memory_order_acquire); + size_t to_read = std::min(count, avail); + + if (to_read == 0) return 0; + + size_t read_pos = read_pos_.load(std::memory_order_relaxed); + + // 分两部分读取(如果需要环绕) + size_t first_part = std::min(to_read, capacity_ - read_pos); + std::memcpy(data, buffer_.data() + read_pos, first_part * sizeof(T)); + + if (to_read > first_part) { + size_t second_part = to_read - first_part; + std::memcpy(data + first_part, buffer_.data(), second_part * sizeof(T)); + } + + read_pos_.store((read_pos + to_read) % capacity_, std::memory_order_release); + available_.fetch_sub(to_read, std::memory_order_acq_rel); + + return to_read; + } + + // 清空缓冲区 + void clear() { + std::lock_guard lock(mutex_); + read_pos_.store(0, std::memory_order_relaxed); + write_pos_.store(0, std::memory_order_relaxed); + available_.store(0, std::memory_order_relaxed); + } + + // 获取可用数据量 + size_t available() const { + return available_.load(std::memory_order_acquire); + } + + // 获取可写空间 + size_t space() const { + return capacity_ - available_.load(std::memory_order_acquire); + } + + // 获取容量 + size_t capacity() const { return capacity_; } + + // 检查是否为空 + bool empty() const { + return available_.load(std::memory_order_acquire) == 0; + } + + // 检查是否已满 + bool full() const { + return available_.load(std::memory_order_acquire) == capacity_; + } + +private: + size_t capacity_; + std::atomic read_pos_; + std::atomic write_pos_; + std::atomic available_; + simd::AlignedBuffer buffer_; + mutable std::mutex mutex_; +}; + +} // namespace audio_backend::engine \ No newline at end of file diff --git a/src/frontend/CMakeLists.txt b/src/frontend/CMakeLists.txt new file mode 100644 index 0000000..371bac7 --- /dev/null +++ b/src/frontend/CMakeLists.txt @@ -0,0 +1,106 @@ +# ================================================================================================ +# Audio Backend - 前端进程模块 +# ================================================================================================ +# 描述: 用户界面和控制进程,负责与音频引擎核心的交互 +# 功能: 硬件抽象层、用户界面集成、控制命令 +# 依赖: Common, Communication +# ================================================================================================ + +# ================================================================================================ +# 自动收集源文件和头文件 +# ================================================================================================ +set(MODULE_SOURCES "") +retrieve_files(${CMAKE_CURRENT_SOURCE_DIR} MODULE_SOURCES) + +# 如果当前没有源文件,创建一个空目标占位 +if(NOT MODULE_SOURCES) + message(STATUS "Frontend模块: 当前无源文件,创建接口库占位") + add_library(audio_backend_frontend INTERFACE) + add_library(AudioBackend::Frontend ALIAS audio_backend_frontend) + + # 设置接口包含路径 + target_include_directories(audio_backend_frontend INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR} + ) + + # 设置接口依赖 + target_link_libraries(audio_backend_frontend INTERFACE + AudioBackend::Common + AudioBackend::Communication + nlohmann_json::nlohmann_json + ) + + return() +endif() + +# ================================================================================================ +# 库目标定义 +# ================================================================================================ +add_library(audio_backend_frontend STATIC ${MODULE_SOURCES}) + +# 设置别名 +add_library(AudioBackend::Frontend ALIAS audio_backend_frontend) + +# ================================================================================================ +# 目标属性配置 +# ================================================================================================ +target_include_directories(audio_backend_frontend + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} +) + +# ================================================================================================ +# 依赖关系配置 +# ================================================================================================ +target_link_libraries(audio_backend_frontend + PUBLIC + ${audio_backend_project_options} + AudioBackend::Common + AudioBackend::Communication + PRIVATE + nlohmann_json::nlohmann_json + yaml-cpp::yaml-cpp + ${PLATFORM_LIBS} +) + +# ================================================================================================ +# 平台特定前端配置 +# ================================================================================================ +if(WIN32) + # Windows前端特定功能 + target_compile_definitions(audio_backend_frontend PRIVATE WIN32_LEAN_AND_MEAN) +elseif(APPLE) + # macOS前端特定功能 + find_library(COREFOUNDATION_FRAMEWORK CoreFoundation) + if(COREFOUNDATION_FRAMEWORK) + target_link_libraries(audio_backend_frontend PRIVATE ${COREFOUNDATION_FRAMEWORK}) + endif() +endif() + +# ================================================================================================ +# 目标编译定义 +# ================================================================================================ +target_compile_definitions(audio_backend_frontend + PRIVATE + AUDIO_BACKEND_FRONTEND_EXPORTS + PUBLIC + $<$:DAW_NETWORK_ENABLED> +) + +# ================================================================================================ +# 操作系统平台定义 +# ================================================================================================ +add_os_definitions(audio_backend_frontend) + +# ================================================================================================ +# 安装规则 +# ================================================================================================ +install(TARGETS audio_backend_frontend + EXPORT AudioBackendTargets + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} +) + +message(STATUS "Frontend模块: 已配置 ${MODULE_SOURCES}个文件") \ No newline at end of file diff --git a/src/plugin_host/CMakeLists.txt b/src/plugin_host/CMakeLists.txt new file mode 100644 index 0000000..4c57203 --- /dev/null +++ b/src/plugin_host/CMakeLists.txt @@ -0,0 +1,147 @@ +# ================================================================================================ +# Audio Backend - 插件沙盒宿主模块 +# ================================================================================================ +# 描述: 插件沙盒隔离执行环境,管理第三方插件的生命周期 +# 功能: 插件加载、沙盒隔离、进程管理、资源限制 +# 依赖: Common, Communication, Engine, Boost::process +# ================================================================================================ + +# ================================================================================================ +# 自动收集源文件和头文件 +# ================================================================================================ +set(MODULE_SOURCES "") +retrieve_files(${CMAKE_CURRENT_SOURCE_DIR} MODULE_SOURCES) + +# 如果当前没有源文件,创建一个空目标占位 +if(NOT MODULE_SOURCES) + message(STATUS "Plugin Host模块: 当前无源文件,创建接口库占位") + add_library(audio_backend_plugin_host INTERFACE) + add_library(AudioBackend::PluginHost ALIAS audio_backend_plugin_host) + + # 设置接口包含路径 + target_include_directories(audio_backend_plugin_host INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR} + ) + + # 设置接口依赖 + target_link_libraries(audio_backend_plugin_host INTERFACE + AudioBackend::Common + AudioBackend::Communication + AudioBackend::Engine + Boost::process + Boost::system + Boost::filesystem + ) + + return() +endif() + +# ================================================================================================ +# 库目标定义 +# ================================================================================================ +add_library(audio_backend_plugin_host STATIC ${MODULE_SOURCES}) + +# 设置别名 +add_library(AudioBackend::PluginHost ALIAS audio_backend_plugin_host) + +# ================================================================================================ +# 目标属性配置 +# ================================================================================================ +target_include_directories(audio_backend_plugin_host + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} +) + +# ================================================================================================ +# 依赖关系配置 +# ================================================================================================ +target_link_libraries(audio_backend_plugin_host + PUBLIC + ${audio_backend_project_options} + AudioBackend::Common + AudioBackend::Communication + AudioBackend::Engine + PRIVATE + Boost::process + Boost::system + Boost::filesystem + ${PLATFORM_LIBS} +) + +# ================================================================================================ +# 插件格式支持配置 +# ================================================================================================ +# VST支持相关的编译定义 +if(DAW_ENABLE_VST2) + target_compile_definitions(audio_backend_plugin_host PUBLIC DAW_VST2_SUPPORT) +endif() + +if(DAW_ENABLE_VST3) + target_compile_definitions(audio_backend_plugin_host PUBLIC DAW_VST3_SUPPORT) +endif() + +if(DAW_ENABLE_CLAP) + target_compile_definitions(audio_backend_plugin_host PUBLIC DAW_CLAP_SUPPORT) +endif() + +# ================================================================================================ +# 平台特定沙盒配置 +# ================================================================================================ +if(WIN32) + # Windows沙盒支持 + target_compile_definitions(audio_backend_plugin_host PRIVATE + SANDBOX_WINDOWS_SUPPORT + ) + target_link_libraries(audio_backend_plugin_host PRIVATE + advapi32 # 用于安全和进程管理 + userenv # 用户环境API + ) +elseif(APPLE) + # macOS沙盒支持 + target_compile_definitions(audio_backend_plugin_host PRIVATE + SANDBOX_MACOS_SUPPORT + ) + find_library(FOUNDATION_FRAMEWORK Foundation) + if(FOUNDATION_FRAMEWORK) + target_link_libraries(audio_backend_plugin_host PRIVATE ${FOUNDATION_FRAMEWORK}) + endif() +elseif(UNIX) + # Linux沙盒支持 (seccomp, namespaces, cgroups) + target_compile_definitions(audio_backend_plugin_host PRIVATE + SANDBOX_LINUX_SUPPORT + ) + # 检查libseccomp可用性 + find_library(SECCOMP_LIB seccomp) + if(SECCOMP_LIB) + target_link_libraries(audio_backend_plugin_host PRIVATE ${SECCOMP_LIB}) + target_compile_definitions(audio_backend_plugin_host PRIVATE HAVE_SECCOMP) + endif() +endif() + +# ================================================================================================ +# 目标编译定义 +# ================================================================================================ +target_compile_definitions(audio_backend_plugin_host + PRIVATE + AUDIO_BACKEND_PLUGIN_HOST_EXPORTS + PUBLIC + $<$:DAW_SANDBOX_ENABLED> +) + +# ================================================================================================ +# 操作系统平台定义 +# ================================================================================================ +add_os_definitions(audio_backend_plugin_host) + +# ================================================================================================ +# 安装规则 +# ================================================================================================ +install(TARGETS audio_backend_plugin_host + EXPORT AudioBackendTargets + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} +) + +message(STATUS "Plugin Host模块: 已配置 ${MODULE_SOURCES}个文件") \ No newline at end of file diff --git a/src/simd/CMakeLists.txt b/src/simd/CMakeLists.txt new file mode 100644 index 0000000..0014ca6 --- /dev/null +++ b/src/simd/CMakeLists.txt @@ -0,0 +1,131 @@ +# ================================================================================================ +# Audio Backend - SIMD优化模块 +# ================================================================================================ +# 描述: 提供SIMD(单指令多数据)优化的音频处理函数 +# 功能: 自动运行时检测CPU指令集并选择最优实现 +# 依赖: Eigen、FFTW、TBB +# ================================================================================================ + +# ================================================================================================ +# 自动收集源文件和头文件 +# ================================================================================================ +set(MODULE_SOURCES "") +retrieve_files(${CMAKE_CURRENT_SOURCE_DIR} MODULE_SOURCES) + +# 如果当前没有源文件,创建一个空目标占位 +if(NOT MODULE_SOURCES) + message(STATUS "SIMD模块: 当前无源文件,创建接口库占位") + add_library(audio_backend_simd INTERFACE) + add_library(AudioBackend::SIMD ALIAS audio_backend_simd) + + # 设置接口包含路径 + target_include_directories(audio_backend_simd INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR} + ) + + # 设置接口依赖 + target_link_libraries(audio_backend_simd INTERFACE + AudioBackend::Common + Eigen3::Eigen + TBB::tbb + ) + + if(TARGET fftw::fftw) + target_link_libraries(audio_backend_simd INTERFACE fftw::fftw) + endif() + + return() +endif() + +# ================================================================================================ +# 库目标定义 +# ================================================================================================ +add_library(audio_backend_simd STATIC ${MODULE_SOURCES}) + +# 设置别名 +add_library(AudioBackend::SIMD ALIAS audio_backend_simd) + +# ================================================================================================ +# 目标属性配置 +# ================================================================================================ +target_include_directories(audio_backend_simd + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} +) + +# ================================================================================================ +# 依赖关系配置 +# ================================================================================================ +target_link_libraries(audio_backend_simd + PUBLIC + ${audio_backend_project_options} + AudioBackend::Common + Eigen3::Eigen + TBB::tbb + PRIVATE + # 私有依赖 +) + +# 条件性依赖FFTW +if(TARGET fftw::fftw) + target_link_libraries(audio_backend_simd PUBLIC fftw::fftw) +endif() + +# ================================================================================================ +# SIMD特定编译选项 +# ================================================================================================ +# 1. 对于x86/x64平台,启用特定的SIMD指令集 +if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64|i686") + if(MSVC) + if(DAW_ENABLE_AVX512) + target_compile_options(audio_backend_simd PRIVATE /arch:AVX512) + elseif(DAW_ENABLE_SIMD) + target_compile_options(audio_backend_simd PRIVATE /arch:AVX2) + endif() + else() # GCC/Clang + if(DAW_ENABLE_AVX512) + target_compile_options(audio_backend_simd PRIVATE + -mavx512f -mavx512vl -mavx512bw -mfma) + elseif(DAW_ENABLE_SIMD) + target_compile_options(audio_backend_simd PRIVATE -mavx2 -mfma) + endif() + endif() +# 2. 对于ARM平台,启用NEON +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm|aarch64|ARM64") + if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|ARM64") + # ARM64自动支持NEON,不需要额外标志 + else() + if(NOT APPLE) # ARM32非Apple平台 + target_compile_options(audio_backend_simd PRIVATE -mfpu=neon) + endif() + endif() +endif() + +# ================================================================================================ +# 目标编译定义 +# ================================================================================================ +target_compile_definitions(audio_backend_simd + PRIVATE + AUDIO_BACKEND_SIMD_EXPORTS + PUBLIC + $<$:DAW_SIMD_ENABLED> + $<$:DAW_AVX512_ENABLED> +) + +# ================================================================================================ +# 操作系统平台定义 +# ================================================================================================ +add_os_definitions(audio_backend_simd) + +# ================================================================================================ +# 安装规则 +# ================================================================================================ +install(TARGETS audio_backend_simd + EXPORT AudioBackendTargets + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} +) + +message(STATUS "SIMD模块: 已配置 ${MODULE_SOURCES}个文件") \ No newline at end of file diff --git a/src/simd/aligned_allocator.h b/src/simd/aligned_allocator.h new file mode 100644 index 0000000..589073a --- /dev/null +++ b/src/simd/aligned_allocator.h @@ -0,0 +1,305 @@ +// ================================================================================================ +// Audio Backend - SIMD内存对齐分配器 +// ================================================================================================ +// 描述: 为SIMD操作提供正确对齐的内存分配 +// 功能: 支持16/32/64字节对齐,确保SIMD指令高效执行 +// ================================================================================================ + +#pragma once + +#include +#include +#include +#include +#include + +namespace audio_backend::simd { + +// ================================================================================================ +// 对齐常量 +// ================================================================================================ +constexpr size_t ALIGNMENT_SSE = 16; // SSE需要16字节对齐 +constexpr size_t ALIGNMENT_AVX = 32; // AVX需要32字节对齐 +constexpr size_t ALIGNMENT_AVX512 = 64; // AVX-512需要64字节对齐 +constexpr size_t ALIGNMENT_CACHE = 64; // CPU缓存行大小(通常64字节) + +// ================================================================================================ +// 对齐内存分配/释放函数 +// ================================================================================================ + +// 分配对齐内存 +inline void* aligned_malloc(size_t size, size_t alignment) { + if (alignment == 0 || (alignment & (alignment - 1)) != 0) { + // 对齐值必须是2的幂 + return nullptr; + } + +#if ALICHO_PLATFORM_WINDOWS + return _aligned_malloc(size, alignment); +#elif ALICHO_PLATFORM_POSIX || ALICHO_PLATFORM_UNIX + void* ptr = nullptr; + if (posix_memalign(&ptr, alignment, size) != 0) { + return nullptr; + } + return ptr; +#else + // 回退实现:手动对齐 + // 分配额外空间来存储原始指针和进行对齐 + size_t total_size = size + alignment + sizeof(void*); + void* raw_ptr = std::malloc(total_size); + if (!raw_ptr) { + return nullptr; + } + + // 计算对齐后的地址 + uintptr_t raw_addr = reinterpret_cast(raw_ptr); + uintptr_t aligned_addr = (raw_addr + sizeof(void*) + alignment - 1) & ~(alignment - 1); + void* aligned_ptr = reinterpret_cast(aligned_addr); + + // 在对齐地址前存储原始指针 + (reinterpret_cast(aligned_ptr))[-1] = raw_ptr; + + return aligned_ptr; +#endif +} + +// 释放对齐内存 +inline void aligned_free(void* ptr) { + if (!ptr) return; + +#if ALICHO_PLATFORM_WINDOWS + _aligned_free(ptr); +#elif ALICHO_PLATFORM_POSIX || ALICHO_PLATFORM_UNIX + std::free(ptr); +#else + // 回退实现:获取原始指针并释放 + void* raw_ptr = (reinterpret_cast(ptr))[-1]; + std::free(raw_ptr); +#endif +} + +// ================================================================================================ +// 对齐分配器(用于STL容器) +// ================================================================================================ +template +class AlignedAllocator { +public: + using value_type = T; + using pointer = T*; + using const_pointer = const T*; + using reference = T&; + using const_reference = const T&; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + + template + struct rebind { + using other = AlignedAllocator; + }; + + AlignedAllocator() noexcept = default; + + template + AlignedAllocator(const AlignedAllocator&) noexcept {} + + pointer allocate(size_type n) { + if (n == 0) return nullptr; + + size_type size = n * sizeof(T); + void* ptr = aligned_malloc(size, Alignment); + + if (!ptr) { + throw std::bad_alloc(); + } + + return static_cast(ptr); + } + + void deallocate(pointer p, size_type) noexcept { + aligned_free(p); + } + + template + void construct(U* p, Args&&... args) { + ::new(static_cast(p)) U(std::forward(args)...); + } + + template + void destroy(U* p) { + p->~U(); + } + + size_type max_size() const noexcept { + return std::numeric_limits::max() / sizeof(T); + } +}; + +template +bool operator==(const AlignedAllocator&, const AlignedAllocator&) noexcept { + return A1 == A2; +} + +template +bool operator!=(const AlignedAllocator&, const AlignedAllocator&) noexcept { + return A1 != A2; +} + +// ================================================================================================ +// 便捷类型定义 +// ================================================================================================ +template +using AlignedVector16 = std::vector>; + +template +using AlignedVector32 = std::vector>; + +template +using AlignedVector64 = std::vector>; + +// 根据当前CPU支持的最高SIMD级别选择对齐方式 +template +using AlignedVectorAuto = std::vector>; + +// ================================================================================================ +// 对齐检查工具 +// ================================================================================================ + +// 检查指针是否对齐 +template +inline bool is_aligned(const void* ptr) { + return (reinterpret_cast(ptr) % Alignment) == 0; +} + +// 检查指针是否按特定字节数对齐 +inline bool is_aligned(const void* ptr, size_t alignment) { + return (reinterpret_cast(ptr) % alignment) == 0; +} + +// 计算对齐后的大小 +inline size_t align_size(size_t size, size_t alignment) { + return (size + alignment - 1) & ~(alignment - 1); +} + +// 计算对齐后的指针 +template +inline void* align_pointer(void* ptr) { + uintptr_t addr = reinterpret_cast(ptr); + uintptr_t aligned = (addr + Alignment - 1) & ~(Alignment - 1); + return reinterpret_cast(aligned); +} + +// ================================================================================================ +// RAII对齐内存管理器 +// ================================================================================================ +template +class AlignedBuffer { +public: + AlignedBuffer() : data_(nullptr), size_(0) {} + + explicit AlignedBuffer(size_t count) : data_(nullptr), size_(0) { + allocate(count); + } + + ~AlignedBuffer() { + deallocate(); + } + + // 禁止拷贝 + AlignedBuffer(const AlignedBuffer&) = delete; + AlignedBuffer& operator=(const AlignedBuffer&) = delete; + + // 允许移动 + AlignedBuffer(AlignedBuffer&& other) noexcept + : data_(other.data_), size_(other.size_) { + other.data_ = nullptr; + other.size_ = 0; + } + + AlignedBuffer& operator=(AlignedBuffer&& other) noexcept { + if (this != &other) { + deallocate(); + data_ = other.data_; + size_ = other.size_; + other.data_ = nullptr; + other.size_ = 0; + } + return *this; + } + + void allocate(size_t count) { + deallocate(); + if (count > 0) { + data_ = static_cast(aligned_malloc(count * sizeof(T), Alignment)); + if (!data_) { + throw std::bad_alloc(); + } + size_ = count; + + // 对于非POD类型,需要构造对象 + if constexpr (!std::is_trivially_constructible_v) { + for (size_t i = 0; i < size_; ++i) { + new(data_ + i) T(); + } + } + } + } + + void deallocate() { + if (data_) { + // 对于非POD类型,需要析构对象 + if constexpr (!std::is_trivially_destructible_v) { + for (size_t i = 0; i < size_; ++i) { + data_[i].~T(); + } + } + aligned_free(data_); + data_ = nullptr; + size_ = 0; + } + } + + void resize(size_t new_count) { + if (new_count != size_) { + allocate(new_count); + } + } + + T* data() noexcept { return data_; } + const T* data() const noexcept { return data_; } + + size_t size() const noexcept { return size_; } + bool empty() const noexcept { return size_ == 0; } + + T& operator[](size_t index) noexcept { return data_[index]; } + const T& operator[](size_t index) const noexcept { return data_[index]; } + + T* begin() noexcept { return data_; } + T* end() noexcept { return data_ + size_; } + const T* begin() const noexcept { return data_; } + const T* end() const noexcept { return data_ + size_; } + + // 检查对齐 + bool is_properly_aligned() const noexcept { + return is_aligned(data_); + } + +private: + T* data_; + size_t size_; +}; + +// ================================================================================================ +// 对齐断言宏 +// ================================================================================================ +#ifdef AUDIO_BACKEND_DEBUG + #define ASSERT_ALIGNED(ptr, alignment) \ + do { \ + if (!audio_backend::simd::is_aligned(ptr, alignment)) { \ + throw std::runtime_error("Pointer not properly aligned"); \ + } \ + } while(0) +#else + #define ASSERT_ALIGNED(ptr, alignment) ((void)0) +#endif + +} // namespace audio_backend::simd \ No newline at end of file diff --git a/src/simd/audio_processing.cpp b/src/simd/audio_processing.cpp new file mode 100644 index 0000000..38a8736 --- /dev/null +++ b/src/simd/audio_processing.cpp @@ -0,0 +1,249 @@ +// ================================================================================================ +// Audio Backend - SIMD音频处理函数实现 +// ================================================================================================ + +#include "audio_processing.h" +#include +#include +#include +#include + +// SSE相关头文件 +#if ALICHO_PLATFORM_X86 +#include +#endif + +// NEON相关头文件 +#if ALICHO_PLATFORM_ARM && defined(__ARM_NEON) +#include +#endif + +namespace audio_backend::simd { + +// ================================================================================================ +// 混合函数 - 标量实现(所有平台通用) +// ================================================================================================ +void mix_audio_f32_scalar(const float* input1, const float* input2, float* output, size_t samples) { + for (size_t i = 0; i < samples; ++i) { + output[i] = input1[i] + input2[i]; + } +} + +// ================================================================================================ +// 混合函数 - SSE实现 +// ================================================================================================ +#if ALICHO_PLATFORM_X86 +void mix_audio_f32_sse(const float* input1, const float* input2, float* output, size_t samples) { + ASSERT_ALIGNED(input1, ALIGNMENT_SSE); + ASSERT_ALIGNED(input2, ALIGNMENT_SSE); + ASSERT_ALIGNED(output, ALIGNMENT_SSE); + + const size_t vector_size = 4; // 每个SSE向量处理4个浮点数 + size_t i = 0; + + // 向量化处理 + for (; i + vector_size <= samples; i += vector_size) { + __m128 vec1 = _mm_load_ps(input1 + i); + __m128 vec2 = _mm_load_ps(input2 + i); + __m128 result = _mm_add_ps(vec1, vec2); + _mm_store_ps(output + i, result); + } + + // 处理剩余元素 + for (; i < samples; ++i) { + output[i] = input1[i] + input2[i]; + } +} + +// ================================================================================================ +// 混合函数 - AVX实现 +// ================================================================================================ +void mix_audio_f32_avx(const float* input1, const float* input2, float* output, size_t samples) { + ASSERT_ALIGNED(input1, ALIGNMENT_AVX); + ASSERT_ALIGNED(input2, ALIGNMENT_AVX); + ASSERT_ALIGNED(output, ALIGNMENT_AVX); + + const size_t vector_size = 8; // 每个AVX向量处理8个浮点数 + size_t i = 0; + + // 向量化处理 + for (; i + vector_size <= samples; i += vector_size) { + __m256 vec1 = _mm256_load_ps(input1 + i); + __m256 vec2 = _mm256_load_ps(input2 + i); + __m256 result = _mm256_add_ps(vec1, vec2); + _mm256_store_ps(output + i, result); + } + + // 处理剩余元素 + for (; i < samples; ++i) { + output[i] = input1[i] + input2[i]; + } +} +#endif + +// ================================================================================================ +// 混合函数 - ARM NEON实现 +// ================================================================================================ +#if ALICHO_PLATFORM_ARM && defined(__ARM_NEON) +void mix_audio_f32_neon(const float* input1, const float* input2, float* output, size_t samples) { + const size_t vector_size = 4; // 每个NEON向量处理4个浮点数 + size_t i = 0; + + // 向量化处理 + for (; i + vector_size <= samples; i += vector_size) { + float32x4_t vec1 = vld1q_f32(input1 + i); + float32x4_t vec2 = vld1q_f32(input2 + i); + float32x4_t result = vaddq_f32(vec1, vec2); + vst1q_f32(output + i, result); + } + + // 处理剩余元素 + for (; i < samples; ++i) { + output[i] = input1[i] + input2[i]; + } +} +#endif + +// ================================================================================================ +// 音量控制函数 - 标量实现 +// ================================================================================================ +void apply_gain_f32_scalar(const float* input, float gain, float* output, size_t samples) { + for (size_t i = 0; i < samples; ++i) { + output[i] = input[i] * gain; + } +} + +// ================================================================================================ +// 音量控制函数 - SSE实现 +// ================================================================================================ +#if ALICHO_PLATFORM_X86 +void apply_gain_f32_sse(const float* input, float gain, float* output, size_t samples) { + ASSERT_ALIGNED(input, ALIGNMENT_SSE); + ASSERT_ALIGNED(output, ALIGNMENT_SSE); + + const size_t vector_size = 4; + size_t i = 0; + + // 创建填充了增益值的向量 + __m128 gain_vec = _mm_set1_ps(gain); + + // 向量化处理 + for (; i + vector_size <= samples; i += vector_size) { + __m128 in_vec = _mm_load_ps(input + i); + __m128 result = _mm_mul_ps(in_vec, gain_vec); + _mm_store_ps(output + i, result); + } + + // 处理剩余元素 + for (; i < samples; ++i) { + output[i] = input[i] * gain; + } +} +#endif + +// ================================================================================================ +// 格式转换 - 16位整数转32位浮点(标量实现) +// ================================================================================================ +void convert_i16_to_f32_scalar(const int16_t* input, float* output, size_t samples) { + const float scale = 1.0f / 32768.0f; // 将[-32768, 32767]缩放到[-1.0, 1.0] + + for (size_t i = 0; i < samples; ++i) { + output[i] = input[i] * scale; + } +} + +// ================================================================================================ +// 格式转换 - 16位整数转32位浮点(SSE实现) +// ================================================================================================ +#if ALICHO_PLATFORM_X86 +void convert_i16_to_f32_sse(const int16_t* input, float* output, size_t samples) { + ASSERT_ALIGNED(output, ALIGNMENT_SSE); + + const size_t vector_size = 4; + size_t i = 0; + + const __m128 scale_vec = _mm_set1_ps(1.0f / 32768.0f); + + // 向量化处理 + for (; i + vector_size <= samples; i += vector_size) { + // 加载4个16位整数并转换为32位整数 + __m128i in_i16 = _mm_loadu_si128(reinterpret_cast(input + i)); + + // 将前4个16位整数转换为32位整数 + __m128i in_i32 = _mm_cvtepi16_epi32(in_i16); + + // 转换为浮点数 + __m128 in_f32 = _mm_cvtepi32_ps(in_i32); + + // 缩放到[-1.0, 1.0] + __m128 result = _mm_mul_ps(in_f32, scale_vec); + + // 存储结果 + _mm_store_ps(output + i, result); + } + + // 处理剩余元素 + for (; i < samples; ++i) { + output[i] = input[i] * (1.0f / 32768.0f); + } +} +#endif + +// ================================================================================================ +// 音频处理函数注册 +// ================================================================================================ +void AudioProcessingRegistry::register_all_functions() { + // 注册混音函数 + REGISTER_SIMD_FUNCTION("mix_audio_f32", FunctionVersion::SCALAR, mix_audio_f32_scalar); + +#if ALICHO_PLATFORM_X86 + REGISTER_SIMD_FUNCTION("mix_audio_f32", FunctionVersion::SSE, mix_audio_f32_sse); + REGISTER_SIMD_FUNCTION("mix_audio_f32", FunctionVersion::AVX, mix_audio_f32_avx); +#endif + +#if ALICHO_PLATFORM_ARM && defined(__ARM_NEON) + REGISTER_SIMD_FUNCTION("mix_audio_f32", FunctionVersion::NEON, mix_audio_f32_neon); +#endif + + // 注册音量控制函数 + REGISTER_SIMD_FUNCTION("apply_gain_f32", FunctionVersion::SCALAR, apply_gain_f32_scalar); + +#if ALICHO_PLATFORM_X86 + REGISTER_SIMD_FUNCTION("apply_gain_f32", FunctionVersion::SSE, apply_gain_f32_sse); +#endif + + // 注册格式转换函数 + REGISTER_SIMD_FUNCTION("convert_i16_to_f32", FunctionVersion::SCALAR, convert_i16_to_f32_scalar); + +#if ALICHO_PLATFORM_X86 + REGISTER_SIMD_FUNCTION("convert_i16_to_f32", FunctionVersion::SSE, convert_i16_to_f32_sse); +#endif + + // 可以在这里添加更多函数注册 +} + +void AudioProcessingRegistry::print_available_functions() { + FunctionDispatcher::instance().print_registry_status(); +} + +// ================================================================================================ +// 对外API实现(调用注册的最优函数) +// ================================================================================================ +void mix_audio_f32(const float* input1, const float* input2, float* output, size_t samples) { + CALL_SIMD_FUNCTION(void(const float*, const float*, float*, size_t), "mix_audio_f32", + input1, input2, output, samples); +} + +void apply_gain_f32(const float* input, float gain, float* output, size_t samples) { + CALL_SIMD_FUNCTION(void(const float*, float, float*, size_t), "apply_gain_f32", + input, gain, output, samples); +} + +void convert_i16_to_f32(const int16_t* input, float* output, size_t samples) { + CALL_SIMD_FUNCTION(void(const int16_t*, float*, size_t), "convert_i16_to_f32", + input, output, samples); +} + +// 其它函数可以按需添加 + +} // namespace audio_backend::simd \ No newline at end of file diff --git a/src/simd/audio_processing.h b/src/simd/audio_processing.h new file mode 100644 index 0000000..7e053a0 --- /dev/null +++ b/src/simd/audio_processing.h @@ -0,0 +1,227 @@ +// ================================================================================================ +// Audio Backend - SIMD音频处理函数 +// ================================================================================================ +// 描述: 使用SIMD优化的音频处理函数集合 +// 功能: 音频混合、音量控制、格式转换、基础数学运算 +// ================================================================================================ + +#pragma once + +#include "function_dispatcher.h" +#include "aligned_allocator.h" +#include +#include + +namespace audio_backend::simd { + +// ================================================================================================ +// 音频格式定义 +// ================================================================================================ +enum class AudioFormat { + INT16, // 16位有符号整数 + INT24, // 24位有符号整数(通常打包在int32中) + INT32, // 32位有符号整数 + FLOAT32, // 32位浮点数 + FLOAT64 // 64位浮点数 +}; + +// ================================================================================================ +// 音频混合函数 +// ================================================================================================ + +// 混合两个浮点音频缓冲区 +void mix_audio_f32(const float* input1, const float* input2, float* output, size_t samples); + +// 混合多个浮点音频缓冲区 +void mix_audio_multi_f32(const float* const* inputs, size_t num_inputs, float* output, size_t samples); + +// 带权重的音频混合 +void mix_audio_weighted_f32(const float* input1, float weight1, + const float* input2, float weight2, + float* output, size_t samples); + +// ================================================================================================ +// 音量控制函数 +// ================================================================================================ + +// 应用恒定音量倍数 +void apply_gain_f32(const float* input, float gain, float* output, size_t samples); + +// 应用渐变音量(线性插值) +void apply_gain_ramp_f32(const float* input, float start_gain, float end_gain, + float* output, size_t samples); + +// 应用每个样本不同的音量 +void apply_gain_per_sample_f32(const float* input, const float* gains, + float* output, size_t samples); + +// ================================================================================================ +// 音频格式转换函数 +// ================================================================================================ + +// 16位整数转32位浮点数 +void convert_i16_to_f32(const int16_t* input, float* output, size_t samples); + +// 32位浮点数转16位整数 +void convert_f32_to_i16(const float* input, int16_t* output, size_t samples); + +// 32位整数转32位浮点数 +void convert_i32_to_f32(const int32_t* input, float* output, size_t samples); + +// 32位浮点数转32位整数 +void convert_f32_to_i32(const float* input, int32_t* output, size_t samples); + +// 单声道转立体声(复制) +void mono_to_stereo_f32(const float* input, float* output, size_t samples); + +// 立体声转单声道(平均) +void stereo_to_mono_f32(const float* input, float* output, size_t samples); + +// ================================================================================================ +// 数学运算函数 +// ================================================================================================ + +// 向量加法 +void vector_add_f32(const float* a, const float* b, float* result, size_t samples); + +// 向量减法 +void vector_subtract_f32(const float* a, const float* b, float* result, size_t samples); + +// 向量乘法 +void vector_multiply_f32(const float* a, const float* b, float* result, size_t samples); + +// 标量乘法 +void vector_scale_f32(const float* input, float scale, float* output, size_t samples); + +// 计算RMS(均方根) +float calculate_rms_f32(const float* input, size_t samples); + +// 计算峰值 +float calculate_peak_f32(const float* input, size_t samples); + +// ================================================================================================ +// 滤波器和效果函数 +// ================================================================================================ + +// 简单低通滤波器(一阶) +void lowpass_filter_f32(const float* input, float* output, size_t samples, + float cutoff_freq, float sample_rate, float* state); + +// 简单高通滤波器(一阶) +void highpass_filter_f32(const float* input, float* output, size_t samples, + float cutoff_freq, float sample_rate, float* state); + +// 延迟效果 +void delay_effect_f32(const float* input, float* output, size_t samples, + float* delay_buffer, size_t delay_buffer_size, + size_t delay_samples, float feedback, float* delay_index); + +// ================================================================================================ +// 音频分析函数 +// ================================================================================================ + +// 检测静音 +bool detect_silence_f32(const float* input, size_t samples, float threshold = -60.0f); + +// 检测削波 +bool detect_clipping_f32(const float* input, size_t samples, float threshold = 0.99f); + +// 计算频谱能量(需要配合FFT使用) +void calculate_spectral_energy_f32(const float* fft_output, float* energy_bands, + size_t fft_size, size_t num_bands); + +// ================================================================================================ +// SIMD优化的音频缓冲区类 +// ================================================================================================ +template +class AudioBuffer { +public: + AudioBuffer() = default; + + AudioBuffer(size_t channels, size_t samples) + : channels_(channels), samples_(samples) { + allocate(channels, samples); + } + + void allocate(size_t channels, size_t samples) { + channels_ = channels; + samples_ = samples; + size_t total_samples = channels * samples; + buffer_.resize(total_samples); + } + + void clear() { + std::fill(buffer_.begin(), buffer_.end(), T{}); + } + + T* channel_data(size_t channel) { + return buffer_.data() + channel * samples_; + } + + const T* channel_data(size_t channel) const { + return buffer_.data() + channel * samples_; + } + + T* data() { return buffer_.data(); } + const T* data() const { return buffer_.data(); } + + size_t channels() const { return channels_; } + size_t samples() const { return samples_; } + size_t size() const { return buffer_.size(); } + + bool empty() const { return buffer_.empty(); } + + // 获取交错格式的数据(LRLRLR...) + void to_interleaved(T* output) const { + for (size_t sample = 0; sample < samples_; ++sample) { + for (size_t channel = 0; channel < channels_; ++channel) { + output[sample * channels_ + channel] = + buffer_[channel * samples_ + sample]; + } + } + } + + // 从交错格式填充数据 + void from_interleaved(const T* input) { + for (size_t sample = 0; sample < samples_; ++sample) { + for (size_t channel = 0; channel < channels_; ++channel) { + buffer_[channel * samples_ + sample] = + input[sample * channels_ + channel]; + } + } + } + + // 检查对齐 + bool is_properly_aligned() const { + return is_aligned(buffer_.data()); + } + +private: + size_t channels_ = 0; + size_t samples_ = 0; + AlignedBuffer buffer_; +}; + +// 便捷类型定义 +using AudioBufferF32 = AudioBuffer; +using AudioBufferI16 = AudioBuffer; +using AudioBufferI32 = AudioBuffer; + +// ================================================================================================ +// 函数注册器(用于在启动时注册所有SIMD版本) +// ================================================================================================ +class AudioProcessingRegistry { +public: + static void register_all_functions(); + static void print_available_functions(); +}; + +// ================================================================================================ +// 便捷宏定义 +// ================================================================================================ + +// 调用最优SIMD版本的宏 +#define CALL_SIMD_AUDIO_FUNCTION(name, ...) \ + CALL_SIMD_FUNCTION(decltype(name), #name, __VA_ARGS__) + +} // namespace audio_backend::simd \ No newline at end of file diff --git a/src/simd/cpu_features.cpp b/src/simd/cpu_features.cpp new file mode 100644 index 0000000..6722656 --- /dev/null +++ b/src/simd/cpu_features.cpp @@ -0,0 +1,513 @@ +// ================================================================================================ +// Audio Backend - SIMD CPU特性检测器实现 +// ================================================================================================ + +#include "cpu_features.h" +#include +#include +#include + +// 平台特定的头文件 +#if ALICHO_PLATFORM_WINDOWS + #include + #include +#elif ALICHO_PLATFORM_UNIX || ALICHO_PLATFORM_POSIX + #if ALICHO_PLATFORM_X86 + #include + #endif + #include + #include + #if ALICHO_PLATFORM_APPLE + #include + #endif +#endif + +// ARM NEON支持 +#if ALICHO_PLATFORM_ARM && defined(__ARM_NEON) + #include +#endif + +namespace audio_backend::simd { + +// ================================================================================================ +// CPUInfo的features_string方法实现 +// ================================================================================================ +std::string CPUInfo::features_string() const { + std::string result; + + struct FeatureNamePair { + CPUFeature feature; + const char* name; + }; + + static const FeatureNamePair feature_names[] = { + { CPUFeature::SSE, "SSE" }, + { CPUFeature::SSE2, "SSE2" }, + { CPUFeature::SSE3, "SSE3" }, + { CPUFeature::SSSE3, "SSSE3" }, + { CPUFeature::SSE41, "SSE4.1" }, + { CPUFeature::SSE42, "SSE4.2" }, + { CPUFeature::AVX, "AVX" }, + { CPUFeature::AVX2, "AVX2" }, + { CPUFeature::FMA, "FMA" }, + { CPUFeature::AVX512F, "AVX512F" }, + { CPUFeature::AVX512VL, "AVX512VL" }, + { CPUFeature::AVX512BW, "AVX512BW" }, + { CPUFeature::AVX512DQ, "AVX512DQ" }, + { CPUFeature::NEON, "NEON" }, + { CPUFeature::NEON_FP16, "NEON_FP16" }, + { CPUFeature::POPCNT, "POPCNT" }, + { CPUFeature::BMI1, "BMI1" } + }; + + for (const auto& pair : feature_names) { + if (supports(pair.feature)) { + if (!result.empty()) { + result += ", "; + } + result += pair.name; + } + } + + return result; +} + +// ================================================================================================ +// x86/x64平台CPUID实现 +// ================================================================================================ +#if ALICHO_PLATFORM_X86 +struct CPUIDResult { + uint32_t eax, ebx, ecx, edx; +}; + +#if ALICHO_PLATFORM_WINDOWS +// Windows平台CPUID实现 +static CPUIDResult cpuid(uint32_t function_id, uint32_t subfunction_id = 0) { + CPUIDResult result; + int regs[4]; + + __cpuidex(regs, function_id, subfunction_id); + + result.eax = static_cast(regs[0]); + result.ebx = static_cast(regs[1]); + result.ecx = static_cast(regs[2]); + result.edx = static_cast(regs[3]); + + return result; +} +#else +// Unix/Linux/macOS平台CPUID实现 +static CPUIDResult cpuid(uint32_t function_id, uint32_t subfunction_id = 0) { + CPUIDResult result; + uint32_t regs[4]; + + __cpuid_count(function_id, subfunction_id, regs[0], regs[1], regs[2], regs[3]); + + result.eax = regs[0]; + result.ebx = regs[1]; + result.ecx = regs[2]; + result.edx = regs[3]; + + return result; +} +#endif + +static void get_vendor_string(char* vendor_string) { + CPUIDResult result = cpuid(0, 0); + + // 制造商ID字符串由EBX, EDX, ECX组成 + reinterpret_cast(vendor_string)[0] = result.ebx; + reinterpret_cast(vendor_string)[1] = result.edx; + reinterpret_cast(vendor_string)[2] = result.ecx; + vendor_string[12] = '\0'; +} + +static void get_brand_string(char* brand_string) { + CPUIDResult result; + + // 检查是否支持品牌字符串 + result = cpuid(0x80000000, 0); + if (result.eax < 0x80000004) { + strcpy(brand_string, "Unknown"); + return; + } + + // 获取品牌字符串的三部分 + for (uint32_t i = 0; i < 3; ++i) { + result = cpuid(0x80000002 + i, 0); + reinterpret_cast(brand_string + i * 16)[0] = result.eax; + reinterpret_cast(brand_string + i * 16)[1] = result.ebx; + reinterpret_cast(brand_string + i * 16)[2] = result.ecx; + reinterpret_cast(brand_string + i * 16)[3] = result.edx; + } + + brand_string[48] = '\0'; +} +#endif // ALICHO_PLATFORM_X86 + +// ================================================================================================ +// 构造函数和初始化 +// ================================================================================================ +CPUFeatureDetector::CPUFeatureDetector() : info_{} { + // 初始化CPU信息 + info_.vendor = "Unknown"; + info_.brand = "Unknown"; + info_.features = 0; + info_.max_simd_level = SIMDLevel::NONE; + + // 检测逻辑核心数 +#if ALICHO_PLATFORM_WINDOWS + SYSTEM_INFO sysInfo; + GetSystemInfo(&sysInfo); + info_.logical_cores = sysInfo.dwNumberOfProcessors; +#else + // Unix/Linux/macOS平台 + info_.logical_cores = static_cast(std::thread::hardware_concurrency()); +#endif + + info_.physical_cores = info_.logical_cores; // 默认,后续可能会修正 + + // 检测CPU特性 + detect_features(); +} + +void CPUFeatureDetector::detect_features() { +#if ALICHO_PLATFORM_X86 + detect_x86_features(); +#elif ALICHO_PLATFORM_ARM + detect_arm_features(); +#else + // 不支持的架构 + info_.max_simd_level = SIMDLevel::NONE; +#endif +} + +#if ALICHO_PLATFORM_X86 +void CPUFeatureDetector::detect_x86_features() { + char vendor[13] = {0}; + char brand[49] = {0}; + + // 获取制造商和品牌字符串 + get_vendor_string(vendor); + get_brand_string(brand); + + info_.vendor = vendor; + info_.brand = brand; + + // 获取标准特性 + CPUIDResult cpuid_1 = cpuid(1, 0); + + // 检测SSE特性 + if ((cpuid_1.edx & (1 << 25)) != 0) { + info_.features |= static_cast(CPUFeature::SSE); + } + if ((cpuid_1.edx & (1 << 26)) != 0) { + info_.features |= static_cast(CPUFeature::SSE2); + } + if ((cpuid_1.ecx & (1 << 0)) != 0) { + info_.features |= static_cast(CPUFeature::SSE3); + } + if ((cpuid_1.ecx & (1 << 9)) != 0) { + info_.features |= static_cast(CPUFeature::SSSE3); + } + if ((cpuid_1.ecx & (1 << 19)) != 0) { + info_.features |= static_cast(CPUFeature::SSE41); + } + if ((cpuid_1.ecx & (1 << 20)) != 0) { + info_.features |= static_cast(CPUFeature::SSE42); + } + if ((cpuid_1.ecx & (1 << 28)) != 0) { + info_.features |= static_cast(CPUFeature::AVX); + } + if ((cpuid_1.ecx & (1 << 12)) != 0) { + info_.features |= static_cast(CPUFeature::FMA); + } + if ((cpuid_1.ecx & (1 << 23)) != 0) { + info_.features |= static_cast(CPUFeature::POPCNT); + } + + // 获取扩展特性 + CPUIDResult cpuid_7 = cpuid(7, 0); + + if ((cpuid_7.ebx & (1 << 5)) != 0) { + info_.features |= static_cast(CPUFeature::AVX2); + } + if ((cpuid_7.ebx & (1 << 3)) != 0) { + info_.features |= static_cast(CPUFeature::BMI1); + } + + // AVX-512检测 + if ((cpuid_7.ebx & (1 << 16)) != 0) { + info_.features |= static_cast(CPUFeature::AVX512F); + } + if ((cpuid_7.ebx & (1 << 31)) != 0) { + info_.features |= static_cast(CPUFeature::AVX512VL); + } + if ((cpuid_7.ebx & (1 << 30)) != 0) { + info_.features |= static_cast(CPUFeature::AVX512BW); + } + if ((cpuid_7.ebx & (1 << 17)) != 0) { + info_.features |= static_cast(CPUFeature::AVX512DQ); + } + + // 确定最高SIMD级别 + if (info_.supports(CPUFeature::AVX512F) && + info_.supports(CPUFeature::AVX512VL) && + info_.supports(CPUFeature::AVX512BW)) { + info_.max_simd_level = SIMDLevel::AVX512; + } + else if (info_.supports(CPUFeature::AVX2) && + info_.supports(CPUFeature::FMA)) { + info_.max_simd_level = SIMDLevel::AVX2; + } + else if (info_.supports(CPUFeature::AVX)) { + info_.max_simd_level = SIMDLevel::AVX; + } + else if (info_.supports(CPUFeature::SSE42)) { + info_.max_simd_level = SIMDLevel::SSE4; + } + else if (info_.supports(CPUFeature::SSSE3) || + info_.supports(CPUFeature::SSE3)) { + info_.max_simd_level = SIMDLevel::SSE3; + } + else if (info_.supports(CPUFeature::SSE2)) { + info_.max_simd_level = SIMDLevel::SSE; + } + else { + info_.max_simd_level = SIMDLevel::NONE; + } + + // 获取物理核心数 - 平台特定实现 +#if ALICHO_PLATFORM_WINDOWS + // Windows特定的物理心数检测 + DWORD length = 0; + PSYSTEM_LOGICAL_PROCESSOR_INFORMATION buffer = nullptr; + + // 获取所需缓冲区大小 + GetLogicalProcessorInformation(buffer, &length); + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + buffer = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)malloc(length); + if (buffer) { + if (GetLogicalProcessorInformation(buffer, &length)) { + DWORD processorCoreCount = 0; + DWORD byteOffset = 0; + PSYSTEM_LOGICAL_PROCESSOR_INFORMATION ptr = buffer; + + while (byteOffset < length) { + if (ptr->Relationship == RelationProcessorCore) { + processorCoreCount++; + } + byteOffset += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); + ptr++; + } + + if (processorCoreCount > 0) { + info_.physical_cores = processorCoreCount; + } + } + free(buffer); + } + } +#elif ALICHO_PLATFORM_MACOS + // macOS特定的物理核数检测 + int nm[2]; + size_t len = 4; + uint32_t count; + + nm[0] = CTL_HW; + nm[1] = HW_AVAILCPU; + sysctlbyname("hw.physicalcpu", &count, &len, NULL, 0); + if (count > 0) { + info_.physical_cores = static_cast(count); + } else { + // 回退到逻辑核心数 + info_.physical_cores = info_.logical_cores; + } +#elif ALICHO_PLATFORM_LINUX + // Linux特定的物理核数检测 + // 尝试读取/proc/cpuinfo + FILE* fp = fopen("/proc/cpuinfo", "r"); + if (fp) { + char buffer[1024]; + std::unordered_set physical_ids; + + while (fgets(buffer, sizeof(buffer), fp)) { + if (strncmp(buffer, "physical id", 11) == 0) { + char* id_pos = strchr(buffer, ':'); + if (id_pos) { + physical_ids.insert(std::string(id_pos + 1)); + } + } + } + fclose(fp); + + if (!physical_ids.empty()) { + info_.physical_cores = static_cast(physical_ids.size()); + } + } +#endif +} +#endif // ALICHO_PLATFORM_X86 + +#if ALICHO_PLATFORM_ARM +void CPUFeatureDetector::detect_arm_features() { + // ARM架构下的特性检测 +#if defined(__ARM_NEON) || defined(__aarch64__) + info_.features |= static_cast(CPUFeature::NEON); + info_.max_simd_level = SIMDLevel::NEON; + +#ifdef __ARM_FEATURE_FP16 + info_.features |= static_cast(CPUFeature::NEON_FP16); + info_.max_simd_level = SIMDLevel::NEON_FP16; +#endif +#endif + + // 在ARM上获取更多CPU信息 +#if ALICHO_PLATFORM_ANDROID + // Android特定代码 + info_.vendor = "ARM"; + // 尝试从/proc/cpuinfo取更多信息 + FILE* fp = fopen("/proc/cpuinfo", "r"); + if (fp) { + char buffer[1024]; + while (fgets(buffer, sizeof(buffer), fp)) { + if (strncmp(buffer, "Hardware", 8) == 0 || + strncmp(buffer, "model name", 10) == 0) { + char* sep = strchr(buffer, ':'); + if (sep) { + // 去除前导空格 + char* value = sep + 1; + while (*value && isspace(*value)) value++; + + // 去除末尾换行符 + char* end = value; + while (*end && *end != '\n') end++; + *end = '\0'; + + info_.brand = value; + break; + } + } + } + fclose(fp); + } +#elif ALICHO_PLATFORM_APPLE + // iOS/macOS ARM (Apple Silicon) + info_.vendor = "Apple"; + info_.brand = "Apple Silicon"; + + // 获取物理核心数(通过sysctl) + int nm[2]; + size_t len = 4; + uint32_t count; + + sysctlbyname("hw.physicalcpu", &count, &len, NULL, 0); + if (count > 0) { + info_.physical_cores = static_cast(count); + } +#else + // 其他ARM平台 + info_.vendor = "ARM"; + info_.brand = "Unknown ARM Processor"; +#endif + + // 获取物理核心数(Linux/Unix) +#if ALICHO_PLATFORM_LINUX && !ALICHO_PLATFORM_ANDROID + // 尝试使用sysconf + info_.physical_cores = static_cast(sysconf(_SC_NPROCESSORS_CONF)); +#endif +} +#endif // ALICHO_PLATFORM_ARM + +SIMDLevel CPUFeatureDetector::recommended_simd_level() const noexcept { + // 根据检测到的SIMD别,返回推荐使用的级别 + // 这可能会考虑性能、兼容性和微架构因素 + + // 基本策略:使用最高可用级别,但对于AVX-512要考虑热降频问题 + + switch (info_.max_simd_level) { + case SIMDLevel::AVX512: + // 某些CPU在使用AVX-512时会降频 + // 在实际应用中可能需要更复杂的检测和决策 + // 例如根据CPU型号或运行时测试决定是否使用AVX-512 +#if ALICHO_PLATFORM_WINDOWS + // Windows平台上特别慎使用AVX-512 + if (info_.vendor.find("Intel") != std::string::npos && + (info_.brand.find("Xeon") != std::string::npos || + info_.brand.find("i9") != std::string::npos)) { + return SIMDLevel::AVX512; // 高端Intel CPU上使用AVX-512 + } +#endif + if (info_.vendor.find("AMD") != std::string::npos) { + return SIMDLevel::AVX512; // 所有AMD CPU上使用AVX-512 + } + return SIMDLevel::AVX2; // 默认情况下返回AVX2 + + case SIMDLevel::AVX2: + case SIMDLevel::AVX: + case SIMDLevel::SSE4: + case SIMDLevel::SSE3: + case SIMDLevel::SSE: + case SIMDLevel::NEON: + case SIMDLevel::NEON_FP16: + return info_.max_simd_level; // 直接使用最高支持级别 + + default: + case SIMDLevel::NONE: + return SIMDLevel::NONE; + } +} + +void CPUFeatureDetector::print_info() const { + std::cout << "CPU信息:" << std::endl; +#if ALICHO_PLATFORM_WINDOWS + std::cout << " 平台: Windows" << std::endl; +#elif ALICHO_PLATFORM_MACOS + std::cout << " 平台: macOS" << std::endl; +#elif ALICHO_PLATFORM_LINUX + std::cout << " 平台: Linux" << std::endl; +#elif ALICHO_PLATFORM_ANDROID + std::cout << " 平台: Android" << std::endl; +#elif ALICHO_PLATFORM_IOS + std::cout << " 平台: iOS" << std::endl; +#else + std::cout << " 平台: 未知" << std::endl; +#endif + + std::cout << " 厂商: " << info_.vendor << std::endl; + std::cout << " 型号: " << info_.brand << std::endl; + std::cout << " 逻辑核心数: " << info_.logical_cores << std::endl; + std::cout << " 物理核心数: " << info_.physical_cores << std::endl; + std::cout << " 最高SIMD级别: "; + + switch (info_.max_simd_level) { + case SIMDLevel::NONE: std::cout << "None (标量)"; break; + case SIMDLevel::SSE: std::cout << "SSE/SSE2"; break; + case SIMDLevel::SSE3: std::cout << "SSE3/SSSE3"; break; + case SIMDLevel::SSE4: std::cout << "SSE4.1/SSE4.2"; break; + case SIMDLevel::AVX: std::cout << "AVX"; break; + case SIMDLevel::AVX2: std::cout << "AVX2"; break; + case SIMDLevel::AVX512: std::cout << "AVX-512"; break; + case SIMDLevel::NEON: std::cout << "NEON"; break; + case SIMDLevel::NEON_FP16: std::cout << "NEON (FP16)"; break; + } + std::cout << std::endl; + + std::cout << " 推荐SIMD级别: "; + switch (recommended_simd_level()) { + case SIMDLevel::NONE: std::cout << "None (标量)"; break; + case SIMDLevel::SSE: std::cout << "SSE/SSE2"; break; + case SIMDLevel::SSE3: std::cout << "SSE3/SSSE3"; break; + case SIMDLevel::SSE4: std::cout << "SSE4.1/SSE4.2"; break; + case SIMDLevel::AVX: std::cout << "AVX"; break; + case SIMDLevel::AVX2: std::cout << "AVX2"; break; + case SIMDLevel::AVX512: std::cout << "AVX-512"; break; + case SIMDLevel::NEON: std::cout << "NEON"; break; + case SIMDLevel::NEON_FP16: std::cout << "NEON (FP16)"; break; + } + std::cout << std::endl; + + std::cout << " 支持的特性: " << info_.features_string() << std::endl; +} + +} // namespace audio_backend::simd \ No newline at end of file diff --git a/src/simd/cpu_features.h b/src/simd/cpu_features.h new file mode 100644 index 0000000..8dcec8b --- /dev/null +++ b/src/simd/cpu_features.h @@ -0,0 +1,178 @@ +// ================================================================================================ +// Audio Backend - SIMD CPU特性检测器 +// ================================================================================================ +// 描述: 运行时检测CPU支持的SIMD指令集 +// 支持: SSE/AVX/AVX2/AVX-512/NEON +// ================================================================================================ + +#pragma once + +#include +#include +#include + +namespace audio_backend::simd { + +// ================================================================================================ +// CPU特性标志 +// ================================================================================================ +enum class CPUFeature : uint32_t { + // x86/x64 SIMD特性 + SSE = 1 << 0, + SSE2 = 1 << 1, + SSE3 = 1 << 2, + SSSE3 = 1 << 3, + SSE41 = 1 << 4, + SSE42 = 1 << 5, + AVX = 1 << 6, + AVX2 = 1 << 7, + FMA = 1 << 8, + AVX512F = 1 << 9, + AVX512VL = 1 << 10, + AVX512BW = 1 << 11, + AVX512DQ = 1 << 12, + + // ARM NEON特性 + NEON = 1 << 20, + NEON_FP16 = 1 << 21, + + // 其他特性 + POPCNT = 1 << 30, + BMI1 = 1 << 31 +}; + +// 位运算支持 +inline CPUFeature operator|(CPUFeature lhs, CPUFeature rhs) { + return static_cast( + static_cast(lhs) | static_cast(rhs) + ); +} + +inline CPUFeature operator&(CPUFeature lhs, CPUFeature rhs) { + return static_cast( + static_cast(lhs) & static_cast(rhs) + ); +} + +inline bool has_feature(CPUFeature features, CPUFeature test) { + return (static_cast(features) & static_cast(test)) != 0; +} + +// ================================================================================================ +// SIMD指令集级别 +// ================================================================================================ +enum class SIMDLevel { + NONE, // 无SIMD支持(纯标量) + SSE, // SSE/SSE2 + SSE3, // SSE3/SSSE3 + SSE4, // SSE4.1/SSE4.2 + AVX, // AVX + AVX2, // AVX2 + FMA + AVX512, // AVX-512 + NEON, // ARM NEON + NEON_FP16 // ARM NEON with FP16 +}; + +// ================================================================================================ +// CPU信息结构 +// ================================================================================================ +struct CPUInfo { + std::string vendor; // CPU厂商 + std::string brand; // CPU品牌字符串 + uint32_t features; // 支持的特性位掩码 + SIMDLevel max_simd_level; // 支持的最高SIMD级别 + int logical_cores; // 逻辑核心数 + int physical_cores; // 物理核心数 + + // 检查是否支持特定特性 + [[nodiscard]] bool supports(CPUFeature feature) const noexcept { + return (features & static_cast(feature)) != 0; + } + + // 获取人类可读的特性字符串 + [[nodiscard]] std::string features_string() const; +}; + +// ================================================================================================ +// CPU特性检测器(单例模式) +// ================================================================================================ +class CPUFeatureDetector { +public: + // 获取单例实例 + static CPUFeatureDetector& instance() { + static CPUFeatureDetector detector; + return detector; + } + + // 禁止拷贝和移动 + CPUFeatureDetector(const CPUFeatureDetector&) = delete; + CPUFeatureDetector& operator=(const CPUFeatureDetector&) = delete; + CPUFeatureDetector(CPUFeatureDetector&&) = delete; + CPUFeatureDetector& operator=(CPUFeatureDetector&&) = delete; + + // 获取CPU信息 + [[nodiscard]] const CPUInfo& cpu_info() const noexcept { return info_; } + + // 便捷方法 + [[nodiscard]] bool supports(CPUFeature feature) const noexcept { + return info_.supports(feature); + } + + [[nodiscard]] SIMDLevel max_simd_level() const noexcept { + return info_.max_simd_level; + } + + // 检查是否至少支持某个SIMD级别 + [[nodiscard]] bool supports_at_least(SIMDLevel level) const noexcept { + return info_.max_simd_level >= level; + } + + // 获取推荐的SIMD级别(考虑性能和兼容性) + [[nodiscard]] SIMDLevel recommended_simd_level() const noexcept; + + // 打印CPU信息 + void print_info() const; + +private: + CPUFeatureDetector(); + ~CPUFeatureDetector() = default; + + // 检测函数 + void detect_features(); + void detect_x86_features(); + void detect_arm_features(); + + // x86 CPUID支持 + #if defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || defined(_M_IX86) + struct CPUIDResult { + uint32_t eax, ebx, ecx, edx; + }; + + static CPUIDResult cpuid(uint32_t function_id, uint32_t subfunction_id = 0); + static void get_vendor_string(char* vendor_string); + static void get_brand_string(char* brand_string); + #endif + + CPUInfo info_; +}; + +// ================================================================================================ +// 全局便捷函数 +// ================================================================================================ +inline const CPUInfo& get_cpu_info() { + return CPUFeatureDetector::instance().cpu_info(); +} + +inline bool cpu_supports(CPUFeature feature) { + return CPUFeatureDetector::instance().supports(feature); +} + +inline SIMDLevel get_max_simd_level() { + return CPUFeatureDetector::instance().max_simd_level(); +} + +inline SIMDLevel get_recommended_simd_level() { + return CPUFeatureDetector::instance().recommended_simd_level(); +} + +} // namespace audio_backend::simd \ No newline at end of file diff --git a/src/simd/function_dispatcher.cpp b/src/simd/function_dispatcher.cpp new file mode 100644 index 0000000..6821962 --- /dev/null +++ b/src/simd/function_dispatcher.cpp @@ -0,0 +1,120 @@ +// ================================================================================================ +// Audio Backend - SIMD函数分发器实现 +// ================================================================================================ + +#include "function_dispatcher.h" +#include + +namespace audio_backend::simd { + +// ================================================================================================ +// 函数版本字符串转换实现 +// ================================================================================================ +const char* function_version_to_string(FunctionVersion version) { + switch (version) { + case FunctionVersion::SCALAR: return "SCALAR"; + case FunctionVersion::SSE: return "SSE"; + case FunctionVersion::SSE3: return "SSE3"; + case FunctionVersion::SSE4: return "SSE4"; + case FunctionVersion::AVX: return "AVX"; + case FunctionVersion::AVX2: return "AVX2"; + case FunctionVersion::AVX512: return "AVX512"; + case FunctionVersion::NEON: return "NEON"; + case FunctionVersion::NEON_FP16: return "NEON_FP16"; + default: return "UNKNOWN"; + } +} + +FunctionVersion string_to_function_version(const std::string& str) { + if (str == "SCALAR") return FunctionVersion::SCALAR; + if (str == "SSE") return FunctionVersion::SSE; + if (str == "SSE3") return FunctionVersion::SSE3; + if (str == "SSE4") return FunctionVersion::SSE4; + if (str == "AVX") return FunctionVersion::AVX; + if (str == "AVX2") return FunctionVersion::AVX2; + if (str == "AVX512") return FunctionVersion::AVX512; + if (str == "NEON") return FunctionVersion::NEON; + if (str == "NEON_FP16") return FunctionVersion::NEON_FP16; + return FunctionVersion::SCALAR; // 默认回退到标量版本 +} + +// ================================================================================================ +// FunctionDispatcher实现 +// ================================================================================================ +void FunctionDispatcher::print_registry_status() const { + std::cout << "\n=== SIMD函数注册状态 ===" << std::endl; + std::cout << "已注册函数数量: " << function_registry_.size() << std::endl; + + // 获取当前CPU支持的最高SIMD级别 + SIMDLevel max_level = get_max_simd_level(); + SIMDLevel recommended_level = get_recommended_simd_level(); + + std::cout << "CPU最高SIMD级别: "; + switch (max_level) { + case SIMDLevel::NONE: std::cout << "None"; break; + case SIMDLevel::SSE: std::cout << "SSE"; break; + case SIMDLevel::SSE3: std::cout << "SSE3"; break; + case SIMDLevel::SSE4: std::cout << "SSE4"; break; + case SIMDLevel::AVX: std::cout << "AVX"; break; + case SIMDLevel::AVX2: std::cout << "AVX2"; break; + case SIMDLevel::AVX512: std::cout << "AVX-512"; break; + case SIMDLevel::NEON: std::cout << "NEON"; break; + case SIMDLevel::NEON_FP16: std::cout << "NEON_FP16"; break; + } + std::cout << std::endl; + + std::cout << "推荐SIMD级别: "; + switch (recommended_level) { + case SIMDLevel::NONE: std::cout << "None"; break; + case SIMDLevel::SSE: std::cout << "SSE"; break; + case SIMDLevel::SSE3: std::cout << "SSE3"; break; + case SIMDLevel::SSE4: std::cout << "SSE4"; break; + case SIMDLevel::AVX: std::cout << "AVX"; break; + case SIMDLevel::AVX2: std::cout << "AVX2"; break; + case SIMDLevel::AVX512: std::cout << "AVX-512"; break; + case SIMDLevel::NEON: std::cout << "NEON"; break; + case SIMDLevel::NEON_FP16: std::cout << "NEON_FP16"; break; + } + std::cout << std::endl; + + std::cout << "\n函数详情:" << std::endl; + for (const auto& pair : function_registry_) { + const std::string& name = pair.first; + const auto& holder = pair.second; + + std::cout << " " << name << ":" << std::endl; + + // 获取可用版本 + auto available_versions = holder->get_available_versions(); + if (available_versions.empty()) { + std::cout << " ❌ 无可用实现" << std::endl; + } else { + std::cout << " ✅ 可用版本: "; + for (size_t i = 0; i < available_versions.size(); ++i) { + if (i > 0) std::cout << ", "; + std::cout << function_version_to_string(available_versions[i]); + } + std::cout << std::endl; + + // 显示将使用的版本 + FunctionVersion preferred_version = simd_level_to_version(recommended_level); + FunctionVersion selected_version = FunctionVersion::SCALAR; + + // 查找最佳匹配版本 + for (int i = static_cast(preferred_version); i >= 0; --i) { + FunctionVersion version = static_cast(i); + auto it = std::find(available_versions.begin(), available_versions.end(), version); + if (it != available_versions.end()) { + selected_version = version; + break; + } + } + + std::cout << " 🎯 将使用版本: " << function_version_to_string(selected_version) << std::endl; + } + } + + std::cout << "=========================" << std::endl; +} + +} // namespace audio_backend::simd \ No newline at end of file diff --git a/src/simd/function_dispatcher.h b/src/simd/function_dispatcher.h new file mode 100644 index 0000000..c5df95c --- /dev/null +++ b/src/simd/function_dispatcher.h @@ -0,0 +1,264 @@ +// ================================================================================================ +// Audio Backend - SIMD函数分发器 +// ================================================================================================ +// 描述: 运行时自动选择最优SIMD实现的函数分发器 +// 功能: 根据CPU特性动态选择最佳的函数实现版本 +// ================================================================================================ + +#pragma once + +#include "cpu_features.h" +#include +#include +#include +#include + +namespace audio_backend::simd { + +// ================================================================================================ +// 函数实现版本枚举 +// ================================================================================================ +enum class FunctionVersion { + SCALAR = 0, // 标量实现(默认回退) + SSE, // SSE实现 + SSE3, // SSE3实现 + SSE4, // SSE4实现 + AVX, // AVX实现 + AVX2, // AVX2实现 + AVX512, // AVX-512实现 + NEON, // ARM NEON实现 + NEON_FP16, // ARM NEON FP16实现 + + VERSION_COUNT // 版本数量(用于数组大小) +}; + +// 将SIMD级别转换为函数版本 +constexpr FunctionVersion simd_level_to_version(SIMDLevel level) { + switch (level) { + case SIMDLevel::NONE: return FunctionVersion::SCALAR; + case SIMDLevel::SSE: return FunctionVersion::SSE; + case SIMDLevel::SSE3: return FunctionVersion::SSE3; + case SIMDLevel::SSE4: return FunctionVersion::SSE4; + case SIMDLevel::AVX: return FunctionVersion::AVX; + case SIMDLevel::AVX2: return FunctionVersion::AVX2; + case SIMDLevel::AVX512: return FunctionVersion::AVX512; + case SIMDLevel::NEON: return FunctionVersion::NEON; + case SIMDLevel::NEON_FP16: return FunctionVersion::NEON_FP16; + default: return FunctionVersion::SCALAR; + } +} + +// ================================================================================================ +// 多版本函数持有者模板 +// ================================================================================================ +template +class MultiVersionFunction; + +template +class MultiVersionFunction { +public: + using FunctionType = std::function; + using FunctionArray = std::array(FunctionVersion::VERSION_COUNT)>; + + MultiVersionFunction() = default; + + // 注册函数版本 + void register_version(FunctionVersion version, FunctionType function) { + functions_[static_cast(version)] = std::move(function); + } + + // 获取最佳函数版本 + const FunctionType& get_best_function() const { + // 获取推荐的SIMD级别 + SIMDLevel recommended_level = get_recommended_simd_level(); + FunctionVersion preferred_version = simd_level_to_version(recommended_level); + + // 从首选版本开始,向下查找可用实现 + for (int i = static_cast(preferred_version); i >= 0; --i) { + FunctionVersion version = static_cast(i); + const auto& func = functions_[static_cast(version)]; + if (func) { + return func; + } + } + + // 如果没有找到任何实现,返回空函数 + static const FunctionType empty_func; + return empty_func; + } + + // 调用最佳函数版本 + ReturnType operator()(Args... args) const { + const auto& func = get_best_function(); + if (func) { + return func(args...); + } else { + // 没有可用实现时的错误处理 + throw std::runtime_error("No suitable function implementation available"); + } + } + + // 检查是否有任何版本的实现 + bool has_implementation() const { + for (const auto& func : functions_) { + if (func) return true; + } + return false; + } + + // 获取可用版本列表 + std::vector get_available_versions() const { + std::vector versions; + for (size_t i = 0; i < functions_.size(); ++i) { + if (functions_[i]) { + versions.push_back(static_cast(i)); + } + } + return versions; + } + +private: + FunctionArray functions_{}; +}; + +// ================================================================================================ +// 函数分发器注册器(单例模式) +// ================================================================================================ +class FunctionDispatcher { +public: + // 获取单例实例 + static FunctionDispatcher& instance() { + static FunctionDispatcher dispatcher; + return dispatcher; + } + + // 禁止拷贝和移动 + FunctionDispatcher(const FunctionDispatcher&) = delete; + FunctionDispatcher& operator=(const FunctionDispatcher&) = delete; + FunctionDispatcher(FunctionDispatcher&&) = delete; + FunctionDispatcher& operator=(FunctionDispatcher&&) = delete; + + // 注册函数(通过函数名) + template + void register_function(const std::string& name, + FunctionVersion version, + std::function function) { + auto& func_holder = get_or_create_function(name); + func_holder.register_version(version, std::move(function)); + } + + // 获取函数 + template + const MultiVersionFunction& get_function(const std::string& name) { + auto& func_holder = get_or_create_function(name); + return func_holder; + } + + // 调用函数(便捷方法) + template + auto call_function(const std::string& name, Args&&... args) + -> decltype(std::declval>()(args...)) { + const auto& func = get_function(name); + return func(std::forward(args)...); + } + + // 列出所有已注册的函数 + std::vector list_functions() const { + std::vector names; + for (const auto& pair : function_registry_) { + names.push_back(pair.first); + } + return names; + } + + // 打印函数注册状态 + void print_registry_status() const; + +private: + FunctionDispatcher() = default; + ~FunctionDispatcher() = default; + + // 类型擦除的基类 + struct FunctionHolderBase { + virtual ~FunctionHolderBase() = default; + virtual std::vector get_available_versions() const = 0; + virtual bool has_implementation() const = 0; + }; + + // 具体的函数持有者 + template + struct FunctionHolder : public FunctionHolderBase { + MultiVersionFunction function; + + std::vector get_available_versions() const override { + return function.get_available_versions(); + } + + bool has_implementation() const override { + return function.has_implementation(); + } + }; + + // 获取或创建函数持有者 + template + MultiVersionFunction& get_or_create_function(const std::string& name) { + auto it = function_registry_.find(name); + if (it == function_registry_.end()) { + auto holder = std::make_unique>(); + auto* raw_holder = holder.get(); + function_registry_[name] = std::move(holder); + return raw_holder->function; + } else { + auto* holder = dynamic_cast*>(it->second.get()); + if (!holder) { + throw std::runtime_error("Function signature mismatch for: " + name); + } + return holder->function; + } + } + + std::unordered_map> function_registry_; +}; + +// ================================================================================================ +// 便捷宏定义 +// ================================================================================================ + +// 注册函数版本的宏 +#define REGISTER_SIMD_FUNCTION(name, version, function) \ + audio_backend::simd::FunctionDispatcher::instance().register_function(name, version, function) + +// 获取函数的宏 +#define GET_SIMD_FUNCTION(signature, name) \ + audio_backend::simd::FunctionDispatcher::instance().get_function(name) + +// 调用函数的宏 +#define CALL_SIMD_FUNCTION(signature, name, ...) \ + audio_backend::simd::FunctionDispatcher::instance().call_function(name, __VA_ARGS__) + +// ================================================================================================ +// 自动注册辅助类 +// ================================================================================================ +template +class AutoRegister { +public: + AutoRegister(const std::string& name, + FunctionVersion version, + std::function function) { + FunctionDispatcher::instance().register_function( + name, version, std::move(function)); + } +}; + +// 自动注册宏 +#define AUTO_REGISTER_SIMD_FUNCTION(name, version, function) \ + static auto _auto_reg_##name##_##version = \ + audio_backend::simd::AutoRegister(#name, version, function) + +// ================================================================================================ +// 函数版本字符串转换 +// ================================================================================================ +const char* function_version_to_string(FunctionVersion version); +FunctionVersion string_to_function_version(const std::string& str); + +} // namespace audio_backend::simd \ No newline at end of file diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..f0778a5 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,181 @@ +# ================================================================================================ +# Audio Backend Framework - 测试配置 +# ================================================================================================ +# 描述: 配置单元测试和集成测试 +# 框架: Google Test (GTest) +# 类型: 单元测试、集成测试、性能测试 +# ================================================================================================ + +message(STATUS "") +message(STATUS "=== 配置测试模块 ===") + +# ================================================================================================ +# 测试相关的全局配置 +# ================================================================================================ +# 启用测试框架 +enable_testing() + +# 设置测试输出目录 +set(TEST_OUTPUT_DIR ${CMAKE_BINARY_DIR}/tests) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${TEST_OUTPUT_DIR}) + +# ================================================================================================ +# 查找测试依赖 +# ================================================================================================ +find_package(GTest REQUIRED) + +# 检查benchmark库是否可用 +set(BENCHMARK_AVAILABLE FALSE) +if(TARGET benchmark::benchmark AND DAW_ENABLE_BENCHMARKS) + set(BENCHMARK_AVAILABLE TRUE) +endif() + +# ================================================================================================ +# 公共测试配置接口库 +# ================================================================================================ +add_library(audio_backend_test_common INTERFACE) + +# 设置测试公共包含路径 +target_include_directories(audio_backend_test_common INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/src +) + +# 链接测试依赖 +target_link_libraries(audio_backend_test_common INTERFACE + ${audio_backend_project_options} + AudioBackend::Common + AudioBackend::Communication + AudioBackend::Engine + GTest::gtest + GTest::gtest_main + ${THREADS_LIB} +) + +# 测试特定编译定义 +target_compile_definitions(audio_backend_test_common INTERFACE + GTEST_HAS_PTHREAD=1 + $<$:AUDIO_BACKEND_TEST_DEBUG> +) + +# 设置操作系统定义 +add_os_definitions(audio_backend_test_common) + +# ================================================================================================ +# 单元测试配置 +# ================================================================================================ +message(STATUS "配置单元测试...") + +# 自动收集单元测试源文件 +set(UNIT_TEST_SOURCES "") +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/unit) + retrieve_files(${CMAKE_CURRENT_SOURCE_DIR}/unit UNIT_TEST_SOURCES) +endif() + +if(UNIT_TEST_SOURCES) + # 创建单元测试可执行文件 + add_executable(audio_backend_unit_tests ${UNIT_TEST_SOURCES}) + + # 链接依赖 + target_link_libraries(audio_backend_unit_tests PRIVATE + audio_backend_test_common + AudioBackend::SIMD + AudioBackend::PluginHost + AudioBackend::Frontend + ) + + # 添加测试到CTest + add_test(NAME UnitTests COMMAND audio_backend_unit_tests) + + # 设置测试属性 + set_tests_properties(UnitTests PROPERTIES + TIMEOUT 300 # 5分钟超时 + LABELS "unit" + ) + + message(STATUS "✓ 单元测试配置完成: ${UNIT_TEST_SOURCES}个件") +else() + message(STATUS "○ 单元测试: 无测试文件") +endif() + +# ================================================================================================ +# 集成测试配置 +# ================================================================================================ +message(STATUS "配置集成测试...") + +# 自动收集集成测试源文件 +set(INTEGRATION_TEST_SOURCES "") +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/integration) + retrieve_files(${CMAKE_CURRENT_SOURCE_DIR}/integration INTEGRATION_TEST_SOURCES) +endif() + +if(INTEGRATION_TEST_SOURCES) + # 创建集成测试可执行文件 + add_executable(audio_backend_integration_tests ${INTEGRATION_TEST_SOURCES}) + + # 链接依赖 + target_link_libraries(audio_backend_integration_tests PRIVATE + audio_backend_test_common + AudioBackend::SIMD + AudioBackend::PluginHost + AudioBackend::Frontend + ) + + # 添加测试到CTest + add_test(NAME IntegrationTests COMMAND audio_backend_integration_tests) + + # 设置测试属性 + set_tests_properties(IntegrationTests PROPERTIES + TIMEOUT 600 # 10分钟超时 + LABELS "integration" + ) + + message(STATUS "✓ 集成测试配置完成: ${INTEGRATION_TEST_SOURCES}个文件") +else() + message(STATUS "○ 集成测试: 无测试文件") +endif() + +# ================================================================================================ +# 性能基准测试配置 +# ================================================================================================ +if(BENCHMARK_AVAILABLE) + message(STATUS "配置性能基准测试...") + + # 自动收集基准测试源文件 + set(BENCHMARK_SOURCES "") + if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/benchmarks) + retrieve_files(${CMAKE_CURRENT_SOURCE_DIR}/benchmarks BENCHMARK_SOURCES) + endif() + + if(BENCHMARK_SOURCES) + # 创建基准测试可执行文件 + add_executable(audio_backend_benchmarks ${BENCHMARK_SOURCES}) + + # 链接依赖 + target_link_libraries(audio_backend_benchmarks PRIVATE + audio_backend_test_common + AudioBackend::SIMD + AudioBackend::Engine + benchmark::benchmark + ) + + # 添加基准测试(不加入CTest,手动运行) + message(STATUS "✓ 性能基准测试配置完成: ${BENCHMARK_SOURCES}个文件") + else() + message(STATUS "○ 性能基准测试: 无测试文件") + endif() +else() + message(STATUS "○ 性能基准测试: benchmark库不可用或被禁用") +endif() + +# ================================================================================================ +# 测试配置摘要 +# ================================================================================================ +message(STATUS "") +message(STATUS "=== 测试配置摘要 ===") +message(STATUS "测试框架: Google Test") +message(STATUS "单元测试: ${UNIT_TEST_SOURCES}个文件") +message(STATUS "集成测试: ${INTEGRATION_TEST_SOURCES}个文件") +message(STATUS "性能测试: ${BENCHMARK_AVAILABLE}") +message(STATUS "测试输出: ${TEST_OUTPUT_DIR}") +message(STATUS "") \ No newline at end of file