<commit_before>/*
 * call-stream.c - Source for TfCallStream
 * Copyright (C) 2010 Collabora Ltd.
 *
 * This library 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.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

/**
 * SECTION:tfcallstream
 *
 * @short_description: Handle the Stream objects for a Call1 channel
 *
 * This class handles the org.freedesktop.Telepathy.Call1.Stream,
 * org.freedesktop.Telepathy.Call1.Stream.Interface.Media and
 * org.freedesktop.Telepathy.Call1.Stream.Endpoint interfaces.
 */

/*
 * TODO:
 * - Support multiple handles
 * - Allow app to fail sending or receiving during call
 *
 * Endpoints:
 * - Support multiple Endpoints (ie SIP forking with ICE)
 * - Call SetControlling
 * - Listen to CandidatePairSelected and call AcceptSelectedCandidatePair/RejectSelectedCandidatePair
 * - Support IsICELite
 */

#include "config.h"

#include "call-stream.h"

#include <telepathy-glib/telepathy-glib.h>
#include <telepathy-glib/proxy-subclass.h>
#include <farstream/fs-conference.h>

#include <stdarg.h>
#include <string.h>
#include <stdlib.h>


#include "tf-signals-marshal.h"
#include "utils.h"


G_DEFINE_TYPE (TfCallStream, tf_call_stream, G_TYPE_OBJECT);

static void tf_call_stream_dispose (GObject *object);

static void tf_call_stream_fail_literal (TfCallStream *self,
    TpCallStateChangeReason reason,
    const gchar *detailed_reason,
    const gchar *message);

static void tf_call_stream_fail (TfCallStream *self,
    TpCallStateChangeReason reason,
    const gchar *detailed_reason,
    const gchar *message_format,
    ...);

static void _tf_call_stream_remove_endpoint (TfCallStream *self);


static void
tf_call_stream_class_init (TfCallStreamClass *klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);

  object_class->dispose = tf_call_stream_dispose;
}

static void
tf_call_stream_init (TfCallStream *self)
{
  self->sending_state = TP_STREAM_FLOW_STATE_STOPPED;
  self->receiving_state = TP_STREAM_FLOW_STATE_STOPPED;
}

static void
tf_call_stream_dispose (GObject *object)
{
  TfCallStream *self = TF_CALL_STREAM (object);

  g_debug (G_STRFUNC);

  if (self->proxy)
    g_object_unref (self->proxy);
  self->proxy = NULL;

  if (self->stun_servers)
    g_boxed_free (TP_ARRAY_TYPE_SOCKET_ADDRESS_IP_LIST, self->stun_servers);
  self->stun_servers = NULL;

  if (self->relay_info)
    g_boxed_free (TP_ARRAY_TYPE_STRING_VARIANT_MAP_LIST, self->relay_info);
  self->relay_info = NULL;

  if (self->fsstream)
    _tf_call_content_put_fsstream (self->call_content, self->fsstream);
  self->fsstream = NULL;

  if (self->endpoint)
    _tf_call_stream_remove_endpoint (self);

  if (G_OBJECT_CLASS (tf_call_stream_parent_class)->dispose)
    G_OBJECT_CLASS (tf_call_stream_parent_class)->dispose (object);
}



static void
sending_state_changed (TpCallStream *proxy,
    guint arg_State,
    gpointer user_data, GObject *weak_object)
{
  TfCallStream *self = TF_CALL_STREAM (weak_object);
  FsStreamDirection dir;

  self->sending_state = arg_State;

  if (!self->fsstream)
    return;

  g_object_get (self->fsstream, "direction", &dir, NULL);

  switch (arg_State)
    {
    case TP_STREAM_FLOW_STATE_PENDING_START:
      if (self->has_send_resource ||
          _tf_content_start_sending (TF_CONTENT (self->call_content)))
        {
          self->has_send_resource = TRUE;

          tp_cli_call_stream_interface_media_call_complete_sending_state_change (
              proxy, -1, TP_STREAM_FLOW_STATE_STARTED,
              NULL, NULL, NULL, NULL);
          g_object_set (self->fsstream,
              "direction", dir | FS_DIRECTION_SEND, NULL);
        }
      else
        {
          tp_cli_call_stream_interface_media_call_report_sending_failure (
              proxy, -1, TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR,
              TP_ERROR_STR_MEDIA_STREAMING_ERROR,
              "Could not start sending", NULL, NULL, NULL, NULL);
          return;
        }
      break;
    case TP_STREAM_FLOW_STATE_PENDING_STOP:
      g_object_set (self->fsstream,
          "direction", dir & ~FS_DIRECTION_SEND, NULL);
      if (self->has_send_resource)
        {
          _tf_content_stop_sending (TF_CONTENT (self->call_content));

          self->has_send_resource = FALSE;
        }
      tp_cli_call_stream_interface_media_call_complete_sending_state_change (
          proxy, -1, TP_STREAM_FLOW_STATE_STOPPED, NULL, NULL, NULL, NULL);<commit_msg>Factor out setting the FsStream direction to/from sending<commit_after>/*
 * call-stream.c - Source for TfCallStream
 * Copyright (C) 2010 Collabora Ltd.
 *
 * This library 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.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

/**
 * SECTION:tfcallstream
 *
 * @short_description: Handle the Stream objects for a Call1 channel
 *
 * This class handles the org.freedesktop.Telepathy.Call1.Stream,
 * org.freedesktop.Telepathy.Call1.Stream.Interface.Media and
 * org.freedesktop.Telepathy.Call1.Stream.Endpoint interfaces.
 */

/*
 * TODO:
 * - Support multiple handles
 * - Allow app to fail sending or receiving during call
 *
 * Endpoints:
 * - Support multiple Endpoints (ie SIP forking with ICE)
 * - Call SetControlling
 * - Listen to CandidatePairSelected and call AcceptSelectedCandidatePair/RejectSelectedCandidatePair
 * - Support IsICELite
 */

#include "config.h"

#include "call-stream.h"

#include <telepathy-glib/telepathy-glib.h>
#include <telepathy-glib/proxy-subclass.h>
#include <farstream/fs-conference.h>

#include <stdarg.h>
#include <string.h>
#include <stdlib.h>


#include "tf-signals-marshal.h"
#include "utils.h"


G_DEFINE_TYPE (TfCallStream, tf_call_stream, G_TYPE_OBJECT);

static void tf_call_stream_dispose (GObject *object);

static void tf_call_stream_fail_literal (TfCallStream *self,
    TpCallStateChangeReason reason,
    const gchar *detailed_reason,
    const gchar *message);

static void tf_call_stream_fail (TfCallStream *self,
    TpCallStateChangeReason reason,
    const gchar *detailed_reason,
    const gchar *message_format,
    ...);

static void _tf_call_stream_remove_endpoint (TfCallStream *self);


static void
tf_call_stream_class_init (TfCallStreamClass *klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);

  object_class->dispose = tf_call_stream_dispose;
}

static void
tf_call_stream_init (TfCallStream *self)
{
  self->sending_state = TP_STREAM_FLOW_STATE_STOPPED;
  self->receiving_state = TP_STREAM_FLOW_STATE_STOPPED;
}

static void
tf_call_stream_dispose (GObject *object)
{
  TfCallStream *self = TF_CALL_STREAM (object);

  g_debug (G_STRFUNC);

  if (self->proxy)
    g_object_unref (self->proxy);
  self->proxy = NULL;

  if (self->stun_servers)
    g_boxed_free (TP_ARRAY_TYPE_SOCKET_ADDRESS_IP_LIST, self->stun_servers);
  self->stun_servers = NULL;

  if (self->relay_info)
    g_boxed_free (TP_ARRAY_TYPE_STRING_VARIANT_MAP_LIST, self->relay_info);
  self->relay_info = NULL;

  if (self->fsstream)
    _tf_call_content_put_fsstream (self->call_content, self->fsstream);
  self->fsstream = NULL;

  if (self->endpoint)
    _tf_call_stream_remove_endpoint (self);

  if (G_OBJECT_CLASS (tf_call_stream_parent_class)->dispose)
    G_OBJECT_CLASS (tf_call_stream_parent_class)->dispose (object);
}


static void
tf_call_stream_update_sending_state (TfCallStream *self)
{
  gboolean sending = FALSE;
  FsStreamDirection dir;

  if (self->fsstream == NULL)
    goto done;

  switch (self->sending_state)
    {
    case TP_STREAM_FLOW_STATE_PENDING_START:
      if (self->has_send_resource)
        sending = TRUE;
      break;
    case TP_STREAM_FLOW_STATE_STARTED:
      sending = TRUE;
      break;
    default:
      break;
    }

 done:
  g_object_get (self->fsstream, "direction", &dir, NULL);
  if (sending)
    g_object_set (self->fsstream, "direction", dir | FS_DIRECTION_SEND, NULL);
  else
    g_object_set (self->fsstream, "direction", dir & ~FS_DIRECTION_SEND, NULL);
}

static void
sending_state_changed (TpCallStream *proxy,
    guint arg_State,
    gpointer user_data, GObject *weak_object)
{
  TfCallStream *self = TF_CALL_STREAM (weak_object);

  self->sending_state = arg_State;

  if (!self->fsstream)
    return;

  switch (arg_State)
    {
    case TP_STREAM_FLOW_STATE_PENDING_START:
      if (self->has_send_resource ||
          _tf_content_start_sending (TF_CONTENT (self->call_content)))
        {
          self->has_send_resource = TRUE;

          tp_cli_call_stream_interface_media_call_complete_sending_state_change (
              proxy, -1, TP_STREAM_FLOW_STATE_STARTED,
              NULL, NULL, NULL, NULL);
          tf_call_stream_update_sending_state (self);
        }
      else
        {
          tp_cli_call_stream_interface_media_call_report_sending_failure (
              proxy, -1, TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR,
              TP_ERROR_STR_MEDIA_STREAMING_ERROR,
              "Could not start sending", NULL, NULL, NULL, NULL);
          return;
        }
      break;
    case TP_STREAM_FLOW_STATE_PENDING_STOP:
      tf_call_stream_update_sending_state (self);
      if (self->has_send_resource)
        {
          _tf_content_stop_sending (TF_CONTENT (self->call_content));

          self->has_send_resource = FALSE;
        }
      tp_cli_call_stream_interface_media_call_complete_sending_state_change (
          proxy, -1, TP_STREAM_FLOW_STATE_STOPPED, NULL, NULL, NULL, NULL);
{'fraction_non_alphanumeric': 0.0878067124189151, 'fraction_numerical': 0.004512550531164802, 'mean_word_length': 3.884297520661157, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 78, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4492552', 'n_tokens_mistral': 3578, 'n_tokens_neox': 3479, 'n_words': 835}