You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Poco C++ WebSocket发送PCM音频失败问题求助

问题:Poco WebSocket传输PCM音频到STT服务失败,第三方未接收音频数据

我使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 01:31:35