我正在实现一个语音聊天服务器,该服务器将在我的Windows虚拟课程电子学习应用程序中使用,该服务器使用Github documentation。
到目前为止,我一直在使用OPUS压缩声音,并且已经测试了各种选项:
目前,我正在将接收到的udp数据报发送给所有其他客户端(稍后,我将进行服务器端混合)。
我当前的UDP语音服务器存在的问题是,即使在同一台PC上也存在滞后:例如,一台服务器和四个客户端连接,其中两个具有开放式麦克风。
通过这种设置,我会听到可听见的延迟:
void VoiceServer(int port)
{
XSOCKET Y = make_shared<XSOCKET>(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (!Y->Bind(port))
return;
auto VoiceServer2 = [&]()
{
OPUSBUFF o;
char d[200] = { 0 };
map<int, vector<char>> udps;
for (;;)
{
// get datagram
int sle = sizeof(sockaddr_in6);
int r = recvfrom(*Y, o.d, 4000, 0, (sockaddr*)d, &sle);
if (r <= 0)
break;
// a MESSAGE is a header and opus data follows
MESSAGE* m = (MESSAGE*)o.d;
// have we received data from this client already?
// m->arb holds the RDP ID of the user
if (udps.find(m->arb) == udps.end())
{
vector<char>& uu = udps[m->arb];
uu.resize(sle);
memcpy(uu.data(), d, sle);
}
for (auto& att2 : aatts) // attendee list
{
long lxid = 0;
att2->get_Id(&lxid);
#ifndef _DEBUG
if (lxid == m->arb) // if same
continue;
#endif
const vector<char>& uud = udps[lxid];
sendto(*Y, o.d + sizeof(MESSAGE), r - sizeof(MESSAGE), 0, (sockaddr*)uud.data(), uud.size());
}
}
};
// 10 threads receiving
for (int i = 0; i < 9; i++)
{
std::thread t(VoiceServer2);
t.detach();
}
VoiceServer2();
}
每个客户端运行一个VoiceServer线程:
void VoiceServer()
{
char b[4000] = { 0 };
vector<char> d2;
for (;;)
{
int r = recvfrom(Socket, b, 4000, 0, 0,0);
if (r <= 0)
break;
d2.resize(r);
memcpy(d2.data(), b, r);
if (audioin && wout)
audioin->push(d2); // this pushes the buffer to a waveOut writing class
SetEvent(hPlayEvent);
}
}
这是因为我在同一台机器上进行测试吗?但是有了TeamSpeak客户,我过去就已经设置了,没有任何滞后。
感谢您的意见。
答案 0 :(得分:0)
SendTo():
对于面向消息的套接字,必须注意不要超过 可以获取的基础子网的最大数据包大小 通过使用
getsockopt
来检索套接字选项的值SO_MAX_MSG_SIZE
。如果数据太长而无法自动通过 基础协议,则返回错误WSAEMSGSIZE且没有数据 被传输。
典型的IPv4标头为20个字节,而UDP标头为8个字节。 UDP数据包最大大小的理论限制(在Windows上)为65507字节(由以下公式确定:0xffff-20-8 = 65507)。实际上是发送这么大数据包的最佳方法吗? 如果我们将数据包大小设置得太大,则网络协议的底部会在IP层拆分数据包。这会占用大量网络带宽,导致延迟。
MTU(最大传输单位)实际上与链路层协议有关。由于以太网传输的电气限制,EthernetII帧DMAC + SMAC + Type + Data + CRC的结构每个以太网帧的最小大小为64字节,并且最大大小不能超过1518字节。对于小于或大于此限制的以太网帧,我们可以将其视为错误。由于以太网EthernetII的最大数据帧为1518字节,除了帧头14Bytes和帧尾CRC校验部分4Bytes外,数据域中仅剩下1500个字节。那是MTU。在MTU为1500字节的情况下,如果希望IP层不拆分数据包,则UDP数据包的最大大小应为1500字节-IP报头(20字节)-UDP报头(8字节)= 1472字节。但是,由于Internet上的标准MTU值为576字节,因此建议在Internet上编程UDP时,应将sendto / recvfrom中的UDP数据长度控制在(576-8-20)548字节内。
您需要减少发送/接收的字节数,然后控制次数。