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

test3av.c

/*
 * test3av.c - Farsight tests
 *
 * Farsight Voice+Video library test suite
 *  Copyright 2005,2006 Collabora Ltd.
 *  Copyright 2005,2006 Nokia Corporation
 *   @author: Rob Taylor <rob.taylor@collabora.co.uk>.
 *   @author: Philippe Khalaf <philippe.khalaf@collabora.co.uk>.
 *
 * 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 <glib.h>
#include <unistd.h>
#include <gst/gst.h>
#include <farsight/farsight-session.h>
#include <farsight/farsight-stream.h>
#include <farsight/farsight-transport.h>

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

#define TYPE_CODEC 1
#define TYPE_READY_BYTE 2

GMainLoop *mainloop = NULL;

gint send_sock = 0;
struct sockaddr_in serv_addr;
FarsightStream *audio_stream, *video_stream;

static void
stream_error (FarsightStream *stream,
    FarsightStreamError error,
    const gchar *debug)
{
  g_print ("%s: stream error: stream=%p error=%s\n", __FUNCTION__, stream, debug);
}

static void
session_error (FarsightSession *stream,
    FarsightSessionError error,
    const gchar *debug)
{
  g_print ("%s: session error: session=%p error=%s\n", __FUNCTION__, stream, debug);
}


static void
new_active_candidate_pair (FarsightStream *stream, gchar* native_candidate, gchar *remote_candidate)
{
  g_print ("%s: new-native-candidate-pair: stream=%p\n", __FUNCTION__, stream);
}

static void
codec_changed (FarsightStream *stream, gint codec_id)
{
  g_print ("%s: codec-changed: codec_id=%d, stream=%p\n", __FUNCTION__, codec_id, stream);
}

static void
native_candidates_prepared (FarsightStream *stream)
{
  const GList *transport_candidates, *lp;
  FarsightTransportInfo *info;

  g_print ("%s: preparation-complete: stream=%p\n", __FUNCTION__, stream);

  transport_candidates = farsight_stream_get_native_candidate_list (stream); 
  for (lp = transport_candidates; 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);
  }
  //g_main_loop_quit(mainloop);
}

static void 
state_changed (FarsightStream *stream, 
    FarsightStreamState state,
    FarsightStreamDirection dir)
{
  switch (state) {
    case FARSIGHT_STREAM_STATE_CONNECTING:
      g_message ("%s: %p connecting\n", __FUNCTION__, stream);
      break;
    case FARSIGHT_STREAM_STATE_CONNECTED:
      g_message ("%s: %p connected\n", __FUNCTION__, stream);
      break;
    case FARSIGHT_STREAM_STATE_DISCONNECTED:
      g_message ("%s: %p disconnected\n", __FUNCTION__, stream);
      break;
  }
}

void
setup_send (gchar * host, gint port)
{
  struct hostent *rx_addr = gethostbyname (host);
  send_sock = socket (AF_INET, SOCK_DGRAM, 0);

  serv_addr.sin_family = AF_INET;
  bcopy (rx_addr->h_addr, &serv_addr.sin_addr, rx_addr->h_length);

  serv_addr.sin_port = htons (port);
}

GIOChannel *
setup_recv (gint port)
{
  int sockfd = socket (AF_INET, SOCK_DGRAM, 0);
  struct sockaddr_in dest_addr;

  g_message (G_STRFUNC);


  bzero (&dest_addr, sizeof (dest_addr));
  dest_addr.sin_family = AF_INET;
  dest_addr.sin_addr.s_addr = INADDR_ANY;
  dest_addr.sin_port = htons (port);

  if (bind (sockfd, (const struct sockaddr *) &dest_addr, sizeof (dest_addr)) == -1)
  {
    g_critical ("%s: bind returned error %s", G_STRFUNC, strerror(errno));
    exit(1);
  }

  g_debug ("%s: sockfd = %d",G_STRFUNC, sockfd);
  return g_io_channel_unix_new (sockfd);
}

static void
send_codecs (const GList *codecs)
{
  const GList *lp;
  FarsightCodec *codec;
  gchar s[300] = { 0 };
  codec = (FarsightCodec *) codecs->data;

  for (lp = codecs; lp; lp = g_list_next (lp)) {
    codec = (FarsightCodec *) lp->data;
    g_message (G_STRFUNC);

    sprintf (s, "%d %d %s %d %u %u ", TYPE_CODEC, codec->media_type,
        codec->encoding_name, codec->id, codec->clock_rate, codec->channels);
    g_message ("Sending codec");
    if (sendto (send_sock, s, strlen (s), 0,
          (struct sockaddr *) &serv_addr, sizeof (struct sockaddr_in)) <0)
      perror ("sendto: ");
  }

  sprintf (s, "%d %d %s %d %u %u ", TYPE_CODEC, codec->media_type, "LAST", 0, 0,
      0);
  g_message ("Sending end of list packet");
  if (sendto (send_sock, s, strlen (s), 0,
        (struct sockaddr *) &serv_addr, sizeof (struct sockaddr_in)) <0)
  {
    g_critical ("%s: sendto returned error %s", G_STRFUNC, strerror(errno));
    exit(1);
  }
}

static void
send_ready_byte ()
{
  gchar s[2];
  sprintf (s, "%d", TYPE_READY_BYTE);
  g_message ("Sending ready byte");
  if (sendto (send_sock, s, strlen (s), 0,
        (struct sockaddr *) &serv_addr, sizeof (struct sockaddr_in)) <0)
  {
    g_critical ("%s: sendto returned error %s", G_STRFUNC, strerror(errno));
    exit(1);
  }
}

static void
do_handshake(gint sockfd)
{
  gint type;
  socklen_t fromlen;
  struct sockaddr_in from_addr;
  gchar buf[1500] = { 0 };

  send_ready_byte();
  /* wait for reply */
  fromlen = sizeof (struct sockaddr_in);

  g_message ("waiting for ready byte");
  if (recvfrom (sockfd, buf, 1500, 0,
        (struct sockaddr *) &from_addr, &fromlen) == -1)
  {
    g_critical ("%s: recvfrom returned error %s", G_STRFUNC, strerror(errno));
    exit(1);
  }
  g_message ("got message!");

  sscanf (buf, "%d", &type);

  if (type == TYPE_READY_BYTE)
  {
    send_ready_byte();
  }

  return;
}

static void
add_remote_codec (FarsightStream *stream, gint pt, gchar *encoding_name,
    FarsightMediaType media_type, guint clock_rate, guint channels)
{
  static GList *remote_codecs_audio = NULL;
  static GList *remote_codecs_video = NULL;
  GList *lp = NULL;
  FarsightCodec *codec;

  if (g_ascii_strcasecmp (encoding_name, "LAST") == 0)
  {
    if (media_type == FARSIGHT_MEDIA_TYPE_AUDIO)
    {
      farsight_stream_set_remote_codecs (stream, remote_codecs_audio);
    }
    else if (media_type == FARSIGHT_MEDIA_TYPE_VIDEO)
    {
      farsight_stream_set_remote_codecs (stream, remote_codecs_video);
    }
    return;
  }

  codec = g_new0 (FarsightCodec, 1);

  codec->id = pt;
  codec->encoding_name = strdup (encoding_name);
  codec->media_type = media_type;
  codec->clock_rate = clock_rate;
  codec->channels = channels;

  if (media_type == FARSIGHT_MEDIA_TYPE_AUDIO)
  {
    remote_codecs_audio = g_list_append (remote_codecs_audio, codec);
  }
  else if (media_type == FARSIGHT_MEDIA_TYPE_VIDEO)
  {
    remote_codecs_video = g_list_append (remote_codecs_video, codec);
  }

  for (lp = remote_codecs_audio; lp; lp = g_list_next (lp)) {
    codec = (FarsightCodec *) lp->data;
    g_message ("added audio codec: %d: %s/%d found", codec->id, codec->encoding_name,
        codec->clock_rate);
  }
  for (lp = remote_codecs_video; lp; lp = g_list_next (lp)) {
    codec = (FarsightCodec *) lp->data;
    g_message ("added video codec: %d: %s/%d found", codec->id, codec->encoding_name,
        codec->clock_rate);
  }
}

static gboolean
receive_loop (GIOChannel *ch, GIOCondition cond, gpointer data)
{
  gint type;
  gint sockfd = g_io_channel_unix_get_fd (ch);

  gchar encoding_name[100] = { 0 };
  gint pt, media_type;
  guint clock_rate, channels;

  gchar buf[1500] = { 0 };
  struct sockaddr_in from_addr;
  socklen_t fromlen;
  fromlen = sizeof (struct sockaddr_in);
  g_message ("waiting for msg");
  if (recvfrom (sockfd, buf, 1500, 0,
        (struct sockaddr *) &from_addr, &fromlen) == -1)
  {
    g_critical ("%s: recvfrom returned error %s", G_STRFUNC, strerror(errno));
    exit(1);
  }
  g_message ("got message!");

  sscanf (buf, "%d", &type);

  g_message ("got type %d", type);

  switch(type)
  {
    case TYPE_CODEC:
      sscanf (buf+1, "%d %s %d %u %u", &media_type, encoding_name, &pt,
          &clock_rate, &channels);

      g_message ("Received %d %s %d %u %u", media_type, encoding_name, pt,
          clock_rate, channels);

      switch((FarsightMediaType)media_type)
      {
        case FARSIGHT_MEDIA_TYPE_AUDIO:
          add_remote_codec (audio_stream, pt, encoding_name, media_type,
              clock_rate, channels);
          break;
        case FARSIGHT_MEDIA_TYPE_VIDEO:
          add_remote_codec (video_stream, pt, encoding_name, media_type,
              clock_rate, channels);
          break;
      }
      break;
    case TYPE_READY_BYTE:
      g_message ("got ready byte");
      break;
  }
  return TRUE;
}


FarsightSession *setup_rtp_session();
FarsightStream *setup_rtp_stream(FarsightSession *session, FarsightMediaType
    type);

int main(int argc, char **argv)
{
  GIOChannel *recv_chan;
  FarsightSession *session;
  GList *a_candidate_glist = NULL;
  GList *v_candidate_glist = NULL;
  FarsightTransportInfo *audio_trans = NULL;
  FarsightTransportInfo *video_trans = NULL;
  GstElement *videosrc, *videosink;
  GstElement *alsasrc, *alsasink;
  GstCaps *src_filter;

  gst_init (&argc, &argv);

  if (argc != 8)
  {
    g_print("usage : test a_remoteip a_remoteport v_remoteip v_remoteport s_remoteip s_remoteport s_localport\n");
    return -1;
  }

  mainloop = g_main_loop_new (NULL, FALSE);

  setup_send (argv[5], atoi (argv[6]));
  g_message ("Sending to %s %d listening on port %d", argv[5], atoi (argv[6]), atoi
      (argv[7]));

  recv_chan = setup_recv (atoi(argv[7]));

  /* this will wait until both sides are loaded before sending anything */
  do_handshake(g_io_channel_unix_get_fd (recv_chan));

  g_io_add_watch (recv_chan, G_IO_IN | G_IO_PRI, receive_loop, NULL);

  session = setup_rtp_session();

  audio_stream = setup_rtp_stream(session, FARSIGHT_MEDIA_TYPE_AUDIO);
  video_stream = setup_rtp_stream(session, FARSIGHT_MEDIA_TYPE_VIDEO);

  /* it's better to set the active codec before the remote_codecs to avoid a
   * send pipeline change from the start */
  //farsight_stream_set_active_codec (stream1, 8);

  /* this assumes both hosts have the same codecs */
  /*
  farsight_stream_set_remote_codecs(audio_stream,
      farsight_stream_get_local_codecs(audio_stream));
  farsight_stream_set_remote_codecs(video_stream,
      farsight_stream_get_local_codecs(video_stream));
      */

  /* let's create our candidate from ip:port given on command line */
  audio_trans = g_new0 (FarsightTransportInfo,1);
  audio_trans->candidate_id = g_strdup_printf ("L1");
  audio_trans->component = 1;
  audio_trans->ip = g_strdup (argv[1]);
  audio_trans->port = atoi(argv[2]);
  audio_trans->proto = FARSIGHT_NETWORK_PROTOCOL_UDP;
  audio_trans->proto_subtype = "RTP";
  audio_trans->proto_profile = "AVP";
  audio_trans->preference = 1.0;
  audio_trans->type = FARSIGHT_CANDIDATE_TYPE_LOCAL;

  a_candidate_glist = g_list_append(a_candidate_glist, audio_trans);

  farsight_stream_set_remote_candidate_list(audio_stream, a_candidate_glist);

  video_trans = g_new0 (FarsightTransportInfo,1);
  video_trans->candidate_id = g_strdup_printf ("L1");
  video_trans->component = 1;
  video_trans->ip = g_strdup (argv[3]);
  video_trans->port = atoi(argv[4]);
  video_trans->proto = FARSIGHT_NETWORK_PROTOCOL_UDP;
  video_trans->proto_subtype = "RTP";
  video_trans->proto_profile = "AVP";
  video_trans->preference = 1.0;
  video_trans->type = FARSIGHT_CANDIDATE_TYPE_LOCAL;

  v_candidate_glist = g_list_append(v_candidate_glist, video_trans);

  farsight_stream_set_remote_candidate_list(video_stream, v_candidate_glist);

  g_free(audio_trans);
  g_free(video_trans);
  g_list_free(a_candidate_glist);
  g_list_free(v_candidate_glist);

  farsight_stream_set_active_candidate_pair(audio_stream, "L1", "L1");
  farsight_stream_set_active_candidate_pair(video_stream, "L1", "L1");

  videosrc = gst_element_factory_make("videotestsrc", "videotestsrc"); 
  videosink = gst_element_factory_make("xvimagesink", "xvimagesink");
  g_object_set (G_OBJECT (videosrc), "use-fixed-fps", FALSE, NULL);
  g_object_set (G_OBJECT (videosink), "sync", FALSE, NULL);
  g_object_set (G_OBJECT (videosrc), "is-live", TRUE, NULL);
  src_filter = gst_caps_new_simple ("video/x-raw-yuv", "width",
      G_TYPE_INT, 352, "height", G_TYPE_INT, 288, "framerate", GST_TYPE_FRACTION, 15,1, NULL);
  farsight_stream_set_source_filter (video_stream, src_filter);
  gst_caps_unref (src_filter);
  farsight_stream_set_source(video_stream, videosrc);
  farsight_stream_set_sink(video_stream, videosink);

  alsasrc = gst_element_factory_make("audiotestsrc", "alsasrc"); 
  alsasink = gst_element_factory_make("alsasink", "alsasink");
  g_object_set(G_OBJECT(alsasink), "sync", FALSE, NULL);
  g_object_set(G_OBJECT(alsasink), "latency-time", G_GINT64_CONSTANT (20000), NULL);
  g_object_set(G_OBJECT(alsasink), "buffer-time", G_GINT64_CONSTANT (80000), NULL);
  g_object_set(G_OBJECT(alsasrc), "blocksize", 320, NULL);
  g_object_set(G_OBJECT(alsasrc), "latency-time", G_GINT64_CONSTANT (20000), NULL);
  g_object_set(G_OBJECT(alsasrc), "is-live", TRUE, NULL);
  farsight_stream_set_source(audio_stream, alsasrc);
  farsight_stream_set_sink(audio_stream, alsasink);

  farsight_stream_start(audio_stream);
  farsight_stream_start(video_stream);

  g_main_loop_run(mainloop); 

  return 0;
}

FarsightSession *setup_rtp_session()
{
  FarsightSession *session;

  session = farsight_session_factory_make ("rtp");

  if (!session) {
    g_error("RTP plugin not found");
    exit(1);
  }
  g_print ("protocol details:\n name: %s\n description: %s\n author: %s\n",
      farsight_plugin_get_name (session->plugin),
      farsight_plugin_get_description (session->plugin),
      farsight_plugin_get_author (session->plugin));
  g_signal_connect (G_OBJECT (session), "error", 
      G_CALLBACK (session_error), NULL);


  return session;
}

FarsightStream *setup_rtp_stream(FarsightSession *session, FarsightMediaType
    type)
{
  FarsightStream *stream;
  const GList *possible_codecs, *lp;
  FarsightCodec *codec;

  stream = farsight_session_create_stream (session,
      type, FARSIGHT_STREAM_DIRECTION_BOTH);
  g_object_set (G_OBJECT (stream), "transmitter", "rawudp", NULL);
  g_signal_connect (G_OBJECT (stream), "error", 
      G_CALLBACK (stream_error), NULL);
  g_signal_connect (G_OBJECT (stream), "new-active-candidate-pair", 
      G_CALLBACK (new_active_candidate_pair), NULL);
  g_signal_connect (G_OBJECT (stream), "codec-changed", 
      G_CALLBACK (codec_changed), NULL);
  g_signal_connect (G_OBJECT (stream), "native-candidates-prepared", 
      G_CALLBACK (native_candidates_prepared), NULL);
  g_signal_connect (G_OBJECT (stream), "state-changed", 
      G_CALLBACK (state_changed), NULL);

  possible_codecs = farsight_stream_get_local_codecs (stream);

  for (lp = possible_codecs; lp; lp = g_list_next (lp)) 
  {
    codec = (FarsightCodec*) lp->data;
    g_message ("codec: %d: %s/%d found", codec->id, codec->encoding_name, 
        codec->clock_rate);
  }

  send_codecs (possible_codecs);

  farsight_stream_prepare_transports(stream);

  return stream;
}

Generated by  Doxygen 1.6.0   Back to index