NEWDolby Interactivity APIs are now the Dolby.io Communications APIs Learn More >
X

Create a Basic Audio Conference Application for iOS

Step 1: Create your project

Project setup

  1. Open Xcode 11 and create a new single view iOS app. Select Swift for the Language and Storyboard for the User Interface option.

Note: New projects created with Xcode 11 are intended for deployment on iOS 13 or later only. To support an earlier version of iOS, some changes will need to be made to the project that has been created. See this blog post for the details on what to change.)

  1. Enable the background mode. To do that, go to your target settings ▸ Signing & Capabilities ▸ add + CapabilityBackground Modes.
  • Turn on Audio, AirPlay, and Picture in Picture.
  • Turn on Voice over IP.
  1. If you want to support CallKit (receiving incoming calls when the application is killed) with VoIP push notifications, enable Push Notifications. You also need to upload your VoIP push certificate to the Dolby.io developer portal.

CapabilitiesCapabilities

  1. To establish privacy permissions, add two new keys in Info.plist:
  • Privacy - Microphone Usage Description.
  • Privacy - Camera Usage Description.

Installation

Carthage

  1. Install Carthage using Homebrew:
$ brew update
$ brew install carthage
  1. To integrate Dolby.io Communications SDK for iOS into your Xcode project, create a Cartfile file in the root folder of your project. Paste the following command to the file:
binary "https://raw.githubusercontent.com/voxeet/voxeet-sdk-ios/master/VoxeetSDK.json" ~> VERSION

Note: Include the latest iOS SDK version instead of the VERSION string.

  1. Build the frameworks.
carthage update

The built frameworks are located in Carthage/Build/iOS. Add VoxeetSDK.framework, WebRTC.framework, and dvclient.framework to your Xcode project as members of the application target. Turn off the Copy items if needed option.

For more information, see the Carthage documentation.

  1. In the General tab of your target, ensure that VoxeetSDK.framework, WebRTC.framework, and dvclient.framework are added to the 'Frameworks, Libraries, and Embedded Content' with the 'Embed & Sign' option selected for both frameworks.

CocoaPods

  1. Install CocoaPods:
sudo gem install cocoapods
  1. Add VoxeetSDK to the Podfile file to integrate SDK into the Xcode project:
pod 'VoxeetSDK'
  1. Make sure that the iOS platform mentioned in Podfile is set to '11.0':
platform :ios, '11.0'
  1. Build dependencies:
pod install
  1. Open the created .xcworkspace project.

Manual installation

  1. Download the latest iOS SDK release zip.

  2. Unzip it and drag and drop VoxeetSDK.framework, WebRTC.framework, and dvclient.framework frameworks to your project.

  3. In the dialog that is displayed, select the Copy items if needed option and make sure that the frameworks are added to the proper target.

  4. In the General tab of your target, add the VoxeetSDK.framework, WebRTC.framework, and dvclient.framework to the 'Frameworks, Libraries, and Embedded Content' with the 'Embed & Sign' option selected for both frameworks.

Step 2: Initialize the SDK with your Dolby.io credentials

There are two methods to initialize the SDK. You can initialize using a token, which requires a server to return the token to the application.
Alternately, you can initialize with the secrets, which is not secure. In this example, we are initializing with the secrets.
However, we recommend using a token to initialize the SDK. For more information, see Initializing.

Locate your Consumer Key and Consumer Secret. The instructions on how to create or find them is in the Prerequiste section of Initializing. It is recommended that you create a new Sample application for this tutorial.

Change the application(application:didFinishLaunchingWithOptions:) method from the AppDelegate.swift file, as in the following example. Replace the consumerKey and consumerSecret strings with the values you just created.

import UIKit
import VoxeetSDK

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        // VoxeetSDK initialization.
        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
        VoxeetSDK.shared.conference.audio3D = false

        return true
    }
}

Step 3: 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 ViewController.swift, 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!

    override func viewDidLoad() {
        super.viewDidLoad()
    }
}

2. In the ViewController class, add a function to create the user interface for the Dolby.io session and assign a random name.

override func viewDidLoad() {
    ...

    initSessionUI()
}

func initSessionUI() {
    let statusBarHeight = 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: 8, y: statusBarHeight + 16, width: 84, height: 30))
    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: 100, y: statusBarHeight + 16, width: 100, height: 30)
    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: 200, y: statusBarHeight + 16, width: 100, height: 30)
    logoutButton.isEnabled = false
    logoutButton.isSelected = true
    logoutButton.setTitle("LOGOUT", for: .normal)
    logoutButton.addTarget(self, action: #selector(logoutButtonAction), for: .touchUpInside)
    self.view.addSubview(logoutButton)
}

3. Add methods to log in and log out of the Voxeeet session.

@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
    }
}

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

Step 4: Add a joining option

Add UI for starting a conference in ViewController.swift.

1. In ViewController.swift, 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() {
    ...
}

2. Add a 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: 8, y: sessionTextField.frame.origin.y + sessionTextField.frame.height + 16, width: 84, height: 30))
    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: 100, y: sessionTextField.frame.origin.y + sessionTextField.frame.height + 16, width: 100, height: 30)
    startButton.isEnabled = false
    startButton.isSelected = true
    startButton.setTitle("START", for: .normal)
    startButton.addTarget(self, action: #selector(startButtonAction), for: .touchUpInside)
    self.view.addSubview(startButton)
}

3. Enable and disable the start button as appropriate.


@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.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 */

    }
}

4. Add a method to start the Voxeeet 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 })
}

Step 5: Add a leaving option

Add UI for leaving a conference in ViewController.swift.

1. In ViewController.swift, 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!

    ...
}

2. 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: 200, y: sessionTextField.frame.origin.y + sessionTextField.frame.height + 16, width: 100, height: 30)
    leaveButton.isEnabled = false
    leaveButton.isSelected = true
    leaveButton.setTitle("LEAVE", for: .normal)
    leaveButton.addTarget(self, action: #selector(leaveButtonAction), for: .touchUpInside)
    self.view.addSubview(leaveButton)
}
...

3. Enable and disable the leave button as appropriate.


@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.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 })
}
...

4. Add a method to leave the Voxeeet conference.

...

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

Step 6: 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 {

        // VoxeetSDK initialization.
        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
        VoxeetSDK.shared.conference.audio3D = 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!

    override func viewDidLoad() {
        super.viewDidLoad()

        initSessionUI()
        initConferenceUI()
    }

    func initSessionUI() {
        let statusBarHeight = 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: 8, y: statusBarHeight + 16, width: 84, height: 30))
        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: 100, y: statusBarHeight + 16, width: 100, height: 30)
        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: 200, y: statusBarHeight + 16, width: 100, height: 30)
        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: 8, y: sessionTextField.frame.origin.y + sessionTextField.frame.height + 16, width: 84, height: 30))
        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: 100, y: sessionTextField.frame.origin.y + sessionTextField.frame.height + 16, width: 100, height: 30)
        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: 200, y: sessionTextField.frame.origin.y + sessionTextField.frame.height + 16, width: 100, height: 30)
        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
        }
    }
}

Did this page help you?