building your first ari app - mark · pdf filebuilding your first ari app ... • astricon...

41
Building Your First ARI App 117,612 Calls Later Mark Ingles Oct 14, 2015 Astricon 2015

Upload: nguyenanh

Post on 31-Mar-2018

219 views

Category:

Documents


5 download

TRANSCRIPT

Page 1: Building Your First ARI App - Mark  · PDF fileBuilding Your First ARI App ... • Astricon Talks • (Half of this year’s talks and 2014 still good) 39. 40. 41

Building Your First ARI App

117,612 Calls Later

Mark Ingles Oct 14, 2015 Astricon 2015

Page 2: Building Your First ARI App - Mark  · PDF fileBuilding Your First ARI App ... • Astricon Talks • (Half of this year’s talks and 2014 still good) 39. 40. 41

Thank You!•

• Joshua Colp – Sr. Dev at Digium

• Nir Simionovich – Greenfield Tech phpari.org

2

Page 3: Building Your First ARI App - Mark  · PDF fileBuilding Your First ARI App ... • Astricon Talks • (Half of this year’s talks and 2014 still good) 39. 40. 41

About Mark Ingles• 15 years writing PHP (or 1 year 15x)

• Former Sysadmin

• Asterisk User for 8 Years

• Business Owner – Printing - like Vistaprint but for established businesses

3

Page 4: Building Your First ARI App - Mark  · PDF fileBuilding Your First ARI App ... • Astricon Talks • (Half of this year’s talks and 2014 still good) 39. 40. 41

Already Using ARI?

4

Page 5: Building Your First ARI App - Mark  · PDF fileBuilding Your First ARI App ... • Astricon Talks • (Half of this year’s talks and 2014 still good) 39. 40. 41

Overview• High Level Ideas And Common Pitfalls

• PHPARI “Basic Stasis Application Template” and Reacting to Events

• Dialing, Bridging, Recording, Sounds In A “Power Dialer” Application

5

Page 6: Building Your First ARI App - Mark  · PDF fileBuilding Your First ARI App ... • Astricon Talks • (Half of this year’s talks and 2014 still good) 39. 40. 41

High Level Ideas• One Process Reacts To Events • Another To Send Requests

6

Asterisk Emits Events

ARI App Receives

ARI App Processes

ARI App Sends

Requests

Send Requests

Asterisk Processes

Page 7: Building Your First ARI App - Mark  · PDF fileBuilding Your First ARI App ... • Astricon Talks • (Half of this year’s talks and 2014 still good) 39. 40. 41

7

ws://localhost:8088/ari/events?api_key=asterisk:asterisk&app=hello-world

Looks like you want to add a prefix or /ari in http.conf Not sure? “core set debug 2” from the Asterisk CLI:

HTTP Request URI is /ari/channels/1443501398.rep-mark match request [ari/channels/1443501398.rep-mark] with handler [httpstatus] len 10 match request [ari/channels/1443501398.rep-mark] with handler [static] len 6 match request [ari/channels/1443501398.rep-mark] with handler [ari] len 3 Match made with [ari]

Common Setup Pitfall “prefix” in http.conf

Page 8: Building Your First ARI App - Mark  · PDF fileBuilding Your First ARI App ... • Astricon Talks • (Half of this year’s talks and 2014 still good) 39. 40. 41

Any Created Resource Gets An ID

8

$response = $channels->originate($ENDPOINT,            array(                "app"    => 'miDialer',               "appArgs"  => 'IsRep',               "callerId“ => $MyCallerID,              "timeout"  => 10,               "channelId" => $NewChannelID,         )); 

Asterisk can return events with this channel BEFORE it returns a response to this request.

Page 9: Building Your First ARI App - Mark  · PDF fileBuilding Your First ARI App ... • Astricon Talks • (Half of this year’s talks and 2014 still good) 39. 40. 41

Use A Library• PHPARI

9

All of the heavy lifting is done. • Websockets • Encryption • REST Client • JSON Encoding/Decoding • Logging • Event Handling

Page 10: Building Your First ARI App - Mark  · PDF fileBuilding Your First ARI App ... • Astricon Talks • (Half of this year’s talks and 2014 still good) 39. 40. 41

High Level Ideas• Dial/Originate goes to Dialplan OR ARI

10

Wiki is updated now. (Oct 2015)

• ARI/Stasis REPLACES dialplan apps

Page 11: Building Your First ARI App - Mark  · PDF fileBuilding Your First ARI App ... • Astricon Talks • (Half of this year’s talks and 2014 still good) 39. 40. 41

11

Page 12: Building Your First ARI App - Mark  · PDF fileBuilding Your First ARI App ... • Astricon Talks • (Half of this year’s talks and 2014 still good) 39. 40. 41

Channel Doesn’t Enter ARI Until Answered

12

 originate($channelid);

 add_to_bridge($bridgeid, $channelid);

This Does NOT work. You have to wait until the StasisStart event, then react to it and add the channel to the bridge.

#1 Pitfall

Page 13: Building Your First ARI App - Mark  · PDF fileBuilding Your First ARI App ... • Astricon Talks • (Half of this year’s talks and 2014 still good) 39. 40. 41

Reacting To Events

13

$this->Events->on('StasisStart', function ($event) {     $channels()->channel_answer($event->channel->id);

}

$this->Events->on('ChannelEnteredBridge', function ($event) {

echo "channel: " . $event->channel->id . " entered bridge: " . $event->bridge->id);

}

Events Happen FAST – no way to get Channel Info on ChannelDestroyed or StasisEnd events

Page 14: Building Your First ARI App - Mark  · PDF fileBuilding Your First ARI App ... • Astricon Talks • (Half of this year’s talks and 2014 still good) 39. 40. 41

Call Detail Records No “DST” Set

14

DST is from the dialplan.

Solution: Log yourself in whatever format you need. (sql, csv)

INSERT INTO CallLog SET ID=NULL, CallStart=$callstart, ChannelID=$channelid

StasisStart or ChannelEnteredBridge UPDATE CallLog SET CallPickup=$callpickup  WHERE ChannelID=$channelid

ChannelDestroyed UPDATE CallLog SET CallEnd=$callend  WHERE ChannelID=$channelid

Page 15: Building Your First ARI App - Mark  · PDF fileBuilding Your First ARI App ... • Astricon Talks • (Half of this year’s talks and 2014 still good) 39. 40. 41

Snoop, Not Chanspy Playbacks Queue

15

Snoop creates a new channel that can listen (spy) or whisper (speak) to another channel.

Playbacks queue a sound file to be played to a channel or bridge.

Record works on all audio in a bridge.

Page 16: Building Your First ARI App - Mark  · PDF fileBuilding Your First ARI App ... • Astricon Talks • (Half of this year’s talks and 2014 still good) 39. 40. 41

New Sounds Aren’t Updated

16

module reload sounds

If you upload or record new sounds, this has to be run from the CLI, not the ARI.

Page 17: Building Your First ARI App - Mark  · PDF fileBuilding Your First ARI App ... • Astricon Talks • (Half of this year’s talks and 2014 still good) 39. 40. 41

Our Power Dialer1. Dialing from a CRM 2. Started with “Drag to Dial” 3. Moved To “Click To Dial” 4. Moved To “Dial Me When Ticket Opened”

in CRM

• Rev 1. ARI Dialer Begins Calling When Previous Call Hungup

• Rev 2. ARI Dialer Leaves Pre-Recorded Voicemail When Told By Human

17

Page 18: Building Your First ARI App - Mark  · PDF fileBuilding Your First ARI App ... • Astricon Talks • (Half of this year’s talks and 2014 still good) 39. 40. 41

Our Power DialerPrerequisites

• Asterisk 13+ Setup With ARI Enabled • Web Server with PHP 5.4+ • Recordings Of Voicemail Messages • MySQL Database For Logging • CRM Access via Database or CURL

18

Page 19: Building Your First ARI App - Mark  · PDF fileBuilding Your First ARI App ... • Astricon Talks • (Half of this year’s talks and 2014 still good) 39. 40. 41

19

Page 20: Building Your First ARI App - Mark  · PDF fileBuilding Your First ARI App ... • Astricon Talks • (Half of this year’s talks and 2014 still good) 39. 40. 41

20

Page 21: Building Your First ARI App - Mark  · PDF fileBuilding Your First ARI App ... • Astricon Talks • (Half of this year’s talks and 2014 still good) 39. 40. 41

Our Power DialerFunctionality

1. Dial Customer Service Rep 2. Call From Highest->Lowest Priority (changes) 3. If Rep Hears VM Greeting, Leave Prerecorded

VM and Dial Next User 4. Log/Record All Calls 5. Notify Rep Of What’s Happening (audio/visual)

21

Page 22: Building Your First ARI App - Mark  · PDF fileBuilding Your First ARI App ... • Astricon Talks • (Half of this year’s talks and 2014 still good) 39. 40. 41

Our Power DialerResults

Click To Dial (and variations) Avg 30 Calls/Hour Dialer Avg 60 Calls/Hour, Max 90 Calls/Hour

PS – No Dialplan

22

Page 23: Building Your First ARI App - Mark  · PDF fileBuilding Your First ARI App ... • Astricon Talks • (Half of this year’s talks and 2014 still good) 39. 40. 41

Originate (to ARI App)

How It Works 1 – Call Rep

23

$channels = new channels($phpari);      # call the rep- only give the rep 10 seconds to respond  $response = $channels->originate(  $ENDPOINT,  array(  "app"            => 'miDialer',  "appArgs"        => 'IsRep, "callerId"       => $_SESSION['MyCallNum'],  "timeout"        => 10,  "channelId"      => $_SESSION['MyChannelID'],  ),  array('CALLERID(name)' => 'Phone Dialer')    );    

Page 24: Building Your First ARI App - Mark  · PDF fileBuilding Your First ARI App ... • Astricon Talks • (Half of this year’s talks and 2014 still good) 39. 40. 41

Check BridgesHow It Works 2 - Call A Client 1/4

24

$channels = new channels($phpari);  $bridges = new bridges($phpari);           # check for the rep dialed in, and nobody else in the bridge  $repready = 0;  $custinbridge = 0;  $bd = $bridges->details('bridge-' . $_SESSION['KUsername']);  if(is_array($bd)) {  foreach($bd['channels'] as $bchannel) {  if($bchannel == $_SESSION['MyChannelID']) {  $repready = 1; }       else {         # someone else in bridge          $custinbridge = 1;       } # if my channel      } # foreach channel  } # is bridge          

Page 25: Building Your First ARI App - Mark  · PDF fileBuilding Your First ARI App ... • Astricon Talks • (Half of this year’s talks and 2014 still good) 39. 40. 41

Setup VariablesHow It Works 2 - Call A Client 2/4

25

if(0 == $repready OR 1 == $custinbridge) {    echo 'Need To Be Dialed In And Hungup With Last Client';     return false;  }      # get bridged with the rep by the stasis app  #$ENDPOINT  = 'PJSIP/17275608297@flowroute';          $ENDPOINT = sprintf(OUTBOUNDTECH, $PhoneNum);  $callerid = $_SESSION['MyCallNum'];  $calleridname = $_SESSION['CIDName'];  $newchannelid = time() . '.client-' . $user . '.' . rand();                

Page 26: Building Your First ARI App - Mark  · PDF fileBuilding Your First ARI App ... • Astricon Talks • (Half of this year’s talks and 2014 still good) 39. 40. 41

Originate (to ARI App)How It Works 2 - Call A Client 3/4

26

$response = $channels->originate(  $ENDPOINT,  array(  "app"       => 'miDialer',  "appArgs " => 'IsOutBound,RepUserName-' . $_SESSION['User'],  "callerId"  => $callerid,  "timeout"   => 50,  "channelId“ => $newchannelid,  ),  array('CALLERID(name)' => $calleridname) );      

Page 27: Building Your First ARI App - Mark  · PDF fileBuilding Your First ARI App ... • Astricon Talks • (Half of this year’s talks and 2014 still good) 39. 40. 41

Logging / RingingHow It Works 2 - Call A Client 4/4

27

# log the call - add to call log table $sql = "INSERT INTO CallLog SET ID=NULL, CallStart=:CallStart, ChannelID=:ChannelID, PhoneNum=:PhoneNum, Rep=:Rep, TicketID=:TicketID, CIDNum=:CIDNum"; # finally, play ringing to rep  $channels->channel_ringing_start($mychannelid); 

Page 28: Building Your First ARI App - Mark  · PDF fileBuilding Your First ARI App ... • Astricon Talks • (Half of this year’s talks and 2014 still good) 39. 40. 41

SoundsHow It Works - 3 Leave A Voicemail 1/6

28

# leave a prerecorded voicemail for a product # (clipped) get ticket to know which voicemail      $sounds = new sounds($phpari);  $soundfile = $_SESSION['User'] . '-' . $vmtype;   # make sure sound is actually there if(!$sounds->detail($soundfile))  {    echo 'Cant Find Voicemail to Play';     return false;  }

         

Page 29: Building Your First ARI App - Mark  · PDF fileBuilding Your First ARI App ... • Astricon Talks • (Half of this year’s talks and 2014 still good) 39. 40. 41

Stop RecordingHow It Works - 3 Leave A Voicemail 2/6

29

$channels = new channels($phpari); $bridges = new bridges($phpari); $bridgeid = 'bridge-' . $_SESSION['KUsername']; $bdetails = $bridges->details($bridgeid); foreach($bdetails['channels'] as $bchannel) {  if($bchannel != $_SESSION['MyChannelID']) {  # this must be the cust's channel, since the bridge  should only have 2 channels, the rep, and the cust  $VMChannelID = $bchannel;                   # stop recording the rep's bridge, create a new bridge  to record both sides of leaving the VM  $recordings = new recordings($phpari);     $recordings->live(‘stop‘, $VMChannelID);     # remove the channel from the rep’s bridge      $bridges->remove_channel($bridgeid, $VMChannelID);            

Page 30: Building Your First ARI App - Mark  · PDF fileBuilding Your First ARI App ... • Astricon Talks • (Half of this year’s talks and 2014 still good) 39. 40. 41

TALK_DETECT()How It Works - 3 Leave A Voicemail 3/6

30

$bridges->create( 'mixing',  'bridge-' . $VMChannelID,  'bridge-' . $VMChannelID );

$bridges->addchannel('bridge-' . $VMChannelID, $VMChannelID, ''); # set a variable on the channel of the sound to play              $channels->setVariable($VMChannelID, 'miVMtoPlay', $soundfile); 

# wait for 2.1 seconds of silence  $channels->setVariable($VMChannelID, 'TALK_DETECT(set)', '2100');

Page 31: Building Your First ARI App - Mark  · PDF fileBuilding Your First ARI App ... • Astricon Talks • (Half of this year’s talks and 2014 still good) 39. 40. 41

ChannelTalkingFinished

How It Works - 3 Leave A Voicemail 4/6

31

# now that talking has stopped, play a voicemail $vmsound = $channels()->getVariable($event->channel->id, 'miVMtoPlay');if($vmsound) { # play it to the bridge so we can record it $bd = $bridges()->details('bridge-' . $event->channel->id); if(FALSE != $bd) {   # check to see if we are already playing it sometimes long pauses in greetings will start playback $pbd = $playbacks()->get_playback('miVMtoPlay' . $event->channel->id);                       if(FALSE != $pbd) {   # already playing, restart it- TODO: possibly put a limit on this    $playbacks()->control(

'miVMtoPlay' . $event->channel->id,  ‘RESTART');

} }

Page 32: Building Your First ARI App - Mark  · PDF fileBuilding Your First ARI App ... • Astricon Talks • (Half of this year’s talks and 2014 still good) 39. 40. 41

ChannelTalkingFinished

How It Works - 3 Leave A Voicemail 5/6

32

# queue the sound to play on the bridge

$bridges()->playbackstart( 'bridge-' . $event->channel->id, 'sound:custom/' . $vmsound['value'], 'custom', 0, 1000, 'miVMtoPlay' . $event->channel->id);                       

We need the ID on the Sound so we know what to do when it’s over.

Page 33: Building Your First ARI App - Mark  · PDF fileBuilding Your First ARI App ... • Astricon Talks • (Half of this year’s talks and 2014 still good) 39. 40. 41

PlaybackFinished

How It Works - 3 Leave A Voicemail 6/6

33

# once we leave the message, hangup the call if('miDialer' == $event->application AND strpos($event->playback->id, 'miVMtoPlay') !== FALSE) {                    $delchannelid = preg_replace('/bridge:bridge-(.*)/', '$1', $event->playback->target_uri);

# hang up customer channel $channels()->delete($delchannelid);  # bridge with the same name as the channel recorded- dump that too $recordings()->live('stop', $delchannelid); $bridges()->delete('bridge-' . $delchannelid);}

Page 34: Building Your First ARI App - Mark  · PDF fileBuilding Your First ARI App ... • Astricon Talks • (Half of this year’s talks and 2014 still good) 39. 40. 41

ChannelHangupRequest

End Recording When Hungup

34

# The channel is already gone by the time we see the request $repname = preg_replace('/\d+\.rep-(\w+?)\.\d+/', '$1', $event->channel->id);$bd = $bridges()->details('bridge-' . $repname);if(is_array($bd)) { foreach($bd['channels'] as $bchannel) {   # hangup anyone else in the bridge- the rep is already gone     $this->phpariObject->channels()->channel_delete($bchannel); # stop and store recording     $this->phpariObject->recordings()->live(‘stop‘, $bchannel);   } # foreach channel } # bridge        

Page 35: Building Your First ARI App - Mark  · PDF fileBuilding Your First ARI App ... • Astricon Talks • (Half of this year’s talks and 2014 still good) 39. 40. 41

ChannelLeftBridge

Audio Notifications

35

# Play a goodbye sound when the client hangs up This is a good place to catch a hangup because we know the channel id and the bridge it left. The channel is probably already destroyed, we don’t have much to work with. If the channel left a client "vm" bridge, we dont need to playbridge-1424374586.client-jessicam.33525 <- sample vm bridge id

if(stripos($event->channel->id, '.CLIENT-') !== FALSE AND stripos($event->bridge->id, '.CLIENT-') === FALSE) { $channels()->channel_playback(

$event->bridge->channels[0], 'sound:goodbye', NULL, NULL, NULL, 'goodbye');

} });

Page 36: Building Your First ARI App - Mark  · PDF fileBuilding Your First ARI App ... • Astricon Talks • (Half of this year’s talks and 2014 still good) 39. 40. 41

StasisStartCall Comes Into ARI App (Rep or Client)

36

# answer the channel $channels()->answer($event->channel->id);# create the bridge this rep will use to talk to their customers foreach($event->args as $arg) { if(preg_match('/^RepUserName-(.*)$/', $arg, $m)) {   $bridgeid = 'bridge-' . $m[1];  }}

# this is an outbound call to a client, just add to bridge if(is_array($event->args) AND in_array('IsOutBound', $event->args)) {   $bridges()->addchannel($bridgeid, $event->channel->id, '');}# this is the rep coming in, create bridge, add to bridge if(is_array($event->args) AND in_array('IsRep', $event->args)) { # can check for a bridge instead delete/recreate      $bridges()->delete($bridgeid);            $bridges()->create('mixing', $bridgeid, $bridgeid);    $bridges()->addchannel($bridgeid, $event->channel->id, '');  }  

Page 37: Building Your First ARI App - Mark  · PDF fileBuilding Your First ARI App ... • Astricon Talks • (Half of this year’s talks and 2014 still good) 39. 40. 41

ChannelEnteredBridge

Call Goes Into Bridge (Rep or Client)

37

# stop ringing on other channel. foreach($event->bridge->channels as $bchannel) {  if($event->channel->id != $bchannel) {    $channels()->channel_ringing_stop($bchannel);  }

# if this is a client, start recording the bridge if(stripos($event->channel->id, '.CLIENT-') !== FALSE) {# if it's a new voicemail bridge, save with a diff name to not clobber the old one we still might not have finished recording    $recordingname = $event->channel->id . 'vm';                     $bridges()->record($event->bridge->id,  $recordingname, ‘wav', 0, 0, ‘fail', FALSE, 'none');                             # update the call log $sql = "UPDATE CallLog SET CallPickup=$callpickup 

WHERE ChannelID=:ChannelID";

Page 38: Building Your First ARI App - Mark  · PDF fileBuilding Your First ARI App ... • Astricon Talks • (Half of this year’s talks and 2014 still good) 39. 40. 41

ChannelDestroyed

Busy or Bad Number Notification

38

# finish the call log $sql = "UPDATE CallLog SET CallEnd=:CallEnd WHERE ChannelID=:ChannelID";

# stop any ringing - only happens if the far end never picks up             $repname = preg_replace('/\d+\.client-(\w+?)\.\d+/', '$1', $event->channel->id);

$channellist = $this->phpariObject->channels()->list();foreach($channellist as $channel) { # stop any ringing if we're dialing out    $channels()->channel_ringing_stop($channel['id']);                         # if its ringing, let the rep know it hung up- TODO: more "causes"     if('Ringing' == $event->channel->state OR 'Unallocated (unassigned) number' == $event->cause_txt OR 'User busy' == $event->cause_txt) {     $channels()->playback($channel['id'], 'sound:number-not-answering', NULL, NULL, NULL, 'notanswering'); }    else {     # its connected and recording, stop recording        $recordings()->live('stop', $event->channel->id);                        }}          

Page 39: Building Your First ARI App - Mark  · PDF fileBuilding Your First ARI App ... • Astricon Talks • (Half of this year’s talks and 2014 still good) 39. 40. 41

Resources• Asterisk Docs Wiki • Swagger Interface http://ari.asterisk.org (set allowed_origins=http://ari.asterisk.org in ari.conf)

• #asterisk or #asterisk-ari on Freenode (only about 10 of us in ari)

• Asterisk Users Mailing List • Asterisk App Dev Mailing List • PHPARI.org / github • Astricon Talks • (Half of this year’s talks and 2014 still good)

39

Page 40: Building Your First ARI App - Mark  · PDF fileBuilding Your First ARI App ... • Astricon Talks • (Half of this year’s talks and 2014 still good) 39. 40. 41

40

Page 41: Building Your First ARI App - Mark  · PDF fileBuilding Your First ARI App ... • Astricon Talks • (Half of this year’s talks and 2014 still good) 39. 40. 41

41

Everyone here has the sense that right now is one of those moments when we are influencing the future.

Steve Jobs 1985 1970s “Bluebox" Phone Hardware Manufacturer

One More Thing