Sat, 29 Dec 2007 06:34:59 +0000
propagate from branch 'im.pidgin.pidgin' (head 5157ec7a2b6f7025fc0f6ed1f1093a725cfcf6f3)
to branch 'im.pidgin.pidgin.vv' (head defa6a4f45cc62c068c5225768278fcf586ac32c)
| 19886 | 1 | /** |
| 2 | * @file media.c Account API | |
| 3 | * @ingroup core | |
| 4 | * | |
| 5 | * Pidgin | |
| 6 | * | |
| 7 | * Pidgin is the legal property of its developers, whose names are too numerous | |
| 8 | * to list here. Please refer to the COPYRIGHT file distributed with this | |
| 9 | * source distribution. | |
| 10 | * | |
| 11 | * This program is free software; you can redistribute it and/or modify | |
| 12 | * it under the terms of the GNU General Public License as published by | |
| 13 | * the Free Software Foundation; either version 2 of the License, or | |
| 14 | * (at your option) any later version. | |
| 15 | * | |
| 16 | * This program is distributed in the hope that it will be useful, | |
| 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 19 | * GNU General Public License for more details. | |
| 20 | * | |
| 21 | * You should have received a copy of the GNU General Public License | |
| 22 | * along with this program; if not, write to the Free Software | |
| 23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| 24 | */ | |
| 25 | ||
| 26 | #include <string.h> | |
| 27 | #include "internal.h" | |
| 28 | #include "connection.h" | |
| 29 | #include "media.h" | |
| 30 | ||
| 31 | #include "gtkmedia.h" | |
| 32 | ||
| 33 | #ifdef USE_FARSIGHT | |
| 34 | ||
| 35 | #include <farsight/farsight.h> | |
| 36 | ||
| 37 | struct _PidginMediaPrivate | |
| 38 | { | |
| 39 | PurpleMedia *media; | |
| 40 | GstElement *send_level; | |
| 41 | GstElement *recv_level; | |
| 42 | ||
| 43 | GtkWidget *accept; | |
| 44 | GtkWidget *reject; | |
| 45 | GtkWidget *hangup; | |
| 46 | ||
| 47 | GtkWidget *send_progress; | |
| 48 | GtkWidget *recv_progress; | |
| 49 | }; | |
| 50 | ||
| 51 | #define PIDGIN_MEDIA_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), PIDGIN_TYPE_MEDIA, PidginMediaPrivate)) | |
| 52 | ||
| 53 | static void pidgin_media_class_init (PidginMediaClass *klass); | |
| 54 | static void pidgin_media_init (PidginMedia *media); | |
| 55 | static void pidgin_media_finalize (GObject *object); | |
| 56 | static void pidgin_media_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); | |
| 57 | static void pidgin_media_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); | |
| 58 | ||
| 59 | static GtkHBoxClass *parent_class = NULL; | |
| 60 | ||
| 61 | ||
| 62 | ||
| 63 | enum { | |
| 64 | MESSAGE, | |
| 65 | LAST_SIGNAL | |
| 66 | }; | |
| 67 | static guint pidgin_media_signals[LAST_SIGNAL] = {0}; | |
| 68 | ||
| 69 | enum { | |
| 70 | PROP_0, | |
| 71 | PROP_MEDIA, | |
| 72 | PROP_SEND_LEVEL, | |
| 73 | PROP_RECV_LEVEL | |
| 74 | }; | |
| 75 | ||
| 76 | GType | |
| 77 | pidgin_media_get_type() | |
| 78 | { | |
| 79 | static GType type = 0; | |
| 80 | ||
| 81 | if (type == 0) { | |
| 82 | static const GTypeInfo info = { | |
| 83 | sizeof(PidginMediaClass), | |
| 84 | NULL, | |
| 85 | NULL, | |
| 86 | (GClassInitFunc) pidgin_media_class_init, | |
| 87 | NULL, | |
| 88 | NULL, | |
| 89 | sizeof(PidginMedia), | |
| 90 | 0, | |
| 91 | (GInstanceInitFunc) pidgin_media_init | |
| 92 | }; | |
| 93 | type = g_type_register_static(GTK_TYPE_HBOX, "PidginMedia", &info, 0); | |
| 94 | } | |
| 95 | return type; | |
| 96 | } | |
| 97 | ||
| 98 | ||
| 99 | static void | |
| 100 | pidgin_media_class_init (PidginMediaClass *klass) | |
| 101 | { | |
| 102 | GObjectClass *gobject_class = (GObjectClass*)klass; | |
| 103 | GtkContainerClass *container_class = (GtkContainerClass*)klass; | |
| 104 | parent_class = g_type_class_peek_parent(klass); | |
| 105 | ||
| 106 | gobject_class->finalize = pidgin_media_finalize; | |
| 107 | gobject_class->set_property = pidgin_media_set_property; | |
| 108 | gobject_class->get_property = pidgin_media_get_property; | |
| 109 | ||
| 110 | g_object_class_install_property(gobject_class, PROP_MEDIA, | |
| 111 | g_param_spec_object("media", | |
| 112 | "PurpleMedia", | |
| 113 | "The PurpleMedia associated with this media.", | |
| 114 | PURPLE_TYPE_MEDIA, | |
| 115 | G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); | |
| 116 | g_object_class_install_property(gobject_class, PROP_SEND_LEVEL, | |
| 117 | g_param_spec_object("send-level", | |
| 118 | "Send level", | |
| 119 | "The GstElement of this media's send 'level'", | |
| 120 | GST_TYPE_ELEMENT, | |
| 121 | G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); | |
| 122 | g_object_class_install_property(gobject_class, PROP_RECV_LEVEL, | |
| 123 | g_param_spec_object("recv-level", | |
| 124 | "Receive level", | |
| 125 | "The GstElement of this media's recv 'level'", | |
| 126 | GST_TYPE_ELEMENT, | |
| 127 | G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); | |
| 128 | ||
| 129 | pidgin_media_signals[MESSAGE] = g_signal_new("message", G_TYPE_FROM_CLASS(klass), | |
| 130 | G_SIGNAL_RUN_LAST, 0, NULL, NULL, | |
| 131 | g_cclosure_marshal_VOID__STRING, | |
| 132 | G_TYPE_NONE, 1, G_TYPE_STRING); | |
| 133 | ||
| 134 | g_type_class_add_private(klass, sizeof(PidginMediaPrivate)); | |
| 135 | } | |
| 136 | ||
| 137 | ||
| 138 | static void | |
| 139 | pidgin_media_init (PidginMedia *media) | |
| 140 | { | |
| 141 | media->priv = PIDGIN_MEDIA_GET_PRIVATE(media); | |
| 142 | media->priv->hangup = gtk_button_new_with_label("Hangup"); | |
| 143 | media->priv->accept = gtk_button_new_with_label("Accept"); | |
| 144 | media->priv->reject = gtk_button_new_with_label("Reject"); | |
| 145 | media->priv->send_progress = gtk_progress_bar_new(); | |
| 146 | media->priv->recv_progress = gtk_progress_bar_new(); | |
| 147 | ||
| 148 | gtk_widget_set_size_request(media->priv->send_progress, 70, 5); | |
| 149 | gtk_widget_set_size_request(media->priv->recv_progress, 70, 5); | |
| 150 | ||
| 151 | gtk_box_pack_start(GTK_BOX(media), media->priv->hangup, FALSE, FALSE, 0); | |
| 152 | gtk_box_pack_start(GTK_BOX(media), media->priv->accept, FALSE, FALSE, 0); | |
| 153 | gtk_box_pack_start(GTK_BOX(media), media->priv->reject, FALSE, FALSE, 0); | |
| 154 | ||
| 155 | gtk_box_pack_start(GTK_BOX(media), media->priv->send_progress, FALSE, FALSE, 6); | |
| 156 | gtk_box_pack_start(GTK_BOX(media), media->priv->recv_progress, FALSE, FALSE, 6); | |
| 157 | ||
| 158 | gtk_widget_show(media->priv->send_progress); | |
| 159 | gtk_widget_show(media->priv->recv_progress); | |
| 160 | gtk_widget_show_all(media->priv->accept); | |
| 161 | gtk_widget_show_all(media->priv->reject); | |
| 162 | } | |
| 163 | ||
| 164 | static void | |
| 165 | pidgin_media_finalize (GObject *media) | |
| 166 | { | |
| 167 | } | |
| 168 | ||
| 169 | static void | |
| 170 | pidgin_media_emit_message(PidginMedia *gtkmedia, const char *msg) | |
| 171 | { | |
| 172 | g_signal_emit(gtkmedia, pidgin_media_signals[MESSAGE], 0, msg); | |
| 173 | } | |
| 174 | ||
| 175 | static gboolean | |
| 176 | level_message_cb(GstBus *bus, GstMessage *message, PidginMedia *gtkmedia) | |
| 177 | { | |
| 178 | const GstStructure *s; | |
| 179 | const gchar *name; | |
| 180 | ||
| 181 | int channels; | |
| 182 | gdouble rms_db, peak_db, decay_db; | |
| 183 | gdouble rms; | |
| 184 | const GValue *list; | |
| 185 | const GValue *value; | |
| 186 | ||
| 187 | GstElement *src = GST_MESSAGE_SRC(message); | |
| 188 | ||
| 189 | if (message->type != GST_MESSAGE_ELEMENT) | |
| 190 | return TRUE; | |
| 191 | ||
| 192 | s = gst_message_get_structure(message); | |
| 193 | name = gst_structure_get_name(s); | |
| 194 | ||
| 195 | if (strcmp(name, "level")) | |
| 196 | return TRUE; | |
| 197 | ||
| 198 | list = gst_structure_get_value(s, "rms"); | |
| 199 | ||
| 200 | /* Only bother with the first channel. */ | |
| 201 | value = gst_value_list_get_value(list, 0); | |
| 202 | rms_db = g_value_get_double(value); | |
| 203 | ||
| 204 | if (!strcmp(gst_element_get_name(src), "sendlevel")) | |
| 205 | gtk_progress_bar_set_fraction(gtkmedia->priv->send_progress, pow(10, rms_db / 20) * 5); | |
| 206 | else | |
| 207 | gtk_progress_bar_set_fraction(gtkmedia->priv->recv_progress, pow(10, rms_db / 20) * 5); | |
| 208 | ||
| 209 | return TRUE; | |
| 210 | } | |
| 211 | ||
| 212 | static void | |
| 213 | pidgin_media_ready_cb(PurpleMedia *media, PidginMedia *gtkmedia) | |
| 214 | { | |
| 215 | GstElement *element = purple_media_get_audio_pipeline(media); | |
| 216 | gst_bus_add_signal_watch(gst_pipeline_get_bus(element)); | |
| 217 | g_signal_connect(G_OBJECT(gst_pipeline_get_bus(GST_PIPELINE(element))), "message", level_message_cb, gtkmedia); | |
| 218 | printf("\n\nbus: %d\n", gst_pipeline_get_bus(GST_PIPELINE(element))); | |
| 219 | } | |
| 220 | ||
| 221 | static void | |
| 222 | pidgin_media_accept_cb(PurpleMedia *media, PidginMedia *gtkmedia) | |
| 223 | { | |
| 224 | pidgin_media_emit_message(gtkmedia, _("Call in progress.")); | |
| 225 | gtk_widget_show(gtkmedia->priv->hangup); | |
| 226 | gtk_widget_hide(gtkmedia->priv->accept); | |
| 227 | gtk_widget_hide(gtkmedia->priv->reject); | |
| 228 | } | |
| 229 | ||
| 230 | static void | |
| 231 | pidgin_media_hangup_cb(PurpleMedia *media, PidginMedia *gtkmedia) | |
| 232 | { | |
| 233 | pidgin_media_emit_message(gtkmedia, _("You have ended the call.")); | |
| 234 | gtk_widget_destroy(gtkmedia); | |
| 235 | } | |
| 236 | ||
| 237 | static void | |
| 238 | pidgin_media_reject_cb(PurpleMedia *media, PidginMedia *gtkmedia) | |
| 239 | { | |
| 240 | pidgin_media_emit_message(gtkmedia, _("You have rejected the call.")); | |
| 241 | gtk_widget_destroy(gtkmedia); | |
| 242 | } | |
| 243 | ||
| 244 | static void | |
| 245 | pidgin_media_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) | |
| 246 | { | |
| 247 | PidginMedia *media; | |
| 248 | g_return_if_fail(PIDGIN_IS_MEDIA(object)); | |
| 249 | ||
| 250 | media = PIDGIN_MEDIA(object); | |
| 251 | switch (prop_id) { | |
| 252 | case PROP_MEDIA: | |
| 253 | if (media->priv->media) | |
| 254 | g_object_unref(media->priv->media); | |
| 255 | media->priv->media = g_value_get_object(value); | |
| 256 | g_object_ref(media->priv->media); | |
| 257 | g_signal_connect_swapped(G_OBJECT(media->priv->accept), "clicked", | |
| 258 | G_CALLBACK(purple_media_accept), media->priv->media); | |
| 259 | g_signal_connect_swapped(G_OBJECT(media->priv->reject), "clicked", | |
| 260 | G_CALLBACK(purple_media_reject), media->priv->media); | |
| 261 | g_signal_connect_swapped(G_OBJECT(media->priv->hangup), "clicked", | |
| 262 | G_CALLBACK(purple_media_hangup), media->priv->media); | |
| 263 | ||
| 264 | g_signal_connect(G_OBJECT(media->priv->media), "accepted", | |
| 265 | G_CALLBACK(pidgin_media_accept_cb), media); | |
| 266 | g_signal_connect(G_OBJECT(media->priv->media) ,"ready", | |
| 267 | G_CALLBACK(pidgin_media_ready_cb), media); | |
| 268 | g_signal_connect(G_OBJECT(media->priv->media), "hangup", | |
| 269 | G_CALLBACK(pidgin_media_hangup_cb), media); | |
| 270 | g_signal_connect(G_OBJECT(media->priv->media), "reject", | |
| 271 | G_CALLBACK(pidgin_media_reject_cb), media); | |
| 272 | break; | |
| 273 | case PROP_SEND_LEVEL: | |
| 274 | if (media->priv->send_level) | |
| 275 | gst_object_unref(media->priv->send_level); | |
| 276 | media->priv->send_level = g_value_get_object(value); | |
| 277 | g_object_ref(media->priv->send_level); | |
| 278 | break; | |
| 279 | case PROP_RECV_LEVEL: | |
| 280 | if (media->priv->recv_level) | |
| 281 | gst_object_unref(media->priv->recv_level); | |
| 282 | media->priv->recv_level = g_value_get_object(value); | |
| 283 | g_object_ref(media->priv->recv_level); | |
| 284 | break; | |
| 285 | default: | |
| 286 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); | |
| 287 | break; | |
| 288 | } | |
| 289 | } | |
| 290 | ||
| 291 | static void | |
| 292 | pidgin_media_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) | |
| 293 | { | |
| 294 | PidginMedia *media; | |
| 295 | g_return_if_fail(PIDGIN_IS_MEDIA(object)); | |
| 296 | ||
| 297 | media = PIDGIN_MEDIA(object); | |
| 298 | ||
| 299 | switch (prop_id) { | |
| 300 | case PROP_MEDIA: | |
| 301 | g_value_set_object(value, media->priv->media); | |
| 302 | break; | |
| 303 | case PROP_SEND_LEVEL: | |
| 304 | g_value_set_object(value, media->priv->send_level); | |
| 305 | break; | |
| 306 | case PROP_RECV_LEVEL: | |
| 307 | g_value_set_object(value, media->priv->recv_level); | |
| 308 | break; | |
| 309 | default: | |
| 310 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); | |
| 311 | break; | |
| 312 | } | |
| 313 | } | |
| 314 | ||
| 315 | GtkWidget * | |
| 316 | pidgin_media_new(PurpleMedia *media, GstElement *sendlevel, GstElement *recvlevel) | |
| 317 | { | |
| 318 | return GTK_WIDGET(g_object_new(pidgin_media_get_type(), "media", media, "send-level", sendlevel, "recv-level", recvlevel, NULL)); | |
| 319 | } | |
| 320 | ||
| 321 | #endif /* USE_FARSIGHT */ |