Poco C++ WebSocket发送PCM音频失败问题求助
我使用Poco::Net::WebSocket向第三方STT服务传输原始PCM音频,目前仅能收到第三方返回的初始连接消息{type:'connected',id:'111034'},后续会收到意外消息,且第三方确认未接收到任何音频数据。联系第三方后得知是content-type设置不符合要求,以下是我的代码,恳请提供解决建议或方向。
#pragma once #include "Poco/Net/HTTPRequest.h" #include <Poco/Net/HTTPSClientSession.h> #include "Poco/Net/HTTPResponse.h" #include "Poco/Net/HTTPMessage.h" #include "Poco/Net/WebSocket.h" #include "Poco/Net/NetException.h" #include "Poco/Buffer.h" #include "Poco/URI.h" #include "logger.h" extern "C" { #include "binn/binn.h" #pragma comment(lib,"binn.lib") } using Poco::Net::WebSocketException; using Poco::Net::HTTPSClientSession; using Poco::Net::HTTPRequest; using Poco::Net::HTTPResponse; using Poco::Net::HTTPMessage; using Poco::Net::WebSocket; using Poco::Buffer; class PocoHelper { WebSocket* m_psock; HTTPSClientSession* cs; HTTPRequest* request; HTTPResponse response; Log logHelper; int msgSize = 8000; Buffer<char>* container; Poco::URI* uri; public: PocoHelper(std::string wsEndPoint) { uri = new Poco::URI(wsEndPoint); cs = new HTTPSClientSession(uri->getHost(), 443); request = new HTTPRequest(HTTPRequest::HTTP_GET, uri->getPathEtc(), HTTPMessage::HTTP_1_1); request->set("origin", "http://localhost"); request->set("content-type", "audio/x-wav;layout=interleaved;rate=32000;format=S16LE;channels=1"); request->setKeepAlive(true); m_psock = new WebSocket(*cs, *request, response); m_psock->setBlocking(false); m_psock->setReceiveTimeout(Poco::Timespan(3, 0)); m_psock->setSendTimeout(Poco::Timespan(3, 0)); container = new Buffer<char>(msgSize); if (m_psock->poll(Poco::Timespan(1, 0), Poco::Net::WebSocket::SelectMode::SELECT_READ)) { receive_buffer(); } } ~PocoHelper() { m_psock->close(); delete m_psock; } void send_buffer(char* buffer, unsigned int bufferLen) { try { if (msgSize <= 0 && m_psock->poll(Poco::Timespan(2, 0), Poco::Net::WebSocket::SelectMode::SELECT_WRITE)) { msgSize = 8000; Buffer<char>* tempBuffer = container; int sent = m_psock->sendBytes(&tempBuffer, tempBuffer->sizeBytes(), WebSocket::FRAME_OP_SETRAW); logHelper.LogMessage("Sent bytes: " + std::to_string(sent)); container = new Buffer<char>(msgSize); } if (m_psock->poll(Poco::Timespan(1, 0), Poco::Net::WebSocket::SelectMode::SELECT_READ)) { receive_buffer(); } if (*buffer) { container->append(buffer, bufferLen); msgSize -= bufferLen; } } catch (Poco::Net::WebSocketException ex) { switch (ex.code()) { case WebSocket::ErrorCodes::WS_ERR_UNAUTHORIZED: logHelper.LogMessage("Unauthorized socket!"); break; case WebSocket::ErrorCodes::WS_ERR_PAYLOAD_TOO_BIG: logHelper.LogMessage("Payload too big..."); case WebSocket::ErrorCodes::WS_ERR_INCOMPLETE_FRAME: logHelper.LogMessage("Incomplete Frame"); break; } string what(ex.message()); if (!what.empty()) { logHelper.LogMessage(what); } } } void receive_buffer() { try { char readMsg[256]; int flags = 0; int rlen = m_psock->receiveFrame(&readMsg, 256, flags); logHelper.LogMessage(readMsg); } catch (Poco::Exception ex) { string msg(ex.what()); logHelper.LogMessage("Exception: " + msg); } } void close() { try { m_psock->shutdown(); } catch (...) { logHelper.LogMessage("closing failed."); } } };
解决建议
修正Content-Type的设置方式:WebSocket握手是GET请求,通常GET请求不需要设置Content-Type。第三方提到的content-type问题,大概率是要求在握手阶段用自定义Header(比如
Sec-WebSocket-Protocol或专门的音频格式Header)声明PCM参数,或是在音频帧中携带格式信息。先确认第三方要求的格式声明位置,将Content-Type从GET请求中移到正确的地方。修复音频发送的核心错误:
sendBytes(&tempBuffer, ...)传递的是指针的地址,而非音频数据的地址。应改为sendBytes(tempBuffer->begin(), tempBuffer->sizeBytes(), ...),这样才会发送容器内的真实音频数据。使用标准WebSocket二进制帧操作码:将
WebSocket::FRAME_OP_SETRAW替换为WebSocket::FRAME_OP_BINARY——SETRAW是非标准自定义操作码,第三方服务大概率只识别标准的二进制帧类型。修正buffer空指针判断:
if (*buffer)会在buffer为nullptr时崩溃,改为if (buffer != nullptr)来判断是否传入有效数据。修复内存泄漏:析构函数中需补充删除构造函数中new的对象:
~PocoHelper() { m_psock->close(); delete m_psock; delete uri; delete cs; delete request; delete container; }优化接收缓冲区:
receive_buffer中的固定256字节缓冲区可能不足,建议根据返回的rlen处理消息,或改用动态缓冲区,避免消息截断导致的“意外消息”问题。
内容的提问来源于stack exchange,提问作者Naeem Ahmed

