Backendless Support
 

Developing an iOS Video Recorder and Player on Swift in 15 minutes

Video broadcasting and streaming is one of the coolest features of Backendless. Our Media Service API enables client-server functionality for working with live and on-demand audio and video content. A mobile application which uses the Media Service API can broadcast audio and video from the device's cameras and microphone. Backendless automatically handles streaming of the received media content to other clients or recording of the content on the server. The API can also support the capability to stream a pre-recorded (on-demand) content managed by the Media Service. More details about these features are available in the Media Service documentation.

This article describes how to build an iOS application using the Swift language. The app will record a video on the server and then subsequently play it back.

Download Backendless SDK for iOS

1. Login to the Backendless account or register to create a new one.

2. Download Backendless SDK for iOS from the  Backendless SDK Downloads page and unzip it.

Create an XCode Project

To start developing IOS Video Recorder  and Player it is necessary   to create a project in XCode:

  1. Navigate to File->New->Project
  2. Select iOS -> Single View Application and click Next button
  3. Enter application name for e.g. SimpleVideoService.
  4. Set the Language to Swift.
  5. Choose iPhone device (make sure Use Core Data is not checked) and click Next.
  6. Choose a location for your project and click Create.

To see what Xcode has built, select  iPhone 6 Simulator in the upper left corner of Xcode and click Play to test the app.  A blank white screen will appear. Xcode has created a single blank screen in the app.

Adding Libraries and Frameworks

In this step it will be necessary to add the appropriate libraries and frameworks:

  1. Find the SimpleVideoService target, go to Build Phases->Link Binary With Libraries, click “+” and choose the following iOS frameworks and libraries by clicking Add:
    • SystemConfiguration.framework
    • libsqlite3.dylib
    • libz.dylib
  2. Mark the project and choose File->”Add Files to …” menu item: 
  3. Choose the “lib” folder from the SDK folder. Notice that the “Add to targets” checkbox must be checked. Push “Add” button.
  4. Make sure the complete list includes the following:

Swift to Objective-C Bridge

For using Objective-C static libraries from Swift the Bridging Header File will be in need. To add Bridging Header File follow the next steps:

  1. Add Bridging-Header.h to project and include the following code to it:
  2. Add Bridging-Header.h to Build Settings:

Backendless Application ID and Secret Key

Once all the steps above are completed, a developer should add the Backendless Application Id & Secret Key:

  1. Register and Login to the Backendless backend (Backendless Console)
  2. Get the Backendless application and secret keys for iOS from the Backendless Console. The keys can be found on the Manage -> App Settings section:
  3. Add Backendless application initialization code block to AppDelegate.swift:

 @UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
 let APP_ID = "-YOUR-APPLICATION-ID-”
 let SECRET_KEY = "-YOUR-APPLICATION-IOS-SECRET-KEY-"
 let VERSION_NUM = "v1"
 var backendless = Backendless.sharedInstance()
 var window: UIWindow?
 func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
 //DebLog.setIsActive(true)
 backendless.initApp(APP_ID, secret:SECRET_KEY, version:VERSION_NUM)
 backendless.setThrowException(false)
 backendless.mediaService = MediaService()
 return true
 }
 . . .
}

The next step is to create the user interface for the iOS app  which is referred to as  a Storyboard. Xcode comes with a built-in tool called Interface Builder that allows to edit Storyboards in a nice, visual way. With Interface Builder, a developer can lay out all of the buttons, text fields, labels, and other controls in your app (called Views) as simply as dragging and dropping individual controls.

There’s a lot of stuff to cover here, so let’s go over each section of the screen one at a time.

  • On the far left is your Project Navigator, where the files in your project are listed.
  • On the left of Interface Builder is your Document Outline, where a developer can see at a glance the views inside each “screen” of your app (view controllers). Be sure to click the “down” arrows next to each item to fully expand the document outline. Right now the app only has one view controller, with only one empty white view. You’ll be adding things into this soon.
  • There’s an arrow to the left of your view controller. This indicates that this is the initial view controller, or the view controller that is first displayed when the app starts up.It is possible to change this by dragging the arrow to a different view controller, or by clicking the “Is Initial View Controller” property on a different view controller in the Attributes.
  • On the bottom of the Interface Builder it will be shown something that says “w Any”, “h Any”. This means that a developer is editing the layout for the app in a way that should work on any sized user interface. It can be accomplished through the power of something called Auto Layout. By clicking this area, a developer can switch to editing the layout for devices of specific size classes.
  • On the top of your view controller you’ll see three small icons, which represent the view controller itself and two other items: First Responder, and Exit. If you’ve been developing in Xcode for a while, you’ll notice that these have moved (they used to be below the view controller).
  • On the bottom right of Interface Builder are four icons related to Auto Layout. This issue will be described below. 
  • On the upper right of Interface Builder are the Inspectors for whatever has been selected in the Document Outline. If the inspectors are not shown, go to View->Utilities->Show Utilities. Note there are several tabs of inspectors. These will be used a lot to configure the views you add to this project.
  • On the bottom right of Interface Builder are the Libraries. This is a list of different types of views or view controllers that can be added to the app. Soon a developer will be dragging items from the library into the view controller to lay out the app.

Creating the Views

The application should have the following UI elements:

    • Text Field for stream name typing,
    • Switch with label “Live” to control live/record streaming mode,
    • View for published stream reviewing,
    • Image View for playback stream viewing,
    • the four Buttons: “Publish”, “Playback”, “Stop” and “Switch Cameras”.

Let’s build this user interface one piece at a time.

  • Navigation Bar. Rather than adding a navigation bar directly, select the view controller and go to Editor->Embed In->Navigation Controller. This will set up a Navigation Bar in the view controller. Double click the Navigation Bar (the one inside the view controller), and set the text to “Backendless Video Service”.
  • Text Field. From the Object Library, drag a Text Field into the view controller. In the Attributes Inspector (the Inspector‘s fourth tab) set Placeholder=”Stream Name”. In the Size Inspector (the Inspector‘s fifth tab) set X=19, Y=70, Width=192 and Height=30.
  • Label. From the Object Library, drag a Label into the view controller. Double click the label and set its text to “Live”. Select the label, and in the Size Inspector set X=219, Y=70, Width=42 and Height=30.
  • Switch. From the Object Library, drag a Switch into the view controller. In the Attribute Inspector, set State=On. In the Size Inspector set X=257 and Y=70.
  • View. From the Object Library, drag a View into the view controller. In the Attributes Inspector set Hidden=switch on. In the Size Inspector set X=0, Y=110, Width=320 and Height=450.
  • Image View. From the Object Library, drag a Image View into the view controller. In the Attributes Inspector set Hidden=switch on. In the Size Inspector set X=0, Y=110, Width=320 and Height=450.
  • Button “Publish”. From the Object Library, drag a Button into the view controller. Double click the Button, and set the text to “Publish”. In the Size Inspector set X=16, Y=562, Width=65 and Height=30.
  • Button “Playback”. From the Object Library, drag a Button into the view controller. Double click the Button, and set the text to “Playback”. In the Size Inspector set X=116, Y=562, Width=69 and Height=30.
  • Button “Stop”. From the Object Library, drag a Button into the view controller. Double click the Button, and set the text to “Stop”. In the Attributes Inspector set Hidden=switch on. In the Size Inspector set X=73, Y=562, Width=46 and Height=30.
  • Button “Switch Cameras”. From the Object Library, drag a Button into the view controller. Double click the Button, and set the text to “Switch Cameras”. In the Attributes Inspector set Hidden=switch on. In the Size Inspector set X=188, Y=562, Width=118 and Height=30.
  • Activity Indicator View. From the Object Library, drag an Activity Indicator View into the view controller. In the Attributes Inspector set Style=Gray, Hides When Stopped=switch on and Hidden=switch on. In the Size Inspector set X=150, Y=274, Width=20 and Height=20.
  • Tap Gesture Recognizer. From the Object Library, drag a Tap Gesture Recognizer onto the main view. This will be used to tell when the user taps the view to dismiss the keyboard.
  • Auto Layout. Interface Builder can often do a great job setting up reasonable Auto Layout constraints fora developer automatically; and it definitely can in this case. To do this, click on the third button in the lower left of the Interface Builder (which looks like a Tie Fighter) and select Add Missing Constraints.

Build and run on your iPhone 6 simulator, and a basic user interface will be shown working already!

Together with the possibilities above it is possible to add some properties for its subviews, and hook them up in interface builder:

Add these following properties to your ViewController class right before viewDidLoad() method:
@IBOutlet var btnPublish : UIButton!
@IBOutlet var btnPlayback : UIButton!
@IBOutlet var btnStopMedia : UIButton!
@IBOutlet var btnSwapCamera : UIButton!
@IBOutlet var preView : UIView!
@IBOutlet var playbackView : UIImageView!
@IBOutlet var textField : UITextField!
@IBOutlet var lblLive : UILabel!
@IBOutlet var switchView : UISwitch!
@IBOutlet var netActivity : UIActivityIndicatorView!

And now we'll connect these properties to the user interface elements.

Open Main.storyboard and select your View Controller named “Backendless Video Service” in the Document Outline. Open the Connections Inspector (the Inspector‘s sixth tab), and a developer will see all of the created properties listed in the Outlets section.

A small circle will appear to the right of  btnPlayback. Control-drag from that button down to the “Playback” button, and release to connect the Swift property to this view.

Now repeat this for the other properties, connecting each one to the appropriate UI element:

  • btnPublish to “Publish” button,
  • btnStopMedia to “Stop” button,
  • btnSwapCamera to “Switch Cameras” button,
  • lblLive to “Live” label,
  • netActivity to Gray Activity Indicator,
  • playbackView to Image View,
  • preview to View,
  • switchView to Switch,
  • textField to “Stream Name” text field.

And finally, in Referencing Outlets section you can see delegate property. Control-drag from its small circle to “Stream Name” text field allowing the View Controller to process UITextFieldDelegate callbacks.

Connecting Actions to View Controller

Just like the views were connected to properties on the view controller, a developer needs to connect certain actions from your views (such as a button click) to methods on your view controller. To do this, open ViewController.swift and add these five new methods in the bottom of class:

@IBAction func switchCamerasControl(sender: AnyObject) {
}
@IBAction func stopMediaControl(sender: AnyObject) {
}
@IBAction func playbackControl(sender: AnyObject) {
}
@IBAction func publishControl(sender: AnyObject) {
}
@IBAction func viewTapped(sender: AnyObject) {
}

To make Interface Builder notice the new methods, you need to mark these methods with the @IBAction .

Then switch back to Main.storyboard and make sure that the view controller is selected in the Document Outline. The Connections Inspector should be opened (the Inspector‘s sixth tab) and a developer will see your new methods listed in the Received Actions section.

Find the circle to the right of playbackControl:, and drag a line from that circle up to the “Playback” button. In the popup that appears, choose “Touch Up Inside:”. This is effectively saying “when the user releases their finger from the screen when over the button, call my method playbackControl:“.

Now repeat this for the other methods:

  • Drag a line from publishControl: to the “Publish” button, and choose “Touch Up Inside:”,
  • Drag a line from stopMediaControl: to the “Stop” button, and choose “Touch Up Inside:”,
  • Drag a line from switchCamerasControl: to the “Switch Cameras” button, and choose “Touch Up Inside:”,
  • Drag from viewTapped: to the Tap Gesture Recognizer in the document outline. There are no actions to choose from for gesture recognizers; your method will simply be called with the recognizer is triggered.

Add Backendless MediaService Elements

  1. Add the UITextFieldDelegate and IMediaStreamerDelegate protocols to ViewController class just after UIViewController class name:
    class ViewController: UIViewController, UITextFieldDelegate, IMediaStreamerDelegate {
    
  2. Declare the following variables and constant just after outlets declaration:
    var backendless = Backendless.sharedInstance()
    var _publisher: MediaPublisher?
    var _player: MediaPlayer?
    let VIDEO_TUBE = "videoTube"
    
  3. Implement publishControl action to start the live/record stream publishing:
    @IBAction func publishControl(sender: AnyObject) {
     var options: MediaPublishOptions
     if (switchView.on) {
     options = MediaPublishOptions.liveStream(self.preView) as MediaPublishOptions
     }
     else {
     options = MediaPublishOptions.recordStream(self.preView) as MediaPublishOptions
     }
     options.orientation = .Portrait
     options.resolution = RESOLUTION_CIF
     _publisher = backendless.mediaService.publishStream(textField.text, tube:VIDEO_TUBE, options:options, responder:self)
     self.btnPublish.hidden = true
     self.btnPlayback.hidden = true
     self.textField.enabled = false
     self.switchView.enabled = false
     self.netActivity.startAnimating()
    }
    

    An “options” instance of MediaPublishOptions sets the publishing mode (live or record) according to switchView state, orientation and resolution values for the stream, and the UIView instance reference that will show the video being published.

    The publisher constructor accepts stream name, a tube name, options and a responder. Since the responder is set to self, the ViewController class must implement IMediaStreamerDelegate protocol.

  4. Implement playbackControl action to start the stream playing:
    @IBAction func playbackControl(sender: AnyObject) {
     var options: MediaPlaybackOptions
     if (switchView.on) {
     options = MediaPlaybackOptions.liveStream(self.playbackView) as MediaPlaybackOptions
     }
     else {
     options = MediaPlaybackOptions.recordStream(self.playbackView) as MediaPlaybackOptions
     }
     options.orientation = .Up
     options.isRealTime = switchView.on
     _player = backendless.mediaService.playbackStream(textField.text, tube:VIDEO_TUBE, options:options, responder:self)
     self.btnPublish.hidden = true
     self.btnPlayback.hidden = true
     self.textField.enabled = false
     self.switchView.enabled = false
     self.netActivity.startAnimating()
    }
    

    An “options” instance of MediaPlaybackOptions sets the playing mode (live or record) according to switchView state, orientation and isRealTime values for the stream, and the UIImageView instance reference that will show the played video. The player constructor accepts stream name, a tube name, options and a responder.

  5. Implement switchCamerasControl action to switch the publishing stream between the front and back cameras:
    @IBAction func switchCamerasControl(sender: AnyObject) {
     _publisher?.switchCameras()
    }
    
  6. Implement stopMediaControl action to stop the stream publishing / playing:
    @IBAction func stopMediaControl(sender: AnyObject) {
     if (_publisher != nil) {
     _publisher?.disconnect()
     _publisher = nil;
     self.preView.hidden = true
     self.btnStopMedia.hidden = true
     self.btnSwapCamera.hidden = true
     }
     if (_player != nil)
     {
     _player?.disconnect()
     _player = nil;
     self.playbackView.hidden = true
     self.btnStopMedia.hidden = true
     }
     self.btnPublish.hidden = false
     self.btnPlayback.hidden = false
     self.textField.enabled = true
     self.switchView.enabled = true
     self.netActivity.stopAnimating()
    }
    

    When the user pushes “Stop” button, this action checks if mode is currently publishing or playing the video, then disconnect from the stream and set the publisher or player to nil.

  7.  Implement viewTapped() action and textFieldShouldReturn() method of UITextFieldDelegate protocol to dismiss the keyboard after stream name typing is finished:
    @IBAction func viewTapped(sender: AnyObject) {
     textField.resignFirstResponder()
    }
    // UITextFieldDelegate protocol methods
    func textFieldShouldReturn(_textField: UITextField) {
     textField.resignFirstResponder()
    }
    
  8. And finally, implement IMediaStreamerDelegate protocol methods  to handle the stream state changes and errors:
    func streamStateChanged(sender: AnyObject!, state: Int32, description: String!) {
    switch state {
    case 0: //CONN_DISCONNECTED
    stopMediaControl(sender)
    return
    case 1: //CONN_CONNECTED
    return
    case 2: //STREAM_CREATED
    self.btnStopMedia.hidden = false
    return
    case 3: //STREAM_PLAYING
    // PUBLISHER
    if (_publisher != nil) {
    if (description != "NetStream.Publish.Start") {
    stopMediaControl(sender)
    return
    }
    self.preView.hidden = false
    self.btnSwapCamera.hidden = false
    netActivity.stopAnimating()
    }
    // PLAYER
    if (_player != nil) {
    if (description == "NetStream.Play.StreamNotFound") {
    stopMediaControl(sender)
    return
    }
    if (description != "NetStream.Play.Start") {
    return
    }
    self.playbackView.hidden = false
    netActivity.stopAnimating()
    }
    return
    case 4: //STREAM_PAUSED
    if (description == "NetStream.Play.StreamNotFound") {
    }
    stopMediaControl(sender)
    return
    default:
    return
    }
    }
     func streamConnectFailed(sender: AnyObject!, code: Int32, description: String){ stopMediaControl(sender) }
    

    The sample code can be downloaded  here.

Is article helpful?