35350

Организация видеосвязи. Видеоконференцсвязь

Курсовая

Информатика, кибернетика и программирование

Видеоконференцсвязь применяется для личного и делового общения, проведения совещаний, конференций и других важных мероприятий, в которых важно присутствие тех субъектов общения, которые по тем или иным причинам не могут находиться в месте проведения мероприятия лично.

Русский

2014-03-24

1.56 MB

83 чел.

PAGE   \* MERGEFORMAT 30

Московский ордена Ленина, ордена Октябрьской Революции
и ордена Трудового Красного Знамени
государственный технический университет им. Н.Э. Баумана

Факультет: Информатика и системы управления

Кафедра: Программное обеспечение ЭВМ и информационные технологии

Расчетно-пояснительная записка к курсовому проекту по курсу “Вычислительные комплексы и сети”

«Организация видеосвязи»

Студент группы ИУ7-72__________  Ермаков П.Д.   

Студент группы ИУ7-72__________ Рейман Ю.Ю.  

Руководитель проекта   __________  Алешин В.А.

Москва, 2010

Содержание

Введение…………………………………………………………………………….3

Сокращения и термины……………………………………………………………4

1. Исследовательская часть………………………………………………………...5

1.1. Обзор предметной области………………………………………………5

1.1.1. Категории видеоконференцсвязи…..…………………………...5

1.1.2. Оборудование для видеоконференцсвязи……………………...5

1.1.3. Организация связи……………………………………………….7

1.1.4. Протоколы для видеопередачи…………………………………8

1.2. Обзор существующих продуктов………………………………………..9

Выводы…………………..…………………………………………………...11

2. Конструкторская часть…………………………………………………………12

2.1. Архитектура сетевого взаимодействия………………………………12

2.2. Описание протокола передачи данных………………………………13

 2.2.1. Взаимодействие клиента с сервером………………………...13

 2.2.2. Взаимодействие между клиентами…………………………..15

2.3. Структура серверного приложения…………………………………..16

2.4. Структура клиентского приложения…………………………………18

Выводы……………………………………………………………………...21

3. Технологическая часть…………………………………………………………22

3.1. Выбор языка и среды программирования……………………………22

3.2.Требования к системе…………………………………………………..22

3.3. Руководство по установке……………………………………………..22

3.4. Описание программных модулей проекта…………………………...22

 3.4.1. Описание модулей серверного приложения………………...22

 3.4.2. Описание модулей клиентского приложения……………….23

3.5. Описание пользовательского интерфейса……………………………24

Выводы……………………………………………………………………...28

Заключение………………………………………………………………………...30

Список использованной литературы…………………………………………….31

Приложения………………………………………………………………………..32

 Введение

Видеоконференция – это область информационной технологии, обеспечивающая одновременно двустороннюю передачу, обработку, преобразование и представление интерактивной информации на расстояние в реальном режиме времени с помощью аппаратно-программных средств вычислительной техники.

Взаимодействие в режиме видеоконференций также называют сеансом видеоконференцсвязи.

Видеоконференцсвязь (сокращенное название ВКС) — это телекоммуникационная технология интерактивного взаимодействия двух и более удаленных абонентов, при которой между ними возможен обмен аудио- и видеоинформацией в реальном масштабе времени с учетом передачи управляющих данных.

Использование видеоконференцсвязи имеет в последние годы широкое распространение, так как в отличие от передачи текста и голосовых сообщений является намного более интуитивным и легко воспринимаемым средством коммутации, вследствие того, что человек большую часть информации воспринимает именно глазами.

Видеоконференцсвязь применяется для личного и делового общения, проведения совещаний, конференций и других важных мероприятий, в которых важно присутствие тех субъектов общения, которые по тем или иным причинам не могут находиться в месте проведения мероприятия лично.

В таком случае благодаря современным средствам передачи данных и высокомощным компьютерам имеется возможность организовать общение в виртуальном режиме, максимально приближенном к реальному общению – в виде видеоконференции.

Сокращения и термины

В данной работе используются следующие сокращения и термины:

TCP (Transmission Control Protocol) – ориентированный на соединение протокол, направленный на обеспечение надежной передачи данных между процессами, выполняемыми на одном или разных компьютерах[2].

UDP (User Datagram Protocol) – простой ориентированный на дейтаграммы протокол без организации соединения, предоставляющий быстрое, но необязательно надежное транспортное обслуживание[2] .

Клиент – компьютер, имеющий удаленный доступ к информации и программам, хранящимся на сервере[1].

Сервер – компьютер, на котором хранится информация, предоставляемая по удаленному доступу клиентам[1].

Ко́дек(англ. codec, от coder/decoder — кодировщик/декодировщик или compressor/decompressor) — устройство или программа, способная выполнять преобразование данных или сигнала[6].

  1.  Исследовательская часть
    1.  Обзор предметной области
      1.  Категории видеоконференцсвязи

Учитывая функции и цели применения, оборудование видеоконференцсвязи систематизируется на категории и классы.

Индивидуальные системы – обеспечивают возможность индивидуального видеообщения пользователя в режиме реального времени, не покидая своего рабочего места.

Групповые системы – предназначены для проведения групповых сеансов видеоконференцсвязи в переговорных (совещательных) комнатах.

Отраслевые системы – применяются непосредственно в определенной отрасли. Например, в медицинской отрасли очень часто применяют системы для проведения операций (телемедицина), в судебной системе — для проведения дистанционных кассационных и надзорных судебных процессов, в нефтегазовой, энергетической, строительной области для оперативности представления информации.

Мобильные системы – позволяют за короткое время организовать сеанс видеоконференцсвязи в нестандартных условиях. Данные системы обычно используются государственными органами, принимающими оперативные решения.

Административные системы – представляют собой совокупность аппаратно-программных средств администрирования/управления многоточечными сеансами видеоконференцсвязи с использованием различного оконечного оборудования.

  1.  Оборудование для видеоконференцсвязи

   Оборудование для видеоконференций разделяется на три основных вида:

  •  Персональные системы видеоконференций, использующие возможности персонального компьютера и веб-камеры; 
  •  Системы видеоконференций для переговорных комнат, предназначенные для установки в конференц-залах малых и средних размеров; 
  •  Системы видеоконференций для залов заседания, используемые в больших конференц-залах и поддерживающие максимально возможное количество дополнительных сервисов.

Для организации видеоконференций используются следующие устройства[3]:

  •  Терминалы абонентов с поддержкой аудио  и видеосвязи —  индивидуальные или групповые видеосистемы или IP-телефоны. Терминал состоит из следующих компонентов:
  •  Кодек (основное обрабатывающее устройство);
  •  Камера;  
  •  Микрофон; 
  •  Отображающее устройство.
  •  Серверы многоточечной связи (MCU). MCU H.323 совмещает в себе обязательный многоточечный контроллер, управляющий соединениями, и один или несколько опциональных мультимедийных процессоров, назначение которых — микширование аудио и видеосигналов, поступающих от многих участников.
  •  Шлюзы (gateways) соединяют коммутируемые ISDN-сети с пакетными IP-сетями.
    В функции шлюза входит преобразование форматов передачи данных и коммуникационных процедур (H.225/H.221 и H.245/H.242).
  •  Контроллеры зоны (gatekeepers) — это программные модули, которые авторизуют подключения, транслируют используемые в системе имена терминалов и шлюзов в IP-адреса, маршрутизируют запросы через шлюзы
    Кроме того, контроллеры зоны предоставляют дополнительные услуги, такие как управление шириной полосы, переадресация вызова, поддержка службы каталогов, статистические отчеты для биллинговых систем.
  •  Сетевые экраны и прокси-серверы (firewalls и proxies) предотвращают несанкционированный доступ к конференции в случае связи через Интернет. 

Структура сети видеоконференцсвязи представлена на рисунке 1.1.

Рисунок 1.1. Инфраструктура сети видеоконференцсвязи

  1.  Организация связи

В зависимости от конфигурации терминалов и MCU, различаются следующие модели обмена данными[4] :

  •  Централизованная - каждый терминал посылает свои аудио- и видеосигналы на MCU, в двухточечном режиме (см. рисунок 1.2).
    MCU определяет возможности каждого из терминалов, и формирует медиапотоки в соответствии с этими возможностями и рассылает их.

Рисунок 1.2. Централизованная модель обмена данными ВКС.

  •  Децентрализованная  - терминалы рассылают свои аудио- и видеосигналы всем остальным терминалам в режиме Multicast (см. рисунок 1.3.). Микширование принятого аудиосигнала и выбор видеосигнала для отображения выполняется терминалами. Управляющая информация и данные по-прежнему передается между контроллером, входящем в состав MCU, и терминалами в двухточечном режиме.
    Multicast позволяет использовать сетевые ресурсы более эффективно, но увеличивает вычислительную нагрузку на терминалы; кроме того, маршрутизаторы и коммутаторы, используемые в сети, также должны поддерживать Multicast.

Рисунок 1.3. Децентрализованная модель обмена данными ВКС

  •  Каскадная — наиболее экономная модель для больших конференций со многими участниками. Взаимодействуют два или более MCU, каждый из которых управляет группой терминалов.
    В некоторых ситуациях, когда в конференции задействовано особенно много терминалов, возможна такая конфигурация системы, при которой только некоторые абоненты принимают в сеансе активное участие, а остальные подключаются только для просмотра. При этом возможно динамическое изменение статуса участника по мере необходимости.
    1.  Протоколы для видеопередачи

Стремительный рост передачи мультимедиа-информации предъявляет новые требования к скорости и объемам передачи данных. И для того чтобы удовлетворить все эти запросы, одного увеличения емкости сети недостаточно, необходимы разумные и эффективные методы управления трафиком и контролем загруженности линий передачи.

В приложениях реального времени отправитель генерирует поток данных с постоянной скоростью, а получатель (или получатели) должен предоставлять эти данные приложению с той же самой скоростью. Такие приложения включают, например, аудио- и видеоконференции, живое видео, удаленную диагностику в медицине, компьютерную телефонию, распределенное интерактивное моделирование, игры, мониторинг в реальном времени и др.

Наиболее широко используемый протокол транспортного уровня — это TCP. Несмотря на то, что TCP позволяет поддерживать множество разнообразных распределенных приложений, он не подходит для приложений реального времени. TCP обеспечивает гарантированную доставку пакетов и проверку их целостности и отлично подходит для задач, связанных с передачей важной информации, не привязанной к времени. Протокол TCP осуществляет проверку доставки пакета и в случае неудачной доставки осуществляет повторную передачу. Такой механизм недопустим для передачи в режиме реального времени, так как в случае потери пакета и его повторной передачи остальные пакеты будут вынуждены ждать доставки утерянного пакета, что приведет к существенному разрыву во времени передачи и приема пакетов – что является недопустимым для передачи информации в реальном времени.

Эту задачу решает дейтаграммный протокол UDP, задача которого – быстрая доставка дейтаграмм без установления соединения, повторной передачи и гарантии доставки пакета. Несмотря на эти недостатки, протокол UDP более предпочтителен для передачи данных реального времени, так как обеспечивает более быструю передачу данных.

В типичной среде реального времени отправитель генерирует пакеты с постоянной скоростью. Они отправляются через одинаковые интервалы времени, проходят через сеть и принимаются получателем, воспроизводящим данные в реальном времени по их получении. Однако ввиду изменения времени задержки при передаче пакетов по сети, они могут прибывать через нерегулярные интервалы времени. Для компенсации этого эффекта поступающие пакеты буферизуются и затем предоставляются с постоянной скоростью программному обеспечению, генерирующему вывод.

  1.  Обзор существующих продуктов

Skype  (http://www.skype.com/intl/ru/get-skype)

Наиболее популярный продукт на рынке видеоконференций – Skype.

Skype – бесплатное проприетарное программное обеспечение с закрытым кодом, обеспечивающее шифрованную голосовую связь через Интернет между компьютерами (VoIP), а также платные услуги для связи с абонентами обычной телефонной сети.

Программа также позволяет совершать конференц-звонки (до 25 голосовых абонентов, включая инициатора), видеозвонки (в т.ч. видеоконференции до 10 абонентов), а также обеспечивает передачу текстовых сообщений и файлов.

Программные клиенты Skype выпущены для операционных систем.

В отличие от многих других программ IP-телефонии, для передачи данных Skype использует P2P-архитектуру. Каталог пользователей Skype распределён по компьютерам пользователей сети Skype, что позволяет сети легко масштабироваться до очень больших размеров (в данный момент более 100 миллионов пользователей, 15—20 миллионов онлайн) без дорогой инфраструктуры централизованных серверов.

Кроме того, Skype может маршрутизировать звонки через компьютеры других пользователей. Это позволяет соединяться друг с другом пользователям, находящимися за NAT или брандмауэром, однако создаёт дополнительную нагрузку на компьютеры и каналы пользователей, подключённых к Интернету напрямую.

Единственным центральным элементом для Skype является сервер идентификации, на котором хранятся учётные записи пользователей и резервные копии их списков контактов. Центральный сервер нужен только для установки связи. После того как связь установлена, компьютеры пересылают голосовые данные напрямую друг другу (если между ними есть прямая связь) или через Skype-посредник (суперузел — компьютер, у которого есть внешний IP-адрес и открыт TCP-порт для Skype). В частности, если два компьютера, находящиеся внутри одной локальной сети, установили между собой Skype-соединение, то связь с Интернетом можно прервать и разговор будет продолжаться вплоть до его завершения пользователями или какого-либо сбоя связи внутри локальной сети.

Минусы:

  •  В процессе работы Skype генерирует типичный для P2P-сетей и неизбежный постоянный трафик, который может достигать гигабайта в месяц.
  •  Skype — это чёрный ящик с многоуровневой системой шифрования, напичканной антиотладочными приёмами исполняемого файла, считывающий с компьютера конфиденциальную информацию и передающий её в сеть по закрытому протоколу.
  •  Как и любая сеть, работающая по принципу P2P, Skype подвержен вирусным эпидемиям. Уже известны случаи распространения вредоносных программ, перехватывающих и записывающих разговоры в Skype.

iChat (http://www.apple.com/macosx/what-is-macosx/ichat.html)

iChat — программа для мгновенного обмена сообщениями, представлена компанией Apple Inc. Специфика данной программы в том, что она разработана под платформу Macintosh. В новой версии добавлены функции голосового и видео чата. Входит в стандартную поставку Mac OS X.

Возможности: Текстовый чат, аудиочат, видеочат, удалённый доступ к рабочему столу, удалённая демонстрация документов (iChat Theater), везде поддерживаются конференции с более чем двумя собеседниками.

Поддерживаемые протоколы: OSCAR (AIM, ICQ), XMPP (Jabber), Bonjour LAN Chat.

Минусы:

  •  Поддерживает только платформу Macintosh.

NetMeeting (http://www.microsoft.com/downloads/en/details.aspx?FamilyID=26c9da7c-f778-4422-a6f4-efb8abba021e)

NetMeeting — программа для видеоконференцсвязи, позволяет организовывать аудио- и видеоконтакты (при наличии видеокамеры) между двумя и более участниками конференции.
Она обладала следующими возможностями:

  1.  Пересылка файлов. В ходе конференции Вы можете обмениваться с пользователями файлами.
  2.  Совместная работа над документом. Одна из самых отличительных особенностей NetMeeting — предоставляет возможность совместного использования приложений.
  3.  Общение в чате. Возможность обмена с собеседником текстовыми сообщениями.
  4.  «Белая» доска (whiteboard). Возможность обмена с собеседником графической информацией в интерактивном режиме.
  5.  Доступ к рабочему столу любого из участников конференции.
  6.  Доступ к любому из открытых приложение любого из участника конференции.

Минусы:

  •  Проблемы с поддержкой кириллических раскладок;
  •  Разработана для работы под Windows;
  •  Не поддерживается в последних версиях Windows.

Выводы

В ходе исследования предметной области и существующих продуктов для реализации видеоконференции были поставлены следующие задачи для реализации проекта:

  •  Поддержка пользовательского интерфейса;
  •  Осуществление соединения по локальной сети между несколькими пользователями;
  •  Организация видеосвязи один-на-один (Peer-To-Peer);
  •  Организация видеовещания (видеосвязь один-ко-многим);
  •  Организация видеоконференции многие-ко-многим;
  •  Осуществление удаленного доступа к рабочему столу участников видеоконференции;
  •  Возможность записи полученного видеопотока в файл.

  1.  Конструкторская часть
    1.  Архитектура сетевого взаимодействия

Для сетевого взаимодействия применяется гибридная архитектура.

С одной стороны необходимо обеспечить гарантированную передачу данных между клиентами и сервером, поэтому была реализована архитектура «клиент-сервер», схема которой представлена на рисунке  2.1.

Рисунок 2.1. Архитектура «клиент-сервер»

Она обеспечивает централизованное управление клиентами на сервере и эффективное гарантированное взаимодействие клиентов между собой через сервер.

С другой стороны необходимо обеспечить быстрое и эффективное взаимодействие между клиентами для передачи мультимедиа. Поэтому была реализована архитектура «точка-точка», схема которой представлена на рисунке 2.2.

Рисунок 2.2. Архитектура «точка-точка»

При такой архитектуре все участники процесса равноправны. Взаимодействие происходит между клиентами, которые одновременно являются и серверами. Отдельно выделенного сервера не существует, поэтому нагрузка на сервер отсутствует, что позволяет масштабировать систему. Такой подход достаточно выгоден при передаче аудио- и видеоданных.

Таким образом, в системе используется гибридная архитектура, которая использует клиент-серверное взаимодействие для осуществления управления в системе и взаимодействие «точка-точка» для передачи данных между клиентами.

  1.  Описание протокола передачи данных

Для осуществления передачи данных между клиентом и сервером используется протокол, основанный на транспортном протоколе TCP,  передача данных между клиентами осуществляется по протоколу, использующему в качестве основы дейтаграммный протокол UDP.

  1.  Взаимодействие клиента с сервером

Взаимодействие клиента с сервером требует высокой степени надежности, поэтому необходима гарантированная доставка сообщений. Для этого использовался протокол, основанный на протоколе TCP. Рассмотрим его основные аспекты.

При подключении клиента устанавливается соединение с сервером. Сервер, получая запрос на соединение, выделяет поток для взаимодействия с пользователем и отправляет ему подтверждение.

После этого клиент отправляет серверу сообщение Authorization, которое сопровождает имя и пароль пользователя, пытающегося подключиться к серверу. Сервер анализирует полученные данные – проверяет, есть ли пользователь с такими учетными данными в списке зарегистрированных пользователей, не находится ли пользователь с таким именем в сети, и отправляет клиенту сообщение AuthorizationSuccess или AuthorizationFailed в зависимости от результата проверки.

В случае регистрации пользователя, клиент отправляет сообщение Registration, сопровождая его учетными данными. Сервер проверяет, нет ли в списке зарегистрированных пользователей пользователя с таким именем, и отправляет клиенту сообщение RegistrationSuccess или RegistrationFailed в зависимости от результатов проверки.

Клиент, получив сообщение об успешной регистрации или авторизации, отправляет на сервер сообщение ClientInfo для получения информации о пользователях, находящихся в сети. Сервер при получении такого сообщения отправляет клиенту информацию обо всех активных пользователях.

Таким образом, каждый клиент имеет информацию обо всех активных пользователях и в случае необходимости сможет организовать передачу данных с другим клиентом.

Рисунок 2.3. Схема взаимодействия между клиентом и сервером

При необходимости прекратить взаимодействие клиент отправляет серверу сообщение Disconnect. Сервер, получив это сообщение, удаляет всю информацию о пользователе.

Схема взаимодействия представлена на рисунке 2.3.

  1.  Взаимодействие между клиентами

Взаимодействие между клиентами осуществляется как по протоколу TCP, так и по протоколу UDP.

По протоколу TCP осуществляется передача запроса на передачу медиаданных, подтверждение или отказ от инициирования передачи, а также уведомления об отключении пользователя от процесса видеопередачи.

По протоколу UDP производится непосредственно передача видео- и аудиоданных.

При инициировании запроса на передачу данных Клиент1 отправляет сообщение TransferRequest Клиенту2, с которым он хочет соединиться.

Клиент2, получив сообщение, соглашается или отказывается от соединения и отправляет сообщение TransferSuccess или TransferFailed соответственно. Если соединение установлено, то начинается передача видео- и аудиоданных по протоколу UDP.

Если Клиент1 хочет прекратить передачу данных – он отправляет Клиенту2 сообщение TransferEnd, после чего оба клиента прекращают передачу медиаданных.

Схема взаимодействия между клиентами представлена на рисунке 2.4.

Рисунок 2.4. Взаимодействие между клиентами

  1.  Структура серверного приложения

Серверное приложение выполняет управляющую функцию, функцию координатора клиентов, а также ведет сбор статистики.

Структура серверного приложения представлена на рисунке 2.5.

Рисунок 2.5. Структура серверного приложения

Блок создания соединений – осуществляет прослушивание порта и при получении запроса на соединение создает объект класса Connection, выделяя для него поток. Инициирует объект класса StatisticBlock. Затем передает управление блоку обслуживания соединений.

Блок обслуживания соединений – осуществляет получение и обработку запросов от клиентов, а также отправку сообщений клиентам.

Алгоритм работы этого блока показан на рисунке 2.6.

В бесконечном цикле блок читает пакеты, приходящие от клиента, с которым установлено соединение. Затем происходит анализ типа полученного пакета.

Если тип пакета = Registration, то происходит регистрация нового пользователя на сервере.

Если тип пакета = Authorization – авторизация пользователя на сервере.

При получении пакета с типом ClientInfo – происходит передача информации обо всех клиентах этому клиенту.  

Получив пакет с типом Disconnect – удаляет пользователя из списка активных пользователей и отсылает всем клиентам сообщение об отключившемся пользователе.

Блок сбора статистики – осуществляет сбор информации обо всех действиях, произведенных на сервере. Полученные данные записывает в файл на жестком диске.

Блок создания соединения создается непосредственно после запуска сервера и функционирует до выхода из серверного приложения. В нем создаются блок сбора статистики, который также функционирует в течение всего времени работы сервера, и блоки обслуживания подключений, каждый из которых создается при соединении с новым клиентом и уничтожается при отключении клиента.

Рисунок 2.6. Блок схема алгоритма работы блока обслуживания соединения

  1.  Структура клиентского приложения

Задачами клиентского приложения являются взаимодействие с пользователем с одной стороны и с сервером с другой стороны.

Структура клиентского приложения представлена на рисунке 2.7.

Рисунок 2.7. Структура клиентского приложения

Пользовательский интерфейс – выполняет функцию взаимодействия пользователя с программным комплексом. С его помощью на экран выводятся данные, полученные как от сервера (список пользователей), так и данные полученные от других клиентов (видео и звук).

Блок взаимодействия с сервером – осуществляет прием и передачу пакетов, и координацию действий клиента в зависимости от полученных данных. В этом блоке производится регистрация и авторизация пользователей, получение списка доступных пользователей, коммутация с другими клиентами для начала и прекращения передачи данных.

Алгоритм работы блока представлен на рисунке 2.8.

После отправки клиентом серверу запроса на подключение, клиент может получить одно из следующих сообщений: Registration/AuthorizationSuccess, Registrtion/AuthrizationFailed, ClientAllreadyConnect. В случае сообщений первого типа – клиент успешно зарегистрирован/авторизован на сервере, он отправляет запрос на получение списка доступных пользователей. Во втором случае регистрация/авторизация была неудачна и на экран выводится сообщение с причиной неудачи. В случае третьего сообщения – на экран выводится уведомление о том, что пользователь с таким именем уже в сети.

При подключении к серверу нового клиента всем другим клиентам отсылается сообщение ClientConnected, получив которое, клиент запрашивает информацию о новом пользователе и добавляет ее в список доступных пользователей.

При отключении клиента от сервера всем другим клиентам отправляется сообщение ClientDisconnected, получив которое, клиент удаляет информацию о пользователе из списка доступных пользователей.

При инициировании передачи видео клиент посылает серверу пакет для другого клиента с типом TransferRequest, содержащий информацию о пользователе.

Рисунок 2.8. Блок-схема алгоритма работы блока взаимодействия с сервером

Клиент, получивший такое сообщение, читает данные о пользователе и выводит сообщение на экран с запросом на соединение. Если пользователь готов начать видеопередачу – он отправляет клиенту пакет типа TransferSuccess, который содержит информацию о данном пользователе.

Получив такой пакет, клиент читает информацию о пользователе и инициирует видеопередачу.

Если пользователь не готов или не желает начать видеопередачу – он отправляет пакет с типом TransferFailed, получив который, другой клиент уведомляет пользователя об отказе в соединении.

При завершении видеопередачи, клиент получает сообщение TransferEnd и прекращает передачу данных. 

Блок взаимодействия с клиентами осуществляет передачу и прием медиаданных от других клиентов, а также организацию взаимодействия между клиентами (запросы на начало и прекращение передачи данных).

Видеоинформация, получаемая с веб-камеры, преобразуется в последовательность кадров, которая передается по UDP-протоколу. Для захвата видео применяются средства библиотеки DirectShow. Захват звука осуществляется также с помощью библиотеки DirectShow и записывается в буфер фрагментами, которые впоследствии передаются также по UDP-протоколу.

Пользовательский интерфейс взаимодействует как с блоком взаимодействия с сервером, так и с блоком взаимодействия с клиентами.

Выводы

Были выявлены следующие требования, накладываемые на программный комплекс:

  •  архитектура программного комплекса должна соответствовать гибридной архитектуре, соединяющей архитектуры «клиент-сервер»  и «точка-точка»;
  •  сетевое взаимодействие должно осуществляться по протоколу, основанному на TCP (клиент-серверное взаимодействие) и на UDP (межклиентное взаимодействие);
  •  для захвата видео и аудио необходимо использовать библиотекe DirectShow;
  •  структура программного комплекса должна соответствовать описанной в пунктах 2.3 и 2.4.

  1.  Технологическая часть
    1.  Выбор языка и среды программирования

В качестве среды программирования была выбрана среда Microsoft Visual Studio, потому что она обладает следующими преимуществами:

  •  удобство разработки программных продуктов;
  •  большое разнообразие классов, в том числе для разработки  сетевых приложений;
  •  простота реализации пользовательского интерфейса;
  •  наличие средств для комфортной отладки сетевых программ.

В качестве языка программирования был выбран язык C#, так как он позволяет с легкостью разрабатывать сложные приложения, имеет большой набор классов и удобные методы разработки приложений.

Для захвата видео и аудио использовались библиотека DirectShow, которые позволяют построить систему кодирования, сжатия, передачи и декодирования медиаданных.

 

  1.  Требования к системе

Для нормального функционирования программного комплекса система должна удовлетворять следующим требованиям:

  •  операционная система Windows XP, Windows Vista, Windows 7;
  •  установленный .NET Framework 3.0;
  •  библиотеки DirectShow и Voice;
  •  наличие веб-камеры (встроенной или внешней);
  •  наличие микрофона (встроенного или внешнего).

  1.  Руководство по установке

Для установки программного комплекса необходимо скопировать папку  на жесткий диск и следовать инструкциям в файле INSTALL.txt

  1.  Описание программных модулей проекта
    1.  Описание модулей серверного приложения

Серверное приложение состоит из трех модулей, которые отражают сущность блоков, описанных в пункте 2.3.

Модуль создания соединений – основной модуль серверного приложения.  Он представлен классом Server, листинг которого отражен в приложении А(1).

Класс содержит информацию о сервере – адрес и порт, сокет для приема и передачи данных клиентам. Также в классе содержится главный поток серверного приложения, который принимает запросы на подключение клиентов, список установленных соединений – объектов класса Connection. В сервере хранится список зарегистрированных и активных пользователей. Здесь же инициализируется объект LogWriter, который отвечает за ведение журнала событий.

Этот модуль осуществляет ожидание нового подключения, а когда подключение инициировано – создает новое соединение для передачи данных.

Модуль обслуживания соединений – модуль, задачей которого является осуществление связи между клиентом и сервером. Он представлен классом Connection, листинг которого отражен в приложении А(2).

Этот класс содержит информацию о конкретном соединении – сокет для передачи данных, имя клиента и поток для организации параллельной обработки сервером запросов от клиентов. Задача модуля – получение, анализ и отправка пакетов клиентам.

Модуль сбора  статистики необходим для осуществления контроля действий, происходящих на сервере. Модуль представлен классом LogWriter, листинг которого представлен в приложении А(3).

Задача модуля – осуществлять анализ событий и записывать информацию он них в лог-файл для последующего анализа состояний сервера. Модуль тесно связан с двумя вышеописанными методами, так как выполняется наряду с работой других модулей клиентского приложения.

  1.  Описание модулей клиентского приложения

Клиентское приложение состоит из трех модулей, которые отражают сущность блоков, описных в пункте 2.4.

Пользовательский интерфейс осуществляет взаимодействие пользователя с программой. Пользовательский интерфейс представлен главной формой приложения, которая содержит окно для вывода видеоизображения, поле, содержащее список пользователей и набор кнопок для управления процессом видеопередачи. Подробное описание пользовательского интерфейса можно найти в пункте 3.5.

Модуль взаимодействия с сервером предназначен для отправки и получения сообщений от сервера. Представлен классом Client, листинг которого приведен в приложении Б(1). В этом классе хранится информация о текущем соединении с сервером – имя, пароль, сокет, поток для обработки сообщений от сервера, а также список подключенных пользователей. Задача модуля – осуществить авторизацию пользователя на сервере, получить список доступных пользователей и далее ожидать сообщения от сервера и осуществлять их обработку. Данный модуль взаимодействует с пользовательским интерфейсом путем генерации и обработки событий.

Модуль взаимодействия между клиентами – модуль, реализующий передачу видеоизображения между клиентами, а также его дополнительную обработку. Модуль реализует основную функциональность клиентского приложения, а именно захват, кодирование, передачу, получение, декодирование и вывод на экран видеоинформации.

Модуль представлен двумя классами VideoSender и VideoReceiver, которые реализую соответственно передачу и получение видеоизображения.

Основу видеозахвата представляет класс Capture. Он построен на основе библиотеки DirectShow и производит захват изображения с веб-камеры. Листинг класса приведен в приложении Б(2).

Класс VideoSender осуществляет передачу изображения, захваченного с помощью объекта класса Capture. В этом классе происходит получение изображения с веб-камеры, запись его в поток и отправка потока по UDP-протоколу.

Класс VideoReceiver занимается получением и выводом на экран изображения. Он читает присланное изображение в поток, затем создает объект класса Image из потока и выводит изображение на экран.

Более подробное описание класса Capture приведено ниже.

Класс Capture построен на основе интерфейса ISampleGrabberCB, который позволяет получить буфер. Задача класса – получить изображение с камеры, представленное в виде указателя на Bitmap.

Для этого строится граф, в который последовательно добавляются устройство видеозахвата, фильтр захвата, определяется размер, тип изображения. Производится установка параметров видео: ширины и высоты изображения, частоты кадров,  качества передаваемого изображения. Затем происходит получение изображения, копирование его в буфер и передача указателя на буфер объекту класса VideoSender, который впоследствии передает изображение другому клиенту.

  1.  Описание пользовательского интерфейса

Основу пользовательского интерфейса составляет главное окно клиентского приложения. Его вид представлен на рисунке 3.1.

Рисунок 3.1. Главное окно клиентского приложения

В центре главного окна располагается поле для вывода видеоизображения, полученного от другого пользователя. В нижнем правом углу – поле-эскиз для вывода изображения, полученного с собственной веб-камеры.

В левом верхнем углу располагается меню. Вкладка «Файл» имеет подпункты «Подключение» и «Отключение» (см. рисунок 3.2.).

Рисунок 3.2. Меню «Файл»

При нажатии на пункт «Подключение» появляется диалоговое окно «Авторизация» (см. рисунок 3.3.), с помощью которого можно осуществить авторизацию или регистрацию на сервере. В этом диалоговом окне расположены поле для ввода имени компьютера, на котором располагается сервер, поля для ввода имени и пароля пользователя. Также в окне находится флаг «Регистрация», установив который, можно зарегистрироваться на сервере.

Рисунок  3.3. Диалоговое окно «Авторизация»

После успешной авторизации/регистрации в левом нижнем углу появляется надпись «<имя пользователя> в сети» (см. рисунок 3.4.).

Рисунок 3.4. Поле статуса

Также клиент получает от сервера информацию о подключенных пользователях и выводит их в поле «Пользователи в сети» (см. рисунок 3.5.).

Рисунок 3.5. Поле Пользователи в сети

Под этим полем находится кнопка «Обновить», нажав которую, можно получить обновленную информацию о подключенных пользователях.

При нажатии  правой кнопкой мыши по полю появляется всплывающее меню, которое содержит подпункты «Начать передачу» и «Закончить передачу» (см. рисунок 3.6.). Нажав на пункт «Начать передачу», пользователь инициирует видеопередачу с пользователем из списка. Нажав на пункт «Прекратить передачу», пользователь завершает видеопередачу.

Рисунок 3.6. Меню передачи видео

При передаче данных главное окно клиентского приложения выглядит, как показано на рисунке 3.7.

В центре окна располагается изображение, полученное от другого пользователя, в правом нижнем углу – изображение пользователя, получающего видеоданные.

Рисунок 3.7. Вид главного окна приложения при передаче видео

Дополнительной опцией являются возможность захвата изображения с рабочего стола и передача его пользователю, с которым установлено соединение (см. рисунок 3.8.).

Рисунок 3.8. Дополнительные опции

Нажав кнопку «Захват рабочего стола», пользователь инициирует передачу изображения со своего рабочего стола собеседнику (см. рисунок 3.9.).

Таким образом, можно проводить дистанционное обучение, делиться интересными статьями, презентациями, графиками и другими визуальными данными. Для прекращения захвата рабочего стола необходимо нажать кнопку «Прекратить захват».

Рисунок 3.9. Передача изображения с рабочего стола

Выводы

Результатом данной курсовой работы стал программный комплекс, состоящий из серверного и клиентского приложения. Программный комплекс решает следующие задачи:

  •  Организация сетевого взаимодействия между клиентом и сервером, а также между клиентами;
  •  Осуществление видео- и аудиопередачи между двумя клиентами;
  •  Осуществление захвата и передача изображения с рабочего стола;
  •  Организация пользовательского интерфейса.

Заключение

В ходе курсовой работы была исследована область применения видеоконференций, были выявлены достоинства и недостатки существующих продуктов в этой сфере. На основе результатов анализа была разработана демо-версия сетевого приложения, осуществляющего видеосвязь. Были выполнены следующие требования:

  •  Поддержка пользовательского интерфейса;
  •  Осуществление соединения по локальной сети между несколькими пользователями;
  •  Организация видеосвязи один-на-один (Peer-To-Peer);
  •  Осуществление удаленного доступа к рабочему столу участников видеоконференции.

Недостатками демо-версиями являются отсутствие возможности видеосвязи один к многим и видеосвязи многие ко многим. Эти недостатки легко устранить при реализации полнофункциональной версии программного комплекса.

Список использованной литературы

[1] Таненбаум Э. Компьютерные сети. – СПб.: Питер, 2003. – 992 с.

[2] Эндрю Кровчик, Винод Кумар, Номан Лагари, Аджит Мунгале, Кристиан Нагел, Тим Паркер, Шриниваса Шивакумар - .NET. Сетевое программирование для профессионалов. – М.:Лори, 2005. – 400 с.

[3] Основы видеоконференций – (http://www.avicon.ru/article/?id=15). – «Авиакон», 2002.

[4] Просто о видеоконференциях – (http://www.stel.ru/videoconference/tech_vc/prosto/). – «Стэл - Компьютерные Системы», 2009.

[5] Библиотека MSDNhttp://msdn.microsoft.com/ru-ru/library, 2010

[6] Википедия – Свободная энциклопедия – http://ru.wikipedia.org/, 2010

Приложения

Приложение А. Фрагменты исходных текстов серверного приложения

  1.  Обзор класса Server 

class Server

{

// класс сервер - содержит адрес и порт сервера, сокет для приема данных, главный поток,

   // список зарегистрированных и активных пользователей, список соединений

   private Socket socket;

   private IPAddress address;

   private int port;

   private Thread thread;

   private List<ClientRecord> registered_clients;

   private List<ClientRecord> active_clients;

   private List<Connection> connections;

   LogWriter log_writer;

   private void AcceptConnections()

   {

       while (true)

       {

           // Принимаем соединение

           Socket t_socket = socket.Accept();

           Connection connection = new Connection();

           connection.Socket = t_socket;

           //connection.stream = new NetworkStream(t_socket);

           log_writer.Write("New connection from " +

                           t_socket.RemoteEndPoint.ToString());

           // Создаем поток для получения данных

           connection.Thread = new Thread(ProcessConnection);

           connection.Thread.IsBackground = true;

           connection.Thread.Start(connection);

           // Сохраняем соединение

           lock (connections) connections.Add(connection);

       }

   }

   private void ProcessConnection(object state)

   {

       // обрабатываем запрос в соединении

       Connection connection = (Connection)state;

       byte[] buffer = new byte[255];

       try

       {

           while (true)

           {

               // читаем тип сообщения

               byte b = NetworkReader.ReadType(connection.Socket);

               switch (b)

{// в зависимости от типа сообщения вызываем соответствующую функцию

                   case (byte)Messages.Registration:

                       {

                           Registration(connection);

                           break;

                       }

                   case (byte)Messages.Authorization:

                       {

                           Authorization(connection);

                           break;

                       }

                   case (byte)Messages.ClientInfo:

                       {

                           ClientInfo(connection);

                           break;

                       }

                   case (byte)Messages.InfoForClient:

                       {

                           RequestToClient(connection);

                           break;

                       }

                   case (byte)Messages.Disconnect:

                       {

                           DisconnectClient(connection);

                           return;

                       }

               }

           }

       }

       catch (SocketException exc)

       {

           MessageBox.Show(exc.Message);

           log_writer.Write("SocketException: " + exc.Message);

       }

       catch (Exception exc)

       {

           MessageBox.Show(exc.Message);

           log_writer.Write("Exception: " + exc.Message);

       }

       finally

       {

           DisconnectClient(connection);

       }

   }

   void Registration(Connection conn)

   {

       // регистрация нового пользователя

       ClientRecord rec = NetworkReader.ReadClientRecord(conn.Socket);

       ClientInfo info = NetworkReader.ReadClientInfo(conn.Socket);

       log_writer.Write("Registration of new user with name <" + rec.Name

                       + "> and password <" + rec.Password + ">");

 // проверяем, не зарегистриван ли пользователь с таким именем на сервере

       foreach (ClientRecord record in registered_clients)

       {

           if (record.Name == rec.Name)

           {

               // отправляем сообщение о неудачной регистрации

               SendMessage(conn, Messages.RegistrationFailed);

               log_writer.Write("Registration of new user with name <" +

               rec.Name + "> and password <" + rec.Password + "> failed");

               // удаляем соединение

               conn.Socket.Close();

               lock (connections) connections.Remove(conn);

               return;

           }

       }

       // иначе добавляем информацию о пользователе в список

       registered_clients.Add(rec);

       active_clients.Add(rec);

       // и отправляем сообщение о удачной регистрации

       SendMessage(conn, Messages.RegistrationSuccess);

       log_writer.Write("Registration of new user with name <" + rec.Name +

                       "> and password <" + rec.Password + "> success");

       conn.Name = rec.Name;

       // рассылаем всех клиентам информацию о новом клиенте

       foreach (Connection c in connections)

       {

           if (c != conn)

           {

               SendMessage(c, Messages.ClientConnected);

               c.SendClientInfo(info);

           }

       }

   }

   void Authorization(Connection conn)

   {

       // авторизация пользователя

       ClientRecord rec = NetworkReader.ReadClientRecord(conn.Socket);

       ClientInfo info = NetworkReader.ReadClientInfo(conn.Socket);

       log_writer.Write("Authorization of new user with name <" + rec.Name +

                           "> and password <" + rec.Password + ">");

       // проверяем, не находится ли пользователь с таким именем в сети

       foreach (ClientRecord record in active_clients)

       {

           if (record.Equals(rec) == true)

           {

// отправляем сообщение о существовании пользователя с таким именем

               SendMessage(conn, Messages.ClientAllredyConnect);

log_writer.Write("User with name <" + rec.Name + "> and password <" + rec.Password + "> allredy on-line");

               // удаляем соединение

               conn.Socket.Close();

               lock (connections) connections.Remove(conn);

               return;

           }

       }

       // проверяем, зарегистрирован ли пользователь с таким именем

       foreach (ClientRecord record in registered_clients)

       {

           if (record.Equals(rec) == true)

           {

// если зарегистрирован - отправляем сообщение о удачной авторизации

               // и добавляем информацию о пользователе в список

               active_clients.Add(rec);

               SendMessage(conn, Messages.AuthorizationSuccess);

log_writer.Write("Authorization of new user with name <" + rec.Name + "> and password <" + rec.Password + "> success");

               conn.Name = rec.Name;

               // рассылаем всех клиентам информацию о новом клиенте

               foreach (Connection c in connections)

               {

                   if (c != conn)

                   {

                       SendMessage(c, Messages.ClientConnected);

                       c.SendClientInfo(info);

                   }

               }

               conn.Name = rec.Name;

               return;

           }

       }

       // иначе отправляем сообщение о неудачной авторизации

       SendMessage(conn, Messages.AuthorizationFailed);

       log_writer.Write("Authorization of new user with name <" + rec.Name +

                           "> and password <" + rec.Password + "> failed");

       conn.Socket.Close();

       lock (connections) connections.Remove(conn);

   }

   void ClientInfo(Connection connection)

   {

       // отправляем клиенту число зарегистрированных пользователей

       NetworkWriter.WriteType(connection.Socket,

                       (byte)(connections.Count - 1));

       log_writer.Write("Request from user with name <" +

           connection.Name + "> for information about connected users");

       foreach (Connection conn in connections)

       {

           //if (conn != connection)

           // отправляем информацию о каждом соединении

           //connection.SendClientInfo(conn);

       }

   }

   void RequestToClient(Connection conn)

   {

       String name = NetworkReader.ReadString(conn.Socket);

       byte type = NetworkReader.ReadType(conn.Socket);

       ClientInfo info = NetworkReader.ReadClientInfo(conn.Socket);

       foreach (Connection c in connections)

       {

           if (c.Name == name)

           {

               NetworkWriter.WriteType(c.Socket, type);

               NetworkWriter.WriteClientInfo(c.Socket, info);

               log_writer.Write("new message from user '" +

                           conn.Name + "' to user '" + c.Name + "'");

               break;

           }

       }

   }

   void DisconnectClient(Connection conn)

   {

       // отключение клиента

       // удаляем пользователя из списка

       foreach (ClientRecord rec in active_clients)

       {

           if (rec.Name == conn.Name)

           {

               active_clients.Remove(rec);

               log_writer.Write("User with name <" + conn.Name +

                               "> disconnected");

               break;

           }

       }

       // всем клиентам отправляем сообщение об отключении пользователя

       foreach (Connection c in connections)

       {

           if (c != conn)

           {

               SendMessage(c, Messages.ClientDisconnected);

               IPEndPoint ep = new IPEndPoint(IPAddress.Loopback, 10000);

               ClientInfo info = new ClientInfo(conn.Name,

                                       ep.Address.ToString(), ep.Port);

               c.SendClientInfo(info);

           }

       }

       // удаляем соединение

       conn.Socket.Close();

       lock (connections) connections.Remove(conn);

   }

   void SendMessage(Connection conn, Messages mes)

   {

       NetworkWriter.WriteType(conn.Socket, (byte)mes);

   }

}

  1.  Обзор класса Connection

class Connection

{

 // класс соединение - содержит имя, поток, сокет, поток для передачи данных

   public String Name;

   public Socket Socket;

   public Thread Thread;

   public void SendClientInfo(ClientInfo info)

   {

      // отправка информации о соединении - имя, адрес и порт

       NetworkWriter.WriteClientInfo(Socket, info);

   }

   public void SendRequest(byte type, String address, int port)

   {

       NetworkWriter.WriteType(Socket, type);

       NetworkWriter.WriteClientInfo(Socket,

new ClientInfo(Name, address, port));

   }

}

  1.  Обзор класса LogWriter

class LogWriter

{

   String filename;

   public LogWriter(String name)

   {

       filename = name;

   }

   public void Write(String s)

   {

       StreamWriter wr = new StreamWriter(filename, true);

       wr.WriteLine(DateTime.Now.ToString() + " : " + s + "\n");

       wr.Close();

   }

}

Приложение Б. Фрагменты исходных текстов клиентского приложения

  1.  Обзор класса Client

class Client

{

   // класс клиент - содержит имя и пароль пользователя,

   // сокет TCP и UDP, поток для передачи данных

   String name;

   String password;

   Socket tcp_socket;

   Thread thread;

   VideoReceiver receiver;

   VideoSender sender;

   List<ClientInfo> connected_clients;

   public List<String> ConnectedUsers;

   public EmptyHandler ClientConnectedHandler;

   public EmptyHandler ClientDisconnectedHandler;

   public RequestHandler TransferRequestHandler;

   public MessageHandler TransferFailedHandler;

   public String Name

   {

       get { return name; }

       set { name = value; }

   }

   public String Password

   {

       get { return password; }

       set { password = value; }

   }

   public Client(String host, String n, String p, bool reg,

                   PictureBox pb, VideoDescriptor desc)

   {

       // присваиваем исходные данные

       name = n;

       password = p;

       connected_clients = new List<ClientInfo>();

       ConnectedUsers = new List<String>();

       // создаем сокет и соединяемся с сервером

       tcp_socket = new Socket(AddressFamily.InterNetwork,

                           SocketType.Stream, ProtocolType.Tcp);

       tcp_socket.Connect(host, 11000);

       // инициализируем отправителя и получателя видео

       int port = ((IPEndPoint)tcp_socket.LocalEndPoint).Port - 10000;

       IPAddress addr = ((IPEndPoint)tcp_socket.LocalEndPoint).Address;

       sender = new VideoSender(desc, addr, port);

       receiver = new VideoReceiver(pb, addr, port + 1);

       //вызываем функцию авторизации и добавления информации о клиентах

       Authorization(reg);

       //SetConnectedClients();

       // создаем поток для обработки сообщений

       thread = new Thread(ReadMessage);

       thread.IsBackground = true;

       thread.Start();

   }

   void Authorization(bool register)

   {

       // авторизация

       byte b;

       if (register == true)

           b = (byte)Messages.Registration;

       else

           b = (byte)Messages.Authorization;

       // отправляем тип сообщения и информацию о пользователе

       NetworkWriter.WriteType(tcp_socket, b);

NetworkWriter.WriteClientRecord(tcp_socket, new ClientRecord(name, password));

       NetworkWriter.WriteClientInfo(tcp_socket, new ClientInfo(name,

         sender.GetEndPoint().Address.ToString(), sender.GetEndPoint().Port));

       // и ожидаем ответа

       b = NetworkReader.ReadType(tcp_socket);

       ProcessMessage(b);

   }

   void ReadMessage()

   {

       while (true)

       {

           // читаем тип сообщения и выполняем соответствующие действия

           byte b = NetworkReader.ReadType(tcp_socket);

           ProcessMessage(b);

       }

   }

   void ProcessMessage(byte type)

   {

       switch (type)

       {

           case (byte)Messages.RegistrationFailed:

               {

throw (new Exception("Пользователь с таким именем уже зарегистрирован"));

               }

           case (byte)Messages.RegistrationSuccess:

               {

                   break;

               }

           case (byte)Messages.AuthorizationFailed:

               {

 throw (new Exception("Пользователь с таким именем уже  зарегистрирован"));

               }

           case (byte)Messages.AuthorizationSuccess:

               {

                   break;

               }

           case (byte)Messages.ClientAllredyConnect:

               {

throw (new Exception("Пользователь с таким именем уже в сети"));

               }

           case (byte)Messages.ClientInfo:

               {

                   ClientInfo();

                   break;

               }

           case (byte)Messages.ClientConnected:

               {

                   NewClientConnected();

                   break;

               }

           case (byte)Messages.ClientDisconnected:

               {

                   ClientDisconnected();

                   break;

               }

           case (byte)Messages.TransferRequest:

               {

                   TransferAnswer();

                   break;

               }

           case (byte)Messages.TransferFailed:

               {

                   TransferFail();

                   break;

               }

           case (byte)Messages.TransferSuccess:

               {

                   BeginVideoTranslation();

                   break;

               }

           case (byte)Messages.TransferEnd:

               {

                   EndVideoTranslation();

                   break;

               }

       }

   }

   void NewClientConnected()

   {

       // подключение нового клиента

       // читаем информацию о новом клиенте и добавляем ее в соответствующие списки

       ClientInfo info = NetworkReader.ReadClientInfo(tcp_socket);

       ConnectedUsers.Add(info.Name);

       connected_clients.Add(info);

       NetworkWriter.WriteType(tcp_socket, (byte)Messages.InfoForClient);

       NetworkWriter.WriteString(tcp_socket, info.Name);

       NetworkWriter.WriteType(tcp_socket, (byte)Messages.ClientInfo);

       NetworkWriter.WriteClientInfo(tcp_socket, new ClientInfo(name,

         sender.GetEndPoint().Address.ToString(), sender.GetEndPoint().Port));

// вызываем событие, чтобы отразить нового пользователя в окне приложения

       ClientConnectedHandler();

   }

   void ClientInfo()

   {

       ClientInfo info = NetworkReader.ReadClientInfo(tcp_socket);

       ConnectedUsers.Add(info.Name);

       connected_clients.Add(info);

// вызываем событие, чтобы отразить нового пользователя в окне приложения

       ClientConnectedHandler();

   }

   void ClientDisconnected()

   {

       // отключение пользователя

       // читаем информацию о пользователе и удаляем ее из списков

       ClientInfo info = NetworkReader.ReadClientInfo(tcp_socket);

       ConnectedUsers.Remove(info.Name);

       foreach (ClientInfo inf in connected_clients)

       {

           if (inf.Name == info.Name)

           {

               connected_clients.Remove(info);

               break;

           }

       }

// вызываем событие, чтобы обновить список пользователей в окне приложения

       ClientDisconnectedHandler();

   }

   void SetConnectedClients()

   {

       // получение списка подключенных пользователей

       List<String> list = new List<String>();

       // отправляем запрос

       NetworkWriter.WriteType(tcp_socket, (byte)Messages.ClientInfo);

       // читаем количество подключенных пользователей

       int clients_count = (int)NetworkReader.ReadType(tcp_socket);

       // и информацию о каждом из них

       for (int i = 0; i < clients_count; i++)

       {

           ClientInfo info = NetworkReader.ReadClientInfo(tcp_socket);

           ConnectedUsers.Add(info.Name);

           connected_clients.Add(info);

       }

   }

   public void TransferRequest(String user_name)

   {

       // отправляем пользователю с именем user_name запрос на соединение

       NetworkWriter.WriteType(tcp_socket, (byte)Messages.InfoForClient);

       NetworkWriter.WriteString(tcp_socket, user_name);

       NetworkWriter.WriteType(tcp_socket, (byte)Messages.TransferRequest);

       NetworkWriter.WriteClientInfo(tcp_socket, new ClientInfo(name,

          sender.GetEndPoint().Address.ToString(), sender.GetEndPoint().Port));

   }

   void TransferAnswer()

   {

       // отправляем ответ пользователю

       // читаем его данные

       ClientInfo info = NetworkReader.ReadClientInfo(tcp_socket);

       // выводим на экран диалоговое окно

       if (TransferRequestHandler(info.Name) == true)

       {

           // отправляем пользователю согласие в видеосвязи

           NetworkWriter.WriteType(tcp_socket, (byte)Messages.InfoForClient);

           NetworkWriter.WriteString(tcp_socket, info.Name);

           NetworkWriter.WriteType(tcp_socket, (byte)Messages.TransferSuccess);

           NetworkWriter.WriteClientInfo(tcp_socket, new ClientInfo(name,

receiver.GetEndPoint().Address.ToString(), receiver.GetEndPoint().Port));

           // связываем сокет с удаленным сокетом

           //receiver.Connect(info.Point);

           sender.Connect(info.Point);

           // и начинаем передачу видео

           BeginVideoTranslation1();

       }

       else

       {

           // отправляем отказ в видеосвязи

           NetworkWriter.WriteType(tcp_socket, (byte)Messages.InfoForClient);

           NetworkWriter.WriteString(tcp_socket, info.Name);

           NetworkWriter.WriteType(tcp_socket, (byte)Messages.TransferFailed);

           NetworkWriter.WriteClientInfo(tcp_socket, new ClientInfo(name,

sender.GetEndPoint().Address.ToString(), sender.GetEndPoint().Port));

       }

   }

   void TransferFail()

   {

       // получив отказ в видеосвязи выводит соответствующее сообщение на экран

       ClientInfo info = NetworkReader.ReadClientInfo(tcp_socket);

       TransferFailedHandler(info.Name);

   }

   public void TransferEnd(String user_name)

   {

       // отправялем пользователю сообщение о завершении видеосвязи

       NetworkWriter.WriteType(tcp_socket, (byte)Messages.InfoForClient);

       NetworkWriter.WriteString(tcp_socket, user_name);

       NetworkWriter.WriteType(tcp_socket, (byte)Messages.TransferEnd);

       NetworkWriter.WriteClientInfo(tcp_socket, new ClientInfo(name,

sender.GetEndPoint().Address.ToString(), sender.GetEndPoint().Port));

       // и заканчиваем видеопередачу

       EndVideoTranslation1();

   }

   public void Close()

   {

       // отправляем сообщение о завершении соединения

       NetworkWriter.WriteType(tcp_socket, (byte)Messages.Disconnect);

       // и отключаем сокет от сервера

       tcp_socket.Disconnect(false);

       receiver = null;

       sender = null;

   }

   public void BeginVideoTranslation()

   {

       ClientInfo info = NetworkReader.ReadClientInfo(tcp_socket);

       receiver.Connect(info.Point);

       sender.Connect(info.Point);

       receiver.BeginReceiving();

       sender.BeginSending();

   }

   void BeginVideoTranslation1()

   {

       receiver.BeginReceiving();

       sender.BeginSending();

   }

   public void EndVideoTranslation()

   {

       ClientInfo info = NetworkReader.ReadClientInfo(tcp_socket);

       receiver.EndReceiving();

       receiver = null;

       sender.EndSending();

       sender = null;

   }

   public void EndVideoTranslation1()

   {

       receiver.EndReceiving();

       receiver = null;

       sender.EndSending();

       sender = null;

   }

}

  1.  Обзор класса Capture

class Capture : ISampleGrabberCB, IDisposable

{

   // Построение интерфейса графа

   private IFilterGraph2 FilterGraph = null;

   private IMediaControl mediaCtrl = null;

   // Можем ли мы ждать окончания асинхронной работы

   private ManualResetEvent PictureReady = null;

   // Установка асинхронности для захвата изображения

   private volatile bool bGotOne = false;

   // Статус графа

   private bool bRunning = false;

   // Размеры изображения

   private IntPtr handle = IntPtr.Zero;

   private int videoWidth;

   private int videoHeight;

   private int stride;

   public int Dropped = 0;

   [DllImport("Kernel32.dll", EntryPoint = "RtlMoveMemory")]

private static extern void CopyMemory(IntPtr Destination, IntPtr Source, int Length);

   public void Dispose()

   {

       CloseInterfaces();

       if (PictureReady != null)

       {

           PictureReady.Close();

           PictureReady = null;

       }

   }

   // Деструктор

   ~Capture()

   {

       Dispose();

   }

   public int Width

   {

       get { return videoWidth; }

   }

   public int Height

   {

       get { return videoHeight; }

   }

   public int Stride

   {

       get { return stride; }

   }

   // Захват следующего изображения

   public IntPtr GetBitMap()

   {

       handle = Marshal.AllocCoTaskMem(stride * videoHeight);

       try

       {

           PictureReady.Reset();

           bGotOne = false;

           // запускаем граф

           Start();

           // и начинаем ждать изображение

           if (!PictureReady.WaitOne(5000, false))

           {

               throw new Exception("Timeout waiting to get picture");

           }

       }

       catch

       {

           Marshal.FreeCoTaskMem(handle);

           throw;

       }

       // возвращаем указатель на изображение

       return handle;

   }

   // Начало захвата

   public void Start()

   {

       if (!bRunning)

       {

           int hr = mediaCtrl.Run();

           DsError.ThrowExceptionForHR(hr);

           bRunning = true;

       }

   }

   // Приостановка (пауза) захвата

   public void Pause()

   {

       if (bRunning)

       {

           int hr = mediaCtrl.Pause();

           DsError.ThrowExceptionForHR(hr);

           bRunning = false;

       }

   }

   // Общий конструктор класса Capture

   public Capture(VideoDescriptor desc)

   {

       DsDevice[] capDevices;

       // Получение всех устройств захвата

       capDevices = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice);

       if (desc.VideoDevice + 1 > capDevices.Length)

       {

           throw new Exception("Устройство захвата не найдено!");

       }

       try

       {

           // Вызов функции установки параметров захвата

SetupGraph(capDevices[desc.VideoDevice], desc.FrameRate, desc.VideoWidth, desc.VideoHeight);

           // Вызов CallBack для игнорирования новых изображений

           PictureReady = new ManualResetEvent(false);

           bGotOne = true;

           bRunning = false;

       }

       catch

       {

           Dispose();

           throw;

       }

   }

   // Инициализация Графа

private void SetupGraph(DsDevice dev, int iFrameRate, int iWidth, int iHeight)

   {

       int hr;

       ISampleGrabber sampGrabber = null;

       IBaseFilter capFilter = null;

       ICaptureGraphBuilder2 capGraph = null;

       // Получение объекта graphbuilder

       FilterGraph = (IFilterGraph2)new FilterGraph();

       mediaCtrl = FilterGraph as IMediaControl;

       try

       {

           // Получение ICaptureGraphBuilder2

           capGraph = (ICaptureGraphBuilder2)new CaptureGraphBuilder2();

           // Получение интерфейса SampleGrabber

           sampGrabber = (ISampleGrabber)new SampleGrabber();

           // Начало построения Графа

           hr = capGraph.SetFiltergraph(FilterGraph);

           DsError.ThrowExceptionForHR(hr);

           // Добавление в Граф устройство видеозахвата

hr = FilterGraph.AddSourceFilterForMoniker(dev.Mon, null, "Video input", out capFilter);

           DsError.ThrowExceptionForHR(hr);

           IBaseFilter baseGrabFlt = (IBaseFilter)sampGrabber;

           ConfigureSampleGrabber(sampGrabber);

           // Добавление в Граф фильтра-захвата

           hr = FilterGraph.AddFilter(baseGrabFlt, "Ds.NET Grabber");

           DsError.ThrowExceptionForHR(hr);

           if (iFrameRate + iHeight + iWidth > 0)

           {

SetConfigParms(capGraph, capFilter, iFrameRate, iWidth, iHeight);

           }

hr = capGraph.RenderStream(PinCategory.Capture, MediaType.Video, capFilter, null, baseGrabFlt);

           DsError.ThrowExceptionForHR(hr);

           SaveSizeInfo(sampGrabber);

       }

       finally

       {

           if (capFilter != null)

           {

               Marshal.ReleaseComObject(capFilter);

               capFilter = null;

           }

           if (sampGrabber != null)

           {

               Marshal.ReleaseComObject(sampGrabber);

               sampGrabber = null;

           }

           if (capGraph != null)

           {

               Marshal.ReleaseComObject(capGraph);

               capGraph = null;

           }

       }

   }

   private void SaveSizeInfo(ISampleGrabber sampGrabber)

   {

       int hr;

       // Получение типа информации из SampleGrabber

       AMMediaType media = new AMMediaType();

       hr = sampGrabber.GetConnectedMediaType(media);

       DsError.ThrowExceptionForHR(hr);

if ((media.formatType != FormatType.VideoInfo) || (media.formatPtr == IntPtr.Zero))

       {

           throw new NotSupportedException("Unknown Grabber Media Format");

       }

       // Размер захвачиваемой информации

VideoInfoHeader videoInfoHeader = (VideoInfoHeader)Marshal.PtrToStructure(media.formatPtr, typeof(VideoInfoHeader));

       videoWidth = videoInfoHeader.BmiHeader.Width;

       videoHeight = videoInfoHeader.BmiHeader.Height;

       stride = videoWidth * (videoInfoHeader.BmiHeader.BitCount / 8);

       DsUtils.FreeAMMediaType(media);

       media = null;

   }

   private void ConfigureSampleGrabber(ISampleGrabber sampGrabber)

   {

       AMMediaType media;

       int hr;

       // устанавливаем тип видео

       media = new AMMediaType();

       media.majorType = MediaType.Video;

       media.subType = MediaSubType.RGB24;

       media.formatType = FormatType.VideoInfo;

       hr = sampGrabber.SetMediaType(media);

       DsError.ThrowExceptionForHR(hr);

       DsUtils.FreeAMMediaType(media);

       media = null;

       // конфигурируем SampleGrabber

       hr = sampGrabber.SetCallback(this, 1);

       DsError.ThrowExceptionForHR(hr);

   }

   // Установка параметров видео

private void SetConfigParms(ICaptureGraphBuilder2 capGraph, IBaseFilter capFilter, int iFrameRate, int iWidth, int iHeight)

   {

       int hr;

       object o;

       AMMediaType media;

       // Нахождение потока конфигурации интерфейса

hr = capGraph.FindInterface(PinCategory.Capture, MediaType.Video, capFilter, typeof(IAMStreamConfig).GUID, out o);

       IAMStreamConfig videoStreamConfig = o as IAMStreamConfig;

       if (videoStreamConfig == null)

       {

           throw new Exception("Failed to get IAMStreamConfig");

       }

       // Получения блока действующего формата

       hr = videoStreamConfig.GetFormat(out media);

       DsError.ThrowExceptionForHR(hr);

       // Копирование из videoinfoheader

       VideoInfoHeader v = new VideoInfoHeader();

       Marshal.PtrToStructure(media.formatPtr, v);

       // Установка частоты кадров

       if (iFrameRate > 0)

       {

           v.AvgTimePerFrame = 10000000 / iFrameRate;

       }

       // Установка ширины

       if (iWidth > 0)

       {

           v.BmiHeader.Width = iWidth;

       }

       // Установка высоты

       if (iHeight > 0)

       {

           v.BmiHeader.Height = iHeight;

       }

       // Обратное копирование структуры информации

       Marshal.StructureToPtr(v, media.formatPtr, false);

       // Установка нового формата

       hr = videoStreamConfig.SetFormat(media);

       DsError.ThrowExceptionForHR(hr);

       DsUtils.FreeAMMediaType(media);

       media = null;

   }

   private void CloseInterfaces()

   {

       int hr;

       try

       {

           if (mediaCtrl != null)

           {

               // Остановка захвата

               hr = mediaCtrl.Stop();

               bRunning = false;

           }

       }

       catch (Exception ex)

       {

           Debug.WriteLine(ex);

       }

       if (FilterGraph != null)

       {

           Marshal.ReleaseComObject(FilterGraph);

           FilterGraph = null;

       }

   }

   int ISampleGrabberCB.SampleCB(double SampleTime, IMediaSample pSample)

   {

       if (!bGotOne)

       {

// Установка bGotOne для предотвращения вызова пока получаем новое изображение

           bGotOne = true;

           IntPtr pBuffer;

           pSample.GetPointer(out pBuffer);

           int iBufferLen = pSample.GetSize();

           if (pSample.GetSize() > stride * videoHeight)

           {

               throw new Exception("Buffer is wrong size");

           }

           CopyMemory(handle, pBuffer, stride * videoHeight);

           // Изображение готово

           PictureReady.Set();

       }

       Marshal.ReleaseComObject(pSample);

       return 0;

   }

int ISampleGrabberCB.BufferCB(double SampleTime, IntPtr pBuffer, int BufferLen)

   {

       if (!bGotOne)

       {

           // Проверка размера буффера

           if (BufferLen <= stride * videoHeight)

           {

               // Копирование изображения в Буфер

               CopyMemory(handle, pBuffer, stride * videoHeight);

           }

           else

           {

               throw new Exception("Buffer is wrong size");

           }

// Установка bGotOne для предотвращения вызова пока получаем новое изображение

           bGotOne = true;

           // Изображение готово

           PictureReady.Set();

       }

       else

       {

           Dropped++;

       }

       return 0;

   }

}


Disconnect

ClientInformation

ClientInfo

Success/Failed

Authorization/Registration

Сервер

лиент

TransferEnd

Блок обслуживания соединения

Медиаданные (UDP)

TransferSuccess/TransferFailed

TransferRequest

Клиент2

Клиент1

Блок сбора статистики

Блок создания соединений

Пользовательский интерфейс

Блок взаимодействия с клиентами

Блок взаимодействия с сервером


 

А также другие работы, которые могут Вас заинтересовать

33447. Основной капитал организации 22.77 KB
  Обе части основного капитала организации в свою очередь подразделяются на следующие группы: здания; сооружения; рабочие и силовые машины и оборудование; измерительные и регулирующие приборы и устройства; вычислительная техника; транспортные средства; инструмент; производственный и хозяйственный инвентарь; рабочий продуктовый племенной скот и многолетние насаждения; прочие основные средства; капитальные вложения на коренное улучшение земель; капитальные вложения в арендованные объекты; земельные участки и объекты пользования находящиеся в...
33448. ПОТОК РЕАЛЬНЫХ ДЕНЕГ 22.24 KB
  Входящие в расчет потоки реальных денег при этом исчисляются по всем видам деятельности участника с учетом условий предоставления и погашения займов. Поток реальных денег от инвестиционной деятельности складывается из различных видов доходов приток и затрат отток распределенных по периодам осуществления инвестиционного проекта шагам расчета которые включают:1. всего инвестиций 56 Поток реальных денег от операционной деятельности включает в себя виды потоков и затрат распределенных по периодам осуществления инвестиционного проекта...
33449. Риск в предпринимательстве 22.74 KB
  Риск в предпринимательстве выполняет ряд созидательных функций: регулятивную функцию состоящую в том что рискованные решения предполагают активную деятельность поиск новаторских идей творческий подход; инновационную функцию поскольку риск предпринимателя ориентирован на осуществление нововведений позволяющих преодолевать неопределенности; аналитическую функцию так как принятие решений в ситуации риска сопровождается разработкой ряда альтернатив и отбором предпочтительного варианта рассчитанного на достижение успеха при допустимом...
33450. Прибыль — разница между доходами (выручки от реализации товаров и услуг) и затратами на производство или приобретение и сбыт этих товаров и услуг 23.09 KB
  Прибыль предприятия является важнейшей экономической категорией и основной целью деятельности любой коммерческой организации. Как экономическая категория прибыль отражает чистый доход созданный в сфере материального производства. Прибыль является показателем наиболее полно отражающим эффективность производства. Это обусловлено тем что акционерные арендные частные предприятия и предприятия других форм собственности получив финансовую самостоятельность и независимость вправе решать на какие цели и в каких размерах направлять прибыль...
33451. Виды операционных потоков наличности 21.41 KB
  Наличная продажа; 2. Продажа активов. Продажа ценных бумаг3.
33452. Прибыль предприятия, как экономическая категория 22.73 KB
  Суммарные доходы в зависимости от их характера условий получения и направлений деятельности предприятия подразделяются на доходы от обычных видов деятельности; операционные доходы; внереализационные доходы; чрезвычайные доходы. Суммарные расходы в зависимости от их характера условий осуществления и направлений деятельности предприятия делятся на расходы по обычным видам деятельности; операционные расходы; внереализационные расходы; чрезвычайные расходы. На предприятиях прибыль формируется как сумма финансовых результатов по всем видам...
33453. Рентабельность 25.07 KB
  Рентабельность комплексно отражает степень эффективности использования материальных трудовых и денежных ресурсов а также природных богатств. Показатели рентабельности часто выражают в процентах Рентабельность продукции; основных; продаж; персонала; Коэффициент базовой прибыльности; активов; собственного капитала; инвестированного перманентного капитала; примененного капитала ROCE; суммарных активов ROT; активов бизнеса ROB; чистых активов; производства; наценки; Различают три вида рентабельности: производства; продукции ; ...
33454. Себестоимость 23.74 KB
  Более полное определение себестоимости: Себестоимость это стоимостная оценка используемых в процессе производства продукции работ услуг природных ресурсов сырья материалов топлива энергии основных фондов трудовых ресурсов и других затрат на ее производство и реализацию В экономической науке и для прикладных задач выделяется несколько типов себестоимости:1 Полная себестоимость средняя соотношение полных издержек к объему производства;2 Предельная себестоимость это себестоимость каждой последующей произведенной единицы...
33455. Собственный капитал 22.64 KB
  Собственный капитал состоит из следующих статей: уставного капитала ; нераспредёленной прибыли заработанной предприятием в результате эффективной деятельности и остающуюся в его распоряжении; добавочного капитала ; резервного капитала резервного фонда создающегося из чистой прибыли; фонд потребления. Структура основного капитала – это доля каждой из групп в их общей стоимости. Не все группы основного капитала играют в процессе производства одинаковую роль. Активная часть основного капитала является ведущей и служит базой в оценке...