• How to use Wowza nDVR recording API

    This article demonstrates how to use a recording API for Wowza nDVR using an HTTP Provider.

    Configuring nDVR

    By default, nDVR starts recording a stream as soon as the stream starts. However, the startRecordingOnStartup property can be set to false in your Application.xml file (under <DVR>/<Properties>.
    <Property>
        <Name>startRecordingOnStartup</Name>
        <Value>false</Value>
        <Type>boolean</Type>
    </Property>
    This will cause the recorder to initialize, but it won't start recording until ILiveStreamDvrRecorder.startRecording() is called.

    The nDVR recording API

    The recording process consists of:

    1. Getting the ILiveStreamDvrRecorder recorder class from the live stream using IMediaStream.getDvrRecorder().

    2. (Optional) Setting the recording name via ILiveStreamDvrRecorder.setRecordingName().

    3. Start the recording via ILiveStreamDvrRecorder.startRecording().

    4. Stop the recording using ILiveStreamDvrRecorder.stopRecording().


    The example HTTP Provider

    The example below demonstrates the nDVR recording API using the HTTPProvider mechanism. An HTTP Provider is an extension to the media server software that can be attached to a HostPort definition in [install-dir]/conf/VHost.xml and can be controlled via a URL. For more detailed information on this subject, see "HTTP Providers" in the Wowza Streaming Engine User's Guide. The class below is an HTTP Provider that controls starting and stopping DVR recording.

    Use the Wowza IDE to compile this class into a JAR file and copy it to the [install-dir]/lib folder in your Wowza media server installation. Then add this HTTP Provider to the <HostPort> (Port 8086) /<HTTPProviders> container in [install-dir]/conf/VHost.xml[B]. This HTTP Provider should be added ABOVE the HTTPServerVersion HTTP Provider, which is typically last in the <HTTPProviders> container for the host port.
    <HTTPProvider>
    	<BaseClass>com.wowza.wms.dvrstreamrecord.HTTPDvrStreamRecord</BaseClass>
    	<RequestFilters>dvrstreamrecord*</RequestFilters>
    	<AuthenticationMethod>none</AuthenticationMethod>
    </HTTPProvider>

    Using the HTTP Provider

    The nDVR recording can be controlled with the HTTP Provider via a URL with the following format:

    http://[wowza-ip-address]:8086/dvrstreamrecord?app=[application-name]&streamname=[stream-name]&recordingname=[recording-name]&action=[start|stop]

    Where:

    • [wowza-ip-address] is the IP address of the Wowza media server.

    • [application-name] is the application name the stream is running on.

    • [stream-name] is the stream name of the live source stream to be recorded.

    • [recording-name] is the name of the recorded store. This is optional and defaults to [stream-name] if not specified.


    Setting RecordingName

    If [recording-name] is set, instead of recording the stream to [install-dir]/dvr/[application-name]/[app-inst]/[stream-name].[version], the recording is made to [install-dir]/dvr/[application-name]/[app-inst]/[recording-name].[version].

    To play the recording, you would specify [recording-name] instead of [stream-name] in the playback URL. For example, if the incoming stream name is myStream and the recording name is myRecording, you would specify this URL for iOS devices:

    http://[wowza-address]:1935/dvr/myRecording/playlist.m3u8?DVR

    Sample code

    Below is the sample code for controlling nDVR recording:
    package com.wowza.wms.dvrstreamrecord;
    
    import java.io.OutputStream;
    import java.util.*;
    
    import com.wowza.wms.application.IApplicationInstance;
    import com.wowza.wms.dvr.*;
    import com.wowza.wms.dvr.io.IDvrFileSystem;
    import com.wowza.wms.http.*;
    import com.wowza.wms.logging.WMSLoggerFactory;
    import com.wowza.wms.stream.IMediaStream;
    import com.wowza.wms.stream.livedvr.*;
    import com.wowza.wms.stream.mediacaster.MediaStreamMediaCasterUtils;
    import com.wowza.wms.vhost.*;
    
    public class HTTPDvrStreamRecord extends HTTProvider2Base {
        private static final String CLASSNAME = "HTTPDvrStreamRecord";
        private static final Class<HTTPDvrStreamRecord> CLASS = HTTPDvrStreamRecord.class;
    
        private Map<String, ILiveStreamDvrRecorder> dvrRecorders = new HashMap<String, ILiveStreamDvrRecorder>();
    
        public void onHTTPRequest(IVHost vhost, IHTTPRequest req, IHTTPResponse resp) {
            if (!doHTTPAuthentication(vhost, req, resp)) {
                return;
            }
    
            WMSLoggerFactory.getLogger(CLASS).info(CLASSNAME + " HTTPRequest");
    
            Map<String, List<String>> params = req.getParameterMap();
    
            String action = "";
            String app = "";
            String streamName = "";
            String report = "";
            String recordingName = "";
    
            if (req.getMethod().equalsIgnoreCase("get") || req.getMethod().equalsIgnoreCase("post")) {
                req.parseBodyForParams(true);
    
                try {
    
                    if (params.containsKey("action")) {
                        action = params.get("action").get(0);
                    } else {
                        report += "<BR>" + "action" + " is required";
                    }
                    WMSLoggerFactory.getLogger(CLASS).info(CLASSNAME + " action: " + action);
    
                    if (params.containsKey("app")) {
                        app = params.get("app").get(0);
                    } else {
                        report += "<BR>" + "app" + " is required";
                    }
                    WMSLoggerFactory.getLogger(CLASS).info(CLASSNAME + " app: " + app);
    
                    if (params.containsKey("streamname")) {
                        streamName = params.get("streamname").get(0);
                        recordingName = streamName; // default to stream name
                    } else {
                        report += "<BR>" + "streamname" + " is required";
                    }
                    WMSLoggerFactory.getLogger(CLASS).info(CLASSNAME + " streamName: " + streamName);
    
                    // If recordingName is specified, use it instead
                    if (params.containsKey("recordingname")) {
                        recordingName = params.get("recordingname").get(0);
                        WMSLoggerFactory.getLogger(CLASS).info(CLASSNAME + " recordingName: " + recordingName);
                    }
                    
                } catch (Exception ex) {
                    report = "Error: " + ex.getMessage();
                }
            } else {
                report = "Nothing to do.";
            }
    
            try {
                IApplicationInstance appInstance = vhost.getApplication(app).getAppInstance("_definst_");
    
                if (!appInstance.getPublishStreamNames().contains(streamName)) {
                    report = "Live stream " + streamName + " does not exist.";
                }
    
                if (action.equalsIgnoreCase("start") && report.equalsIgnoreCase("")) {
                    WMSLoggerFactory.getLogger(CLASS).info(String.format("%s.%s: %s", CLASSNAME, "start", streamName));
    
                    String streamTypeStr = appInstance.getStreamType();
    
                    boolean isLiveRepeaterEdge = false;
                    while (true) {
                        StreamList streamDefs = appInstance.getVHost().getStreamTypes();
                        StreamItem streamDef = streamDefs.getStreamDef(streamTypeStr);
                        if (streamDef == null)
                            break;
                        isLiveRepeaterEdge = streamDef.getProperties().getPropertyBoolean("isLiveRepeaterEdge",
                                isLiveRepeaterEdge);
                        break;
                    }
    
                    if (isLiveRepeaterEdge)
                        streamName = MediaStreamMediaCasterUtils.mapMediaCasterName(appInstance, null, streamName);
    
                    IMediaStream stream = appInstance.getStreams().getStream(streamName);
                    if (stream != null) {
                        startRecording(stream, recordingName);
                        report = action + " " + streamName + " as " + recordingName;
                    } else {
                        WMSLoggerFactory.getLogger(CLASS).warn(String.format("%s.%s: stream '%s' not found.", CLASSNAME, "start", streamName));
                        report = "Stream Not Found: " + streamName;
                    }
    
                } else if (action.equalsIgnoreCase("stop") & report.equalsIgnoreCase("")) {
                    WMSLoggerFactory.getLogger(CLASS).info(String.format("%s.%s: %s", CLASSNAME, "stop", streamName));
    
                    String path = stopRecording(streamName);
                    report = action + " " + streamName + " " + path;
                }
    
            } catch (Exception e) {
                report = "Error: " + e.getMessage();
            }
    
            String retStr = "<html><head><title>HTTPProvider DvrStreamRecord</title></head><body><h1>" + report + "</h1></body></html>";
    
            try {
                OutputStream out = resp.getOutputStream();
                byte[] outBytes = retStr.getBytes();
                out.write(outBytes);
            } catch (Exception e) {
                WMSLoggerFactory.getLogger(CLASS).error(CLASSNAME + ": " + e.toString());
            }
    
        }
    
        public void startRecording(IMediaStream stream, String recordingName) {
    
            String streamName = stream.getName();
    
            // add it to the recorders list
            synchronized (dvrRecorders) {
                // Stop previous recorder
                ILiveStreamDvrRecorder prevRecorder = dvrRecorders.get(streamName);
                if (prevRecorder != null && prevRecorder.isRecording()) {
                    prevRecorder.stopRecording();
                }
    
                // get the stream's DVR recorder and save it in a map of recorders
                ILiveStreamDvrRecorder dvrRecorder = stream.getDvrRecorder(IDvrConstants.DVR_DEFAULT_RECORDER_ID);
    
                if (dvrRecorder != null) {
    
                    if (dvrRecorder.isRecording()) {
                        dvrRecorder.stopRecording();
                    }
    
                    // start recording
                    dvrRecorder.setRecordingName(recordingName);
                    dvrRecorder.startRecording();
    
                    dvrRecorders.put(streamName, dvrRecorder);
    
                } else {
                    WMSLoggerFactory.getLogger(CLASS).warn(String.format("%s.%s: DVR Recorder not found for stream '%s'.", CLASSNAME, "start", streamName));
                }
            }
        }
    
    
        public String stopRecording(String streamName) {
            String path = "";
            ILiveStreamDvrRecorder dvrRecorder = null;
            synchronized (dvrRecorders) {
                dvrRecorder = dvrRecorders.remove(streamName);
            }
    
            if (dvrRecorder != null) {
                IDvrStreamManager dvrManager = dvrRecorder.getDvrManager();
                if (dvrManager != null) {
                    IDvrStreamStore store = dvrManager.getRecordingStreamStore();
                    IDvrFileSystem fs = store.getFileSystem();
                    path = fs.getBasePath();
                }
    
                // stop recording
                dvrRecorder.stopRecording();
    
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
    
            } else {
                WMSLoggerFactory.getLogger(CLASS).warn(String.format("%s.%s: DVR Manager not found for stream '%s'.", CLASSNAME, "stop", streamName));
            }
    
            return path;
        }
    }

    Originally Published: 10-12-2011.
    Updated: For Wowza Streaming Engine on 03-04-2015.

    If you're having problems or want to discuss this article, post in our forum.