Logo Search packages:      
Sourcecode: farsight version File versions

jingle_c.cpp

/*
 * Farsight Voice+Video library
 * Copyright 2006 Collabora Ltd, 
 * Copyright 2006 Nokia Corporation
 *   @author: Philippe Khalaf <philippe.khalaf@collabora.co.uk>.
 * Copyright (C) 2005 INdT 
 *   @author Andre Moreira Magalhaes <andre.magalhaes@indt.org.br>
 *
 * 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
 */

#include "jingle_c.h"

#include <glib.h>

#include <talk/base/thread.h>
#include <talk/base/physicalsocketserver.h>
#include <talk/base/socketaddress.h>
#include <talk/p2p/client/socketclient.h>

class SignalListener1 : public sigslot::has_slots<>
{
  private:
    callback_list cb_list;
    SocketClient *socketclient;
    guint native_candidate_count;

  public:
    SignalListener1(SocketClient *sc) { memset(&cb_list, 0, sizeof(callback_list)); socketclient = sc; native_candidate_count = 0; };
    callback_list *getCbList() { return &cb_list; };
    void OnCandidatesReady(const std::vector<Candidate>& candidates);
    void OnNetworkError();
    void OnSocketState(bool state);
};

void SignalListener1::OnCandidatesReady(const std::vector<Candidate>& candidates)
{
  g_message ("OnCandidatesReady called with %d candidates in list", candidates.size());

  /* We want to send them out one candidate at a time */
  /* at the moment, it seems that libjingle dosen't support multiple
   * components per candidate, so each candidate will be a GList with one
   * element only */
  FarsightTransportInfo *trans = NULL;
  std::vector<Candidate>::const_iterator it;
  guint i;
  for (it = candidates.begin(); it != candidates.end(); it++)
  {
    trans = g_new0 (FarsightTransportInfo,1);
    trans->candidate_id = g_strdup_printf ("L%d", ++native_candidate_count);
    trans->component = 1;
    trans->ip = g_strdup ((*it).address().IPAsString().c_str());
    trans->port = (*it).address().port();
    trans->proto = ((*it).protocol() == "udp")?
        FARSIGHT_NETWORK_PROTOCOL_UDP:FARSIGHT_NETWORK_PROTOCOL_TCP;
    /* TODO are they all really RTP/AVP? */
    trans->proto_subtype = g_strdup ("RTP");
    trans->proto_profile = g_strdup ("AVP");
    trans->preference = (*it).preference();
    if ((*it).type() == "local")
      trans->type = FARSIGHT_CANDIDATE_TYPE_LOCAL;
    else if((*it).type() == "stun")
      trans->type = FARSIGHT_CANDIDATE_TYPE_DERIVED;
    else if((*it).type() == "relay")
      trans->type = FARSIGHT_CANDIDATE_TYPE_RELAY;
    else
      g_warning("Candidate type unknown %s", (*it).type().c_str());
    trans->username = g_strdup ((*it).username().c_str());
    trans->password = g_strdup ((*it).password().c_str());

    for (i = 0; i < socketclient->sigl1->getCbList()->candidates_ready_cb_array->len; i++)
    {
      cb_info *cb;
      cb = &g_array_index (socketclient->sigl1->getCbList()->candidates_ready_cb_array, cb_info, i);
      candidates_ready_cb_type cb_ptr =
        (candidates_ready_cb_type)cb->callback;
      cb_ptr (cb->data, (const FarsightTransportInfo *)trans);
    }
    farsight_transport_destroy (trans);
  }

  /*
  GList *lp = NULL;
  FarsightTransportInfo *info = NULL;
  for (lp = candidates_glist; lp; lp = g_list_next (lp)) 
  {
    info = (FarsightTransportInfo*)lp->data;
    g_message ("Local transport candidate: %s %d %s %s %s:%d, pref %f", 
        info->candidate_id, info->component, (info->proto == FARSIGHT_NETWORK_PROTOCOL_TCP)?"TCP":"UDP",
        info->proto_subtype, info->ip, info->port, (double) info->preference);
  }
  */
}

void SignalListener1::OnNetworkError()
{
  guint i;
  g_warning ("Network error encountered at SocketManager");

  /* call callback */
  for (i = 0; i < socketclient->sigl1->getCbList()->network_error_cb_array->len; i++)
  {
    cb_info *cb;
    cb = &g_array_index (socketclient->sigl1->getCbList()->network_error_cb_array, cb_info, i);
    network_error_cb_type cb_ptr = (network_error_cb_type)cb->callback;
    cb_ptr (cb->data);
  }
}

void SignalListener1::OnSocketState(bool state)
{
  gint state_ = 0;
  guint i;

  switch (state) {
    case P2PSocket::STATE_WRITABLE:
      /*
      g_message ("Writable from %s:%d to %s:%d", 
              socket->best_connection()->local_candidate().address().IPAsString().c_str(),
              socket->best_connection()->local_candidate().address().port(),
              socket->best_connection()->remote_candidate().address().IPAsString().c_str(),
              socket->best_connection()->remote_candidate().address().port());
      */
      state_ = 1;
      break;

    default:
      break;
  }
  /* call callbacks */
  for (i = 0; i < socketclient->sigl1->getCbList()->socket_state_change_cb_array->len; i++)
  {
    cb_info *cb;
    cb = &g_array_index (socketclient->sigl1->getCbList()->socket_state_change_cb_array, cb_info, i);
    socket_state_change_cb_type cb_ptr =
        (socket_state_change_cb_type)cb->callback;
    cb_ptr (cb->data, state_);
  }
}

static void init_callback_list (SocketClient *sc)
{
  if (!sc->sigl1)
    sc->sigl1 = new SignalListener1(sc);
  if (!sc->sigl1->getCbList()->mutex)
    sc->sigl1->getCbList()->mutex = g_mutex_new();

  if (!sc->sigl1->getCbList()->network_error_cb_array)
  {
    sc->sigl1->getCbList()->network_error_cb_array = g_array_new(FALSE,
            TRUE, sizeof(cb_info));
    sc->getSocketManager()->SignalNetworkError.connect(sc->sigl1,
            &SignalListener1::OnNetworkError);
  }

  if (!sc->sigl1->getCbList()->socket_state_change_cb_array)
  {
    sc->sigl1->getCbList()->socket_state_change_cb_array = g_array_new(FALSE,
            TRUE, sizeof(cb_info));
    if (sc->getSocket())
    {
      sc->getSocketManager()->SignalState_s.connect(sc->sigl1,
              &SignalListener1::OnSocketState);
    }
    else
    {
      g_message ("No socket created yet! SocketState not connected");
    }
  }

  if (!sc->sigl1->getCbList()->candidates_ready_cb_array)
  {
    sc->sigl1->getCbList()->candidates_ready_cb_array = g_array_new(FALSE,
            TRUE, sizeof(cb_info));
    sc->getSocketManager()->SignalCandidatesReady.connect(sc->sigl1,
            &SignalListener1::OnCandidatesReady);
  }
}

void connect_signal_candidates_ready (socketclient_t sockclient, 
                                      gpointer callback, 
                                      gpointer data)
{
  SocketClient *sc =
      reinterpret_cast<SocketClient*>(sockclient);
  if (!sc->sigl1)
  {
    init_callback_list(sc);
  }

  cb_info new_cb;
  new_cb.callback = callback;
  new_cb.data = data;

  g_mutex_lock (sc->sigl1->getCbList()->mutex);
  g_array_append_val (sc->sigl1->getCbList()->candidates_ready_cb_array, new_cb);
  g_mutex_unlock (sc->sigl1->getCbList()->mutex);
}

void connect_signal_socket_state_change (socketclient_t sockclient, 
                                         gpointer callback, 
                                         gpointer data)
{
  SocketClient *sc =
      reinterpret_cast<SocketClient*>(sockclient);
  if (!sc->sigl1)
  {
    init_callback_list(sc);
  }

  cb_info new_cb;
  new_cb.callback = callback;
  new_cb.data = data;

  g_mutex_lock (sc->sigl1->getCbList()->mutex);
  g_array_append_val (sc->sigl1->getCbList()->socket_state_change_cb_array, new_cb);
  g_mutex_unlock (sc->sigl1->getCbList()->mutex);
}

void connect_signal_network_error (socketclient_t sockclient, 
                                   gpointer callback,
                                   gpointer data)
{
  SocketClient *sc =
      reinterpret_cast<SocketClient*>(sockclient);
  if (!sc->sigl1)
  {
    init_callback_list(sc);
  }

  cb_info new_cb;
  new_cb.callback = callback;
  new_cb.data = data;

  g_mutex_lock (sc->sigl1->getCbList()->mutex);
  g_array_append_val (sc->sigl1->getCbList()->network_error_cb_array, new_cb);
  g_mutex_unlock (sc->sigl1->getCbList()->mutex);
}

static gboolean loop_thread(gpointer data)
{
  cricket::Thread *main_thread = (cricket::Thread*)data;
  main_thread->Loop (10);
  return TRUE;
}

socketclient_t socketclient_init (const gchar *stun_ip, guint stun_port, 
                                  const gchar *relay_token)
{
  cricket::SocketAddress *stun_addr = NULL;
  if (stun_ip)
  {
    stun_addr =
        new cricket::SocketAddress(std::string(stun_ip), stun_port);
  }

  static cricket::Thread *main_thread = NULL;

  SocketClient *sc = NULL;

  static cricket::PhysicalSocketServer *ss = NULL;

  if (ss == NULL)
    ss = new PhysicalSocketServer();

  if (main_thread == NULL)
  {
    main_thread = new Thread(ss);
    cricket::ThreadManager::SetCurrent(main_thread);
    g_idle_add ((GSourceFunc) loop_thread, (gpointer) main_thread);
  }

  sc = new SocketClient (stun_addr, NULL);
  if (relay_token)
    sc->SetRelayToken(relay_token);

  return sc;
}

void socketclient_destroy (socketclient_t sockclient)
{
  SocketClient *sc =
      reinterpret_cast<SocketClient *>(sockclient);

  delete sc;
}

void socketclient_create_socket (socketclient_t sockclient, const gchar *name)
{
  SocketClient *sc =
      reinterpret_cast<SocketClient*>(sockclient);

  sc->CreateSocket(std::string(name));

  sc->getSocketManager()->SignalState_s.connect(sc->sigl1,
      &SignalListener1::OnSocketState);
}

void socketclient_start_processing_candidates (socketclient_t sockclient)
{
  SocketClient *sc = 
      reinterpret_cast<SocketClient*>(sockclient);

  sc->getSocketManager()->StartProcessingCandidates();
}

void socketclient_add_remote_candidates (socketclient_t sockclient, 
                                         const GList *remote_candidates)
{
  SocketClient *sc = 
      reinterpret_cast<SocketClient*>(sockclient);

  std::vector<Candidate> candidates;

  FarsightTransportInfo *trans = NULL;
  const GList *lp;

  for (lp = remote_candidates; lp; lp = g_list_next (lp)) {
    Candidate candidate;
    trans = (FarsightTransportInfo *) lp->data;

    /* TODO I will only add components of RTP protosubtype for now */
    if (g_ascii_strcasecmp(trans->proto_subtype, "RTP"))
    {
      continue;
    }

    candidate.set_name("rtp");
    candidate.set_address(
            SocketAddress(std::string(trans->ip), trans->port));
    if (trans->username)
      candidate.set_username(std::string(trans->username));
    if (trans->password)
      candidate.set_password(std::string(trans->password));
    candidate.set_preference(trans->preference);
    candidate.set_protocol((trans->proto==FARSIGHT_NETWORK_PROTOCOL_UDP)?
            std::string("udp"):
            ((trans->port == 443)?std::string("ssltcp"):std::string("tcp")));
    std::string type;
    switch (trans->type)
    {
      case FARSIGHT_CANDIDATE_TYPE_LOCAL:
        type = "local";
        break;
      case FARSIGHT_CANDIDATE_TYPE_DERIVED:
        type = "stun";
        break;
      case FARSIGHT_CANDIDATE_TYPE_RELAY:
        type = "relay";
        break;
      default:;
    }
    candidate.set_type(type);
    candidate.set_generation(0);

    candidates.push_back(candidate);
  }

  sc->getSocketManager()->AddRemoteCandidates(candidates);
}

gboolean socketclient_is_writable(socketclient_t sockclient)
{
  SocketClient *sc = 
      reinterpret_cast<SocketClient*>(sockclient);

  return sc->getSocketManager()->writable();
}

/*
void socketclient_set_candidate_ready_cb(socketclient_t sockclient,
        candidates_ready_cb_type cb, gpointer data)
{
  SocketClient *sc = 
      reinterpret_cast<SocketClient*>(sockclient);

  connect_signal_candidates_ready (cb, data);
}

void socketclient_set_state_cb(socketclient_t sockclient, socket_state_change_cb_type cb, gpointer data)
{
  SocketClient *sc = 
      reinterpret_cast<SocketClient*>(sockclient);

  connect_signal_socket_state_change (cb, data);
}

void socketclient_set_network_error_cb(socketclient_t sockclient,
        empty_cb_type cb, gpointer data)
{
  SocketClient *sc = 
      reinterpret_cast<SocketClient*>(sockclient);

  connect_signal_network_error (cb, data);
}

void socketclient_set_socket_read_cb(socketclient_t sockclient,
        socket_read_cb_type cb, gpointer data)
{
  SocketClient *sc = 
      reinterpret_cast<SocketClient*>(sockclient);

  connect_signal_socket_read (cb, data);
}
*/

Generated by  Doxygen 1.6.0   Back to index