[Asterisk-Dev] Presence, Barge-in, and auto-conferencing

John Todd jtodd at loligo.com
Tue Jun 8 09:20:39 MST 2004


[Very long.  Get a coffee and a comfortable chair.]

At 2:08 PM -0500 on 6/2/04, Steven Sokol wrote:
>Asterisk's MeetMe is powerful and flexible, but sometimes you just want to
>do an old-fashioned basic conference from the client, without having to
>transfer everybody into a conference room.  This is pretty common
>functionality on most office phone systems.
>
>Scenario:
>
>1.  You (party A) are on an active call with party B.
>2.  You decide to add in another party (C).
>3.  You key the CONF button on your business set.
>	- Party B gets MOH or silence.
>	- Party B's appearance on your phone goes to the HELD state.
>	- You get new dial-tone on a new appearance
>4.  You dial the number for party C.
>5.  Party C answers and you communicate briefly.
>6.  You press the CONF key again to establish the conference
>	- The bridging takes place in the PBX/KSU
>	- Party B is pulled out of MOH-land and added to the new call
>	- Party B's appearance returns to the ACTIVE state
>
>Now you are conferenced.  Both call appearances show active.  You can even
>follow the same set of steps to conference in another user if you have
>additional appearances on your set.
>
>In Asterisk using most VoIP phones (soft or hard) this scenario does not
>play out.  You wind up transferring party A into the MeetMe, calling party B
>and transferring them into the MeetMe, then dialing into the MeetMe
>yourself.
>
>This is further complicated by the fact that any given static MeetMe may or
>may not already be occupied by others doing the same thing.  Dynamic MeetMes
>make this a bit more flexible, but there's little documentation to the
>dynamic feature.
>
>Is there an elegant way to execute dynamic conferencing in Asterisk?  Can
>this be done without building conferencing logic into the client UA?  If so,
>how?
>
>If not (which I think is the case), how do we add this in?  I have a number
>of clients using my IAX Phone who are not really happy about having to jump
>through hoops to handle spontaneous conferences.
>
>I would be happy to _try_ to code the solution into IAX2 (both chan_iax2 and
>libiax2) if somebody can tell me where to begin.  I would think there has to
>be some way to add in an IAX2 command to merge two calls or to command
>Asterisk to bridge the calls at the server.
>
>Also, is there a way execute such a conference from SIP, MGCP, H323, or
>other protocols?  If so, who wants to implement it?
>
>Any thoughts would be appreciated.  Apologies in advance if I missed some
>really simple way of doing this.
>
>Thanks,
>
>Steve
>
>Steven Sokol
>Owner/Manager
>Sokol & Associates, LLC
>
>Phone:  816.822.1807
>IaxTel: 700.613.9004
>Web:    http://www.sokol-associates.com

(Steven - sorry for the delay on the private reply to this; various 
other emergencies have put me even further behind in my email and 
thinking time)

You are correct: key system functionality is currently not provided 
by Asterisk, and that is a huge handicap in convincing customers to 
switch over.  However, now that desksets are starting to emerge that 
support SUBSCRIBE/NOTIFY, we should as a community consider how we 
can actually use those new features to finally kill off the last 
objections that key system or digital PBX vendors can use against 
Asterisk's feature set.

Putting conference or barge-in capability into the client is only a 
very temporary solution, and is un-scaleable at best.

I can sort-of envision how this would work on the server in my mind, 
but it's a real big mess full of auto-dialers, hacks to the Dial 
application, and creation of a whole new "object" that determines 
"presence".  There is no easy way to do a barge-in without knowing 
the status of a line, and really, the key system replacement concept 
relies almost completely on the concept of presence - the user needs 
to be able to tell that someone else is on "line1" because the little 
light is lit up over "line1".  I don't think the two (presence and 
barge-in capability) can be easily separated, so I describe a config 
file (but not a programmatical method) below.

This message covers both the concept of "presence" on a channel 
basis, and also then introduces a new idea about a channel type to 
allow for barge-ins in a "clean" manner.  My apologies to those who 
are much more familiar with the presence models than am I.  I'm sure 
Jabber handles this in some very clever way, but we primitive 
Asterisk users are always re-inventing the wheel because we can't 
just use the Jabber code in Asterisk due to license issues.


First:
   We need the concept of a presence entity.  It's not sufficient to 
say that a channel defines an entity, since a user could have 
multiple channels associated with themselves, or a presence entity 
might not be a "user", so we have to abstract the concept of the 
entity into a separate file.  All we need to do is uniquely name the 
entity so it can be referenced by other routines.  We need to have a 
name and context, so we can have "virtual" presence entities that are 
easily extended to have overlapping namespace.  The permissions model 
is not addressed in this message, and in fact may not need to be 
addressed since it is implicit in the way the dialplan and (usually) 
sip.conf is laid out and password-protected.

Second:
   Now that we've named the presence entity, for each channel type we 
need to be able to have some special actions that can access a 
presence entity.  In chan_sip, for instance, it is possible for there 
to be a registration by a device (or software, or whatever) to a 
presence entity.  However, we may have multiple username/password 
combinations that allow subscription to the same presence entity, so 
we abstract that in the chan_sip file.  Similarly, we could (if such 
a thing became possible with the zap drivers) attach presence to a 
chan_zap channel that might support ADSI indications based on 
presence.  We would associate the presence element in the zapata.conf 
file in that instance.  We might have multiple overlapping presence 
entities changing the same indicator.

Third:
   We need applications to allow for the dynamic alteration and 
examination of presence status for a particular entity, so that we 
can execute conditionals based on current settings and so we can 
create changes in presence.  A presence method is typically 
conditional on the status of the call leg(this is, after all, a 
telephony system) but may be optionally set to "sticky" where that 
presence remains even after one or both call legs are hung up.
   We need the ability to specify presence for both ends of a call. 
The Dial application will need some minor changes (because it is 
impossible to determine some states of a call once "Dial" has been 
called - as an example, "Ringing" versus "Picked up") but even that 
might be an optionally used setting.  By appropriate use of 
chan_local, it is possible for both legs of a call to be parsed 
through the dialplan so that presence information is handled 
correctly on both sides of a call by applications other than app_dial.



Hypothetical example, using made-up applications and situations:

My office has one outbound X100P, and two SIP devices.

Let's say for deskphones, I'm using FooFones which are SIP devices. 
FooFones support PLAR dialing, so the second I pick up the phone, it 
can be configured to dial a SIP URI.  FooFones support 
SUBSCRIBE/NOTIFY, and for each line I can configure a SUBSCRIBE URI 
that is different than the REGISTER URI.  If a FooFone gets a 
"NOTIFY" with the appropriate data, it will cause the "status" light 
above the selected line appearance button to light up, meaning "in 
use".

FooFones have two line appearances, and each device is configured like this:

Device 2203:
Line1: auto-dials 2203 (labelled "2203")
Line2: auto-dials 2204 (labelled "2204")

Device "2204":
Line1: auto-dials 2204 (labelled "2204")
Line2: auto-dials 2203 (labelled "2203")


Requirements:
   Each FooFone is in a different room, far apart.  Thus, each person 
wants to be able to see visually if the other person is on the phone. 
If they are on the phone, they would like to be able to press the 
button of the other person, and be inserted into the conversation.

   Note that this system does NOT tell you if Zap/1 is offhook or not, 
nor does it allow you to barge in on (specifically) the Zap/1 
channel.  The system (as configured in my example) shows each user 
the status of the other user's primary line.

   So, a simplistic and VERY incomplete (no error-checking or 
busy-handling) dialplan and config files could look like this for 
normal outbound calls and also allow for other people in the office 
to "barge in" to a conversation happening on some other line.


=========================
sip.conf:

[2203]
type=friend
secret=overthruster
context=from-sip-phones
;
[2204]
type=friend
secret=prettypenny
context=from-sip-phones
;
;
; Both desktop devices subscribe to the SIP presence elements
;  of 2203-presence and 2204-presence, and each device has
;  each subscription mapped to a light that is then labelled
;  with that number.
; Any time the presence status changes for the listed presence-entity,
;  then all devices subscribed to this SIP element will receive a NOTIFY
;  that informs the device of the changed status.
;
[2204-presence]
type=presence
secret=yoyodyne
presence-entity=2203 at default
;
[2204-presence]
type=presence
secret=johnparker
presence-entity=2204 at default



===========================
appearance.conf:

[2203]
context=default

[2204]
context=default


============================
extensions.conf:

; We'll assume that an idle phone returns a ${PRESENCE} = "idle"
;
; Whenever someone picks up a line, the phone auto-dials the 'line group'
;  number (a four digit number, in our case) which gets them to
;  the [from-sip-phones] context.  We do this via PLAR ("hotline" or
;  "auto-dial") on the phone handset.
;
[from-sip-phones]
exten => _X.,1,SetVar(ORIG-EXTEN=${EXTEN})
exten => _X.,2,GetPresence(${EXTEN}@default)
exten => _X.,3,GotoIf($[${PRESENCE} != idle]?barge-line|${EXTEN}|1:4)
exten => _X.,4,Goto(make-dialtone,begin,1)
;
;
;
[make-dialtone]
;
; First, set the status of the calling extension to "offhook"
;  This causes all of the SUBSCRIBE'ed entities to receive a
;  NOTIFY that this entity has now changed to offhook.  This
;  transmission to other subscribed entities is hidden to
;  the user - that is dependent on chan_sip (and any other
;  method that uses subscriptions) to send the transmission to
;  the subscribed device.
;
exten => begin,1,SetPresence(${ORIG-EXTEN},offhook)
;
; Next, we need to somehow store the channel identifier with
;  the presence entity.  This is not the job of any particular
;  application, since this relationship is fairly fluid and
;  should not be hard-coded into any particular application.
;  In this example, we want to say that the extension group
;  (${ORIG-EXTEN}) has a channel associated with it, so we
;  store it in the astdb so that other instances of this
;  extension group can access it.  We don't need to clear this
;  data out of astdb, since we use "GetPresence" in the
;  previous priority as a check to see if we should
;  even use that value, so it is (hopefully) always valid or
;  if not valid, unused.
;
exten => begin,2,DBPut(LIVE-CHANNEL/${ORIG-EXTEN}=${CHANNEL})
;
;
; Now, give a dialtone and let the user dial something
;
exten => begin,3,DISA(no-password|make-dialtone2)
;
;
;
[make-dialtone2]
;
; We don't need to use the "a" modifier on the Dial, since we're not publishing
;  the status of Zap/1-1 in our model.  We've already sent the
;  notification to the extension group (${ORIG-EXTEN}) that
;  this line group is now offhook.  Anyone who has a light
;  on their phone that is subscribed to that four-digit extension
;  group will now show the light as lit.  It doesn't matter that
;  the call is going out Zap/1 since we're not tracking the
;  state of Zap lines, just the state of the extension
;  groups on the phones.
;
exten => _1XXXXXXXXXX,1,Dial(Zap/1/${EXTEN})
;
;
; Now, here is where we have to think a little bit.  In our
;  next extension matching rules, we're going to check and see
;  if the called number is one of our "local" extensions.  If
;  it is, then we need to put the ${CHANNEL} value into the
;  astdb for the called number.  Why the called number?  Because
;  we don't know what the channel identifier will be for the
;  Dial in priority 2, but that doesn't really matter - if we
;  barge in on the original channel, it's the same conversation,
;  so we're covered.
;
; Recall that even in the instance of a transfer, this will still
;  work, since the presence indicator for the called channel
;  will then go back to "idle", and this value won't be examined.
;
exten => _2XXX,1,DBPut(LIVE-CHANNEL/${EXTEN}=${CHANNEL})
;
; ...and now we actually dial the local number. We set the
;  presence for the number we're calling by using the "a" modifier
;  in Dial, so we can send notifications around to the devices
;  which are subscribed to that particular presence entity.
;
exten => _2XXX,2,Dial(SIP/${EXTEN},a[${EXTEN}@default])
;
;
; ..and the usual "cleanup" extensions here:
;
exten => h,1,Hangup
exten => i,1,Hangup
exten => t,1,Hangup
;
;
[barge-line]
;
; OK, so the line we picked up is already live somewhere, so
;  we need to find out what the channel identifier is for
;  the other live line...
;
exten => _X.,1,DBGet(BARGE-CHANNEL=LIVE-CHANNEL/${EXTEN})
;
; ...and now we barge in on the channel.  Recall that chan_multi
;  takes a channel identifier and inserts the new call into that
;  existing channel's audio stream.
;
exten => _X.,2,Dial(MULTI/${BARGE-CHANNEL})
;
;
; ...cleanup extensions.
exten => h,1,Hangup
exten => i,1,Hangup
exten => t,1,Hangup
;
; end


Requirements for this all to work:

  - a new application called 
"SetPresence(label at context,status,options)" need to be created.  It 
sends a NOTIFY to the subscribed entities listed in appearance.conf 
with the status contents.  Options are "p", which means "p"ersist the 
values when this call leg is destroyed (default is to reset the 
presence status to null after call is ended.)  I would suggest that 
this application always exit with "0" result, though if the presence 
entity did not exist or did not accept a particular type of status 
flag, an error message should be logged to the console.

  - a new application called "GetPresence(label at context)" that returns 
a variable called ${PRESENCE} of the listed element.  If the presence 
entity does not exist, then the word "error" should be returned as 
the presence value.

  - Modifications to app_dial:

app1*CLI> show application dial
app1*CLI>
   -= Info about application 'Dial' =-

[Synopsis]:
Place a call and connect to the current channel

[Description]:
 
Dial(Technology/resource[&Technology2/resource2...][|timeout][|options][|URL]):
Requests one or more channels and places specified outgoing calls on them.
[...]
The option string may contain zero or more of the following characters:
       'a[presence at context]' -- use the values stored in appearance.conf
                              to specify presence publishing during a dial
                              sequence.  Defaults to "idle" when channel
                              is hung up (unless set to another value with
                              a persistent flag in SetPresence.)  Dial
                              will not alter presence values if there was
                              a previous presence value set with the persistent
                              flag.


  - an agreed-upon mapping will need to be created for each channel 
type that reflects how the channel will populate a presence value 
during a Dial call that uses the "a[presence at context]" modifier.

  - chan_sip will need to be heavily modified to support the 
presence-entity and "type=presence" features I describe in the 
chan_sip example above.
    - It should be noted that the "presence-entity=" value should 
support a comma-separated list of presence-entities.  This, however, 
is an insanely complex undertaking, involving a new concept of 
"presence priorities" in which one presence would have more "weight" 
than another, and I'm just going to leave that mess well enough alone 
for now.  But think about how you would handle a situation like 
"manager on duty" as a presence indication, if there are multiple 
managers who may be overlapping in their "on duty" timeframes.

  - a new channel type, chan_multiplex.  The multiplex channel type 
will take as an argument a call leg identifier of an existing call 
(i.e.: "Zap/1-1" or "SIP/2203-e867") and will then create a barge-in. 
The new caller will be multiplexed into the existing call leg, 
without hanging up the prior call event.  Dial events to non-existent 
call identifiers or to calls that do not have media flowing through 
the Asterisk server will be rejected as "busy".  Examples of 
chan_multi:
    Dial(MULTI/SIP/2203-e867)
    Dial(MULTI/Zap/1-1)

   - Certain options will not function correctly in a MULTI channel: T,t,r,H
   - This will also be an answer to those people wanting to have a 
"barge" application that works on any channel type.
   - Channel type "MULTI" can recursively connect to other MULTI channels.
   - It may be required to add another add-on to Dial that allows 
specification of the called number in the CDR, since something like 
"SIP-109ce2" is not very descriptive (though it is the "extension" 
that is dialed in a chan_multi Dial statement.)

- the "Dial" application will not be influenced by presence, since a 
channel and a presence entity are not directly related.  One should 
execute a "GetPresence" and then a GotoIf to block calls to an 
extension (or set of extensions) that have "DND" or "Away" set.


More thoughts:

  - do the presence events associated with a Dial (and the "a" 
modifier) need to change as a call status changes? dialing, on hold, 
etc. - should those all cause NOTIFY events?  Is there a standard?

  - DND would be set with a SetPresence that uses a persistent flag. 
It is possible, of course, to override DND by not doing a GotoIf 
comparison before executing a Dial against a particular extension, or 
by overriding (ignoring) the results of a presence comparison during 
the Boolean logic flow.

  - If a call is made to a MULTI channel type, and the call leg that 
is specified is a SIP channel that has been re-INVITE'ed to the 
endpoints, would it be possible to re-re-INVITE the RTP stream back 
to flowing through the Asterisk server so that the multiplex could 
take place?  How about IAX2?

  - Presence status should probably be stored in astdb for persistence 
across restarts.  The applications SetPresence and GetPresence would 
be mostly conveniences, but there is the important point of having 
Dial manipulate the same table space when events have been handed off 
to an application that is outside of the dialplan's control. 
Addtionally, SetPresence and GetPresence would trigger the "push" of 
NOTIFY events back out to SIP devices (and anything else that was 
associated with a presence entity - this should be a _generic_ 
framework.)




More information about the asterisk-dev mailing list