Tuesday 5 March 2019

GO AMI - Asterisk Originate Example

package main

import (
    "fmt"
    "log"

    "github.com/heltonmarx/goami/ami"
)

var username, secret, host string = "test", "test", "127.0.0.1:5038"

func main() {
    //flag.Parse()

    socket, err := ami.NewSocket(host)

    orig := ami.OriginateData{}
    ////////////////////////////////////////////////
    orig.Channel = "Local/1000@leg1"
    orig.Exten = "2000"
    orig.Context = "leg2"
    orig.Priority = 1
    //orig.Application = ""
    orig.Data = ""
    orig.Timeout = 10
    //orig.CallerID = "bot"
    //orig.Variable = ""
    //orig.Account = "bot"
    orig.Async = "true"
    //orig.Codecs = "alaw&ulaw&g729"
    ////////////////////////////////////////////////

    socket, err := ami.NewSocket(host)
    if err != nil {
        log.Fatalf("socket error: %v\n", err)
    }
    if _, err := ami.Connect(socket); err != nil {
        log.Fatalf("connect error: %v\n", err)
    }
    //Generate UUID for AMI requests
    uuid, _ := ami.GetUUID()
    if err := ami.Login(socket, username, secret, "Off", uuid); err != nil {
        log.Fatalf("login error: %v\n", err)
    }
    fmt.Printf("login ok!\n")

    if res, err := ami.Originate(socket, uuid, orig); err != nil {
        println("ERROR: ", err)
        println("Response: ", res)
    }

    println("Call originated Successfully")

    //time.Sleep(5 * time.Second)

    if ami.Logoff(socket, uuid) != nil {
        println("Logoff Failed")
    } else {
        println("Logoff successful")
    }
}



/// Asterisk  Dialplan
/etc/asterisk/extensions.conf
//////////////////////////////////////////////////////
[leg1]
exten =>1000,1,NoOp(leg1)
same=>n,Answer()

[leg2]
exten =>2000,1,NoOp(leg2)
same=>n,playback(tt-monkies)





// Asterisk Manager configuration

//////////////////////////////////////////
/etc/asterisk/manager.conf

[test]
secret=test
deny=0.0.0.0/0.0.0.0
permit=127.0.0.1/255.255.255.0
read=system,call,log,verbose,command,agent,user,config,command,dtmf,reporting,cdr,dialplan,originate
write=system,call,log,verbose,command,agent,user,config,command,dtmf,reporting,cdr,dialplan,originate


Tuesday 18 September 2018

ping with push results in file with timestamp

ping 10.230.0.26 | while read pong; do echo "$(date +%Y-%m-%d\ %H:%M:%S): $pong"; done >>ping_test.log &

Tuesday 11 September 2018

Perl NetSIP REGISTER and INVITE Example

use Net::SIP;
#use strict;
#use warnings;


my $uae_sip = '10.0.0.2:5060';
my $from = '111';
my $secret = 'abcd12';

my $to = '14168404385';


# create new agent
my $ua = Net::SIP::Simple->new(
      outgoing_proxy => $uae_sip,
      registrar => $uae_sip,
      domain => $uae_sip,
      from => $from,
      auth => [ $from, $secret ],
);


if($ua->register( expires => 60 )){
    print "REGISTER sucessful. \n";
}else {
    print "REGISTER Failed";
}

#$ua->register( expires => 60 );

#print $ua->error;
#print $ua_error;
##die();
#if ($ua->error){
#    print "Registration Failed " . $ua->error;
#}else {
#    print "SIP Registration Sucessful \n";
#}

#my $rtp_done;

my $hangup = 20;
my $stopvar = 20;
my $file = '';
my $to = '0581104414';

my $peer_hangup;

my $call = $ua->invite( $to,
    init_media => $ua->rtp( 'recv_echo', $file,0 ),
    recv_bye => \$peer_hangup,
);
if($call->error ){
    # do nothing.
    print "INVITE Failed" . $call->error . "\n";
}else{

    print "INVITE sucessful \n";
}

# mainloop until other party hangs up or we hang up after

my $stopvar;
$ua->add_timer( $hangup, \$stopvar ) if $hangup;
$ua->loop( \$stopvar,\$peer_hangup );

# timeout checking block.
if ( $stopvar ) {
    $stopvar = undef;
    $call->bye( cb_final => \$stopvar );
    $ua->loop( \$stopvar );
}






Wednesday 20 January 2016

Asterisk AMI Events using Perl POE


POE is a Perl framework for reactive systems, cooperative multitasking, and network applications. Read more about POE.

I'll explain, how we can use POE event loop to process the AMI Event in a asynchronous way. We can build any application in Perl that is based on AMI Events. Like Realtime Asterisk based billing, custom application to push events for web application, or any other application. With this POE Application we have all states of the calls, include some states which we don't have in the Asterisk Dialplan.


#!/usr/bin/perl -w

use strict;
use threads;
use threads::shared;
use warnings;
use Data::Dumper;
use Config::Abstract::Ini;
use POE qw(Component::Client::Asterisk::Manager);


#AMI-POE
my $host = '10.11.22.33';
my $port = '5038';
my $user = 'user';
my $pass = 'password';

my $debug = 1;
my @threadz;

POE::Component::Client::Asterisk::Manager->new(
        Alias => 'monitor',
        RemoteHost      => $host,
        RemotePort      => $port,
        Username        => $user,
        Password        => $pass,
        CallBacks       => {
                #cb_on_event => ':all', # catchall for all manager events
                cb_on_new_channel      => { 'Event' => 'Newchannel', },
                cb_on_rename =>{'Event' => 'Rename'},
                cb_on_dial             => {'Event' => 'Dial'},
                cb_on_newexten => {'Event' => 'Newexten'},
                on_Bridge      => {'Event' => 'Bridge','Bridgestate' => 'Link'},
                on_peer_status => { 'Event' => 'PeerStatus', },
                on_new_callerid        => { 'Event' => 'Newcallerid', },
                on_ring => { 'Event' => 'Newchannel', 'State' => 'Ring', },
                on_hangup      => { 'Event' => 'Hangup','Cause-txt' => 'Normal Clearing', },
                on_cdr => { 'Event' => 'Cdr', },
                on_rtcp_received => { 'Event' => 'RTCPReceived' },


        },
        inline_states => {
                #cb_on_event    => \&on_event,
                cb_on_new_channel      => \&on_new_channel,
                cb_on_rename => \&on_rename,
                cb_on_dial             => \&on_dial,
                cb_on_newexten => \&on_newexten,
                 on_Bridge      => \&on_Bridge,
                on_answer      => \&on_answer,
                on_peer_status => \&on_peer_status,
                on_new_callerid        => \&on_new_callerid,
                on_ring => \&on_ring,
                on_hangup      => \&on_hangup,
                on_cdr => \&on_cdr,
                on_rtcp_received => \&on_rtcp_received,
        },
); POE::Kernel->run();


sub on_rtcp_received(){
        my $input = $_[ARG0];
        #print Data::Dumper->Dump([$input]);
        my $packet_loss = $input->{'PacketsLost'};
        if($packet_loss >200){
                print Data::Dumper->Dump([$input]);
                # This call has lot of packet loss
        }
}


sub on_answer{
    #print "We are in ON-Answer STATE \n";
    my $input = $_[ARG0];
    print Data::Dumper->Dump([$input]);

}

sub on_rename{
    print "----------------> on_rename() \n";
        my $input = $_[ARG0];
        print Data::Dumper->Dump([$input]);

}



sub on_Bridge{
        my $input = $_[ARG0];
        #print "on Bridge CALLER ID\n";
        print Data::Dumper->Dump([$input]);
}

sub on_dial{
        my $input = $_[ARG0];
        print "on_dial\n";
        print Data::Dumper->Dump([$input]);

}

sub on_event{
        # Print all AMI Events
        my $input = $_[ARG0];
        print Data::Dumper->Dump([$input]);
        #print "on_event\n";
}

sub on_newexten{
         my $input = $_[ARG0];
         print Data::Dumper->Dump([$input]);

        my $fu_callerid = $input->{'CallerIDNum'};
        my $ext_status = $input->{'Application'};
        if($ext_status eq 'Answer'){
               print Data::Dumper->Dump([$input]);
               my $channel = $input->{'Channel'};
               my $context = $input->{'Context'};
               my $local_ext = $input->{'Extension'};
               my $priority = $input->{'Priority'};
               print "in Answer state, $channel, $context, $local_ext, $priority \n";
        }
       #print "on_newexten\n";

}


sub on_new_channel{
    my $input = $_[ARG0];
    print "on_new_channel()\n";
    print Data::Dumper->Dump([$input]);

}

sub on_peer_status{
}

sub on_new_callerid{
    print "on_new_callerid\n";
    my $input = $_[ARG0];
    my @Dial_Event=Data::Dumper->Dump([$input]);
    my $callerid = $input->{'CallerIDNum'};
    print "on_new_callerid: $callerid \n";
}


sub on_ring{

}



sub on_hangup{
         my $input = $_[ARG0];
        print Data::Dumper->Dump([$input]);
        my $fu_callerid = $input->{'ConnectedLineNum'};
        my $cause_text = $input->{'Cause-txt'};
        my $channel  = $input->{'Channel'};

        my $tmp0 = substr($channel,0,3);
        print "leg detection...$tmp0\n";
}


sub on_cdr{

}


Webrtc based calling using sipml5 and Asterisk

* This tutorial is deprecated. Asterisk compilation is seamless with pjsip-bundled option. Asterisk compilation part is deprecated one, rest of the tutorial should work.

There are few steps to make calls using webrtc client. 

  1. Install prerequisites
  2. Install pjproject
  3. Install Asterisk 
  4. Generate wss DTLS certificates for Asterisk
  5. Install Apache HTTP Server
  6. Generate self signed https certificates for Apache
  7. Configure Asterisk
  8. Configure sipml5 client

1 - Download and install prerequisites

apt-get update
apt-get upgrade
reboot
apt-get install build-essential libncurses5-dev libxml2-dev libsqlite3-dev libssl-dev uuid-dev libjansson-dev libsrtp0-dev pkg-config unzip
cd /usr/src
wget http://downloads.asterisk.org/pub/telephony/asterisk/asterisk-13-current.tar.gz
wget https://github.com/sipml5/sipml5/archive/master.zip




2 -  Install pjproject
cd /usr/src/
tar -xjvf pjproject-2.4.5.tar.bz2
cd pjproject-2.4.5
./configure --prefix=/usr --enable-shared --disable-sound --disable-resample --disable-video --disable-opencore-amr CFLAGS='-O2 -DNDEBUG'
make dep
make
make install
ldconfig
ldconfig -p | grep pj
PKG_CONFIG_PATH=/usr/lib64/pkgconfig/
export PKG_CONFIG_PATH


3 -  Install Asterisk
cd /usr/src/
tar -xzvf asterisk-13-current.tar.gz
./configure --prefix=/usr --libdir=/usr/lib64
make && make install && make samples                        

ln -sf /usr/lib64/libasteriskssl.so.1 /usr/lib/libasteriskssl.so.1
ln -sf /usr/lib64/libresample.so.2 /usr/lib/libresample.so.2
ln -sf /usr/lib64/libportaudio.so.2 /usr/lib/libresample.so.2

4 -  Generate wss DTLS certificates

cd /usr/src/asterisk-13.7.0/contrib/scripts/
./ast_tls_cert -C mypbx.local -O "my local pbx" -d /etc/asterisk/keys

5 -  Install Apache HTTP Server

apt-get install apache2


6 -  Generate self signed ssl certificates

openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/apache2/ssl/apache.key -out /etc/apache2/ssl/apache.crt

sudo a2enmod ssl
vim /etc/apache2/sites-available/default-ssl.conf
Search ssl block  <VirtualHost _default_:443> and update the following fields.
      
        ServerAdmin admin@example.com
        ServerName your_domain.com
        ServerAlias www.your_domain.com
        DocumentRoot /var/www/html       
        SSLCertificateFile /etc/apache2/ssl/apache.crt
        SSLCertificateKeyFile /etc/apache2/ssl/apache.key

a2ensite default-ssl.conf
/etc/init.d/apache2 restart


7 -  Configure Asterisk


sip.conf
[99300]
deny=0.0.0.0/0.0.0.0
dtmfmode=rfc2833
canreinvite=no
host=dynamic
trustpid=yes
sendpid=no
insecure=port,invite
type=friend
nat=no
port=5060
qualify=yes
qualifyfreq=60
transport=ws,wss,udp
avpf=yes
force_avp=yes
icesupport=yes
encryption=yes
callgroup=
pickupgroup=
permit=0.0.0.0/0.0.0.0
dial=SIP/99300
secret=c602999e72c0054c7ad2f4b94559b23d
context=users
mailbox=99300@device
callerid=300 <99300>
callcounter=yes
faxdetect=no
cc_monitor_policy=generic
dtlsenable=yes
dtlsverify=fingerprint
dtlscertfile=/etc/asterisk/keys/asterisk.pem
dtlscafile=/etc/asterisk/keys/ca.crt
dtlssetup=actpass
dtlsrekey=0
disallow=all
;allow=g729
allow=alaw
allow=ulaw
;allow=ilbc
;allow=g726
;allow=opus


[100]
type=friend
callerid="100" <100>
defaultusername=100
host=dynamic
secret=100
dtmfmode=rfc2833
insecure=invite,port
canreinvite=yes
nat=force_rport,comedia
qualify=no
context=users
disallow=all
;allow=g729
allow=alaw
allow=ulaw
;allow=ilbc



extensions.conf
[users]
exten => 100,1,Dial(SIP/100)
exten => 99300,1,Dial(SIP/99300)

http.conf
enabled=yes
bindaddr=0.0.0.0
bindport=8088
tlsenable=yes          ; enable tls - default no.
tlsbindaddr=0.0.0.0:8089    ; address and port to bind to - default is bindaddr and port 8089.
tlscertfile=/etc/asterisk/keys/asterisk.pem
tlsprivatekey=/etc/asterisk/keys/asterisk.pem



8 -  Configure sipml5 client

cd /usr/src/
unzip master.zip
mv sipml5-master/ /var/www/html/
cd /var/www/html/
mv sipml5-master/ sipml5
chown www-data:www-data sipml5 -R

Open latest Chrome/Firefox and accpet certificates.
https://asterisk-ip:8089/
https://asterisk-ip/sipml5/call.htm


Click on the advanced setting
Disable Video:
Enable RTCWeb Breaker[1]: check on
WebSocket Server URL[2]: wss://server-ip:8089/ws
SIP outbound Proxy URL[3]:udp://server-ip:5060
ICE Servers[4]: [ ]

Save the advanced setting page and nevigate to call.htm page and enter fields.

Click Register button and start making/receiving calls.

This works for my LAN environment, configure it as per your environment.
Hope it will be useful in developing your calling scenarios.