# HG changeset patch # User Marcus Lundblad # Date 1231788475 0 # Node ID b04508e5cc6cad6fffac2875112f9e8e8a8c1a1f # Parent e5f9cf20c4aa36d52e680173dc1c0f4bd500185b# Parent 5275c7ef9edf77d5778aafabf1296b5697a3fcef merge of 'd43b253ca7568a3f07aa77bf397fe4351db73a90' and 'dcc53c9783aecbdde6269c4310ec4b0cf511bd9e' diff -r e5f9cf20c4aa -r b04508e5cc6c libpurple/media.c --- a/libpurple/media.c Sat Jan 10 01:32:34 2009 +0000 +++ b/libpurple/media.c Mon Jan 12 19:27:55 2009 +0000 @@ -239,7 +239,7 @@ G_SIGNAL_RUN_LAST, 0, NULL, NULL, purple_smarshal_VOID__POINTER_POINTER_OBJECT, G_TYPE_NONE, 3, G_TYPE_POINTER, - G_TYPE_POINTER, FS_TYPE_CANDIDATE); + G_TYPE_POINTER, PURPLE_TYPE_MEDIA_CANDIDATE); 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, @@ -247,7 +247,8 @@ purple_media_signals[CANDIDATE_PAIR] = g_signal_new("candidate-pair", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, purple_smarshal_VOID__BOXED_BOXED, - G_TYPE_NONE, 2, FS_TYPE_CANDIDATE, FS_TYPE_CANDIDATE); + G_TYPE_NONE, 2, PURPLE_TYPE_MEDIA_CANDIDATE, + PURPLE_TYPE_MEDIA_CANDIDATE); purple_media_signals[CODECS_READY] = g_signal_new("codecs-ready", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__STRING, @@ -413,6 +414,169 @@ } +PurpleMediaCandidate * +purple_media_candidate_new(const gchar *foundation, guint component_id, + PurpleMediaCandidateType type, + PurpleMediaNetworkProtocol proto, + const gchar *ip, guint port) +{ + PurpleMediaCandidate *candidate = g_new0(PurpleMediaCandidate, 1); + candidate->foundation = g_strdup(foundation); + candidate->component_id = component_id; + candidate->type = type; + candidate->proto = proto; + candidate->ip = g_strdup(ip); + candidate->port = port; + return candidate; +} + +static PurpleMediaCandidate * +purple_media_candidate_copy(PurpleMediaCandidate *candidate) +{ + PurpleMediaCandidate *new_candidate; + + if (candidate == NULL) + return NULL; + + new_candidate = g_new0(PurpleMediaCandidate, 1); + new_candidate->foundation = g_strdup(candidate->foundation); + new_candidate->component_id = candidate->component_id; + new_candidate->ip = g_strdup(candidate->ip); + new_candidate->port = candidate->port; + new_candidate->base_ip = g_strdup(candidate->base_ip); + new_candidate->base_port = candidate->base_port; + new_candidate->proto = candidate->proto; + new_candidate->priority = candidate->priority; + new_candidate->type = candidate->type; + new_candidate->username = g_strdup(candidate->username); + new_candidate->password = g_strdup(candidate->password); + new_candidate->ttl = candidate->ttl; + return new_candidate; +} + +static void +purple_media_candidate_free(PurpleMediaCandidate *candidate) +{ + if (candidate == NULL) + return; + + g_free((gchar*)candidate->foundation); + g_free((gchar*)candidate->ip); + g_free((gchar*)candidate->base_ip); + g_free((gchar*)candidate->username); + g_free((gchar*)candidate->password); + g_free(candidate); +} + +static FsCandidate * +purple_media_candidate_to_fs(PurpleMediaCandidate *candidate) +{ + FsCandidate *fscandidate; + + if (candidate == NULL) + return NULL; + + fscandidate = fs_candidate_new(candidate->foundation, + candidate->component_id, candidate->type, + candidate->proto, candidate->ip, candidate->port); + + fscandidate->base_ip = g_strdup(candidate->base_ip); + fscandidate->base_port = candidate->base_port; + fscandidate->priority = candidate->priority; + fscandidate->username = g_strdup(candidate->username); + fscandidate->password = g_strdup(candidate->password); + fscandidate->ttl = candidate->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); + candidate->base_ip = g_strdup(fscandidate->base_ip); + candidate->base_port = fscandidate->base_port; + candidate->priority = fscandidate->priority; + candidate->username = g_strdup(fscandidate->username); + candidate->password = g_strdup(fscandidate->password); + candidate->ttl = fscandidate->ttl; + 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; +} + +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, g_boxed_copy( + PURPLE_TYPE_MEDIA_CANDIDATE, + 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_boxed_free(PURPLE_TYPE_MEDIA_CANDIDATE, + candidates->data); + } +} + +GType +purple_media_candidate_get_type() +{ + static GType type = 0; + + if (type == 0) { + type = g_boxed_type_register_static("PurpleMediaCandidate", + (GBoxedCopyFunc)purple_media_candidate_copy, + (GBoxedFreeFunc)purple_media_candidate_free); + } + return type; +} + static FsMediaType purple_media_to_fs_media_type(PurpleMediaSessionType type) { @@ -458,6 +622,232 @@ return result; } +void +purple_media_codec_add_optional_parameter(PurpleMediaCodec *codec, + const gchar *name, const gchar *value) +{ + PurpleMediaCodecParameter *new_param; + + g_return_if_fail(name != NULL && value != NULL); + + new_param = g_new0(PurpleMediaCodecParameter, 1); + new_param->name = g_strdup(name); + new_param->value = g_strdup(value); + codec->optional_params = g_list_append( + codec->optional_params, new_param); +} + +void +purple_media_codec_remove_optional_parameter(PurpleMediaCodec *codec, + PurpleMediaCodecParameter *param) +{ + g_free(param->name); + g_free(param->value); + g_free(param); + codec->optional_params = + g_list_remove(codec->optional_params, param); +} + +PurpleMediaCodecParameter * +purple_media_codec_get_optional_parameter(PurpleMediaCodec *codec, + const gchar *name, const gchar *value) +{ + GList *iter; + + g_return_val_if_fail(codec != NULL, NULL); + g_return_val_if_fail(name != NULL, NULL); + + for (iter = codec->optional_params; iter; iter = g_list_next(iter)) { + PurpleMediaCodecParameter *param = iter->data; + if (!g_ascii_strcasecmp(param->name, name) && + (value == NULL || + !g_ascii_strcasecmp(param->value, value))) + return param; + } + + return NULL; +} + +PurpleMediaCodec * +purple_media_codec_new(int id, const char *encoding_name, + PurpleMediaSessionType media_type, guint clock_rate) +{ + PurpleMediaCodec *codec = g_new0(PurpleMediaCodec, 1); + + codec->id = id; + codec->encoding_name = g_strdup(encoding_name); + codec->media_type = media_type; + codec->clock_rate = clock_rate; + return codec; +} + +static PurpleMediaCodec * +purple_media_codec_copy(PurpleMediaCodec *codec) +{ + PurpleMediaCodec *new_codec; + GList *iter; + + if (codec == NULL) + return NULL; + + new_codec = purple_media_codec_new(codec->id, codec->encoding_name, + codec->media_type, codec->clock_rate); + new_codec->channels = codec->channels; + + for (iter = codec->optional_params; iter; iter = g_list_next(iter)) { + PurpleMediaCodecParameter *param = + (PurpleMediaCodecParameter*)iter->data; + purple_media_codec_add_optional_parameter(new_codec, + param->name, param->value); + } + + return new_codec; +} + +static void +purple_media_codec_free(PurpleMediaCodec *codec) +{ + if (codec == NULL) + return; + + g_free(codec->encoding_name); + + for (; codec->optional_params; codec->optional_params = + g_list_delete_link(codec->optional_params, + codec->optional_params)) { + purple_media_codec_remove_optional_parameter(codec, + codec->optional_params->data); + } + + g_free(codec); +} + +static FsCodec * +purple_media_codec_to_fs(const PurpleMediaCodec *codec) +{ + FsCodec *new_codec; + GList *iter; + + if (codec == NULL) + return NULL; + + new_codec = fs_codec_new(codec->id, codec->encoding_name, + purple_media_to_fs_media_type(codec->media_type), + codec->clock_rate); + new_codec->channels = codec->channels; + + for (iter = codec->optional_params; iter; iter = g_list_next(iter)) { + PurpleMediaCodecParameter *param = + (PurpleMediaCodecParameter*)iter->data; + fs_codec_add_optional_parameter(new_codec, + param->name, 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); + new_codec->channels = codec->channels; + + 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; +} + +gchar * +purple_media_codec_to_string(const PurpleMediaCodec *codec) +{ + FsCodec *fscodec = purple_media_codec_to_fs(codec); + gchar *str = fs_codec_to_string(fscodec); + fs_codec_destroy(fscodec); + return str; +} + +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; +} + +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, g_boxed_copy( + PURPLE_TYPE_MEDIA_CODEC, + 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_boxed_free(PURPLE_TYPE_MEDIA_CODEC, + codecs->data); + } +} + +GType +purple_media_codec_get_type() +{ + static GType type = 0; + + if (type == 0) { + type = g_boxed_type_register_static("PurpleMediaCodec", + (GBoxedCopyFunc)purple_media_codec_copy, + (GBoxedFreeFunc)purple_media_codec_free); + } + return type; +} + + + PurpleMediaSessionType purple_media_get_overall_type(PurpleMedia *media) { @@ -1069,8 +1459,6 @@ const gchar *audio_device = purple_prefs_get_string("/purple/media/audio/device"); double input_volume = purple_prefs_get_int("/purple/media/audio/volume/input")/10.0; - purple_debug_info("media", "purple_media_audio_init_src\n"); - *sendbin = gst_bin_new("purplesendaudiobin"); src = gst_element_factory_make("alsasrc", "asrc"); volume = gst_element_factory_make("volume", "purpleaudioinputvolume"); @@ -1099,8 +1487,6 @@ const gchar *video_device = purple_prefs_get_string( "/purple/media/video/device"); - purple_debug_info("media", "purple_media_video_init_src\n"); - *sendbin = gst_bin_new("purplesendvideobin"); src = gst_element_factory_make(video_plugin, "purplevideosource"); gst_bin_add(GST_BIN(*sendbin), src); @@ -1143,8 +1529,6 @@ double output_volume = purple_prefs_get_int( "/purple/media/audio/volume/output")/10.0; - purple_debug_info("media", "purple_media_audio_init_recv\n"); - *recvbin = gst_bin_new("pidginrecvaudiobin"); sink = gst_element_factory_make("alsasink", "asink"); g_object_set(G_OBJECT(sink), "sync", FALSE, NULL); @@ -1158,8 +1542,6 @@ ghost = gst_ghost_pad_new("ghostsink", pad); gst_element_add_pad(*recvbin, ghost); g_object_set(G_OBJECT(*recvlevel), "message", TRUE, NULL); - - purple_debug_info("media", "purple_media_audio_init_recv end\n"); } void @@ -1168,16 +1550,12 @@ GstElement *sink; GstPad *pad, *ghost; - purple_debug_info("media", "purple_media_video_init_recv\n"); - *recvbin = gst_bin_new("pidginrecvvideobin"); sink = gst_element_factory_make("autovideosink", "purplevideosink"); gst_bin_add(GST_BIN(*recvbin), sink); pad = gst_element_get_pad(sink, "sink"); ghost = gst_ghost_pad_new("ghostsink", pad); gst_element_add_pad(*recvbin, ghost); - - purple_debug_info("media", "purple_media_video_init_recv end\n"); } static void @@ -1187,7 +1565,7 @@ { gchar *name; FsParticipant *participant; - FsCandidate *candidate; + PurpleMediaCandidate *candidate; 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); @@ -1195,10 +1573,10 @@ purple_media_insert_local_candidate(session, name, fs_candidate_copy(local_candidate)); - candidate = 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); - fs_candidate_destroy(candidate); + purple_media_candidate_free(candidate); g_free(name); } @@ -1234,8 +1612,10 @@ { gchar *name; FsParticipant *participant; - FsCandidate *local = fs_candidate_copy(native_candidate); - FsCandidate *remote = fs_candidate_copy(remote_candidate); + PurpleMediaCandidate *local = + purple_media_candidate_from_fs(native_candidate); + PurpleMediaCandidate *remote = + purple_media_candidate_from_fs(remote_candidate); PurpleMediaStream *stream; g_object_get(fsstream, "participant", &participant, NULL); @@ -1251,8 +1631,18 @@ g_signal_emit(session->media, purple_media_signals[CANDIDATE_PAIR], 0, local, remote); - fs_candidate_destroy(local); - fs_candidate_destroy(remote); + purple_media_candidate_free(local); + purple_media_candidate_free(remote); +} + +static gboolean +purple_media_connected_cb(PurpleMediaStream *stream) +{ + g_signal_emit(stream->session->media, + purple_media_signals[STATE_CHANGED], + 0, PURPLE_MEDIA_STATE_CHANGED_CONNECTED, + stream->session->id, stream->participant); + return FALSE; } static void @@ -1268,13 +1658,10 @@ gst_bin_add(GST_BIN(purple_media_get_pipeline(stream->session->media)), stream->sink); sinkpad = gst_element_get_static_pad(stream->sink, "ghostsink"); - purple_debug_info("media", "connecting new src pad: %s\n", - gst_pad_link(srcpad, sinkpad) == GST_PAD_LINK_OK ? "success" : "failure"); + gst_pad_link(srcpad, sinkpad); gst_element_set_state(stream->sink, GST_STATE_PLAYING); - g_signal_emit(stream->session->media, purple_media_signals[STATE_CHANGED], - 0, PURPLE_MEDIA_STATE_CHANGED_CONNECTED, - stream->session->id, stream->participant); + g_timeout_add(0, (GSourceFunc)purple_media_connected_cb, stream); } static gchar * @@ -1476,9 +1863,12 @@ GList * purple_media_get_codecs(PurpleMedia *media, const gchar *sess_id) { + GList *fscodecs; GList *codecs; g_object_get(G_OBJECT(purple_media_get_session(media, sess_id)->session), - "codecs", &codecs, NULL); + "codecs", &fscodecs, NULL); + codecs = purple_media_codec_list_from_fs(fscodecs); + fs_codec_list_destroy(fscodecs); return codecs; } @@ -1486,7 +1876,7 @@ purple_media_get_local_candidates(PurpleMedia *media, const gchar *sess_id, const gchar *name) { PurpleMediaStream *stream = purple_media_get_stream(media, sess_id, name); - return fs_candidate_list_copy(stream->local_candidates); + return purple_media_candidate_list_from_fs(stream->local_candidates); } void @@ -1495,32 +1885,36 @@ { PurpleMediaStream *stream = purple_media_get_stream(media, sess_id, name); stream->remote_candidates = g_list_concat(stream->remote_candidates, - fs_candidate_list_copy(remote_candidates)); + purple_media_candidate_list_to_fs(remote_candidates)); if (stream->session->accepted == TRUE) { purple_media_set_remote_candidates(stream); } } -FsCandidate * +PurpleMediaCandidate * purple_media_get_local_candidate(PurpleMedia *media, const gchar *sess_id, const gchar *name) { - return purple_media_get_stream(media, sess_id, name)->local_candidate; + return purple_media_candidate_from_fs(purple_media_get_stream( + media, sess_id, name)->local_candidate); } -FsCandidate * +PurpleMediaCandidate * purple_media_get_remote_candidate(PurpleMedia *media, const gchar *sess_id, const gchar *name) { - return purple_media_get_stream(media, sess_id, name)->remote_candidate; + return purple_media_candidate_from_fs(purple_media_get_stream( + media, sess_id, name)->remote_candidate); } gboolean purple_media_set_remote_codecs(PurpleMedia *media, const gchar *sess_id, const gchar *name, GList *codecs) { FsStream *stream = purple_media_get_stream(media, sess_id, name)->stream; + GList *fscodecs = purple_media_codec_list_to_fs(codecs); GError *err = NULL; - fs_stream_set_remote_codecs(stream, codecs, &err); + fs_stream_set_remote_codecs(stream, fscodecs, &err); + fs_codec_list_destroy(fscodecs); if (err) { purple_debug_error("media", "Error setting remote codecs: %s\n", @@ -1547,12 +1941,14 @@ } gboolean -purple_media_set_send_codec(PurpleMedia *media, const gchar *sess_id, FsCodec *codec) +purple_media_set_send_codec(PurpleMedia *media, const gchar *sess_id, PurpleMediaCodec *codec) { PurpleMediaSession *session = purple_media_get_session(media, sess_id); + FsCodec *fscodec = purple_media_codec_to_fs(codec); GError *err = NULL; - fs_session_set_send_codec(session->session, codec, &err); + fs_session_set_send_codec(session->session, fscodec, &err); + fs_codec_destroy(fscodec); if (err) { purple_debug_error("media", "Error setting send codec\n"); diff -r e5f9cf20c4aa -r b04508e5cc6c libpurple/media.h --- a/libpurple/media.h Sat Jan 10 01:32:34 2009 +0000 +++ b/libpurple/media.h Mon Jan 12 19:27:55 2009 +0000 @@ -30,13 +30,14 @@ #ifdef USE_VV #include -#include #include #include G_BEGIN_DECLS #define PURPLE_TYPE_MEDIA (purple_media_get_type()) +#define PURPLE_TYPE_MEDIA_CANDIDATE (purple_media_candidate_get_type()) +#define PURPLE_TYPE_MEDIA_CODEC (purple_media_codec_get_type()) #define PURPLE_MEDIA(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_MEDIA, PurpleMedia)) #define PURPLE_MEDIA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_MEDIA, PurpleMediaClass)) #define PURPLE_IS_MEDIA(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_MEDIA)) @@ -51,6 +52,12 @@ typedef struct _PurpleMediaClass PurpleMediaClass; /** @copydoc _PurpleMediaPrivate */ typedef struct _PurpleMediaPrivate PurpleMediaPrivate; +/** @copydoc _PurpleMediaCandidate */ +typedef struct _PurpleMediaCandidate PurpleMediaCandidate; +/** @copydoc _PurpleMediaCodec */ +typedef struct _PurpleMediaCodec PurpleMediaCodec; +/** @copydoc _PurpleMediaCodecParameter */ +typedef struct _PurpleMediaCodecParameter PurpleMediaCodecParameter; #else @@ -76,6 +83,25 @@ PURPLE_MEDIA_STATE_CHANGED_END, } PurpleMediaStateChangedType; +typedef enum { + PURPLE_MEDIA_CANDIDATE_TYPE_HOST, + PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX, + PURPLE_MEDIA_CANDIDATE_TYPE_PRFLX, + PURPLE_MEDIA_CANDIDATE_TYPE_RELAY, + PURPLE_MEDIA_CANDIDATE_TYPE_MULTICAST, +} PurpleMediaCandidateType; + +typedef enum { + PURPLE_MEDIA_COMPONENT_NONE = 0, + PURPLE_MEDIA_COMPONENT_RTP = 1, + PURPLE_MEDIA_COMPONENT_RTCP = 2, +} PurpleMediaComponentType; + +typedef enum { + PURPLE_MEDIA_NETWORK_PROTOCOL_UDP, + PURPLE_MEDIA_NETWORK_PROTOCOL_TCP, +} PurpleMediaNetworkProtocol; + #ifdef USE_VV /** The media class */ @@ -91,6 +117,38 @@ PurpleMediaPrivate *priv; /**< The private data of this object. */ }; +struct _PurpleMediaCandidate +{ + const gchar *foundation; + guint component_id; + const gchar *ip; + guint16 port; + const gchar *base_ip; + guint16 base_port; + PurpleMediaNetworkProtocol proto; + guint32 priority; + PurpleMediaCandidateType type; + const gchar *username; + const gchar *password; + guint ttl; +}; + +struct _PurpleMediaCodecParameter +{ + gchar *name; + gchar *value; +}; + +struct _PurpleMediaCodec +{ + gint id; + char *encoding_name; + PurpleMediaSessionType media_type; + guint clock_rate; + guint channels; + GList *optional_params; +}; + #ifdef __cplusplus extern "C" { #endif @@ -110,6 +168,124 @@ GType purple_media_state_changed_get_type(void); /** + * Gets the type of the media candidate structure. + * + * @return The media canditate's GType + */ +GType purple_media_candidate_get_type(void); + +/** + * Creates a PurpleMediaCandidate instance. + * + * @param foundation The foundation of the candidate. + * @param component_id The component this candidate is for. + * @param type The type of candidate. + * @param proto The protocol this component is for. + * @param ip The IP address of this component. + * @param port The network port. + * + * @return The newly created PurpleMediaCandidate instance. + */ +PurpleMediaCandidate *purple_media_candidate_new( + const gchar *foundation, guint component_id, + PurpleMediaCandidateType type, + PurpleMediaNetworkProtocol proto, + const gchar *ip, guint port); + +/** + * Copies a GList of PurpleMediaCandidate and its contents. + * + * @param candidates The list of candidates to be copied. + * + * @return The copy of the GList. + */ +GList *purple_media_candidate_list_copy(GList *candidates); + +/** + * Frees a GList of PurpleMediaCandidate and its contents. + * + * @param candidates The list of candidates to be freed. + */ +void purple_media_candidate_list_free(GList *candidates); + +/** + * Gets the type of the media codec structure. + * + * @return The media codec's GType + */ +GType purple_media_codec_get_type(void); + +/** + * Creates a new PurpleMediaCodec instance. + * + * @param id Codec identifier. + * @param encoding_name Name of the media type this encodes. + * @param media_type PurpleMediaSessionType of this codec. + * @param clock_rate The clock rate this codec encodes at, if applicable. + * + * @return The newly created PurpleMediaCodec. + */ +PurpleMediaCodec *purple_media_codec_new(int id, const char *encoding_name, + PurpleMediaSessionType media_type, guint clock_rate); + +/** + * Creates a string representation of the codec. + * + * @param codec The codec to create the string of. + * + * @return The new string representation. + */ +gchar *purple_media_codec_to_string(const PurpleMediaCodec *codec); + +/** + * Adds an optional parameter to the codec. + * + * @param codec The codec to add the parameter to. + * @param name The name of the parameter to add. + * @param value The value of the parameter to add. + */ +void purple_media_codec_add_optional_parameter(PurpleMediaCodec *codec, + const gchar *name, const gchar *value); + +/** + * Removes an optional parameter from the codec. + * + * @param codec The codec to remove the parameter from. + * @param param A pointer to the parameter to remove. + */ +void purple_media_codec_remove_optional_parameter(PurpleMediaCodec *codec, + PurpleMediaCodecParameter *param); + +/** + * Gets an optional parameter based on the values given. + * + * @param codec The codec to find the parameter in. + * @param name The name of the parameter to search for. + * @param value The value to search for or NULL. + * + * @return The value found or NULL. + */ +PurpleMediaCodecParameter *purple_media_codec_get_optional_parameter( + PurpleMediaCodec *codec, const gchar *name, + const gchar *value); + +/** + * Copies a GList of PurpleMediaCodec and its contents. + * + * @param codecs The list of codecs to be copied. + * + * @return The copy of the GList. + */ +GList *purple_media_codec_list_copy(GList *codecs); + +/** + * Frees a GList of PurpleMediaCodec and its contents. + * + * @param codecs The list of codecs to be freed. + */ +void purple_media_codec_list_free(GList *codecs); + +/** * Combines all the separate session types into a single PurpleMediaSessionType. * * @param media The media session to retrieve session types from. @@ -388,7 +564,8 @@ * * @return The active candidate retrieved. */ -FsCandidate *purple_media_get_local_candidate(PurpleMedia *media, const gchar *sess_id, const gchar *name); +PurpleMediaCandidate *purple_media_get_local_candidate(PurpleMedia *media, + const gchar *sess_id, const gchar *name); /** * Gets the active remote candidate for the stream. @@ -399,7 +576,8 @@ * * @return The remote candidate retrieved. */ -FsCandidate *purple_media_get_remote_candidate(PurpleMedia *media, const gchar *sess_id, const gchar *name); +PurpleMediaCandidate *purple_media_get_remote_candidate(PurpleMedia *media, + const gchar *sess_id, const gchar *name); /** * Gets remote candidates from the stream. @@ -432,7 +610,7 @@ * * @return @c TRUE The codec was successfully changed, or @c FALSE otherwise. */ -gboolean purple_media_set_send_codec(PurpleMedia *media, const gchar *sess_id, FsCodec *codec); +gboolean purple_media_set_send_codec(PurpleMedia *media, const gchar *sess_id, PurpleMediaCodec *codec); /** * Gets whether a session's codecs are ready to be used. diff -r e5f9cf20c4aa -r b04508e5cc6c libpurple/protocols/jabber/google.c --- a/libpurple/protocols/jabber/google.c Sat Jan 10 01:32:34 2009 +0000 +++ b/libpurple/protocols/jabber/google.c Mon Jan 12 19:27:55 2009 +0000 @@ -111,7 +111,7 @@ xmlnode_set_namespace(desc, "http://www.google.com/session/phone"); for (;codecs; codecs = codecs->next) { - FsCodec *codec = (FsCodec*)codecs->data; + PurpleMediaCodec *codec = (PurpleMediaCodec*)codecs->data; char id[8], clockrate[10]; payload = xmlnode_new_child(desc, "payload-type"); g_snprintf(id, sizeof(id), "%d", codec->id); @@ -121,7 +121,7 @@ xmlnode_set_attrib(payload, "clockrate", clockrate); } - fs_codec_list_destroy(codecs); + purple_media_codec_list_free(codecs); jabber_iq_send(iq); } @@ -161,7 +161,7 @@ JabberIq *iq = jabber_iq_new(session->js, JABBER_IQ_SET); GList *candidates = purple_media_get_local_candidates(session->media, "google-voice", session->remote_jid); - FsCandidate *transport; + PurpleMediaCandidate *transport; xmlnode *sess; xmlnode *candidate; sess = google_session_create_xmlnode(session, "candidates"); @@ -171,7 +171,7 @@ for (;candidates;candidates = candidates->next) { char port[8]; char pref[8]; - transport = (FsCandidate*)(candidates->data); + transport = (PurpleMediaCandidate*)(candidates->data); if (!strcmp(transport->ip, "127.0.0.1")) continue; @@ -194,10 +194,14 @@ transport->password != NULL ? transport->password : ""); xmlnode_set_attrib(candidate, "preference", pref); - xmlnode_set_attrib(candidate, "protocol", transport->proto == FS_NETWORK_PROTOCOL_UDP ? "udp" : "tcp"); - xmlnode_set_attrib(candidate, "type", transport->type == FS_CANDIDATE_TYPE_HOST ? "local" : - transport->type == FS_CANDIDATE_TYPE_SRFLX ? "stun" : - transport->type == FS_CANDIDATE_TYPE_RELAY ? "relay" : NULL); + xmlnode_set_attrib(candidate, "protocol", transport->proto == + PURPLE_MEDIA_NETWORK_PROTOCOL_UDP ? "udp" : "tcp"); + xmlnode_set_attrib(candidate, "type", transport->type == + PURPLE_MEDIA_CANDIDATE_TYPE_HOST ? "local" : + transport->type == + PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX ? "stun" : + transport->type == + PURPLE_MEDIA_CANDIDATE_TYPE_RELAY ? "relay" : NULL); xmlnode_set_attrib(candidate, "generation", "0"); xmlnode_set_attrib(candidate, "network", "0"); xmlnode_insert_child(sess, candidate); @@ -230,7 +234,7 @@ codecs = purple_media_get_codecs(media, "google-voice"); for (iter = codecs; iter; iter = g_list_next(iter)) { - FsCodec *codec = (FsCodec*)iter->data; + PurpleMediaCodec *codec = (PurpleMediaCodec*)iter->data; gchar *id = g_strdup_printf("%d", codec->id); gchar *clock_rate = g_strdup_printf("%d", codec->clock_rate); payload = xmlnode_new_child(desc, "payload-type"); @@ -240,7 +244,7 @@ g_free(clock_rate); g_free(id); } - fs_codec_list_destroy(codecs); + purple_media_codec_list_free(codecs); jabber_iq_send(iq); @@ -329,7 +333,7 @@ JabberIq *result; GList *codecs = NULL; xmlnode *desc_element, *codec_element; - FsCodec *codec; + PurpleMediaCodec *codec; const char *id, *encoding_name, *clock_rate; GParameter param; @@ -364,7 +368,7 @@ id = xmlnode_get_attrib(codec_element, "id"); clock_rate = xmlnode_get_attrib(codec_element, "clockrate"); - codec = fs_codec_new(atoi(id), encoding_name, FS_MEDIA_TYPE_AUDIO, + codec = purple_media_codec_new(atoi(id), encoding_name, PURPLE_MEDIA_AUDIO, clock_rate ? atoi(clock_rate) : 0); codecs = g_list_append(codecs, codec); } @@ -381,7 +385,7 @@ G_CALLBACK(google_session_candidates_prepared), session); purple_media_ready(session->media); - fs_codec_list_destroy(codecs); + purple_media_codec_list_free(codecs); result = jabber_iq_new(js, JABBER_IQ_RESULT); jabber_iq_set_id(result, xmlnode_get_attrib(packet, "id")); @@ -399,17 +403,21 @@ char n[4]; for (cand = xmlnode_get_child(sess, "candidate"); cand; cand = xmlnode_get_next_twin(cand)) { - FsCandidate *info; + PurpleMediaCandidate *info; g_snprintf(n, sizeof(n), "S%d", name++); - info = fs_candidate_new(n, FS_COMPONENT_RTP, !strcmp(xmlnode_get_attrib(cand, "type"), "local") ? - FS_CANDIDATE_TYPE_HOST : + info = purple_media_candidate_new(n, PURPLE_MEDIA_COMPONENT_RTP, + !strcmp(xmlnode_get_attrib(cand, "type"), "local") ? + PURPLE_MEDIA_CANDIDATE_TYPE_HOST : !strcmp(xmlnode_get_attrib(cand, "type"), "stun") ? - FS_CANDIDATE_TYPE_PRFLX : + PURPLE_MEDIA_CANDIDATE_TYPE_PRFLX : !strcmp(xmlnode_get_attrib(cand, "type"), "relay") ? - FS_CANDIDATE_TYPE_RELAY : FS_CANDIDATE_TYPE_HOST, + PURPLE_MEDIA_CANDIDATE_TYPE_RELAY : + PURPLE_MEDIA_CANDIDATE_TYPE_HOST, !strcmp(xmlnode_get_attrib(cand, "protocol"),"udp") ? - FS_NETWORK_PROTOCOL_UDP : FS_NETWORK_PROTOCOL_TCP, - xmlnode_get_attrib(cand, "address"), atoi(xmlnode_get_attrib(cand, "port"))); + PURPLE_MEDIA_NETWORK_PROTOCOL_UDP : + PURPLE_MEDIA_NETWORK_PROTOCOL_TCP, + xmlnode_get_attrib(cand, "address"), + atoi(xmlnode_get_attrib(cand, "port"))); info->username = g_strdup(xmlnode_get_attrib(cand, "username")); info->password = g_strdup(xmlnode_get_attrib(cand, "password")); @@ -418,7 +426,7 @@ } purple_media_add_remote_candidates(session->media, "google-voice", session->remote_jid, list); - fs_candidate_list_destroy(list); + purple_media_candidate_list_free(list); result = jabber_iq_new(js, JABBER_IQ_RESULT); jabber_iq_set_id(result, xmlnode_get_attrib(packet, "id")); @@ -441,9 +449,9 @@ const gchar *clock_rate = xmlnode_get_attrib(codec_element, "clockrate"); - FsCodec *codec = fs_codec_new(atoi(id), encoding_name, - FS_MEDIA_TYPE_AUDIO, clock_rate ? - atoi(clock_rate) : 0); + PurpleMediaCodec *codec = purple_media_codec_new(atoi(id), + encoding_name, PURPLE_MEDIA_AUDIO, + clock_rate ? atoi(clock_rate) : 0); codecs = g_list_append(codecs, codec); } diff -r e5f9cf20c4aa -r b04508e5cc6c libpurple/protocols/jabber/jingle/rtp.c --- a/libpurple/protocols/jabber/jingle/rtp.c Sat Jan 10 01:32:34 2009 +0000 +++ b/libpurple/protocols/jabber/jingle/rtp.c Mon Jan 12 19:27:55 2009 +0000 @@ -193,7 +193,7 @@ JingleTransport *transport = jingle_transport_create(JINGLE_TRANSPORT_RAWUDP); JingleRawUdpCandidate *rawudp_candidate; for (; candidates; candidates = g_list_next(candidates)) { - FsCandidate *candidate = candidates->data; + PurpleMediaCandidate *candidate = candidates->data; id = jabber_get_next_id(jingle_session_get_js(session)); rawudp_candidate = jingle_rawudp_candidate_new(id, generation, candidate->component_id, @@ -206,14 +206,14 @@ JingleTransport *transport = jingle_transport_create(JINGLE_TRANSPORT_ICEUDP); JingleIceUdpCandidate *iceudp_candidate; for (; candidates; candidates = g_list_next(candidates)) { - FsCandidate *candidate = candidates->data; + PurpleMediaCandidate *candidate = candidates->data; iceudp_candidate = jingle_iceudp_candidate_new(candidate->component_id, candidate->foundation, generation, candidate->ip, 0, candidate->port, candidate->priority, "udp", - candidate->type == FS_CANDIDATE_TYPE_HOST ? "host" : - candidate->type == FS_CANDIDATE_TYPE_SRFLX ? "srflx" : - candidate->type == FS_CANDIDATE_TYPE_PRFLX ? "prflx" : - candidate->type == FS_CANDIDATE_TYPE_RELAY ? "relay" : "", + candidate->type == PURPLE_MEDIA_CANDIDATE_TYPE_HOST ? "host" : + candidate->type == PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX ? "srflx" : + candidate->type == PURPLE_MEDIA_CANDIDATE_TYPE_PRFLX ? "prflx" : + candidate->type == PURPLE_MEDIA_CANDIDATE_TYPE_RELAY ? "relay" : "", candidate->username, candidate->password); jingle_iceudp_add_local_candidate(JINGLE_ICEUDP(transport), iceudp_candidate); } @@ -233,8 +233,10 @@ for (; candidates; candidates = g_list_delete_link(candidates, candidates)) { JingleRawUdpCandidate *candidate = candidates->data; - ret = g_list_append(ret, fs_candidate_new("", candidate->component, - FS_CANDIDATE_TYPE_SRFLX, FS_NETWORK_PROTOCOL_UDP, + ret = g_list_append(ret, purple_media_candidate_new( + "", candidate->component, + PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX, + PURPLE_MEDIA_NETWORK_PROTOCOL_UDP, candidate->ip, candidate->port)); } @@ -244,17 +246,22 @@ for (; candidates; candidates = g_list_delete_link(candidates, candidates)) { JingleIceUdpCandidate *candidate = candidates->data; - FsCandidate *fscandidate = fs_candidate_new( + PurpleMediaCandidate *new_candidate = purple_media_candidate_new( candidate->foundation, candidate->component, - !strcmp(candidate->type, "host") ? FS_CANDIDATE_TYPE_HOST : - !strcmp(candidate->type, "srflx") ? FS_CANDIDATE_TYPE_SRFLX : - !strcmp(candidate->type, "prflx") ? FS_CANDIDATE_TYPE_PRFLX : - !strcmp(candidate->type, "relay") ? FS_CANDIDATE_TYPE_RELAY : 0, - FS_NETWORK_PROTOCOL_UDP, candidate->ip, candidate->port); - fscandidate->username = g_strdup(candidate->username); - fscandidate->password = g_strdup(candidate->password); - fscandidate->priority = candidate->priority; - ret = g_list_append(ret, fscandidate); + !strcmp(candidate->type, "host") ? + PURPLE_MEDIA_CANDIDATE_TYPE_HOST : + !strcmp(candidate->type, "srflx") ? + PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX : + !strcmp(candidate->type, "prflx") ? + PURPLE_MEDIA_CANDIDATE_TYPE_PRFLX : + !strcmp(candidate->type, "relay") ? + PURPLE_MEDIA_CANDIDATE_TYPE_RELAY : 0, + PURPLE_MEDIA_NETWORK_PROTOCOL_UDP, + candidate->ip, candidate->port); + new_candidate->username = g_strdup(candidate->username); + new_candidate->password = g_strdup(candidate->password); + new_candidate->priority = candidate->priority; + ret = g_list_append(ret, new_candidate); } return ret; @@ -264,7 +271,7 @@ } static void -jingle_rtp_new_candidate_cb(PurpleMedia *media, gchar *sid, gchar *name, FsCandidate *candidate, JingleSession *session) +jingle_rtp_new_candidate_cb(PurpleMedia *media, gchar *sid, gchar *name, PurpleMediaCandidate *candidate, JingleSession *session) { purple_debug_info("jingle-rtp", "jingle_rtp_new_candidate_cb\n"); } @@ -427,10 +434,11 @@ GList *codecs = NULL; xmlnode *codec_element = NULL; const char *encoding_name,*id, *clock_rate; - FsCodec *codec; + PurpleMediaCodec *codec; const gchar *media = xmlnode_get_attrib(description, "media"); - FsMediaType type = !strcmp(media, "video") ? FS_MEDIA_TYPE_VIDEO : - !strcmp(media, "audio") ? FS_MEDIA_TYPE_AUDIO : 0; + PurpleMediaSessionType type = + !strcmp(media, "video") ? PURPLE_MEDIA_VIDEO : + !strcmp(media, "audio") ? PURPLE_MEDIA_AUDIO : 0; for (codec_element = xmlnode_get_child(description, "payload-type") ; codec_element ; @@ -442,18 +450,18 @@ id = xmlnode_get_attrib(codec_element, "id"); clock_rate = xmlnode_get_attrib(codec_element, "clockrate"); - codec = fs_codec_new(atoi(id), encoding_name, + codec = purple_media_codec_new(atoi(id), encoding_name, type, clock_rate ? atoi(clock_rate) : 0); for (param = xmlnode_get_child(codec_element, "parameter"); param; param = xmlnode_get_next_twin(param)) { - fs_codec_add_optional_parameter(codec, + purple_media_codec_add_optional_parameter(codec, xmlnode_get_attrib(param, "name"), xmlnode_get_attrib(param, "value")); } - codec_str = fs_codec_to_string(codec); + codec_str = purple_media_codec_to_string(codec); purple_debug_info("jingle-rtp", "received codec: %s\n", codec_str); g_free(codec_str); @@ -477,7 +485,7 @@ jingle_rtp_add_payloads(xmlnode *description, GList *codecs) { for (; codecs ; codecs = codecs->next) { - FsCodec *codec = (FsCodec*)codecs->data; + PurpleMediaCodec *codec = (PurpleMediaCodec*)codecs->data; GList *iter = codec->optional_params; char id[8], clockrate[10], channels[10]; gchar *codec_str; @@ -493,13 +501,13 @@ xmlnode_set_attrib(payload, "channels", channels); for (; iter; iter = g_list_next(iter)) { - FsCodecParameter *fsparam = iter->data; + PurpleMediaCodecParameter *mparam = iter->data; xmlnode *param = xmlnode_new_child(payload, "parameter"); - xmlnode_set_attrib(param, "name", fsparam->name); - xmlnode_set_attrib(param, "value", fsparam->value); + xmlnode_set_attrib(param, "name", mparam->name); + xmlnode_set_attrib(param, "value", mparam->value); } - codec_str = fs_codec_to_string(codec); + codec_str = purple_media_codec_to_string(codec); purple_debug_info("jingle", "adding codec: %s\n", codec_str); g_free(codec_str); } diff -r e5f9cf20c4aa -r b04508e5cc6c pidgin/gtkmedia.c --- a/pidgin/gtkmedia.c Sat Jan 10 01:32:34 2009 +0000 +++ b/pidgin/gtkmedia.c Mon Jan 12 19:27:55 2009 +0000 @@ -337,7 +337,6 @@ return TRUE; name = gst_object_get_name(GST_MESSAGE_SRC (message)); - purple_debug_info("gtkmedia", "prepare-xwindow-id object name: %s\n", name); /* The XOverlay's name is the sink's name with a suffix */ if (!strncmp(name, "purplevideosink", strlen("purplevideosink"))) @@ -350,10 +349,18 @@ return TRUE; } +static gboolean +realize_cb_cb(GstElement *element) +{ + gst_element_set_locked_state(element, FALSE); + gst_element_set_state(element, GST_STATE_PLAYING); + return FALSE; +} + static void realize_cb(GtkWidget *widget, GstElement *element) { - gst_element_set_state(element, GST_STATE_PLAYING); + g_timeout_add(0, (GSourceFunc)realize_cb_cb, element); } static void @@ -408,6 +415,7 @@ } else if (type & PURPLE_MEDIA_VIDEO) { if (!videosendbin && (type & PURPLE_MEDIA_SEND_VIDEO)) { purple_media_video_init_src(&videosendbin); + gst_element_set_locked_state(videosendbin, TRUE); purple_media_set_src(media, sessions->data, videosendbin); } if (!videorecvbool && (type & PURPLE_MEDIA_RECV_VIDEO)) {