在开始部署FunASR之前,需确保您的Windows系统满足以下要求,并安装相关开发工具:
从ModelScope或FunASR的GitHub仓库下载所需的模型文件,并将其放置在指定目录。例如:
git clone https://www.modelscope.cn/damo/speech_fsmn_vad_zh-cn-16k-common-onnx.git
git clone https://www.modelscope.cn/damo/speech_paraformer-large-vad-punc_asr_nat-zh-cn-16k-common-vocab8404-onnx.git
git clone https://www.modelscope.cn/damo/speech_ngram_lm_zh-cn-ai-wesp-fst.git
git clone https://www.modelscope.cn/damo/punc_ct-transformer_cn-en-common-vocab471067-large-onnx.git
使用Docker启动FunASR服务端,并挂载模型目录:
docker run -p 10095:10095 -it --privileged=true \
-v d:/FunASR/model:/workspace/models \
registry.cn-hangzhou.aliyuncs.com/funasr_repo/funasr:funasr-runtime-sdk-online-cpu-0.1.9
PortAudio是一个跨平台的音频I/O库,用于捕获麦克风音频。可通过以下步骤进行安装:
git clone https://git.assembla.com/portaudio.git
cd portaudio
./configure
make
make install
Boost库提供了丰富的C++库支持,特别适用于网络通信。使用vcpkg进行安装:
vcpkg install boost:x86-windows
根据FunASR的需求,可能需要安装以下库:
编写C++代码,使用PortAudio库实时捕获麦克风音频数据。以下是基本的音频捕获设置:
// 初始化PortAudio
PaError err = Pa_Initialize();
if (err != paNoError) {
std::cerr << "PortAudio初始化失败: " << Pa_GetErrorText(err) << std::endl;
return -1;
}
// 打开默认输入流
PaStream* stream;
err = Pa_OpenDefaultStream(&stream, 1, 0, paInt16, 16000, 256, nullptr, nullptr);
if (err != paNoError) {
std::cerr << "打开音频流失败: " << Pa_GetErrorText(err) << std::endl;
return -1;
}
// 启动流
err = Pa_StartStream(stream);
if (err != paNoError) {
std::cerr << "启动音频流失败: " << Pa_GetErrorText(err) << std::endl;
return -1;
}
捕获到的音频数据需要进行预处理,以符合FunASR模型的输入要求。这包括:
使用Boost.Beast库建立与FunASR服务端的WebSocket连接:
#include <boost/beast/websocket.hpp>
#include <boost/asio.hpp>
boost::asio::io_context ioc;
boost::asio::ip::tcp::resolver resolver(ioc);
auto const results = resolver.resolve("127.0.0.1", "10095");
boost::beast::websocket::stream<boost::asio::ip::tcp::socket> ws(ioc);
boost::asio::connect(ws.next_layer(), results.begin(), results.end());
ws.handshake("127.0.0.1", "/");
将预处理后的音频数据通过WebSocket实时发送到FunASR服务端:
// 读取音频数据
short buffer[256];
while (true) {
Pa_ReadStream(stream, buffer, 256);
// 发送数据
ws.write(boost::asio::buffer(buffer, sizeof(buffer)));
// 接收识别结果
boost::beast::flat_buffer res;
ws.read(res);
std::string result = boost::beast::buffers_to_string(res.data());
std::cout << "识别结果: " << result << std::endl;
}
FunASR会返回识别结果,可以实时显示或进行后续处理:
// 处理返回的识别结果
ws.on_message([](const std::string& result) {
std::cout << "识别结果: " << result << std::endl;
});
在开始实时识别之前,建议先使用预先录制的音频文件进行离线测试,确保预处理和识别流程的正确性。
实时识别的延迟需要尽量控制,可以通过调整音频缓冲区大小、帧长度等参数来优化性能。
为了确保音频捕获与识别过程互不干扰,建议采用多线程设计:
如果识别速度较慢,可以考虑通过GPU加速或使用TensorRT等工具对FunASR模型进行优化。
以下是一个简化的C++客户端示例,展示了如何捕获麦克风音频并与FunASR进行实时通信:
#include <iostream>
#include <thread>
#include <queue>
#include <mutex>
#include <atomic>
#include <portaudio.h>
#include <boost/beast/websocket.hpp>
#include <boost/asio.hpp>
// 共享队列与互斥锁
std::queue<std::vector<short>> audioQueue;
std::mutex queueMutex;
std::atomic<bool> capturing(true);
// PortAudio 回调函数——采集音频数据
static int audioCallback(const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void *userData)
{
const short* in = reinterpret_cast<const short*>(inputBuffer);
std::vector<short> frame(in, in + framesPerBuffer);
{
std::lock_guard<std::mutex> lock(queueMutex);
audioQueue.push(frame);
}
return paContinue;
}
// 模型识别线程函数
void recognitionThread(boost::beast::websocket::stream<boost::asio::ip::tcp::socket>& ws)
{
while (capturing || !audioQueue.empty())
{
std::vector<short> audioFrame;
{
std::lock_guard<std::mutex> lock(queueMutex);
if (!audioQueue.empty())
{
audioFrame = std::move(audioQueue.front());
audioQueue.pop();
}
}
if (!audioFrame.empty()) {
ws.write(boost::asio::buffer(audioFrame.data(), audioFrame.size() * sizeof(short)));
// 接收识别结果
boost::beast::flat_buffer res;
ws.read(res);
std::string result = boost::beast::buffers_to_string(res.data());
if (!result.empty()) {
std::cout << "识别结果: " << result << std::endl;
}
}
else {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
}
int main()
{
// 初始化PortAudio
PaError err = Pa_Initialize();
if (err != paNoError) {
std::cerr << "PortAudio初始化失败: " << Pa_GetErrorText(err) << std::endl;
return -1;
}
// 打开默认输入流
PaStream* stream;
err = Pa_OpenDefaultStream(&stream, 1, 0, paInt16, 16000, 256, audioCallback, nullptr);
if (err != paNoError) {
std::cerr << "打开音频流失败: " << Pa_GetErrorText(err) << std::endl;
return -1;
}
// 启动音频流
err = Pa_StartStream(stream);
if (err != paNoError) {
std::cerr << "启动音频流失败: " << Pa_GetErrorText(err) << std::endl;
return -1;
}
// 初始化Boost.Asio和WebSocket
boost::asio::io_context ioc;
boost::asio::ip::tcp::resolver resolver(ioc);
auto const results = resolver.resolve("127.0.0.1", "10095");
boost::beast::websocket::stream<boost::asio::ip::tcp::socket> ws(ioc);
boost::asio::connect(ws.next_layer(), results.begin(), results.end());
ws.handshake("127.0.0.1", "/");
// 启动识别线程
std::thread recogThread(recognitionThread, std::ref(ws));
// 主循环,等待用户输入退出
std::cout << "按回车键停止采集并结束识别..." << std::endl;
std::cin.get();
capturing = false;
// 停止PortAudio流
Pa_StopStream(stream);
Pa_CloseStream(stream);
Pa_Terminate();
// 等待识别线程结束
recogThread.join();
return 0;
}
解决方案:
解决方案:
解决方案:
将音频捕获和识别处理分离到不同线程,确保实时性和响应性。
合理设置音频缓冲区大小,平衡延迟和系统负载。
使用GPU进行模型推理,或通过TensorRT进行模型优化,提升识别速度。
优化内存使用,避免内存泄漏和资源浪费,确保系统长时间稳定运行。
在Windows平台上使用C++本地部署FunASR,实现流式自动语音识别,需要经过环境准备、依赖安装、麦克风音频配置、FunASR集成以及调试优化等多个步骤。通过合理的设计和优化,可以实现高效、准确的实时语音识别系统。