Live streaming (Beta)

Cloudinary provides an end-to-end live video streaming solution, with on-the-fly video effects and transformations via a JavaScript library. The solution is based on WebRTC, which is great for device compatibility and makes it most suitable for embedding in your own web or mobile application, allowing your users to start live streaming from any device.

Important
Live Streaming is currently in BETA. There may be minor changes to parameter names or other implementation details before the general access release. We invite you to try it out. We would appreciate any feedback via our support team.

This guide describes cloudinary-js-streaming version 1.2.0.

The live streaming workflow using Cloudinary is:

  1. The video is streamed from the user's device camera.
  2. The video is up-streamed through Cloudinary (including any pre-configured transformations and effects), providing the streaming user with a Cloudinary public ID and resource URL.
  3. The stream is now publicly available through that URL, and can be fed into any streaming-supported video player.

Take a look at our live streaming demo to try it out for yourself.

Installation

Install the library using npm:

Copy to clipboard
npm install @cloudinary/js-streaming

Setup

1. Create a new live streaming upload preset

Create a new unsigned upload preset or modify an existing one to set live broadcast to true. You can do this using either the Admin API by setting the live parameter to 'true' or management console, in the Storage and Access section, turn on live broadcast. You can also add any effects and transformations to your stream using the Incoming transformations section under Upload Manipulations.

Caution
Adding transformations that affect video duration will cause errors with your live streaming.

You can also configure your upload preset to use a streaming profile. You can use a streaming profile to define your adaptive bitrate streaming settings for your users.

2. Import the library

Copy to clipboard
import {initLiveStream} from '@cloudinary/js-streaming'

Alternatively, if you didn't install with NPM, you can include the file in your HTML page and then load it in your javascript. For example:

In your HTML:

Copy to clipboard
<script src="https://unpkg.com/@cloudinary/js-streaming/dist/js-streaming.js"></script>

In your JavaScript:

Copy to clipboard
const {initLiveStream} = cloudinaryJsStreaming;

3. Set Cloudinary configuration parameters

To initialize live streaming you need to include at least your cloud name and the upload preset you configured for live broadcast. You can define these as constants and include them in your initLiveStream request.

Copy to clipboard
const cloudName = "{your-cloud-name}";
const uploadPreset = "{your-upload-preset}";

Initializing live streaming

Use the initLiveStream(options) method to initialize live streaming in your app.

Options

Required parameters

Param Type Description
cloudName String The cloud name for your Cloudinary account.
uploadPreset String A "live broadcast" enabled upload preset. See setup for more information.

Optional parameters

Param Type Description
debug String or Array The Log level (disabled by default). A string or array of strings listing the type of messages to print. Possible values trace, debug, vdebug, log, warn, error, all.
bandwidth String The streaming bandwidth, in bits. Default 1 Mbit/s (1024 * 1024).
hlsTarget Boolean Whether to live stream using the hls protocol.
fileTarget Boolean Whether to save an mp4 file in your Cloudinary Media Library.
facebookUri String (URI) The Facebook streaming URI used to direct the stream to facebook. Supplied by Facebook when configuring Facebook streaming.
youtubeUri String (URI) The Youtube streaming URI used to direct the stream to Youtube. Supplied by Youtube when configuring Youtube streaming.
events Callback Callback for events, supporting the following functions:
start: Called when the streaming starts. Includes the recording Id.
stop: Called when the streaming stops. Includes the recording Id.
error: Called when the library encounters an error. The error message is included in the callback.
local_stream: Called when the stream is available locally (stream is provided in the callback). This can be used to display to the user his own streaming as it up-streams.

Example

The example below shows a simple initialization:

Copy to clipboard
initLiveStream({
    cloudName: cloudName,
    uploadPreset: uploadPreset,
    debug: "all",
    hlsTarget: true,
    fileTarget: true,
    events: {
        start: function (args) {
            // user code
        },
        stop: function (args) {
            // user code
        },
        error: function(error){
            // user code
        },
        local_stream: function (stream) {
            // user code, typically attaching the stream to a video view:
        }
    }
})

Response

The response includes the new live streaming instance. You should store this in order to attach, start and stop your live stream. You can use a promise to do this, for example:

Copy to clipboard
let liveStream;
//...
// initLiveStream code
//...
}).then(result => {
    liveStream = result;
});

The result itself includes a response object that contains information about the initialized live stream. This includes the public_id which you need to use when starting the live stream.

Here's an example of the response object:

Copy to clipboard
{
    "public_id": "zeotgizr0ywj9w8owms7",
    "version": 1579706079,
    "signature": "2f25a24948aaf35e9c357355893978f5aa880dda",
    "format": "live",
    "resource_type": "video",
    "created_at": "2020-01-22T15:14:39Z",
    "tags": [],
    "bytes": 87,
    "type": "upload",
    "placeholder": false,
    "url": "http://res.cloudinary.com/mycloudname/video/upload/v1579706079/zeotgizr0ywj9w8owms7.live",
    "secure_url": "https://res.cloudinary.com/mycloudname/video/upload/v1579706079/zeotgizr0ywj9w8owms7.live",
    "access_mode": "public",
    "original_filename": "blob"
}

Instance methods

Once you have an instance of live streaming initialized you can make use of the instance methods to control your live streaming:

Attach

attach()

Attach your live stream to a video element to show the local stream to the user that is streaming. You can use the local_stream event when initializing your stream to trigger this, for example:

Copy to clipboard
//...
    events: {
    //...
      local_stream: function (stream) {
        liveStream.attach(document.getElementById("video"), stream);
      }

Start

start(publicID)

Start your live streaming using the start method. The method takes a single publicId string argument. This is the public ID of the video stream returned by the initialize request.

For example:

Copy to clipboard
liveStream.start("<public-id>")

This will start live streaming from the device that calls this method.

Stop

stop()

Stop live streaming using the stop method. This will end live streaming and if fileTarget was set to true, your video will be saved in your Cloudinary account.

For example:

Copy to clipboard
liveStream.stop()

Controlling the camera

In addition to the standard live streaming functions, you can also make use of some convenient camera functions to enable the user to preview their device camera before initializing a live stream.

attachCamera

attachCamera(<video-element>, facingMode)

Shows the camera in an HTML video element.

detachCamera

detachCamera(<video-element>, stopStream): Removes the camera from an HTML element.

  • <video-element> - The HTML <video> element to detach the camera from. Required.
  • stopStream - Whether to stop the camera stream as well as detaching from the video element. Optional. Default: true.

Here's a simple example of how to use the attachCamera and detachCamera functions to show or hide the camera preview to the user:

Copy to clipboard
import {attachCamera, detachCamera} from '@cloudinary/js-streaming';
const video = document.getElementById("video");
const facingMode =  { exact: "user" };

// Show camera in an html <video> element
// facingMode is optional
attachCamera(video, facingMode).then(stream=>console.log(stream));

// Remove camera from an html <video> element
detachCamera(video).then(videoElement=>console.log(videoElement));

Streamer

A convenient wrapper for camera and streaming functions, it exposes functions for showing, hiding and streaming from a camera.

The Streamer wrapper makes it easier to use both camera and live streaming functions together. Here's an example of how to use the Streamer wrapper:

Copy to clipboard
import {Streamer} from '@cloudinary/js-streaming';
const video = document.getElementById("video");
const facingMode =  { exact: "user" };
const liveStreamOptions = {};
const streamer = new Streamer(video);

// Show camera in an html <video> element
// facingMode is optional
streamer.attachCamera(facingMode).then(stream=>console.log(stream));

// Remove camera from an html <video> element
streamer.detachCamera().then(videoElement=>console.log(videoElement));

// Initialize live-streaming using streaming configuration object
streamer.initLiveStream(liveStreamOptions).then(result => console.log(result));

Streaming to other media platforms

Cloudinary's live streaming can also be streamed using other platforms such as Facebook or Youtube.

To stream to other platforms, you need to include the streaming URI retrieved from the relevant platforms, using the facebookUri and youtubeUri parameters when initializing your live stream.

Working example

Here's a simple HTML, JavaScript and CSS example of how to add live streaming to your website or application.

The HTML includes buttons to show/hide the camera, initialize the stream, and to start and stop live streaming. It also displays some of the response elements from the initialization, such as the file and stream URL as well as the public ID.

Copy to clipboard
<link href="./styles.css" rel="stylesheet" type="text/css">
<script src="https://unpkg.com/@cloudinary/js-streaming/dist/js-streaming.js"></script>

<div class="container wrapper">
    <h1>Cloudinary Live Streaming Example</h1>
    <div class="video-wrapper">
        <video class="video" id="video" autoPlay muted="muted" playsInline></video>
    </div>
    <div class="center">
        <div class="center-text">
            <button id="viewbtn" onclick="view();">Show camera</button>
            <button id="hidebtn" onclick="hide();">Hide camera</button>
        </div>
        <div class="center-text">
            <button id="initbtn" onclick="initialize();">Initialize stream</button>
            <button disabled id="startbtn" onclick="start();">Start stream</button>
            <button disabled id="stopbtn" onclick="stop();">Stop stream</button>
        </div>

        <div class="ui">
            <p>Status: <span id="status">Click on 'initialize Stream' to begin</span></p>
            <p>Public Id: <span id="publicid"></span></p>
            <p>File url: <a id="file_url" target="_blank"></a></p>
            <p>Stream url: <a id="stream_url" target="_blank"></a></p>
        </div>
    </div>
</div>
<script src="<index.js"></script>

The JavaScript is where you can add your configuration options and controls the logic of the live streaming:

Copy to clipboard
const {initLiveStream, attachCamera, detachCamera} = cloudinaryJsStreaming;
const CLOUD_NAME = '<your-cloud-name>';
const UPLOAD_PRESET = '<your-upload-preset>';
let liveStream, publicId, url;

function setText(id, text) {
  document.getElementById(id).innerHTML = text;
}

function setStatus(status) {
  setText("status", status);
}

function toggleButton(id, enabled) {
  document.getElementById(id).disabled = !enabled;
}

function toggleBtns(init = false, start = false, stop = false) {
  toggleButton("initbtn", init);
  toggleButton("startbtn", start);
  toggleButton("stopbtn", stop);
}

function setUrl(url) {
  const fileUrl = url + '.mp4';
  const streamUrl = url + '.m3u8';

  const file_link = document.getElementById('file_url');
  const stream_link = document.getElementById('stream_url');

  file_link.href = fileUrl;
  file_link.innerText = fileUrl;
  stream_link.href = streamUrl;
  stream_link.innerText = streamUrl;
}

function view(){
  attachCamera(document.getElementById("video")).then(c=>{
    console.log(c);
  })
}

function hide(){
  detachCamera(document.getElementById("video")).then(c=>{
    console.log(c);
  })
}

function start() {
  setStatus("starting...");
  toggleBtns();
  liveStream.start(publicId);
}

function stop() {
  setStatus("stopping...");
  toggleBtns();
  liveStream.stop();
}

// call initLiveStream with the configuration parameters:
function initialize() {
  setStatus("initializing...");
  toggleBtns();

  initLiveStream({
    cloudName: CLOUD_NAME,
    uploadPreset: UPLOAD_PRESET,
    debug: "all",
    hlsTarget: true,
    fileTarget: true,
    events: {
      start: function (args) {
        setStatus("started");
        document.getElementById("video").className = "video recording";
        toggleBtns(false, false, true);
      },
      stop: function (args) {
        setStatus("stopped");
        document.getElementById("video").className = "video";
        toggleBtns(true, false, false);
      },
      error: function (error) {
        setStatus("error: " + error);
        toggleBtns(true, false, false);
      },
      local_stream: function (stream) {
        setStatus("local stream");
        // Attach the stream to a video element:
        liveStream.attach(document.getElementById("video"), stream);
      }
    }
  }).then(result => {
    // keep handle to instance to start/stop streaming
    liveStream = result;

    // Extract public id and url from result (publish the url for people to watch the stream):
    publicId = result.response.public_id;
    url = 'https://res.cloudinary.com/demo-live/video/upload/' + publicId;

    setStatus("initialized");
    setText("publicid", publicId);
    setUrl(url);

    toggleBtns(false, true, false);
  });
}

The CSS adds some basic styling to the page:

Copy to clipboard
.container {
    max-width: 600px;
}

.info {
    height: 400px;
}

.ui {
    text-align: left;
    height: 400px;
}

.wrapper {
    display: inline-block;
}

.video-wrapper {
    width: 320px;
    margin-bottom: 15px;
    display: inline-block;
}

.video {
    width: 100%;
    border: 5px solid black;
}

.recording {
    border: 5px solid red;
}

.center-text {
    text-align: center;
}

.center {
    margin-left: auto;
    margin-right: auto;
    display: block
}

This is how the example would look when added to the page:


Cloudinary Live Streaming Example

Status: Click on 'initialize Stream' to begin

Public Id:

File url:

Stream url:


Notes

  • The maximum duration for a live stream is one hour. Streaming will end after an hour and you'll need to initialize a new live stream.
  • The public ID for the stream will be assigned automatically, you can't manually set the public ID.
  • If the video from your live stream exceeds your storage limits, the video will not be stored in your account.