VoIP blog

OpenSIPS Push Notification and GCM Service integration for device battery optimization.

 The main issue in mobile devices is battery consumption in efficient way. SIP based smart phone applications keeps UDP/TCP connection open for SIP registration for receiving incoming call and SIP Options for Keep Alive. We can save mobile phone battery by stooping the SIP connection for Keep Alive Message and REGISTER Request, and will only open the connection when a incoming or outgoing call is requested. We will stop the SIP connection when app is not using it. Apple iOS, Google Android and Microsoft Windows Phone has exposed its API’s and networking services for receiving/sending remote notification so that app can interact according to the notification type. The device will remain close it SIP connection and will open when it need to send/receive a call. Also these devices open one Light weight TLS/HTTPS connection with their OS Services for receiving push notification for all type of applications installed on the device.When a device is in PUSH state we keep track its device token, current state in the database and use it for sending notifications.

 OpenSIPS Configuration for PUSH Notification Services.

we are assuming that we have a OpenSIPS configure and a PUSH Notification Server configured. There is excellent tutorial shared by raywender for developing push based client application development.

USAGE Scenario 

User A is registered in OpenSIPS in location table. User-A is dialing to user B and User-B’s device token exists in the database.

OpenSIPS will send a PUSH Notification to User-B by a curl web hit, and will wait for User-B to come online for 45 Seconds.

When User-B come online a real SIP INVITE will be lander to his/her SIP phone and SIP call will be connected.

 Remember, every time a user installed the calling applicatin it will tell it app server about its device token using any TCP connection or any HTTPS based web POST hit.

There are Three calling cases:

*I’m supposing that we usually give ringing bell to source for 45 seconds.

We fetch the device token from the database and store to $avp(device_token)….

Fetch Device Token from DB.

avp_db_query("SELECT callerid, ipaddr, port, realm, regseconds, apns_devicetoken, platform FROM location WHERE block='0' callerid='$var(dst)' LIMIT 1","$avp(callerid);$avp(ip);$avp(port));$avp(realm);$avp(regseconds);$avp(device_token);$avp(platform)","1");

We got device token in $avp(device_token), we need to save avp in db for keeping it for a complete SIP dialog, as after a transaction AVP destroys. If we save these along with CALL-ID we can retrieve it after next transaction.

$avp(push_key) = "push_" + $ci + $avp(callerid);
if(!cache_fetch("local","$avp(push_key)",$avp(device_token))) {
 cache_store("local","$avp(push_key)","$avp(device_token)",60);
avp_db_store("$ci", "$avp(callerid)");  # tu_callerid
avp_db_store("$ci", "$avp(fu_callerid)");
avp_db_store("$ci", "$avp(device_token)");
avp_db_store("$ci", "$avp(platform)");
}

1- CANCEL PROCESSING:

Missed call Notification will occur when user has less then 45 seconds call. In OpenSIPS we will handle in CANCEL processing section.

##################################################################################

if (is_method("CANCEL")) {
 # your own opensips dialplan logic comes here....
 # before cancel request you need to fetch device token from the database and save to avp("device_token")
 if (avp_db_load("$ci", "$avp(callerid)") && avp_db_load("$ci", "$avp(fu_callerid)") && avp_db_load("$ci", "$avp(device_token)") && avp_db_load("$ci", "$avp (platform)"))
 {
 if($avp(platform) =~ "android" ) {
 xlog("L_NOTICE", "[$pr:$fU@$si:$sp]: Android user canceling the call\n");
 exec_avp("wget -q -O - 'https://techvoiper.com/push/push.php?apnsid=1&destination=00$avp(callerid)&callerid=00$avp(fu_callerid)'","$avp(status)");
 xlog("L_NOTICE", "[$pr:$fU@$si:$sp]: $avp(status) \n");
 }else
 {
 exec_avp("wget -q -O - 'https://techvoiper.com/push/push.php?apnsid=1&destination=00$avp(callerid)&callerid=00$avp(fu_callerid)'","$avp(status)");
 };
 xlog("L_NOTICE", "[$pr:$fU@$si:$sp]: Missed call from '$avp(platform)' user '$fu' to '$tu' \n");
 };
 exit;
 };

 

##################################################################################

2- Timed out call(more then 45 seconds call)

If ring timeout is occured, i-e 480, you need to send

sl_send_reply("480","Temporarily Unavailable: no response from callee");

# rest of code is same of CANCEL procession block…

##################################################################################

3- Incoming Call Processing

You need to hit a web url in INVITE block and give the source caller a fake ring from any media server like Asterisk.

From media server you give a ringing, return busy to opensips  while opensips iterate the same for 45 second i-e  Nine fake rings from Media server of duration 5 Seconds.

 

 OpenSIPS Configuration is done, now you need to write a PUSH notification server for delivering push notification to the device and device_token update service.
Device calls the https based web servie to tell the system about its device token.
OpenSIPS -> PUSH Server -> Apple PUSH NOTIFICATION SERVER|Google GCM SERVER ---> Apple iPhone| Android Device
Your PUSH Notification server will sends NOTIFICATION to APPLE SERVER via SSL connection or Google GCM via HTTPS.
Push notification server for sending notification to Device
#pem certificate generation process for server and client iOS application from raywender
#http://www.raywenderlich.com/3525/apple-push-notification-services-tutorial-part-2
The above link covers PUSH Notification based chat application for iPhone.
I'll add a iOS SIP phone using pjSIP Stack later on, right now, you should write your own..

PUSH Notification Service for connecting to APNS

 #####################################################################

#push.php
 <?php
 $gateway = 'ssl://gateway.push.apple.com:2195';
 $cert = '/var/www/certs/server_apns_certificates_bundle.pem';
 $company = "TechVoIPer";
 $apnsid = (int)@$_REQUEST['apnsid'] or $apnsid = (int)@$argv[1];
 $deviceToken = @$_REQUEST['dtk'] or $deviceToken = @$argv[2];
 $destination = @$_REQUEST['destination'] or $destination = @$argv[3];
 $callerid = @$_REQUEST['callerid'] or $callerid = @$argv[4] or $callerid = "";
 $platform = @$_REQUEST['platform'] or $platform = "";
 # iPhone specific php code...
 if($apnsid == 1) {
 $message = !is_null($destination) ? ("$incoming_call_from ".str_replace(" ","+",$destination)) : ("$incoming_call_from $company");
 $act_loc_key = "$answer";
 $body['aps'] = array('alert' => array('body' => $message, 'action-loc-key' => $act_lock_key));
 if ($badge) { $body['aps']['badge'] = $badge; }
 if ($sound) { $body['aps']['sound'] = $sound; }
 $body['apnsid']=1;
 sendNotification($message,$body,$deviceToken);
 return;
}
function sendNotification($message,$body,$deviceToken) {
 global $cert;
 global $apnsid;
 $ctx = stream_context_create();
 stream_context_set_option( $ctx, 'ssl', 'local_cert', $cert);
 $fp = stream_socket_client($gateway, $err, $errstr, 60, STREAM_CLIENT_CONNECT, $ctx);
 if (!$fp) {
 print "Failed to connect $err $errstr\n";
 return;
 } else {
 print "Connection OK\n";
 }
$payload = json_encode($body);
 $msg = chr(1) . chr(1) . chr(1) . chr(1) . chr(1) . pack('N', 40000). pack("n",32) . pack('H*', str_replace(' ', '', $deviceToken)) . pack("n",strlen($payload)) . $payload;
 fwrite($fp, $msg);
 fclose($fp);
 }
?>
*OpenSIPS+ APNS code snippets  code:Download

 


Hit Counter provided by Curio cabinets