Я начну с того, что устал от поисков по этому поводу и, наконец, решил задать этот вопрос
Хорошо, сначала немного фона
Раньше я работал в единстве, мне приходилось делать видеозвонки и проводил на нем большую часть летних каникул. Простые вещи были просты, такие как веб-камера и класс микрофонов, поэтому не стоит беспокоиться, но поскольку многопоточность не является сильной стороной единства. , баги начали появляться как проблемы с 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);
}