static void
tp_base_call_stream_get_property (
    GObject *object,
    guint property_id,
    GValue *value,
    GParamSpec *pspec)
{
  TpBaseCallStream *self = TP_BASE_CALL_STREAM (object);
  TpBaseCallStreamClass *klass = TP_BASE_CALL_STREAM_GET_CLASS (self);

  switch (property_id)
    {
      case PROP_CONNECTION:
        g_value_set_object (value, self->priv->conn);
        break;
      case PROP_OBJECT_PATH:
        g_value_set_string (value, self->priv->object_path);
        break;
      case PROP_CONTENT:
        g_value_set_object (value, self->priv->content);
        break;
      case PROP_CHANNEL:
        g_value_set_object (value, self->priv->channel);
        break;
      case PROP_REMOTE_MEMBERS:
        g_value_set_boxed (value, self->priv->remote_members);
        break;
      case PROP_REMOTE_MEMBER_IDENTIFIERS:
        {
          GHashTable *identifiers;

          identifiers = _tp_base_call_dup_member_identifiers (self->priv->conn,
              self->priv->remote_members);
          g_value_set_boxed (value, identifiers);

          g_hash_table_unref (identifiers);
          break;
        }
      case PROP_LOCAL_SENDING_STATE:
        g_value_set_uint (value, self->priv->local_sending_state);
        break;
      case PROP_CAN_REQUEST_RECEIVING:
        {
          g_value_set_boolean (value, klass->request_receiving != NULL);
          break;
        }
      case PROP_INTERFACES:
        {
          GPtrArray *interfaces = klass->get_interfaces (self);

          g_ptr_array_add (interfaces, NULL);
          g_value_set_boxed (value, interfaces->pdata);
          g_ptr_array_unref (interfaces);
          break;
        }
      default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
        break;
    }
}
static void
tp_base_call_stream_set_property (
    GObject *object,
    guint property_id,
    const GValue *value,
    GParamSpec *pspec)
{
  TpBaseCallStream *self = TP_BASE_CALL_STREAM (object);

  switch (property_id)
    {
      case PROP_CONNECTION:
        self->priv->conn = g_value_dup_object (value);
        g_assert (self->priv->conn != NULL);
        break;
      case PROP_CONTENT:
        {
          TpBaseCallContent *content = g_value_get_object (value);
          if (content)
            _tp_base_call_stream_set_content (self, content);
        }
        break;
      case PROP_OBJECT_PATH:
        g_free (self->priv->object_path);
        self->priv->object_path = g_value_dup_string (value);
        break;
      case PROP_LOCAL_SENDING_STATE:
        self->priv->local_sending_state = g_value_get_uint (value);
        break;
      default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
        break;
    }
}
static void
call_content_setup_jingle (GabbleCallContent *self,
    GabbleCallMemberContent *mcontent)
{
  TpBaseCallContent *base = TP_BASE_CALL_CONTENT (self);
  GabbleJingleContent *jingle;
  GabbleCallStream *stream;
  gchar *path;
  JingleTransportType transport;
  JingleMediaDescription *md;
  GHashTable *tp_md;
  TpHandle contact;

  jingle = gabble_call_member_content_get_jingle_content (mcontent);

  if (jingle == NULL)
    return;

  transport = gabble_jingle_content_get_transport_type (jingle);
  path = g_strdup_printf ("%s/Stream%p",
      tp_base_call_content_get_object_path (base),
      jingle);
  stream = g_object_new (GABBLE_TYPE_CALL_STREAM,
      "object-path", path,
      "connection", tp_base_call_content_get_connection (base),
      "jingle-content", jingle,
      "transport", _jingle_to_tp_transport (transport),
      NULL);
  g_free (path);

  md = jingle_media_description_new ();

  /* FIXME: correct??? */
  contact = gabble_call_member_get_handle (
      gabble_call_member_content_get_member (mcontent));
  tp_md = tp_base_media_call_content_get_local_media_description (
      TP_BASE_MEDIA_CALL_CONTENT (self), contact);
  if (tp_md != NULL)
    {
      md->codecs = codec_array_to_list (tp_asv_get_boxed (tp_md,
          TP_PROP_CALL_CONTENT_MEDIA_DESCRIPTION_CODECS,
          TP_ARRAY_TYPE_CODEC_LIST));
    }

  if (md->codecs != NULL)
    jingle_media_rtp_set_local_media_description (
        GABBLE_JINGLE_MEDIA_RTP (jingle), md, TRUE, NULL);
  else
    jingle_media_description_free (md);

  tp_base_call_content_add_stream (base, TP_BASE_CALL_STREAM (stream));
  gabble_call_stream_update_member_states (stream);
  g_object_unref (stream);
}
static void
tp_base_call_stream_finalize (GObject *object)
{
  TpBaseCallStream *self = TP_BASE_CALL_STREAM (object);

  /* free any data held directly by the object here */
  g_free (self->priv->object_path);
  g_hash_table_unref (self->priv->remote_members);

  if (G_OBJECT_CLASS (tp_base_call_stream_parent_class)->finalize != NULL)
    G_OBJECT_CLASS (tp_base_call_stream_parent_class)->finalize (object);
}
/**
 * tp_base_media_call_stream_update_receiving_state:
 * @self: a #TpBaseMediaCallStream
 *
 * Update the receiving state.
 *
 * Since: 0.17.5
 */
void
tp_base_media_call_stream_update_receiving_state (TpBaseMediaCallStream *self)
{
  TpBaseCallStream *bcs = TP_BASE_CALL_STREAM (self);
  GHashTable *remote_members = _tp_base_call_stream_get_remote_members (bcs);
  GHashTableIter iter;
  gpointer key, value;
  gboolean remote_sending = FALSE;
  TpBaseCallChannel *channel = _tp_base_call_stream_get_channel (bcs);

  if (channel == NULL || !_tp_base_call_channel_is_locally_accepted (channel))
    goto done;

  if (self->priv->receiving_failure)
    goto done;

  if (TP_IS_BASE_MEDIA_CALL_CHANNEL (channel))
    {
      TpBaseMediaCallChannel *mediachan = TP_BASE_MEDIA_CALL_CHANNEL (channel);

      if (_tp_base_media_channel_is_held (mediachan))
        goto done;
    }

  g_hash_table_iter_init (&iter, remote_members);
  while (g_hash_table_iter_next (&iter, &key, &value))
    {
      TpSendingState state = GPOINTER_TO_UINT (value);

      switch (state)
        {
        case TP_SENDING_STATE_SENDING:
        case TP_SENDING_STATE_PENDING_SEND:
          remote_sending = TRUE;
          break;
        case TP_SENDING_STATE_PENDING_STOP_SENDING:
        case TP_SENDING_STATE_NONE:
          break;
        default:
          g_assert_not_reached ();
        }
      if (remote_sending)
        break;
    }

done:

  if (remote_sending)
    set_receiving_state (self, TP_STREAM_FLOW_STATE_PENDING_START);
  else
    set_receiving_state (self, TP_STREAM_FLOW_STATE_PENDING_STOP);
}
static void
tp_base_call_stream_set_sending_dbus (TpSvcCallStream *iface,
    gboolean sending,
    DBusGMethodInvocation *context)
{
  TpBaseCallStream *self = TP_BASE_CALL_STREAM (iface);
  GError *error = NULL;

  if (_tp_base_call_stream_set_sending (TP_BASE_CALL_STREAM (iface), sending,
          tp_base_channel_get_self_handle ((TpBaseChannel *) self->priv->channel),
          TP_CALL_STATE_CHANGE_REASON_USER_REQUESTED, "",
          "User changed the sending state", &error))
    {
      tp_svc_call_stream_return_from_set_sending (context);
    }
  else
    {
      dbus_g_method_return_error (context, error);
    }

  g_clear_error (&error);
}
static void
tp_base_call_stream_dispose (GObject *object)
{
  TpBaseCallStream *self = TP_BASE_CALL_STREAM (object);
  TpDBusDaemon *bus = tp_base_connection_get_dbus_daemon (
      (TpBaseConnection *) self->priv->conn);

  tp_dbus_daemon_unregister_object (bus, G_OBJECT (self));

  tp_clear_object (&self->priv->conn);

  if (G_OBJECT_CLASS (tp_base_call_stream_parent_class)->dispose != NULL)
    G_OBJECT_CLASS (tp_base_call_stream_parent_class)->dispose (object);
}
static void
tp_base_call_stream_constructed (GObject *obj)
{
  TpBaseCallStream *self = TP_BASE_CALL_STREAM (obj);
  TpDBusDaemon *bus = tp_base_connection_get_dbus_daemon (
      (TpBaseConnection *) self->priv->conn);

  if (G_OBJECT_CLASS (tp_base_call_stream_parent_class)->constructed != NULL)
    G_OBJECT_CLASS (tp_base_call_stream_parent_class)->constructed (obj);

  /* register object on the bus */
  DEBUG ("Registering %s", self->priv->object_path);
  tp_dbus_daemon_register_object (bus, self->priv->object_path, obj);
}
void
rakia_call_content_add_stream (RakiaCallContent *self)
{
  RakiaCallContentPrivate *priv = self->priv;
  TpBaseCallContent *bcc = TP_BASE_CALL_CONTENT (self);
  gchar *object_path;

  object_path = g_strdup_printf ("%s/Stream",
      tp_base_call_content_get_object_path (bcc));
  priv->stream = rakia_call_stream_new (self, priv->media,
      object_path, TP_STREAM_TRANSPORT_TYPE_RAW_UDP,
      tp_base_call_content_get_connection (bcc));
  g_free (object_path);

  tp_base_call_content_add_stream (bcc, TP_BASE_CALL_STREAM (priv->stream));
}
static void
tp_base_media_call_stream_report_sending_failure (
    TpSvcCallStreamInterfaceMedia *iface,
    TpCallStateChangeReason reason,
    const gchar *dbus_reason,
    const gchar *message,
    DBusGMethodInvocation *context)
{
  TpBaseMediaCallStream *self = TP_BASE_MEDIA_CALL_STREAM (iface);
  TpBaseMediaCallStreamClass *klass =
      TP_BASE_MEDIA_CALL_STREAM_GET_CLASS (self);
  TpStreamFlowState old_state = self->priv->sending_state;
  TpBaseCallChannel *channel = _tp_base_call_stream_get_channel (
      TP_BASE_CALL_STREAM (self));
  gboolean was_held = FALSE;

  if (self->priv->sending_state == TP_STREAM_FLOW_STATE_STOPPED)
    goto done;

  self->priv->sending_failure = TRUE;
  self->priv->sending_stop_requested = FALSE;
  self->priv->sending_state = TP_STREAM_FLOW_STATE_STOPPED;

  if (channel != NULL && TP_IS_BASE_MEDIA_CALL_CHANNEL (channel))
    {
      was_held = _tp_base_media_call_channel_streams_sending_state_changed (
          TP_BASE_MEDIA_CALL_CHANNEL (channel), FALSE);
    }

  if (!was_held)
    {
      self->priv->local_sending = FALSE;
      if (klass->report_sending_failure != NULL)
        klass->report_sending_failure (self, old_state, reason, dbus_reason,
            message);
    }

  g_object_notify (G_OBJECT (self), "sending-state");
  tp_svc_call_stream_interface_media_emit_sending_state_changed (self,
      self->priv->sending_state);

  self->priv->sending_failure = FALSE;

done:
  tp_svc_call_stream_interface_media_return_from_report_sending_failure (
      context);
}
static void
set_receiving_state (TpBaseMediaCallStream *self,
    TpStreamFlowState state)
{
  if (ignore_state_change (self->priv->receiving_state, state))
    return;

  DEBUG ("%s => %s (path: %s)",
      stream_flow_state_to_string (self->priv->receiving_state),
      stream_flow_state_to_string (state),
      tp_base_call_stream_get_object_path (TP_BASE_CALL_STREAM (self)));

  self->priv->receiving_state = state;
  g_object_notify (G_OBJECT (self), "receiving-state");

  tp_svc_call_stream_interface_media_emit_receiving_state_changed (self, state);
}
static void
tp_base_media_call_stream_complete_receiving_state_change (
    TpSvcCallStreamInterfaceMedia *iface,
    TpStreamFlowState state,
    DBusGMethodInvocation *context)
{
  TpBaseMediaCallStream *self = TP_BASE_MEDIA_CALL_STREAM (iface);
  TpBaseMediaCallStreamClass *klass =
      TP_BASE_MEDIA_CALL_STREAM_GET_CLASS (self);
  TpBaseCallChannel *channel = _tp_base_call_stream_get_channel (
      TP_BASE_CALL_STREAM (self));

  if (!correct_state_transition (self->priv->receiving_state, state))
    {
      GError e = { TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
          "Invalid receiving state transition" };
      dbus_g_method_return_error (context, &e);
      return;
    }

  self->priv->receiving_state = state;
  g_object_notify (G_OBJECT (self), "receiving-state");

  if (channel != NULL && TP_IS_BASE_MEDIA_CALL_CHANNEL (channel))
    _tp_base_media_call_channel_streams_receiving_state_changed (
        TP_BASE_MEDIA_CALL_CHANNEL (channel), TRUE);

  if (state == TP_STREAM_FLOW_STATE_STARTED)
    {
      TpIntsetFastIter iter;
      TpHandle contact;

      tp_intset_fast_iter_init (&iter, self->priv->receiving_requests);
      while (tp_intset_fast_iter_next (&iter, &contact))
        {
          if (klass->request_receiving != NULL)
            klass->request_receiving (self, contact, TRUE);
        }

      tp_intset_clear (self->priv->receiving_requests);
    }

  tp_svc_call_stream_interface_media_emit_receiving_state_changed (self, state);
  tp_svc_call_stream_interface_media_return_from_complete_receiving_state_change
      (context);
}
static void
tp_base_media_call_stream_complete_sending_state_change (
    TpSvcCallStreamInterfaceMedia *iface,
    TpStreamFlowState state,
    DBusGMethodInvocation *context)
{
  TpBaseMediaCallStream *self = TP_BASE_MEDIA_CALL_STREAM (iface);
  TpBaseMediaCallStreamClass *klass =
      TP_BASE_MEDIA_CALL_STREAM_GET_CLASS (self);
  TpBaseCallChannel *channel = _tp_base_call_stream_get_channel (
      TP_BASE_CALL_STREAM (self));

  if (!correct_state_transition (self->priv->sending_state, state))
    {
      GError e = { TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
          "Invalid sending state transition" };
      dbus_g_method_return_error (context, &e);
      return;
    }

  self->priv->sending_state = state;

  if (channel != NULL && TP_IS_BASE_MEDIA_CALL_CHANNEL (channel))
    _tp_base_media_call_channel_streams_sending_state_changed (
        TP_BASE_MEDIA_CALL_CHANNEL (channel), TRUE);

  if (state == TP_STREAM_FLOW_STATE_STOPPED &&
      klass->set_sending != NULL &&
      self->priv->sending_stop_requested)
    klass->set_sending (self, FALSE, NULL);

  self->priv->sending_stop_requested = FALSE;

  tp_svc_call_stream_interface_media_emit_sending_state_changed (self, state);
  tp_svc_call_stream_interface_media_return_from_complete_sending_state_change
      (context);
}
/**
 * tp_base_media_call_stream_update_sending_state:
 * @self: a #TpBaseMediaCallStream
 *
 * Update the sending state.
 *
 * Since: 0.17.5
 */
void
tp_base_media_call_stream_update_sending_state (TpBaseMediaCallStream *self)
{
  TpBaseCallChannel *channel = _tp_base_call_stream_get_channel (
      TP_BASE_CALL_STREAM (self));
  gboolean sending = FALSE;

  if (channel == NULL)
    goto done;

  if (TP_IS_BASE_MEDIA_CALL_CHANNEL (channel))
    {
      TpBaseMediaCallChannel *mediachan = TP_BASE_MEDIA_CALL_CHANNEL (channel);

      if (_tp_base_media_channel_is_held (mediachan))
        goto done;
    }

  if (!tp_base_call_channel_is_accepted (TP_BASE_CALL_CHANNEL (channel)))
    goto done;

  if (self->priv->remotely_held)
    goto done;

  if (self->priv->sending_failure)
    goto done;

  sending = self->priv->local_sending;

done:

  if (sending)
    set_sending_state (self, TP_STREAM_FLOW_STATE_PENDING_START);
  else
    set_sending_state (self, TP_STREAM_FLOW_STATE_PENDING_STOP);
}
static void
tp_base_media_call_stream_fail (TpSvcCallStreamInterfaceMedia *iface,
    const GValueArray *reason_array,
    DBusGMethodInvocation *context)
{
  TpBaseMediaCallStream *self = TP_BASE_MEDIA_CALL_STREAM (iface);
  TpBaseCallStream *base = TP_BASE_CALL_STREAM (self);
  TpBaseCallChannel *channel;
  TpBaseCallContent *content;

  channel = _tp_base_call_stream_get_channel (base);
  content = _tp_base_call_stream_get_content (base);

  _tp_base_call_content_remove_stream_internal (content, base, reason_array);

  /* If it was the last stream, remove the content */
  if (tp_base_call_content_get_streams (content) == NULL)
    {
      _tp_base_call_channel_remove_content_internal (channel, content,
          reason_array);
    }

  tp_svc_call_stream_interface_media_return_from_fail (context);
}
static void
tp_base_call_stream_request_receiving (TpSvcCallStream *iface,
    TpHandle contact,
    gboolean receiving,
    DBusGMethodInvocation *context)
{
  TpBaseCallStream *self = TP_BASE_CALL_STREAM (iface);
  TpBaseCallStreamClass *klass = TP_BASE_CALL_STREAM_GET_CLASS (self);
  GError *error = NULL;
  TpSendingState remote_sending_state;
  gboolean can_request_receiving;

  g_object_get (self, "can-request-receiving", &can_request_receiving, NULL);
  if (!can_request_receiving)
    {
      g_set_error (&error, TP_ERROR, TP_ERROR_NOT_CAPABLE,
          "The contact does not support requesting to receive");
      goto error;
    }

  if (!g_hash_table_lookup_extended (self->priv->remote_members,
          GUINT_TO_POINTER (contact), NULL, (gpointer *) &remote_sending_state))
    {
      g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
          "Contact %u is not member of this stream", contact);
      goto error;
    }

  if (klass->request_receiving == NULL)
    {
      g_set_error_literal (&error, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED,
          "This CM does not implement request_receiving");
      goto error;
    }


  /* Determine if there is a state change for our receiving side
   * aka remote sending
   */
  switch (remote_sending_state)
    {
      case TP_SENDING_STATE_NONE:
      case TP_SENDING_STATE_PENDING_STOP_SENDING:
        if (!receiving)
          goto out;
        break;
      case TP_SENDING_STATE_SENDING:
      case TP_SENDING_STATE_PENDING_SEND:
        if (receiving)
          goto out;
        break;
      default:
        g_assert_not_reached ();
    }

  if (!klass->request_receiving (self, contact, receiving, &error))
    goto error;

out:
  tp_svc_call_stream_return_from_request_receiving (context);
  return;

error:
  dbus_g_method_return_error (context, error);
  g_clear_error (&error);
}