migration-guide-from-tokbox-to-agora

Migration Guide from TokBox to Agora – iOS edition

Agora’s voice, video and live broadcasting software all run on a Software Defined Real-Time Network (SD-RTN™), which is a realtime transmission network built by Agora and is the only network infrastructure specifically designed for realtime communications in the world. All voice and video services provided by the Agora SDK are deployed and transmitted through the Agora SD-RTN™.

The Agora SD-RTN™ may be one motivation for adopting the Agora iOS SDK for all of your voice, video or live broadcasting needs. Another may be pricing. Whatever the need may be, the following guide details how a generically functional app with a working TokBox video integration may be disintegrated to provide essentially the same functionality but on a totally different infrastructure, with a completely different set of required methods, and an entirely new feel.

Adoption Guide

To drive adoption, Agora is offering this guide. To simplify the adoption process, here are the three primary codebases:

The codebase for the sample application is a standardized, generic, and minimalistic set of basic features or functionalities (i.e., call button, answer button, mute button, hang-up button, & programmatic video display view). The sample application with your old TokBox integration connects with each of the features. Your sample application with your new Agora integration is the final destination.

What is the singleton design pattern?

A singleton is a design pattern much like the all too familiar Model View Controller is a design pattern, except it is a pattern whose single instance returns no matter which application resource makes the request. It provides a global point of access to its available methods. Used in situations where a single point of control is desirable, a singleton is great for services like those offered by Agora in the CPaaS market such as live voice, video or broadcasting.

In this adoption guide, you learn how to singlehandedly replace Twilio’s TwilioVideo with Agora’s AgoraRtcEngine_iOS to power live voice, video or broadcasting integrations.

Adoption

At Agora we empathize web developers such as Dzung Nguyen or Anand Nimje, who look for simplicity in development so that our iOS SDK is designed in accordance with popular development sentiments in mind. Many developers such as Dzung Nguyen, for instance, claim the Singleton pattern in iOS to be “the most common and easiest-to-implement design pattern.” Others such as Anand Nimje, whose describes the design pattern as “very popular in development”, says it is a “[very simple, common and easy to use.”

TokBox, which runs on media serves, has three layers comparable to Agora: session, token, publishing / subscribing where the primary difference between each is 1) sessions in TokBox are like channels in Agora, which exists independently of a user in Agora, 2) tokens are like Agora’s two options of security, and finally, 3) subscribing / publishing is a much more redundant pattern for simply joining a channel. But there is no one-to-one correspondence like a bijection from one function in TokBox to another in Agora. This primarily so because of the difference in architecture. TokBox, for instance, relies heavily upon delegates, whereas TokBox’s architecture is based upon a singleton. To illustrate this point, see the diagram below:

Since TokBox’s relies heavily, however, on the delegation design pattern, your first step in disintegrating TokBox is to eliminate the publisher, subscriber or session delegate. Your next step is to integrate Agora’s singleton design pattern, which replaces tokens as well as sessions. Agora’s setup for remote or local video, albeit similar, nonetheless, requires you remove TokBox’s publish/subscribe architecture. With these steps out of the way, the remainder of the guide focuses on joining or leaving a channel.

It might be important to emphasize that after an instance of the AgoraRtcEngine is initialized, nearly all of the important aspects of the SDK’s functionality are called through its methods or, in other words, all of the important SDK functions are its methods: setupLocalVideo()setupRemoteVideo()enableVideo()setChannelProfile()joinChannel()leaveChannel(). If you learn how to use these methods, the Agora iOS SDK is at your fingertips.

Step One

The first step to replacing TokBox’s delegate design pattern with Agora’s singleton design pattern is to create an easily accessible variable in the AppDelegate.swift:

let AppID = ""

Step Two

The next step requires replacing both the TokBox pod as well as the imports. In the pod file add AgoraRtcEngine_iOS in place of the OpenTok pod in the Podfile. At the top of the ViewController file replace the import OpenTokwith AgoraRtcEngineKit.

Step Three

The next step requires replacing the three TokBox delegates with an instance of Agora’s singleton. At the bottom of theViewController, remove the three extensions: OTPublisherDelegateOTSessionDelegateOTSubscriberDelegate. With these three delegates removed, create a function for initializing an instance of the Agora singleton:

func initializeAgoraEngine() {
    agoraKit = AgoraRtcEngineKit.sharedEngine(withAppId: AppID, delegate: self)
    agoraKit.enableWebSdkInteroperability(true)
}

Here you pass your AppID into the sharedEngine method, assigning the delegate as “self”. While enabling web SDK interoperability is optional, enable it here so that you can use it for testing with the web. With the initialization function setup, make sure to call the function in viewDidLoad(). Finally, make sure to create a property at the top of your ViewController file for initialization:

var agoraKit: AgoraRtcEngineKit!

There is essentially all you need to completely replace TokBox’s heavily delegate design pattern with Agora’s singleton design pattern. As stated earlier, an instance of the Agora singleton puts nearly all of the SDK’s important methods right at your fingertips! With the design pattern of the app’s architecture transformed, the next steps are to replace TokBox’s publisher/subscriber functionality with Agora’s local and remote video setups.

Step Four

To replace TokBox’s publisher/subscriber functionality with Agora’s local and remote video setups, remove the publisher/subscriber methods:

  • publish()
  • subscribe()
  • addSubscribeView()
  • handleError(_ error: OTError?)

Remote/Local v. Publisher/Subscriber

Before we move ahead, let us take a step back. Publisher and subscriber are confusing terms. They lack orientation. Local and remote are specific to a user’s device. It makes more sense to think of video streams in terms of a device-specific orientation than in terms of abstract concepts such as “publishing” or “subscribing”. Think of two users, for instance, like user Alice and user Bob. It is much easier to understand how local and remote are better terms than subscriber and publisher if you think of these two users. From the perspective of Alice’s device, Alice’s local video is her video and the remote video on her device is Bob’s video. From Bob’s, Bob’s local video is his video and his remote video is Alice’s video. Speak in terms of publisher/subscriber. Publishing to whom? Are you just a publisher? Subscribing to whom? Are you just a subscriber? The problem here is that both Alice and Bob are publisher and subscriber at the same time but from whose perspective? There’s no perspective. That’s why it makes more sense to think in terms of local and remote and NOT in subscriber and publisher.

With this concept explained and their four methods removed, you need to enable video, set up video, and configure the canvas or video display through a delegate, which is standard in iOS.

  • Add a function now for enabling video:
func setupVideo() {
    agoraKit.enableVideo()
    agoraKit.setVideoEncoderConfiguration(AgoraVideoEncoderConfiguration(size: AgoraVideoDimension640x360, frameRate: .fps15, bitrate: AgoraVideoBitrateStandard, orientationMode: .adaptative) ) // Default video profile is 360P }

Agora’s AgoraVideoEncoderConfiguration is designed primarily to empower developers with the ability to set a video dimension, a frame rate, a bitrate, and an orientation so that you can control how to deliver your video.

  • Add a function for setting up local video:
func setupLocalVideo(uid: UInt) {
        
        let videoView = UIView()
        videoView.tag = Int(uid)
        videoView.backgroundColor = UIColor.orange
        
        let videoCanvas = AgoraRtcVideoCanvas()
        videoCanvas.uid = uid
        videoCanvas.view = videoView
        videoCanvas.renderMode = .hidden
        agoraKit.setupLocalVideo(videoCanvas)
        
        stackView.addArrangedSubview(videoView)
        
    }

The local video is, as explained earlier, Alice’s device camera capturing video of her and upon joining a channel, as you will see later, it streams into Bob’s phone as a remote video.

  • Add an extension to ViewController for the AgoraRtcEngineDelegate to configure the canvas or video:
func rtcEngine(_ engine: AgoraRtcEngineKit, firstRemoteVideoFrameOfUid uid: UInt, size: CGSize, elapsed: Int) {        let videoView = UIView()
        videoView.tag = Int(uid)
        videoView.backgroundColor = UIColor.purple
        
        let videoCanvas = AgoraRtcVideoCanvas()
        videoCanvas.uid = uid
        videoCanvas.view = videoView
        videoCanvas.renderMode = .hidden
        agoraKit.setupRemoteVideo(videoCanvas)
        
    }
    
    internal func rtcEngine(_ engine: AgoraRtcEngineKit, didOfflineOfUid uid:UInt, reason:AgoraUserOfflineReason) {
        
        guard let view = stackView.arrangedSubviews.first(where: { (view) -> Bool in
            return view.tag == Int(uid)
        }) else { return }
        
        stackView.removeArrangedSubview(view)
    }
    
    func rtcEngine(_ engine: AgoraRtcEngineKit, didVideoMuted muted: Bool, byUid uid: UInt) {
        //
    }

Agora’s delegate method firstRemoteVideoFrameOfUid kicks off the reception of another user’s local video or, put in another way, Alice’s local video on Bob’s device as a remote video. It is the method designed to handle the first frame coming out of a remote stream! If that UID drops off, didOfflineOfUid handles their departure and its consequences for the call.

Finally, add a call to setupVideo() in viewDidLoad().

Step Five

Last but not least is joining a channel. Users join channels with.joinChannel, a single method in the Agora iOS SDK:

func joinChannel() {
    agoraKit.setDefaultAudioRouteToSpeakerphone(true)
    agoraKit.joinChannel(byToken: nil, channelId: “demoChannel1”, info:nil, uid:0){[weak self] (sid, uid, elapsed) -> Void in
    // Join channel “demoChannel1”
    }
   UIApplication.shared.isIdleTimerDisabled = true
}

Although important for production, byToken is not important for our purposes, since Agora enables you to get up and running ASAP without having to deal with tokens by default. If you want to read more about tokens in the Agora SDK, check out the documentation or this blog.

Run

There you go! If it builds and runs, then you have successfully adopted Agora! Congratulations! Welcome to the benefits of the Agora SD-RTN™!

Although it would be impossible to account for all of the different integrations, you should note that you replaced all of the salient generic features of TokBox with those of Agora in less than five steps. Now it should be easy to simulate fully a large scale adoption with Agora. The changes that need to be made are the shift in design pattern architecture, as well as the new concepts such as local vs. remote video (as opposed to publish or subscribe) together with joining a channel. Accordingly, you probably have a few questions now about product design with respect to SDKs.

Product Design

The SD-RTN™, for instance, provides:

  1. Global network coverage
  • Covers 200+ countries and regions
  • Covers dozens of small and medium telecommunication providers in China

2. Mass access capability

  • Supports multiple intelligent terminal access
  • A single channel can support a million people online at the same time

3. QoS (Quality of Service) capability enhancement

  • Prevents network congestion in advance
  • Weak network anti-loss guarantee

4. QoS-based dynamic routing

  • Comprehensive assessment of network resources
  • QoS optimal path guarantee

5. SLA (Service Level Agreement) guarantee

  • 7 × 24 support, including ticketing system/IM/community
  • One-to-one VIP service

6. Global network reliability

  • Global network availability at 99.999%
  • Invisible core business, such as anti-DDoS

7. Compatibility and Interoperability

  • Support for 6000+ devices
  • Support for mainstream web browsers, including Google Chrome, Safari, and Firefox
  • Support for iOS, Android, the Web, Windows, macOS, Linux, CoCos, Unity, and so on

8. UDP (User Datagram Protocol) optimizationOptimizes multiple private protocols based on the UDPSelf-developed audio and video codecs

  • Efficient use of network resources
  • Self-developed SOLO and NOVA codecs

9. Anti-packet-loss optimization

  • Algorithm for optimizing anti-packet-loss mechanism under weak network conditions
  • Audio anti-packet-loss rate of 70%

With these features enabled through the SD-RTN™ natively both in the iOS as well as the Android mobile SDKs Agora provides a powerful, competitive source of live voice, video or broadcasting for your needs.

Runtime Comparison

Test it out. Although most product specialists take an ad-hoc approach to field-test their SDKs under different conditions (if at all), there is another way. Wouldn’t it be great to complete a runtime comparison? How does TokBox’s video streaming compare to Agora’s SD-RTN™ in terms of multiple levels of packet degradation? Apple’s Network Link Conditioner is a really useful utility that allows macOS and iOS devices to accurately and consistently simulate adverse networking environments (i.e., 100% Loss, 3G, DSL, EDGE, High Latency DNS, LTE, Very Bad Network, WiFi,
WiFi 802.11ac) that simulate packet degradation, or, check out the blog on successively degraded network conditions with customized packet loss.