Copyright © 2009 Collabora Limited Copyright © 2009 Nokia Corporation

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

(as stable API)

An interface for multi-user conference channels that can "continue from" one or more individual channels. This could be used to invite other contacts to an existing 1-1 text conversation, combine two phone calls into one conference call, and so on, with roughly the same API in each case.

This interface addresses freedesktop.org bug #24906 (GSM-compatible conference calls) and bug #24939 (upgrading calls and chats to multi-user). See those bugs for more rationale and use cases.

Existing channels are upgraded by requesting a new channel of the same ChannelType, listing the channels to be merged into the new conference in the InitialChannels property of the request. If InitialInviteeHandles and InitialInviteeIDs are Allowed_Properties in RequestableChannelClasses, ad-hoc conferences to a set of contacts may be created by requesting a channel, specifying InitialInviteeHandles and/or InitialInviteeIDs to be the contacts in question. A request may specify these alongside InitialChannels, to simultaneously upgrade a channel to a conference and invite others to join it.

Channels with this interface MAY also implement MergeableConference1 to support merging more 1-1 channels into an ongoing conference. Similarly, 1-1 channels MAY implement Splittable1 to support being broken out of a Conference channel.

The Group1 interface on Conference channels MAY use channel-specific handles for participants; clients SHOULD support both Conferences that have channel-specific handles, and those that do not.

In the GSM case, the Conference's Group interface MAY have channel-specific handles, to represent the fact that the same phone number may be in a conference twice (for instance, it could be the number of a corporate switchboard).

In the XMPP case, the Conference's Group interface SHOULD have channel-specific handles, to reflect the fact that the participants have MUC-specific identities, and the user might also be able to see their global identities, or not.

In most other cases, including MSN and link-local XMPP, the Conference's Group interface SHOULD NOT have channel-specific handles, since users' identities are always visible.

Connection managers implementing channels with this interface MUST NOT allow the object paths of channels that could be merged into a Conference to be re-used, unless the channel re-using the object path is equivalent to the channel that previously used it.

If you upgrade some channels into a conference, and then close the original channels, InitialChannels (which is immutable) will contain paths to channels which no longer exist. This implies that you should not re-use channel object paths, unless future incarnations of the path are equivalent.

For instance, on protocols where you can only have zero or one 1-1 text channels with Emily at one time, it would be OK to re-use the same object path for every 1-1 text channel with Emily; but on protocols where this is not true, it would be misleading.

Examples of usage

A pair of 1-1 GSM calls C1 and C2 can be merged into a single conference call by calling:

CreateChannel({ ...ChannelType: ...Call, ...InitialChannels: [C1, C2] })

which returns a new channel Cn implementing the conference interface. (As a quirk of GSM, both 1-1 will cease to function normally until they are Split from the conference, or the conference ends.)

An XMPP 1-1 conversation C3 (with chris@example.com, say) can be continued in a newly created multi-user chatroom by calling:

CreateChannel({ ...ChannelType: ...Text, ...InitialChannels: [C3] })

Or, to invite emily@example.net to join the newly-created MUC at the same time:

CreateChannel({ ...ChannelType: ...Text, ...InitialChannels: [C3], ...InitialInviteeIDs: ['emily@example.net'] })

To continue C3 in a particular multi-user chatroom (rather than the implementation inventing a unique name for the room), call:

EnsureChannel({ ...ChannelType: ...Text, ...TargetHandleType: ...Room, ...TargetID: 'telepathy@conf.example.com', ...InitialChannels: [C3] })

Note the use of EnsureChannel — if a channel for telepathy@conf.example.com is already open, this SHOULD be equivalent to inviting chris@example.com to the existing channel.

In the above cases, the text channel C3 SHOULD remain open and fully functional (until explicitly closed by a client); new incoming 1-1 messages from chris@example.com SHOULD appear in C3, and messages sent using C3 MUST be relayed only to chris@example.com.

If there is an open 1-1 text channel with a contact, in every other situation new messages will appear in that channel. Given that the old channel remains open — which is the least surprising behaviour, and eases us towards a beautiful world where channels never close themselves — it stands to reason that it should be where new messages from Chris should appear. On MSN, creating a conference from C3 should migrate the underlying switchboard from C3 to the new channel; this is an implementation detail, and should not affect the representation on D-Bus. With a suitable change of terminology, Skype has the same behaviour.

If the current handler of that channel doesn't want this to happen (maybe it transformed the existing tab into the group chat window, and so there'd be no UI element still around to show new messages), then it should just Close the old 1-1 channel; it'll respawn if necessary.

Either of the XMPP cases could work for Call channels, to upgrade from 1-1 Jingle to multi-user Jingle. Any of the XMPP cases could in principle work for link-local XMPP (XEP-0174).

XMPP and MSN do not natively have a concept of merging two or more channels C1, C2... into one channel, Cn. However, the GSM-style merging API can be supported on XMPP and MSN, as an API short-cut for upgrading C1 into a conference Cn (which invites the TargetHandle of C1 into Cn), then immediately inviting the TargetHandle of C2, the TargetHandle of C3, etc. into Cn as well.

Sample RequestableChannelClasses

A GSM connection might advertise the following channel class for conference calls:

( Fixed = {
    ...ChannelType: ...Call1
  },
  Allowed = [ InitialChannels, InitialAudio ]
)

This indicates support for starting audio-only conference calls by merging two or more existing channels (since InitialInviteeHandles and InitialInviteeIDs are not allowed).

An XMPP connection might advertise the following classes for ad-hoc multi-user text chats:

( Fixed = {
    ...ChannelType: ...Text
  },
  Allowed = [ InitialChannels, InitialInviteeHandles, InitialInviteeIDs, InvitationMessage ]
),
( Fixed = {
    ...ChannelType: ...Text,
    ...TargetHandleType: Room
  },
  Allowed = [ TargetHandle, TargetID,
              InitialChannels, InitialInviteeHandles, InitialInviteeIDs, InvitationMessage ]
)

The first class indicates support for starting ad-hoc (nameless) chat rooms, upgraded from existing 1-1 channels and/or inviting new contacts, along with a message to be sent along with the invitations. The second indicates support for upgrading to a particular named chat room.

The individual Channels that are continued by this conference, which have the same ChannelType as this one, but with TargetHandleType = CONTACT.

This property MUST NOT be requestable; instead, the InitialChannels property may be specified when requesting a channel.

This is consistent with requesting InitialInviteeHandles and InitialInviteeIDs, rather than requesting Group1.Members and some hypothetical ID version of that property.

Change notification is via the ChannelMerged and ChannelRemoved signals.

Emitted when a new channel is added to the value of Channels.

The channel that was added to Channels. A new channel-specific handle for the TargetHandle of Channel, as will appear in OriginalChannels, or 0 if a global handle is used for Channel's TargetHandle on the Group1 interface of this channel. Channel's immutable properties.

Emitted when a channel is removed from the value of Channels, either because it closed or because it was split using the Splittable1.Split method.

If a channel is removed because it was closed, Closed should be emitted before this signal.

The channel that was removed from Channels. Additional information about the removal, which may include the same well-known keys as the Details argument of MembersChanged, with the same semantics.

The initial value of Channels.

This property SHOULD be requestable. Omitting it from a request is equivalent to providing it with an empty list as value. Requests where its value has at least two channel paths SHOULD be expected to succeed on any implementation of this interface. If InitialInviteeHandles and InitialInviteeIDs are Allowed_Properties in RequestableChannelClasses, then requests with zero or one channel paths SHOULD also succeed; otherwise, clients SHOULD NOT make requests with zero or one paths for this property.

In GSM, a pair of calls can be merged into a conference, but you can't start a conference call from zero or one existing calls. In XMPP and MSN, you can create a new chatroom, or upgrade one 1-1 channel into a chatroom; however, on these protocols, it is also possible to fake GSM-style merging by upgrading the first channel, then inviting the targets of all the other channels into it.

If possible, the Channels' states SHOULD NOT be altered by merging them into a conference. However, depending on the protocol, the Channels MAY be placed in a "frozen" state by placing them in this property's value or by calling MergeableConference1.Merge on them.

In Jingle, nothing special will happen to merged calls. UIs MAY automatically place calls on hold before merging them, if that is the desired behaviour; this SHOULD always work. Not doing an implicit hold/unhold seems to preserve least-astonishment.

In GSM, the calls that are merged go into a state similar to Hold, but they cannot be unheld, only split from the conference call using Channel.Interface.Splittable1.Split.

Depending on the protocol, it might be signalled to remote users that this channel is a continuation of all the requested channels, or that it is only a continuation of the first channel in the list.

In MSN, the conference steals the underlying switchboard (protocol construct) from one of its component channels, so the conference appears to remote users to be a continuation of that channel and no other. The connection manager has to make some arbitrary choice, so we arbitrarily mandate that it SHOULD choose the first channel in the list as the one to continue.

A list of additional contacts invited to this conference when it was created.

If it is possible to invite new contacts when creating a conference (as opposed to merging several channels into one new conference channel), this property SHOULD be requestable, and appear in the allowed properties in RequestableChannelClasses. Otherwise, this property SHOULD NOT be requestable, and its value SHOULD always be the empty list.

On GSM you have to place a 1-1 call before you can merge it into a conference; on the other hand, you can invite new contacts to XMPP Muji calls and XMPP/MSN/Skype ad-hoc chat rooms without starting a 1-1 channel with them first.

If included in a request, the given contacts are automatically invited into the new channel, as if they had been added with Group1.AddMembers(InitialInviteeHandles, InvitationMessage) immediately after the channel was created.

This is a simple convenience API for the common case that a UI upgrades a 1-1 chat to a multi-user chat solely in order to invite someone else to participate.

If the local user was not the initiator of this channel, the Group1.SelfHandle SHOULD appear in the value of this property, together with any other contacts invited at the same time (if that information is known).

InitialInviteeHandles, InitialInviteeIDs and InitialChannels MAY be combined in a single request.

For example, if you have a 1-1 channel C1 with Rob, and you want to invite Sjoerd to join the discussion, you can do so by requesting a channel with InitialChannels=[C1] and InitialInviteeHandles=[sjoerd], or InitialChannels=[C1] and InitialInviteeIDs=["sjoerd@example.com"].

If a request includes some combination of InitialInviteeHandles, InitialInviteeIDs and InitialChannels, then the value of InitialInviteeHandles on the resulting channel SHOULD be the union of the handles from InitialInviteeHandles, the handles corresponding to the InitialInviteeIDs, and the target handles of the InitialChannels, with any duplicate handles removed. Because this property is immutable, its value SHOULD be computed before the channel is announced via the NewChannels signal.

This simplifies identification of new channels in clients - they only have to look at one of the properties, not both. For example, after either of the requests mentioned above, the NewChannels signal would announce the channel with InitialChannels=[C1], InitialInviteeHandles=[rob, sjoerd], and InitialInviteeIDs=["rob@example.net", "sjoerd.example.com"].

A list of additional contacts invited to this conference when it was created.

This property SHOULD be requestable if and only if InitialInviteeHandles is requestable. Its semantics are the same, except that it takes a list of the string representations of contact handles; invitations are sent to any contact present in either or both of these properties.

When a channel is created, the values of InitialInviteeHandles and InitialInviteeIDs MUST correspond to each other. In particular, this means that the value of InitialInviteeIDs will include the TargetID of each channel in InitialChannels, and the ID corresponding to each handle in InitialInviteeHandles.

The message that was sent to the InitialInviteeHandles when they were invited.

This property SHOULD be requestable, and appear in the allowed properties in RequestableChannelClasses, in protocols where invitations can have an accompanying text message.

This allows invitations with a message to be sent when using InitialInviteeHandles or InitialInviteeIDs.

If the local user was not the initiator of this channel, the message with which they were invited (if any) SHOULD appear in the value of this property.

On GSM conference calls, it is possible to have the same phone number in a conference twice; for instance, it could be the number of a corporate switchboard. This is represented using channel-specific handles; whether or not a channel uses channel-specific handles is reported in Group1.GroupFlags. The Group1.HandleOwners property specifies the mapping from opaque channel-specific handles to actual numbers; this property specifies the original 1-1 channel corresponding to each channel-specific handle in the conference.

In protocols where this situation cannot arise, such as XMPP, this property MAY remain empty.

For example, consider this situation:

  1. Place a call (with path /call/to/simon) to the contact +441234567890 (which is assigned the handle h, say), and ask to be put through to Simon McVittie;
  2. Put that call on hold;
  3. Place another call (with path /call/to/jonny) to +441234567890, and ask to be put through to Jonny Lamb;
  4. Request a new channel with InitialChannels: ['/call/to/simon', '/call/to/jonny'].

The new channel will have the following properties, for some handles s and j:

{
...Group1.GroupFlags: Channel_Specific_Handles | (other flags),
...Group1.Members: [self_handle, s, j],
...Group1.HandleOwners: { s: h, j: h },
...InitialChannels: ['/call/to/simon', '/call/to/jonny'],
...Channels: ['/call/to/simon', '/call/to/jonny'],
...OriginalChannels: { s: '/call/to/simon', j: '/call/to/jonny' },
# ...standard properties like ChannelType: Group elided...
}

Change notification is via the ChannelMerged and ChannelRemoved signals: if Channel_Specific_Handle in the former is non-zero, this property SHOULD be updated to map that handle to the merged channel's path.

A channel-specific handle for a participant in this conference. The object path of Channels representing the original 1-1 channel with Channel_Specific_Handle. A mapping from members of a conference to the original 1-1 channel with that contact, if any. See OriginalChannels for details.