Реализация teampeak как голосовой сервер - PullRequest
0 голосов
/ 25 февраля 2019

Я внедряю сервер голосового чата, который будет использоваться в моем приложении электронного обучения Virtual Class для Windows, в котором используется Remote Desktop API .

Пока что яМы сжимали голос с помощью OPUS, и я тестировал различные варианты:

  1. Чтобы передать голос через RDP Виртуальный канал .Это работает, но создает большое отставание, несмотря на создание канала с помощью CHANNEL_PRIORITY_HI.
  2. Для использования собственного голосового сервера TCP (или UDP).Для этой опции мне было интересно, какой метод лучше всего реализовать.

В настоящее время я отправляю полученную дейтаграмму udp всем остальным клиентам (позже я сделаю микширование на стороне сервера)..

Проблема с моим текущим голосовым сервером UDP заключается в том, что он имеет задержку даже на одном и том же компьютере: один сервер и четыре подключенных клиента, два из которых имеют, например, открытые микрофоны.

При такой настройке у меня слышится задержка звука:

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, который я настраивал в прошлом, нет никакой задержки.

Спасибо за ваше мнение.

1 Ответ

0 голосов
/ 28 февраля 2019

SendTo ():

Для сокетов, ориентированных на сообщения, необходимо соблюдать осторожность, чтобы не превысить максимальный размер пакета базовых подсетей, который можно получить с помощьюgetsockopt для получения значения опции сокета SO_MAX_MSG_SIZE.Если данные слишком длинные для атомарной передачи через базовый протокол, возвращается ошибка WSAEMSGSIZE и данные не передаются.

Типичный заголовок IPv4 составляет 20 байтов, а заголовок UDP - 8 байтов.Теоретический предел (в Windows) для максимального размера пакета UDP составляет 65507 байт (определяется по следующей формуле: 0xffff - 20 - 8 = 65507).Это действительно лучший способ отправить такой большой пакет? Если мы установим слишком большой размер пакета, нижняя часть сетевого протокола будет разбивать пакеты на уровне IP.Это занимает большую полосу пропускания сети, вызывая задержку.

MTU (максимальная единица передачи) фактически относится к протоколу канального уровня.Структура кадра EthernetII DMAC + SMAC + Type + Data + CRC имеет минимальный размер 64 байта на кадр Ethernet из-за электрических ограничений передачи Ethernet, а максимальный размер не может превышать 1518 байтов.Для кадров Ethernet меньше или больше этого ограничения мы можем расценивать это как ошибку.Так как самый большой кадр данных Ethernet EthernetII составляет 1518 байт, за исключением заголовка кадра 14Bytes и части 4Byte проверки CRC хвоста кадра, в области данных осталось только 1500 байтов.Это MTU.

В случае, если MTU составляет 1500 байтов, максимальный размер пакета UDP должен быть 1500 байтов - заголовок IP (20 байтов) - заголовок UDP (8 байтов) = 1472 байта, если вы хотите IPслой, чтобы не разбивать пакеты.Однако, поскольку стандартное значение MTU в Интернете составляет 576 байтов, рекомендуется, чтобы длина данных UDP контролировалась в пределах (576-8-20) 548 байтов в sendto / recvfrom при программировании UDP в Интернете.

Вам необходимо уменьшить количество байтов отправки / получения, а затем контролировать количество раз.

...