Logo Search packages:      
Sourcecode: galaxium version File versions  Download package

WebcamConnection.cs

/*
 * Galaxium Messenger
 * 
 * Copyright (C) 2008 Paul Burton <paulburton89@gmail.com>
 * 
 * License: GNU General Public License (GPL)
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;

using Anculus.Core;

using Galaxium.Core;
using Galaxium.Protocol;

namespace Galaxium.Protocol.Msn
{
      public class WebcamConnection
      {
            public event EventHandler<WebcamFrameReceivedEventArgs> FrameReceived;
            
            XmlElement _xml;
            MsnSession _session;
            MsnContact _remote;
            byte[] _buffer = new byte[0];
            IConnection _connection;
            List<KeyValuePair <string, int>> _addresses = new List<KeyValuePair <string, int>> ();
            bool _connected;
            
            const string _connectedString = "connected\r\n\r\n";
            
            protected string Auth
            {
                  get
                  {
                        return string.Format ("recipientid={0}&sessionid={1}", RecipientID, SessionID);
                  }
            }
            
            public bool Connected
            {
                  get { return _connected; }
            }
            
            public int RecipientID
            {
                  get { return int.Parse (MsnXmlUtility.FindChild (_xml, "rid").InnerText); }
            }
            
            public int SessionID
            {
                  get { return int.Parse (MsnXmlUtility.FindChild (_xml, "session").InnerText); }
            }
            
            public string LocalXml
            {
                  get
                  {
                        //TODO: we need to find an available port
                        int port = 80;
                        
                        //TODO: we need to know our IP addresses, both internal and external
                        // We can get our external IP from our profile data
                        //--> IP's + ports should be retrieved using the port mapping utility
                        
                        return "<viewer><version>2.0</version><rid>" + RecipientID +
                              "</rid><udprid>" + (RecipientID + 1).ToString () +
                              "</udprid><session>" + SessionID.ToString () +
                              "</session><ctypes>0</ctypes><cpu>2931</cpu>" +
                              "<tcp><tcpport>" + port.ToString () +
                              "</tcpport>\t\t\t\t\t\t\t\t  <tcplocalport>" + port.ToString () +
                              "</tcplocalport>\t\t\t\t\t\t\t\t  <tcpexternalport>" + port.ToString () +
                              "</tcpexternalport><tcpipaddress>192.168.0.1</tcpipaddress></tcp>" +
                              "<udp><udplocalport>7786</udplocalport><udpexternalport>31863</udpexternalport><udpexternalip>192.168.0.1" +
                              "</udpexternalip><a1_port>31859</a1_port><b1_port>31860</b1_port><b2_port>31861</b2_port>" +
                              "<b3_port>31862</b3_port><symmetricallocation>1</symmetricallocation><symmetricallocationincrement>1</symmetricallocationincrement>" +
                              "<udpversion>1</udpversion><udpinternalipaddress1>127.0.0.1</udpinternalipaddress1></udp>" +
                              "<codec></codec><channelmode>1</channelmode></viewer>\r\n\r\n";
                  }
            }
            
            public MsnSession Session
            {
                  get { return _session; }
            }
            
            public WebcamConnection (MsnContact remote, XmlElement xml)
            {
                  _xml = xml;
                  _remote = remote;
                  _session = _remote.Session as MsnSession;
                  
                  int port = int.Parse (MsnXmlUtility.FindElement (_xml, "tcp/tcpport").InnerText);
                  
                  foreach (XmlNode node in MsnXmlUtility.FindChild (_xml, "tcp"))
                  {
                        if (node.LocalName.StartsWith ("tcpipaddress"))
                              _addresses.Add (new KeyValuePair <string, int> (node.InnerText, port));
                  }
                  
                  _connection = new Galaxium.Protocol.TCPConnection (_session, new WebcamConnectionInfo (_addresses[0].Key, _addresses[0].Value));
                  _connection.AfterConnect += OnConnected;
                  _connection.Closed += OnClosed;
                  _connection.DataReceived += OnDataReceived;
            }
            
            public void Connect ()
            {
                  _connection.Connect ();
            }
            
            void OnConnected (object sender, ConnectionEventArgs args)
            {
                  Log.Debug ("Connected, sending auth ({0})", Auth);
                  
                  _connection.Send (Encoding.UTF8.GetBytes (Auth + "\r\n\r\n"));
            }
            
            void OnClosed (object sender, ConnectionEventArgs args)
            {
                  Log.Debug ("Closed");
            }
            
            void OnDataReceived (object sender, ConnectionDataEventArgs args)
            {
                  AppendToBuffer (args.Buffer, args.Length);
                  
                  if (!_connected)
                  {
                        if (_buffer.Length < _connectedString.Length)
                              return;
                        
                        string str = Encoding.UTF8.GetString (ReadBuffer ((uint)_connectedString.Length));
                        ShrinkBuffer ((uint)_connectedString.Length);

                        if (str != _connectedString)
                        {
                              Log.Error ("Received something other than connected string");
                              Log.Debug (str);
                              
                              return;
                        }
                        
                        _connected = true;
                        return;
                  }
                  
                  if (_buffer.Length < 24)
                  {
                        //Log.Debug ("Waiting until header is received");
                        return;
                  }
                  
                  byte[] header = ReadBuffer (24);
                  uint size = (uint)(header[8] + (header[9] << 8) + (header[10] << 16) + (header[11] << 24));
                  
                  if (_buffer.Length < 24 + size)
                  {
                        //Log.Debug ("Waiting until {0} bytes received", 24 + size);
                        return;
                  }
                  
                  // We now have enough data for a frame
                  
                  // Remove the header from the buffer
                  ShrinkBuffer (24);
                  
                  byte[] data = ReadBuffer (size);
                  ShrinkBuffer (size);
                  
                  if (FrameReceived != null)
                        FrameReceived (this, new WebcamFrameReceivedEventArgs (data, 0, 0));
            }
            
            void AppendToBuffer (byte[] data, int length)
            {
                  byte[] newBuffer = new byte[_buffer.Length + length];

                  Array.Copy (_buffer, 0, newBuffer, 0, _buffer.Length);
                  Array.Copy (data, 0, newBuffer, _buffer.Length, length);

                  _buffer = newBuffer;
            }
            
            byte[] ReadBuffer (uint size)
            {
                  byte[] data = new byte[size];
                  Array.Copy (_buffer, 0, data, 0, size);
                  return data;
            }
            
            void ShrinkBuffer (uint skip)
            {
                  if (skip > _buffer.Length)
                        skip = (uint)_buffer.Length;
                  
                  byte[] newBuffer = new byte[_buffer.Length - skip];

                  if (newBuffer.Length > 0)
                        Array.Copy (_buffer, skip, newBuffer, 0, newBuffer.Length);

                  _buffer = newBuffer;
            }
            
            class WebcamConnectionInfo : AbstractConnectionInfo
            {
                  public WebcamConnectionInfo (string host, int ip)
                        : base (host, ip, false)
                  {
                  }
            }
      }
}

Generated by  Doxygen 1.6.0   Back to index