Click here to Skip to main content
15,879,348 members
Articles / Programming Languages / C#

Web-Cam SecureChat

Rate me:
Please Sign up or sign in to vote.
4.94/5 (16 votes)
12 Mar 2010CPOL6 min read 93.5K   7.4K   70   42
This article will explain how to create a simple chat program using this remoting technology, which supports web-cam and sending files.

Introduction

This article explains how to create a simple Secure Chat with WebCam support using Pfz.Remoting.

Background

I've already written some articles about communication, in special Pfz.Remoting and Creating an Asymmetric/Symmetric Secure Stream without SSL, which is in fact part of the remoting DLL. This article will explain how to create a simple chat program using this remoting technology, which supports web-cam and sending files.

I then wanted to create an article explaining how to create a simple multi-user chat but, when I saw AForge and its video capture capabilities, I wanted to create a chat program with web-cam support. In the end, I created a very basic chat, almost without exception handling, but the important part is that it supports web-cam and audio capture with multiple clients.

The Principle

The principle is very simple. Data can be lost. This is not a very big problem for video, it can be for audio, but it is not possible to simple avoid it.

For example, the program receiving the web-cam frames can receive 10 frames, but the client which receives it can only be able to receive 5. Intermediate frames must be lost.

Also, in the architecture I made for this sample, everything goes throught the server. So, the web-cam owner receives 10 frames. The server receives only seven frames. And it can distribute the frames it receives among its clients, which one can be able to receive them all (the 7), another can receive only 3 and another can receive only 5. So, how do we distribute the data?

ActualValueEnumerator and EnumeratorDistributor

I created two main classes that help the distribution of data that "can be lost". The ActualValueEnumerator is a class that "enumerates" throught its values, and waits for new values when all values are already read. But, if two or more values appears before the "enumerator" is able to read them, only the last one (the actual) remains. That's why I called the class ActualValueEnumerator.

In the first version of the article I made the WebCamEnumerator class using ManualResetEvent, but it was ugly. Now it is very simple. So, look at the code:

C#
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using AForge.Video;
using AForge.Video.DirectShow;
using Pfz.Collections;
 
namespace SecureChat.Client
{
	public sealed class WebCamEnumerator:
		ActualValueEnumerator<byte[]>
	{
		private volatile VideoCaptureDevice fDevice;
		public WebCamEnumerator(string monikerString)
		{
			var device = new VideoCaptureDevice(monikerString);
			fDevice = device;
			device.DesiredFrameSize = new Size(160, 120);
			device.NewFrame += p_NewFrame;
			device.Start();
		}
		protected override void Dispose(bool disposing)
		{
			var device = fDevice;
			if (device != null)
			{
				fDevice = null;
				device.SignalToStop();
				device.WaitForStop();
			}
 
 			 base.Dispose(disposing);
		}
 
		private void p_NewFrame(object sender, NewFrameEventArgs eventArgs)
		{
			var image = (Bitmap)eventArgs.Frame;
			
			using(var stream = new MemoryStream())
			{
				image.Save(stream, ImageFormat.Jpeg);
				ActualValue = stream.ToArray();
			}
		}
	}
}

The important things here are: In the constructor, it starts the web-cam and sets the NewFrame event. In the dispose it stops the web-cam. And, in the new frame, it generates the byte array of the image and sets the ActualValue to such bytes. I convert the image to bytes so the server does not need to know how to process graphics... it only receives bytes and distribute bytes to the clients. It may not be "visible" in the first moment, but as this class inherits from ActualValueEnumerator, it can be used in a foreach (must use Pfz.Extensions.FastEnumeratorExtensions and the AsEnumerable method) and it already deals with the possibility of loosing frames.

The server is always a bit more complicated, and I must admit I made it hard. I will try to make it easier and re-update the article, but to help the server be less-complicated I created the EnumeratorDistributor class. Similar to the ActualValueEnumerator, it allows values to be lost. But, instead of being an enumerator itself, it must be used over another enumerator, and each client gets its own enumerator which allows the frames to be lost. So, different speed clients will receive different number of values. So, to use it, the server receives the enumerator from one client (for example, the server receives the WebCamEnumerator from one client), and creates an EnumeratorDistributor over it. Each client that is now interested in such web-cam will get a new enumerator (throught the CreateClient method), which will always receive the last frame from such base enumerator. If frames are to be skipped, they will be.

The project As I said earlier, the server is still more complicated than it needs to be, but the basic idea here is: There is the Common library, in which the classes and interfaces used by both client and server are present. Note that any method the client needs to call in the server or that the client must call in the client must be done via interfaces, which are here.

There is the server project, which supports the client connections and implements the server part, so it is responsible for telling all other clients when a new one connects and to find another client, requests its web-cam or sound-capture device and returning the appropriate enumerator when someone asks for the web-cam or sound from another client. And the client project. It is "simpler" than the server as it does not need to deals with many clients, but it must be able to capture video and sound and must be able to play them. Actually, when one client wants the video or sound from another one, it must request the Server for such information, which will be returned as a IFastEnumerator. The IFastEnumerator is faster than a custom enumerator over the TCP/IP, as instead of first calling "MoveNext" (which sends and receives information) and then Current (which agains sends and receives information) it uses only GetNext, which can return null to tell there are no more values. Well, I hope this little explanation and the source-code is enough for anyone trying to create an application which remote web-cam or sound-capture support.

The Samples

If you want to try the samples, you must:

  • Run the server in command prompt with any parameter (I use the parameter DEBUG), or install it with installutil and then start the service.
  • Run a local client normally, if you want.
  • Change the app.config to point to the server host and run a client from another computer. Having more clients is better.
  • Actually the user-name is taken from the user logged in the system, and this user can't log many times in the same server. Someone must start his own web-cam (be it a fake web-cam or a real one). Then, the others can ask to start that clients' web-cam.

The program supports simple chat and file transfer (drag-and-drop a file over a user name). Dragging a file to your own name will do a really wasteful work of sending the file to the server and then sending the file back to the client.

History

  • 17th December, 2009: Initial post
  • 11th January, 2010: New version of webcam source - This version has corrected a bug in the server, where a client with two webcams will only send the first one for the clients, not importing which one the client asked. Also, it has corrected a bug when sending files with more than 2GB.
  • 12th March, 2010: Added very basic support to sound capture.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Microsoft
United States United States
I started to program computers when I was 11 years old, as a hobbyist, programming in AMOS Basic and Blitz Basic for Amiga.
At 12 I had my first try with assembler, but it was too difficult at the time. Then, in the same year, I learned C and, after learning C, I was finally able to learn assembler (for Motorola 680x0).
Not sure, but probably between 12 and 13, I started to learn C++. I always programmed "in an object oriented way", but using function pointers instead of virtual methods.

At 15 I started to learn Pascal at school and to use Delphi. At 16 I started my first internship (using Delphi). At 18 I started to work professionally using C++ and since then I've developed my programming skills as a professional developer in C++ and C#, generally creating libraries that help other developers do their work easier, faster and with less errors.

Want more info or simply want to contact me?
Take a look at: http://paulozemek.azurewebsites.net/
Or e-mail me at: paulozemek@outlook.com

Codeproject MVP 2012, 2015 & 2016
Microsoft MVP 2013-2014 (in October 2014 I started working at Microsoft, so I can't be a Microsoft MVP anymore).

Comments and Discussions

 
GeneralRe: Is a web version of this application possible? Pin
Paulo Zemek6-Mar-10 6:25
mvaPaulo Zemek6-Mar-10 6:25 
Generalwebcam code Pin
Spricer31-Jan-10 8:17
Spricer31-Jan-10 8:17 
GeneralRe: webcam code Pin
Paulo Zemek31-Jan-10 12:55
mvaPaulo Zemek31-Jan-10 12:55 
GeneralRe: webcam code Pin
Spricer23-Mar-10 1:46
Spricer23-Mar-10 1:46 
GeneralRe: webcam code Pin
Paulo Zemek23-Mar-10 12:40
mvaPaulo Zemek23-Mar-10 12:40 
Generalnice application Pin
contact_ashishjain6-Jan-10 5:43
contact_ashishjain6-Jan-10 5:43 
GeneralRe: nice application Pin
Paulo Zemek6-Jan-10 11:37
mvaPaulo Zemek6-Jan-10 11:37 
GeneralRe: nice application Pin
Paulo Zemek14-Jan-10 7:51
mvaPaulo Zemek14-Jan-10 7:51 
Download the new source-code. It may solve your problem with many web-cams.
GeneralRe: nice application Pin
Paulo Zemek2-Mar-10 12:05
mvaPaulo Zemek2-Mar-10 12:05 
GeneralRe: Nice App! & a few questions. Pin
Paulo Zemek29-Dec-09 1:26
mvaPaulo Zemek29-Dec-09 1:26 
GeneralRe: Nice App! & a few questions. Pin
Paulo Zemek29-Dec-09 4:17
mvaPaulo Zemek29-Dec-09 4:17 
GeneralRe: Nice App! & a few questions. Pin
Paulo Zemek30-Dec-09 0:48
mvaPaulo Zemek30-Dec-09 0:48 
GeneralThe code, the code ! Pin
Nicolas Dorier19-Dec-09 9:27
professionalNicolas Dorier19-Dec-09 9:27 
GeneralRe: The code, the code ! Pin
Paulo Zemek19-Dec-09 10:57
mvaPaulo Zemek19-Dec-09 10:57 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.