developer
interactivity
Setup a Live Stream with Dolby.io and Mux
Fabien Lavocat

Mux.com allows you to pilot your live streams either through their dashboard or using REST API calls. In this article I will show you how to first use the Mux dashboard to create your first live stream, then I will share some C# code to illustrate how to call the Mux REST APIs and the Dolby.io APIs to start a new live stream programmatically.

Using the Mux Dashboard

Log into your Mux account and go to the VIDEO and Live Streams section.

On the Live Streams page, click on Create New Live Stream.

In the POST body editor, you can configure your live stream; check the Mux Reference documentation for more information on configuration settings. You can leave the default to start. Click the Run Request button.

Click on View Live Stream.

Click on Show Stream Key and copy it. You will need it to generate the URL of where to send the RTMP stream to. Now, during your conference, you will need to make a REST API call to the Dolby API with the URL of the RTMP endpoint, e.g. rtmps://global-live.mux.com:443/app/11111111-aaaa-2222-bbbb-333333333333

curl https://session.voxeet.com/v1/api/conferences/mix/{conference_id}/live/start \
    -H "Content-Type: application/json" \
    -X POST \
    -d '{ "uri": "rtmps://global-live.mux.com:443/app/{stream_key}" }' \
    -u {DOLBY_CONSUMER_KEY}:{DOLBY_CONSUMER_SECRET}

A few seconds after calling the API, you will be able to see the live stream starting on the Live Stream page.

If you need to stop the live stream before the conference ends, call the following API:

curl https://session.voxeet.com/v1/api/conferences/mix/{conference_id}/live/stop \
    -H "Content-Type: application/json" \
    -X POST \
    -u {DOLBY_CONSUMER_KEY}:{DOLBY_CONSUMER_SECRET}

Note: if the conference you want to live stream is protected using enhanced conference access control, you must use a conference access token to authenticate against the APIs and point to the /v2/ endpoints (Documentation).

Using REST APIs with C#

Log into your Mux account as an administrator and go to the VIDEO and Get Started section.

Click the button Create an API Access Token, then select the environment you wish to use for your live stream. In the permissions section, for Mux Video, select Full Access. Provide a name for this token and click Generate Token. Keep this access token secure, do not expose it in your source code. Follow the Mux documentation.

Setup of the C# Code

Install the NuGet package Newtonsoft to parse the JSON payload.

Use the following imports in your C# file:

using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;

Create an HttpClient in order to make the REST API calls to both Mux.com and Dolby.io.

private static readonly HttpClient httpClient = new HttpClient();

Call the Mux API

This is the description of the payload message we will receive from the Mux API.

public sealed class DataResponse<T>
{
    [JsonProperty("data")]
    public T Data { get; set; }
}
 
public sealed class CreateLiveStreamResponse
{
    [JsonProperty("id")]
    public string Id { get; set; }
 
    [JsonProperty("stream_key")]
    public string StreamKey { get; set; }
}

This function will create the live stream on Mux and return the RTMP endpoint URL.

/// <summary>
/// Creates a new live stream on mux.com.
/// </summary>
/// <param name="accessTokenId">Mux Access Token ID.</param>
/// <param name="secretKey">Mux Secret Key.</param>
/// <returns>URL of the RTMP endpoint.</returns>
public async Task<string> CreateLiveStreamAsync(string accessTokenId, string secretKey)
{
    // URL where to send the creation request
    const string url = "https://api.mux.com/video/v1/live-streams";
 
    // Payload to use to create and configure the live stream
    // Reference: https://docs.mux.com/reference#create-a-live-stream
    const string json = "{ \"playback_policy\": [\"public\"], \"new_asset_settings\": { \"playback_policy\": [\"public\"] } }";
 
    try
    {
        HttpRequestMessage httpRequest = new HttpRequestMessage(HttpMethod.Post, url);
 
        // Generate the Authorization header for the HTTP request
        byte[] bytes = Encoding.UTF8.GetBytes($"{accessTokenId}:{secretKey}");
        string base64 = Convert.ToBase64String(bytes);
        httpRequest.Headers.TryAddWithoutValidation("Authorization", $"Basic {base64}");
 
        httpRequest.Content = new StringContent(json, Encoding.UTF8, "application/json");
 
        using HttpResponseMessage response = await httpClient.SendAsync(httpRequest);
        response.EnsureSuccessStatusCode();
 
        string strResponse = await response.Content.ReadAsStringAsync();
        DataResponse<CreateLiveStreamResponse> createLiveStreamResponse =
            JsonConvert.DeserializeObject<DataResponse<CreateLiveStreamResponse>>(strResponse);
 
        // Generate the RTMP endpoint URL
        // Source: https://docs.mux.com/docs/live-streaming#2-start-broadcasting
        return $"rtmps://global-live.mux.com:443/app/{createLiveStreamResponse.Data.StreamKey}";
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Exception: {ex.Message}");
        throw;
    }
}

Call the Dolby.io APIs for Enhanced Conference Access Control

If the conference you want to live stream is protected using enhanced conference access control, you must follow this section. Otherwise, jump to the next section.

First, create the function to request a conference access token that we will use for the REST API calls on dolby.io (Documentation).

/// <summary>
/// Requests a conference access token.
/// </summary>
/// <param name="consumerKey">Dolby.io Consumer Key.</param>
/// <param name="consumerSecret">Dolby.io Consumer Secret.</param>
/// <returns>The access token to use to call the APIs.</returns>
private async Task<string> GetAccessTokenAsync(string consumerKey, string consumerSecret)
{
    const string url = "https://api.voxeet.com/v1/auth/token";
    const string json = "{ \"grant_type\": \"client_credentials\" }";
 
    try
    {
        HttpRequestMessage httpRequest = new HttpRequestMessage(HttpMethod.Post, url);
 
        // Generate the Authorization header for the HTTP request
        byte[] bytes = Encoding.UTF8.GetBytes($"{consumerKey}:{consumerSecret}");
        string base64 = Convert.ToBase64String(bytes);
        httpRequest.Headers.TryAddWithoutValidation("Authorization", $"Basic {base64}");
 
        httpRequest.Content = new StringContent(json, Encoding.UTF8, "application/json");
 
        using HttpResponseMessage response = await httpClient.SendAsync(httpRequest);
        response.EnsureSuccessStatusCode();
 
        string strResponse = await response.Content.ReadAsStringAsync();
        JwtToken jwtToken = JsonConvert.DeserializeObject<JwtToken>(strResponse);
 
        return jwtToken.AccessToken;
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Exception: {ex.Message}");
        throw;
    }
}
 
public class JwtToken
{
    [JsonProperty("access_token")]
    public string AccessToken { get; set; }
 
    [JsonProperty("expires_in")]
    public int ExpiresIn { get; set; }
 
    [JsonProperty("token_type")]
    public string TokenType { get; set; }
}

Now here are the functions to start and stop the RTMP stream.

/// <summary>
/// Starts an RTMP stream.
/// </summary>
/// <param name="consumerKey">Dolby.io Consumer Key.</param>
/// <param name="consumerSecret">Dolby.io Consumer Secret.</param>
/// <param name="conferenceId">Conference identifier.</param>
/// <param name="rtmpUrl">URL of the RTMP endpoint.</param>
public async Task StartRtmpStreamAsync(string consumerKey, string consumerSecret, string conferenceId, string rtmpUrl)
{
    string url = $"https://api.voxeet.com/v2/conferences/mix/{conferenceId}/rtmp/start";
    string json = $"{{ \"uri\": \"{rtmpUrl}\" }}";
 
    try
    {
        HttpRequestMessage httpRequest = new HttpRequestMessage(HttpMethod.Post, url);
 
        // Generate the Authorization header for the HTTP request
        string accessToken = await GetAccessTokenAsync(consumerKey, consumerSecret);
        httpRequest.Headers.TryAddWithoutValidation("Authorization", $"Bearer {accessToken}");
 
        httpRequest.Content = new StringContent(json, Encoding.UTF8, "application/json");
 
        using HttpResponseMessage response = await httpClient.SendAsync(httpRequest);
        response.EnsureSuccessStatusCode();
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Exception: {ex.Message}");
        throw;
    }
}
 
/// <summary>
/// Stops an RTMP live stream.
/// </summary>
/// <param name="consumerKey">Dolby.io Consumer Key.</param>
/// <param name="consumerSecret">Dolby.io Consumer Secret.</param>
/// <param name="conferenceId">Conference identifier.</param>
public async Task StopRtmpStreamAsync(string consumerKey, string consumerSecret, string conferenceId)
{
    string url = $"https://api.voxeet.com/v2/api/conferences/mix/{conferenceId}/live/stop";
 
    try
    {
        HttpRequestMessage httpRequest = new HttpRequestMessage(HttpMethod.Post, url);
 
        // Generate the Authorization header for the HTTP request
        string accessToken = await GetAccessTokenAsync(consumerKey, consumerSecret);
        httpRequest.Headers.TryAddWithoutValidation("Authorization", $"Bearer {accessToken}");
 
        using HttpResponseMessage response = await httpClient.SendAsync(httpRequest);
        response.EnsureSuccessStatusCode();
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Exception: {ex.Message}");
        throw;
    }
}

Call the Dolby.io APIs Regular Conferences

If the conference you want to live stream is not protected using enhanced conference access control, you must follow this section. The only difference in the code that follows is around the authentication. We will use Basic authentication for the API calls.

/// <summary>
/// Starts an RTMP live stream.
/// </summary>
/// <param name="consumerKey">Dolby.io Consumer Key.</param>
/// <param name="consumerSecret">Dolby.io Consumer Secret.</param>
/// <param name="conferenceId">Conference identifier.</param>
/// <param name="rtmpUrl">URL of the RTMP endpoint.</param>
public async Task StartRtmpStreamAsync(string consumerKey, string consumerSecret, string conferenceId, string rtmpUrl)
{
    string url = $"https://session.voxeet.com/v1/api/conferences/mix/{conferenceId}/live/start";
    string json = $"{{ \"uri\": \"{rtmpUrl}\" }}";
 
    try
    {
        HttpRequestMessage httpRequest = new HttpRequestMessage(HttpMethod.Post, url);
 
        // Generate the Authorization header for the HTTP request
        byte[] bytes = Encoding.UTF8.GetBytes($"{consumerKey}:{consumerSecret}");
        string base64 = Convert.ToBase64String(bytes);
        httpRequest.Headers.TryAddWithoutValidation("Authorization", $"Basic {base64}");
 
        httpRequest.Content = new StringContent(json, Encoding.UTF8, "application/json");
 
        using HttpResponseMessage response = await httpClient.SendAsync(httpRequest);
        response.EnsureSuccessStatusCode();
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Exception: {ex.Message}");
        throw;
    }
}
 
/// <summary>
/// Stops an RTMP live stream.
/// </summary>
/// <param name="consumerKey">Dolby.io Consumer Key.</param>
/// <param name="consumerSecret">Dolby.io Consumer Secret.</param>
/// <param name="conferenceId">Conference identifier.</param>
public async Task StopRtmpStreamAsync(string consumerKey, string consumerSecret, string conferenceId)
{
    string url = $"https://session.voxeet.com/v1/api/conferences/mix/{conferenceId}/live/stop";
 
    try
    {
        HttpRequestMessage httpRequest = new HttpRequestMessage(HttpMethod.Post, url);
 
        // Generate the Authorization header for the HTTP request
        byte[] bytes = Encoding.UTF8.GetBytes($"{consumerKey}:{consumerSecret}");
        string base64 = Convert.ToBase64String(bytes);
        httpRequest.Headers.TryAddWithoutValidation("Authorization", $"Basic {base64}");
 
        using HttpResponseMessage response = await httpClient.SendAsync(httpRequest);
        response.EnsureSuccessStatusCode();
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Exception: {ex.Message}");
        throw;
    }
}

Test Your Code

Now that the code is ready, create a conference in your environment and call the different functions to create a live stream on Mux then start and stop the broadcast. After a few seconds, you will see the conference being broadcasted on Mux.com and a minute later it will stop.

public async Task StartAndStopAsync(string conferenceId)
{
    // Store these credentials somewhere safe
    const string MUX_ACCESS_TOKEN_ID = "";
    const string MUX_SECRET_KEY = "";
    const string DOLBY_CONSUMER_KEY = "";
    const string DOLBY_CONSUMER_SECRET = "";
 
    // Create the Live Stream on Mux.com and get the RTMP URL
    string rtmpsUrl = await CreateLiveStreamAsync(MUX_ACCESS_TOKEN_ID, MUX_SECRET_KEY);
 
    // Start the RTMP streaming from Dolby.IO to Mux.com
    await StartRtmpStreamAsync(DOLBY_CONSUMER_KEY, DOLBY_CONSUMER_SECRET, conferenceId, rtmpsUrl);
 
    // Wait a minute before stopping the RTMP stream
    System.Threading.Thread.Sleep(60 * 1000);
 
    // Stop the RTMP stream
    await StopRtmpStreamAsync(DOLBY_CONSUMER_KEY, DOLBY_CONSUMER_SECRET, conferenceId);
}

Conclusion

You can find the source code for this sample project here:

https://github.com/dolbyio-samples/blog-rtmp-mux

Look for more samples soon for integrating your video conferences with various streaming platforms over RTMP.

Tags: c#, rtmp
RELATED POSTS
DEVELOPER
MEDIA
Recording Audio on Android with Examples

How-to get started recording audio on Android with the most common libraries compared.

Megan Ren
|
android
DEVELOPER
INTERACTIVITY
Generate Access Tokens Using AWS Services

Tips to secure your API Key by using AWS services to generate initialization tokens.

Katie Gray
|
aws
security
INTERACTIVITY
PRODUCT
To Build the Best Web Conferencing Tool, Use a Product Roadmap

Strategies and product methodologies to build a web conferencing application that users will love.

Dolby.io
|
We're happy to chat about our APIs, SDKs...or magic.