pidgin/ljfisher-ssl-client-auth
Clone
Summary
Browse
Changes
Graph
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 */