What is Twilio?

Twilio is powering the future of business communications, enabling developers to embed voice, VoIP, and messaging into applications. They virtualize all infrastructure needed in a cloud-based, global environment, exposing it through the Twilio communications API platform. Applications are simple to build and scalable. Enjoy flexibility with pay-as-you go pricing, and benefit from cloud reliability.

Twilio Voice allows your applications to make and receive phone calls. Twilio SMS enables your applications to send and receive SMS messages.Twilio Client allows you to make VoIP calls from any phone, tablet, or browser and supports WebRTC.

Concepts

The Twilio API is a RESTful API that provides voice and SMS functionality for applications. Client libraries are available in multiple languages; for a list, see Twilio API Libraries.

Key aspects of the Twilio API are Twilio verbs and Twilio Markup Language (TwiML).

 

Twilio verbs

The API makes use of Twilio verbs; for example, the <Say> verb instructs Twilio to audibly deliver a message on a call.

The following is a list of Twilio verbs. Learn about the other verbs and capabilities via Twilio Markup Language documentation.

  • <Dial>: Connects the caller to another phone.
  • <Gather>: Collects numeric digits entered on the telephone keypad.
  • <Hangup>: Ends a call.
  • <Play>: Plays an audio file.
  • <Pause>: Waits silently for a specified number of seconds.
  • <Record>: Records the caller's voice and returns a URL of a file that contains the recording.
  • <Redirect>: Transfers control of a call or SMS to the TwiML at a different URL.
  • <Reject>: Rejects an incoming call to your Twilio number without billing you
  • <Say>: Converts text to speech that is made on a call.
  • <Sms>: Sends an SMS message.

Create a Twilio Account

When you're ready to get a Twilio account, sign up at Try Twilio. You can start with a free account, and upgrade your account later.

When you sign up for a Twilio account, you'll receive an account ID and an authentication token. Both will be needed to make Twilio API calls. To prevent unauthorized access to your account, keep your authentication token secure. Your account ID and authentication token are viewable at the Twilio account page, in the fields labeled ACCOUNT SID and AUTH TOKEN, respectively.

Let's Start.....

Create new project in xcode.

We are integrating Twilio with pod. So if you are not familiar with pod then please check this link CocoaPods.org and install cocoapod on your system else open terminal and go to your project directory and run this command $ pod init

this command will install pod file in your project directory. Now open your pod file and insert this in your pod file.


        source 'https://github.com/twilio/cocoapod-specs'
        use_frameworks!
        target 'TwilioDemo' do
              pod 'TwilioConversationsClient'
        end

After save pod file go to terminal and run this command $pod install

this command will install Twilio library in your project.

Now create header file for your project and add this line 

#import <TwilioConversationsClient/TwilioConversationsClient.h> in your header file.

Now Go to storyboard in drag view controller from object library to storyBoard.

We required 3 things in this view controller.

1. remote view - It will show romete view of user.

2. local view - It will show local preview.

3. Identity label - This label is indicating user conversation name.

After drawing this your view will look like this.

Create VideoCallViewController class and link with view.

Insert this on header on VideoCallViewController.swift file.

import TwilioCommon

Create variable for Video SDK components


   // Video SDK components

    var accessManager: TwilioAccessManager?

    var client: TwilioConversationsClient?

    var localMedia: TWCLocalMedia?

    var camera: TWCCameraCapturer?

    var conversation: TWCConversation?

    var incomingInvite: TWCIncomingInvite?

    var outgoingInvite: TWCOutgoingInvite?

    var dimensions:CMVideoDimensions = CMVideoDimensions()

    var username:String = String()

Create UI Element Outlets 


   // MARK: UI Element Outlets and handles
    @IBOutlet weak var remoteMediaView: UIView!
    @IBOutlet weak var localMediaView: UIView!
    @IBOutlet weak var identityLabel: UILabel!

Add helper to determine to running on iphone or simulator.


   // Helper to determine if we're running on simulator or device
    struct Platform {
        static let isSimulator: Bool = {
            var isSim = false
            #if arch(i386) || arch(x86_64)
                isSim = true
            #endif
            return isSim
        }()
    }

Now we are required token to communicate with client. 

Configure access token manually for testing, if desired! Create one manually in the console at https://www.twilio.com/user/account/video/dev-tools/testing-tools

Insert any client id like "Demo" and Choose your Configuration Profile and click on Generate Access Token button.

It will create access token like this.

  

Create access_token variable and assign this token value to access_token.

Add Twilio delegates and finally your code look like this:

 


    import UIKit
import TwilioCommon
import SwiftyJSON

class VideoCallViewController: UIViewController {
    // MARK: View Controller Members
    // Configure access token manually for testing, if desired! Create one manually in the console
    // at https://www.twilio.com/user/account/video/dev-tools/testing-tools
    var accessToken = ""
    
    // Configure remote URL to fetch token from
    var tokenUrl = ""
    
    // Video SDK components
    var accessManager: TwilioAccessManager?
    var client: TwilioConversationsClient?
    var localMedia: TWCLocalMedia?
    var camera: TWCCameraCapturer?
    var conversation: TWCConversation?
    var incomingInvite: TWCIncomingInvite?
    var outgoingInvite: TWCOutgoingInvite?
    var dimensions:CMVideoDimensions = CMVideoDimensions()
    // MARK: UI Element Outlets and handles
    var alertController: UIAlertController?
    @IBOutlet weak var remoteMediaView: UIView!
    @IBOutlet weak var localMediaView: UIView!
    @IBOutlet weak var identityLabel: UILabel!
    @IBOutlet var hangUpView: UIView!
    // Helper to determine if we're running on simulator or device
    struct Platform {
        static let isSimulator: Bool = {
            var isSim = false
            #if arch(i386) || arch(x86_64)
                isSim = true
            #endif
            return isSim
        }()
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        accessToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImN0eSI6InR3aWxpby1mcGE7dj0xIn0.eyJqdGkiOiJTSzJkMmUxODcyZjI1YTFkYzM3MDBjNGM5MWUyNmQ1OGFjLTE0NjU4OTk3MDAiLCJpc3MiOiJTSzJkMmUxODcyZjI1YTFkYzM3MDBjNGM5MWUyNmQ1OGFjIiwic3ViIjoiQUMyOGQ0ODA2MzI0NDQyNTEzNzhmZGYzNWYzODEwNDViMSIsImV4cCI6MTQ2NTkwMzMwMCwiZ3JhbnRzIjp7ImlkZW50aXR5IjoiYWJjIiwicnRjIjp7ImNvbmZpZ3VyYXRpb25fcHJvZmlsZV9zaWQiOiJWU2QwYWNhNTIyMjdkMThiNjFhNGMwODUxYzRmYzY5MDQwIn19fQ.WfFySUcxE_xXkVQ8f1pHqvu7IUAXNRKaFVe3uLoqoQw"
        // Configure access token either from server or manually
        // If the default wasn't changed, try fetching from server
        if self.accessToken == "" {
            // If the token wasn't configured manually, try to fetch it from server
            let config = NSURLSessionConfiguration.defaultSessionConfiguration()
            let session = NSURLSession(configuration: config, delegate: nil, delegateQueue: nil)
            let url = NSURL(string: self.tokenUrl)
            let request  = NSMutableURLRequest(URL: url!)
            request.HTTPMethod = "GET"
            
            // Make HTTP request
            session.dataTaskWithRequest(request, completionHandler: { data, response, error in
                if (data != nil) {
                    // Parse result JSON
                    let json = JSON(data: data!)
                    self.accessToken = json["token"].stringValue
                    // Update UI and client on main thread
                    dispatch_async(dispatch_get_main_queue()) {
                        self.initializeClient()
                    }
                } else {
                    print("Error fetching token :\(error)")
                }
            }).resume()
        } else {
            // If token was manually set, initialize right away
            self.initializeClient()
        }
        
        // video dimension for remote view
        dimensions.width = Int32(self.remoteMediaView.frame.size.height)
        dimensions.height = Int32(self.remoteMediaView.frame.size.height)
    }
    
    // Once access token is set, initialize the Conversations SDK and display the identity of the
    // current user
    func initializeClient() {
        // Set up Twilio Conversations client
        self.accessManager = TwilioAccessManager(token:self.accessToken, delegate:self);
        self.client = TwilioConversationsClient(accessManager: self.accessManager!, delegate: self);
        self.client?.listen();
        
        self.startPreview()
        
        self.identityLabel.text = self.username
    }
    
    func startPreview() {
        // Setup local media preview
        self.localMedia = TWCLocalMedia(delegate: self)
        self.camera = self.localMedia?.addCameraTrack()
        
        if((self.camera) != nil && Platform.isSimulator != true) {
            self.camera!.videoTrack?.attach(self.localMediaView)
            self.camera!.videoTrack?.delegate = self;
            
            // Start the preview.
            self.camera!.startPreview();
            self.localMediaView!.addSubview((self.camera!.previewView)!)
            self.camera!.previewView?.frame = self.localMediaView!.bounds
            self.camera!.previewView?.contentMode = .ScaleToFill
            self.camera!.previewView?.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
        }
    }
}

// MARK: TWCLocalMediaDelegate
extension VideoCallViewController: TWCLocalMediaDelegate {
    func localMedia(media: TWCLocalMedia, didAddVideoTrack videoTrack: TWCVideoTrack) {
        //print("added media track")
    }
}

// MARK: TWCVideoTrackDelegate
extension VideoCallViewController: TWCVideoTrackDelegate {
    func videoTrack(track: TWCVideoTrack, dimensionsDidChange dimensions: CMVideoDimensions) {
        print("video dimensions changed")
    }
}

// MARK: TwilioAccessManagerDelegate
extension VideoCallViewController: TwilioAccessManagerDelegate {
    func accessManagerTokenExpired(accessManager: TwilioAccessManager!) {
        
    }
    
    func accessManager(accessManager: TwilioAccessManager!, error: NSError!) {
                print("Access manager error:")
                print(error)
    }
}

// MARK: TwilioConversationsClientDelegate
extension VideoCallViewController: TwilioConversationsClientDelegate {
    func conversationsClient(conversationsClient: TwilioConversationsClient,
                             didFailToStartListeningWithError error: NSError) {
            print("failed to start listening:")
            print(error)
        
    }
    
    // Automatically accept any invitation
    func conversationsClient(conversationsClient: TwilioConversationsClient,
                             didReceiveInvite invite: TWCIncomingInvite) {
        //print(invite.from)
        invite.acceptWithLocalMedia(self.localMedia!) { conversation, error in
            self.conversation = conversation
            self.conversation!.delegate = self
        }
    }
}

// MARK: TWCConversationDelegate
extension VideoCallViewController: TWCConversationDelegate {
    func conversation(conversation: TWCConversation,
                      didConnectParticipant participant: TWCParticipant) {
        self.navigationItem.title = participant.identity
        participant.delegate = self
    }
    
    func conversation(conversation: TWCConversation,
                      didDisconnectParticipant participant: TWCParticipant) {
        disconnectCall()
        
    }
    
    func conversationEnded(conversation: TWCConversation) {
        self.navigationItem.title = "no call connected"
        // Restart the preview.
        self.startPreview()
    }
}

// MARK: TWCParticipantDelegate
extension VideoCallViewController: TWCParticipantDelegate {
    func participant(participant: TWCParticipant, addedVideoTrack videoTrack: TWCVideoTrack) {
        videoTrack.attach(self.remoteMediaView)
    }
    
}

Build your project and make call.