Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Rayo specification

Contra edited this page · 3 revisions

Calls

The Rayo protocol primarily deals with calls. Inbound calls originate from the PSTN or via SIP and are offered to Rayo clients via XMPP using a Jabber Identifier (JID). Each call is in turn represented by it's own unique JID allowing a two way conversation between the Rayo client and the server that's handling the call signaling and media.

JID Format

The JID follows a specific format. In XMPP the JID is constructed as

  <node>@<domain>/<resource>

For Rayo, the <node> portion of the JID always represents the call ID. The <resource>, when present, represents the affected command ID.

Incoming Calls

  <!-- Message comes from the Call's JID -->
  <presence to='16577@app.rayo.net/1' from='9f00061@call.rayo.net/1'>
    <offer xmlns='urn:xmpp:rayo:1'
        to='tel:+18003211212'
        from='tel:+13058881212'>
      <!-- Signaling (e.g. SIP) Headers -->
      <header name='Via' value='192.168.0.1' />
      <header name='Contact' value='192.168.0.1' />
    </offer>
  </presence>

The Rayo client can now control the call by using one of the following commands.

  <!-- Accept (e.g. SIP 180/Ringing). Only applies to incoming calls. -->
  <iq id='1234' type='set' to='9f00061@call.rayo.net/1' from='16577@app.rayo.net/1'>
    <accept xmlns='urn:xmpp:rayo:1'>
      <!-- Sample Headers (optional) -->
      <header name="x-skill" value="agent" />
      <header name="x-customer-id" value="8877" />
    </accept>
  </iq>

  <!-- Answer (e.g. SIP 200/OK). Only applies to incoming calls. -->
  <iq id='1234' type='set' to='9f00061@call.rayo.net/1' from='16577@app.rayo.net/1'>
    <answer xmlns='urn:xmpp:rayo:1'>    
      <!-- Sample Headers (optional) -->
      <header name="x-skill" value="agent" />
      <header name="x-customer-id" value="8877" />
    </answer>
  </iq>

  <!-- Redirect (e.g. SIP 302/Redirect). Only applies to incoming calls. -->
  <iq id='1234' type='set' to='9f00061@call.rayo.net/1' from='16577@app.rayo.net/1'>
    <redirect to='tel:+14152226789' xmlns='urn:xmpp:rayo:1'>    
      <!-- Sample Headers (optional) -->
      <header name="x-skill" value="agent" />
      <header name="x-customer-id" value="8877" />
    </redirect>
  </iq>

A call can also be rejected. Rejections can include an optional rejection reason. Rejection reasons are one of <busy/>, <decline/> or <error/>. If not specified, <decline/> is used as the default reason.

  <!-- Decline  (.g. SIP 603/Decline). Only applies to incoming calls. -->
  <iq id='1234' type='set' to='9f00061@call.rayo.net/1' from='16577@app.rayo.net/1'>
    <reject xmlns='urn:xmpp:rayo:1'>
      <decline />
      <!-- Sample Headers (optional) -->
      <header name="x-reason-internal" value="bad-skill" />
    </reject>
  </iq>

  <!-- Busy  (.g. SIP 486/Busy). Only applies to incoming calls. -->
  <iq id='1234' type='set' to='9f00061@call.rayo.net/1' from='16577@app.rayo.net/1'>
    <reject xmlns='urn:xmpp:rayo:1'>
      <busy />
      <!-- Sample Headers (optional) -->
      <header name="x-busy-detail" value="out of licenses" />
    </reject>
  </iq>

  <!-- Error  (.g. SIP 500/Internal Server Error). Only applies to incoming calls. -->
  <iq id='1234' type='set' to='9f00061@call.rayo.net/1' from='16577@app.rayo.net/1'>
    <reject xmlns='urn:xmpp:rayo:1'>
      <error />
      <!-- Sample Headers (optional) -->
      <header name="x-error-detail" value="some descriptive error message" />
    </reject>
  </iq>

A call can be set to hold status with the hold command:

  <iq id='1234' type='set' to='9f00061@call.rayo.net/1' from='16577@app.rayo.net/1'>
    <hold xmlns='urn:xmpp:rayo:1'/>
  </iq>

A call be set to unhold status with the unhold command:

  <iq id='1234' type='set' to='9f00061@call.rayo.net/1' from='16577@app.rayo.net/1'>
    <unhold xmlns='urn:xmpp:rayo:1'/>
  </iq>

A call can be muted with the mute command:

  <iq id='1234' type='set' to='9f00061@call.rayo.net/1' from='16577@app.rayo.net/1'>
    <mute xmlns='urn:xmpp:rayo:1'/>
  </iq>

A call be unmuted with the unmute command:

  <iq id='1234' type='set' to='9f00061@call.rayo.net/1' from='16577@app.rayo.net/1'>
    <unmute xmlns='urn:xmpp:rayo:1'/>
  </iq>

Outbound Calls

Rayo clients can initiate outbound calls using the <dial /> command.

  <!-- Handled by the domain controller which picks a random Rayo Server -->
  <iq id='123456' type='set' to='call.rayo.net' from='16577@app.rayo.net/1'>
     <dial to='tel:+13055195825' from='tel:+14152226789' xmlns='urn:xmpp:rayo:1'>
        <header name="x-skill" value="agent" />
        <header name="x-customer-id" value="8877" />
     </dial>
  </iq>

  <iq id='123456' type='result' to='16577@app.rayo.net/1' from='call.rayo.net'>
     <!-- The Call's ID -->
     <ref id='9f00061' />
  </iq>

The client will then begin to receive progress events as the call makes it's way through the network.

  <!-- Far end has accepted the call and is ringing (e.g. 180/Ringing) -->
  <presence to='16577@app.rayo.net/1' from='9f00061@call.rayo.net/1'>
    <ringing xmlns='urn:xmpp:rayo:1'>
      <!-- SIP Headers -->
      <header name="x-skill" value="agent" />
      <header name="x-customer-id" value="8877" />
    </ringing>
  </presence>

  <!-- The outgoing call has been answered (e.g. 200/OK) -->
  <presence to='16577@app.rayo.net/1' from='9f00061@call.rayo.net/1'>
    <answered xmlns='urn:xmpp:rayo:1'>
      <!-- SIP Headers -->
      <header name="x-skill" value="agent" />
      <header name="x-customer-id" value="8877" />
    </answered>
  </presence>

If for some reason the call is not accepted by the far end, the Rayo client will receive an <end/> event indicating the reason for the failure.

  <!-- Dial destination did not answer within the timeout period -->
  <presence to='16577@app.rayo.net/1' from='9f00061@call.rayo.net/1'>
    <end xmlns='urn:xmpp:rayo:1'>    
      <timeout />
    </end>
  </presence>

  <!-- Dial destination is busy and annot answer the call -->
  <presence to='16577@app.rayo.net/1' from='9f00061@call.rayo.net/1'>
    <end xmlns='urn:xmpp:rayo:1'>    
      <busy />
    </end>
  </presence>

  <!-- Dial destination rejected the call -->
  <presence to='16577@app.rayo.net/1' from='9f00061@call.rayo.net/1'>
    <end xmlns='urn:xmpp:rayo:1'>    
      <reject />
    </end>
  </presence>

  <!-- Rayo encountered a system error while dialing -->
  <presence to='16577@app.rayo.net/1' from='9f00061@call.rayo.net/1'>
    <end xmlns='urn:xmpp:rayo:1'>    
      <error>Lucy, you got some 'splainin to do</error>
    </end>
  </presence>

Note: A Rayo <end/> indicates that the call has been disconnected and that no more events are possible for this call. Therefore, the <end/> event is a perfect point for clients to clean up resources related to the controlling of the call.

Handling caller hangup

If the caller hangs up the call Rayo will produce an <end/> event with a <hangup/> reason like so:

<presence to='16577@app.rayo.net/1' from='9f00061@call.rayo.net/1'>
  <end xmlns='urn:xmpp:rayo:1'>    
    <hangup/>
  </end>
</presence>

Note: A Rayo <end/> indicates that the call has been disconnected and that no more events are possible for this call. Therefore, the <end/> event is a perfect point for clients to clean up resources related to the controlling of the call.

Forcing a call to end

Rayo clients can force a call to end by sending a <hangup/> command to the call's JID.

<iq id='1234' type='set' to='9f00061@call.rayo.net/1' from='16577@app.rayo.net/1'>
  <hangup xmlns='urn:xmpp:rayo:1'>    
    <!-- Sample Headers (optional) -->
    <header name="x-reason-internal" value="bad-skill" />
  </hangup>
</iq>

NOTE: The client will still receive an <end/> event indicating that that call has been disconnected and that no further events or commands are possible.

Additional Call Events

<!-- Caller pressed the '#' key on their phone -->
<presence id='1234' to='16577@app.rayo.net/1' from='9f00061@call.rayo.net/1'>
  <dtmf xmlns='urn:xmpp:rayo:1' signal='#' />    
</iq>

Components

Components extend the Rayo protocol by providing additional media and call control functionality.

Components are started by sending a specialized command to the Rayo server. This example shows the use of the <say xmlns='urn:xmpp:tropo:say:1'/> component. Don't worry about the specifics of the <say/> element for now. We'll discuss each component in detail in the folowing chapters. The key point here is that a component request is being sent to the call's JID.

NOTE: You can easily spot a component request because the namespace will be in the format urn:xmpp:rayo:COMPONENT_NAME:1

  <iq id='1234' type='set' to='9f00061@call.rayo.net/1' from='16577@app.rayo.net/1'>
    <say xmlns='urn:xmpp:tropo:say:1' 
      voice='allison'>
      <audio src='http://acme.com/greeting.mp3'>
          Thanks for calling ACME company
      </audio>
      <audio src='http://acme.com/package-shipped.mp3'>
          Your package was shipped on
      </audio>
      <say-as interpret-as='date'>12/01/2011</say-as>
    </say>
  </iq>

The Rayo server will validate the component request and attach a new instance of the component to the call. In a happy day scenario the client will immediately receive an IQ result containing the newly created component's ID. The component's ID is combined with the call's JID to control the component (e.g. pause, resume, stop, etc.) and to corelate events coming from the component as well.

A component's JID is calculated by combining the call's JID with the newly created component's ID like so: <call-id>@<rayo-domain>/<component-id>

  <!-- Server responds a unique ID -->
  <iq id='1234' type='result' to='16577@app.rayo.net/1' to='9f00061@call.rayo.net/1'>
     <ref id='fgh4590' xmlns='urn:xmpp:rayo:1' />
  </iq>

NOTE: Remember that Rayo executes components asynchronously and in many cases more than one component can run at the same time. For example, you can have the <record xmlns='' /> component running throught the entire while you interact with the user using the "say" and "ask" components resulting in the entire call being recorded.

Component Commands

Components are controlled by sending command messages to their unique JID. The only command required by all components is the <stop/> command.

  <iq id='1234' type='set' to='9f00061@call.rayo.net/fgh4590' from='16577@app.rayo.net/1'>
    <stop xmlns='urn:xmpp:rayo:1' />
  </iq>

As you'll see in the following chapters, component developers can get very creative with the command they support allowing for some really interesting capabilities. For example, the ability to pause and resum audio playback as well as muting and unmuting the caller's microphone while in a conference.

Component Events

Events are specialized lifecycle messages that flow from a component instance to the Rayo client that's controlling the call. As you'll see in the following chapters, component events are very powerful and can provide great insight into a running application.

The only event required by all components is the <complete xmlns='urn:xmpp:rayo:ext:complete:1' />. This is an example complete event produced by the <say urn:xmpp:tropo:say:1/> component when audio playback has completed succesfully.

  <presence to='9f00061@call.rayo.net/fgh4590' from='16577@app.rayo.net/1'>
   <complete xmlns='urn:xmpp:rayo:ext:1'>
     <success xmlns='urn:xmpp:tropo:say:complete:1' />
   </complete>
  </presence>
Something went wrong with that request. Please try again.