Creating a live broadcasting app in Swift 3 using Xcode

This guide is based on Xcode 8.0.

This guide focuses on the bare minimum required to start broadcasting. Make sure to familiarize yourself with the example apps in the SDK bundles for a more complete overview.

Create a new Application

  • Open Xcode.

  • Select File -> New -> Project...

  • Choose the Single View Application template.

  • Enter a suitable product name, your organization and identifier

  • Ensure Swift is the selected language. Or see the Objective C guide if you prefer Objective C.

Add dependencies

Installing dependencies using CocoaPods

If your development environment is set up for it, you can use CocoaPods to install the Bambuser SDK:s.

  • Prepare the newly created project for CocoaPods use with pod init.

  • Add pod 'libbambuser-ios', '0.9.19' to your Podfile.

  • Run pod install to fetch the SDK and configure the project.

Add the objective-C bridging header

As the Bambuser broadcasting SDK is written in Objective-C, we will need to add a bridging header to our Swift project.

  • Create a new Header file and add it to the project - in this example we name it libbambuser-bridge.h

  • Add the following import to the new file:

#import "libbambuser.h"
- Navigate through the project settings by selecting the project in the navigation view - Select your target and navigate to the Build Settings tab - Under the section Swift Compiler - General, edit the property named Objective-C Bridging Header and set it to the path where you created the header file. In our example it is `BroadcastDemo/libbambuser-bridge.h`

Enable camera and microphone access

Your app will not be allowed to access the camera or microphone unless its Info.plist file contains entries for Privacy - Camera Usage Description and Privacy - Microphone Usage Description.

Double-click Info.plist to bring up the editor and add them to the bottom of the list.

Install dependencies manually

The Bambuser broadcasting library has the following dependencies:

  • libz.tbd, libc++.tbd
  • AudioToolbox, AVFoundation, CoreGraphics, CoreLocation, CoreMedia, CoreVideo, Foundation, QuartzCore, SystemConfiguration, UIKit, VideoToolbox

The VideoToolbox framework is only required from iOS 8, thus it should be linked as an optional library.

Add the broadcast SDK

  • Log in to the Bambuser site and download the latest iOS SDK bundle from the Developer page.

  • Open up Finder and navigate to the download folder, then double click the SDK bundle to unzip it.

  • Drag the contents of the prebuilt/ directory from the SDK bundle into the Frameworks section of your Xcode project's file tree navigator.

  • Check Copy items if needed to ensure that your project folder gets its own copy of the files.
  • Select the newly added prebuilt group, press enter to rename it to something more descriptive.
  • The act of adding prebuilt into Frameworks should also have added libbambuser.a and libbambuserplayer.a to Linked Frameworks and Libraries under General. For the purpose of this guide, at least libbambuser.a must be linked.

Add the objective-C bridging header

As the Bambuser broadcasting SDK is written in Objective-C, we will need to add a bridging header to our Swift project.

- Drag the header to the project folder in XCode - Check copy items if needed. - Navigate through the project settings by selecting the project in the navigation view - Select your target and navigate to the Build Settings tab - Under the section Swift Compiler - General, edit the property named Objective-C Bridging Header and set it to the path where the header you copied can be found. In our example it's `BroadcastDemo/libbambuser-bridge.h`

Bootstrap the SDK

Now that you have installed the dependencies it's time to start using the SDK.

In ViewController.swift add a variable of the type BambuserView to your ViewController class.

class ViewController: UIViewController, BambuserViewDelegate {
	var bambuserView : BambuserView
	...

In ViewController.swift overide the init function of ViewController class to initialize our new variable. BambuserView requires a preset, kSessionPresetAuto is optimal for most apps.

required init?(coder aDecoder: NSCoder) {
	bambuserView = BambuserView(preparePreset: kSessionPresetAuto)
	super.init(coder: aDecoder)
}

Add the viewfinder

In ViewController.swift in the viewDidLoad method, add the viewfinder to the view hierarchy and ensure it is rotated correctly.

bambuserView.orientation = UIApplication.shared.statusBarOrientation
self.view.addSubview(bambuserView.view)

In ViewController.swift override the viewWillLayoutSubviews method, then add some code to ensure the viewfinder is assigned the desired dimensions.

override func viewWillLayoutSubviews() {
	var statusBarOffset : CGFloat = 0.0
	statusBarOffset = CGFloat(self.topLayoutGuide.length)
	bambuserView.previewFrame = CGRect(x: 0.0, y: 0.0 + statusBarOffset, width: self.view.bounds.size.width, height: self.view.bounds.size.height - statusBarOffset)
}

Start capturing frames

After all settings to BambuserView has been done, add a call to to startCapture in the viewDidLoad method.

bambuserView.startCapture()

Authentication

To be able to broadcast, your app needs to identify itself to Bambuser. Head over to the Developer page on the Bambuser site again and get the Sandbox applicationId, then assign it to BambuserView in ViewController.swift directly after initialization.

Remember to replace the Sandbox id with a Production applicationId before you release your app!

bambuserView.applicationId = "GFZalqkR5iyZcIgaolQmA"

Add a broadcasting button

Let's add a simple button to be able to control the broadcast start and stop triggers.

In ViewController.swift, add a variable of the type UIButton:

class ViewController: UIViewController {
	var bambuserView : BambuserView
	var broadcastButton : UIButton

In ViewController.swift, initialize the button in the init method.

broadcastButton = UIButton(type: UIButtonType.system)

In ViewController.swift, set up the button in the viewDidLoad method and add it to the view hierarchy.

broadcastButton.addTarget(self, action: #selector(ViewController.broadcast), for: UIControlEvents.touchUpInside)
broadcastButton.setTitle("Broadcast", for: UIControlState.normal)
self.view.addSubview(broadcastButton)

In ViewController.swift, in the viewWillLayoutSubviews method, position the button to taste

broadcastButton.frame = CGRect(x: 0.0, y: 0.0 + statusBarOffset, width: 100.0, height: 50.0);

Also add a new method to handle button taps

func broadcast() {
	NSLog("Starting broadcast")
	broadcastButton.setTitle("Connecting", for: UIControlState.normal)
	broadcastButton.removeTarget(nil, action: nil, for: UIControlEvents.touchUpInside)
	broadcastButton.addTarget(bambuserView, action: #selector(bambuserView.stopBroadcasting), for: UIControlEvents.touchUpInside)
	bambuserView.startBroadcasting()
}

Subscribe to events

To know what's going on inside BambuserView, we should hook up ourself as its delegate. In ViewController.swift, assign self to bambuserView.delegate directly after initializing our superclass:

bambuserView.delegate = self;

In ViewController.swift, we now need to declare that our class supports the BambuserViewDelegate protocol:

class ViewController: UIViewController, BambuserViewDelegate {

Finally, we add a few callback methods in ViewController.swift:

func broadcastStarted() {
	NSLog("Received broadcastStarted signal")
	broadcastButton.setTitle("Stop", for: UIControlState.normal)
	broadcastButton.removeTarget(nil, action: nil, for: UIControlEvents.touchUpInside)
	broadcastButton.addTarget(bambuserView, action: #selector(bambuserView.stopBroadcasting), for: UIControlEvents.touchUpInside)
}
	func broadcastStopped() {
	NSLog("Received broadcastStopped signal")
	broadcastButton.setTitle("Broadcast", for: UIControlState.normal)
	broadcastButton.removeTarget(nil, action: nil, for: UIControlEvents.touchUpInside)
	broadcastButton.addTarget(self, action: #selector(ViewController.broadcast), for: UIControlEvents.touchUpInside)
}

Putting it all together

The above steps should lead to a main view source somewhat along these lines:

ViewController.swift

import UIKit

class ViewController: UIViewController, BambuserViewDelegate {
	var bambuserView : BambuserView
	var broadcastButton : UIButton
	required init?(coder aDecoder: NSCoder) {
		bambuserView = BambuserView(preparePreset: kSessionPresetAuto)
		bambuserView.delegate = self
		bambuserView.applicationId = "GFZalqkR5iyZcIgaolQmA"
		broadcastButton = UIButton(type: UIButtonType.system)
		super.init(coder: aDecoder)
	}
	override func viewDidLoad() {
		super.viewDidLoad()
		// Do any additional setup after loading the view, typically from a nib.
		bambuserView.orientation = UIApplication.shared.statusBarOrientation
		self.view.addSubview(bambuserView.view)
		bambuserView.startCapture()

		broadcastButton.addTarget(self, action: #selector(ViewController.broadcast), for: UIControlEvents.touchUpInside)
		broadcastButton.setTitle("Broadcast", for: UIControlState.normal)
		self.view.addSubview(broadcastButton)
	}

	override func viewWillLayoutSubviews() {
		var statusBarOffset : CGFloat = 0.0
		statusBarOffset = CGFloat(self.topLayoutGuide.length)
		bambuserView.previewFrame = CGRect(x: 0.0, y: 0.0 + statusBarOffset, width: self.view.bounds.size.width, height: self.view.bounds.size.height - statusBarOffset)
		broadcastButton.frame = CGRect(x: 0.0, y: 0.0 + statusBarOffset, width: 100.0, height: 50.0);
	}

	override func didReceiveMemoryWarning() {
		super.didReceiveMemoryWarning()
		// Dispose of any resources that can be recreated.
	}

	func broadcast() {
		NSLog("Starting broadcast")
		broadcastButton.setTitle("Connecting", for: UIControlState.normal)
		broadcastButton.removeTarget(nil, action: nil, for: UIControlEvents.touchUpInside)
		broadcastButton.addTarget(bambuserView, action: #selector(bambuserView.stopBroadcasting), for: UIControlEvents.touchUpInside)
		bambuserView.startBroadcasting()
	}

	func broadcastStarted() {
		NSLog("Received broadcastStarted signal")
		broadcastButton.setTitle("Stop", for: UIControlState.normal)
		broadcastButton.removeTarget(nil, action: nil, for: UIControlEvents.touchUpInside)
		broadcastButton.addTarget(bambuserView, action: #selector(bambuserView.stopBroadcasting), for: UIControlEvents.touchUpInside)
	}

	func broadcastStopped() {
		NSLog("Received broadcastStopped signal")
		broadcastButton.setTitle("Broadcast", for: UIControlState.normal)
		broadcastButton.removeTarget(nil, action: nil, for: UIControlEvents.touchUpInside)
		broadcastButton.addTarget(self, action: #selector(ViewController.broadcast), for: UIControlEvents.touchUpInside)
	}
}

Testing in the simulator

Since the iOS Simulator does not feature a camera, what you can do there is limited.

Testing on a device

How to configure Xcode for ad-hoc development is out of scope for this guide. Assuming you have all the required privileges, you should be able to tether your iOS device to Xcode and click run.

If everything is set up correctly, you should be able to start your first broadcast by tapping the button we added earlier.

Check the Bambuser site when logged in for a notification and web preview when you go live in Sandbox mode.

This is how it looks on the phone

Tap the button to start a broadcast.

Screenshot 1-2: The first time, iOS asks the user for camera and microphone access.

Screenshot 3: Then the broadcast is running and the button turns into a stop button.

Screnshot 4: Finally, we tap the button again and return to the non-broadcasting state.

What's next

  • Be sure to experience a few of your live broadcasts via the Sandbox player on the Bambuser website.

  • Consider whether you also need a player in your app and / or on your website.

  • Study the REST APIs and Webhooks, which can be used to make your backend broadcast-aware.