Publishing a Facebook live video using Wowza Streaming Cloud REST API from Android

Avaneesh Asokan
6 min readFeb 26, 2021

Recently, I was trying to stream some content from my phone to multiple social media platform starting with Facebook. Here’s how I got it working.

Photo by Tarun Savvy on Unsplash

I come from an android background and this was my first time working with Wowza and Facebook. So after a few sessions of research, head-scratching and tinkering, I was making some steady progress.

Note: If you need to connect to Facebook via Wowza using their streaming cloud and not specifically with the REST API then you can check out that guide here: https://www.wowza.com/docs/how-to-stream-to-facebook-live-from-wowza-streaming-cloud

Prerequisites:

  1. Have an outgoing RTMP video stream ready.
  2. A Wowza cloud account.
  3. A Facebook developer account and an app created for accessing FB.

Let’s get started!

Setting up Facebook integration:

Photo by Caspar Camille Rubin on Unsplash

Getting started with Facebook is very well documented and straightforward. The only thing to note is that since we are planning to use the app to stream video to Facebook we must request the publish_video permission that can be added to the Facebook login button as shown:

loginButton.setPermissions(Arrays.asList("publish_video"));

Once we have successfully logged in to FB, then we can request for the live video object from FB; since that will contain the URL that we need to send to Wowza when we are creating a streaming target.

@POST("live_videos")
Call<LiveVideo> getLiveVideoObject(@Query("status") String status, @Query("access_token") String accessToken);

In the code above I’m using retrofit 2 for network calls and GSON for JSON processing, also note that the status parameter must be “LIVE_NOW”.

Capture the details that we receive and we are set to move on to the next step!

Setting up Wowza Cloud from the Rest API is as follows:

Photo by Hu lei on Unsplash

A quick point to note is that while Facebook will maintain your session for you, you’ll have to pass the Wowza API_KEY and ACCESS_KEY with every request you make to the Wowza cloud.

This can be done in retrofit by adding an Interceptor while creating the retrofit instance, like so:

httpClient.addInterceptor(chain -> {
Request original = chain.request();

Request request = original.newBuilder()
.header("Content-Type", "application/json")
.header("wsc-access-key", ACCESS_KEY)
.header("wsc-api-key", API_KEY)
.build();
return chain.proceed(request);
});

Also, note that you must add a digest in the header for the production code ‘wsc-signature: [signature-generated-from-HMAC-256-Hexdigest-algorithm]’

Okay now with that out of the way, let’s take a look at the steps we need to take to make Wowza send the incoming RTMP stream to Facebook as an RTMPS stream.

  1. Create a Wowza “Live Stream” that captures the incoming stream.
    - this, thankfully, creates the transcoder and a default stream target for us, which we’ll get to in a second.
  2. Creating a stream target that points to Facebook.
  3. Create an output format that the transcoder can use and output to the stream target we mentioned in the previous step.

Let’s get right into it!

NOTE: we will be using API 1.6 for this process: so you can set your base URL to https://api.cloud.wowza.com/api/v1.6/

STEP 1: CREATING LIVE STREAM APP ON WOWZA CLOUD

For step one we have to create an object to be passed in the body of the request and this is what I’ve used:

LiveStream newLiveStream = new LiveStream();
newLiveStream.setAspectRatioHeight(1280L);
newLiveStream.setAspectRatioWidth(720L);
newLiveStream.setBillingMode(BillingMode.pay_as_you_go.name());
newLiveStream.setBroadcastLocation(BroadcastLocation.asia_pacific_india.name());
newLiveStream.setEncoder(Encoder.other_rtmp.name());
newLiveStream.setName(liveStreamAppName);
newLiveStream.setTranscoderType(TranscoderType.transcoded.name());

newLiveStream.setDisableAuthentication(true);
newLiveStream.setHostedPage(false);
newLiveStream.setLowLatency(false);
newLiveStream.setPlayerCountdown(false);
newLiveStream.setRecording(false);
List<String> deliveryProtocol = new ArrayList<>();
deliveryProtocol.add("rtmp");
newLiveStream.setDeliveryProtocols(deliveryProtocol);

LiveStreamWrapper wrapper = new LiveStreamWrapper();
wrapper.setLiveStream(newLiveStream);

The LiveStreamWrapper class does nothing other than wrap the LiveStream object with the name “live_stream” like so

public class LiveStreamWrapper {
@SerializedName("live_stream")
LiveStream liveStream;
...
//getters and setters go here
}

Once the network request is sent out using

@POST("live_streams")
public Call<LiveStreamWrapper> createLiveStream(@Body LiveStreamWrapper liveStream);

we are looking for a responseCode of 201

Here we can capture some of the responses we get:

String liveStreamAppName = response.body().getLiveStream().getName();String streamId = response.body().getLiveStream().getId();String primaryServer = response.body().getLiveStream().getSourceConnectionInformation().getPrimaryServer();String streamName = response.body().getLiveStream().getSourceConnectionInformation().getStreamName();

The primaryServer value is the entry point to the created live app in Wowza and we must point the data we want to stream to this URL.

STEP 2: STARTING THE LIVE STREAM APP

Now that we have created the live stream app, we need to start it before we can interact with it:

Starting the live stream app is done by passing the streamId we received in Step 1 with the request below:

@PUT("live_streams/{id}/start")
public Call<LiveStreamWrapper> startLiveStreamById(@Path("id") String streamId);

Now, this process could take a while to complete (sometimes even a couple of minutes) but once triggered successfully, we should receive a responseCode of 200.

Since this could take a while you may have to poll for the current status as shown below by passing in the streamId:

@GET("live_streams/{id}/state")
public Call<LiveStreamWrapper> getLiveStreamStatusById(@Path("id") String streamId);

The possible states are as follows:

stopped,
stopping,
resetting,
starting,
started

Once the status returns as “started” we can move on to the next step: (Yay! so many steps!)

STEP 3: CREATING THE FB STREAM TARGET

Okay for this, let's take a look at the streaming URL we received from Facebook when we made the request for getting a live video object. It will be in the following format:

rtmps://live-api-s.facebook.com:443/rtmp/<stream_key_string>

For creating the stream target Wowza requires you to pass the primary URL without the protocol and without the trailing ‘/’ as below

String[] parts = fbStreamUrl.split("live-api-s.facebook.com:443/rtmp/");StreamTargetCustom customTarget = new StreamTargetCustom();
customTarget.setName(liveStreamAppName + "_fb"); // name of the custom target
customTarget.setPrimaryUrl("live-api-s.facebook.com:443/rtmp");
customTarget.setProvider("rtmps");
customTarget.setStreamName(parts[1]);
customTarget.setUsername("123546789"); // username of your choice
customTarget.setPassword("987654321"); // password of your choice

This object is then passed to the server to create the custom target as shown below:

@POST("stream_targets/custom")
Call<CustomStreamTargetWrapper> createStreamTarget(@Body CustomStreamTargetWrapper targetCustom);

The CustomStreamTargetWrapper class is used simply to wrap the StreamCustomTarget as “stream_target_custom”

public class CustomStreamTargetWrapper {

@SerializedName("stream_target_custom")
private StreamTargetCustom streamTargetCustom;

...
}

Once we have this created we will get a responseCode of 201.

STEP 4: CREATING AND ADDING THE OUTPUT FORMAT TO THE TRANSCODER

Now we have to connect the streaming target to the transcoder that is automatically created with the live stream app that we created in step 1.

This will contain the live stream app name that we saved earlier as liveStreamAppName +“ / Transcoder”

We can find the transcoder we require by sending the request to fetch all available transcoders and parsing them to find the one we are after:

@GET("transcoders")
Call<Transcoders> getAllTranscoders();

and on iterating through the list of available transcoders we can find what we are looking for

for (TranscodersItem item : tList) {
if (item.getName().contains(liveStreamAppName)) {
...
transcoderId = item.getId();
createFbRtmpOutputFormat();
...
}
}

The createFbRtmpOutputFormat method creates the output format that FB requires and:

Output output = new Output();
output.setVideoCodec("h264");
output.setAudioCodec("aac");
output.setBitrateVideo(1024);
output.setBitrateAudio(128);
output.setAspectRatioHeight(1280);
output.setAspectRatioWidth(720);

This is then sent along with the request to create the RTMP output format as part of the request body

@POST("transcoders/{transcoder_id}/outputs")
Call<OutputFormat> createOutputForTranscoder(@Path("transcoder_id") String transcoderId, @Body OutputFormat outputFormat);

This should return a responseCode of 201.

STEP 5 ASSOCIATING THE OUTPUT FORMAT OF THE TRANSCODER TO THE TARGET STREAM:

Since the FB target has been created we can associate this with the output format of the transcoder

OutputStreamTarget target = new OutputStreamTarget();
target.setStreamTargetId(fbStreamTarget.getId());
target.setUseStreamTargetBackupUrl(false);

This is then sent to Wowza using the following:

@POST("transcoders/{transcoder_id}/outputs/{output_id}/output_stream_targets")
Call<OutputStreamTargetWrapper> createStreamOutputForTranscoder(@Path("transcoder_id") String transcoderId, @Path("output_id") String outputId, @Body OutputStreamTargetWrapper streamTargetWrapper);

Once we get a responseCode of 201, we are all set to stream!

You’ll simply have to start the stream from the app and this will be visible within a few seconds on your Facebook profile page.

Photo by bruce mars on Unsplash

--

--

Avaneesh Asokan

Pro android app developer. Recent discovery: Sometimes reading the documentation can be helpful.