static void ringing_cb (RakiaSipSession *session, RakiaCallChannel *self) { tp_base_call_channel_update_member_flags (TP_BASE_CALL_CHANNEL (self), tp_base_channel_get_target_handle (TP_BASE_CHANNEL (self)), TP_CALL_MEMBER_FLAG_RINGING, tp_base_channel_get_target_handle (TP_BASE_CHANNEL (self)), TP_CALL_STATE_CHANGE_REASON_PROGRESS_MADE, "", "Remote side has started ringing"); }
static void send_message (GObject *object, TpMessage *message, TpMessageSendingFlags flags) { FetionImChannel *self = FETION_IM_CHANNEL (object); TpBaseChannel *base = TP_BASE_CHANNEL (self); if (tp_asv_get_string (tp_message_peek (message, 0), "interface") != NULL) { /* this message is interface-specific - let's not echo it */ goto finally; } FetionConnection *conn = FETION_CONNECTION (tp_base_channel_get_connection(base)); HybridAccount *account = conn->priv->account; TpHandle from = tp_base_channel_get_target_handle (base); const GHashTable *input = tp_message_peek (message, 1); const gchar *send_message = tp_asv_get_string (input, "content"); HybridBuddy *buddy = hybrid_blist_find_buddy_by_handle(account, from); hybrid_conv_send_message(account,buddy,send_message); finally: /* "OK, we've sent the message" (after calling this, message must not be * dereferenced) */ tp_message_mixin_sent (object, message, flags, "", NULL); }
static void _im_channel_closed_cb (IdleIMChannel *chan, gpointer user_data) { IdleIMManager *self = IDLE_IM_MANAGER (user_data); IdleIMManagerPrivate *priv = IDLE_IM_MANAGER_GET_PRIVATE (self); TpBaseChannel *base = TP_BASE_CHANNEL (chan); tp_channel_manager_emit_channel_closed_for_object (self, TP_EXPORTABLE_CHANNEL (chan)); if (priv->channels) { TpHandle handle = tp_base_channel_get_target_handle (base); if (tp_base_channel_is_destroyed (base)) { IDLE_DEBUG ("removing channel with handle %u", handle); g_hash_table_remove (priv->channels, GUINT_TO_POINTER (handle)); } else { IDLE_DEBUG ("reopening channel with handle %u due to pending messages", handle); tp_channel_manager_emit_new_channel (self, (TpExportableChannel *) chan, NULL); } } }
static void remote_held_changed_cb (RakiaSipSession *session, GParamSpec *pspec, RakiaCallChannel *self) { TpBaseChannel *bchan = TP_BASE_CHANNEL (self); TpBaseCallChannel *bcc = TP_BASE_CALL_CHANNEL (self); gboolean remote_held; GHashTable *members; TpCallMemberFlags member_flags; TpHandle remote_contact = tp_base_channel_get_target_handle (bchan); g_object_get (session, "remote-held", &remote_held, NULL); members = tp_base_call_channel_get_call_members (bcc); member_flags = GPOINTER_TO_UINT (g_hash_table_lookup (members, GUINT_TO_POINTER (remote_contact))); if (!!(member_flags & TP_CALL_MEMBER_FLAG_HELD) == remote_held) return; if (remote_held) member_flags |= TP_CALL_MEMBER_FLAG_HELD; else member_flags &= ~TP_CALL_MEMBER_FLAG_HELD; tp_base_call_channel_update_member_flags (bcc, remote_contact, member_flags, remote_contact, TP_CALL_STATE_CHANGE_REASON_USER_REQUESTED, "", remote_held ? "Held by remote side" : "Unheld by remote side"); }
static void new_content (RakiaCallChannel *self, const gchar *name, RakiaSipMedia *media, TpCallContentDisposition disposition) { TpBaseChannel *bchan = TP_BASE_CHANNEL (self); RakiaCallContent *content; TpMediaStreamType media_type; TpHandle creator; gchar *object_path; gchar *free_name = NULL; const gchar *media_type_name; switch (rakia_sip_media_get_media_type (media)) { case TP_MEDIA_STREAM_TYPE_AUDIO: media_type = TP_MEDIA_STREAM_TYPE_AUDIO; media_type_name = "Audio"; break; case TP_MEDIA_STREAM_TYPE_VIDEO: media_type = TP_MEDIA_STREAM_TYPE_VIDEO; media_type_name = "Video"; break; default: g_assert_not_reached (); } if (rakia_sip_media_is_created_locally (media)) creator = tp_base_channel_get_self_handle (bchan); else creator = tp_base_channel_get_target_handle (bchan); object_path = g_strdup_printf ("%s/Content%u", tp_base_channel_get_object_path (bchan), ++self->priv->last_content_no); if (name == NULL) name = free_name = g_strdup_printf ("%s %u", media_type_name, self->priv->last_content_no); /* We already request bidi for initial media, * the client can change it before accepting. */ if (disposition == TP_CALL_CONTENT_DISPOSITION_INITIAL) rakia_sip_media_set_requested_direction (media, TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL); content = rakia_call_content_new (self, media, object_path, tp_base_channel_get_connection (bchan), name, media_type, creator, disposition); g_free (free_name); g_free (object_path); tp_base_call_channel_add_content (TP_BASE_CALL_CHANNEL (self), TP_BASE_CALL_CONTENT (content)); rakia_call_content_add_stream (content); }
/** start send message **/ static void send_message (GObject *object, TpMessage *message, TpMessageSendingFlags flags) { LwqqChannel* self = LWQQ_CHANNEL(object); TpBaseChannel *base = TP_BASE_CHANNEL (self); if (tp_asv_get_string (tp_message_peek (message, 0), "interface") != NULL) { /* this message is interface-specific - let's not echo it */ goto finally; } LwqqConnection *conn = LWQQ_CONNECTION(tp_base_channel_get_connection(base)); LwqqClient* lc = conn->lc; TpHandle to = tp_base_channel_get_target_handle (base); const GHashTable *input = tp_message_peek (message, 1); const gchar *send_message = tp_asv_get_string (input, "content"); LwqqBuddy* buddy = lwqq_find_buddy_by_handle(conn, to); lwqq_msg_send_text(lc, LWQQ_MS_BUDDY_MSG, buddy->uin, send_message); finally: /* "OK, we've sent the message" (after calling this, message must not be * dereferenced) */ tp_message_mixin_sent (object, message, flags, "", NULL); }
static void media_remote_codecs_updated_cb (RakiaSipMedia *media, gboolean is_offer, RakiaCallContent *self) { TpBaseCallContent *bcc = TP_BASE_CALL_CONTENT (self); TpBaseMediaCallContent *bmcc = TP_BASE_MEDIA_CALL_CONTENT (self); RakiaCallContentPrivate *priv = self->priv; GPtrArray *remote_codecs = rakia_sip_media_get_remote_codec_offer (priv->media); TpCallContentMediaDescription *md; TpDBusDaemon *bus = tp_base_connection_get_dbus_daemon ( tp_base_call_content_get_connection (bcc)); gchar *object_path; guint i, j; if (remote_codecs == NULL) return; object_path = g_strdup_printf ("%s/Offer%u", tp_base_call_content_get_object_path (bcc), ++priv->codec_offer_id); md = tp_call_content_media_description_new (bus, object_path, tp_base_channel_get_target_handle (TP_BASE_CHANNEL (priv->channel)), TRUE, is_offer); g_free (object_path); for (i = 0; i < remote_codecs->len; i++) { RakiaSipCodec *codec = g_ptr_array_index (remote_codecs, i); GHashTable *parameters = g_hash_table_new (g_str_hash, g_str_equal); /* No need to copy the values as .._append_codec() will */ if (codec->params) for (j = 0; j < codec->params->len; j++) { RakiaSipCodecParam *param = g_ptr_array_index (codec->params, j); g_hash_table_insert (parameters, param->name, param->value); } tp_call_content_media_description_append_codec (md, codec->id, codec->encoding_name, codec->clock_rate, codec->channels, TRUE, parameters); g_hash_table_unref (parameters); } tp_base_media_call_content_offer_media_description_async (bmcc, md, md_offer_cb, GUINT_TO_POINTER (FALSE)); g_object_unref (md); }
gboolean gabble_call_member_start_session (GabbleCallMember *self, const gchar *audio_name, const gchar *video_name, GError **error) { GabbleCallMemberPrivate *priv = self->priv; TpBaseChannel *base_channel = TP_BASE_CHANNEL (priv->call); TpHandle target = tp_base_channel_get_target_handle (base_channel); const gchar *resource; JingleDialect dialect; gchar *jid; const gchar *transport; GabbleJingleFactory *jf; GabbleJingleSession *session; /* FIXME might need to wait on capabilities, also don't need transport * and dialect already */ if (!jingle_pick_best_resource (gabble_call_member_get_connection (self), target, audio_name != NULL, video_name != NULL, &transport, &dialect, &resource)) { g_set_error (error, TP_ERROR, TP_ERROR_NOT_CAPABLE, "member does not have the desired audio/video capabilities"); return FALSE; } jid = gabble_peer_to_jid (gabble_call_member_get_connection (self), target, resource); jf = gabble_jingle_mint_get_factory ( gabble_call_member_get_connection (self)->jingle_mint); g_return_val_if_fail (jf != NULL, FALSE); session = gabble_jingle_factory_create_session (jf, jid, dialect, FALSE); g_free (jid); gabble_call_member_set_session (self, session); priv->transport_ns = g_strdup (transport); if (audio_name != NULL) gabble_call_member_create_content (self, audio_name, JINGLE_MEDIA_TYPE_AUDIO, JINGLE_CONTENT_SENDERS_BOTH, NULL); if (video_name != NULL) gabble_call_member_create_content (self, video_name, JINGLE_MEDIA_TYPE_VIDEO, JINGLE_CONTENT_SENDERS_BOTH, NULL); return TRUE; }
static void media_removed_cb (RakiaSipSession *session, RakiaSipMedia *media, RakiaCallChannel *self) { RakiaCallContent *content; content = rakia_call_channel_get_content_by_media (self, media); if (content == NULL) return; tp_base_call_channel_remove_content (TP_BASE_CALL_CHANNEL (self), TP_BASE_CALL_CONTENT (content), tp_base_channel_get_target_handle (TP_BASE_CHANNEL (self)), TP_CALL_STATE_CHANGE_REASON_USER_REQUESTED, "", "Removed by remote side"); }
static void rakia_call_content_constructed (GObject *object) { RakiaCallContent *self = RAKIA_CALL_CONTENT (object); RakiaCallContentPrivate *priv = self->priv; TpBaseChannel *bchan = TP_BASE_CHANNEL (priv->channel); TpBaseCallContent *bcc = TP_BASE_CALL_CONTENT (self); TpBaseMediaCallContent *bmcc = TP_BASE_MEDIA_CALL_CONTENT (self); TpHandle creator; gchar *object_path; g_signal_connect_object (priv->media, "remote-codec-offer-updated", G_CALLBACK (media_remote_codecs_updated_cb), self, 0); g_signal_connect (self, "local-media-description-updated", G_CALLBACK (local_media_description_updated), NULL); g_object_get (object, "creator", &creator, NULL); if (creator == tp_base_channel_get_self_handle (bchan)) { TpCallContentMediaDescription *md; TpDBusDaemon *bus = tp_base_connection_get_dbus_daemon ( tp_base_call_content_get_connection (bcc)); object_path = g_strdup_printf ("%s/InitialOffer", tp_base_call_content_get_object_path (bcc)); md = tp_call_content_media_description_new (bus, object_path, tp_base_channel_get_target_handle (bchan), FALSE, TRUE); g_free (object_path); tp_base_media_call_content_offer_media_description_async (bmcc, md, md_offer_cb, GUINT_TO_POINTER (TRUE)); } else { media_remote_codecs_updated_cb (priv->media, TRUE, self); } G_OBJECT_CLASS (rakia_call_content_parent_class)->constructed (object); }
/** * im_channel_closed_cb: * * Signal callback for when an IM channel is closed. Removes the references * that #GabbleConnection holds to them - unless the channel has pending * messages, in which case it is re-announced (so from the perspective of the * D-Bus API, it was replaced by an identical channel). */ static void im_channel_closed_cb (GabbleIMChannel *chan, gpointer user_data) { GabbleImFactory *self = GABBLE_IM_FACTORY (user_data); GabbleImFactoryPrivate *priv = self->priv; TpBaseChannel *base = TP_BASE_CHANNEL (chan); TpHandle contact_handle = tp_base_channel_get_target_handle (base); DEBUG ("%p, channel %p", self, chan); if (tp_base_channel_is_registered (base)) { tp_channel_manager_emit_channel_closed_for_object (self, (TpExportableChannel *) chan); } if (priv->channels != NULL) { if (tp_base_channel_is_destroyed (base)) { DEBUG ("removing channel with handle %u", contact_handle); g_hash_table_remove (priv->channels, GUINT_TO_POINTER (contact_handle)); } else if (tp_base_channel_is_respawning (base)) { DEBUG ("reopening channel with handle %u due to pending messages", contact_handle); tp_channel_manager_emit_new_channel (self, (TpExportableChannel *) chan, NULL); } else { /* this basically means tp_base_channel_disappear() must * have been called; this doesn't have any meaning in this * channel manager. */ g_assert_not_reached (); } } }
static void md_offer_cb (GObject *obj, GAsyncResult *res, gpointer user_data) { RakiaCallContent *self = RAKIA_CALL_CONTENT (obj); RakiaCallContentPrivate *priv = self->priv; TpBaseMediaCallContent *bmcc = TP_BASE_MEDIA_CALL_CONTENT (self); GError *error = NULL; gboolean is_initial_offer = GPOINTER_TO_UINT (user_data); if (tp_base_media_call_content_offer_media_description_finish (bmcc, res, &error)) { GHashTable *local_md = tp_base_media_call_content_get_local_media_description (bmcc, tp_base_channel_get_target_handle (TP_BASE_CHANNEL (priv->channel))); set_telepathy_codecs (self, local_md); } else { /* Only reject if the codecs where rejected */ if (error->domain == TP_ERROR && error->code == TP_ERROR_MEDIA_CODECS_INCOMPATIBLE) { g_assert (!is_initial_offer); rakia_sip_media_codecs_rejected (priv->media); DEBUG ("Codecs rejected: %s", error->message); } /* FIXME: We need to allow for partial failures */ g_clear_error (&error); } }
static void ended_cb (RakiaSipSession *session, gboolean self_actor, guint status, gchar *message, RakiaCallChannel *self) { TpHandle actor; TpCallStateChangeReason reason; const gchar *detailed_reason = ""; gchar *free_message = NULL; if (self_actor) actor = tp_base_channel_get_self_handle (TP_BASE_CHANNEL (self)); else actor = tp_base_channel_get_target_handle (TP_BASE_CHANNEL (self)); switch (status) { case 400: /* Bad Request */ case 405: /* Method Not Allowed */ case 406: /* Not Acceptable */ case 413: /* Request Entity Too Large */ case 414: /* Request-URI Too Long */ case 415: /* Unsupported Media Type */ case 416: /* Unsupported URI Scheme */ case 420: /* Bad Extension */ case 421: /* Extension Required */ case 483: /* Too Many Hops */ case 484: /* Address incomplete */ case 485: /* Ambiguous */ case 493: /* Undecipherable */ case 606: /* Not Acceptable */ reason = TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR; detailed_reason = TP_ERROR_STR_CONFUSED; break; case 500: /* Server Internal Error */ case 501: /* Not Implemented */ case 502: /* Bad Gateway */ case 503: /* Service Unavailable */ case 504: /* Server Time-out */ case 505: /* Version Not Supported */ case 513: /* Message Too Large */ reason = TP_CALL_STATE_CHANGE_REASON_SERVICE_ERROR; detailed_reason = TP_ERROR_STR_SERVICE_CONFUSED; break; case 401: /* Unauthorized */ case 403: /* Forbidden */ reason = TP_CALL_STATE_CHANGE_REASON_PERMISSION_DENIED; detailed_reason = TP_ERROR_STR_PERMISSION_DENIED; break; case 404: /* Not Found */ case 410: /* Gone */ case 604: /* Does Not Exist Anywhere */ reason = TP_CALL_STATE_CHANGE_REASON_INVALID_CONTACT; detailed_reason = TP_ERROR_STR_DOES_NOT_EXIST; break; case 480: /* Temporarily Unavaible */ case 408: /* Request Timeout */ reason = TP_CALL_STATE_CHANGE_REASON_NO_ANSWER; detailed_reason = TP_ERROR_STR_NO_ANSWER; break; case 486: /* Busy Here */ case 600: /* Busy Everywhere */ reason = TP_CALL_STATE_CHANGE_REASON_BUSY; detailed_reason = TP_ERROR_STR_BUSY; break; case 603: /* Decline */ reason = TP_CALL_STATE_CHANGE_REASON_REJECTED; detailed_reason = TP_ERROR_STR_REJECTED; break; default: reason = TP_CALL_STATE_CHANGE_REASON_USER_REQUESTED; break; } if (message[0] == 0 && reason != 0) free_message = message = g_strdup_printf ("SIP status code %d", status); tp_base_call_channel_set_state (TP_BASE_CALL_CHANNEL (self), TP_CALL_STATE_ENDED, actor, reason, detailed_reason, message); g_free (free_message); }
static void rakia_call_channel_constructed (GObject *obj) { TpBaseChannel *bc = TP_BASE_CHANNEL (obj); TpBaseCallChannel *bcc = TP_BASE_CALL_CHANNEL (obj); RakiaCallChannel *self = RAKIA_CALL_CHANNEL (obj); GObjectClass *parent_object_class = G_OBJECT_CLASS (rakia_call_channel_parent_class); TpHandle actor; TpCallStateChangeReason reason; g_signal_connect_object (self->priv->session, "ended", G_CALLBACK (ended_cb), self, 0); g_signal_connect_object (self->priv->session, "ringing", G_CALLBACK (ringing_cb), self, 0); g_signal_connect_object (self->priv->session, "queued", G_CALLBACK (queued_cb), self, 0); g_signal_connect_object (self->priv->session, "in-progress", G_CALLBACK (in_progress_cb), self, 0); g_signal_connect_object (self->priv->session, "media-added", G_CALLBACK (media_added_cb), self, 0); g_signal_connect_object (self->priv->session, "media-removed", G_CALLBACK (media_removed_cb), self, 0); g_signal_connect_object (self->priv->session, "state-changed", G_CALLBACK (state_changed_cb), self, 0); g_signal_connect_object (self->priv->session, "notify::remote-held", G_CALLBACK (remote_held_changed_cb), self, 0); if (tp_base_channel_is_requested (bc)) { const gchar *initial_audio_name; const gchar *initial_video_name; if (tp_base_call_channel_has_initial_audio (bcc, &initial_audio_name)) rakia_sip_session_add_media (self->priv->session, TP_MEDIA_STREAM_TYPE_AUDIO, initial_audio_name, TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL); if (tp_base_call_channel_has_initial_video (bcc, &initial_video_name)) rakia_sip_session_add_media (self->priv->session, TP_MEDIA_STREAM_TYPE_VIDEO, initial_video_name, TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL); actor = tp_base_channel_get_self_handle (bc); reason = TP_CALL_STATE_CHANGE_REASON_USER_REQUESTED; } else { guint i; GPtrArray *medias = rakia_sip_session_get_medias (self->priv->session); for (i = 0; i < medias->len; i++) { RakiaSipMedia *media = g_ptr_array_index (medias, i); gchar *name; if (media) { name = g_strdup_printf ("initial_%s_%u", sip_media_get_media_type_str (media), i + 1); new_content (self, name, media, TP_CALL_CONTENT_DISPOSITION_INITIAL); g_free (name); } } actor = tp_base_channel_get_target_handle (bc); reason = TP_CALL_STATE_CHANGE_REASON_PROGRESS_MADE; } tp_base_call_channel_update_member_flags (bcc, tp_base_channel_get_target_handle (bc), 0, actor, reason, "", "Call Created"); if (parent_object_class->constructed != NULL) parent_object_class->constructed (obj); }