summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Swindell <t.swindell@rubyx.co.uk>2013-03-04 12:30:37 +0000
committerTom Swindell <t.swindell@rubyx.co.uk>2013-03-04 12:30:37 +0000
commit41a3143837ee5fcabf7959cae1fec17a7a0ff5ae (patch)
treeb574dbf504c68bb1c222d01cd61b11ab8bef1679
parent7f88b8c4d039fe7e534ebe2ec8f2dbadea3a3def (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.xml168
-rw-r--r--ring-extensions/Call_Stream.xml178
-rw-r--r--ring-extensions/Channel_Type_Call.xml946
-rw-r--r--ring-extensions/Makefile.am3
-rw-r--r--src/Makefile.am5
-rw-r--r--src/base-call-channel.c761
-rw-r--r--src/base-call-channel.h104
-rw-r--r--src/base-call-content.c434
-rw-r--r--src/base-call-content.h97
-rw-r--r--src/base-call-stream.c351
-rw-r--r--src/base-call-stream.h87
-rw-r--r--src/ring-call-content.c140
-rw-r--r--src/ring-call-content.h68
-rw-r--r--src/ring-call-stream.c90
-rw-r--r--src/ring-call-stream.h61
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 */