Managing Wowza Playlists

Wowza Streaming Engine allows you to define playlists in SMIL file format statically. This is helpful if you have the ability to know the schedule upfront, but does not allow you to create and mange these playlists dynamically. The below article shows you how to use Scissor modules REST API to work effectively with dynamic playlists. You can create and play out new playlists immediately, skip forward or backward in the playlist, add / alter and remove items from the playlist while it is on air.

Installing Scissor into a live application

Download and copy the Scissor jar file into the lib folder of your Wowza installation, e.g. c:\Program Files (x86)\Wowza Media\Wowza Streaming Engine\lib or /usr/local/WowzaStreamingEngine/lib

After physically deploying the jar file, you must reboot Wowza Streaming Engine to allow the classloader to pick up the new jar file.

Configure Scissor via the Engine Manager Interface

In this example we are using a "live" application created on the manager interface called "scissor". You can see on the below image how to configure the Scissor module inside your live application

You need to define the below minimal set of configuration properties in your module in the "Custom" section. Please note that Scissor comes with a lot of additional options, see Scissor reference for all the details.

You need to create the below parameters one by one, or alternatively you can directly edit the Application.xml file that gets created under the conf/scissor directory of your Wowza installation.

Restart the application

After making changes to the configuration, you need to restart the scissor application in Wowza by clicking on the Restart button in the top right corner.

Boot up the live application within Wowza

Scissor module starts up when the surrounding Wowza application starts up. You can use com.wowza.wms.plugin.streampublisher.ServerListenerStreamPublisher in Server.xml to make sure it starts up automatically (see this article for more details) or alternatively you can invoke the below URL from your browser / curl / Postman to start up the application within Wowza Streaming Engine.

We are using curl command in the below example to activate scissor application by trying to play a non-existing stream called boot.

C:\>curl http://localhost:1935/scissor/boot/playlist.m3u8 -v
*   Trying ::1...
* TCP_NODELAY set
* connect to ::1 port 1935 failed: Connection refused
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 1935 (#0)
> GET /scissor/boot/playlist.m3u8 HTTP/1.1
> Host: localhost:1935
> User-Agent: curl/7.55.1
> Accept: */*
>
< HTTP/1.1 404 Not Found
< Accept-Ranges: bytes
< Server: WowzaStreamingEngine/4.7.7
< Content-Length: 0

As a result of this, we should see the below printed into wowzastreamingengine_access.log

INFO server comment - Wowza Streaming Engine is started!
INFO server comment - MediaCasterStreamValidator.init[scissor/_definst_]: Started
INFO server comment - Starting Scissor 2018.11.04, Free version
INFO server comment - License number: 1
INFO server comment - No time limit
INFO server comment - Scissor is starting worker thread for application scissor/_definst_
INFO server comment - Default output stream name(s): [mux]
INFO server comment - Default stream name is live
INFO server comment - Scissor worker thread is running in scissor
INFO server comment - Config path is W:/wowza-4.7.7/conf/scissor/Application.xml
INFO server comment - Trying to read from file W:\wowza-4.7.7\conf\admin.password
INFO server comment - Started Scissor UI on http://localhost:4567 without SSL enabled
INFO application app-start _definst_ scissor/_definst_

The key message here is that Scissor has started listening on port 4567 and we can start talking to it using standard REST messages.

Talking to Scissor via REST API

Depending on how familiar are you with webservices you can use a range of different techniques to consume a REST API. Scissor comes with a standard Open API specification and there is a Swagger UI installed on this website to allow anyone quickly trying the API without the need to install tools like Postman or using low-lever curl commands. In the below examples we are going to use Swagger UI. It is important to load the UI without SSL to allow the browser talking to the non-SSL Scissor API at this point. The module itself can be configured to use SSL and various ways of authentication, but in this article we focus on the minimum.

Open http://streamtoolbox.com/swagger-ui/?url=http://streamtoolbox.com/api-docs/scissor.json#/playlists/addPlaylistsRoute in your browser to load Scissor API docs.

Fill in the Server variables section with your server details. The calls sent form the test page will all use these to reach Scissor.

For this demo we have placed two mp4 files into the content folder of our Wowza installation and we'll use those to define a new playlist. Scroll down to the POST /scissor/playlist section in Swagger and click the "Edit" button to make the request body editable.

Paste in the below sample JSON message for sending:

{
   "id":"demo","output":"myStream","repeat":true,
   "items":[
     {"id":"1","vod":true,"name":"mp4:fish.mp4"},
     {"id":"2","vod":true,"name":"mp4:hornet.mp4"}
   ]
}

Click the Execute button and you should see a HTTP 200 response echoing you back the playlist you have submitted.

The message that was sent in defined a new playlist with an arbitrary identifier demo. Scissor was instructed to put two items into the playlist and define a new output stream called myStream and start playing it out immediately with infinite repeats.

This is how it looks like from Wowza logs perspective:

INFO stream create myStream -
WARN server comment - CupertinoPacketHandler.handleHolder [scissor/_definst_/myStream] Ending the current a+v chunk although the chunk does not start with a video keyframe
INFO server comment - LiveStreamPacketizerCupertino.endChunkTS[scissor/_definst_/myStream]: Add chunk: id:1 mode:TS[H264,AAC] a/v/k:48/91/1 duration:3033
INFO server comment - LiveStreamPacketizerCupertino.endChunkTS[scissor/_definst_/myStream]: Add chunk: id:2 mode:TS[H264,AAC] a/v/k:48/91/1 duration:3034
INFO server comment - Stream.switch[scissor/_definst_/myStream]: index: 1 name:mp4:hornet.mp4 start:0 length:-1 interItemGap(a/v/c/u):21/33/0/33
INFO server comment - Starting item mp4:hornet.mp4
INFO server comment - LiveStreamPacketizerCupertino.endChunkTS[scissor/_definst_/myStream]: Add chunk: id:3 mode:TS[H264,AAC] a/v/k:33/63/1 duration:2115
INFO server comment - LiveStreamPacketizerCupertino.endChunkTS[scissor/_definst_/myStream]: Add chunk: id:4 mode:TS[H264,AAC] a/v/k:47/72/1 duration:3000
INFO server comment - LiveStreamPacketizerCupertino.endChunkTS[scissor/_definst_/myStream]: Add chunk: id:5 mode:TS[H264,AAC] a/v/k:47/72/1 duration:3000
INFO server comment - LiveStreamPacketizerCupertino.endChunkTS[scissor/_definst_/myStream]: Add chunk: id:6 mode:TS[H264,AAC] a/v/k:46/72/1 duration:3000
INFO server comment - LiveStreamPacketizerCupertino.endChunkTS[scissor/_definst_/myStream]: Add chunk: id:7 mode:TS[H264,AAC] a/v/k:47/72/1 duration:3000
INFO server comment - LiveStreamPacketizerCupertino.endChunkTS[scissor/_definst_/myStream]: Add chunk: id:8 mode:TS[H264,AAC] a/v/k:47/72/1 duration:3000
INFO server comment - LiveStreamPacketizerCupertino.endChunkTS[scissor/_definst_/myStream]: Add chunk: id:9 mode:TS[H264,AAC] a/v/k:47/72/1 duration:3000
INFO server comment - LiveStreamPacketizerCupertino.endChunkTS[scissor/_definst_/myStream]: Add chunk: id:10 mode:TS[H264,AAC] a/v/k:47/72/1 duration:3000
INFO server comment - LiveStreamPacketizerCupertino.endChunkTS[scissor/_definst_/myStream]: Add chunk: id:11 mode:TS[H264,AAC] a/v/k:47/72/1 duration:3000
INFO server comment - Stream.switch[scissor/_definst_/myStream]: index: 0 name:mp4:fish.mp4 start:0 length:-1 interItemGap(a/v/c/u):21/42/0/42
INFO server comment - Starting item mp4:fish.mp4
INFO server comment - Stream.switch[scissor/_definst_/myStream]: index: 1 name:mp4:hornet.mp4 start:0 length:-1 interItemGap(a/v/c/u):21/33/0/33
INFO server comment - Starting item mp4:hornet.mp4
INFO server comment - Stream.switch[scissor/_definst_/myStream]: index: 0 name:mp4:fish.mp4 start:0 length:-1 interItemGap(a/v/c/u):21/42/0/42
INFO server comment - Starting item mp4:fish.mp4
INFO server comment - Stream.switch[scissor/_definst_/myStream]: index: 1 name:mp4:hornet.mp4 start:0 length:-1 interItemGap(a/v/c/u):21/33/0/33
INFO server comment - Starting item mp4:hornet.mp4
INFO server comment - Stream.switch[scissor/_definst_/myStream]: index: 0 name:mp4:fish.mp4 start:0 length:-1 interItemGap(a/v/c/u):21/42/0/42

And we can check the output stream with VLC

The REST API has a complete documentation in Swagger and you can find all the operations required to make changes to the playlist. The API was primarily designed to allow integration with web interfaces and has helper endpoints to load thumbnail image of the current stream, list all available VOD files in the content directory, etc. Please check out Scissor reference for more details.

In case of any questions, feel free to email us at help@streamtoolbox.com or book a free consulting session.