297 lines
11 KiB
C++
297 lines
11 KiB
C++
// ================================================================================================
|
||
// 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
|