Introduction

This document serves as an overview for developers intending to integrate with Rebtel SDK for the first time. Furthermore, it outlines the prerequisites and guides the developer through the process of setting up and answering calls as well as sending and receiving instant messages.

The Rebtel SDK is a communication library that makes adding voice and/or messaging to mobile apps very easy. It handles all the complexity of signaling and audio management while providing the app developer the freedom to create a stunning UI.

The reference documentation contains a comprehensive description of all the classes. Please refer to the links below to find the information for your target platform:

The SDK archive can be downloaded here. It contains: The library binary, this user guide, the reference documentation and sample apps for calling and instant messaging.

A Graphical Overview

Figure 1. Schematic view over basic calling setup.
Figure 1. Schematic view over basic calling setup.

The image shows a high-level architecture overview. The two users are connected through the Rebtel cloud and talk with each other.

Glossary

The glossary below defines some of the domain specific terms used throughout this document.

Term Explanation
Caller (or “A”) The user initiating a call.
Callee (or “B”) The user receiving a call.
Application The mobile application running on iOS and/or Android. A partner can have more than one application.
Application Instance One installation of the application on a single device.
Application Key A key generated by Rebtel. The key is unique to the application. A key looks like 196087a1-e815-4bc4-8984-60d8d8a43f1d (lowercase hexadecimal formatted GUID).
Application Secret A string generated by Rebtel. The secret is used to verify the application. A secret looks like oYdgGRXoxEuJhGDY2KQ/HQ== (Base64-encoded string representation).
User A user of the mobile application. The actual person holding the mobile device.
User Identity Identity of a user in the application domain. Can be any string, for instance a user name, user id, phone number or email address.
PSTN The public switched telephone network, i.e. the regular telephone network.
Active Connection A socket connection for signaling purposes where incoming calls are received.

First Time Setup

There are a few steps which will need to be completed the first time the Rebtel SDK is used.

First, the application needs to be registered with Rebtel. Registration is available through the Rebtel Developer web at http://developer.rebtel.com/register where you will be able to obtain an Application Key and an Application Secret.

Minimum Requirements

Android 2.3 (Gingerbread) is the minimum Android version required for using the Rebtel SDK.

Adding the Rebtel Library

To be able to use the Rebtel SDK, the Rebtel library needs to be included in the app. This section is a step by step guide to that process.

Eclipse

Assuming that the latest version of the Android Development Tools are being used, copy the entire libs folder from the Rebtel SDK archive into the project’s root directory.

IntelliJ

Copy the entire libs folder to the project’s root directory. Right click on the jar files and choose Add as Library.

Permissions

In order for the app to use the Rebtel SDK, a minimum set of permissions are needed. These are specified in the AndroidManifest.xml file. If the calling functionality of the Rebtel SDK is wanted, all five permissions below are needed. However, if the calling functionality isn’t wanted, the three last (RECORD_AUDIO, MODIFY_AUDIO_SETTINGS and READ_PHONE_STATE) can be omitted.

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />

Note: The Rebtel SDK will by default hang up any Rebtel call if there is a regular call for the regular phone app. This requires the permission READ_PHONE_STATE. However, if this default functionality isn’t wanted, it’s possible to turn it off by calling RebtelClient.setRespectNativeCalls(false);. This will get apps out of requiring the READ_PHONE_STATE permission.

Moreover, for apps that do want the calling functionality but does not rely on it, consider specifying the microphone feature as being optional. In that case the app also needs to handle the lack of hardware on certain devices by disabling the Rebtel calling functionality.

<uses-feature android:name="android.hardware.microphone" android:required="false" />

Verify manifest in runtime during development

To verify that the manifest have necessary permissions the RebtelClient.checkManifest() method can be used. This method is to be called right before starting the client and will throw an exception if the manifest isn’t setup correctly. RebtelClient.checkManifest() should only be called during development. When the application is ready for release the method call can safely be removed.

Note: This method will take into consideration what the app want to supports (e.g. calling, instant messaging, respecting native calls, etc.). With that being said, call RebtelClient.checkManifest() after the setup, but before start, of the RebtelClient.

Live and Test Environment

Rebtel provides two environments:

  • Live environment - Should be used for applications deployed in production.
  • Sandbox environment - Should be used during development and testing.

The environment is passed as a parameter to the client instantiation method (see example above).

When registering an application in the developer account, two sets of Application Key and Application Secret will be generated, one for the Live environment and one for Sandbox.

Environment EnvironmentHost parameter
Live clientapi.rebtel.com
Sandbox sdksandbox.rebtel.com

Restrictions on User IDs

User IDs are restricted to only contain characters in the printable ASCII character set. That is:

!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~

User IDs must not be longer than 64 characters.

Rebtel Client

Starting the Client

To make calls or receive incoming calls an instance of the Rebtel Client is needed. To create it the following information is needed:

  • Application Key
  • Application Secret
  • Environment Host
  • User ID

The Application Key and Application Secret are obtained from Rebtel. For Environment, choose either sandbox or live (see the section Live and Test Environment. The User ID uniquely identifies the user running the Rebtel Client.

Then, set up the client listener (see Reference documentation).

Note: The client listener will be called on the same thread that the call to RebtelSDK.getRebtelClient is made on. If the calling thread is not the main-thread, it needs to have an associated Looper.

Lastly, let the Rebtel service know that the mobile application is ready for calling. Do this by calling the methods start and startListeningOnActiveConnection.

Note: The method startListeningOnActiveConnection must not be called before the RebtelClient is started. It’s safe to call once the callback onClientStarted is executed.

Setting up the client:

// Instantiate a client object using the RebtelSDK.
RebtelClient client = RebtelSDK.getRebtelClient(this, "userId",
"applicationKey", "applicationSecret", "sdksandbox.rebtel.com");

client.addClientListener(...);

// Start the Rebtel Client
client.start();

// Start listening for incoming calls.
@Override
public void onClientStarted(RebtelClient client) {
    client.startListeningOnActiveConnection();
}

Note: If the application is meant to only make outgoing calls but not receive incoming calls, simply don’t call the startListeningOnActiveConnection. Outgoing calls can be made after calling the start method.

Stopping the Client

If the app is finished with the Rebtel client, it needs to be stopped. If the client is currently listening for incoming calls, it needs to stop listening as well. After these two methods, it’s safe to release the client object.

Stopping the Rebtel client:

client.stopListeningOnActiveConnection();

client.stop();

Calling

Setting up a Call

Setting up a call using the SDK is easy. Start the Rebtel client (described in Starting the Client). Then use the client to start the call (the call method). Pass on the user identifier of the receiver to the call method, so that Rebtel services can connect the call to the receiver.

Call call = client.call("someRemoteUserId");

A call object will be returned, containing details about the participants in the call, call details such as start time, call state, possible errors etc.

Assuming the callee’s device is available, the method onCallReceivedOnRemoteEnd will be called on the CallListener, to notify that the other side has received the incoming call request. If a progress tone should be played in the app, this is where it should be started.

When the other party answers, the onCallEstablished method will be called. At this point, the users can start talking. If a progress tone was previously played, it should be stopped now.

Answering a Call

To be able to answer calls, the application has to be notified when the user receives an incoming call.

Start the Rebtel client (described in Starting the Client). The client listener will then be notified via onIncomingCall as the calls come in to the device.

When the incoming call method is executed, the call can either be connected automatically without any user action, or it can wait for the user to press an answer button. If the latter is preferred it is recommended to play a ringtone for the purpose of notifying the user that there is an incoming call.

Answering an incoming call:

@Override
public void onIncomingCall(RebtelClient client, Call call) {
    call.addCallListener(...);

    // Connect the call straight away
    call.answer();
}

In order to get events related to the call, add a call listener.

Connect the call by using the answer method on the call object passed to the method. The call object contains details about participants, start time, potential error codes and error messages.

At this point, the clients on both ends will establish the connection. When the call is established and the voice streams are running in both directions, the onCallEstablished listener method will be called. Stop the ringtone and allow for the conversation to start.

If the call should not be answered, simply use the hangup method on the call to decline. The caller will be notified that the incoming call was denied.

Hanging up an incoming call:

@Override
public void onIncomingCall(RebtelClient client, Call call) {
    call.addCallListener(...);

    // User does not want to answer
    call.hangup();
}

Disconnecting a Call

When the user wants to disconnect an ongoing call, use the hangup method. Either user taking part in a call can disconnect it.

Hanging up a call:

call.hangup();

When either part disconnects a call, the application will be notified via the call listener method onCallEnded. This allows for the user interface to be updated, an alert tone to be played, or similar.

A call can be disconnected before it has been completely established.

Hanging up a connecting call:

// Starting a call
Call call = client.call("someRemoteUserId");

// User changed his/her mind, let’s hangup
call.hangup();

Instant Messaging

The MessageClient is the entry point to Instant Messaging in the Rebtel SDK.

Messages are sent through the MessageClient, events are received via the MessageClientListener. The message client is owned by the RebtelClient and accessed via RebtelClient.getMessageClient(). Instant messaging is not enabled by default. In order to enabled instant messaging, RebtelClient.setSupportMessaging(true) must be set.

rebtelClient.setSupportMessaging(true);
rebtelClient.start();

...

MessageClient messageClient = rebtelClient.getMessageClient();
messageClient.addMessageListener(...);

Sending a message

Sending a message with the Rebtel SDK is easy. Get hold of a MessageClient as described above and pass it a WritableMessage.

// Create a WritableMessage
WritableMessage message = new WritableMessage(
        "someRecipientUserId",
        "Hello someRecipientUserId! How are you?"); 

// Send it
messageClient.send(message);

Message delivery success

When a message is successfully sent, there will be an event on the MessageClientListener, onSentMessage.

@Override
public void onSentMessage(MessageClient client, Message message) {
    // Persist message
    // Update UI
}

Updating the UI from the onSentMessage callback is especially convenient when a user is logged in into more than one device simultaneously. The onSentMessage callback will be fired on each device. This aids in keeping the UI consistent across devices.

As soon as the system has confirmed the messages were delivered the listener will be notified using the onMessageDeliveredmethod. Inspecting the MessageDeliveryInfo parameter passed to the callback reveals more details on the specific event.

@Override
public void onMessageDelivered(MessageClient client, MessageDeliveryInfo deliveryInfo) {
    Log.d(TAG, "The message with id "+deliveryInfo.getMessageId()
                +" was delivered at "+deliveryInfo.getTimestamp());
}

Message delivery failures

Delivering a message can fail for various reasons: there might not be a network available, the recipient does not have instant messaging support etc. When a message failed to reach its destination the listener is notified via the onMessageFailed callback. The reason for failing to deliver a message is propagated back as an array of MessageFailureInfo instances.

@Override
public void onMessageFailed(MessageClient client, Message message, List<MessageFailureInfo> failureInfos) {
    for(MessageFailureInfo info : failureInfos) {
        Log.d(TAG, "Failed to send to user: "+info.getRecipientId()
                    +" because: "+info.getRebtelError().getMessage());
    }
}

Note: Messages are stored in the backend for 30 days before being removed. If the recipient has not started the app and downloaded the message history within this time frame, the message will be lost and no notification received.

Resending a failed message

When a message has been returned in onMessageFailed the message instance is considered stale and should not be resent. Resending a failed message will result in an undefined behavior. Instead a new message should be created using WritableMessage(Message). This will create a new message with the same contents as the original message but with a new internal state that can be sent.

Receiving a message

Incoming messages (Message) will be delivered via the method onIncomingMessage on the MessageClientListener.

@Override
public void onIncomingMessage(MessageClient client, Message message) {
    // Persist message
    // Update UI
}

Push Notifications

An application is considered offline in the following scenarios:

  • When the application is not running at all.
  • When background mode has been disabled for the Rebtel client, and the application is not in the foreground.

For these two scenarios, offline support must have been implemented for the application to still be able to receive incoming calls and instant messages. The following sections cover how to support receiving offline calls and messages and how to handle them.

The Rebtel client relies on a push service to launch the application if it is not currently listening for incoming calls or messages due to the application being offline. Which push service to use is up to the developer, but for Android applications, the typical choice would be to use Google Cloud Messaging (GCM).

When offline, the recipient of a call or message will receive a push notification containing a Rebtel-specific payload that enables the Rebtel Client to connect the incoming call or message. Acting on the push notification brings the application to the foreground to allow the user to answer the call or view the message.

Figure 2. Push notification sequence.
Figure 2. Push notification sequence.

Figure 2 describes the following sequence of events: Both users start their applications and Rebtel clients. B kills the application, and A calls B. Rebtel notices that B is offline, and tells A to send a push notification to B so that B can answer the call.

When the Rebtel client on the caller’s (or sender’s) side observes that the destination client is offline, it will notify the application that it is required to trigger the sending of a push notification to the recipient device.

Push Notification Data

On startup, each instance of the application is expected to register a device identifier that push notifications can be addressed to, in the event that the application goes offline. The identifier is referred to as push notification data and should be provided to the Rebtel client via the method registerPushNotificationData.

The push notification data consists of an arbitrary byte sequence and it is up to the application developer to define its structure and what it contains. It should contain enough information to allow a push service to send the push to a particular user of the application on a particular device. For example, an Android exclusive application would likely use the GCM registration id as its push notification data. Multi-platform applications may use a mix of different push services. For instance, in an application running on both iOS and Android, a platform identifier in the push notification data can be used by the push server to determine whether APNS or GCM should be used.

The device specific push notification data is first registered on start up of the application. If user B then turns off the application, and user A calls B, user A’s application would get the callback CallListener.onShouldSendPushNotification. One of the parameters in this callback, is a list of PushPairs that contain a payload and a push notification data. Each element in this list corresponds to each of B’s registered push notification data (a user can have multiple devices).

The push notification data can also be unregistered by calling the RebtelClient.unregisterPushNotificationData method. This will effectively disable incoming calls or messages via push notifications for the particular device.

Enable Push Notifications

The following sections will assume that GCM is used, but the usage pattern for other push services would be similar.

The easiest way to enable offline calls or messages using GCM is to first call RebtelClient.setSupportPushNotifications(true) and then register the device specific push notification data with RebtelClient.registerPushNotificationData. In a simple example we can use the registration id received from Google when registrering to GCM.

// Register with the GCM service to get a device specific registrationId
// Should be done in a background job
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(context);
String regId = gcm.register("Your-Sender-ID");

...

rebtelClient.setSupportPushNotifications(true);
rebtelClient.start();
rebtelClient.registerPushNotificationData(regId);

Please refer to Google’s Google Cloud Messaging for Android for more information on how to use the GCM service.

Note: As described in the Push Data Notification section, the data that you register with the registerPushNotificationData method is up to the application developer to define. If using GCM, it at least has to be the registrationId from Google (so a GCM server can push to the particular device).

Sending and Receiving Push Notifications

Figure 3. Simplified view of incoming calls when offline.
Figure 3. Simplified view of incoming calls when offline.

The caller or sender will get an event notifying the application that a push notification must be sent to the recipient. The application sends the event data to the application developer’s server, which passes the push payload on to Google’s servers. Google then sends a push notification to the recipient’s device that there will be an incoming call or message. The recipient can subsequently answer the call or read the message.

The application developer must have a server that is configured for sending push notifications to Google Cloud Messaging Service. Please see the Rebtel REST API User Guide for details on how to handle feedback from Google Cloud Messaging Service.

Please refer to Google’s Google Cloud Messaging for Android for more information.

On ”A” Side

When the recipient’s application is offline and it is required to notify the user via a push notification, the caller’s or sender’s application will be notified via the callback method CallListener.onShouldSendPushNotification.

The callback includes a List of PushPairs. The pairs contain a payload that is Rebtel- and call-specific. Moreover the pairs contain a push data byte array. The Rebtel specific payload should be embedded in the push notification sent to the recipient’s device(s). The push data is the same push data that the recipient’s application registered earlier. There might be multiple registered devices for the recipient user (e.g. the same user is using the application on both a phone and a tablet), that is why the callback includes a List of Push Pairs.

public void onShouldSendPushNotification(Call call, List<PushPair> pushPairs) {
    // Send payload and push data to application server
    // which should communicate with GCM Service to send push notifications.
}

A push notification should be sent to each device, where each entry in the parameter pushPairs list corresponds to one device. Each push notification should include the Rebtel-specific payload so it can be forwarded to the Rebtel client running on the destination device.

The Rebtel-specific payload should be embedded as custom payload data in the GCM Payload.

{
  "registration_ids" : ["APA91bHun4MxP5egoKMwt2KZFBaFUH-1RYqx...", ...],
  "data" : {
    "Rebtel" : <payload>,
  },
}

Please refer to Google’s Google Cloud Messaging for Android for more information.

On ”B” Side

As a prerequisite, offline calling and messaging must have been enabled on the receiver’s side (see Push Notifications).

When the application receives a push notification from the Google Cloud Messaging Service, the application should extract the Rebtel-specific payload from the push notification, and forwarding it to the Rebtel client via the method relayRemotePushNotificationPayload.

protected void onMessage(final Context context, final Intent intent) {
    String rebtelPayload = intent.getStringExtra("Rebtel");

    rebtelClient.relayRemotePushNotificationPayload(payload);
}

Application Authentication

When initiating a Rebtel client, a user identity should be provided. The first time the application instance and the Rebtel client is running on behalf of a particular user, it is required to register against the Rebtel service. This is something that is mainly handled transparently by the Rebtel SDK, but also works a bit differently depending on which authentication scheme the developer chooses to use.

The step of registering a user identity against the Rebtel service requires the application instance to be authenticated and authorized to perform the user registration. Once the application instance has successfully registered the user identity, it will also have obtained the necessary credentials to perform further authorized requests for that specific user, i.e. calling.

Two different authentication schemes are available as described below.

Authentication by Client Access to Application Secret

This application authentication scheme is based on giving the application direct access to the Application Secret, which enables the Rebtel Client SDK in the application to self-sign an authorized request to perform user registration. Choosing this authentication scheme corresponds to initiating the Rebtel client by using the factory method that takes both an Application Key and an Application Secret.

Using this authentication scheme is the quickest to get started with as the client application instances can directly perform authorized requests against the Rebtel service.

Note: It is not recommended to have the application secret in plain text in the source code in the release version of the application.

Authentication Supported by Application Server

This application authentication scheme is based on the client application instance not having direct access to the Application Secret. Instead, when the Rebtel client needs to perform an authorized request to register a user identity against the Rebtel service, it will need to be provided with an authentication signature and a registration sequence to perform the registration. This should be provided by the application’s backend service, e.g. via a HTTP request over an SSL connection.

This scheme has the benefit of the application secret never being directly accessible by the client applications and gives a better level of security as well as flexibility.

Note: The need for the Rebtel client to request an authentication signature and registration sequence is only required once per user and device. Not on every application launch.

Figure 4. Authentication Supported by Application Server
Figure 4. Authentication Supported by Application Server

Generating the Signature

The Application Server is responsible for generating a valid signature for each registration request that it accepts as a valid user registration. The sequence is a cryptographic nonce, and must be a monotonically increasing value. The signature is then generated as as follows (pseudogrammar):

string userId;
string applicationKey; // E.g. "196087a1-e815-4bc4-8984-60d8d8a43f1d"
string applicationSecret; // E.g. "oYdgGRXoxEuJhGDY2KQ/HQ=="
uint64 sequence = previous_sequence + 1; // E.g. previous_sequence = 0

string stringToSign = userId + applicationKey + sequence + applicationSecret;

// Use a Base64-encoder that don't introduce line-breaks, 
// or trim the output signature afterwards.
string signature = Base64.encode(SHA1.digest(stringToSign));

E.g. in Java:

    // Generating the Signature - Java
    // import java.security.MessageDigest;
    // import org.apache.commons.codec.binary.Base64;

    String userId; 
    String applicationKey; // E.g. "196087a1-e815-4bc4-8984-60d8d8a43f1d";
    String applicationSecret; // E.g. "oYdgGRXoxEuJhGDY2KQ/HQ==";
    long sequence; // fetch and increment last used sequence

    String toSign = userId + applicationKey + sequence + applicationSecret;

    MessageDigest messageDigest = MessageDigest.getInstance("SHA-1");
    byte[] hash = messageDigest.digest(toSign.getBytes("UTF-8"));

    String signature = Base64.encodeBase64String(hash).trim();

Starting the Client and Providing Authorization credentials for User Registration

RebtelClient client = RebtelSDK.getRebtelClient(getApplicationContext(), "userId", "applicationKey", "sdksandbox.rebtel.com");
client.addClientListener(...);


// This will on the first run for this user call onRegistrationCredentialsRequired on the client listener.

public void onRegistrationCredentialsRequired(RebtelClient client, final ClientRegistration registrationCallback) {
    // Perform API request to server which keeps the Application Secret.
    myApiService.getAuthorizedSignatureForUser("userId", new OnCompletedCallback() {

        public void onCompleted(String signature, long sequence) {
            registrationCallback.register(signature, sequence);
        }
    });
}

Miscellaneous

Sample applications

We have included sample applications that show how to build very basic apps using the Rebtel SDK. The code can be found in the “/samples” folder. To be able to call or message with the sample applications, just enter a valid application key and a valid application secret in the classes RebtelClientService and MessageService, respectively.

Note: This is only meant as small samples, and should not be seen as a complete example how to build a calling or messaging apps.

Encryption Export and Google Play

Please make sure to check the Summary of U.S. Export Controls Applicable to Commercial Encryption Products and ensure that the application is registered for the Encryption Regulations, if applicable. It can be found under this link.

Statistics

The Rebtel SDK client will upload statistics to the Rebtel servers at the end of a call, a call failure or similar event. The statistics are used for monitoring of network status, call quality and other aspects regarding the general quality of the service.

Some of the information is not anonymous and may be associated with the User ID call participants.

The statistics upload is done by the client in the background.

Support

If you need support, please visit our community or send an email to sdk@rebtel.com.

Third Party Libraries and Copyright

All Third Party Libraries and Copyright notices can be found under this link.