diff options
author | Olivier Crête <olivier.crete@collabora.com> | 2012-02-20 17:31:41 -0500 |
---|---|---|
committer | Olivier Crête <olivier.crete@collabora.com> | 2012-02-20 17:31:41 -0500 |
commit | 7d56e7b4b3c801a5ef5e9f88fc34c84656e0aa0d (patch) | |
tree | fa2d5d617855b7a849c65197e474bbfe823f601b | |
parent | ac8cae2410b5ba8c59249d51ba0b53b79754ea9c (diff) | |
parent | bf1bb9987d0f9ad5bdccc42d67fb0a8e78feaf0a (diff) | |
download | telepathy-farstream-7d56e7b4b3c801a5ef5e9f88fc34c84656e0aa0d.tar.gz |
Merge branch 'call1'
Conflicts:
configure.ac
examples/call-handler.c
extensions/Makefile.am
extensions/call-content.xml
telepathy-farstream/call-content.c
telepathy-farstream/call-stream.c
telepathy-farstream/stream.c
telepathy-farstream/telepathy-farstream.c
53 files changed, 2309 insertions, 5339 deletions
diff --git a/Makefile.am b/Makefile.am index 5ee77f3..34daccf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -7,7 +7,6 @@ endif SUBDIRS = m4 \ tools \ - extensions \ telepathy-farstream \ doc \ $(PYTHON_SUBDIR) \ diff --git a/configure.ac b/configure.ac index 62eeb99..7dae38c 100644 --- a/configure.ac +++ b/configure.ac @@ -9,7 +9,7 @@ AC_PREREQ([2.59]) m4_define([tp_farstream_major_version], [0]) m4_define([tp_farstream_minor_version], [2]) -m4_define([tp_farstream_micro_version], [99]) +m4_define([tp_farstream_micro_version], [0]) m4_define([tp_farstream_nano_version], [1]) dnl CURRENT, REVISION, AGE @@ -17,8 +17,8 @@ dnl - library source changed -> increment REVISION dnl - interfaces added/removed/changed -> increment CURRENT, REVISION = 0 dnl - interfaces added -> increment AGE dnl - interfaces removed -> AGE = 0 -m4_define([tp_farstream_lt_current], [0]) -m4_define([tp_farstream_lt_revision], [2]) +m4_define([tp_farstream_lt_current], [1]) +m4_define([tp_farstream_lt_revision], [0]) m4_define([tp_farstream_lt_age], [0]) @@ -142,7 +142,6 @@ AC_OUTPUT( Makefile \ doc/Makefile \ doc/lib/Makefile \ m4/Makefile \ - extensions/Makefile \ examples/Makefile \ telepathy-farstream/Makefile \ telepathy-farstream/telepathy-farstream.pc \ diff --git a/doc/lib/Makefile.am b/doc/lib/Makefile.am index 674c326..47587f8 100644 --- a/doc/lib/Makefile.am +++ b/doc/lib/Makefile.am @@ -46,7 +46,7 @@ CFILE_GLOB=$(top_srcdir)/telepathy-farstream/channel.c $(top_srcdir)/telepathy-f # e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h IGNORE_HFILES=channel-priv.h content-priv.h session-priv.h stream-priv.h \ stream.h call-channel.h call-content.h call-stream.h tf-signals-marshal.h \ - media-signalling-channel.h media-signalling-content.h + media-signalling-channel.h media-signalling-content.h utils.h # Images to copy into HTML directory. # e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png diff --git a/doc/lib/telepathy-farstream-sections.txt b/doc/lib/telepathy-farstream-sections.txt index 4a1382d..41903c4 100644 --- a/doc/lib/telepathy-farstream-sections.txt +++ b/doc/lib/telepathy-farstream-sections.txt @@ -1,6 +1,5 @@ <SECTION> -<TITLE>Core</TITLE> -tf_init +<TITLE>Utilities</TITLE> tp_media_type_to_fs </SECTION> @@ -12,6 +11,10 @@ TfContentClass tf_content_iterate_src_pads tf_content_error tf_content_error_literal +tf_content_receiving_failed +tf_content_receiving_failed_literal +tf_content_sending_failed +tf_content_sending_failed_literal <SUBSECTION Private> TfContentPrivate <SUBSECTION Standard> diff --git a/examples/Makefile.am b/examples/Makefile.am index b7e60a7..ca22edf 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -2,7 +2,6 @@ noinst_PROGRAMS = call-handler LDADD = \ ../telepathy-farstream/libtelepathy-farstream.la \ - ../extensions/libfuture-extensions.la \ $(GLIB_LIBS) \ $(DBUS_LIBS) \ $(GST_LIBS) \ diff --git a/examples/call-handler.c b/examples/call-handler.c index f56763e..58f2d6c 100644 --- a/examples/call-handler.c +++ b/examples/call-handler.c @@ -19,7 +19,6 @@ #include <gst/gst.h> #include <telepathy-glib/telepathy-glib.h> -#include <extensions/extensions.h> #include <farstream/fs-element-added-notifier.h> #include <farstream/fs-utils.h> #include <telepathy-farstream/telepathy-farstream.h> @@ -546,7 +545,7 @@ new_call_channel_cb (TpSimpleHandler *handler, tp_handle_channels_context_accept (handler_context); - tf_future_cli_channel_type_call_call_accept (proxy, -1, + tp_cli_channel_type_call_call_accept (proxy, -1, NULL, NULL, NULL, NULL); context->proxy = g_object_ref (proxy); @@ -559,17 +558,16 @@ int main (int argc, char **argv) { TpBaseClient *client; - TpAccountManager *account_manager; + TpAccountManager *am; g_type_init (); - tf_init (); gst_init (&argc, &argv); loop = g_main_loop_new (NULL, FALSE); - account_manager = tp_account_manager_dup (); + am = tp_account_manager_dup (); - client = tp_simple_handler_new_with_am (account_manager, + client = tp_simple_handler_new_with_am (am, FALSE, FALSE, "TpFsCallHandlerDemo", @@ -581,35 +579,35 @@ main (int argc, char **argv) tp_base_client_take_handler_filter (client, tp_asv_new ( TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, - TF_FUTURE_IFACE_CHANNEL_TYPE_CALL, + TP_IFACE_CHANNEL_TYPE_CALL, TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, TP_HANDLE_TYPE_CONTACT, - TF_FUTURE_PROP_CHANNEL_TYPE_CALL_INITIAL_AUDIO, G_TYPE_BOOLEAN, + TP_PROP_CHANNEL_TYPE_CALL_INITIAL_AUDIO, G_TYPE_BOOLEAN, TRUE, NULL)); tp_base_client_take_handler_filter (client, tp_asv_new ( TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, - TF_FUTURE_IFACE_CHANNEL_TYPE_CALL, + TP_IFACE_CHANNEL_TYPE_CALL, TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, TP_HANDLE_TYPE_CONTACT, - TF_FUTURE_PROP_CHANNEL_TYPE_CALL_INITIAL_VIDEO, G_TYPE_BOOLEAN, + TP_PROP_CHANNEL_TYPE_CALL_INITIAL_VIDEO, G_TYPE_BOOLEAN, TRUE, NULL)); tp_base_client_add_handler_capabilities_varargs (client, - TF_FUTURE_IFACE_CHANNEL_TYPE_CALL "/video/h264", - TF_FUTURE_IFACE_CHANNEL_TYPE_CALL "/shm", - TF_FUTURE_IFACE_CHANNEL_TYPE_CALL "/ice", - TF_FUTURE_IFACE_CHANNEL_TYPE_CALL "/gtalk-p2p", + TP_IFACE_CHANNEL_TYPE_CALL "/video/h264", + TP_IFACE_CHANNEL_TYPE_CALL "/shm", + TP_IFACE_CHANNEL_TYPE_CALL "/ice", + TP_IFACE_CHANNEL_TYPE_CALL "/gtalk-p2p", NULL); tp_base_client_register (client, NULL); g_main_loop_run (loop); - g_object_unref (account_manager); + g_object_unref (am); g_object_unref (client); g_main_loop_unref (loop); diff --git a/extensions/Call_Content.xml b/extensions/Call_Content.xml deleted file mode 100644 index 270d99b..0000000 --- a/extensions/Call_Content.xml +++ /dev/null @@ -1,255 +0,0 @@ -<?xml version="1.0" ?> -<node name="/Call_Content" - xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"> - <tp:copyright>Copyright © 2009-2010 Collabora Ltd.</tp:copyright> - <tp:copyright>Copyright © 2009-2010 Nokia Corporation</tp:copyright> - <tp:license xmlns="http://www.w3.org/1999/xhtml"> - <p>This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version.</p> - - <p>This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details.</p> - - <p>You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA.</p> - </tp:license> - - <interface name="org.freedesktop.Telepathy.Call.Content.DRAFT" - tp:causes-havoc="experimental"> - <tp:added version="0.19.0">(draft 1)</tp:added> - - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - This object represents one Content inside a <tp:dbus-ref - namespace="ofdT.Channel.Type">Call.DRAFT</tp:dbus-ref>. For - example, in an audio/video call there would be one audio content - and one video content. Each content has one or more <tp:dbus-ref - namespace="ofdT.Call">Stream.DRAFT</tp:dbus-ref> objects which - represent the actual transport to one or more remote contacts. - </tp:docstring> - - <tp:enum name="Content_Removal_Reason" type="u"> - <tp:added version="0.21.2"/> - <tp:docstring> - A representation of the reason for a content to be removed, - which may be used by simple clients, or used as a fallback - when the DBus_Reason is not understood. This enum will be - extended with future reasons as and when appropriate, so - clients SHOULD keep up to date with its values, but also be - happy to fallback to the Unknown value when an unknown value - is encountered. - </tp:docstring> - - <tp:enumvalue suffix="Unknown" value="0"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - We just don't know. Unknown values of this enum SHOULD also be - treated like this. - </tp:docstring> - </tp:enumvalue> - - <tp:enumvalue suffix="User_Requested" value="1"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>The local user requests that this content is removed - from the call.</p> - </tp:docstring> - </tp:enumvalue> - - <tp:enumvalue suffix="Error" value="2"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>There is an error with the content which means that it - has to be removed from the call.</p> - </tp:docstring> - </tp:enumvalue> - - <tp:enumvalue suffix="Unsupported" value="3"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>Some aspect of the content is unsupported so has to be - removed from the call.</p> - </tp:docstring> - </tp:enumvalue> - </tp:enum> - - <method name="Remove" tp:name-for-bindings="Remove"> - <tp:changed version="0.21.2">previously there were no - arguments</tp:changed> - <tp:docstring> - Remove the content from the call. - </tp:docstring> - - <arg direction="in" name="Reason" type="u" - tp:type="Content_Removal_Reason"> - <tp:docstring> - A generic hangup reason. - </tp:docstring> - </arg> - - <arg direction="in" name="Detailed_Removal_Reason" type="s" - tp:type="DBus_Error_Name"> - <tp:docstring> - A more specific reason for the content removal, if one is - available, or an empty string. - </tp:docstring> - </arg> - - <arg direction="in" name="Message" type="s"> - <tp:docstring> - A human-readable message for the reason of removing the - content, such as "Fatal streaming failure" or "no codec - intersection". This property can be left empty if no reason - is to be given. - </tp:docstring> - </arg> - - <tp:possible-errors> - <tp:error name="org.freedesktop.Telepathy.Error.NetworkError" /> - <tp:error name="org.freedesktop.Telepathy.Error.NotImplemented"> - <tp:docstring> - Raised when a Call doesn't support removing contents - (e.g. a Google Talk video call). - </tp:docstring> - </tp:error> - </tp:possible-errors> - </method> - - <signal name="Removed" tp:name-for-bindings="Removed"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>Emitted when the content is removed from the call. This - is the same as the <tp:dbus-ref - namespace="ofdT.Channel.Type">Call.DRAFT.ContentRemoved</tp:dbus-ref> - signal.</p> - </tp:docstring> - </signal> - - <property name="Interfaces" tp:name-for-bindings="Interfaces" - type="as" tp:type="DBus_Interface[]" access="read" tp:immutable="yes"> - <tp:added version="0.19.11"/> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>Extra interfaces provided by this content, such as <tp:dbus-ref - namespace="ofdT.Call">Content.Interface.Media.DRAFT</tp:dbus-ref> or - <tp:dbus-ref namespace="ofdT.Call">Content.Interface.Mute.DRAFT</tp:dbus-ref>. - This SHOULD NOT include the Content interface itself, and cannot - change once the content has been created.</p> - </tp:docstring> - </property> - - <property name="Name" tp:name-for-bindings="Name" type="s" access="read" - tp:immutable="yes"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>The name of the content.</p> - - <tp:rationale> - The content name property should be meaningful, so should be - given a name which is significant to the user. The name - could be the "audio" or "video" string localized, or perhaps - include some string identifying the source, such as a webcam - identifier. - </tp:rationale> - </tp:docstring> - </property> - - <property name="Type" tp:name-for-bindings="Type" - type="u" tp:type="Media_Stream_Type" access="read" tp:immutable="yes"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>The media type of this content.</p> - </tp:docstring> - </property> - - <tp:enum name="Call_Content_Disposition" type="u"> - <tp:docstring> - The disposition of this content, which defines whether to - automatically start sending data on the streams when - <tp:dbus-ref - namespace="ofdT.Channel.Type">Call.DRAFT</tp:dbus-ref> is - called on the channel. - </tp:docstring> - - <tp:enumvalue suffix="None" value="0"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - The content has no specific disposition - </tp:docstring> - </tp:enumvalue> - - <tp:enumvalue suffix="Initial" value="1"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>The content was initially part of the call. When - <tp:dbus-ref - namespace="ofdT.Channel.Type.Call.DRAFT">Accept</tp:dbus-ref> - is called on the channel, all streams of this content with - <tp:dbus-ref - namespace="ofdT.Call.Stream.DRAFT">LocalSendingState</tp:dbus-ref> - set to <tp:type>Sending_State</tp:type>_Pending_Send will be - moved to <tp:type>Sending_State</tp:type>_Sending as if - <tp:dbus-ref - namespace="ofdT.Call.Stream.DRAFT">SetSending</tp:dbus-ref> - (True) had been called.</p> - </tp:docstring> - </tp:enumvalue> - </tp:enum> - - <property name="Disposition" tp:name-for-bindings="Disposition" - type="u" tp:type="Call_Content_Disposition" access="read" - tp:immutable="yes"> - <tp:docstring> - The disposition of this content. - </tp:docstring> - </property> - - <signal name="StreamsAdded" tp:name-for-bindings="Streams_Added"> - <tp:changed version="0.21.2">plural version, renamed from - StreamAdded</tp:changed> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>Emitted when streams are added to a call.</p> - </tp:docstring> - <arg name="Streams" type="ao"> - <tp:docstring> - The <tp:dbus-ref - namespace="ofdT.Call">Stream.DRAFT</tp:dbus-ref>s which were - added. - </tp:docstring> - </arg> - </signal> - - <signal name="StreamsRemoved" tp:name-for-bindings="Streams_Removed"> - <tp:changed version="0.21.2">plural version, renamed from - StreamRemoved</tp:changed> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>Emitted when streams are removed from a call</p> - </tp:docstring> - <arg name="Streams" type="ao"> - <tp:docstring> - The <tp:dbus-ref - namespace="ofdT.Call">Stream.DRAFT</tp:dbus-ref>s which were - removed. - </tp:docstring> - </arg> - </signal> - - <property name="Streams" tp:name-for-bindings="Streams" - type="ao" access="read"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>The list of <tp:dbus-ref namespace="ofdT.Call" - >Stream.DRAFT</tp:dbus-ref> objects that exist in this - content.</p> - - <tp:rationale> - In a conference call multiple parties can share one media - content (say, audio), but the streaming of that media can - either be shared or separate. For example, in a multicast - conference all contacts would share one stream, while in a - Muji conference there would be a stream for each - participant. - </tp:rationale> - - <p>Change notification is through the - <tp:member-ref>StreamsAdded</tp:member-ref> and - <tp:member-ref>StreamsRemoved</tp:member-ref> signals.</p> - </tp:docstring> - </property> - </interface> -</node> -<!-- vim:set sw=2 sts=2 et ft=xml: --> diff --git a/extensions/Call_Content_Codec_Offer.xml b/extensions/Call_Content_Codec_Offer.xml deleted file mode 100644 index f88143f..0000000 --- a/extensions/Call_Content_Codec_Offer.xml +++ /dev/null @@ -1,87 +0,0 @@ -<?xml version="1.0" ?> -<node name="/Call_Content_Codec_Offer" - xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"> - <tp:copyright>Copyright © 2009-2010 Collabora Ltd.</tp:copyright> - <tp:copyright>Copyright © 2009-2010 Nokia Corporation</tp:copyright> - <tp:license xmlns="http://www.w3.org/1999/xhtml"> - <p>This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version.</p> - - <p>This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details.</p> - - <p>You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA.</p> - </tp:license> - - <interface name="org.freedesktop.Telepathy.Call.Content.CodecOffer.DRAFT" - tp:causes-havoc="experimental"> - <tp:added version="0.19.0">(draft 1)</tp:added> - - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - This object represents an offer of a Codec payload mapping. - </tp:docstring> - - <method name="Accept" tp:name-for-bindings="Accept"> - <arg name="Codecs" direction="in" - type="a(usuua{ss})" tp:type="Codec[]"> - <tp:docstring> - The local codec mapping to send to the remote contacts and - to use in the <tp:dbus-ref - namespace="ofdT.Call">Content.DRAFT</tp:dbus-ref>. - </tp:docstring> - </arg> - <tp:docstring> - Accept the updated Codec mapping and update the local mapping. - </tp:docstring> - <tp:possible-errors> - <tp:error name="org.freedesktop.Telepathy.Error.InvalidArgument"> - <tp:docstring> - The codecs given as the argument are invalid in some way. - </tp:docstring> - </tp:error> - </tp:possible-errors> - </method> - - <method name="Reject" tp:name-for-bindings="Reject"> - <tp:docstring> - Reject the proposed update to the codecs - FIXME add error codes and strings here - </tp:docstring> - </method> - - <property name="Interfaces" tp:name-for-bindings="Interfaces" - type="as" tp:type="DBus_Interface[]" access="read" tp:immutable="yes"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>Extra interfaces provided by this codec offer. This SHOULD - NOT include the CodecOffer interface itself, and cannot change - once the content has been created.</p> - </tp:docstring> - </property> - - <property name="RemoteContactCodecs" - tp:name-for-bindings="Remote_Contact_Codecs" - type="a(usuua{ss})" tp:type="Codec[]" access="read" - tp:immutable="yes"> - <tp:docstring> - A list of codecs the remote contact supports. - </tp:docstring> - </property> - - <property name="RemoteContact" tp:name-for-bindings="Remote_Contact" - type="u" tp:type="Contact_Handle" access="read" tp:immutable="yes"> - <tp:docstring> - The contact handle that this codec offer applies to. - </tp:docstring> - </property> - - - </interface> -</node> -<!-- vim:set sw=2 sts=2 et ft=xml: --> diff --git a/extensions/Call_Content_Interface_Audio_Control.xml b/extensions/Call_Content_Interface_Audio_Control.xml deleted file mode 100644 index 1229fb5..0000000 --- a/extensions/Call_Content_Interface_Audio_Control.xml +++ /dev/null @@ -1,111 +0,0 @@ -<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> -<node name="/Call_Content_Interface_Audio_Control" - xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"> - <tp:copyright>Copyright © 2009-2011 Collabora Ltd.</tp:copyright> - <tp:license xmlns="http://www.w3.org/1999/xhtml"> - <p>This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version.</p> - - <p>This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details.</p> - - <p>You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA.</p> - </tp:license> - - <interface name="org.freedesktop.Telepathy.Call1.Content.Interface.AudioControl" - tp:causes-havoc="experimental"> - <tp:added version="0.25.UNRELEASED">(draft 1)</tp:added> - <tp:requires interface="org.freedesktop.Telepathy.Call1.Content.Interface.Media"/> - <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/> - - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>This interface allows the connection manager to be kept informed of, - and control, the input and output volumes of an audio stream. - While generally not needed, if the connection manager needs to - handle stream volumes directly (typically when using - <tp:value-ref>Call_Content_Packetization_Type_Raw</tp:value-ref>), - this interface may be necessary.</p> - - <p>If this interface is present, the handler should call - <tp:member-ref>ReportInputVolume</tp:member-ref> - and <tp:member-ref>ReportOutputVolume</tp:member-ref> whenever the - input and output volume change, both when the user manually modifies - the volume and when the volumes are adjusted in response to - <tp:member-ref>RequestedInputVolume</tp:member-ref> and - <tp:member-ref>RequestedOutputVolume</tp:member-ref> changing.</p> - - <p>The maximum volume as used in this interface represent the unamplified - hardware volume (0 dB). No software amplification should be used to - boost the signal to a higher level when this Interface is in use</p> - </tp:docstring> - - <property name="RequestedInputVolume" tp:type="Audio_Control_Volume" - type="i" access="read" tp:name-for-bindings="Requested_Input_Volume"> - <tp:docstring> - The input volume as requested by the Connection Manager. - Initially and on any changes the client should change its input volume - to match the requested volume. - </tp:docstring> - </property> - - <method name="ReportInputVolume" tp:name-for-bindings="Report_Input_Volume"> - <arg direction="in" name="Volume" tp:type="Audio_Control_Volume" type="i"> - <tp:docstring> - Report the input volume level as set by the client. - </tp:docstring> - </arg> - <tp:docstring> - <p>Report to the CM that the Content input volume has been - changed by the client.</p> - - <p>It is the client's responsibility to change the input volume used for - the content. However, the client MUST call this whenever it changes - input volume for the content.</p> - </tp:docstring> - </method> - - <property name="RequestedOutputVolume" tp:type="Audio_Control_Volume" - type="i" access="read" tp:name-for-bindings="Requested_Output_Volume"> - <tp:docstring> - The input volume as requested by the Connection Manager. - Initially and on any changes the client should change its input volume - to match the requested volume. - </tp:docstring> - </property> - - <method name="ReportOutputVolume" - tp:name-for-bindings="Report_Output_Volume"> - <arg direction="in" name="Volume" tp:type="Audio_Control_Volume" type="i"> - <tp:docstring> - Report the output volume level as set by the client. - </tp:docstring> - </arg> - <tp:docstring> - <p>Report to the CM that the content output volume has been - changed by the client.</p> - - <p>It is the client's responsibility to change the output volume used - for the content. However, the client MUST call this whenever it - changes output volume for the content.</p> - </tp:docstring> - </method> - - <tp:simple-type name="Audio_Control_Volume" type="i"> - <tp:docstring> - <p>A volume value either reported to or requested by the Connection - Manager. This value should either be -1 for an unknown value or in the - range of 0-255, with 0 being the minimal volume and 255 being the - highest unamplified volume the input or output is capable of (known - as 0 dB) - </p> - </tp:docstring> - </tp:simple-type> - </interface> -</node> diff --git a/extensions/Call_Content_Interface_Media.xml b/extensions/Call_Content_Interface_Media.xml deleted file mode 100644 index 038ce8c..0000000 --- a/extensions/Call_Content_Interface_Media.xml +++ /dev/null @@ -1,367 +0,0 @@ -<?xml version="1.0" ?> -<node name="/Call_Content_Interface_Media" - xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"> - <tp:copyright>Copyright © 2009-2010 Collabora Ltd.</tp:copyright> - <tp:copyright>Copyright © 2009-2010 Nokia Corporation</tp:copyright> - <tp:license xmlns="http://www.w3.org/1999/xhtml"> - <p>This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version.</p> - - <p>This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details.</p> - - <p>You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA.</p> - </tp:license> - - <interface name="org.freedesktop.Telepathy.Call.Content.Interface.Media.DRAFT" - tp:causes-havoc="experimental"> - <tp:added version="0.19.0">(draft 1)</tp:added> - <tp:requires interface="org.freedesktop.Telepathy.Call.Content.DRAFT"/> - - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>Interface to use by a software implementation of media - streaming. The reason behind splitting the members of this - interface out from the main <tp:dbus-ref - namespace="ofdT.Call">Content.DRAFT</tp:dbus-ref> interface is - that the software is not necessarily what controls the - media. An example of this is in GSM phones, where the CM just - tells the phone to dial a number and it does the audio routing - in a device specific hardware way and the CM does not need - to concern itself with codecs.</p> - - <h4>Codec negotiation</h4> - - <p>When a new <tp:dbus-ref - namespace="ofdT.Channel.Type">Call.DRAFT</tp:dbus-ref> channel - appears, whether it was requested or not, a <tp:dbus-ref - namespace="ofdT.Call.Content">CodecOffer.DRAFT</tp:dbus-ref> - will either be waiting in the - <tp:member-ref>CodecOffer</tp:member-ref> property, or will - appear at some point via the - <tp:member-ref>NewCodecOffer</tp:member-ref> signal.</p> - - <p>The <tp:dbus-ref - namespace="ofdT.Call.Content.CodecOffer.DRAFT">RemoteContactCodecs</tp:dbus-ref> - property on the codec offer lists the codecs which are - supported by the remote contact, and so will determine the - codecs that should be proposed by the local user's streaming - implementation. An empty list means all codecs can be proposed.</p> - - <p>For incoming calls on protocols where codecs are proposed when - starting the call (for example, <a - href="http://xmpp.org/extensions/xep-0166.html">Jingle</a>), - the <tp:dbus-ref - namespace="ofdT.Call.Content.CodecOffer.DRAFT">RemoteContactCodecs</tp:dbus-ref> - will contain information on the codecs that have already been - proposed by the remote contact, otherwise the codec map will - be the empty list.</p> - - <p>The streaming implementation should look at the remote codec - map and the codecs known by the local user and call - <tp:dbus-ref - namespace="ofdT.Call.Content">CodecOffer.DRAFT.Accept</tp:dbus-ref> - on the intersection of these two codec lists.</p> - - <p>This means that in practice, outgoing calls will have a codec - offer pop up with no information in the <tp:dbus-ref - namespace="ofdT.Call.Content.CodecOffer.DRAFT">RemoteContactCodecs</tp:dbus-ref>, - so the local user will call <tp:dbus-ref - namespace="ofdT.Call.Content.CodecOffer.DRAFT">Accept</tp:dbus-ref> - with the list of all codecs supported. If this codec offer is - accepted, then <tp:member-ref>CodecsChanged</tp:member-ref> - will fire with the details of the codecs passed into - <tp:dbus-ref - namespace="ofdT.Call.Content.CodecOffer.DRAFT">Accept</tp:dbus-ref>. If - the call is incoming, then the <tp:dbus-ref - namespace="ofdT.Call.Content.CodecOffer.DRAFT">RemoteContactCodecs</tp:dbus-ref> - will contain details of the remote contact's codecs and the - local user will call <tp:dbus-ref - namespace="ofdT.Call.Content.CodecOffer.DRAFT">Accept</tp:dbus-ref> - with the codecs that both sides understand. After the codec - set is accepted, <tp:member-ref>CodecsChanged</tp:member-ref> - will fire to signal this change.</p> - - <h4>Protocols without codec negotiation</h4> - - <p>For protocols where the codecs are not negotiable, instead of - popping up the initial content's <tp:dbus-ref - namespace="ofdT.Call.Content">CodecOffer.DRAFT</tp:dbus-ref> - object with an empty <tp:dbus-ref - namespace="ofdT.Call.Content.CodecOffer.DRAFT">RemoteContactCodecs</tp:dbus-ref>, - the CM should set the supported codec values to known codec - values in the said object's codec map.</p> - - <h4>Changing codecs mid-call</h4> - - <p>To update the codec list used mid-call, the - <tp:member-ref>UpdateCodecs</tp:member-ref> method should be - called with details of the new codec list. If this is - accepted, then <tp:member-ref>CodecsChanged</tp:member-ref> - will be emitted with the new codec set.</p> - - <p>If the other side decides to update his or her codec list - during a call, a new <tp:dbus-ref - namespace="ofdT.Call.Content">CodecOffer.DRAFT</tp:dbus-ref> - object will appear through - <tp:member-ref>NewCodecOffer</tp:member-ref> which should be - acted on as documented above.</p> - - </tp:docstring> - - <tp:struct name="Codec" array-name="Codec_List"> - <tp:docstring> - A description of a codec. - </tp:docstring> - <tp:member name="Identifier" type="u"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - Numeric identifier for the codec. This will be used as the PT in the - SDP or content description. - </tp:docstring> - </tp:member> - <tp:member name="Name" type="s"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - The name of the codec. - </tp:docstring> - </tp:member> - <tp:member name="Clockrate" type="u"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - The clockrate of the codec. - </tp:docstring> - </tp:member> - <tp:member name="Channels" type="u"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - Number of channels of the codec if applicable, otherwise 0. - </tp:docstring> - </tp:member> - <tp:member name="Parameters" type="a{ss}" tp:type="String_String_Map"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - Extra parameters for this codec. - </tp:docstring> - </tp:member> - </tp:struct> - - <tp:mapping name="Contact_Codec_Map"> - <tp:docstring> - A map from contact to the list of codecs he or she supports. - </tp:docstring> - <tp:member name="Handle" type="u" tp:type="Contact_Handle"> - <tp:docstring> - A contact handle. - </tp:docstring> - </tp:member> - <tp:member name="Codecs" type="a(usuua{ss})" tp:type="Codec[]"> - <tp:docstring> - The codecs that the contact supports. - </tp:docstring> - </tp:member> - </tp:mapping> - - <tp:struct name="Codec_Offering"> - <tp:docstring> - A codec offer and its corresponding remote contact codec map. - </tp:docstring> - <tp:member name="Codec_Offer" type="o"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - The object path to the <tp:dbus-ref namespace="ofdT.Call.Content" - >CodecOffer.DRAFT</tp:dbus-ref> - </tp:docstring> - </tp:member> - <tp:member name="Remote_Contact" type="u" tp:type="Contact_Handle"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - The contact handle that this codec offer applies to. - </tp:docstring> - </tp:member> - <tp:member name="Remote_Contact_Codecs" type="a(usuua{ss})" - tp:type="Codec[]"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - The <tp:dbus-ref namespace="ofdT.Call.Content" - >CodecOffer.DRAFT.RemoteContactCodecs</tp:dbus-ref> property - of the codec offer. - </tp:docstring> - </tp:member> - </tp:struct> - - <signal name="CodecsChanged" tp:name-for-bindings="Codecs_Changed"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>Emitted when the codecs in use change.</p> - - <p>As well as acting as change notification for the - <tp:member-ref>ContactCodecMap</tp:member-ref>, emission of this - signal implies that the <tp:member-ref>CodecOffer</tp:member-ref> - property has changed to <code>('/', {})</code>.</p> - </tp:docstring> - <arg name="Updated_Codecs" type="a{ua(usuua{ss})}" - tp:type="Contact_Codec_Map"> - <tp:docstring> - A map from contact to his or her codecs. Each pair in this - map is added to the - <tp:member-ref>ContactCodecMap</tp:member-ref> property, - replacing any previous pair with that key. - </tp:docstring> - </arg> - <arg name="Removed_Contacts" type="au" tp:type="Contact_Handle[]"> - <tp:docstring> - A list of keys which were removed from the - <tp:member-ref>ContactCodecMap</tp:member-ref>, probably because - those contacts left the call. - </tp:docstring> - </arg> - </signal> - - <method name="UpdateCodecs" tp:name-for-bindings="Update_Codecs"> - <tp:docstring> - Update the local codec mapping. This method should only be - used during an existing call to update the codec mapping. - </tp:docstring> - <arg name="Codecs" direction="in" - type="a(usuua{ss})" tp:type="Codec[]"> - <tp:docstring> - The codecs now supported by the local user. - </tp:docstring> - </arg> - <tp:possible-errors> - <tp:error name="org.freedesktop.Telepathy.Error.NotAvailable"> - <tp:docstring> - Raised when a <tp:dbus-ref - namespace="ofdT.Call.Content">CodecOffer.DRAFT</tp:dbus-ref> - object exists and is referred to in the - <tp:member-ref>CodecOffer</tp:member-ref> property which - should be used instead of calling this method, or before - the content's initial <tp:dbus-ref - namespace="ofdT.Call.Content">CodecOffer.DRAFT</tp:dbus-ref> - object has appeared. - </tp:docstring> - </tp:error> - </tp:possible-errors> - </method> - - <property name="ContactCodecMap" tp:name-for-bindings="Contact_Codec_Map" - type="a{ua(usuua{ss})}" tp:type="Contact_Codec_Map" access="read"> - <tp:docstring> - <p>A map from contact handles (including the local user's own handle) - to the codecs supported by that contact.</p> - - <p>Change notification is via the - <tp:member-ref>CodecsChanged</tp:member-ref> signal.</p> - </tp:docstring> - </property> - - <signal name="NewCodecOffer" tp:name-for-bindings="New_Codec_Offer"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>Emitted when a new <tp:dbus-ref namespace="ofdT.Call.Content" - >CodecOffer.DRAFT</tp:dbus-ref> appears. The streaming - implementation MUST respond by calling the <tp:dbus-ref - namespace="ofdT.Call.Content.CodecOffer.DRAFT" - >Accept</tp:dbus-ref> or <tp:dbus-ref - namespace="ofdT.Call.Content.CodecOffer.DRAFT" - >Reject</tp:dbus-ref> method on the codec offer object.</p> - - <p>Emission of this signal indicates that the - <tp:member-ref>CodecOffer</tp:member-ref> property has changed to - <code>(Contact, Offer, Codecs)</code>.</p> - </tp:docstring> - <arg name="Contact" type="u"> - <tp:docstring> - The contact the codec offer belongs to. - </tp:docstring> - </arg> - <arg name="Offer" type="o"> - <tp:docstring> - The object path of the new codec offer. This replaces any previous - codec offer. - </tp:docstring> - </arg> - <arg name="Codecs" type="a(usuua{ss})" tp:type="Codec[]"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>The <tp:dbus-ref namespace="ofdT.Call.Content" - >CodecOffer.DRAFT.RemoteContactCodecs</tp:dbus-ref> property - of the codec offer.</p> - - <tp:rationale> - Having the <tp:dbus-ref - namespace="ofdT.Call.Content.CodecOffer.DRAFT">RemoteContactCodecs</tp:dbus-ref> - property here saves a D-Bus round-trip - it shouldn't be - necessary to get the property from the CodecOffer object, in - practice. - </tp:rationale> - </tp:docstring> - </arg> - </signal> - - <property name="CodecOffer" tp:name-for-bindings="Codec_Offer" - type="(oua(usuua{ss}))" tp:type="Codec_Offering" access="read"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>The object path to the current - <tp:dbus-ref namespace="ofdT.Call.Content" - >CodecOffer.DRAFT</tp:dbus-ref> object, its - <tp:dbus-ref namespace="ofdT.Call.Content" - >CodecOffer.DRAFT.RemoteContact</tp:dbus-ref> and - <tp:dbus-ref namespace="ofdT.Call.Content" - >CodecOffer.DRAFT.RemoteContactCodecs</tp:dbus-ref> properties. - If the object path is "/" then there isn't an outstanding - codec offer, and the mapping MUST be empty.</p> - - <tp:rationale> - Having the <tp:dbus-ref - namespace="ofdT.Call.Content.CodecOffer.DRAFT" - >RemoteContact</tp:dbus-ref> and - <tp:dbus-ref namespace="ofdT.Call.Content.CodecOffer.DRAFT" - >RemoteContactCodecs</tp:dbus-ref> - properties here saves a D-Bus round-trip - it shouldn't be - necessary to get these properties from the CodecOffer object, in - practice. - </tp:rationale> - - <p>Change notification is via the - <tp:member-ref>NewCodecOffer</tp:member-ref> (which replaces the - value of this property with a new codec offer), and - <tp:member-ref>CodecsChanged</tp:member-ref> (which implies that - there is no longer any active codec offer) signals.</p> - </tp:docstring> - </property> - - <tp:enum name="Call_Content_Packetization_Type" type="u"> - <tp:added version="0.21.2"/> - <tp:docstring> - A packetization method that can be used for a content. - </tp:docstring> - - <tp:enumvalue suffix="RTP" value="0"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - Real-time Transport Protocol, as documented by RFC 3550. - </tp:docstring> - </tp:enumvalue> - - <tp:enumvalue suffix="Raw" value="1"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - Raw media. - </tp:docstring> - </tp:enumvalue> - - <tp:enumvalue suffix="MSN_Webcam" value="2"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - MSN webcam. This is the video-only one-way type which was - used in earlier versions of WLM. Although no longer used, - modern WLM clients still support the MSN webcam protocol. - </tp:docstring> - </tp:enumvalue> - </tp:enum> - - <property name="Packetization" tp:name-for-bindings="Packetization" - type="u" tp:type="Call_Content_Packetization_Type" access="read" - tp:immutable="yes"> - <tp:added version="0.21.2"/> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>The packetization method in use for this content.</p> - </tp:docstring> - </property> - </interface> -</node> -<!-- vim:set sw=2 sts=2 et ft=xml: --> diff --git a/extensions/Call_Content_Interface_Mute.xml b/extensions/Call_Content_Interface_Mute.xml deleted file mode 100644 index f926e03..0000000 --- a/extensions/Call_Content_Interface_Mute.xml +++ /dev/null @@ -1,85 +0,0 @@ -<?xml version="1.0" ?> -<node name="/Call_Content_Interface_Mute" xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"> - <tp:copyright> Copyright © 2005-2010 Nokia Corporation </tp:copyright> - <tp:copyright> Copyright © 2005-2010 Collabora Ltd </tp:copyright> - <tp:license xmlns="http://www.w3.org/1999/xhtml"> -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - </tp:license> - - <interface name="org.freedesktop.Telepathy.Call.Content.Interface.Mute.DRAFT" tp:causes-havoc="experimental"> - <tp:added version="0.19.6">(draft version, not API-stable)</tp:added> - <tp:requires interface="org.freedesktop.Telepathy.Call.Content.DRAFT"/> - - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>Interface for calls which may be muted. This only makes sense - for channels where audio or video is streaming between members.</p> - - <p>Muting a call content indicates that the user does not wish to send - outgoing audio or video.</p> - - <p>Although it's client's responsibility to actually mute the microphone - or turn off the camera, using this interface the client can also - inform the CM and other clients of that fact.</p> - - <tp:rationale> - For some protocols, the fact that the content is muted needs - to be transmitted to the peer; for others, the notification - to the peer is only informational (eg. XMPP), and some - protocols may have no notion of muting at all. - </tp:rationale> - </tp:docstring> - - <signal name="MuteStateChanged" tp:name-for-bindings="Mute_State_Changed"> - <tp:docstring> - Emitted to indicate that the mute state has changed for this call content. - This may occur as a consequence of the client calling - <tp:member-ref>SetMuted</tp:member-ref>, or as an indication that another - client has (un)muted the content. - </tp:docstring> - <arg name="MuteState" type="b"> - <tp:docstring> - True if the content is now muted. - </tp:docstring> - </arg> - </signal> - - <property name="MuteState" type="b" - access="read" tp:name-for-bindings="Mute_State"> - <tp:docstring> - True if the content is muted. - </tp:docstring> - </property> - - <method name="SetMuted" tp:name-for-bindings="Set_Muted"> - <tp:changed version="0.21.2">renamed from SetMuted to Mute</tp:changed> - <tp:changed version="0.21.3">renamed back from Mute to SetMuted</tp:changed> - <arg direction="in" name="Muted" type="b"> - <tp:docstring> - True if the client has muted the content. - </tp:docstring> - </arg> - <tp:docstring> - <p>Inform the CM that the call content has been muted or unmuted by - the client.</p> - - <p>It is the client's responsibility to actually mute or unmute the - microphone or camera used for the content. However, the client - MUST call this whenever it mutes or unmutes the content.</p> - </tp:docstring> - </method> - - </interface> -</node> -<!-- vim:set sw=2 sts=2 et ft=xml: --> diff --git a/extensions/Call_Content_Interface_Video_Control.xml b/extensions/Call_Content_Interface_Video_Control.xml deleted file mode 100644 index b066de4..0000000 --- a/extensions/Call_Content_Interface_Video_Control.xml +++ /dev/null @@ -1,137 +0,0 @@ -<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> -<node name="/Call_Content_Interface_Video_Control" - xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"> - <tp:copyright>Copyright © 2009-2010 Collabora Ltd.</tp:copyright> - <tp:copyright>Copyright © 2009-2010 Nokia Corporation</tp:copyright> - <tp:license xmlns="http://www.w3.org/1999/xhtml"> - <p>This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version.</p> - - <p>This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details.</p> - - <p>You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA.</p> - </tp:license> - - <interface name="org.freedesktop.Telepathy.Call.Content.Interface.VideoControl.DRAFT" - tp:causes-havoc="experimental"> - <tp:added version="0.21.10">(draft 1)</tp:added> - <tp:requires interface="org.freedesktop.Telepathy.Call.Content.Interface.Media.DRAFT"/> - - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>An interface that allows the connection manager to control the video - stream.</p> - <p>This interface is generally not needed. In cases where the connection - manager handles the network communication and the media is transferred - from the client to the connection manager via shared memory, it can - sometimes be beneficial for the connection manager to be able to - control certain aspects of the video stream.</p> - </tp:docstring> - - <signal name="KeyFrameRequested" tp:name-for-bindings="Key_Frame_Requested"> - <tp:docstring> - Request that the video encoder produce a new key frame as soon as - possible. - </tp:docstring> - </signal> - - <tp:struct name="Video_Resolution" - array-name="Video_Resolution_Struct"> - <tp:member type="u" name="Width"> - <tp:docstring> - With of the video stream. - </tp:docstring> - </tp:member> - <tp:member type="u" name="Height"> - <tp:docstring> - Height of the video stream. - </tp:docstring> - </tp:member> - </tp:struct> - - <property name="VideoResolution" type="(uu)" tp:type="Video_Resolution" - access="read" tp:name-for-bindings="Video_Resolution"> - <tp:docstring> - The resolution at which the streaming engine should be sending. - - <p>Change notification is via the - <tp:member-ref>VideoResolutionChanged</tp:member-ref> signal.</p> - </tp:docstring> - </property> - - <signal name="VideoResolutionChanged" - tp:name-for-bindings="Video_Resolution_Changed"> - <tp:docstring> - The desired video resolution has changed. - </tp:docstring> - <arg type="(uu)" tp:type="Video_Resolution" name="NewResolution" /> - </signal> - - <property name="Bitrate" type="u" access="read" - tp:name-for-bindings="Bitrate"> - <tp:docstring> - The bitrate the streaming engine should be sending at. - - <p>Change notification is via the - <tp:member-ref>BitrateChanged</tp:member-ref> signal.</p> - </tp:docstring> - </property> - - <signal name="BitrateChanged" - tp:name-for-bindings="Bitrate_Changed"> - <tp:docstring> - The desired bitrate has changed - </tp:docstring> - <arg type="u" name="NewBitrate" /> - </signal> - - <property name="Framerate" type="u" access="read" - tp:name-for-bindings="Framerate"> - <tp:docstring> - The framerate the streaming engine should be sending at. - - <p>Change notification is via the - <tp:member-ref>FramerateChanged</tp:member-ref> signal.</p> - </tp:docstring> - </property> - - <signal name="FramerateChanged" - tp:name-for-bindings="Framerate_Changed"> - <tp:docstring> - The desired framerate has changed - </tp:docstring> - <arg type="u" name="NewFramerate" /> - </signal> - - <property name="MTU" type="u" access="read" - tp:name-for-bindings="MTU"> - <tp:docstring> - The Maximum Transmission Unit - - <p>Change notification is via the - <tp:member-ref>MTUChanged</tp:member-ref> signal.</p> - </tp:docstring> - </property> - - <signal name="MTUChanged" tp:name-for-bindings="MTU_Changed"> - <tp:docstring> - The Maximum Transmission Unit has changed - </tp:docstring> - <arg type="u" name="NewMTU" /> - </signal> - - <property name="ManualKeyFrames" type="b" access="read" - tp:name-for-bindings="Manual_Key_Frames"> - <tp:docstring> - Only send key frames when manually requested - </tp:docstring> - </property> - </interface> -</node> diff --git a/extensions/Call_Stream.xml b/extensions/Call_Stream.xml deleted file mode 100644 index 1d7b281..0000000 --- a/extensions/Call_Stream.xml +++ /dev/null @@ -1,261 +0,0 @@ -<?xml version="1.0" ?> -<node name="/Call_Stream" - xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"> - <tp:copyright>Copyright © 2009-2010 Collabora Ltd.</tp:copyright> - <tp:copyright>Copyright © 2009-2010 Nokia Corporation</tp:copyright> - <tp:license xmlns="http://www.w3.org/1999/xhtml"> - <p>This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version.</p> - - <p>This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details.</p> - - <p>You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA.</p> - </tp:license> - - <interface name="org.freedesktop.Telepathy.Call.Stream.DRAFT" - tp:causes-havoc="experimental"> - <tp:added version="0.19.0">(draft 1)</tp:added> - - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - One stream inside a <tp:dbus-ref - namespace="ofdT.Call">Content.DRAFT</tp:dbus-ref>. - </tp:docstring> - - <method name="SetSending" tp:name-for-bindings="Set_Sending"> - <tp:docstring> - Set the stream to start or stop sending media from the local - user to other contacts. - </tp:docstring> - - <arg name="Send" type="b" direction="in"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>If True, the - <tp:member-ref>LocalSendingState</tp:member-ref> should - change to <tp:type>Sending_State</tp:type>_Sending, if it isn't - already.</p> - - <p>If False, the - <tp:member-ref>LocalSendingState</tp:member-ref> should - change to <tp:type>Sending_State</tp:type>_None, if it isn't - already.</p> - </tp:docstring> - </arg> - - <tp:possible-errors> - <tp:error name="org.freedesktop.Telepathy.Error.NotImplemented" /> - </tp:possible-errors> - </method> - - <method name="RequestReceiving" tp:name-for-bindings="Request_Receiving"> - <tp:docstring> - <p>Request that a remote contact stops or starts sending on - this stream.</p> - - <p>The <tp:member-ref>CanRequestReceiving</tp:member-ref> - property defines whether the protocol allows the local user to - request the other side start sending on this stream.</p> - </tp:docstring> - - <arg name="Contact" type="u" tp:type="Contact_Handle" direction="in"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>Contact from which sending is requested</p> - </tp:docstring> - </arg> - - <arg name="Receive" type="b" direction="in"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>If true, request that the given contact starts to send media. - If false, request that the given contact stops sending media.</p> - </tp:docstring> - </arg> - - <tp:possible-errors> - <tp:error name="org.freedesktop.Telepathy.Error.InvalidHandle"/> - <tp:error name="org.freedesktop.Telepathy.Error.InvalidArgument"> - <tp:docstring> - The request contact is valid but is not involved in this - stream. - </tp:docstring> - </tp:error> - <tp:error name="org.freedesktop.Telepathy.Error.NotImplemented"> - <tp:docstring> - The protocol does not allow the local user to request the - other side starts sending on this stream. - </tp:docstring> - </tp:error> - </tp:possible-errors> - </method> - - <signal name="RemoteMembersChanged" - tp:name-for-bindings="Remote_Members_Changed"> - <tp:changed version="0.21.2">renamed from SendersChanged to MembersChanged</tp:changed> - <tp:changed version="0.21.3">renamed from MembersChanged to RemoteMembersChanged</tp:changed> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - Emitted when <tp:member-ref>RemoteMembers</tp:member-ref> changes. - </tp:docstring> - - <arg name="Updates" type="a{uu}" tp:type="Contact_Sending_State_Map"> - <tp:docstring> - A mapping from channel-specific handles to their updated sending - state, whose keys include at least the members who were added, - and the members whose states changed. - </tp:docstring> - </arg> - <arg name="Removed" type="au" tp:type="Contact_Handle[]"> - <tp:docstring> - The channel-specific handles that were removed from the keys - of the <tp:member-ref>RemoteMembers</tp:member-ref> - property, as a result of the contact leaving this stream - </tp:docstring> - </arg> - </signal> - - <signal name="LocalSendingStateChanged" - tp:name-for-bindings="Local_Sending_State_Changed"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - Emitted when <tp:member-ref>LocalSendingState</tp:member-ref> changes. - </tp:docstring> - - <arg name="State" type="u" tp:type="Sending_State"> - <tp:docstring> - The new value of - <tp:member-ref>LocalSendingState</tp:member-ref>. - </tp:docstring> - </arg> - </signal> - - <tp:enum name="Sending_State" type="u"> - <tp:docstring> - Enum indicating whether a contact is sending media. - </tp:docstring> - - <tp:enumvalue suffix="None" value="0"> - <tp:docstring> - The contact is not sending media and has not been asked to - do so. - </tp:docstring> - </tp:enumvalue> - - <tp:enumvalue suffix="Pending_Send" value="1"> - <tp:docstring> - The contact has been asked to start sending media. - </tp:docstring> - </tp:enumvalue> - - <tp:enumvalue suffix="Sending" value="2"> - <tp:docstring> - The contact is sending media. - </tp:docstring> - </tp:enumvalue> - - <tp:enumvalue suffix="Pending_Stop_Sending" value="3"> - <tp:docstring> - The contact has been asked to stop sending media. - </tp:docstring> - </tp:enumvalue> - </tp:enum> - - <tp:mapping name="Contact_Sending_State_Map"> - <tp:docstring> - A map from a contact to his or her sending state. - </tp:docstring> - <tp:member name="Contact" type="u" tp:type="Contact_Handle"> - <tp:docstring> - The contact handle. - </tp:docstring> - </tp:member> - <tp:member name="Sending" type="u" tp:type="Sending_State"> - <tp:docstring> - The sending state of the contact. - </tp:docstring> - </tp:member> - </tp:mapping> - - <property name="Interfaces" tp:name-for-bindings="Interfaces" - type="as" tp:type="DBus_Interface[]" access="read" tp:immutable="yes"> - <tp:added version="0.19.11"/> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>Extra interfaces provided by this stream, such as <tp:dbus-ref - namespace="ofdT.Call">Stream.Interface.Media.DRAFT</tp:dbus-ref>. - This SHOULD NOT include the Stream interface itself, and cannot - change once the stream has been created.</p> - </tp:docstring> - </property> - - <property name="RemoteMembers" tp:name-for-bindings="Remote_Members" - type="a{uu}" access="read" tp:type="Contact_Sending_State_Map"> - <tp:changed version="0.21.2">renamed from Senders</tp:changed> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>A map from remote contacts to their sending state. The - local user's sending state is shown in - <tp:member-ref>LocalSendingState</tp:member-ref>.</p> - - <p><tp:type>Sending_State</tp:type>_Pending_Send indicates - that another contact has asked the local user to send - media.</p> - - <p>Other contacts' handles in this map indicate whether they are - sending media to the contacts in this stream. - Sending_State_Pending_Send indicates contacts who are not sending but - have been asked to do so.</p> - </tp:docstring> - </property> - - <property name="LocalSendingState" tp:name-for-bindings="Local_Sending_State" - type="u" access="read" tp:type="Sending_State"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>The local user's sending state. Media sent on this stream - should be assumed to be received, directly or indirectly, by - every other contact in the - <tp:member-ref>RemoteMembers</tp:member-ref> mapping. Change - notification is given via the - <tp:member-ref>LocalSendingStateChanged</tp:member-ref> - signal.</p> - - <tp:rationale> - Implementations of the first Call draft had the self handle - in the <tp:member-ref>RemoteMembers</tp:member-ref> (then - called Members) map and this showed that it's annoying - having to keep track of the self handle so that it can be - special-cased. - </tp:rationale> - - <p>A value of <tp:type>Sending_State</tp:type>_Pending_Send for - this property indicates that the other side requested the - local user start sending media, which can be done by calling - <tp:member-ref>SetSending</tp:member-ref>. When a call is - accepted, all initial contents with streams that have a - local sending state of - <tp:type>Sending_State</tp:type>_Pending_Send are - automatically set to sending. For example, on an incoming - call it means you need to <tp:dbus-ref - namespace="ofdT.Channel.Type.Call.DRAFT">Accept</tp:dbus-ref> - to start the actual call, on an outgoing call it might mean - you need to call <tp:dbus-ref - namespace="ofdT.Channel.Type.Call.DRAFT">Accept</tp:dbus-ref> - before actually starting the call.</p> - </tp:docstring> - </property> - - <property name="CanRequestReceiving" tp:name-for-bindings="Can_Request_Receiving" - type="b" access="read" tp:immutable="yes"> - <tp:added version="0.21.2"/> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>If true, the user can request that a remote contact starts - sending on this stream.</p> - - <tp:rationale>Not all protocols allow the user to ask the - other side to start sending media.</tp:rationale> - </tp:docstring> - </property> - </interface> -</node> -<!-- vim:set sw=2 sts=2 et ft=xml: --> diff --git a/extensions/Call_Stream_Endpoint.xml b/extensions/Call_Stream_Endpoint.xml deleted file mode 100644 index 4818168..0000000 --- a/extensions/Call_Stream_Endpoint.xml +++ /dev/null @@ -1,182 +0,0 @@ -<?xml version="1.0" ?> -<node name="/Call_Stream_Endpoint" - xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"> - <tp:copyright>Copyright © 2009-2010 Collabora Ltd.</tp:copyright> - <tp:copyright>Copyright © 2009-2010 Nokia Corporation</tp:copyright> - <tp:license xmlns="http://www.w3.org/1999/xhtml"> - <p>This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version.</p> - - <p>This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details.</p> - - <p>You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA.</p> - </tp:license> - - <interface name="org.freedesktop.Telepathy.Call.Stream.Endpoint.DRAFT" - tp:causes-havoc="experimental"> - <tp:added version="0.19.0">(draft 1)</tp:added> - - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>This object represents an endpoint for a stream. In a one-to-one - call, there will be one (bidirectional) stream per content and - one endpoint per stream (as there is only one remote - contact). In a multi-user call there is a stream for each remote - contact and each stream has one endpoint as it refers to the one - physical machine on the other end of the stream.</p> - - <p>The multiple endpoint use case appears when SIP call forking - is used. Unlike jingle call forking (which is just making - multiple jingle calls to different resources appear as one - call), SIP call forking is actually done at the server so you - have one stream to the remote contact and then and endpoint for - each SIP client to be called.</p> - </tp:docstring> - - <property name="RemoteCredentials" - tp:name-for-bindings="Remote_Credentials" - type="(ss)" tp:type="Stream_Credentials" access="read"> - <tp:docstring> - The ICE credentials used for all candidates. If each candidate - has different credentials, then this property SHOULD be ("", - ""). Per-candidate credentials are set in the - <tp:type>Candidate</tp:type>'s - <tp:type>Candidate_Info</tp:type> a{sv}. - </tp:docstring> - </property> - - <signal name="RemoteCredentialsSet" - tp:name-for-bindings="Remote_Credentials_Set"> - <arg name="Username" type="s"> - <tp:docstring> - The username set. - </tp:docstring> - </arg> - <arg name="Password" type="s"> - <tp:docstring> - The password set. - </tp:docstring> - </arg> - <tp:docstring> - Emitted when the remote ICE credentials for the endpoint are - set. If each candidate has different credentials, then this - signal will never be fired. - </tp:docstring> - </signal> - - <property name="RemoteCandidates" tp:name-for-bindings="Remote_Candidates" - type="a(usqa{sv})" tp:type="Candidate[]" access="read"> - <tp:docstring> - A list of candidates for this endpoint. - </tp:docstring> - </property> - - <signal name="RemoteCandidatesAdded" - tp:name-for-bindings="Remote_Candidates_Added"> - <tp:docstring> - Emitted when remote candidates are added to the - <tp:member-ref>RemoteCandidates</tp:member-ref> property. - </tp:docstring> - <arg name="Candidates" - type="a(usqa{sv})" tp:type="Candidate[]"> - <tp:docstring> - The candidates that were added. - </tp:docstring> - </arg> - </signal> - - <signal name="CandidateSelected" - tp:name-for-bindings="Candidate_Selected"> - <tp:docstring> - Emitted when a candidate is selected for use in the stream. - </tp:docstring> - <arg name="Candidate" - type="(usqa{sv})" tp:type="Candidate"> - <tp:docstring> - The candidate that has been selected. - </tp:docstring> - </arg> - </signal> - - <property name="SelectedCandidate" - tp:name-for-bindings="Selected_Candidate" - type="(usqa{sv})" tp:type="Candidate" access="read"> - <tp:docstring> - The candidate that has been selected for use to stream packets - to the remote contact. Change notification is given via the - the <tp:member-ref>CandidateSelected</tp:member-ref> signal. - </tp:docstring> - </property> - - <method name="SetSelectedCandidate" - tp:name-for-bindings="Set_Selected_Candidate"> - <tp:docstring> - Set the value of - <tp:member-ref>CandidateSelected</tp:member-ref>. - </tp:docstring> - <arg name="Candidate" - type="(usqa{sv})" tp:type="Candidate" direction="in"> - <tp:docstring> - The candidate that has been selected. - </tp:docstring> - </arg> - <tp:possible-errors> - <tp:error name="org.freedesktop.Telepathy.Error.InvalidArgument"/> - </tp:possible-errors> - </method> - - <property name="StreamState" tp:name-for-bindings="Stream_State" - type="u" tp:type="Media_Stream_State" - access="read"> - <tp:docstring> - The stream state of the endpoint. - </tp:docstring> - </property> - - <signal name="StreamStateChanged" - tp:name-for-bindings="Stream_State_Changed"> - <tp:docstring> - Emitted when the <tp:member-ref>StreamState</tp:member-ref> - property changes. - </tp:docstring> - <arg name="state" type="u" tp:type="Media_Stream_State"> - <tp:docstring> - The new <tp:member-ref>StreamState</tp:member-ref> value. - </tp:docstring> - </arg> - </signal> - - <method name="SetStreamState" - tp:name-for-bindings="Set_Stream_State"> - <tp:docstring> - Change the <tp:member-ref>StreamState</tp:member-ref> of the - endpoint. - </tp:docstring> - <arg direction="in" name="State" type="u" tp:type="Media_Stream_State"> - <tp:docstring> - The requested stream state. - </tp:docstring> - </arg> - <tp:possible-errors> - <tp:error name="org.freedesktop.Telepathy.Error.InvalidArgument"/> - <tp:error name="org.freedesktop.Telepathy.Error.NotAvailable"/> - </tp:possible-errors> - </method> - - <property name="Transport" tp:name-for-bindings="Transport" - type="u" tp:type="Stream_Transport_Type" access="read"> - <tp:docstring> - The transport type for the stream endpoint. - </tp:docstring> - </property> - - </interface> -</node> -<!-- vim:set sw=2 sts=2 et ft=xml: --> diff --git a/extensions/Call_Stream_Interface_Media.xml b/extensions/Call_Stream_Interface_Media.xml deleted file mode 100644 index 9e62c87..0000000 --- a/extensions/Call_Stream_Interface_Media.xml +++ /dev/null @@ -1,447 +0,0 @@ -<?xml version="1.0" ?> -<node name="/Call_Stream_Interface_Media" - xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"> - <tp:copyright>Copyright © 2009-2010 Collabora Ltd.</tp:copyright> - <tp:copyright>Copyright © 2009-2010 Nokia Corporation</tp:copyright> - <tp:license xmlns="http://www.w3.org/1999/xhtml"> - <p>This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version.</p> - - <p>This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details.</p> - - <p>You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA.</p> - </tp:license> - - <interface name="org.freedesktop.Telepathy.Call.Stream.Interface.Media.DRAFT" - tp:causes-havoc="experimental"> - <tp:added version="0.19.0">(draft 1)</tp:added> - <tp:requires interface="org.freedesktop.Telepathy.Call.Stream.DRAFT"/> - - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - [FIXME] - - <h4>ICE restarts</h4> - - <p>If the <tp:dbus-ref - namespace="ofdT.Call.Stream.Endpoint.DRAFT">RemoteCredentialsSet</tp:dbus-ref> - signal is fired during a call once it has been called before - whilst setting up the call for initial use, and the - credentials have changed, then there has been an ICE - restart. In such a case, the CM SHOULD also empty the remote - candidate list in the <tp:dbus-ref - namespace="ofdT.Call.Stream">Endpoint.DRAFT</tp:dbus-ref>.</p> - - <p>If the CM does an ICE restart, then the - <tp:member-ref>PleaseRestartICE</tp:member-ref> signal is - emitted and the streaming implementation should then call - <tp:member-ref>SetCredentials</tp:member-ref> again.</p> - - <p>For more information on ICE restarts see - <a href="http://tools.ietf.org/html/rfc5245#section-9.1.1.1">RFC 5245 - section 9.1.1.1</a></p> - </tp:docstring> - - <method name="SetCredentials" tp:name-for-bindings="Set_Credentials"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>Used to set the username fragment and password for streams that have - global credentials.</p> - </tp:docstring> - <arg name="Username" type="s" direction="in"> - <tp:docstring> - The username to use when authenticating on the stream. - </tp:docstring> - </arg> - <arg name="Password" type="s" direction="in"> - <tp:docstring> - The password to use when authenticating on the stream. - </tp:docstring> - </arg> - </method> - - <tp:mapping name="Candidate_Info"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>Extra information about the candidate. Allowed and mandatory keys - depend on the transport protocol used. The following keys are commenly - used:</p> - - <dl> - <dt>Type (u)</dt> - <dd>type of candidate (host, srflx, prflx, relay)</dd> - - <dt>Foundation (s)</dt> - <dd>the foundation of this candiate</dd> - - <dt>Protocol (u) </dt> - <dd>Underlying protocol of the candidate (udp, tcp) </dd> - - <dt>Priority (u) </dt> - <dd>Priority of the candidate </dd> - - <dt>BaseIP (u) </dt> - <dd>Base IP of this candidate </dd> - - <dt>Username (s) </dt> - <dd>Username of this candidate - (only if credentials are per candidate)</dd> - - <dt>Password (s) </dt> - <dd>Password of this candidate - (only if credentials are per candidate)</dd> - - <dt>RawUDPFallback (b) </dt> - <dd>Indicate whether this candidate may be used to provide a UDP - fallback</dd> - </dl> - </tp:docstring> - <tp:member name="Key" type="s"> - <tp:docstring>One of the well-known keys documented here, or an - implementation-specific key.</tp:docstring> - </tp:member> - <tp:member name="Value" type="v"> - <tp:docstring>The value corresponding to that key.</tp:docstring> - </tp:member> - </tp:mapping> - - <tp:struct name="Candidate" array-name="Candidate_List"> - <tp:docstring>A Stream Candidate.</tp:docstring> - <tp:member name="Component" type="u"> - <tp:docstring>The component number.</tp:docstring> - </tp:member> - <tp:member name="IP" type="s"> - <tp:docstring>The IP address to use.</tp:docstring> - </tp:member> - <tp:member name="Port" type="q"> - <tp:docstring>The port number to use.</tp:docstring> - </tp:member> - <tp:member name="Info" type="a{sv}" tp:type="Candidate_Info"> - <tp:docstring>Additional information about the candidate.</tp:docstring> - </tp:member> - </tp:struct> - - <method name="AddCandidates" tp:name-for-bindings="Add_Candidates"> - <tp:docstring> - Add candidates to the - <tp:member-ref>LocalCandidates</tp:member-ref> property and - signal them to the remote contact(s). - </tp:docstring> - <arg name="Candidates" direction="in" - type="a(usqa{sv})" tp:type="Candidate[]"> - <tp:docstring> - The candidates to be added. - </tp:docstring> - </arg> - </method> - - <method name="CandidatesPrepared" - tp:name-for-bindings="Candidates_Prepared"> - <tp:docstring> - This indicates to the CM that the initial batch of candidates - has been added. - </tp:docstring> - </method> - - <tp:enum type="u" name="Stream_Transport_Type"> - <tp:changed version="0.21.2">WLM_8_5 was removed</tp:changed> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - A transport that can be used for streaming. - </tp:docstring> - <tp:enumvalue suffix="Unknown" value="0"> - <tp:docstring> - The stream transport type is unknown or not applicable - (for streams that do not have a configurable transport). - </tp:docstring> - </tp:enumvalue> - <tp:enumvalue suffix="Raw_UDP" value="1"> - <tp:docstring> - Raw UDP, with or without STUN. All streaming clients are assumed to - support this transport, so there is no handler capability token for - it in the <tp:dbus-ref namespace="ofdT.Channel.Type" - >Call.DRAFT</tp:dbus-ref> interface. - [This corresponds to "none" or "stun" in the old Media.StreamHandler - interface.] - </tp:docstring> - </tp:enumvalue> - <tp:enumvalue suffix="ICE" value="2"> - <tp:docstring> - Interactive Connectivity Establishment, as defined by RFC - 5245. Note that this value covers ICE-UDP only. - [This corresponds to "ice-udp" in the old - Media.StreamHandler interface.] - </tp:docstring> - </tp:enumvalue> - <tp:enumvalue suffix="GTalk_P2P" value="3"> - <tp:docstring> - Google Talk peer-to-peer connectivity establishment, as implemented - by libjingle 0.3. - [This corresponds to "gtalk-p2p" in the old Media.StreamHandler - interface.] - </tp:docstring> - </tp:enumvalue> - <tp:enumvalue suffix="WLM_2009" value="4"> - <tp:docstring> - The transport used by Windows Live Messenger 2009 or later, which - resembles ICE draft 19. - [This corresponds to "wlm-2009" in the old Media.StreamHandler - interface.] - </tp:docstring> - </tp:enumvalue> - <tp:enumvalue suffix="SHM" value="5"> - <tp:added version="0.21.2"/> - <tp:docstring> - Shared memory transport, as implemented by the GStreamer - shmsrc and shmsink plugins. - </tp:docstring> - </tp:enumvalue> - <tp:enumvalue suffix="Multicast" value="6"> - <tp:added version="0.21.5"/> - <tp:docstring> - Multicast transport. - </tp:docstring> - </tp:enumvalue> - </tp:enum> - - <property name="Transport" tp:name-for-bindings="Transport" - type="u" tp:type="Stream_Transport_Type" access="read" tp:immutable="yes"> - <tp:docstring> - The transport for this stream. - </tp:docstring> - </property> - - <property name="LocalCandidates" tp:name-for-bindings="Local_Candidates" - type="a(usqa{sv})" tp:type="Candidate[]" access="read"> - <tp:docstring> - [FIXME]. Change notification is via the - <tp:member-ref>LocalCandidatesAdded</tp:member-ref> signal. - </tp:docstring> - </property> - - <signal name="LocalCandidatesAdded" - tp:name-for-bindings="Local_Candidates_Added"> - <tp:docstring> - Emitted when local candidates are added to the - <tp:member-ref>LocalCandidates</tp:member-ref> property. - </tp:docstring> - <arg name="Candidates" type="a(usqa{sv})" tp:type="Candidate[]"> - <tp:docstring> - Candidates that have been added. - </tp:docstring> - </arg> - </signal> - - <tp:struct name="Stream_Credentials"> - <tp:docstring>A username and password pair.</tp:docstring> - - <tp:member name="Username" type="s"> - <tp:docstring>The username.</tp:docstring> - </tp:member> - - <tp:member name="Password" type="s"> - <tp:docstring>The password.</tp:docstring> - </tp:member> - </tp:struct> - - <property name="LocalCredentials" tp:name-for-bindings="Local_Credentials" - type="(ss)" tp:type="Stream_Credentials" access="read"> - <tp:docstring> - [FIXME]. Change notification is via the - <tp:member-ref>LocalCredentialsChanged</tp:member-ref> signal. - </tp:docstring> - </property> - - <signal name="LocalCredentialsChanged" - tp:name-for-bindings="Local_Credentials_Changed"> - <tp:changed version="0.21.2">renamed from LocalCredentailsSet</tp:changed> - <tp:docstring> - Emitted when the value of - <tp:member-ref>LocalCredentials</tp:member-ref> changes. - </tp:docstring> - <arg name="Username" type="s" /> - <arg name="Password" type="s" /> - </signal> - - <signal name="RelayInfoChanged" - tp:name-for-bindings="Relay_Info_Changed"> - <tp:docstring> - Emitted when the value of - <tp:member-ref>RelayInfo</tp:member-ref> changes. - </tp:docstring> - <arg name="Relay_Info" type="aa{sv}" tp:type="String_Variant_Map[]" /> - </signal> - - <signal name="STUNServersChanged" - tp:name-for-bindings="STUN_Servers_Changed"> - <tp:docstring> - Emitted when the value of - <tp:member-ref>STUNServers</tp:member-ref> changes. - </tp:docstring> - <arg name="Servers" type="a(sq)" tp:type="Socket_Address_IP[]" /> - </signal> - - <property name="STUNServers" tp:name-for-bindings="STUN_Servers" - type="a(sq)" tp:type="Socket_Address_IP[]" access="read"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>The IP addresses of possible STUN servers to use for NAT - traversal, as dotted-quad IPv4 address literals or RFC2373 - IPv6 address literals. Change notification is via the - <tp:member-ref>STUNServersChanged</tp:member-ref> - signal. The IP addresses MUST NOT be given as DNS hostnames.</p> - - <tp:rationale> - High-quality connection managers already need an asynchronous - DNS resolver, so they might as well resolve this name to an IP - to make life easier for streaming implementations. - </tp:rationale> - </tp:docstring> - </property> - - <property name="RelayInfo" type="aa{sv}" access="read" - tp:type="String_Variant_Map[]" tp:name-for-bindings="Relay_Info"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>A list of mappings describing TURN or Google relay servers - available for the client to use in its candidate gathering, as - determined from the protocol. Map keys are:</p> - - <dl> - <dt><code>ip</code> - s</dt> - <dd>The IP address of the relay server as a dotted-quad IPv4 - address literal or an RFC2373 IPv6 address literal. This MUST NOT - be a DNS hostname. - - <tp:rationale> - High-quality connection managers already need an asynchronous - DNS resolver, so they might as well resolve this name to an IP - and make life easier for streaming implementations. - </tp:rationale> - </dd> - - <dt><code>type</code> - s</dt> - <dd> - <p>Either <code>udp</code> for UDP (UDP MUST be assumed if this - key is omitted), <code>tcp</code> for TCP, or - <code>tls</code>.</p> - - <p>The precise meaning of this key depends on the - <tp:member-ref>Transport</tp:member-ref> property: if - Transport is ICE, <code>tls</code> means - TLS over TCP as referenced by ICE draft 19, and if - Transport is GTalk_P2P, <code>tls</code> means - a fake SSL session over TCP as implemented by libjingle.</p> - </dd> - - <dt><code>port</code> - q</dt> - <dd>The UDP or TCP port of the relay server as an ASCII unsigned - integer</dd> - - <dt><code>username</code> - s</dt> - <dd>The username to use</dd> - - <dt><code>password</code> - s</dt> - <dd>The password to use</dd> - - <dt><code>component</code> - u</dt> - <dd>The component number to use this relay server for, as an - ASCII unsigned integer; if not included, this relay server - may be used for any or all components. - - <tp:rationale> - In ICE draft 6, as used by Google Talk, credentials are only - valid once, so each component needs relaying separately. - </tp:rationale> - </dd> - </dl> - - <tp:rationale> - <p>An equivalent of the gtalk-p2p-relay-token property on - MediaSignalling channels is not included here. The connection - manager should be responsible for making the necessary HTTP - requests to turn the token into a username and password.</p> - </tp:rationale> - - <p>The type of relay server that this represents depends on - the value of the <tp:member-ref>Transport</tp:member-ref> - property. If Transport is ICE, this is a TURN server; - if Transport is GTalk_P2P, this is a Google relay server; - otherwise, the meaning of RelayInfo is undefined.</p> - - <p>If relaying is not possible for this stream, the list is - empty.</p> - - <p>Change notification is given via the - <tp:member-ref>RelayInfoChanged</tp:member-ref> signal.</p> - </tp:docstring> - </property> - - <signal name="ServerInfoRetrieved" - tp:name-for-bindings="Server_Info_Retrieved"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>Signals that the initial information about STUN and Relay servers - has been retrieved, i.e. the - <tp:member-ref>HasServerInfo</tp:member-ref> property is - now true.</p> - </tp:docstring> - </signal> - - <property name="HasServerInfo" type="b" - tp:name-for-bindings="Has_Server_Info" access="read"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>True if all the initial information about STUN servers and Relay - servers has been retrieved. Change notification is via the - <tp:member-ref>ServerInfoRetrieved</tp:member-ref> signal.</p> - - <tp:rationale> - Streaming implementations that can't cope with STUN and - relay servers being added later SHOULD wait for this - property to become true before proceeding. - </tp:rationale> - </tp:docstring> - </property> - - <signal name="EndpointsChanged" - tp:name-for-bindings="Endpoints_Changed"> - <tp:docstring> - Emitted when the <tp:member-ref>Endpoints</tp:member-ref> property - changes. - </tp:docstring> - <arg name="Endpoints_Added" type="ao"> - <tp:docstring> - Endpoints that were added. - </tp:docstring> - </arg> - <arg name="Endpoints_Removed" type="ao"> - <tp:docstring> - Endpoints that no longer exist. - </tp:docstring> - </arg> - </signal> - - <property name="Endpoints" tp:name-for-bindings="Endpoints" - type="ao" access="read"> - <tp:docstring> - <p>The list of <tp:dbus-ref namespace="ofdT.Call.Stream" - >Endpoint.DRAFT</tp:dbus-ref> objects that exist for this - stream.</p> - - <p>Change notification is via the - <tp:member-ref>EndpointsChanged</tp:member-ref> signal.</p> - </tp:docstring> - </property> - - <signal name="PleaseRestartICE" - tp:name-for-bindings="Please_Restart_ICE"> - <tp:docstring> - Emitted when the CM does an ICE restart to notify the - streaming implementation that it should call - <tp:member-ref>SetCredentials</tp:member-ref> again. - </tp:docstring> - </signal> - </interface> -</node> -<!-- vim:set sw=2 sts=2 et ft=xml: --> diff --git a/extensions/Channel_Type_Call.xml b/extensions/Channel_Type_Call.xml deleted file mode 100644 index 045d416..0000000 --- a/extensions/Channel_Type_Call.xml +++ /dev/null @@ -1,1429 +0,0 @@ -<?xml version="1.0" ?> -<node name="/Channel_Type_Call" xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"> - <tp:copyright>Copyright © 2009-2010 Collabora Limited</tp:copyright> - <tp:copyright>Copyright © 2009-2010 Nokia Corporation</tp:copyright> - <tp:license> - This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - </tp:license> - <interface name="org.freedesktop.Telepathy.Channel.Type.Call.DRAFT" - tp:causes-havoc="experimental"> - <tp:added version="0.19.0">(draft 1)</tp:added> - - <tp:requires interface="org.freedesktop.Telepathy.Channel"/> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>A channel type for making audio and video calls. Call - channels supersede the old <tp:dbus-ref - namespace="ofdT.Channel.Type">StreamedMedia</tp:dbus-ref> - channel type. Call channels are much more flexible than its - predecessor and allow more than two participants.</p> - - <p>Handlers are advised against executing all the media - signalling, codec and candidate negotiation themselves but - instead use a helper library such as <a - href="http://telepathy.freedesktop.org/doc/telepathy-farstream/">telepathy-farstream</a> - which when given a new Call channel will set up the - transports and codecs and create GStreamer pads which - can be added to the handler UI. This is useful as it means - the handler does not have to worry how exactly the - connection between the call participants is being made.</p> - - <p>The <tp:dbus-ref - namespace="ofdT.Channel">TargetHandle</tp:dbus-ref> and - <tp:dbus-ref namespace="ofdT.Channel">TargetID</tp:dbus-ref> - properties in a Call channel refer to the contact that the - user initially called, or which contact initially called the - user. Even in a conference call, where there are multiple - contacts in the call, these properties refer to the - initial contact, who might have left the conference since - then. As a result, handlers should not rely on these - properties.</p> - - <h4>Contents</h4> - - <p><tp:dbus-ref namespace="ofdT.Call">Content.DRAFT</tp:dbus-ref> - objects represent the actual media that forms the Call (for - example an audio content and a video content). Calls always - have one or more Content objects associated with them. As a - result, a new Call channel request MUST have either - <tp:member-ref>InitialAudio</tp:member-ref>=True, or - <tp:member-ref>InitialVideo</tp:member-ref>=True, or both, - as the Requestable Channel Classes will document.</p> - - <p><tp:dbus-ref - namespace="ofdT.Call">Content.DRAFT</tp:dbus-ref> objects have - one or more stream associated with them. More information on - these streams and how to maniuplate them can be found on the - <tp:dbus-ref namespace="ofdT.Call">Content.DRAFT</tp:dbus-ref> - interface page.</p> - - <h4>Outgoing calls</h4> - - <p>To make an audio-only call to a contact <tt>foo@example.com</tt> - handlers should call:</p> - - <blockquote> - <pre> -<tp:dbus-ref namespace="ofdT.Connection.Interface.Requests">CreateChannel</tp:dbus-ref>({ - ...<tp:dbus-ref namespace="ofdT.Channel">ChannelType</tp:dbus-ref>: ...<tp:dbus-ref - namespace="ofdT.Channel.Type">Call.DRAFT</tp:dbus-ref>, - ...<tp:dbus-ref namespace="ofdT.Channel">TargetHandleType</tp:dbus-ref>: Contact, - ...<tp:dbus-ref namespace="ofdT.Channel">TargetID</tp:dbus-ref>: 'foo@example.com', - ...<tp:member-ref>InitialAudio</tp:member-ref>: True, -})</pre></blockquote> - - <p>As always, <tp:dbus-ref - namespace="ofdT.Channel">TargetHandle</tp:dbus-ref> may be used - in place of - <tp:dbus-ref namespace="ofdT.Channel">TargetID</tp:dbus-ref> - if the contact's handle is already known. To make an audio - and video call, the handler should also specify - <tp:member-ref>InitialVideo</tp:member-ref> The - connection manager SHOULD return a channel whose immutable - properties contain the local user as the <tp:dbus-ref - namespace="ofdT.Channel">InitiatorHandle</tp:dbus-ref>, the - remote contact as the <tp:dbus-ref - namespace="ofdT.Channel">TargetHandle</tp:dbus-ref>, - <tp:dbus-ref namespace="ofdT.Channel">Requested</tp:dbus-ref> = - <code>True</code> (indicating the call is outgoing).</p> - - <p>After a new Call channel is requested, the - <tp:member-ref>CallState</tp:member-ref> property will be - <tp:type>Call_State</tp:type>_Pending_Initiator. As the local - user is the initiator, the call must be accepted by the handler - by calling the <tp:member-ref>Accept</tp:member-ref> method. - At this point, <tp:member-ref>CallState</tp:member-ref> changes - to <tp:type>Call_State</tp:type>_Pending_Receiver which signifies - that the call is ringing, waiting for the remote contact to - accept the call. All changes to - <tp:member-ref>CallState</tp:member-ref> property are signalled - using the <tp:member-ref>CallStateChanged</tp:member-ref> - signal.</p> - - <p>When the call is accepted by the remote contact, the - <tp:member-ref>CallStateChanged</tp:member-ref> signal fires - again to show that <tp:member-ref>CallState</tp:member-ref> = - <tp:type>Call_State</tp:type>_Accepted.</p> - - <p>At this point <a - href="http://telepathy.freedesktop.org/doc/telepathy-farstream/">telepathy-farstream</a> - will signal that a pad is available for the handler to show - in the user interface.</p> - - <h5>Missed calls</h5> - - <p>If the remote contact does not accept the call in time, then - the call can be terminated by the server. Note that this only - happens in some protocols. Most XMPP clients, for example, do - not do this and rely on the call initiator terminating the call. - A missed call is shown in a Call channel by the - <tp:member-ref>CallState</tp:member-ref> property changing to - <tp:type>Call_State</tp:type>_Ended, and the - <tp:member-ref>CallStateReason</tp:member-ref> property changing - to (remote contact, - <tp:type>Call_State_Change_Reason</tp:type>_No_Answer, "").</p> - - <h5>Rejected calls</h5> - - <p>If the remote contact decides he or she does not feel like - talking to the local user, he or she can reject his or her - incoming call. This will be shown in the Call channel by - <tp:member-ref>CallState</tp:member-ref> changing to - <tp:type>Call_State</tp:type>_Ended and the - <tp:member-ref>CallStateReason</tp:member-ref> property - changing to (remote contact, - <tp:type>Call_State</tp:type>_Change_Reason_User_Requested, - "org.freedesktop.Telepathy.Error.Rejected").</p> - - <h4>Incoming calls</h4> - - <p>When an incoming call occurs, something like the following - <tp:dbus-ref - namespace="ofdT.Connection.Interface.Requests">NewChannels</tp:dbus-ref> - signal will occur:</p> - - <blockquote> - <pre> -<tp:dbus-ref namespace="ofdT.Connection.Interface.Requests">NewChannels</tp:dbus-ref>([ - /org/freedesktop/Telepathy/Connection/foo/bar/foo_40bar_2ecom/CallChannel, - { - ...<tp:dbus-ref namespace="ofdT.Channel">ChannelType</tp:dbus-ref>: ...<tp:dbus-ref - namespace="ofdT.Channel.Type">Call.DRAFT</tp:dbus-ref>, - ...<tp:dbus-ref namespace="ofdT.Channel">TargetHandleType</tp:dbus-ref>: Contact, - ...<tp:dbus-ref namespace="ofdT.Channel">TargetID</tp:dbus-ref>: 'foo@example.com', - ...<tp:dbus-ref namespace="ofdT.Channel">TargetHandle</tp:dbus-ref>: 42, - ...<tp:dbus-ref namespace="ofdT.Channel">Requested</tp:dbus-ref>: False, - ...<tp:member-ref>InitialAudio</tp:member-ref>: True, - ...<tp:member-ref>InitialVideo</tp:member-ref>: True, - ...<tp:member-ref>InitialAudioName</tp:member-ref>: "audio", - ...<tp:member-ref>InitialVideoName</tp:member-ref>: "video", - ...<tp:member-ref>MutableContents</tp:member-ref>: True, - }])</pre></blockquote> - - <p>The <tp:member-ref>InitialAudio</tp:member-ref> and - <tp:member-ref>InitialVideo</tp:member-ref> properties show that - the call has been started with two contents: one for audio - streaming and one for video streaming. The - <tp:member-ref>InitialAudioName</tp:member-ref> and - <tp:member-ref>InitialVideoName</tp:member-ref> properties also - show that the aforementioned audio and video contents have names - "audio" and "video".</p> - - <p>Once the handler has notified the local user that there is an - incoming call waiting for acceptance, the handler should call - <tp:member-ref>SetRinging</tp:member-ref> to let the CM know. - The new channel should also be given to telepathy-farstream to - work out how the two participants will connect together. - telepathy-farstream will call the appropriate methods on the call's - <tp:dbus-ref namespace="ofdT.Call">Content.DRAFT</tp:dbus-ref>s - to negotiate codecs and transports.</p> - - <p>To pick up the call, the handler should call - <tp:member-ref>Accept</tp:member-ref>. The - <tp:member-ref>CallState</tp:member-ref> property changes to - <tp:type>Call_State</tp:type>_Accepted and once media is - being transferred, telepathy-farstream will notify the - handler of a new pad to be shown to the local user in the - UI</p> - - <p>To reject the call, the handler should call the - <tp:member-ref>Hangup</tp:member-ref> method. The - <tp:member-ref>CallState</tp:member-ref> property will change to - <tp:type>Call_State</tp:type>_Ended and the - <tp:member-ref>CallStateReason</tp:member-ref> property will - change to (self handle, - <tp:type>Call_State_Change_Reason</tp:type>_User_Requested, - "org.freedesktop.Telepathy.Error.Rejected").</p> - - <h4>Ongoing calls</h4> - - <h5>Adding and removing contents</h5> - - <p>When a call is open, new contents can be added as long as the - CM supports it. The - <tp:member-ref>MutableContents</tp:member-ref> property will let - the handler know whether further contents can be added or - existing contents removed. An example of this is starting a - voice call between a contact and then adding a video content. - To do this, the should call - <tp:member-ref>AddContent</tp:member-ref> like this:</p> - - <blockquote> - <pre><tp:member-ref>AddContent</tp:member-ref>("video", - <tp:type>Media_Stream_Type</tp:type>_Video)</pre> - </blockquote> - - <p>Assuming no errors, the new video content will be added to - the call. telepathy-farstream will pick up the new content and - perform the transport and codec negotiation automatically. - telpathy-farstream will signal when the video is ready to - show in the handler's user interface.</p> - - <p>A similar method is used for removing contents from a call, - except that the <tp:dbus-ref - namespace="ofdT.Call.Content.DRAFT">Remove</tp:dbus-ref> method - is on the <tp:dbus-ref - namespace="ofdT.Call">Content.DRAFT</tp:dbus-ref> object.</p> - - <h5>Ending the call</h5> - - <p>To end the call, the handler should call the - <tp:member-ref>Hangup</tp:member-ref> method. The - <tp:member-ref>CallState</tp:member-ref> property will change to - <tp:type>Call_State</tp:type>_Ended and - <tp:member-ref>CallStateReason</tp:member-ref> will change - to (self handle, - <tp:type>Call_State_Change_Reason</tp:type>_User_Requested, - "org.freedesktop.Telepathy.Error.Cancelled").</p> - - <p>If the other participant hangs up first then the - <tp:member-ref>CallState</tp:member-ref> property will change to - <tp:type>Call_State</tp:type>_Ended and - <tp:member-ref>CallStateReason</tp:member-ref> will change - to (remote contact, - <tp:type>Call_State_Change_Reason</tp:type>_User_Requested, - "org.freedesktop.Telepathy.Error.Terminated").</p> - - <h4>Multi-party calls</h4> - - [TODO] - - <h4>Call states</h4> - - <p>There are many combinations of the - <tp:member-ref>CallState</tp:member-ref> and - <tp:member-ref>CallStateReason</tp:member-ref> properties which - mean different things. Here is a table to try to make these - meanings clearer:</p> - - <table> - <tr> - <th rowspan="2"><tp:dbus-ref namespace="ofdT.Channel">Requested</tp:dbus-ref></th> - <th rowspan="2"><tp:member-ref>CallState</tp:member-ref></th> - <th colspan="3"><tp:member-ref>CallStateReason</tp:member-ref></th> - <th rowspan="2">Meaning</th> - </tr> - <tr> - <th>Actor</th> - <th>Reason</th> - <th>DBus_Reason</th> - </tr> - <!-- Pending_Initiator --> - <tr> - <td>True</td> - <td><tp:type>Call_State</tp:type>_Pending_Initiator</td> - <td>Self handle</td> - <td><tp:type>Call_State_Change_Reason</tp:type>_User_Requested</td> - <td>""</td> - <td>The outgoing call channel is waiting for the local user to call <tp:member-ref>Accept</tp:member-ref>.</td> - </tr> - <!-- Pending_Receiver --> - <tr> - <td>True</td> - <td><tp:type>Call_State</tp:type>_Pending_Receiver</td> - <td>Self handle</td> - <td><tp:type>Call_State_Change_Reason</tp:type>_User_Requested</td> - <td>""</td> - <td>The outgoing call is waiting for the remote contact to pick up the call.</td> - </tr> - <tr> - <td>False</td> - <td><tp:type>Call_State</tp:type>_Pending_Receiver</td> - <td>0</td> - <td><tp:type>Call_State_Change_Reason</tp:type>_Unknown</td> - <td>""</td> - <td>The incoming call is waiting for the local user to call <tp:member-ref>Accept</tp:member-ref> on the call.</td> - </tr> - <!-- Accepted --> - <tr> - <td>True</td> - <td><tp:type>Call_State</tp:type>_Accepted</td> - <td>Remote contact handle</td> - <td><tp:type>Call_State_Change_Reason</tp:type>_User_Requested</td> - <td>""</td> - <td>The remote contact accepted the outgoing call.</td> - </tr> - <tr> - <td>False</td> - <td><tp:type>Call_State</tp:type>_Accepted</td> - <td>Self handle</td> - <td><tp:type>Call_State_Change_Reason</tp:type>_User_Requested</td> - <td>""</td> - <td>The local user accepted the incoming call.</td> - </tr> - <!-- Ended --> - <tr> - <td>True or False</td> - <td><tp:type>Call_State</tp:type>_Ended</td> - <td>Self handle</td> - <td><tp:type>Call_State_Change_Reason</tp:type>_User_Requested</td> - <td><tp:error-ref>Cancelled</tp:error-ref></td> - <td>The local user hung up the incoming or outgoing call.</td> - </tr> - <tr> - <td>True or False</td> - <td><tp:type>Call_State</tp:type>_Ended</td> - <td>Remote contact handle</td> - <td><tp:type>Call_State_Change_Reason</tp:type>_User_Requested</td> - <td><tp:error-ref>Terminated</tp:error-ref></td> - <td>The remote contact hung up the incoming or outgoing call.</td> - </tr> - <tr> - <td>True</td> - <td><tp:type>Call_State</tp:type>_Ended</td> - <td>Remote contact handle</td> - <td><tp:type>Call_State_Change_Reason</tp:type>_No_Answer</td> - <td>""</td> - <td>The outgoing call was not picked up and the call ended.</td> - </tr> - <tr> - <td>False</td> - <td><tp:type>Call_State</tp:type>_Ended</td> - <td>Remote contact handle</td> - <td><tp:type>Call_State_Change_Reason</tp:type>_User_Requested</td> - <td><tp:error-ref>PickedUpElsewhere</tp:error-ref></td> - <td>The incoming call was ended because it was picked up elsewhere.</td> - </tr> - </table> - - <h4>Requestable channel classes</h4> - - <p>The <tp:dbus-ref - namespace="ofdT.Connection.Interface.Requests">RequestableChannelClasses</tp:dbus-ref> - for <tp:dbus-ref - namespace="ofdT.Channel.Type">Call.DRAFT</tp:dbus-ref> channels - can be:</p> - - <blockquote> - <pre> -[( Fixed = { ...<tp:dbus-ref namespace="ofdT.Channel">ChannelType</tp:dbus-ref>: ...<tp:dbus-ref namespace="ofdT.Channel.Type">Call.DRAFT</tp:dbus-ref>, - ...<tp:dbus-ref namespace="ofdT.Channel">TargetHandleType</tp:dbus-ref>: Contact, - ...<tp:member-ref>InitialVideo</tp:member-ref>: True - }, - Allowed = [ ...<tp:member-ref>InitialVideoName</tp:member-ref>, - ...<tp:member-ref>InitialAudio</tp:member-ref>, - ...<tp:member-ref>InitialAudioName</tp:member-ref> - ] -), -( Fixed = { ...<tp:dbus-ref namespace="ofdT.Channel">ChannelType</tp:dbus-ref>: ...<tp:dbus-ref namespace="ofdT.Channel.Type">Call.DRAFT</tp:dbus-ref>, - ...<tp:dbus-ref namespace="ofdT.Channel">TargetHandleType</tp:dbus-ref>: Contact, - ...<tp:member-ref>InitialAudio</tp:member-ref>: True - }, - Allowed = [ ...<tp:member-ref>InitialAudioName</tp:member-ref>, - ...<tp:member-ref>InitialVideo</tp:member-ref>, - ...<tp:member-ref>InitialVideoName</tp:member-ref> - ] -)]</pre></blockquote> - - <p>Clients aren't allowed to make outgoing calls that have - neither initial audio nor initial video. Clearly, CMs - which don't support video should leave out the first class and - omit <tp:member-ref>InitialVideo</tp:member-ref> from the second - class, and vice versa for CMs without audio support.</p> - - <p>Handlers should not close <tp:dbus-ref - namespace="ofdT.Channel.Type">Call.DRAFT</tp:dbus-ref> channels - without first calling <tp:member-ref>Hangup</tp:member-ref> on - the channel. If a Call handler crashes, the <tp:dbus-ref - namespace="ofdT">ChannelDispatcher</tp:dbus-ref> will call - <tp:dbus-ref namespace="ofdT.Channel">Close</tp:dbus-ref> on the - channel which SHOULD also imply a call to - <tp:member-ref>Hangup</tp:member-ref>(<tp:type>Call_State_Change_Reason</tp:type>_User_Requested, - "org.freedesktop.Telepathy.Error.Terminated", "") before - actually closing the channel.</p> - - </tp:docstring> - - <method name="SetRinging" tp:name-for-bindings="Set_Ringing"> - <tp:changed version="0.21.2">renamed from Ringing</tp:changed> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>Indicate that the local user has been alerted about the incoming - call.</p> - - <p>This method is only useful if the - channel's <tp:dbus-ref namespace="ofdT.Channel">Requested</tp:dbus-ref> - property is False, and - the <tp:member-ref>CallState</tp:member-ref> is - <tp:type>Call_State</tp:type>_Pending_Receiver (an incoming - call waiting on the local user to pick up). While this is - the case, this method SHOULD change the - <tp:member-ref>CallFlags</tp:member-ref> to include - <tp:type>Call_Flags</tp:type>_Locally_Ringing, and notify the - remote contact that the local user has been alerted (if the - protocol implements this); repeated calls to this method - SHOULD succeed, but have no further effect.</p> - - <p>In all other states, this method SHOULD fail with the error - NotAvailable.</p> - </tp:docstring> - - <tp:possible-errors> - <tp:error name="org.freedesktop.Telepathy.Error.InvalidArgument"> - <tp:docstring> - The call was <tp:dbus-ref namespace="ofdT.Channel" - >Requested</tp:dbus-ref>, so ringing does not make sense. - </tp:docstring> - </tp:error> - <tp:error name="org.freedesktop.Telepathy.Error.NotAvailable"> - <tp:docstring> - The call is no longer in state - <tp:type>Call_State</tp:type>_Pending_Receiver. - </tp:docstring> - </tp:error> - </tp:possible-errors> - </method> - - <method name="Accept" tp:name-for-bindings="Accept"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>For incoming calls in state - <tp:type>Call_State</tp:type>_Pending_Receiver, accept the - incoming call; this changes the - <tp:member-ref>CallState</tp:member-ref> to - <tp:type>Call_State</tp:type>_Accepted.</p> - - <p>For outgoing calls in state - <tp:type>Call_State</tp:type>_Pending_Initiator, actually - call the remote contact; this changes the - <tp:member-ref>CallState</tp:member-ref> to - <tp:type>Call_State</tp:type>_Pending_Receiver.</p> - - <p>Otherwise, this method SHOULD fail with the error NotAvailable.</p> - - <p>This method should be called exactly once per Call, by whatever - client (user interface) is handling the channel.</p> - - <p>When this method is called, for each <tp:dbus-ref - namespace="ofdT.Call" >Content.DRAFT</tp:dbus-ref> whose - <tp:dbus-ref namespace="ofdT.Call.Content.DRAFT" - >Disposition</tp:dbus-ref> is - <tp:type>Call_Content_Disposition</tp:type>_Initial, any - streams where the <tp:dbus-ref - namespace="ofdT.Call.Stream.DRAFT">LocalSendingState</tp:dbus-ref> - is <tp:type>Sending_State</tp:type>_Pending_Send will be - moved to <tp:type>Sending_State</tp:type>_Sending as if - <tp:dbus-ref namespace="ofdT.Call.Stream.DRAFT" - >SetSending</tp:dbus-ref>(True) had been called.</p> - </tp:docstring> - - <tp:possible-errors> - <tp:error name="org.freedesktop.Telepathy.Error.NotAvailable"> - <tp:docstring> - The call is not in one of the states where this method makes sense. - </tp:docstring> - </tp:error> - </tp:possible-errors> - </method> - - <method name="Hangup" tp:name-for-bindings="Hangup"> - <tp:docstring> - Request that the call is ended. All contents will be removed - from the Call so that the - <tp:member-ref>Contents</tp:member-ref> property will be the - empty list. - </tp:docstring> - - <arg direction="in" name="Reason" - type="u" tp:type="Call_State_Change_Reason"> - <tp:docstring> - A generic hangup reason. - </tp:docstring> - </arg> - - <arg direction="in" name="Detailed_Hangup_Reason" - type="s" tp:type="DBus_Error_Name"> - <tp:docstring> - A more specific reason for the call hangup, if one is available, or - an empty string otherwise. - </tp:docstring> - </arg> - - <arg direction="in" name="Message" type="s"> - <tp:docstring> - A human-readable message to be sent to the remote contact(s). - - <tp:rationale> - XMPP Jingle allows calls to be terminated with a human-readable - message. - </tp:rationale> - </tp:docstring> - </arg> - - <tp:possible-errors> - <tp:error name="org.freedesktop.Telepathy.Error.NotAvailable"> - <tp:docstring> - The call has already been ended. - </tp:docstring> - </tp:error> - </tp:possible-errors> - </method> - - <method name="AddContent" tp:name-for-bindings="Add_Content"> - <tp:docstring> - Request that a new <tp:dbus-ref - namespace="ofdT.Call">Content.DRAFT</tp:dbus-ref> of type - Content_Type is added to the Call. Handlers should check the - value of the <tp:member-ref>MutableContents</tp:member-ref> - property before trying to add another content as it might not - be allowed. - </tp:docstring> - <arg direction="in" name="Content_Name" type="s"> - <tp:docstring> - <p>The suggested name of the content to add.</p> - - <tp:rationale> - The content name property should be meaningful, so should - be given a name which is significant to the user. The name - could be a localized "audio", "video" or perhaps include - some string identifying the source, such as a webcam - identifier. - </tp:rationale> - - <p>If there is already a content with the same name as this - property then a sensible suffix should be added. For example, - if this argument is "audio" but a content of the same name - already exists, a sensible suffix such as " (1)" is appended - to name the new content "audio (1)". A further content with the - name "audio" would then be named "audio (2)".</p> - - </tp:docstring> - </arg> - <arg direction="in" name="Content_Type" type="u" - tp:type="Media_Stream_Type"> - <tp:docstring> - The media stream type of the content to be added to the - call. - </tp:docstring> - </arg> - <arg direction="out" name="Content" type="o"> - <tp:docstring> - Path to the newly-created <tp:dbus-ref - namespace="org.freedesktop.Telepathy" - >Call.Content.DRAFT</tp:dbus-ref> object. - </tp:docstring> - </arg> - - <tp:possible-errors> - <tp:error name="org.freedesktop.Telepathy.Error.InvalidArgument"> - <tp:docstring> - The media stream type given is invalid. - </tp:docstring> - </tp:error> - <tp:error name="org.freedesktop.Telepathy.Error.NotImplemented"> - <tp:docstring> - The media stream type requested is not implemented by the - CM. - </tp:docstring> - </tp:error> - <tp:error name="org.freedesktop.Telepathy.Error.NotCapable"> - <tp:docstring> - The content type requested cannot be added to this - call. Examples of why this might be the case include - because a second video stream cannot be added, or a - content cannot be added when the content set isn't - mutable. - </tp:docstring> - </tp:error> - </tp:possible-errors> - </method> - - <signal name="ContentAdded" - tp:name-for-bindings="Content_Added"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>Emitted when a new <tp:dbus-ref namespace="ofdT.Call" - >Content.DRAFT</tp:dbus-ref> is added to the call.</p> - </tp:docstring> - <arg name="Content" type="o"> - <tp:docstring> - Path to the newly-created <tp:dbus-ref namespace="ofdT.Call" - >Content.DRAFT</tp:dbus-ref> object. - </tp:docstring> - </arg> - </signal> - - <signal name="ContentRemoved" tp:name-for-bindings="Content_Removed"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>Emitted when a <tp:dbus-ref namespace="ofdT.Call" - >Content.DRAFT</tp:dbus-ref> is removed from the call.</p> - </tp:docstring> - <arg name="Content" type="o"> - <tp:docstring> - The <tp:dbus-ref namespace="ofdT.Call" - >Content.DRAFT</tp:dbus-ref> which was removed. - </tp:docstring> - </arg> - </signal> - - <property name="Contents" type="ao" access="read" - tp:name-for-bindings="Contents"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>The list of <tp:dbus-ref - namespace="ofdT.Call">Content.DRAFT</tp:dbus-ref> objects that - are part of this call. Change notification is via the - <tp:member-ref>ContentAdded</tp:member-ref> and - <tp:member-ref>ContentRemoved</tp:member-ref> signals. - </p> - </tp:docstring> - </property> - - <tp:enum type="u" name="Call_State"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>The state of a call, as a whole.</p> - - <p>The allowed transitions are:</p> - - <ul> - <li>Pending_Initiator → Pending_Receiver (for outgoing calls, - when <tp:member-ref>Accept</tp:member-ref> is called)</li> - <li>Pending_Receiver → Accepted (for incoming calls, when - <tp:member-ref>Accept</tp:member-ref> is called; for outgoing - calls to a contact, when the remote contact accepts the call; - for joining a conference call, when the local user successfully - joins the conference)</li> - <li>Accepted → Pending_Receiver (when transferred to another - contact)</li> - <li>any state → Ended (when the call is terminated normally, or - when an error occurs)</li> - </ul> - - <p>Clients MAY consider unknown values from this enum to be an - error - additional values will not be defined after the Call - specification is declared to be stable.</p> - </tp:docstring> - - <tp:enumvalue suffix="Unknown" value = "0"> - <tp:docstring> - The call state is not known. This call state MUST NOT appear as a - value of the <tp:member-ref>CallState</tp:member-ref> property, but - MAY be used by client code to represent calls whose state is as yet - unknown. - </tp:docstring> - </tp:enumvalue> - <tp:enumvalue suffix="Pending_Initiator" value = "1"> - <tp:docstring> - The initiator of the call hasn't accepted the call yet. This state - only makes sense for outgoing calls, where it means that the local - user has not yet sent any signalling messages to the remote user(s), - and will not do so until <tp:member-ref>Accept</tp:member-ref> is - called. - </tp:docstring> - </tp:enumvalue> - <tp:enumvalue suffix="Pending_Receiver" value = "2"> - <tp:docstring> - The receiver (the contact being called) hasn't accepted the call yet. - </tp:docstring> - </tp:enumvalue> - <tp:enumvalue suffix="Accepted" value = "3"> - <tp:docstring> - The contact being called has accepted the call. - </tp:docstring> - </tp:enumvalue> - <tp:enumvalue suffix="Ended" value = "4"> - <tp:docstring> - The call has ended, either via normal termination or an error. - </tp:docstring> - </tp:enumvalue> - </tp:enum> - - <tp:flags name="Call_Flags" value-prefix="Call_Flag" type="u"> - <tp:docstring> - A set of flags representing the status of the call as a whole, - providing more specific information than the - <tp:member-ref>CallState</tp:member-ref>. Many of these flags only make - sense in a particular state. - </tp:docstring> - - <tp:flag suffix="Locally_Ringing" value="1"> - <tp:docstring> - The local contact has been alerted about the call but has not - responded; if possible, the remote contact(s) have been informed of - this fact. This flag only makes sense on incoming calls in - state <tp:type>Call_State</tp:type>_Pending_Receiver. It SHOULD - be set when <tp:member-ref>SetRinging</tp:member-ref> is - called successfully, and unset when the state changes. - </tp:docstring> - </tp:flag> - - <tp:flag suffix="Queued" value="2"> - <tp:docstring> - The contact is temporarily unavailable, and the call has been placed - in a queue (e.g. 182 Queued in SIP, or call-waiting in telephony). - This flag only makes sense on outgoing 1-1 calls in - state <tp:type>Call_State</tp:type>_Pending_Receiver. It SHOULD be - set or unset according to informational messages from other - contacts. - </tp:docstring> - </tp:flag> - - <tp:flag suffix="Locally_Held" value="4"> - <tp:docstring> - The call has been put on hold by the local user, e.g. using - the <tp:dbus-ref namespace="ofdT.Channel.Interface" - >Hold</tp:dbus-ref> interface. This flag SHOULD only be set - if there is at least one Content, and all Contents are - locally held; it makes sense on calls in state - <tp:type>Call_State</tp:type>_Pending_Receiver - or <tp:type>Call_State</tp:type>_Accepted. - - <tp:rationale> - Otherwise, in transient situations where some but not all contents - are on hold, UIs would falsely indicate that the call as a whole - is on hold, which could lead to the user saying something they'll - regret, while under the impression that the other contacts can't - hear them! - </tp:rationale> - </tp:docstring> - </tp:flag> - - <tp:flag suffix="Forwarded" value="8"> - <tp:docstring> - The initiator of the call originally called a contact other than the - current recipient of the call, but the call was then forwarded or - diverted. This flag only makes sense on outgoing calls, in state - <tp:type>Call_State</tp:type>_Pending_Receiver or - <tp:type>Call_State</tp:type>_Accepted. It SHOULD be set or unset - according to informational messages from other contacts. - </tp:docstring> - </tp:flag> - - <tp:flag suffix="In_Progress" value="16"> - <tp:docstring> - Progress has been made in placing the outgoing call, but the - contact may not have been made aware of the call yet - (so the Ringing state is not appropriate). This corresponds to SIP's - status code 183 Session Progress, and could be used when the - outgoing call has reached a gateway, for instance. - This flag only makes sense on outgoing calls in state - <tp:type>Call_State</tp:type>_Pending_Receiver, and SHOULD be set - or unset according to informational messages from servers, gateways - and other infrastructure. - </tp:docstring> - </tp:flag> - - <tp:flag suffix="Clearing" value="32"> - <tp:docstring> - This flag only occurs when the CallState is Ended. The call with - this flag set has ended, but not all resources corresponding to the - call have been freed yet. - - Depending on the protocol there might be some audible feedback while - the clearing flag is set. - - <tp:rationale> - In calls following the ITU-T Q.931 standard there is a period of - time between the call ending and the underlying channel being - completely free for re-use. - </tp:rationale> - </tp:docstring> - </tp:flag> - - <tp:flag suffix="Muted" value="64"> - <tp:docstring> - The call has been muted by the local user, e.g. using the - <tp:dbus-ref namespace="ofdT.Call.Content.Interface" - >Mute.DRAFT</tp:dbus-ref> interface. This flag SHOULD only - be set if there is at least one Content, and all Contents - are locally muted; it makes sense on calls in state - <tp:type>Call_State</tp:type>_Pending_Receiver or - <tp:type>Call_State</tp:type>_Accepted. - </tp:docstring> - </tp:flag> - </tp:flags> - - <property name="CallStateDetails" - tp:name-for-bindings="Call_State_Details" type="a{sv}" access="read"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>A map used to provide optional extensible details for the - <tp:member-ref>CallState</tp:member-ref>, - <tp:member-ref>CallFlags</tp:member-ref> and/or - <tp:member-ref>CallStateReason</tp:member-ref>.</p> - - <p>Well-known keys and their corresponding value types include:</p> - - <dl> - <dt>hangup-message - s</dt> - <dd>An optional human-readable message sent when the call was ended, - corresponding to the Message argument to the - <tp:member-ref>Hangup</tp:member-ref> method. This is only - applicable when the call state is <tp:type>Call_State</tp:type>_Ended. - <tp:rationale> - XMPP Jingle can send such messages. - </tp:rationale> - </dd> - - <dt>queue-message - s</dt> - <dd>An optional human-readable message sent when the local contact - is being held in a queue. This is only applicable when - <tp:type>Call_Flags</tp:type>_Queued is in the call flags. - <tp:rationale> - SIP 182 notifications can have human-readable messages attached. - </tp:rationale> - </dd> - - <dt>debug-message - s</dt> - <dd>A message giving further details of any error indicated by the - <tp:member-ref>CallStateReason</tp:member-ref>. This will not - normally be localized or suitable for display to users, and is only - applicable when the call state is - <tp:type>Call_State</tp:type>_Ended.</dd> - </dl> - </tp:docstring> - </property> - - <property name="CallState" type="u" access="read" - tp:name-for-bindings="Call_State" tp:type="Call_State"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>The current high-level state of this call. The - <tp:member-ref>CallFlags</tp:member-ref> provide additional - information, and the <tp:member-ref>CallStateReason</tp:member-ref> - and <tp:member-ref>CallStateDetails</tp:member-ref> explain the - reason for the current values for those properties.</p> - - <p>Note that when in a conference call, this property is - purely to show your state in joining the call. The receiver - (or remote contact) in this context is the conference server - itself. The property does not change when other call members' - states change.</p> - - <p>Clients MAY consider unknown values in this property to be an - error.</p> - </tp:docstring> - </property> - - <property name="CallFlags" type="u" access="read" - tp:name-for-bindings="Call_Flags" tp:type="Call_Flags"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>Flags representing the status of the call as a whole, - providing more specific information than the - <tp:member-ref>CallState</tp:member-ref>.</p> - - <p>Clients are expected to ignore unknown flags in this property, - without error.</p> - - <p>When an ongoing call is active and not on hold or has any - other problems, this property will be 0.</p> - </tp:docstring> - </property> - - <tp:enum name="Call_State_Change_Reason" type="u"> - <tp:docstring> - A simple representation of the reason for a change in the call's - state, which may be used by simple clients, or used as a fallback - when the DBus_Reason member of a <tp:type>Call_State_Reason</tp:type> - struct is not understood. - </tp:docstring> - - <tp:enumvalue suffix="Unknown" value="0"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - We just don't know. Unknown values of this enum SHOULD also be - treated like this. - </tp:docstring> - </tp:enumvalue> - - <tp:enumvalue suffix="User_Requested" value="1"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>The change was requested by the contact indicated by the Actor - member of a <tp:type>Call_State_Reason</tp:type> struct.</p> - - <p>If the Actor is the local user, the DBus_Reason SHOULD be the - empty string.</p> - - <p>If the Actor is a remote user, the DBus_Reason SHOULD be the empty - string if the call was terminated normally, but MAY be a non-empty - error name to indicate error-like call termination reasons (call - rejected as busy, kicked from a conference by a moderator, etc.).</p> - </tp:docstring> - </tp:enumvalue> - - <tp:enumvalue suffix="Forwarded" value="2"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>The call was forwarded. If known, the handle of the contact - the call was forwarded to will be indicated by the Actor member - of a <tp:type>Call_State_Reason</tp:type> struct.</p> - </tp:docstring> - </tp:enumvalue> - - <tp:enumvalue suffix="No_Answer" value="3"> - <tp:added version="0.21.2"/> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>The <tp:member-ref>CallState</tp:member-ref> changed from - <tp:type>Call_State</tp:type>_Pending_Receiver to - <tp:type>Call_State</tp:type>_Ended because the initiator - ended the call before the receiver accepted it. With an - incoming call this state change reason signifies a missed - call.</p> - </tp:docstring> - </tp:enumvalue> - </tp:enum> - - <tp:struct name="Call_State_Reason"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>A description of the reason for a change to the - <tp:member-ref>CallState</tp:member-ref> and/or - <tp:member-ref>CallFlags</tp:member-ref>.</p> - </tp:docstring> - - <tp:member type="u" tp:type="Contact_Handle" name="Actor"> - <tp:docstring> - The contact responsible for the change, or 0 if no contact was - responsible. - </tp:docstring> - </tp:member> - - <tp:member type="u" tp:type="Call_State_Change_Reason" name="Reason"> - <tp:docstring> - The reason, chosen from a limited set of possibilities defined by - the Telepathy specification. If - <tp:type>Call_State_Change_Reason</tp:type>_User_Requested then - the Actor member will dictate whether it was the local user or - a remote contact responsible. - </tp:docstring> - </tp:member> - - <tp:member type="s" tp:type="DBus_Error_Name" name="DBus_Reason"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>A specific reason for the change, which may be a D-Bus error in - the Telepathy namespace, a D-Bus error in any other namespace - (for implementation-specific errors), or the empty string to - indicate that the state change was not an error.</p> - - <p>This SHOULD be an empty string for changes to any state other - than Ended.</p> - - <p>The errors Cancelled and Terminated SHOULD NOT be used here; - an empty string SHOULD be used instead.</p> - - <tp:rationale> - <p>Those error names are used to indicate normal call - termination by the local user or another user, respectively, - in contexts where a D-Bus error name must appear.</p> - </tp:rationale> - </tp:docstring> - </tp:member> - </tp:struct> - - <property name="CallStateReason" tp:name-for-bindings="Call_State_Reason" - type="(uus)" access="read" tp:type="Call_State_Reason"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>The reason for the last change to the - <tp:member-ref>CallState</tp:member-ref> and/or - <tp:member-ref>CallFlags</tp:member-ref>. The - <tp:member-ref>CallStateDetails</tp:member-ref> MAY provide additional - information.</p> - </tp:docstring> - </property> - - <signal name="CallStateChanged" - tp:name-for-bindings="Call_State_Changed"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>Emitted when the state of the call as a whole changes.</p> - - <p>This signal is emitted for any change in the properties - corresponding to its arguments, even if the other properties - referenced remain unchanged.</p> - </tp:docstring> - - <arg name="Call_State" type="u" tp:type="Call_State"> - <tp:docstring> - The new value of the <tp:member-ref>CallState</tp:member-ref> - property. - </tp:docstring> - </arg> - - <arg name="Call_Flags" type="u" tp:type="Call_Flags"> - <tp:docstring> - The new value of the <tp:member-ref>CallFlags</tp:member-ref> - property. - </tp:docstring> - </arg> - - <arg name="Call_State_Reason" type="(uus)" tp:type="Call_State_Reason"> - <tp:docstring> - The new value of the <tp:member-ref>CallStateReason</tp:member-ref> - property. - </tp:docstring> - </arg> - - <arg name="Call_State_Details" type="a{sv}"> - <tp:docstring> - The new value of the <tp:member-ref>CallStateDetails</tp:member-ref> - property. - </tp:docstring> - </arg> - </signal> - - <property name="HardwareStreaming" tp:name-for-bindings="Hardware_Streaming" - type="b" access="read" tp:immutable="yes"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>If this property is True, all of the media streaming is done by some - mechanism outside the scope of Telepathy.</p> - - <tp:rationale> - <p>A connection manager might be intended for a specialized hardware - device, which will take care of the audio streaming (e.g. - telepathy-yafono, which uses GSM hardware which does the actual - audio streaming for the call).</p> - </tp:rationale> - - <p>If this is False, the handler is responsible for doing the actual - media streaming for at least some contents itself. Those contents - will have the <tp:dbus-ref namespace="ofdT.Call.Content.Interface" - >Media.DRAFT</tp:dbus-ref> interface, to communicate the necessary - information to a streaming implementation. Connection managers SHOULD - operate like this, if possible.</p> - - <tp:rationale> - <p>Many connection managers (such as telepathy-gabble) only do the - call signalling, and expect the client to do the actual streaming - using something like - <a href="http://farsight.freedesktop.org/">Farsight</a>, to improve - latency and allow better UI integration.</p> - </tp:rationale> - </tp:docstring> - </property> - - <tp:flags type="u" name="Call_Member_Flags" value-prefix="Call_Member_Flag"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>A set of flags representing the status of a remote contact in a - call.</p> - - <p>It is protocol- and client-specific whether a particular contact - will ever have a particular flag set on them, and Telepathy clients - SHOULD NOT assume that a flag will ever be set.</p> - - <tp:rationale> - <p>180 Ringing in SIP, and its equivalent in XMPP, are optional - informational messages, and implementations are not required - to send them. The same applies to the messages used to indicate - hold state.</p> - </tp:rationale> - </tp:docstring> - - <tp:flag suffix="Ringing" value = "1"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>The remote contact's client has told us that the contact has been - alerted about the call but has not responded.</p> - - <tp:rationale> - <p>This is a flag per member, not a flag for the call as a whole, - because in Muji conference calls, you could invite someone and - have their state be "ringing" for a while.</p> - </tp:rationale> - </tp:docstring> - </tp:flag> - - <tp:flag suffix="Held" value = "2"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>The call member has put this call on hold.</p> - - <tp:rationale> - <p>This is a flag per member, not a flag for the call as a whole, - because in conference calls, any member could put the conference - on hold.</p> - </tp:rationale> - </tp:docstring> - </tp:flag> - - <tp:flag suffix="Conference_Host" value="4"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - This contact has merged this call into a conference. Note that GSM - provides a notification when the remote party merges a call into a - conference, but not when it is split out again; thus, this flag can - only indicate that the call has been part of a conference at some - point. If a GSM connection manager receives a notification that a - call has been merged into a conference a second time, it SHOULD - represent this by clearing and immediately re-setting this flag on - the remote contact. - </tp:docstring> - </tp:flag> - </tp:flags> - - <tp:mapping name="Call_Member_Map" array-name="Call_Member_Map_List"> - <tp:docstring>A mapping from handles to their current state in the call. - </tp:docstring> - <tp:member type="u" tp:type="Handle" name="key"/> - <tp:member type="u" tp:type="Call_Member_Flags" name="Flag"/> - </tp:mapping> - - <signal name="CallMembersChanged" - tp:name-for-bindings="Call_Members_Changed"> - <tp:docstring> - Emitted when the <tp:member-ref>CallMembers</tp:member-ref> property - changes in any way, either because contacts have been added to the - call, contacts have been removed from the call, or contacts' flags - have changed. - </tp:docstring> - - <arg name="Flags_Changed" type="a{uu}" tp:type="Call_Member_Map"> - <tp:docstring> - A map from members of the call to their new call member flags, - including at least the members who have been added to - <tp:member-ref>CallMembers</tp:member-ref>, and the members whose - flags have changed. - </tp:docstring> - </arg> - <arg name="Removed" type="au" tp:type="Contact_Handle[]"> - <tp:docstring> - A list of members who have left the call, i.e. keys to be removed - from <tp:member-ref>CallMembers</tp:member-ref>. - </tp:docstring> - </arg> - </signal> - - <property name="CallMembers" tp:name-for-bindings="Call_Members" - type="a{uu}" access="read" tp:type="Call_Member_Map"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>A mapping from the remote contacts that are part of this call to flags - describing their status. This mapping never has the local user's handle - as a key.</p> - - <p>When the call ends, this property should be an empty list, - and notified with - <tp:member-ref>CallMembersChanged</tp:member-ref></p> - - <p>If the Call implements - <tp:dbus-ref namespace="ofdT.Channel.Interface" - >Group</tp:dbus-ref> and the Group members are - channel-specific handles, then this call SHOULD also use - channel-specific handles.</p> - - <p>Anonymous members are exposed as channel-specific handles - with no owner.</p> - </tp:docstring> - </property> - - <property name="InitialTransport" tp:name-for-bindings="Initial_Transport" - type="u" tp:type="Stream_Transport_Type" access="read" - tp:requestable="yes" tp:immutable="yes"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>If set on a requested channel, this indicates the transport that - should be used for this call. Where not applicable, this property - is defined to be <tp:type>Stream_Transport_Type</tp:type>_Unknown, - in particular, on CMs with hardware streaming.</p> - - <tp:rationale> - When implementing a voip gateway one wants the outgoing leg of the - gatewayed to have the same transport as the incoming leg. This - property allows the gateway to request a Call with the right - transport from the CM. - </tp:rationale> - </tp:docstring> - </property> - - <property name="InitialAudio" tp:name-for-bindings="Initial_Audio" - type="b" access="read" tp:immutable="yes" tp:requestable="yes"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>If set to True in a channel request that will create a new channel, - the connection manager should immediately attempt to establish an - audio stream to the remote contact, making it unnecessary for the - client to call <tp:dbus-ref - namespace="ofdT.Channel.Type.Call.DRAFT">AddContent</tp:dbus-ref>.</p> - - <p>If this property, or InitialVideo, is passed to EnsureChannel - (as opposed to CreateChannel), the connection manager SHOULD ignore - these properties when checking whether it can return an existing - channel as suitable; these properties only become significant when - the connection manager has decided to create a new channel.</p> - - <p>If True on a requested channel, this indicates that the audio - stream has already been requested and the client does not need to - call RequestStreams, although it MAY still do so.</p> - - <p>If True on an unrequested (incoming) channel, this indicates that - the remote contact initially requested an audio stream; this does - not imply that that audio stream is still active (as indicated by - <tp:dbus-ref namespace="ofdT.Channel.Type.Call.DRAFT" - >Contents</tp:dbus-ref>).</p> - - <p>The name of this new content can be decided by using the - <tp:member-ref>InitialAudioName</tp:member-ref> property.</p> - - <p>Connection managers that support the <tp:dbus-ref - namespace="ofdT.Connection.Interface">ContactCapabilities</tp:dbus-ref> - interface SHOULD represent the capabilities of receiving audio - and/or video calls by including a channel class in - a contact's capabilities with ChannelType = Call - in the fixed properties dictionary, and InitialAudio and/or - InitialVideo in the allowed properties list. Clients wishing to - discover whether a particular contact is likely to be able to - receive audio and/or video calls SHOULD use this information.</p> - - <tp:rationale> - <p>Not all clients support video calls, and it would also be - possible (although unlikely) to have a client which could only - stream video, not audio.</p> - </tp:rationale> - - <p>Clients that are willing to receive audio and/or video calls - SHOULD include the following among their channel classes if - calling <tp:dbus-ref - namespace="ofdT.Connection.Interface.ContactCapabilities">UpdateCapabilities</tp:dbus-ref> - (clients of a <tp:dbus-ref - namespace="org.freedesktop.Telepathy">ChannelDispatcher</tp:dbus-ref> - SHOULD instead arrange for the ChannelDispatcher to do this, - by including the filters in their <tp:dbus-ref - namespace="ofdT.Client.Handler">HandlerChannelFilter</tp:dbus-ref> - properties):</p> - - <ul> - <li>{ ChannelType = Call }</li> - <li>{ ChannelType = Call, InitialAudio = True } - if receiving calls with audio is supported</li> - <li>{ ChannelType = Call, InitialVideo = True } - if receiving calls with video is supported</li> - </ul> - - <tp:rationale> - <p>Connection managers for protocols with capability discovery, - like XMPP, need this information to advertise the appropriate - capabilities for their protocol.</p> - </tp:rationale> - </tp:docstring> - </property> - - <property name="InitialVideo" tp:name-for-bindings="Initial_Video" - type="b" access="read" tp:immutable="yes" tp:requestable="yes"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>The same as <tp:member-ref>InitialAudio</tp:member-ref>, but for - a video stream. This property is immutable (cannot change).</p> - - <p>In particular, note that if this property is False, this does not - imply that an active video stream has not been added, only that no - video stream was active at the time the channel appeared.</p> - - <p>This property is the correct way to discover whether connection - managers, contacts etc. support video calls; it appears in - capabilities structures in the same way as InitialAudio.</p> - </tp:docstring> - </property> - - <property name="InitialAudioName" tp:name-for-bindings="Initial_Audio_Name" - type="s" access="read" tp:immutable="yes" tp:requestable="yes"> - <tp:added version="0.21.2"/> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>If <tp:member-ref>InitialAudio</tp:member-ref> is set to - True, then this property will name the intial audio content - with the value of this property.</p> - - <tp:rationale> - <p>Content names are meant to be significant, but if no name - can be given to initial audio content, then its name cannot - be meaningful or even localized.</p> - </tp:rationale> - - <p>If this property is empty or missing from the channel - request and InitialAudio is True, then the CM must come up - with a sensible for the content, such as "audio".</p> - - <p>If the protocol has no concept of stream names then this - property will not show up in the allowed properties list of - the Requestable Channel Classes for call channels.</p> - </tp:docstring> - </property> - - <property name="InitialVideoName" tp:name-for-bindings="Initial_Video_Name" - type="s" access="read" tp:immutable="yes" tp:requestable="yes"> - <tp:added version="0.21.2"/> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>The same as - <tp:member-ref>InitialAudioName</tp:member-ref>, but for a - video stream created by setting - <tp:member-ref>InitialVideo</tp:member-ref> to True. This - property is immutable and so cannot change.</p> - </tp:docstring> - </property> - - <property name="MutableContents" tp:name-for-bindings="Mutable_Contents" - type="b" access="read" tp:immutable="yes"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>If True, a stream of a different content type can be added - after the Channel has been requested </p> - - <p>If this property is missing, clients SHOULD assume that it is False, - and thus that the channel's streams cannot be changed once the call - has started.</p> - - <p>If this property isn't present in the "allowed" set in any of the - Call entries contact capabilities, then user interfaces MAY choose to - show a separate "call" option for each class of call.</p> - - <tp:rationale> - <p>For example, once an audio-only Google Talk call has started, - it is not possible to add a video stream; both audio and video - must be requested at the start of the call if video is desired. - User interfaces may use this pseudo-capability as a hint to - display separate "Audio call" and "Video call" buttons, rather - than a single "Call" button with the option to add and remove - video once the call has started for contacts without this flag. - </p> - </tp:rationale> - </tp:docstring> - </property> - - <tp:hct name="audio"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>This client supports audio calls.</p> - </tp:docstring> - </tp:hct> - - <tp:hct name="video"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>This client supports video calls.</p> - </tp:docstring> - </tp:hct> - - <tp:hct name="gtalk-p2p"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>The client can implement streaming for streams whose <tp:dbus-ref - namespace="ofdT.Call.Stream.Interface.Media.DRAFT">Transport</tp:dbus-ref> - property is <tp:type>Stream_Transport_Type</tp:type>_GTalk_P2P.</p> - </tp:docstring> - </tp:hct> - - <tp:hct name="ice"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>The client can implement streaming for streams whose <tp:dbus-ref - namespace="ofdT.Call.Stream.Interface.Media.DRAFT">Transport</tp:dbus-ref> - property is <tp:type>Stream_Transport_Type</tp:type>_ICE.</p> - </tp:docstring> - </tp:hct> - - <tp:hct name="wlm-2009"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>The client can implement streaming for streams whose <tp:dbus-ref - namespace="ofdT.Call.Stream.Interface.Media.DRAFT">Transport</tp:dbus-ref> - property is <tp:type>Stream_Transport_Type</tp:type>_WLM_2009.</p> - </tp:docstring> - </tp:hct> - - <tp:hct name="shm"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>The client can implement streaming for streams whose <tp:dbus-ref - namespace="ofdT.Call.Stream.Interface.Media.DRAFT">Transport</tp:dbus-ref> - property is <tp:type>Stream_Transport_Type</tp:type>_SHM.</p> - </tp:docstring> - </tp:hct> - - <tp:hct name="video/h264" is-family="yes"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>The client supports media streaming with H264 (etc.).</p> - - <p>This handler capability token is a one of a family - of similar tokens: for any other audio or video codec whose MIME - type is audio/<em>subtype</em> or video/<em>subtype</em>, a handler - capability token of this form may exist (the subtype MUST appear - in lower case in this context). Clients MAY support more - codecs than they explicitly advertise support for; clients SHOULD - explicitly advertise support for their preferred codec(s), and - for codecs like H264 that are, in practice, significant in codec - negotiation.</p> - - <tp:rationale> - <p>For instance, the XMPP capability used by the Google Video - Chat web client to determine whether a client is compatible - with it requires support for H264 video, so an XMPP - connection manager that supports this version of Jingle should - not advertise the Google Video Chat capability unless there - is at least one installed client that declares that it supports - <code>video/h264</code> on Call channels.</p> - </tp:rationale> - - <p>For example, a client could advertise support for audio and video - calls using Speex, Theora and H264 by having five handler capability - tokens in its <tp:dbus-ref - namespace="ofdT.Client.Handler">Capabilities</tp:dbus-ref> - property:</p> - - <ul> - <li><code>org.freedesktop.Telepathy.Channel.Type.Call.DRAFT/audio</code></li> - <li><code>org.freedesktop.Telepathy.Channel.Type.Call.DRAFT/audio/speex</code></li> - <li><code>org.freedesktop.Telepathy.Channel.Type.Call.DRAFT/video</code></li> - <li><code>org.freedesktop.Telepathy.Channel.Type.Call.DRAFT/video/theora</code></li> - <li><code>org.freedesktop.Telepathy.Channel.Type.Call.DRAFT/video/h264</code></li> - </ul> - - <p>Clients MAY have media signalling abilities without explicitly - supporting any particular codec, and connection managers SHOULD - support this usage.</p> - - <tp:rationale> - <p>This is necessary to support gatewaying between two Telepathy - connections, in which case the available codecs might not be - known to the gatewaying process.</p> - </tp:rationale> - </tp:docstring> - </tp:hct> - - </interface> -</node> -<!-- vim:set sw=2 sts=2 et ft=xml: --> diff --git a/extensions/Makefile.am b/extensions/Makefile.am deleted file mode 100644 index 6fdc6b6..0000000 --- a/extensions/Makefile.am +++ /dev/null @@ -1,167 +0,0 @@ -# This directory re-uses telepathy-glib's code generation mechanisms to -# generate code for interfaces that aren't stable enough for telepathy-glib -# yet, so we can start to adapt example code to use them. - -tools_dir = $(top_srcdir)/tools - -AM_CFLAGS = \ - $(ERROR_CFLAGS) \ - $(GLIB_CFLAGS) \ - $(TELEPATHY_CFLAGS) \ - $(DBUS_CFLAGS) \ - -I${top_builddir} -I${top_srcdir} - -EXTRA_DIST = \ - all.xml \ - Call_Content_Codec_Offer.xml \ - Call_Content_Interface_Audio_Control.xml \ - Call_Content_Interface_Media.xml \ - Call_Content_Interface_Mute.xml \ - Call_Content_Interface_Video_Control.xml \ - call-content.xml \ - Call_Content.xml \ - Call_Stream_Endpoint.xml \ - Call_Stream_Interface_Media.xml \ - call-stream.xml \ - Call_Stream.xml \ - Channel_Type_Call.xml \ - channel.xml \ - misc.xml - -noinst_LTLIBRARIES = libfuture-extensions.la - -# In an external project you'd use $(TP_GLIB_LIBS) (obtained from -# pkg-config via autoconf) instead of the .la path -libfuture_extensions_la_LIBADD = \ - $(GLIB_LIBS) \ - $(TELEPATHY_LIBS) - -libfuture_extensions_la_SOURCES = \ - call-content.c \ - call-content.h \ - call-stream.c \ - call-stream.h \ - extensions.c \ - extensions-cli.c \ - extensions.h - -nodist_libfuture_extensions_la_SOURCES = \ - _gen/signals-marshal.c \ - _gen/signals-marshal.h \ - _gen/signals-marshal.list \ - _gen/register-dbus-glib-marshallers-body.h \ - _gen/enums.h \ - _gen/gtypes.h \ - _gen/gtypes-body.h \ - _gen/interfaces.h \ - _gen/interfaces-body.h \ - _gen/cli-call-content.h \ - _gen/cli-call-content-body.h \ - _gen/cli-call-stream.h \ - _gen/cli-call-stream-body.h \ - _gen/cli-channel.h \ - _gen/cli-channel-body.h \ - _gen/cli-misc.h \ - _gen/cli-misc-body.h - -BUILT_SOURCES = \ - _gen/all.xml \ - _gen/call-content.xml \ - _gen/call-stream.xml \ - _gen/channel.xml \ - _gen/misc.xml \ - $(nodist_libfuture_extensions_la_SOURCES) - -CLEANFILES = $(BUILT_SOURCES) - -clean-local: - rm -rf _gen - -XSLTPROCFLAGS = --nonet --novalid - -# Generated files which can be generated for all categories simultaneously - -_gen/all.xml: all.xml $(wildcard $(srcdir)/*.xml) $(wildcard $(top_srcdir)/spec/*.xml) $(tools_dir)/xincludator.py - $(mkdir_p) _gen - $(AM_V_GEN)$(PYTHON) $(tools_dir)/xincludator.py $< > $@ - -_gen/gtypes.h _gen/gtypes-body.h: _gen/all.xml \ - $(top_srcdir)/tools/glib-gtypes-generator.py - $(AM_V_GEN)$(PYTHON) $(top_srcdir)/tools/glib-gtypes-generator.py \ - $< _gen/gtypes Tf_Future - -_gen/signals-marshal.list: _gen/all.xml \ - $(tools_dir)/glib-signals-marshal-gen.py - $(AM_V_GEN)$(PYTHON) $(tools_dir)/glib-signals-marshal-gen.py $< > $@ - -_gen/signals-marshal.h: _gen/signals-marshal.list Makefile.am - $(AM_V_GEN)$(GLIB_GENMARSHAL) --header --prefix=_tf_future_ext_marshal $< > $@ - -_gen/signals-marshal.c: _gen/signals-marshal.list Makefile.am - $(AM_V_GEN){ echo '#include "_gen/signals-marshal.h"' && \ - $(GLIB_GENMARSHAL) --body --prefix=_tf_future_ext_marshal $< ; } > $@ - -_gen/register-dbus-glib-marshallers-body.h: _gen/all.xml \ - $(tools_dir)/glib-client-marshaller-gen.py - $(AM_V_GEN)$(PYTHON) $(tools_dir)/glib-client-marshaller-gen.py $< \ - _tf_future_ext > $@ - -_gen/enums.h: _gen/all.xml \ - $(tools_dir)/c-constants-gen.py - $(AM_V_GEN)$(PYTHON) $(tools_dir)/c-constants-gen.py \ - Tf_Future \ - $< _gen/enums - -_gen/interfaces-body.h _gen/interfaces.h: _gen/all.xml \ - $(tools_dir)/glib-interfaces-gen.py - $(AM_V_GEN)$(PYTHON) $(tools_dir)/glib-interfaces-gen.py \ - Tf_Future _gen/interfaces-body.h _gen/interfaces.h $< - -# Generated files which must be generated per "category". Each TpProxy -# subclass you want to use with --subclass will need to have its own category, -# although you can subdivide further if you want. - -_gen/%.xml: %.xml $(wildcard $(srcdir)/*.xml) $(wildcard $(top_srcdir)/spec/*.xml) $(tools_dir)/xincludator.py - $(mkdir_p) _gen - $(AM_V_GEN)$(PYTHON) $(tools_dir)/xincludator.py $< > $@ - -_gen/cli-channel-body.h _gen/cli-channel.h: _gen/channel.xml \ - $(tools_dir)/glib-client-gen.py Makefile.am - $(AM_V_GEN)$(PYTHON) $(tools_dir)/glib-client-gen.py \ - --group=channel \ - --subclass=TpChannel \ - --subclass-assert=TP_IS_CHANNEL \ - --iface-quark-prefix=TF_FUTURE_IFACE_QUARK \ - --tp-proxy-api=0.7.6 \ - $< Tf_Future_Cli _gen/cli-channel - -_gen/cli-call-content-body.h _gen/cli-call-content.h: _gen/call-content.xml \ - $(tools_dir)/glib-client-gen.py Makefile.am - $(AM_V_GEN)$(PYTHON) $(tools_dir)/glib-client-gen.py \ - --group=call_content \ - --subclass=TfFutureCallContent \ - --subclass-assert=TF_FUTURE_IS_CALL_CONTENT \ - --iface-quark-prefix=TF_FUTURE_IFACE_QUARK \ - --tp-proxy-api=0.7.6 \ - $< Tf_Future_Cli _gen/cli-call-content - -_gen/cli-call-stream-body.h _gen/cli-call-stream.h: _gen/call-stream.xml \ - $(tools_dir)/glib-client-gen.py Makefile.am - $(AM_V_GEN)$(PYTHON) $(tools_dir)/glib-client-gen.py \ - --group=call_stream \ - --subclass=TfFutureCallStream \ - --subclass-assert=TF_FUTURE_IS_CALL_STREAM \ - --iface-quark-prefix=TF_FUTURE_IFACE_QUARK \ - --tp-proxy-api=0.7.6 \ - $< Tf_Future_Cli _gen/cli-call-stream - -# for now the Endpoint etc. interfaces are on every TpProxy - when we -# have a TpCallEndpoint etc., they should appear on that - -_gen/cli-misc-body.h _gen/cli-misc.h: _gen/misc.xml \ - $(tools_dir)/glib-client-gen.py Makefile.am - $(AM_V_GEN)$(PYTHON) $(tools_dir)/glib-client-gen.py \ - --group=misc \ - --iface-quark-prefix=TF_FUTURE_IFACE_QUARK \ - --tp-proxy-api=0.7.6 \ - $< Tf_Future_Cli _gen/cli-misc diff --git a/extensions/all.xml b/extensions/all.xml deleted file mode 100644 index 618cef7..0000000 --- a/extensions/all.xml +++ /dev/null @@ -1,12 +0,0 @@ -<tp:spec - xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0" - xmlns:xi="http://www.w3.org/2001/XInclude"> - -<tp:title>Extensions from the future</tp:title> - -<xi:include href="call-content.xml"/> -<xi:include href="call-stream.xml"/> -<xi:include href="channel.xml"/> -<xi:include href="misc.xml"/> - -</tp:spec> diff --git a/extensions/call-content.c b/extensions/call-content.c deleted file mode 100644 index deb36ec..0000000 --- a/extensions/call-content.c +++ /dev/null @@ -1,161 +0,0 @@ -/* - * call-content.c - proxy for a Content in a Call channel - * - * Copyright (C) 2009 Collabora Ltd. <http://www.collabora.co.uk/> - * Copyright (C) 2009 Nokia Corporation - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "extensions/call-content.h" - -#include <telepathy-glib/proxy-subclass.h> -#include <telepathy-glib/telepathy-glib.h> - -#include "extensions/extensions.h" - -/* Generated code */ -#include "_gen/cli-call-content-body.h" - -/** - * SECTION:call-content - * @title: TfFutureCallContent - * @short_description: proxy for a Content in a Call channel - * @see_also: #TpChannel - * - * FIXME - * - * Since: FIXME - */ - -/** - * TfFutureCallContentClass: - * - * The class of a #TfFutureCallContent. - * - * Since: FIXME - */ -struct _TfFutureCallContentClass { - TpProxyClass parent_class; - /*<private>*/ - gpointer priv; -}; - -/** - * TfFutureCallContent: - * - * A proxy object for a Telepathy connection manager. - * - * Since: FIXME - */ -struct _TfFutureCallContent { - TpProxy parent; - /*<private>*/ - TfFutureCallContentPrivate *priv; -}; - -struct _TfFutureCallContentPrivate { - int dummy; -}; - -G_DEFINE_TYPE (TfFutureCallContent, - tf_future_call_content, - TP_TYPE_PROXY); - -static void -tf_future_call_content_init (TfFutureCallContent *self) -{ - self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, TF_FUTURE_TYPE_CALL_CONTENT, - TfFutureCallContentPrivate); -} - -static void -tf_future_call_content_class_init (TfFutureCallContentClass *klass) -{ - TpProxyClass *proxy_class = (TpProxyClass *) klass; - - g_type_class_add_private (klass, sizeof (TfFutureCallContentPrivate)); - - proxy_class->must_have_unique_name = TRUE; - proxy_class->interface = TF_FUTURE_IFACE_QUARK_CALL_CONTENT; - tf_future_call_content_init_known_interfaces (); -} - -/** - * tf_future_call_content_new: - * @channel: the Call channel - * @object_path: the object path of the content; may not be %NULL - * @error: used to indicate the error if %NULL is returned - * - * <!-- --> - * - * Returns: a new content proxy, or %NULL on invalid arguments - * - * Since: FIXME - */ -TfFutureCallContent * -tf_future_call_content_new (TpChannel *channel, - const gchar *object_path, - GError **error) -{ - TfFutureCallContent *ret = NULL; - - g_return_val_if_fail (TP_IS_CHANNEL (channel), NULL); - g_return_val_if_fail (object_path != NULL, NULL); - - if (!tp_dbus_check_valid_object_path (object_path, error)) - goto finally; - - ret = TF_FUTURE_CALL_CONTENT (g_object_new (TF_FUTURE_TYPE_CALL_CONTENT, - /* FIXME: pass in the Channel as a property? */ - "dbus-daemon", tp_proxy_get_dbus_daemon (channel), - "bus-name", tp_proxy_get_bus_name (channel), - "object-path", object_path, - NULL)); - -finally: - return ret; -} - -/** - * tf_future_call_content_init_known_interfaces: - * - * Ensure that the known interfaces for TfFutureCallContent have been set up. - * This is done automatically when necessary, but for correct - * overriding of library interfaces by local extensions, you should - * call this function before calling - * tp_proxy_or_subclass_hook_on_interface_add() with first argument - * %TF_FUTURE_TYPE_CALL_CONTENT. - * - * Since: 0.7.32 - */ -void -tf_future_call_content_init_known_interfaces (void) -{ - static gsize once = 0; - - if (g_once_init_enter (&once)) - { - GType tp_type = TF_FUTURE_TYPE_CALL_CONTENT; - - tp_proxy_init_known_interfaces (); - tp_proxy_or_subclass_hook_on_interface_add (tp_type, - tf_future_cli_call_content_add_signals); - tp_proxy_subclass_add_error_mapping (tp_type, - TP_ERROR_PREFIX, TP_ERRORS, TP_TYPE_ERROR); - - g_once_init_leave (&once, 1); - } -} diff --git a/extensions/call-content.h b/extensions/call-content.h deleted file mode 100644 index 68873d5..0000000 --- a/extensions/call-content.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * call-content.h - proxy for a Content in a Call channel - * - * Copyright (C) 2009 Collabora Ltd. <http://www.collabora.co.uk/> - * Copyright (C) 2009 Nokia Corporation - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef TF_FUTURE_CALL_CONTENT_H -#define TF_FUTURE_CALL_CONTENT_H - -#include <telepathy-glib/channel.h> -#include <telepathy-glib/proxy.h> - -G_BEGIN_DECLS - -typedef struct _TfFutureCallContent TfFutureCallContent; -typedef struct _TfFutureCallContentPrivate TfFutureCallContentPrivate; -typedef struct _TfFutureCallContentClass TfFutureCallContentClass; - -GType tf_future_call_content_get_type (void); - -/* TYPE MACROS */ -#define TF_FUTURE_TYPE_CALL_CONTENT \ - (tf_future_call_content_get_type ()) -#define TF_FUTURE_CALL_CONTENT(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), TF_FUTURE_TYPE_CALL_CONTENT, \ - TfFutureCallContent)) -#define TF_FUTURE_CALL_CONTENT_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), TF_FUTURE_TYPE_CALL_CONTENT, \ - TfFutureCallContentClass)) -#define TF_FUTURE_IS_CALL_CONTENT(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), TF_FUTURE_TYPE_CALL_CONTENT)) -#define TF_FUTURE_IS_CALL_CONTENT_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), TF_FUTURE_TYPE_CALL_CONTENT)) -#define TF_FUTURE_CALL_CONTENT_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), TF_FUTURE_TYPE_CALL_CONTENT, \ - TfFutureCallContentClass)) - -TfFutureCallContent *tf_future_call_content_new (TpChannel *channel, - const gchar *object_path, GError **error); - -void tf_future_call_content_init_known_interfaces (void); - -G_END_DECLS - -#include "extensions/_gen/cli-call-content.h" - -#endif diff --git a/extensions/call-content.xml b/extensions/call-content.xml deleted file mode 100644 index ead2fe5..0000000 --- a/extensions/call-content.xml +++ /dev/null @@ -1,12 +0,0 @@ -<tp:spec - xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0" - xmlns:xi="http://www.w3.org/2001/XInclude"> - -<tp:title>Call Content</tp:title> - -<xi:include href="Call_Content.xml"/> -<xi:include href="Call_Content_Interface_Audio_Control.xml"/> -<xi:include href="Call_Content_Interface_Media.xml"/> -<xi:include href="Call_Content_Interface_Video_Control.xml"/> - -</tp:spec> diff --git a/extensions/call-stream.c b/extensions/call-stream.c deleted file mode 100644 index a9a0d1c..0000000 --- a/extensions/call-stream.c +++ /dev/null @@ -1,161 +0,0 @@ -/* - * call-stream.c - proxy for a Stream in a Call channel - * - * Copyright (C) 2009 Collabora Ltd. <http://www.collabora.co.uk/> - * Copyright (C) 2009 Nokia Corporation - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "extensions/call-stream.h" - -#include <telepathy-glib/proxy-subclass.h> -#include <telepathy-glib/telepathy-glib.h> - -#include "extensions/extensions.h" - -/* Generated code */ -#include "_gen/cli-call-stream-body.h" - -/** - * SECTION:call-stream - * @title: TfFutureCallStream - * @short_description: proxy for a Stream in a Call channel - * @see_also: #TpChannel - * - * FIXME - * - * Since: FIXME - */ - -/** - * TfFutureCallStreamClass: - * - * The class of a #TfFutureCallStream. - * - * Since: FIXME - */ -struct _TfFutureCallStreamClass { - TpProxyClass parent_class; - /*<private>*/ - gpointer priv; -}; - -/** - * TfFutureCallStream: - * - * A proxy object for a Telepathy connection manager. - * - * Since: FIXME - */ -struct _TfFutureCallStream { - TpProxy parent; - /*<private>*/ - TfFutureCallStreamPrivate *priv; -}; - -struct _TfFutureCallStreamPrivate { - int dummy; -}; - -G_DEFINE_TYPE (TfFutureCallStream, - tf_future_call_stream, - TP_TYPE_PROXY); - -static void -tf_future_call_stream_init (TfFutureCallStream *self) -{ - self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, TF_FUTURE_TYPE_CALL_STREAM, - TfFutureCallStreamPrivate); -} - -static void -tf_future_call_stream_class_init (TfFutureCallStreamClass *klass) -{ - TpProxyClass *proxy_class = (TpProxyClass *) klass; - - g_type_class_add_private (klass, sizeof (TfFutureCallStreamPrivate)); - - proxy_class->must_have_unique_name = TRUE; - proxy_class->interface = TF_FUTURE_IFACE_QUARK_CALL_STREAM; - tf_future_call_stream_init_known_interfaces (); -} - -/** - * tf_future_call_stream_new: - * @channel: the Call channel - * @object_path: the object path of the stream; may not be %NULL - * @error: used to indicate the error if %NULL is returned - * - * <!-- --> - * - * Returns: a new stream proxy, or %NULL on invalid arguments - * - * Since: FIXME - */ -TfFutureCallStream * -tf_future_call_stream_new (TpChannel *channel, - const gchar *object_path, - GError **error) -{ - TfFutureCallStream *ret = NULL; - - g_return_val_if_fail (TP_IS_CHANNEL (channel), NULL); - g_return_val_if_fail (object_path != NULL, NULL); - - if (!tp_dbus_check_valid_object_path (object_path, error)) - goto finally; - - ret = TF_FUTURE_CALL_STREAM (g_object_new (TF_FUTURE_TYPE_CALL_STREAM, - /* FIXME: pass in the Channel as a property? */ - "dbus-daemon", tp_proxy_get_dbus_daemon (channel), - "bus-name", tp_proxy_get_bus_name (channel), - "object-path", object_path, - NULL)); - -finally: - return ret; -} - -/** - * tf_future_call_stream_init_known_interfaces: - * - * Ensure that the known interfaces for TfFutureCallStream have been set up. - * This is done automatically when necessary, but for correct - * overriding of library interfaces by local extensions, you should - * call this function before calling - * tp_proxy_or_subclass_hook_on_interface_add() with first argument - * %TF_FUTURE_TYPE_CALL_STREAM. - * - * Since: 0.7.32 - */ -void -tf_future_call_stream_init_known_interfaces (void) -{ - static gsize once = 0; - - if (g_once_init_enter (&once)) - { - GType tp_type = TF_FUTURE_TYPE_CALL_STREAM; - - tp_proxy_init_known_interfaces (); - tp_proxy_or_subclass_hook_on_interface_add (tp_type, - tf_future_cli_call_stream_add_signals); - tp_proxy_subclass_add_error_mapping (tp_type, - TP_ERROR_PREFIX, TP_ERRORS, TP_TYPE_ERROR); - - g_once_init_leave (&once, 1); - } -} diff --git a/extensions/call-stream.h b/extensions/call-stream.h deleted file mode 100644 index 2cd82b5..0000000 --- a/extensions/call-stream.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * call-stream.h - proxy for a Stream in a Call channel - * - * Copyright (C) 2009 Collabora Ltd. <http://www.collabora.co.uk/> - * Copyright (C) 2009 Nokia Corporation - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef TF_FUTURE_CALL_STREAM_H -#define TF_FUTURE_CALL_STREAM_H - -#include <telepathy-glib/channel.h> -#include <telepathy-glib/proxy.h> - -G_BEGIN_DECLS - -typedef struct _TfFutureCallStream TfFutureCallStream; -typedef struct _TfFutureCallStreamPrivate TfFutureCallStreamPrivate; -typedef struct _TfFutureCallStreamClass TfFutureCallStreamClass; - -GType tf_future_call_stream_get_type (void); - -/* TYPE MACROS */ -#define TF_FUTURE_TYPE_CALL_STREAM \ - (tf_future_call_stream_get_type ()) -#define TF_FUTURE_CALL_STREAM(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), TF_FUTURE_TYPE_CALL_STREAM, \ - TfFutureCallStream)) -#define TF_FUTURE_CALL_STREAM_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), TF_FUTURE_TYPE_CALL_STREAM, \ - TfFutureCallStreamClass)) -#define TF_FUTURE_IS_CALL_STREAM(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), TF_FUTURE_TYPE_CALL_STREAM)) -#define TF_FUTURE_IS_CALL_STREAM_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), TF_FUTURE_TYPE_CALL_STREAM)) -#define TF_FUTURE_CALL_STREAM_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), TF_FUTURE_TYPE_CALL_STREAM, \ - TfFutureCallStreamClass)) - -TfFutureCallStream *tf_future_call_stream_new (TpChannel *channel, - const gchar *object_path, GError **error); - -void tf_future_call_stream_init_known_interfaces (void); - -G_END_DECLS - -#include "extensions/_gen/cli-call-stream.h" - -#endif diff --git a/extensions/call-stream.xml b/extensions/call-stream.xml deleted file mode 100644 index 3e85b37..0000000 --- a/extensions/call-stream.xml +++ /dev/null @@ -1,10 +0,0 @@ -<tp:spec - xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0" - xmlns:xi="http://www.w3.org/2001/XInclude"> - -<tp:title>Call Stream</tp:title> - -<xi:include href="Call_Stream.xml"/> -<xi:include href="Call_Stream_Interface_Media.xml"/> - -</tp:spec> diff --git a/extensions/channel.xml b/extensions/channel.xml deleted file mode 100644 index b4e0a46..0000000 --- a/extensions/channel.xml +++ /dev/null @@ -1,9 +0,0 @@ -<tp:spec - xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0" - xmlns:xi="http://www.w3.org/2001/XInclude"> - -<tp:title>Channel extensions from the future</tp:title> - -<xi:include href="Channel_Type_Call.xml"/> - -</tp:spec> diff --git a/extensions/extensions-cli.c b/extensions/extensions-cli.c deleted file mode 100644 index 971669d..0000000 --- a/extensions/extensions-cli.c +++ /dev/null @@ -1,35 +0,0 @@ -#include "extensions.h" - -#include <telepathy-glib/telepathy-glib.h> -#include <telepathy-glib/proxy-subclass.h> - -static void _tf_future_ext_register_dbus_glib_marshallers (void); - -/* include auto-generated stubs for client-specific code */ -#include "_gen/signals-marshal.h" -#include "_gen/cli-channel-body.h" -#include "_gen/cli-misc-body.h" -#include "_gen/register-dbus-glib-marshallers-body.h" - -static gpointer -tf_future_cli_once (gpointer data) -{ - _tf_future_ext_register_dbus_glib_marshallers (); - - tp_channel_init_known_interfaces (); - - tp_proxy_or_subclass_hook_on_interface_add (TP_TYPE_PROXY, - tf_future_cli_misc_add_signals); - tp_proxy_or_subclass_hook_on_interface_add (TP_TYPE_CHANNEL, - tf_future_cli_channel_add_signals); - - return NULL; -} - -void -tf_future_cli_init (void) -{ - static GOnce once = G_ONCE_INIT; - - g_once (&once, tf_future_cli_once, NULL); -} diff --git a/extensions/extensions.c b/extensions/extensions.c deleted file mode 100644 index eeda462..0000000 --- a/extensions/extensions.c +++ /dev/null @@ -1,6 +0,0 @@ -#include "extensions.h" - -/* include auto-generated stubs for things common to service and client */ -#include "_gen/gtypes-body.h" -#include "_gen/interfaces-body.h" -#include "_gen/signals-marshal.h" diff --git a/extensions/extensions.h b/extensions/extensions.h deleted file mode 100644 index f6e080d..0000000 --- a/extensions/extensions.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef FUTURE_EXTENSIONS_H -#define FUTURE_EXTENSIONS_H - -#include <glib-object.h> -#include <telepathy-glib/telepathy-glib.h> - -#include "extensions/_gen/enums.h" -#include "extensions/_gen/cli-channel.h" -#include "extensions/_gen/cli-misc.h" - -#include "extensions/call-content.h" -#include "extensions/call-stream.h" - -G_BEGIN_DECLS - -#include "extensions/_gen/gtypes.h" -#include "extensions/_gen/interfaces.h" - -void tf_future_cli_init (void); - -G_END_DECLS - -#endif diff --git a/extensions/misc.xml b/extensions/misc.xml deleted file mode 100644 index 0384410..0000000 --- a/extensions/misc.xml +++ /dev/null @@ -1,10 +0,0 @@ -<tp:spec - xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0" - xmlns:xi="http://www.w3.org/2001/XInclude"> - -<tp:title>Miscellaneous extensions from the future</tp:title> - -<xi:include href="Call_Content_Codec_Offer.xml"/> -<xi:include href="Call_Stream_Endpoint.xml"/> - -</tp:spec> diff --git a/python/examples/constants.py b/python/examples/constants.py index 0def268..43af8ba 100644 --- a/python/examples/constants.py +++ b/python/examples/constants.py @@ -20,23 +20,23 @@ from telepathy.interfaces import CHANNEL_INTERFACE CHANNEL = CHANNEL_INTERFACE CHANNEL_TYPE = CHANNEL + ".ChannelType" -CHANNEL_TYPE_CALL = CHANNEL + ".Type.Call.DRAFT" +CHANNEL_TYPE_CALL = CHANNEL + ".Type.Call1" CALL_INITIAL_AUDIO = CHANNEL_TYPE_CALL + '.InitialAudio' CALL_INITIAL_VIDEO = CHANNEL_TYPE_CALL + '.InitialVideo' CALL_MUTABLE_CONTENTS = CHANNEL_TYPE_CALL + '.MutableContents' -CALL_CONTENT = 'org.freedesktop.Telepathy.Call.Content.DRAFT' +CALL_CONTENT = 'org.freedesktop.Telepathy.Call1.Content' CALL_CONTENT_IFACE_MEDIA = \ - 'org.freedesktop.Telepathy.Call.Content.Interface.Media.DRAFT' + 'org.freedesktop.Telepathy.Call1.Content.Interface.Media' CALL_CONTENT_CODECOFFER = \ - 'org.freedesktop.Telepathy.Call.Content.CodecOffer.DRAFT' + 'org.freedesktop.Telepathy.Call1.Content.CodecOffer' -CALL_STREAM = 'org.freedesktop.Telepathy.Call.Stream.DRAFT' +CALL_STREAM = 'org.freedesktop.Telepathy.Call1.Stream' CALL_STREAM_IFACE_MEDIA = \ - 'org.freedesktop.Telepathy.Call.Stream.Interface.Media.DRAFT' + 'org.freedesktop.Telepathy.Call1.Stream.Interface.Media' -CALL_STREAM_ENDPOINT = 'org.freedesktop.Telepathy.Call.Stream.Endpoint.DRAFT' +CALL_STREAM_ENDPOINT = 'org.freedesktop.Telepathy.Call1.Stream.Endpoint' STREAM_TRANSPORT_RAW_UDP = 1 STREAM_TRANSPORT_ICE_UDP = 2 diff --git a/python/pytpfarstream.defs b/python/pytpfarstream.defs index 59b6783..fa2e554 100644 --- a/python/pytpfarstream.defs +++ b/python/pytpfarstream.defs @@ -29,11 +29,6 @@ ;; From telepathy-farstream.h -(define-function tf_init - (c-name "tf_init") - (return-type "none") -) - ;; -*- scheme -*- ; object definitions ... @@ -74,8 +69,6 @@ (c-name "tf_content_error_literal") (return-type "none") (parameters - '("guint" "reason") - '("const-gchar*" "detailed_reason") '("const-gchar*" "message") ) ) @@ -85,8 +78,48 @@ (c-name "tf_content_error") (return-type "none") (parameters - '("guint" "reason") - '("const-gchar*" "detailed_reason") + '("const-gchar*" "message_format") + ) + (varargs #t) +) + +(define-method sending_failed_literal + (of-object "TfContent") + (c-name "tf_content_sending_failed_literal") + (return-type "none") + (parameters + '("const-gchar*" "message") + ) +) + +(define-method sending_failed + (of-object "TfContent") + (c-name "tf_content_sending_failed") + (return-type "none") + (parameters + '("const-gchar*" "message_format") + ) + (varargs #t) +) + +(define-method receiving_failed_literal + (of-object "TfContent") + (c-name "tf_content_receiving_failed_literal") + (return-type "none") + (parameters + '("guint*" "handles") + '("guint" "handle_count") + '("const-gchar*" "message") + ) +) + +(define-method receiving_failed + (of-object "TfContent") + (c-name "tf_content_receiving_failed") + (return-type "none") + (parameters + '("guint*" "handles") + '("guint" "handle_count") '("const-gchar*" "message_format") ) (varargs #t) diff --git a/python/pytpfarstreammodule.c b/python/pytpfarstreammodule.c index f6e6f86..460ca29 100644 --- a/python/pytpfarstreammodule.c +++ b/python/pytpfarstreammodule.c @@ -15,7 +15,6 @@ inittpfarstream(void) { PyObject *m, *d; - tf_init (); init_pygobject (); m = Py_InitModule ("tpfarstream", tf_functions); diff --git a/telepathy-farstream/Makefile.am b/telepathy-farstream/Makefile.am index 723fa4b..7b8830c 100644 --- a/telepathy-farstream/Makefile.am +++ b/telepathy-farstream/Makefile.am @@ -20,7 +20,6 @@ libtelepathy_farstream_la_SOURCES = \ session.c \ channel.c \ channel.h \ - stream-priv.h \ session-priv.h \ channel-priv.h \ media-signalling-channel.c \ @@ -34,7 +33,6 @@ libtelepathy_farstream_la_SOURCES = \ call-stream.h \ call-stream.c \ telepathy-farstream.h \ - telepathy-farstream.c \ utils.h nodist_libtelepathy_farstream_la_SOURCES = $(BUILT_SOURCES) @@ -60,8 +58,7 @@ libtelepathy_farstream_la_LIBADD = \ $(DBUS_LIBS) \ $(GST_LIBS) \ $(FARSTREAM_LIBS) \ - $(TELEPATHY_LIBS) \ - ../extensions/libfuture-extensions.la + $(TELEPATHY_LIBS) libtelepathy_farstream_la_LDFLAGS = -no-undefined \ -export-symbols-regex "^tf_(init|content_|channel_).*" \ diff --git a/telepathy-farstream/call-channel.c b/telepathy-farstream/call-channel.c index 57c650f..94bdc4c 100644 --- a/telepathy-farstream/call-channel.c +++ b/telepathy-farstream/call-channel.c @@ -34,8 +34,6 @@ #include <telepathy-glib/interfaces.h> #include <farstream/fs-conference.h> -#include "extensions/extensions.h" - #include "call-content.h" #include "tf-signals-marshal.h" @@ -94,8 +92,14 @@ static gboolean tf_call_channel_init_finish (GAsyncInitable *initable, GAsyncResult *res, GError **error); -static void got_hardware_streaming (TpProxy *proxy, const GValue *out_value, - const GError *error, gpointer user_data, GObject *weak_object); +static void content_added (TpCallChannel *proxy, + TpCallContent *context_proxy, TfCallChannel *self); +static void content_removed (TpCallChannel *proxy, + TpCallContent *content_proxy, TpCallStateReason *reason, + TfCallChannel *self); +static void channel_prepared (GObject *proxy, GAsyncResult *prepare_res, + gpointer user_data); + static void @@ -200,10 +204,12 @@ tf_call_channel_init_async (GAsyncInitable *initable, res = g_simple_async_result_new (G_OBJECT (self), callback, user_data, tf_call_channel_init_async); - tp_cli_dbus_properties_call_get (self->proxy, -1, - TF_FUTURE_IFACE_CHANNEL_TYPE_CALL, - "HardwareStreaming", - got_hardware_streaming, res, NULL, G_OBJECT (self)); + tp_g_signal_connect_object (self->proxy, "content-added", + G_CALLBACK (content_added), self, 0); + tp_g_signal_connect_object (self->proxy, "content-removed", + G_CALLBACK (content_removed), self, 0); + + tp_proxy_prepare_async (self->proxy, NULL, channel_prepared, res); } static gboolean @@ -244,18 +250,10 @@ tf_call_channel_dispose (GObject *object) already been disposed of. */ if (self->contents) { - GHashTableIter iter; - gpointer key, value; - - g_hash_table_iter_init (&iter, self->contents); - while (g_hash_table_iter_next (&iter, &key, &value)) - { - g_object_run_dispose (G_OBJECT (value)); - } - - g_hash_table_destroy (self->contents); - self->contents = NULL; + g_ptr_array_foreach (self->contents, (GFunc) g_object_run_dispose, NULL); + g_ptr_array_free (self->contents, TRUE); } + self->contents = NULL; if (self->participants) g_ptr_array_unref (self->participants); @@ -317,38 +315,34 @@ content_ready (GObject *object, GAsyncResult *res, gpointer user_data) if (g_async_initable_init_finish (G_ASYNC_INITABLE (object), res, NULL)) { g_signal_emit (self, signals[SIGNAL_CONTENT_ADDED], 0, content); - g_object_unref (content); } else { - GHashTableIter iter; - gpointer key, value; - - g_hash_table_iter_init (&iter, self->contents); - while (g_hash_table_iter_next (&iter, &key, &value)) - { - if (value == object) - { - g_hash_table_iter_remove (&iter); - break; - } - } + g_ptr_array_remove_fast (self->contents, content); } g_object_unref (self); } static gboolean -add_content (TfCallChannel *self, const gchar *content_path) +add_content (TfCallChannel *self, TpCallContent *content_proxy) { GError *error = NULL; TfCallContent *content; + guint i; /* Check if content already added */ - if (g_hash_table_lookup (self->contents, content_path)) - return TRUE; + if (!self->contents) + return FALSE; + + for (i = 0; i < self->contents->len; i++) + { + if (tf_call_content_get_proxy (g_ptr_array_index (self->contents, i)) == + content_proxy) + return TRUE; + } - content = tf_call_content_new_async (self, content_path, + content = tf_call_content_new_async (self, content_proxy, &error, content_ready, g_object_ref (self)); if (error) @@ -359,52 +353,16 @@ add_content (TfCallChannel *self, const gchar *content_path) return FALSE; } - g_hash_table_insert (self->contents, g_strdup (content_path), content); + g_ptr_array_add (self->contents, content); return TRUE; } static void -got_contents (TpProxy *proxy, const GValue *out_value, - const GError *error, gpointer user_data, GObject *weak_object) +content_added (TpCallChannel *proxy, + TpCallContent *content_proxy, + TfCallChannel *self) { - TfCallChannel *self = TF_CALL_CHANNEL (weak_object); - GSimpleAsyncResult *res = user_data; - GPtrArray *contents; - guint i; - - if (error) - { - g_warning ("Error getting the Contents property: %s", - error->message); - g_simple_async_result_set_from_error (res, error); - goto out; - } - - contents = g_value_get_boxed (out_value); - - self->contents = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, g_object_unref); - - for (i = 0; i < contents->len; i++) - if (!add_content (self, g_ptr_array_index (contents, i))) - break; - - g_simple_async_result_set_op_res_gboolean (res, TRUE); - -out: - g_simple_async_result_complete (res); - g_object_unref (res); -} - -static void -content_added (TpChannel *proxy, - const gchar *arg_Content, - gpointer user_data, - GObject *weak_object) -{ - TfCallChannel *self = TF_CALL_CHANNEL (weak_object); - /* Ignore signals before we got the "Contents" property to avoid races that * could cause the same content to be added twice */ @@ -412,91 +370,77 @@ content_added (TpChannel *proxy, if (!self->contents) return; - add_content (self, arg_Content); + add_content (self, content_proxy); } static void -content_removed (TpChannel *proxy, - const gchar *arg_Content, - gpointer user_data, - GObject *weak_object) +content_removed (TpCallChannel *proxy, + TpCallContent *content_proxy, + TpCallStateReason *reason, + TfCallChannel *self) { - TfCallChannel *self = TF_CALL_CHANNEL (weak_object); - TfCallContent *content; - + guint i; if (!self->contents) return; - content = g_hash_table_lookup (self->contents, arg_Content); - - if (content) + for (i = 0; i < self->contents->len; i++) { - g_object_ref (content); - g_hash_table_remove (self->contents, arg_Content); - g_signal_emit (self, signals[SIGNAL_CONTENT_REMOVED], 0, content); - g_object_unref (content); + if (tf_call_content_get_proxy (g_ptr_array_index (self->contents, i)) == + content_proxy) + { + TfCallContent *content = g_ptr_array_index (self->contents, i); + + g_object_ref (content); + g_ptr_array_remove_index_fast (self->contents, i); + g_signal_emit (self, signals[SIGNAL_CONTENT_REMOVED], 0, content); + g_object_unref (content); + return; + } } } - static void -got_hardware_streaming (TpProxy *proxy, const GValue *out_value, - const GError *error, gpointer user_data, GObject *weak_object) +channel_prepared (GObject *proxy, GAsyncResult *prepare_res, gpointer user_data) { - TfCallChannel *self = TF_CALL_CHANNEL (weak_object); GSimpleAsyncResult *res = user_data; - GError *myerror = NULL; + TfCallChannel *self = + TF_CALL_CHANNEL (g_async_result_get_source_object (G_ASYNC_RESULT (res))); + GError *error = NULL; + GPtrArray *contents; + guint i; - if (error) + if (!tp_proxy_prepare_finish (proxy, prepare_res, &error)) { - g_warning ("Error getting the hardware streaming property: %s", + g_warning ("Preparing the channel: %s", error->message); - g_simple_async_result_set_from_error (res, error); - goto error; + g_simple_async_result_take_error (res, error); + goto out; } - if (g_value_get_boolean (out_value)) + if (tp_call_channel_has_hardware_streaming (TP_CALL_CHANNEL (proxy))) { g_warning ("Hardware streaming property is TRUE, ignoring"); g_simple_async_result_set_error (res, TP_ERROR, TP_ERROR_NOT_CAPABLE, "This channel does hardware streaming, not handled here"); - goto error; + goto out; } - tf_future_cli_channel_type_call_connect_to_content_added (TP_CHANNEL (proxy), - content_added, NULL, NULL, G_OBJECT (self), &myerror); - if (myerror) - { - g_warning ("Error connectiong to ContentAdded signal: %s", - myerror->message); - g_simple_async_result_set_from_error (res, myerror); - g_clear_error (&myerror); - goto error; - } + contents = tp_call_channel_get_contents (TP_CALL_CHANNEL (proxy)); - tf_future_cli_channel_type_call_connect_to_content_removed ( - TP_CHANNEL (proxy), content_removed, NULL, NULL, G_OBJECT (self), - &myerror); - if (myerror) - { - g_warning ("Error connectiong to ContentRemoved signal: %s", - myerror->message); - g_simple_async_result_set_from_error (res, myerror); - g_clear_error (&myerror); - goto error; - } + self->contents = g_ptr_array_new_with_free_func (g_object_unref); - tp_cli_dbus_properties_call_get (proxy, -1, - TF_FUTURE_IFACE_CHANNEL_TYPE_CALL, "Contents", - got_contents, res, NULL, G_OBJECT (self)); + for (i = 0; i < contents->len; i++) + if (!add_content (self, g_ptr_array_index (contents, i))) + break; - return; + g_simple_async_result_set_op_res_gboolean (res, TRUE); -error: +out: g_simple_async_result_complete (res); g_object_unref (res); + g_object_unref (self); } void @@ -541,9 +485,8 @@ tf_call_channel_bus_message (TfCallChannel *channel, { GError *error = NULL; gchar *debug; - GHashTableIter iter; - gpointer key, value; struct CallConference *cc; + guint i; cc = find_call_conference_by_conference (channel, GST_MESSAGE_SRC (message)); if (!cc) @@ -573,9 +516,9 @@ tf_call_channel_bus_message (TfCallChannel *channel, break; } - g_hash_table_iter_init (&iter, channel->contents); - while (g_hash_table_iter_next (&iter, &key, &value)) - if (tf_call_content_bus_message (value, message)) + for (i = 0; i < channel->contents->len; i++) + if (tf_call_content_bus_message (g_ptr_array_index (channel->contents, i), + message)) return TRUE; return FALSE; @@ -584,9 +527,8 @@ tf_call_channel_bus_message (TfCallChannel *channel, void tf_call_channel_error (TfCallChannel *channel) { - tf_future_cli_channel_type_call_call_hangup (channel->proxy, - -1, TF_FUTURE_CALL_STATE_CHANGE_REASON_UNKNOWN, "", "", - NULL, NULL, NULL, NULL); + tp_call_channel_hangup_async (TP_CALL_CHANNEL (channel->proxy), + TP_CALL_STATE_CHANGE_REASON_UNKNOWN, "", "", NULL, NULL); } @@ -719,5 +661,4 @@ _tf_call_channel_put_participant (TfCallChannel *channel, return; } } - } diff --git a/telepathy-farstream/call-channel.h b/telepathy-farstream/call-channel.h index 3848818..8c268d2 100644 --- a/telepathy-farstream/call-channel.h +++ b/telepathy-farstream/call-channel.h @@ -76,7 +76,7 @@ struct _TfCallChannel { GHashTable *fsconferences; - GHashTable *contents; /* NULL before getting the first contents */ + GPtrArray *contents; /* NULL before getting the first contents */ GPtrArray *participants; }; diff --git a/telepathy-farstream/call-content.c b/telepathy-farstream/call-content.c index e799d50..8a5b4b6 100644 --- a/telepathy-farstream/call-content.c +++ b/telepathy-farstream/call-content.c @@ -20,32 +20,43 @@ /** * SECTION:call-content - * @short_description: Handle the Call interface on a Channel + * @short_description: Handle the Content objects on a Call channel * - * This class handles the - * org.freedesktop.Telepathy.Channel.Interface.Call on a - * channel using Farstream. + * This class handles the org.freedesktop.Telepathy.Call1.Content, + * org.freedesktop.Telepathy.Call1.Content.Interface.Media, + * org.freedesktop.Telepathy.Call1.Content.Interface.VideoControl, + * org.freedesktop.Telepathy.Call1.Content.MediaDescription, + * prg.freedesktop.Telepathy.Call1.Content.MediaDescription.Interface.RTPHeaderExtensions + * and org.freedesktop.Telepathy.Call1.Content.MediaDescription.Interface.RTCPFeedback interfaces + * + */ + +/* TODO: + * + * In MediaDescription: + * - SSRCs */ + #include "call-content.h" -#include <telepathy-glib/util.h> -#include <telepathy-glib/interfaces.h> +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/proxy-subclass.h> #include <farstream/fs-conference.h> #include <farstream/fs-utils.h> +#include <farstream/fs-rtp.h> #include <farstream/fs-element-added-notifier.h> #include <stdarg.h> #include <string.h> -#include <telepathy-glib/proxy-subclass.h> #include "call-stream.h" #include "tf-signals-marshal.h" #include "utils.h" -#include "extensions/extensions.h" +#define DTMF_TONE_VOLUME (8) struct _TfCallContent { TfContent parent; @@ -53,27 +64,38 @@ struct _TfCallContent { TfCallChannel *call_channel; FsConference *fsconference; - TfFutureCallContent *proxy; + TpCallContent *proxy; FsSession *fssession; - TpMediaStreamType media_type; - GList *current_codecs; - TpProxy *current_offer; - guint current_offer_contact_handle; - GList *current_offer_fscodecs; + TpProxy *current_media_description; + guint current_md_contact_handle; + GList *current_md_fscodecs; + GList *current_md_rtp_hdrext; + + gboolean current_has_rtp_hdrext; + gboolean current_has_rtcp_fb; + gboolean has_rtp_hdrext; + gboolean has_rtcp_fb; - GHashTable *streams; /* NULL before getting the first streams */ + GList *last_sent_codecs; + + GPtrArray *streams; /* NULL before getting the first streams */ /* Streams for which we don't have a session yet*/ GList *outstanding_streams; GMutex *mutex; + gboolean remote_codecs_set; + + TpSendingState dtmf_sending_state; + guint current_dtmf_event; + /* Content protected by the Mutex */ GPtrArray *fsstreams; guint fsstreams_cookie; - gboolean got_codec_offer_property; + gboolean got_media_description_property; /* AudioControl API */ gint requested_input_volume; @@ -93,7 +115,7 @@ struct _TfCallContent { guint height; }; -struct _TfCallContentClass{ +struct _TfCallContentClass { TfContentClass parent_class; }; @@ -175,11 +197,24 @@ static void src_pad_added (FsStream *fsstream, GstPad *pad, FsCodec *codec, static GstIterator * tf_call_content_iterate_src_pads (TfContent *content, guint *handles, guint handle_count); -static void tf_call_content_error (TfContent *content, - guint reason, /* TfFutureContentRemovalReason */ +static void tf_call_content_error (TfCallContent *self, + TpCallStateChangeReason reason, + const gchar *detailed_reason, + const gchar *message_format, + ...) G_GNUC_PRINTF (4, 5); +static void tf_call_content_error_literal (TfCallContent *self, + TpCallStateChangeReason reason, const gchar *detailed_reason, const gchar *message); +static void tf_call_content_error_impl (TfContent *content, + const gchar *message); +static void tf_call_content_sending_failed (TfContent *content, + const gchar *message); +static void tf_call_content_receiving_failed (TfContent *content, + guint *handles, guint handle_count, + const gchar *message); + static void tf_call_content_class_init (TfCallContentClass *klass) { @@ -188,7 +223,9 @@ tf_call_content_class_init (TfCallContentClass *klass) content_class->iterate_src_pads = tf_call_content_iterate_src_pads; - content_class->content_error = tf_call_content_error; + content_class->content_error = tf_call_content_error_impl; + content_class->sending_failed = tf_call_content_sending_failed; + content_class->receiving_failed = tf_call_content_receiving_failed; object_class->dispose = tf_call_content_dispose; object_class->finalize = tf_call_content_finalize; @@ -281,7 +318,7 @@ free_content_fsstream (gpointer data) { struct CallFsStream *cfs = data; - g_object_run_dispose (G_OBJECT (cfs->fsstream)); + fs_stream_destroy (cfs->fsstream); g_object_unref (cfs->fsstream); _tf_call_channel_put_participant (cfs->parent_channel, cfs->fsparticipant); g_slice_free (struct CallFsStream, cfs); @@ -291,6 +328,7 @@ static void tf_call_content_init (TfCallContent *self) { self->fsstreams = g_ptr_array_new (); + self->dtmf_sending_state = TP_SENDING_STATE_NONE; self->mutex = g_mutex_new (); self->requested_input_volume = -1; @@ -308,12 +346,12 @@ tf_call_content_dispose (GObject *object) g_debug (G_STRFUNC); if (self->streams) - g_hash_table_destroy (self->streams); + g_ptr_array_free (self->streams, TRUE); self->streams = NULL; if (self->fssession) { - g_object_run_dispose (G_OBJECT (self->fssession)); + fs_session_destroy (self->fssession); g_object_unref (self->fssession); } self->fssession = NULL; @@ -340,6 +378,9 @@ tf_call_content_dispose (GObject *object) g_object_unref (self->proxy); self->proxy = NULL; + fs_codec_list_destroy (self->last_sent_codecs); + self->last_sent_codecs = NULL; + /* We do not hold a ref to the call channel, and use it as a flag to ensure * we will bail out when disposed */ self->call_channel = NULL; @@ -436,7 +477,7 @@ tf_call_content_set_property (GObject *object, break; self->reported_input_volume = g_value_get_int (value); - tf_future_cli_call_content_interface_audio_control_call_report_input_volume ( + tp_cli_call_content_interface_audio_control_call_report_input_volume ( self->proxy, -1, self->reported_input_volume, NULL, NULL, NULL, NULL); @@ -447,7 +488,7 @@ tf_call_content_set_property (GObject *object, break; self->reported_output_volume = g_value_get_int (value); - tf_future_cli_call_content_interface_audio_control_call_report_output_volume ( + tp_cli_call_content_interface_audio_control_call_report_output_volume ( self->proxy, -1, self->reported_output_volume, NULL, NULL, NULL, NULL); break; @@ -458,49 +499,25 @@ tf_call_content_set_property (GObject *object, } static void -create_stream (TfCallContent *self, gchar *stream_path) +add_stream (TfCallContent *self, TpCallStream *stream_proxy) { - GError *error = NULL; - TfCallStream *stream = tf_call_stream_new (self->call_channel, self, - stream_path, &error); - - if (error) - { - /* TODO: Use per-stream errors */ - tf_content_error (TF_CONTENT (self), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, "", - "Error creating the stream object: %s", error->message); - return; - } - - g_hash_table_insert (self->streams, stream_path, stream); + g_ptr_array_add (self->streams, + tf_call_stream_new (self, stream_proxy)); } static void -add_stream (TfCallContent *self, const gchar *stream_path) +add_initial_streams (TfCallContent *self) { - - if (!self->fsconference) - { - self->outstanding_streams = g_list_prepend (self->outstanding_streams, - g_strdup (stream_path)); - } else { - create_stream (self, g_strdup (stream_path)); - } -} - -static void -update_streams (TfCallContent *self) -{ - GList *l; + GPtrArray *streams; + guint i; g_assert (self->fsconference); + g_assert (self->streams->len == 0); - for (l = self->outstanding_streams ; l != NULL; l = l->next) - create_stream (self, l->data); + streams = tp_call_content_get_streams (self->proxy); - g_list_free (self->outstanding_streams); - self->outstanding_streams = NULL; + for (i = 0; i < streams->len; i++) + add_stream (self, g_ptr_array_index (streams, i)); } static void @@ -514,7 +531,8 @@ tpparam_to_fsparam (gpointer key, gpointer value, gpointer user_data) } static GList * -tpcodecs_to_fscodecs (FsMediaType fsmediatype, const GPtrArray *tpcodecs) +tpcodecs_to_fscodecs (FsMediaType fsmediatype, const GPtrArray *tpcodecs, + gboolean does_avpf, GHashTable *rtcp_fb) { GList *fscodecs = NULL; guint i; @@ -528,15 +546,51 @@ tpcodecs_to_fscodecs (FsMediaType fsmediatype, const GPtrArray *tpcodecs) guint channels; GHashTable *params; FsCodec *fscodec; + gchar *tmp; + GValueArray *feedback_params = NULL; + gboolean updated; - tp_value_array_unpack (tpcodec, 5, &pt, &name, &clock_rate, &channels, - ¶ms); + tp_value_array_unpack (tpcodec, 6, &pt, &name, &clock_rate, &channels, + &updated, ¶ms); fscodec = fs_codec_new (pt, name, fsmediatype, clock_rate); fscodec->channels = channels; g_hash_table_foreach (params, tpparam_to_fsparam, fscodec); + if (does_avpf) + fscodec->minimum_reporting_interval = 0; + + if (rtcp_fb) + feedback_params = g_hash_table_lookup (rtcp_fb, GUINT_TO_POINTER (pt)); + + if (feedback_params) + { + guint rtcp_minimum_interval; + GPtrArray *messages; + guint j; + + tp_value_array_unpack (feedback_params, 2, &rtcp_minimum_interval, + &messages); + if (rtcp_minimum_interval != G_MAXUINT) + fscodec->minimum_reporting_interval = rtcp_minimum_interval; + + for (j = 0; j < messages->len ; j++) + { + GValueArray *message = g_ptr_array_index (messages, j); + const gchar *type, *subtype, *extra_params; + + tp_value_array_unpack (message, 3, &type, &subtype, + &extra_params); + + fs_codec_add_feedback_parameter (fscodec, type, subtype, + extra_params); + } + } + + tmp = fs_codec_to_string (fscodec); + g_debug ("%s", tmp); + g_free (tmp); fscodecs = g_list_prepend (fscodecs, fscodec); } @@ -545,82 +599,311 @@ tpcodecs_to_fscodecs (FsMediaType fsmediatype, const GPtrArray *tpcodecs) return fscodecs; } +static GList * +tprtphdrext_to_fsrtphdrext (GPtrArray *rtp_hdrext) +{ + GQueue ret = G_QUEUE_INIT; + guint i; + + if (!rtp_hdrext) + return NULL; + + for (i = 0; i < rtp_hdrext->len; i++) + { + GValueArray *extension = g_ptr_array_index (rtp_hdrext, i); + guint id; + TpMediaStreamDirection direction; + const char *uri; + const gchar *parameters; + FsRtpHeaderExtension *ext; + + tp_value_array_unpack (extension, 4, &id, &direction, &uri, ¶meters); + + ext = fs_rtp_header_extension_new (id, + tpdirection_to_fsdirection (direction), uri); + + g_debug ("hdrext: " FS_RTP_HEADER_EXTENSION_FORMAT, + FS_RTP_HEADER_EXTENSION_ARGS (ext)); + + g_queue_push_tail (&ret, ext); + } + + return ret.head; +} + +static gboolean +object_has_property (GObject *object, const gchar *property) +{ + return g_object_class_find_property (G_OBJECT_GET_CLASS (object), + property) != NULL; +} + static void -process_codec_offer_try_codecs (TfCallContent *self, FsStream *fsstream, - TpProxy *offer, GList *fscodecs) +on_content_dtmf_change_requested (TpCallContent *proxy, + guchar arg_Event, + guint arg_State, + gpointer user_data, + GObject *weak_object) +{ + TfCallContent *self = TF_CALL_CONTENT (weak_object); + + /* Ignore the signal until we've got the original properties and codecs */ + if (!self->fssession || !self->remote_codecs_set) { + self->dtmf_sending_state = arg_State; + self->current_dtmf_event = arg_Event; + return; + } + + switch (arg_State) + { + case TP_SENDING_STATE_PENDING_STOP_SENDING: + if (self->dtmf_sending_state != TP_SENDING_STATE_SENDING) + { + tf_call_content_error (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_CONFUSED, + "Tried to stop a %u DTMF event while state is %d", + arg_Event, self->dtmf_sending_state); + } + + if (fs_session_stop_telephony_event (self->fssession)) + { + self->dtmf_sending_state = TP_SENDING_STATE_PENDING_STOP_SENDING; + } + else + { + tf_call_content_error (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_MEDIA_STREAMING_ERROR, + "Could not stop DTMF event %d", arg_Event); + tp_cli_call_content_interface_media_call_acknowledge_dtmf_change ( + self->proxy, -1, arg_Event, TP_SENDING_STATE_SENDING, + NULL, NULL, NULL, NULL); + } + break; + case TP_SENDING_STATE_PENDING_SEND: + if (self->dtmf_sending_state != TP_SENDING_STATE_NONE) + { + tf_call_content_error (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_CONFUSED, + "Tried to start a new DTMF event %u while %d is already playing", + arg_Event, self->current_dtmf_event); + fs_session_stop_telephony_event (self->fssession); + } + + if (fs_session_start_telephony_event (self->fssession, + arg_Event, DTMF_TONE_VOLUME)) + { + self->current_dtmf_event = arg_Event; + self->dtmf_sending_state = TP_SENDING_STATE_PENDING_SEND; + } + else + { + tf_call_content_error (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_MEDIA_STREAMING_ERROR, + "Could not start DTMF event %d", arg_Event); + tp_cli_call_content_interface_media_call_acknowledge_dtmf_change ( + self->proxy, -1, arg_Event, TP_SENDING_STATE_NONE, + NULL, NULL, NULL, NULL); + } + break; + default: + tf_call_content_error (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_CONFUSED, + "Invalid State %d in DTMFChangeRequested signal for event %d", + arg_State, arg_Event); + break; + } +} + + +static void +process_media_description_try_codecs (TfCallContent *self, FsStream *fsstream, + TpProxy *media_description, GList *fscodecs, GList *rtp_hdrext) { gboolean success = TRUE; GError *error = NULL; if (fscodecs != NULL) - success = fs_stream_set_remote_codecs (fsstream, fscodecs, &error); + { + GList *old_rtp_hdrext = NULL; + + if (object_has_property (G_OBJECT (fsstream), "rtp-header-extensions")) + { + g_object_get (fsstream, "rtp-header-extensions", &old_rtp_hdrext, + NULL); + g_object_set (fsstream, "rtp-header-extensions", rtp_hdrext, NULL); + } + + success = fs_stream_set_remote_codecs (fsstream, fscodecs, &error); + + if (success) + { + if (!self->remote_codecs_set) + on_content_dtmf_change_requested (NULL, self->current_dtmf_event, + self->dtmf_sending_state, NULL, G_OBJECT (self)); + self->remote_codecs_set = TRUE; + } + + if (!success && + object_has_property (G_OBJECT (fsstream), "rtp-header-extensions")) + g_object_set (fsstream, "rtp-header-extensions", old_rtp_hdrext, NULL); + + fs_rtp_header_extension_list_destroy (old_rtp_hdrext); + } + fs_rtp_header_extension_list_destroy (rtp_hdrext); fs_codec_list_destroy (fscodecs); if (success) { - self->current_offer = offer; + self->current_media_description = media_description; tf_call_content_try_sending_codecs (self); } else { - tf_future_cli_call_content_codec_offer_call_reject (offer, - -1, NULL, NULL, NULL, NULL); - g_object_unref (offer); + GValueArray *reason = tp_value_array_build (4, + G_TYPE_UINT, 0, + G_TYPE_UINT, TP_CALL_STATE_CHANGE_REASON_MEDIA_ERROR, + G_TYPE_STRING, TP_ERROR_STR_MEDIA_CODECS_INCOMPATIBLE, + G_TYPE_STRING, + "Remote codecs are not compatible with the local ones", + G_TYPE_INVALID); + + g_debug ("Rejecting Media Description"); + tp_cli_call_content_media_description_call_reject (media_description, + -1, reason, NULL, NULL, NULL, NULL); + g_value_array_free (reason); + g_object_unref (media_description); } - + g_clear_error (&error); } static void -process_codec_offer (TfCallContent *self, const gchar *offer_objpath, - guint contact_handle, const GPtrArray *codecs) +process_media_description (TfCallContent *self, + const gchar *media_description_objpath, + const GHashTable *properties) { TpProxy *proxy; GError *error = NULL; FsStream *fsstream; + GPtrArray *codecs; + GPtrArray *rtp_hdrext = NULL; + GHashTable *rtcp_fb = NULL; + gboolean does_avpf = FALSE; GList *fscodecs; + const gchar * const *interfaces; + guint i; + GList *fsrtp_hdrext; + guint contact_handle; + gboolean valid; /* Guard against early disposal */ if (self->call_channel == NULL) return; - if (!tp_dbus_check_valid_object_path (offer_objpath, &error)) + if (!tp_dbus_check_valid_object_path (media_description_objpath, &error)) { - tf_content_error (TF_CONTENT (self), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, "", - "Invalid offer path: %s", error->message); + tf_call_content_error (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, TP_ERROR_STR_CONFUSED, + "Invalid MediaDescription path: %s", error->message); g_clear_error (&error); return; } + contact_handle = tp_asv_get_uint32 (properties, + TP_PROP_CALL_CONTENT_MEDIA_DESCRIPTION_REMOTE_CONTACT, &valid); + if (!valid) + { + tf_call_content_error_literal (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, TP_ERROR_STR_CONFUSED, + "MediaDescription does not contain a valid contact handle"); + g_clear_error (&error); + return; + } + + codecs = tp_asv_get_boxed (properties, + TP_PROP_CALL_CONTENT_MEDIA_DESCRIPTION_CODECS, TP_ARRAY_TYPE_CODEC_LIST); + + if (!codecs) + { + tf_call_content_error_literal (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, TP_ERROR_STR_CONFUSED, + "MediaDescription does not contain codecs"); + g_clear_error (&error); + return; + } + + tp_call_content_media_description_init_known_interfaces (); proxy = g_object_new (TP_TYPE_PROXY, "dbus-daemon", tp_proxy_get_dbus_daemon (self->proxy), "bus-name", tp_proxy_get_bus_name (self->proxy), - "object-path", offer_objpath, + "object-path", media_description_objpath, NULL); tp_proxy_add_interface_by_id (TP_PROXY (proxy), - TF_FUTURE_IFACE_QUARK_CALL_CONTENT_CODEC_OFFER); + TP_IFACE_QUARK_CALL_CONTENT_MEDIA_DESCRIPTION); + + interfaces = tp_asv_get_strv (properties, + TP_PROP_CALL_CONTENT_MEDIA_DESCRIPTION_INTERFACES); + + + self->current_has_rtcp_fb = FALSE; + self->current_has_rtp_hdrext = FALSE; + for (i = 0; interfaces[i]; i++) + { + if (!strcmp (interfaces[i], + TP_IFACE_CALL_CONTENT_MEDIA_DESCRIPTION_INTERFACE_RTCP_FEEDBACK)) + { + gboolean valid; + + self->current_has_rtcp_fb = TRUE; + rtcp_fb = tp_asv_get_boxed (properties, + TP_PROP_CALL_CONTENT_MEDIA_DESCRIPTION_INTERFACE_RTCP_FEEDBACK_FEEDBACK_MESSAGES, + TP_HASH_TYPE_RTCP_FEEDBACK_MESSAGE_MAP); + does_avpf = tp_asv_get_boolean (properties, + TP_PROP_CALL_CONTENT_MEDIA_DESCRIPTION_INTERFACE_RTCP_FEEDBACK_DOES_AVPF, &valid); + if (!valid) + does_avpf = FALSE; + } + else if (!strcmp (interfaces[i], + TP_IFACE_CALL_CONTENT_MEDIA_DESCRIPTION_INTERFACE_RTP_HEADER_EXTENSIONS)) + { + self->current_has_rtp_hdrext = TRUE; + rtp_hdrext = tp_asv_get_boxed (properties, + TP_PROP_CALL_CONTENT_MEDIA_DESCRIPTION_INTERFACE_RTP_HEADER_EXTENSIONS_HEADER_EXTENSIONS, + TP_ARRAY_TYPE_RTP_HEADER_EXTENSIONS_LIST); + } + } + + + g_debug ("Got MediaDescription"); + fscodecs = tpcodecs_to_fscodecs (tf_call_content_get_fs_media_type (self), + codecs, does_avpf, rtcp_fb); - fscodecs = tpcodecs_to_fscodecs (tp_media_type_to_fs (self->media_type), - codecs); + fsrtp_hdrext = tprtphdrext_to_fsrtphdrext (rtp_hdrext); fsstream = tf_call_content_get_existing_fsstream_by_handle (self, contact_handle); if (!fsstream) { - g_debug ("Delaying codec offer processing"); - self->current_offer = proxy; - self->current_offer_contact_handle = contact_handle; - self->current_offer_fscodecs = fscodecs; + g_debug ("Delaying codec media_description processing"); + self->current_media_description = proxy; + self->current_md_contact_handle = contact_handle; + self->current_md_fscodecs = fscodecs; + self->current_md_rtp_hdrext = fsrtp_hdrext; return; } - process_codec_offer_try_codecs (self, fsstream, proxy, fscodecs); + process_media_description_try_codecs (self, fsstream, proxy, fscodecs, + fsrtp_hdrext); } static void -on_content_video_keyframe_requested (TfFutureCallContent *proxy, +on_content_video_keyframe_requested (TpCallContent *proxy, gpointer user_data, GObject *weak_object) { @@ -655,7 +938,7 @@ on_content_video_keyframe_requested (TfFutureCallContent *proxy, } static void -on_content_video_resolution_changed (TfFutureCallContent *proxy, +on_content_video_resolution_changed (TpCallContent *proxy, const GValueArray *resolution, gpointer user_data, GObject *weak_object) @@ -684,7 +967,7 @@ on_content_video_resolution_changed (TfFutureCallContent *proxy, } static void -on_content_video_bitrate_changed (TfFutureCallContent *proxy, +on_content_video_bitrate_changed (TpCallContent *proxy, guint bitrate, gpointer user_data, GObject *weak_object) @@ -703,7 +986,7 @@ on_content_video_bitrate_changed (TfFutureCallContent *proxy, } static void -on_content_video_framerate_changed (TfFutureCallContent *proxy, +on_content_video_framerate_changed (TpCallContent *proxy, guint framerate, gpointer user_data, GObject *weak_object) @@ -722,7 +1005,7 @@ on_content_video_framerate_changed (TfFutureCallContent *proxy, } static void -on_content_video_mtu_changed (TfFutureCallContent *proxy, +on_content_video_mtu_changed (TpCallContent *proxy, guint mtu, gpointer user_data, GObject *weak_object) @@ -746,6 +1029,44 @@ on_content_video_mtu_changed (TfFutureCallContent *proxy, } } +static void +streams_added (TpCallContent *proxy, + GPtrArray *streams, + TfCallContent *self) +{ + guint i; + + /* Ignore signals before we got the "Contents" property to avoid races that + * could cause the same content to be added twice + */ + + if (!self->streams) + return; + + for (i = 0; i < streams->len; i++) + add_stream (self, g_ptr_array_index (streams, i)); +} + +static void +streams_removed (TpCallContent *proxy, + const GPtrArray *streams, + TpCallStateReason *reason, + TfCallContent *self) +{ + guint i, j; + + if (!self->streams) + return; + + for (i = 0; i < streams->len; i++) + for (j = 0; j < self->streams->len; j++) + if (g_ptr_array_index (streams, i) == + tf_call_stream_get_proxy (g_ptr_array_index (self->streams, j))) + { + g_ptr_array_remove_index_fast (self->streams, j); + break; + } +} static void got_content_media_properties (TpProxy *proxy, GHashTable *properties, @@ -754,14 +1075,16 @@ got_content_media_properties (TpProxy *proxy, GHashTable *properties, TfCallContent *self = TF_CALL_CONTENT (weak_object); GSimpleAsyncResult *res = user_data; GValueArray *gva; - const gchar *offer_objpath; - guint contact; + const gchar *media_description_objpath = NULL; + GHashTable *media_description_properties; GError *myerror = NULL; - GPtrArray *codecs; guint32 packetization; const gchar *conference_type; gboolean valid; GList *codec_prefs; + guchar dtmf_event; + guint dtmf_state; + const GValue *dtmf_event_value; /* Guard against early disposal */ if (self->call_channel == NULL) @@ -775,8 +1098,9 @@ got_content_media_properties (TpProxy *proxy, GHashTable *properties, if (error != NULL) { - tf_content_error (TF_CONTENT (self), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, "", + tf_call_content_error (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_MEDIA_STREAMING_ERROR, "Error getting the Content's media properties: %s", error->message); g_simple_async_result_set_from_error (res, error); g_simple_async_result_complete (res); @@ -793,15 +1117,16 @@ got_content_media_properties (TpProxy *proxy, GHashTable *properties, switch (packetization) { - case TF_FUTURE_CALL_CONTENT_PACKETIZATION_TYPE_RTP: + case TP_CALL_CONTENT_PACKETIZATION_TYPE_RTP: conference_type = "rtp"; break; - case TF_FUTURE_CALL_CONTENT_PACKETIZATION_TYPE_RAW: + case TP_CALL_CONTENT_PACKETIZATION_TYPE_RAW: conference_type = "raw"; break; default: - tf_content_error (TF_CONTENT (self), - TF_FUTURE_CONTENT_REMOVAL_REASON_UNSUPPORTED, "", + tf_call_content_error (self, + TP_CALL_STATE_CHANGE_REASON_MEDIA_ERROR, + TP_ERROR_STR_MEDIA_UNSUPPORTED_TYPE, "Could not create FsConference for type %d", packetization); g_simple_async_result_set_error (res, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "Could not create FsConference for type %d", packetization); @@ -814,8 +1139,9 @@ got_content_media_properties (TpProxy *proxy, GHashTable *properties, conference_type); if (!self->fsconference) { - tf_content_error (TF_CONTENT (self), - TF_FUTURE_CONTENT_REMOVAL_REASON_UNSUPPORTED, "", + tf_call_content_error (self, + TP_CALL_STATE_CHANGE_REASON_MEDIA_ERROR, + TP_ERROR_STR_MEDIA_UNSUPPORTED_TYPE, "Could not create FsConference for type %s", conference_type); g_simple_async_result_set_error (res, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "Error getting the Content's properties: invalid type"); @@ -825,12 +1151,13 @@ got_content_media_properties (TpProxy *proxy, GHashTable *properties, } self->fssession = fs_conference_new_session (self->fsconference, - tp_media_type_to_fs (self->media_type), &myerror); + tf_call_content_get_fs_media_type (self), &myerror); if (!self->fssession) { - tf_content_error (TF_CONTENT (self), - TF_FUTURE_CONTENT_REMOVAL_REASON_UNSUPPORTED, "", + tf_call_content_error (self, + TP_CALL_STATE_CHANGE_REASON_MEDIA_ERROR, + TP_ERROR_STR_MEDIA_UNSUPPORTED_TYPE, "Could not create FsSession: %s", myerror->message); g_simple_async_result_set_from_error (res, myerror); g_simple_async_result_complete (res); @@ -843,11 +1170,9 @@ got_content_media_properties (TpProxy *proxy, GHashTable *properties, fs_element_added_notifier_add (self->notifier, GST_BIN (self->fsconference)); - /* Now process outstanding streams */ - update_streams (self); - gva = tp_asv_get_boxed (properties, "CodecOffer", - TF_FUTURE_STRUCT_TYPE_CODEC_OFFERING); + gva = tp_asv_get_boxed (properties, "MediaDescriptionOffer", + TP_STRUCT_TYPE_MEDIA_DESCRIPTION_OFFER); if (gva == NULL) { goto invalid_property; @@ -867,16 +1192,41 @@ got_content_media_properties (TpProxy *proxy, GHashTable *properties, } /* First complete so we get signalled and the preferences can be set, then - * start looking at the offer. We only unref the result later, to avoid + * start looking at the media_description. We only unref the result later, to avoid * self possibly being disposed early */ g_simple_async_result_set_op_res_gboolean (res, TRUE); g_simple_async_result_complete (res); - tp_value_array_unpack (gva, 3, &offer_objpath, &contact, &codecs); + /* Now process outstanding streams */ + add_initial_streams (self); + + tp_g_signal_connect_object (self->proxy, "streams-added", + G_CALLBACK (streams_added), self, 0); + tp_g_signal_connect_object (self->proxy, "streams-removed", + G_CALLBACK (streams_removed), self, 0); + + tp_value_array_unpack (gva, 2, &media_description_objpath, + &media_description_properties); + + if (strcmp (media_description_objpath, "/")) + { + process_media_description (self, media_description_objpath, + media_description_properties); + } + self->got_media_description_property = TRUE; - process_codec_offer (self, offer_objpath, contact, codecs); - self->got_codec_offer_property = TRUE; + dtmf_state = tp_asv_get_uint32 (properties, "CurrentDTMFState", &valid); + if (!valid) + goto invalid_property; + + dtmf_event_value = tp_asv_lookup (properties, "CurrentDTMFEvent"); + if (!dtmf_event_value || !G_VALUE_HOLDS_UCHAR (dtmf_event_value)) + goto invalid_property; + dtmf_event = g_value_get_uchar (dtmf_event_value); + + on_content_dtmf_change_requested (NULL, dtmf_event, dtmf_state, NULL, + G_OBJECT (self)); /* The async result holds a ref to self which may be the last one, so this * comes after we're done with self */ @@ -884,8 +1234,9 @@ got_content_media_properties (TpProxy *proxy, GHashTable *properties, return; invalid_property: - tf_content_error_literal (TF_CONTENT (self), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, "", + tf_call_content_error_literal (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_CONFUSED, "Error getting the Content's properties: invalid type"); g_simple_async_result_set_error (res, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "Error getting the Content's properties: invalid type"); @@ -895,13 +1246,30 @@ got_content_media_properties (TpProxy *proxy, GHashTable *properties, } static void -setup_content_media_properties (TfCallContent *self, - TpProxy *proxy, - GSimpleAsyncResult *res) +setup_content_media_properties (TfCallContent *self, GSimpleAsyncResult *res) { - tp_cli_dbus_properties_call_get_all (proxy, -1, - TF_FUTURE_IFACE_CALL_CONTENT_INTERFACE_MEDIA, + GError *error = NULL; + + + if (tp_cli_call_content_interface_media_connect_to_dtmf_change_requested ( + self->proxy, on_content_dtmf_change_requested, + NULL, NULL, G_OBJECT (self), &error) == NULL) + goto connect_failed; + + tp_cli_dbus_properties_call_get_all (TP_PROXY (self->proxy), -1, + TP_IFACE_CALL_CONTENT_INTERFACE_MEDIA, got_content_media_properties, res, NULL, G_OBJECT (self)); + + return; +connect_failed: + tf_call_content_error (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_CONFUSED, + "Could not connect to the DTMFChangeRequested signal: %s", + error->message); + g_simple_async_result_take_error (res, error); + g_simple_async_result_complete (res); + g_object_unref (res); } static void @@ -934,10 +1302,10 @@ on_content_audio_control_properties_changed (TpProxy *proxy, gpointer user_data, GObject *weak_object) { - TfCallContent *self = TF_CALL_CONTENT (weak_object); + TfCallContent *self = TF_CALL_CONTENT (proxy); if (tp_strdiff (interface_name, - TF_FUTURE_IFACE_CALL_CONTENT_INTERFACE_AUDIO_CONTROL)) + TP_IFACE_CALL_CONTENT_INTERFACE_AUDIO_CONTROL)) return; /* Guard against early disposal */ @@ -951,13 +1319,14 @@ static void got_content_audio_control_properties (TpProxy *proxy, GHashTable *properties, const GError *error, gpointer user_data, GObject *weak_object) { - TfCallContent *self = TF_CALL_CONTENT (weak_object); + TfCallContent *self = TF_CALL_CONTENT (proxy); GSimpleAsyncResult *res = user_data; if (error) { - tf_content_error (TF_CONTENT (self), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, "", + tf_call_content_error (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_CONFUSED, "Error getting the Content's AudioControl properties: %s", error->message); g_simple_async_result_set_from_error (res, error); @@ -974,8 +1343,9 @@ got_content_audio_control_properties (TpProxy *proxy, GHashTable *properties, if (properties == NULL) { - tf_content_error_literal (TF_CONTENT (self), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, "", + tf_call_content_error_literal (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_CONFUSED, "Error getting the Content's AudioControl properties: " "there are none"); g_simple_async_result_set_error (res, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, @@ -986,7 +1356,7 @@ got_content_audio_control_properties (TpProxy *proxy, GHashTable *properties, update_audio_control (self, properties); - setup_content_media_properties (self, proxy, res); + setup_content_media_properties (self, res); return; error: @@ -997,42 +1367,32 @@ error: static void setup_content_audio_control (TfCallContent *self, - TpProxy *proxy, GSimpleAsyncResult *res) { GError *error = NULL; - tp_proxy_add_interface_by_id (proxy, - TF_FUTURE_IFACE_QUARK_CALL_CONTENT_INTERFACE_AUDIO_CONTROL); - - if (tp_cli_dbus_properties_connect_to_properties_changed (proxy, + if (tp_cli_dbus_properties_connect_to_properties_changed (self, on_content_audio_control_properties_changed, - NULL, NULL, G_OBJECT (self), &error) == NULL) + NULL, NULL, NULL, &error) == NULL) goto connect_failed; - tp_cli_dbus_properties_call_get_all (proxy, -1, - TF_FUTURE_IFACE_CALL_CONTENT_INTERFACE_AUDIO_CONTROL, - got_content_audio_control_properties, res, NULL, G_OBJECT (self)); + tp_cli_dbus_properties_call_get_all (self, -1, + TP_IFACE_CALL_CONTENT_INTERFACE_AUDIO_CONTROL, + got_content_audio_control_properties, res, NULL, NULL); return; connect_failed: - tf_content_error (TF_CONTENT (self), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, "", - "Error getting the Content's AudioControl properties: %s", + tf_call_content_error (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_CONFUSED, + "Error getting the Content's VideoControl properties: %s", error->message); g_simple_async_result_take_error (res, error); g_simple_async_result_complete (res); g_object_unref (res); } -static gboolean -object_has_property (GObject *object, const gchar *property) -{ - return g_object_class_find_property (G_OBJECT_GET_CLASS (object), - property) != NULL; -} - static void content_video_element_added (FsElementAddedNotifier *notifier, GstBin *conference, @@ -1079,8 +1439,9 @@ got_content_video_control_properties (TpProxy *proxy, GHashTable *properties, if (error) { - tf_content_error (TF_CONTENT (self), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, "", + tf_call_content_error (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_CONFUSED, "Error getting the Content's VideoControl properties: %s", error->message); g_simple_async_result_set_from_error (res, error); @@ -1097,8 +1458,9 @@ got_content_video_control_properties (TpProxy *proxy, GHashTable *properties, if (properties == NULL) { - tf_content_error_literal (TF_CONTENT (self), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, "", + tf_call_content_error_literal (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_CONFUSED, "Error getting the Content's VideoControl properties: " "there are none"); g_simple_async_result_set_error (res, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, @@ -1124,16 +1486,16 @@ got_content_video_control_properties (TpProxy *proxy, GHashTable *properties, self->manual_keyframes = manual_keyframes; array = tp_asv_get_boxed (properties, "VideoResolution", - TF_FUTURE_STRUCT_TYPE_VIDEO_RESOLUTION); + TP_STRUCT_TYPE_VIDEO_RESOLUTION); if (array) - on_content_video_resolution_changed (TF_FUTURE_CALL_CONTENT (proxy), array, + on_content_video_resolution_changed (TP_CALL_CONTENT (proxy), array, NULL, G_OBJECT (self)); self->notifier = fs_element_added_notifier_new (); g_signal_connect (self->notifier, "element-added", G_CALLBACK (content_video_element_added), self); - setup_content_media_properties (self, proxy, res); + setup_content_media_properties (self, res); return; error: @@ -1144,54 +1506,45 @@ error: static void -setup_content_video_control (TfCallContent *self, - TpProxy *proxy, - GSimpleAsyncResult *res) +setup_content_video_control (TfCallContent *self, GSimpleAsyncResult *res) { GError *error = NULL; - tp_proxy_add_interface_by_id (proxy, - TF_FUTURE_IFACE_QUARK_CALL_CONTENT_INTERFACE_VIDEO_CONTROL); - - if (tf_future_cli_call_content_interface_video_control_connect_to_key_frame_requested ( - TF_FUTURE_CALL_CONTENT (proxy), - on_content_video_keyframe_requested, + if (tp_cli_call_content_interface_video_control_connect_to_key_frame_requested ( + self->proxy, on_content_video_keyframe_requested, NULL, NULL, G_OBJECT (self), &error) == NULL) goto connect_failed; - if (tf_future_cli_call_content_interface_video_control_connect_to_video_resolution_changed ( - TF_FUTURE_CALL_CONTENT (proxy), - on_content_video_resolution_changed, + if (tp_cli_call_content_interface_video_control_connect_to_video_resolution_changed ( + self->proxy, on_content_video_resolution_changed, NULL, NULL, G_OBJECT (self), &error) == NULL) goto connect_failed; - if (tf_future_cli_call_content_interface_video_control_connect_to_bitrate_changed ( - TF_FUTURE_CALL_CONTENT (proxy), - on_content_video_bitrate_changed, + if (tp_cli_call_content_interface_video_control_connect_to_bitrate_changed ( + self->proxy, on_content_video_bitrate_changed, NULL, NULL, G_OBJECT (self), NULL) == NULL) goto connect_failed; - if (tf_future_cli_call_content_interface_video_control_connect_to_framerate_changed ( - TF_FUTURE_CALL_CONTENT (proxy), - on_content_video_framerate_changed, + if (tp_cli_call_content_interface_video_control_connect_to_framerate_changed ( + self->proxy, on_content_video_framerate_changed, NULL, NULL, G_OBJECT (self), NULL) == NULL) goto connect_failed; - if (tf_future_cli_call_content_interface_video_control_connect_to_mtu_changed ( - TF_FUTURE_CALL_CONTENT (proxy), - on_content_video_mtu_changed, + if (tp_cli_call_content_interface_video_control_connect_to_mtu_changed ( + self->proxy, on_content_video_mtu_changed, NULL, NULL, G_OBJECT (self), NULL) == NULL) goto connect_failed; - tp_cli_dbus_properties_call_get_all (proxy, -1, - TF_FUTURE_IFACE_CALL_CONTENT_INTERFACE_VIDEO_CONTROL, + tp_cli_dbus_properties_call_get_all (TP_PROXY (self->proxy), -1, + TP_IFACE_CALL_CONTENT_INTERFACE_VIDEO_CONTROL, got_content_video_control_properties, res, NULL, G_OBJECT (self)); return; connect_failed: - tf_content_error (TF_CONTENT (self), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, "", + tf_call_content_error (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_CONFUSED, "Error getting the Content's VideoControl properties: %s", error->message); g_simple_async_result_take_error (res, error); @@ -1200,10 +1553,9 @@ connect_failed: } static void -new_codec_offer (TfFutureCallContent *proxy, - guint arg_Contact, - const gchar *arg_Offer, - const GPtrArray *arg_Codecs, +new_media_description_offer (TpCallContent *proxy, + const gchar *arg_Media_Description, + GHashTable *arg_Properties, gpointer user_data, GObject *weak_object) { @@ -1213,42 +1565,40 @@ new_codec_offer (TfFutureCallContent *proxy, if (self->call_channel == NULL) return; - /* Ignore signals before we get the first codec offer property */ - if (!self->got_codec_offer_property) + /* Ignore signals before we get the first codec MediaDescription property */ + if (!self->got_media_description_property) return; - if (self->current_offer) { - g_object_unref (self->current_offer); - fs_codec_list_destroy (self->current_offer_fscodecs); - self->current_offer = NULL; - self->current_offer_fscodecs = NULL; + if (self->current_media_description) { + g_object_unref (self->current_media_description); + fs_codec_list_destroy (self->current_md_fscodecs); + fs_rtp_header_extension_list_destroy (self->current_md_rtp_hdrext); + self->current_media_description = NULL; + self->current_md_fscodecs = NULL; + self->current_md_rtp_hdrext = NULL; } - process_codec_offer (self, arg_Offer, arg_Contact, arg_Codecs); + process_media_description (self, arg_Media_Description, arg_Properties); } static void -got_content_properties (TpProxy *proxy, GHashTable *out_Properties, - const GError *error, gpointer user_data, GObject *weak_object) +content_prepared (GObject *src, GAsyncResult *prepare_res, + gpointer user_data) { - TfCallContent *self = TF_CALL_CONTENT (weak_object); + TpCallContent *proxy = TP_CALL_CONTENT (src); GSimpleAsyncResult *res = user_data; - gboolean valid; - GPtrArray *streams; - GError *myerror = NULL; - guint i; - const gchar * const *interfaces; - gboolean got_media_interface = FALSE; - gboolean got_audio_control_interface = FALSE; - gboolean got_video_control_interface = FALSE; + TfCallContent *self = + TF_CALL_CONTENT (g_async_result_get_source_object (G_ASYNC_RESULT (res))); + GError *error = NULL; - if (error) + if (!tp_proxy_prepare_finish (proxy, prepare_res, &error)) { - tf_content_error (TF_CONTENT (self), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, "", + tf_call_content_error (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_CONFUSED, "Error getting the Content's properties: %s", error->message); - g_simple_async_result_set_from_error (res, error); + g_simple_async_result_take_error (res, error); g_simple_async_result_complete (res); g_object_unref (res); return; @@ -1264,53 +1614,12 @@ got_content_properties (TpProxy *proxy, GHashTable *out_Properties, return; } - if (!out_Properties) - { - tf_content_error_literal (TF_CONTENT (self), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, "", - "Error getting the Content's properties: there are none"); - g_simple_async_result_set_error (res, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, - "Error getting the Content's properties: there are none"); - g_simple_async_result_complete (res); - g_object_unref (res); - return; - } - - interfaces = tp_asv_get_strv (out_Properties, "Interfaces"); - - if (interfaces == NULL) - { - tf_content_error_literal (TF_CONTENT (self), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, "", - "Content does not have the Interfaces property, " - "but HardwareStreaming was NOT true"); - g_simple_async_result_set_error (res, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, - "Content does not have the Interfaces property, " - "but HardwareStreaming was NOT true"); - g_simple_async_result_complete (res); - g_object_unref (res); - return; - } - - for (i = 0; interfaces[i]; i++) + if (!tp_proxy_has_interface_by_id (proxy, + TP_IFACE_QUARK_CALL_CONTENT_INTERFACE_MEDIA)) { - if (!strcmp (interfaces[i], - TF_FUTURE_IFACE_CALL_CONTENT_INTERFACE_MEDIA)) - got_media_interface = TRUE; - - if (!strcmp (interfaces[i], - TF_FUTURE_IFACE_CALL_CONTENT_INTERFACE_AUDIO_CONTROL)) - got_audio_control_interface = TRUE; - - if (!strcmp (interfaces[i], - TF_FUTURE_IFACE_CALL_CONTENT_INTERFACE_VIDEO_CONTROL)) - got_video_control_interface = TRUE; - } - - if (!got_media_interface) - { - tf_content_error_literal (TF_CONTENT (self), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, "", + tf_call_content_error_literal (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_CONFUSED, "Content does not have the media interface," " but HardwareStreaming was NOT true"); g_simple_async_result_set_error (res, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, @@ -1321,96 +1630,36 @@ got_content_properties (TpProxy *proxy, GHashTable *out_Properties, return; } - self->media_type = tp_asv_get_uint32 (out_Properties, "Type", &valid); - if (!valid) - goto invalid_property; - - - streams = tp_asv_get_boxed (out_Properties, "Streams", - TP_ARRAY_TYPE_OBJECT_PATH_LIST); - if (!streams) - goto invalid_property; - - self->streams = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, g_object_unref); - - for (i = 0; i < streams->len; i++) - add_stream (self, g_ptr_array_index (streams, i)); - - tp_proxy_add_interface_by_id (TP_PROXY (self->proxy), - TF_FUTURE_IFACE_QUARK_CALL_CONTENT_INTERFACE_MEDIA); + self->streams = g_ptr_array_new_with_free_func (g_object_unref); + tp_cli_call_content_interface_media_connect_to_new_media_description_offer ( + self->proxy, new_media_description_offer, NULL, NULL, + G_OBJECT (self), &error); - tf_future_cli_call_content_interface_media_connect_to_new_codec_offer ( - TF_FUTURE_CALL_CONTENT (proxy), new_codec_offer, NULL, NULL, - G_OBJECT (self), &myerror); - - if (myerror) + if (error) { - tf_content_error (TF_CONTENT (self), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, "", - "Error connectiong to NewCodecOffer signal: %s", - myerror->message); - g_simple_async_result_set_from_error (res, myerror); + tf_call_content_error (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_CONFUSED, + "Error connecting to NewCodecMediaDescription signal: %s", + error->message); + g_simple_async_result_set_from_error (res, error); g_simple_async_result_complete (res); g_object_unref (res); - g_clear_error (&myerror); + g_clear_error (&error); return; } - if (got_audio_control_interface) - setup_content_audio_control (self, proxy, res); - else if (got_video_control_interface) - setup_content_video_control (self, proxy, res); + if (tp_proxy_has_interface_by_id (proxy, + TP_IFACE_QUARK_CALL_CONTENT_INTERFACE_AUDIO_CONTROL)) + setup_content_audio_control (self, res); + else if (tp_proxy_has_interface_by_id (proxy, + TP_IFACE_QUARK_CALL_CONTENT_INTERFACE_VIDEO_CONTROL)) + setup_content_video_control (self, res); else - setup_content_media_properties (self, proxy, res); + setup_content_media_properties (self, res); return; - - invalid_property: - tf_content_error_literal (TF_CONTENT (self), TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, - "", "Error getting the Content's properties: invalid type"); - g_simple_async_result_set_error (res, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, - "Error getting the Content's properties: invalid type"); - g_simple_async_result_complete (res); - g_object_unref (res); - return; -} - -static void -streams_added (TfFutureCallContent *proxy, - const GPtrArray *arg_Streams, - gpointer user_data, - GObject *weak_object) -{ - TfCallContent *self = TF_CALL_CONTENT (weak_object); - guint i; - - /* Ignore signals before we got the "Contents" property to avoid races that - * could cause the same content to be added twice - */ - - if (!self->streams) - return; - - for (i = 0; i < arg_Streams->len; i++) - add_stream (self, g_ptr_array_index (arg_Streams, i)); -} - -static void -streams_removed (TfFutureCallContent *proxy, - const GPtrArray *arg_Streams, - gpointer user_data, - GObject *weak_object) -{ - TfCallContent *self = TF_CALL_CONTENT (weak_object); - guint i; - - if (!self->streams) - return; - - for (i = 0; i < arg_Streams->len; i++) - g_hash_table_remove (self->streams, g_ptr_array_index (arg_Streams, i)); } @@ -1422,7 +1671,6 @@ tf_call_content_init_async (GAsyncInitable *initable, gpointer user_data) { TfCallContent *self = TF_CALL_CONTENT (initable); - GError *myerror = NULL; GSimpleAsyncResult *res; if (cancellable != NULL) @@ -1433,39 +1681,11 @@ tf_call_content_init_async (GAsyncInitable *initable, return; } - tf_future_cli_call_content_connect_to_streams_added ( - TF_FUTURE_CALL_CONTENT (self->proxy), streams_added, NULL, NULL, - G_OBJECT (self), &myerror); - if (myerror) - { - tf_content_error (TF_CONTENT (self), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, "", - "Error connectiong to StreamAdded signal: %s", myerror->message); - g_simple_async_report_gerror_in_idle (G_OBJECT (self), callback, - user_data, myerror); - return; - } - - tf_future_cli_call_content_connect_to_streams_removed ( - TF_FUTURE_CALL_CONTENT (self->proxy), streams_removed, NULL, NULL, - G_OBJECT (self), &myerror); - if (myerror) - { - tf_content_error (TF_CONTENT (self), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, "", - "Error connectiong to StreamRemoved signal: %s", myerror->message); - g_simple_async_report_gerror_in_idle (G_OBJECT (self), callback, - user_data, myerror); - return; - } - res = g_simple_async_result_new (G_OBJECT (self), callback, user_data, tf_call_content_init_async); - tp_cli_dbus_properties_call_get_all (self->proxy, -1, - TF_FUTURE_IFACE_CALL_CONTENT, got_content_properties, res, - NULL, G_OBJECT (self)); + tp_proxy_prepare_async (self->proxy, NULL, content_prepared, res); } static gboolean @@ -1487,34 +1707,67 @@ tf_call_content_init_finish (GAsyncInitable *initable, TfCallContent * tf_call_content_new_async (TfCallChannel *call_channel, - const gchar *object_path, GError **error, + TpCallContent *content_proxy, GError **error, GAsyncReadyCallback callback, gpointer user_data) { TfCallContent *self; - TfFutureCallContent *proxy = tf_future_call_content_new ( - call_channel->proxy, object_path, error); - if (!proxy) - return NULL; + g_return_val_if_fail (call_channel != NULL, NULL); + g_return_val_if_fail (content_proxy != NULL, NULL); self = g_object_new (TF_TYPE_CALL_CONTENT, NULL); self->call_channel = call_channel; - self->proxy = proxy; + self->proxy = g_object_ref (content_proxy); g_async_initable_init_async (G_ASYNC_INITABLE (self), 0, NULL, callback, user_data); - return g_object_ref (self); + return self; } +static gboolean +find_codec (GList *codecs, FsCodec *codec) +{ + GList *item; + + for (item = codecs; item ; item = item->next) + if (fs_codec_are_equal (item->data, codec)) + return TRUE; + + return FALSE; +} -static GPtrArray * -fscodecs_to_tpcodecs (GList *codecs) +static GHashTable * +fscodecs_to_media_descriptions (TfCallContent *self, GList *codecs) { GPtrArray *tpcodecs = g_ptr_array_new (); GList *item; + GList *resend_codecs = NULL; + GHashTable *retval; + GPtrArray *rtp_hdrext = NULL; + GHashTable *rtcp_fb = NULL; + GPtrArray *interfaces; + + if (self->last_sent_codecs) + resend_codecs = fs_session_codecs_need_resend (self->fssession, + self->last_sent_codecs, codecs); + + if (!self->current_media_description && !resend_codecs) + return NULL; + + if ((self->current_media_description && self->current_has_rtp_hdrext) + || self->has_rtp_hdrext) + rtp_hdrext = dbus_g_type_specialized_construct ( + TP_ARRAY_TYPE_RTP_HEADER_EXTENSIONS_LIST); + + if ((self->current_media_description && self->current_has_rtcp_fb) + || self->has_rtcp_fb) + rtcp_fb = dbus_g_type_specialized_construct ( + TP_HASH_TYPE_RTCP_FEEDBACK_MESSAGE_MAP); + + g_debug ("Local codecs:"); for (item = codecs; item; item = item->next) { @@ -1522,6 +1775,12 @@ fscodecs_to_tpcodecs (GList *codecs) GValue tpcodec = { 0, }; GHashTable *params; GList *param_item; + gboolean updated; + gchar *tmp; + + tmp = fs_codec_to_string (fscodec); + g_debug ("%s", tmp); + g_free (tmp); params = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); @@ -1535,37 +1794,130 @@ fscodecs_to_tpcodecs (GList *codecs) g_strdup (param->value)); } - g_value_init (&tpcodec, TF_FUTURE_STRUCT_TYPE_CODEC); + updated = find_codec (resend_codecs, fscodec); + + g_value_init (&tpcodec, TP_STRUCT_TYPE_CODEC); g_value_take_boxed (&tpcodec, - dbus_g_type_specialized_construct (TF_FUTURE_STRUCT_TYPE_CODEC)); + dbus_g_type_specialized_construct (TP_STRUCT_TYPE_CODEC)); dbus_g_type_struct_set (&tpcodec, 0, fscodec->id, 1, fscodec->encoding_name, 2, fscodec->clock_rate, 3, fscodec->channels, - 4, params, + 4, updated, + 5, params, G_MAXUINT); g_hash_table_destroy (params); g_ptr_array_add (tpcodecs, g_value_get_boxed (&tpcodec)); + + if (rtcp_fb != NULL && + (fscodec->minimum_reporting_interval != G_MAXUINT || + fscodec->feedback_params)) + { + GPtrArray *messages = g_ptr_array_new (); + GList *item2; + + for (item2 = fscodec->feedback_params; item2; item2 = item2->next) + { + FsFeedbackParameter *fb = item2->data; + + g_ptr_array_add (messages, tp_value_array_build (3, + G_TYPE_STRING, fb->type, + G_TYPE_STRING, fb->subtype, + G_TYPE_STRING, fb->extra_params, + G_TYPE_INVALID)); + } + + g_hash_table_insert (rtcp_fb, GUINT_TO_POINTER (fscodec->id), + tp_value_array_build (2, + G_TYPE_UINT, + fscodec->minimum_reporting_interval != G_MAXUINT ? + fscodec->minimum_reporting_interval : 5000, + TP_ARRAY_TYPE_RTCP_FEEDBACK_MESSAGE_LIST, messages, + G_TYPE_INVALID)); + + g_boxed_free (TP_ARRAY_TYPE_RTCP_FEEDBACK_MESSAGE_LIST, messages); + } + } + + fs_codec_list_destroy (resend_codecs); + + + if (rtp_hdrext) + { + GList *fs_rtp_hdrexts; + + g_object_get (self->fssession, "rtp-header-extensions", &fs_rtp_hdrexts, + NULL); + + for (item = fs_rtp_hdrexts; item; item = item->next) + { + FsRtpHeaderExtension *hdrext = item->data; + + g_debug (FS_RTP_HEADER_EXTENSION_FORMAT, + FS_RTP_HEADER_EXTENSION_ARGS (hdrext)); + + g_ptr_array_add (rtp_hdrext, tp_value_array_build (4, + G_TYPE_UINT, hdrext->id, + G_TYPE_UINT, fsdirection_to_tpdirection (hdrext->direction), + G_TYPE_STRING, hdrext->uri, + G_TYPE_STRING, "", + G_TYPE_INVALID)); + } + + fs_rtp_header_extension_list_destroy (fs_rtp_hdrexts); } - return tpcodecs; + retval = tp_asv_new ( + TP_PROP_CALL_CONTENT_MEDIA_DESCRIPTION_CODECS, + TP_ARRAY_TYPE_CODEC_LIST, tpcodecs, + TP_PROP_CALL_CONTENT_MEDIA_DESCRIPTION_FURTHER_NEGOTIATION_REQUIRED, + G_TYPE_BOOLEAN, !!resend_codecs, + NULL); + + interfaces = g_ptr_array_new (); + + if (rtp_hdrext) + { + tp_asv_take_boxed (retval, TP_PROP_CALL_CONTENT_MEDIA_DESCRIPTION_INTERFACE_RTP_HEADER_EXTENSIONS_HEADER_EXTENSIONS, + TP_ARRAY_TYPE_RTP_HEADER_EXTENSIONS_LIST, + rtp_hdrext); + g_ptr_array_add (interfaces, + g_strdup (TP_IFACE_CALL_CONTENT_MEDIA_DESCRIPTION_INTERFACE_RTP_HEADER_EXTENSIONS)); + } + + if (rtcp_fb) + { + tp_asv_set_boolean (retval, TP_PROP_CALL_CONTENT_MEDIA_DESCRIPTION_INTERFACE_RTCP_FEEDBACK_DOES_AVPF, g_hash_table_size (rtcp_fb)); + tp_asv_take_boxed (retval, TP_PROP_CALL_CONTENT_MEDIA_DESCRIPTION_INTERFACE_RTCP_FEEDBACK_FEEDBACK_MESSAGES, + TP_HASH_TYPE_RTCP_FEEDBACK_MESSAGE_MAP, rtcp_fb); + g_ptr_array_add (interfaces, + g_strdup (TP_IFACE_CALL_CONTENT_MEDIA_DESCRIPTION_INTERFACE_RTP_HEADER_EXTENSIONS)); + } + + g_ptr_array_add (interfaces, NULL); + tp_asv_take_boxed (retval, TP_PROP_CALL_CONTENT_MEDIA_DESCRIPTION_INTERFACES, + G_TYPE_STRV, interfaces->pdata); + g_ptr_array_free (interfaces, FALSE); + + return retval; } static void tf_call_content_try_sending_codecs (TfCallContent *self) { GList *codecs; - GPtrArray *tpcodecs; + GHashTable *media_description; const gchar *codecs_prop = NULL; - if (self->current_offer_fscodecs != NULL) + if (self->current_md_fscodecs != NULL) { - g_debug ("Ignoring updated codecs unprocessed offer outstanding"); + g_debug ("Ignoring updated codecs unprocessed media description" + " outstanding"); return; } @@ -1581,40 +1933,123 @@ tf_call_content_try_sending_codecs (TfCallContent *self) if (!codecs) return; - if (fs_codec_list_are_equal (codecs, self->current_codecs)) + if (fs_codec_list_are_equal (codecs, self->last_sent_codecs)) { fs_codec_list_destroy (codecs); return; } - tpcodecs = fscodecs_to_tpcodecs (codecs); + media_description = fscodecs_to_media_descriptions (self, codecs); - if (self->current_offer) + if (self->current_media_description) { - tf_future_cli_call_content_codec_offer_call_accept (self->current_offer, - -1, tpcodecs, NULL, NULL, NULL, NULL); + g_debug ("Accepting Media Description"); + + tp_cli_call_content_media_description_call_accept ( + self->current_media_description, -1, media_description, + NULL, NULL, NULL, NULL); - g_object_unref (self->current_offer); - self->current_offer = NULL; + g_object_unref (self->current_media_description); + self->current_media_description = NULL; } else { - tf_future_cli_call_content_interface_media_call_update_codecs ( - self->proxy, -1, tpcodecs, NULL, NULL, NULL, NULL); + if (media_description) + { + g_debug ("Updating local Media Description"); + tp_cli_call_content_interface_media_call_update_local_media_description ( + self->proxy, -1, media_description, NULL, NULL, NULL, NULL); + } + else + { + fs_codec_list_destroy (codecs); + } } - g_boxed_free (TF_FUTURE_ARRAY_TYPE_CODEC_LIST, tpcodecs); + if (media_description) + { + fs_codec_list_destroy (self->last_sent_codecs); + self->last_sent_codecs = codecs; + self->has_rtcp_fb = self->current_has_rtcp_fb; + self->has_rtp_hdrext = self->current_has_rtp_hdrext; + + g_boxed_free (TP_HASH_TYPE_MEDIA_DESCRIPTION_PROPERTIES, media_description); + } } +static void +tf_call_content_dtmf_started (TfCallContent *self, FsDTMFMethod method, + FsDTMFEvent event, guint8 volume) +{ + if (volume != DTMF_TONE_VOLUME) + { + tf_call_content_error (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_MEDIA_STREAMING_ERROR, + "DTMF volume is %d, while we use %d", volume, DTMF_TONE_VOLUME); + return; + } + + if (self->dtmf_sending_state != TP_SENDING_STATE_PENDING_SEND) + { + tf_call_content_error (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_MEDIA_STREAMING_ERROR, + "Farstream started a DTMFevent, but we were in the %d state", + self->dtmf_sending_state); + return; + } + + if (self->current_dtmf_event != event) + { + tf_call_content_error (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_MEDIA_STREAMING_ERROR, + "Farstream started the wrong dtmf event, got %d but " + "expected %d", event, self->current_dtmf_event); + return; + } + + tp_cli_call_content_interface_media_call_acknowledge_dtmf_change ( + self->proxy, -1, event, TP_SENDING_STATE_SENDING, + NULL, NULL, NULL, NULL); + self->dtmf_sending_state = TP_SENDING_STATE_SENDING; +} + +static void +tf_call_content_dtmf_stopped (TfCallContent *self, FsDTMFMethod method) +{ + if (self->dtmf_sending_state != TP_SENDING_STATE_PENDING_STOP_SENDING) + { + tf_call_content_error (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_MEDIA_STREAMING_ERROR, + "Farstream stopped a DTMFevent, but we were in the %d state", + self->dtmf_sending_state); + return; + } + + tp_cli_call_content_interface_media_call_acknowledge_dtmf_change ( + self->proxy, -1, self->current_dtmf_event, TP_SENDING_STATE_NONE, + NULL, NULL, NULL, NULL); + self->dtmf_sending_state = TP_SENDING_STATE_NONE; +} + + gboolean tf_call_content_bus_message (TfCallContent *content, GstMessage *message) { - const GstStructure *s; - gboolean ret = FALSE; - const gchar *debug; - GHashTableIter iter; - gpointer key, value; + gboolean ret = TRUE; + FsDTMFMethod method; + FsDTMFEvent event; + guint8 volume; + FsCodec *codec; + GList *secondary_codecs; + FsError error_no; + const gchar *error_msg; + guint i; + /* Guard against early disposal */ if (content->call_channel == NULL) @@ -1626,81 +2061,123 @@ tf_call_content_bus_message (TfCallContent *content, if (GST_MESSAGE_TYPE (message) != GST_MESSAGE_ELEMENT) return FALSE; - s = gst_message_get_structure (message); - if (gst_structure_has_name (s, "farstream-error")) + if (fs_parse_error (G_OBJECT (content->fssession), message, &error_no, + &error_msg)) { - GObject *object; - const GValue *value = NULL; - - value = gst_structure_get_value (s, "src-object"); - object = g_value_get_object (value); - - if (object == (GObject*) content->fssession) - { - const gchar *msg; - FsError errorno; - GEnumClass *enumclass; - GEnumValue *enumvalue; - - value = gst_structure_get_value (s, "error-no"); - errorno = g_value_get_enum (value); - msg = gst_structure_get_string (s, "error-msg"); - debug = gst_structure_get_string (s, "debug-msg"); - - enumclass = g_type_class_ref (FS_TYPE_ERROR); - enumvalue = g_enum_get_value (enumclass, errorno); - g_warning ("error (%s (%d)): %s : %s", - enumvalue->value_nick, errorno, msg, debug); - g_type_class_unref (enumclass); - - tf_content_error_literal (TF_CONTENT (content), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, "", msg); - - ret = TRUE; - } + GEnumClass *enumclass; + GEnumValue *enumvalue; + + enumclass = g_type_class_ref (FS_TYPE_ERROR); + enumvalue = g_enum_get_value (enumclass, error_no); + g_warning ("error (%s (%d)): %s", + enumvalue->value_nick, error_no, error_msg); + g_type_class_unref (enumclass); + + tf_call_content_error_literal (content, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_MEDIA_STREAMING_ERROR, error_msg); } - else if (gst_structure_has_name (s, "farstream-codecs-changed")) + else if (fs_session_parse_codecs_changed (content->fssession, message)) { - FsSession *fssession; - const GValue *value; + g_debug ("Codecs changed"); - value = gst_structure_get_value (s, "session"); - fssession = g_value_get_object (value); + tf_call_content_try_sending_codecs (content); + } + else if (fs_session_parse_telephony_event_started (content->fssession, + message, &method, &event, &volume)) + { + g_debug ("DTMF started: method: %d event: %u volume: %u", + method, event, volume); - if (fssession != content->fssession) - return FALSE; + tf_call_content_dtmf_started (content, method, event, volume); + } + else if (fs_session_parse_telephony_event_stopped (content->fssession, + message, &method)) + { + g_debug ("DTMF stopped: method: %d", method); - g_debug ("Codecs changed"); + tf_call_content_dtmf_stopped (content, method); + } + else if (fs_session_parse_send_codec_changed (content->fssession, message, + &codec, &secondary_codecs)) + { + gchar *tmp; + guint i = 1; - tf_call_content_try_sending_codecs (content); + tmp = fs_codec_to_string (codec); + g_debug ("Send codec changed: %s", tmp); + g_free (tmp); - ret = TRUE; + while (secondary_codecs) + { + tmp = fs_codec_to_string (secondary_codecs->data); + g_debug ("Secondary send codec %u changed: %s", i++, tmp); + g_free (tmp); + secondary_codecs = secondary_codecs->next; + } + } + else + { + ret = FALSE; } - g_hash_table_iter_init (&iter, content->streams); - while (g_hash_table_iter_next (&iter, &key, &value)) - if (tf_call_stream_bus_message (value, message)) + for (i = 0; i < content->streams->len; i++) + if (tf_call_stream_bus_message (g_ptr_array_index (content->streams, i), + message)) return TRUE; return ret; } + static void -tf_call_content_error (TfContent *content, - guint reason, /* TfFutureContentRemovalReason */ +tf_call_content_error (TfCallContent *self, + TpCallStateChangeReason reason, const gchar *detailed_reason, - const gchar *message) + const gchar *message_format, + ...) { - TfCallContent *self = TF_CALL_CONTENT (content); + gchar *message; + va_list valist; + + va_start (valist, message_format); + message = g_strdup_vprintf (message_format, valist); + va_end (valist); + + tf_call_content_error_literal (self, reason, detailed_reason, message); + g_free (message); +} + +static void +tf_call_content_error_literal (TfCallContent *self, + TpCallStateChangeReason reason, + const gchar *detailed_reason, + const gchar *message) +{ g_warning ("%s", message); - tf_future_cli_call_content_call_remove ( - self->proxy, -1, reason, detailed_reason, message, NULL, NULL, - NULL, NULL); + tp_cli_call_content_interface_media_call_fail ( + self->proxy, -1, + tp_value_array_build (4, + G_TYPE_UINT, 0, + G_TYPE_UINT, reason, + G_TYPE_STRING, detailed_reason, + G_TYPE_STRING, message, + G_TYPE_INVALID), + NULL, NULL, NULL, NULL); } +static void +tf_call_content_error_impl (TfContent *content, + const gchar *message) +{ + tf_call_content_error_literal (TF_CALL_CONTENT (content), + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_MEDIA_STREAMING_ERROR, message); +} + static FsStream * tf_call_content_get_existing_fsstream_by_handle (TfCallContent *content, @@ -1731,6 +2208,7 @@ tf_call_content_get_existing_fsstream_by_handle (TfCallContent *content, FsStream * _tf_call_content_get_fsstream_by_handle (TfCallContent *content, guint contact_handle, + FsStreamDirection dir, const gchar *transmitter, guint stream_transmitter_n_parameters, GParameter *stream_transmitter_parameters, @@ -1750,7 +2228,7 @@ _tf_call_content_get_fsstream_by_handle (TfCallContent *content, if (!p) return NULL; - s = fs_session_new_stream (content->fssession, p, FS_DIRECTION_RECV, error); + s = fs_session_new_stream (content->fssession, p, dir, error); if (!s) { _tf_call_channel_put_participant (content->call_channel, p); @@ -1778,17 +2256,20 @@ _tf_call_content_get_fsstream_by_handle (TfCallContent *content, g_ptr_array_add (content->fsstreams, cfs); content->fsstreams_cookie ++; - if (content->current_offer != NULL - && content->current_offer_contact_handle == contact_handle) + if (content->current_media_description != NULL + && content->current_md_contact_handle == contact_handle) { - GList *codecs = content->current_offer_fscodecs; - TpProxy *current_offer = content->current_offer; - content->current_offer_fscodecs = NULL; - content->current_offer = NULL; + GList *codecs = content->current_md_fscodecs; + TpProxy *current_media_description = content->current_media_description; + GList *rtp_hdrext = content->current_md_rtp_hdrext; + + content->current_md_fscodecs = NULL; + content->current_media_description = NULL; + content->current_md_rtp_hdrext = NULL; /* ownership transfers to try_codecs */ - process_codec_offer_try_codecs (content, s, - current_offer, codecs); + process_media_description_try_codecs (content, s, + current_media_description, codecs, rtp_hdrext); } return s; @@ -1825,7 +2306,7 @@ _tf_call_content_put_fsstream (TfCallContent *content, FsStream *fsstream) FsMediaType tf_call_content_get_fs_media_type (TfCallContent *content) { - return tp_media_type_to_fs (content->media_type); + return tp_media_type_to_fs (tp_call_content_get_media_type (content->proxy)); } static void @@ -1947,3 +2428,50 @@ tf_call_content_iterate_src_pads (TfContent *content, guint *handles, return (GstIterator *) iter; } + +static void +tf_call_content_sending_failed (TfContent *content, + const gchar *message) +{ + TfCallContent *self = TF_CALL_CONTENT (content); + guint i; + + if (!self->streams) + { + g_warning ("Too early, ignoring sending error"); + return; + } + + for (i = 0; i < self->streams->len; i++) + tf_call_stream_sending_failed (g_ptr_array_index (self->streams, i), + message); +} + + +static void +tf_call_content_receiving_failed (TfContent *content, + guint *handles, guint handle_count, + const gchar *message) +{ + TfCallContent *self = TF_CALL_CONTENT (content); + guint i; + + if (!self->streams) + { + g_warning ("Too early, ignoring sending error"); + return; + } + + for (i = 0; i < self->streams->len; i++) + tf_call_stream_receiving_failed (g_ptr_array_index (self->streams, i), + handles, handle_count, message); +} + + +TpCallContent * +tf_call_content_get_proxy (TfCallContent *content) +{ + g_return_val_if_fail (TF_IS_CALL_CONTENT (content), NULL); + + return content->proxy; +} diff --git a/telepathy-farstream/call-content.h b/telepathy-farstream/call-content.h index 697148e..499eead 100644 --- a/telepathy-farstream/call-content.h +++ b/telepathy-farstream/call-content.h @@ -23,9 +23,8 @@ #include <glib-object.h> #include <gst/gst.h> -#include <telepathy-glib/channel.h> +#include <telepathy-glib/telepathy-glib.h> -#include "extensions/extensions.h" #include "call-channel.h" #include "content.h" #include "content-priv.h" @@ -75,7 +74,7 @@ GType tf_call_content_get_type (void); TfCallContent *tf_call_content_new_async ( TfCallChannel *call_channel, - const gchar *object_path, + TpCallContent *content_proxy, GError **error, GAsyncReadyCallback callback, gpointer user_data); @@ -87,6 +86,7 @@ gboolean tf_call_content_bus_message (TfCallContent *content, /* Private */ FsStream *_tf_call_content_get_fsstream_by_handle (TfCallContent *content, guint contact_handle, + FsStreamDirection dir, const gchar *transmitter, guint stream_transmitter_n_parameters, GParameter *stream_transmitter_parameters, @@ -100,6 +100,9 @@ tf_call_content_get_fs_media_type (TfCallContent *content); gboolean tf_call_content_bus_message (TfCallContent *content, GstMessage *message); +TpCallContent * +tf_call_content_get_proxy (TfCallContent *content); + G_END_DECLS #endif /* __TF_CALL_CONTENT_H__ */ diff --git a/telepathy-farstream/call-stream.c b/telepathy-farstream/call-stream.c index f7257d6..e4286da 100644 --- a/telepathy-farstream/call-stream.c +++ b/telepathy-farstream/call-stream.c @@ -20,26 +20,35 @@ /** * SECTION:tfcallstream * - * @short_description: Handle the Stream interface on a Channel + * @short_description: Handle the Stream objects for a Call1 channel * - * This class handles the - * org.freedesktop.Telepathy.Channel.Interface.Stream on a - * channel using Farstream. + * This class handles the org.freedesktop.Telepathy.Call1.Stream, + * org.freedesktop.Telepathy.Call1.Stream.Interface.Media and + * org.freedesktop.Telepathy.Call1.Stream.Endpoint interfaces. + */ + +/* + * TODO: + * - Support multiple handles + * - Allow app to fail sending or receiving during call + * + * Endpoints: + * - Support multiple Endpoints (ie SIP forking with ICE) + * - Call SetControlling + * - Listen to CandidatePairSelected and call AcceptSelectedCandidatePair/RejectSelectedCandidatePair + * - Support IsICELite */ #include "call-stream.h" -#include <telepathy-glib/util.h> -#include <telepathy-glib/interfaces.h> +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/proxy-subclass.h> #include <farstream/fs-conference.h> #include <stdarg.h> #include <string.h> #include <stdlib.h> -#include <telepathy-glib/proxy-subclass.h> - -#include "extensions/extensions.h" #include "tf-signals-marshal.h" #include "utils.h" @@ -49,6 +58,18 @@ G_DEFINE_TYPE (TfCallStream, tf_call_stream, G_TYPE_OBJECT); static void tf_call_stream_dispose (GObject *object); +static void tf_call_stream_fail_literal (TfCallStream *self, + TpCallStateChangeReason reason, + const gchar *detailed_reason, + const gchar *message); + +static void tf_call_stream_fail (TfCallStream *self, + TpCallStateChangeReason reason, + const gchar *detailed_reason, + const gchar *message_format, + ...); + + static void tf_call_stream_class_init (TfCallStreamClass *klass) { @@ -60,6 +81,8 @@ tf_call_stream_class_init (TfCallStreamClass *klass) static void tf_call_stream_init (TfCallStream *self) { + self->sending_state = TP_STREAM_FLOW_STATE_STOPPED; + self->receiving_state = TP_STREAM_FLOW_STATE_STOPPED; } static void @@ -101,56 +124,124 @@ tf_call_stream_dispose (GObject *object) G_OBJECT_CLASS (tf_call_stream_parent_class)->dispose (object); } + + static void -local_sending_state_changed (TfFutureCallStream *proxy, +sending_state_changed (TpCallStream *proxy, guint arg_State, gpointer user_data, GObject *weak_object) { TfCallStream *self = TF_CALL_STREAM (weak_object); + FsStreamDirection dir; - self->local_sending_state = arg_State; + self->sending_state = arg_State; if (!self->fsstream) return; - if (arg_State == TF_FUTURE_SENDING_STATE_SENDING) - { - if (!self->has_send_resource) - { - if (_tf_content_start_sending (TF_CONTENT (self->call_content))) - { - self->has_send_resource = TRUE; - } - else - { - /* FIXME add a way to call to report media errors */ - g_warning ("Sending failed"); - return; - } - } - } + g_object_get (self->fsstream, "direction", &dir, NULL); switch (arg_State) { - case TF_FUTURE_SENDING_STATE_PENDING_STOP_SENDING: - case TF_FUTURE_SENDING_STATE_PENDING_SEND: - /* the UI should respond to these */ - break; - case TF_FUTURE_SENDING_STATE_SENDING: - g_object_set (self->fsstream, "direction", FS_DIRECTION_BOTH, NULL); + case TP_STREAM_FLOW_STATE_PENDING_START: + if (self->has_send_resource || + _tf_content_start_sending (TF_CONTENT (self->call_content))) + { + self->has_send_resource = TRUE; + + tp_cli_call_stream_interface_media_call_complete_sending_state_change ( + proxy, -1, TP_STREAM_FLOW_STATE_STARTED, + NULL, NULL, NULL, NULL); + g_object_set (self->fsstream, + "direction", dir | FS_DIRECTION_SEND, NULL); + } + else + { + tp_cli_call_stream_interface_media_call_report_sending_failure ( + proxy, -1, TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_MEDIA_STREAMING_ERROR, + "Could not start sending", NULL, NULL, NULL, NULL); + return; + } break; - case TF_FUTURE_SENDING_STATE_NONE: + case TP_STREAM_FLOW_STATE_PENDING_STOP: + g_object_set (self->fsstream, + "direction", dir & ~FS_DIRECTION_SEND, NULL); if (self->has_send_resource) { _tf_content_stop_sending (TF_CONTENT (self->call_content)); self->has_send_resource = FALSE; } - g_object_set (self->fsstream, "direction", FS_DIRECTION_RECV, NULL); + tp_cli_call_stream_interface_media_call_complete_sending_state_change ( + proxy, -1, TP_STREAM_FLOW_STATE_STOPPED, NULL, NULL, NULL, NULL); + break; + default: break; } } +static void +tf_call_stream_start_receiving (TfCallStream *self, FsStreamDirection dir) +{ + if (self->has_receive_resource || + _tf_content_start_receiving (TF_CONTENT (self->call_content), + &self->contact_handle, 1)) + { + self->has_receive_resource = TRUE; + if (self->fsstream) + g_object_set (self->fsstream, + "direction", dir | FS_DIRECTION_RECV, NULL); + tp_cli_call_stream_interface_media_call_complete_receiving_state_change ( + self->proxy, -1, TP_STREAM_FLOW_STATE_STARTED, + NULL, NULL, NULL, NULL); + } + else + { + tp_cli_call_stream_interface_media_call_report_receiving_failure ( + self->proxy, -1, TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_MEDIA_STREAMING_ERROR, + "Could not start receiving", NULL, NULL, NULL, NULL); + } +} + +static void +receiving_state_changed (TpCallStream *proxy, + guint arg_State, + gpointer user_data, GObject *weak_object) +{ + TfCallStream *self = TF_CALL_STREAM (weak_object); + FsStreamDirection dir; + + self->receiving_state = arg_State; + + if (!self->fsstream) + return; + + g_object_get (self->fsstream, "direction", &dir, NULL); + + switch (arg_State) + { + case TP_STREAM_FLOW_STATE_PENDING_START: + tf_call_stream_start_receiving (self, dir); + break; + case TP_STREAM_FLOW_STATE_PENDING_STOP: + g_object_set (self->fsstream, + "direction", dir & ~FS_DIRECTION_RECV, NULL); + if (self->has_receive_resource) + { + _tf_content_stop_receiving (TF_CONTENT (self->call_content), + &self->contact_handle, 1); + + self->has_receive_resource = FALSE; + } + tp_cli_call_stream_interface_media_call_complete_receiving_state_change ( + proxy, -1, TP_STREAM_FLOW_STATE_STOPPED, NULL, NULL, NULL, NULL); + break; + default: + break; + } +} static void tf_call_stream_try_adding_fsstream (TfCallStream *self) @@ -161,6 +252,7 @@ tf_call_stream_try_adding_fsstream (TfCallStream *self) GParameter params[6] = { {NULL,} }; GList *preferred_local_candidates = NULL; guint i; + FsStreamDirection dir = FS_DIRECTION_NONE; memset (params, 0, sizeof(params)); @@ -171,9 +263,11 @@ tf_call_stream_try_adding_fsstream (TfCallStream *self) switch (self->transport_type) { - case TF_FUTURE_STREAM_TRANSPORT_TYPE_RAW_UDP: + case TP_STREAM_TRANSPORT_TYPE_RAW_UDP: transmitter = "rawudp"; + g_debug ("Transmitter: rawudp"); + switch (tf_call_content_get_fs_media_type (self->call_content)) { case TP_MEDIA_STREAM_TYPE_VIDEO: @@ -198,43 +292,50 @@ tf_call_stream_try_adding_fsstream (TfCallStream *self) n_params++; } break; - case TF_FUTURE_STREAM_TRANSPORT_TYPE_ICE: - case TF_FUTURE_STREAM_TRANSPORT_TYPE_GTALK_P2P: - case TF_FUTURE_STREAM_TRANSPORT_TYPE_WLM_2009: + case TP_STREAM_TRANSPORT_TYPE_ICE: + case TP_STREAM_TRANSPORT_TYPE_GTALK_P2P: + case TP_STREAM_TRANSPORT_TYPE_WLM_2009: transmitter = "nice"; - /* MISSING: Set Controlling mode property here */ + params[n_params].name = "controlling-mode"; + g_value_init (¶ms[n_params].value, G_TYPE_BOOLEAN); + g_value_set_boolean (¶ms[n_params].value, self->controlling); + n_params++; params[n_params].name = "compatibility-mode"; g_value_init (¶ms[n_params].value, G_TYPE_UINT); switch (self->transport_type) { - case TF_FUTURE_STREAM_TRANSPORT_TYPE_ICE: + case TP_STREAM_TRANSPORT_TYPE_ICE: g_value_set_uint (¶ms[n_params].value, 0); break; - case TF_FUTURE_STREAM_TRANSPORT_TYPE_GTALK_P2P: + case TP_STREAM_TRANSPORT_TYPE_GTALK_P2P: g_value_set_uint (¶ms[n_params].value, 1); self->multiple_usernames = TRUE; break; - case TF_FUTURE_STREAM_TRANSPORT_TYPE_WLM_2009: + case TP_STREAM_TRANSPORT_TYPE_WLM_2009: g_value_set_uint (¶ms[n_params].value, 3); break; default: break; } + + g_debug ("Transmitter: nice: TpTransportType:%d controlling:%d", + self->transport_type, self->controlling); + n_params++; break; - case TF_FUTURE_STREAM_TRANSPORT_TYPE_SHM: + case TP_STREAM_TRANSPORT_TYPE_SHM: transmitter = "shm"; params[n_params].name = "create-local-candidates"; g_value_init (¶ms[n_params].value, G_TYPE_BOOLEAN); g_value_set_boolean (¶ms[n_params].value, TRUE); n_params++; + g_debug ("Transmitter: shm"); break; default: - tf_content_error (TF_CONTENT (self->call_content), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, - "org.freedesktop.Telepathy.Error.NotImplemented", + tf_call_stream_fail (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, TP_ERROR_STR_CONFUSED, "Unknown transport type %d", self->transport_type); return; } @@ -331,8 +432,15 @@ tf_call_stream_try_adding_fsstream (TfCallStream *self) g_value_array_free (fs_relay_info); } + if (self->receiving_state == TP_STREAM_FLOW_STATE_PENDING_START) + { + tf_call_stream_start_receiving (self, FS_DIRECTION_NONE); + dir = FS_DIRECTION_RECV; + } + self->fsstream = _tf_call_content_get_fsstream_by_handle (self->call_content, self->contact_handle, + dir, transmitter, n_params, params, @@ -343,22 +451,21 @@ tf_call_stream_try_adding_fsstream (TfCallStream *self) if (!self->fsstream) { - tf_content_error (TF_CONTENT (self->call_content), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, - "", + tf_call_stream_fail (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_MEDIA_STREAMING_ERROR, "Could not create FsStream: %s", error->message); g_clear_error (&error); return; } - if (self->local_sending_state == TF_FUTURE_SENDING_STATE_PENDING_SEND || - self->local_sending_state == TF_FUTURE_SENDING_STATE_SENDING) - local_sending_state_changed (self->proxy, self->local_sending_state, - NULL, (GObject *) self); + if (self->sending_state == TP_STREAM_FLOW_STATE_PENDING_START) + sending_state_changed (self->proxy, + self->sending_state, NULL, (GObject *) self); } static void -server_info_retrieved (TfFutureCallStream *proxy, +server_info_retrieved (TpCallStream *proxy, gpointer user_data, GObject *weak_object) { TfCallStream *self = TF_CALL_STREAM (weak_object); @@ -369,7 +476,7 @@ server_info_retrieved (TfFutureCallStream *proxy, } static void -relay_info_changed (TfFutureCallStream *proxy, +relay_info_changed (TpCallStream *proxy, const GPtrArray *arg_Relay_Info, gpointer user_data, GObject *weak_object) { @@ -377,9 +484,9 @@ relay_info_changed (TfFutureCallStream *proxy, if (self->server_info_retrieved) { - tf_content_error_literal (TF_CONTENT (self->call_content), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, - "org.freedesktop.Telepathy.Error.NotImplemented", + tf_call_stream_fail_literal (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_NOT_IMPLEMENTED, "Changing relay servers after ServerInfoRetrived is not implemented"); return; } @@ -394,7 +501,7 @@ relay_info_changed (TfFutureCallStream *proxy, } static void -stun_servers_changed (TfFutureCallStream *proxy, +stun_servers_changed (TpCallStream *proxy, const GPtrArray *arg_Servers, gpointer user_data, GObject *weak_object) { @@ -402,9 +509,9 @@ stun_servers_changed (TfFutureCallStream *proxy, if (self->server_info_retrieved) { - tf_content_error_literal (TF_CONTENT (self->call_content), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, - "org.freedesktop.Telepathy.Error.NotImplemented", + tf_call_stream_fail_literal (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_NOT_IMPLEMENTED, "Changing STUN servers after ServerInfoRetrived is not implemented"); return; } @@ -418,6 +525,46 @@ stun_servers_changed (TfFutureCallStream *proxy, arg_Servers); } +static FsCandidateType +tpcandidate_type_to_fs (TpCallStreamCandidateType type) +{ + switch(type) + { + case TP_CALL_STREAM_CANDIDATE_TYPE_NONE: + g_warning ("Candidate type NONE, assigning to HOST"); + /* fallthrough */ + case TP_CALL_STREAM_CANDIDATE_TYPE_HOST: + return FS_CANDIDATE_TYPE_HOST; + case TP_CALL_STREAM_CANDIDATE_TYPE_SERVER_REFLEXIVE: + return FS_CANDIDATE_TYPE_SRFLX; + case TP_CALL_STREAM_CANDIDATE_TYPE_PEER_REFLEXIVE: + return FS_CANDIDATE_TYPE_PRFLX; + case TP_CALL_STREAM_CANDIDATE_TYPE_RELAY: + return FS_CANDIDATE_TYPE_RELAY; + case TP_CALL_STREAM_CANDIDATE_TYPE_MULTICAST: + return FS_CANDIDATE_TYPE_MULTICAST; + default: + g_warning ("Candidate type %d unknown, assigning to HOST", type); + return FS_CANDIDATE_TYPE_HOST; + } +} + +static FsNetworkProtocol +tpnetworkproto_to_fs (TpMediaStreamBaseProto proto) +{ + switch(proto) + { + case TP_MEDIA_STREAM_BASE_PROTO_UDP: + return FS_NETWORK_PROTOCOL_UDP; + case TP_MEDIA_STREAM_BASE_PROTO_TCP: + return FS_NETWORK_PROTOCOL_TCP; + default: + g_debug ("Network protocol %d unknown, assigning to UDP", proto); + return FS_NETWORK_PROTOCOL_UDP; + } +} + + static void tf_call_stream_add_remote_candidates (TfCallStream *self, const GPtrArray *candidates) @@ -444,30 +591,61 @@ tf_call_stream_add_remote_candidates (TfCallStream *self, const gchar *password; gboolean valid; FsCandidate *cand; + guint type; + guint protocol; + guint ttl; + const gchar *base_ip; + guint base_port; tp_value_array_unpack (tpcandidate, 4, &component, &ip, &port, &extra_info); - foundation = tp_asv_get_string (extra_info, "Foundation"); + foundation = tp_asv_get_string (extra_info, "foundation"); if (!foundation) foundation = ""; - priority = tp_asv_get_uint32 (extra_info, "Priority", &valid); + priority = tp_asv_get_uint32 (extra_info, "priority", &valid); if (!valid) priority = 0; - username = tp_asv_get_string (extra_info, "Username"); + username = tp_asv_get_string (extra_info, "username"); if (!username) username = self->creds_username; - password = tp_asv_get_string (extra_info, "Password"); + password = tp_asv_get_string (extra_info, "password"); if (!password) password = self->creds_password; - cand = fs_candidate_new (foundation, component, FS_CANDIDATE_TYPE_HOST, - FS_NETWORK_PROTOCOL_UDP, ip, port); + type = tp_asv_get_uint32 (extra_info, "type", &valid); + if (!valid) + type = TP_CALL_STREAM_CANDIDATE_TYPE_HOST; + + protocol = tp_asv_get_uint32 (extra_info, "protocol", &valid); + if (!valid) + protocol = TP_MEDIA_STREAM_BASE_PROTO_UDP; + + base_ip = tp_asv_get_string (extra_info, "base-ip"); + base_port = tp_asv_get_uint32 (extra_info, "base-port", &valid); + if (!valid) + base_port = 0; + + + ttl = tp_asv_get_uint32 (extra_info, "ttl", &valid); + if (!valid) + ttl = 0; + + g_debug ("Remote Candidate: %s c:%d tptype:%d tpproto: %d ip:%s port:%u prio:%d u/p:%s/%s ttl:%d base_ip:%s base_port:%d", + foundation, component, type, protocol, ip, port, priority, + username, password, ttl, base_ip, base_port); + + cand = fs_candidate_new (foundation, component, + tpcandidate_type_to_fs (type), tpnetworkproto_to_fs (protocol), + ip, port); cand->priority = priority; cand->username = g_strdup (username); cand->password = g_strdup (password); + cand->ttl = ttl; + cand->base_ip = base_ip; + cand->base_port = base_port; fscandidates = g_list_append (fscandidates, cand); } @@ -479,15 +657,15 @@ tf_call_stream_add_remote_candidates (TfCallStream *self, switch (self->transport_type) { - case TF_FUTURE_STREAM_TRANSPORT_TYPE_RAW_UDP: - case TF_FUTURE_STREAM_TRANSPORT_TYPE_SHM: - case TF_FUTURE_STREAM_TRANSPORT_TYPE_MULTICAST: + case TP_STREAM_TRANSPORT_TYPE_RAW_UDP: + case TP_STREAM_TRANSPORT_TYPE_SHM: + case TP_STREAM_TRANSPORT_TYPE_MULTICAST: ret = fs_stream_force_remote_candidates (self->fsstream, fscandidates, &error); break; - case TF_FUTURE_STREAM_TRANSPORT_TYPE_ICE: - case TF_FUTURE_STREAM_TRANSPORT_TYPE_GTALK_P2P: - case TF_FUTURE_STREAM_TRANSPORT_TYPE_WLM_2009: + case TP_STREAM_TRANSPORT_TYPE_ICE: + case TP_STREAM_TRANSPORT_TYPE_GTALK_P2P: + case TP_STREAM_TRANSPORT_TYPE_WLM_2009: ret = fs_stream_add_remote_candidates (self->fsstream, fscandidates, &error); break; @@ -497,8 +675,9 @@ tf_call_stream_add_remote_candidates (TfCallStream *self, if (!ret) { - tf_content_error (TF_CONTENT (self->call_content), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, "", + tf_call_stream_fail (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_MEDIA_STREAMING_ERROR, "Error setting the remote candidates: %s", error->message); g_clear_error (&error); } @@ -518,6 +697,9 @@ remote_candidates_added (TpProxy *proxy, { TfCallStream *self = TF_CALL_STREAM (weak_object); + if (!self->has_endpoint_properties) + return; + tf_call_stream_add_remote_candidates (self, arg_Candidates); } @@ -532,6 +714,8 @@ remote_credentials_set (TpProxy *proxy, if ((self->creds_username && strcmp (self->creds_username, arg_Username)) || (self->creds_password && strcmp (self->creds_password, arg_Password))) { + g_debug ("Remote credentials changed," + " remote is doing an ICE restart"); /* Remote credentials changed, this will perform a ICE restart, so * clear old remote candidates */ fs_candidate_list_destroy (self->stored_remote_candidates); @@ -542,6 +726,8 @@ remote_credentials_set (TpProxy *proxy, g_free (self->creds_password); self->creds_username = g_strdup (arg_Username); self->creds_password = g_strdup (arg_Password); + + g_debug ("Credentials set: %s / %s", arg_Username, arg_Password); } @@ -553,45 +739,79 @@ got_endpoint_properties (TpProxy *proxy, GHashTable *out_Properties, GValueArray *credentials; gchar *username, *password; GPtrArray *candidates; + gboolean valid = FALSE; + guint transport_type; if (error) { - tf_content_error (TF_CONTENT (self->call_content), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, "", + tf_call_stream_fail (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_CONFUSED, "Error getting the Streams's media properties: %s", error->message); return; } if (!out_Properties) { - tf_content_error_literal (TF_CONTENT (self->call_content), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, "", + tf_call_stream_fail_literal (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_CONFUSED, "Error getting the Stream's media properties: there are none"); return; } + g_debug ("Got Endpoint Properties"); + credentials = tp_asv_get_boxed (out_Properties, "RemoteCredentials", - TF_FUTURE_STRUCT_TYPE_STREAM_CREDENTIALS); + TP_STRUCT_TYPE_STREAM_CREDENTIALS); if (!credentials) goto invalid_property; tp_value_array_unpack (credentials, 2, &username, &password); - self->creds_username = g_strdup (username); - self->creds_password = g_strdup (password); + if (username && username[0]) + self->creds_username = g_strdup (username); + if (password && password[0]) + self->creds_password = g_strdup (password); + + if (self->creds_username || self->creds_password) + g_debug ("Credentials set: %s / %s", username, password); candidates = tp_asv_get_boxed (out_Properties, "RemoteCandidates", - TF_FUTURE_ARRAY_TYPE_CANDIDATE_LIST); + TP_ARRAY_TYPE_CANDIDATE_LIST); if (!candidates) goto invalid_property; + transport_type = tp_asv_get_uint32 (out_Properties, "Transport", &valid); + if (!valid) + { + g_warning ("No valid transport"); + goto invalid_property; + } + + if (transport_type != self->transport_type) + { + if (transport_type != TP_STREAM_TRANSPORT_TYPE_RAW_UDP) + { + tf_call_stream_fail (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_INVALID_ARGUMENT, + "The Transport of a Endpoint can only be changed to rawudp: %d invalid", transport_type); + return; + } + self->transport_type = transport_type; + } + + self->has_endpoint_properties = TRUE; + tf_call_stream_add_remote_candidates (self, candidates); return; invalid_property: - tf_content_error_literal (TF_CONTENT (self->call_content), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, "", + tf_call_stream_fail_literal (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_CONFUSED, "Error getting the Endpoint's properties: invalid type"); } @@ -600,48 +820,51 @@ tf_call_stream_add_endpoint (TfCallStream *self) { GError *error = NULL; + tp_call_stream_endpoint_init_known_interfaces (); self->endpoint = g_object_new (TP_TYPE_PROXY, "dbus-daemon", tp_proxy_get_dbus_daemon (self->proxy), "bus-name", tp_proxy_get_bus_name (self->proxy), "object-path", self->endpoint_objpath, NULL); tp_proxy_add_interface_by_id (TP_PROXY (self->endpoint), - TF_FUTURE_IFACE_QUARK_CALL_STREAM_ENDPOINT); + TP_IFACE_QUARK_CALL_STREAM_ENDPOINT); - tf_future_cli_call_stream_endpoint_connect_to_remote_credentials_set ( + tp_cli_call_stream_endpoint_connect_to_remote_credentials_set ( TP_PROXY (self->endpoint), remote_credentials_set, NULL, NULL, G_OBJECT (self), &error); if (error) { - tf_content_error (TF_CONTENT (self->call_content), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, "", - "Error connectiong to RemoteCredentialsSet signal: %s", + tf_call_stream_fail (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_CONFUSED, + "Error connecting to RemoteCredentialsSet signal: %s", error->message); g_clear_error (&error); return; } - tf_future_cli_call_stream_endpoint_connect_to_remote_candidates_added ( + tp_cli_call_stream_endpoint_connect_to_remote_candidates_added ( TP_PROXY (self->endpoint), remote_candidates_added, NULL, NULL, G_OBJECT (self), &error); if (error) { - tf_content_error (TF_CONTENT (self->call_content), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, "", - "Error connectiong to RemoteCandidatesAdded signal: %s", + tf_call_stream_fail (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_CONFUSED, + "Error connecting to RemoteCandidatesAdded signal: %s", error->message); g_clear_error (&error); return; } tp_cli_dbus_properties_call_get_all (self->endpoint, -1, - TF_FUTURE_IFACE_CALL_STREAM_ENDPOINT, + TP_IFACE_CALL_STREAM_ENDPOINT, got_endpoint_properties, NULL, NULL, G_OBJECT (self)); } static void -endpoints_changed (TfFutureCallStream *proxy, +endpoints_changed (TpCallStream *proxy, const GPtrArray *arg_Endpoints_Added, const GPtrArray *arg_Endpoints_Removed, gpointer user_data, GObject *weak_object) @@ -654,18 +877,18 @@ endpoints_changed (TfFutureCallStream *proxy, if (arg_Endpoints_Removed->len != 0) { - tf_content_error_literal (TF_CONTENT (self->call_content), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, - "org.freedesktop.Telepathy.Error.NotImplemented", + tf_call_stream_fail_literal (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_NOT_IMPLEMENTED, "Removing Endpoints is not implemented"); return; } if (arg_Endpoints_Added->len != 1) { - tf_content_error_literal (TF_CONTENT (self->call_content), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, - "org.freedesktop.Telepathy.Error.NotImplemented", + tf_call_stream_fail_literal (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_NOT_IMPLEMENTED, "Having more than one endpoint is not implemented"); return; } @@ -674,9 +897,10 @@ endpoints_changed (TfFutureCallStream *proxy, { if (strcmp (g_ptr_array_index (arg_Endpoints_Added, 0), self->endpoint_objpath)) - tf_content_error_literal (TF_CONTENT (self->call_content), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, "", - "Trying to give a different endpoint, CM bug"); + tf_call_stream_fail_literal (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_NOT_IMPLEMENTED, + "Having more than one endpoint is not implemented"); return; } @@ -698,8 +922,9 @@ got_stream_media_properties (TpProxy *proxy, GHashTable *out_Properties, if (error) { - tf_content_error (TF_CONTENT (self->call_content), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, "", + tf_call_stream_fail (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_CONFUSED, "Error getting the Streams's media properties: %s", error->message); return; @@ -707,8 +932,9 @@ got_stream_media_properties (TpProxy *proxy, GHashTable *out_Properties, if (!out_Properties) { - tf_content_error_literal (TF_CONTENT (self->call_content), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, "", + tf_call_stream_fail_literal (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_INVALID_ARGUMENT, "Error getting the Stream's media properties: there are none"); return; } @@ -745,7 +971,31 @@ got_stream_media_properties (TpProxy *proxy, GHashTable *out_Properties, goto invalid_property; } + self->sending_state = tp_asv_get_uint32 (out_Properties, "SendingState", + &valid); + if (!valid) + { + g_warning ("No valid sending state"); + goto invalid_property; + } + + self->receiving_state = tp_asv_get_uint32 (out_Properties, + "ReceivingState", &valid); + if (!valid) + { + g_warning ("No valid receiving state"); + goto invalid_property; + } +/* FIXME: controlling is on the endpoint + self->controlling = tp_asv_get_boolean (out_Properties, + "Controlling", &valid); + if (!valid) + { + g_warning ("No Controlling property"); + goto invalid_property; + } +*/ self->stun_servers = g_boxed_copy (TP_ARRAY_TYPE_SOCKET_ADDRESS_IP_LIST, stun_servers); self->relay_info = g_boxed_copy (TP_ARRAY_TYPE_STRING_VARIANT_MAP_LIST, @@ -756,9 +1006,9 @@ got_stream_media_properties (TpProxy *proxy, GHashTable *out_Properties, if (endpoints->len > 1) { - tf_content_error_literal (TF_CONTENT (self->call_content), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, - "org.freedesktop.Telepathy.Error.NotImplemented", + tf_call_stream_fail_literal (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_NOT_IMPLEMENTED, "Having more than one endpoint is not implemented"); return; } @@ -775,223 +1025,313 @@ got_stream_media_properties (TpProxy *proxy, GHashTable *out_Properties, return; invalid_property: - tf_content_error_literal (TF_CONTENT (self->call_content), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, "", + tf_call_stream_fail_literal (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_INVALID_ARGUMENT, "Error getting the Stream's properties: invalid type"); return; } - static void -got_stream_properties (TpProxy *proxy, GHashTable *out_Properties, - const GError *error, gpointer user_data, GObject *weak_object) +ice_restart_requested (TpCallStream *proxy, + gpointer user_data, GObject *weak_object) { TfCallStream *self = TF_CALL_STREAM (weak_object); - gboolean valid; GError *myerror = NULL; - guint i; - const gchar * const * interfaces; - gboolean got_media_interface = FALSE; - guint32 local_sending_state; - GHashTable *members; - GHashTableIter iter; - gpointer key, value; - if (error) + if (!self->fsstream) + return; + + if (self->multiple_usernames) { - tf_content_error (TF_CONTENT (self->call_content), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, "", - "Error getting the Streams's properties: %s", error->message); + tf_call_stream_fail_literal (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_INVALID_ARGUMENT, + "CM tried to ICE restart an ICE-6 or Google compatible connection"); return; } - if (!out_Properties) + g_debug ("Restarting ICE"); + + if (fs_stream_add_remote_candidates (self->fsstream, NULL, &myerror)) { - tf_content_error_literal (TF_CONTENT (self->call_content), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, "", - "Error getting the Content's properties: there are none"); - return; + g_free (self->last_local_username); + g_free (self->last_local_password); + self->last_local_username = NULL; + self->last_local_password = NULL; } + else + { + tf_call_stream_fail (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_MEDIA_STREAMING_ERROR, + "Error restarting the ICE process: %s", myerror->message); + g_clear_error (&myerror); + } +} - interfaces = tp_asv_get_strv (out_Properties, "Interfaces"); - - for (i = 0; interfaces[i]; i++) - if (!strcmp (interfaces[i], TF_FUTURE_IFACE_CALL_STREAM_INTERFACE_MEDIA)) - { - got_media_interface = TRUE; - break; - } +static void +stream_prepared (GObject *src_object, GAsyncResult *res, gpointer user_data) +{ + TfCallStream *self = TF_CALL_STREAM (user_data); + TpProxy *proxy = TP_PROXY (src_object); + GError *error = NULL; + GHashTable *members; + GHashTableIter iter; + gpointer key, value; - if (!got_media_interface) + if (!tp_proxy_prepare_finish (src_object, res, &error)) { - tf_content_error_literal (TF_CONTENT (self->call_content), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, "", - "Stream does not have the media interface," - " but HardwareStreaming was NOT true"); + tf_call_stream_fail (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_CONFUSED, + "Error preparing the stream Streams: %s", error->message); + g_clear_error (&error); return; } - members = tp_asv_get_boxed (out_Properties, "RemoteMembers", - TF_FUTURE_HASH_TYPE_CONTACT_SENDING_STATE_MAP); - if (!members) - goto invalid_property; + if (!tp_proxy_has_interface_by_id (proxy, + TP_IFACE_QUARK_CALL_STREAM_INTERFACE_MEDIA)) + { + tf_call_stream_fail_literal (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_INVALID_ARGUMENT, + "Stream does not have the media interface," + " but HardwareStreaming was NOT true"); + return; + } - local_sending_state = tp_asv_get_uint32 (out_Properties, "LocalSendingState", - &valid); - if (!valid) - goto invalid_property; + members = tp_call_stream_get_remote_members (self->proxy); - self->local_sending_state = local_sending_state; + if (g_hash_table_size (members) != 1) + { + tf_call_stream_fail (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_NOT_IMPLEMENTED, + "Only one Member per Stream is supported, there are %d", + g_hash_table_size (members)); + return; + } - if (g_hash_table_size (members) != 1) + g_hash_table_iter_init (&iter, members); + if (g_hash_table_iter_next (&iter, &key, &value)) { - tf_content_error (TF_CONTENT (self->call_content), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, - "org.freedesktop.Telepathy.Error.NotImplemented", - "Only one Member per Stream is supported, there are %d", - g_hash_table_size (members)); + self->has_contact = TRUE; + self->contact_handle = tp_contact_get_handle (key); + } + + tp_cli_call_stream_interface_media_connect_to_sending_state_changed ( + TP_CALL_STREAM (proxy), sending_state_changed, NULL, NULL, + G_OBJECT (self), &error); + if (error) + { + tf_call_stream_fail (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, "", + "Error connecting to SendingStateChanged signal: %s", + error->message); + g_clear_error (&error); return; } - g_hash_table_iter_init (&iter, members); - if (g_hash_table_iter_next (&iter, &key, &value)) + tp_cli_call_stream_interface_media_connect_to_receiving_state_changed ( + TP_CALL_STREAM (proxy), receiving_state_changed, NULL, NULL, + G_OBJECT (self), &error); + if (error) { - self->has_contact = TRUE; - self->contact_handle = GPOINTER_TO_UINT (key); + tf_call_stream_fail (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, "", + "Error connecting to ReceivingStateChanged signal: %s", + error->message); + g_clear_error (&error); + return; } - tp_proxy_add_interface_by_id (TP_PROXY (self->proxy), - TF_FUTURE_IFACE_QUARK_CALL_STREAM_INTERFACE_MEDIA); + tp_cli_call_stream_interface_media_connect_to_server_info_retrieved ( + TP_CALL_STREAM (proxy), server_info_retrieved, NULL, NULL, + G_OBJECT (self), &error); + if (error) + { + tf_call_stream_fail (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, "", + "Error connecting to ServerInfoRetrived signal: %s", + error->message); + g_clear_error (&error); + return; + } - tf_future_cli_call_stream_interface_media_connect_to_server_info_retrieved ( - TF_FUTURE_CALL_STREAM (proxy), server_info_retrieved, NULL, NULL, - G_OBJECT (self), &myerror); - if (myerror) + tp_cli_call_stream_interface_media_connect_to_stun_servers_changed ( + TP_CALL_STREAM (proxy), stun_servers_changed, NULL, NULL, + G_OBJECT (self), &error); + if (error) { - tf_content_error (TF_CONTENT (self->call_content), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, "", - "Error connectiong to ServerInfoRetrived signal: %s", - myerror->message); - g_clear_error (&myerror); + tf_call_stream_fail (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, "", + "Error connecting to ServerInfoRetrived signal: %s", + error->message); + g_clear_error (&error); return; } - tf_future_cli_call_stream_interface_media_connect_to_stun_servers_changed ( - TF_FUTURE_CALL_STREAM (proxy), stun_servers_changed, NULL, NULL, - G_OBJECT (self), &myerror); - if (myerror) + + tp_cli_call_stream_interface_media_connect_to_relay_info_changed ( + TP_CALL_STREAM (proxy), relay_info_changed, NULL, NULL, + G_OBJECT (self), &error); + if (error) { - tf_content_error (TF_CONTENT (self->call_content), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, "", - "Error connectiong to ServerInfoRetrived signal: %s", - myerror->message); - g_clear_error (&myerror); + tf_call_stream_fail (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, "", + "Error connecting to ServerInfoRetrived signal: %s", + error->message); + g_clear_error (&error); return; } - tf_future_cli_call_stream_interface_media_connect_to_relay_info_changed ( - TF_FUTURE_CALL_STREAM (proxy), relay_info_changed, NULL, NULL, - G_OBJECT (self), &myerror); - if (myerror) + tp_cli_call_stream_interface_media_connect_to_endpoints_changed ( + TP_CALL_STREAM (proxy), endpoints_changed, NULL, NULL, + G_OBJECT (self), &error); + if (error) { - tf_content_error (TF_CONTENT (self->call_content), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, "", - "Error connectiong to ServerInfoRetrived signal: %s", - myerror->message); - g_clear_error (&myerror); + tf_call_stream_fail (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, "", + "Error connecting to EndpointsChanged signal: %s", + error->message); + g_clear_error (&error); return; } - tf_future_cli_call_stream_interface_media_connect_to_endpoints_changed ( - TF_FUTURE_CALL_STREAM (proxy), endpoints_changed, NULL, NULL, - G_OBJECT (self), &myerror); - if (myerror) + tp_cli_call_stream_interface_media_connect_to_ice_restart_requested ( + TP_CALL_STREAM (proxy), ice_restart_requested, NULL, NULL, + G_OBJECT (self), &error); + if (error) { - tf_content_error (TF_CONTENT (self->call_content), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, "", - "Error connectiong to EndpointsChanged signal: %s", - myerror->message); - g_clear_error (&myerror); + tf_call_stream_fail (self, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, "", + "Error connecting to ICERestartRequested signal: %s", + error->message); + g_clear_error (&error); return; } - tp_cli_dbus_properties_call_get_all (proxy, -1, - TF_FUTURE_IFACE_CALL_STREAM_INTERFACE_MEDIA, + tp_cli_dbus_properties_call_get_all (TP_PROXY (self->proxy), -1, + TP_IFACE_CALL_STREAM_INTERFACE_MEDIA, got_stream_media_properties, NULL, NULL, G_OBJECT (self)); return; - - invalid_property: - tf_content_error_literal (TF_CONTENT (self->call_content), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, "", - "Error getting the Stream's properties: invalid type"); - return; } TfCallStream * -tf_call_stream_new (TfCallChannel *call_channel, - TfCallContent *call_content, - const gchar *object_path, - GError **error) +tf_call_stream_new (TfCallContent *call_content, + TpCallStream *stream_proxy) { TfCallStream *self; - TfFutureCallStream *proxy = tf_future_call_stream_new (call_channel->proxy, - object_path, error); - GError *myerror = NULL; - if (!proxy) - return NULL; + g_assert (call_content != NULL); + g_assert (stream_proxy != NULL); - self = g_object_new (TF_TYPE_STREAM, NULL); + self = g_object_new (TF_TYPE_CALL_STREAM, NULL); self->call_content = call_content; - self->proxy = proxy; + self->proxy = g_object_ref (stream_proxy); - tf_future_cli_call_stream_connect_to_local_sending_state_changed ( - TF_FUTURE_CALL_STREAM (proxy), local_sending_state_changed, NULL, NULL, - G_OBJECT (self), &myerror); - if (myerror) + tp_proxy_prepare_async (self->proxy, NULL, stream_prepared, + g_object_ref (self)); + + return self; +} + +static TpCallStreamCandidateType +fscandidatetype_to_tp (FsCandidateType type) +{ + switch(type) { - tf_content_error (TF_CONTENT (self->call_content), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, "", - "Error connectiong to LocalSendingStateChanged signal: %s", - myerror->message); - g_object_unref (self); - g_propagate_error (error, myerror); - return NULL; + case FS_CANDIDATE_TYPE_HOST: + return TP_CALL_STREAM_CANDIDATE_TYPE_HOST; + case FS_CANDIDATE_TYPE_SRFLX: + return TP_CALL_STREAM_CANDIDATE_TYPE_SERVER_REFLEXIVE; + case FS_CANDIDATE_TYPE_PRFLX: + return TP_CALL_STREAM_CANDIDATE_TYPE_PEER_REFLEXIVE; + case FS_CANDIDATE_TYPE_RELAY: + return TP_CALL_STREAM_CANDIDATE_TYPE_RELAY; + case FS_CANDIDATE_TYPE_MULTICAST: + return TP_CALL_STREAM_CANDIDATE_TYPE_MULTICAST; + default: + g_warning ("Unkown candidate type, assigning type NONE"); + return TP_CALL_STREAM_CANDIDATE_TYPE_NONE; } +} - tp_cli_dbus_properties_call_get_all (proxy, -1, TF_FUTURE_IFACE_CALL_STREAM, - got_stream_properties, NULL, NULL, G_OBJECT (self)); - return self; +static TpMediaStreamBaseProto +fs_network_proto_to_tp (FsNetworkProtocol proto) +{ + switch (proto) + { + case FS_NETWORK_PROTOCOL_UDP: + return TP_MEDIA_STREAM_BASE_PROTO_UDP; + case FS_NETWORK_PROTOCOL_TCP: + return TP_MEDIA_STREAM_BASE_PROTO_TCP; + default: + g_warning ("Invalid protocl, assigning to UDP"); + return TP_MEDIA_STREAM_BASE_PROTO_UDP; + } } -static void -cb_fs_new_local_candidate (TfCallStream *stream, FsCandidate *candidate) + +static GValueArray * +fscandidate_to_tpcandidate (TfCallStream *stream, FsCandidate *candidate) { - GPtrArray *candidate_list = g_ptr_array_sized_new (1); - GValueArray *gva; GHashTable *extra_info; extra_info = tp_asv_new (NULL, NULL); - if (candidate->priority) - tp_asv_set_uint32 (extra_info, "Priority", candidate->priority); + + tp_asv_set_uint32 (extra_info, "type", + fscandidatetype_to_tp (candidate->type)); if (candidate->foundation) - tp_asv_set_string (extra_info, "Foundation", candidate->foundation); + tp_asv_set_string (extra_info, "foundation", candidate->foundation); + + tp_asv_set_uint32 (extra_info, "protocol", + fs_network_proto_to_tp (candidate->proto)); + + if (candidate->base_ip) + { + tp_asv_set_string (extra_info, "base-ip", candidate->base_ip); + tp_asv_set_uint32 (extra_info, "base-port", candidate->base_port); + } + + if (candidate->priority) + tp_asv_set_uint32 (extra_info, "priority", candidate->priority); + + + if (candidate->type == FS_CANDIDATE_TYPE_MULTICAST) + tp_asv_set_uint32 (extra_info, "ttl", candidate->ttl); if (stream->multiple_usernames) { if (candidate->username) - tp_asv_set_string (extra_info, "Username", candidate->username); + tp_asv_set_string (extra_info, "username", candidate->username); if (candidate->password) - tp_asv_set_string (extra_info, "Password", candidate->password); + tp_asv_set_string (extra_info, "password", candidate->password); } - else + + + return tp_value_array_build (4, + G_TYPE_UINT, candidate->component_id, + G_TYPE_STRING, candidate->ip, + G_TYPE_UINT, candidate->port, + TP_HASH_TYPE_CANDIDATE_INFO, extra_info, + G_TYPE_INVALID); +} + +static void +cb_fs_new_local_candidate (TfCallStream *stream, FsCandidate *candidate) +{ + GPtrArray *candidate_list = g_ptr_array_sized_new (1); + + if (!stream->multiple_usernames) { if ((!stream->last_local_username && candidate->username) || (!stream->last_local_password && candidate->password) || @@ -1011,36 +1351,38 @@ cb_fs_new_local_candidate (TfCallStream *stream, FsCandidate *candidate) stream->last_local_password = g_strdup (""); /* Add a callback to kill Call on errors */ - tf_future_cli_call_stream_interface_media_call_set_credentials ( + tp_cli_call_stream_interface_media_call_set_credentials ( stream->proxy, -1, stream->last_local_username, stream->last_local_password, NULL, NULL, NULL, NULL); } } - gva = tp_value_array_build (4, - G_TYPE_UINT, candidate->component_id, - G_TYPE_STRING, candidate->ip, - G_TYPE_UINT, candidate->port, - TF_FUTURE_HASH_TYPE_CANDIDATE_INFO, extra_info, - G_TYPE_INVALID); + g_debug ("Local Candidate: %s c:%d fstype:%d fsproto: %d ip:%s port:%u prio:%d u/p:%s/%s ttl:%d base_ip:%s base_port:%d", + candidate->foundation,candidate->component_id, candidate->type, + candidate->proto, candidate->ip, candidate->port, + candidate->priority, candidate->username, candidate->password, + candidate->ttl,candidate-> base_ip, candidate->base_port); + - g_ptr_array_add (candidate_list, gva); + g_ptr_array_add (candidate_list, + fscandidate_to_tpcandidate (stream, candidate)); /* Should also check for errors */ - tf_future_cli_call_stream_interface_media_call_add_candidates (stream->proxy, + tp_cli_call_stream_interface_media_call_add_candidates (stream->proxy, -1, candidate_list, NULL, NULL, NULL, NULL); - g_boxed_free (TF_FUTURE_ARRAY_TYPE_CANDIDATE_LIST, candidate_list); + g_boxed_free (TP_ARRAY_TYPE_CANDIDATE_LIST, candidate_list); } static void cb_fs_local_candidates_prepared (TfCallStream *stream) { - tf_future_cli_call_stream_interface_media_call_candidates_prepared ( - stream->proxy, -1, NULL, NULL, NULL, NULL); + g_debug ("Local candidates prepared"); + tp_cli_call_stream_interface_media_call_finish_initial_candidates ( + stream->proxy, -1, NULL, NULL, NULL, NULL); } static void @@ -1054,102 +1396,103 @@ cb_fs_component_state_changed (TfCallStream *stream, guint component, switch (fsstate) { + default: + g_warning ("Unknown Farstream state, returning ExhaustedCandidates"); + /* fall through */ case FS_STREAM_STATE_FAILED: - case FS_STREAM_STATE_DISCONNECTED: - state = TP_MEDIA_STREAM_STATE_DISCONNECTED; + state = TP_STREAM_ENDPOINT_STATE_EXHAUSTED_CANDIDATES; break; + case FS_STREAM_STATE_DISCONNECTED: case FS_STREAM_STATE_GATHERING: case FS_STREAM_STATE_CONNECTING: - case FS_STREAM_STATE_CONNECTED: - state = TP_MEDIA_STREAM_STATE_CONNECTING; + state = TP_STREAM_ENDPOINT_STATE_CONNECTING; break; + case FS_STREAM_STATE_CONNECTED: + state = TP_STREAM_ENDPOINT_STATE_PROVISIONALLY_CONNECTED; case FS_STREAM_STATE_READY: - default: - state = TP_MEDIA_STREAM_STATE_CONNECTED; + state = TP_STREAM_ENDPOINT_STATE_FULLY_CONNECTED; break; } - tf_future_cli_call_stream_endpoint_call_set_stream_state (stream->endpoint, - -1, state, NULL, NULL, NULL, NULL); + g_debug ("Endpoint state changed to %d (fs: %d)", + state, fsstate); + + tp_cli_call_stream_endpoint_call_set_endpoint_state (stream->endpoint, + -1, component, state, NULL, NULL, NULL, NULL); } +static void +cb_fs_new_active_candidate_pair (TfCallStream *stream, + FsCandidate *local_candidate, + FsCandidate *remote_candidate) +{ + GValueArray *local_tp_candidate = + fscandidate_to_tpcandidate (stream, local_candidate); + GValueArray *remote_tp_candidate = + fscandidate_to_tpcandidate (stream, remote_candidate); + + g_debug ("new active candidate pair local: %s (%d) remote: %s (%d)", + local_candidate->ip, local_candidate->port, + remote_candidate->ip, remote_candidate->port); + + tp_cli_call_stream_endpoint_call_set_selected_candidate_pair ( + stream->endpoint, -1, local_tp_candidate, remote_tp_candidate, + NULL, NULL, NULL, NULL); + + g_boxed_free (TP_STRUCT_TYPE_CANDIDATE, local_tp_candidate); + g_boxed_free (TP_STRUCT_TYPE_CANDIDATE, remote_tp_candidate); +} gboolean tf_call_stream_bus_message (TfCallStream *stream, GstMessage *message) { - const GstStructure *s; - const GValue *val; + FsError errorno; + const gchar *msg; + FsCandidate *candidate; + guint component; + FsStreamState fsstate; + FsCandidate *local_candidate; + FsCandidate *remote_candidate; if (!stream->fsstream) return FALSE; - s = gst_message_get_structure (message); - - if (gst_structure_has_name (s, "farstream-error")) + if (fs_parse_error (G_OBJECT (stream->fsstream), message, &errorno, &msg)) { - GObject *object; - const gchar *msg; - FsError errorno; GEnumClass *enumclass; GEnumValue *enumvalue; - const gchar *debug; - - val = gst_structure_get_value (s, "src-object"); - object = g_value_get_object (val); - - if (object != (GObject*) stream->fsstream) - return FALSE; - - val = gst_structure_get_value (s, "error-no"); - errorno = g_value_get_enum (val); - msg = gst_structure_get_string (s, "error-msg"); - debug = gst_structure_get_string (s, "debug-msg"); enumclass = g_type_class_ref (FS_TYPE_ERROR); enumvalue = g_enum_get_value (enumclass, errorno); - g_warning ("error (%s (%d)): %s : %s", - enumvalue->value_nick, errorno, msg, debug); + g_warning ("error (%s (%d)): %s", + enumvalue->value_nick, errorno, msg); g_type_class_unref (enumclass); - tf_content_error_literal (TF_CONTENT (stream->call_content), - TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR, "", msg); - return TRUE; + tf_call_stream_fail_literal (stream, + TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_MEDIA_STREAMING_ERROR, msg); } - - val = gst_structure_get_value (s, "stream"); - if (!val) - return FALSE; - if (!G_VALUE_HOLDS_OBJECT (val)) - return FALSE; - if (g_value_get_object (val) != stream->fsstream) - return FALSE; - - if (gst_structure_has_name (s, "farstream-new-local-candidate")) + else if (fs_stream_parse_new_local_candidate (stream->fsstream, message, + &candidate)) { - FsCandidate *candidate; - - val = gst_structure_get_value (s, "candidate"); - candidate = g_value_get_boxed (val); - cb_fs_new_local_candidate (stream, candidate); - return TRUE; } - else if (gst_structure_has_name (s, "farstream-local-candidates-prepared")) + else if (fs_stream_parse_local_candidates_prepared (stream->fsstream, + message)) { cb_fs_local_candidates_prepared (stream); } - else if (gst_structure_has_name (s, "farstream-component-state-changed")) + else if (fs_stream_parse_component_state_changed (stream->fsstream, message, + &component, &fsstate)) { - guint component; - FsStreamState fsstate; - - if (!gst_structure_get_uint (s, "component", &component) || - !gst_structure_get_enum (s, "state", FS_TYPE_STREAM_STATE, - (gint*) &fsstate)) - return TRUE; - cb_fs_component_state_changed (stream, component, fsstate); } + else if (fs_stream_parse_new_active_candidate_pair (stream->fsstream, message, + &local_candidate, &remote_candidate)) + { + cb_fs_new_active_candidate_pair (stream, local_candidate, + remote_candidate); + } else { return FALSE; @@ -1157,3 +1500,85 @@ tf_call_stream_bus_message (TfCallStream *stream, GstMessage *message) return TRUE; } + +static void +tf_call_stream_fail_literal (TfCallStream *self, + TpCallStateChangeReason reason, + const gchar *detailed_reason, + const gchar *message) +{ + g_warning ("%s", message); + tp_cli_call_stream_interface_media_call_fail ( + self->proxy, -1, + tp_value_array_build (4, + G_TYPE_UINT, 0, + G_TYPE_UINT, reason, + G_TYPE_STRING, detailed_reason, + G_TYPE_STRING, message, + G_TYPE_INVALID), + NULL, NULL, NULL, NULL); +} + + +static void +tf_call_stream_fail (TfCallStream *self, + TpCallStateChangeReason reason, + const gchar *detailed_reason, + const gchar *message_format, + ...) +{ + gchar *message; + va_list valist; + + va_start (valist, message_format); + message = g_strdup_vprintf (message_format, valist); + va_end (valist); + + tf_call_stream_fail_literal (self, reason, detailed_reason, message); + g_free (message); +} + +void +tf_call_stream_sending_failed (TfCallStream *self, const gchar *message) +{ + g_warning ("Reporting sending failure: %s", message); + + tp_cli_call_stream_interface_media_call_report_sending_failure ( + self->proxy, -1, TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_MEDIA_STREAMING_ERROR, + message, NULL, NULL, NULL, NULL); +} + + +void +tf_call_stream_receiving_failed (TfCallStream *self, + guint *handles, guint handle_count, + const gchar *message) +{ + if (handle_count && handle_count > 0) + { + guint i; + + for (i = 0; i < handle_count; i++) + if (handles[i] == self->contact_handle) + goto ok; + return; + } + ok: + + g_warning ("Reporting receiving failure: %s", message); + + tp_cli_call_stream_interface_media_call_report_receiving_failure ( + self->proxy, -1, TP_CALL_STATE_CHANGE_REASON_INTERNAL_ERROR, + TP_ERROR_STR_MEDIA_STREAMING_ERROR, + message, NULL, NULL, NULL, NULL); +} + + +TpCallStream * +tf_call_stream_get_proxy (TfCallStream *stream) +{ + g_return_val_if_fail (TF_IS_CALL_STREAM (stream), NULL); + + return stream->proxy; +} diff --git a/telepathy-farstream/call-stream.h b/telepathy-farstream/call-stream.h index dc65184..31961c1 100644 --- a/telepathy-farstream/call-stream.h +++ b/telepathy-farstream/call-stream.h @@ -23,33 +23,32 @@ #include <glib-object.h> #include <gst/gst.h> -#include <telepathy-glib/channel.h> +#include <telepathy-glib/telepathy-glib.h> #include "call-channel.h" #include "call-content.h" -#include "extensions/extensions.h" G_BEGIN_DECLS -#define TF_TYPE_STREAM tf_call_stream_get_type() +#define TF_TYPE_CALL_STREAM tf_call_stream_get_type() #define TF_CALL_STREAM(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ - TF_TYPE_STREAM, TfCallStream)) + TF_TYPE_CALL_STREAM, TfCallStream)) #define TF_CALL_STREAM_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), \ - TF_TYPE_STREAM, TfCallStreamClass)) + TF_TYPE_CALL_STREAM, TfCallStreamClass)) -#define TF_IS_STREAM(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TF_TYPE_STREAM)) +#define TF_IS_CALL_STREAM(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TF_TYPE_CALL_STREAM)) -#define TF_IS_STREAM_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE ((klass), TF_TYPE_STREAM)) +#define TF_IS_CALL_STREAM_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), TF_TYPE_CALL_STREAM)) #define TF_CALL_STREAM_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), \ - TF_TYPE_STREAM, TfCallStreamClass)) + TF_TYPE_CALL_STREAM, TfCallStreamClass)) typedef struct _TfCallStreamPrivate TfCallStreamPrivate; @@ -76,27 +75,32 @@ struct _TfCallStream { TfCallContent *call_content; - TfFutureCallStream *proxy; + TpCallStream *proxy; + gboolean has_endpoint_properties; gchar *endpoint_objpath; TpProxy *endpoint; gchar *creds_username; gchar *creds_password; GList *stored_remote_candidates; gboolean multiple_usernames; + gboolean controlling; gchar *last_local_username; gchar *last_local_password; - TfFutureSendingState local_sending_state; + TpStreamFlowState sending_state; gboolean has_send_resource; + TpStreamFlowState receiving_state; + gboolean has_receive_resource; + gboolean has_contact; guint contact_handle; FsStream *fsstream; gboolean has_media_properties; - TfFutureStreamTransportType transport_type; + TpStreamTransportType transport_type; gboolean server_info_retrieved; GPtrArray *stun_servers; GPtrArray *relay_info; @@ -110,13 +114,21 @@ struct _TfCallStreamClass{ GType tf_call_stream_get_type (void); TfCallStream *tf_call_stream_new ( - TfCallChannel *channel, TfCallContent *content, - const gchar *object_path, - GError **error); + TpCallStream *stream_proxy); gboolean tf_call_stream_bus_message (TfCallStream *stream, GstMessage *message); +void tf_call_stream_sending_failed (TfCallStream *stream, const gchar *message); + +void tf_call_stream_receiving_failed (TfCallStream *stream, + guint *handles, guint handle_count, + const gchar *message); + +TpCallStream * +tf_call_stream_get_proxy (TfCallStream *stream); + + G_END_DECLS #endif /* __TF_CALL_STREAM_H__ */ diff --git a/telepathy-farstream/channel.c b/telepathy-farstream/channel.c index d2f77b0..ac903c1 100644 --- a/telepathy-farstream/channel.c +++ b/telepathy-farstream/channel.c @@ -31,16 +31,10 @@ #include <stdlib.h> -#include <telepathy-glib/channel.h> -#include <telepathy-glib/dbus.h> -#include <telepathy-glib/enums.h> -#include <telepathy-glib/errors.h> -#include <telepathy-glib/interfaces.h> -#include <telepathy-glib/util.h> +#include <telepathy-glib/telepathy-glib.h> #include <farstream/fs-conference.h> -#include "extensions/extensions.h" #include "channel.h" #include "channel-priv.h" @@ -152,8 +146,23 @@ tf_channel_get_property (GObject *object, break; case PROP_FS_CONFERENCES: if (self->priv->call_channel) - g_object_get_property (G_OBJECT (self->priv->call_channel), - "fs-conferences", value); + { + g_object_get_property (G_OBJECT (self->priv->call_channel), + "fs-conferences", value); + } + else if (self->priv->media_signalling_channel && + self->priv->media_signalling_channel->session) + { + GPtrArray *array = + g_ptr_array_new_with_free_func ((GDestroyNotify) gst_object_unref); + FsConference *conf = NULL; + + g_object_get (self->priv->media_signalling_channel->session, + "farstream-conference", &conf, NULL); + g_ptr_array_add (array, conf); + g_value_take_boxed (value, array); + } + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -326,22 +335,34 @@ channel_prepared (GObject *obj, "stream-created", G_CALLBACK (channel_stream_created), self, 0); g_simple_async_result_set_op_res_gboolean (res, TRUE); + g_simple_async_result_complete (res); } else if (tp_proxy_has_interface_by_id (as_proxy, - TF_FUTURE_IFACE_QUARK_CHANNEL_TYPE_CALL)) + TP_IFACE_QUARK_CHANNEL_TYPE_CALL)) { - tf_call_channel_new_async (channel_proxy, call_channel_ready, res); + if (!TP_IS_CALL_CHANNEL (channel_proxy)) + { + g_simple_async_result_set_error (res, TP_ERROR, + TP_ERROR_INVALID_ARGUMENT, + "You must pass a TpCallChannel object if its a Call channel"); + g_simple_async_result_set_op_res_gboolean (res, FALSE); + g_simple_async_result_complete (res); + } + else + { + tf_call_channel_new_async (channel_proxy, call_channel_ready, res); - self->priv->channel_invalidated_handler = g_signal_connect ( - self->priv->channel_proxy, - "invalidated", G_CALLBACK (channel_invalidated), self); + self->priv->channel_invalidated_handler = g_signal_connect ( + self->priv->channel_proxy, + "invalidated", G_CALLBACK (channel_invalidated), self); + } } else { g_simple_async_result_set_error (res, TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, "Channel does not implement " TP_IFACE_CHANNEL_INTERFACE_MEDIA_SIGNALLING " or " - TF_FUTURE_IFACE_CHANNEL_TYPE_CALL); + TP_IFACE_CHANNEL_TYPE_CALL); goto error; } @@ -606,6 +627,9 @@ tf_channel_new_async (TpChannel *channel_proxy, GAsyncReadyCallback callback, gpointer user_data) { + g_return_if_fail (channel_proxy != NULL); + g_return_if_fail (callback != NULL); + return g_async_initable_new_async (TF_TYPE_CHANNEL, 0, NULL, callback, user_data, "channel", channel_proxy, @@ -627,6 +651,9 @@ gboolean tf_channel_bus_message (TfChannel *channel, GstMessage *message) { + g_return_val_if_fail (channel != NULL, FALSE); + g_return_val_if_fail (message != NULL, FALSE); + if (channel->priv->media_signalling_channel) return tf_media_signalling_channel_bus_message ( channel->priv->media_signalling_channel, message); diff --git a/telepathy-farstream/content-priv.h b/telepathy-farstream/content-priv.h index bee82e3..ab137da 100644 --- a/telepathy-farstream/content-priv.h +++ b/telepathy-farstream/content-priv.h @@ -19,8 +19,12 @@ struct _TfContentClass{ GObjectClass parent_class; void (*content_error) (TfContent *content, - guint reason, /* TfFutureContentRemovalReason */ - const gchar *detailed_reason, + const gchar *message); + + void (*sending_failed) (TfContent *content, + const gchar *message); + void (*receiving_failed) (TfContent *content, + guint *handles, guint handle_count, const gchar *message); GstIterator * (*iterate_src_pads) (TfContent *content, guint *handle, @@ -29,14 +33,15 @@ struct _TfContentClass{ gboolean _tf_content_start_sending (TfContent *self); void _tf_content_stop_sending (TfContent *self); +void _tf_content_mute_to_stop_sending (TfContent *self); void _tf_content_emit_src_pad_added (TfContent *self, guint handle, FsStream *stream, GstPad *pad, FsCodec *codec); gboolean _tf_content_start_receiving (TfContent *self, guint *handles, guint handle_count); -void _tf_content_stop_receiving (TfContent *self, guint *handles, - guint handle_count); +void _tf_content_stop_receiving (TfContent *self, + guint *handles, guint handle_count); G_END_DECLS diff --git a/telepathy-farstream/content.c b/telepathy-farstream/content.c index 7f23596..5a76dd6 100644 --- a/telepathy-farstream/content.c +++ b/telepathy-farstream/content.c @@ -15,10 +15,10 @@ * Objects of this class allow the user to handle the media side of a Telepathy * channel handled by #TfChannel. * - * This object is created by the #TfChannel and the user is notified of its - * creation by the #TfChannel::content-added signal. In the callback for this - * signal, the user should call tf_content_set_codec_preferences() and connect - * to the #TfContent::src-pad-added signal. + * This object is created by the #TfChannel and the user is notified + * of its creation by the #TfChannel::content-added signal. In the + * callback for this signal, the user should connect to the + * #TfContent::src-pad-added signal. * */ @@ -152,7 +152,7 @@ tf_content_class_init (TfContentClass *klass) G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, - g_cclosure_marshal_VOID__VOID, + g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 0); /** @@ -221,7 +221,7 @@ tf_content_class_init (TfContentClass *klass) G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, - _tf_marshal_VOID__POINTER_UINT, + _tf_marshal_VOID__BOOLEAN_POINTER_UINT, G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_UINT); /** @@ -255,6 +255,7 @@ _tf_content_start_sending (TfContent *self) GValue sending_success_val = {0,}; gboolean sending_success; + if (self->sending_count) { self->sending_count ++; @@ -289,9 +290,12 @@ _tf_content_stop_sending (TfContent *self) self->sending_count --; if (self->sending_count == 0) - g_signal_emit (self, signals[SIGNAL_STOP_SENDING], 0); + { + g_signal_emit (self, signals[SIGNAL_STOP_SENDING], 0); + } } + void _tf_content_emit_src_pad_added (TfContent *self, guint handle, FsStream *stream, GstPad *pad, FsCodec *codec) @@ -303,24 +307,23 @@ _tf_content_emit_src_pad_added (TfContent *self, guint handle, /** * tf_content_error_literal: * @content: a #TfContent - * @reason: the reason (a #TfContentRemovalReason) - * @detailed_reason: The detailled error (as a DBus name) * @message: error Message * - * Send an error to the Content to the CM, the effect is most likely that the - * content will be removed. + * Send a fatal streaming error to the Content to the CM, the effect is most + * likely that the content will be removed. */ void tf_content_error_literal (TfContent *content, - guint reason, /* TfFutureContentRemovalReason */ - const gchar *detailed_reason, const gchar *message) { TfContentClass *klass = TF_CONTENT_GET_CLASS (content); + g_return_if_fail (content != NULL); + g_return_if_fail (message != NULL); + if (klass->content_error) - klass->content_error (content, reason, detailed_reason, message); + klass->content_error (content, message); else GST_WARNING ("content_error not defined in class: %s", message); } @@ -328,30 +331,29 @@ tf_content_error_literal (TfContent *content, /** * tf_content_error: * @content: a #TfContent - * @reason: the reason (a #TfContentRemovalReason) - * @detailed_reason: The detailled error (as a DBus name) * @message_format: error Message with printf style formatting * @...: Parameters to insert into the @message_format string * - * Send an error to the Content to the CM, the effect is most likely that the - * content will be removed. + * Send a fatal streaming error to the Content to the CM, the effect is most + * likely that the content will be removed. */ void tf_content_error (TfContent *content, - guint reason, /* TfFutureContentRemovalReason */ - const gchar *detailed_reason, const gchar *message_format, ...) { gchar *message; va_list valist; + g_return_if_fail (content != NULL); + g_return_if_fail (message_format != NULL); + va_start (valist, message_format); message = g_strdup_vprintf (message_format, valist); va_end (valist); - tf_content_error_literal (content, reason, detailed_reason, message); + tf_content_error_literal (content, message); g_free (message); } @@ -373,6 +375,8 @@ tf_content_iterate_src_pads (TfContent *content, guint *handles, { TfContentClass *klass = TF_CONTENT_GET_CLASS (content); + g_return_val_if_fail (content != NULL, NULL); + if (klass->iterate_src_pads) return klass->iterate_src_pads (content, handles, handle_count); else @@ -419,6 +423,129 @@ void _tf_content_stop_receiving (TfContent *self, guint *handles, guint handle_count) { - g_signal_emit (self, signals[SIGNAL_STOP_SENDING], 0, handles, + g_debug ("Requesting that the application stop receiving"); + g_signal_emit (self, signals[SIGNAL_STOP_RECEIVING], 0, handles, handle_count); } + + +/** + * tf_content_sending_failed_literal: + * @content: a #TfContent + * @message_format: Message with printf style formatting + * @...: Parameters to insert into the @message_format string + * + * Informs the Connection Manager that sending has failed for this + * content. This is a transient error and it may or not not end the Content + * and the call. + */ + +void +tf_content_sending_failed_literal (TfContent *content, + const gchar *message) +{ + TfContentClass *klass = TF_CONTENT_GET_CLASS (content); + + g_return_if_fail (content != NULL); + g_return_if_fail (message != NULL); + + if (klass->content_error) + klass->sending_failed (content, message); + else + GST_WARNING ("sending_failed not defined in class, ignoring error: %s", + message); +} + +/** + * tf_content_sending_failed: + * @content: a #TfContent + * @message: The error message + * + * Informs the Connection Manager that sending has failed for this + * content. This is a transient error and it may or not not end the Content + * and the call. + */ + +void +tf_content_sending_failed (TfContent *content, + const gchar *message_format, ...) +{ + gchar *message; + va_list valist; + + g_return_if_fail (content != NULL); + g_return_if_fail (message_format != NULL); + + va_start (valist, message_format); + message = g_strdup_vprintf (message_format, valist); + va_end (valist); + + tf_content_sending_failed_literal (content, message); + g_free (message); +} + +/** + * tf_content_receiving_failed_literal: + * @content: a #TfContent + * @handles: an array of #guint representing Telepathy handles, may be %NULL + * @handle_count: the numner of handles in @handles + * @message: The error message + * + * Informs the Connection Manager that receiving has failed for this + * content. This is a transient error and it may or not not end the Content + * and the call. + * + * If handles are not specific, it assumes that it is valid for all handles. + */ + +void +tf_content_receiving_failed_literal (TfContent *content, + guint *handles, guint handle_count, + const gchar *message) +{ + TfContentClass *klass = TF_CONTENT_GET_CLASS (content); + + g_return_if_fail (content != NULL); + g_return_if_fail (message != NULL); + + if (klass->content_error) + klass->receiving_failed (content, handles, handle_count, message); + else + GST_WARNING ("receiving_failed not defined in class, ignoring error: %s", + message); +} + + +/** + * tf_content_receiving_failed: + * @content: a #TfContent + * @handles: an array of #guint representing Telepathy handles, may be %NULL + * @handle_count: the numner of handles in @handles + * @message_format: Message with printf style formatting + * @...: Parameters to insert into the @message_format string + * + * Informs the Connection Manager that receiving has failed for this + * content. This is a transient error and it may or not not end the Content + * and the call. + * + * If handles are not specific, it assumes that it is valid for all handles. + */ + +void +tf_content_receiving_failed (TfContent *content, + guint *handles, guint handle_count, + const gchar *message_format, ...) +{ + gchar *message; + va_list valist; + + g_return_if_fail (content != NULL); + g_return_if_fail (message_format != NULL); + + va_start (valist, message_format); + message = g_strdup_vprintf (message_format, valist); + va_end (valist); + + tf_content_receiving_failed_literal (content, handles, handle_count, message); + g_free (message); +} diff --git a/telepathy-farstream/content.h b/telepathy-farstream/content.h index e071679..97c5c3a 100644 --- a/telepathy-farstream/content.h +++ b/telepathy-farstream/content.h @@ -47,13 +47,21 @@ typedef struct _TfContentClass TfContentClass; GType tf_content_get_type (void); void tf_content_error_literal (TfContent *content, - guint reason, /* TfFutureContentRemovalReason */ - const gchar *detailed_reason, const gchar *message); - void tf_content_error (TfContent *content, - guint reason, /* TfFutureContentRemovalReason */ - const gchar *detailed_reason, + const gchar *message_format, ...) G_GNUC_PRINTF (2, 3); + + +void tf_content_sending_failed_literal (TfContent *content, + const gchar *message); +void tf_content_sending_failed (TfContent *content, + const gchar *message_format, ...) G_GNUC_PRINTF (2, 3); + +void tf_content_receiving_failed_literal (TfContent *content, + guint *handles, guint handle_count, + const gchar *message); +void tf_content_receiving_failed (TfContent *content, + guint *handles, guint handle_count, const gchar *message_format, ...) G_GNUC_PRINTF (4, 5); GstIterator *tf_content_iterate_src_pads (TfContent *content, diff --git a/telepathy-farstream/media-signalling-channel.c b/telepathy-farstream/media-signalling-channel.c index bfd3696..a029f91 100644 --- a/telepathy-farstream/media-signalling-channel.c +++ b/telepathy-farstream/media-signalling-channel.c @@ -35,31 +35,9 @@ #include "stream.h" #include "session-priv.h" -#include "stream-priv.h" #include "tf-signals-marshal.h" -struct _TfMediaSignallingChannel { - GObject parent; - - TpChannel *channel_proxy; - - TfNatProperties nat_props; - guint prop_id_nat_traversal; - guint prop_id_stun_server; - guint prop_id_stun_port; - guint prop_id_gtalk_p2p_relay_token; - - /* sessions is NULL until we've had a reply from GetSessionHandlers */ - TfSession *session; - gboolean got_sessions; - GPtrArray *streams; -}; - -struct _TfMediaSignallingChannelClass{ - GObjectClass parent_class; -}; - G_DEFINE_TYPE (TfMediaSignallingChannel, tf_media_signalling_channel, G_TYPE_OBJECT); diff --git a/telepathy-farstream/media-signalling-channel.h b/telepathy-farstream/media-signalling-channel.h index 3e9f1a2..57871df 100644 --- a/telepathy-farstream/media-signalling-channel.h +++ b/telepathy-farstream/media-signalling-channel.h @@ -26,6 +26,7 @@ #include <telepathy-glib/channel.h> #include "stream.h" +#include "session-priv.h" G_BEGIN_DECLS @@ -66,6 +67,29 @@ typedef struct _TfMediaSignallingChannel TfMediaSignallingChannel; * There are no overridable functions */ + +struct _TfMediaSignallingChannel { + GObject parent; + + TpChannel *channel_proxy; + + TfNatProperties nat_props; + guint prop_id_nat_traversal; + guint prop_id_stun_server; + guint prop_id_stun_port; + guint prop_id_gtalk_p2p_relay_token; + + /* sessions is NULL until we've had a reply from GetSessionHandlers */ + TfSession *session; + gboolean got_sessions; + GPtrArray *streams; +}; + +struct _TfMediaSignallingChannelClass{ + GObjectClass parent_class; +}; + + typedef struct _TfMediaSignallingChannelClass TfMediaSignallingChannelClass; GType tf_media_signalling_channel_get_type (void); diff --git a/telepathy-farstream/media-signalling-content.c b/telepathy-farstream/media-signalling-content.c index 34c3ebc..e11edc8 100644 --- a/telepathy-farstream/media-signalling-content.c +++ b/telepathy-farstream/media-signalling-content.c @@ -28,17 +28,17 @@ * channel using Farstream. */ - #include "media-signalling-content.h" #include <farstream/fs-conference.h> #include <farstream/fs-utils.h> +#include <telepathy-glib/proxy-subclass.h> +#include <telepathy-glib/util.h> + #include <stdarg.h> #include <string.h> -#include <telepathy-glib/proxy-subclass.h> - #include "tf-signals-marshal.h" #include "utils.h" @@ -86,8 +86,6 @@ tf_media_signalling_content_get_property (GObject *object, GParamSpec *pspec); static void tf_media_signalling_content_error (TfContent *content, - guint reason, /* TfFutureContentRemovalReason */ - const gchar *detailed_reason, const gchar *message); static GstIterator * tf_media_signalling_content_iterate_src_pads ( @@ -247,18 +245,20 @@ request_resource (TfStream *stream, guint direction, { if (direction & TP_MEDIA_STREAM_DIRECTION_SEND) return _tf_content_start_sending (TF_CONTENT (self)); - - if (!self->receiving && direction & TP_MEDIA_STREAM_DIRECTION_RECEIVE) + else if (direction & TP_MEDIA_STREAM_DIRECTION_RECEIVE) { - guint handles[2] = { self->handle, 0}; + if (!self->receiving) + { + guint handles[2] = { self->handle, 0}; - self->receiving = _tf_content_start_receiving (TF_CONTENT (self), - handles, 1); + self->receiving = _tf_content_start_receiving (TF_CONTENT (self), + handles, 1); + } return self->receiving; } - - return FALSE; + else + g_assert_not_reached (); } @@ -286,23 +286,11 @@ restart_source (TfStream *stream, TfMediaSignallingContent *self) static void tf_media_signalling_content_error (TfContent *content, - guint reason, /* TfFutureContentRemovalReason */ - const gchar *detailed_reason, const gchar *message) { TfMediaSignallingContent *self = TF_MEDIA_SIGNALLING_CONTENT (content); - TpMediaStreamError stream_error; - - switch (reason) - { - case TF_FUTURE_CONTENT_REMOVAL_REASON_ERROR: - stream_error = TP_MEDIA_STREAM_ERROR_MEDIA_ERROR; - break; - default: - stream_error = TP_MEDIA_STREAM_ERROR_UNKNOWN; - } - tf_stream_error (self->stream, stream_error, message); + tf_stream_error (self->stream, TP_MEDIA_STREAM_ERROR_MEDIA_ERROR, message); } static GstIterator * diff --git a/telepathy-farstream/media-signalling-content.h b/telepathy-farstream/media-signalling-content.h index 2bb7fd4..085ed9d 100644 --- a/telepathy-farstream/media-signalling-content.h +++ b/telepathy-farstream/media-signalling-content.h @@ -26,7 +26,6 @@ #include <gst/gst.h> #include <telepathy-glib/channel.h> -#include "extensions/extensions.h" #include "media-signalling-channel.h" #include "content.h" #include "content-priv.h" diff --git a/telepathy-farstream/stream-priv.h b/telepathy-farstream/stream-priv.h deleted file mode 100644 index 3e82a18..0000000 --- a/telepathy-farstream/stream-priv.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef __TF_STREAM_PRIV_H__ -#define __TF_STREAM_PRIV_H__ - -#include "stream.h" - -G_BEGIN_DECLS - -typedef struct _TfStreamPrivate TfStreamPrivate; - -/* - * TfStream: - * @parent: the parent #GObject - * @stream_id: the ID of the stream (READ-ONLY) - * - * All other members are privated - */ - -struct _TfStream { - GObject parent; - - /* Read-only */ - guint stream_id; - - /*< private >*/ - - TfStreamPrivate *priv; -}; - -/* - * TfStreamClass: - * @parent_class: the parent #GObjecClass - * - * There are no overridable functions - */ - -struct _TfStreamClass { - GObjectClass parent_class; - - /*< private >*/ - - gpointer unused[4]; -}; - - -typedef struct { - gchar *nat_traversal; - gchar *stun_server; - guint16 stun_port; - gchar *relay_token; -} TfNatProperties; - -typedef void (NewStreamCreatedCb) (TfStream *stream, gpointer channel); - -TfStream * -_tf_stream_new (gpointer channel, - FsConference *conference, - FsParticipant *participant, - TpMediaStreamHandler *proxy, - guint stream_id, - TpMediaStreamType media_type, - TpMediaStreamDirection direction, - TfNatProperties *nat_props, - GList *local_codecs_config, - NewStreamCreatedCb new_stream_created_cb); - -gboolean _tf_stream_bus_message (TfStream *stream, - GstMessage *message); - -void _tf_stream_try_sending_codecs (TfStream *stream); - -TpMediaStreamError fserror_to_tperror (GError *error); - -G_END_DECLS - -#endif /* __TF_STREAM_PRIV_H__ */ diff --git a/telepathy-farstream/stream.c b/telepathy-farstream/stream.c index a525e91..5afd9ad 100644 --- a/telepathy-farstream/stream.c +++ b/telepathy-farstream/stream.c @@ -46,8 +46,7 @@ #include <farstream/fs-utils.h> #include "stream.h" -#include "stream-priv.h" -#include "channel.h" +#include "media-signalling-channel.h" #include "tf-signals-marshal.h" #include "utils.h" @@ -83,7 +82,7 @@ struct DtmfEvent { struct _TfStreamPrivate { - TfChannel *channel; + TfMediaSignallingChannel *channel; FsConference *fs_conference; FsParticipant *fs_participant; FsSession *fs_session; @@ -332,7 +331,7 @@ tf_stream_set_property (GObject *object, { case PROP_CHANNEL: self->priv->channel = - TF_CHANNEL (g_value_get_object (value)); + TF_MEDIA_SIGNALLING_CHANNEL (g_value_get_object (value)); break; case PROP_FARSTREAM_CONFERENCE: self->priv->fs_conference = @@ -430,7 +429,7 @@ tf_stream_dispose (GObject *object) tf_stream_free_resource (stream, TP_MEDIA_STREAM_DIRECTION_RECEIVE); - g_object_run_dispose (G_OBJECT (priv->fs_stream)); + fs_stream_destroy (priv->fs_stream); g_object_unref (priv->fs_stream); tf_stream_free_resource (stream, @@ -441,7 +440,7 @@ tf_stream_dispose (GObject *object) if (priv->fs_session) { - g_object_run_dispose (G_OBJECT (priv->fs_session)); + fs_session_destroy (priv->fs_session); g_object_unref (priv->fs_session); priv->fs_session = NULL; } @@ -506,7 +505,7 @@ tf_stream_class_init (TfStreamClass *klass) g_param_spec_object ("channel", "Telepathy channel", "The TfChannel this stream is in", - TF_TYPE_CHANNEL, + TF_TYPE_MEDIA_SIGNALLING_CHANNEL, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_FARSTREAM_CONFERENCE, @@ -1606,23 +1605,6 @@ fill_fs_params (gpointer key, gpointer value, gpointer user_data) fs_codec_add_optional_parameter (codec, key, value); } -static FsStreamDirection -tpdirection_to_fsdirection (TpMediaStreamDirection dir) -{ - switch (dir) { - case TP_MEDIA_STREAM_DIRECTION_NONE: - return FS_DIRECTION_NONE; - case TP_MEDIA_STREAM_DIRECTION_SEND: - return FS_DIRECTION_SEND; - case TP_MEDIA_STREAM_DIRECTION_RECEIVE: - return FS_DIRECTION_RECV; - case TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL: - return FS_DIRECTION_BOTH; - default: - g_assert_not_reached (); - } -} - static void set_remote_codecs (TpMediaStreamHandler *proxy G_GNUC_UNUSED, const GPtrArray *codecs, @@ -2035,13 +2017,11 @@ start_telephony_event (TpMediaStreamHandler *proxy G_GNUC_UNUSED, static gboolean check_codecs_for_telephone_event (TfStream *self, GList **codecs, - FsCodec *send_codec, guint codecid) + FsCodec *send_codec, gint codecid) { GList *item = NULL; - gboolean found = FALSE; GError *error = NULL; - - again: + gboolean changed = FALSE; for (item = *codecs; item; item = item->next) { @@ -2050,29 +2030,25 @@ check_codecs_for_telephone_event (TfStream *self, GList **codecs, if (!g_ascii_strcasecmp (codec->encoding_name, "telephone-event") && send_codec->clock_rate == codec->clock_rate) { - if (found) - { - *codecs = g_list_delete_link (*codecs, item); - goto again; - } - else if (codecid == (guint) codec->id) - { - return TRUE; } + if (codecid < 0 || codecid == codec->id) + return TRUE; else - { - codec->id = codecid; - } + codec->id = codecid; + changed = TRUE; + break; } } - if (!found) + if (codecid < 0) + return FALSE; + + if (!changed) { FsCodec *codec = fs_codec_new (codecid, "telephone-event", FS_MEDIA_TYPE_AUDIO, send_codec->clock_rate); *codecs = g_list_append (*codecs, codec); } - if (!fs_stream_set_remote_codecs (self->priv->fs_stream, *codecs, &error)) { /* @@ -2145,11 +2121,28 @@ start_sound_telephony_event (TpMediaStreamHandler *proxy, guchar event, gpointer user_data, GObject *object) { TfStream *self = TF_STREAM (object); + FsCodec *send_codec = NULL; + GList *codecs = NULL; g_assert (self->priv->fs_session != NULL); DEBUG (self, "called with event %u", event); + g_object_get (self->priv->fs_session, + "current-send-codec", &send_codec, + "codecs", &codecs, + NULL); + + if (send_codec == NULL) + goto out; + + if (check_codecs_for_telephone_event (self, &codecs, send_codec, -1)) + { + WARNING (self, "Tried to do sound event while telephone-event is set," + " ignoring"); + goto out; + } + if (self->priv->sending_telephony_event) { WARNING (self, "start new telephony event without stopping the" @@ -2163,6 +2156,10 @@ start_sound_telephony_event (TpMediaStreamHandler *proxy, guchar event, if (!fs_session_start_telephony_event (self->priv->fs_session, event, 8)) WARNING (self, "sending sound event %u failed", event); self->priv->sending_telephony_event = TRUE; + + out: + fs_codec_destroy (send_codec); + fs_codec_list_destroy (codecs); } @@ -2178,8 +2175,7 @@ stop_telephony_event (TpMediaStreamHandler *proxy G_GNUC_UNUSED, DEBUG (self, "called"); if (!self->priv->sending_telephony_event) - WARNING (self, "Trying to stop telephony event without having started" - " one"); + WARNING (self, "Trying to stop telephony event without having started one"); self->priv->sending_telephony_event = FALSE; if (!fs_session_stop_telephony_event (self->priv->fs_session)) @@ -2494,12 +2490,16 @@ _tf_stream_bus_message (TfStream *stream, value = gst_structure_get_value (s, "stream"); fsstream = g_value_get_object (value); + g_debug ("new local fs: %p s:%p", stream->priv->fs_stream, stream); + if (fsstream != stream->priv->fs_stream) return FALSE; value = gst_structure_get_value (s, "candidate"); candidate = g_value_get_boxed (value); + g_debug ("NEW LOCAL CAND"); + cb_fs_new_local_candidate (stream, candidate); return TRUE; } @@ -2511,9 +2511,13 @@ _tf_stream_bus_message (TfStream *stream, value = gst_structure_get_value (s, "stream"); fsstream = g_value_get_object (value); + g_debug ("local cand prep fs: %p s:%p", stream->priv->fs_stream, stream); + if (fsstream != stream->priv->fs_stream) return FALSE; + g_debug ("LOCAL CAND PREP"); + cb_fs_local_candidates_prepared (stream); return TRUE; @@ -2608,10 +2612,6 @@ _tf_stream_bus_message (TfStream *stream, FS_CODEC_ARGS (codec)); cb_fs_send_codec_changed (stream, codec, secondary_codecs); - - if (codec) - fs_codec_destroy (codec); - fs_codec_list_destroy (secondary_codecs); return TRUE; } else if (gst_structure_has_name (s, "farstream-component-state-changed")) @@ -2797,23 +2797,6 @@ fs_codecs_to_feedback_messages (GList *fscodecs) } -static TpMediaStreamDirection -fsdirection_to_tpdirection (FsStreamDirection dir) -{ - switch (dir) { - case FS_DIRECTION_NONE: - return TP_MEDIA_STREAM_DIRECTION_NONE; - case FS_DIRECTION_SEND: - return TP_MEDIA_STREAM_DIRECTION_SEND; - case FS_DIRECTION_RECV: - return TP_MEDIA_STREAM_DIRECTION_RECEIVE; - case FS_DIRECTION_BOTH: - return TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL; - default: - g_assert_not_reached (); - } -} - static GPtrArray * _tf_stream_get_header_extensions (TfStream *stream) @@ -3054,7 +3037,7 @@ cb_fs_component_state_changed (TfStream *self, FsStreamState fsstate) { TpMediaStreamState state; - const gchar *state_str; + const gchar *state_str = ""; if (component != 1) return; diff --git a/telepathy-farstream/stream.h b/telepathy-farstream/stream.h index ddd4b6b..40a8048 100644 --- a/telepathy-farstream/stream.h +++ b/telepathy-farstream/stream.h @@ -56,6 +56,73 @@ void tf_stream_error (TfStream *self, const gchar *message); +typedef struct _TfStreamPrivate TfStreamPrivate; + +/* + * TfStream: + * @parent: the parent #GObject + * @stream_id: the ID of the stream (READ-ONLY) + * + * All other members are privated + */ + +struct _TfStream { + GObject parent; + + /* Read-only */ + guint stream_id; + + /*< private >*/ + + TfStreamPrivate *priv; +}; + +/* + * TfStreamClass: + * @parent_class: the parent #GObjecClass + * + * There are no overridable functions + */ + +struct _TfStreamClass { + GObjectClass parent_class; + + /*< private >*/ + + gpointer unused[4]; +}; + + +typedef struct { + gchar *nat_traversal; + gchar *stun_server; + guint16 stun_port; + gchar *relay_token; +} TfNatProperties; + +typedef void (NewStreamCreatedCb) (TfStream *stream, gpointer channel); + +TfStream * +_tf_stream_new (gpointer channel, + FsConference *conference, + FsParticipant *participant, + TpMediaStreamHandler *proxy, + guint stream_id, + TpMediaStreamType media_type, + TpMediaStreamDirection direction, + TfNatProperties *nat_props, + GList *local_codecs_config, + NewStreamCreatedCb new_stream_created_cb); + +gboolean _tf_stream_bus_message (TfStream *stream, + GstMessage *message); + +void _tf_stream_try_sending_codecs (TfStream *stream); + +TpMediaStreamError fserror_to_tperror (GError *error); + + + G_END_DECLS #endif /* __TF_STREAM_H__ */ diff --git a/telepathy-farstream/telepathy-farstream.c b/telepathy-farstream/telepathy-farstream.c deleted file mode 100644 index afc2762..0000000 --- a/telepathy-farstream/telepathy-farstream.c +++ /dev/null @@ -1,34 +0,0 @@ -/* - * telepathy-farstream.c - Global functions for telepathy-farstream - * Copyright (C) 2011 Collabora Ltd. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "extensions/extensions.h" -#include "telepathy-farstream.h" - -/** - * tf_init: - * - * Initializes telepathy-farstream. This must be called at the start of your - * application, specifically before any DBus proxies related to Call channels - * are created - */ -void -tf_init (void) -{ - tf_future_cli_init (); -} diff --git a/telepathy-farstream/telepathy-farstream.h b/telepathy-farstream/telepathy-farstream.h index 2563894..4a24fb2 100644 --- a/telepathy-farstream/telepathy-farstream.h +++ b/telepathy-farstream/telepathy-farstream.h @@ -23,11 +23,5 @@ #include <telepathy-farstream/channel.h> #include <telepathy-farstream/content.h> -G_BEGIN_DECLS - -void tf_init (void); - -G_END_DECLS - #endif /* __TF_FARSTREAM_H__ */ diff --git a/telepathy-farstream/utils.h b/telepathy-farstream/utils.h index 934924c..3bf02c8 100644 --- a/telepathy-farstream/utils.h +++ b/telepathy-farstream/utils.h @@ -24,5 +24,39 @@ tp_media_type_to_fs (TpMediaStreamType type) } } +static inline TpMediaStreamDirection +fsdirection_to_tpdirection (FsStreamDirection dir) +{ + switch (dir) { + case FS_DIRECTION_NONE: + return TP_MEDIA_STREAM_DIRECTION_NONE; + case FS_DIRECTION_SEND: + return TP_MEDIA_STREAM_DIRECTION_SEND; + case FS_DIRECTION_RECV: + return TP_MEDIA_STREAM_DIRECTION_RECEIVE; + case FS_DIRECTION_BOTH: + return TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL; + default: + g_assert_not_reached (); + } +} + +static inline FsStreamDirection +tpdirection_to_fsdirection (TpMediaStreamDirection dir) +{ + switch (dir) { + case TP_MEDIA_STREAM_DIRECTION_NONE: + return FS_DIRECTION_NONE; + case TP_MEDIA_STREAM_DIRECTION_SEND: + return FS_DIRECTION_SEND; + case TP_MEDIA_STREAM_DIRECTION_RECEIVE: + return FS_DIRECTION_RECV; + case TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL: + return FS_DIRECTION_BOTH; + default: + g_assert_not_reached (); + } +} + #endif /* __UTILS_H__ */ |