Люди, помогите пожалуйста решить проблему! Необходимо создать приложение, которое вещает речь по сети. С одной стороны человек говорит что-нибудь в микрофон, а с другой принимается и воспроизводится! Я организовал передачу речи, запихивание её в буфер и приём в буфер на другой стороне, но при воспроизведении речи слышны очень сильные щелчки и абсолютно не слышно самой речи - слышно только допустим постукивание по микрофону!В чём может быть проблема?
Код | //подключение необходимых библиотек #include <vcl.h> #include <MMSystem.h> #include <winsock2.h>
//включение информации из файла #include "voi.h"
#pragma hdrstop #pragma package(smart_init) #pragma resource "*.dfm"
TForm1 *Form1; //--------------------------------------------------------------------------- //необходимые переменные и константы const int SIZE_OF_VOICE=128; //размер области аудиоданных пакета
//параметры буфера для принятых пакетов int fst; //указатель на первый элемент буфера int lst; //указатель на следующий за последним элемент буфера const int SIZE_OF_BUF=7; //максимальная длина буфера в пакетах char QUEUE[SIZE_OF_BUF][SIZE_OF_VOICE]; //буфер
//буфер для воспроизведения char PlayBuf[SIZE_OF_VOICE];
bool EnableReceive=false; //индикатор разрешения приёма трансляции bool StreamOpen=false; //индикатор создания потока bool Timer2Enable=false; //инликатор запуска таймера на воспроизведение char WaveBuf[SIZE_OF_VOICE]; //буфер для считанных из файла данных HANDLE Soc_id; //дескриптор потока DWORD S_id; //идентификатор потока
//структура, описывающая буферы для записи и проигрывания звука WAVEHDR pwhPlay, pwhRec; HWAVEOUT hwo; //идентификатор устройства воспроизведения HWAVEIN phwi; //идентификатор устройства записи MMRESULT mres; //переменная для хранения результата выполнения функции
//структуры с описанием формата звуковых данных WAVEFORMATEX CurrentFormatFile;
//функция записи принятых аудиоданных в циклический буфер void In(char* SoundBuff); //--------------------------------------------------------------------------- //структура пакета struct Voice { char Name[10]; //имя отправителя int Number; //номер кадра char VoiceData[SIZE_OF_VOICE]; //аудиоданные }; //--------------------------------------------------------------------------- //функция записи принятых аудиоданных в циклический буфер void In(char* Buf) { //запись в буфер memcpy(QUEUE[lst],Buf,SIZE_OF_VOICE); lst=(lst+1)%SIZE_OF_BUF;
//разрешить срабатывание таймера на воспроизведение принятых данных //если он еще не запущен if (Timer2Enable==false) { Form1->Timer2->Enabled=true; Timer2Enable=true; }; } //--------------------------------------------------------------------------- //описание класса TSoc class TSoc { public: int i, j; //число отправленных/принятых пакетов int prevNumber; //номер предыдущего принятого пакета SOCKET s; //идентификатор сокета SOCKADDR_IN to; //структура с описанием адреса получателя SOCKADDR_IN from; //структура с описанием адреса отправителя char RecvBuffer[SIZE_OF_VOICE+14]; //буфер для принятого пакета Voice sVoice; //объект класса Sound
TSoc(); //конструктор класса bool Create(); //создание и инициализация сокета bool Receive(); //приём данных из сети void Send(char* SendVoiceBuf); //отправка данных }; //--------------------------------------------------------------------------- //конструктор класса TSoc TSoc::TSoc() { i=1; //число приняных пакетов j=1; //число переданных пакетов prevNumber=0; //номер предыдущего принятого пакета } //--------------------------------------------------------------------------- //создание сокета bool TSoc::Create() { //инициализация сокета WSADATA wsadata; WORD wVersionRequested; wVersionRequested = MAKEWORD( 2, 0 ); if (WSAStartup(wVersionRequested,&wsadata)==SOCKET_ERROR) { MessageBox(0,"Error: WSAStart",0,MB_OK); return false; };
//инициализация сокета и присвоение идентификатора s=socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP); if(s==INVALID_SOCKET) { MessageBox(0,"Error: Can't create socket",0,MB_OK); return false; };
//создание структуры адреса откуда будут принимаются пакеты from.sin_addr.S_un.S_addr=ADDR_ANY; from.sin_family=PF_INET; from.sin_port=5000;
//подключение сокета к коммуникационной среде int errSer=bind(s,(LPSOCKADDR)&from,sizeof(from)); if(errSer!=0) { MessageBox(0,"Error: Bind",0,MB_OK); closesocket(s); //закрытие сокета return false; };
return true; } //--------------------------------------------------------------------------- //передача звука по сети void TSoc::Send(char* SendVoiceBuf) { //заполнение заголовка пакета //имя отправителя берётся из поля От кого memcpy(sVoice.Name,Form1->From->Text.c_str(),10); //номер пакета sVoice.Number=j;
//заполнение поля данных memcpy(sVoice.VoiceData,SendVoiceBuf,SIZE_OF_VOICE);
//формирование структуры с IP-адресом отправки to.sin_family=PF_INET; to.sin_addr.S_un.S_addr=inet_addr(Form1->To->Text.c_str()); to.sin_port=5000;
//отправка пакета int err=sendto(s,(char*)(&sVoice),sizeof(Voice),0,(struct sockaddr*)&to,sizeof(to)); if (err==SOCKET_ERROR) MessageBox(0,"Error: Send sound",0,MB_OK); //число переданных пакетов else { Form1->lSend->Caption="Послано пакетов: "+IntToStr(j); j++; }; } //--------------------------------------------------------------------------- //приём данных из сети bool TSoc::Receive() { //определение наличия пришедших данных unsigned long lSize; ioctlsocket(s,FIONREAD,&lSize); if (lSize==0) return false;
//приём данных int cadr=sizeof(from); recvfrom(s,RecvBuffer,SIZE_OF_VOICE,0,(struct sockaddr*)&from,&cadr);
//указатель на буфер с принятыми данными Voice* pointVoice; pointVoice=(Voice*) RecvBuffer;
//анализ номера пакета //если нумерация нарушается, то пакет не воспроизводится if (pointVoice->Number>prevNumber) { //вывод числа принятых пакетов и имени отправителя AnsiString st=pointVoice->Name; Form1->lReceive->Caption="От "+st+" принято пакетов: "+IntToStr(i); i++;
//отправка данных в буфер для накопления In(pointVoice->VoiceData); }; return true; }
TSoc Soc; //объект класса TSoc //--------------------------------------------------------------------------- //функция потока для контроля данных пришедших на сокет DWORD WINAPI ThreadSoc(LPVOID) { while(true) { //индикатор разрешения приёма трансляции if (EnableReceive) { Soc.Receive(); //вызов функции обработки принятых данных }; }; } //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { //вызов функции создания сокета if (!Soc.Create()) return; else {
//инициализация формата звукового файла CurrentFormatFile.wFormatTag=WAVE_FORMAT_PCM; CurrentFormatFile.nChannels=1; CurrentFormatFile.nSamplesPerSec=8000; CurrentFormatFile.nAvgBytesPerSec=8000; CurrentFormatFile.nBlockAlign=1; CurrentFormatFile.wBitsPerSample=8; CurrentFormatFile.cbSize=0;
//инициализация устройств для записи и воспроизведения UINT uDeviceID=WAVE_MAPPER;
//открытие устройства вывода звука для воспроизведения mres=waveOutOpen(&hwo,uDeviceID,&CurrentFormatFile,0,0,0); if (mres!=0) MessageBox(0,"Error: waveOutOpen",0,MB_OK); else btReceive->Enabled=true; //активировать кнопку "Принимать"
//открытие устройства ввода звука для записи mres=waveInOpen(&phwi,uDeviceID,&CurrentFormatFile,0,0,0); if (mres!=0) MessageBox(0,"Error: waveInOpen",0,MB_OK); else { btSend->Enabled=true; //активировать кнопку "Начать передачу" From->Enabled=true; //активировать поле "От кого" To->Enabled=true; //активировать поле "Кому" }; }; } //--------------------------------------------------------------------------- //кнопка Начать передачу void __fastcall TForm1::btSendClick(TObject *Sender) { Timer1->Enabled=true; //разрешить срабатывание таймера на отправку пакетов
btSend->Enabled=false; //деактивировать кнопку "Начать передачу" btStopSend->Enabled=true; //активировать кнопку "Остановить" From->Enabled=false; //блокировка поля "От кого" To->Enabled=false; //блокировка поля "Кому" } //--------------------------------------------------------------------------- //срабатывание таймера на отправку пакетов void __fastcall TForm1::Timer1Timer(TObject *Sender) { //подготовка буфера для записи pwhRec.lpData=WaveBuf; pwhRec.dwBufferLength=SIZE_OF_VOICE; pwhRec.dwFlags=0;
//подготовка буфера для ввода аудиоданных mres=waveInPrepareHeader(phwi,&pwhRec, sizeof(pwhRec)); if (mres!=0) { MessageBox(0,"Error: waveInPrepareHeader",0,MB_OK); return; }; //отправка буфера заданному устройству записи mres=waveInAddBuffer(phwi,&pwhRec,sizeof(pwhRec)); if (mres!=0) { MessageBox(0,"Error: waveInAddBuffer",0,MB_OK); return; }; //ввод аудиоданных через заданное устройство ввода mres=waveInStart(phwi); if (mres!=0) { MessageBox(0,"Error: waveInStart",0,MB_OK); return; };
//вызов функции отправки пакета Soc.Send(WaveBuf); } //--------------------------------------------------------------------------- //нажатие кнопки Остановить void __fastcall TForm1::btStopSendClick(TObject *Sender) { Timer1->Enabled=false; //запретить срабатывание таймера на отправку пакетов
btSend->Enabled=true; //активировать кнопку "Начать передачу" btStopSend->Enabled=false; //деактивировать кнопку "Остановить" From->Enabled=true; //разблокировка поля "От кого" To->Enabled=true; //разблокировка поля "Кому" } //--------------------------------------------------------------------------- //нажатие кнопки Принимать void __fastcall TForm1::btReceiveClick(TObject *Sender) { EnableReceive=true; //индикатор разрешения проигрывания звука if (StreamOpen==false) //индикатор создания потока { //создание потока Soc_id=CreateThread(0,0,ThreadSoc,0,0,&S_id); StreamOpen=true; //индикатор создания потока }; btReceive->Enabled=false; //деактивировать кнопку "Принимать" btStopReceive->Enabled=true; //активировать кнопку "Принимать" } //--------------------------------------------------------------------------- //срабатывание таймера на воспроизведение принятых данных void __fastcall TForm1::Timer2Timer(TObject *Sender) { //взять блок данных из начала очереди memcpy(PlayBuf,QUEUE[(fst+5)%SIZE_OF_BUF],SIZE_OF_VOICE); fst=(fst+1)%SIZE_OF_BUF;
//подготовка буфера для воспроизведения pwhPlay.lpData=PlayBuf; pwhPlay.dwBufferLength=SIZE_OF_VOICE; pwhPlay.dwFlags=0;
|
|