pidgin  2.13.0
About: Pidgin is a chat program (multi-protocol instant messaging client) which lets you log in to accounts on multiple chat networks simultaneously (old name "gaim").
  Fossies Dox: pidgin-2.13.0.tar.gz  ("inofficial" and yet experimental doxygen-generated source code documentation)  

media.c
Go to the documentation of this file.
1 
6 /* purple
7  *
8  * Purple is the legal property of its developers, whose names are too numerous
9  * to list here. Please refer to the COPYRIGHT file distributed with this
10  * source distribution.
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
25  */
26 #include "internal.h"
27 
28 #include "account.h"
29 #include "media.h"
30 #include "media/backend-iface.h"
31 #include "mediamanager.h"
32 
33 #include "debug.h"
34 
35 #ifdef USE_GSTREAMER
36 #include "media/backend-fs2.h"
37 #include "marshallers.h"
38 #include "media-gst.h"
39 #endif
40 
41 #ifdef USE_VV
42 
44 typedef struct _PurpleMediaSession PurpleMediaSession;
46 typedef struct _PurpleMediaStream PurpleMediaStream;
48 typedef struct _PurpleMediaClass PurpleMediaClass;
50 typedef struct _PurpleMediaPrivate PurpleMediaPrivate;
51 
53 struct _PurpleMediaClass
54 {
55  GObjectClass parent_class;
56 };
57 
59 struct _PurpleMedia
60 {
61  GObject parent;
62  PurpleMediaPrivate *priv;
63 };
64 
65 struct _PurpleMediaSession
66 {
67  gchar *id;
68  PurpleMedia *media;
70  gboolean initiator;
71 };
72 
73 struct _PurpleMediaStream
74 {
75  PurpleMediaSession *session;
76  gchar *participant;
77 
78  GList *local_candidates;
79  GList *remote_candidates;
80 
81  gboolean initiator;
82  gboolean accepted;
83  gboolean candidates_prepared;
84 
85  GList *active_local_candidates;
86  GList *active_remote_candidates;
87 };
88 #endif
89 
91 {
92 #ifdef USE_VV
93  PurpleMediaManager *manager;
95  PurpleMediaBackend *backend;
96  gchar *conference_type;
97  gboolean initiator;
98  gpointer prpl_data;
99 
100  GHashTable *sessions; /* PurpleMediaSession table */
101  GList *participants;
102  GList *streams; /* PurpleMediaStream table */
103 #else
104  gpointer dummy;
105 #endif
106 };
107 
108 #ifdef USE_VV
109 #define PURPLE_MEDIA_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_MEDIA, PurpleMediaPrivate))
110 
111 static void purple_media_class_init (PurpleMediaClass *klass);
112 static void purple_media_init (PurpleMedia *media);
113 static void purple_media_dispose (GObject *object);
114 static void purple_media_finalize (GObject *object);
115 static void purple_media_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
116 static void purple_media_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
117 
118 static void purple_media_new_local_candidate_cb(PurpleMediaBackend *backend,
119  const gchar *sess_id, const gchar *participant,
120  PurpleMediaCandidate *candidate, PurpleMedia *media);
121 static void purple_media_candidates_prepared_cb(PurpleMediaBackend *backend,
122  const gchar *sess_id, const gchar *name, PurpleMedia *media);
123 static void purple_media_candidate_pair_established_cb(
124  PurpleMediaBackend *backend,
125  const gchar *sess_id, const gchar *name,
126  PurpleMediaCandidate *local_candidate,
127  PurpleMediaCandidate *remote_candidate,
128  PurpleMedia *media);
129 static void purple_media_codecs_changed_cb(PurpleMediaBackend *backend,
130  const gchar *sess_id, PurpleMedia *media);
131 
132 static GObjectClass *parent_class = NULL;
133 
134 
135 
136 enum {
137  S_ERROR,
140  LEVEL,
142  STATE_CHANGED,
143  STREAM_INFO,
144  CANDIDATE_PAIR_ESTABLISHED,
146 };
147 static guint purple_media_signals[LAST_SIGNAL] = {0};
148 
149 enum {
150  PROP_0,
151  PROP_MANAGER,
152  PROP_BACKEND,
153  PROP_ACCOUNT,
154  PROP_CONFERENCE_TYPE,
155  PROP_INITIATOR,
156  PROP_PRPL_DATA,
157 };
158 #endif
159 
160 
161 GType
163 {
164 #ifdef USE_VV
165  static GType type = 0;
166 
167  if (type == 0) {
168  static const GTypeInfo info = {
169  sizeof(PurpleMediaClass),
170  NULL,
171  NULL,
172  (GClassInitFunc) purple_media_class_init,
173  NULL,
174  NULL,
175  sizeof(PurpleMedia),
176  0,
177  (GInstanceInitFunc) purple_media_init,
178  NULL
179  };
180  type = g_type_register_static(G_TYPE_OBJECT, "PurpleMedia", &info, 0);
181  }
182  return type;
183 #else
184  return G_TYPE_NONE;
185 #endif
186 }
187 
188 #ifdef USE_VV
189 static void
190 purple_media_class_init (PurpleMediaClass *klass)
191 {
192  GObjectClass *gobject_class = (GObjectClass*)klass;
193  parent_class = g_type_class_peek_parent(klass);
194 
195  gobject_class->dispose = purple_media_dispose;
196  gobject_class->finalize = purple_media_finalize;
197  gobject_class->set_property = purple_media_set_property;
198  gobject_class->get_property = purple_media_get_property;
199 
200  g_object_class_install_property(gobject_class, PROP_MANAGER,
201  g_param_spec_object("manager",
202  "Purple Media Manager",
203  "The media manager that contains this media session.",
205  G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
206 
207  /*
208  * This one should be PURPLE_TYPE_MEDIA_BACKEND, but it doesn't
209  * like interfaces because they "aren't GObjects"
210  */
211  g_object_class_install_property(gobject_class, PROP_BACKEND,
212  g_param_spec_object("backend",
213  "Purple Media Backend",
214  "The backend object this media object uses.",
215  G_TYPE_OBJECT,
216  G_PARAM_READABLE));
217 
218  g_object_class_install_property(gobject_class, PROP_ACCOUNT,
219  g_param_spec_pointer("account",
220  "PurpleAccount",
221  "The account this media session is on.",
222  G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
223 
224  g_object_class_install_property(gobject_class, PROP_CONFERENCE_TYPE,
225  g_param_spec_string("conference-type",
226  "Conference Type",
227  "The type of conference that this media object "
228  "has been created to provide.",
229  NULL,
230  G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
231 
232  g_object_class_install_property(gobject_class, PROP_INITIATOR,
233  g_param_spec_boolean("initiator",
234  "initiator",
235  "If the local user initiated the conference.",
236  FALSE,
237  G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
238 
239  g_object_class_install_property(gobject_class, PROP_PRPL_DATA,
240  g_param_spec_pointer("prpl-data",
241  "gpointer",
242  "Data the prpl plugin set on the media session.",
243  G_PARAM_READWRITE));
244 
245  purple_media_signals[S_ERROR] = g_signal_new("error", G_TYPE_FROM_CLASS(klass),
246  G_SIGNAL_RUN_LAST, 0, NULL, NULL,
247  g_cclosure_marshal_VOID__STRING,
248  G_TYPE_NONE, 1, G_TYPE_STRING);
249  purple_media_signals[CANDIDATES_PREPARED] = g_signal_new("candidates-prepared", G_TYPE_FROM_CLASS(klass),
250  G_SIGNAL_RUN_LAST, 0, NULL, NULL,
252  G_TYPE_NONE, 2, G_TYPE_STRING,
253  G_TYPE_STRING);
254  purple_media_signals[CODECS_CHANGED] = g_signal_new("codecs-changed", G_TYPE_FROM_CLASS(klass),
255  G_SIGNAL_RUN_LAST, 0, NULL, NULL,
256  g_cclosure_marshal_VOID__STRING,
257  G_TYPE_NONE, 1, G_TYPE_STRING);
258  purple_media_signals[LEVEL] = g_signal_new("level", G_TYPE_FROM_CLASS(klass),
259  G_SIGNAL_RUN_LAST, 0, NULL, NULL,
261  G_TYPE_NONE, 3, G_TYPE_STRING,
262  G_TYPE_STRING, G_TYPE_DOUBLE);
263  purple_media_signals[NEW_CANDIDATE] = g_signal_new("new-candidate", G_TYPE_FROM_CLASS(klass),
264  G_SIGNAL_RUN_LAST, 0, NULL, NULL,
266  G_TYPE_NONE, 3, G_TYPE_POINTER,
267  G_TYPE_POINTER, PURPLE_TYPE_MEDIA_CANDIDATE);
268  purple_media_signals[STATE_CHANGED] = g_signal_new("state-changed", G_TYPE_FROM_CLASS(klass),
269  G_SIGNAL_RUN_LAST, 0, NULL, NULL,
271  G_TYPE_NONE, 3, PURPLE_MEDIA_TYPE_STATE,
272  G_TYPE_STRING, G_TYPE_STRING);
273  purple_media_signals[STREAM_INFO] = g_signal_new("stream-info", G_TYPE_FROM_CLASS(klass),
274  G_SIGNAL_RUN_LAST, 0, NULL, NULL,
276  G_TYPE_NONE, 4, PURPLE_MEDIA_TYPE_INFO_TYPE,
277  G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN);
278  purple_media_signals[CANDIDATE_PAIR_ESTABLISHED] = g_signal_new("candidate-pair-established", G_TYPE_FROM_CLASS(klass),
279  G_SIGNAL_RUN_LAST, 0, NULL, NULL,
281  G_TYPE_NONE, 4, G_TYPE_POINTER, G_TYPE_POINTER,
283  g_type_class_add_private(klass, sizeof(PurpleMediaPrivate));
284 }
285 
286 
287 static void
288 purple_media_init (PurpleMedia *media)
289 {
290  media->priv = PURPLE_MEDIA_GET_PRIVATE(media);
291  memset(media->priv, 0, sizeof(*media->priv));
292 }
293 
294 static void
295 purple_media_stream_free(PurpleMediaStream *stream)
296 {
297  if (stream == NULL)
298  return;
299 
300  g_free(stream->participant);
301 
302  if (stream->local_candidates)
303  purple_media_candidate_list_free(stream->local_candidates);
304  if (stream->remote_candidates)
305  purple_media_candidate_list_free(stream->remote_candidates);
306 
307  if (stream->active_local_candidates)
309  stream->active_local_candidates);
310  if (stream->active_remote_candidates)
312  stream->active_remote_candidates);
313 
314  g_free(stream);
315 }
316 
317 static void
318 purple_media_session_free(PurpleMediaSession *session)
319 {
320  if (session == NULL)
321  return;
322 
323  g_free(session->id);
324  g_free(session);
325 }
326 
327 static void
328 purple_media_dispose(GObject *media)
329 {
330  PurpleMediaPrivate *priv = PURPLE_MEDIA_GET_PRIVATE(media);
331 
332  purple_debug_info("media","purple_media_dispose\n");
333 
334  purple_media_manager_remove_media(priv->manager, PURPLE_MEDIA(media));
335 
336  if (priv->backend) {
337  g_object_unref(priv->backend);
338  priv->backend = NULL;
339  }
340 
341  if (priv->manager) {
342  g_object_unref(priv->manager);
343  priv->manager = NULL;
344  }
345 
346  G_OBJECT_CLASS(parent_class)->dispose(media);
347 }
348 
349 static void
350 purple_media_finalize(GObject *media)
351 {
352  PurpleMediaPrivate *priv = PURPLE_MEDIA_GET_PRIVATE(media);
353  purple_debug_info("media","purple_media_finalize\n");
354 
355  for (; priv->streams; priv->streams = g_list_delete_link(priv->streams, priv->streams))
356  purple_media_stream_free(priv->streams->data);
357 
358  for (; priv->participants; priv->participants = g_list_delete_link(
359  priv->participants, priv->participants))
360  g_free(priv->participants->data);
361 
362  if (priv->sessions) {
363  GList *sessions = g_hash_table_get_values(priv->sessions);
364  for (; sessions; sessions = g_list_delete_link(sessions, sessions)) {
365  purple_media_session_free(sessions->data);
366  }
367  g_hash_table_destroy(priv->sessions);
368  }
369 
370  G_OBJECT_CLASS(parent_class)->finalize(media);
371 }
372 
373 static void
374 purple_media_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
375 {
376  PurpleMedia *media;
377  g_return_if_fail(PURPLE_IS_MEDIA(object));
378 
379  media = PURPLE_MEDIA(object);
380 
381  switch (prop_id) {
382  case PROP_MANAGER:
383  media->priv->manager = g_value_dup_object(value);
384  break;
385  case PROP_ACCOUNT:
386  media->priv->account = g_value_get_pointer(value);
387  break;
388  case PROP_CONFERENCE_TYPE:
389  media->priv->conference_type =
390  g_value_dup_string(value);
391  media->priv->backend = g_object_new(
394  "conference-type",
395  media->priv->conference_type,
396  "media", media,
397  NULL);
398  g_signal_connect(media->priv->backend,
399  "active-candidate-pair",
400  G_CALLBACK(
401  purple_media_candidate_pair_established_cb),
402  media);
403  g_signal_connect(media->priv->backend,
404  "candidates-prepared",
405  G_CALLBACK(
406  purple_media_candidates_prepared_cb),
407  media);
408  g_signal_connect(media->priv->backend,
409  "codecs-changed",
410  G_CALLBACK(
411  purple_media_codecs_changed_cb),
412  media);
413  g_signal_connect(media->priv->backend,
414  "new-candidate",
415  G_CALLBACK(
416  purple_media_new_local_candidate_cb),
417  media);
418  break;
419  case PROP_INITIATOR:
420  media->priv->initiator = g_value_get_boolean(value);
421  break;
422  case PROP_PRPL_DATA:
423  media->priv->prpl_data = g_value_get_pointer(value);
424  break;
425  default:
426  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
427  break;
428  }
429 }
430 
431 static void
432 purple_media_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
433 {
434  PurpleMedia *media;
435  g_return_if_fail(PURPLE_IS_MEDIA(object));
436 
437  media = PURPLE_MEDIA(object);
438 
439  switch (prop_id) {
440  case PROP_MANAGER:
441  g_value_set_object(value, media->priv->manager);
442  break;
443  case PROP_BACKEND:
444  g_value_set_object(value, media->priv->backend);
445  break;
446  case PROP_ACCOUNT:
447  g_value_set_pointer(value, media->priv->account);
448  break;
449  case PROP_CONFERENCE_TYPE:
450  g_value_set_string(value,
451  media->priv->conference_type);
452  break;
453  case PROP_INITIATOR:
454  g_value_set_boolean(value, media->priv->initiator);
455  break;
456  case PROP_PRPL_DATA:
457  g_value_set_pointer(value, media->priv->prpl_data);
458  break;
459  default:
460  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
461  break;
462  }
463 
464 }
465 
466 static PurpleMediaSession*
467 purple_media_get_session(PurpleMedia *media, const gchar *sess_id)
468 {
469  g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
470  return (PurpleMediaSession*) (media->priv->sessions) ?
471  g_hash_table_lookup(media->priv->sessions, sess_id) : NULL;
472 }
473 
474 static PurpleMediaStream*
475 purple_media_get_stream(PurpleMedia *media, const gchar *session, const gchar *participant)
476 {
477  GList *streams;
478 
479  g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
480 
481  streams = media->priv->streams;
482 
483  for (; streams; streams = g_list_next(streams)) {
484  PurpleMediaStream *stream = streams->data;
485  if (purple_strequal(stream->session->id, session) &&
486  purple_strequal(stream->participant, participant))
487  return stream;
488  }
489 
490  return NULL;
491 }
492 
493 static GList *
494 purple_media_get_streams(PurpleMedia *media, const gchar *session,
495  const gchar *participant)
496 {
497  GList *streams;
498  GList *ret = NULL;
499 
500  g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
501 
502  streams = media->priv->streams;
503 
504  for (; streams; streams = g_list_next(streams)) {
505  PurpleMediaStream *stream = streams->data;
506  if ((session == NULL ||
507  purple_strequal(stream->session->id, session)) &&
508  (participant == NULL ||
509  purple_strequal(stream->participant, participant)))
510  ret = g_list_append(ret, stream);
511  }
512 
513  return ret;
514 }
515 
516 static void
517 purple_media_add_session(PurpleMedia *media, PurpleMediaSession *session)
518 {
519  g_return_if_fail(PURPLE_IS_MEDIA(media));
520  g_return_if_fail(session != NULL);
521 
522  if (!media->priv->sessions) {
523  purple_debug_info("media", "Creating hash table for sessions\n");
524  media->priv->sessions = g_hash_table_new_full(g_str_hash, g_str_equal,
525  g_free, NULL);
526  }
527  g_hash_table_insert(media->priv->sessions, g_strdup(session->id), session);
528 }
529 
530 #if 0
531 static gboolean
532 purple_media_remove_session(PurpleMedia *media, PurpleMediaSession *session)
533 {
534  g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
535  return g_hash_table_remove(media->priv->sessions, session->id);
536 }
537 #endif
538 
539 static PurpleMediaStream *
540 purple_media_insert_stream(PurpleMediaSession *session,
541  const gchar *name, gboolean initiator)
542 {
543  PurpleMediaStream *media_stream;
544 
545  g_return_val_if_fail(session != NULL, NULL);
546 
547  media_stream = g_new0(PurpleMediaStream, 1);
548  media_stream->participant = g_strdup(name);
549  media_stream->session = session;
550  media_stream->initiator = initiator;
551 
552  session->media->priv->streams =
553  g_list_append(session->media->priv->streams, media_stream);
554 
555  return media_stream;
556 }
557 
558 static void
559 purple_media_insert_local_candidate(PurpleMediaSession *session, const gchar *name,
560  PurpleMediaCandidate *candidate)
561 {
562  PurpleMediaStream *stream;
563 
564  g_return_if_fail(session != NULL);
565 
566  stream = purple_media_get_stream(session->media, session->id, name);
567  stream->local_candidates = g_list_append(stream->local_candidates, candidate);
568 }
569 #endif
570 
571 GList *
573 {
574 #ifdef USE_VV
575  g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
576  return media->priv->sessions != NULL ?
577  g_hash_table_get_keys(media->priv->sessions) : NULL;
578 #else
579  return NULL;
580 #endif
581 }
582 
583 #ifdef USE_GSTREAMER
584 GstElement *
585 purple_media_get_src(PurpleMedia *media, const gchar *sess_id)
586 {
587 #ifdef USE_VV
588  g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
589 
590  if (PURPLE_IS_MEDIA_BACKEND_FS2(media->priv->backend))
591  return purple_media_backend_fs2_get_src(
593  media->priv->backend), sess_id);
594 
595  g_return_val_if_reached(NULL);
596 #else
597  return NULL;
598 #endif
599 }
600 #endif /* USE_GSTREAMER */
601 
604 {
605 #ifdef USE_VV
607  g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
608  g_object_get(G_OBJECT(media), "account", &account, NULL);
609  return account;
610 #else
611  return NULL;
612 #endif
613 }
614 
615 gpointer
617 {
618 #ifdef USE_VV
619  gpointer prpl_data;
620  g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
621  g_object_get(G_OBJECT(media), "prpl-data", &prpl_data, NULL);
622  return prpl_data;
623 #else
624  return NULL;
625 #endif
626 }
627 
628 void
629 purple_media_set_prpl_data(PurpleMedia *media, gpointer prpl_data)
630 {
631 #ifdef USE_VV
632  g_return_if_fail(PURPLE_IS_MEDIA(media));
633  g_object_set(G_OBJECT(media), "prpl-data", prpl_data, NULL);
634 #endif
635 }
636 
637 void
638 purple_media_error(PurpleMedia *media, const gchar *error, ...)
639 {
640 #ifdef USE_VV
641  va_list args;
642  gchar *message;
643 
644  g_return_if_fail(PURPLE_IS_MEDIA(media));
645 
646  va_start(args, error);
647  message = g_strdup_vprintf(error, args);
648  va_end(args);
649 
650  purple_debug_error("media", "%s\n", message);
651  g_signal_emit(media, purple_media_signals[S_ERROR], 0, message);
652 
653  g_free(message);
654 #endif
655 }
656 
657 void
659  const gchar *session_id, const gchar *participant)
660 {
661 #ifdef USE_VV
662  GList *iter, *sessions = NULL, *participants = NULL;
663 
664  g_return_if_fail(PURPLE_IS_MEDIA(media));
665 
666  iter = purple_media_get_streams(media, session_id, participant);
667 
668  /* Free matching streams */
669  for (; iter; iter = g_list_delete_link(iter, iter)) {
670  PurpleMediaStream *stream = iter->data;
671 
672  g_signal_emit(media, purple_media_signals[STATE_CHANGED],
674  stream->session->id, stream->participant);
675 
676  media->priv->streams =
677  g_list_remove(media->priv->streams, stream);
678 
679  if (g_list_find(sessions, stream->session) == NULL)
680  sessions = g_list_prepend(sessions, stream->session);
681 
682  if (g_list_find_custom(participants, stream->participant,
683  (GCompareFunc)strcmp) == NULL)
684  participants = g_list_prepend(participants,
685  g_strdup(stream->participant));
686 
687  purple_media_stream_free(stream);
688  }
689 
690  iter = media->priv->streams;
691 
692  /* Reduce to list of sessions to remove */
693  for (; iter; iter = g_list_next(iter)) {
694  PurpleMediaStream *stream = iter->data;
695 
696  sessions = g_list_remove(sessions, stream->session);
697  }
698 
699  /* Free sessions with no streams left */
700  for (; sessions; sessions = g_list_delete_link(sessions, sessions)) {
701  PurpleMediaSession *session = sessions->data;
702 
703  g_signal_emit(media, purple_media_signals[STATE_CHANGED],
705  session->id, NULL);
706 
707  g_hash_table_remove(media->priv->sessions, session->id);
708  purple_media_session_free(session);
709  }
710 
711  iter = media->priv->streams;
712 
713  /* Reduce to list of participants to remove */
714  for (; iter; iter = g_list_next(iter)) {
715  PurpleMediaStream *stream = iter->data;
716  GList *tmp;
717 
718  tmp = g_list_find_custom(participants,
719  stream->participant, (GCompareFunc)strcmp);
720 
721  if (tmp != NULL) {
722  g_free(tmp->data);
723  participants = g_list_delete_link(participants, tmp);
724  }
725  }
726 
727  /* Remove participants with no streams left (just emit the signal) */
728  for (; participants; participants =
729  g_list_delete_link(participants, participants)) {
730  gchar *participant = participants->data;
731  GList *link = g_list_find_custom(media->priv->participants,
732  participant, (GCompareFunc)strcmp);
733 
734  g_signal_emit(media, purple_media_signals[STATE_CHANGED],
736  NULL, participant);
737 
738  if (link != NULL) {
739  g_free(link->data);
740  media->priv->participants = g_list_delete_link(
741  media->priv->participants, link);
742  }
743 
744  g_free(participant);
745  }
746 
747  /* Free the conference if no sessions left */
748  if (media->priv->sessions != NULL &&
749  g_hash_table_size(media->priv->sessions) == 0) {
750  g_signal_emit(media, purple_media_signals[STATE_CHANGED],
752  NULL, NULL);
753  g_object_unref(media);
754  return;
755  }
756 #endif
757 }
758 
759 void
761  const gchar *session_id, const gchar *participant,
762  gboolean local)
763 {
764 #ifdef USE_VV
765  g_return_if_fail(PURPLE_IS_MEDIA(media));
766 
768  GList *streams, *sessions = NULL, *participants = NULL;
769 
770  g_return_if_fail(PURPLE_IS_MEDIA(media));
771 
772  streams = purple_media_get_streams(media,
773  session_id, participant);
774 
775  /* Emit stream acceptance */
776  for (; streams; streams =
777  g_list_delete_link(streams, streams)) {
778  PurpleMediaStream *stream = streams->data;
779 
780  stream->accepted = TRUE;
781 
782  g_signal_emit(media,
783  purple_media_signals[STREAM_INFO],
784  0, type, stream->session->id,
785  stream->participant, local);
786 
787  if (g_list_find(sessions, stream->session) == NULL)
788  sessions = g_list_prepend(sessions,
789  stream->session);
790 
791  if (g_list_find_custom(participants,
792  stream->participant,
793  (GCompareFunc)strcmp) == NULL)
794  participants = g_list_prepend(participants,
795  g_strdup(stream->participant));
796  }
797 
798  /* Emit session acceptance */
799  for (; sessions; sessions =
800  g_list_delete_link(sessions, sessions)) {
801  PurpleMediaSession *session = sessions->data;
802 
803  if (purple_media_accepted(media, session->id, NULL))
804  g_signal_emit(media, purple_media_signals[
805  STREAM_INFO], 0,
807  session->id, NULL, local);
808  }
809 
810  /* Emit participant acceptance */
811  for (; participants; participants = g_list_delete_link(
812  participants, participants)) {
813  gchar *participant = participants->data;
814 
815  if (purple_media_accepted(media, NULL, participant))
816  g_signal_emit(media, purple_media_signals[
817  STREAM_INFO], 0,
819  NULL, participant, local);
820 
821  g_free(participant);
822  }
823 
824  /* Emit conference acceptance */
825  if (purple_media_accepted(media, NULL, NULL))
826  g_signal_emit(media,
827  purple_media_signals[STREAM_INFO],
829  NULL, NULL, local);
830 
831  return;
832  } else if (type == PURPLE_MEDIA_INFO_HANGUP ||
834  GList *streams;
835 
836  g_return_if_fail(PURPLE_IS_MEDIA(media));
837 
838  streams = purple_media_get_streams(media,
839  session_id, participant);
840 
841  /* Emit for stream */
842  for (; streams; streams =
843  g_list_delete_link(streams, streams)) {
844  PurpleMediaStream *stream = streams->data;
845 
846  g_signal_emit(media,
847  purple_media_signals[STREAM_INFO],
848  0, type, stream->session->id,
849  stream->participant, local);
850  }
851 
852  if (session_id != NULL && participant != NULL) {
853  /* Everything that needs to be emitted has been */
854  } else if (session_id == NULL && participant == NULL) {
855  /* Emit for everything in the conference */
856  GList *sessions = NULL;
857  GList *participants = media->priv->participants;
858 
859  if (media->priv->sessions != NULL)
860  sessions = g_hash_table_get_values(
861  media->priv->sessions);
862 
863  /* Emit for sessions */
864  for (; sessions; sessions = g_list_delete_link(
865  sessions, sessions)) {
866  PurpleMediaSession *session = sessions->data;
867 
868  g_signal_emit(media, purple_media_signals[
869  STREAM_INFO], 0, type,
870  session->id, NULL, local);
871  }
872 
873  /* Emit for participants */
874  for (; participants; participants =
875  g_list_next(participants)) {
876  gchar *participant = participants->data;
877 
878  g_signal_emit(media, purple_media_signals[
879  STREAM_INFO], 0, type,
880  NULL, participant, local);
881  }
882 
883  /* Emit for conference */
884  g_signal_emit(media,
885  purple_media_signals[STREAM_INFO],
886  0, type, NULL, NULL, local);
887  } else if (session_id != NULL) {
888  /* Emit just the specific session */
889  PurpleMediaSession *session =
890  purple_media_get_session(
891  media, session_id);
892 
893  if (session == NULL) {
894  purple_debug_warning("media",
895  "Couldn't find session"
896  " to hangup/reject.\n");
897  } else {
898  g_signal_emit(media, purple_media_signals[
899  STREAM_INFO], 0, type,
900  session->id, NULL, local);
901  }
902  } else if (participant != NULL) {
903  /* Emit just the specific participant */
904  if (!g_list_find_custom(media->priv->participants,
905  participant, (GCompareFunc)strcmp)) {
906  purple_debug_warning("media",
907  "Couldn't find participant"
908  " to hangup/reject.\n");
909  } else {
910  g_signal_emit(media, purple_media_signals[
911  STREAM_INFO], 0, type, NULL,
912  participant, local);
913  }
914  }
915 
916  purple_media_end(media, session_id, participant);
917  return;
918  }
919 
920  g_signal_emit(media, purple_media_signals[STREAM_INFO],
921  0, type, session_id, participant, local);
922 #endif
923 }
924 
925 void
927  guint num_params, GParameter *params)
928 {
929 #ifdef USE_VV
930  g_return_if_fail(PURPLE_IS_MEDIA(media));
931 
932  purple_media_backend_set_params(media->priv->backend, num_params, params);
933 #endif
934 }
935 
936 const gchar **
938 {
939  static const gchar *NULL_ARRAY[] = { NULL };
940 #ifdef USE_VV
941  g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL_ARRAY);
942 
943  return purple_media_backend_get_available_params(media->priv->backend);
944 #else
945  return NULL_ARRAY;
946 #endif
947 }
948 
949 gboolean
950 purple_media_param_is_supported(PurpleMedia *media, const gchar *param)
951 {
952 #ifdef USE_VV
953  const gchar **params;
954 
955  g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
956  g_return_val_if_fail(param != NULL, FALSE);
957 
958  params = purple_media_backend_get_available_params(media->priv->backend);
959  for (; *params != NULL; ++params)
960  if (purple_strequal(*params, param))
961  return TRUE;
962 #endif
963  return FALSE;
964 }
965 
966 #ifdef USE_VV
967 static void
968 purple_media_new_local_candidate_cb(PurpleMediaBackend *backend,
969  const gchar *sess_id, const gchar *participant,
970  PurpleMediaCandidate *candidate, PurpleMedia *media)
971 {
972  PurpleMediaSession *session =
973  purple_media_get_session(media, sess_id);
974 
975  purple_media_insert_local_candidate(session, participant,
976  purple_media_candidate_copy(candidate));
977 
978  g_signal_emit(session->media, purple_media_signals[NEW_CANDIDATE],
979  0, session->id, participant, candidate);
980 }
981 
982 static void
983 purple_media_candidates_prepared_cb(PurpleMediaBackend *backend,
984  const gchar *sess_id, const gchar *name, PurpleMedia *media)
985 {
986  PurpleMediaStream *stream_data;
987 
988  g_return_if_fail(PURPLE_IS_MEDIA(media));
989 
990  stream_data = purple_media_get_stream(media, sess_id, name);
991  stream_data->candidates_prepared = TRUE;
992 
993  g_signal_emit(media, purple_media_signals[CANDIDATES_PREPARED],
994  0, sess_id, name);
995 }
996 
997 /* callback called when a pair of transport candidates (local and remote)
998  * has been established */
999 static void
1000 purple_media_candidate_pair_established_cb(PurpleMediaBackend *backend,
1001  const gchar *sess_id, const gchar *name,
1002  PurpleMediaCandidate *local_candidate,
1003  PurpleMediaCandidate *remote_candidate,
1004  PurpleMedia *media)
1005 {
1006  PurpleMediaStream *stream;
1007  GList *iter;
1008  guint id;
1009 
1010  g_return_if_fail(PURPLE_IS_MEDIA(media));
1011 
1012  stream = purple_media_get_stream(media, sess_id, name);
1013  id = purple_media_candidate_get_component_id(local_candidate);
1014 
1015  iter = stream->active_local_candidates;
1016  for(; iter; iter = g_list_next(iter)) {
1017  PurpleMediaCandidate *c = iter->data;
1019  g_object_unref(c);
1020  stream->active_local_candidates =
1021  g_list_delete_link(iter, iter);
1022  stream->active_local_candidates = g_list_prepend(
1023  stream->active_local_candidates,
1025  local_candidate));
1026  break;
1027  }
1028  }
1029  if (iter == NULL)
1030  stream->active_local_candidates = g_list_prepend(
1031  stream->active_local_candidates,
1033  local_candidate));
1034 
1035  id = purple_media_candidate_get_component_id(local_candidate);
1036 
1037  iter = stream->active_remote_candidates;
1038  for(; iter; iter = g_list_next(iter)) {
1039  PurpleMediaCandidate *c = iter->data;
1041  g_object_unref(c);
1042  stream->active_remote_candidates =
1043  g_list_delete_link(iter, iter);
1044  stream->active_remote_candidates = g_list_prepend(
1045  stream->active_remote_candidates,
1047  remote_candidate));
1048  break;
1049  }
1050  }
1051  if (iter == NULL)
1052  stream->active_remote_candidates = g_list_prepend(
1053  stream->active_remote_candidates,
1055  remote_candidate));
1056 
1057  g_signal_emit(media, purple_media_signals[CANDIDATE_PAIR_ESTABLISHED],
1058  0, sess_id, name, local_candidate, remote_candidate);
1059  purple_debug_info("media", "candidate pair established\n");
1060 }
1061 
1062 static void
1063 purple_media_codecs_changed_cb(PurpleMediaBackend *backend,
1064  const gchar *sess_id, PurpleMedia *media)
1065 {
1066  g_signal_emit(media, purple_media_signals[CODECS_CHANGED], 0, sess_id);
1067 }
1068 #endif /* USE_VV */
1069 
1070 gboolean
1071 purple_media_add_stream(PurpleMedia *media, const gchar *sess_id,
1072  const gchar *who, PurpleMediaSessionType type,
1073  gboolean initiator, const gchar *transmitter,
1074  guint num_params, GParameter *params)
1075 {
1076 #ifdef USE_VV
1077  PurpleMediaSession *session;
1078 
1079  g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
1080 
1081  if (!purple_media_backend_add_stream(media->priv->backend,
1082  sess_id, who, type, initiator, transmitter,
1083  num_params, params)) {
1084  purple_debug_error("media", "Error adding stream.\n");
1085  return FALSE;
1086  }
1087 
1088  session = purple_media_get_session(media, sess_id);
1089 
1090  if (!session) {
1091  session = g_new0(PurpleMediaSession, 1);
1092  session->id = g_strdup(sess_id);
1093  session->media = media;
1094  session->type = type;
1095  session->initiator = initiator;
1096 
1097  purple_media_add_session(media, session);
1098  g_signal_emit(media, purple_media_signals[STATE_CHANGED],
1100  session->id, NULL);
1101  }
1102 
1103  if (!g_list_find_custom(media->priv->participants,
1104  who, (GCompareFunc)strcmp)) {
1105  media->priv->participants = g_list_prepend(
1106  media->priv->participants, g_strdup(who));
1107 
1108  g_signal_emit_by_name(media, "state-changed",
1110  }
1111 
1112  if (purple_media_get_stream(media, sess_id, who) == NULL) {
1113  purple_media_insert_stream(session, who, initiator);
1114 
1115  g_signal_emit(media, purple_media_signals[STATE_CHANGED],
1117  session->id, who);
1118  }
1119 
1120  return TRUE;
1121 #else
1122  return FALSE;
1123 #endif /* USE_VV */
1124 }
1125 
1128 {
1129  PurpleMediaManager *ret;
1130  g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
1131  g_object_get(media, "manager", &ret, NULL);
1132  return ret;
1133 }
1134 
1136 purple_media_get_session_type(PurpleMedia *media, const gchar *sess_id)
1137 {
1138 #ifdef USE_VV
1139  PurpleMediaSession *session;
1140  g_return_val_if_fail(PURPLE_IS_MEDIA(media), PURPLE_MEDIA_NONE);
1141  session = purple_media_get_session(media, sess_id);
1142  return session->type;
1143 #else
1144  return PURPLE_MEDIA_NONE;
1145 #endif
1146 }
1147 /* XXX: Should wait until codecs-ready is TRUE before using this function */
1148 GList *
1149 purple_media_get_codecs(PurpleMedia *media, const gchar *sess_id)
1150 {
1151 #ifdef USE_VV
1152  g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
1153 
1154  return purple_media_backend_get_codecs(media->priv->backend, sess_id);
1155 #else
1156  return NULL;
1157 #endif
1158 }
1159 
1160 GList *
1161 purple_media_get_local_candidates(PurpleMedia *media, const gchar *sess_id,
1162  const gchar *participant)
1163 {
1164 #ifdef USE_VV
1165  g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
1166 
1167  return purple_media_backend_get_local_candidates(media->priv->backend,
1168  sess_id, participant);
1169 #else
1170  return NULL;
1171 #endif
1172 }
1173 
1174 void
1176  const gchar *participant,
1177  GList *remote_candidates)
1178 {
1179 #ifdef USE_VV
1180  PurpleMediaStream *stream;
1181 
1182  g_return_if_fail(PURPLE_IS_MEDIA(media));
1183  stream = purple_media_get_stream(media, sess_id, participant);
1184 
1185  if (stream == NULL) {
1186  purple_debug_error("media",
1187  "purple_media_add_remote_candidates: "
1188  "couldn't find stream %s %s.\n",
1189  sess_id ? sess_id : "(null)",
1190  participant ? participant : "(null)");
1191  return;
1192  }
1193 
1194  stream->remote_candidates = g_list_concat(stream->remote_candidates,
1195  purple_media_candidate_list_copy(remote_candidates));
1196 
1197  purple_media_backend_add_remote_candidates(media->priv->backend,
1198  sess_id, participant, remote_candidates);
1199 #endif
1200 }
1201 
1202 GList *
1204  const gchar *sess_id, const gchar *participant)
1205 {
1206 #ifdef USE_VV
1207  PurpleMediaStream *stream;
1208  g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
1209  stream = purple_media_get_stream(media, sess_id, participant);
1211  stream->active_local_candidates);
1212 #else
1213  return NULL;
1214 #endif
1215 }
1216 
1217 GList *
1219  const gchar *sess_id, const gchar *participant)
1220 {
1221 #ifdef USE_VV
1222  PurpleMediaStream *stream;
1223  g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
1224  stream = purple_media_get_stream(media, sess_id, participant);
1226  stream->active_remote_candidates);
1227 #else
1228  return NULL;
1229 #endif
1230 }
1231 
1232 gboolean
1233 purple_media_set_remote_codecs(PurpleMedia *media, const gchar *sess_id,
1234  const gchar *participant, GList *codecs)
1235 {
1236 #ifdef USE_VV
1237  g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
1238 
1239  return purple_media_backend_set_remote_codecs(media->priv->backend,
1240  sess_id, participant, codecs);
1241 #else
1242  return FALSE;
1243 #endif
1244 }
1245 
1246 gboolean
1248  const gchar *session_id, const gchar *participant)
1249 {
1250 #ifdef USE_VV
1251  GList *streams;
1252  gboolean prepared = TRUE;
1253 
1254  g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
1255 
1256  streams = purple_media_get_streams(media, session_id, participant);
1257 
1258  for (; streams; streams = g_list_delete_link(streams, streams)) {
1259  PurpleMediaStream *stream = streams->data;
1260  if (stream->candidates_prepared == FALSE) {
1261  g_list_free(streams);
1262  prepared = FALSE;
1263  break;
1264  }
1265  }
1266 
1267  return prepared;
1268 #else
1269  return FALSE;
1270 #endif
1271 }
1272 
1273 gboolean
1274 purple_media_set_send_codec(PurpleMedia *media, const gchar *sess_id, PurpleMediaCodec *codec)
1275 {
1276 #ifdef USE_VV
1277  g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
1278 
1280  media->priv->backend, sess_id, codec);
1281 #else
1282  return FALSE;
1283 #endif
1284 }
1285 
1286 gboolean
1288  const gchar *cipher, const gchar *auth,
1289  const gchar *key, gsize key_len)
1290 {
1291 #ifdef USE_VV
1292  g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
1293  return purple_media_backend_set_encryption_parameters(media->priv->backend,
1294  sess_id, cipher, auth, key, key_len);
1295 #else
1296  return FALSE;
1297 #endif
1298 }
1299 
1300 gboolean
1302  const gchar *participant, const gchar *cipher,
1303  const gchar *auth, const gchar *key, gsize key_len)
1304 {
1305 #ifdef USE_VV
1306  g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
1307  return purple_media_backend_set_decryption_parameters(media->priv->backend,
1308  sess_id, participant, cipher, auth, key, key_len);
1309 #else
1310  return FALSE;
1311 #endif
1312 }
1313 
1314 gboolean
1315 purple_media_codecs_ready(PurpleMedia *media, const gchar *sess_id)
1316 {
1317 #ifdef USE_VV
1318  g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
1319 
1321  media->priv->backend, sess_id);
1322 #else
1323  return FALSE;
1324 #endif
1325 }
1326 
1327 gboolean
1328 purple_media_set_send_rtcp_mux(PurpleMedia *media, const gchar *sess_id,
1329  const gchar *participant, gboolean send_rtcp_mux)
1330 {
1331 #ifdef USE_VV
1332  g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
1333 
1334  return purple_media_backend_set_send_rtcp_mux(media->priv->backend,
1335  sess_id, participant, send_rtcp_mux);
1336 #else
1337  return FALSE;
1338 #endif
1339 }
1340 
1341 gboolean
1343  const gchar *sess_id, const gchar *participant)
1344 {
1345 #ifdef USE_VV
1346  g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
1347 
1348  if (sess_id == NULL && participant == NULL)
1349  return media->priv->initiator;
1350  else if (sess_id != NULL && participant == NULL) {
1351  PurpleMediaSession *session =
1352  purple_media_get_session(media, sess_id);
1353  return session != NULL ? session->initiator : FALSE;
1354  } else if (sess_id != NULL && participant != NULL) {
1355  PurpleMediaStream *stream = purple_media_get_stream(
1356  media, sess_id, participant);
1357  return stream != NULL ? stream->initiator : FALSE;
1358  }
1359 #endif
1360  return FALSE;
1361 }
1362 
1363 gboolean
1364 purple_media_accepted(PurpleMedia *media, const gchar *sess_id,
1365  const gchar *participant)
1366 {
1367 #ifdef USE_VV
1368  gboolean accepted = TRUE;
1369 
1370  g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
1371 
1372  if (sess_id == NULL && participant == NULL) {
1373  GList *streams = media->priv->streams;
1374 
1375  for (; streams; streams = g_list_next(streams)) {
1376  PurpleMediaStream *stream = streams->data;
1377  if (stream->accepted == FALSE) {
1378  accepted = FALSE;
1379  break;
1380  }
1381  }
1382  } else if (sess_id != NULL && participant == NULL) {
1383  GList *streams = purple_media_get_streams(
1384  media, sess_id, NULL);
1385  for (; streams; streams =
1386  g_list_delete_link(streams, streams)) {
1387  PurpleMediaStream *stream = streams->data;
1388  if (stream->accepted == FALSE) {
1389  g_list_free(streams);
1390  accepted = FALSE;
1391  break;
1392  }
1393  }
1394  } else if (sess_id != NULL && participant != NULL) {
1395  PurpleMediaStream *stream = purple_media_get_stream(
1396  media, sess_id, participant);
1397  if (stream == NULL || stream->accepted == FALSE)
1398  accepted = FALSE;
1399  }
1400 
1401  return accepted;
1402 #else
1403  return FALSE;
1404 #endif
1405 }
1406 
1408  const gchar *session_id, double level)
1409 {
1410 #ifdef USE_VV
1411  g_return_if_fail(PURPLE_IS_MEDIA(media));
1412  g_return_if_fail(PURPLE_IS_MEDIA_BACKEND_FS2(media->priv->backend));
1413 
1414  purple_media_backend_fs2_set_input_volume(
1416  media->priv->backend),
1417  session_id, level);
1418 #endif
1419 }
1420 
1422  const gchar *session_id, const gchar *participant,
1423  double level)
1424 {
1425 #ifdef USE_VV
1426  g_return_if_fail(PURPLE_IS_MEDIA(media));
1427  g_return_if_fail(PURPLE_IS_MEDIA_BACKEND_FS2(media->priv->backend));
1428 
1429  purple_media_backend_fs2_set_output_volume(
1431  media->priv->backend),
1432  session_id, participant, level);
1433 #endif
1434 }
1435 
1436 gulong
1437 purple_media_set_output_window(PurpleMedia *media, const gchar *session_id,
1438  const gchar *participant, gulong window_id)
1439 {
1440 #ifdef USE_VV
1441  g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
1442 
1443  return purple_media_manager_set_output_window(media->priv->manager,
1444  media, session_id, participant, window_id);
1445 #else
1446  return 0;
1447 #endif
1448 }
1449 
1450 void
1452 {
1453 #ifdef USE_VV
1454  GList *iter = media->priv->streams;
1455  for (; iter; iter = g_list_next(iter)) {
1456  PurpleMediaStream *stream = iter->data;
1458  media->priv->manager, media,
1459  stream->session->id, stream->participant);
1460  }
1461 
1462  iter = purple_media_get_session_ids(media);
1463  for (; iter; iter = g_list_delete_link(iter, iter)) {
1464  gchar *session_name = iter->data;
1466  media->priv->manager, media,
1467  session_name, NULL);
1468  }
1469 #endif
1470 }
1471 
1472 #ifdef USE_GSTREAMER
1473 GstElement *
1475  const gchar *session_id, const gchar *participant)
1476 {
1477 #ifdef USE_VV
1478  g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
1479 
1480  if (PURPLE_IS_MEDIA_BACKEND_FS2(media->priv->backend))
1481  return purple_media_backend_fs2_get_tee(
1483  media->priv->backend),
1484  session_id, participant);
1485  g_return_val_if_reached(NULL);
1486 #else
1487  return NULL;
1488 #endif
1489 }
1490 #endif /* USE_GSTREAMER */
1491 
1492 gboolean
1493 purple_media_send_dtmf(PurpleMedia *media, const gchar *session_id,
1494  gchar dtmf, guint8 volume, guint16 duration)
1495 {
1496 #ifdef USE_VV
1497  PurpleMediaBackendIface *backend_iface = NULL;
1498 
1499  if (media)
1500  {
1501  backend_iface = PURPLE_MEDIA_BACKEND_GET_INTERFACE(media->priv->backend);
1502  }
1503 
1504  if (dtmf == 'a')
1505  dtmf = 'A';
1506  else if (dtmf == 'b')
1507  dtmf = 'B';
1508  else if (dtmf == 'c')
1509  dtmf = 'C';
1510  else if (dtmf == 'd')
1511  dtmf = 'D';
1512 
1513  g_return_val_if_fail(strchr("0123456789ABCD#*", dtmf), FALSE);
1514 
1515  if (backend_iface && backend_iface->send_dtmf
1516  && backend_iface->send_dtmf(media->priv->backend,
1517  session_id, dtmf, volume, duration))
1518  {
1519  return TRUE;
1520  }
1521 #endif
1522  return FALSE;
1523 }
purple_media_stream_info
void purple_media_stream_info(PurpleMedia *media, PurpleMediaInfoType type, const gchar *session_id, const gchar *participant, gboolean local)
Definition: media.c:760
dbus-analyze-signals.args
args
Definition: dbus-analyze-signals.py:37
purple_media_backend_set_decryption_parameters
gboolean purple_media_backend_set_decryption_parameters(PurpleMediaBackend *self, const gchar *sess_id, const gchar *participant, const gchar *cipher, const gchar *auth, const gchar *key, gsize key_len)
Definition: backend-iface.c:211
purple_smarshal_VOID__ENUM_STRING_STRING_BOOLEAN
void purple_smarshal_VOID__ENUM_STRING_STRING_BOOLEAN(GClosure *closure, GValue *return_value G_GNUC_UNUSED, guint n_param_values, const GValue *param_values, gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data)
Definition: marshallers.c:250
info
static PurplePluginInfo info
Definition: gntclipboard.c:147
name
char * name
Definition: gntbindable.c:47
PURPLE_TYPE_MEDIA_CANDIDATE
#define PURPLE_TYPE_MEDIA_CANDIDATE
Definition: candidate.h:36
purple_media_backend_set_send_rtcp_mux
gboolean purple_media_backend_set_send_rtcp_mux(PurpleMediaBackend *self, const gchar *sess_id, const gchar *participant, gboolean send_rtcp_mux)
Definition: backend-iface.c:243
purple_media_set_output_window
gulong purple_media_set_output_window(PurpleMedia *media, const gchar *session_id, const gchar *participant, gulong window_id)
Definition: media.c:1437
purple_media_backend_add_remote_candidates
void purple_media_backend_add_remote_candidates(PurpleMediaBackend *self, const gchar *sess_id, const gchar *participant, GList *remote_candidates)
Definition: backend-iface.c:140
purple_media_manager_remove_media
void purple_media_manager_remove_media(PurpleMediaManager *manager, PurpleMedia *media)
Definition: mediamanager.c:475
account
static PurpleAccount * account
Definition: raw.c:45
CODECS_CHANGED
Definition: backend-iface.c:34
purple_strequal
gboolean purple_strequal(const gchar *left, const gchar *right)
NEW_CANDIDATE
Definition: backend-iface.c:35
PURPLE_MEDIA_STATE_NEW
Definition: enum-types.h:107
purple_media_set_send_rtcp_mux
gboolean purple_media_set_send_rtcp_mux(PurpleMedia *media, const gchar *sess_id, const gchar *participant, gboolean send_rtcp_mux)
Definition: media.c:1328
purple_media_get_tee
GstElement * purple_media_get_tee(PurpleMedia *media, const gchar *session_id, const gchar *participant)
purple_media_get_src
GstElement * purple_media_get_src(PurpleMedia *media, const gchar *sess_id)
purple_media_get_local_candidates
GList * purple_media_get_local_candidates(PurpleMedia *media, const gchar *sess_id, const gchar *participant)
Definition: media.c:1161
purple_media_manager_get
PurpleMediaManager * purple_media_manager_get()
Definition: mediamanager.c:274
PurpleMediaInfoType
PurpleMediaInfoType
Definition: enum-types.h:70
account.h
PurpleMedia
struct _PurpleMedia PurpleMedia
Definition: media.h:47
purple_media_backend_set_params
void purple_media_backend_set_params(PurpleMediaBackend *self, guint num_params, GParameter *params)
Definition: backend-iface.c:226
purple_media_is_initiator
gboolean purple_media_is_initiator(PurpleMedia *media, const gchar *sess_id, const gchar *participant)
Definition: media.c:1342
purple_media_candidate_copy
PurpleMediaCandidate * purple_media_candidate_copy(PurpleMediaCandidate *candidate)
Definition: candidate.c:340
media.h
PURPLE_MEDIA_INFO_REJECT
Definition: enum-types.h:73
purple_debug_error
void purple_debug_error(const char *category, const char *format,...)
Definition: debug.c:145
purple_media_manager_get_backend_type
GType purple_media_manager_get_backend_type(PurpleMediaManager *manager)
Definition: mediamanager.c:1723
PurpleMediaSessionType
PurpleMediaSessionType
Definition: enum-types.h:91
marshallers.h
purple_media_set_encryption_parameters
gboolean purple_media_set_encryption_parameters(PurpleMedia *media, const gchar *sess_id, const gchar *cipher, const gchar *auth, const gchar *key, gsize key_len)
Definition: media.c:1287
PURPLE_MEDIA_INFO_HANGUP
Definition: enum-types.h:71
_PurpleMediaCandidate
Definition: candidate.c:45
PURPLE_MEDIA
#define PURPLE_MEDIA(obj)
Definition: media.h:40
purple_media_backend_codecs_ready
gboolean purple_media_backend_codecs_ready(PurpleMediaBackend *self, const gchar *sess_id)
Definition: backend-iface.c:150
PURPLE_MEDIA_NONE
Definition: enum-types.h:92
PROP_ACCOUNT
Definition: gtkstatusbox.c:145
purple_media_set_input_volume
void purple_media_set_input_volume(PurpleMedia *media, const gchar *session_id, double level)
Definition: media.c:1407
purple_smarshal_VOID__POINTER_POINTER_OBJECT
void purple_smarshal_VOID__POINTER_POINTER_OBJECT(GClosure *closure, GValue *return_value G_GNUC_UNUSED, guint n_param_values, const GValue *param_values, gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data)
Definition: marshallers.c:53
CANDIDATES_PREPARED
Definition: backend-iface.c:33
purple_media_get_type
GType purple_media_get_type()
Definition: media.c:162
purple_media_get_session_type
PurpleMediaSessionType purple_media_get_session_type(PurpleMedia *media, const gchar *sess_id)
Definition: media.c:1136
purple_media_candidate_get_component_id
guint purple_media_candidate_get_component_id(PurpleMediaCandidate *candidate)
Definition: candidate.c:396
purple_media_backend_get_available_params
const gchar ** purple_media_backend_get_available_params(PurpleMediaBackend *self)
Definition: backend-iface.c:234
_PurpleMediaPrivate
Definition: media.c:90
PURPLE_MEDIA_STATE_END
Definition: enum-types.h:109
parent_class
static GObjectClass * parent_class
Definition: gntbindable.c:40
purple_media_manager_set_output_window
gulong purple_media_manager_set_output_window(PurpleMediaManager *manager, PurpleMedia *media, const gchar *session_id, const gchar *participant, gulong window_id)
Definition: mediamanager.c:1541
klass
GntBindableClass * klass
Definition: gntbindable.c:46
PURPLE_MEDIA_TYPE_INFO_TYPE
#define PURPLE_MEDIA_TYPE_INFO_TYPE
Definition: enum-types.h:36
PURPLE_IS_MEDIA_BACKEND_FS2
#define PURPLE_IS_MEDIA_BACKEND_FS2(obj)
Definition: backend-fs2.h:40
media-gst.h
PURPLE_TYPE_MEDIA_MANAGER
#define PURPLE_TYPE_MEDIA_MANAGER
Definition: mediamanager.h:67
purple_media_backend_get_codecs
GList * purple_media_backend_get_codecs(PurpleMediaBackend *self, const gchar *sess_id)
Definition: backend-iface.c:159
PURPLE_MEDIA_TYPE_STATE
#define PURPLE_MEDIA_TYPE_STATE
Definition: enum-types.h:39
NULL
#define NULL
Definition: getopt1.c:52
purple_media_codecs_ready
gboolean purple_media_codecs_ready(PurpleMedia *media, const gchar *sess_id)
Definition: media.c:1315
purple_media_get_session_ids
GList * purple_media_get_session_ids(PurpleMedia *media)
Definition: media.c:572
purple_media_manager_remove_output_windows
void purple_media_manager_remove_output_windows(PurpleMediaManager *manager, PurpleMedia *media, const gchar *session_id, const gchar *participant)
Definition: mediamanager.c:1656
purple_media_add_stream
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)
Definition: media.c:1071
purple_smarshal_VOID__POINTER_POINTER_OBJECT_OBJECT
void purple_smarshal_VOID__POINTER_POINTER_OBJECT_OBJECT(GClosure *closure, GValue *return_value G_GNUC_UNUSED, guint n_param_values, const GValue *param_values, gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data)
Definition: marshallers.c:369
link
static struct et_list link
Definition: zephyr_err.c:50
purple_media_get_active_remote_candidates
GList * purple_media_get_active_remote_candidates(PurpleMedia *media, const gchar *sess_id, const gchar *participant)
Definition: media.c:1218
purple_media_candidate_list_free
void purple_media_candidate_list_free(GList *candidates)
Definition: candidate.c:378
strchr
#define strchr
Definition: sysdep.h:62
TRUE
#define TRUE
Definition: protobuf-c.c:56
_PurpleAccount
Definition: account.h:169
dbus-analyze-signals.type
string type
Definition: dbus-analyze-signals.py:42
purple_media_send_dtmf
gboolean purple_media_send_dtmf(PurpleMedia *media, const gchar *session_id, gchar dtmf, guint8 volume, guint16 duration)
Definition: media.c:1493
purple_media_set_prpl_data
void purple_media_set_prpl_data(PurpleMedia *media, gpointer prpl_data)
Definition: media.c:629
FALSE
#define FALSE
Definition: protobuf-c.c:57
purple_smarshal_VOID__STRING_STRING
void purple_smarshal_VOID__STRING_STRING(GClosure *closure, GValue *return_value G_GNUC_UNUSED, guint n_param_values, const GValue *param_values, gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data)
Definition: marshallers.c:135
PROP_0
Definition: gntbox.c:35
PURPLE_IS_MEDIA
#define PURPLE_IS_MEDIA(obj)
Definition: media.h:42
PURPLE_MEDIA_INFO_ACCEPT
Definition: enum-types.h:72
purple_media_add_remote_candidates
void purple_media_add_remote_candidates(PurpleMedia *media, const gchar *sess_id, const gchar *participant, GList *remote_candidates)
Definition: media.c:1175
LAST_SIGNAL
Definition: backend-iface.c:37
_PurpleMediaPrivate::dummy
gpointer dummy
Definition: media.c:104
PurpleMediaManager
struct _PurpleMediaManager PurpleMediaManager
Definition: mediamanager.h:34
purple_debug_info
void purple_debug_info(const char *category, const char *format,...)
Definition: debug.c:121
purple_media_get_prpl_data
gpointer purple_media_get_prpl_data(PurpleMedia *media)
Definition: media.c:616
purple_media_set_params
void purple_media_set_params(PurpleMedia *media, guint num_params, GParameter *params)
Definition: media.c:926
purple_media_get_active_local_candidates
GList * purple_media_get_active_local_candidates(PurpleMedia *media, const gchar *sess_id, const gchar *participant)
Definition: media.c:1203
PURPLE_MEDIA_BACKEND_GET_INTERFACE
#define PURPLE_MEDIA_BACKEND_GET_INTERFACE(inst)
Definition: backend-iface.h:40
purple_media_set_remote_codecs
gboolean purple_media_set_remote_codecs(PurpleMedia *media, const gchar *sess_id, const gchar *participant, GList *codecs)
Definition: media.c:1233
internal.h
purple_media_error
void purple_media_error(PurpleMedia *media, const gchar *error,...)
Definition: media.c:638
purple_media_set_decryption_parameters
gboolean purple_media_set_decryption_parameters(PurpleMedia *media, const gchar *sess_id, const gchar *participant, const gchar *cipher, const gchar *auth, const gchar *key, gsize key_len)
Definition: media.c:1301
purple_media_accepted
gboolean purple_media_accepted(PurpleMedia *media, const gchar *sess_id, const gchar *participant)
Definition: media.c:1364
PURPLE_MEDIA_BACKEND_FS2
#define PURPLE_MEDIA_BACKEND_FS2(obj)
Definition: backend-fs2.h:42
_PurpleMediaBackendIface::send_dtmf
gboolean(* send_dtmf)(PurpleMediaBackend *self, const gchar *sess_id, gchar dtmf, guint8 volume, guint16 duration)
Definition: backend-iface.h:81
purple_media_get_codecs
GList * purple_media_get_codecs(PurpleMedia *media, const gchar *sess_id)
Definition: media.c:1149
_PurpleMediaBackendIface
Definition: backend-iface.h:47
purple_media_set_output_volume
void purple_media_set_output_volume(PurpleMedia *media, const gchar *session_id, const gchar *participant, double level)
Definition: media.c:1421
_PurpleMediaCodec
Definition: codec.c:43
error
const char * error
Definition: auth_scram.c:51
purple_media_candidates_prepared
gboolean purple_media_candidates_prepared(PurpleMedia *media, const gchar *session_id, const gchar *participant)
Definition: media.c:1247
S_ERROR
Definition: backend-iface.c:32
backend-iface.h
purple_media_set_send_codec
gboolean purple_media_set_send_codec(PurpleMedia *media, const gchar *sess_id, PurpleMediaCodec *codec)
Definition: media.c:1274
backend-fs2.h
mediamanager.h
purple_smarshal_VOID__STRING_STRING_DOUBLE
void purple_smarshal_VOID__STRING_STRING_DOUBLE(GClosure *closure, GValue *return_value G_GNUC_UNUSED, guint n_param_values, const GValue *param_values, gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data)
Definition: marshallers.c:172
purple_media_candidate_list_copy
GList * purple_media_candidate_list_copy(GList *candidates)
Definition: candidate.c:364
purple_media_backend_get_local_candidates
GList * purple_media_backend_get_local_candidates(PurpleMediaBackend *self, const gchar *sess_id, const gchar *participant)
Definition: backend-iface.c:168
purple_media_backend_set_send_codec
gboolean purple_media_backend_set_send_codec(PurpleMediaBackend *self, const gchar *sess_id, PurpleMediaCodec *codec)
Definition: backend-iface.c:188
purple_smarshal_VOID__ENUM_STRING_STRING
void purple_smarshal_VOID__ENUM_STRING_STRING(GClosure *closure, GValue *return_value G_GNUC_UNUSED, guint n_param_values, const GValue *param_values, gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data)
Definition: marshallers.c:211
purple_media_get_account
PurpleAccount * purple_media_get_account(PurpleMedia *media)
Definition: media.c:603
params
GList * params
Definition: gntbindable.c:48
value
gpointer value
Definition: gntwm.c:1782
PurpleMediaBackend
struct _PurpleMediaBackend PurpleMediaBackend
Definition: backend-iface.h:43
purple_media_remove_output_windows
void purple_media_remove_output_windows(PurpleMedia *media)
Definition: media.c:1451
purple_media_get_available_params
const gchar ** purple_media_get_available_params(PurpleMedia *media)
Definition: media.c:937
purple_media_backend_set_remote_codecs
gboolean purple_media_backend_set_remote_codecs(PurpleMediaBackend *self, const gchar *sess_id, const gchar *participant, GList *codecs)
Definition: backend-iface.c:178
purple_media_param_is_supported
gboolean purple_media_param_is_supported(PurpleMedia *media, const gchar *param)
Definition: media.c:950
purple_media_backend_set_encryption_parameters
gboolean purple_media_backend_set_encryption_parameters(PurpleMediaBackend *self, const gchar *sess_id, const gchar *cipher, const gchar *auth, const gchar *key, gsize key_len)
Definition: backend-iface.c:197
debug.h
purple_debug_warning
void purple_debug_warning(const char *category, const char *format,...)
Definition: debug.c:133
purple_media_backend_add_stream
gboolean purple_media_backend_add_stream(PurpleMediaBackend *self, const gchar *sess_id, const gchar *who, PurpleMediaSessionType type, gboolean initiator, const gchar *transmitter, guint num_params, GParameter *params)
Definition: backend-iface.c:127
purple_media_end
void purple_media_end(PurpleMedia *media, const gchar *session_id, const gchar *participant)
Definition: media.c:658
purple_media_get_manager
PurpleMediaManager * purple_media_get_manager(PurpleMedia *media)
Definition: media.c:1127