diff options
author | Tom Swindell <t.swindell@rubyx.co.uk> | 2013-03-04 12:30:37 +0000 |
---|---|---|
committer | Tom Swindell <t.swindell@rubyx.co.uk> | 2013-03-04 12:30:37 +0000 |
commit | 41a3143837ee5fcabf7959cae1fec17a7a0ff5ae (patch) | |
tree | b574dbf504c68bb1c222d01cd61b11ab8bef1679 | |
parent | 7f88b8c4d039fe7e534ebe2ec8f2dbadea3a3def (diff) |
Refactored to use ratified telepathy call spec.
Signed-off-by: Tom Swindell <t.swindell@rubyx.co.uk>
-rw-r--r-- | ring-extensions/Call_Content.xml | 168 | ||||
-rw-r--r-- | ring-extensions/Call_Stream.xml | 178 | ||||
-rw-r--r-- | ring-extensions/Channel_Type_Call.xml | 946 | ||||
-rw-r--r-- | ring-extensions/Makefile.am | 3 | ||||
-rw-r--r-- | src/Makefile.am | 5 | ||||
-rw-r--r-- | src/base-call-channel.c | 761 | ||||
-rw-r--r-- | src/base-call-channel.h | 104 | ||||
-rw-r--r-- | src/base-call-content.c | 434 | ||||
-rw-r--r-- | src/base-call-content.h | 97 | ||||
-rw-r--r-- | src/base-call-stream.c | 351 | ||||
-rw-r--r-- | src/base-call-stream.h | 87 | ||||
-rw-r--r-- | src/ring-call-content.c | 140 | ||||
-rw-r--r-- | src/ring-call-content.h | 68 | ||||
-rw-r--r-- | src/ring-call-stream.c | 90 | ||||
-rw-r--r-- | src/ring-call-stream.h | 61 |
15 files changed, 2198 insertions, 1295 deletions
diff --git a/ring-extensions/Call_Content.xml b/ring-extensions/Call_Content.xml deleted file mode 100644 index bbe5de5..0000000 --- a/ring-extensions/Call_Content.xml +++ /dev/null @@ -1,168 +0,0 @@ -<?xml version="1.0" ?> -<node name="/Call_Content" - xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"> - <tp:copyright>Copyright © 2009 Collabora Ltd.</tp:copyright> - <tp:copyright>Copyright © 2009 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 Call. For example in an - audio/video call there would be one audio and one video content. Each - content has one or more <tp:dbus-ref - namespace="org.freedesktop.Telepathy.Call">Stream.DRAFT</tp:dbus-ref> - objects which represent the actual transport to one or more contacts. - - </tp:docstring> - - <method name="Remove" tp:name-for-bindings="Remove"> - <tp:docstring>Remove the content from the call.</tp:docstring> - - <tp:possible-errors> - <tp:error name="org.freedesktop.Telepathy.Error.NetworkError"> - </tp:error> - <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> - - <property name="Interfaces" tp:name-for-bindings="Interfaces" - type="as" tp:type="DBus_Interface[]" access="read"> - <tp:added version="0.19.UNRELEASED"/> - <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:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>The name of the content. - [FIXME: rationale?]</p> - </tp:docstring> - </property> - - <property name="Type" tp:name-for-bindings="Type" - type="u" tp:type="Media_Stream_Type" access="read"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>The media type of this content</p> - </tp:docstring> - </property> - - <property name="Creator" tp:name-for-bindings="Creator" - type="u" tp:type="Contact_Handle" access="read"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>The creator of this content</p> - </tp:docstring> - </property> - - <tp:enum name="Call_Content_Disposition" type="u"> - <tp:docstring> - [FIXME] - </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="Early_Media" value="1"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - [FIXME: what does this mean?] - </tp:docstring> - </tp:enumvalue> - - <tp:enumvalue suffix="Initial" value="2"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>The content was initially part of the call. When <tp:dbus-ref - namespace="org.freedesktop.Telepathy.Channel.Type.Call.DRAFT" - >Accept</tp:dbus-ref> is called on the channel, all streams of - this content where the self-handle's sending state in <tp:dbus-ref - namespace="org.freedesktop.Telepathy.Call.Stream.DRAFT" - >Senders</tp:dbus-ref> is Sending_State_Pending_Send - will be moved to Sending_State_Sending as if <tp:dbus-ref - namespace="org.freedesktop.Telepathy.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:docstring> - The disposition of this content. This property cannot change. - </tp:docstring> - </property> - - <signal name="StreamAdded" tp:name-for-bindings="Stream_Added"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>Emitted when a stream is added to a call</p> - </tp:docstring> - <arg name="Stream" type="o"> - <tp:docstring> - The stream which was added - </tp:docstring> - </arg> - </signal> - - <signal name="StreamRemoved" tp:name-for-bindings="Stream_Removed"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>Emitted when a stream is added to a call</p> - </tp:docstring> - <arg name="Stream" type="o"> - <tp:docstring> - The stream which was 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="org.freedesktop.Telepathy.Call">Stream.DRAFT</tp:dbus-ref> - objects that exist in this content.</p> - - <tp:rationale> - <p>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.</p> - </tp:rationale> - - <p>Change notification is via - <tp:member-ref>StreamAdded</tp:member-ref> and - <tp:member-ref>StreamRemoved</tp:member-ref>.</p> - </tp:docstring> - </property> - </interface> -</node> -<!-- vim:set sw=2 sts=2 et ft=xml: --> diff --git a/ring-extensions/Call_Stream.xml b/ring-extensions/Call_Stream.xml deleted file mode 100644 index d11d7d2..0000000 --- a/ring-extensions/Call_Stream.xml +++ /dev/null @@ -1,178 +0,0 @@ -<?xml version="1.0" ?> -<node name="/Call_Stream" - xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"> - <tp:copyright>Copyright © 2009 Collabora Ltd.</tp:copyright> - <tp:copyright>Copyright © 2009 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 content - FIXME, direction should be a mapping of contact -> (bool)sending ? - </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 local user's sending state should change - to Sending, if it isn't already.</p> - - <p>If false, the local user's sending state should change to None, - if it isn't already.</p> - </tp:docstring> - </arg> - - <tp:possible-errors> - <tp:error name="org.freedesktop.Telepathy.Error.NotImplemented"> - <tp:docstring> - [FIXME: when?] - </tp:docstring> - </tp:error> - </tp:possible-errors> - </method> - - <method name="RequestReceiving" tp:name-for-bindings="Request_Receiving"> - <tp:docstring> - Request that a remote contact stops or starts sending on this stream. - </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.NotImplemented"> - <tp:docstring> - [FIXME: when?] - </tp:docstring> - </tp:error> - </tp:possible-errors> - </method> - - <signal name="SendersChanged" - tp:name-for-bindings="Senders_Changed"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - Emitted when <tp:member-ref>Senders</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 senders who were added, - and the senders 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 Senders property, as a result of the - contact leaving this stream - </tp:docstring> - </arg> - </signal> - - <tp:enum name="Sending_State" type="u"> - <tp:docstring> - Tristate 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:enum> - - <tp:mapping name="Contact_Sending_State_Map"> - <tp:docstring> - A map from contacts to their sending state. - </tp:docstring> - <tp:member name="Contact" type="u" tp:type="Contact_Handle"> - </tp:member> - <tp:member name="Sending" type="u" tp:type="Sending_State"> - <tp:docstring> - </tp:docstring> - </tp:member> - </tp:mapping> - - <property name="Interfaces" tp:name-for-bindings="Interfaces" - type="as" tp:type="DBus_Interface[]" access="read"> - <tp:added version="0.19.UNRELEASED"/> - <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="Senders" tp:name-for-bindings="Senders" - type="a{uu}" access="read" tp:type="Contact_Sending_State_Map"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>A map from contacts to their sending state.</p> - - <p>The local user's handle in this map (the <tp:dbus-ref - namespace="org.freedesktop.Telepathy.Channel.Interface" - >Group.SelfHandle</tp:dbus-ref> if the channel implements - Group, or the <tp:dbus-ref - namespace="org.freedesktop.Telepathy" - >Connection.SelfHandle</tp:dbus-ref> otherwise) indicates - whether the local user is sending media. Media sent on this stream - should be assumed to be received, directly or indirectly, by every - other contact in the Senders mapping. Sending_State_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> - </interface> -</node> -<!-- vim:set sw=2 sts=2 et ft=xml: --> diff --git a/ring-extensions/Channel_Type_Call.xml b/ring-extensions/Channel_Type_Call.xml deleted file mode 100644 index f1d0f0e..0000000 --- a/ring-extensions/Channel_Type_Call.xml +++ /dev/null @@ -1,946 +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 Collabora Limited</tp:copyright> - <tp:copyright>Copyright © 2009 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.</p> - - <p>A Call channel can have one or more <tp:dbus-ref - namespace="org.freedesktop.Telepathy.Call">Content.DRAFT</tp:dbus-ref> - objects, which represent the actual Media that forms the Call (e.g. an - audio content and a video content).</p> - </tp:docstring> - - <method name="Ringing" tp:name-for-bindings="Ringing"> - <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="org.freedesktop.Telepathy.Channel" - >Requested</tp:dbus-ref> property is false, and the - <tp:member-ref>CallState</tp:member-ref> is - Call_State_Pending_Receiver. While this is the case, - this method SHOULD change the - <tp:member-ref>CallFlags</tp:member-ref> to include - Call_Flag_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="org.freedesktop.Telepathy.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 Call_State_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 Call_State_Pending_Receiver, accept the - incoming call; this changes the - <tp:member-ref>CallState</tp:member-ref> to Call_State_Accepted.</p> - - <p>For outgoing calls in state Call_State_Pending_Initiator, actually - call the remote contact; this changes the - <tp:member-ref>CallState</tp:member-ref> to - Call_State_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="org.freedesktop.Telepathy.Call" - >Content.DRAFT</tp:dbus-ref> whose <tp:dbus-ref - namespace="org.freedesktop.Telepathy.Call.Content.DRAFT" - >Disposition</tp:dbus-ref> is Call_Content_Disposition_Initial, - any streams where the self-handle's sending state in <tp:dbus-ref - namespace="org.freedesktop.Telepathy.Call.Stream.DRAFT" - >Senders</tp:dbus-ref> is Sending_State_Pending_Send - will be moved to Sending_State_Sending as if <tp:dbus-ref - namespace="org.freedesktop.Telepathy.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. - </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> - [FIXME] - </tp:docstring> - <arg direction="in" name="Content_Name" type="s"> - <tp:docstring> - The suggested name of the content to add - - <tp:rationale> - [FIXME: rationale] - </tp:rationale> - </tp:docstring> - </arg> - <arg direction="in" name="Content_Type" type="u" - tp:type="Media_Stream_Type"> - <tp:docstring> - The media type of the content to add - </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> - [FIXME: when?] - </tp:docstring> - </tp:error> - <tp:error name="org.freedesktop.Telepathy.Error.NotImplemented"> - <tp:docstring> - [FIXME: when?] - </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="org.freedesktop.Telepathy.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="org.freedesktop.Telepathy.Call" - >Content.DRAFT</tp:dbus-ref> object. - </tp:docstring> - </arg> - <arg name="Content_Type" type="u" tp:type="Media_Stream_Type"> - <tp:docstring> - The media type of the content which was added - </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="org.freedesktop.Telepathy.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="org.freedesktop.Telepathy.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="org.freedesktop.Telepathy.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 Call_State_Pending_Receiver. It SHOULD be set when - <tp:member-ref>Ringing</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 Call_State_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="org.freedesktop.Telepathy.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 Call_State_Pending_Receiver or - Call_State_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 - Call_State_Pending_Receiver or Call_State_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 - Call_State_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="org.freedesktop.Telepathy.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 Call_State_Pending_Receiver or - Call_State_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 Call_State_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 - Call_Flag_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 Call_State_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>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> - </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: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. - </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: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="org.freedesktop.Telepathy.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: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"> - A mapping from the remote contacts that are part of this call to flags - discribing their status. This mapping never has the local user's handle - as a key. - </tp:docstring> - </property> - - <property name="InitialTransport" tp:name-for-bindings="Initial_Transport" - type="s" access="read"> - <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. - <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> - </p> - </tp:docstring> - </property> - - <property name="InitialAudio" tp:name-for-bindings="Initial_Audio" - type="b" access="read"> - <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="org.freedesktop.Telepathy.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="org.freedesktop.Telepathy.Channel.Type.Call.DRAFT">Contents</tp:dbus-ref>).</p> - - <p>This property is immutable (cannot change), and therefore SHOULD - appear wherever immutable properties are reported, e.g. <tp:dbus-ref - namespace="org.freedesktop.Telepathy.Connection.Interface.Requests">NewChannels</tp:dbus-ref> - signals.</p> - - <tp:rationale><p>This reduces D-Bus round trips.</p></tp:rationale> - - <p>Connection managers that support the <tp:dbus-ref - namespace="org.freedesktop.Telepathy.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="org.freedesktop.Telepathy.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="org.freedesktop.Telepathy.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: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="MutableContents" tp:name-for-bindings="Mutable_Contents" - type="b" access="read"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>If <tt>True</tt>, 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> - - <p>This property is immutable, and therefore SHOULD be announced - in <tp:dbus-ref - namespace="org.freedesktop.Telepathy.Connection.Interface.Requests">NewChannels</tp:dbus-ref>, - etc.</p> - </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="org.freedesktop.Telepathy.Call.Stream.Interface.Media.DRAFT">Transport</tp:dbus-ref> - property is Stream_Transport_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="org.freedesktop.Telepathy.Call.Stream.Interface.Media.DRAFT">Transport</tp:dbus-ref> - property is Stream_Transport_Type_ICE.</p> - </tp:docstring> - </tp:hct> - - <tp:hct name="wlm-8.5"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>The client can implement streaming for streams whose <tp:dbus-ref - namespace="org.freedesktop.Telepathy.Call.Stream.Interface.Media.DRAFT">Transport</tp:dbus-ref> - property is Stream_Transport_Type_WLM_8_5.</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="org.freedesktop.Telepathy.Call.Stream.Interface.Media.DRAFT">Transport</tp:dbus-ref> - property is Stream_Transport_Type_WLM_2009.</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="org.freedesktop.Telepathy.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/ring-extensions/Makefile.am b/ring-extensions/Makefile.am index e4af90a..6190942 100644 --- a/ring-extensions/Makefile.am +++ b/ring-extensions/Makefile.am @@ -3,9 +3,6 @@ tools_dir = $(top_srcdir)/tools EXTRA_DIST = all.xml.in $(EXT_IFACES) EXT_IFACES = \ - $(srcdir)/Call_Content.xml \ - $(srcdir)/Call_Stream.xml \ - $(srcdir)/Channel_Type_Call.xml \ $(srcdir)/Channel_Future.xml \ $(srcdir)/Channel_Interface_Splittable.xml \ $(srcdir)/Channel_Interface_Mergeable_Conference.xml diff --git a/src/Makefile.am b/src/Makefile.am index acbb922..24353ff 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -41,6 +41,9 @@ test_ring_LDADD = \ # Rules for building the targets libtpring_la_SOURCES = \ + base-call-channel.h base-call-channel.c \ + base-call-content.h base-call-content.c \ + base-call-stream.h base-call-stream.c \ ring-connection-manager.h ring-connection-manager.c \ ring-protocol.h ring-protocol.c \ ring-connection.h ring-connection.c \ @@ -54,6 +57,8 @@ libtpring_la_SOURCES = \ ring-member-channel.h ring-member-channel.c \ ring-conference-manager.h ring-conference-manager.c \ ring-conference-channel.h ring-conference-channel.c \ + ring-call-content.h ring-call-content.c \ + ring-call-stream.h ring-call-stream.c \ ring-param-spec.h ring-param-spec.c \ ring-emergency-service.h ring-emergency-service.c \ ring-util.h ring-util.c diff --git a/src/base-call-channel.c b/src/base-call-channel.c new file mode 100644 index 0000000..9812268 --- /dev/null +++ b/src/base-call-channel.c @@ -0,0 +1,761 @@ +/* + * base-call-channel.c - Source for GabbleBaseCallChannel + * Copyright © 2009–2010 Collabora Ltd. + * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk> + * + * 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 <stdio.h> +#include <stdlib.h> + +#include <gio/gio.h> + +#include <telepathy-glib/dbus.h> +#include <telepathy-glib/enums.h> +#include <telepathy-glib/exportable-channel.h> +#include <telepathy-glib/interfaces.h> +#include <telepathy-glib/channel-iface.h> +#include <telepathy-glib/svc-channel.h> +#include <telepathy-glib/svc-properties-interface.h> +#include <telepathy-glib/base-connection.h> +#include <telepathy-glib/gtypes.h> + +#include "base-call-channel.h" +#include "base-call-content.h" + +#include "ring-connection.h" + +#define DEBUG_FLAG RING_DEBUG_MEDIA +#include "ring-debug.h" + +static void call_iface_init (gpointer, gpointer); +static void gabble_base_call_channel_close (TpBaseChannel *base); + +G_DEFINE_TYPE_WITH_CODE(GabbleBaseCallChannel, gabble_base_call_channel, + TP_TYPE_BASE_CHANNEL, + G_IMPLEMENT_INTERFACE (TP_TYPE_BASE_MEDIA_CALL_CHANNEL, + call_iface_init) +); + +static const gchar *gabble_base_call_channel_interfaces[] = { + NULL +}; + +/* properties */ +enum +{ + PROP_OBJECT_PATH_PREFIX = 1, + + PROP_INITIAL_AUDIO, + PROP_INITIAL_VIDEO, + PROP_MUTABLE_CONTENTS, + PROP_HARDWARE_STREAMING, + PROP_CONTENTS, + + PROP_CALL_STATE, + PROP_CALL_FLAGS, + PROP_CALL_STATE_DETAILS, + PROP_CALL_STATE_REASON, + + PROP_CALL_MEMBERS, + + LAST_PROPERTY +}; + +enum +{ + ENDED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0, }; + + +/* private structure */ +struct _GabbleBaseCallChannelPrivate +{ + gchar *object_path_prefix; + + gboolean dispose_has_run; + + GList *contents; + + TpCallState state; + TpCallFlags flags; + GHashTable *details; + GValueArray *reason; + + /* handle -> TpCallMemberFlags hash */ + GHashTable *members; +}; + +static void +gabble_base_call_channel_constructed (GObject *obj) +{ + GabbleBaseCallChannel *self = GABBLE_BASE_CALL_CHANNEL (obj); + TpBaseChannel *base = TP_BASE_CHANNEL (self); + + if (G_OBJECT_CLASS (gabble_base_call_channel_parent_class)->constructed + != NULL) + G_OBJECT_CLASS (gabble_base_call_channel_parent_class)->constructed (obj); + + if (tp_base_channel_is_requested (base)) + gabble_base_call_channel_set_state (self, + TP_CALL_STATE_PENDING_INITIATOR); + else + gabble_base_call_channel_set_state (self, + TP_CALL_STATE_INITIALISING); +} + +static void +gabble_base_call_channel_init (GabbleBaseCallChannel *self) +{ + GabbleBaseCallChannelPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self, + GABBLE_TYPE_BASE_CALL_CHANNEL, GabbleBaseCallChannelPrivate); + + self->priv = priv; + + priv->reason = tp_value_array_build (3, + G_TYPE_UINT, 0, + G_TYPE_UINT, 0, + G_TYPE_STRING, "", + G_TYPE_INVALID); + + priv->details = tp_asv_new (NULL, NULL); + + priv->members = g_hash_table_new (NULL, NULL); +} + +static void gabble_base_call_channel_dispose (GObject *object); +static void gabble_base_call_channel_finalize (GObject *object); + +static void +gabble_base_call_channel_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GabbleBaseCallChannel *self = GABBLE_BASE_CALL_CHANNEL (object); + GabbleBaseCallChannelPrivate *priv = self->priv; + GabbleBaseCallChannelClass *klass = GABBLE_BASE_CALL_CHANNEL_GET_CLASS (self); + + switch (property_id) + { + case PROP_OBJECT_PATH_PREFIX: + g_value_set_string (value, priv->object_path_prefix); + break; + case PROP_INITIAL_AUDIO: + g_value_set_boolean (value, self->initial_audio); + break; + case PROP_INITIAL_VIDEO: + g_value_set_boolean (value, self->initial_video); + break; + case PROP_MUTABLE_CONTENTS: + g_value_set_boolean (value, klass->mutable_contents); + break; + case PROP_CONTENTS: + { + GPtrArray *arr = g_ptr_array_sized_new (2); + GList *l; + + for (l = priv->contents; l != NULL; l = g_list_next (l)) + { + GabbleBaseCallContent *c = GABBLE_BASE_CALL_CONTENT (l->data); + g_ptr_array_add (arr, + (gpointer) gabble_base_call_content_get_object_path (c)); + } + + g_value_set_boxed (value, arr); + g_ptr_array_free (arr, TRUE); + break; + } + case PROP_HARDWARE_STREAMING: + g_value_set_boolean (value, klass->hardware_streaming); + break; + case PROP_CALL_STATE: + g_value_set_uint (value, priv->state); + break; + case PROP_CALL_FLAGS: + g_value_set_uint (value, priv->flags); + break; + case PROP_CALL_STATE_DETAILS: + g_value_set_boxed (value, priv->details); + break; + case PROP_CALL_STATE_REASON: + g_value_set_boxed (value, priv->reason); + break; + case PROP_CALL_MEMBERS: + g_value_set_boxed (value, priv->members); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gabble_base_call_channel_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GabbleBaseCallChannel *self = GABBLE_BASE_CALL_CHANNEL (object); + GabbleBaseCallChannelPrivate *priv = self->priv; + + switch (property_id) + { + case PROP_OBJECT_PATH_PREFIX: + priv->object_path_prefix = g_value_dup_string (value); + break; + case PROP_INITIAL_AUDIO: + self->initial_audio = g_value_get_boolean (value); + break; + case PROP_INITIAL_VIDEO: + self->initial_video = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static gchar * +gabble_base_call_channel_get_object_path_suffix (TpBaseChannel *base) +{ + GabbleBaseCallChannel *self = GABBLE_BASE_CALL_CHANNEL (base); + GabbleBaseCallChannelPrivate *priv = self->priv; + + g_assert (priv->object_path_prefix != NULL); + + return g_strdup_printf ("%s/CallChannel%p", priv->object_path_prefix, self); +} + +static void +gabble_base_call_channel_fill_immutable_properties ( + TpBaseChannel *chan, + GHashTable *properties) +{ + TP_BASE_CHANNEL_CLASS (gabble_base_call_channel_parent_class) + ->fill_immutable_properties (chan, properties); + + tp_dbus_properties_mixin_fill_properties_hash ( + G_OBJECT (chan), properties, + TP_IFACE_CHANNEL_TYPE_CALL, "InitialAudio", + TP_IFACE_CHANNEL_TYPE_CALL, "InitialVideo", + TP_IFACE_CHANNEL_TYPE_CALL, "MutableContents", + TP_IFACE_CHANNEL_TYPE_CALL, "HardwareStreaming", + NULL); +} + +static void +gabble_base_call_channel_class_init ( + GabbleBaseCallChannelClass *gabble_base_call_channel_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (gabble_base_call_channel_class); + TpBaseChannelClass *base_channel_class = + TP_BASE_CHANNEL_CLASS (gabble_base_call_channel_class); + GParamSpec *param_spec; + static TpDBusPropertiesMixinPropImpl call_props[] = { + { "CallMembers", "call-members", NULL }, + { "MutableContents", "mutable-contents", NULL }, + { "InitialAudio", "initial-audio", NULL }, + { "InitialVideo", "initial-video", NULL }, + { "Contents", "contents", NULL }, + { "HardwareStreaming", "hardware-streaming", NULL }, + { "CallState", "call-state", NULL }, + { "CallFlags", "call-flags", NULL }, + { "CallStateReason", "call-state-reason", NULL }, + { "CallStateDetails", "call-state-details", NULL }, + { NULL } + }; + + g_type_class_add_private (gabble_base_call_channel_class, + sizeof (GabbleBaseCallChannelPrivate)); + + object_class->constructed = gabble_base_call_channel_constructed; + + object_class->get_property = gabble_base_call_channel_get_property; + object_class->set_property = gabble_base_call_channel_set_property; + + object_class->dispose = gabble_base_call_channel_dispose; + object_class->finalize = gabble_base_call_channel_finalize; + + base_channel_class->channel_type = TP_IFACE_CHANNEL_TYPE_CALL; + base_channel_class->interfaces = gabble_base_call_channel_interfaces; + base_channel_class->get_object_path_suffix = + gabble_base_call_channel_get_object_path_suffix; + base_channel_class->fill_immutable_properties = + gabble_base_call_channel_fill_immutable_properties; + base_channel_class->close = gabble_base_call_channel_close; + + signals[ENDED] = g_signal_new ("ended", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + param_spec = g_param_spec_string ("object-path-prefix", "Object path prefix", + "prefix of the object path", + NULL, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_OBJECT_PATH_PREFIX, + param_spec); + + param_spec = g_param_spec_boolean ("initial-audio", "InitialAudio", + "Whether the channel initially contained an audio stream", + FALSE, + G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_INITIAL_AUDIO, + param_spec); + + param_spec = g_param_spec_boolean ("initial-video", "InitialVideo", + "Whether the channel initially contained an video stream", + FALSE, + G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_INITIAL_VIDEO, + param_spec); + + param_spec = g_param_spec_boolean ("mutable-contents", "MutableContents", + "Whether the set of streams on this channel are mutable once requested", + FALSE, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_MUTABLE_CONTENTS, + param_spec); + + param_spec = g_param_spec_boxed ("contents", "Contents", + "The contents of the channel", + TP_ARRAY_TYPE_OBJECT_PATH_LIST, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_CONTENTS, + param_spec); + + param_spec = g_param_spec_boolean ("hardware-streaming", "HardwareStreaming", + "True if all the streaming is done by hardware", + FALSE, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_HARDWARE_STREAMING, + param_spec); + + param_spec = g_param_spec_uint ("call-state", "CallState", + "The status of the call", + TP_CALL_STATE_UNKNOWN, + NUM_TP_CALL_STATES, + TP_CALL_STATE_UNKNOWN, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_CALL_STATE, param_spec); + + param_spec = g_param_spec_uint ("call-flags", "CallFlags", + "Flags representing the status of the call", + 0, G_MAXUINT, 0, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_CALL_FLAGS, + param_spec); + + param_spec = g_param_spec_boxed ("call-state-reason", "CallStateReason", + "The reason why the call is in the current state", + TP_STRUCT_TYPE_CALL_STATE_REASON, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_CALL_STATE_REASON, + param_spec); + + param_spec = g_param_spec_boxed ("call-state-details", "CallStateDetails", + "The reason why the call is in the current state", + TP_HASH_TYPE_QUALIFIED_PROPERTY_VALUE_MAP, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_CALL_STATE_DETAILS, + param_spec); + + param_spec = g_param_spec_boxed ("call-members", "CallMembers", + "The members", + TP_HASH_TYPE_CALL_MEMBER_MAP, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_CALL_MEMBERS, + param_spec); + + tp_dbus_properties_mixin_implement_interface (object_class, + TP_IFACE_QUARK_CHANNEL_TYPE_CALL, + tp_dbus_properties_mixin_getter_gobject_properties, + NULL, + call_props); +} + +void +gabble_base_call_channel_dispose (GObject *object) +{ + GabbleBaseCallChannel *self = GABBLE_BASE_CALL_CHANNEL (object); + GabbleBaseCallChannelPrivate *priv = self->priv; + + if (priv->dispose_has_run) + return; + + self->priv->dispose_has_run = TRUE; + + g_list_foreach (priv->contents, (GFunc) gabble_base_call_content_deinit, NULL); + g_list_foreach (priv->contents, (GFunc) g_object_unref, NULL); + tp_clear_pointer (&priv->contents, g_list_free); + + tp_clear_pointer (&priv->members, g_hash_table_unref); + + if (G_OBJECT_CLASS (gabble_base_call_channel_parent_class)->dispose) + G_OBJECT_CLASS (gabble_base_call_channel_parent_class)->dispose (object); +} + +void +gabble_base_call_channel_finalize (GObject *object) +{ + GabbleBaseCallChannel *self = GABBLE_BASE_CALL_CHANNEL (object); + GabbleBaseCallChannelPrivate *priv = self->priv; + + g_hash_table_unref (priv->details); + g_value_array_free (priv->reason); + g_free (self->priv->object_path_prefix); + + G_OBJECT_CLASS (gabble_base_call_channel_parent_class)->finalize (object); +} + +void +gabble_base_call_channel_set_state (GabbleBaseCallChannel *self, + TpCallState state) +{ + GabbleBaseCallChannelPrivate *priv = self->priv; + + DEBUG ("changing from %u to %u", priv->state, state); + + if (state == priv->state) + return; + + /* signal when going to the ended state */ + if (state == TP_CALL_STATE_ENDED) + g_signal_emit (self, signals[ENDED], 0); + + priv->state = state; + + if (priv->state != TP_CALL_STATE_INITIALISING) + priv->flags &= ~TP_CALL_FLAG_LOCALLY_RINGING; + + if (tp_base_channel_is_registered (TP_BASE_CHANNEL (self))) + tp_svc_channel_type_call_emit_call_state_changed (self, priv->state, + priv->flags, priv->reason, priv->details); +} + +TpCallState +gabble_base_call_channel_get_state (GabbleBaseCallChannel *self) +{ + return self->priv->state; +} + +void +gabble_base_call_channel_update_flags (GabbleBaseCallChannel *self, + TpCallFlags set_flags, + TpCallFlags clear_flags) +{ + GabbleBaseCallChannelPrivate *priv = self->priv; + TpCallFlags old_flags = priv->flags; + + priv->flags = (old_flags | set_flags) & ~clear_flags; + DEBUG ("was %u; set %u and cleared %u; now %u", old_flags, set_flags, + clear_flags, priv->flags); + + if (priv->flags != old_flags) + tp_svc_channel_type_call_emit_call_state_changed (self, priv->state, + priv->flags, priv->reason, priv->details); +} + +static gboolean +base_call_channel_update_member (GabbleBaseCallChannel *self, + TpHandle contact, + TpCallMemberFlags set_flags, + TpCallMemberFlags clear_flags, + TpCallMemberFlags *new_flags) +{ + gpointer old_flags_p; + + DEBUG ("updating member #%u, setting %u and clearing %u", contact, set_flags, + clear_flags); + + if (g_hash_table_lookup_extended (self->priv->members, + GUINT_TO_POINTER (contact), NULL, &old_flags_p)) + { + TpCallMemberFlags old_flags = GPOINTER_TO_UINT (old_flags_p); + + *new_flags = (old_flags | set_flags) & ~clear_flags; + + DEBUG ("previous flags: %u; new flags: %u", old_flags, *new_flags); + + if (old_flags == *new_flags) + return FALSE; + } + else + { + *new_flags = set_flags & ~clear_flags; + DEBUG ("not previously a member; new flags: %u", *new_flags); + } + + g_hash_table_insert (self->priv->members, GUINT_TO_POINTER (contact), + GUINT_TO_POINTER (*new_flags)); + return TRUE; +} + +gboolean +gabble_base_call_channel_update_members ( + GabbleBaseCallChannel *self, + TpHandle contact, + TpCallMemberFlags set_flags, + TpCallMemberFlags clear_flags, + ...) +{ + GHashTable *updates = g_hash_table_new (NULL, NULL); + gboolean updated = FALSE; + va_list args; + + va_start (args, clear_flags); + + do + { + TpCallMemberFlags new_flags; + + if (base_call_channel_update_member (self, contact, set_flags, + clear_flags, &new_flags)) + { + g_hash_table_insert (updates, + GUINT_TO_POINTER (contact), + GUINT_TO_POINTER (new_flags)); + updated = TRUE; + } + + contact = va_arg (args, TpHandle); + + if (contact != 0) + { + set_flags = va_arg (args, TpCallMemberFlags); + clear_flags = va_arg (args, TpCallMemberFlags); + } + } + while (contact != 0); + + if (updated) + { + GArray *empty = g_array_new (FALSE, FALSE, sizeof (TpHandle)); + + tp_svc_channel_type_call_emit_call_members_changed (self, updates, NULL, + empty, empty); + g_array_unref (empty); + } + + g_hash_table_unref (updates); + return updated; +} + +gboolean +gabble_base_call_channel_remove_members ( + GabbleBaseCallChannel *self, + TpHandle contact, + ...) +{ + GArray *removed = g_array_new (FALSE, FALSE, sizeof (TpHandle)); + gboolean updated = FALSE; + va_list args; + + va_start (args, contact); + + do + { + if (g_hash_table_remove (self->priv->members, GUINT_TO_POINTER (contact))) + { + g_array_append_val (removed, contact); + updated = TRUE; + } + + contact = va_arg (args, TpHandle); + } + while (contact != 0); + + if (updated) + { + GHashTable *empty = g_hash_table_new (NULL, NULL); + + tp_svc_channel_type_call_emit_call_members_changed (self, empty, + removed); + g_hash_table_unref (empty); + } + + g_array_unref (removed); + return updated; +} + +void +gabble_base_call_channel_add_content (GabbleBaseCallChannel *self, + GabbleBaseCallContent *content) +{ + self->priv->contents = g_list_prepend (self->priv->contents, + g_object_ref (content)); + + if (tp_base_channel_is_registered (TP_BASE_CHANNEL (self))) + tp_svc_channel_type_call_emit_content_added (self, + gabble_base_call_content_get_object_path (content), + gabble_base_call_content_get_media_type (content)); +} + +static void +gabble_base_call_channel_close (TpBaseChannel *base) +{ + GabbleBaseCallChannel *self = GABBLE_BASE_CALL_CHANNEL (base); + GabbleBaseCallChannelPrivate *priv = self->priv; + + DEBUG ("Closing media channel %s", tp_base_channel_get_object_path (base)); + + /* shutdown all our contents */ + g_list_foreach (priv->contents, (GFunc) gabble_base_call_content_deinit, + NULL); + g_list_foreach (priv->contents, (GFunc) g_object_unref, NULL); + tp_clear_pointer (&priv->contents, g_list_free); + + tp_base_channel_destroyed (base); +} + +static void +gabble_base_call_channel_ringing (TpSvcChannelTypeCall *iface, + DBusGMethodInvocation *context) +{ + GabbleBaseCallChannel *self = GABBLE_BASE_CALL_CHANNEL (iface); + GabbleBaseCallChannelPrivate *priv = self->priv; + TpBaseChannel *tp_base = TP_BASE_CHANNEL (self); + + if (tp_base_channel_is_requested (tp_base)) + { + GError e = { TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + "Call was requested. Ringing doesn't make sense." }; + dbus_g_method_return_error (context, &e); + } + else if (priv->state != TP_CALL_STATE_INITIALISING) + { + GError e = { TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + "Call is not in the right state for Ringing." }; + dbus_g_method_return_error (context, &e); + } + else + { + if ((priv->flags & TP_CALL_FLAG_LOCALLY_RINGING) == 0) + { + DEBUG ("Client is ringing"); + priv->flags |= TP_CALL_FLAG_LOCALLY_RINGING; + gabble_base_call_channel_set_state (self, priv->state); + } + + tp_svc_channel_type_call_return_from_ringing (context); + } +} + +static void +gabble_base_call_channel_accept (TpSvcChannelTypeCall *iface, + DBusGMethodInvocation *context) +{ + GabbleBaseCallChannel *self = GABBLE_BASE_CALL_CHANNEL (iface); + GabbleBaseCallChannelPrivate *priv = self->priv; + GabbleBaseCallChannelClass *base_class = + GABBLE_BASE_CALL_CHANNEL_GET_CLASS (self); + TpBaseChannel *tp_base = TP_BASE_CHANNEL (self); + + DEBUG ("Client accepted the call"); + + if (tp_base_channel_is_requested (tp_base)) + { + if (priv->state == TP_CALL_STATE_PENDING_INITIATOR) + { + gabble_base_call_channel_set_state (self, + TP_CALL_STATE_INITIALISING); + } + else + { + DEBUG ("Invalid state for Accept: Channel requested and " + "state == %d", priv->state); + goto err; + } + } + else if (priv->state < TP_CALL_STATE_ACCEPTED) + { + gabble_base_call_channel_set_state (self, + TP_CALL_STATE_ACCEPTED); + } + else + { + DEBUG ("Invalid state for Accept: state == %d", priv->state); + goto err; + } + + if (base_class->accept != NULL) + base_class->accept (self); + + tp_svc_channel_type_call_return_from_accept (context); + return; + +err: + { + GError e = { TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + "Invalid state for Accept" }; + dbus_g_method_return_error (context, &e); + } +} + +static void +gabble_base_call_channel_hangup (TpSvcChannelTypeCall *iface, + guint reason, + const gchar *detailed_reason, + const gchar *message, + DBusGMethodInvocation *context) +{ + GabbleBaseCallChannel *self = GABBLE_BASE_CALL_CHANNEL (iface); + GabbleBaseCallChannelClass *base_class = + GABBLE_BASE_CALL_CHANNEL_GET_CLASS (self); + + if (base_class->hangup) + base_class->hangup (self, reason, detailed_reason, message); + + gabble_base_call_channel_set_state ( GABBLE_BASE_CALL_CHANNEL (self), + TP_CALL_STATE_ENDED); + + tp_svc_channel_type_call_return_from_hangup (context); +} + +static void +gabble_base_call_channel_add_content_dbus (RingSvcChannelTypeCall *iface, + const gchar *name, + TpMediaStreamType mtype, + DBusGMethodInvocation *context) +{ + GError e = { TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, + "Contents cannot be added; only a single audio content is supported" }; + + dbus_g_method_return_error (context, &e); +} + + +static void +call_iface_init (gpointer g_iface, gpointer iface_data) +{ + RingSvcChannelTypeCallClass *klass = g_iface; + +#define IMPLEMENT(x, suffix) ring_svc_channel_type_call_implement_##x (\ + klass, gabble_base_call_channel_##x##suffix) + IMPLEMENT(ringing,); + IMPLEMENT(accept,); + IMPLEMENT(hangup,); + IMPLEMENT(add_content, _dbus); +#undef IMPLEMENT +} diff --git a/src/base-call-channel.h b/src/base-call-channel.h new file mode 100644 index 0000000..c82fe90 --- /dev/null +++ b/src/base-call-channel.h @@ -0,0 +1,104 @@ +/* + * base-call-channel.h - Header for GabbleBaseCallChannel + * Copyright © 2009–2010 Collabora Ltd. + * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk> + * + * 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 __GABBLE_BASE_CALL_CHANNEL_H__ +#define __GABBLE_BASE_CALL_CHANNEL_H__ + +#include <glib-object.h> + +#include <ring-extensions/ring-extensions.h> + +#include <telepathy-glib/base-channel.h> + +#include "base-call-content.h" + +G_BEGIN_DECLS + +typedef struct _GabbleBaseCallChannel GabbleBaseCallChannel; +typedef struct _GabbleBaseCallChannelPrivate GabbleBaseCallChannelPrivate; +typedef struct _GabbleBaseCallChannelClass GabbleBaseCallChannelClass; + +struct _GabbleBaseCallChannelClass { + TpBaseChannelClass parent_class; + + gboolean hardware_streaming; + gboolean mutable_contents; + + void (*accept) (GabbleBaseCallChannel *self); + void (*hangup) (GabbleBaseCallChannel *self, + guint reason, + const gchar *detailed_reason, + const gchar *message); +}; + +struct _GabbleBaseCallChannel { + TpBaseChannel parent; + + gboolean initial_audio; + gboolean initial_video; + + GabbleBaseCallChannelPrivate *priv; +}; + +GType gabble_base_call_channel_get_type (void); + +/* TYPE MACROS */ +#define GABBLE_TYPE_BASE_CALL_CHANNEL \ + (gabble_base_call_channel_get_type ()) +#define GABBLE_BASE_CALL_CHANNEL(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + GABBLE_TYPE_BASE_CALL_CHANNEL, GabbleBaseCallChannel)) +#define GABBLE_BASE_CALL_CHANNEL_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GABBLE_TYPE_BASE_CALL_CHANNEL, GabbleBaseCallChannelClass)) +#define GABBLE_IS_BASE_CALL_CHANNEL(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GABBLE_TYPE_BASE_CALL_CHANNEL)) +#define GABBLE_IS_BASE_CALL_CHANNEL_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GABBLE_TYPE_BASE_CALL_CHANNEL)) +#define GABBLE_BASE_CALL_CHANNEL_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + GABBLE_TYPE_BASE_CALL_CHANNEL, GabbleBaseCallChannelClass)) + +TpCallState gabble_base_call_channel_get_state ( + GabbleBaseCallChannel *self); +void gabble_base_call_channel_set_state (GabbleBaseCallChannel *self, + TpCallState state); + +void gabble_base_call_channel_update_flags (GabbleBaseCallChannel *self, + TpCallFlags set_flags, + TpCallFlags clear_flags); + +gboolean gabble_base_call_channel_update_members ( + GabbleBaseCallChannel *self, + TpHandle contact, + TpCallMemberFlags set_flags, + TpCallMemberFlags clear_flags, + ...) G_GNUC_NULL_TERMINATED; +gboolean gabble_base_call_channel_remove_members ( + GabbleBaseCallChannel *self, + TpHandle contact, + ...) G_GNUC_NULL_TERMINATED; + +void gabble_base_call_channel_add_content (GabbleBaseCallChannel *self, + GabbleBaseCallContent *content); + +G_END_DECLS + +#endif /* #ifndef __GABBLE_BASE_CALL_CHANNEL_H__*/ diff --git a/src/base-call-content.c b/src/base-call-content.c new file mode 100644 index 0000000..44fb532 --- /dev/null +++ b/src/base-call-content.c @@ -0,0 +1,434 @@ +/* + * base-call-content.c - Source for GabbleBaseCallContent + * Copyright © 2009–2010 Collabora Ltd. + * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk> + * @author Will Thompson <will.thompson@collabora.co.uk> + * + * 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 "base-call-content.h" + +#include "base-call-stream.h" + +#define DEBUG_FLAG RING_DEBUG_MEDIA +#include "ring-debug.h" + +G_DEFINE_TYPE_WITH_CODE(GabbleBaseCallContent, gabble_base_call_content, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES, + tp_dbus_properties_mixin_iface_init); + /* The base class doesn't implement Remove(), which is pretty + * protocol-specific. It just implements the properties. + */ + G_IMPLEMENT_INTERFACE (RING_TYPE_SVC_CALL_CONTENT, + NULL); + ); + +struct _GabbleBaseCallContentPrivate +{ + RingConnection *conn; + TpDBusDaemon *dbus_daemon; + + gchar *object_path; + + gchar *name; + TpMediaStreamType media_type; + TpHandle creator; + TpCallContentDisposition disposition; + + GList *streams; + + gboolean dispose_has_run; + gboolean deinit_has_run; +}; + +enum +{ + PROP_OBJECT_PATH = 1, + PROP_CONNECTION, + + PROP_INTERFACES, + PROP_NAME, + PROP_MEDIA_TYPE, + PROP_CREATOR, + PROP_DISPOSITION, + PROP_STREAMS +}; + +static void base_call_content_deinit_real (GabbleBaseCallContent *self); + +static void +gabble_base_call_content_init (GabbleBaseCallContent *self) +{ + GabbleBaseCallContentPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self, + GABBLE_TYPE_BASE_CALL_CONTENT, GabbleBaseCallContentPrivate); + + self->priv = priv; +} + +static void +gabble_base_call_content_constructed (GObject *obj) +{ + GabbleBaseCallContent *self = GABBLE_BASE_CALL_CONTENT (obj); + GabbleBaseCallContentPrivate *priv = self->priv; + + if (G_OBJECT_CLASS (gabble_base_call_content_parent_class)->constructed != NULL) + G_OBJECT_CLASS (gabble_base_call_content_parent_class)->constructed (obj); + + DEBUG ("Registering %s", priv->object_path); + priv->dbus_daemon = g_object_ref ( + tp_base_connection_get_dbus_daemon ((TpBaseConnection *) priv->conn)); + tp_dbus_daemon_register_object (priv->dbus_daemon, priv->object_path, obj); +} + +static void +gabble_base_call_content_dispose (GObject *object) +{ + GabbleBaseCallContent *self = GABBLE_BASE_CALL_CONTENT (object); + GabbleBaseCallContentPrivate *priv = self->priv; + GList *l; + + if (priv->dispose_has_run) + return; + + priv->dispose_has_run = TRUE; + + for (l = priv->streams; l != NULL; l = g_list_next (l)) + g_object_unref (l->data); + + tp_clear_pointer (&priv->streams, g_list_free); + tp_clear_object (&priv->conn); + + if (G_OBJECT_CLASS (gabble_base_call_content_parent_class)->dispose != NULL) + G_OBJECT_CLASS (gabble_base_call_content_parent_class)->dispose (object); +} + +static void +gabble_base_call_content_finalize (GObject *object) +{ + GabbleBaseCallContent *self = GABBLE_BASE_CALL_CONTENT (object); + GabbleBaseCallContentPrivate *priv = self->priv; + + /* free any data held directly by the object here */ + g_free (priv->object_path); + g_free (priv->name); + + G_OBJECT_CLASS (gabble_base_call_content_parent_class)->finalize (object); +} + +static void +gabble_base_call_content_get_property ( + GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GabbleBaseCallContent *content = GABBLE_BASE_CALL_CONTENT (object); + GabbleBaseCallContentPrivate *priv = content->priv; + + switch (property_id) + { + case PROP_OBJECT_PATH: + g_value_set_string (value, priv->object_path); + break; + case PROP_CONNECTION: + g_value_set_object (value, priv->conn); + break; + case PROP_INTERFACES: + { + GabbleBaseCallContentClass *klass = + GABBLE_BASE_CALL_CONTENT_GET_CLASS (content); + + if (klass->extra_interfaces != NULL) + { + g_value_set_boxed (value, klass->extra_interfaces); + } + else + { + static gchar *empty[] = { NULL }; + + g_value_set_boxed (value, empty); + } + break; + } + case PROP_NAME: + g_value_set_string (value, priv->name); + break; + case PROP_MEDIA_TYPE: + g_value_set_uint (value, priv->media_type); + break; + case PROP_CREATOR: + g_value_set_uint (value, priv->creator); + break; + case PROP_DISPOSITION: + g_value_set_uint (value, priv->disposition); + break; + case PROP_STREAMS: + { + GPtrArray *arr = g_ptr_array_sized_new (2); + GList *l; + + for (l = priv->streams; l != NULL; l = g_list_next (l)) + { + GabbleBaseCallStream *s = GABBLE_BASE_CALL_STREAM (l->data); + g_ptr_array_add (arr, + g_strdup (gabble_base_call_stream_get_object_path (s))); + } + + g_value_take_boxed (value, arr); + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gabble_base_call_content_set_property ( + GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GabbleBaseCallContent *content = GABBLE_BASE_CALL_CONTENT (object); + GabbleBaseCallContentPrivate *priv = content->priv; + + switch (property_id) + { + case PROP_OBJECT_PATH: + priv->object_path = g_value_dup_string (value); + g_assert (priv->object_path != NULL); + break; + case PROP_CONNECTION: + priv->conn = g_value_dup_object (value); + break; + case PROP_NAME: + priv->name = g_value_dup_string (value); + break; + case PROP_MEDIA_TYPE: + priv->media_type = g_value_get_uint (value); + break; + case PROP_CREATOR: + priv->creator = g_value_get_uint (value); + break; + case PROP_DISPOSITION: + priv->disposition = g_value_get_uint (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gabble_base_call_content_class_init ( + GabbleBaseCallContentClass *bcc_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (bcc_class); + GParamSpec *param_spec; + static TpDBusPropertiesMixinPropImpl content_props[] = { + { "Interfaces", "interfaces", NULL }, + { "Name", "name", NULL }, + { "Type", "media-type", NULL }, + { "Creator", "creator", NULL }, + { "Disposition", "disposition", NULL }, + { "Streams", "streams", NULL }, + { NULL } + }; + static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = { + { RING_IFACE_CALL_CONTENT, + tp_dbus_properties_mixin_getter_gobject_properties, + NULL, + content_props, + }, + { NULL } + }; + + g_type_class_add_private (bcc_class, sizeof (GabbleBaseCallContentPrivate)); + + object_class->constructed = gabble_base_call_content_constructed; + object_class->dispose = gabble_base_call_content_dispose; + object_class->finalize = gabble_base_call_content_finalize; + object_class->get_property = gabble_base_call_content_get_property; + object_class->set_property = gabble_base_call_content_set_property; + + param_spec = g_param_spec_string ("object-path", "D-Bus object path", + "The D-Bus object path used for this object on the bus.", + NULL, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_OBJECT_PATH, param_spec); + + param_spec = g_param_spec_object ("connection", "RingConnection object", + "Gabble connection object that owns this call content", + RING_TYPE_CONNECTION, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_CONNECTION, param_spec); + + param_spec = g_param_spec_boxed ("interfaces", "Extra D-Bus interfaces", + "Additional interfaces implemented by this content", + G_TYPE_STRV, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_INTERFACES, param_spec); + + param_spec = g_param_spec_string ("name", "Name", + "The name of this content, if any", + "", + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_NAME, param_spec); + + param_spec = g_param_spec_uint ("media-type", "Media Type", + "The media type of this content", + 0, G_MAXUINT, 0, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_MEDIA_TYPE, param_spec); + + param_spec = g_param_spec_uint ("creator", "Creator", + "The creator of this content", + 0, G_MAXUINT, 0, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_CREATOR, param_spec); + + param_spec = g_param_spec_uint ("disposition", "Disposition", + "The disposition of this content", + 0, G_MAXUINT, 0, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_DISPOSITION, param_spec); + + param_spec = g_param_spec_boxed ("streams", "Stream", + "The streams of this content", + TP_ARRAY_TYPE_OBJECT_PATH_LIST, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_STREAMS, + param_spec); + + bcc_class->dbus_props_class.interfaces = prop_interfaces; + tp_dbus_properties_mixin_class_init (object_class, + G_STRUCT_OFFSET (GabbleBaseCallContentClass, dbus_props_class)); + + bcc_class->deinit = base_call_content_deinit_real; +} + +RingConnection * +gabble_base_call_content_get_connection (GabbleBaseCallContent *self) +{ + g_return_val_if_fail (GABBLE_IS_BASE_CALL_CONTENT (self), NULL); + + return self->priv->conn; +} + +const gchar * +gabble_base_call_content_get_object_path (GabbleBaseCallContent *self) +{ + g_return_val_if_fail (GABBLE_IS_BASE_CALL_CONTENT (self), NULL); + + return self->priv->object_path; +} + +const gchar * +gabble_base_call_content_get_name (GabbleBaseCallContent *self) +{ + g_return_val_if_fail (GABBLE_IS_BASE_CALL_CONTENT (self), NULL); + + return self->priv->name; +} + +TpMediaStreamType +gabble_base_call_content_get_media_type (GabbleBaseCallContent *self) +{ + g_return_val_if_fail (GABBLE_IS_BASE_CALL_CONTENT (self), + TP_MEDIA_STREAM_TYPE_AUDIO); + + return self->priv->media_type; +} + +TpCallContentDisposition +gabble_base_call_content_get_disposition (GabbleBaseCallContent *self) +{ + g_return_val_if_fail (GABBLE_IS_BASE_CALL_CONTENT (self), + TP_CALL_CONTENT_DISPOSITION_NONE); + + return self->priv->disposition; +} + +GList * +gabble_base_call_content_get_streams (GabbleBaseCallContent *self) +{ + g_return_val_if_fail (GABBLE_IS_BASE_CALL_CONTENT (self), NULL); + + return self->priv->streams; +} + +void +gabble_base_call_content_add_stream (GabbleBaseCallContent *self, + GabbleBaseCallStream *stream) +{ + g_return_if_fail (GABBLE_IS_BASE_CALL_CONTENT (self)); + + self->priv->streams = g_list_prepend (self->priv->streams, + g_object_ref (stream)); + ring_svc_call_content_emit_stream_added (self, + gabble_base_call_stream_get_object_path (stream)); +} + +void +gabble_base_call_content_remove_stream (GabbleBaseCallContent *self, + GabbleBaseCallStream *stream) +{ + GabbleBaseCallContentPrivate *priv; + GList *l; + + g_return_if_fail (GABBLE_IS_BASE_CALL_CONTENT (self)); + + priv = self->priv; + + l = g_list_find (priv->streams, stream); + g_return_if_fail (l != NULL); + + priv->streams = g_list_remove_link (priv->streams, l); + ring_svc_call_content_emit_stream_removed (self, + gabble_base_call_stream_get_object_path (stream)); + g_object_unref (stream); +} + +static void +base_call_content_deinit_real (GabbleBaseCallContent *self) +{ + GabbleBaseCallContentPrivate *priv = self->priv; + + if (priv->deinit_has_run) + return; + + priv->deinit_has_run = TRUE; + + tp_dbus_daemon_unregister_object (priv->dbus_daemon, G_OBJECT (self)); + tp_clear_object (&priv->dbus_daemon); + + g_list_foreach (priv->streams, (GFunc) g_object_unref, NULL); + tp_clear_pointer (&priv->streams, g_list_free); +} + +void +gabble_base_call_content_deinit (GabbleBaseCallContent *self) +{ + GabbleBaseCallContentClass *klass; + + g_return_if_fail (GABBLE_IS_BASE_CALL_CONTENT (self)); + + klass = GABBLE_BASE_CALL_CONTENT_GET_CLASS (self); + g_return_if_fail (klass->deinit != NULL); + klass->deinit (self); +} diff --git a/src/base-call-content.h b/src/base-call-content.h new file mode 100644 index 0000000..705f7b1 --- /dev/null +++ b/src/base-call-content.h @@ -0,0 +1,97 @@ +/* + * base-call-content.h - Header for GabbleBaseBaseCallContent + * Copyright © 2009–2010 Collabora Ltd. + * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk> + * @author Will Thompson <will.thompson@collabora.co.uk> + * + * 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 GABBLE_BASE_CALL_CONTENT_H +#define GABBLE_BASE_CALL_CONTENT_H + +#include <glib-object.h> + +#include <telepathy-glib/telepathy-glib.h> + +#include <ring-extensions/ring-extensions.h> + +#include "ring-connection.h" +#include "base-call-stream.h" + +G_BEGIN_DECLS + +typedef struct _GabbleBaseCallContent GabbleBaseCallContent; +typedef struct _GabbleBaseCallContentPrivate GabbleBaseCallContentPrivate; +typedef struct _GabbleBaseCallContentClass GabbleBaseCallContentClass; + +typedef void (*GabbleBaseCallContentFunc) (GabbleBaseCallContent *); + +struct _GabbleBaseCallContentClass { + GObjectClass parent_class; + + TpDBusPropertiesMixinClass dbus_props_class; + + const gchar * const *extra_interfaces; + GabbleBaseCallContentFunc deinit; +}; + +struct _GabbleBaseCallContent { + GObject parent; + + GabbleBaseCallContentPrivate *priv; +}; + +GType gabble_base_call_content_get_type (void); + +/* TYPE MACROS */ +#define GABBLE_TYPE_BASE_CALL_CONTENT \ + (gabble_base_call_content_get_type ()) +#define GABBLE_BASE_CALL_CONTENT(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GABBLE_TYPE_BASE_CALL_CONTENT, GabbleBaseCallContent)) +#define GABBLE_BASE_CALL_CONTENT_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GABBLE_TYPE_BASE_CALL_CONTENT, GabbleBaseCallContentClass)) +#define GABBLE_IS_BASE_CALL_CONTENT(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GABBLE_TYPE_BASE_CALL_CONTENT)) +#define GABBLE_IS_BASE_CALL_CONTENT_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GABBLE_TYPE_BASE_CALL_CONTENT)) +#define GABBLE_BASE_CALL_CONTENT_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + GABBLE_TYPE_BASE_CALL_CONTENT, GabbleBaseCallContentClass)) + +RingConnection *gabble_base_call_content_get_connection ( + GabbleBaseCallContent *self); +const gchar *gabble_base_call_content_get_object_path ( + GabbleBaseCallContent *self); + +const gchar *gabble_base_call_content_get_name (GabbleBaseCallContent *self); +TpMediaStreamType gabble_base_call_content_get_media_type ( + GabbleBaseCallContent *self); +TpCallContentDisposition gabble_base_call_content_get_disposition ( + GabbleBaseCallContent *self); + +GList *gabble_base_call_content_get_streams (GabbleBaseCallContent *self); +void gabble_base_call_content_add_stream (GabbleBaseCallContent *self, + GabbleBaseCallStream *stream); +void gabble_base_call_content_remove_stream (GabbleBaseCallContent *self, + GabbleBaseCallStream *stream); + +void gabble_base_call_content_deinit (GabbleBaseCallContent *self); + +G_END_DECLS + +#endif /* #ifndef __GABBLE_BASE_CALL_CONTENT_H__*/ diff --git a/src/base-call-stream.c b/src/base-call-stream.c new file mode 100644 index 0000000..e8449aa --- /dev/null +++ b/src/base-call-stream.c @@ -0,0 +1,351 @@ +/* + * base-call-stream.c - Source for GabbleBaseCallStream + * Copyright © 2009–2010 Collabora Ltd. + * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk> + * @author Will Thompson <will.thompson@collabora.co.uk> + * + * 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 "base-call-stream.h" + +#define DEBUG_FLAG RING_DEBUG_MEDIA +#include "ring-debug.h" + +#include "ring-connection.h" + +G_DEFINE_TYPE_WITH_CODE(GabbleBaseCallStream, gabble_base_call_stream, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES, + tp_dbus_properties_mixin_iface_init); + /* The base class doesn't implement SetSending or RequestReceiving, because + * they're pretty protocol-specific. It just implements the properties. */ + G_IMPLEMENT_INTERFACE (RING_TYPE_SVC_CALL_STREAM, NULL); + ) + +enum +{ + PROP_OBJECT_PATH = 1, + PROP_CONNECTION, + + /* Call interface properties */ + PROP_INTERFACES, + PROP_SENDERS, +}; + +struct _GabbleBaseCallStreamPrivate +{ + gboolean dispose_has_run; + + gchar *object_path; + RingConnection *conn; + + GHashTable *senders; +}; + +static void +gabble_base_call_stream_init (GabbleBaseCallStream *self) +{ + GabbleBaseCallStreamPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self, + GABBLE_TYPE_BASE_CALL_STREAM, GabbleBaseCallStreamPrivate); + + self->priv = priv; + priv->senders = g_hash_table_new (g_direct_hash, g_direct_equal); +} + +static void +gabble_base_call_stream_constructed (GObject *obj) +{ + GabbleBaseCallStream *self = GABBLE_BASE_CALL_STREAM (obj); + GabbleBaseCallStreamPrivate *priv = self->priv; + TpDBusDaemon *bus = tp_base_connection_get_dbus_daemon ( + (TpBaseConnection *) priv->conn); + + if (G_OBJECT_CLASS (gabble_base_call_stream_parent_class)->constructed + != NULL) + G_OBJECT_CLASS (gabble_base_call_stream_parent_class)->constructed (obj); + + DEBUG ("Registering %s", priv->object_path); + tp_dbus_daemon_register_object (bus, priv->object_path, obj); +} + +static void +gabble_base_call_stream_dispose (GObject *object) +{ + GabbleBaseCallStream *self = GABBLE_BASE_CALL_STREAM (object); + GabbleBaseCallStreamPrivate *priv = self->priv; + + if (priv->dispose_has_run) + return; + + priv->dispose_has_run = TRUE; + + tp_clear_object (&priv->conn); + + if (G_OBJECT_CLASS (gabble_base_call_stream_parent_class)->dispose != NULL) + G_OBJECT_CLASS (gabble_base_call_stream_parent_class)->dispose (object); +} + +static void +gabble_base_call_stream_finalize (GObject *object) +{ + GabbleBaseCallStream *self = GABBLE_BASE_CALL_STREAM (object); + GabbleBaseCallStreamPrivate *priv = self->priv; + + /* free any data held directly by the object here */ + g_free (priv->object_path); + g_hash_table_destroy (priv->senders); + + if (G_OBJECT_CLASS (gabble_base_call_stream_parent_class)->finalize != NULL) + G_OBJECT_CLASS (gabble_base_call_stream_parent_class)->finalize (object); +} + +static void +gabble_base_call_stream_get_property ( + GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GabbleBaseCallStream *self = GABBLE_BASE_CALL_STREAM (object); + GabbleBaseCallStreamPrivate *priv = self->priv; + + switch (property_id) + { + case PROP_CONNECTION: + g_value_set_object (value, priv->conn); + break; + case PROP_OBJECT_PATH: + g_value_set_string (value, priv->object_path); + break; + case PROP_INTERFACES: + { + GabbleBaseCallStreamClass *klass = + GABBLE_BASE_CALL_STREAM_GET_CLASS (self); + + if (klass->extra_interfaces != NULL) + { + g_value_set_boxed (value, klass->extra_interfaces); + } + else + { + gchar *empty[] = { NULL }; + + g_value_set_boxed (value, empty); + } + break; + } + case PROP_SENDERS: + g_value_set_boxed (value, priv->senders); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gabble_base_call_stream_set_property ( + GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GabbleBaseCallStream *self = GABBLE_BASE_CALL_STREAM (object); + GabbleBaseCallStreamPrivate *priv = self->priv; + + switch (property_id) + { + case PROP_CONNECTION: + priv->conn = g_value_dup_object (value); + g_assert (priv->conn != NULL); + break; + case PROP_OBJECT_PATH: + g_free (priv->object_path); + priv->object_path = g_value_dup_string (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gabble_base_call_stream_class_init (GabbleBaseCallStreamClass *bsc_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (bsc_class); + GParamSpec *param_spec; + static TpDBusPropertiesMixinPropImpl stream_props[] = { + { "Interfaces", "interfaces", NULL }, + { "Senders", "senders", NULL }, + { NULL } + }; + static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = { + { RING_IFACE_CALL_STREAM, + tp_dbus_properties_mixin_getter_gobject_properties, + NULL, + stream_props, + }, + { NULL } + }; + + g_type_class_add_private (bsc_class, sizeof (GabbleBaseCallStreamPrivate)); + + object_class->constructed = gabble_base_call_stream_constructed; + object_class->dispose = gabble_base_call_stream_dispose; + object_class->finalize = gabble_base_call_stream_finalize; + object_class->set_property = gabble_base_call_stream_set_property; + object_class->get_property = gabble_base_call_stream_get_property; + + param_spec = g_param_spec_string ("object-path", "D-Bus object path", + "The D-Bus object path used for this object on the bus.", + NULL, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_OBJECT_PATH, param_spec); + + param_spec = g_param_spec_boxed ("interfaces", "Extra D-Bus interfaces", + "Additional interfaces implemented by this stream", + G_TYPE_STRV, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_INTERFACES, param_spec); + + param_spec = g_param_spec_boxed ("senders", "Senders", + "Sender map", + RING_HASH_TYPE_CONTACT_SENDING_STATE_MAP, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_SENDERS, param_spec); + + param_spec = g_param_spec_object ("connection", "RingConnection object", + "Gabble connection object that owns this call stream", + RING_TYPE_CONNECTION, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_CONNECTION, param_spec); + + bsc_class->dbus_props_class.interfaces = prop_interfaces; + tp_dbus_properties_mixin_class_init (object_class, + G_STRUCT_OFFSET (GabbleBaseCallStreamClass, dbus_props_class)); +} + +RingConnection * +gabble_base_call_stream_get_connection (GabbleBaseCallStream *self) +{ + g_return_val_if_fail (GABBLE_IS_BASE_CALL_STREAM (self), NULL); + + return self->priv->conn; +} + +const gchar * +gabble_base_call_stream_get_object_path (GabbleBaseCallStream *self) +{ + g_return_val_if_fail (GABBLE_IS_BASE_CALL_STREAM (self), NULL); + + return self->priv->object_path; +} + +static gboolean +base_call_stream_sender_update_state (GabbleBaseCallStream *self, + TpHandle contact, + TpSendingState state) +{ + GabbleBaseCallStreamPrivate *priv = self->priv; + gpointer state_p = 0; + gboolean exists; + + exists = g_hash_table_lookup_extended (priv->senders, + GUINT_TO_POINTER (contact), + NULL, + &state_p); + + if (exists && GPOINTER_TO_UINT (state_p) == state) + return FALSE; + + DEBUG ("Updating sender %d state: %d => %d", contact, + GPOINTER_TO_UINT (state_p), state); + + g_hash_table_insert (priv->senders, + GUINT_TO_POINTER (contact), + GUINT_TO_POINTER (state)); + + return TRUE; +} + +gboolean +gabble_base_call_stream_update_senders ( + GabbleBaseCallStream *self, + TpHandle contact, + TpSendingState state, + ...) +{ + GHashTable *updates = g_hash_table_new (g_direct_hash, g_direct_equal); + gboolean updated = FALSE; + va_list args; + + va_start (args, state); + + do + { + if (base_call_stream_sender_update_state (self, contact, state)) + { + g_hash_table_insert (updates, + GUINT_TO_POINTER (contact), + GUINT_TO_POINTER (state)); + updated = TRUE; + } + + contact = va_arg (args, TpHandle); + if (contact != 0) + state = va_arg (args, TpSendingState); + } + while (contact != 0); + + if (updated) + { + GArray *empty = g_array_new (FALSE, TRUE, sizeof (TpHandle)); + + ring_svc_call_stream_emit_senders_changed (self, updates, empty); + g_array_unref (empty); + } + + g_hash_table_unref (updates); + return updated; +} + +TpSendingState +gabble_base_call_stream_get_sender_state ( + GabbleBaseCallStream *self, + TpHandle sender, + gboolean *existed) +{ + gpointer state; + + g_return_val_if_fail (GABBLE_IS_BASE_CALL_STREAM (self), + TP_SENDING_STATE_NONE); + + if (g_hash_table_lookup_extended (self->priv->senders, + GUINT_TO_POINTER (sender), NULL, &state)) + { + if (existed != NULL) + *existed = TRUE; + + return GPOINTER_TO_UINT (state); + } + else + { + if (existed != NULL) + *existed = FALSE; + + return TP_SENDING_STATE_NONE; + } +} diff --git a/src/base-call-stream.h b/src/base-call-stream.h new file mode 100644 index 0000000..b33ef7c --- /dev/null +++ b/src/base-call-stream.h @@ -0,0 +1,87 @@ +/* + * base-call-stream.h - Header for GabbleBaseCallStream + * Copyright © 2009–2010 Collabora Ltd. + * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk> + * @author Will Thompson <will.thompson@collabora.co.uk> + * + * 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 GABBLE_BASE_CALL_STREAM_H +#define GABBLE_BASE_CALL_STREAM_H + +#include <glib-object.h> + +#include <telepathy-glib/telepathy-glib.h> +#include <ring-extensions/ring-extensions.h> + +#include "ring-connection.h" + +G_BEGIN_DECLS + +typedef struct _GabbleBaseCallStream GabbleBaseCallStream; +typedef struct _GabbleBaseCallStreamPrivate GabbleBaseCallStreamPrivate; +typedef struct _GabbleBaseCallStreamClass GabbleBaseCallStreamClass; + +struct _GabbleBaseCallStreamClass { + GObjectClass parent_class; + + TpDBusPropertiesMixinClass dbus_props_class; + + const gchar * const *extra_interfaces; +}; + +struct _GabbleBaseCallStream { + GObject parent; + + GabbleBaseCallStreamPrivate *priv; +}; + +GType gabble_base_call_stream_get_type (void); + +/* TYPE MACROS */ +#define GABBLE_TYPE_BASE_CALL_STREAM \ + (gabble_base_call_stream_get_type ()) +#define GABBLE_BASE_CALL_STREAM(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), GABBLE_TYPE_BASE_CALL_STREAM, GabbleBaseCallStream)) +#define GABBLE_BASE_CALL_STREAM_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), GABBLE_TYPE_BASE_CALL_STREAM, \ + GabbleBaseCallStreamClass)) +#define GABBLE_IS_BASE_CALL_STREAM(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GABBLE_TYPE_BASE_CALL_STREAM)) +#define GABBLE_IS_BASE_CALL_STREAM_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GABBLE_TYPE_BASE_CALL_STREAM)) +#define GABBLE_BASE_CALL_STREAM_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GABBLE_TYPE_BASE_CALL_STREAM, \ + GabbleBaseCallStreamClass)) + +RingConnection *gabble_base_call_stream_get_connection ( + GabbleBaseCallStream *self); +const gchar *gabble_base_call_stream_get_object_path ( + GabbleBaseCallStream *self); + +TpSendingState gabble_base_call_stream_get_sender_state ( + GabbleBaseCallStream *self, + TpHandle sender, + gboolean *existed); +gboolean gabble_base_call_stream_update_senders ( + GabbleBaseCallStream *self, + TpHandle contact, + TpSendingState state, + ...) G_GNUC_NULL_TERMINATED; + +G_END_DECLS + +#endif diff --git a/src/ring-call-content.c b/src/ring-call-content.c new file mode 100644 index 0000000..30cc802 --- /dev/null +++ b/src/ring-call-content.c @@ -0,0 +1,140 @@ +/* + * ring-call-content.c - a Content object owned by a Call channel + * Copyright ©2010 Collabora Ltd. + * Copyright ©2010 Nokia Corporation + * @author Will Thompson <will.thompson@collabora.co.uk> + * + * 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 "ring-call-content.h" + +#include <telepathy-glib/telepathy-glib.h> + +#include <ring-extensions/ring-extensions.h> + +#define DEBUG_FLAG RING_DEBUG_MEDIA +#include "ring-debug.h" + +struct _RingCallContentPrivate { + RingCallStream *stream; +}; + +static void implement_call_content (gpointer klass, + gpointer unused G_GNUC_UNUSED); + +G_DEFINE_TYPE_WITH_CODE (RingCallContent, ring_call_content, + GABBLE_TYPE_BASE_CALL_CONTENT, + G_IMPLEMENT_INTERFACE (RING_TYPE_SVC_CALL_CONTENT, implement_call_content); +) + +static void +ring_call_content_init (RingCallContent *self) +{ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, RING_TYPE_CALL_CONTENT, + RingCallContentPrivate); +} + +static void +ring_call_content_constructed (GObject *object) +{ + RingCallContent *self = RING_CALL_CONTENT (object); + RingCallContentPrivate *priv = self->priv; + GabbleBaseCallContent *base = GABBLE_BASE_CALL_CONTENT (self); + gchar *stream_path; + + if (G_OBJECT_CLASS (ring_call_content_parent_class)->constructed != NULL) + G_OBJECT_CLASS (ring_call_content_parent_class)->constructed (object); + + stream_path = g_strdup_printf ("%s/%s", + gabble_base_call_content_get_object_path (base), "stream"); + priv->stream = ring_call_stream_new ( + gabble_base_call_content_get_connection (base), stream_path); + gabble_base_call_content_add_stream (base, + GABBLE_BASE_CALL_STREAM (priv->stream)); + g_free (stream_path); +} + +static void +ring_call_content_dispose (GObject *object) +{ + RingCallContent *self = RING_CALL_CONTENT (object); + RingCallContentPrivate *priv = self->priv; + + tp_clear_object (&priv->stream); + + if (G_OBJECT_CLASS (ring_call_content_parent_class)->dispose != NULL) + G_OBJECT_CLASS (ring_call_content_parent_class)->dispose (object); +} + +static void +ring_call_content_class_init (RingCallContentClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->constructed = ring_call_content_constructed; + object_class->dispose = ring_call_content_dispose; + + g_type_class_add_private (klass, sizeof (RingCallContentPrivate)); +} + +RingCallContent * +ring_call_content_new (RingConnection *connection, + const gchar *object_path, + TpHandle creator) +{ + return g_object_new (RING_TYPE_CALL_CONTENT, + "connection", connection, + "object-path", object_path, + "name", "audio", + "media-type", TP_MEDIA_STREAM_TYPE_AUDIO, + "creator", creator, + "disposition", TP_CALL_CONTENT_DISPOSITION_INITIAL, + NULL); +} + +RingCallStream * +ring_call_content_get_stream (RingCallContent *self) +{ + g_return_val_if_fail (RING_IS_CALL_CONTENT (self), NULL); + + return self->priv->stream; +} + +static void +ring_call_content_remove ( + RingSvcCallContent *self, + DBusGMethodInvocation *context) +{ + /* We could just leave all this out — the base class leaves Remove() + * unimplemented, so TP_ERROR_NOT_IMPLEMENTED would be returned just like + * this. But I think having a less generic error message is worth thirty(!) + * lines of boilerplate. + */ + GError error = { TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, + "Removing contents is not supported for cellular calls." }; + + dbus_g_method_return_error (context, &error); +} + +static void +implement_call_content (gpointer klass, + gpointer unused G_GNUC_UNUSED) +{ +#define IMPLEMENT(x) ring_svc_call_content_implement_##x (\ + klass, ring_call_content_##x) + IMPLEMENT (remove); +#undef IMPLEMENT +} diff --git a/src/ring-call-content.h b/src/ring-call-content.h new file mode 100644 index 0000000..a33a4be --- /dev/null +++ b/src/ring-call-content.h @@ -0,0 +1,68 @@ +/* + * ring-call-content.h - header for a Content object owned by a Call channel + * Copyright ©2010 Collabora Ltd. + * Copyright ©2010 Nokia Corporation + * @author Will Thompson <will.thompson@collabora.co.uk> + * + * 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 RING_CALL_CONTENT_H +#define RING_CALL_CONTENT_H + +#include <glib-object.h> + +#include "base-call-content.h" +#include "ring-call-stream.h" + +typedef struct _RingCallContent RingCallContent; +typedef struct _RingCallContentClass RingCallContentClass; +typedef struct _RingCallContentPrivate RingCallContentPrivate; + +struct _RingCallContentClass { + GabbleBaseCallContentClass parent_class; +}; + +struct _RingCallContent { + GabbleBaseCallContent parent; + + RingCallContentPrivate *priv; +}; + +GType ring_call_content_get_type (void); + +RingCallContent *ring_call_content_new (RingConnection *connection, + const gchar *object_path, + TpHandle creator); + +RingCallStream *ring_call_content_get_stream (RingCallContent *self); + +/* TYPE MACROS */ +#define RING_TYPE_CALL_CONTENT \ + (ring_call_content_get_type ()) +#define RING_CALL_CONTENT(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), RING_TYPE_CALL_CONTENT, RingCallContent)) +#define RING_CALL_CONTENT_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), RING_TYPE_CALL_CONTENT,\ + RingCallContentClass)) +#define RING_IS_CALL_CONTENT(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), RING_TYPE_CALL_CONTENT)) +#define RING_IS_CALL_CONTENT_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), RING_TYPE_CALL_CONTENT)) +#define RING_CALL_CONTENT_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), RING_TYPE_CALL_CONTENT, \ + RingCallContentClass)) + +#endif /* RING_CALL_CONTENT_H */ diff --git a/src/ring-call-stream.c b/src/ring-call-stream.c new file mode 100644 index 0000000..d79e83f --- /dev/null +++ b/src/ring-call-stream.c @@ -0,0 +1,90 @@ +/* + * ring-call-stream.c - a Stream object owned by a RingCallContent + * Copyright ©2010 Collabora Ltd. + * Copyright ©2010 Nokia Corporation + * @author Will Thompson <will.thompson@collabora.co.uk> + * + * 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 "ring-call-stream.h" + +#define DEBUG_FLAG RING_DEBUG_MEDIA +#include "ring-debug.h" + +static void implement_call_stream (gpointer klass, gpointer unused); + +G_DEFINE_TYPE_WITH_CODE (RingCallStream, ring_call_stream, + GABBLE_TYPE_BASE_CALL_STREAM, + G_IMPLEMENT_INTERFACE (RING_TYPE_SVC_CALL_STREAM, implement_call_stream) +) + +static void +ring_call_stream_init (RingCallStream *self) +{ +} + +static void +ring_call_stream_class_init (RingCallStreamClass *klass) +{ +} + +RingCallStream * +ring_call_stream_new (RingConnection *connection, + const gchar *object_path) +{ + return g_object_new (RING_TYPE_CALL_STREAM, + "connection", connection, + "object-path", object_path, + NULL); +} + +static void +ring_call_stream_set_sending ( + RingSvcCallStream *self, + gboolean send, + DBusGMethodInvocation *context) +{ + GError error = { TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, + "SetSending is not supported for cellular calls." }; + + /* Maybe we should put the call on hold/resume? */ + + dbus_g_method_return_error (context, &error); +} + +static void +ring_call_stream_request_receiving ( + RingSvcCallStream *self, + TpHandle contact, + gboolean receive, + DBusGMethodInvocation *context) +{ + GError error = { TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, + "RequestReceiving is not supported for cellular calls." }; + + dbus_g_method_return_error (context, &error); +} + +static void +implement_call_stream (gpointer klass, + gpointer unused G_GNUC_UNUSED) +{ +#define IMPLEMENT(x) ring_svc_call_stream_implement_##x (\ + klass, ring_call_stream_##x) + IMPLEMENT (set_sending); + IMPLEMENT (request_receiving); +#undef IMPLEMENT +} diff --git a/src/ring-call-stream.h b/src/ring-call-stream.h new file mode 100644 index 0000000..d0930d6 --- /dev/null +++ b/src/ring-call-stream.h @@ -0,0 +1,61 @@ +/* + * ring-call-stream.h - header for a Stream object owned by a RingCallContent + * Copyright ©2010 Collabora Ltd. + * Copyright ©2010 Nokia Corporation + * @author Will Thompson <will.thompson@collabora.co.uk> + * + * 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 RING_CALL_STREAM_H +#define RING_CALL_STREAM_H + +#include <glib-object.h> + +#include "base-call-stream.h" + +typedef struct _RingCallStream RingCallStream; +typedef struct _RingCallStreamClass RingCallStreamClass; + +struct _RingCallStreamClass { + GabbleBaseCallStreamClass parent_class; +}; + +struct _RingCallStream { + GabbleBaseCallStream parent; +}; + +GType ring_call_stream_get_type (void); + +RingCallStream *ring_call_stream_new (RingConnection *connection, + const gchar *object_path); + +/* TYPE MACROS */ +#define RING_TYPE_CALL_STREAM \ + (ring_call_stream_get_type ()) +#define RING_CALL_STREAM(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), RING_TYPE_CALL_STREAM, RingCallStream)) +#define RING_CALL_STREAM_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), RING_TYPE_CALL_STREAM,\ + RingCallStreamClass)) +#define RING_IS_CALL_STREAM(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), RING_TYPE_CALL_STREAM)) +#define RING_IS_CALL_STREAM_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), RING_TYPE_CALL_STREAM)) +#define RING_CALL_STREAM_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), RING_TYPE_CALL_STREAM, \ + RingCallStreamClass)) + +#endif /* RING_CALL_STREAM_H */ |