Как сделать видео конференцию / звонок C # TCP - PullRequest
0 голосов
/ 08 сентября 2018

Я начну с того, что устал от поисков по этому поводу и, наконец, решил задать этот вопрос
Хорошо, сначала немного фона
Раньше я работал в единстве, мне приходилось делать видеозвонки и проводил на нем большую часть летних каникул. Простые вещи были просты, такие как веб-камера и класс микрофонов, поэтому не стоит беспокоиться, но поскольку многопоточность не является сильной стороной единства. , баги начали появляться как проблемы с DLL и зависали при работе с Texture2D (2D-изображение), и вещи в интерфейсе утомляли меня так, я решил повесить трубку и подумал о переходе на xamarin, прежде чем я хочу сделать приложение на winforms, потому что в конце концов приложение сервера будет на окнах, а клиенты на мобильных телефонах. Это не P2P.

Что я уже сделал
C # не имеет класса веб-камеры, я так думаю,
В единстве

  • Используйте Opus.net (github) для кодирования аудио из NAudio и отправки по сети без буфера (максимальный размер байта ограничен 350), без понимания части, поэтому бесполезно, если я не смогу учиться, в любом случае, если кто-то решает объяснить потом комментарий.
  • Получайте изображение с веб-камеры каждые 10 секунд или около того, а затем без кодирования получите JPG-файл из класса Texture2D и отправьте его на сервер.
  • Один из лучших способов отправки и получения (опубликуйте код ниже)
  • Аудио перестало буферизоваться, и кадры веб-камеры были в порядке.
  • Даже несмотря на то, что многопоточность была не лучшим набором, я почти идеально использовал многопоточность при получении и отправке байтов (за исключением того, что сервер запускал новые потоки для каждого клиента).

Проблемы / Что я хочу

  • Добивайтесь лучших результатов с помощью C # winforms, теперь я могу более свободно использовать DLL.
  • Сервер не был лучшим в работе с клиентами ( не является приоритетом в этом вопросе ).
  • Нужен кто-то, чтобы объяснить мне ту часть, которую я не понимаю в аудио.
  • Как получить веб-камеру и эффективный способ передачи данных на другой конец провода, поскольку Размер изображений был слишком большим, например, более 1500 или около того и до 30000

TLDR; Как получить веб-камеру и что делать точно так же, как кодирование изображений и отправка? библиотека? Большинство кодировщиков, которые я нашел, были для C ++, поэтому, особенно бесполезно для отправки изображения с веб-камеры.

КОД Часть, которую я не понимаю (SendToServer (); метод мой):

/// <summary>
/// Formula : Sample Rate / 1000 * FrameSize
/// </summary>
int _segmentFrames;
byte[] soundBuffer = new byte[e.BytesRecorded + _notEncodedBuffer.Length];
    for (int i = 0; i < _notEncodedBuffer.Length; i++)
        soundBuffer[i] = _notEncodedBuffer[i];
    for (int i = 0; i < e.BytesRecorded; i++)
        soundBuffer[i + _notEncodedBuffer.Length] = e.Buffer[i];

    int byteCap = _bytesPerSegment;
    int segmentCount = (int)Math.Floor((decimal)soundBuffer.Length / byteCap);
    int segmentsEnd = segmentCount * byteCap;
    int notEncodedCount = soundBuffer.Length - segmentsEnd;
    _notEncodedBuffer = new byte[notEncodedCount];
    for (int i = 0; i < notEncodedCount; i++)
    {
        _notEncodedBuffer[i] = soundBuffer[segmentsEnd + i];
    }

    for (int i = 0; i < segmentCount; i++)
    {
        byte[] segment = new byte[byteCap];
        for (int j = 0; j < segment.Length; j++)
            segment[j] = soundBuffer[(i * byteCap) + j];
        int len;
        byte[] buff = _encoder.Encode(segment, segment.Length, out len);
        _bytesSent += (ulong)len;

        SendToServer(buff, len);
    }

Отправка / получение довольно много одинаково для обоих, если в единстве, то внутри метода обновления. Если в получающем потоке, то через некоторое время истинный цикл и return s заменяются на continue в основном .

//Receive
//if signaled to stop then stop
    if (_resetEvent.WaitOne(1)) return;
    //if not connected to the server then wait
    if (!_socketReady) return;

    //if no data is available to receive then wait
    if (!_stream.DataAvailable) return;

    //get message type
    byte[] messageType = new byte[sizeof(int)];
    int recv = _stream.Read(messageType, 0, messageType.Length);
    Message type = MessageTypes.FindType(messageType);

    //if we do not expect more data then our work here is done
    if (!type.HasCustomData) { ReceivedDataReplyHandler(type); return; }

    //Get the length of the message we expect
    byte[] lenBuff = new byte[sizeof(int)];
    recv = _stream.Read(lenBuff, 0, lenBuff.Length);

    //Get the length in integer
    int messagelen = BitConverter.ToInt32(lenBuff, 0);

    //Gte the message we expected
    byte[] messageBuff = new byte[messagelen];
    recv = _stream.Read(messageBuff, 0, messageBuff.Length);

    //bind the received data
    type.MessageData = messageBuff;

    //handle with the received Data
    ReceivedDataReplyHandler(type);

public void Send(MessageNames messageName, byte[] data)
{
    Message type = MessageTypes.FindType(messageName);

    if (!type.HasCustomData) { print("This type do not have custom data plz use the other method!"); }

    byte[] message = data;
    byte[] length = BitConverter.GetBytes(message.Length);
    byte[] buffer = new byte[sizeof(int) + message.Length + sizeof(int)];

    //Copy the length of the data
    Array.Copy(BitConverter.GetBytes(type.Value), 0, buffer, 0, sizeof(int));

    //Copy the length of the data
    Array.Copy(length, 0, buffer, sizeof(int), sizeof(int));

    //Copy the data
    Array.Copy(message, 0, buffer, sizeof(int) + sizeof(int), message.Length);

    //Send the data to the server
    _stream.Write(buffer, 0, buffer.Length);
}

Message Класс

public bool HasCustomData { get; private set; }
public int Value { get; private set; }
public MessageNames Name { get; private set; }

//Only for Client (When receiving message from Server), gets the actual bytes data
public byte[] MessageData { get; set; }

// ONLY FOR SERVER (When receiving message from Client), gets the client from whome the message is received
public ServerClient SentFromClient { get; set; }

public Message(bool HasCustomData, int Value, MessageNames Name)
{
    this.HasCustomData = HasCustomData;
    this.Value = Value;
    this.Name = Name;
}

MessageTypes Структура (могла бы быть и лучше):

private static List<Message> TypesofMessages = new List<Message>()
{
    new Message(true, 1,MessageNames.Microphone),
    new Message(true, 2,MessageNames.Webcam),
    new Message(true, 3,MessageNames.Connection),
    new Message(true, 4,MessageNames.Message),
    new Message(true, 5,MessageNames.PlayerAddition),
    new Message(false, 6,MessageNames.HangUp),
    new Message(false, 7,MessageNames.Confirm),
    new Message(true, 8,MessageNames.VideoCall),
    new Message(true, 9,MessageNames.VoiceCall)
};

public static bool Compare(Message x, Message y)
{
    return x.Value == y.Value && x.Name == y.Name;
}

public static Message FindType(byte[] value)
{
    return TypesofMessages.First(m => m.Value == BitConverter.ToInt32(value, 0));
}

public static Message FindType(MessageNames name)
{
    return TypesofMessages.First(m => m.Name == name);
}
...