pidgin/ljfisher-ssl-client-auth

Fix some white spaces issues.
soc.2009.webkitmessageview
2011-06-16, Jorge VillaseƱor
f150788023c0
Fix some white spaces issues.
/**
* @file media.c Media API
* @ingroup core
*/
/* 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 "mediamanager.h"
#include "network.h"
#include "debug.h"
#ifdef USE_GSTREAMER
#include "marshallers.h"
#include "media-gst.h"
#endif
#ifdef USE_VV
#include <gst/farsight/fs-conference-iface.h>
#include <gst/farsight/fs-element-added-notifier.h>
/** @copydoc _PurpleMediaSession */
typedef struct _PurpleMediaSession PurpleMediaSession;
/** @copydoc _PurpleMediaStream */
typedef struct _PurpleMediaStream PurpleMediaStream;
/** @copydoc _PurpleMediaClass */
typedef struct _PurpleMediaClass PurpleMediaClass;
/** @copydoc _PurpleMediaPrivate */
typedef struct _PurpleMediaPrivate PurpleMediaPrivate;
/** @copydoc _PurpleMediaCandidateClass */
typedef struct _PurpleMediaCandidateClass PurpleMediaCandidateClass;
/** @copydoc _PurpleMediaCandidatePrivate */
typedef struct _PurpleMediaCandidatePrivate PurpleMediaCandidatePrivate;
/** @copydoc _PurpleMediaCodecClass */
typedef struct _PurpleMediaCodecClass PurpleMediaCodecClass;
/** @copydoc _PurpleMediaCodecPrivate */
typedef struct _PurpleMediaCodecPrivate PurpleMediaCodecPrivate;
/** The media class */
struct _PurpleMediaClass
{
GObjectClass parent_class; /**< The parent class. */
};
/** The media class's private data */
struct _PurpleMedia
{
GObject parent; /**< The parent of this object. */
PurpleMediaPrivate *priv; /**< The private data of this object. */
};
struct _PurpleMediaSession
{
gchar *id;
PurpleMedia *media;
GstElement *src;
GstElement *tee;
FsSession *session;
PurpleMediaSessionType type;
gboolean initiator;
};
struct _PurpleMediaStream
{
PurpleMediaSession *session;
gchar *participant;
FsStream *stream;
GstElement *src;
GstElement *tee;
GstElement *volume;
GstElement *level;
GList *local_candidates;
GList *remote_candidates;
gboolean initiator;
gboolean accepted;
gboolean candidates_prepared;
gboolean held;
gboolean paused;
GList *active_local_candidates;
GList *active_remote_candidates;
guint connected_cb_id;
};
#endif
struct _PurpleMediaPrivate
{
#ifdef USE_VV
PurpleMediaManager *manager;
PurpleAccount *account;
FsConference *conference;
gboolean initiator;
gpointer prpl_data;
GHashTable *sessions; /* PurpleMediaSession table */
GHashTable *participants; /* FsParticipant table */
GList *streams; /* PurpleMediaStream table */
GstElement *confbin;
#else
gpointer dummy;
#endif
};
#ifdef USE_VV
#define PURPLE_MEDIA_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_MEDIA, PurpleMediaPrivate))
#define PURPLE_MEDIA_CANDIDATE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_MEDIA_CANDIDATE, PurpleMediaCandidatePrivate))
#define PURPLE_MEDIA_CODEC_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_MEDIA_CODEC, PurpleMediaCodecPrivate))
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(FsStream *stream,
FsCandidate *local_candidate, PurpleMediaSession *session);
static void purple_media_candidates_prepared_cb(FsStream *stream,
PurpleMediaSession *session);
static void purple_media_candidate_pair_established_cb(FsStream *stream,
FsCandidate *native_candidate, FsCandidate *remote_candidate,
PurpleMediaSession *session);
static gboolean media_bus_call(GstBus *bus,
GstMessage *msg, PurpleMedia *media);
static GObjectClass *parent_class = NULL;
enum {
S_ERROR,
CANDIDATES_PREPARED,
CODECS_CHANGED,
LEVEL,
NEW_CANDIDATE,
STATE_CHANGED,
STREAM_INFO,
LAST_SIGNAL
};
static guint purple_media_signals[LAST_SIGNAL] = {0};
enum {
PROP_0,
PROP_MANAGER,
PROP_ACCOUNT,
PROP_CONFERENCE,
PROP_INITIATOR,
PROP_PRPL_DATA,
};
#endif
/*
* PurpleMediaElementType
*/
GType
purple_media_session_type_get_type()
{
static GType type = 0;
if (type == 0) {
static const GFlagsValue values[] = {
{ PURPLE_MEDIA_NONE,
"PURPLE_MEDIA_NONE", "none" },
{ PURPLE_MEDIA_RECV_AUDIO,
"PURPLE_MEDIA_RECV_AUDIO", "recv-audio" },
{ PURPLE_MEDIA_SEND_AUDIO,
"PURPLE_MEDIA_SEND_AUDIO", "send-audio" },
{ PURPLE_MEDIA_RECV_VIDEO,
"PURPLE_MEDIA_RECV_VIDEO", "recv-video" },
{ PURPLE_MEDIA_SEND_VIDEO,
"PURPLE_MEDIA_SEND_VIDEO", "send-audio" },
{ PURPLE_MEDIA_AUDIO,
"PURPLE_MEDIA_AUDIO", "audio" },
{ PURPLE_MEDIA_VIDEO,
"PURPLE_MEDIA_VIDEO", "video" },
{ 0, NULL, NULL }
};
type = g_flags_register_static(
"PurpleMediaSessionType", values);
}
return type;
}
GType
purple_media_get_type()
{
#ifdef USE_VV
static GType type = 0;
if (type == 0) {
static const GTypeInfo info = {
sizeof(PurpleMediaClass),
NULL,
NULL,
(GClassInitFunc) purple_media_class_init,
NULL,
NULL,
sizeof(PurpleMedia),
0,
(GInstanceInitFunc) purple_media_init,
NULL
};
type = g_type_register_static(G_TYPE_OBJECT, "PurpleMedia", &info, 0);
}
return type;
#else
return G_TYPE_NONE;
#endif
}
GType
purple_media_state_changed_get_type()
{
static GType type = 0;
if (type == 0) {
static const GEnumValue values[] = {
{ PURPLE_MEDIA_STATE_NEW,
"PURPLE_MEDIA_STATE_NEW", "new" },
{ PURPLE_MEDIA_STATE_CONNECTED,
"PURPLE_MEDIA_STATE_CONNECTED", "connected" },
{ PURPLE_MEDIA_STATE_END,
"PURPLE_MEDIA_STATE_END", "end" },
{ 0, NULL, NULL }
};
type = g_enum_register_static("PurpleMediaState", values);
}
return type;
}
GType
purple_media_info_type_get_type()
{
static GType type = 0;
if (type == 0) {
static const GEnumValue values[] = {
{ PURPLE_MEDIA_INFO_HANGUP,
"PURPLE_MEDIA_INFO_HANGUP", "hangup" },
{ PURPLE_MEDIA_INFO_ACCEPT,
"PURPLE_MEDIA_INFO_ACCEPT", "accept" },
{ PURPLE_MEDIA_INFO_REJECT,
"PURPLE_MEDIA_INFO_REJECT", "reject" },
{ PURPLE_MEDIA_INFO_MUTE,
"PURPLE_MEDIA_INFO_MUTE", "mute" },
{ PURPLE_MEDIA_INFO_UNMUTE,
"PURPLE_MEDIA_INFO_UNMUTE", "unmute" },
{ PURPLE_MEDIA_INFO_PAUSE,
"PURPLE_MEDIA_INFO_PAUSE", "pause" },
{ PURPLE_MEDIA_INFO_UNPAUSE,
"PURPLE_MEDIA_INFO_UNPAUSE", "unpause" },
{ PURPLE_MEDIA_INFO_HOLD,
"PURPLE_MEDIA_INFO_HOLD", "hold" },
{ PURPLE_MEDIA_INFO_UNHOLD,
"PURPLE_MEDIA_INFO_UNHOLD", "unhold" },
{ 0, NULL, NULL }
};
type = g_enum_register_static("PurpleMediaInfoType", values);
}
return type;
}
#ifdef USE_VV
static void
purple_media_class_init (PurpleMediaClass *klass)
{
GObjectClass *gobject_class = (GObjectClass*)klass;
parent_class = g_type_class_peek_parent(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_object_class_install_property(gobject_class, PROP_ACCOUNT,
g_param_spec_pointer("account",
"PurpleAccount",
"The account this media session is on.",
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
g_object_class_install_property(gobject_class, PROP_CONFERENCE,
g_param_spec_object("conference",
"Farsight conference",
"The FsConference associated with this media.",
FS_TYPE_CONFERENCE,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE));
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_object_class_install_property(gobject_class, PROP_PRPL_DATA,
g_param_spec_pointer("prpl-data",
"gpointer",
"Data the prpl plugin set on the media session.",
G_PARAM_READWRITE));
purple_media_signals[S_ERROR] = g_signal_new("error", G_TYPE_FROM_CLASS(klass),
G_SIGNAL_RUN_LAST, 0, NULL, NULL,
g_cclosure_marshal_VOID__STRING,
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,
purple_smarshal_VOID__STRING_STRING,
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,
g_cclosure_marshal_VOID__STRING,
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,
purple_smarshal_VOID__STRING_STRING_DOUBLE,
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,
purple_smarshal_VOID__POINTER_POINTER_OBJECT,
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,
purple_smarshal_VOID__ENUM_STRING_STRING,
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,
purple_smarshal_VOID__ENUM_STRING_STRING_BOOLEAN,
G_TYPE_NONE, 4, PURPLE_MEDIA_TYPE_INFO_TYPE,
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN);
g_type_class_add_private(klass, sizeof(PurpleMediaPrivate));
}
static void
purple_media_init (PurpleMedia *media)
{
media->priv = PURPLE_MEDIA_GET_PRIVATE(media);
memset(media->priv, 0, sizeof(*media->priv));
}
static void
purple_media_stream_free(PurpleMediaStream *stream)
{
if (stream == NULL)
return;
/* Remove the connected_cb timeout */
if (stream->connected_cb_id != 0)
purple_timeout_remove(stream->connected_cb_id);
g_free(stream->participant);
if (stream->local_candidates)
fs_candidate_list_destroy(stream->local_candidates);
if (stream->remote_candidates)
fs_candidate_list_destroy(stream->remote_candidates);
if (stream->active_local_candidates)
fs_candidate_list_destroy(stream->active_local_candidates);
if (stream->active_remote_candidates)
fs_candidate_list_destroy(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_PRIVATE(media);
GList *iter = NULL;
purple_debug_info("media","purple_media_dispose\n");
purple_media_manager_remove_media(priv->manager, PURPLE_MEDIA(media));
if (priv->confbin) {
gst_element_set_locked_state(priv->confbin, TRUE);
gst_element_set_state(GST_ELEMENT(priv->confbin),
GST_STATE_NULL);
gst_bin_remove(GST_BIN(purple_media_manager_get_pipeline(
priv->manager)), priv->confbin);
priv->confbin = NULL;
priv->conference = NULL;
}
for (iter = priv->streams; iter; iter = g_list_next(iter)) {
PurpleMediaStream *stream = iter->data;
if (stream->stream) {
g_object_unref(stream->stream);
stream->stream = NULL;
}
}
if (priv->sessions) {
GList *sessions = g_hash_table_get_values(priv->sessions);
for (; sessions; sessions = g_list_delete_link(sessions, sessions)) {
PurpleMediaSession *session = sessions->data;
if (session->session) {
g_object_unref(session->session);
session->session = NULL;
}
}
}
if (priv->participants) {
GList *participants = g_hash_table_get_values(priv->participants);
for (; participants; participants = g_list_delete_link(participants, participants))
g_object_unref(participants->data);
}
if (priv->manager) {
GstElement *pipeline = purple_media_manager_get_pipeline(
priv->manager);
GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
g_signal_handlers_disconnect_matched(G_OBJECT(bus),
G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
0, 0, 0, media_bus_call, media);
gst_object_unref(bus);
g_object_unref(priv->manager);
priv->manager = NULL;
}
G_OBJECT_CLASS(parent_class)->dispose(media);
}
static void
purple_media_finalize(GObject *media)
{
PurpleMediaPrivate *priv = PURPLE_MEDIA_GET_PRIVATE(media);
purple_debug_info("media","purple_media_finalize\n");
for (; priv->streams; priv->streams = g_list_delete_link(priv->streams, priv->streams))
purple_media_stream_free(priv->streams->data);
if (priv->sessions) {
GList *sessions = g_hash_table_get_values(priv->sessions);
for (; sessions; sessions = g_list_delete_link(sessions, sessions)) {
purple_media_session_free(sessions->data);
}
g_hash_table_destroy(priv->sessions);
}
G_OBJECT_CLASS(parent_class)->finalize(media);
}
static void
purple_media_setup_pipeline(PurpleMedia *media)
{
GstBus *bus;
gchar *name;
GstElement *pipeline;
if (media->priv->conference == NULL || media->priv->manager == NULL)
return;
pipeline = purple_media_manager_get_pipeline(media->priv->manager);
name = g_strdup_printf("conf_%p",
media->priv->conference);
media->priv->confbin = gst_bin_new(name);
g_free(name);
bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
g_signal_connect(G_OBJECT(bus), "message",
G_CALLBACK(media_bus_call), media);
gst_object_unref(bus);
gst_bin_add(GST_BIN(pipeline),
media->priv->confbin);
gst_bin_add(GST_BIN(media->priv->confbin),
GST_ELEMENT(media->priv->conference));
gst_element_set_state(GST_ELEMENT(media->priv->confbin),
GST_STATE_PLAYING);
}
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_get_object(value);
g_object_ref(media->priv->manager);
purple_media_setup_pipeline(media);
break;
case PROP_ACCOUNT:
media->priv->account = g_value_get_pointer(value);
break;
case PROP_CONFERENCE: {
if (media->priv->conference)
gst_object_unref(media->priv->conference);
media->priv->conference = g_value_get_object(value);
gst_object_ref(media->priv->conference);
purple_media_setup_pipeline(media);
break;
}
case PROP_INITIATOR:
media->priv->initiator = g_value_get_boolean(value);
break;
case PROP_PRPL_DATA:
media->priv->prpl_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_ACCOUNT:
g_value_set_pointer(value, media->priv->account);
break;
case PROP_CONFERENCE:
g_value_set_object(value, media->priv->conference);
break;
case PROP_INITIATOR:
g_value_set_boolean(value, media->priv->initiator);
break;
case PROP_PRPL_DATA:
g_value_set_pointer(value, media->priv->prpl_data);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
#endif
/*
* PurpleMediaCandidateType
*/
GType
purple_media_candidate_type_get_type()
{
static GType type = 0;
if (type == 0) {
static const GEnumValue values[] = {
{ PURPLE_MEDIA_CANDIDATE_TYPE_HOST,
"PURPLE_MEDIA_CANDIDATE_TYPE_HOST",
"host" },
{ PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX,
"PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX",
"srflx" },
{ PURPLE_MEDIA_CANDIDATE_TYPE_PRFLX,
"PURPLE_MEDIA_CANDIDATE_TYPE_PRFLX",
"prflx" },
{ PURPLE_MEDIA_CANDIDATE_TYPE_RELAY,
"PPURPLE_MEDIA_CANDIDATE_TYPE_RELAY",
"relay" },
{ PURPLE_MEDIA_CANDIDATE_TYPE_MULTICAST,
"PURPLE_MEDIA_CANDIDATE_TYPE_MULTICAST",
"multicast" },
{ 0, NULL, NULL }
};
type = g_enum_register_static("PurpleMediaCandidateType",
values);
}
return type;
}
/*
* PurpleMediaNetworkProtocol
*/
GType
purple_media_network_protocol_get_type()
{
static GType type = 0;
if (type == 0) {
static const GEnumValue values[] = {
{ PURPLE_MEDIA_NETWORK_PROTOCOL_UDP,
"PURPLE_MEDIA_NETWORK_PROTOCOL_UDP",
"udp" },
{ PURPLE_MEDIA_NETWORK_PROTOCOL_TCP,
"PURPLE_MEDIA_NETWORK_PROTOCOL_TCP",
"tcp" },
{ 0, NULL, NULL }
};
type = g_enum_register_static("PurpleMediaNetworkProtocol",
values);
}
return type;
}
/*
* PurpleMediaCandidate
*/
struct _PurpleMediaCandidateClass
{
GObjectClass parent_class;
};
struct _PurpleMediaCandidate
{
GObject parent;
};
#ifdef USE_VV
struct _PurpleMediaCandidatePrivate
{
gchar *foundation;
guint component_id;
gchar *ip;
guint16 port;
gchar *base_ip;
guint16 base_port;
PurpleMediaNetworkProtocol proto;
guint32 priority;
PurpleMediaCandidateType type;
gchar *username;
gchar *password;
guint ttl;
};
enum {
PROP_CANDIDATE_0,
PROP_FOUNDATION,
PROP_COMPONENT_ID,
PROP_IP,
PROP_PORT,
PROP_BASE_IP,
PROP_BASE_PORT,
PROP_PROTOCOL,
PROP_PRIORITY,
PROP_TYPE,
PROP_USERNAME,
PROP_PASSWORD,
PROP_TTL,
};
static void
purple_media_candidate_init(PurpleMediaCandidate *info)
{
PurpleMediaCandidatePrivate *priv =
PURPLE_MEDIA_CANDIDATE_GET_PRIVATE(info);
priv->foundation = NULL;
priv->component_id = 0;
priv->ip = NULL;
priv->port = 0;
priv->base_ip = NULL;
priv->proto = PURPLE_MEDIA_NETWORK_PROTOCOL_UDP;
priv->priority = 0;
priv->type = PURPLE_MEDIA_CANDIDATE_TYPE_HOST;
priv->username = NULL;
priv->password = NULL;
priv->ttl = 0;
}
static void
purple_media_candidate_finalize(GObject *info)
{
PurpleMediaCandidatePrivate *priv =
PURPLE_MEDIA_CANDIDATE_GET_PRIVATE(info);
g_free(priv->foundation);
g_free(priv->ip);
g_free(priv->base_ip);
g_free(priv->username);
g_free(priv->password);
}
static void
purple_media_candidate_set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
{
PurpleMediaCandidatePrivate *priv;
g_return_if_fail(PURPLE_IS_MEDIA_CANDIDATE(object));
priv = PURPLE_MEDIA_CANDIDATE_GET_PRIVATE(object);
switch (prop_id) {
case PROP_FOUNDATION:
g_free(priv->foundation);
priv->foundation = g_value_dup_string(value);
break;
case PROP_COMPONENT_ID:
priv->component_id = g_value_get_uint(value);
break;
case PROP_IP:
g_free(priv->ip);
priv->ip = g_value_dup_string(value);
break;
case PROP_PORT:
priv->port = g_value_get_uint(value);
break;
case PROP_BASE_IP:
g_free(priv->base_ip);
priv->base_ip = g_value_dup_string(value);
break;
case PROP_BASE_PORT:
priv->base_port = g_value_get_uint(value);
break;
case PROP_PROTOCOL:
priv->proto = g_value_get_enum(value);
break;
case PROP_PRIORITY:
priv->priority = g_value_get_uint(value);
break;
case PROP_TYPE:
priv->type = g_value_get_enum(value);
break;
case PROP_USERNAME:
g_free(priv->username);
priv->username = g_value_dup_string(value);
break;
case PROP_PASSWORD:
g_free(priv->password);
priv->password = g_value_dup_string(value);
break;
case PROP_TTL:
priv->ttl = g_value_get_uint(value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(
object, prop_id, pspec);
break;
}
}
static void
purple_media_candidate_get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
{
PurpleMediaCandidatePrivate *priv;
g_return_if_fail(PURPLE_IS_MEDIA_CANDIDATE(object));
priv = PURPLE_MEDIA_CANDIDATE_GET_PRIVATE(object);
switch (prop_id) {
case PROP_FOUNDATION:
g_value_set_string(value, priv->foundation);
break;
case PROP_COMPONENT_ID:
g_value_set_uint(value, priv->component_id);
break;
case PROP_IP:
g_value_set_string(value, priv->ip);
break;
case PROP_PORT:
g_value_set_uint(value, priv->port);
break;
case PROP_BASE_IP:
g_value_set_string(value, priv->base_ip);
break;
case PROP_BASE_PORT:
g_value_set_uint(value, priv->base_port);
break;
case PROP_PROTOCOL:
g_value_set_enum(value, priv->proto);
break;
case PROP_PRIORITY:
g_value_set_uint(value, priv->priority);
break;
case PROP_TYPE:
g_value_set_enum(value, priv->type);
break;
case PROP_USERNAME:
g_value_set_string(value, priv->username);
break;
case PROP_PASSWORD:
g_value_set_string(value, priv->password);
break;
case PROP_TTL:
g_value_set_uint(value, priv->ttl);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(
object, prop_id, pspec);
break;
}
}
static void
purple_media_candidate_class_init(PurpleMediaCandidateClass *klass)
{
GObjectClass *gobject_class = (GObjectClass*)klass;
gobject_class->finalize = purple_media_candidate_finalize;
gobject_class->set_property = purple_media_candidate_set_property;
gobject_class->get_property = purple_media_candidate_get_property;
g_object_class_install_property(gobject_class, PROP_FOUNDATION,
g_param_spec_string("foundation",
"Foundation",
"The foundation of the candidate.",
NULL,
G_PARAM_READWRITE));
g_object_class_install_property(gobject_class, PROP_COMPONENT_ID,
g_param_spec_uint("component-id",
"Component ID",
"The component id of the candidate.",
0, G_MAXUINT, 0,
G_PARAM_READWRITE));
g_object_class_install_property(gobject_class, PROP_IP,
g_param_spec_string("ip",
"IP Address",
"The IP address of the candidate.",
NULL,
G_PARAM_READWRITE));
g_object_class_install_property(gobject_class, PROP_PORT,
g_param_spec_uint("port",
"Port",
"The port of the candidate.",
0, G_MAXUINT16, 0,
G_PARAM_READWRITE));
g_object_class_install_property(gobject_class, PROP_BASE_IP,
g_param_spec_string("base-ip",
"Base IP",
"The internal IP address of the candidate.",
NULL,
G_PARAM_READWRITE));
g_object_class_install_property(gobject_class, PROP_BASE_PORT,
g_param_spec_uint("base-port",
"Base Port",
"The internal port of the candidate.",
0, G_MAXUINT16, 0,
G_PARAM_READWRITE));
g_object_class_install_property(gobject_class, PROP_PROTOCOL,
g_param_spec_enum("protocol",
"Protocol",
"The protocol of the candidate.",
PURPLE_TYPE_MEDIA_NETWORK_PROTOCOL,
PURPLE_MEDIA_NETWORK_PROTOCOL_UDP,
G_PARAM_READWRITE));
g_object_class_install_property(gobject_class, PROP_PRIORITY,
g_param_spec_uint("priority",
"Priority",
"The priority of the candidate.",
0, G_MAXUINT32, 0,
G_PARAM_READWRITE));
g_object_class_install_property(gobject_class, PROP_TYPE,
g_param_spec_enum("type",
"Type",
"The type of the candidate.",
PURPLE_TYPE_MEDIA_CANDIDATE_TYPE,
PURPLE_MEDIA_CANDIDATE_TYPE_HOST,
G_PARAM_READWRITE));
g_object_class_install_property(gobject_class, PROP_USERNAME,
g_param_spec_string("username",
"Username",
"The username used to connect to the candidate.",
NULL,
G_PARAM_READWRITE));
g_object_class_install_property(gobject_class, PROP_PASSWORD,
g_param_spec_string("password",
"Password",
"The password use to connect to the candidate.",
NULL,
G_PARAM_READWRITE));
g_object_class_install_property(gobject_class, PROP_TTL,
g_param_spec_uint("ttl",
"TTL",
"The TTL of the candidate.",
0, G_MAXUINT, 0,
G_PARAM_READWRITE));
g_type_class_add_private(klass, sizeof(PurpleMediaCandidatePrivate));
}
G_DEFINE_TYPE(PurpleMediaCandidate,
purple_media_candidate, G_TYPE_OBJECT);
#else
GType
purple_media_candidate_get_type()
{
return G_TYPE_NONE;
}
#endif
PurpleMediaCandidate *
purple_media_candidate_new(const gchar *foundation, guint component_id,
PurpleMediaCandidateType type,
PurpleMediaNetworkProtocol proto,
const gchar *ip, guint port)
{
return g_object_new(PURPLE_TYPE_MEDIA_CANDIDATE,
"foundation", foundation,
"component-id", component_id,
"type", type,
"protocol", proto,
"ip", ip,
"port", port, NULL);
}
static PurpleMediaCandidate *
purple_media_candidate_copy(PurpleMediaCandidate *candidate)
{
#ifdef USE_VV
PurpleMediaCandidatePrivate *priv;
PurpleMediaCandidate *new_candidate;
if (candidate == NULL)
return NULL;
priv = PURPLE_MEDIA_CANDIDATE_GET_PRIVATE(candidate);
new_candidate = purple_media_candidate_new(priv->foundation,
priv->component_id, priv->type, priv->proto,
priv->ip, priv->port);
g_object_set(new_candidate,
"base-ip", priv->base_ip,
"base-port", priv->base_port,
"priority", priv->priority,
"username", priv->username,
"password", priv->password,
"ttl", priv->ttl, NULL);
return new_candidate;
#else
return NULL;
#endif
}
#ifdef USE_VV
static FsCandidate *
purple_media_candidate_to_fs(PurpleMediaCandidate *candidate)
{
PurpleMediaCandidatePrivate *priv;
FsCandidate *fscandidate;
if (candidate == NULL)
return NULL;
priv = PURPLE_MEDIA_CANDIDATE_GET_PRIVATE(candidate);
fscandidate = fs_candidate_new(priv->foundation,
priv->component_id, priv->type,
priv->proto, priv->ip, priv->port);
fscandidate->base_ip = g_strdup(priv->base_ip);
fscandidate->base_port = priv->base_port;
fscandidate->priority = priv->priority;
fscandidate->username = g_strdup(priv->username);
fscandidate->password = g_strdup(priv->password);
fscandidate->ttl = priv->ttl;
return fscandidate;
}
static PurpleMediaCandidate *
purple_media_candidate_from_fs(FsCandidate *fscandidate)
{
PurpleMediaCandidate *candidate;
if (fscandidate == NULL)
return NULL;
candidate = purple_media_candidate_new(fscandidate->foundation,
fscandidate->component_id, fscandidate->type,
fscandidate->proto, fscandidate->ip, fscandidate->port);
g_object_set(candidate,
"base-ip", fscandidate->base_ip,
"base-port", fscandidate->base_port,
"priority", fscandidate->priority,
"username", fscandidate->username,
"password", fscandidate->password,
"ttl", fscandidate->ttl, NULL);
return candidate;
}
static GList *
purple_media_candidate_list_from_fs(GList *candidates)
{
GList *new_list = NULL;
for (; candidates; candidates = g_list_next(candidates)) {
new_list = g_list_prepend(new_list,
purple_media_candidate_from_fs(
candidates->data));
}
new_list = g_list_reverse(new_list);
return new_list;
}
static GList *
purple_media_candidate_list_to_fs(GList *candidates)
{
GList *new_list = NULL;
for (; candidates; candidates = g_list_next(candidates)) {
new_list = g_list_prepend(new_list,
purple_media_candidate_to_fs(
candidates->data));
}
new_list = g_list_reverse(new_list);
return new_list;
}
#endif
GList *
purple_media_candidate_list_copy(GList *candidates)
{
GList *new_list = NULL;
for (; candidates; candidates = g_list_next(candidates)) {
new_list = g_list_prepend(new_list,
purple_media_candidate_copy(candidates->data));
}
new_list = g_list_reverse(new_list);
return new_list;
}
void
purple_media_candidate_list_free(GList *candidates)
{
for (; candidates; candidates =
g_list_delete_link(candidates, candidates)) {
g_object_unref(candidates->data);
}
}
gchar *
purple_media_candidate_get_foundation(PurpleMediaCandidate *candidate)
{
gchar *foundation;
g_return_val_if_fail(PURPLE_IS_MEDIA_CANDIDATE(candidate), NULL);
g_object_get(candidate, "foundation", &foundation, NULL);
return foundation;
}
guint
purple_media_candidate_get_component_id(PurpleMediaCandidate *candidate)
{
guint component_id;
g_return_val_if_fail(PURPLE_IS_MEDIA_CANDIDATE(candidate), 0);
g_object_get(candidate, "component-id", &component_id, NULL);
return component_id;
}
gchar *
purple_media_candidate_get_ip(PurpleMediaCandidate *candidate)
{
gchar *ip;
g_return_val_if_fail(PURPLE_IS_MEDIA_CANDIDATE(candidate), NULL);
g_object_get(candidate, "ip", &ip, NULL);
return ip;
}
guint16
purple_media_candidate_get_port(PurpleMediaCandidate *candidate)
{
guint port;
g_return_val_if_fail(PURPLE_IS_MEDIA_CANDIDATE(candidate), 0);
g_object_get(candidate, "port", &port, NULL);
return port;
}
gchar *
purple_media_candidate_get_base_ip(PurpleMediaCandidate *candidate)
{
gchar *base_ip;
g_return_val_if_fail(PURPLE_IS_MEDIA_CANDIDATE(candidate), NULL);
g_object_get(candidate, "base-ip", &base_ip, NULL);
return base_ip;
}
guint16
purple_media_candidate_get_base_port(PurpleMediaCandidate *candidate)
{
guint base_port;
g_return_val_if_fail(PURPLE_IS_MEDIA_CANDIDATE(candidate), 0);
g_object_get(candidate, "base_port", &base_port, NULL);
return base_port;
}
PurpleMediaNetworkProtocol
purple_media_candidate_get_protocol(PurpleMediaCandidate *candidate)
{
PurpleMediaNetworkProtocol protocol;
g_return_val_if_fail(PURPLE_IS_MEDIA_CANDIDATE(candidate),
PURPLE_MEDIA_NETWORK_PROTOCOL_UDP);
g_object_get(candidate, "protocol", &protocol, NULL);
return protocol;
}
guint32
purple_media_candidate_get_priority(PurpleMediaCandidate *candidate)
{
guint priority;
g_return_val_if_fail(PURPLE_IS_MEDIA_CANDIDATE(candidate), 0);
g_object_get(candidate, "priority", &priority, NULL);
return priority;
}
PurpleMediaCandidateType
purple_media_candidate_get_candidate_type(PurpleMediaCandidate *candidate)
{
PurpleMediaCandidateType type;
g_return_val_if_fail(PURPLE_IS_MEDIA_CANDIDATE(candidate),
PURPLE_MEDIA_CANDIDATE_TYPE_HOST);
g_object_get(candidate, "type", &type, NULL);
return type;
}
gchar *
purple_media_candidate_get_username(PurpleMediaCandidate *candidate)
{
gchar *username;
g_return_val_if_fail(PURPLE_IS_MEDIA_CANDIDATE(candidate), NULL);
g_object_get(candidate, "username", &username, NULL);
return username;
}
gchar *
purple_media_candidate_get_password(PurpleMediaCandidate *candidate)
{
gchar *password;
g_return_val_if_fail(PURPLE_IS_MEDIA_CANDIDATE(candidate), NULL);
g_object_get(candidate, "password", &password, NULL);
return password;
}
guint
purple_media_candidate_get_ttl(PurpleMediaCandidate *candidate)
{
guint ttl;
g_return_val_if_fail(PURPLE_IS_MEDIA_CANDIDATE(candidate), 0);
g_object_get(candidate, "ttl", &ttl, NULL);
return ttl;
}
#ifdef USE_VV
static FsMediaType
purple_media_to_fs_media_type(PurpleMediaSessionType type)
{
if (type & PURPLE_MEDIA_AUDIO)
return FS_MEDIA_TYPE_AUDIO;
else if (type & PURPLE_MEDIA_VIDEO)
return FS_MEDIA_TYPE_VIDEO;
else
return 0;
}
static FsStreamDirection
purple_media_to_fs_stream_direction(PurpleMediaSessionType type)
{
if ((type & PURPLE_MEDIA_AUDIO) == PURPLE_MEDIA_AUDIO ||
(type & PURPLE_MEDIA_VIDEO) == PURPLE_MEDIA_VIDEO)
return FS_DIRECTION_BOTH;
else if ((type & PURPLE_MEDIA_SEND_AUDIO) ||
(type & PURPLE_MEDIA_SEND_VIDEO))
return FS_DIRECTION_SEND;
else if ((type & PURPLE_MEDIA_RECV_AUDIO) ||
(type & PURPLE_MEDIA_RECV_VIDEO))
return FS_DIRECTION_RECV;
else
return FS_DIRECTION_NONE;
}
static PurpleMediaSessionType
purple_media_from_fs(FsMediaType type, FsStreamDirection direction)
{
PurpleMediaSessionType result = PURPLE_MEDIA_NONE;
if (type == FS_MEDIA_TYPE_AUDIO) {
if (direction & FS_DIRECTION_SEND)
result |= PURPLE_MEDIA_SEND_AUDIO;
if (direction & FS_DIRECTION_RECV)
result |= PURPLE_MEDIA_RECV_AUDIO;
} else if (type == FS_MEDIA_TYPE_VIDEO) {
if (direction & FS_DIRECTION_SEND)
result |= PURPLE_MEDIA_SEND_VIDEO;
if (direction & FS_DIRECTION_RECV)
result |= PURPLE_MEDIA_RECV_VIDEO;
}
return result;
}
#endif
/*
* PurpleMediaCodec
*/
struct _PurpleMediaCodecClass
{
GObjectClass parent_class;
};
struct _PurpleMediaCodec
{
GObject parent;
};
#ifdef USE_VV
struct _PurpleMediaCodecPrivate
{
gint id;
char *encoding_name;
PurpleMediaSessionType media_type;
guint clock_rate;
guint channels;
GList *optional_params;
};
enum {
PROP_CODEC_0,
PROP_ID,
PROP_ENCODING_NAME,
PROP_MEDIA_TYPE,
PROP_CLOCK_RATE,
PROP_CHANNELS,
PROP_OPTIONAL_PARAMS,
};
static void
purple_media_codec_init(PurpleMediaCodec *info)
{
PurpleMediaCodecPrivate *priv =
PURPLE_MEDIA_CODEC_GET_PRIVATE(info);
priv->encoding_name = NULL;
priv->optional_params = NULL;
}
static void
purple_media_codec_finalize(GObject *info)
{
PurpleMediaCodecPrivate *priv =
PURPLE_MEDIA_CODEC_GET_PRIVATE(info);
g_free(priv->encoding_name);
for (; priv->optional_params; priv->optional_params =
g_list_delete_link(priv->optional_params,
priv->optional_params)) {
g_free(priv->optional_params->data);
}
}
static void
purple_media_codec_set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
{
PurpleMediaCodecPrivate *priv;
g_return_if_fail(PURPLE_IS_MEDIA_CODEC(object));
priv = PURPLE_MEDIA_CODEC_GET_PRIVATE(object);
switch (prop_id) {
case PROP_ID:
priv->id = g_value_get_uint(value);
break;
case PROP_ENCODING_NAME:
g_free(priv->encoding_name);
priv->encoding_name = g_value_dup_string(value);
break;
case PROP_MEDIA_TYPE:
priv->media_type = g_value_get_flags(value);
break;
case PROP_CLOCK_RATE:
priv->clock_rate = g_value_get_uint(value);
break;
case PROP_CHANNELS:
priv->channels = g_value_get_uint(value);
break;
case PROP_OPTIONAL_PARAMS:
priv->optional_params = g_value_get_pointer(value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(
object, prop_id, pspec);
break;
}
}
static void
purple_media_codec_get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
{
PurpleMediaCodecPrivate *priv;
g_return_if_fail(PURPLE_IS_MEDIA_CODEC(object));
priv = PURPLE_MEDIA_CODEC_GET_PRIVATE(object);
switch (prop_id) {
case PROP_ID:
g_value_set_uint(value, priv->id);
break;
case PROP_ENCODING_NAME:
g_value_set_string(value, priv->encoding_name);
break;
case PROP_MEDIA_TYPE:
g_value_set_flags(value, priv->media_type);
break;
case PROP_CLOCK_RATE:
g_value_set_uint(value, priv->clock_rate);
break;
case PROP_CHANNELS:
g_value_set_uint(value, priv->channels);
break;
case PROP_OPTIONAL_PARAMS:
g_value_set_pointer(value, priv->optional_params);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(
object, prop_id, pspec);
break;
}
}
static void
purple_media_codec_class_init(PurpleMediaCodecClass *klass)
{
GObjectClass *gobject_class = (GObjectClass*)klass;
gobject_class->finalize = purple_media_codec_finalize;
gobject_class->set_property = purple_media_codec_set_property;
gobject_class->get_property = purple_media_codec_get_property;
g_object_class_install_property(gobject_class, PROP_ID,
g_param_spec_uint("id",
"ID",
"The numeric identifier of the codec.",
0, G_MAXUINT, 0,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
g_object_class_install_property(gobject_class, PROP_ENCODING_NAME,
g_param_spec_string("encoding-name",
"Encoding Name",
"The name of the codec.",
NULL,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
g_object_class_install_property(gobject_class, PROP_MEDIA_TYPE,
g_param_spec_flags("media-type",
"Media Type",
"Whether this is an audio of video codec.",
PURPLE_TYPE_MEDIA_SESSION_TYPE,
PURPLE_MEDIA_NONE,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
g_object_class_install_property(gobject_class, PROP_CLOCK_RATE,
g_param_spec_uint("clock-rate",
"Create Callback",
"The function called to create this element.",
0, G_MAXUINT, 0,
G_PARAM_READWRITE));
g_object_class_install_property(gobject_class, PROP_CHANNELS,
g_param_spec_uint("channels",
"Channels",
"The number of channels in this codec.",
0, G_MAXUINT, 0,
G_PARAM_READWRITE));
g_object_class_install_property(gobject_class, PROP_OPTIONAL_PARAMS,
g_param_spec_pointer("optional-params",
"Optional Params",
"A list of optional parameters for the codec.",
G_PARAM_READWRITE));
g_type_class_add_private(klass, sizeof(PurpleMediaCodecPrivate));
}
G_DEFINE_TYPE(PurpleMediaCodec,
purple_media_codec, G_TYPE_OBJECT);
#else
GType
purple_media_codec_get_type()
{
return G_TYPE_NONE;
}
#endif
guint
purple_media_codec_get_id(PurpleMediaCodec *codec)
{
guint id;
g_return_val_if_fail(PURPLE_IS_MEDIA_CODEC(codec), 0);
g_object_get(codec, "id", &id, NULL);
return id;
}
gchar *
purple_media_codec_get_encoding_name(PurpleMediaCodec *codec)
{
gchar *name;
g_return_val_if_fail(PURPLE_IS_MEDIA_CODEC(codec), NULL);
g_object_get(codec, "encoding-name", &name, NULL);
return name;
}
guint
purple_media_codec_get_clock_rate(PurpleMediaCodec *codec)
{
guint clock_rate;
g_return_val_if_fail(PURPLE_IS_MEDIA_CODEC(codec), 0);
g_object_get(codec, "clock-rate", &clock_rate, NULL);
return clock_rate;
}
guint
purple_media_codec_get_channels(PurpleMediaCodec *codec)
{
guint channels;
g_return_val_if_fail(PURPLE_IS_MEDIA_CODEC(codec), 0);
g_object_get(codec, "channels", &channels, NULL);
return channels;
}
GList *
purple_media_codec_get_optional_parameters(PurpleMediaCodec *codec)
{
GList *optional_params;
g_return_val_if_fail(PURPLE_IS_MEDIA_CODEC(codec), NULL);
g_object_get(codec, "optional-params", &optional_params, NULL);
return optional_params;
}
void
purple_media_codec_add_optional_parameter(PurpleMediaCodec *codec,
const gchar *name, const gchar *value)
{
#ifdef USE_VV
PurpleMediaCodecPrivate *priv;
PurpleKeyValuePair *new_param;
g_return_if_fail(codec != NULL);
g_return_if_fail(name != NULL && value != NULL);
priv = PURPLE_MEDIA_CODEC_GET_PRIVATE(codec);
new_param = g_new0(PurpleKeyValuePair, 1);
new_param->key = g_strdup(name);
new_param->value = g_strdup(value);
priv->optional_params = g_list_append(
priv->optional_params, new_param);
#endif
}
void
purple_media_codec_remove_optional_parameter(PurpleMediaCodec *codec,
PurpleKeyValuePair *param)
{
#ifdef USE_VV
PurpleMediaCodecPrivate *priv;
g_return_if_fail(codec != NULL && param != NULL);
priv = PURPLE_MEDIA_CODEC_GET_PRIVATE(codec);
g_free(param->key);
g_free(param->value);
g_free(param);
priv->optional_params =
g_list_remove(priv->optional_params, param);
#endif
}
PurpleKeyValuePair *
purple_media_codec_get_optional_parameter(PurpleMediaCodec *codec,
const gchar *name, const gchar *value)
{
#ifdef USE_VV
PurpleMediaCodecPrivate *priv;
GList *iter;
g_return_val_if_fail(codec != NULL, NULL);
g_return_val_if_fail(name != NULL, NULL);
priv = PURPLE_MEDIA_CODEC_GET_PRIVATE(codec);
for (iter = priv->optional_params; iter; iter = g_list_next(iter)) {
PurpleKeyValuePair *param = iter->data;
if (!g_ascii_strcasecmp(param->key, name) &&
(value == NULL ||
!g_ascii_strcasecmp(param->value, value)))
return param;
}
#endif
return NULL;
}
PurpleMediaCodec *
purple_media_codec_new(int id, const char *encoding_name,
PurpleMediaSessionType media_type, guint clock_rate)
{
PurpleMediaCodec *codec =
g_object_new(PURPLE_TYPE_MEDIA_CODEC,
"id", id,
"encoding_name", encoding_name,
"media_type", media_type,
"clock-rate", clock_rate, NULL);
return codec;
}
static PurpleMediaCodec *
purple_media_codec_copy(PurpleMediaCodec *codec)
{
#ifdef USE_VV
PurpleMediaCodecPrivate *priv;
PurpleMediaCodec *new_codec;
GList *iter;
if (codec == NULL)
return NULL;
priv = PURPLE_MEDIA_CODEC_GET_PRIVATE(codec);
new_codec = purple_media_codec_new(priv->id, priv->encoding_name,
priv->media_type, priv->clock_rate);
g_object_set(codec, "channels", priv->channels, NULL);
for (iter = priv->optional_params; iter; iter = g_list_next(iter)) {
PurpleKeyValuePair *param =
(PurpleKeyValuePair*)iter->data;
purple_media_codec_add_optional_parameter(new_codec,
param->key, param->value);
}
return new_codec;
#else
return NULL;
#endif
}
#ifdef USE_VV
static FsCodec *
purple_media_codec_to_fs(const PurpleMediaCodec *codec)
{
PurpleMediaCodecPrivate *priv;
FsCodec *new_codec;
GList *iter;
if (codec == NULL)
return NULL;
priv = PURPLE_MEDIA_CODEC_GET_PRIVATE(codec);
new_codec = fs_codec_new(priv->id, priv->encoding_name,
purple_media_to_fs_media_type(priv->media_type),
priv->clock_rate);
new_codec->channels = priv->channels;
for (iter = priv->optional_params; iter; iter = g_list_next(iter)) {
PurpleKeyValuePair *param = (PurpleKeyValuePair*)iter->data;
fs_codec_add_optional_parameter(new_codec,
param->key, param->value);
}
return new_codec;
}
static PurpleMediaCodec *
purple_media_codec_from_fs(const FsCodec *codec)
{
PurpleMediaCodec *new_codec;
GList *iter;
if (codec == NULL)
return NULL;
new_codec = purple_media_codec_new(codec->id, codec->encoding_name,
purple_media_from_fs(codec->media_type,
FS_DIRECTION_BOTH), codec->clock_rate);
g_object_set(new_codec, "channels", codec->channels, NULL);
for (iter = codec->optional_params; iter; iter = g_list_next(iter)) {
FsCodecParameter *param = (FsCodecParameter*)iter->data;
purple_media_codec_add_optional_parameter(new_codec,
param->name, param->value);
}
return new_codec;
}
#endif
gchar *
purple_media_codec_to_string(const PurpleMediaCodec *codec)
{
#ifdef USE_VV
FsCodec *fscodec = purple_media_codec_to_fs(codec);
gchar *str = fs_codec_to_string(fscodec);
fs_codec_destroy(fscodec);
return str;
#else
return g_strdup("");
#endif
}
#ifdef USE_VV
static GList *
purple_media_codec_list_from_fs(GList *codecs)
{
GList *new_list = NULL;
for (; codecs; codecs = g_list_next(codecs)) {
new_list = g_list_prepend(new_list,
purple_media_codec_from_fs(
codecs->data));
}
new_list = g_list_reverse(new_list);
return new_list;
}
static GList *
purple_media_codec_list_to_fs(GList *codecs)
{
GList *new_list = NULL;
for (; codecs; codecs = g_list_next(codecs)) {
new_list = g_list_prepend(new_list,
purple_media_codec_to_fs(
codecs->data));
}
new_list = g_list_reverse(new_list);
return new_list;
}
#endif
GList *
purple_media_codec_list_copy(GList *codecs)
{
GList *new_list = NULL;
for (; codecs; codecs = g_list_next(codecs)) {
new_list = g_list_prepend(new_list,
purple_media_codec_copy(codecs->data));
}
new_list = g_list_reverse(new_list);
return new_list;
}
void
purple_media_codec_list_free(GList *codecs)
{
for (; codecs; codecs =
g_list_delete_link(codecs, codecs)) {
g_object_unref(codecs->data);
}
}
#ifdef USE_VV
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 FsParticipant*
purple_media_get_participant(PurpleMedia *media, const gchar *name)
{
g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
return (FsParticipant*) (media->priv->participants) ?
g_hash_table_lookup(media->priv->participants, name) : 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 (!strcmp(stream->session->id, session) &&
!strcmp(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 ||
!strcmp(stream->session->id, session)) &&
(participant == NULL ||
!strcmp(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(g_str_hash, g_str_equal);
}
g_hash_table_insert(media->priv->sessions, g_strdup(session->id), session);
}
static gboolean
purple_media_remove_session(PurpleMedia *media, PurpleMediaSession *session)
{
g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
return g_hash_table_remove(media->priv->sessions, session->id);
}
static FsParticipant *
purple_media_add_participant(PurpleMedia *media, const gchar *name)
{
FsParticipant *participant;
GError *err = NULL;
g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
participant = purple_media_get_participant(media, name);
if (participant)
return participant;
participant = fs_conference_new_participant(media->priv->conference,
(gchar*)name, &err);
if (err) {
purple_debug_error("media", "Error creating participant: %s\n",
err->message);
g_error_free(err);
return NULL;
}
if (!media->priv->participants) {
purple_debug_info("media", "Creating hash table for participants\n");
media->priv->participants = g_hash_table_new_full(g_str_hash,
g_str_equal, g_free, NULL);
}
g_hash_table_insert(media->priv->participants, g_strdup(name), participant);
return participant;
}
static PurpleMediaStream *
purple_media_insert_stream(PurpleMediaSession *session, const gchar *name, FsStream *stream)
{
PurpleMediaStream *media_stream;
g_return_val_if_fail(session != NULL, NULL);
media_stream = g_new0(PurpleMediaStream, 1);
media_stream->stream = stream;
media_stream->participant = g_strdup(name);
media_stream->session = session;
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,
FsCandidate *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
static void
purple_media_set_src(PurpleMedia *media, const gchar *sess_id, GstElement *src)
{
PurpleMediaSession *session;
GstPad *sinkpad;
GstPad *srcpad;
g_return_if_fail(PURPLE_IS_MEDIA(media));
g_return_if_fail(GST_IS_ELEMENT(src));
session = purple_media_get_session(media, sess_id);
if (session == NULL) {
purple_debug_warning("media", "purple_media_set_src: trying"
" to set src on non-existent session\n");
return;
}
if (session->src)
gst_object_unref(session->src);
session->src = src;
gst_element_set_locked_state(session->src, TRUE);
session->tee = gst_element_factory_make("tee", NULL);
gst_bin_add(GST_BIN(session->media->priv->confbin), session->tee);
/* This supposedly isn't necessary, but it silences some warnings */
if (GST_ELEMENT_PARENT(session->media->priv->confbin)
== GST_ELEMENT_PARENT(session->src)) {
GstPad *pad = gst_element_get_static_pad(session->tee, "sink");
GstPad *ghost = gst_ghost_pad_new(NULL, pad);
gst_object_unref(pad);
gst_pad_set_active(ghost, TRUE);
gst_element_add_pad(session->media->priv->confbin, ghost);
}
gst_element_set_state(session->tee, GST_STATE_PLAYING);
gst_element_link(session->src, session->media->priv->confbin);
g_object_get(session->session, "sink-pad", &sinkpad, NULL);
if (session->type & PURPLE_MEDIA_SEND_AUDIO) {
gchar *name = g_strdup_printf("volume_%s", session->id);
GstElement *level;
GstElement *volume = gst_element_factory_make("volume", name);
double input_volume = purple_prefs_get_int(
"/purple/media/audio/volume/input")/10.0;
g_free(name);
name = g_strdup_printf("sendlevel_%s", session->id);
level = gst_element_factory_make("level", name);
g_free(name);
gst_bin_add(GST_BIN(session->media->priv->confbin), volume);
gst_bin_add(GST_BIN(session->media->priv->confbin), level);
gst_element_set_state(level, GST_STATE_PLAYING);
gst_element_set_state(volume, GST_STATE_PLAYING);
gst_element_link(volume, level);
gst_element_link(session->tee, volume);
srcpad = gst_element_get_static_pad(level, "src");
g_object_set(volume, "volume", input_volume, NULL);
} else {
srcpad = gst_element_get_request_pad(session->tee, "src%d");
}
purple_debug_info("media", "connecting pad: %s\n",
gst_pad_link(srcpad, sinkpad) == GST_PAD_LINK_OK
? "success" : "failure");
gst_element_set_locked_state(session->src, FALSE);
gst_object_unref(session->src);
}
#endif
#ifdef USE_GSTREAMER
GstElement *
purple_media_get_src(PurpleMedia *media, const gchar *sess_id)
{
#ifdef USE_VV
PurpleMediaSession *session;
g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
session = purple_media_get_session(media, sess_id);
return (session != NULL) ? session->src : NULL;
#else
return NULL;
#endif
}
#endif /* USE_GSTREAMER */
#ifdef USE_VV
static PurpleMediaSession *
purple_media_session_from_fs_stream(PurpleMedia *media, FsStream *stream)
{
FsSession *fssession;
GList *values;
g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
g_return_val_if_fail(FS_IS_STREAM(stream), NULL);
g_object_get(stream, "session", &fssession, NULL);
values = g_hash_table_get_values(media->priv->sessions);
for (; values; values = g_list_delete_link(values, values)) {
PurpleMediaSession *session = values->data;
if (session->session == fssession) {
g_list_free(values);
g_object_unref(fssession);
return session;
}
}
g_object_unref(fssession);
return NULL;
}
static gboolean
media_bus_call(GstBus *bus, GstMessage *msg, PurpleMedia *media)
{
switch(GST_MESSAGE_TYPE(msg)) {
case GST_MESSAGE_ELEMENT: {
if (g_signal_has_handler_pending(media,
purple_media_signals[LEVEL], 0, FALSE)
&& gst_structure_has_name(
gst_message_get_structure(msg), "level")) {
GstElement *src = GST_ELEMENT(GST_MESSAGE_SRC(msg));
gchar *name;
gchar *participant = NULL;
PurpleMediaSession *session = NULL;
gdouble rms_db;
gdouble percent;
const GValue *list;
const GValue *value;
if (!PURPLE_IS_MEDIA(media) ||
GST_ELEMENT_PARENT(src) !=
media->priv->confbin)
break;
name = gst_element_get_name(src);
if (!strncmp(name, "sendlevel_", 10)) {
session = purple_media_get_session(
media, name+10);
} else {
GList *iter = media->priv->streams;
for (; iter; iter = g_list_next(iter)) {
PurpleMediaStream *stream = iter->data;
if (stream->level == src) {
session = stream->session;
participant = stream->participant;
break;
}
}
}
g_free(name);
if (!session)
break;
list = gst_structure_get_value(
gst_message_get_structure(msg), "rms");
value = gst_value_list_get_value(list, 0);
rms_db = g_value_get_double(value);
percent = pow(10, rms_db / 20) * 5;
if(percent > 1.0)
percent = 1.0;
g_signal_emit(media, purple_media_signals[LEVEL],
0, session->id, participant, percent);
break;
}
if (!FS_IS_CONFERENCE(GST_MESSAGE_SRC(msg)) ||
!PURPLE_IS_MEDIA(media) ||
media->priv->conference !=
FS_CONFERENCE(GST_MESSAGE_SRC(msg)))
break;
if (gst_structure_has_name(msg->structure, "farsight-error")) {
FsError error_no;
gst_structure_get_enum(msg->structure, "error-no",
FS_TYPE_ERROR, (gint*)&error_no);
switch (error_no) {
case FS_ERROR_NO_CODECS:
purple_media_error(media, _("No codecs found. Install some GStreamer codecs found in GStreamer plugins packages."));
purple_media_end(media, NULL, NULL);
break;
case FS_ERROR_NO_CODECS_LEFT:
purple_media_error(media, _("No codecs left. Your codec preferences in fs-codecs.conf are too strict."));
purple_media_end(media, NULL, NULL);
break;
case FS_ERROR_UNKNOWN_CNAME:
/*
* Unknown CName is only a problem for the
* multicast transmitter which isn't used.
* It is also deprecated.
*/
break;
default:
purple_debug_error("media", "farsight-error: %i: %s\n", error_no,
gst_structure_get_string(msg->structure, "error-msg"));
break;
}
if (FS_ERROR_IS_FATAL(error_no)) {
purple_media_error(media, _("A non-recoverable Farsight2 error has occurred."));
purple_media_end(media, NULL, NULL);
}
} else if (gst_structure_has_name(msg->structure,
"farsight-new-local-candidate")) {
FsStream *stream = g_value_get_object(gst_structure_get_value(msg->structure, "stream"));
FsCandidate *local_candidate = g_value_get_boxed(gst_structure_get_value(msg->structure, "candidate"));
PurpleMediaSession *session = purple_media_session_from_fs_stream(media, stream);
purple_media_new_local_candidate_cb(stream, local_candidate, session);
} else if (gst_structure_has_name(msg->structure,
"farsight-local-candidates-prepared")) {
FsStream *stream = g_value_get_object(gst_structure_get_value(msg->structure, "stream"));
PurpleMediaSession *session = purple_media_session_from_fs_stream(media, stream);
purple_media_candidates_prepared_cb(stream, session);
} else if (gst_structure_has_name(msg->structure,
"farsight-new-active-candidate-pair")) {
FsStream *stream = g_value_get_object(gst_structure_get_value(msg->structure, "stream"));
FsCandidate *local_candidate = g_value_get_boxed(gst_structure_get_value(msg->structure, "local-candidate"));
FsCandidate *remote_candidate = g_value_get_boxed(gst_structure_get_value(msg->structure, "remote-candidate"));
PurpleMediaSession *session = purple_media_session_from_fs_stream(media, stream);
purple_media_candidate_pair_established_cb(stream, local_candidate, remote_candidate, session);
} else if (gst_structure_has_name(msg->structure,
"farsight-recv-codecs-changed")) {
GList *codecs = g_value_get_boxed(gst_structure_get_value(msg->structure, "codecs"));
FsCodec *codec = codecs->data;
purple_debug_info("media", "farsight-recv-codecs-changed: %s\n", codec->encoding_name);
} else if (gst_structure_has_name(msg->structure,
"farsight-component-state-changed")) {
FsStreamState fsstate = g_value_get_enum(gst_structure_get_value(msg->structure, "state"));
guint component = g_value_get_uint(gst_structure_get_value(msg->structure, "component"));
const gchar *state;
switch (fsstate) {
case FS_STREAM_STATE_FAILED:
state = "FAILED";
break;
case FS_STREAM_STATE_DISCONNECTED:
state = "DISCONNECTED";
break;
case FS_STREAM_STATE_GATHERING:
state = "GATHERING";
break;
case FS_STREAM_STATE_CONNECTING:
state = "CONNECTING";
break;
case FS_STREAM_STATE_CONNECTED:
state = "CONNECTED";
break;
case FS_STREAM_STATE_READY:
state = "READY";
break;
default:
state = "UNKNOWN";
break;
}
purple_debug_info("media", "farsight-component-state-changed: component: %u state: %s\n", component, state);
} else if (gst_structure_has_name(msg->structure,
"farsight-send-codec-changed")) {
FsCodec *codec = g_value_get_boxed(gst_structure_get_value(msg->structure, "codec"));
gchar *codec_str = fs_codec_to_string(codec);
purple_debug_info("media", "farsight-send-codec-changed: codec: %s\n", codec_str);
g_free(codec_str);
} else if (gst_structure_has_name(msg->structure,
"farsight-codecs-changed")) {
GList *sessions = g_hash_table_get_values(PURPLE_MEDIA(media)->priv->sessions);
FsSession *fssession = g_value_get_object(gst_structure_get_value(msg->structure, "session"));
for (; sessions; sessions = g_list_delete_link(sessions, sessions)) {
PurpleMediaSession *session = sessions->data;
if (session->session == fssession) {
gchar *session_id = g_strdup(session->id);
g_signal_emit(media, purple_media_signals[CODECS_CHANGED], 0, session_id);
g_free(session_id);
g_list_free(sessions);
break;
}
}
}
break;
}
case GST_MESSAGE_ERROR: {
GstElement *element = GST_ELEMENT(GST_MESSAGE_SRC(msg));
GstElement *lastElement = NULL;
while (!GST_IS_PIPELINE(element)) {
if (element == media->priv->confbin) {
purple_media_error(media, _("Conference error"));
purple_media_end(media, NULL, NULL);
break;
}
lastElement = element;
element = GST_ELEMENT_PARENT(element);
}
if (GST_IS_PIPELINE(element)) {
GList *sessions = g_hash_table_get_values(media->priv->sessions);
for (; sessions; sessions = g_list_delete_link(sessions, sessions)) {
PurpleMediaSession *session = sessions->data;
if (session->src == lastElement) {
if (session->type & PURPLE_MEDIA_AUDIO)
purple_media_error(media, _("Error with your microphone"));
else
purple_media_error(media, _("Error with your webcam"));
purple_media_end(media, NULL, NULL);
break;
}
}
g_list_free(sessions);
}
}
default:
break;
}
return TRUE;
}
#endif
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_prpl_data(PurpleMedia *media)
{
#ifdef USE_VV
gpointer prpl_data;
g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
g_object_get(G_OBJECT(media), "prpl-data", &prpl_data, NULL);
return prpl_data;
#else
return NULL;
#endif
}
void
purple_media_set_prpl_data(PurpleMedia *media, gpointer prpl_data)
{
#ifdef USE_VV
g_return_if_fail(PURPLE_IS_MEDIA(media));
g_object_set(G_OBJECT(media), "prpl-data", prpl_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
g_return_if_fail(PURPLE_IS_MEDIA(media));
if (session_id == NULL && participant == NULL) {
g_signal_emit(media, purple_media_signals[STATE_CHANGED],
0, PURPLE_MEDIA_STATE_END,
NULL, NULL);
g_object_unref(media);
}
#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;
g_return_if_fail(PURPLE_IS_MEDIA(media));
streams = purple_media_get_streams(media,
session_id, participant);
for (; streams; streams =
g_list_delete_link(streams, streams)) {
PurpleMediaStream *stream = streams->data;
g_object_set(G_OBJECT(stream->stream), "direction",
purple_media_to_fs_stream_direction(
stream->session->type), NULL);
stream->accepted = TRUE;
if (stream->remote_candidates != NULL &&
stream->initiator == FALSE) {
GError *err = NULL;
fs_stream_set_remote_candidates(stream->stream,
stream->remote_candidates, &err);
if (err) {
purple_debug_error("media", "Error adding remote"
" candidates: %s\n", err->message);
g_error_free(err);
}
}
}
} else if (local == TRUE && (type == PURPLE_MEDIA_INFO_MUTE ||
type == PURPLE_MEDIA_INFO_UNMUTE)) {
GList *sessions;
gboolean active = (type == PURPLE_MEDIA_INFO_MUTE);
g_return_if_fail(PURPLE_IS_MEDIA(media));
if (session_id == NULL)
sessions = g_hash_table_get_values(
media->priv->sessions);
else
sessions = g_list_prepend(NULL,
purple_media_get_session(
media, session_id));
purple_debug_info("media", "Turning mute %s\n",
active ? "on" : "off");
for (; sessions; sessions = g_list_delete_link(
sessions, sessions)) {
PurpleMediaSession *session = sessions->data;
if (session->type & PURPLE_MEDIA_SEND_AUDIO) {
gchar *name = g_strdup_printf("volume_%s",
session->id);
GstElement *volume = gst_bin_get_by_name(
GST_BIN(session->media->
priv->confbin), name);
g_free(name);
g_object_set(volume, "mute", active, NULL);
}
}
} else if (local == TRUE && (type == PURPLE_MEDIA_INFO_PAUSE ||
type == PURPLE_MEDIA_INFO_UNPAUSE)) {
gboolean active = (type == PURPLE_MEDIA_INFO_PAUSE);
GList *streams = purple_media_get_streams(media,
session_id, participant);
for (; streams; streams = g_list_delete_link(streams, streams)) {
PurpleMediaStream *stream = streams->data;
if (stream->session->type & PURPLE_MEDIA_SEND_VIDEO) {
stream->paused = active;
if (!stream->held)
g_object_set(stream->stream, "direction",
purple_media_to_fs_stream_direction(
stream->session->type & ((active) ?
~PURPLE_MEDIA_SEND_VIDEO :
PURPLE_MEDIA_VIDEO)), NULL);
}
}
} else if (local == TRUE && (type == PURPLE_MEDIA_INFO_HOLD ||
type == PURPLE_MEDIA_INFO_UNHOLD)) {
GList *streams;
gboolean active = (type == PURPLE_MEDIA_INFO_HOLD);
g_return_if_fail(PURPLE_IS_MEDIA(media));
streams = purple_media_get_streams(media,
session_id, participant);
for (; streams; streams = g_list_delete_link(streams, streams)) {
PurpleMediaStream *stream = streams->data;
stream->held = active;
if (stream->session->type & PURPLE_MEDIA_VIDEO) {
FsStreamDirection direction;
direction = ((active) ?
~PURPLE_MEDIA_VIDEO :
PURPLE_MEDIA_VIDEO);
if (!active && stream->paused)
direction &= ~PURPLE_MEDIA_SEND_VIDEO;
g_object_set(stream->stream, "direction",
purple_media_to_fs_stream_direction(
stream->session->type & direction), NULL);
} else if (stream->session->type & PURPLE_MEDIA_AUDIO) {
g_object_set(stream->stream, "direction",
purple_media_to_fs_stream_direction(
stream->session->type & ((active) ?
~PURPLE_MEDIA_AUDIO :
PURPLE_MEDIA_AUDIO)), NULL);
}
}
}
g_signal_emit(media, purple_media_signals[STREAM_INFO],
0, type, session_id, participant, local);
if (type == PURPLE_MEDIA_INFO_HANGUP ||
type == PURPLE_MEDIA_INFO_REJECT) {
purple_media_end(media, session_id, participant);
}
#endif
}
#ifdef USE_VV
static void
purple_media_new_local_candidate_cb(FsStream *stream,
FsCandidate *local_candidate,
PurpleMediaSession *session)
{
gchar *name;
FsParticipant *participant;
PurpleMediaCandidate *candidate;
g_return_if_fail(FS_IS_STREAM(stream));
g_return_if_fail(session != NULL);
purple_debug_info("media", "got new local candidate: %s\n", local_candidate->foundation);
g_object_get(stream, "participant", &participant, NULL);
g_object_get(participant, "cname", &name, NULL);
g_object_unref(participant);
purple_media_insert_local_candidate(session, name, fs_candidate_copy(local_candidate));
candidate = purple_media_candidate_from_fs(local_candidate);
g_signal_emit(session->media, purple_media_signals[NEW_CANDIDATE],
0, session->id, name, candidate);
g_object_unref(candidate);
g_free(name);
}
static void
purple_media_candidates_prepared_cb(FsStream *stream, PurpleMediaSession *session)
{
gchar *name;
FsParticipant *participant;
PurpleMediaStream *stream_data;
g_return_if_fail(FS_IS_STREAM(stream));
g_return_if_fail(session != NULL);
g_object_get(stream, "participant", &participant, NULL);
g_object_get(participant, "cname", &name, NULL);
g_object_unref(participant);
stream_data = purple_media_get_stream(session->media, session->id, name);
stream_data->candidates_prepared = TRUE;
g_signal_emit(session->media,
purple_media_signals[CANDIDATES_PREPARED],
0, session->id, name);
g_free(name);
}
/* callback called when a pair of transport candidates (local and remote)
* has been established */
static void
purple_media_candidate_pair_established_cb(FsStream *fsstream,
FsCandidate *native_candidate,
FsCandidate *remote_candidate,
PurpleMediaSession *session)
{
gchar *name;
FsParticipant *participant;
PurpleMediaStream *stream;
GList *iter;
g_return_if_fail(FS_IS_STREAM(fsstream));
g_return_if_fail(session != NULL);
g_object_get(fsstream, "participant", &participant, NULL);
g_object_get(participant, "cname", &name, NULL);
g_object_unref(participant);
stream = purple_media_get_stream(session->media, session->id, name);
iter = stream->active_local_candidates;
for(; iter; iter = g_list_next(iter)) {
FsCandidate *c = iter->data;
if (native_candidate->component_id == c->component_id) {
fs_candidate_destroy(c);
stream->active_local_candidates =
g_list_delete_link(iter, iter);
stream->active_local_candidates = g_list_prepend(
stream->active_local_candidates,
fs_candidate_copy(native_candidate));
break;
}
}
if (iter == NULL)
stream->active_local_candidates = g_list_prepend(
stream->active_local_candidates,
fs_candidate_copy(native_candidate));
iter = stream->active_remote_candidates;
for(; iter; iter = g_list_next(iter)) {
FsCandidate *c = iter->data;
if (native_candidate->component_id == c->component_id) {
fs_candidate_destroy(c);
stream->active_remote_candidates =
g_list_delete_link(iter, iter);
stream->active_remote_candidates = g_list_prepend(
stream->active_remote_candidates,
fs_candidate_copy(remote_candidate));
break;
}
}
if (iter == NULL)
stream->active_remote_candidates = g_list_prepend(
stream->active_remote_candidates,
fs_candidate_copy(remote_candidate));
purple_debug_info("media", "candidate pair established\n");
}
static gboolean
purple_media_connected_cb(PurpleMediaStream *stream)
{
g_return_val_if_fail(stream != NULL, FALSE);
stream->connected_cb_id = 0;
purple_media_manager_create_output_window(
stream->session->media->priv->manager,
stream->session->media,
stream->session->id, stream->participant);
g_signal_emit(stream->session->media,
purple_media_signals[STATE_CHANGED],
0, PURPLE_MEDIA_STATE_CONNECTED,
stream->session->id, stream->participant);
return FALSE;
}
static void
purple_media_src_pad_added_cb(FsStream *fsstream, GstPad *srcpad,
FsCodec *codec, PurpleMediaStream *stream)
{
PurpleMediaPrivate *priv;
GstPad *sinkpad;
g_return_if_fail(FS_IS_STREAM(fsstream));
g_return_if_fail(stream != NULL);
priv = stream->session->media->priv;
if (stream->src == NULL) {
GstElement *sink = NULL;
if (codec->media_type == FS_MEDIA_TYPE_AUDIO) {
GstElement *queue = NULL;
double output_volume = purple_prefs_get_int(
"/purple/media/audio/volume/output")/10.0;
/*
* Should this instead be:
* audioconvert ! audioresample ! liveadder !
* audioresample ! audioconvert ! realsink
*/
queue = gst_element_factory_make("queue", NULL);
stream->volume = gst_element_factory_make(
"volume", NULL);
g_object_set(stream->volume, "volume",
output_volume, NULL);
stream->level = gst_element_factory_make(
"level", NULL);
stream->src = gst_element_factory_make(
"liveadder", NULL);
sink = purple_media_manager_get_element(priv->manager,
PURPLE_MEDIA_RECV_AUDIO,
stream->session->media,
stream->session->id,
stream->participant);
gst_bin_add(GST_BIN(priv->confbin), queue);
gst_bin_add(GST_BIN(priv->confbin), stream->volume);
gst_bin_add(GST_BIN(priv->confbin), stream->level);
gst_bin_add(GST_BIN(priv->confbin), sink);
gst_element_set_state(sink, GST_STATE_PLAYING);
gst_element_set_state(stream->level, GST_STATE_PLAYING);
gst_element_set_state(stream->volume, GST_STATE_PLAYING);
gst_element_set_state(queue, GST_STATE_PLAYING);
gst_element_link(stream->level, sink);
gst_element_link(stream->volume, stream->level);
gst_element_link(queue, stream->volume);
sink = queue;
} else if (codec->media_type == FS_MEDIA_TYPE_VIDEO) {
stream->src = gst_element_factory_make(
"fsfunnel", NULL);
sink = gst_element_factory_make(
"fakesink", NULL);
g_object_set(G_OBJECT(sink), "async", FALSE, NULL);
gst_bin_add(GST_BIN(priv->confbin), sink);
gst_element_set_state(sink, GST_STATE_PLAYING);
}
stream->tee = gst_element_factory_make("tee", NULL);
gst_bin_add_many(GST_BIN(priv->confbin),
stream->src, stream->tee, NULL);
gst_element_set_state(stream->tee, GST_STATE_PLAYING);
gst_element_set_state(stream->src, GST_STATE_PLAYING);
gst_element_link_many(stream->src, stream->tee, sink, NULL);
}
sinkpad = gst_element_get_request_pad(stream->src, "sink%d");
gst_pad_link(srcpad, sinkpad);
gst_object_unref(sinkpad);
stream->connected_cb_id = purple_timeout_add(0,
(GSourceFunc)purple_media_connected_cb, stream);
}
static void
purple_media_element_added_cb(FsElementAddedNotifier *self,
GstBin *bin, GstElement *element, gpointer user_data)
{
/*
* Hack to make H264 work with Gmail video.
*/
if (!strncmp(GST_ELEMENT_NAME(element), "x264", 4)) {
g_object_set(GST_OBJECT(element), "cabac", FALSE, NULL);
}
}
#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;
FsParticipant *participant = NULL;
PurpleMediaStream *stream = NULL;
FsMediaType media_type = purple_media_to_fs_media_type(type);
FsStreamDirection type_direction =
purple_media_to_fs_stream_direction(type);
gboolean is_nice = !strcmp(transmitter, "nice");
g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
session = purple_media_get_session(media, sess_id);
if (!session) {
GError *err = NULL;
GList *codec_conf = NULL, *iter = NULL;
gchar *filename = NULL;
PurpleMediaSessionType session_type;
GstElement *src = NULL;
session = g_new0(PurpleMediaSession, 1);
session->session = fs_conference_new_session(
media->priv->conference, media_type, &err);
if (err != NULL) {
purple_media_error(media, _("Error creating session: %s"), err->message);
g_error_free(err);
g_free(session);
return FALSE;
}
filename = g_build_filename(purple_user_dir(), "fs-codec.conf", NULL);
codec_conf = fs_codec_list_from_keyfile(filename, &err);
g_free(filename);
if (err != NULL) {
if (err->code == 4)
purple_debug_info("media", "Couldn't read "
"fs-codec.conf: %s\n",
err->message);
else
purple_debug_error("media", "Error reading "
"fs-codec.conf: %s\n",
err->message);
g_error_free(err);
}
/*
* Add SPEEX if the configuration file doesn't exist or
* there isn't a speex entry.
*/
for (iter = codec_conf; iter; iter = g_list_next(iter)) {
FsCodec *codec = iter->data;
if (!g_ascii_strcasecmp(codec->encoding_name, "speex"))
break;
}
if (iter == NULL) {
codec_conf = g_list_prepend(codec_conf,
fs_codec_new(FS_CODEC_ID_ANY,
"SPEEX", FS_MEDIA_TYPE_AUDIO, 8000));
codec_conf = g_list_prepend(codec_conf,
fs_codec_new(FS_CODEC_ID_ANY,
"SPEEX", FS_MEDIA_TYPE_AUDIO, 16000));
}
fs_session_set_codec_preferences(session->session, codec_conf, NULL);
/*
* Removes a 5-7 second delay before
* receiving the src-pad-added signal.
* Only works for non-multicast FsRtpSessions.
*/
if (is_nice || !strcmp(transmitter, "rawudp"))
g_object_set(G_OBJECT(session->session),
"no-rtcp-timeout", 0, NULL);
/*
* Hack to make x264 work with Gmail video.
*/
if (is_nice && !strcmp(sess_id, "google-video")) {
FsElementAddedNotifier *notifier =
fs_element_added_notifier_new();
g_signal_connect(G_OBJECT(notifier), "element-added",
G_CALLBACK(purple_media_element_added_cb),
stream);
fs_element_added_notifier_add(notifier,
GST_BIN(media->priv->conference));
}
fs_codec_list_destroy(codec_conf);
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 (type_direction & FS_DIRECTION_SEND) {
session_type = purple_media_from_fs(media_type,
FS_DIRECTION_SEND);
src = purple_media_manager_get_element(
media->priv->manager, session_type,
media, session->id, who);
if (!GST_IS_ELEMENT(src)) {
purple_debug_error("media",
"Error creating src for session %s\n",
session->id);
purple_media_end(media, session->id, NULL);
return FALSE;
}
purple_media_set_src(media, session->id, src);
gst_element_set_state(session->src, GST_STATE_PLAYING);
purple_media_manager_create_output_window(
media->priv->manager,
session->media,
session->id, NULL);
}
}
if (!(participant = purple_media_add_participant(media, who))) {
purple_media_remove_session(media, session);
g_free(session);
return FALSE;
} else {
g_signal_emit(media, purple_media_signals[STATE_CHANGED],
0, PURPLE_MEDIA_STATE_NEW,
NULL, who);
}
stream = purple_media_get_stream(media, sess_id, who);
if (!stream) {
GError *err = NULL;
FsStream *fsstream = NULL;
const gchar *stun_ip = purple_network_get_stun_ip();
const gchar *turn_ip = purple_network_get_turn_ip();
if (stun_ip || turn_ip) {
guint new_num_params =
(stun_ip && is_nice) && turn_ip ?
num_params + 2 : num_params + 1;
guint next_param_index = num_params;
GParameter *param = g_new0(GParameter, new_num_params);
memcpy(param, params, sizeof(GParameter) * num_params);
if (stun_ip) {
purple_debug_info("media",
"setting property stun-ip on new stream: %s\n", stun_ip);
param[next_param_index].name = "stun-ip";
g_value_init(&param[next_param_index].value, G_TYPE_STRING);
g_value_set_string(&param[next_param_index].value, stun_ip);
next_param_index++;
}
if (turn_ip && is_nice) {
GValueArray *relay_info = g_value_array_new(0);
GValue value;
gint turn_port =
purple_prefs_get_int("/purple/network/turn_port");
const gchar *username =
purple_prefs_get_string("/purple/network/turn_username");
const gchar *password =
purple_prefs_get_string("/purple/network/turn_password");
GstStructure *turn_setup = gst_structure_new("relay-info",
"ip", G_TYPE_STRING, turn_ip,
"port", G_TYPE_UINT, turn_port,
"username", G_TYPE_STRING, username,
"password", G_TYPE_STRING, password,
NULL);
if (turn_setup) {
memset(&value, 0, sizeof(GValue));
g_value_init(&value, GST_TYPE_STRUCTURE);
gst_value_set_structure(&value, turn_setup);
relay_info = g_value_array_append(relay_info, &value);
gst_structure_free(turn_setup);
purple_debug_info("media",
"setting property relay-info on new stream\n");
param[next_param_index].name = "relay-info";
g_value_init(&param[next_param_index].value,
G_TYPE_VALUE_ARRAY);
g_value_set_boxed(&param[next_param_index].value,
relay_info);
g_value_array_free(relay_info);
} else {
purple_debug_error("media", "Error relay info");
g_object_unref(participant);
g_hash_table_remove(media->priv->participants, who);
purple_media_remove_session(media, session);
g_free(session);
return FALSE;
}
}
fsstream = fs_session_new_stream(session->session,
participant, initiator == TRUE ?
type_direction : (type_direction &
FS_DIRECTION_RECV), transmitter,
new_num_params, param, &err);
g_free(param);
} else {
fsstream = fs_session_new_stream(session->session,
participant, initiator == TRUE ?
type_direction : (type_direction &
FS_DIRECTION_RECV), transmitter,
num_params, params, &err);
}
if (fsstream == NULL) {
purple_debug_error("media",
"Error creating stream: %s\n",
err && err->message ?
err->message : "NULL");
if (err)
g_error_free(err);
g_object_unref(participant);
g_hash_table_remove(media->priv->participants, who);
purple_media_remove_session(media, session);
g_free(session);
return FALSE;
}
stream = purple_media_insert_stream(session, who, fsstream);
stream->initiator = initiator;
/* callback for source pad added (new stream source ready) */
g_signal_connect(G_OBJECT(fsstream),
"src-pad-added", G_CALLBACK(purple_media_src_pad_added_cb), stream);
g_signal_emit(media, purple_media_signals[STATE_CHANGED],
0, PURPLE_MEDIA_STATE_NEW,
session->id, who);
} else {
if (purple_media_to_fs_stream_direction(stream->session->type)
!= type_direction) {
/* change direction */
g_object_set(stream->stream, "direction",
type_direction, NULL);
}
}
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
GList *fscodecs;
GList *codecs;
PurpleMediaSession *session;
g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
session = purple_media_get_session(media, sess_id);
if (session == NULL)
return NULL;
g_object_get(G_OBJECT(session->session),
"codecs", &fscodecs, NULL);
codecs = purple_media_codec_list_from_fs(fscodecs);
fs_codec_list_destroy(fscodecs);
return codecs;
#else
return NULL;
#endif
}
GList *
purple_media_get_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 stream ? purple_media_candidate_list_from_fs(
stream->local_candidates) : NULL;
#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;
GError *err = NULL;
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_to_fs(remote_candidates));
if (stream->initiator == TRUE || stream->accepted == TRUE) {
fs_stream_set_remote_candidates(stream->stream,
stream->remote_candidates, &err);
if (err) {
purple_debug_error("media", "Error adding remote"
" candidates: %s\n", err->message);
g_error_free(err);
}
}
#endif
}
#if 0
/*
* These two functions aren't being used and I'd rather not lock in the API
* until they are needed. If they ever are.
*/
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_from_fs(
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_from_fs(
stream->active_remote_candidates);
#else
return NULL;
#endif
}
#endif
gboolean
purple_media_set_remote_codecs(PurpleMedia *media, const gchar *sess_id,
const gchar *participant, GList *codecs)
{
#ifdef USE_VV
PurpleMediaStream *stream;
FsStream *fsstream;
GList *fscodecs;
GError *err = NULL;
g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
stream = purple_media_get_stream(media, sess_id, participant);
if (stream == NULL)
return FALSE;
fsstream = stream->stream;
fscodecs = purple_media_codec_list_to_fs(codecs);
fs_stream_set_remote_codecs(fsstream, fscodecs, &err);
fs_codec_list_destroy(fscodecs);
if (err) {
purple_debug_error("media", "Error setting remote codecs: %s\n",
err->message);
g_error_free(err);
return FALSE;
}
return TRUE;
#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
PurpleMediaSession *session;
FsCodec *fscodec;
GError *err = NULL;
g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
session = purple_media_get_session(media, sess_id);
if (session != NULL)
return FALSE;
fscodec = purple_media_codec_to_fs(codec);
fs_session_set_send_codec(session->session, fscodec, &err);
fs_codec_destroy(fscodec);
if (err) {
purple_debug_error("media", "Error setting send codec\n");
g_error_free(err);
return FALSE;
}
return TRUE;
#else
return FALSE;
#endif
}
gboolean
purple_media_codecs_ready(PurpleMedia *media, const gchar *sess_id)
{
#ifdef USE_VV
gboolean ret;
g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
if (sess_id != NULL) {
PurpleMediaSession *session;
session = purple_media_get_session(media, sess_id);
if (session == NULL)
return FALSE;
if (session->type & (PURPLE_MEDIA_SEND_AUDIO |
PURPLE_MEDIA_SEND_VIDEO))
g_object_get(session->session,
"codecs-ready", &ret, NULL);
else
ret = TRUE;
} else {
GList *values = g_hash_table_get_values(media->priv->sessions);
for (; values; values = g_list_delete_link(values, values)) {
PurpleMediaSession *session = values->data;
if (session->type & (PURPLE_MEDIA_SEND_AUDIO |
PURPLE_MEDIA_SEND_VIDEO))
g_object_get(session->session,
"codecs-ready", &ret, NULL);
else
ret = TRUE;
if (ret == FALSE)
break;
}
if (values != NULL)
g_list_free(values);
}
return ret;
#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
GList *sessions;
g_return_if_fail(PURPLE_IS_MEDIA(media));
purple_prefs_set_int("/purple/media/audio/volume/input", level);
if (session_id == NULL)
sessions = g_hash_table_get_values(media->priv->sessions);
else
sessions = g_list_append(NULL,
purple_media_get_session(media, session_id));
for (; sessions; sessions = g_list_delete_link(sessions, sessions)) {
PurpleMediaSession *session = sessions->data;
if (session->type & PURPLE_MEDIA_SEND_AUDIO) {
gchar *name = g_strdup_printf("volume_%s",
session->id);
GstElement *volume = gst_bin_get_by_name(
GST_BIN(session->media->priv->confbin),
name);
g_free(name);
g_object_set(volume, "volume", level/10.0, NULL);
}
}
#endif
}
void purple_media_set_output_volume(PurpleMedia *media,
const gchar *session_id, const gchar *participant,
double level)
{
#ifdef USE_VV
GList *streams;
g_return_if_fail(PURPLE_IS_MEDIA(media));
purple_prefs_set_int("/purple/media/audio/volume/output", level);
streams = purple_media_get_streams(media,
session_id, participant);
for (; streams; streams = g_list_delete_link(streams, streams)) {
PurpleMediaStream *stream = streams->data;
if (stream->session->type & PURPLE_MEDIA_RECV_AUDIO
&& GST_IS_ELEMENT(stream->volume)) {
g_object_set(stream->volume, "volume", level/10.0, NULL);
}
}
#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_GSTREAMER
GstElement *
purple_media_get_tee(PurpleMedia *media,
const gchar *session_id, const gchar *participant)
{
#ifdef USE_VV
g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
if (session_id != NULL && participant == NULL) {
PurpleMediaSession *session =
purple_media_get_session(media, session_id);
return (session != NULL) ? session->tee : NULL;
} else if (session_id != NULL && participant != NULL) {
PurpleMediaStream *stream =
purple_media_get_stream(media,
session_id, participant);
return (stream != NULL) ? stream->tee : NULL;
}
g_return_val_if_reached(NULL);
#else
return NULL;
#endif
}
#endif /* USE_GSTREAMER */