pidgin/pidgin

Add missing files to Pidgin API docs.

2019-11-22, Elliott Sales de Andrade
0c7b2c569028
Add missing files to Pidgin API docs.
/* purple
*
* Purple is the legal property of its developers, whose names are too numerous
* to list here. Please refer to the COPYRIGHT file distributed with this
* source distribution.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
*/
#include "internal.h"
#include "account.h"
#include "media.h"
#include "media/backend-iface.h"
#include "mediamanager.h"
#include "debug.h"
#ifdef USE_GSTREAMER
#include "media/backend-fs2.h"
#include "media-gst.h"
#endif /* USE_GSTREAMER */
#ifdef USE_VV
/** @copydoc _PurpleMediaSession */
typedef struct _PurpleMediaSession PurpleMediaSession;
/** @copydoc _PurpleMediaStream */
typedef struct _PurpleMediaStream PurpleMediaStream;
struct _PurpleMediaSession
{
gchar *id;
PurpleMedia *media;
PurpleMediaSessionType type;
gboolean initiator;
};
struct _PurpleMediaStream
{
PurpleMediaSession *session;
gchar *participant;
GList *local_candidates;
GList *remote_candidates;
gboolean initiator;
gboolean accepted;
gboolean candidates_prepared;
GList *active_local_candidates;
GList *active_remote_candidates;
};
#endif
struct _PurpleMediaPrivate
{
#ifdef USE_VV
PurpleMediaManager *manager;
PurpleAccount *account;
PurpleMediaBackend *backend;
gchar *conference_type;
gboolean initiator;
gpointer protocol_data;
GHashTable *sessions; /* PurpleMediaSession table */
GList *participants;
GList *streams; /* PurpleMediaStream table */
#else
gpointer dummy;
#endif
};
#ifdef USE_VV
static void purple_media_class_init (PurpleMediaClass *klass);
static void purple_media_init (PurpleMedia *media);
static void purple_media_dispose (GObject *object);
static void purple_media_finalize (GObject *object);
static void purple_media_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
static void purple_media_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
static void purple_media_new_local_candidate_cb(PurpleMediaBackend *backend,
const gchar *sess_id, const gchar *participant,
PurpleMediaCandidate *candidate, PurpleMedia *media);
static void purple_media_candidates_prepared_cb(PurpleMediaBackend *backend,
const gchar *sess_id, const gchar *name, PurpleMedia *media);
static void purple_media_candidate_pair_established_cb(
PurpleMediaBackend *backend,
const gchar *sess_id, const gchar *name,
PurpleMediaCandidate *local_candidate,
PurpleMediaCandidate *remote_candidate,
PurpleMedia *media);
static void purple_media_codecs_changed_cb(PurpleMediaBackend *backend,
const gchar *sess_id, PurpleMedia *media);
enum {
S_ERROR,
CANDIDATES_PREPARED,
CODECS_CHANGED,
LEVEL,
NEW_CANDIDATE,
STATE_CHANGED,
STREAM_INFO,
CANDIDATE_PAIR_ESTABLISHED,
LAST_SIGNAL
};
static guint purple_media_signals[LAST_SIGNAL] = {0};
enum {
PROP_0,
PROP_MANAGER,
PROP_BACKEND,
PROP_ACCOUNT,
PROP_CONFERENCE_TYPE,
PROP_INITIATOR,
PROP_PROTOCOL_DATA,
};
G_DEFINE_TYPE_WITH_PRIVATE(PurpleMedia, purple_media, G_TYPE_OBJECT);
#else
GType
purple_media_get_type()
{
return G_TYPE_NONE;
}
#endif /* USE_VV */
#ifdef USE_VV
static void
purple_media_class_init (PurpleMediaClass *klass)
{
GObjectClass *gobject_class = (GObjectClass*)klass;
gobject_class->dispose = purple_media_dispose;
gobject_class->finalize = purple_media_finalize;
gobject_class->set_property = purple_media_set_property;
gobject_class->get_property = purple_media_get_property;
g_object_class_install_property(gobject_class, PROP_MANAGER,
g_param_spec_object("manager",
"Purple Media Manager",
"The media manager that contains this media session.",
PURPLE_TYPE_MEDIA_MANAGER,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
/*
* This one should be PURPLE_TYPE_MEDIA_BACKEND, but it doesn't
* like interfaces because they "aren't GObjects"
*/
g_object_class_install_property(gobject_class, PROP_BACKEND,
g_param_spec_object("backend",
"Purple Media Backend",
"The backend object this media object uses.",
G_TYPE_OBJECT,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property(gobject_class, PROP_ACCOUNT,
g_param_spec_object("account", "PurpleAccount",
"The account this media session is on.",
PURPLE_TYPE_ACCOUNT,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property(gobject_class, PROP_CONFERENCE_TYPE,
g_param_spec_string("conference-type",
"Conference Type",
"The type of conference that this media object "
"has been created to provide.",
NULL,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property(gobject_class, PROP_INITIATOR,
g_param_spec_boolean("initiator",
"initiator",
"If the local user initiated the conference.",
FALSE,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property(gobject_class, PROP_PROTOCOL_DATA,
g_param_spec_pointer("protocol-data",
"gpointer",
"Data the protocol set on the media session.",
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
purple_media_signals[S_ERROR] = g_signal_new("error", G_TYPE_FROM_CLASS(klass),
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
G_TYPE_NONE, 1, G_TYPE_STRING);
purple_media_signals[CANDIDATES_PREPARED] = g_signal_new("candidates-prepared", G_TYPE_FROM_CLASS(klass),
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
G_TYPE_NONE, 2, G_TYPE_STRING,
G_TYPE_STRING);
purple_media_signals[CODECS_CHANGED] = g_signal_new("codecs-changed", G_TYPE_FROM_CLASS(klass),
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
G_TYPE_NONE, 1, G_TYPE_STRING);
purple_media_signals[LEVEL] = g_signal_new("level", G_TYPE_FROM_CLASS(klass),
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
G_TYPE_NONE, 3, G_TYPE_STRING,
G_TYPE_STRING, G_TYPE_DOUBLE);
purple_media_signals[NEW_CANDIDATE] = g_signal_new("new-candidate", G_TYPE_FROM_CLASS(klass),
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
G_TYPE_NONE, 3, G_TYPE_POINTER,
G_TYPE_POINTER, PURPLE_TYPE_MEDIA_CANDIDATE);
purple_media_signals[STATE_CHANGED] = g_signal_new("state-changed", G_TYPE_FROM_CLASS(klass),
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
G_TYPE_NONE, 3, PURPLE_MEDIA_TYPE_STATE,
G_TYPE_STRING, G_TYPE_STRING);
purple_media_signals[STREAM_INFO] = g_signal_new("stream-info", G_TYPE_FROM_CLASS(klass),
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
G_TYPE_NONE, 4, PURPLE_MEDIA_TYPE_INFO_TYPE,
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN);
purple_media_signals[CANDIDATE_PAIR_ESTABLISHED] = g_signal_new("candidate-pair-established", G_TYPE_FROM_CLASS(klass),
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
G_TYPE_NONE, 4, G_TYPE_POINTER, G_TYPE_POINTER,
PURPLE_TYPE_MEDIA_CANDIDATE, PURPLE_TYPE_MEDIA_CANDIDATE);
}
static void
purple_media_init (PurpleMedia *media)
{
media->priv = purple_media_get_instance_private(media);
memset(media->priv, 0, sizeof(*media->priv));
}
static void
purple_media_stream_free(PurpleMediaStream *stream)
{
if (stream == NULL)
return;
g_free(stream->participant);
if (stream->local_candidates)
purple_media_candidate_list_free(stream->local_candidates);
if (stream->remote_candidates)
purple_media_candidate_list_free(stream->remote_candidates);
if (stream->active_local_candidates)
purple_media_candidate_list_free(
stream->active_local_candidates);
if (stream->active_remote_candidates)
purple_media_candidate_list_free(
stream->active_remote_candidates);
g_free(stream);
}
static void
purple_media_session_free(PurpleMediaSession *session)
{
if (session == NULL)
return;
g_free(session->id);
g_free(session);
}
static void
purple_media_dispose(GObject *media)
{
PurpleMediaPrivate *priv =
purple_media_get_instance_private(PURPLE_MEDIA(media));
purple_debug_info("media","purple_media_dispose\n");
purple_media_manager_remove_media(priv->manager, PURPLE_MEDIA(media));
if (priv->backend) {
g_object_unref(priv->backend);
priv->backend = NULL;
}
if (priv->manager) {
g_object_unref(priv->manager);
priv->manager = NULL;
}
G_OBJECT_CLASS(purple_media_parent_class)->dispose(media);
}
static void
purple_media_finalize(GObject *media)
{
PurpleMediaPrivate *priv =
purple_media_get_instance_private(PURPLE_MEDIA(media));
purple_debug_info("media","purple_media_finalize\n");
g_list_free_full(priv->streams, (GDestroyNotify)purple_media_stream_free);
g_list_free_full(priv->participants, g_free);
if (priv->sessions) {
GList *sessions = g_hash_table_get_values(priv->sessions);
g_list_free_full(sessions, (GDestroyNotify)purple_media_session_free);
g_hash_table_destroy(priv->sessions);
}
G_OBJECT_CLASS(purple_media_parent_class)->finalize(media);
}
static void
purple_media_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
{
PurpleMedia *media;
g_return_if_fail(PURPLE_IS_MEDIA(object));
media = PURPLE_MEDIA(object);
switch (prop_id) {
case PROP_MANAGER:
media->priv->manager = g_value_dup_object(value);
break;
case PROP_ACCOUNT:
media->priv->account = g_value_get_object(value);
break;
case PROP_CONFERENCE_TYPE:
media->priv->conference_type =
g_value_dup_string(value);
media->priv->backend = g_object_new(
purple_media_manager_get_backend_type(
purple_media_manager_get()),
"conference-type",
media->priv->conference_type,
"media", media,
NULL);
g_signal_connect(media->priv->backend,
"active-candidate-pair",
G_CALLBACK(
purple_media_candidate_pair_established_cb),
media);
g_signal_connect(media->priv->backend,
"candidates-prepared",
G_CALLBACK(
purple_media_candidates_prepared_cb),
media);
g_signal_connect(media->priv->backend,
"codecs-changed",
G_CALLBACK(
purple_media_codecs_changed_cb),
media);
g_signal_connect(media->priv->backend,
"new-candidate",
G_CALLBACK(
purple_media_new_local_candidate_cb),
media);
break;
case PROP_INITIATOR:
media->priv->initiator = g_value_get_boolean(value);
break;
case PROP_PROTOCOL_DATA:
media->priv->protocol_data = g_value_get_pointer(value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
purple_media_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
{
PurpleMedia *media;
g_return_if_fail(PURPLE_IS_MEDIA(object));
media = PURPLE_MEDIA(object);
switch (prop_id) {
case PROP_MANAGER:
g_value_set_object(value, media->priv->manager);
break;
case PROP_BACKEND:
g_value_set_object(value, media->priv->backend);
break;
case PROP_ACCOUNT:
g_value_set_object(value, media->priv->account);
break;
case PROP_CONFERENCE_TYPE:
g_value_set_string(value,
media->priv->conference_type);
break;
case PROP_INITIATOR:
g_value_set_boolean(value, media->priv->initiator);
break;
case PROP_PROTOCOL_DATA:
g_value_set_pointer(value, media->priv->protocol_data);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static PurpleMediaSession*
purple_media_get_session(PurpleMedia *media, const gchar *sess_id)
{
g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
return (PurpleMediaSession*) (media->priv->sessions) ?
g_hash_table_lookup(media->priv->sessions, sess_id) : NULL;
}
static PurpleMediaStream*
purple_media_get_stream(PurpleMedia *media, const gchar *session, const gchar *participant)
{
GList *streams;
g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
streams = media->priv->streams;
for (; streams; streams = g_list_next(streams)) {
PurpleMediaStream *stream = streams->data;
if (purple_strequal(stream->session->id, session) &&
purple_strequal(stream->participant, participant))
return stream;
}
return NULL;
}
static GList *
purple_media_get_streams(PurpleMedia *media, const gchar *session,
const gchar *participant)
{
GList *streams;
GList *ret = NULL;
g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
streams = media->priv->streams;
for (; streams; streams = g_list_next(streams)) {
PurpleMediaStream *stream = streams->data;
if ((session == NULL ||
purple_strequal(stream->session->id, session)) &&
(participant == NULL ||
purple_strequal(stream->participant, participant)))
ret = g_list_append(ret, stream);
}
return ret;
}
static void
purple_media_add_session(PurpleMedia *media, PurpleMediaSession *session)
{
g_return_if_fail(PURPLE_IS_MEDIA(media));
g_return_if_fail(session != NULL);
if (!media->priv->sessions) {
purple_debug_info("media", "Creating hash table for sessions\n");
media->priv->sessions = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free, NULL);
}
g_hash_table_insert(media->priv->sessions, g_strdup(session->id), session);
}
static PurpleMediaStream *
purple_media_insert_stream(PurpleMediaSession *session,
const gchar *name, gboolean initiator)
{
PurpleMediaStream *media_stream;
g_return_val_if_fail(session != NULL, NULL);
media_stream = g_new0(PurpleMediaStream, 1);
media_stream->participant = g_strdup(name);
media_stream->session = session;
media_stream->initiator = initiator;
session->media->priv->streams =
g_list_append(session->media->priv->streams, media_stream);
return media_stream;
}
static void
purple_media_insert_local_candidate(PurpleMediaSession *session, const gchar *name,
PurpleMediaCandidate *candidate)
{
PurpleMediaStream *stream;
g_return_if_fail(session != NULL);
stream = purple_media_get_stream(session->media, session->id, name);
stream->local_candidates = g_list_append(stream->local_candidates, candidate);
}
#endif
GList *
purple_media_get_session_ids(PurpleMedia *media)
{
#ifdef USE_VV
g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
return media->priv->sessions != NULL ?
g_hash_table_get_keys(media->priv->sessions) : NULL;
#else
return NULL;
#endif
}
#ifdef USE_VV
GstElement *
purple_media_get_src(PurpleMedia *media, const gchar *sess_id)
{
g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
if (PURPLE_IS_MEDIA_BACKEND_FS2(media->priv->backend))
return purple_media_backend_fs2_get_src(
PURPLE_MEDIA_BACKEND_FS2(
media->priv->backend), sess_id);
g_return_val_if_reached(NULL);
}
#endif /* USE_VV */
PurpleAccount *
purple_media_get_account(PurpleMedia *media)
{
#ifdef USE_VV
PurpleAccount *account;
g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
g_object_get(G_OBJECT(media), "account", &account, NULL);
return account;
#else
return NULL;
#endif
}
gpointer
purple_media_get_protocol_data(PurpleMedia *media)
{
#ifdef USE_VV
gpointer protocol_data;
g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
g_object_get(G_OBJECT(media), "protocol-data", &protocol_data, NULL);
return protocol_data;
#else
return NULL;
#endif
}
void
purple_media_set_protocol_data(PurpleMedia *media, gpointer protocol_data)
{
#ifdef USE_VV
g_return_if_fail(PURPLE_IS_MEDIA(media));
g_object_set(G_OBJECT(media), "protocol-data", protocol_data, NULL);
#endif
}
void
purple_media_error(PurpleMedia *media, const gchar *error, ...)
{
#ifdef USE_VV
va_list args;
gchar *message;
g_return_if_fail(PURPLE_IS_MEDIA(media));
va_start(args, error);
message = g_strdup_vprintf(error, args);
va_end(args);
purple_debug_error("media", "%s\n", message);
g_signal_emit(media, purple_media_signals[S_ERROR], 0, message);
g_free(message);
#endif
}
void
purple_media_end(PurpleMedia *media,
const gchar *session_id, const gchar *participant)
{
#ifdef USE_VV
GList *iter, *sessions = NULL, *participants = NULL;
g_return_if_fail(PURPLE_IS_MEDIA(media));
iter = purple_media_get_streams(media, session_id, participant);
/* Free matching streams */
for (; iter; iter = g_list_delete_link(iter, iter)) {
PurpleMediaStream *stream = iter->data;
g_signal_emit(media, purple_media_signals[STATE_CHANGED],
0, PURPLE_MEDIA_STATE_END,
stream->session->id, stream->participant);
media->priv->streams =
g_list_remove(media->priv->streams, stream);
if (g_list_find(sessions, stream->session) == NULL)
sessions = g_list_prepend(sessions, stream->session);
if (g_list_find_custom(participants, stream->participant,
(GCompareFunc)strcmp) == NULL)
participants = g_list_prepend(participants,
g_strdup(stream->participant));
purple_media_stream_free(stream);
}
iter = media->priv->streams;
/* Reduce to list of sessions to remove */
for (; iter; iter = g_list_next(iter)) {
PurpleMediaStream *stream = iter->data;
sessions = g_list_remove(sessions, stream->session);
}
/* Free sessions with no streams left */
for (; sessions; sessions = g_list_delete_link(sessions, sessions)) {
PurpleMediaSession *session = sessions->data;
g_signal_emit(media, purple_media_signals[STATE_CHANGED],
0, PURPLE_MEDIA_STATE_END,
session->id, NULL);
g_hash_table_remove(media->priv->sessions, session->id);
purple_media_session_free(session);
}
iter = media->priv->streams;
/* Reduce to list of participants to remove */
for (; iter; iter = g_list_next(iter)) {
PurpleMediaStream *stream = iter->data;
GList *tmp;
tmp = g_list_find_custom(participants,
stream->participant, (GCompareFunc)strcmp);
if (tmp != NULL) {
g_free(tmp->data);
participants = g_list_delete_link(participants, tmp);
}
}
/* Remove participants with no streams left (just emit the signal) */
for (; participants; participants =
g_list_delete_link(participants, participants)) {
gchar *participant = participants->data;
GList *link = g_list_find_custom(media->priv->participants,
participant, (GCompareFunc)strcmp);
g_signal_emit(media, purple_media_signals[STATE_CHANGED],
0, PURPLE_MEDIA_STATE_END,
NULL, participant);
if (link != NULL) {
g_free(link->data);
media->priv->participants = g_list_delete_link(
media->priv->participants, link);
}
g_free(participant);
}
/* Free the conference if no sessions left */
if (media->priv->sessions != NULL &&
g_hash_table_size(media->priv->sessions) == 0) {
g_signal_emit(media, purple_media_signals[STATE_CHANGED],
0, PURPLE_MEDIA_STATE_END,
NULL, NULL);
g_object_unref(media);
return;
}
#endif
}
void
purple_media_stream_info(PurpleMedia *media, PurpleMediaInfoType type,
const gchar *session_id, const gchar *participant,
gboolean local)
{
#ifdef USE_VV
g_return_if_fail(PURPLE_IS_MEDIA(media));
if (type == PURPLE_MEDIA_INFO_ACCEPT) {
GList *streams, *sessions = NULL, *participants = NULL;
g_return_if_fail(PURPLE_IS_MEDIA(media));
streams = purple_media_get_streams(media,
session_id, participant);
/* Emit stream acceptance */
for (; streams; streams =
g_list_delete_link(streams, streams)) {
PurpleMediaStream *stream = streams->data;
stream->accepted = TRUE;
g_signal_emit(media,
purple_media_signals[STREAM_INFO],
0, type, stream->session->id,
stream->participant, local);
if (g_list_find(sessions, stream->session) == NULL)
sessions = g_list_prepend(sessions,
stream->session);
if (g_list_find_custom(participants,
stream->participant,
(GCompareFunc)strcmp) == NULL)
participants = g_list_prepend(participants,
g_strdup(stream->participant));
}
/* Emit session acceptance */
for (; sessions; sessions =
g_list_delete_link(sessions, sessions)) {
PurpleMediaSession *session = sessions->data;
if (purple_media_accepted(media, session->id, NULL))
g_signal_emit(media, purple_media_signals[
STREAM_INFO], 0,
PURPLE_MEDIA_INFO_ACCEPT,
session->id, NULL, local);
}
/* Emit participant acceptance */
for (; participants; participants = g_list_delete_link(
participants, participants)) {
gchar *participant = participants->data;
if (purple_media_accepted(media, NULL, participant))
g_signal_emit(media, purple_media_signals[
STREAM_INFO], 0,
PURPLE_MEDIA_INFO_ACCEPT,
NULL, participant, local);
g_free(participant);
}
/* Emit conference acceptance */
if (purple_media_accepted(media, NULL, NULL))
g_signal_emit(media,
purple_media_signals[STREAM_INFO],
0, PURPLE_MEDIA_INFO_ACCEPT,
NULL, NULL, local);
return;
} else if (type == PURPLE_MEDIA_INFO_HANGUP ||
type == PURPLE_MEDIA_INFO_REJECT) {
GList *streams;
g_return_if_fail(PURPLE_IS_MEDIA(media));
streams = purple_media_get_streams(media,
session_id, participant);
/* Emit for stream */
for (; streams; streams =
g_list_delete_link(streams, streams)) {
PurpleMediaStream *stream = streams->data;
g_signal_emit(media,
purple_media_signals[STREAM_INFO],
0, type, stream->session->id,
stream->participant, local);
}
if (session_id != NULL && participant != NULL) {
/* Everything that needs to be emitted has been */
} else if (session_id == NULL && participant == NULL) {
/* Emit for everything in the conference */
GList *sessions = NULL;
GList *participants = media->priv->participants;
if (media->priv->sessions != NULL)
sessions = g_hash_table_get_values(
media->priv->sessions);
/* Emit for sessions */
for (; sessions; sessions = g_list_delete_link(
sessions, sessions)) {
PurpleMediaSession *session = sessions->data;
g_signal_emit(media, purple_media_signals[
STREAM_INFO], 0, type,
session->id, NULL, local);
}
/* Emit for participants */
for (; participants; participants =
g_list_next(participants)) {
gchar *participant = participants->data;
g_signal_emit(media, purple_media_signals[
STREAM_INFO], 0, type,
NULL, participant, local);
}
/* Emit for conference */
g_signal_emit(media,
purple_media_signals[STREAM_INFO],
0, type, NULL, NULL, local);
} else if (session_id != NULL) {
/* Emit just the specific session */
PurpleMediaSession *session =
purple_media_get_session(
media, session_id);
if (session == NULL) {
purple_debug_warning("media",
"Couldn't find session"
" to hangup/reject.\n");
} else {
g_signal_emit(media, purple_media_signals[
STREAM_INFO], 0, type,
session->id, NULL, local);
}
} else if (participant != NULL) {
/* Emit just the specific participant */
if (!g_list_find_custom(media->priv->participants,
participant, (GCompareFunc)strcmp)) {
purple_debug_warning("media",
"Couldn't find participant"
" to hangup/reject.\n");
} else {
g_signal_emit(media, purple_media_signals[
STREAM_INFO], 0, type, NULL,
participant, local);
}
}
purple_media_end(media, session_id, participant);
return;
}
g_signal_emit(media, purple_media_signals[STREAM_INFO],
0, type, session_id, participant, local);
#endif
}
void
purple_media_set_params(PurpleMedia *media,
guint num_params, GParameter *params)
{
#ifdef USE_VV
g_return_if_fail(PURPLE_IS_MEDIA(media));
purple_media_backend_set_params(media->priv->backend, num_params, params);
#endif
}
const gchar **
purple_media_get_available_params(PurpleMedia *media)
{
static const gchar *NULL_ARRAY[] = { NULL };
#ifdef USE_VV
g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL_ARRAY);
return purple_media_backend_get_available_params(media->priv->backend);
#else
return NULL_ARRAY;
#endif
}
gboolean
purple_media_param_is_supported(PurpleMedia *media, const gchar *param)
{
#ifdef USE_VV
const gchar **params;
g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
g_return_val_if_fail(param != NULL, FALSE);
params = purple_media_backend_get_available_params(media->priv->backend);
for (; *params != NULL; ++params)
if (purple_strequal(*params, param))
return TRUE;
#endif
return FALSE;
}
#ifdef USE_VV
static void
purple_media_new_local_candidate_cb(PurpleMediaBackend *backend,
const gchar *sess_id, const gchar *participant,
PurpleMediaCandidate *candidate, PurpleMedia *media)
{
PurpleMediaSession *session =
purple_media_get_session(media, sess_id);
purple_media_insert_local_candidate(session, participant,
purple_media_candidate_copy(candidate));
g_signal_emit(session->media, purple_media_signals[NEW_CANDIDATE],
0, session->id, participant, candidate);
}
static void
purple_media_candidates_prepared_cb(PurpleMediaBackend *backend,
const gchar *sess_id, const gchar *name, PurpleMedia *media)
{
PurpleMediaStream *stream_data;
g_return_if_fail(PURPLE_IS_MEDIA(media));
stream_data = purple_media_get_stream(media, sess_id, name);
stream_data->candidates_prepared = TRUE;
g_signal_emit(media, purple_media_signals[CANDIDATES_PREPARED],
0, sess_id, name);
}
/* callback called when a pair of transport candidates (local and remote)
* has been established */
static void
purple_media_candidate_pair_established_cb(PurpleMediaBackend *backend,
const gchar *sess_id, const gchar *name,
PurpleMediaCandidate *local_candidate,
PurpleMediaCandidate *remote_candidate,
PurpleMedia *media)
{
PurpleMediaStream *stream;
GList *iter;
guint id;
g_return_if_fail(PURPLE_IS_MEDIA(media));
stream = purple_media_get_stream(media, sess_id, name);
id = purple_media_candidate_get_component_id(local_candidate);
iter = stream->active_local_candidates;
for(; iter; iter = g_list_next(iter)) {
PurpleMediaCandidate *c = iter->data;
if (id == purple_media_candidate_get_component_id(c)) {
g_object_unref(c);
stream->active_local_candidates =
g_list_delete_link(iter, iter);
stream->active_local_candidates = g_list_prepend(
stream->active_local_candidates,
purple_media_candidate_copy(
local_candidate));
break;
}
}
if (iter == NULL)
stream->active_local_candidates = g_list_prepend(
stream->active_local_candidates,
purple_media_candidate_copy(
local_candidate));
id = purple_media_candidate_get_component_id(local_candidate);
iter = stream->active_remote_candidates;
for(; iter; iter = g_list_next(iter)) {
PurpleMediaCandidate *c = iter->data;
if (id == purple_media_candidate_get_component_id(c)) {
g_object_unref(c);
stream->active_remote_candidates =
g_list_delete_link(iter, iter);
stream->active_remote_candidates = g_list_prepend(
stream->active_remote_candidates,
purple_media_candidate_copy(
remote_candidate));
break;
}
}
if (iter == NULL)
stream->active_remote_candidates = g_list_prepend(
stream->active_remote_candidates,
purple_media_candidate_copy(
remote_candidate));
g_signal_emit(media, purple_media_signals[CANDIDATE_PAIR_ESTABLISHED],
0, sess_id, name, local_candidate, remote_candidate);
purple_debug_info("media", "candidate pair established\n");
}
static void
purple_media_codecs_changed_cb(PurpleMediaBackend *backend,
const gchar *sess_id, PurpleMedia *media)
{
g_signal_emit(media, purple_media_signals[CODECS_CHANGED], 0, sess_id);
}
#endif /* USE_VV */
gboolean
purple_media_add_stream(PurpleMedia *media, const gchar *sess_id,
const gchar *who, PurpleMediaSessionType type,
gboolean initiator, const gchar *transmitter,
guint num_params, GParameter *params)
{
#ifdef USE_VV
PurpleMediaSession *session;
g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
if (!purple_media_backend_add_stream(media->priv->backend,
sess_id, who, type, initiator, transmitter,
num_params, params)) {
purple_debug_error("media", "Error adding stream.\n");
return FALSE;
}
session = purple_media_get_session(media, sess_id);
if (!session) {
session = g_new0(PurpleMediaSession, 1);
session->id = g_strdup(sess_id);
session->media = media;
session->type = type;
session->initiator = initiator;
purple_media_add_session(media, session);
g_signal_emit(media, purple_media_signals[STATE_CHANGED],
0, PURPLE_MEDIA_STATE_NEW,
session->id, NULL);
}
if (!g_list_find_custom(media->priv->participants,
who, (GCompareFunc)strcmp)) {
media->priv->participants = g_list_prepend(
media->priv->participants, g_strdup(who));
g_signal_emit(media, purple_media_signals[STATE_CHANGED], 0,
PURPLE_MEDIA_STATE_NEW, NULL, who);
}
if (purple_media_get_stream(media, sess_id, who) == NULL) {
purple_media_insert_stream(session, who, initiator);
g_signal_emit(media, purple_media_signals[STATE_CHANGED],
0, PURPLE_MEDIA_STATE_NEW,
session->id, who);
}
return TRUE;
#else
return FALSE;
#endif /* USE_VV */
}
PurpleMediaManager *
purple_media_get_manager(PurpleMedia *media)
{
PurpleMediaManager *ret;
g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
g_object_get(media, "manager", &ret, NULL);
return ret;
}
PurpleMediaSessionType
purple_media_get_session_type(PurpleMedia *media, const gchar *sess_id)
{
#ifdef USE_VV
PurpleMediaSession *session;
g_return_val_if_fail(PURPLE_IS_MEDIA(media), PURPLE_MEDIA_NONE);
session = purple_media_get_session(media, sess_id);
return session->type;
#else
return PURPLE_MEDIA_NONE;
#endif
}
/* XXX: Should wait until codecs-ready is TRUE before using this function */
GList *
purple_media_get_codecs(PurpleMedia *media, const gchar *sess_id)
{
#ifdef USE_VV
g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
return purple_media_backend_get_codecs(media->priv->backend, sess_id);
#else
return NULL;
#endif
}
GList *
purple_media_get_local_candidates(PurpleMedia *media, const gchar *sess_id,
const gchar *participant)
{
#ifdef USE_VV
g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
return purple_media_backend_get_local_candidates(media->priv->backend,
sess_id, participant);
#else
return NULL;
#endif
}
void
purple_media_add_remote_candidates(PurpleMedia *media, const gchar *sess_id,
const gchar *participant,
GList *remote_candidates)
{
#ifdef USE_VV
PurpleMediaStream *stream;
g_return_if_fail(PURPLE_IS_MEDIA(media));
stream = purple_media_get_stream(media, sess_id, participant);
if (stream == NULL) {
purple_debug_error("media",
"purple_media_add_remote_candidates: "
"couldn't find stream %s %s.\n",
sess_id ? sess_id : "(null)",
participant ? participant : "(null)");
return;
}
stream->remote_candidates = g_list_concat(stream->remote_candidates,
purple_media_candidate_list_copy(remote_candidates));
purple_media_backend_add_remote_candidates(media->priv->backend,
sess_id, participant, remote_candidates);
#endif
}
GList *
purple_media_get_active_local_candidates(PurpleMedia *media,
const gchar *sess_id, const gchar *participant)
{
#ifdef USE_VV
PurpleMediaStream *stream;
g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
stream = purple_media_get_stream(media, sess_id, participant);
return purple_media_candidate_list_copy(
stream->active_local_candidates);
#else
return NULL;
#endif
}
GList *
purple_media_get_active_remote_candidates(PurpleMedia *media,
const gchar *sess_id, const gchar *participant)
{
#ifdef USE_VV
PurpleMediaStream *stream;
g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
stream = purple_media_get_stream(media, sess_id, participant);
return purple_media_candidate_list_copy(
stream->active_remote_candidates);
#else
return NULL;
#endif
}
gboolean
purple_media_set_remote_codecs(PurpleMedia *media, const gchar *sess_id,
const gchar *participant, GList *codecs)
{
#ifdef USE_VV
g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
return purple_media_backend_set_remote_codecs(media->priv->backend,
sess_id, participant, codecs);
#else
return FALSE;
#endif
}
gboolean
purple_media_candidates_prepared(PurpleMedia *media,
const gchar *session_id, const gchar *participant)
{
#ifdef USE_VV
GList *streams;
gboolean prepared = TRUE;
g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
streams = purple_media_get_streams(media, session_id, participant);
for (; streams; streams = g_list_delete_link(streams, streams)) {
PurpleMediaStream *stream = streams->data;
if (stream->candidates_prepared == FALSE) {
g_list_free(streams);
prepared = FALSE;
break;
}
}
return prepared;
#else
return FALSE;
#endif
}
gboolean
purple_media_set_send_codec(PurpleMedia *media, const gchar *sess_id, PurpleMediaCodec *codec)
{
#ifdef USE_VV
g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
return purple_media_backend_set_send_codec(
media->priv->backend, sess_id, codec);
#else
return FALSE;
#endif
}
gboolean
purple_media_set_encryption_parameters(PurpleMedia *media, const gchar *sess_id,
const gchar *cipher, const gchar *auth,
const gchar *key, gsize key_len)
{
#ifdef USE_VV
g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
return purple_media_backend_set_encryption_parameters(media->priv->backend,
sess_id, cipher, auth, key, key_len);
#else
return FALSE;
#endif
}
gboolean
purple_media_set_decryption_parameters(PurpleMedia *media, const gchar *sess_id,
const gchar *participant, const gchar *cipher,
const gchar *auth, const gchar *key, gsize key_len)
{
#ifdef USE_VV
g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
return purple_media_backend_set_decryption_parameters(media->priv->backend,
sess_id, participant, cipher, auth, key, key_len);
#else
return FALSE;
#endif
}
gboolean
purple_media_codecs_ready(PurpleMedia *media, const gchar *sess_id)
{
#ifdef USE_VV
g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
return purple_media_backend_codecs_ready(
media->priv->backend, sess_id);
#else
return FALSE;
#endif
}
gboolean
purple_media_set_send_rtcp_mux(PurpleMedia *media, const gchar *sess_id,
const gchar *participant, gboolean send_rtcp_mux)
{
#ifdef USE_VV
g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
return purple_media_backend_set_send_rtcp_mux(media->priv->backend,
sess_id, participant, send_rtcp_mux);
#else
return FALSE;
#endif
}
gboolean
purple_media_is_initiator(PurpleMedia *media,
const gchar *sess_id, const gchar *participant)
{
#ifdef USE_VV
g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
if (sess_id == NULL && participant == NULL)
return media->priv->initiator;
else if (sess_id != NULL && participant == NULL) {
PurpleMediaSession *session =
purple_media_get_session(media, sess_id);
return session != NULL ? session->initiator : FALSE;
} else if (sess_id != NULL && participant != NULL) {
PurpleMediaStream *stream = purple_media_get_stream(
media, sess_id, participant);
return stream != NULL ? stream->initiator : FALSE;
}
#endif
return FALSE;
}
gboolean
purple_media_accepted(PurpleMedia *media, const gchar *sess_id,
const gchar *participant)
{
#ifdef USE_VV
gboolean accepted = TRUE;
g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
if (sess_id == NULL && participant == NULL) {
GList *streams = media->priv->streams;
for (; streams; streams = g_list_next(streams)) {
PurpleMediaStream *stream = streams->data;
if (stream->accepted == FALSE) {
accepted = FALSE;
break;
}
}
} else if (sess_id != NULL && participant == NULL) {
GList *streams = purple_media_get_streams(
media, sess_id, NULL);
for (; streams; streams =
g_list_delete_link(streams, streams)) {
PurpleMediaStream *stream = streams->data;
if (stream->accepted == FALSE) {
g_list_free(streams);
accepted = FALSE;
break;
}
}
} else if (sess_id != NULL && participant != NULL) {
PurpleMediaStream *stream = purple_media_get_stream(
media, sess_id, participant);
if (stream == NULL || stream->accepted == FALSE)
accepted = FALSE;
}
return accepted;
#else
return FALSE;
#endif
}
void purple_media_set_input_volume(PurpleMedia *media,
const gchar *session_id, double level)
{
#ifdef USE_VV
g_return_if_fail(PURPLE_IS_MEDIA(media));
g_return_if_fail(PURPLE_IS_MEDIA_BACKEND_FS2(media->priv->backend));
purple_media_backend_fs2_set_input_volume(
PURPLE_MEDIA_BACKEND_FS2(
media->priv->backend),
session_id, level);
#endif
}
void purple_media_set_output_volume(PurpleMedia *media,
const gchar *session_id, const gchar *participant,
double level)
{
#ifdef USE_VV
g_return_if_fail(PURPLE_IS_MEDIA(media));
g_return_if_fail(PURPLE_IS_MEDIA_BACKEND_FS2(media->priv->backend));
purple_media_backend_fs2_set_output_volume(
PURPLE_MEDIA_BACKEND_FS2(
media->priv->backend),
session_id, participant, level);
#endif
}
gulong
purple_media_set_output_window(PurpleMedia *media, const gchar *session_id,
const gchar *participant, gulong window_id)
{
#ifdef USE_VV
g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
return purple_media_manager_set_output_window(media->priv->manager,
media, session_id, participant, window_id);
#else
return 0;
#endif
}
void
purple_media_remove_output_windows(PurpleMedia *media)
{
#ifdef USE_VV
GList *iter = media->priv->streams;
for (; iter; iter = g_list_next(iter)) {
PurpleMediaStream *stream = iter->data;
purple_media_manager_remove_output_windows(
media->priv->manager, media,
stream->session->id, stream->participant);
}
iter = purple_media_get_session_ids(media);
for (; iter; iter = g_list_delete_link(iter, iter)) {
gchar *session_name = iter->data;
purple_media_manager_remove_output_windows(
media->priv->manager, media,
session_name, NULL);
}
#endif
}
#ifdef USE_VV
GstElement *
purple_media_get_tee(PurpleMedia *media,
const gchar *session_id, const gchar *participant)
{
g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
if (PURPLE_IS_MEDIA_BACKEND_FS2(media->priv->backend))
return purple_media_backend_fs2_get_tee(
PURPLE_MEDIA_BACKEND_FS2(
media->priv->backend),
session_id, participant);
g_return_val_if_reached(NULL);
}
#endif /* USE_VV */
gboolean
purple_media_send_dtmf(PurpleMedia *media, const gchar *session_id,
gchar dtmf, guint8 volume, guint16 duration)
{
#ifdef USE_VV
PurpleMediaBackendInterface *backend_iface = NULL;
if (media)
{
backend_iface = PURPLE_MEDIA_BACKEND_GET_INTERFACE(media->priv->backend);
}
if (dtmf == 'a')
dtmf = 'A';
else if (dtmf == 'b')
dtmf = 'B';
else if (dtmf == 'c')
dtmf = 'C';
else if (dtmf == 'd')
dtmf = 'D';
g_return_val_if_fail(strchr("0123456789ABCD#*", dtmf), FALSE);
if (backend_iface && backend_iface->send_dtmf
&& backend_iface->send_dtmf(media->priv->backend,
session_id, dtmf, volume, duration))
{
return TRUE;
}
#endif
return FALSE;
}