• How to start and stop live stream recordings programmatically (IMediaStreamActionNotify3)

    You can use an example module that uses the LiveStreamRecord APIs and IMediaStreamActionNotify3 interface to start recording a live stream automatically when it is published and stop recording it automatically when it is unpublished.

    Note: Wowza Media Server™ 3.5.0 or later is required.

    About the LiveStreamRecordAutoRecord example module

    The LiveStreamRecordAutoRecord example module uses the startRecordSegmentByDuration API to automatically split a live stream recording into files with 60 minute durations. The following code example records every stream in an associated application.
    package com.wowza.wms.example.module;
    
    import java.util.HashMap;
    import java.util.Map;
    
    import com.wowza.wms.livestreamrecord.model.ILiveStreamRecord;
    import com.wowza.wms.livestreamrecord.model.LiveStreamRecorderMP4;
    import com.wowza.wms.media.model.MediaCodecInfoAudio;
    import com.wowza.wms.media.model.MediaCodecInfoVideo;
    import com.wowza.wms.module.*;
    import com.wowza.wms.stream.*;
    import com.wowza.wms.amf.AMFPacket;
    import com.wowza.wms.application.IApplicationInstance;
    import com.wowza.wms.application.WMSProperties;
    
    public class ModuleLiveStreamRecordAutoRecord extends ModuleBase implements IModuleOnStream
    {
    	private Map<String, ILiveStreamRecord> recorders = new HashMap<String, ILiveStreamRecord>();
    	private IApplicationInstance appInstance;
    	
    	
    	public void onAppStart(IApplicationInstance appInstance)
    	{
         	this.appInstance = appInstance;
    	}
    	
    	class StreamListener implements IMediaStreamActionNotify3
    	{
    		public void onMetaData(IMediaStream stream, AMFPacket metaDataPacket)
    		{
    			System.out.println("onMetaData[" + stream.getContextStr() + "]: " + metaDataPacket.toString());
    		}
    
    		public void onPauseRaw(IMediaStream stream, boolean isPause, double location)
    		{
    			System.out.println("onPauseRaw[" + stream.getContextStr() + "]: isPause:" + isPause + " location:" + location);
    		}
    
    		public void onPause(IMediaStream stream, boolean isPause, double location)
    		{
    			System.out.println("onPause[" + stream.getContextStr() + "]: isPause:" + isPause + " location:" + location);
    		}
    
    		public void onPlay(IMediaStream stream, String streamName, double playStart, double playLen, int playReset)
    		{
    			System.out.println("onPlay[" + stream.getContextStr() + "]: playStart:" + playStart + " playLen:" + playLen + " playReset:" + playReset);
    		}
    
    		public void onPublish(IMediaStream stream, String streamName, boolean isRecord, boolean isAppend)
    		{
    			System.out.println("onPublish[" + stream.getContextStr() + "]: streamName:" + streamName + " isRecord:" + isRecord + " isAppend:" + isAppend);
    			//create a livestreamrecorder instance to create .mp4 files
    			ILiveStreamRecord recorder = new LiveStreamRecorderMP4();
    		    recorder.init(appInstance);
    		    recorder.setRecordData(true);
    		    recorder.setStartOnKeyFrame(true);
    		    recorder.setVersionFile(true);
    		       
    			// add it to the recorders list
    			synchronized (recorders)
    			{
    				ILiveStreamRecord prevRecorder = recorders.get(streamName);
    				if (prevRecorder != null)
    					prevRecorder.stopRecording();
    				recorders.put(streamName, recorder);
    			}
    			// start recording, create 1 minute segments using default content path
    			System.out.println("--- startRecordingSegmentByDuration for 60 minutes");
    			recorder.startRecordingSegmentByDuration(stream, null, null, 60*60*1000);
    			// start recording, create 1MB segments using default content path
    			//System.out.println("--- startRecordingSegmentBySize for 1MB");
    			//recorder.startRecordingSegmentBySize(stream, null, null, 1024*1024);
    			// start recording, create new segment at 1:00am each day.
    			//System.out.println("--- startRecordingSegmentBySchedule every "0 1 * * * *");
    			//recorder.startRecordingSegmentBySchedule(stream, null, null, "0 1 * * * *");
    			
    		    // start recording, using the default content path, do not append (i.e. overwrite if file exists)
    			//System.out.println("--- startRecording");
    		    //recorder.startRecording(stream, false);
    		    
    		    // log where the recording is being written
    			System.out.println("onPublish[" + stream.getContextStr() + "]: new Recording started:" + recorder.getFilePath());
    		}
            
    		public void onUnPublish(IMediaStream stream, String streamName, boolean isRecord, boolean isAppend)
    		{
    			System.out.println("onUnPublish[" + stream.getContextStr() + "]: streamName:" + streamName + " isRecord:" + isRecord + " isAppend:" + isAppend);
    			
    			ILiveStreamRecord recorder = null;
    			synchronized (recorders)
    			{
    				recorder = recorders.remove(streamName);
    			}
    			
    			if (recorder != null)
    			{
    				// grab the current path to the recorded file
    				String filepath = recorder.getFilePath();
    				
    				// stop recording
    				recorder.stopRecording();
    				System.out.println("onUnPublish[" + stream.getContextStr() + "]: File Closed:" + filepath);
    			}
    			else
    			{
    				System.out.println("onUnPublish[" + stream.getContextStr() + "]: streamName:" + streamName + " stream recorder not found");
    			}
    		}
    		
    		public void onSeek(IMediaStream stream, double location)
    		{
    			System.out.println("onSeek[" + stream.getContextStr() + "]: location:" + location);
    		}
    
    		public void onStop(IMediaStream stream)
    		{
    			System.out.println("onStop[" + stream.getContextStr() + "]: ");
    		}
    
    		public void onCodecInfoAudio(IMediaStream stream,MediaCodecInfoAudio codecInfoAudio) {
    			System.out.println("onCodecInfoAudio[" + stream.getContextStr() + " Audio Codec" + codecInfoAudio.toCodecsStr() + "]: ");
    		}
    
    		public void onCodecInfoVideo(IMediaStream stream,MediaCodecInfoVideo codecInfoVideo) {
    			System.out.println("onCodecInfoVideo[" + stream.getContextStr() + " Video Codec" + codecInfoVideo.toCodecsStr() + "]: ");
    		}
    	}
    
    	public void onStreamCreate(IMediaStream stream)
    	{
    		getLogger().info("onStreamCreate["+stream+"]: clientId:" + stream.getClientId());
    		IMediaStreamActionNotify3 actionNotify = new StreamListener();
    
    		WMSProperties props = stream.getProperties();
    		synchronized (props)
    		{
    			props.put("streamActionNotifier", actionNotify);
    		}
    		stream.addClientListener(actionNotify);
    	}
    
    	public void onStreamDestroy(IMediaStream stream)
    	{
    		getLogger().info("onStreamDestroy["+stream+"]: clientId:" + stream.getClientId());
    
    		IMediaStreamActionNotify3 actionNotify = null;
    		WMSProperties props = stream.getProperties();
    		synchronized (props)
    		{
    			actionNotify = (IMediaStreamActionNotify3) stream.getProperties().get("streamActionNotifier");
    		}
    		if (actionNotify != null)
    		{
    			stream.removeClientListener(actionNotify);
    			getLogger().info("removeClientListener: " + stream.getSrc());
    		}
    	}
    }
    Note: When using this module, streams must have a unique name within the application. If a duplicate stream name is used, the existing recording associated with the current stream name will be stopped and a new recording will be started for the duplicate stream name.

    Using the LiveStreamRecordAutoRecord module with the "live" application

    To install and configure the module

    1. Compile the above code and then copy the .jar file to the [install-dir]/lib/ folder.

    2. Create an application folder named [install-dir]/applications/live.

    3. Create a configuration folder [install-dir]/conf/live and copy [install-dir]/conf/Application.xml to this new folder.

    4. Open [install-dir]/conf/live/Application.xml in a text editor then:

      1. Change <Streams>/<StreamType> to live.

      2. Add the following module definition as the last entry in the <Modules> list:
        <Module>
             <Name>ModuleLiveStreamRecordAutoRecord</Name>
             <Description>ModuleLiveStreamRecordAutoRecord</Description>
             <Class>com.wowza.wms.example.module.ModuleLiveStreamRecordAutoRecord</Class>
        </Module>
    5. If Wowza Media Server was running, restart the server.

    6. Live streams that are sent to the live application will be recorded automatically to [install-dir]/content.

    More resources



    Originally Published: For Wowza Media Server 3.5.0 on 11-14-2012.

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