Create a Basic Audio Conference Application for iOS

This tutorial guides how to create a basic conference application using the iOS SDK.

In order to test the conference call created in this guide, use a physical iOS device when running the app.

Initialize the SDK with your Dolby.io credentials

Initialize the SDK using the secure authentication method that uses a token in the application. For more information, see the Initializing the SDK document. For the purpose of this example, we are using a client access token generated from the Dolby.io dashboard. We recommend creating a new Sample application for this tutorial.

  1. Locate your Key and Secret in your Dolby.io dashboard. The instructions on how to create or find them is in the Prerequisite section of the Initializing the SDK document. We recommend creating a new Sample application for this tutorial.

  2. Locate the AppDelegate.swift file in your project.

  3. In the file, change the application(application, launchOptions) method as in the following example. Replace the TestClientAccessToken string with the token generated from the Dolby.io dashboard.

import UIKit
import VoxeetSDK

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Initialize the Voxeet SDK
        // Please read the documentation at:
        // https://docs.dolby.io/communications-apis/docs/initializing-ios
        // Generate a client access token from the Dolby.io dashboard and insert into accessToken variable
        let accessToken = "ClientAccessToken"
        VoxeetSDK.shared.initialize(accessToken: accessToken) { closure, isExpired in
            closure(accessToken)
        }

        // Example of public variables to change the conference behavior.
        VoxeetSDK.shared.notification.push.type = .none
        VoxeetSDK.shared.conference.defaultBuiltInSpeaker = true
        VoxeetSDK.shared.conference.defaultVideo = false

        return true
    }
}

Open and close a session

To allow creating and joining conferences, log in with a user name. In this tutorial, random user names are assigned.

  1. In the ViewController.swift file, add some variables in the ViewController class to refer to the user interface elements that will be created in step 2.
import VoxeetSDK

class ViewController: UIViewController {
    // Session UI.
    var sessionTextField: UITextField!
    var logInButton: UIButton!
    var logoutButton: UIButton!

    // User interface settings.
    let margin: CGFloat = 16
    let buttonWidth: CGFloat = 120
    let buttonHeight: CGFloat = 35
    let textFieldWidth: CGFloat = 120 + 16 + 120
    let textFieldHeight: CGFloat = 40

    override func viewDidLoad() {
        super.viewDidLoad()
    }
}
  1. In the ViewController class, add the following function to create the user interface for the Dolby.io session and assign a random name.
override func viewDidLoad() {
    super.viewDidLoad()

    initSessionUI()
}

func initSessionUI() {
    
        var statusBarHeight: CGFloat {
            // 13.0 and later
            if #available(iOS 13.0, *){
                let scenes = UIApplication.shared.connectedScenes
                let windowScene = scenes.first as? UIWindowScene
                let window = windowScene?.windows.first
                return  window?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0;
            }else {
                return UIApplication.shared.statusBarFrame.height
            }
        }

    let avengersNames = [
        "Thor",
        "Cap",
        "Tony Stark",
        "Black Panther",
        "Black Widow",
        "Hulk",
        "Spider-Man",
    ]

    // Session text field.
    sessionTextField = UITextField(
        frame: CGRect(
            x: margin,
            y: statusBarHeight + margin,
            width: textFieldWidth,
            height: textFieldHeight
        )
    )
    sessionTextField.borderStyle = .roundedRect
    sessionTextField.placeholder = "Username"
    sessionTextField.autocorrectionType = .no
    sessionTextField.text = avengersNames.randomElement()
    self.view.addSubview(sessionTextField)

    // Open session button.
    logInButton = UIButton(type: .system) as UIButton
    logInButton.frame = CGRect(
        x: margin,
        y: sessionTextField.frame.origin.y + sessionTextField.frame.height + margin,
        width: buttonWidth,
        height: buttonHeight
    )
    logInButton.backgroundColor = logInButton.tintColor
    logInButton.layer.cornerRadius = 5
    logInButton.isEnabled = true
    logInButton.isSelected = true
    logInButton.setTitle("LOG IN", for: .normal)
    logInButton.addTarget(self, action: #selector(logInButtonAction), for: .touchUpInside)
    self.view.addSubview(logInButton)

    // Close session button.
    logoutButton = UIButton(type: .system) as UIButton
    logoutButton.frame = CGRect(
        x: logInButton.frame.origin.x + logInButton.frame.width + margin,
        y: logInButton.frame.origin.y,
        width: buttonWidth,
        height: buttonHeight
    )
    logoutButton.backgroundColor = logoutButton.tintColor
    logoutButton.layer.cornerRadius = 5
    logoutButton.isEnabled = false
    logoutButton.isSelected = true
    logoutButton.setTitle("LOGOUT", for: .normal)
    logoutButton.addTarget(self, action: #selector(logoutButtonAction), for: .touchUpInside)
    self.view.addSubview(logoutButton)
}
  1. Add methods to log in and log out of the Dolby.io session.
@objc func logInButtonAction(sender: UIButton!) {
    // Open participant session.
    let info = VTParticipantInfo(name: sessionTextField.text, avatarURL: nil)
    VoxeetSDK.shared.session.open(info: info) { error in
        self.logInButton.isEnabled = false
        self.logoutButton.isEnabled = true
    }
}

@objc func logoutButtonAction(sender: UIButton!) {
    // Close participant session.
    VoxeetSDK.shared.session.close { error in
        self.logInButton.isEnabled = true
        self.logoutButton.isEnabled = false
    }
}

Add a joining option

Add UI for starting a conference in the ViewController.swift file.

  1. In the ViewController.swift file, add some variables to the ViewController class to refer to the user interface elements that will be created in step 2.
class ViewController: UIViewController {
    ...

    // Conference UI.
    var conferenceTextField: UITextField!
    var startButton: UIButton!

    override func viewDidLoad() {
        ...
    }
}
  1. Add the following method to extend the user interface for the Dolby.io conference.
override func viewDidLoad() {
    ...

    initSessionUI()
    initConferenceUI()
}

...

func initConferenceUI() {
    // Session text field.
    conferenceTextField = UITextField(
        frame: CGRect(
            x: margin,
            y: logoutButton.frame.origin.y + logoutButton.frame.height + margin,
            width: textFieldWidth,
            height: textFieldHeight
        )
    )
    conferenceTextField.borderStyle = .roundedRect
    conferenceTextField.placeholder = "Conference"
    conferenceTextField.autocorrectionType = .no
    conferenceTextField.text = "Avengers meeting"
    self.view.addSubview(conferenceTextField)

    // Conference create/join button.
    startButton = UIButton(type: .system) as UIButton
    startButton.frame = CGRect(
        x: margin,
        y: conferenceTextField.frame.origin.y + conferenceTextField.frame.height + margin,
        width: buttonWidth,
        height: buttonHeight
    )
    startButton.backgroundColor = startButton.tintColor
    startButton.layer.cornerRadius = 5
    startButton.isEnabled = false
    startButton.isSelected = true
    startButton.setTitle("START", for: .normal)
    startButton.addTarget(self, action: #selector(startButtonAction), for: .touchUpInside)
    self.view.addSubview(startButton)
}
  1. Enable and disable the start button as appropriate.
@objc func logInButtonAction(sender: UIButton!) {
    // Open participant session.
    let info = VTParticipantInfo(name: sessionTextField.text, avatarURL: nil)
    VoxeetSDK.shared.session.open(info: info) { error in

        ...
        self.startButton.isEnabled = true /* Update start button state */

    }
}

@objc func logoutButtonAction(sender: UIButton!) {
    // Close participant session.
    VoxeetSDK.shared.session.close { error in

        ...
        self.startButton.isEnabled = false /* Update start button state */

    }
}
  1. Add a method to start the Dolby.io conference.
@objc func startButtonAction(sender: UIButton!) {
    // Create a conference room with an alias.
    let options = VTConferenceOptions()
    options.params.dolbyVoice = true
    options.alias = conferenceTextField.text ?? ""
    VoxeetSDK.shared.conference.create(options: options, success: { conference in
        // Join the conference with its id.
        VoxeetSDK.shared.conference.join(conference: conference, success: { response in
            self.logoutButton.isEnabled = false
            self.startButton.isEnabled = false
        }, fail: { error in })
    }, fail: { error in })
}

Add a leaving option

Add UI for leaving a conference in the ViewController.swift file.

  1. In the ViewController.swift file, add a variable to the ViewController class to refer to the user interface element that will be created in step 2.
class ViewController: UIViewController {
    ...

    // Conference UI.
    ...
    var leaveButton: UIButton!

    ...
}
  1. Modify initConferenceUI to extend the user interface for the Dolby.io conference.
func initConferenceUI() {
    ...

    // Conference leave button.
    leaveButton = UIButton(type: .system) as UIButton
    leaveButton.frame = CGRect(
        x: startButton.frame.origin.x + startButton.frame.width + margin,
        y: startButton.frame.origin.y,
        width: buttonWidth,
        height: buttonHeight
    )
    leaveButton.backgroundColor = leaveButton.tintColor
    leaveButton.layer.cornerRadius = 5
    leaveButton.isEnabled = false
    leaveButton.isSelected = true
    leaveButton.setTitle("LEAVE", for: .normal)
    leaveButton.addTarget(self, action: #selector(leaveButtonAction), for: .touchUpInside)
    self.view.addSubview(leaveButton)
}
  1. Enable and disable the leave button as appropriate.
@objc func logInButtonAction(sender: UIButton!) {
    // Open participant session.
    let info = VTParticipantInfo(name: sessionTextField.text, avatarURL: nil)
    VoxeetSDK.shared.session.open(info: info) { error in

        ...
        self.leaveButton.isEnabled = false /* Update leave button state */

    }
}

@objc func logoutButtonAction(sender: UIButton!) {
    // Close participant session.
    VoxeetSDK.shared.session.close { error in

        ...
        self.leaveButton.isEnabled = false /* Update leave button state */

    }
}

@objc func startButtonAction(sender: UIButton!) {
    ...
        // Join the conference with its id.
        VoxeetSDK.shared.conference.join(conference: conference, success: { response in

            ...
            self.leaveButton.isEnabled = true /* Update leave button state */

        }, fail: { error in })
    }, fail: { error in })
}
  1. Add a method to leave the Dolby.io conference.
@objc func leaveButtonAction(sender: UIButton!) {
    VoxeetSDK.shared.conference.leave { error in
        self.logoutButton.isEnabled = true
        self.startButton.isEnabled = true
        self.leaveButton.isEnabled = false
    }
}

Run your application

The app should now build and run.

For reference, the complete contents of the files should be:

AppDelegate.swift

import UIKit
import VoxeetSDK

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Initialize the Voxeet SDK
        // WARNING: It is best practice to use the VoxeetSDK.shared.initialize(accessToken, refreshTokenClosureWithParam) function to initialize the SDK.
        // Please read the documentation at:
        // https://docs.dolby.io/communications-apis/docs/initializing-ios
        VoxeetSDK.shared.initialize(consumerKey: "YOUR_CONSUMER_KEY", consumerSecret: "YOUR_CONSUMER_SECRET")

        // Example of public variables to change the conference behavior.
        VoxeetSDK.shared.notification.push.type = .none
        VoxeetSDK.shared.conference.defaultBuiltInSpeaker = true
        VoxeetSDK.shared.conference.defaultVideo = false

        return true
    }
}

ViewController.swift

import UIKit
import VoxeetSDK

class ViewController: UIViewController {
    // Session UI.
    var sessionTextField: UITextField!
    var logInButton: UIButton!
    var logoutButton: UIButton!

    // Conference UI.
    var conferenceTextField: UITextField!
    var startButton: UIButton!
    var leaveButton: UIButton!

    // User interface settings.
    let margin: CGFloat = 16
    let buttonWidth: CGFloat = 120
    let buttonHeight: CGFloat = 35
    let textFieldWidth: CGFloat = 120 + 16 + 120
    let textFieldHeight: CGFloat = 40

    override func viewDidLoad() {
        super.viewDidLoad()

        initSessionUI()
        initConferenceUI()
    }

    func initSessionUI() {

        var statusBarHeight: CGFloat {
            // 13.0 and later
            if #available(iOS 13.0, *){
                let scenes = UIApplication.shared.connectedScenes
                let windowScene = scenes.first as? UIWindowScene
                let window = windowScene?.windows.first
                return  window?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0;
            }else {
                return UIApplication.shared.statusBarFrame.height
            }
        }

        let avengersNames = [
            "Thor",
            "Cap",
            "Tony Stark",
            "Black Panther",
            "Black Widow",
            "Hulk",
            "Spider-Man",
        ]

        // Session text field.
        sessionTextField = UITextField(
            frame: CGRect(
                x: margin,
                y: statusBarHeight + margin,
                width: textFieldWidth,
                height: textFieldHeight
            )
        )
        sessionTextField.borderStyle = .roundedRect
        sessionTextField.placeholder = "Username"
        sessionTextField.autocorrectionType = .no
        sessionTextField.text = avengersNames.randomElement()
        self.view.addSubview(sessionTextField)

        // Open session button.
        logInButton = UIButton(type: .system) as UIButton
        logInButton.frame = CGRect(
            x: margin,
            y: sessionTextField.frame.origin.y + sessionTextField.frame.height + margin,
            width: buttonWidth,
            height: buttonHeight
        )
        logInButton.backgroundColor = logInButton.tintColor
        logInButton.layer.cornerRadius = 5
        logInButton.isEnabled = true
        logInButton.isSelected = true
        logInButton.setTitle("LOG IN", for: .normal)
        logInButton.addTarget(self, action: #selector(logInButtonAction), for: .touchUpInside)
        self.view.addSubview(logInButton)

        // Close session button.
        logoutButton = UIButton(type: .system) as UIButton
        logoutButton.frame = CGRect(
            x: logInButton.frame.origin.x + logInButton.frame.width + margin,
            y: logInButton.frame.origin.y,
            width: buttonWidth,
            height: buttonHeight
        )
        logoutButton.backgroundColor = logoutButton.tintColor
        logoutButton.layer.cornerRadius = 5
        logoutButton.isEnabled = false
        logoutButton.isSelected = true
        logoutButton.setTitle("LOGOUT", for: .normal)
        logoutButton.addTarget(self, action: #selector(logoutButtonAction), for: .touchUpInside)
        self.view.addSubview(logoutButton)
    }

    func initConferenceUI() {
        // Session text field.
        conferenceTextField = UITextField(
            frame: CGRect(
                x: margin,
                y: logoutButton.frame.origin.y + logoutButton.frame.height + margin,
                width: textFieldWidth,
                height: textFieldHeight
            )
        )
        conferenceTextField.borderStyle = .roundedRect
        conferenceTextField.placeholder = "Conference"
        conferenceTextField.autocorrectionType = .no
        conferenceTextField.text = "Avengers meeting"
        self.view.addSubview(conferenceTextField)

        // Conference create/join button.
        startButton = UIButton(type: .system) as UIButton
        startButton.frame = CGRect(
            x: margin,
            y: conferenceTextField.frame.origin.y + conferenceTextField.frame.height + margin,
            width: buttonWidth,
            height: buttonHeight
        )
        startButton.backgroundColor = startButton.tintColor
        startButton.layer.cornerRadius = 5
        startButton.isEnabled = false
        startButton.isSelected = true
        startButton.setTitle("START", for: .normal)
        startButton.addTarget(self, action: #selector(startButtonAction), for: .touchUpInside)
        self.view.addSubview(startButton)

        // Conference leave button.
        leaveButton = UIButton(type: .system) as UIButton
        leaveButton.frame = CGRect(
            x: startButton.frame.origin.x + startButton.frame.width + margin,
            y: startButton.frame.origin.y,
            width: buttonWidth,
            height: buttonHeight
        )
        leaveButton.backgroundColor = leaveButton.tintColor
        leaveButton.layer.cornerRadius = 5
        leaveButton.isEnabled = false
        leaveButton.isSelected = true
        leaveButton.setTitle("LEAVE", for: .normal)
        leaveButton.addTarget(self, action: #selector(leaveButtonAction), for: .touchUpInside)
        self.view.addSubview(leaveButton)
    }

    @objc func logInButtonAction(sender: UIButton!) {
        // Open participant session.
        let info = VTParticipantInfo(externalID: nil, name: sessionTextField.text, avatarURL: nil)
        VoxeetSDK.shared.session.open(info: info) { error in
            self.logInButton.isEnabled = false
            self.logoutButton.isEnabled = true
            self.startButton.isEnabled = true
            self.leaveButton.isEnabled = false
        }
    }

    @objc func logoutButtonAction(sender: UIButton!) {
        // Close participant session.
        VoxeetSDK.shared.session.close { error in
            self.logInButton.isEnabled = true
            self.logoutButton.isEnabled = false
            self.startButton.isEnabled = false
            self.leaveButton.isEnabled = false
        }
    }

    @objc func startButtonAction(sender: UIButton!) {
        // Create a conference room with an alias.
        let options = VTConferenceOptions()
        options.params.dolbyVoice = true
        options.alias = conferenceTextField.text ?? ""
        VoxeetSDK.shared.conference.create(options: options, success: { conference in
            // Join the conference with its id.
            VoxeetSDK.shared.conference.join(conference: conference, success: { response in
                self.logoutButton.isEnabled = false
                self.startButton.isEnabled = false
                self.leaveButton.isEnabled = true
            }, fail: { error in })
        }, fail: { error in })
    }

    @objc func leaveButtonAction(sender: UIButton!) {
        VoxeetSDK.shared.conference.leave { error in
            self.logoutButton.isEnabled = true
            self.startButton.isEnabled = true
            self.leaveButton.isEnabled = false
        }
    }
}