Getting Started with Publishing

Follow these steps to add the publishing capability to your application.

1. Capture audio and video

To capture media, get an array of available audio and video sources and choose the preferred sources from the list. After you start capturing audio and video, the SDK will return an audio and video track that you can add to the publisher later.

// Configure the audio session for capturing
let session = AVAudioSession.sharedInstance()
try session.setCategory(
    .playAndRecord,
    mode: .videoChat,
    options: [.mixWithOthers, .allowBluetooth, .allowBluetoothA2DP]
)
try session.setActive(true)

// Create an audio track
var audioTrack : MCAudioTrack? = nil
if 
    let audioSources = MCMedia.getAudioSources(), // Get an array of audio sources
    !audioSources.isEmpty // There is at least one audio source
{
    // Choose the preferred audio source and start capturing
    let audioSource = audioSources[0]
    audioTrack = audioSource.startCapture() as? MCAudioTrack
}

// Create a video track
var videoTrack : MCVideoTrack? = nil
if
    let videoSources = MCMedia.getVideoSources(), // Get an array of available video sources
    !videoSources.isEmpty // There is at least one video source
{
    // Choose the preferred video source
    let videoSource = videoSources[0];
    
    // Get capabilities of the available video sources, such as
    // width, height, and frame rate of the video sources
    guard let capabilities = videoSource.getCapabilities() else {
        fatalError("No capability is available!") // In production replace with a throw
    }
    
    let capability = capabilities[0]; // Get the first capability
    videoSource.setCapability(capability);
    
    // Start video recording and create a video track
    videoTrack = videoSource.startCapture() as? MCVideoTrack
}

2. Publish a stream

Create a publisher object and set a listener object to the publisher to receive proper events. This requires creating a class that inherits the publisher's listener interface.

// A class that listens to the publisher
class PubListener : MCPublisherListener {
    func onPublishing() {}
    func onPublishingError(_ error: String!) {}
    func onConnected() {}
    func onConnectionError(_ status: Int32, withReason reason: String!) {}
    func onSignalingError(_ error: String!) {}
    func onStatsReport(_ report: MCStatsReport!) {}
    func onViewerCount(_ count: Int32) {}
    func onActive() {}
    func onInactive() {}
    func onDisconnected() {}
}

Then, create a stream in your Dolby.io developer dashboard or using the Dolby.io Streaming REST API. Use the credentials from the dashboard as presented in the following example:

// Create a publisher object
guard let publisher = MCPublisher.create() else {
    fatalError("Could not create a publisher") // In production replace with a throw
}

self.publisher = publisher // Not part of the doc

// Create an instance of your listener and set it to the publisher
let listener = PubListener();
publisher.setListener(listener)

// Get the credentials structure from your publisher instance, fill it in,
// and set the modified credentials
let credentials = MCPublisherCredentials()
credentials.apiUrl = "streamName"; // The name of the stream you want to publish
credentials.streamName = "aefea56153765316754fe"; // The publishing token
credentials.token
    = "https://director.millicast.com/api/director/publish"; // The publish API URL
                                                                
publisher.setCredentials(credentials);

3. Configure your publishing session

Get a list of the available codecs and set the codecs that you want to use. By default, the SDK uses VP8 as the video codec and Opus as the audio codec.

Additionally, to publish several sources from the same application, create a publisher instance for each source. We recommend enabling discontinuous transmission that detects audio input and sends audio only when it is detected.

let publisherOptions = MCClientOptions()

// Get a list of supported codecs
if let audioCodecs = MCMedia.getSupportedAudioCodecs() {
    // Choose the preferred audio codec
    publisherOptions.audioCodec = audioCodecs[0]
    
} else {
    print("No audio codecs available!") // In production replace with proper error handling
}

if let videoCodecs = MCMedia.getSupportedVideoCodecs() {
    // Choose the preferred video codec
    publisherOptions.videoCodec = videoCodecs[0]
    
} else {
    print("No video codecs available!") // In production replace with proper error handling
}

// To use multi-source, set a source ID of the publisher and
// enable discontinuous transmission
publisherOptions.sourceId = "MySource"
publisherOptions.dtx = true

// Enable stereo
publisherOptions.stereo = true

// Set the selected options to the publisher
publisher!.connect()
publisher!.publish(with: publisherOptions)

4. Add the audio and video track

Add the audio and video track that you created earlier when you started capturing media.

if let videoTrack = videoTrack {
    publisher.add(videoTrack)
}
if let audioTrack = audioTrack {
    publisher.add(audioTrack)
}

5. Authenticate using the Director API

Authenticate to access Dolby.io Real-time Streaming through the Director API.

guard publisher.connect() else {
    fatalError("Connection error could not connect.") // In production replace with a throw
}

6. Start publishing

Wait for the publisher to connect and then start publishing. Modify the onConnected method of the listener created in step 2.

class PubListener : MCPublisherListener {

    /* ... */

    func onConnected() {
        publisher.publish()
    }

    /* ... */
}

Note that the publisher created earlier needs to be available for the listener. The example above assumes that the listener stores a reference to that publisher in an instance variable.

Once the publisher starts sending media, the SDK calls the listener's onPublishing method.

Collecting RTC statistics

You can periodically collect the WebRTC peer connection statistics if you enable them through the enableStats method of the viewer or publisher. After enabling the statistics, you will get a report every second through the onStatsReport callback in the listener object. The identifiers and way to browse the stats are following the RTC specification.
The report contains the StatsReport object, which is a collection of several Stats objects. They all have a specific type, whether it is inbound, outbound, codec, or media. Inbound is the statistics of incoming transport for the viewer and outbound is a type of outgoing statistics for the publisher.