Skip to content

Making an outgoing call 2.x

Marco Brescianini edited this page Aug 30, 2024 · 7 revisions

This guide will show you how to make an outgoing call and how to present the call UI using the Kaleyra Video iOS SDK 2.x version. If you are looking for the 1.x version guide take a look here.

Table of contents:

Overview

Making an outgoing call with the Kaleyra Video iOS SDK it's a simple and straightforward process. It requires you to do make few simple steps in your code to setup the call and Bandyer will take care of the rest. From now on we are assuming you read the previous guides regarding the call client initialization and its life cycle. We are also assuming the Bandyer call client is started.

The steps required to place an outgoing call are the following:

  1. Start the call client and wait until it is running
  2. Create an intent containing the information needed to place the call
  3. Create or retrieve the call window
  4. Provide the intent to the call window

The StartOutgoingCallIntent

In order to tell the SDK who you want to call you must create a StartOutgoingCallIntent. You must provide this object the user aliases for the users you want to call, along with the options for the call that will take place. The most notable option you can provide to the Kaleyra Video iOS SDK is the type of call you want to make.

There are three call types supported:

  • Audio / Video
  • Audio Upgradable
  • Audio Only

The audioVideo call type, as the name suggests, will make the Kaleyra Video iOS SDK start a video call. The audioOnly call type will make the Kaleyra Video iOS SDK start a voice call which cannot be updated to a video call. The audioUpgradable call type, is a special call type which will start as a voice call and can be upgraded to a video call at any time by one of the call participants.

In the following code we are going to show you how to create a StartOutgoingCallIntent:

class MyViewController: UIViewController {

    func startOutgoingCall(callees: [String]) {
        let intent = StartOutgoingCallIntent(callees: callees,
                                             options: .init(callType: .audioVideo))
    }
}
@implementation MyViewController

- (void)startOutgoingCall:(NSArray<NSString *> *)callees
{
    BDKStartOutgoingCallIntent *intent = [BDKStartOutgoingCallIntent intentWithCallees:callees
                                                                               options:[BDKCallOptions optionsWithCallType:BDKCallTypeAudioVideo]];
}

@end

The StartOutgoingCallIntent takes a CallOptions object specifying the call options you want to enable for your call. At the moment the options available, apart from the call type, are:

  • Recording
  • Maximum call duration

The former will tell our platform you want the call to be recorded. The latter will tell our platform the maximum number of seconds the call can last, when that threshold is exceeded the call will end automatically.

The CallWindow

Once you created the intent for the call, it's time to create the window where the call user interface will be presented. Starting from version 1.2.0 we introduced a subclass of UIWindow named CallWindow that will present the call UI in front of any content your app is displaying. This window will take care of creating and present a call view controller for you. In your code you need to do three things: create the call window (or retrieve it if you have created one already), provide the call window a configuration object, tell it to handle the previously created intent

The following code will show you these three steps:

class MyViewController: UIViewController {

    //The call window instance must be created only once and kept alive keeping a reference to it
    lazy var callWindow: CallWindow = {
        var window: CallWindow
	if CallWindow.instance != nil {
	    window = CallWindow.instance!
	} else {
	    window = CallWindow()
	}

	window.callDelegate = self
	return window
    }()
	
    func startOutgoingCall(callees: [String]) {
        //First we create the view controller configuration object
	let config = CallViewControllerConfiguration()
	let filePath = Bundle.main.path(forResource: "SIMULATOR MP4 VIDEO", ofType: "mp4")

	guard let path = filePath else {
             fatalError("The fake file for the file capturer could not be found")
	}
	
        config.fakeCapturerFileURL = URL(fileURLWithPath:path)
		
	//Then we set the configuration object on the call window
	callWindow.setConfiguration(config)
		
	//We create the call intent
	let intent = StartOutgoingCallIntent(callees: callees,
                                             options: .init(callType: .audioVideo))
		
	//Finally, we present the call view controller on the window
	callWindow.presentCallViewController(for: intent) { error in
            guard let error = error else { return }
            
            switch error {
            case let presentationError as CallPresentationError where presentationError.errorCode == CallPresentationErrorCode.anotherCallOnGoing.rawValue:
                //Another call is already in progress...
            default:
                //Configuration error...
            }       
        }
    }
}
@implementation MyViewController

//The call window instance must be created only once and kept alive keeping a reference to it
- (BDKCallWindow *)callWindow
{
    if (!_callWindow)
    {
	if (BDKCallWindow.instance)
	{
             _callWindow = BDKCallWindow.instance;
	} else
	{
             //This will automatically save the new instance inside BDKCallWindow.instance.
             _callWindow = [[BDKCallWindow alloc] init];
	}
		
	_callWindow.callDelegate = self;
    }

    return _callWindow;	
}

- (void)startOutgoingCall:(NSArray<NSString *>*)callees
{
    //First we create the view controller configuration object
    BDKCallViewControllerConfiguration *config = [BDKCallViewControllerConfiguration new];

    NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"SIMULATOR MP4 VIDEO" ofType:@"mp4"]];
    config.fakeCapturerFileURL = url;
    
    //Then we set the configuration object on the call window   
    [self.callWindow setConfiguration:config];

    //We create the call intent
    BDKStartOutgoingCallIntent *intent = [BDKStartOutgoingCallIntent intentWithCallees:callees
                                                                               options:[BDKCallOptions optionsWithCallType:BDKCallTypeAudioVideo]];

    //Finally, we present the call view controller on the window
    [self.callWindow presentCallViewControllerFor:intent completion:^(NSError * error) {
         if ([error.domain isEqualToString:BDKCallPresentationErrorDomain.value] && error.code == BDKCallPresentationErrorCodeAnotherCallOnGoing)
         {
              //Another call is already in progress...
         }
         else if (error)
         {
              //Configuration error...
          }
     }];
}

@end

The code listing above shows you how to present and start an outgoing call along with the call user interface. It doesn't show you how to dismiss the call user interface once the call has ended. To do that you must register as the call window delegate and implement the required methods of the protocol. As you might have noticed, in the code listing above we registered as the call window delegate, when we lazily created the call window. The call window will call its delegate to inform it when important events have occurred, like when the call interface must be dismissed or if the user has requested to open a chat with the user is performing the call. In the following code listing we implement the CallWindowDelegate, and we dismiss the window when it informs us it has finished handling the call.

class MyViewController: UIViewController {

    //The call window instance must be created only once and kept alive keeping a reference to it
    lazy var callWindow: CallWindow = {
        var window: CallWindow
	if CallWindow.instance != nil {
	    window = CallWindow.instance!
	} else {
	    window = CallWindow()
	}
	
        window.callDelegate = self
	return window
    }()
	
    func startOutgoingCall(callees: [String]) {
	// .....
    }
}

extension MyViewController: CallWindowDelegate {
    func callWindowDidFinish(_ window: CallWindow) {
        window.isHidden = true
    }

    func callWindow(_ window: CallWindow, openChatWith intent: OpenChatIntent) {
    	print("Open chat with intent \(intent)")
    }
}
@implementation MyViewController

- (BDKCallWindow *)callWindow
{
    if (!_callWindow)
    {
         if (BDKCallWindow.instance)
	 {
	     _callWindow = BDKCallWindow.instance;
	 } else
	 {
	     //This will automatically save the new instance inside BDKCallWindow.instance.
	     _callWindow = [[BDKCallWindow alloc] init];
	 }
		
	 //Here we are registering as the call window delegate
	 _callWindow.callDelegate = self;
    }

    return _callWindow;	
}

- (void)startOutgoingCall:(NSArray<NSString *>*)callees
{
    //....
}

#pragma mark - Call window delegate

- (void)callWindowDidFinish:(BDKCallWindow *)window
{
    self.callWindow.hidden = YES;
}

- (void)callWindow:(BDKCallWindow *)window openChatWith:(BDKOpenChatIntent *)intent
{
    NSLog(@"Open chat with intent %@", intent);
}

@end

That's it! the steps you've seen are the only steps required to make an outgoing call.

Where to go from here

The next guide Receiving an incoming call will show you how to receive an incoming call. Also, if you haven't already, we suggest you to take a look at our sample apps (objective-c swift) to see how to make an outgoing call in a real app.

What's next

Clone this wiki locally