459 lines
17 KiB
C++
459 lines
17 KiB
C++
// ================================================================================================
|
|
// Audio Backend - 前端通信接口示例
|
|
// ================================================================================================
|
|
// 描述: 演示前端通信模块的使用方法
|
|
// 功能: 引擎连接、设备管理、网络发现、音频传输
|
|
// ================================================================================================
|
|
|
|
#include "audio_backend/frontend.h"
|
|
#include <iostream>
|
|
#include <string>
|
|
#include <thread>
|
|
#include <chrono>
|
|
#include <atomic>
|
|
#include <csignal>
|
|
|
|
using namespace audio_backend;
|
|
using namespace audio_backend::frontend;
|
|
|
|
// 全局退出标志
|
|
std::atomic<bool> g_running{true};
|
|
|
|
// 信号处理器
|
|
void signal_handler(int signal) {
|
|
std::cout << "接收到信号: " << signal << ", 准备退出..." << std::endl;
|
|
g_running = false;
|
|
}
|
|
|
|
// 事件监听器
|
|
class DemoEventListener : public IFrontendEventListener {
|
|
public:
|
|
void on_frontend_event(FrontendEvent event, const std::string& data) override {
|
|
std::cout << "[事件] ";
|
|
switch (event) {
|
|
case FrontendEvent::EngineConnected:
|
|
std::cout << "引擎已连接";
|
|
break;
|
|
case FrontendEvent::EngineDisconnected:
|
|
std::cout << "引擎已断开";
|
|
break;
|
|
case FrontendEvent::DeviceAdded:
|
|
std::cout << "设备已添加";
|
|
break;
|
|
case FrontendEvent::DeviceRemoved:
|
|
std::cout << "设备已移除";
|
|
break;
|
|
case FrontendEvent::NetworkServiceFound:
|
|
std::cout << "发现网络服务";
|
|
break;
|
|
case FrontendEvent::NetworkServiceLost:
|
|
std::cout << "丢失网络服务";
|
|
break;
|
|
case FrontendEvent::AudioStreamStarted:
|
|
std::cout << "音频流已开始";
|
|
break;
|
|
case FrontendEvent::AudioStreamStopped:
|
|
std::cout << "音频流已停止";
|
|
break;
|
|
case FrontendEvent::ConfigurationChanged:
|
|
std::cout << "配置已更改";
|
|
break;
|
|
default:
|
|
std::cout << "未知事件";
|
|
break;
|
|
}
|
|
if (!data.empty()) {
|
|
std::cout << ": " << data;
|
|
}
|
|
std::cout << std::endl;
|
|
}
|
|
|
|
void on_audio_device_changed(const std::string& device_id, bool added) override {
|
|
std::cout << "[设备] " << (added ? "添加" : "移除") << " 设备: " << device_id << std::endl;
|
|
}
|
|
|
|
void on_audio_stream_data(const engine::AudioBuffer& buffer) override {
|
|
// 在实际应用中处理收到的音频数据
|
|
std::cout << "[音频] 收到音频数据: "
|
|
<< buffer.frames() << " 帧, "
|
|
<< buffer.channels() << " 声道" << std::endl;
|
|
}
|
|
|
|
void on_network_service_discovered(const std::string& service_name,
|
|
const std::string& address,
|
|
uint16_t port) override {
|
|
std::cout << "[发现] 服务: " << service_name
|
|
<< " 地址: " << address
|
|
<< " 端口: " << port << std::endl;
|
|
}
|
|
|
|
void on_frontend_error(common::ErrorCode error, const std::string& message) override {
|
|
std::cout << "[错误] 代码: " << static_cast<int>(error)
|
|
<< " 消息: " << message << std::endl;
|
|
}
|
|
};
|
|
|
|
// ================================================================================================
|
|
// 本地音频引擎连接示例
|
|
// ================================================================================================
|
|
void local_engine_demo() {
|
|
std::cout << "\n=== 本地音频引擎连接示例 ===\n" << std::endl;
|
|
|
|
// 创建前端管理器
|
|
auto frontend = create_frontend_manager("demo_frontend");
|
|
if (!frontend) {
|
|
std::cerr << "无法创建前端管理器" << std::endl;
|
|
return;
|
|
}
|
|
|
|
// 添加事件监听器
|
|
auto listener = std::make_shared<DemoEventListener>();
|
|
frontend->add_event_listener(listener);
|
|
|
|
// 初始化前端
|
|
auto result = frontend->initialize();
|
|
if (result != common::ErrorCode::SUCCESS) {
|
|
std::cerr << "前端初始化失败: " << static_cast<int>(result) << std::endl;
|
|
return;
|
|
}
|
|
std::cout << "前端初始化成功" << std::endl;
|
|
|
|
// 连接到音频引擎
|
|
std::cout << "连接到本地音频引擎..." << std::endl;
|
|
result = frontend->connect_to_engine("tcp://localhost:5555");
|
|
if (result != common::ErrorCode::SUCCESS) {
|
|
std::cerr << "无法连接到音频引擎: " << static_cast<int>(result) << std::endl;
|
|
std::cout << "请确保音频引擎正在运行,继续演示其他功能..." << std::endl;
|
|
} else {
|
|
std::cout << "成功连接到音频引擎" << std::endl;
|
|
}
|
|
|
|
// 获取音频设备
|
|
std::cout << "\n获取音频设备列表..." << std::endl;
|
|
auto devices = frontend->get_audio_devices();
|
|
if (devices.empty()) {
|
|
std::cout << "未找到音频设备" << std::endl;
|
|
} else {
|
|
std::cout << "找到 " << devices.size() << " 个音频设备:" << std::endl;
|
|
for (const auto& device : devices) {
|
|
std::cout << " - " << device.name
|
|
<< " (ID: " << device.id << ")"
|
|
<< " [" << (device.is_input ? "输入" : "")
|
|
<< (device.is_output ? "输出" : "") << "]"
|
|
<< (device.is_default ? " 默认" : "") << std::endl;
|
|
}
|
|
|
|
// 如果找到默认输出设备,设置它
|
|
for (const auto& device : devices) {
|
|
if (device.is_output && device.is_default) {
|
|
std::cout << "\n设置默认输出设备: " << device.name << std::endl;
|
|
frontend->set_output_device(device.id);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 启动音频流(在实际环境中可能会开始播放声音)
|
|
std::cout << "\n尝试启动音频..." << std::endl;
|
|
result = frontend->start_audio_stream();
|
|
if (result != common::ErrorCode::SUCCESS) {
|
|
std::cerr << "无法启动音频流: " << static_cast<int>(result) << std::endl;
|
|
} else {
|
|
std::cout << "音频流已启动" << std::endl;
|
|
|
|
// 保持音频流一小段时间
|
|
std::cout << "音频流运行中..." << std::endl;
|
|
std::this_thread::sleep_for(std::chrono::seconds(2));
|
|
|
|
std::cout << "停止音频流..." << std::endl;
|
|
frontend->stop_audio_stream();
|
|
}
|
|
|
|
// 断开音频引擎
|
|
std::cout << "\n断开音频引擎..." << std::endl;
|
|
frontend->disconnect_from_engine();
|
|
|
|
// 关闭前端
|
|
std::cout << "关闭前端..." << std::endl;
|
|
frontend->shutdown();
|
|
|
|
std::cout << "本地音频引擎示例完成" << std::endl;
|
|
}
|
|
|
|
// ================================================================================================
|
|
// 网络服务发现示例
|
|
// ================================================================================================
|
|
void network_discovery_demo() {
|
|
std::cout << "\n=== 网络服务发现示例 ===\n" << std::endl;
|
|
|
|
// 创建前端管理器
|
|
auto frontend = create_frontend_manager("discovery_demo");
|
|
if (!frontend) {
|
|
std::cerr << "无法创建前端管理器" << std::endl;
|
|
return;
|
|
}
|
|
|
|
// 添加事件监听器
|
|
auto listener = std::make_shared<DemoEventListener>();
|
|
frontend->add_event_listener(listener);
|
|
|
|
// 初始化前端
|
|
auto result = frontend->initialize();
|
|
if (result != common::ErrorCode::SUCCESS) {
|
|
std::cerr << "前端初始化失败: " << static_cast<int>(result) << std::endl;
|
|
return;
|
|
}
|
|
|
|
// 启动网络发现
|
|
std::cout << "启动网络服务发现..." << std::endl;
|
|
result = frontend->start_network_discovery();
|
|
if (result != common::ErrorCode::SUCCESS) {
|
|
std::cerr << "无法启动网络发现: " << static_cast<int>(result) << std::endl;
|
|
frontend->shutdown();
|
|
return;
|
|
}
|
|
|
|
// 等待并显示发现的服务
|
|
std::cout << "搜索网络音频服务 (5秒)..." << std::endl;
|
|
std::this_thread::sleep_for(std::chrono::seconds(5));
|
|
|
|
auto services = frontend->get_discovered_services();
|
|
if (services.empty()) {
|
|
std::cout << "未找到网络音频服务" << std::endl;
|
|
} else {
|
|
std::cout << "找到 " << services.size() << " 个网络音频服务:" << std::endl;
|
|
for (const auto& service : services) {
|
|
std::cout << " - " << service.service_name
|
|
<< " (类型: " << service.service_type << ")"
|
|
<< " 地址: " << service.address
|
|
<< " 端口: " << service.port << std::endl;
|
|
}
|
|
|
|
// 如果发现了服务,尝试连接第一个服务
|
|
if (!services.empty()) {
|
|
const auto& first_service = services[0];
|
|
std::cout << "\n尝试连接到服务: " << first_service.service_name << std::endl;
|
|
|
|
result = frontend->connect_to_network_service(first_service.service_id);
|
|
if (result != common::ErrorCode::SUCCESS) {
|
|
std::cerr << "无法连接到服务: " << static_cast<int>(result) << std::endl;
|
|
} else {
|
|
std::cout << "成功连接到服务" << std::endl;
|
|
|
|
// 在实际应用中,此处可以开始音频流传输
|
|
// frontend->start_network_audio_stream(...);
|
|
|
|
std::cout << "断开服务连接..." << std::endl;
|
|
frontend->disconnect_from_network_service(first_service.service_id);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 停止网络发现
|
|
std::cout << "\n停止网络发现..." << std::endl;
|
|
frontend->stop_network_discovery();
|
|
|
|
// 关闭前端
|
|
frontend->shutdown();
|
|
|
|
std::cout << "网络服务发现示例完成" << std::endl;
|
|
}
|
|
|
|
// ================================================================================================
|
|
// 音频流传输示例
|
|
// ================================================================================================
|
|
void audio_streaming_demo() {
|
|
std::cout << "\n=== 音频流传输示例 ===\n" << std::endl;
|
|
|
|
// 创建音频流发送器
|
|
auto sender_config = network::create_balanced_config();
|
|
auto sender = network::create_audio_stream_sender(sender_config);
|
|
if (!sender) {
|
|
std::cerr << "无法创建音频流发送器" << std::endl;
|
|
return;
|
|
}
|
|
|
|
// 创建音频流接收器
|
|
auto receiver_config = network::create_balanced_config();
|
|
auto receiver = network::create_audio_stream_receiver(receiver_config);
|
|
if (!receiver) {
|
|
std::cerr << "无法创建音频流接收器" << std::endl;
|
|
return;
|
|
}
|
|
|
|
// 创建UDP传输
|
|
auto transport_config = network::transport_factory::get_recommended_udp_config();
|
|
transport_config.local_port = 12345; // 发送端端口
|
|
auto transport = network::transport_factory::create_udp_transport();
|
|
if (!transport) {
|
|
std::cerr << "无法创建UDP传输" << std::endl;
|
|
return;
|
|
}
|
|
|
|
// 初始化传输
|
|
if (transport->initialize(transport_config) != common::ErrorCode::SUCCESS) {
|
|
std::cerr << "无法初始化UDP传输" << std::endl;
|
|
return;
|
|
}
|
|
|
|
// 绑定到本地端口
|
|
network::NetworkEndpoint local_endpoint("127.0.0.1", 12345, network::TransportProtocol::UDP);
|
|
if (transport->bind(local_endpoint) != common::ErrorCode::SUCCESS) {
|
|
std::cerr << "无法绑定到本地端口" << std::endl;
|
|
return;
|
|
}
|
|
|
|
// 接收器的传输(在实际应用中,这会在不同机器上)
|
|
auto receiver_transport = network::transport_factory::create_udp_transport();
|
|
transport_config.local_port = 12346; // 接收端端口
|
|
receiver_transport->initialize(transport_config);
|
|
network::NetworkEndpoint receiver_endpoint("127.0.0.1", 12346, network::TransportProtocol::UDP);
|
|
receiver_transport->bind(receiver_endpoint);
|
|
|
|
// 初始化发送器和接收器
|
|
sender->initialize(transport);
|
|
receiver->initialize(receiver_transport);
|
|
|
|
std::cout << "音频流传输已设置,实际应用中会传输音频数据" << std::endl;
|
|
std::cout << "发送器 -> 127.0.0.1:12345" << std::endl;
|
|
std::cout << "接收器 <- 127.0.0.1:12346" << std::endl;
|
|
|
|
// 在实际应用中,此处会有一个循环发送音频数据
|
|
/*
|
|
// 示例代码(不会执行)
|
|
engine::AudioConfig config;
|
|
config.sample_rate = 48000;
|
|
config.channels = 2;
|
|
config.format = engine::AudioFormat::FLOAT32;
|
|
config.frames_per_buffer = 480; // 10ms @ 48kHz
|
|
|
|
engine::AudioBuffer buffer(config);
|
|
|
|
while (running) {
|
|
// 获取音频数据到buffer
|
|
sender->send_audio(buffer);
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
|
}
|
|
*/
|
|
|
|
// 关闭发送器和接收器
|
|
std::cout << "\n关闭音频流..." << std::endl;
|
|
sender->shutdown();
|
|
receiver->shutdown();
|
|
transport->shutdown();
|
|
receiver_transport->shutdown();
|
|
|
|
std::cout << "音频流传输示例成" << std::endl;
|
|
}
|
|
|
|
// ================================================================================================
|
|
// 编解码示例
|
|
// ================================================================================================
|
|
void codec_demo() {
|
|
std::cout << "\n=== 音频编解码示例 ===\n" << std::endl;
|
|
|
|
// 创建Opus编解码器
|
|
codec::CodecConfig opus_config;
|
|
opus_config.codec_type = codec::CodecType::OPUS;
|
|
opus_config.sample_rate = 48000;
|
|
opus_config.channels = 2;
|
|
opus_config.bitrate = 128000; // 128 kbps
|
|
|
|
auto encoder = codec::create_codec(opus_config);
|
|
if (!encoder) {
|
|
std::cerr << "无法创建Opus编解码器" << std::endl;
|
|
return;
|
|
}
|
|
|
|
// 初始化编码器
|
|
encoder->initialize();
|
|
|
|
// 创建测试音频缓冲区
|
|
engine::AudioConfig audio_config;
|
|
audio_config.sample_rate = 48000;
|
|
audio_config.channels = 2;
|
|
audio_config.format = engine::AudioFormat::FLOAT32;
|
|
audio_config.frames_per_buffer = 960; // 20ms @ 48kHz
|
|
|
|
engine::AudioBuffer test_buffer(audio_config);
|
|
|
|
// 生成正弦波测试数据
|
|
float* data = test_buffer.interleaved_data<float>();
|
|
for (uint32_t i = 0; i < test_buffer.frames(); i++) {
|
|
for (uint16_t c = 0; c < test_buffer.channels(); c++) {
|
|
// 生成一个440Hz的正弦波
|
|
float sample = std::sin(2.0f * 3.14159f * 440.0f * i / 48000.0f);
|
|
data[i * test_buffer.channels() + c] = sample * 0.5f; // 半音量
|
|
}
|
|
}
|
|
|
|
// 编码测试数据
|
|
std::vector<uint8_t> encoded_data;
|
|
auto result = encoder->encode(test_buffer, encoded_data);
|
|
if (result != common::ErrorCode::SUCCESS) {
|
|
std::cerr << "编码失败: " << static_cast<int>(result) << std::endl;
|
|
encoder->shutdown();
|
|
return;
|
|
}
|
|
|
|
std::cout << "音频编码结果:" << std::endl;
|
|
std::cout << " - 原始大小: " << test_buffer.size_bytes() << " 字节" << std::endl;
|
|
std::cout << " - 编码大小: " << encoded_data.size() << " 字节" << std::endl;
|
|
std::cout << " - 压缩率: " << (100.0 * encoded_data.size() / test_buffer.size_bytes()) << "%" << std::endl;
|
|
|
|
// 解码测试数据
|
|
engine::AudioBuffer decoded_buffer;
|
|
result = encoder->decode(encoded_data, decoded_buffer);
|
|
if (result != common::ErrorCode::SUCCESS) {
|
|
std::cerr << "解码失败: " << static_cast<int>(result) << std::endl;
|
|
encoder->shutdown();
|
|
return;
|
|
}
|
|
|
|
std::cout << "音频解码结果:" << std::endl;
|
|
std::cout << " - 解码后大小: " << decoded_buffer.size_bytes() << " 字节" << std::endl;
|
|
std::cout << " - 帧数: " << decoded_buffer.frames() << std::endl;
|
|
std::cout << " - 声道数: " << decoded_buffer.channels() << std::endl;
|
|
|
|
// 关闭编解码器
|
|
encoder->shutdown();
|
|
|
|
std::cout << "音频编解码示例完成" << std::endl;
|
|
}
|
|
|
|
// ================================================================================================
|
|
// 主函数
|
|
// ================================================================================================
|
|
int main() {
|
|
std::cout << "====================================\n";
|
|
std::cout << "Audio Backend 前端通信示例\n";
|
|
std::cout << "====================================\n";
|
|
|
|
// 设置信号处理
|
|
std::signal(SIGINT, signal_handler); // Ctrl+C
|
|
std::signal(SIGTERM, signal_handler); // 终止信号
|
|
|
|
try {
|
|
// 初始化前端系统
|
|
frontend::initialize_frontend();
|
|
|
|
// 运行各个示例
|
|
local_engine_demo();
|
|
network_discovery_demo();
|
|
audio_streaming_demo();
|
|
codec_demo();
|
|
|
|
// 关闭前端系统
|
|
frontend::shutdown_frontend();
|
|
|
|
std::cout << "\n====================================\n";
|
|
std::cout << "演示完成\n";
|
|
std::cout << "====================================\n";
|
|
|
|
} catch (const std::exception& e) {
|
|
std::cerr << "演示过程中发生错误: " << e.what() << "\n";
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
} |