1 /*
2  * Farstream - Farstream Session
3  *
4  * Copyright 2007 Collabora Ltd.
5  *  @author: Philippe Kalaf <philippe.kalaf@collabora.co.uk>
6  * Copyright 2007 Nokia Corp.
7  *
8  * fs-session.c - A Farstream Session gobject (base implementation)
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
23  */
24 
25 
26 
27 /**
28  * SECTION:fs-session
29  * @short_description: A session in a conference
30  *
31  * This object is the base implementation of a Farstream Session. It needs to be
32  * derived and implemented by a farstream conference gstreamer element. A
33  * Farstream session is defined in the same way as an RTP session. It can contain
34  * one or more participants but represents only one media stream (i.e. One
35  * session for video and one session for audio in an AV conference). Sessions
36  * contained in the same conference will be synchronised together during
37  * playback.
38  *
39  *
40  * This will communicate asynchronous events to the user through #GstMessage
41  * of type #GST_MESSAGE_ELEMENT sent over the #GstBus.
42  *
43  * <refsect2><title>The "<literal>farstream-send-codec-changed</literal>"
44  *   message</title>
45  * <table>
46  *  <tr>
47  *   <td><code>"session"</code></td>
48  *   <td>#FsSession</td>
49  *   <td>The session that emits the message</td>
50  *  </tr>
51  *  <tr>
52  *   <td><code>"codec"</code></td>
53  *   <td>#FsCodec</td>
54  *   <td>The new send codec</td>
55  *  </tr>
56  *  <tr>
57  *   <td><code>"secondary-codecs"</code></td>
58  *   <td>#GList</td>
59  *   <td>A #GList of #FsCodec (to be freed with fs_codec_list_destroy())
60  *   </td>
61  *  </tr>
62  * </table>
63  * <para>
64  * This message is sent on the bus when the value of the
65  * #FsSession:current-send-codec property changes.
66  * </para>
67  * </refsect2>
68  * <refsect2><title>The "<literal>farstream-codecs-changed</literal>"
69  *  message</title>
70  * <table>
71  *  <tr>
72  *   <td><code>"session"</code></td>
73  *   <td>#FsSession</td>
74  *   <td>The session that emits the message</td>
75  *  </tr>
76  * </table>
77  * <para>
78  * This message is sent on the bus when the value of the
79  * #FsSession:codecs or #FsSession:codecs-without-config properties change.
80  * If one is using codecs that have configuration data that needs to be
81  * transmitted reliably, one should fetch #FsSession:codecs, otherwise,
82  * #FsSession:codecs-without-config should be enough.
83  * </para>
84  * </refsect2>
85  * <refsect2><title>The "<literal>farstream-telephony-event-started</literal>"
86  *  message</title>
87  * <table>
88  *  <tr>
89  *   <td><code>"session"</code></td>
90  *   <td>#FsSession</td>
91  *   <td>The session that emits the message</td>
92  *  </tr>
93  *  <tr>
94  *   <td><code>"method"</code></td>
95  *   <td>#FsDTMFMethod</td>
96  *   <td>The method used to send the DTMF</td>
97  *  </tr>
98  *  <tr>
99  *   <td><code>"event"</code></td>
100  *   <td>#FSDTMFEvent</td>
101  *   <td>The event number</td>
102  *  </tr>
103  *  <tr>
104  *   <td><code>"volume"</code></td>
105  *   <td>guchar</td>
106  *   <td>The volume of the event</td>
107  *  </tr>
108  * </table>
109  * <para>
110  * This message is emitted after a succesful call to
111  * fs_session_start_telephony_event() to inform the application that the
112  * telephony event has started.
113  * </para>
114  * </refsect2>
115  * <refsect2><title>The "<literal>farstream-telephony-event-stopped</literal>"
116  *  message</title>
117  * <table>
118  *  <tr>
119  *   <td><code>"session"</code></td>
120  *   <td>#FsSession</td>
121  *   <td>The session that emits the message</td>
122  *  </tr>
123  *  <tr>
124  *   <td><code>"method"</code></td>
125  *   <td>#FsDTMFMethod</td>
126  *   <td>The method used to send the DTMF</td>
127  *  </tr>
128  * </table>
129  * <para>
130  * This message is emitted after a succesful call to
131  * fs_session_stop_telephony_event() to inform the application that the
132  * telephony event has stopped.
133  * </para>
134  * </refsect2>
135  *
136  */
137 
138 #ifdef HAVE_CONFIG_H
139 #include "config.h"
140 #endif
141 
142 #include "fs-session.h"
143 
144 #include <gst/gst.h>
145 
146 #include "fs-conference.h"
147 #include "fs-codec.h"
148 #include "fs-enumtypes.h"
149 #include "fs-private.h"
150 
151 #define GST_CAT_DEFAULT _fs_conference_debug
152 
153 /* Signals */
154 enum
155 {
156   ERROR_SIGNAL,
157   LAST_SIGNAL
158 };
159 
160 /* props */
161 enum
162 {
163   PROP_0,
164   PROP_CONFERENCE,
165   PROP_MEDIA_TYPE,
166   PROP_ID,
167   PROP_SINK_PAD,
168   PROP_CODEC_PREFERENCES,
169   PROP_CODECS,
170   PROP_CODECS_WITHOUT_CONFIG,
171   PROP_CURRENT_SEND_CODEC,
172   PROP_TYPE_OF_SERVICE,
173   PROP_ALLOWED_SRC_CAPS,
174   PROP_ALLOWED_SINK_CAPS,
175   PROP_ENCRYPTION_PARAMETERS
176 };
177 
178 /*
179 struct _FsSessionPrivate
180 {
181 };
182 
183 #define FS_SESSION_GET_PRIVATE(o)  \
184    (G_TYPE_INSTANCE_GET_PRIVATE ((o), FS_TYPE_SESSION, FsSessionPrivate))
185 */
186 
187 G_DEFINE_ABSTRACT_TYPE(FsSession, fs_session, G_TYPE_OBJECT)
188 
189 static void fs_session_get_property (GObject *object,
190                                      guint prop_id,
191                                      GValue *value,
192                                      GParamSpec *pspec);
193 static void fs_session_set_property (GObject *object,
194                                      guint prop_id,
195                                      const GValue *value,
196                                      GParamSpec *pspec);
197 
198 static guint signals[LAST_SIGNAL] = { 0 };
199 
200 static void
fs_session_class_init(FsSessionClass * klass)201 fs_session_class_init (FsSessionClass *klass)
202 {
203   GObjectClass *gobject_class;
204 
205   gobject_class = (GObjectClass *) klass;
206 
207   gobject_class->set_property = fs_session_set_property;
208   gobject_class->get_property = fs_session_get_property;
209 
210 
211   /**
212    * FsSession:conference:
213    *
214    * The #FsConference parent of this session. This property is a
215    * construct param and is read-only.
216    *
217    */
218   g_object_class_install_property (gobject_class,
219     PROP_CONFERENCE,
220     g_param_spec_object ("conference",
221       "The FsConference",
222       "The Conference this stream refers to",
223       FS_TYPE_CONFERENCE,
224       G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
225 
226   /**
227    * FsSession:media-type:
228    *
229    * The media-type of the session. This is either Audio, Video or both.
230    * This is a constructor parameter that cannot be changed.
231    *
232    */
233   g_object_class_install_property (gobject_class,
234       PROP_MEDIA_TYPE,
235       g_param_spec_enum ("media-type",
236         "The media type of the session",
237         "An enum that specifies the media type of the session",
238         FS_TYPE_MEDIA_TYPE,
239         FS_MEDIA_TYPE_AUDIO,
240         G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
241 
242   /**
243    * FsSession:id:
244    *
245    * The ID of the session, the first number of the pads linked to this session
246    * will be this id
247    *
248    */
249   g_object_class_install_property (gobject_class,
250       PROP_ID,
251       g_param_spec_uint ("id",
252         "The ID of the session",
253         "This ID is used on pad related to this session",
254         0, G_MAXUINT, 0,
255         G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
256 
257   /**
258    * FsSession:sink-pad:
259    *
260    * The Gstreamer sink pad that must be used to send media data on this
261    * session. User must unref this GstPad when done with it.
262    *
263    */
264   g_object_class_install_property (gobject_class,
265       PROP_SINK_PAD,
266       g_param_spec_object ("sink-pad",
267         "A gstreamer sink pad for this session",
268         "A pad used for sending data on this session",
269         GST_TYPE_PAD,
270         G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
271 
272   /**
273    * FsSession:codec-preferences: (type GLib.List(FsCodec)) (transfer full)
274    *
275    * This is the current preferences list for the local codecs. It is
276    * set by the user to specify the codec options and priorities. The user may
277    * change its value with fs_session_set_codec_preferences() at any time
278    * during a session. It is a #GList of #FsCodec.
279    * The user must free this codec list using fs_codec_list_destroy() when done.
280    *
281    * The payload type may be a valid dynamic PT (96-127), %FS_CODEC_ID_DISABLE
282    * or %FS_CODEC_ID_ANY. If the encoding name is "reserve-pt", then the
283    * payload type of the codec will be "reserved" and not be used by any
284    * dynamically assigned payload type.
285    */
286   g_object_class_install_property (gobject_class,
287       PROP_CODEC_PREFERENCES,
288       g_param_spec_boxed ("codec-preferences",
289         "List of user preferences for the codecs",
290         "A GList of FsCodecs that allows user to set his codec options and"
291         " priorities",
292         FS_TYPE_CODEC_LIST,
293         G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
294 
295   /**
296    * FsSession:codecs: (type GLib.List(FsCodec)) (transfer full)
297    *
298    * This is the list of codecs used for this session. It will include the
299    * codecs and payload type used to receive media on this session. It will
300    * also include any configuration parameter that must be transmitted reliably
301    * for the other end to decode the content.
302    *
303    * It may change when the codec preferences are set, when codecs are set
304    * on a #FsStream in this session, when a #FsStream is destroyed or
305    * asynchronously when new config data is discovered.
306    *
307    * If any configuration parameter needs to be discovered, this property
308    * will be %NULL until they have been discovered. One can always get
309    * the codecs from #FsSession:codecs-without-config.
310    * The "farstream-codecs-changed" message will be emitted whenever the value
311    * of this property changes.
312    *
313    * It is a #GList of #FsCodec. User must free this codec list using
314    * fs_codec_list_destroy() when done.
315    */
316   g_object_class_install_property (gobject_class,
317       PROP_CODECS,
318       g_param_spec_boxed ("codecs",
319         "List of codecs",
320         "A GList of FsCodecs indicating the codecs for this session",
321         FS_TYPE_CODEC_LIST,
322         G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
323 
324   /**
325    * FsSession:codecs-without-config: (type GLib.List(FsCodec)) (transfer full)
326    *
327    * This is the same list of codecs as #FsSession:codecs without
328    * the configuration information that describes the data sent. It is suitable
329    * for configurations where a list of codecs is shared by many senders.
330    * If one is using codecs such as Theora, Vorbis or H.264 that require
331    * such information to be transmitted, the configuration data should be
332    * included in the stream and retransmitted regularly.
333    *
334    * It may change when the codec preferences are set, when codecs are set
335    * on a #FsStream in this session, when a #FsStream is destroyed or
336    * asynchronously when new config data is discovered.
337    *
338    * The "farstream-codecs-changed" message will be emitted whenever the value
339    * of this property changes.
340    *
341    * It is a #GList of #FsCodec. User must free this codec list using
342    * fs_codec_list_destroy() when done.
343    */
344   g_object_class_install_property (gobject_class,
345       PROP_CODECS_WITHOUT_CONFIG,
346       g_param_spec_boxed ("codecs-without-config",
347           "List of codecs without the configuration data",
348           "A GList of FsCodecs indicating the codecs for this session without "
349           "any configuration data",
350           FS_TYPE_CODEC_LIST,
351           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
352 
353   /**
354    * FsSession:current-send-codec:
355    *
356    * Indicates the currently active send codec. A user can change the active
357    * send codec by calling fs_session_set_send_codec(). The send codec could
358    * also be automatically changed by Farstream. This property is an
359    * #FsCodec. User must free the codec using fs_codec_destroy() when done.
360    * The "farstream-send-codec-changed" message is emitted on the bus when
361    * the value of this property changes.
362    */
363   g_object_class_install_property (gobject_class,
364       PROP_CURRENT_SEND_CODEC,
365       g_param_spec_boxed ("current-send-codec",
366         "Current active send codec",
367         "An FsCodec indicating the currently active send codec",
368         FS_TYPE_CODEC,
369         G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
370 
371   /**
372    * FsSession:tos:
373    *
374    * Sets the IP ToS field (and if possible the IPv6 TCLASS field
375    */
376   g_object_class_install_property (gobject_class,
377       PROP_TYPE_OF_SERVICE,
378       g_param_spec_uint ("tos",
379           "IP Type of Service",
380           "The IP Type of Service to set on sent packets",
381           0, 255, 0,
382           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
383 
384   /**
385    * FsSession:allowed-sink-caps:
386    *
387    * These are the #GstCaps that can be fed into the session,
388    * they are used to filter the codecs to only those that can
389    * accepted those caps as input.
390    */
391   g_object_class_install_property (gobject_class,
392       PROP_ALLOWED_SINK_CAPS,
393       g_param_spec_boxed ("allowed-sink-caps",
394         "Allowed sink caps",
395         "GstCaps that can be fed into the session",
396         GST_TYPE_CAPS,
397         G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
398 
399   /**
400    * FsSession:allowed-src-caps:
401    *
402    * These are the #GstCaps that the session can produce,
403    * they are used to filter the codecs to only those that can
404    * accepted those caps as output.
405    */
406   g_object_class_install_property (gobject_class,
407       PROP_ALLOWED_SRC_CAPS,
408       g_param_spec_boxed ("allowed-src-caps",
409         "Allowed source caps",
410         "GstCaps that the session can produce",
411         GST_TYPE_CAPS,
412         G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
413 
414   /**
415    * FsSession:encryption-parameters:
416    *
417    * Retrieves previously set encryption parameters
418    */
419   g_object_class_install_property (gobject_class,
420       PROP_ENCRYPTION_PARAMETERS,
421       g_param_spec_boxed ("encryption-parameters",
422           "Encryption parameters",
423           "Parameters used to encrypt the stream",
424           GST_TYPE_STRUCTURE,
425           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
426 
427 
428   /**
429    * FsSession::error:
430    * @self: #FsSession that emitted the signal
431    * @object: The #Gobject that emitted the signal
432    * @error_no: The number of the error
433    * @error_msg: Error message
434    *
435    * This signal is emitted in any error condition, it can be emitted on any
436    * thread. Applications should listen to the GstBus for errors.
437    *
438    */
439   signals[ERROR_SIGNAL] = g_signal_new ("error",
440       G_TYPE_FROM_CLASS (klass),
441       G_SIGNAL_RUN_LAST,
442       0, NULL, NULL, NULL,
443       G_TYPE_NONE, 3, G_TYPE_OBJECT, FS_TYPE_ERROR, G_TYPE_STRING);
444 }
445 
446 static void
fs_session_init(FsSession * self)447 fs_session_init (FsSession *self)
448 {
449   /* member init */
450   // self->priv = FS_SESSION_GET_PRIVATE (self);
451 }
452 
453 static void
fs_session_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)454 fs_session_get_property (GObject *object,
455                          guint prop_id,
456                          GValue *value,
457                          GParamSpec *pspec)
458 {
459   switch (prop_id) {
460     case PROP_ENCRYPTION_PARAMETERS:
461       g_value_set_boxed (value, NULL);
462       /* Not having parameters is valid, in this case set nothing */
463       break;
464     default:
465       GST_WARNING ("Subclass %s of FsSession does not override the %s property"
466           " getter",
467           G_OBJECT_TYPE_NAME(object),
468           g_param_spec_get_name (pspec));
469       break;
470   }
471 }
472 
473 static void
fs_session_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)474 fs_session_set_property (GObject *object,
475                          guint prop_id,
476                          const GValue *value,
477                          GParamSpec *pspec)
478 {
479   GST_WARNING ("Subclass %s of FsSession does not override the %s property"
480       " setter",
481       G_OBJECT_TYPE_NAME(object),
482       g_param_spec_get_name (pspec));
483 }
484 
485 static void
fs_session_error_forward(GObject * signal_src,FsError error_no,gchar * error_msg,FsSession * session)486 fs_session_error_forward (GObject *signal_src,
487                           FsError error_no, gchar *error_msg,
488                           FsSession *session)
489 {
490   /* We just need to forward the error signal including a ref to the stream
491    * object (signal_src) */
492   g_signal_emit (session, signals[ERROR_SIGNAL], 0, signal_src, error_no,
493       error_msg);
494 }
495 
496 /**
497  * fs_session_new_stream:
498  * @session: a #FsSession
499  * @participant: #FsParticipant of a participant for the new stream
500  * @direction: #FsStreamDirection describing the direction of the new stream that will
501  * be created for this participant
502  * @error: location of a #GError, or %NULL if no error occured
503  *
504  * This function creates a stream for the given participant into the active session.
505  *
506  * Returns: (transfer full): the new #FsStream that has been created.
507  * User must unref the #FsStream when the stream is ended. If an error occured,
508  * returns NULL.
509  */
510 FsStream *
fs_session_new_stream(FsSession * session,FsParticipant * participant,FsStreamDirection direction,GError ** error)511 fs_session_new_stream (FsSession *session,
512     FsParticipant *participant,
513     FsStreamDirection direction,
514     GError **error)
515 {
516   FsSessionClass *klass;
517   FsStream *new_stream = NULL;
518 
519   g_return_val_if_fail (session, NULL);
520   g_return_val_if_fail (FS_IS_SESSION (session), NULL);
521   klass = FS_SESSION_GET_CLASS (session);
522   g_return_val_if_fail (klass->new_stream, NULL);
523 
524   new_stream = klass->new_stream (session, participant, direction, error);
525 
526   if (!new_stream)
527     return NULL;
528 
529   /* Let's catch all stream errors and forward them */
530   g_signal_connect_object (new_stream, "error",
531       G_CALLBACK (fs_session_error_forward), session, 0);
532 
533   return new_stream;
534 }
535 
536 /**
537  * fs_session_start_telephony_event:
538  * @session: a #FsSession
539  * @event: A #FsStreamDTMFEvent or another number defined at
540  * http://www.iana.org/assignments/audio-telephone-event-registry
541  * @volume: The volume in dBm0 without the negative sign. Should be between
542  * 0 and 36. Higher values mean lower volume
543  *
544  * This function will start sending a telephony event (such as a DTMF
545  * tone) on the #FsSession. You have to call the function
546  * fs_session_stop_telephony_event() to stop it.
547  *
548  * If this function returns %TRUE, a "farstream-telephony-event-started" will
549  * always be emitted when the event is actually played out.
550  *
551  * Returns: %TRUE if sucessful, it can return %FALSE if the #FsStream
552  * does not support this telephony event.
553  */
554 gboolean
fs_session_start_telephony_event(FsSession * session,guint8 event,guint8 volume)555 fs_session_start_telephony_event (FsSession *session, guint8 event,
556                                   guint8 volume)
557 {
558   FsSessionClass *klass;
559 
560   g_return_val_if_fail (session, FALSE);
561   g_return_val_if_fail (FS_IS_SESSION (session), FALSE);
562   klass = FS_SESSION_GET_CLASS (session);
563 
564   if (klass->start_telephony_event) {
565     return klass->start_telephony_event (session, event, volume);
566   } else {
567     GST_WARNING ("start_telephony_event not defined in class");
568   }
569   return FALSE;
570 }
571 
572 /**
573  * fs_session_stop_telephony_event:
574  * @session: an #FsSession
575  *
576  * This function will stop sending a telephony event started by
577  * fs_session_start_telephony_event(). If the event was being sent
578  * for less than 50ms, it will be sent for 50ms minimum. If the
579  * duration was a positive and the event is not over, it will cut it
580  * short.
581  *
582  * If this function returns %TRUE, a "farstream-telephony-event-stopped" will
583  * always be emitted when the event is actually stopped.
584 
585  * Returns: %TRUE if sucessful, it can return %FALSE if the #FsSession
586  * does not support telephony events or if no telephony event is being sent
587  */
588 gboolean
fs_session_stop_telephony_event(FsSession * session)589 fs_session_stop_telephony_event (FsSession *session)
590 {
591   FsSessionClass *klass;
592 
593   g_return_val_if_fail (session, FALSE);
594   g_return_val_if_fail (FS_IS_SESSION (session), FALSE);
595   klass = FS_SESSION_GET_CLASS (session);
596 
597   if (klass->stop_telephony_event) {
598     return klass->stop_telephony_event (session);
599   } else {
600     GST_WARNING ("stop_telephony_event not defined in class");
601   }
602   return FALSE;
603 }
604 
605 /**
606  * fs_session_set_send_codec:
607  * @session: a #FsSession
608  * @send_codec: a #FsCodec representing the codec to send
609  * @error: location of a #GError, or %NULL if no error occured
610  *
611  * This function will set the currently being sent codec for all streams in this
612  * session. The given #FsCodec must be taken directly from the #codecs
613  * property of the session. If the given codec is not in the codecs
614  * list, @error will be set and %FALSE will be returned. The @send_codec will be
615  * copied so it must be free'd using fs_codec_destroy() when done.
616  *
617  * Returns: %FALSE if the send codec couldn't be set.
618  */
619 gboolean
fs_session_set_send_codec(FsSession * session,FsCodec * send_codec,GError ** error)620 fs_session_set_send_codec (FsSession *session, FsCodec *send_codec,
621                            GError **error)
622 {
623   FsSessionClass *klass;
624 
625   g_return_val_if_fail (session, FALSE);
626   g_return_val_if_fail (FS_IS_SESSION (session), FALSE);
627   klass = FS_SESSION_GET_CLASS (session);
628 
629   if (klass->set_send_codec) {
630     return klass->set_send_codec (session, send_codec, error);
631   } else {
632     GST_WARNING ("set_send_codec not defined in class");
633     g_set_error (error, FS_ERROR, FS_ERROR_NOT_IMPLEMENTED,
634       "set_send_codec not defined in class");
635   }
636   return FALSE;
637 }
638 
639 /**
640  * fs_session_set_codec_preferences:
641  * @session: a #FsSession
642  * @codec_preferences: (element-type FsCodec) (allow-none): a #GList of #FsCodec with the
643  *   desired configuration
644  * @error: location of a #GError, or %NULL if no error occured
645  *
646  * Set the list of desired codec preferences. The user may
647  * change this value during an ongoing session. Note that doing this can cause
648  * the codecs to change. Therefore this requires the user to fetch
649  * the new codecs and renegotiate them with the peers. It is a #GList
650  * of #FsCodec. The changes are immediately effective.
651  * The function does not take ownership of the list.
652  *
653  * The payload type may be a valid dynamic PT (96-127), %FS_CODEC_ID_DISABLE
654  * or %FS_CODEC_ID_ANY. If the encoding name is "reserve-pt", then the
655  * payload type of the codec will be "reserved" and not be used by any
656  * dynamically assigned payload type.
657  *
658  * If the list of specifications would invalidate all codecs, an error will
659  * be returned.
660  *
661  * Returns: %TRUE on success, %FALSE on error.
662  */
663 gboolean
fs_session_set_codec_preferences(FsSession * session,GList * codec_preferences,GError ** error)664 fs_session_set_codec_preferences (FsSession *session,
665     GList *codec_preferences,
666     GError **error)
667 {
668   FsSessionClass *klass;
669 
670   g_return_val_if_fail (session, FALSE);
671   g_return_val_if_fail (FS_IS_SESSION (session), FALSE);
672   klass = FS_SESSION_GET_CLASS (session);
673 
674   if (klass->set_codec_preferences) {
675     return klass->set_codec_preferences (session, codec_preferences, error);
676   } else {
677     GST_WARNING ("set_send_preferences not defined in class");
678     g_set_error (error, FS_ERROR, FS_ERROR_NOT_IMPLEMENTED,
679         "set_codec_preferences not defined in class");
680   }
681   return FALSE;
682 }
683 
684 /**
685  * fs_session_emit_error:
686  * @session: #FsSession on which to emit the error signal
687  * @error_no: The number of the error of type #FsError
688  * @error_msg: Error message
689  *
690  * This function emit the "error" signal on a #FsSession, it should only be
691  * called by subclasses.
692  */
693 void
fs_session_emit_error(FsSession * session,gint error_no,const gchar * error_msg)694 fs_session_emit_error (FsSession *session,
695     gint error_no,
696     const gchar *error_msg)
697 {
698   g_signal_emit (session, signals[ERROR_SIGNAL], 0, session, error_no,
699       error_msg);
700 }
701 
702 /**
703  * fs_session_list_transmitters:
704  * @session: A #FsSession
705  *
706  * Get the list of all available transmitters for this session.
707  *
708  * Returns: (transfer full): a newly-allocagted %NULL terminated array of
709  * named of transmitters or %NULL if no transmitter is needed for this type of
710  * session. It should be freed with g_strfreev().
711  */
712 
713 gchar **
fs_session_list_transmitters(FsSession * session)714 fs_session_list_transmitters (FsSession *session)
715 {
716   FsSessionClass *klass;
717 
718   g_return_val_if_fail (session, NULL);
719   g_return_val_if_fail (FS_IS_SESSION (session), NULL);
720   klass = FS_SESSION_GET_CLASS (session);
721 
722   if (klass->list_transmitters) {
723     return klass->list_transmitters (session);
724   } else {
725     return NULL;
726   }
727 }
728 
729 
730 /**
731  * fs_session_get_stream_transmitter_type:
732  * @session: A #FsSession
733  * @transmitter: The name of the transmitter
734  *
735  * Returns the GType of the stream transmitter, bindings can use it
736  * to validate/convert the parameters passed to fs_session_new_stream().
737  *
738  * Returns: The #GType of the stream transmitter
739  */
740 GType
fs_session_get_stream_transmitter_type(FsSession * session,const gchar * transmitter)741 fs_session_get_stream_transmitter_type (FsSession *session,
742     const gchar *transmitter)
743 {
744   FsSessionClass *klass;
745 
746   g_return_val_if_fail (session, 0);
747   g_return_val_if_fail (FS_IS_SESSION (session), 0);
748   klass = FS_SESSION_GET_CLASS (session);
749 
750   if (klass->get_stream_transmitter_type)
751     return klass->get_stream_transmitter_type (session, transmitter);
752 
753   return 0;
754 }
755 
756 /**
757  * fs_session_codecs_need_resend:
758  * @session: a #FsSession
759  * @old_codecs: (element-type FsCodec) (transfer none) (allow-none):
760  *  Codecs previously retrieved from the #FsSession:codecs property
761  * @new_codecs: (element-type FsCodec) (transfer none) (allow-none):
762  *   Codecs recently retrieved from the #FsSession:codecs property
763  *
764  * Some codec updates need to be reliably transmitted to the other side
765  * because they contain important parameters required to decode the media.
766  * Other codec updates, caused by user action, don't.
767  *
768  * Returns: (element-type FsCodec) (transfer full): A new #GList of
769  *  #FsCodec that need to be resent or %NULL if there are none. This
770  *  list must be freed with fs_codec_list_destroy().
771  */
772 GList *
fs_session_codecs_need_resend(FsSession * session,GList * old_codecs,GList * new_codecs)773 fs_session_codecs_need_resend (FsSession *session,
774     GList *old_codecs, GList *new_codecs)
775 {
776   FsSessionClass *klass;
777 
778   g_return_val_if_fail (session, 0);
779   g_return_val_if_fail (FS_IS_SESSION (session), 0);
780   klass = FS_SESSION_GET_CLASS (session);
781 
782   if (klass->codecs_need_resend)
783     return klass->codecs_need_resend (session, old_codecs, new_codecs);
784 
785   return NULL;
786 }
787 
788 /**
789  * fs_session_set_encryption_parameters:
790  * @session: a #FsSession
791  * @parameters: (transfer none) (allow-none): a #GstStructure containing the
792  *   encryption  parameters or %NULL to disable encryption
793  * @error: the location where to store a #GError or %NULL
794  *
795  * Sets encryption parameters. The exact parameters depend on the type of
796  * plugin being used.
797  *
798  * Returns: %TRUE if the encryption parameters could be set, %FALSE otherwise
799  * Since: UNRELEASED
800  */
801 gboolean
fs_session_set_encryption_parameters(FsSession * session,GstStructure * parameters,GError ** error)802 fs_session_set_encryption_parameters (FsSession *session,
803     GstStructure *parameters, GError **error)
804 {
805   FsSessionClass *klass;
806 
807   g_return_val_if_fail (session, FALSE);
808   g_return_val_if_fail (FS_IS_SESSION (session), FALSE);
809   klass = FS_SESSION_GET_CLASS (session);
810 
811   if (klass->set_encryption_parameters)
812     return klass->set_encryption_parameters (session, parameters, error);
813 
814   g_set_error (error, FS_ERROR, FS_ERROR_NOT_IMPLEMENTED,
815       "Does not support encryption");
816 
817   return FALSE;
818 }
819 
820 /**
821  * fs_session_destroy:
822  * @session: a #FsSession
823  *
824  * This will cause the session to remove all links to other objects and to
825  * remove itself from the #FsConference, it will also destroy all #FsStream
826  * inside this #FsSession Once a #FsSession has been destroyed, it
827  * can not be used anymore.
828  *
829  * It is strongly recommended to call this function from the main thread because
830  * releasing the application's reference to a session.
831  */
832 
833 void
fs_session_destroy(FsSession * session)834 fs_session_destroy (FsSession *session)
835 {
836   g_return_if_fail (session);
837   g_return_if_fail (FS_IS_SESSION (session));
838 
839   g_object_run_dispose (G_OBJECT (session));
840 }
841 
842 static gboolean
check_message(GstMessage * message,FsSession * session,const gchar * message_name)843 check_message (GstMessage *message,
844     FsSession *session,
845     const gchar *message_name)
846 {
847   const GstStructure *s;
848   const GValue *value;
849   FsSession *message_session;
850 
851   if (GST_MESSAGE_TYPE (message) != GST_MESSAGE_ELEMENT)
852     return FALSE;
853 
854   s = gst_message_get_structure (message);
855 
856   if (!gst_structure_has_name (s, message_name))
857     return FALSE;
858 
859   value = gst_structure_get_value (s, "session");
860   if (!value || !G_VALUE_HOLDS (value, FS_TYPE_SESSION))
861     return FALSE;
862   message_session = g_value_get_object (value);
863 
864   if (session != message_session)
865     return FALSE;
866 
867   return TRUE;
868 }
869 
870 /**
871  * fs_session_parse_send_codec_changed:
872  * @session: a #FsSession to match against the message
873  * @message: a #GstMessage to parse
874  * @codec: (out) (transfer none): Returns the #FsCodec in the message if not
875  *   %NULL.
876  * @secondary_codecs: (out) (transfer none) (element-type FsCodec):
877  *  Returns a #GList of #FsCodec of the message if not %NULL
878  *
879  * Parses a "farstream-send-codec-changed" message and checks if it matches
880  * the @session parameters.
881  *
882  * Returns: %TRUE if the message matches the session and is valid.
883  */
884 gboolean
fs_session_parse_send_codec_changed(FsSession * session,GstMessage * message,FsCodec ** codec,GList ** secondary_codecs)885 fs_session_parse_send_codec_changed ( FsSession *session,
886     GstMessage *message,
887     FsCodec **codec,
888     GList **secondary_codecs)
889 {
890   const GstStructure *s;
891   const GValue *value;
892 
893   g_return_val_if_fail (session != NULL, FALSE);
894 
895   if (!check_message (message, session, "farstream-send-codec-changed"))
896     return FALSE;
897 
898   s = gst_message_get_structure (message);
899 
900   value = gst_structure_get_value (s, "codec");
901   if (!value || !G_VALUE_HOLDS (value, FS_TYPE_CODEC))
902     return FALSE;
903   if (codec)
904     *codec = g_value_get_boxed (value);
905 
906   value = gst_structure_get_value (s, "secondary-codecs");
907   if (!value || !G_VALUE_HOLDS (value, FS_TYPE_CODEC_LIST))
908     return FALSE;
909   if (secondary_codecs)
910     *secondary_codecs = g_value_get_boxed (value);
911 
912   return TRUE;
913 }
914 
915 
916 /**
917  * fs_session_parse_codecs_changed:
918  * @session: a #FsSession to match against the message
919  * @message: a #GstMessage to parse
920  *
921  * Parses a "farstream-codecs-changed" message and checks if it matches
922  * the @session parameters.
923  *
924  * Returns: %TRUE if the message matches the session and is valid.
925  */
926 gboolean
fs_session_parse_codecs_changed(FsSession * session,GstMessage * message)927 fs_session_parse_codecs_changed (FsSession *session,
928     GstMessage *message)
929 {
930   g_return_val_if_fail (session != NULL, FALSE);
931 
932   return check_message (message, session, "farstream-codecs-changed");
933 }
934 
935 /**
936  * fs_session_parse_telephony_event_started:
937  * @session: a #FsSession to match against the message
938  * @message: a #GstMessage to parse
939  * @method: (out): Returns the #FsDTMFMethod in the message if not %NULL.
940  * @event: (out): Returns the #FsDTMFEvent in the message if not %NULL.
941  * @volume: (out): Returns the volume in the message if not %NULL.
942  *
943  * Parses a "farstream-telephony-event-started" message and checks if it matches
944  * the @session parameters.
945  *
946  * Returns: %TRUE if the message matches the session and is valid.
947  */
948 gboolean
fs_session_parse_telephony_event_started(FsSession * session,GstMessage * message,FsDTMFMethod * method,FsDTMFEvent * event,guint8 * volume)949 fs_session_parse_telephony_event_started (FsSession *session,
950     GstMessage *message,
951     FsDTMFMethod *method, FsDTMFEvent *event,
952     guint8 *volume)
953 {
954   const GstStructure *s;
955   const GValue *value;
956 
957   g_return_val_if_fail (session != NULL, FALSE);
958 
959   if (!check_message (message, session, "farstream-telephony-event-started"))
960     return FALSE;
961 
962   s = gst_message_get_structure (message);
963 
964   if (!gst_structure_has_field_typed (s, "method", FS_TYPE_DTMF_METHOD))
965     return FALSE;
966   if (method)
967     gst_structure_get_enum (s, "method", FS_TYPE_DTMF_METHOD, (gint*) method);
968 
969   if (!gst_structure_has_field_typed (s, "event", FS_TYPE_DTMF_EVENT))
970     return FALSE;
971   if (event)
972     gst_structure_get_enum (s, "event", FS_TYPE_DTMF_EVENT, (gint*) event);
973 
974   value = gst_structure_get_value (s, "volume");
975   if (!value || !G_VALUE_HOLDS (value, G_TYPE_UCHAR))
976     return FALSE;
977   if (volume)
978     *volume = g_value_get_uchar (value);
979 
980   return TRUE;
981 }
982 
983 
984 /**
985  * fs_session_parse_telephony_event_stopped:
986  * @session: a #FsSession to match against the message
987  * @message: a #GstMessage to parse
988  * @method: (out): Returns the #FsDTMFMethod in the message if not %NULL.
989  *
990  * Parses a "farstream-telephony-event-stopped" message and checks if it matches
991  * the @session parameters.
992  *
993  * Returns: %TRUE if the message matches the session and is valid.
994  */
995 gboolean
fs_session_parse_telephony_event_stopped(FsSession * session,GstMessage * message,FsDTMFMethod * method)996 fs_session_parse_telephony_event_stopped (FsSession *session,
997     GstMessage *message,
998      FsDTMFMethod *method)
999 {
1000   const GstStructure *s;
1001 
1002   g_return_val_if_fail (session != NULL, FALSE);
1003 
1004   if (!check_message (message, session, "farstream-telephony-event-stopped"))
1005     return FALSE;
1006 
1007   s = gst_message_get_structure (message);
1008 
1009   if (!gst_structure_has_field_typed (s, "method", FS_TYPE_DTMF_METHOD))
1010     return FALSE;
1011   if (method)
1012     gst_structure_get_enum (s, "method", FS_TYPE_DTMF_METHOD, (gint*) method);
1013 
1014   return TRUE;
1015 }
1016 
1017 /**
1018  * fs_session_set_allowed_caps:
1019  * @session: a #FsSession
1020  * @sink_caps: (allow-none): Caps for the sink pad or %NULL
1021  * @src_caps: (allow-none): Caps for the src pad or %NULL
1022  * @error: the location where a #GError can be stored or %NULL
1023  *
1024  * Sets the allowed caps for the sink and source pads for this #FsSession.
1025  * Only codecs that can take the input specified by the @sink_caps and
1026  * can produce output as specified by the @src_caps will be produced
1027  * in the #FsSession:codecs property and so only those will be negotiated.
1028  *
1029  * If %NULL is passed to either @src_caps or @sink_caps, it is not changed.
1030  *
1031  * The default is "video/x-raw" for a video stream, "audio/x-raw" for an audio
1032  * stream and "ANY" for an application stream.
1033  *
1034  * The values can be retrived using the #FsSession:allowed-src-caps and
1035  * #FsSession:allowed-sink-caps properties.
1036  *
1037  * Returns: %TRUE if the new filter caps were acceptable.
1038  *
1039  * Since: UNRELEASED
1040  */
1041 gboolean
fs_session_set_allowed_caps(FsSession * session,GstCaps * sink_caps,GstCaps * src_caps,GError ** error)1042 fs_session_set_allowed_caps (FsSession *session, GstCaps *sink_caps,
1043     GstCaps *src_caps, GError **error)
1044 {
1045   FsSessionClass *klass;
1046 
1047   g_return_val_if_fail (FS_IS_SESSION (session), FALSE);
1048 
1049   if (sink_caps == NULL && src_caps == NULL)
1050     return TRUE;
1051 
1052   klass = FS_SESSION_GET_CLASS (session);
1053 
1054   if (klass->set_allowed_caps)
1055     return klass->set_allowed_caps (session, sink_caps, src_caps, error);
1056 
1057   g_set_error (error, FS_ERROR, FS_ERROR_NOT_IMPLEMENTED,
1058       "set_allowed_caps is not implemented");
1059 
1060   return FALSE;
1061 }
1062