init
This commit is contained in:
192
CMakeLists.txt
Normal file
192
CMakeLists.txt
Normal file
@@ -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(
|
||||
$<$<CONFIG:Debug>:AUDIO_BACKEND_DEBUG>
|
||||
$<$<CONFIG:Release>: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 "")
|
||||
213
build.bat
Normal file
213
build.bat
Normal file
@@ -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
|
||||
310
build.sh
Normal file
310
build.sh
Normal file
@@ -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 "$@"
|
||||
103
cmake/build_options.cmake
Normal file
103
cmake/build_options.cmake
Normal file
@@ -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()
|
||||
170
cmake/compiler_options.cmake
Normal file
170
cmake/compiler_options.cmake
Normal file
@@ -0,0 +1,170 @@
|
||||
# ================================================================================================
|
||||
# DAW Backend Framework - 编译器选项配置模块
|
||||
# 描述: 配置编译器特定选项、警告级别和优化设置
|
||||
# ================================================================================================
|
||||
|
||||
# ================================================================================================
|
||||
# 配置编译器选项
|
||||
# ================================================================================================
|
||||
function(configure_compiler_options)
|
||||
# 使用生成器表达式为多配置生成器(如Visual Studio)正确配置选项
|
||||
if(MSVC)
|
||||
# Debug配置特定设置
|
||||
add_compile_options(
|
||||
$<$<CONFIG:Debug>:/Zi> # 调试信息
|
||||
$<$<CONFIG:Debug>:/Od> # 禁用优化
|
||||
$<$<CONFIG:Debug>:/RTC1> # 运行时检查
|
||||
$<$<CONFIG:Debug>:/W4> # 严格警告
|
||||
)
|
||||
add_compile_definitions(
|
||||
$<$<CONFIG:Debug>:DAW_DEBUG_BUILD>
|
||||
)
|
||||
|
||||
# Release配置特定设置
|
||||
add_compile_options(
|
||||
$<$<CONFIG:Release>:/O2> # 最大优化
|
||||
$<$<CONFIG:Release>:/Ob2> # 内联展开
|
||||
$<$<CONFIG:Release>:/Zi> # 调试信息(用于调试Release版本)
|
||||
)
|
||||
add_compile_definitions(
|
||||
$<$<CONFIG:Release>:DAW_RELEASE_BUILD>
|
||||
$<$<CONFIG:Release>:NDEBUG>
|
||||
)
|
||||
|
||||
# RelWithDebInfo配置
|
||||
add_compile_options(
|
||||
$<$<CONFIG:RelWithDebInfo>:/O2>
|
||||
$<$<CONFIG:RelWithDebInfo>:/Ob1>
|
||||
$<$<CONFIG:RelWithDebInfo>:/Zi>
|
||||
)
|
||||
add_compile_definitions(
|
||||
$<$<CONFIG:RelWithDebInfo>:DAW_RELEASE_BUILD>
|
||||
$<$<CONFIG:RelWithDebInfo>:NDEBUG>
|
||||
)
|
||||
|
||||
# MinSizeRel配置
|
||||
add_compile_options(
|
||||
$<$<CONFIG:MinSizeRel>:/O1>
|
||||
$<$<CONFIG:MinSizeRel>:/Ob1>
|
||||
$<$<CONFIG:MinSizeRel>:/Zi>
|
||||
)
|
||||
add_compile_definitions(
|
||||
$<$<CONFIG:MinSizeRel>:DAW_RELEASE_BUILD>
|
||||
$<$<CONFIG:MinSizeRel>: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()
|
||||
41
cmake/config_macos.cmake
Normal file
41
cmake/config_macos.cmake
Normal file
@@ -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 ()
|
||||
147
cmake/dependencies.cmake
Normal file
147
cmake/dependencies.cmake
Normal file
@@ -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()
|
||||
161
cmake/detect_os.cmake
Normal file
161
cmake/detect_os.cmake
Normal file
@@ -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)
|
||||
110
cmake/install_config.cmake
Normal file
110
cmake/install_config.cmake
Normal file
@@ -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()
|
||||
41
cmake/mingw_dll.cmake
Normal file
41
cmake/mingw_dll.cmake
Normal file
@@ -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}"
|
||||
"$<TARGET_FILE_DIR:${target}>"
|
||||
COMMENT "Copying ${DLL} to output directory"
|
||||
VERBATIM)
|
||||
else()
|
||||
message(WARNING "DLL not found: ${MINGW_DIR}/${DLL}")
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
endfunction()
|
||||
44
cmake/mirage_utils.cmake
Normal file
44
cmake/mirage_utils.cmake
Normal file
@@ -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), 可执行文件将位于 <build>/bin/
|
||||
# 对于多配置生成器 (如 Visual Studio, Xcode), CMake 通常会自动在此路径下附加配置名称
|
||||
# (例如 <build>/bin/Debug/, <build>/bin/Release/)
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin CACHE PATH "Directory for runtime executables")
|
||||
message(STATUS "运行时输出目录设置为: ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
|
||||
|
||||
# **设置库文件输出路径 (共享库和静态库)**:
|
||||
# 规则同上,库文件将位于 <build>/lib/ 或 <build>/lib/<Config>/
|
||||
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()
|
||||
138
cmake/project_cpp_standard.cmake
Normal file
138
cmake/project_cpp_standard.cmake
Normal file
@@ -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 及以上的 <filesystem> 支持添加链接库
|
||||
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 依赖 (用于 <filesystem>)")
|
||||
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()
|
||||
545
cmake/retrieve_files.cmake
Normal file
545
cmake/retrieve_files.cmake
Normal file
@@ -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 $<TARGET_FILE:gRPC::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
|
||||
$<BUILD_INTERFACE:${ARG_OUTPUT_PATH}>
|
||||
$<INSTALL_INTERFACE:include>
|
||||
)
|
||||
|
||||
# 链接必要的库
|
||||
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)
|
||||
# 对于多配置,没有单一的顶级运行时目录变量。
|
||||
# 可以考虑使用 $<OUTPUT_DIRECTORY> 配合一个已知的可执行文件名,但这会使函数复杂化。
|
||||
# 最好的做法是要求用户设置 CMAKE_RUNTIME_OUTPUT_DIRECTORY_<CONFIG>
|
||||
# 或者我们直接报错,强制用户设置 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_<CONFIG> 变量。")
|
||||
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()
|
||||
109
conanfile.txt
Normal file
109
conanfile.txt
Normal file
@@ -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
|
||||
82
docs/README.md
Normal file
82
docs/README.md
Normal file
@@ -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**: 每次提交的说明信息都应使用中文描述本次变更的内容。
|
||||
1256
docs/architecture-design.md
Normal file
1256
docs/architecture-design.md
Normal file
File diff suppressed because it is too large
Load Diff
4
setup_conan.bat
Normal file
4
setup_conan.bat
Normal file
@@ -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
|
||||
63
src/CMakeLists.txt
Normal file
63
src/CMakeLists.txt
Normal file
@@ -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 "")
|
||||
98
src/common/CMakeLists.txt
Normal file
98
src/common/CMakeLists.txt
Normal file
@@ -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
|
||||
$<$<BOOL:${DAW_ENABLE_PROFILING}>: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}个文件")
|
||||
297
src/common/error.cpp
Normal file
297
src/common/error.cpp
Normal file
@@ -0,0 +1,297 @@
|
||||
// ================================================================================================
|
||||
// Audio Backend - 错误处理和异常类实现
|
||||
// ================================================================================================
|
||||
|
||||
#include "error.h"
|
||||
#include <algorithm>
|
||||
#include <unordered_map>
|
||||
|
||||
#if ALICHO_PLATFORM_WINDOWS
|
||||
#include <windows.h>
|
||||
#elif ALICHO_PLATFORM_UNIX
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
namespace audio_backend::common {
|
||||
|
||||
// ================================================================================================
|
||||
// 错误码描述映射
|
||||
// ================================================================================================
|
||||
static const std::unordered_map<ErrorCode, std::string> 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<ErrorCode, ErrorCategory> 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<int>(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<ErrorCode>(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
|
||||
382
src/common/error.h
Normal file
382
src/common/error.h
Normal file
@@ -0,0 +1,382 @@
|
||||
// ================================================================================================
|
||||
// Audio Backend - 错误处理和异常类
|
||||
// ================================================================================================
|
||||
// 描述: 定义自定义异常层次结构和错误处理机制
|
||||
// 功能: 提供统一的异常类型和错误码
|
||||
// ================================================================================================
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
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<ErrorCode>(ev));
|
||||
}
|
||||
|
||||
private:
|
||||
AudioBackendErrorCategory() = default;
|
||||
};
|
||||
|
||||
// 创建error_code
|
||||
inline std::error_code make_error_code(ErrorCode e) {
|
||||
return {static_cast<int>(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<void(const AudioBackendException&)>;
|
||||
|
||||
// 获取单例实例
|
||||
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<ErrorCallback> 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<audio_backend::common::ErrorCode> : public true_type {};
|
||||
} // namespace std
|
||||
181
src/common/logger.cpp
Normal file
181
src/common/logger.cpp
Normal file
@@ -0,0 +1,181 @@
|
||||
// ================================================================================================
|
||||
// Audio Backend - 日志系统实现
|
||||
// ================================================================================================
|
||||
|
||||
#include "logger.h"
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
|
||||
#if ALICHO_PLATFORM_WINDOWS
|
||||
#include <windows.h>
|
||||
#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<spdlog::sinks::stdout_color_sink_mt>();
|
||||
console_sink_->set_level(static_cast<spdlog::level::level_enum>(console_level));
|
||||
console_sink_->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%^%l%$] [%n] %v");
|
||||
|
||||
std::vector<spdlog::sink_ptr> 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<spdlog::sinks::rotating_file_sink_mt>(
|
||||
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<spdlog::logger>(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<spdlog::level::level_enum>(level));
|
||||
}
|
||||
}
|
||||
|
||||
void Logger::set_console_level(LogLevel level) {
|
||||
if (console_sink_) {
|
||||
console_sink_->set_level(static_cast<spdlog::level::level_enum>(level));
|
||||
}
|
||||
}
|
||||
|
||||
void Logger::set_file_level(LogLevel level) {
|
||||
if (file_sink_) {
|
||||
file_sink_->set_level(static_cast<spdlog::level::level_enum>(level));
|
||||
}
|
||||
}
|
||||
|
||||
LogLevel Logger::get_level() const {
|
||||
if (logger_) {
|
||||
return static_cast<LogLevel>(logger_->level());
|
||||
}
|
||||
return LogLevel::INFO;
|
||||
}
|
||||
|
||||
std::shared_ptr<spdlog::logger> 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<spdlog::logger> Logger::create_logger(const std::string& logger_name) {
|
||||
std::vector<spdlog::sink_ptr> sinks;
|
||||
|
||||
if (console_sink_) {
|
||||
sinks.push_back(console_sink_);
|
||||
}
|
||||
|
||||
if (file_sink_) {
|
||||
sinks.push_back(file_sink_);
|
||||
}
|
||||
|
||||
auto new_logger = std::make_shared<spdlog::logger>(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
|
||||
179
src/common/logger.h
Normal file
179
src/common/logger.h
Normal file
@@ -0,0 +1,179 @@
|
||||
// ================================================================================================
|
||||
// Audio Backend - 日志系统
|
||||
// ================================================================================================
|
||||
// 描述: 基于spdlog的日志系统封装
|
||||
// 功能: 提供统一的日志接口,支持多种日志级别和格式
|
||||
// ================================================================================================
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <spdlog/sinks/stdout_color_sinks.h>
|
||||
#include <spdlog/sinks/rotating_file_sink.h>
|
||||
#include <spdlog/fmt/ostr.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
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<spdlog::logger> get_logger() const {
|
||||
return logger_;
|
||||
}
|
||||
|
||||
// 获取特定模块的日志器
|
||||
std::shared_ptr<spdlog::logger> get_module_logger(const std::string& module_name);
|
||||
|
||||
// 刷新日志缓冲区
|
||||
void flush();
|
||||
|
||||
// 便捷的日志记录方法
|
||||
template<typename... Args>
|
||||
void trace(std::string_view fmt, const Args&... args) {
|
||||
if (logger_) logger_->trace(fmt, args...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void debug(std::string_view fmt, const Args&... args) {
|
||||
if (logger_) logger_->debug(fmt, args...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void info(std::string_view fmt, const Args&... args) {
|
||||
if (logger_) logger_->info(fmt, args...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void warn(std::string_view fmt, const Args&... args) {
|
||||
if (logger_) logger_->warn(fmt, args...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void err(std::string_view fmt, const Args&... args) {
|
||||
if (logger_) logger_->error(fmt, args...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void critical(std::string_view fmt, const Args&... args) {
|
||||
if (logger_) logger_->critical(fmt, args...);
|
||||
}
|
||||
|
||||
private:
|
||||
Logger();
|
||||
~Logger();
|
||||
|
||||
// 创建日志器
|
||||
std::shared_ptr<spdlog::logger> create_logger(const std::string& logger_name);
|
||||
|
||||
// 创建日志目录
|
||||
void create_log_directory(const std::string& dir);
|
||||
|
||||
std::shared_ptr<spdlog::logger> logger_;
|
||||
std::shared_ptr<spdlog::sinks::stdout_color_sink_mt> console_sink_;
|
||||
std::shared_ptr<spdlog::sinks::rotating_file_sink_mt> file_sink_;
|
||||
|
||||
std::string log_directory_;
|
||||
bool initialized_ = false;
|
||||
};
|
||||
|
||||
// ================================================================================================
|
||||
// 全局日志函数
|
||||
// ================================================================================================
|
||||
template<typename... Args>
|
||||
inline void log_trace(std::string_view fmt, const Args&... args) {
|
||||
Logger::instance().trace(fmt, args...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
inline void log_debug(std::string_view fmt, const Args&... args) {
|
||||
Logger::instance().debug(fmt, args...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
inline void log_info(std::string_view fmt, const Args&... args) {
|
||||
Logger::instance().info(fmt, args...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
inline void log_warn(std::string_view fmt, const Args&... args) {
|
||||
Logger::instance().warn(fmt, args...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
inline void log_err(std::string_view fmt, const Args&... args) {
|
||||
Logger::instance().err(fmt, args...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
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
|
||||
112
src/communication/CMakeLists.txt
Normal file
112
src/communication/CMakeLists.txt
Normal file
@@ -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
|
||||
$<$<BOOL:${ENABLE_ENHANCED_IPC}>: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}个文件")
|
||||
67
src/communication/README.md
Normal file
67
src/communication/README.md
Normal file
@@ -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传输抽象和音频流协议
|
||||
135
src/communication/core/message.cpp
Normal file
135
src/communication/core/message.cpp
Normal file
@@ -0,0 +1,135 @@
|
||||
// ================================================================================================
|
||||
// Audio Backend - 消息抽象接口实现
|
||||
// ================================================================================================
|
||||
|
||||
#include "message.h"
|
||||
#include "logger.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <random>
|
||||
#include <atomic>
|
||||
|
||||
namespace audio_backend::communication {
|
||||
|
||||
// ================================================================================================
|
||||
// Endpoint 实现
|
||||
// ================================================================================================
|
||||
|
||||
std::string Endpoint::to_string() const {
|
||||
std::ostringstream oss;
|
||||
oss << "Endpoint{id=" << id
|
||||
<< ", type=" << static_cast<int>(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<uint64_t> counter{0};
|
||||
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto timestamp = std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
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<uint32_t> dis(0, 0xFFFFFFFF);
|
||||
oss << std::setw(8) << dis(gen);
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
} // namespace audio_backend::communication
|
||||
199
src/communication/core/message.h
Normal file
199
src/communication/core/message.h
Normal file
@@ -0,0 +1,199 @@
|
||||
// ================================================================================================
|
||||
// Audio Backend - 消息抽象接口
|
||||
// ================================================================================================
|
||||
// 描述: 定义通信模块消息的基础接口和结构
|
||||
// 功能: 提供统一的消息处理方式,支持不同类型的消息传输
|
||||
// ================================================================================================
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <chrono>
|
||||
|
||||
#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<uint8_t>& raw_data() const = 0;
|
||||
|
||||
// 消息大小(字节数)
|
||||
virtual size_t size() const = 0;
|
||||
|
||||
// 克隆消息
|
||||
virtual std::unique_ptr<IMessage> 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<uint8_t>& 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<uint8_t>& data) { raw_data_ = data; }
|
||||
void set_raw_data(std::vector<uint8_t>&& 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<uint8_t> raw_data_;
|
||||
|
||||
// 消息大小阈值(大于此值使用共享内存)
|
||||
static constexpr size_t SHARED_MEMORY_THRESHOLD = 4 * 1024; // 4KB
|
||||
};
|
||||
|
||||
// 工厂函数:创建新的消息ID
|
||||
std::string generate_message_id();
|
||||
|
||||
// 消息工厂类
|
||||
class MessageFactory {
|
||||
public:
|
||||
// 创建消息的工厂方法
|
||||
template<typename MessageType, typename... Args>
|
||||
static std::unique_ptr<MessageType> create(Args&&... args) {
|
||||
auto message = std::make_unique<MessageType>(std::forward<Args>(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
|
||||
222
src/communication/core/serializer.cpp
Normal file
222
src/communication/core/serializer.cpp
Normal file
@@ -0,0 +1,222 @@
|
||||
// ================================================================================================
|
||||
// Audio Backend - 消息序列化器实现
|
||||
// ================================================================================================
|
||||
|
||||
#include "serializer.h"
|
||||
#include <cstring>
|
||||
|
||||
// 跨平台网络字节序转换
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#pragma comment(lib, "ws2_32.lib")
|
||||
#else
|
||||
#include <arpa/inet.h>
|
||||
#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<uint8_t>& 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<uint8_t> message_data;
|
||||
SerializationError result = it->second(message, message_data);
|
||||
if (result != SerializationError::Success) {
|
||||
log_err("序列化消息类型 '%s' 失败: %d", type_name.c_str(), static_cast<int>(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
// 构建完整的消息,包含消息头
|
||||
MessageHeader header;
|
||||
header.magic = htonl(HEADER_MAGIC);
|
||||
header.version = htons(CURRENT_VERSION);
|
||||
header.type_length = htons(static_cast<uint16_t>(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<const uint8_t*>(&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<uint8_t>& data, std::unique_ptr<IMessage>& 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<uint8_t> 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<int>(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<uint8_t>& 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<ISerializer> 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<uint8_t>& 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
|
||||
177
src/communication/core/serializer.h
Normal file
177
src/communication/core/serializer.h
Normal file
@@ -0,0 +1,177 @@
|
||||
// ================================================================================================
|
||||
// Audio Backend - 消息序列化器
|
||||
// ================================================================================================
|
||||
// 描述: 定义消息序列化和反序列化接口
|
||||
// 功能: 提供消息与二进制数据之间的转换机制,支持Protocol Buffers格式
|
||||
// ================================================================================================
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <functional>
|
||||
#include <typeindex>
|
||||
|
||||
#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<uint8_t>& output) = 0;
|
||||
|
||||
// 反序列化二进制数据为消息
|
||||
virtual SerializationError deserialize(const std::vector<uint8_t>& data, std::unique_ptr<IMessage>& 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<uint8_t>& output) override;
|
||||
SerializationError deserialize(const std::vector<uint8_t>& data, std::unique_ptr<IMessage>& 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<SerializationError(const IMessage&, std::vector<uint8_t>&)>;
|
||||
using DeserializeFunction = std::function<SerializationError(const std::vector<uint8_t>&, std::unique_ptr<IMessage>&)>;
|
||||
|
||||
// 消息类型注册
|
||||
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<uint8_t>& 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<std::string, SerializeFunction> serialize_funcs_;
|
||||
std::unordered_map<std::string, DeserializeFunction> deserialize_funcs_;
|
||||
};
|
||||
|
||||
// ================================================================================================
|
||||
// 序列化器工厂
|
||||
// ================================================================================================
|
||||
class SerializerFactory {
|
||||
public:
|
||||
// 获取实例(单例)
|
||||
static SerializerFactory& instance();
|
||||
|
||||
// 注册序列化器
|
||||
void register_serializer(const std::string& name, std::unique_ptr<ISerializer> 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<uint8_t>& 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<std::string, std::unique_ptr<ISerializer>> serializers_;
|
||||
};
|
||||
|
||||
// ================================================================================================
|
||||
// 序列化辅助函数
|
||||
// ================================================================================================
|
||||
// 序列化任意消息
|
||||
template<typename MessageType>
|
||||
SerializationError serialize_message(const MessageType& message, std::vector<uint8_t>& 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<typename MessageType>
|
||||
SerializationError deserialize_message(const std::vector<uint8_t>& data, std::unique_ptr<MessageType>& output) {
|
||||
std::unique_ptr<IMessage> 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<MessageType*>(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
|
||||
219
src/communication/proto/audio_meta.proto
Normal file
219
src/communication/proto/audio_meta.proto
Normal file
@@ -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<string, string> 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<string, string> global_params = 4; // 全局参数
|
||||
bool enabled = 5; // 是否启用
|
||||
}
|
||||
|
||||
message ProcessingNode {
|
||||
string node_id = 1; // 节点ID
|
||||
string processor_type = 2; // 处理器类型
|
||||
map<string, ParameterValue> 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; // 系统独占
|
||||
}
|
||||
161
src/communication/proto/common.proto
Normal file
161
src/communication/proto/common.proto
Normal file
@@ -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<string, string> 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套接字
|
||||
}
|
||||
196
src/communication/proto/control.proto
Normal file
196
src/communication/proto/control.proto
Normal file
@@ -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<string, string> 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<string, string> 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<string, string> 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<string, string> properties = 2; // 连接属性
|
||||
Version protocol_version = 3; // 协议版本
|
||||
bool encrypted = 4; // 是否加密
|
||||
string encryption_method = 5; // 加密方法
|
||||
}
|
||||
299
src/communication/proto/plugin_mgmt.proto
Normal file
299
src/communication/proto/plugin_mgmt.proto
Normal file
@@ -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<string, string> 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<string, ParameterValue> parameters = 6; // 参数值
|
||||
bytes binary_data = 7; // 二进制数据(如果有)
|
||||
map<string, string> 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; // 重命名预设
|
||||
}
|
||||
348
src/communication/proto/status.proto
Normal file
348
src/communication/proto/status.proto
Normal file
@@ -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<string, string> 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<string, string> 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<string, string> details = 7; // 详细信息
|
||||
}
|
||||
|
||||
enum SeverityLevel {
|
||||
SEVERITY_INFO = 0; // 信息
|
||||
SEVERITY_LOW = 1; // 低
|
||||
SEVERITY_MEDIUM = 2; // 中
|
||||
SEVERITY_HIGH = 3; // 高
|
||||
SEVERITY_CRITICAL = 4; // 严重
|
||||
}
|
||||
117
src/engine/CMakeLists.txt
Normal file
117
src/engine/CMakeLists.txt
Normal file
@@ -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}个文件")
|
||||
290
src/engine/audio_buffer.cpp
Normal file
290
src/engine/audio_buffer.cpp
Normal file
@@ -0,0 +1,290 @@
|
||||
// ================================================================================================
|
||||
// Audio Backend - 音频缓冲区管理实现
|
||||
// ================================================================================================
|
||||
|
||||
#include "audio_buffer.h"
|
||||
#include "audio_processing.h"
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
|
||||
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<float*>(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<const int16_t*>(data_.data());
|
||||
float* dest = reinterpret_cast<float*>(result.data_.data());
|
||||
simd::convert_i16_to_f32(src, dest, sample_count);
|
||||
} else {
|
||||
const float* src = reinterpret_cast<const float*>(data_.data());
|
||||
int16_t* dest = reinterpret_cast<int16_t*>(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<double>(new_sample_rate) / config_.sample_rate;
|
||||
uint32_t new_frames = static_cast<uint32_t>(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<float*>(data_.data());
|
||||
const float* src_data = reinterpret_cast<const float*>(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<float, simd::ALIGNMENT_AVX> 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
|
||||
346
src/engine/audio_buffer.h
Normal file
346
src/engine/audio_buffer.h
Normal file
@@ -0,0 +1,346 @@
|
||||
// ================================================================================================
|
||||
// Audio Backend - 音频缓冲区管理
|
||||
// ================================================================================================
|
||||
// 描述: 高性能音频缓冲区管理,支持多种格式和声道配置
|
||||
// 功能: SIMD对齐、零拷贝、线程安全
|
||||
// ================================================================================================
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "aligned_allocator.h"
|
||||
#include "error.h"
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
|
||||
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<double>(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<typename T>
|
||||
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<T*>(data_.data() + channel * channel_stride_);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const T* channel_data(uint16_t channel) const {
|
||||
return const_cast<AudioBuffer*>(this)->channel_data<T>(channel);
|
||||
}
|
||||
|
||||
// 数据访问(交错格式)
|
||||
template<typename T>
|
||||
T* interleaved_data() {
|
||||
if (!interleaved_) {
|
||||
throw common::AudioException(
|
||||
common::ErrorCode::INVALID_OPERATION,
|
||||
"Cannot access interleaved data in non-interleaved buffer");
|
||||
}
|
||||
return reinterpret_cast<T*>(data_.data());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const T* interleaved_data() const {
|
||||
return const_cast<AudioBuffer*>(this)->interleaved_data<T>();
|
||||
}
|
||||
|
||||
// 原始数据访问
|
||||
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<uint8_t, simd::ALIGNMENT_AVX> data_;
|
||||
|
||||
// 辅助函数
|
||||
void validate_config() const;
|
||||
size_t calculate_buffer_size() const;
|
||||
size_t calculate_channel_stride() const;
|
||||
};
|
||||
|
||||
// ================================================================================================
|
||||
// 环形缓冲区(用于实时音频流)
|
||||
// ================================================================================================
|
||||
template<typename T>
|
||||
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<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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<size_t> read_pos_;
|
||||
std::atomic<size_t> write_pos_;
|
||||
std::atomic<size_t> available_;
|
||||
simd::AlignedBuffer<T, simd::ALIGNMENT_AVX> buffer_;
|
||||
mutable std::mutex mutex_;
|
||||
};
|
||||
|
||||
} // namespace audio_backend::engine
|
||||
106
src/frontend/CMakeLists.txt
Normal file
106
src/frontend/CMakeLists.txt
Normal file
@@ -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
|
||||
$<$<BOOL:${DAW_ENABLE_NETWORK}>: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}个文件")
|
||||
147
src/plugin_host/CMakeLists.txt
Normal file
147
src/plugin_host/CMakeLists.txt
Normal file
@@ -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
|
||||
$<$<BOOL:${DAW_ENABLE_SANDBOX}>: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}个文件")
|
||||
131
src/simd/CMakeLists.txt
Normal file
131
src/simd/CMakeLists.txt
Normal file
@@ -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
|
||||
$<$<BOOL:${DAW_ENABLE_SIMD}>:DAW_SIMD_ENABLED>
|
||||
$<$<BOOL:${DAW_ENABLE_AVX512}>: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}个文件")
|
||||
305
src/simd/aligned_allocator.h
Normal file
305
src/simd/aligned_allocator.h
Normal file
@@ -0,0 +1,305 @@
|
||||
// ================================================================================================
|
||||
// Audio Backend - SIMD内存对齐分配器
|
||||
// ================================================================================================
|
||||
// 描述: 为SIMD操作提供正确对齐的内存分配
|
||||
// 功能: 支持16/32/64字节对齐,确保SIMD指令高效执行
|
||||
// ================================================================================================
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
#include <new>
|
||||
#include <type_traits>
|
||||
|
||||
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<uintptr_t>(raw_ptr);
|
||||
uintptr_t aligned_addr = (raw_addr + sizeof(void*) + alignment - 1) & ~(alignment - 1);
|
||||
void* aligned_ptr = reinterpret_cast<void*>(aligned_addr);
|
||||
|
||||
// 在对齐地址前存储原始指针
|
||||
(reinterpret_cast<void**>(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<void**>(ptr))[-1];
|
||||
std::free(raw_ptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
// ================================================================================================
|
||||
// 对齐分配器(用于STL容器)
|
||||
// ================================================================================================
|
||||
template<typename T, size_t Alignment = ALIGNMENT_AVX>
|
||||
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<typename U>
|
||||
struct rebind {
|
||||
using other = AlignedAllocator<U, Alignment>;
|
||||
};
|
||||
|
||||
AlignedAllocator() noexcept = default;
|
||||
|
||||
template<typename U>
|
||||
AlignedAllocator(const AlignedAllocator<U, Alignment>&) 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<pointer>(ptr);
|
||||
}
|
||||
|
||||
void deallocate(pointer p, size_type) noexcept {
|
||||
aligned_free(p);
|
||||
}
|
||||
|
||||
template<typename U, typename... Args>
|
||||
void construct(U* p, Args&&... args) {
|
||||
::new(static_cast<void*>(p)) U(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
void destroy(U* p) {
|
||||
p->~U();
|
||||
}
|
||||
|
||||
size_type max_size() const noexcept {
|
||||
return std::numeric_limits<size_type>::max() / sizeof(T);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T1, size_t A1, typename T2, size_t A2>
|
||||
bool operator==(const AlignedAllocator<T1, A1>&, const AlignedAllocator<T2, A2>&) noexcept {
|
||||
return A1 == A2;
|
||||
}
|
||||
|
||||
template<typename T1, size_t A1, typename T2, size_t A2>
|
||||
bool operator!=(const AlignedAllocator<T1, A1>&, const AlignedAllocator<T2, A2>&) noexcept {
|
||||
return A1 != A2;
|
||||
}
|
||||
|
||||
// ================================================================================================
|
||||
// 便捷类型定义
|
||||
// ================================================================================================
|
||||
template<typename T>
|
||||
using AlignedVector16 = std::vector<T, AlignedAllocator<T, ALIGNMENT_SSE>>;
|
||||
|
||||
template<typename T>
|
||||
using AlignedVector32 = std::vector<T, AlignedAllocator<T, ALIGNMENT_AVX>>;
|
||||
|
||||
template<typename T>
|
||||
using AlignedVector64 = std::vector<T, AlignedAllocator<T, ALIGNMENT_AVX512>>;
|
||||
|
||||
// 根据当前CPU支持的最高SIMD级别选择对齐方式
|
||||
template<typename T>
|
||||
using AlignedVectorAuto = std::vector<T, AlignedAllocator<T, ALIGNMENT_AVX>>;
|
||||
|
||||
// ================================================================================================
|
||||
// 对齐检查工具
|
||||
// ================================================================================================
|
||||
|
||||
// 检查指针是否对齐
|
||||
template<size_t Alignment>
|
||||
inline bool is_aligned(const void* ptr) {
|
||||
return (reinterpret_cast<uintptr_t>(ptr) % Alignment) == 0;
|
||||
}
|
||||
|
||||
// 检查指针是否按特定字节数对齐
|
||||
inline bool is_aligned(const void* ptr, size_t alignment) {
|
||||
return (reinterpret_cast<uintptr_t>(ptr) % alignment) == 0;
|
||||
}
|
||||
|
||||
// 计算对齐后的大小
|
||||
inline size_t align_size(size_t size, size_t alignment) {
|
||||
return (size + alignment - 1) & ~(alignment - 1);
|
||||
}
|
||||
|
||||
// 计算对齐后的指针
|
||||
template<size_t Alignment>
|
||||
inline void* align_pointer(void* ptr) {
|
||||
uintptr_t addr = reinterpret_cast<uintptr_t>(ptr);
|
||||
uintptr_t aligned = (addr + Alignment - 1) & ~(Alignment - 1);
|
||||
return reinterpret_cast<void*>(aligned);
|
||||
}
|
||||
|
||||
// ================================================================================================
|
||||
// RAII对齐内存管理器
|
||||
// ================================================================================================
|
||||
template<typename T, size_t Alignment = ALIGNMENT_AVX>
|
||||
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<T*>(aligned_malloc(count * sizeof(T), Alignment));
|
||||
if (!data_) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
size_ = count;
|
||||
|
||||
// 对于非POD类型,需要构造对象
|
||||
if constexpr (!std::is_trivially_constructible_v<T>) {
|
||||
for (size_t i = 0; i < size_; ++i) {
|
||||
new(data_ + i) T();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void deallocate() {
|
||||
if (data_) {
|
||||
// 对于非POD类型,需要析构对象
|
||||
if constexpr (!std::is_trivially_destructible_v<T>) {
|
||||
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<Alignment>(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
|
||||
249
src/simd/audio_processing.cpp
Normal file
249
src/simd/audio_processing.cpp
Normal file
@@ -0,0 +1,249 @@
|
||||
// ================================================================================================
|
||||
// Audio Backend - SIMD音频处理函数实现
|
||||
// ================================================================================================
|
||||
|
||||
#include "audio_processing.h"
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <iostream>
|
||||
|
||||
// SSE相关头文件
|
||||
#if ALICHO_PLATFORM_X86
|
||||
#include <immintrin.h>
|
||||
#endif
|
||||
|
||||
// NEON相关头文件
|
||||
#if ALICHO_PLATFORM_ARM && defined(__ARM_NEON)
|
||||
#include <arm_neon.h>
|
||||
#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<const __m128i*>(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
|
||||
227
src/simd/audio_processing.h
Normal file
227
src/simd/audio_processing.h
Normal file
@@ -0,0 +1,227 @@
|
||||
// ================================================================================================
|
||||
// Audio Backend - SIMD音频处理函数
|
||||
// ================================================================================================
|
||||
// 描述: 使用SIMD优化的音频处理函数集合
|
||||
// 功能: 音频混合、音量控制、格式转换、基础数学运算
|
||||
// ================================================================================================
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "function_dispatcher.h"
|
||||
#include "aligned_allocator.h"
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
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<typename T, size_t Alignment = ALIGNMENT_AVX>
|
||||
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<Alignment>(buffer_.data());
|
||||
}
|
||||
|
||||
private:
|
||||
size_t channels_ = 0;
|
||||
size_t samples_ = 0;
|
||||
AlignedBuffer<T, Alignment> buffer_;
|
||||
};
|
||||
|
||||
// 便捷类型定义
|
||||
using AudioBufferF32 = AudioBuffer<float>;
|
||||
using AudioBufferI16 = AudioBuffer<int16_t>;
|
||||
using AudioBufferI32 = AudioBuffer<int32_t>;
|
||||
|
||||
// ================================================================================================
|
||||
// 函数注册器(用于在启动时注册所有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
|
||||
513
src/simd/cpu_features.cpp
Normal file
513
src/simd/cpu_features.cpp
Normal file
@@ -0,0 +1,513 @@
|
||||
// ================================================================================================
|
||||
// Audio Backend - SIMD CPU特性检测器实现
|
||||
// ================================================================================================
|
||||
|
||||
#include "cpu_features.h"
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
|
||||
// 平台特定的头文件
|
||||
#if ALICHO_PLATFORM_WINDOWS
|
||||
#include <windows.h>
|
||||
#include <intrin.h>
|
||||
#elif ALICHO_PLATFORM_UNIX || ALICHO_PLATFORM_POSIX
|
||||
#if ALICHO_PLATFORM_X86
|
||||
#include <cpuid.h>
|
||||
#endif
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#if ALICHO_PLATFORM_APPLE
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// ARM NEON支持
|
||||
#if ALICHO_PLATFORM_ARM && defined(__ARM_NEON)
|
||||
#include <arm_neon.h>
|
||||
#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<uint32_t>(regs[0]);
|
||||
result.ebx = static_cast<uint32_t>(regs[1]);
|
||||
result.ecx = static_cast<uint32_t>(regs[2]);
|
||||
result.edx = static_cast<uint32_t>(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<int*>(vendor_string)[0] = result.ebx;
|
||||
reinterpret_cast<int*>(vendor_string)[1] = result.edx;
|
||||
reinterpret_cast<int*>(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<int*>(brand_string + i * 16)[0] = result.eax;
|
||||
reinterpret_cast<int*>(brand_string + i * 16)[1] = result.ebx;
|
||||
reinterpret_cast<int*>(brand_string + i * 16)[2] = result.ecx;
|
||||
reinterpret_cast<int*>(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<int>(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<uint32_t>(CPUFeature::SSE);
|
||||
}
|
||||
if ((cpuid_1.edx & (1 << 26)) != 0) {
|
||||
info_.features |= static_cast<uint32_t>(CPUFeature::SSE2);
|
||||
}
|
||||
if ((cpuid_1.ecx & (1 << 0)) != 0) {
|
||||
info_.features |= static_cast<uint32_t>(CPUFeature::SSE3);
|
||||
}
|
||||
if ((cpuid_1.ecx & (1 << 9)) != 0) {
|
||||
info_.features |= static_cast<uint32_t>(CPUFeature::SSSE3);
|
||||
}
|
||||
if ((cpuid_1.ecx & (1 << 19)) != 0) {
|
||||
info_.features |= static_cast<uint32_t>(CPUFeature::SSE41);
|
||||
}
|
||||
if ((cpuid_1.ecx & (1 << 20)) != 0) {
|
||||
info_.features |= static_cast<uint32_t>(CPUFeature::SSE42);
|
||||
}
|
||||
if ((cpuid_1.ecx & (1 << 28)) != 0) {
|
||||
info_.features |= static_cast<uint32_t>(CPUFeature::AVX);
|
||||
}
|
||||
if ((cpuid_1.ecx & (1 << 12)) != 0) {
|
||||
info_.features |= static_cast<uint32_t>(CPUFeature::FMA);
|
||||
}
|
||||
if ((cpuid_1.ecx & (1 << 23)) != 0) {
|
||||
info_.features |= static_cast<uint32_t>(CPUFeature::POPCNT);
|
||||
}
|
||||
|
||||
// 获取扩展特性
|
||||
CPUIDResult cpuid_7 = cpuid(7, 0);
|
||||
|
||||
if ((cpuid_7.ebx & (1 << 5)) != 0) {
|
||||
info_.features |= static_cast<uint32_t>(CPUFeature::AVX2);
|
||||
}
|
||||
if ((cpuid_7.ebx & (1 << 3)) != 0) {
|
||||
info_.features |= static_cast<uint32_t>(CPUFeature::BMI1);
|
||||
}
|
||||
|
||||
// AVX-512检测
|
||||
if ((cpuid_7.ebx & (1 << 16)) != 0) {
|
||||
info_.features |= static_cast<uint32_t>(CPUFeature::AVX512F);
|
||||
}
|
||||
if ((cpuid_7.ebx & (1 << 31)) != 0) {
|
||||
info_.features |= static_cast<uint32_t>(CPUFeature::AVX512VL);
|
||||
}
|
||||
if ((cpuid_7.ebx & (1 << 30)) != 0) {
|
||||
info_.features |= static_cast<uint32_t>(CPUFeature::AVX512BW);
|
||||
}
|
||||
if ((cpuid_7.ebx & (1 << 17)) != 0) {
|
||||
info_.features |= static_cast<uint32_t>(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<int>(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<std::string> 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<int>(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<uint32_t>(CPUFeature::NEON);
|
||||
info_.max_simd_level = SIMDLevel::NEON;
|
||||
|
||||
#ifdef __ARM_FEATURE_FP16
|
||||
info_.features |= static_cast<uint32_t>(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<int>(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<int>(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
|
||||
178
src/simd/cpu_features.h
Normal file
178
src/simd/cpu_features.h
Normal file
@@ -0,0 +1,178 @@
|
||||
// ================================================================================================
|
||||
// Audio Backend - SIMD CPU特性检测器
|
||||
// ================================================================================================
|
||||
// 描述: 运行时检测CPU支持的SIMD指令集
|
||||
// 支持: SSE/AVX/AVX2/AVX-512/NEON
|
||||
// ================================================================================================
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <array>
|
||||
|
||||
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<CPUFeature>(
|
||||
static_cast<uint32_t>(lhs) | static_cast<uint32_t>(rhs)
|
||||
);
|
||||
}
|
||||
|
||||
inline CPUFeature operator&(CPUFeature lhs, CPUFeature rhs) {
|
||||
return static_cast<CPUFeature>(
|
||||
static_cast<uint32_t>(lhs) & static_cast<uint32_t>(rhs)
|
||||
);
|
||||
}
|
||||
|
||||
inline bool has_feature(CPUFeature features, CPUFeature test) {
|
||||
return (static_cast<uint32_t>(features) & static_cast<uint32_t>(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<uint32_t>(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
|
||||
120
src/simd/function_dispatcher.cpp
Normal file
120
src/simd/function_dispatcher.cpp
Normal file
@@ -0,0 +1,120 @@
|
||||
// ================================================================================================
|
||||
// Audio Backend - SIMD函数分发器实现
|
||||
// ================================================================================================
|
||||
|
||||
#include "function_dispatcher.h"
|
||||
#include <iostream>
|
||||
|
||||
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<int>(preferred_version); i >= 0; --i) {
|
||||
FunctionVersion version = static_cast<FunctionVersion>(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
|
||||
264
src/simd/function_dispatcher.h
Normal file
264
src/simd/function_dispatcher.h
Normal file
@@ -0,0 +1,264 @@
|
||||
// ================================================================================================
|
||||
// Audio Backend - SIMD函数分发器
|
||||
// ================================================================================================
|
||||
// 描述: 运行时自动选择最优SIMD实现的函数分发器
|
||||
// 功能: 根据CPU特性动态选择最佳的函数实现版本
|
||||
// ================================================================================================
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cpu_features.h"
|
||||
#include <functional>
|
||||
#include <array>
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
|
||||
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<typename FuncSignature>
|
||||
class MultiVersionFunction;
|
||||
|
||||
template<typename ReturnType, typename... Args>
|
||||
class MultiVersionFunction<ReturnType(Args...)> {
|
||||
public:
|
||||
using FunctionType = std::function<ReturnType(Args...)>;
|
||||
using FunctionArray = std::array<FunctionType, static_cast<size_t>(FunctionVersion::VERSION_COUNT)>;
|
||||
|
||||
MultiVersionFunction() = default;
|
||||
|
||||
// 注册函数版本
|
||||
void register_version(FunctionVersion version, FunctionType function) {
|
||||
functions_[static_cast<size_t>(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<int>(preferred_version); i >= 0; --i) {
|
||||
FunctionVersion version = static_cast<FunctionVersion>(i);
|
||||
const auto& func = functions_[static_cast<size_t>(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<FunctionVersion> get_available_versions() const {
|
||||
std::vector<FunctionVersion> versions;
|
||||
for (size_t i = 0; i < functions_.size(); ++i) {
|
||||
if (functions_[i]) {
|
||||
versions.push_back(static_cast<FunctionVersion>(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<typename FuncSignature>
|
||||
void register_function(const std::string& name,
|
||||
FunctionVersion version,
|
||||
std::function<FuncSignature> function) {
|
||||
auto& func_holder = get_or_create_function<FuncSignature>(name);
|
||||
func_holder.register_version(version, std::move(function));
|
||||
}
|
||||
|
||||
// 获取函数
|
||||
template<typename FuncSignature>
|
||||
const MultiVersionFunction<FuncSignature>& get_function(const std::string& name) {
|
||||
auto& func_holder = get_or_create_function<FuncSignature>(name);
|
||||
return func_holder;
|
||||
}
|
||||
|
||||
// 调用函数(便捷方法)
|
||||
template<typename FuncSignature, typename... Args>
|
||||
auto call_function(const std::string& name, Args&&... args)
|
||||
-> decltype(std::declval<std::function<FuncSignature>>()(args...)) {
|
||||
const auto& func = get_function<FuncSignature>(name);
|
||||
return func(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// 列出所有已注册的函数
|
||||
std::vector<std::string> list_functions() const {
|
||||
std::vector<std::string> 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<FunctionVersion> get_available_versions() const = 0;
|
||||
virtual bool has_implementation() const = 0;
|
||||
};
|
||||
|
||||
// 具体的函数持有者
|
||||
template<typename FuncSignature>
|
||||
struct FunctionHolder : public FunctionHolderBase {
|
||||
MultiVersionFunction<FuncSignature> function;
|
||||
|
||||
std::vector<FunctionVersion> get_available_versions() const override {
|
||||
return function.get_available_versions();
|
||||
}
|
||||
|
||||
bool has_implementation() const override {
|
||||
return function.has_implementation();
|
||||
}
|
||||
};
|
||||
|
||||
// 获取或创建函数持有者
|
||||
template<typename FuncSignature>
|
||||
MultiVersionFunction<FuncSignature>& get_or_create_function(const std::string& name) {
|
||||
auto it = function_registry_.find(name);
|
||||
if (it == function_registry_.end()) {
|
||||
auto holder = std::make_unique<FunctionHolder<FuncSignature>>();
|
||||
auto* raw_holder = holder.get();
|
||||
function_registry_[name] = std::move(holder);
|
||||
return raw_holder->function;
|
||||
} else {
|
||||
auto* holder = dynamic_cast<FunctionHolder<FuncSignature>*>(it->second.get());
|
||||
if (!holder) {
|
||||
throw std::runtime_error("Function signature mismatch for: " + name);
|
||||
}
|
||||
return holder->function;
|
||||
}
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, std::unique_ptr<FunctionHolderBase>> function_registry_;
|
||||
};
|
||||
|
||||
// ================================================================================================
|
||||
// 便捷宏定义
|
||||
// ================================================================================================
|
||||
|
||||
// 注册函数版本的宏
|
||||
#define REGISTER_SIMD_FUNCTION(name, version, function) \
|
||||
audio_backend::simd::FunctionDispatcher::instance().register_function<decltype(function)>(name, version, function)
|
||||
|
||||
// 获取函数的宏
|
||||
#define GET_SIMD_FUNCTION(signature, name) \
|
||||
audio_backend::simd::FunctionDispatcher::instance().get_function<signature>(name)
|
||||
|
||||
// 调用函数的宏
|
||||
#define CALL_SIMD_FUNCTION(signature, name, ...) \
|
||||
audio_backend::simd::FunctionDispatcher::instance().call_function<signature>(name, __VA_ARGS__)
|
||||
|
||||
// ================================================================================================
|
||||
// 自动注册辅助类
|
||||
// ================================================================================================
|
||||
template<typename FuncSignature>
|
||||
class AutoRegister {
|
||||
public:
|
||||
AutoRegister(const std::string& name,
|
||||
FunctionVersion version,
|
||||
std::function<FuncSignature> function) {
|
||||
FunctionDispatcher::instance().register_function<FuncSignature>(
|
||||
name, version, std::move(function));
|
||||
}
|
||||
};
|
||||
|
||||
// 自动注册宏
|
||||
#define AUTO_REGISTER_SIMD_FUNCTION(name, version, function) \
|
||||
static auto _auto_reg_##name##_##version = \
|
||||
audio_backend::simd::AutoRegister<decltype(function)>(#name, version, function)
|
||||
|
||||
// ================================================================================================
|
||||
// 函数版本字符串转换
|
||||
// ================================================================================================
|
||||
const char* function_version_to_string(FunctionVersion version);
|
||||
FunctionVersion string_to_function_version(const std::string& str);
|
||||
|
||||
} // namespace audio_backend::simd
|
||||
181
tests/CMakeLists.txt
Normal file
181
tests/CMakeLists.txt
Normal file
@@ -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
|
||||
$<$<CONFIG:Debug>: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 "")
|
||||
Reference in New Issue
Block a user