Logo Search packages:      
Sourcecode: farsight version File versions

msnwebcam.c

/*
 * Farsight MSN Video Conference Module
 * Copyright (C) 2005 Rob Taylor, Philippe Khalaf
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser 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 Lesser 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
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif 

#include <string.h>
#include <libxml/xmlreader.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>

#include <farsight/farsight-plugin.h>

#include "msnwebcam.h"

enum {
   ARG_0,
   ARG_LOCALXML,
   ARG_REMOTEXML
};

static void     farsight_msnwebcam_class_init    (FarsightMsnWebcamClass *klass);
static void     farsight_msnwebcam_init          (FarsightMsnWebcam      *msnwebcam);

static void     farsight_msnwebcam_connect       (FarsightProtocol *protocol);
static void     farsight_msnwebcam_disconnect    (FarsightProtocol *protocol);
static GstElement *
                farsight_msnwebcam_create_bin    (FarsightProtocol *protocol);

static void     farsight_msnwebcam_finalize      (GObject      *object);
static void     farsight_msnwebcam_set_property  (GObject      *object, 
                                            guint             prop_id,
                                            const GValue     *value, 
                                            GParamSpec       *pspec);
static void     farsight_msnwebcam_get_property  (GObject          *object, 
                                            guint             prop_id, 
                                            GValue           *value,
                                            GParamSpec       *pspec);


static gboolean farsight_msnwebcam_authenticate_incoming (FarsightMsnWebcam *msnwebcam, gint fd);
static gboolean farsight_msnwebcam_authenticate_outgoing (FarsightMsnWebcam *msnwebcam, gint fd);

static GObjectClass *parent_class = NULL;

GType
farsight_msnwebcam_get_type (void)
{
    static GType type = 0;

    if (type == 0) {
        static const GTypeInfo info = {
            sizeof (FarsightMsnWebcamClass),
            NULL,
            NULL,
            (GClassInitFunc) farsight_msnwebcam_class_init,
            NULL,
            NULL,
            sizeof (FarsightMsnWebcam),
            0,
            (GInstanceInitFunc) farsight_msnwebcam_init
        };

        type = g_type_register_static (FARSIGHT_PROTOCOL_TYPE,
                                       "FarsightMsnWebcamType",
                                       &info, 0);
    }

    return type;
}

static void
farsight_msnwebcam_class_init (FarsightMsnWebcamClass *klass)
{
    GObjectClass *gobject_class;
    FarsightProtocolClass *farsight_protocol_class;

    gobject_class = (GObjectClass *) klass;
    farsight_protocol_class = (FarsightProtocolClass*) klass;
    parent_class = g_type_class_peek_parent (klass);

    farsight_protocol_class->connect = farsight_msnwebcam_connect;
    farsight_protocol_class->disconnect = farsight_msnwebcam_disconnect;
    farsight_protocol_class->create_bin = farsight_msnwebcam_create_bin;

    gobject_class->finalize = farsight_msnwebcam_finalize;

    gobject_class->set_property = farsight_msnwebcam_set_property;
    gobject_class->get_property = farsight_msnwebcam_get_property;

    g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LOCALXML,
        g_param_spec_string ("localxml", "Local XML",
            "The local xml block as returned from MSN Webcam negotiation, converted to utf-8",
            "", G_PARAM_READWRITE));

    g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_REMOTEXML,
        g_param_spec_string ("remotexml", "Remote XML",
            "The remote xml block as returned from MSN Webcam negotiation, converted to utf-8",
            "", G_PARAM_READWRITE));
}

static void
init_xml_info_struct (MsnWebcamXmlInfo *info)
{
    info->tcpaddress1 = NULL;
    info->tcpaddress2 = NULL;
    info->tcpaddress3 = NULL;

    info->tcpport = 0;
    info->tcplocalport = 0;
    info->tcpexternalport = 0;
}

static void
farsight_msnwebcam_init (FarsightMsnWebcam *msnwebcam)
{
    msnwebcam->localxml= NULL;
    msnwebcam->remotexml = NULL;

    init_xml_info_struct (&(msnwebcam->localinfo));
    init_xml_info_struct (&(msnwebcam->remoteinfo));

    msnwebcam->connection = NULL;

    msnwebcam->fdlist = g_array_new (FALSE, FALSE, sizeof(GIOChannel *));
}

static void
processNode(FarsightMsnWebcam *msnwebcam, xmlTextReaderPtr reader, gboolean is_local) {
    const xmlChar *name; 
    const xmlChar *value;

    MsnWebcamXmlInfo *info = NULL;

    if (is_local)
    {
        info = &(msnwebcam->localinfo);
    }
    else
    {
        info = &(msnwebcam->remoteinfo);
    }

    name = xmlTextReaderConstName(reader);

    if(xmlTextReaderNodeType(reader)==1)
    {
        if (is_local && strcmp (name, "viewer")==0 && xmlTextReaderRead(reader))
        {
            msnwebcam->session_type = VIEWER;
        }
        else if (is_local && strcmp (name, "producer")==0 && xmlTextReaderRead(reader))
        {
            msnwebcam->session_type = PRODUCER;
        }
        else if (strcmp (name, "rid")==0 && xmlTextReaderRead(reader))
        {
            value = xmlTextReaderConstValue(reader);
            if (value)
                info->recipientid=atol(value);
        }
        else if (strcmp (name, "udprid")==0 && xmlTextReaderRead(reader))
        {
            value = xmlTextReaderConstValue(reader);
            if (value)
                info->udp_recipientid=atol(value);
        }
        else if (strcmp (name, "session")==0 && xmlTextReaderRead(reader))
        {
            value = xmlTextReaderConstValue(reader);
            if (value)
                info->sessionid=atol(value);
        }
        else if (strcmp (name, "tcpport")==0 && xmlTextReaderRead(reader))
        {
            value = xmlTextReaderConstValue(reader);
            if (value)
                info->tcpport=atol(value);
        }
        else if (strcmp (name, "tcplocalport")==0 && xmlTextReaderRead(reader))
        {
            value = xmlTextReaderConstValue(reader);
            if (value)
                if (atol(value) != info->tcpport)
                    info->tcplocalport=atol(value);
        }
        else if (strcmp (name, "tcpexternalport")==0 && xmlTextReaderRead(reader))
        {
            value = xmlTextReaderConstValue(reader);
            if (value)
                if (atol(value) != info->tcpport &&
                        atol(value) != info->tcplocalport)
                    info->tcpexternalport=atol(value);
        }
        else if (strcmp (name, "tcpipaddress1")==0 && xmlTextReaderRead(reader))
        {
            value = xmlTextReaderConstValue(reader);
            if (value)
                info->tcpaddress1 = (gchar *)strdup(value);
        }
        else if (strcmp (name, "tcpipaddress2")==0 && xmlTextReaderRead(reader))
        {
            value = xmlTextReaderConstValue(reader);
            if (value)
                if (strcmp (value, info->tcpaddress1) != 0)
                    info->tcpaddress2 = (gchar *)strdup(value);
        }
        else if (strcmp (name, "tcpipaddress3")==0 && xmlTextReaderRead(reader))
        {
            value = xmlTextReaderConstValue(reader);
            if (value)
                if ( (strcmp (value, info->tcpaddress1) != 0) &&
                 (strcmp (value, info->tcpaddress2) != 0) )
                    info->tcpaddress3 = (gchar *)strdup(value);
        }
    }
}

static void
farsight_msnwebcam_parse_xml (FarsightMsnWebcam *msnwebcam, gboolean is_local)
{
    xmlTextReaderPtr reader;
    gint ret;

    gchar *xml;
    if (is_local)
    {
        xml = msnwebcam->localxml;
    }
    else
    {
        xml = msnwebcam->remotexml;
    }

    reader = xmlReaderForMemory(xml, strlen (xml), "", NULL, 0);
    if (reader != NULL) {
        ret = xmlTextReaderRead(reader);
        while (ret == 1) {
            processNode(msnwebcam, reader, is_local);
            ret = xmlTextReaderRead(reader);
        }
        xmlFreeTextReader(reader);
        if (ret != 0) {
            //xml was incomplete. raise an error.
        }
    } else {
        //failed to create xml reader, out of mem? raise error
    }
}

// Called when the main connection disconnects
static gboolean
main_fd_closed_cb (GIOChannel *ch, GIOCondition cond, gpointer data)
{
    FarsightMsnWebcam *msnwebcam = FARSIGHT_MSNWEBCAM (data);

    g_message ("disconnection on video feed %p %p", ch, msnwebcam->connection);
    g_source_remove (msnwebcam->connect_watch);

    farsight_protocol_disconnect (FARSIGHT_PROTOCOL (msnwebcam));

    return FALSE;
}

// called when someone tries to connect to us
// we will try to accept it
static gboolean
fd_accept_connection_cb (GIOChannel *ch, GIOCondition cond, gpointer data)
{
    FarsightMsnWebcam *msnwebcam = FARSIGHT_MSNWEBCAM (data);
    struct sockaddr_in in;
    int fd;
    GIOChannel *newchan = NULL;
    socklen_t n = sizeof (in);

    if (!(cond & G_IO_IN))
    {
        g_message ("Error in condition not G_IO_IN");
        return FALSE;
    }

    if ((fd = accept(g_io_channel_unix_get_fd (ch), (struct sockaddr*) &in, &n)) == -1)
    {
        g_message ("Error while running accept() %d", errno);
        return FALSE;
    }

    // ok we got a connection, let's set it up
    newchan = g_io_channel_unix_new (fd);
    g_io_channel_set_close_on_unref (newchan, TRUE);

    /* Remove NON BLOCKING MODE */
    if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_NONBLOCK) != 0)
    {
        g_warning ("fcntl() failed");
        goto error;
    }

    // now we try to auth
    if (farsight_msnwebcam_authenticate_incoming (msnwebcam, fd))
    {
        g_message ("Authenticated successfully fd %d", fd);
        msnwebcam->connection = newchan;

        // success! we need to shutdown/close all other channels 
        gint i;
        for (i = 0; i < msnwebcam->fdlist->len; i++)
        {
            GIOChannel *chan = g_array_index(msnwebcam->fdlist, GIOChannel*, i);
            if (chan != newchan)
            {
                g_message ("closing fd %d", g_io_channel_unix_get_fd (chan));
                g_io_channel_shutdown (chan, TRUE, NULL);
                g_io_channel_unref (chan);
                g_array_remove_index (msnwebcam->fdlist, i);
            }
        }
        g_source_remove (msnwebcam->connect_watch);

        // add a watch on this fd to when it disconnects
        msnwebcam->connect_watch = g_io_add_watch (newchan, 
                (G_IO_ERR|G_IO_HUP|G_IO_NVAL), 
                main_fd_closed_cb, msnwebcam);

        FARSIGHT_PROTOCOL_CLASS (parent_class)->connected (FARSIGHT_PROTOCOL (msnwebcam));
        return FALSE;
    }

    /* Error */
error:
    g_message ("Got error from fd %d, closing", fd);
    // find, shutdown and remove channel from fdlist
    gint i;
    for (i = 0; i < msnwebcam->fdlist->len; i++)
    {
        GIOChannel *chan = g_array_index(msnwebcam->fdlist, GIOChannel*, i);
        if (newchan == chan)
        {
            g_io_channel_shutdown (chan, TRUE, NULL);
            g_io_channel_unref (chan);
            g_array_remove_index (msnwebcam->fdlist, i);
        }
    }

    return FALSE;
}

// Open servers on all local ports in xml
static void
farsight_msnwebcam_open_listening_ports (FarsightMsnWebcam *msnwebcam)
{
    guint16 ports[NUM_PORTS];

    g_message ("Ports are %d %d %d", msnwebcam->localinfo.tcpport, msnwebcam->localinfo.tcplocalport, msnwebcam->localinfo.tcpexternalport);
    ports[0] = msnwebcam->localinfo.tcpport;
    ports[1] = msnwebcam->localinfo.tcplocalport;
    ports[2] = msnwebcam->localinfo.tcpexternalport;

    gint i;
    for (i = 0; i < NUM_PORTS; i++)
    {
        if (ports[i] == 0)
        {
            // don't process non set ports
            continue;
        }

        GIOChannel *chan;
        gint fd = -1;
        struct sockaddr_in theiraddr;
        memset(&theiraddr, 0, sizeof(theiraddr));

        if ( (fd = socket(PF_INET, SOCK_STREAM, 0)) == -1 )
        {
            // show error
            g_message ("could not create socket!");
            continue;
        }

        // set non-blocking mode
        fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);

        theiraddr.sin_family = AF_INET;
        theiraddr.sin_port = htons (ports[i]);

        // bind
        if (bind(fd, (struct sockaddr *) &theiraddr, sizeof(theiraddr)) != 0)
        {
            close (fd);
            continue;
        }

#if 0
        // get sockname, do i need this? 
        socklen = GNET_SOCKADDR_LEN(sa);
        if (getsockname(fd, &GNET_SOCKADDR_SA(sa), &socklen) != 0)
        {
            close (fd);
            continue;
        }
#endif

        /* Listen */
        if (listen(fd, 3) != 0)
        {
            close (fd);
            continue;
        }

        g_message ("Listening on port %d", ports[i]);

        chan = g_io_channel_unix_new (fd);
        g_io_channel_set_close_on_unref (chan, TRUE);
        g_array_append_val (msnwebcam->fdlist, chan);

        msnwebcam->connect_watch = g_io_add_watch(chan,
                G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
                fd_accept_connection_cb, msnwebcam);
    }
}

// Called when an outgoing connection attempt succeeds
static gboolean 
successfull_connection_cb (GIOChannel *ch, GIOCondition cond, gpointer data)
{
    FarsightMsnWebcam *msnwebcam = FARSIGHT_MSNWEBCAM (data);
    gint error, len;
    gint fd = g_io_channel_unix_get_fd (ch);

    g_message ("handler called on fd %d", fd);

    errno = 0;
    if (!((cond & G_IO_IN) || (cond & G_IO_OUT)))
    {
        g_message ("Condition received is %d", cond);
        goto error;
    }

    len = sizeof(error);

    /* Get the error option */
    if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*) &error, &len) < 0)
    {
        g_warning ("getsockopt() failed");
        goto error;
    }

    /* Check if there is an error */
    if (error)
    {
        g_message ("getsockopt gave an error : %d", error);
        goto error;
    }

    /* Remove NON BLOCKING MODE */
    if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_NONBLOCK) != 0)
    {
        g_warning ("fcntl() failed");
        goto error;
    }

    g_message ("Got connection on fd %d", fd);

    //g_source_remove (msnwebcam->connect_watch);
    //g_io_channel_unref (ch);
    // let's try to auth on this connection
    if (farsight_msnwebcam_authenticate_outgoing (msnwebcam, fd))
    {
        g_message ("Authenticated successfully fd %d", fd);
        msnwebcam->connection = ch;

        // success! we need to shutdown/close all other channels 
        gint i;
        for (i = 0; i < msnwebcam->fdlist->len; i++)
        {
            GIOChannel *chan = g_array_index(msnwebcam->fdlist, GIOChannel*, i);
            if (chan != ch)
            {
                g_message ("closing fd %d", g_io_channel_unix_get_fd (chan));
                g_io_channel_shutdown (chan, TRUE, NULL);
                g_io_channel_unref (chan);
                g_array_remove_index (msnwebcam->fdlist, i);
            }
        }
        g_source_remove (msnwebcam->connect_watch);

        // add a watch on this fd to when it disconnects
        msnwebcam->connect_watch = g_io_add_watch (ch, 
                (G_IO_ERR|G_IO_HUP|G_IO_NVAL), 
                main_fd_closed_cb, msnwebcam);

        FARSIGHT_PROTOCOL_CLASS (parent_class)->connected (FARSIGHT_PROTOCOL (msnwebcam));
        return FALSE;
    }
    else
    {
        g_message ("Authentification failed on fd %d", fd);
    }

    /* Error */
error:
    g_message ("Got error from fd %d, closing", fd);
    // find, shutdown and remove channel from fdlist
    gint i;
    for (i = 0; i < msnwebcam->fdlist->len; i++)
    {
        GIOChannel *chan = g_array_index(msnwebcam->fdlist, GIOChannel*, i);
        if (ch == chan)
        {
            g_io_channel_shutdown (chan, TRUE, NULL);
            g_io_channel_unref (chan);
            g_array_remove_index (msnwebcam->fdlist, i);
        }
    }

    return FALSE;
}

// Called when the allowed time for connecting is over
// after that we try the deflector
static gboolean
attempt_timeout_cb (gpointer data)
{
    FarsightMsnWebcam *msnwebcam = FARSIGHT_MSNWEBCAM (data);

    if (msnwebcam->connection == NULL)
    {
        g_message ("Connections timed out, trying deflector now");

        if (msnwebcam->connect_watch)
            g_source_remove (msnwebcam->connect_watch);

        // close all channels and remove from fdlist
        gint i;
        for (i = 0; i < msnwebcam->fdlist->len; i++)
        {
            GIOChannel *chan = g_array_index(msnwebcam->fdlist, GIOChannel*, i);
            g_io_channel_shutdown (chan, TRUE, NULL);
            g_io_channel_unref (chan);
            g_array_remove_index (msnwebcam->fdlist, i);
        }

        farsight_protocol_disconnect (FARSIGHT_PROTOCOL (msnwebcam));
    }

    return FALSE;
}

// Try to connect on all ip:port combinations
static void
farsight_msnwebcam_try_connect_all_combinations (FarsightMsnWebcam *msnwebcam)
{
    gchar *ips[NUM_IPS];
    gint16 ports[NUM_PORTS];
    fd_set fdset;
    struct timeval timeout;

    timeout.tv_sec = 5;
    timeout.tv_usec = 0;

    ips[0] = msnwebcam->remoteinfo.tcpaddress1;
    ips[1] = msnwebcam->remoteinfo.tcpaddress2;
    ips[2] = msnwebcam->remoteinfo.tcpaddress3;

    ports[0] = msnwebcam->remoteinfo.tcpport;
    ports[1] = msnwebcam->remoteinfo.tcplocalport;
    ports[2] = msnwebcam->remoteinfo.tcpexternalport;

    // This loop will go through all ip<->port combinations
    // and try to connect to them, in non-blocking mode
    gint i, j;
    for (i=0; i < NUM_IPS; i++)
    {
        for (j=0; j < NUM_PORTS; j++)
        {
            // don't process if ip or port are not set
            if (ips[i] == NULL || ports[j] == 0)
            {
                continue;
            }

            GIOChannel *chan;
            gint fd = -1;
            struct sockaddr_in theiraddr;
            memset(&theiraddr, 0, sizeof(theiraddr));

            if ( (fd = socket(PF_INET, SOCK_STREAM, 0)) == -1 )
            {
                // show error
                g_message ("could not create socket!");
                continue;
            }

            chan = g_io_channel_unix_new (fd);
            g_io_channel_set_close_on_unref (chan, TRUE);
            g_array_append_val (msnwebcam->fdlist, chan);

            // set non-blocking mode
            fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);

            theiraddr.sin_family = AF_INET;
            theiraddr.sin_addr.s_addr = inet_addr (ips[i]);
            theiraddr.sin_port = htons (ports[j]);

            g_message ("Attempting connection to %s %d on socket %d", ips[i], ports[j], fd);
            // this is non blocking, the return value isn't too usefull
            gint ret = connect (fd, (struct sockaddr *) &theiraddr, sizeof (theiraddr));
            if (ret < 0)
            {
                if (errno != EINPROGRESS)
                {
                    g_io_channel_shutdown (chan, TRUE, NULL);
                    g_io_channel_unref (chan);
                    return;
                }
            }
            g_message("ret %d %d %s", ret, errno, strerror(errno));

            // add a watch on that io for when it connects
            msnwebcam->connect_watch = g_io_add_watch (chan, 
                    (G_IO_IN|G_IO_OUT|G_IO_PRI|G_IO_ERR|G_IO_HUP|G_IO_NVAL), 
                    successfull_connection_cb, msnwebcam);
        }
    }

}

// authenticate someone trying to connect to us
static gboolean
farsight_msnwebcam_authenticate_incoming (FarsightMsnWebcam *msnwebcam, gint fd)
{
    if (fd != 0)
    {
        gchar str[400];
        gchar check[400];

        memset(str, 0, sizeof(str));
        if (recv(fd, str, sizeof(str), 0) != -1)
        {
            g_message ("Got %s, checking if it's auth", str);
            sprintf(str, "recipientid=%d&sessionid=%d\r\n\r\n", 
                    msnwebcam->localinfo.recipientid, msnwebcam->remoteinfo.sessionid);
            if (strcmp (str, check) != 0)
            {
                // send our connected message also
                memset(str, 0, sizeof(str));
                sprintf(str, "connected\r\n\r\n");
                send(fd, str, strlen(str), 0);

                // now we get connected
                memset(str, 0, sizeof(str));
                if (recv(fd, str, sizeof(str), 0) != -1)
                {
                    if (strcmp (str, "connected\r\n\r\n") == 0)
                    {
                        g_message ("Authentication successfull");
                        return TRUE;
                    }
                }
            }
        }
        else
        {
            perror("auth");
        }
    }
    return FALSE;
}

// Authenticate ourselves when connecting out
static gboolean
farsight_msnwebcam_authenticate_outgoing (FarsightMsnWebcam *msnwebcam, gint fd)
{
    gchar str[400];
    memset(str, 0, sizeof(str));
    if (fd != 0)
    {
        g_message ("Authenticating connection on %d...", fd);
        g_message ("sending : recipientid=%d&sessionid=%d\r\n\r\n", msnwebcam->remoteinfo.recipientid, msnwebcam->remoteinfo.sessionid);
        sprintf(str, "recipientid=%d&sessionid=%d\r\n\r\n", 
                msnwebcam->remoteinfo.recipientid, msnwebcam->remoteinfo.sessionid);
        if (send(fd, str, strlen(str), 0) == -1)
        {
            g_message("sending failed");
            perror("auth");
        }

        memset(str, 0, sizeof(str));
        if (recv(fd, str, sizeof(str), 0) != -1)
        {
            g_message ("Got %s, checking if it's auth", str);
            // we should get a connected message now
            if (strcmp (str, "connected\r\n\r\n") == 0)
            {
                // send our connected message also
                memset(str, 0, sizeof(str));
                sprintf(str, "connected\r\n\r\n");
                send(fd, str, strlen(str), 0);
                g_message ("Authentication successfull");
                return TRUE;
            }
        }
        else
        {
            perror("auth");
        }
    }
    return FALSE;
}

static void 
farsight_msnwebcam_connect (FarsightProtocol *protocol)
{
    FarsightMsnWebcam *msnwebcam;

    g_return_if_fail (protocol != NULL);

    msnwebcam = FARSIGHT_MSNWEBCAM (protocol);

    farsight_msnwebcam_open_listening_ports (FARSIGHT_MSNWEBCAM (protocol));
    farsight_msnwebcam_try_connect_all_combinations (FARSIGHT_MSNWEBCAM (protocol));

    // give them 5 seconds
    g_timeout_add (5000, (GSourceFunc)attempt_timeout_cb, msnwebcam);
}

static void 
farsight_msnwebcam_disconnect (FarsightProtocol *protocol)
{
    FarsightMsnWebcam *msnwebcam;

    g_return_if_fail (protocol != NULL);

    msnwebcam = FARSIGHT_MSNWEBCAM (protocol);

    // close fd
    if (msnwebcam->connection)
    {
        g_io_channel_shutdown (msnwebcam->connection, TRUE, NULL);
        g_io_channel_unref (msnwebcam->connection);
    }
}

static GstElement *
farsight_msnwebcam_create_bin (FarsightProtocol *protocol)
{
    FarsightMsnWebcam *msnwebcam;
    GstElement *bin;

    g_return_val_if_fail (protocol != NULL, NULL);

    msnwebcam = FARSIGHT_MSNWEBCAM (protocol);

    gint fd = g_io_channel_unix_get_fd (msnwebcam->connection);

    fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);

    /* verify the caps and create the bin */
    if (msnwebcam->session_type == VIEWER)
    {
        bin = gst_bin_new ("msnwebcam_receive");
        g_message ("Creating viewer bin, receiver on fd %d", fd);
        GstElement *fdsrc = gst_element_factory_make ("fdsrc", "fdsrc");
        GstElement *mimicdec = gst_element_factory_make ("mimdec", "mimicdec");

        //GstElement *filesink = gst_element_factory_make ("filesink", "filesinkelement");

        g_object_set (G_OBJECT(fdsrc), "fd", fd, NULL);
        g_object_set (G_OBJECT(fdsrc), "blocksize", 512, NULL);

        //g_object_set (G_OBJECT(filesink), "location", "dumped.bin", NULL);

        //gst_bin_add_many (GST_BIN(bin), fdsrc, filesink, NULL);
        gst_bin_add_many (GST_BIN(bin), fdsrc, mimicdec, NULL);
        //gst_element_link_pads (fdsrc, "src", filesink, "sink");
        gst_element_link_pads (fdsrc, "src", mimicdec, "sink");

#if 1
        gst_element_add_pad (bin,
            gst_ghost_pad_new("videosrc",
                gst_element_get_pad (mimicdec, "src")));
#endif
    }
    else
    {
        bin = gst_bin_new ("msnwebcam_send");
        g_message ("Creating producer bin, sending on fd %d", fd);
        GstElement *fdsink = gst_element_factory_make ("multifdsink", "fdsinkelement");
        GstElement *mimicenc = gst_element_factory_make ("mimenc", "mimicencelement");

        gst_bin_add_many (GST_BIN(bin), fdsink, mimicenc, NULL);
        gst_element_link_pads (mimicenc, "src", fdsink, "sink");

        gst_element_set_state (fdsink, GST_STATE_READY);
        g_signal_emit_by_name (G_OBJECT(fdsink), "add", fd);

        gst_element_add_pad (bin,
            gst_ghost_pad_new("videosink",
                gst_element_get_pad (mimicenc, "sink")));
    }

    return bin;
}

static void
free_xml_info_struct (MsnWebcamXmlInfo *info)
{
    if (info->tcpaddress1)
        g_free (info->tcpaddress1);
    if (info->tcpaddress2)
        g_free (info->tcpaddress2);
    if (info->tcpaddress3)
        g_free (info->tcpaddress3);
}

static void
farsight_msnwebcam_finalize (GObject *object)
{
    FarsightMsnWebcam *msnwebcam = NULL;

    msnwebcam = FARSIGHT_MSNWEBCAM (object);
    g_return_if_fail (msnwebcam != NULL);
    g_return_if_fail (FARSIGHT_IS_MSNWEBCAM (msnwebcam));

    // free our vars
    if (msnwebcam->localxml)
        g_free (msnwebcam->localxml);
    if (msnwebcam->remotexml)
        g_free (msnwebcam->remotexml);

    if (msnwebcam->fdlist)
        g_array_free (msnwebcam->fdlist, TRUE);

    free_xml_info_struct (&(msnwebcam->localinfo));
    free_xml_info_struct (&(msnwebcam->remoteinfo));

    G_OBJECT_CLASS (parent_class)->finalize (object);
}

static void
farsight_msnwebcam_set_property (GObject      *object, 
                           guint         prop_id,
                           const GValue *value, 
                           GParamSpec   *pspec)
{
    FarsightMsnWebcam *msnwebcam;

    g_return_if_fail (FARSIGHT_IS_MSNWEBCAM (object));

    msnwebcam = FARSIGHT_MSNWEBCAM (object);

    switch (prop_id) {
        case ARG_LOCALXML:
            if (msnwebcam->localxml)
                g_free (msnwebcam->localxml);
            msnwebcam->localxml = g_value_dup_string (value);
            g_message ("setting localxml to %s", msnwebcam->localxml);
            // let's parse the xml we received
            farsight_msnwebcam_parse_xml (msnwebcam, TRUE);
            g_message ("parsed");
            break;

        case ARG_REMOTEXML:
            if (msnwebcam->remotexml)
                g_free (msnwebcam->remotexml);
            msnwebcam->remotexml = g_value_dup_string (value);
            g_message ("setting remotexml to %s", msnwebcam->remotexml);
            // let's parse the xml we received
            farsight_msnwebcam_parse_xml (msnwebcam, FALSE);
            break;
    }
}

static void
farsight_msnwebcam_get_property (GObject    *object, 
                           guint       prop_id, 
                           GValue     *value,
                           GParamSpec *pspec)
{
    FarsightMsnWebcam *msnwebcam;

    g_return_if_fail (FARSIGHT_IS_MSNWEBCAM (object));
    msnwebcam = FARSIGHT_MSNWEBCAM (object);

    switch (prop_id) {
        case ARG_LOCALXML:
            g_value_set_string (value, msnwebcam->localxml);
            break;
        case ARG_REMOTEXML:
            g_value_set_string (value, msnwebcam->remotexml);
            break;
    }
}

static gboolean 
init_plugin (FarsightPlugin *plugin)
{
    if (!farsight_protocol_register (plugin, FARSIGHT_TYPE_MSNWEBCAM))
        return FALSE;
    return TRUE;
}

static FarsightPluginInfo plugin_info = {
    FARSIGHT_MAJOR_VERSION,
    FARSIGHT_MINOR_VERSION,

    "MSN Webcam Protocol",                                /* description */
    "0.1.0",                                            /* version */
    "Farsight Project",  /* author */
    "http://farsight.sf.net/",                          /* homepage */
    NULL,                                               /* load */
    NULL                                                /* unload */
};

FARSIGHT_INIT_PLUGIN (init_plugin, plugin_info);

Generated by  Doxygen 1.6.0   Back to index