• How to log play statistics on a timer

    Module to log stats for each play stream on a timer.

    Code:
    package com.wowza.wms.example.module;
    
    import java.util.*;
    import com.wowza.wms.application.*;
    import com.wowza.wms.amf.*;
    import com.wowza.wms.application.WMSProperties;
    import com.wowza.wms.module.*;
    import com.wowza.wms.stream.IMediaStream;
    import com.wowza.wms.stream.IMediaStreamActionNotify2;
    import java.util.Timer;
    import com.wowza.util.IOPerformanceCounter;
    
    public class ModuleStreamStats extends ModuleBase {
    	
    	public void onStreamCreate(IMediaStream stream) {
    		getLogger().info("onStreamCreate by: " + stream.getClientId());
    		IMediaStreamActionNotify2 actionNotify  = new StreamListener();
    		
    		WMSProperties props = stream.getProperties();
    		synchronized(props)
    		{
    			props.put("streamActionNotifier", actionNotify);
    		}
    		stream.addClientListener(actionNotify);
    	}
    	public void onStreamDestroy(IMediaStream stream) {
    		getLogger().info("onStreamDestroy by: " + stream.getClientId());
    		
    		IMediaStreamActionNotify2 actionNotify = null;
    		WMSProperties props = stream.getProperties();
    		synchronized(props)
    		{
    			actionNotify = (IMediaStreamActionNotify2)stream.getProperties().get("streamActionNotifier");
    		}
    		if (actionNotify != null)
    		{
    			stream.removeClientListener(actionNotify);
    			getLogger().info("removeClientListener: "+stream.getSrc());
    		}
    	}
    	
    	class StreamListener  implements IMediaStreamActionNotify2 
    	{
    		public void onPlay(IMediaStream stream, String streamName, double playStart, double playLen, int playReset) 
    		{
    			streamName = stream.getName();
    			getLogger().info("Stream Name: " + streamName);
    			
    			StreamStats watchdog = new StreamStats();
    			IApplicationInstance appInstance;
    			try
    			{
    				try
    				{
    					appInstance = stream.getClient().getAppInstance();
    				}
    				catch(Exception ex)
    				{
    					appInstance = stream.getRTPStream().getAppInstance();
    				}
    				
    				watchdog.stream = stream;
    				watchdog.start();
    				appInstance.getProperties().setProperty(streamName, watchdog);
    			}
    			catch(Exception ex)
    			{
    			}
    			
    		}
    		
    		public void onMetaData(IMediaStream stream, AMFPacket metaDataPacket) 
    		{
    			getLogger().info("onMetaData By: " + stream.getClientId());
    		}	
    		
    		public void onPauseRaw(IMediaStream stream, boolean isPause, double location) 
    		{
    			getLogger().info("onPauseRaw By: " + stream.getClientId());
    		}
    
    		public void onSeek(IMediaStream stream, double location)
    		{
    		}
    		
    		public void onStop(IMediaStream stream)
    		{
    			getLogger().info("onStop By: " + stream.getClientId());
    			String streamName = stream.getName();
    			StreamStats watchdog = (StreamStats)stream.getClient().getAppInstance().getProperties().getProperty(streamName);
    			if (watchdog != null)
    				watchdog.stop();
    		}
    		
    		public void onUnPublish(IMediaStream stream, String streamName, boolean isRecord, boolean isAppend)
    		{					
    		}
    
    		public  void onPublish(IMediaStream stream, String streamName, boolean isRecord, boolean isAppend)
    		{	
    		}
    		public void onPause(IMediaStream stream, boolean isPause, double location)
    		{
    		}
    	}
    	
    	private class StreamStats
    	{
    		public Timer mTimer;
    		public TimerTask mTask;
    		public IMediaStream stream;
    		public StreamStats(){
    			mTask = new TimerTask()
    			{
    				public void run() 
    				{
    					getLogger().info("Run StreamStats");
    	                
                        if (stream!=null)
                        {
                        	IOPerformanceCounter perf = stream.getMediaIOPerformance();
                        
                        	getLogger().info("Perf: " + perf.getMessagesOutBytes());
                        }                	
    				}
    			};
    		}
    		
    		public void start(){
    			
    			if (mTimer==null)
    				mTimer = new Timer();
    			mTimer.schedule(mTask, 10000, 10000);
    			getLogger().info("Start StreamStats");
    		}
    		
    		public void stop(){
    			if (mTimer != null){
    				mTimer.cancel();
    				mTimer=null;
    				getLogger().info("Stop StreamStats");				
    			}
    		}
    	}
    }

    Comments 3 Comments
    1. maanas -
      The Timer is running even after pause of the stream. How to account pause
    1. rrlanham -
      The stream is still active during pause, there would be no reason not to continue reporting on a paused stream

      Richard
    1. maanas -
      Yes i figured it out. I infact made a module which stops the stream onPauseRaw. I think that is the client side event. I also noticed that even after pause the onPause event is fired which appears to be server side event.
      I had to bind the thing to start again on onPause when set to true. This appears to be close approximation. Couple with when we got onPause true then the location returned by the onPauseRaw is actual location.

      onPause true when stream resumes, i observer the location value is little more than what is actual location of the client. Is the different in location onPauseRaw is onPause can be calculated or depends on set paramter if that is the case then i can make some correction and come to close approximation of the client.

      One more thing i noticed that onMeta event is not firing. Through the video has meta data. Any suggestion for same.