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