Create voice chat app using Twilio SDK in iOS
Introduction
As described in previous post , today I will show you how to build a simple chat voice iOS app using Twilio Video SDK.
Overview, Twilio Video is a well known platform providing many services to build experiences with video: real-time video, voice, and screen sharing. It received so much good response from customers globally.
https://www.g2.com/products/twilio/reviews
https://www.trustradius.com/products/twilio-video/reviews
In this post we will try using Video API to build a voice chat application.
Create an project in Twilio
Create an account at Twillo
Go to console page
Create a new project name “TwilioDemoChat” or any name as you want at link
After created app, a welcome page will be shown
Choose “Other” and skip to dashboard to finish creating project step.
Save ACCOUNT SID and AUTH TOKEN in somewhere so that you can use later.
Create API Key
Create a new api key and save it securely in somewhere, because this just be shown in ONCE TIME.
Create Access Tokens
Go to this link to create 2 new access tokens. We are going to test with 2 users connect to the same room name “TwilioDemoChatRoom” and has client identifies are “TwilioDemoChatRoomUser1” and “TwilioDemoChatRoomUser1”, so that click on “Generate Access Token” to get access tokens for that room, save 2 access tokens so we can use in iOS side.
NOTE:In a production application, your back-end server will need to generate an Access Token for every user in your application. An Access Token is a short-lived credential used to authenticate your client-side application to Twilio.
Implement Voice Chat in iOS
Create a new project named “TwilioDemoChat”
Configure CocoaPods
Create a empty file named PodFile put in root project’s directory and paste following commands:
platform :ios,'11.0' use_frameworks! def install_pods pod 'TwilioVideo' pod 'MBProgressHUD' end target 'TwilioDemoChat' do install_pods end
Open Terminal app then run following command at project’s root directory to install TwilioVideo SDK:
pod install
Because our application need to use micro for voice chat so we need to add micro permission to info.plist
NSMicrophoneUsageDescription This sample uses a mic device for voice chat
Implement Twilio
First we need a controller to handle joining room,.. named TwilioController.swift
import UIKit import TwilioVideo import MBProgressHUD let TWILIO_TEST_ROOM = "TwilioDemoChatRoom" let TWILIO_ACCESS_TOKEN_1 = "access_token_generated_from_step_Create_Access_Tokens" let TWILIO_ACCESS_TOKEN_2 = "access_token_generated_from_step_Create_Access_Tokens" let kTwilioController = TwilioController.shared public enum RoomStatus{ case Connected case Disconnected case ParticipantConnected case ParticipantDisconnected case Error } public typealias RoomStatusUpdatedHandler = (RoomStatus) -> (Void) class TwilioController: NSObject { static let shared = TwilioController() var room:Room? = nil var connected = false var roomStatusHandler:RoomStatusUpdatedHandler? private var localAudioTrack = LocalAudioTrack() //connect to room defined in TWILIO_TEST_ROOM func connectToRoom(handler:RoomStatusUpdatedHandler?) { roomStatusHandler = handler let connectOptions = ConnectOptions(token: TWILIO_ACCESS_TOKEN_2) { (builder) in builder.roomName = TWILIO_TEST_ROOM //setup local audio track if let audioTrack = self.localAudioTrack { builder.audioTracks = [ audioTrack ] } } room = TwilioVideoSDK.connect(options: connectOptions, delegate: self) } func disconnectFromRoom() { room?.disconnect() } // MARK: - Private methods private func toastMessage(message:String){ print("toastMessage \(message)") DispatchQueue.main.asyncAfter(deadline: .now() ) { let hud = MBProgressHUD.showAdded(to: UIApplication.shared.keyWindow!, animated: true) hud.mode = .text hud.label.text = message hud.removeFromSuperViewOnHide = true hud.hide(animated: true, afterDelay: 2) } } } extension TwilioController : RoomDelegate{ //event when did connect to room func roomDidConnect(room: Room) { connected = true roomStatusHandler?(.Connected) } //event when did disconnect to room func roomDidDisconnect(room: Room, error: Error?) { connected = false roomStatusHandler?(.Disconnected) } //event when can't connect to room, because of timeout or network error.. func roomDidFailToConnect(room: Room, error: Error) { connected = false roomStatusHandler?(.Error) } //event when participant joined the room func participantDidConnect(room: Room, participant: RemoteParticipant) { let message = "participant \(participant.identity) connected" toastMessage(message: message) roomStatusHandler?(.ParticipantConnected) } //event when participant left the room func participantDidDisconnect(room: Room, participant: RemoteParticipant) { let message = "participant \(participant.identity) disconnected" toastMessage(message: message) roomStatusHandler?(.ParticipantDisconnected) } }
Mainly, this controller has 2 main functions:
– connectToRoom(): connect to specific room defined as TWILIO_TEST_ROOM and specific access token (TWILIO_ACCESS_TOKEN_1 or TWILIO_ACCESS_TOKEN_2), if you try running in physical devices, set different access token for each device. This function has callback to handle events like:
- Connected: current user connected to room
- Disconnected: current user disconnected from room
- ParticipantConnected: other participant connected to room
- ParticipantDisconnected: other participant disconnected from room
– disconnectFromRoom(): simply disconnect from room
Then we create a sample view controller named CallViewController like following
in CallViewController.swift we include following code
import UIKit import MBProgressHUD class CallViewController: UIViewController { @IBOutlet weak var joinButton: UIButton! @IBOutlet weak var roomTxt: UITextField! //when joined status update, update button title also private var joined = false{ didSet{ if joined { joinButton.setTitle("End call", for: .normal) }else{ joinButton.setTitle("Join", for: .normal) } } } override func viewDidLoad() { super.viewDidLoad() roomTxt.text = TWILIO_TEST_ROOM } @IBAction func joinRoom(_ sender: Any) { if !joined{ MBProgressHUD.showAdded(to: self.view, animated: true) kTwilioController.connectToRoom { (status) -> (Void) in if status == .Connected { self.joined = true } if status == .Disconnected{ self.joined = false } MBProgressHUD.hide(for: self.view, animated: true) } }else{ kTwilioController.disconnectFromRoom() } } }
Simply, we have a textfield to display test room name(TwilioDemoChatRoom, not editable), with a button to Join or End Call (we detect the room’s status has changed to update button’s title and call function connectToRoom() or disconnectFromRoom() properly).
Now you run project in 2 devices (simulator not supported) to check how it works. Remember to change access token for each device when running.
Refs: