Docs

User Guide

Introduction

The Sinch SDK is a product that makes adding voice calling and/or instant messaging to mobile apps easy. It handles the complexity of signaling and audio management while providing you the freedom to create a stunning user interface.

This document provides an overview for developers integrating with Sinch SDK for the first time. It outlines the prerequisites and guides you through the process of setting up and answering calls as well as sending and receiving instant messages.

Please see the Reference Documentation for a comprehensive description of all the classes.

First time setup

This is a step-by-step guide about setting up the Sinch SDK for the first time.

Register an Application

  1. Register a Sinch Developer account at http://www.sinch.com/signup.
  2. Setup a new Application using the Dashboard where you can then obtain an Application Key and an Application Secret.

Download

The Sinch SDK can be downloaded at www.sinch.com/download/. It contains: the library binary, this user guide, reference documentation, and sample apps for calling and instant messaging.

Add the Sinch framework

Drag the Sinch framework folder from the SDK distribution package folder into the Frameworks section of the Project Navigator.

The Sinch SDK depends on the following frameworks, which must be added to the project and linked with the application target.

  • AudioToolbox.framework
  • AVFoundation.framework
  • Security.framework

Some additional linker flags need to be added. In the Build Settings pane for the application target, set the following:

  • Other Linker Flags -> -ObjC -Xlinker -lstdc++

Sinch is available as a CocoaPod

If you are using CocoaPods, add the following to your Podfile:

pod 'SinchRTC'

Tip: Using the pod allows you to skip the manual setup of linker flags in the previous section.

Info.plist

If only the instant messaging functionality will be used, then no changes to the Info.plist are necessary.

If voice calling functionality will be enabled and used, add the following to your Info.plist:

  • Required background modes (UIBackgroundModes):
    • Application plays audio (audio)
    • Application provides Voice over IP services (voip)

Sinch client

The SINClient is the Sinch SDK entry point. It is used to configure the user’s and device’s capabilities, as well as providing access to feature classes such as the SINCallClient, SINMessageClient and SINAudioController.

Creating the SINClient

Set up the client and its delegate (SINClientDelegate, see Reference documentation).

#import <Sinch/Sinch.h>

// Instantiate a Sinch client object
id<SINClient> sinchClient = [Sinch clientWithApplicationKey:@"<application key>" 
                                          applicationSecret:@"<application secret>"
                                            environmentHost:@"sandbox.sinch.com" 
                                                     userId:@"<user id>"];

The Application Key and Application Secret are obtained from the Sinch Developer Dashboard. See Production and Sandbox Environments for valid values for environmentHost. The User ID should uniquely identify the user on the particular device.

Specifying capabilities

The SINClient can be configured to enable / disable certain functionality. Please see the Reference for details.

The following example shows how to setup the client with both voice calling and instant messaging enabled.

// Specify the client capabilities. 
// At least one of the messaging or calling capabilities should be enabled.
[sinchClient setSupportCalling:YES];
[sinchClient setSupportMessaging:YES];
[sinchClient setSupportActiveConnectionInBackground:YES]; 
[sinchClient setSupportPushNotifications:YES];                                                    

Starting the Sinch client

Before starting the client, make sure you assign a SINClientDelegate.

// Assign as SINClientDelegate                             
sinchClient.delegate = ... ;

// Start the Sinch Client
[sinchClient start];

// Start listening for incoming events (calls and messages).
[sinchClient startListeningOnActiveConnection];

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

For applications that want to to receive incoming calls while not running in the foreground, a few additional steps are required. Refer to the Background Mode and Push Notifications sections for details.

Life cycle management of a SINClient-instance

We recommend that you initiate the Sinch client, start it, but not terminate it, during the lifetime of the running application. That also implies that the SINClient-instance should be retained by the application code.

If incoming events are not needed, stop listening for incoming events by invoking -[SINClient stopListeningOnActiveConnection]), but not invoking -[SINClient terminate]. The reason is initializing and starting the client is relatively resource-intensive in terms of CPU.

It is best to keep the client instance alive and started unless there are reasons specific to your application. It should not be necessary to dispose of the client instance if memory warnings are received from iOS, because once the client is started it does not use much memory in comparison to view layers, view controllers etc.

For the same reason, if the support for push notifications is enabled, the preferred method of temporarily stopping incoming events using push notifications is to unregister the push notification data (see Push Notifications).

The Sinch client can of course be completely stopped and also disposed. To do so, call the terminate method on the client before the application code releases its last reference to the client object.

The following example shows how to dispose the Sinch client:

[sinchClient stopListeningOnActiveConnection];
[sinchClient terminate];
[sinchClient release]; // unless using ARC
sinchClient = nil;

Calling

The Sinch SDK supports two types of calls: app-to-app calls and app-to-phone calls. The SINCallClient is the entry point for the calling functionality of the Sinch SDK.

Calls are placed through the SINCallClient and events are received using the SINCallClientDelegate. The call client is owned by the SinchClient and accessed using [sinchClient callClient]. Calling is not enabled by default.

Enable calling with the following method before starting the SINCallClient:

[sinchClient setSupportCalling:YES];    

Setting up an app-to-app call

Use the call client to start the call using the callUserWithId: method by passing the user identifier of the callee (the user receiving a call) as an argument.

id<SINCallClient> callClient = [sinchClient callClient];
id<SINCall> call = [callClient callUserWithId:@"<remote user id>"];

A call object is returned, containing details about the participants in the call, call details such as start time, call state, possible errors, and so on.

Assuming the callee’s device is available and responsive, the delegate method callDidProgress: is called. It notifies the application that the outgoing call is progressing. If a progress tone should be played, this is where it should be started. We recommend that you use the available functionality provided by the Sinch SDK to play sounds such as ringtones (SINAudioController). See Playing Ringtones for details.

When the other party answers, the callDidEstablish: call delegate method is called. Now, the users can start talking. If a progress tone has been initiated, it should be stopped now, in the delegate callback method.

Setting up an app-to-phone call

An app-to-phone call is a call that is made to a phone on the regular telephone network. Setting up an app-to-phone call is not much different from setting up an app-to-app call.

Instead of invoking the callUserWithId: method, invoke the callPhoneNumber: method on the SINCallClient object. Sufficient funds must be available on the Sinch account and a valid phone number specified for the call to connect successfully. The phone number should be specified according to the E.164 number formatting (http://en.wikipedia.org/wiki/E.164) recommendation and should be prefixed with a ‘+’. E.g. to call the US phone number 415 555 0101, the phone number should be specified as “+14155550101”. The ‘+’ is the required prefix and the US country code ‘1’ prepended to the local subscriber number.

Placing an app-to-phone call requires an account with credits; topping up credits can be done on the Account page. Credits are used each time an app-to-phone call is placed and the balance history is updated after each call.

App-to-phone calls can be tested by calling the following test number: +46000000000. When placing a call to this number, you will hear a voice prompt stating that the call has been connected, and shortly after that the call will automatically be ended.

Handling incoming calls

To answer calls, the application must be notified when the user receives an incoming call.

To act on the incoming calls, add a call client delegate to the call client. The call client delegate is notified using the delegate method didReceiveIncomingCall: as calls come in to the device.

When the delegate method is executed, the call can either be connected automatically without any user action, or it can wait for the user to press the answer or the hangup button. We recommend that ringtones are played from within the delegate callback method. See Playing Ringtones for details.

- (void)client:(id<SINCallClient>)client didReceiveIncomingCall:(id<SINCall>)call {
    // Start playing ringing tone
    ... 

    // Assign delegate
    call.delegate = self;
}

To get events related to the call, set the call delegate. The call object contains details about participants, start time, potential error codes, and error messages.

Answering an incoming call

To answer a call, use the answer method on the call to accept it. If a ringtone was previously played, it should be stopped now.

User presses the answer button:

// User answers the call 
[call answer];

// Stop playing ringing tone
...     

Now, the clients on both ends establish the connection. When the call is established and the voice streams are running in both directions, the callDidEstablish: delegate method is called.

Declining an incoming call

If the call should not be answered, use the hangup method on the call to decline. The caller is notified that the incoming call was denied. If a ringtone was previously played, it should be stopped now.

User presses the hangup button:

// User does not want to answer
[call hangup];

// Stop playing ringing tone
...     

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 party disconnects a call, the application is notified using the call delegate method callDidEnd:. This allows the user interface to be updated, an alert tone to be played, or similar actions to occur.

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

Hanging up a connecting call:

// Starting a call
id<SINCall> call = [client callUserWithId:@"<remote user id>"];

// User changed his/her mind, let’s hangup
[call hangup];

Handling a call that ends:

// SINCallDelegate implementation

- (void)callDidEnd:(id<SINCall>) call {
  // update user interface, e.g. hide the call screen.
}

Instant messaging

The SINMessageClient is the entry point to Instant Messaging functionality in the Sinch SDK.

Messages are sent through the SINMessageClient and events are received by the SINMessageClientDelegate. The message client is owned by the SINClient and accessed via -[SINClient messageClient]. Instant messaging is not enabled by default. In order to enabled instant messaging, - [SINClient setSupportMessaging: YES] must be set.

SINClient sinchClient;
[sinchClient setSupportMessaging: YES];
SINMessageClient messageClient = [sinchClient messageClient];

// Assign a delegate for instant messages events
messageClient.delegate = ...

Sending a message

Messages are created using the static method +[SINOutgoingMessage messageWithRecipient:text:]. Once created, sending the message is as simple as calling -[SINMessageClient sendMessage:]:

SINOutgoingMessage *message = [SINOutgoingMessage messageWithRecipient:@"<recipient user id> text:@"Hi there!"];

[messageClient sendMessage:message];

Message delivery success

When a message to a recipient is successfully sent, the delegate is notified:

// SINMessageClientDelegate

- (void) messageSent:(id<SINMessage>)message recipientId:(NSString *)recipientId{
  // Persist outgoing message
  // Update UI
}

Updating the UI from the messageSent: callback is especially convenient when a user is simultaneously logged into more than one device. The messageSent: callback is 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 delegate is notified using the messageDelivered:method. Inspecting the infoparameter passed to the callback reveals more details about the event.

- (void) messageDelivered:(id<SINMessageDeliveryInfo>)info {
   NSLog(@"Message with id %@ was delivered to recipient with id  %@",
                                               info.messageId,
                                               info.recipientId);
}

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, and so on. When a message failed to reach its destination the delegate is notified using the messageDeliveryFailed: callback. The reason for failing to deliver a message is propagated back as an array of SINMessageFailureInfo instances.

- (void) messageDeliveryFailed:(id<SINMessage>) message info:(NSArray *)messageFailureInfo {
    for (id<SINMessageFailureInfo> reason in messageFailureInfo) {
        NSLog(@"Delivering message with id %@ failed to user %@. Reason %@", 
        reason.messageId, reason.recipientId, [reason.error localizedDescription]);
    }
}

Note: Messages are persisted internally in the SDK. In case the message was not sent successfully it will be retried automatically at a later point in time. The message will be retried for 12 hours and then fail permanently firing the failure callback.

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, the message will be lost and no notification received.

Note: A message should be retried only in case of network unavailability (use [[failureInfo.error domain] isEqualToString:SINErrorDomainNetwork]). In this case, create a new instance of SINOutgoingMessage (using +[SINOutgoingMessage messageWithMessage:]) and send that instance because the previous message is considered stale.

Receiving a message

Incoming messages are delivered to the delegate:

- (void) messageClient:(id<SINMessageClient>) messageClient 
          didReceiveIncomingMessage:(id<SINMessage>)message {             

  // Present a Local Notification if app is in background
  if([UIApplication sharedApplication].applicationState == UIApplicationStateBackground){

    UILocalNotification* notification = [[UILocalNotification alloc] init];
    notification.alertBody = [NSString stringWithFormat:@"Message from %@",
                                                        [message recipientIds][0]];

    [[UIApplication sharedApplication] presentLocalNotificationNow:notification];
  } else {
    // Update UI in-app
  }

  // Persist incoming message

}

Note: The application handles iOS local notifications for instant messages which is different than how incoming calls are handled. The Sinch SDK manages the local notifications for incoming calls.

Sending a message to multiple recipients

To send a message to multiple recipients, create the outgoing message with the +[SINOutgoingMessage messageWithRecipients:text:].

NSArray *recipients = @[@"recipient user id 1", @"recipient user id 2"];
SINOutgoingMessage *message = [SINOutgoingMessage messageWithRecipients:recipients text:@"Hi there!"];

[messageClient sendMessage:message];

Receiving status updates for multi-recipient Messages

When a message transitions to a new state it is communicated back using SINMessageClientDelegate as the single recipient case. The delegate’s callbacks are triggered once for every recipient.

Audio handling

If the application plays audio that does not originate from the Sinch SDK, certain guidelines should be followed. Additional information on audio session-related topics is available in the Audio Session Programming Guide.

Audio sessions

When a call is established, the Sinch client activates the shared audio session. When the call is disconnected, the Sinch client deactivates the shared audio session. If the application wants to play audio in any other context, it needs to reactivate the shared audio session. This applies after each finished call.

When started, the Sinch SDK client sets itself as the audio session delegate. If the application wishes to override this behavior, the application needs to reset the delegate after the client has started but before any call has been started. (Doing this is not recommended.)

Audio session categories

When the Sinch client is started, it sets the audio session category to PlayAndRecord. The reason the Sinch client only sets the audio category once, is to avoid interfering with what the hosting application may want to do with the audio session.

If the application changes the audio session category, it is responsible for changing the category back to PlayAndRecord after the application has performed its audio task so that the category is correctly setup for calls.

The Sinch SDK applies the audio session category mode AVAudioSessionModeVoiceChat for improved voice quality. Please see Apple’s AVAudioSession documentation for further details.

Audio session interruptions

When the users are in the midst of a Sinch SDK call, someone might call users using the PSTN network, thus interrupting the application and make iOS play the regular native ringtone. If the native phone call ends within 30 seconds, the application will start running again. If not, the Sinch SDK call will be terminated.

Playing ringtones

The SINAudioController object provides a convenience method startPlayingSoundFile:loop: for playing sounds that are related to a call, such as ringtones and busy tones. Details on how to use it can be found in the Reference documentation.

The sound file must be a mono (1 channel), 16-bit, uncompressed (PCM) .wav file with a sample rate of 8kHz, 16kHz, or 32kHz.

- (void)callReceivedOnRemoteEnd:(id<SINCall>)call {
    NSString* soundFilePath = [[NSBundle mainBundle] pathForResource:@"progresstone" ofType:@"wav"];
    // get audio controller from SINClient
    id<SINAudioController> audioController = [self.client audioController];
    [audioController startPlayingSoundFile:soundFilePath loop:NO];
}

Applications that prefer to use their own code for playing sounds are free to do so, but they should follow the guidelines for Audio Sessions and Audio Session Categories above.

Background mode

Normally, when an iOS app enters background mode, all its sockets are closed by the OS. For VoIP apps, iOS provides the option to keep a signaling socket open in background mode, by tagging it as a VoIP socket. The Sinch SDK uses this option to be able to receive incoming calls while the app is in the background.

If the app is not running in either the foreground or the background, the app is considered to be offline. If you have written your application to use push notifications when the application is offline, the Sinch SDK resorts to using those notifications to notify the app of incoming calls. Choosing which push notification service to use is up to you, but for iOS devices, the typical choice is to use Apple Remote Push Notifications. Refer to the Push Notifications section for details.

To enable the use of a VoIP-tagged signaling socket for receiving incoming calls while in background mode, call the setSupportActiveConnectionInBackground: method on the Sinch client object:

[client setSupportActiveConnectionInBackground:YES];

Note that the setSupportActiveConnectionInBackground: method should be called before the client has been started with the start method.

When an incoming call is received, iOS notices that there is pending activity on the VoIP signaling socket and temporarily wakes up the app. The app is not entirely awake, but it has a few seconds to let the Sinch SDK process the received data in the background. If a call was received, the Sinch SDK schedules a local iOS notification, which is presented to the user immediately.

If the user taps the notification, iOS brings the app back into the foreground. The notification object contains information that is needed by the Sinch SDK to start the incoming call. To hand over the notification object to the Sinch client, use the relayLocalNotification: method:

- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {

    if ([notification sin_isSinchNotification]){

      // This will trigger -[SINClientDelegate didReceiveIncomingCall:] if the notification
      // represents a call (i.e. contrast to that it may represent an instant-message)
      id<SINNotificationResult> result = [client relayLocalNotification:notification];

      if (result.isCall && result.callResult.isTimedOut) {
        // The notification is is related to an incoming call,
        // but was too old and the call has expired.
        // The call should be treated as a missed call appropriate
        // action should be taken to communicate that to the user.
      }
    }
}

Customizing the local notification content

Apps that are designed to receive calls with a VoIP tagged socket in background mode must implement the delegate method client:localNotificationForIncomingCall:. The delegate is responsible for composing a SINLocalNotification object with content that is shown to the user when the local notification is presented to the user by the OS. The content includes various descriptive strings, a badge number, and the path to a sound file that is played when the notification is presented.

Answering when notified

Once the Sinch SDK has processed the call information extracted from the notification, it calls the delegate method client:didReceiveIncomingCall:. Depending on the desired behavior for the app, the incoming call may either be treated as any other incoming call and let the user tap an additional button to answer it, or the call may be answered automatically when the user has acted on the local notification.

In the latter case, the app can determine whether the call originated from background mode or not by examining the applicationStateWhenReceived property of the call details object. If the application was active when it received the call, it means the app was in the foreground. This approach is also applicable to offline calls with Apple Push Notifications.

- (void)client:(id<SINClient>)client didReceiveIncomingCall:(id<SINCall>)call {
    call.delegate = self;

    if (call.details.applicationStateWhenReceived == UIApplicationStateActive) {
        // Show an answer button or similar in the UI
    } else {
        // Application was in not in the foreground when the call was initially received,
        // and the user has opened the application (e.g. via a Local Notification),
        // which we then interpret as that the user want to answer the call.
        [call answer];
    }
}

Sinch local notifications and the Notification Center

If the Sinch SDK is used with support for an active signaling connection in the background enabled (it is disabled by default), local notifications are used.

The following details explain how the Sinch SDK handles local notifications and how it affects what is presented in the Notification Center.

  • A notification is passed in to the method -[SINClient relayLocalNotification:notification:] is removed from the Notification Center after it has been handled.
  • A local notification representing an incoming call is removed if the call times out.
  • Invoking -[SINCall hangup] from -[SINClient client:localNotificationForIncomingCall] is a valid operation and can be used to dismiss a call while the user is busy talking in the regular phone app. This effectively prevents the SDK from invoking the -[SINClientDelegate client:didReceiveIncomingCall:] method when the app returns to foreground.
  • Invoking -[SINCall answer] while being in the background is possible. The call is not immediately answered but the operation is considered pending and the call answered once the app returns to the foreground.

Push notifications

An application is considered offline in the following scenarios:

  • When the application is not running
  • When background mode has been disabled for the Sinch client, and the application is not in the foreground

For these scenarios, push notifications must be implemented in the application to be able to receive incoming calls and instant messages. The following sections cover how to support receiving calls and messages using push notifications.

The Sinch 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. The choice of which push service to use is up to you, but for iOS applications, the typical choice is to use Apple Remote Push Notifications.

When offline, the recipient of a call or message receives a push notification containing a Sinch-specific payload which enables the Sinch client to connect the incoming call or message. Acting on the push notification brings the application to the foreground which allows 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 Sinch clients. When A (the caller) calls B (the callee), B’s application is in a state where it is not considered online (that is reachable using an active socket connection). Sinch notices that B is not online, and tells A to send a push notification to B so that B can answer the call.

When the Sinch client on the caller’s (or sender’s) side observes that the destination client is offline, it notifies the application to trigger the sending of a push notification to the callee’s device.

Push notification data

On startup, each instance of the application is expected to register a device identifier. The identifier is referred to as push notification data and should be provided to the Sinch client by the method registerPushNotificationData:.

Push notifications can be addressed to that identifier in the event that the application goes offline.

The push notification data can be any byte sequence; it is up to you to define its structure and what it contains. However, the push notification data must not exceed 1024 bytes. It should contain enough information to allow your application or application server to use a push service to send a push notification to a specific user of the application on a specific device. For example, an iOS exclusive application would likely use the Apple Push Notification Device Token as push notification data. Multi-platform applications may use a mix of different push services. The following sections assume that Apple Remote Notifications are used, but the use pattern for other push services is similar.

The push notification data can be unregistered by calling the unregisterPushNotificationData method. This disables incoming calls using push notifications addressed to the specific device.

Enable push notifications

Start by enabling support for push notifications when initiating the SINClient:

#import <Sinch/Sinch.h>

id<SINClient> client = [Sinch clientWithApplicationKey:@"<application key>" 
                                         applicationSecret:@"<application secret>"
                                           environmentHost:@"sandbox.sinch.com" 
                                                    userId:@"<user id>"];

[client setSupportPushNotifications:YES];

client.delegate = ...; 

[client start];

Supporting offline calls and/or messages requires that the application registers for remote push notifications, which in the example that follows is done in the method -[UIApplicationDelegate application:didFinishLaunchingWithOptions:].

- (BOOL)application:(UIApplication *)app didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    UIRemoteNotificationType types = UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound;
    [[UIApplication sharedApplication] registerForRemoteNotificationTypes:types];
}

The next step is to register the push notification data with the SINClient, which in the example below is done by using the APNS device token as push notification data. Upon receiving the the device token from Apple Push Notification Service using the UIApplicationDelegate-method, it is registered with the SINClient.

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    // get previously initiated Sinch client
    id<SINClient> client = [self sinchClient];

    [client registerPushNotificationData:deviceToken];
}

Please refer to Apple’s Local and Push Notification Programming Guide for more information on how to obtain the Apple Push Notification Device Token.

Sending and receiving Apple push notifications

To send push messages, you must have a server that is configured for sending push notifications to Apple Push Notification Service. Please see the Sinch REST API User Guide for details on how to handle feedback from Apple Push Notification Service.

Please also refer to Apple’s Local and Push Notification Programming Guide for further details on push notifications.

On the caller side

When the recipient’s application is offline and the app needs to notify the user using a push notification, the caller’s or sender’s application is notified using the delegate method call:shouldSendPushNotifications:.

Because there might be multiple registered devices for the recipient user (for example, the same user is using the application on both an iPhone and an iPad) the callback is passed an array of SINPushPairs. The pairs contain a payload that is Sinch- and call-specific. Moreover, the pairs contain a push data byte array. The Sinch-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.

- (void)call:(id<SINCall>)call shouldSendPushNotifications:(NSArray *) pushPairs {
    // Send payload and push data to application server
    // which should communicate with Apple Push Notification Service
    // to send push notifications.
}

NOTE: This example shows the calling case. Messaging works the same way.

A push notification should be sent to each device, where each pushPair.pushData entry in the array corresponds to one device. The push notification should include the Sinch-specific payload so it can be forwarded to the Sinch client running on the destination device.

The Sinch-specific payload should be embedded as custom payload data in the Apple Push Notification Payload, see JSON example below.

{
    "aps" : {
        "alert" : "Incoming call from <user>",
        "sound" : "bingbong.aiff"
    },
    "SIN" : <payload>,
}

The Sinch-specific payload will not exceed 100 bytes, meaning that there should be 156 bytes available in the push notification payload for application-specific purposes.

Please refer to Apple’s Local and Push Notification Programming Guide for further details.

On the callee 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 Apple Push Notification Service, the application launches and extracts the Sinch-specific payload from the push notification. Once extracted the payload is forwarded to the Sinch client using the method relayRemotePushNotificationPayload:.

- (BOOL)application:(UIApplication *)app didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    NSDictionary* remotePush = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];

    if (remotePush) {

        // Extract the Sinch-specific payload from the Apple Remote Push Notification
        NSString* payload = [remotePush objectForKey:@"SIN"]; 

        // Get previously initiated Sinch client
        id<SINClient> client = [self sinchClient];

        id<SINNotificationResult> result = [client relayRemotePushNotificationPayload:payload];

        if (result.isCall && result.callResult.isTimedOut) {
            // Present alert notifying about missed call
        } else if (!result.isValid) {
            // Handle error                
        }
    }
}

Note: You should have similar logic of relaying the push notification payload to the SINClient-instance in your implementation of -[UIApplicationDelegate application: didReceiveRemoteNotification:].

Application authentication

A user identity must be provided when initiating a Sinch client. The first time the application instance and the Sinch client are running on behalf of a particular user, they are required to register against the Sinch service. This is mostly handled transparently by the Sinch SDK, but it works slightly differently depending on which authentication scheme you choose to use.

The step of registering a user identity against the Sinch 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, for example, calling.

Two different authentication schemes are available: authentication by client access to application secret and authentication supported by application server.

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 Sinch Client SDK in the application to self-sign an authorized request to perform user registration. Choosing this authentication scheme corresponds to initiating the Sinch client by using the factory method that takes both an Application Key and an Application Secret.

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

Caution: 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 Sinch client needs to perform an authorized request to register a user identity against the Sinch service, it needs 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, for example, by using 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 provides a better level of security as well as flexibility.

Note: The need for the Sinch 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));

For example, 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

// Instantiate a client object using the client factory method.
id<SINClient> client = [Sinch clientWithApplicationKey:@"<application key>" 
                                           environmentHost:@"sandbox.sinch.com" 
                                                    userId:@"<user id>"];

client.delegate = ...;

[client start];

// This will on the first run for this user, call 
// -[SINClientDelegate client:requiresRegistrationCredentials:], 
// which implementations could look something like this:

- (void)client:(id<SINClient>)client 
requiresRegistrationCredentials:(id<SINClientRegistration>) registrationCallback {

  // Perform API request to server which keeps the Application Secret
  [myAPIService getAuthorizedSignatureForUser:[client userId]
  onSuccess:^(NSString* signature, long long sequence){

    // Forward the signature and sequence back into Sinch SDK
    [registrationCallback registerWithSignature:signature sequence:sequence];
  }
  onFailure:^(NSError* error) {

    // Forward potential network request error to Sinch SDK, 
    // e.g. failure due to no internet connection.
    [registrationCallback registerDidFail:error];
  }];
}

Miscellaneous

Minimum requirements

iOS 5.0 is the minimum iOS version required for using the Sinch SDK (iOS Deployment Target).

Note: The Sinch SDK library uses Automatic Reference Counting (ARC). However, it can still be used in non-ARC projects.

Note on Sinch.framework file size vs. linked size

The Sinch.framework file includes binaries for three architectures, armv7, armv7s, and i386. When linking an application target against the Sinch.framework targeting an iOS device, it will add a total of total approximately 12.9Mb to the application binary. (Note that this is less than the size of the Sinch.framework file because only the ARM slices are linked, i386 is used only for the iOS Simulator.)

Production and Sandbox environments

Sinch provides two environments:

  • Production - Used for applications deployed in production.
  • Sandbox - Used during development and testing.

The environment is passed as the parameter environmentHost when instantiating the Sinch client.

Environment EnvironmentHost parameter
Production clientapi.sinch.com
Sandbox sandbox.sinch.com

Restrictions on User IDs

User IDs can only contain characters in the printable ASCII character set. That is:

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

User IDs must not be longer than 64 characters.

Encryption export regulations

Please 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 Sinch SDK client uploads statistics to the Sinch 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.

iOS 7 Compatibility guidelines

Request user permission for using the microphone

In iOS 7, additional user privacy constraints are enforced which requires the application to be granted permission to use the device microphone. Unless the application has explicitly requested permission to use the microphone, the user is shown a dialog the first time the microphone is activated.

In the context of the Sinch SDK, this occurs once the first call is established unless the application has been granted permission earlier. We strongly recommend you explicitly request permission to use the microphone in your application at an appropriate time such as when the user first sets up Sinch. You should not rely on the permission dialog shown when the first Sinch call is established as this will create an awkward user experience.

By explicitly requesting permission using the methods available in the iOS SDK, the application has more control over when the dialog is shown to the user. This results in a better user experience. Please see the Apple iOS SDK documentation on the class AVAudioSession for details on how request permission to use the microphone.

arm64 architecture not supported - Xcode build setting instructions

The arm64 architecture is not yet supported by the iOS Sinch SDK.

With the introduction of Xcode 5.1, arm64 is included in the default "Standard architecture” build setting. This results in projects using the default setting automatically building for arm64 along with the standard 32-bit architectures.

Currently, you need to exclude arm64 explicitly as follows:

Open the Xcode project Build Settings and set both ‘Architectures’ and ‘Valid architectures’ to $(ARCHS_STANDARD_32_BIT)

It should then look like this:

iOS 8 App Extensions and arm64

App Extensions is a new feature in iOS 8. App extensions are compiled into executables that are separate from the main application executable. Apple requires all app extensions to be compiled as arm64, thus due to that the Sinch SDK does not support arm64 it is not supported to use the Sinch SDK from an app extension. Though it is valid to use the Sinch SDK in the main application and build it as a 32-bit only executable and still bundle other app extensions as part of your application.

Glossary

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

Term Explanation
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 Sinch. 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 Sinch. The secret is used to verify the application. A secret looks like oYdgGRXoxEuJhGDY2KQ/HQ== (Base64-encoded string representation).
Callee The person receiving a call.
Caller The person making a call.
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.
Active Connection A socket connection for signaling purposes where incoming calls are received.

Third party libraries and copyright notices

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