- •Курсовая Работа
- •Разработка прикладного протокола передачи и приём звукового файла
- •Цель курсового проекта.
- •Задание на курсовое проектирование
- •Решение
- •Структура пакета
- •Буфер и таймеры
- •Алгоритм работы программы
- •Описание программы
- •Инициализация
- •Посылка одного блока данных
- •Функция приема блока
- •Функция воспроизведения блока
Функция приема блока
Данная функция начинает свою работу только если для приема есть нужное количество данных.
unsigned long lSize;
ioctlsocket(s,FIONREAD,&lSize);
if (lSize==0) return;
Далее происходит прием сообщение, выделение его составляющих, проверка его номера для отброса неактуальных сообщений, увеличение счетчика сообщений, вывод символьного имени и отправка аудиоданных в буфер для последующего воспроизведения.
//приём данных
int cadr=sizeof(from);
recvfrom(s,RecvBuffer,sizeof(Sound),0,(struct sockaddr*)&from,&cadr);
//указатель на буфер с принятыми данными
Sound* pointSound;
pointSound=(Sound*) RecvBuffer;
//анализ номера пакета
//если нумерация нарушается, то пакет не воспроизводится
if (pointSound->Number>prevNumber)
{
//вывод числа принятых пакетов и имени отправителя
/*AnsiString st=pointSound->Name;
Form1->lReceive->Caption="От "+st+" принято пакетов: "+IntToStr(i);
i++;*/
String^ a= gcnew String(pointSound->Name,0,strlen(pointSound->Name));
textBox_file_name->Text=a;
numericUpDown_reseive->Value++;
//отправка данных в буфер для накопления
In(pointSound->SoundData);
};
return;
Функция воспроизведения блока
В данной функции происходит сначала чтение семпла из буфера.
//взять блок данных из начала очереди
memcpy(PlayBuf,QUEUE[(fst+1)%SIZE_OF_BUF],SIZE_OF_SOUND);
fst=(fst+1)%SIZE_OF_BUF;
Далее его подготовка к воспроизведению, т.е. создание структуры данных понятной аудиоустройству.
//подготовка буфера для воспроизведения
pwhPlay.lpData=PlayBuf;
pwhPlay.dwBufferLength=SIZE_OF_SOUND;
pwhPlay.dwFlags=0;
//подготовка блока аудиоданных для воспроизведения
mres=waveOutPrepareHeader(hwo,&pwhPlay,sizeof(pwhPlay));
if (mres!=0) textBox_error->Text=L"Error: OutPrepareHeader";
И Далее отправка блока на аудиоустройство
//отправка блока аудиоданных заданному устройству вывода
mres=waveOutWrite(hwo,&pwhPlay,sizeof(pwhPlay));
if (mres!=0) textBox_error->Text=L"Error: waveOutWrite";
Подключение необходимых библиотек
Для работы программы необходимо подключить 2 основные библиотеки – это библиотека работы с сокетами и библиотека работы со звуком.
Помимо подключения заголовочных файлов
#include <Winsock2.h>
#include <MMSystem.h>
Приложение
Блок-схемы
Инициализация сокета
Инициализация звука
Прием одного пакета
Передача одного пакета
SDL-диаграммы
Текст программы
// kur.cpp: главный файл проекта.
#include "stdafx.h"
#include "Form1.h"
using namespace kur;
[STAThreadAttribute]
int main(array<System::String ^> ^args)
{
// Включение визуальных эффектов Windows XP до создания каких-либо элементов управления
Application::EnableVisualStyles();
Application::SetCompatibleTextRenderingDefault(false);
// Создание главного окна и его запуск
Application::Run(gcnew Form1());
return 0;
}
// Form1.h
#pragma once
//подключение необходимых библиотек
#include <Winsock2.h>
#include <stdio.h>
#include <string.h>
#include <MMSystem.h>
const int SIZE_OF_SOUND=192*50;
//структура с описанием формата пакета
struct Sound
{
char Name[10]; //имя отправителя
int Number; //номер кадра
char SoundData[SIZE_OF_SOUND]; //аудиоданные
};
//---------------------------------------------------------------------------
//необходимые переменные и константы
int num = 0;
//размер области аудиоданных пакета
//параметры циклического буфера для принятых аудиоданных
int fst; //указатель на первый элемент буфера
int lst; //указатель на следующий за последним элемент буфера
const int SIZE_OF_BUF=14; //максимальное число элементов буфера
char QUEUE[SIZE_OF_BUF][SIZE_OF_SOUND]; //буфер
//буфер для воспроизведения
char PlayBuf[SIZE_OF_SOUND];
bool EnableReceive=false; //индикатор разрешения приёма трансляции
bool StreamOpen=false; //индикатор создания потока
bool Timer2Enable=false; //индикатор запуска таймера на воспроизведение
char WaveBuf[SIZE_OF_SOUND]; //буфер для считанных из файла данных
HANDLE Soc_id; //дескриптор потока
DWORD S_id; //идентификатор потока
WAVEHDR pwhPlay; //структура, описывающая буфер на проигрывание звука
HWAVEOUT hwo; //идентификатор аудиоустройства
WAVEFORMATEX CurrentFormatFile; //структура с описанием формата звуковых данных
MMRESULT mres; //переменная для хранения результата выполнения функции
HMMIO hmmio; //идентификатор файла
//из класса Tsoc
int i, j; //число отправленных/принятых пакетов
int prevNumber; //номер предыдущего принятого пакета
SOCKET s; //идентификатор сокета
SOCKADDR_IN to; //структура с описанием адреса получателя
SOCKADDR_IN from; //структура с описанием адреса отправителя
char RecvBuffer[SIZE_OF_SOUND+14]; //буфер для принятого пакета
Sound sSound; //объект класса Sound
//TSoc(); //конструктор
bool Create(); //функция создания и настройки сокета
void Receive(); //функция приёма пакетов
void Send(char* SendVoiceBuf); //функция отправки пакетов
//---
//функция записи принятых аудиоданных в циклический буфер
void In(char* SoundBuff);
//---------------------------------------------------------------------------
namespace kur {
using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
public ref class Form1 : public System::Windows::Forms::Form
{
public:
Form1(void)
{
InitializeComponent();
//
//TODO: добавьте код конструктора
//
}
protected:
/// <summary>
/// Освободить все используемые ресурсы.
/// </summary>
~Form1()
{
if (components)
{
delete components;
}
}
private: System::Windows::Forms::Button^ button_start_send;
private: System::Windows::Forms::Button^ button_end_send;
private: System::Windows::Forms::Button^ button_start_reseive;
private: System::Windows::Forms::Button^ button_end__reseive;
private: System::Windows::Forms::TextBox^ textBox_error;
private: System::Windows::Forms::Timer^ timer_send;
private: System::Windows::Forms::Timer^ timer_reseive;
private: System::Windows::Forms::Timer^ timer_play;
private: System::Windows::Forms::NumericUpDown^ numericUpDown_send;
private: System::Windows::Forms::NumericUpDown^ numericUpDown_reseive;
private: System::Windows::Forms::NumericUpDown^ numericUpDown_timer;
private: System::Windows::Forms::TextBox^ textBox_file_name;
private: System::Windows::Forms::TextBox^ textBox_IP;
private: System::ComponentModel::IContainer^ components;
protected:
protected:
protected:
private:
/// <summary>
/// Требуется переменная конструктора.
/// </summary>
#pragma region Windows Form Designer generated code
/// <summary>
/// Обязательный метод для поддержки конструктора - не изменяйте
/// содержимое данного метода при помощи редактора кода.
/// </summary>
void InitializeComponent(void)
{
this->components = (gcnew System::ComponentModel::Container());
this->button_start_send = (gcnew System::Windows::Forms::Button());
this->button_end_send = (gcnew System::Windows::Forms::Button());
this->button_start_reseive = (gcnew System::Windows::Forms::Button());
this->button_end__reseive = (gcnew System::Windows::Forms::Button());
this->textBox_error = (gcnew System::Windows::Forms::TextBox());
this->timer_send = (gcnew System::Windows::Forms::Timer(this->components));
this->timer_reseive = (gcnew System::Windows::Forms::Timer(this->components));
this->timer_play = (gcnew System::Windows::Forms::Timer(this->components));
this->numericUpDown_send = (gcnew System::Windows::Forms::NumericUpDown());
this->numericUpDown_reseive = (gcnew System::Windows::Forms::NumericUpDown());
this->numericUpDown_timer = (gcnew System::Windows::Forms::NumericUpDown());
this->textBox_file_name = (gcnew System::Windows::Forms::TextBox());
this->textBox_IP = (gcnew System::Windows::Forms::TextBox());
(cli::safe_cast<System::ComponentModel::ISupportInitialize^ >(this->numericUpDown_send))->BeginInit();
(cli::safe_cast<System::ComponentModel::ISupportInitialize^ >(this->numericUpDown_reseive))->BeginInit();
(cli::safe_cast<System::ComponentModel::ISupportInitialize^ >(this->numericUpDown_timer))->BeginInit();
this->SuspendLayout();
//
// button_start_send
//
this->button_start_send->Location = System::Drawing::Point(12, 179);
this->button_start_send->Name = L"button_start_send";
this->button_start_send->Size = System::Drawing::Size(128, 29);
this->button_start_send->TabIndex = 0;
this->button_start_send->Text = L"Начать отправку";
this->button_start_send->UseVisualStyleBackColor = true;
this->button_start_send->Click += gcnew System::EventHandler(this, &Form1::button1_Click);
//
// button_end_send
//
this->button_end_send->Location = System::Drawing::Point(12, 214);
this->button_end_send->Name = L"button_end_send";
this->button_end_send->Size = System::Drawing::Size(128, 29);
this->button_end_send->TabIndex = 1;
this->button_end_send->Text = L"Закончить отправку";
this->button_end_send->UseVisualStyleBackColor = true;
this->button_end_send->Click += gcnew System::EventHandler(this, &Form1::button_end_send_Click);
//
// button_start_reseive
//
this->button_start_reseive->Location = System::Drawing::Point(274, 179);
this->button_start_reseive->Name = L"button_start_reseive";
this->button_start_reseive->Size = System::Drawing::Size(128, 29);
this->button_start_reseive->TabIndex = 2;
this->button_start_reseive->Text = L"Начать прием";
this->button_start_reseive->UseVisualStyleBackColor = true;
this->button_start_reseive->Click += gcnew System::EventHandler(this, &Form1::button_start_reseive_Click);
//
// button_end__reseive
//
this->button_end__reseive->Location = System::Drawing::Point(274, 214);
this->button_end__reseive->Name = L"button_end__reseive";
this->button_end__reseive->Size = System::Drawing::Size(128, 29);
this->button_end__reseive->TabIndex = 3;
this->button_end__reseive->Text = L"Закончит прием";
this->button_end__reseive->UseVisualStyleBackColor = true;
this->button_end__reseive->Click += gcnew System::EventHandler(this, &Form1::button_end__reseive_Click);
//
// textBox_error
//
this->textBox_error->Location = System::Drawing::Point(12, 278);
this->textBox_error->Name = L"textBox_error";
this->textBox_error->Size = System::Drawing::Size(390, 20);
this->textBox_error->TabIndex = 4;
//
// timer_send
//
this->timer_send->Interval = 1270;
this->timer_send->Tick += gcnew System::EventHandler(this, &Form1::timer_send_Tick);
//
// timer_reseive
//
this->timer_reseive->Interval = 1270;
this->timer_reseive->Tick += gcnew System::EventHandler(this, &Form1::timer_reseive_Tick);
//
// timer_play
//
this->timer_play->Interval = 1270;
this->timer_play->Tick += gcnew System::EventHandler(this, &Form1::timer_play_Tick);
//
// numericUpDown_send
//
this->numericUpDown_send->Location = System::Drawing::Point(12, 140);
this->numericUpDown_send->Maximum = System::Decimal(gcnew cli::array< System::Int32 >(4) {10000, 0, 0, 0});
this->numericUpDown_send->Name = L"numericUpDown_send";
this->numericUpDown_send->Size = System::Drawing::Size(120, 20);
this->numericUpDown_send->TabIndex = 5;
//
// numericUpDown_reseive
//
this->numericUpDown_reseive->Location = System::Drawing::Point(282, 140);
this->numericUpDown_reseive->Maximum = System::Decimal(gcnew cli::array< System::Int32 >(4) {10000, 0, 0, 0});
this->numericUpDown_reseive->Name = L"numericUpDown_reseive";
this->numericUpDown_reseive->Size = System::Drawing::Size(120, 20);
this->numericUpDown_reseive->TabIndex = 6;
//
// numericUpDown_timer
//
this->numericUpDown_timer->Location = System::Drawing::Point(140, 12);
this->numericUpDown_timer->Maximum = System::Decimal(gcnew cli::array< System::Int32 >(4) {10000, 0, 0, 0});
this->numericUpDown_timer->Name = L"numericUpDown_timer";
this->numericUpDown_timer->Size = System::Drawing::Size(120, 20);
this->numericUpDown_timer->TabIndex = 7;
this->numericUpDown_timer->Value = System::Decimal(gcnew cli::array< System::Int32 >(4) {1270, 0, 0, 0});
this->numericUpDown_timer->ValueChanged += gcnew System::EventHandler(this, &Form1::numericUpDown_timer_ValueChanged);
//
// textBox_file_name
//
this->textBox_file_name->Location = System::Drawing::Point(198, 85);
this->textBox_file_name->Name = L"textBox_file_name";
this->textBox_file_name->Size = System::Drawing::Size(209, 20);
this->textBox_file_name->TabIndex = 8;
//
// textBox_IP
//
this->textBox_IP->Location = System::Drawing::Point(26, 76);
this->textBox_IP->Name = L"textBox_IP";
this->textBox_IP->Size = System::Drawing::Size(100, 20);
this->textBox_IP->TabIndex = 9;
this->textBox_IP->Text = L"127.0.0.1";
//
// Form1
//
this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
this->ClientSize = System::Drawing::Size(419, 310);
this->Controls->Add(this->textBox_IP);
this->Controls->Add(this->textBox_file_name);
this->Controls->Add(this->numericUpDown_timer);
this->Controls->Add(this->numericUpDown_reseive);
this->Controls->Add(this->numericUpDown_send);
this->Controls->Add(this->textBox_error);
this->Controls->Add(this->button_end__reseive);
this->Controls->Add(this->button_start_reseive);
this->Controls->Add(this->button_end_send);
this->Controls->Add(this->button_start_send);
this->Name = L"Form1";
this->Text = L"Form1";
this->Load += gcnew System::EventHandler(this, &Form1::Form1_Load);
(cli::safe_cast<System::ComponentModel::ISupportInitialize^ >(this->numericUpDown_send))->EndInit();
(cli::safe_cast<System::ComponentModel::ISupportInitialize^ >(this->numericUpDown_reseive))->EndInit();
(cli::safe_cast<System::ComponentModel::ISupportInitialize^ >(this->numericUpDown_timer))->EndInit();
this->ResumeLayout(false);
this->PerformLayout();
}
#pragma endregion
// мои функции
//функция записи принятых аудиоданных в циклический буфер
void In(char* Buf)
{
//запись в буфер
memcpy(QUEUE[lst],Buf,SIZE_OF_SOUND);
lst=(lst+1)%SIZE_OF_BUF;
//разрешить срабатывание таймера на воспроизведение принятых данных
//если он ещё не запущен
if (timer_play->Enabled==false)
{
//Form1->Timer2->Enabled=true;
timer_play->Enabled=true;
};
}
//---------------------------------------------------------------------------
//функция создания и настройки сокета
bool Create()
{
//инициализация сокета
WSADATA wsadata;
WORD wVersionRequested;
wVersionRequested = MAKEWORD(2,0);
if (WSAStartup(wVersionRequested,&wsadata)==SOCKET_ERROR)
{
// MessageBox(0,"Error: WSAStartup",0,MB_OK);
textBox_error->Text=L"Error: WSAStartup";
return false;
};
//создание сокета и присвоение идентификатора
s=socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(s==INVALID_SOCKET)
{
// MessageBox(0,"Error: Create socket",0,MB_OK);
textBox_error->Text=L"Error: Create socket";
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);
textBox_error->Text=L"Error: Bind";
closesocket(s); //закрытие сокета
return false;
};
return true;
}
//---------------------------------------------------------------------------
//функция формирования и передачи пакетов
void Send(char* SendVoiceBuf)
{
//заполнение заголовка пакета
//имя отправителя берётся из поля "От кого"
memcpy(sSound.Name,"telefon",10);
//номер пакета
sSound.Number=num++;
//заполнение поля данных
memcpy(sSound.SoundData,SendVoiceBuf,SIZE_OF_SOUND);
//формирование структуры с IP-адресом получателя
::to.sin_family=PF_INET;
//::to.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
String^ strinput2=textBox_IP->Text;
char c[20];
for(int j=0;j<strinput2->Length;j++)
c[j]=strinput2[j];
c[strinput2->Length]='\0';
to.sin_addr.S_un.S_addr=inet_addr(c);
::to.sin_port=5000;
//отправка пакета
int err=sendto(s,(char*)(&sSound),sizeof(Sound),0,(struct sockaddr*)&to,sizeof(to));
if (err==SOCKET_ERROR)
//MessageBox(0,"Error: Send sound",0,MB_OK);
textBox_error->Text=L"Error: Send sound";
//число переданных пакетов
else
{
//Form1->lSend->Caption="Послано пакетов: "+IntToStr(j);
//j++;
numericUpDown_send->Value++;
};
}
//---------------------------------------------------------------------------
//функция приёма пакетов
void Receive()
{
//определение наличия пришедших данных
unsigned long lSize;
ioctlsocket(s,FIONREAD,&lSize);
if (lSize==0) return;
//приём данных
int cadr=sizeof(from);
recvfrom(s,RecvBuffer,sizeof(Sound),0,(struct sockaddr*)&from,&cadr);
//указатель на буфер с принятыми данными
Sound* pointSound;
pointSound=(Sound*) RecvBuffer;
//анализ номера пакета
//если нумерация нарушается, то пакет не воспроизводится
if (pointSound->Number>prevNumber)
{
//вывод числа принятых пакетов и имени отправителя
/*AnsiString st=pointSound->Name;
Form1->lReceive->Caption="От "+st+" принято пакетов: "+IntToStr(i);
i++;*/
String^ a= gcnew String(pointSound->Name,0,strlen(pointSound->Name));
textBox_file_name->Text=a;
numericUpDown_reseive->Value++;
//отправка данных в буфер для накопления
In(pointSound->SoundData);
};
return;
}
//---------------------------------------------------------------------------
//конец функций
private: System::Void Form1_Load(System::Object^ sender, System::EventArgs^ e) {
//вызов функции создания и настройки сокета
Create();
//if (Create()) btSend->Enabled=true;
//else return;
//инициализация формата звуковых данных
CurrentFormatFile.wFormatTag=WAVE_FORMAT_PCM;
CurrentFormatFile.nChannels=1;
CurrentFormatFile.nSamplesPerSec=8000;
CurrentFormatFile.nAvgBytesPerSec=8000;
CurrentFormatFile.nBlockAlign=1;
CurrentFormatFile.wBitsPerSample=8;
//открытие устройства воспроизведения
UINT uDeviceID=WAVE_MAPPER;
mres=waveOutOpen(&hwo,uDeviceID,&CurrentFormatFile,0,0,0);
if (mres!=0)
//MessageBox(0,"Error: WaveOutOpen",0,MB_OK);
textBox_error->Text=L"Error: WaveOutOpen";
//else btReceive->Enabled=true;
//---------------------------------------------------------------------------
}
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
//открытие файла для чтения
hmmio=mmioOpen(L"telephon.wav",0,MMIO_READ);
if (hmmio==0)
{
//MessageBox(0,"Error: mmioOpen",0,MB_OK);
textBox_error->Text=L"Error: mmioOpen";
//btSend->Enabled=false;
return;
};
/*
btSend->Enabled=false; //деактивация кнопки "Начать передачу"
btStopSend->Enabled=true; //активация кнопки "Остановить"
From->Enabled=false; //запрещение редктирования поля "От кого"
To->Enabled=false; //запрещение редктирования поля "Кому"
*/
//разрешить срабатывание таймера на отправку пакетов
timer_send->Enabled=true;
}
private: System::Void button_end_send_Click(System::Object^ sender, System::EventArgs^ e) {
timer_send->Enabled=false; //запретить срабатывание таймера на отправку пакетов
}
private: System::Void timer_send_Tick(System::Object^ sender, System::EventArgs^ e) {
//прочитать данные из открытого блока
mmioRead(hmmio,WaveBuf,SIZE_OF_SOUND);
//вызов функции отправки пакета
Send(WaveBuf);
}
private: System::Void button_start_reseive_Click(System::Object^ sender, System::EventArgs^ e) {
timer_reseive->Enabled=true;
}
private: System::Void button_end__reseive_Click(System::Object^ sender, System::EventArgs^ e) {
timer_reseive->Enabled=false;
timer_play->Enabled=false;
}
private: System::Void timer_reseive_Tick(System::Object^ sender, System::EventArgs^ e) {
Receive();
}
private: System::Void timer_play_Tick(System::Object^ sender, System::EventArgs^ e) {
//взять блок данных из начала очереди
memcpy(PlayBuf,QUEUE[(fst+1)%SIZE_OF_BUF],SIZE_OF_SOUND);
fst=(fst+1)%SIZE_OF_BUF;
//подготовка буфера для воспроизведения
pwhPlay.lpData=PlayBuf;
pwhPlay.dwBufferLength=SIZE_OF_SOUND;
pwhPlay.dwFlags=0;
//подготовка блока аудиоданных для воспроизведения
mres=waveOutPrepareHeader(hwo,&pwhPlay,sizeof(pwhPlay));
if (mres!=0)
//MessageBox(0,"Error: OutPrepareHeader",0,MB_OK);
textBox_error->Text=L"Error: OutPrepareHeader";
//отправка блока аудиоданных заданному устройству вывода
mres=waveOutWrite(hwo,&pwhPlay,sizeof(pwhPlay));
if (mres!=0)
//MessageBox(0,"Error: waveOutWrite",0,MB_OK);
textBox_error->Text=L"Error: waveOutWrite";
}
private: System::Void numericUpDown_timer_ValueChanged(System::Object^ sender, System::EventArgs^ e) {
timer_play->Interval=numericUpDown_timer->Value.ToInt32(numericUpDown_timer->Value);
timer_send->Interval=numericUpDown_timer->Value.ToInt32(numericUpDown_timer->Value);
timer_reseive->Interval=numericUpDown_timer->Value.ToInt32(numericUpDown_timer->Value);
}
};
}
