Голосовой чат в C#
В статье описывается пример элементарного голосового чата. Звук берётся с микрофона при помощи DirectSound и передаётся UDP-пакетами. Перед тем как передать, данные сжимаются войскодером G711. Протокол общения между приёмником и передатчиком выглядит следующим образом:
| Приглашение |
| --------------------------------> |
| OK |
| <-------------------------------- |
| |
| --------------------------------> |
| поток Аудио |
| <-------------------------------- |
| Досвидание |
| --------------------------------> |
A B
Структура, содержаща управляющие команды:
enum Command
{
Invite, //Сделать вызов.
Bye, //Закончить вызов.
Busy, //Пользователь занят.
OK, //Ответ на приглашение. Значение OK указывает,
//что вызов принят.
Null, //пустой пакет.
}
Когда пользователь делает вызов другого собеседника, приложение посылает команду Invite и ждёт ответа OK. Как только получен ответ OK, начинается приём/передача аудио захваченного с микрофона. Если противоположная сторона отвергает вызов, то отправляется ответ Busy. Для прекращения чата достаточно отправить сообщение Bye. Данный пример приложения ассинхронно принимает/передаёт команды на 1450 порту и синхронно принимает/передаёт звуковые данные 1550 порту. Другими словами, приложение ожидает данных на двух портах: один для управляющих сообщений, а другой для аудио-потока. При запуске, автоматически запускается прослушивание командных сообщений на 1450 порту:
//использование UDP сокетов
clientSocket = new Socket(AddressFamily.InterNetwork,
SocketType.Dgram,
ProtocolType.Udp);
EndPoint ourEP = new IPEndPoint(IPAddress.Any, 1450);
//Ассинхронное прослушивание управляющих сообщений (Invite, Bye и т.д.) на 1450 порту
clientSocket.Bind(ourEP);
//Получение данных разрешается с любого IP-адреса.
EndPoint remoteEP = (EndPoint)(new IPEndPoint(IPAddress.Any, 0));
byteData = new byte[1024];
//Ассинхронный приём данных.
clientSocket.BeginReceiveFrom(byteData,
0, byteData.Length,
SocketFlags.None,
ref remoteEP,
new AsyncCallback(OnReceive),
null);
После получения сообщения, происходит его обработка. За это отвечает обработчик OnReceive (см. исходник). Для приёма/передачи звука с микрофона запускаются два потока, чтобы можно было синхронно посылать/принимать данные и при этом не блокировать пользовательский интерфейс:
private void InitializeCall()
{
try
{
//Запускаем прослушивание на 1550 порту.
udpClient = new UdpClient(1550);
Thread senderThread = new Thread(new ThreadStart(Send));
Thread receiverThread = new Thread(new ThreadStart(Receive));
bIsCallActive = true;
//Запускаем принимающий и передающий потоки.
receiverThread.Start();
senderThread.Start();
btnCall.Enabled = false;
btnEndCall.Enabled = true;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message,
"VoiceChat-InitializeCall ()", MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
}
Методы Send и Receive можно посмотреть в прилагаемом ниже исходнике; разобраться с ними не составит труда.
Предыдущая часть темы: Голосовой чат в C#