Join us in San Francisco on the 29/30th of October for two days of developer workshops and technical talks

How to Receive Phone Calls with the Nexmo Client SDK in JavaScript

In this guide, you'll learn how to forward an incoming phone call from a Nexmo phone number, to an in-app user by implementing a webhook and linking that to a Nexmo application.

You will create a simple app to receive a call. The app will automatically log in a user called Jane. After logging in, Jane is able to receive a call and perform actions such as answer, reject or hangup.

Nexmo Concepts

Before proceeding any further, here are couple of concepts that you'll need to understand.

A Nexmo application allows you to easily use Nexmo products, in this case the Voice API to build voice applications in the Cloud.

A Nexmo application requires two URLs as parameters:

  • answer_url - Nexmo will make a request to this URL as soon as someone makes a call to your Nexmo number. It contains the actions that will happen throughout the call.
  • event_url - Nexmo sends event information asynchronously to this URL when the call status changes; this ultimately depicts the flow of the call.

Both URLs need to return JSON and follow the Nexmo Call Control Object (NCCO) reference. In the example below, you will define an NCCO that reads a predefined text for an incoming call, using the Text to Speech engine.

A Nexmo virtual number will be associated with the app and serve as the "entry point" to it - this is the number you'll call to test the application.

For more information on Nexmo applications please visit the Nexmo API Reference.)

Prerequisites

Application webhook

For your application to connect an incoming phone call to an app user, you'll need to provide a URL as the Answer URL webhook - we've created a gist for you to use.

To add this URL, go to your Nexmo dashboard, navigate to applications, select your application and click the 'Edit' button.

Now, set the application's Answer URL to:

https://gist.githubusercontent.com/NexmoDev/ed91ac99a0b278fbdcbde72ca3599ac7/raw/4a134363f8b3bbebae27f04095a57d0cebc5a1be/ncco.json

and click 'Save changes'.

NOTE: This gist is specific to this tutorial and in a real-life scenario, the answer_url should be provided by a purposely built web solution that can serve custom NCCOs if required.

A Nexmo virtual number Nexmo phone number is a phone number that you can link to your Nexmo Application. When a user calls that phone number, the answer_url that is defined on your Nexmo Application is executed. In this tutorial case, you set up an answer_url in the above step, that upon calling connects the call to your app user Jane.

To link a Nexmo number to your app:

  1. Go to your Nexmo dashboard
  2. Navigate to applications
  3. Select your application
  4. Click the 'Edit' button.

  5. Switch to Numbers tab above, search for a number you'd like, and click Link, to link.

Adding the Nexmo Client to your application

We'll start with a blank HTML page with three buttons for answering, declining and hanging up a call. Create a minimal index.html file, for example:

<html>
  <head>
    <title>Receive Phone Calls</title>
    <script src="./node_modules/nexmo-client/dist/nexmoClient.js"></script>
  </head>
  <body>
    <p id="notification"></p>
    <button type="button" id="answer">Answer</button>
    <button type="button" id="reject">Reject</button>
    <button type="button" id="hangup">Hang Up</button>
    <script>

    </script>
  </body>
</html>

We'll need to add the Nexmo Client to our folder, in order to do that we'll install it from NPM first, by running this command in the same folder as your index.html file:

$ npm install nexmo-client --save

Login

Using the Nexmo Client SDK should start with logging in to ConversationClient, using a jwt user token.

In production apps, your server would authenticate the user, and would return a correctly configured JWT to your app.

For testing and getting started purposes, you can use the Nexmo CLI to generate JWTs.

We'll update the empty <script> tag that's at the bottom of your <body> tag to login with a USER_JWT, and update the notification paragraph when the login was successful. We'll create a new ConversationClient, and then call the login method, with a string for the user JWT. That returns a promise containing an application object, and we'll use that to check we're logged in with the correct user.

<script>
  const USER_JWT = "YOUR USER JWT";

  let notification = document.getElementById("notification");

  new ConversationClient()
      .login(USER_JWT)
      .then(application => {
          notification.textContent = `You've logged in with the user ${application.me.name}`
      })
      .catch(console.log);
</script>

At this point you should already be able to run the app and see that you can login successfully with the SDK. Because the Nexmo Client uses IndexedDB for its sync mechanism, we suggest you don't serve index.html using the file:// protocol. That corrupts the IndexedDB for any other users and makes the SDK behave inconsistently. You can use any HTTP server, like http-server. If you want to install it from NPM and then run it with cache disabled, here are the terminal commands:

$ npm install -g http-server
$ http-server -c-1

Listen for incoming call

When the phone number associated with your Nexmo app receives a call, the application should notify the user Jane so that they can decide whether to answer or reject it.

This is done by listening for member:call events on the application object returned by the login() promise.

.then(application => {
    notification.textContent = `You've logged in with the user ${application.me.user.name}`;
    application.on("member:call", (member, call) => {
      notification.textContent = `You're receiving a call`;
    })
})

The listener method receives an member object that contains information about who's calling, and a call object, that lets you interact with the call in progress.

Answer a call

In order to answer a call, you'll have to use the answer() method on the call object that you received when the member:call event was triggered.

application.on("member:call", (member, call) => {
  notification.textContent = `You're receiving a call`;

  document.getElementById("answer").addEventListener("click", () => {
    call.answer();
    notification.textContent = `You're in a call`;
  })
})

Reject a call

In order to reject an incoming call, you'll have to use the reject() method on the call object that you received when the member:call event was triggered.

application.on("member:call", (member, call) => {
  notification.textContent = `You're receiving a call`;
  ...
  document.getElementById("reject").addEventListener("click", () => {
    call.reject();
    notification.textContent = `You rejected the call`;
  })
})

Hangup a call

You can hang up a call after you've answered it by using the hangUp() method on the call object.

new ConversationClient()
    .login(USER_JWT)
    .then(application => {
        ...
        application.on("member:call", (member, call) => {
          notification.textContent = `You're receiving a call`;
          ...
          document.getElementById("hangup").addEventListener("click", () => {
            call.hangUp();
            notification.textContent = "The call has ended";
          })
        })
    })
    .catch(console.log);

Conclusion

You have implemented your first Phone to App Voice application with the Nexmo Client SDK for JavaScript.

Open the webpage in a browser to see that you can answer, reject and hangup a call received on the phone number associated with your Nexmo application. If you've followed along this tutorial, your code should look similar to this.

How to Receive Phone Calls with the Nexmo Client SDK on Android

In this guide, you'll learn how to receive an incoming phone call in an Android application.

You will create a simple Android app, that will log in a user called Jane. After logging in, Jane is able to receive a call and perform actions such as answer or hangup.

Nexmo Concepts

Before proceeding any further, here are couple of concepts that you'll need to understand.

A Nexmo application allows you to easily use Nexmo products, in this case the Voice API to build voice applications in the Cloud.

A Nexmo application requires two URLs as parameters:

  • answer_url - Nexmo will make a request to this URL as soon as someone makes a call to your Nexmo number. It contains the actions that will happen throughout the call.
  • event_url - Nexmo sends event information asynchronously to this URL when the call status changes; this ultimately depicts the flow of the call.

Both URLs need to return JSON and follow the Nexmo Call Control Object (NCCO) reference. In the example below, you will define an NCCO that reads a predefined text for an incoming call, using the Text to Speech engine.

A Nexmo virtual number will be associated with the app and serve as the "entry point" to it - this is the number you'll call to test the application.

For more information on Nexmo applications please visit the Nexmo API Reference.)

Prerequisites

Application webhook

For your application to connect an incoming phone call to an app user, you'll need to provide a URL as the Answer URL webhook - we've created a gist for you to use.

To add this URL, go to your Nexmo dashboard, navigate to applications, select your application and click the 'Edit' button.

Now, set the application's Answer URL to:

https://gist.githubusercontent.com/NexmoDev/ed91ac99a0b278fbdcbde72ca3599ac7/raw/4a134363f8b3bbebae27f04095a57d0cebc5a1be/ncco.json

and click 'Save changes'.

NOTE: This gist is specific to this tutorial and in a real-life scenario, the answer_url should be provided by a purposely built web solution that can serve custom NCCOs if required.

A Nexmo virtual number Nexmo phone number is a phone number that you can link to your Nexmo Application. When a user calls that phone number, the answer_url that is defined on your Nexmo Application is executed. In this tutorial case, you set up an answer_url in the above step, that upon calling connects the call to your app user Jane.

To link a Nexmo number to your app:

  1. Go to your Nexmo dashboard
  2. Navigate to applications
  3. Select your application
  4. Click the 'Edit' button.

  5. Switch to Numbers tab above, search for a number you'd like, and click Link, to link.

The starter project

Clone or download the GitHub repository on either Kotlin orJava. On that repository you'll find two apps:

  • GetStartedCalls-Start - if you want to follow along and add the code with this tutorials
  • GetStartedCalls-Complete - if you want to look at the final result

Open the NexmoHelper class.

  1. Make sure that in enabledFeatures you have to Features.PHONE_to_IN_APP. You can remove the rest, if you haven't completed their tutorials yet.

  2. Replace the user IDs and tokens:

String USER_ID_JANE = "USR-XXX"; //TODO: replace with the UserId you generated for Jane
String JWT_JANE = "PLACEHOLDER";//TODO: replace with the JWT you generated for Jane
val USER_ID_JANE = "USR-XXX"; //TODO("replace with the UserId you generated for Jane")
val JWT_JANE = "PLACEHOLDER"; //TODO("replace with the JWT you generated for Jane")

Login

To start using the Nexmo Client SDK you need to log in to NexmoClient, using a JWT user token.

In production apps, your server would authenticate the user, and would return a correctly configured JWT to your app.

For testing and getting started purposes, you can use the Nexmo CLI to generate JWTs.

Open LoginActivity. It already has a button handler:onLoginJaneClick(...) that calls loginToSdk(...) method, with the jwt you provided.

When the login is successful, the logged in NexmoUser returns. For convenience, save a reference to NexmoUser on NexmoHelper, and then, start MainActivity.

Complete the loginToSdk() method implementation:

void loginToSdk(String token) {
    NexmoClient.get().login(token, new NexmoRequestListener<NexmoUser>() {

        @Override
        public void onError(NexmoApiError nexmoApiError) {}

        @Override
        public void onSuccess(NexmoUser user) {
            NexmoHelper.user = user;

            Intent intent = new Intent(getBaseContext(), MainActivity.class);
            startActivity(intent);
            finish();
        }
    });
}
fun loginToSdk(token: String) {
        NexmoClient.get().login(token, object : NexmoRequestListener<NexmoUser> {

            override fun onError(nexmoApiError: NexmoApiError) {
                notifyError(nexmoApiError)
            }

            override fun onSuccess(user: NexmoUser?) {
                currentUser = user

                val intent = Intent(baseContext, MainActivity::class.java)
                startActivity(intent)
                finish()
            }
        })
    }
}

At this point you should already be able to run the app and see that you can login successfully with the SDK.

Receive incoming call

When the phone number associated with your Nexmo app receives a call, the app should notify the user Jane so that she can decide whether to answer or reject it.

It is done by registering to incoming events, with NexmoIncomingCallListener and implementing onIncomingCall().

For simplicity in this example, you will accept incoming calls only on MainActivity. Open MainActivity and create the NexmoIncomingCallListener to save the reference to the incoming call on NexmoHelper, and start IncomingCallActivity:

NexmoIncomingCallListener incomingCallListener = new NexmoIncomingCallListener() {
    @Override
    public void onIncomingCall(NexmoCall call) {

        NexmoHelper.currentCall = call;
        startActivity(new Intent(MainActivity.this, IncomingCallActivity.class));
    }
};
val incomingCallListener = NexmoIncomingCallListener { call ->
    currentCall = call
    startActivity(Intent(this@MainActivity, IncomingCallActivity::class.java))
}

You need to register and unregister the listener in onCreate() and onDestroy():

@Override
protected void onStart() {
    super.onStart()
    NexmoClient.get().addIncomingCallListener(incomingCallListener);
}

@Override
protected void onStop() {
    NexmoClient.get().removeIncomingCallListeners();
    super.onStop();
}
override fun onStart() {
    super.onStart()
    NexmoClient.get().addIncomingCallListener(incomingCallListener)
}

override fun onStop() {
    NexmoClient.get().removeIncomingCallListeners()
    super.onStop()
}

Answer a call

Once a incoming call is received, it can be answered. Open IncomingCallActivity, and complete the prepared onAnswer() button handler, to start OnCallActivity after a successful answer:

public void onAnswer(View view) {
    NexmoHelper.currentCall.answer(new NexmoRequestListener<NexmoCall>() {
        @Override
        public void onError(NexmoApiError nexmoApiError) { }

        @Override
        public void onSuccess(NexmoCall call) {
            startActivity(new Intent(IncomingCallActivity.this, OnCallActivity.class));
            finish();
        }
    });
}
fun onAnswer(view: View) {
    currentCall?.answer(object : NexmoRequestListener<NexmoCall> {
        override fun onError(nexmoApiError: NexmoApiError) {}

        override fun onSuccess(call: NexmoCall) {
            startActivity(Intent(this@IncomingCallActivity, OnCallActivity::class.java))
            finish()
        }
    })
}

Hangup

The onHangup() handler allows to reject the call. Complete the implementation in IncomingCallActivity to finish the activity:

public void onHangup(View view) {
    NexmoHelper.currentCall.hangup(new NexmoRequestListener<NexmoCall>() {
        @Override
        public void onError(NexmoApiError nexmoApiError) { }

        @Override
        public void onSuccess(NexmoCall call) {
            finish();
        }
    });
}
currentCall?.hangup(object : NexmoRequestListener<NexmoCall> {
    override fun onError(nexmoApiError: NexmoApiError) {}

    override fun onSuccess(call: NexmoCall) {
        startActivity(Intent(this@IncomingCallActivity, OnCallActivity::class.java))
        finish()
    }
})

Register to call status

To be aware of the call status, for example, if one of the members answers or hangs up, you should register to CallEvents. The FinishOnCallEnd is a NexmoCallEventListener that finishes the current activity if the call is completed or canceled.

Register to its instance, to address the use cases mentioned previously.

On both OnCallActivity and IncomingCallActivity, add:

NexmoCallEventListener callEventListener = new FinishOnCallEnd(this);

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    NexmoHelper.currentCall.addCallEventListener(callEventListener);
}


@Override
protected void onDestroy() {
    NexmoHelper.currentCall.removeCallEventListener(callEventListener);
    super.onDestroy();
}
var callEventListener = FinishOnCallEnd(this)

override fun onCreate(savedInstanceState: Bundle?) {
    currentCall?.addCallEventListener(callEventListener)
}


override fun onDestroy() {
    currentCall?.removeCallEventListener(callEventListener)
    super.onDestroy()
}

Handle permissions

For devices running Android 6.0 (API level 23) and higher, creation and operation of calls requires requesting runtime permissions. To simplify the implementation in this tutorial, BaseActivity checks the permissions in every Activity's onStart() and onStop().

To read more about the permissions required, see the setup tutorial.

Conclusion

Congratulations! You have implemented your first Phone to App Voice application with the Nexmo Client SDK for Android.

Run the app on a simulator or a device, and with another device call the Nexmo Number you linked to you application. Then, see that you receive the call, and can answer and hangup.

How to Receive Phone Calls with the Nexmo Client SDK on iOS

In this guide, you'll learn how to receive an incoming phone call in a Nexmo application by implementing a webhook and linking that to a Nexmo application.

Nexmo Concepts

Before proceeding any further, here are couple of concepts that you'll need to understand.

A Nexmo application allows you to easily use Nexmo products, in this case the Voice API to build voice applications in the Cloud.

A Nexmo application requires two URLs as parameters:

  • answer_url - Nexmo will make a request to this URL as soon as someone makes a call to your Nexmo number. It contains the actions that will happen throughout the call.
  • event_url - Nexmo sends event information asynchronously to this URL when the call status changes; this ultimately depicts the flow of the call.

Both URLs need to return JSON and follow the Nexmo Call Control Object (NCCO) reference. In the example below, you will define an NCCO that reads a predefined text for an incoming call, using the Text to Speech engine.

A Nexmo virtual number will be associated with the app and serve as the "entry point" to it - this is the number you'll call to test the application.

For more information on Nexmo applications please visit the Nexmo API Reference.)

Prerequisites

Application webhook

For your application to connect an incoming phone call to an app user, you'll need to provide a URL as the Answer URL webhook - we've created a gist for you to use.

To add this URL, go to your Nexmo dashboard, navigate to applications, select your application and click the 'Edit' button.

Now, set the application's Answer URL to:

https://gist.githubusercontent.com/NexmoDev/ed91ac99a0b278fbdcbde72ca3599ac7/raw/4a134363f8b3bbebae27f04095a57d0cebc5a1be/ncco.json

and click 'Save changes'.

NOTE: This gist is specific to this tutorial and in a real-life scenario, the answer_url should be provided by a purposely built web solution that can serve custom NCCOs if required.

A Nexmo virtual number Nexmo phone number is a phone number that you can link to your Nexmo Application. When a user calls that phone number, the answer_url that is defined on your Nexmo Application is executed. In this tutorial case, you set up an answer_url in the above step, that upon calling connects the call to your app user Jane.

To link a Nexmo number to your app:

  1. Go to your Nexmo dashboard
  2. Navigate to applications
  3. Select your application
  4. Click the 'Edit' button.

  5. Switch to Numbers tab above, search for a number you'd like, and click Link, to link.

The Starter project

Clone this Github project.

Using the Github project you cloned, in the Start folder, open GettingStarted.xcworkspace. Then, within XCode:

  1. Open Constants.swift file and add a jwt for Jane:
    var jwt: String {
        switch self {
        case .jane:
            return "" //TODO: swap with a token for Jane
        ...
  1. From the Receive-phone-call group, open ReceivePhoneCallViewController.swift file and make sure the following lines exist:
  • import NexmoClient - imports the sdk
  • let user = User.jane - sets the user that places the call
  • var client: NXMClient? - property for the client instance
  • var call: NXMCall? - property for the call instance

Clone this Github project.

Using the Github project you cloned, in the Start folder, open GettingStarted.xcworkspace. Then, within XCode:

  1. Open User.h file and replace the user token:
#define kJaneUUID @"" //TODO: swap with a user uuid for Jane
  1. From the Receive-phone-call group, open ReceivePhoneCallViewController.m file and make sure the following lines exist:
  • #import <NexmoClient/NexmoClient.h> - imports the sdk
  • @property User *user; - sets the user that places the call
  • @property NXMClient *client; - property for the client instance
  • @property NXMCall *call; - property for the call instance

Login

Using the Nexmo Client SDK should start with logging in to NexmoClient, using a jwt user token.

In production apps, your server would authenticate the user, and would return a correctly configured JWT to your app.

For testing and getting started purposes, you can use the Nexmo CLI to generate JWTs.

Inside ReceivePhoneCallViewController, explore the setup methods that were written for you on viewDidLoad.

Now locate the following line //MARK: Setup Nexmo Client and complete the setupNexmoClient method implementation:

func setupNexmoClient() {
    client.setDelegate(self)
    client.login(withAuthToken: user.jwt)
}

Notice that self is set to be the delegate for NXMClient. Do not forget to adopt the NXMClientDelegate protocol and implement the required methods.

Add the required protocol adoption declaration to the class extension located towards the end of the ReceivePhoneCallViewController.swift file, under the //MARK:- Client Delegate line:

extension ReceivePhoneCallViewController: NXMClientDelegate {
    ...
}

The client(_:didChanged:reason:) methods of the NXMClientDelegate protocol indicates if the login was successful and you can start using the SDK.

Add the following methods inside the extension.

extension ReceivePhoneCallViewController: NXMClientDelegate {

    func client(_ client: NXMClient, didChange status: NXMConnectionStatus, reason: NXMConnectionStatusReason) {
        updateInterface()
    }

    func client(_ client: NXMClient, didReceiveError error: Error) {
        updateInterface()
    }

}

Inside ReceivePhoneCallViewController, explore the setup methods that were written for you on viewDidLoad.

Now locate the following line //MARK: Setup Nexmo Client and complete the setupNexmoClient method implementation:

- (void)setupNexmoClient {
    self.client = [NXMClient shared];
    [self.client setDelegate:self];
    [self.client loginWithAuthToken:self.user.jwt];
}

Notice that self is set to be the delegate for NXMClient. Do not forget to adopt the NXMClientDelegate protocol and implement the required methods.

Locate the //MARK:- NXMClientDelegate line and add the required protocol methods:

- (void)client:(nonnull NXMClient *)client didChangeConnectionStatus:(NXMConnectionStatus)status reason:(NXMConnectionStatusReason)reason {
    [self updateInterface];
}

- (void)client:(nonnull NXMClient *)client didReceiveError:(nonnull NSError *)error {
    [self updateInterface];
}

At this point you should already be able to run the app and see that you can login successfully with the SDK.

Receive incoming call

When the phone number associated with your Nexmo app receives a call, the app should notify the user Jane so that she can decide whether to answer or reject it.

This is done by implementing the optional client(_:didReceive:) method which is declared in the NXMClientDelegate.

Go back to the NXMClientDelegate extension and add the following methods:

func client(_ client: NXMClient, didReceive call: NXMCall) {
    DispatchQueue.main.async { [weak self] in
        self?.displayIncomingCallAlert(call: call)
    }
}

func displayIncomingCallAlert(call: NXMCall) {
    var from = "Unknown"
    if let otherParty = call.otherCallMembers.firstObject as? NXMCallMember {
        print("Type: \(String(describing: otherParty.channel?.from.type))")
        print("Number: \(String(describing: otherParty.channel?.from.data))")
        from = otherParty.channel?.from.data ?? "Unknown"
    }
    let alert = UIAlertController(title: "Incoming call from", message: from, preferredStyle: .alert)
    alert.addAction(UIAlertAction(title: "Answer", style: .default, handler: { _ in
        self.answer(call: call)
    }))
    alert.addAction(UIAlertAction(title: "Reject", style: .default, handler: { _ in
        self.reject(call: call)
    }))
    self.present(alert, animated: true, completion: nil)
}

Go back to the NXMClientDelegate extension and add the following methods:

- (void)client:(nonnull NXMClient *)client didReceiveCall:(nonnull NXMCall *)call {
    [self displayIncomingCallAlert:call];
}

- (void)displayIncomingCallAlert:(NXMCall *)call {
    if(![NSThread isMainThread]){
        dispatch_async(dispatch_get_main_queue(), ^{
            [self displayIncomingCallAlert:call];
        });
        return;
    }

    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Incoming Call" message: nil preferredStyle:UIAlertControllerStyleAlert];

    __weak ReceivePhoneCallViewController *weakSelf = self;
    UIAlertAction* answerAction = [UIAlertAction actionWithTitle:@"Answer" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        [weakSelf didPressAnswerIncomingCall:call];
    }];

    UIAlertAction* rejectAction = [UIAlertAction actionWithTitle:@"Reject" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        [weakSelf didPressRejectIncomingCall:call];
    }];

    [alertController addAction:answerAction];
    [alertController addAction:rejectAction];
    [self presentViewController:alertController animated:YES completion:nil];
}

This method takes as a parameter an NXMCall object with which you can answer or reject the call. An alert was implemented for you, to allow the user to choose whether to answer or reject the call.

Answer a call

Under the //MARK: Incoming call - Accept, implement this method to answer the incoming call:

private func answer(call: NXMCall) {
    self.call = call
    self.call?.setDelegate(self)
    call.answer { [weak self] error in
        if let error = error {
            print("error answering call: \(error.localizedDescription)")
        }
        self?.updateInterface()
    }
}

Under the //MARK: Incoming call - Accept, implement this method to answer the incoming call:

- (void)didPressAnswerIncomingCall:(NXMCall *)call {
    self.call = nil;
    self.callStatus = CallStatusInitiated;
    [self updateInterface];

    __weak ReceivePhoneCallViewController *weakSelf = self;
    self.call = call;
    [call answer:^(NSError * _Nullable error) {
        if(error) {
            NSLog(@"✆  ‼️ error answering call: %@", error.localizedDescription);
            [weakSelf displayAlertWithTitle:@"Answer Call" andMessage:@"Error answering call"];
            weakSelf.call = nil;
            [weakSelf updateInterface];
            return;
        }
        [weakSelf.call setDelegate:self];
        NSLog(@"✆  🤙 call answered");
        [weakSelf updateInterface];
    }];
}

answer:completionHandler: accepts an object adopting the NXMCallDelegate and a completion block to indicate if an error occurred in the process. You already implemented NXMCallDelegate in a previous step.

Reject a call

Under the //MARK: Incoming call - Reject, implement this method to reject the incoming call:

private func reject(call: NXMCall) {
    call.reject { [weak self] error in
        if let error = error {
            print("error declining call: \(error.localizedDescription)")
        }
        self?.updateInterface()
    }
}

Under the //MARK: Incoming call - Reject, implement this method to reject the incoming call:

- (void)didPressRejectIncomingCall:(NXMCall *)call {
    self.call = nil;
    __weak ReceivePhoneCallViewController *weakSelf = self;
    [call reject:^(NSError * _Nullable error) {
        if(error) {
            NSLog(@"✆  ‼️ error rejecting call: %@", error.localizedDescription);
            [weakSelf displayAlertWithTitle:@"Reject Call" andMessage:@"Error rejecting call"];
            return;
        }
        NSLog(@"✆  🤙 call rejected");
        [weakSelf updateInterface];
    }];
}

reject: accepts a single completionHandler parameter to indicate if an error occurred in the process.

Call Delegate

We'll now adopt the NXMCallDelegate as an extension on ReceivePhoneCallViewController, under the //MARK:- NXMCallDelegate line:

extension ReceivePhoneCallViewController: NXMCallDelegate {

}

Copy the following NXMCallDelegate methods inside the extension:

func call(_ call: NXMCall, didUpdate callMember: NXMCallMember, with status: NXMCallMemberStatus) {

    // call ended
    if call.myCallMember == callMember, status == .completed {
        self.callStatus = .completed
        self.call?.hangup()
        self.call = nil
    }

    // call error
    if call.otherCallMembers.contains(callMember), [NXMCallMemberStatus.failed, NXMCallMemberStatus.busy, NXMCallMemberStatus.timeout].contains(callMember.status) {
        self.callStatus = .rejected
        self.call?.hangup()
        self.call = nil
    }

    // call rejected
    if call.otherCallMembers.contains(callMember), callMember.status == .rejected {
        self.callStatus = .rejected
        self.call?.hangup()
        self.call = nil
    }

    // call ended
    if call.otherCallMembers.contains(callMember), callMember.status == .completed {
        self.callStatus = .completed
        self.call?.hangup()
        self.call = nil
    }

    updateInterface()

}

func call(_ call: NXMCall, didUpdate callMember: NXMCallMember, isMuted muted: Bool) {
    updateInterface()
}

func call(_ call: NXMCall, didReceive error: Error) {
    updateInterface()
}

As with NXMClient, NXMCall also has a delegate. Add the required protocol methods under the //MARK:- NXMCallDelegate line:

- (void)call:(nonnull NXMCall *)call didUpdate:(nonnull NXMCallMember *)callMember withStatus:(NXMCallMemberStatus)status {
    NSLog(@"✆  🤙 Call Status update | member: %@ | status: %@", callMember.user.displayName, callMemberStatusDescriptionFor(status));

    // call completed
    if (status == NXMCallMemberStatusCanceled || status == NXMCallMemberStatusCompleted) {
        self.callStatus = CallStatusCompleted;
        [self.call hangup];
        self.call = nil;
    }

    // call error
    if ( (call.myCallMember.memberId != callMember.memberId) && (status == NXMCallMemberStatusFailed || status == NXMCallMemberStatusBusy)) {
        self.callStatus = CallStatusError;
        [self.call hangup];
        self.call = nil;
    }

    // call rejected
    if ( (call.myCallMember.memberId != callMember.memberId) && (status == NXMCallMemberStatusRejected)) {
        self.callStatus = CallStatusRejected;
        [self.call hangup];
        self.call = nil;
    }

    [self updateInterface];
}

- (void)call:(nonnull NXMCall *)call didUpdate:(nonnull NXMCallMember *)callMember isMuted:(BOOL)muted {
    [self updateInterface];
}

- (void)call:(nonnull NXMCall *)call didReceive:(nonnull NSError *)error {
    NSLog(@"✆  ‼️ call error: %@", [error localizedDescription]);
    [self updateInterface];
}

The call(_:didUpdate:with:) method notifies on changes that happens to members on the call.

Hangup a call

Once Jane presses the 'End Call' button, it is time to hangup the call. Implement the private end: method and call hangup for myCallMember.

private func end(call: NXMCall) {
    guard let call = call else {
        updateInterface()
        return
    }
    call.hangup()
}

Updates for callMember statuses are received in call(_:didUpdate:with:) as part of the NXMCallDelegate as you have seen before.

The existing implementation is already handling call hangup.

Once Jane presses the "End Call" button, it is time to hangup the call. Implement endCall: method and call hangup for call.

- (IBAction)endCall:(id)sender {
    [self.call hangup];
    [self updateInterface];
}

Handle permissions

For the call to happen, Audio Permissions are required. In the appDelegate of the sample project, you can find an implementation for the permissions request in application:didFinishLaunchingWithOptions.

To read more about the permissions required, see the setup tutorial.

Conclusion

Congratulations! You have implemented your first Phone to App Voice application with the Nexmo Client SDK for iOS.

Run the app on a simulator, and with another device call the nexmo Number you linked. Then, see that you can answer, reject and hangup a call received on the phone number associated with your Nexmo application.

If possible, test the application on a device using your developer signing and provisioning facility.