• How to set up a command line interface to Wowza API

    The following is a quick and dirty Java class that utilizes the JMX interface to implement a small set of command line operations such as starting stopping virtual hosts and application instances, starting and stopping streams and getting connection count and IO statistics:
    Note: This functionality is only supported in Wowza Media Server™ 3 or later.
    import java.util.*;
    import javax.management.*;
    import javax.management.remote.*;
    
    public class JMXCommandLine
    {
    	public static final String STREAMINGTYPES_TOTAL = "total";
    	public static final String STREAMINGTYPES_CUPERTINO = "cupertino";
    	public static final String STREAMINGTYPES_SMOOTH = "smooth";
    	public static final String STREAMINGTYPES_RTMP = "rtmp";
    	public static final String STREAMINGTYPES_RTSP = "rtsp";
    
    	public static final String[][] countStrs = {
    		{"Connections", STREAMINGTYPES_TOTAL},
    		{"ConnectionsHTTPCupertino", STREAMINGTYPES_CUPERTINO},
    		{"ConnectionsHTTPSmooth", STREAMINGTYPES_SMOOTH},
    		{"ConnectionsRTMP", STREAMINGTYPES_RTMP},
    		{"ConnectionsRTP", STREAMINGTYPES_RTSP},
    	};
    
    	public static final String[][] ioStrs = {
    		{"IOPerformance", STREAMINGTYPES_TOTAL},
    		{"IOPerformanceHTTPCupertino", STREAMINGTYPES_CUPERTINO},
    		{"IOPerformanceHTTPSmooth", STREAMINGTYPES_SMOOTH},
    		{"IOPerformanceRTMP", STREAMINGTYPES_RTMP},
    		{"IOPerformanceRTP", STREAMINGTYPES_RTSP},
    	};
    
    	public static final int SESSIONPROTOCOL_SMOOTHSTREAMING = 0;
    	public static final int SESSIONPROTOCOL_CUPERTINOSTREAMING = 1;
    
    	public static final String MBEANNAME = "WowzaMediaServerPro";
    
    	public static final String CMD_GETSERVERVERSION = "getServerVersion";
    	public static final String CMD_STARTVHOST = "startVHost";
    	public static final String CMD_STOPVHOST = "stopVHost";
    	public static final String CMD_RELOADVHOSTCONFIG = "reloadVHostConfig";
    	public static final String CMD_STARTAPPINSTANCE = "startAppInstance";
    	public static final String CMD_TOUCHAPPINSTANCE = "touchAppInstance";
    	public static final String CMD_SHUTDOWNAPPINSTANCE = "shutdownAppInstance";
    	public static final String CMD_STARTMEDIACASTERSTREAM = "startMediaCasterStream";
    	public static final String CMD_STOPMEDIACASTERSTREAM = "stopMediaCasterStream";
    	public static final String CMD_RESETMEDIACASTERSTREAM = "resetMediaCasterStream";
    	public static final String CMD_GETCONNECTIONCOUNTS = "getConnectionCounts";
    	public static final String CMD_GETIOOUTBYTERATE = "getIOOutByteRate";
    	public static final String CMD_GETIOINBYTERATE = "getIOInByteRate";
    
    	public static final String DEFAULT_VHOST = "_defaultVHost_";
    	public static final String DEFAULT_APPLICATION = "_defapp_";
    	public static final String DEFAULT_APPINSTANCE = "_definst_";
    
    	public static class AppConextName
    	{
    		String vhostName = null;
    		String appName = null;
    		String appInstName = null;
    
    		public AppConextName()
    		{
    		}
    
    		public AppConextName(String fullname, boolean startWithDefaults)
    		{
    			if (startWithDefaults)
    			{
    				vhostName = DEFAULT_VHOST;
    				appName = DEFAULT_APPLICATION;
    				appInstName = DEFAULT_APPINSTANCE;
    			}
    
    			int qloc = fullname.indexOf(":");
    			if (qloc >= 0)
    			{
    				vhostName = fullname.substring(0, qloc);
    				fullname = fullname.substring(qloc+1);
    			}
    			else
    				vhostName = DEFAULT_VHOST;
    
    			if (fullname.length() > 0)
    			{
    				appName = fullname;
    				int sloc = fullname.indexOf("/");
    				if (sloc >= 0)
    				{
    					appName = fullname.substring(0, sloc);
    					appInstName = fullname.substring(sloc+1);
    				}
    			}
    		}
    
    		String getObjName()
    		{
    			String ret = "";
    
    			while(true)
    			{
    				if (vhostName == null)
    					break;
    
    				ret += "vHosts=VHosts,vHostName="+vhostName;
    
    				if (appName == null)
    					break;
    
    				ret += ",applications=Applications,applicationName="+appName;
    
    				if (appInstName == null)
    					break;
    
    				ret += ",applicationInstances=ApplicationInstances,applicationInstanceName="+appInstName;
    				break;
    			}
    
    			return ret;
    		}
    	}
    
    	public static void printUsage()
    	{
    		System.out.println("");
    		System.out.println("Usage:");
    		System.out.println("");
    		System.out.println("[command] -[switch [value]...] [command] [params...]");
    		System.out.println("");
    		System.out.println("Switches:");
    		System.out.println("");
    		System.out.println("  -jmx  [jmx-url]");
    		System.out.println("  -user [jmx-username]");
    		System.out.println("  -pass [jmx-password]");
    		System.out.println("");
    		System.out.println("Commands:");
    		System.out.println("");
    
    		System.out.println("  "+CMD_GETSERVERVERSION);
    
    		System.out.println("  "+CMD_STARTVHOST+" [vhost]");
    		System.out.println("  "+CMD_STOPVHOST+" [vhost]");
    		System.out.println("  "+CMD_RELOADVHOSTCONFIG+"");
    
    		System.out.println("  "+CMD_STARTAPPINSTANCE+" [vhost:application/appInstance]");
    		System.out.println("  "+CMD_TOUCHAPPINSTANCE+" [vhost:application/appInstance]");
    		System.out.println("  "+CMD_SHUTDOWNAPPINSTANCE+" [vhost:application/appInstance]");
    
    		System.out.println("  "+CMD_STARTMEDIACASTERSTREAM+" [vhost:application/appInstance] [stream-name] [mediacaster-type]");
    		System.out.println("  "+CMD_STOPMEDIACASTERSTREAM+" [vhost:application/appInstance] [stream-name]");
    		System.out.println("  "+CMD_RESETMEDIACASTERSTREAM+" [vhost:application/appInstance] [stream-name]");
    
    		System.out.println("  "+CMD_GETCONNECTIONCOUNTS);
    		System.out.println("  "+CMD_GETCONNECTIONCOUNTS+" [vhost:application/appInstance]");
    		System.out.println("  "+CMD_GETCONNECTIONCOUNTS+" [vhost:application/appInstance] [stream-name]");
    
    		System.out.println("  "+CMD_GETIOOUTBYTERATE);
    		System.out.println("  "+CMD_GETIOOUTBYTERATE+" [vhost:application/appInstance]");
    
    		System.out.println("  "+CMD_GETIOINBYTERATE);
    		System.out.println("  "+CMD_GETIOINBYTERATE+" [vhost:application/appInstance]");
    
    		System.out.println("");
    	}
    
    	public static long objToLong(Object valueObj)
    	{
    		long ret = 0;
    		if (valueObj != null)
    		{
    			try
    			{
    				ret = Long.parseLong(valueObj.toString());
    			}
    			catch(Exception e)
    			{
    			}
    		}
    		return ret;
    	}
    
    	public static Object doInvoke(MBeanServerConnection connection, ObjectName connectsObjName, String cmdStr, Object[] arguments, String[] signature)
    	{
    		Object returnObj = null;
    		try
    		{
    			returnObj = connection.invoke(connectsObjName, cmdStr, arguments, signature);
    		}
    		catch(Exception e)
    		{
    			System.out.println("ERROR: doInvoke: "+e.toString());
    		}
    
    		return returnObj;
    	}
    
    	public static Object doGetAttribute(MBeanServerConnection connection, ObjectName connectsObjName, String attributeName)
    	{
    		Object returnObj = null;
    		try
    		{
    			returnObj = connection.getAttribute(connectsObjName, attributeName);
    		}
    		catch(Exception e)
    		{
    		}
    
    		return returnObj;
    	}
    
    	public static void main(String[] args)
    	{
    
    		try
    		{
    			for(int i=0;i<args.length;i++)
    				args[i] = args[i].trim();
    
    			String host = "localhost";
    			String username = null;
    			String password = null;
    			String jmxURL = "service:jmx:rmi://"+host+":8084/jndi/rmi://"+host+":8085/jmxrmi";
    
    			int argOffset = 0;
    			while(true)
    			{
    				if (argOffset >= args.length)
    					break;
    
    				if (!args[argOffset].startsWith("-"))
    					break;
    
    				if (args[argOffset].startsWith("-host"))
    				{
    					argOffset++;
    					host = args[argOffset];
    					jmxURL = "service:jmx:rmi://"+host+":8084/jndi/rmi://"+host+":8085/jmxrmi";
    				}
    				else if (args[argOffset].startsWith("-jmx"))
    				{
    					argOffset++;
    					jmxURL = args[argOffset];
    				}
    				else if (args[argOffset].startsWith("-user"))
    				{
    					argOffset++;
    					username = args[argOffset];
    				}
    				else if (args[argOffset].startsWith("-pass"))
    				{
    					argOffset++;
    					password = args[argOffset];
    				}
    
    				argOffset++;
    			}
    
    			if (argOffset >= args.length)
    			{
    				printUsage();
    				return;
    			}
    
    			// create a connection URL
    			JMXServiceURL serviceURL = new JMXServiceURL(jmxURL);
    
    			// create a environment hash with username and password
    			Map<String, Object> env = new HashMap<String, Object>();
    
    			if (username != null && password != null)
    			{
    				String[] creds = {username, password};
    				env.put(JMXConnector.CREDENTIALS, creds);
    			}
    
    			JMXConnector connector = JMXConnectorFactory.connect(serviceURL, env);
    			MBeanServerConnection connection = connector.getMBeanServerConnection();
    
    			if (connection == null)
    			{
    				System.out.println("ERROR: Cannot connect to JMX interface: "+jmxURL);
    				return;
    			}
    
    			if (args[argOffset].equalsIgnoreCase(CMD_GETSERVERVERSION))
    			{
    				String connectsName = MBEANNAME+":name=Server";
    				ObjectName connectsObjName = new ObjectName(connectsName);
    
    				Object attrObj = doGetAttribute(connection, connectsObjName, "version");
    				if (attrObj != null)
    					System.out.println(attrObj);
    				else
    					System.out.println("unknown");
    			}
    			else if (args[argOffset].equalsIgnoreCase(CMD_STARTVHOST))
    			{
    				String connectsName = MBEANNAME+":name=Server";
    				ObjectName connectsObjName = new ObjectName(connectsName);
    
    				System.out.println(args[argOffset]+" "+args[argOffset+1]);
    				Object[] arguments = {args[argOffset+1]};
    				String[] signature = {"java.lang.String"};
    				doInvoke(connection, connectsObjName, "startVHost", arguments, signature);
    			}
    			else if (args[argOffset].equalsIgnoreCase(CMD_STOPVHOST))
    			{
    				String connectsName = MBEANNAME+":name=Server";
    				ObjectName connectsObjName = new ObjectName(connectsName);
    
    				System.out.println(args[argOffset]+" "+args[argOffset+1]);
    				Object[] arguments = {args[argOffset+1]};
    				String[] signature = {"java.lang.String"};
    				doInvoke(connection, connectsObjName, "stopVHost", arguments, signature);
    			}
    			else if (args[argOffset].equalsIgnoreCase(CMD_RELOADVHOSTCONFIG))
    			{
    				String connectsName = MBEANNAME+":name=Server";
    				ObjectName connectsObjName = new ObjectName(connectsName);
    
    				System.out.println(args[argOffset]);
    				Object[] arguments = {};
    				String[] signature = {};
    				doInvoke(connection, connectsObjName, "reloadVHostConfig", null, null);
    			}
    			else if (args[argOffset].equalsIgnoreCase(CMD_STARTAPPINSTANCE))
    			{
    				System.out.println(args[argOffset]+" "+args[argOffset+1]);
    
    				AppConextName context = new AppConextName(args[argOffset+1], true);
    
    				String connectsName = MBEANNAME+":vHosts=VHosts,vHostName="+context.vhostName+",name=VHost";
    				ObjectName connectsObjName = new ObjectName(connectsName);
    
    				Object[] arguments = {context.appName, context.appInstName};
    				String[] signature = {"java.lang.String", "java.lang.String"};
    				doInvoke(connection, connectsObjName, "startApplicationInstance", arguments, signature);
    			}
    			else if (args[argOffset].equalsIgnoreCase(CMD_TOUCHAPPINSTANCE))
    			{
    				System.out.println(args[argOffset]+" "+args[argOffset+1]);
    
    				AppConextName context = new AppConextName(args[argOffset+1], true);
    
    				String connectsName = MBEANNAME+":vHosts=VHosts,vHostName="+context.vhostName+",name=VHost";
    				ObjectName connectsObjName = new ObjectName(connectsName);
    
    				Object[] arguments = {context.appName, context.appInstName};
    				String[] signature = {"java.lang.String", "java.lang.String"};
    				doInvoke(connection, connectsObjName, "touchApplicationInstance", arguments, signature);
    			}
    			else if (args[argOffset].equalsIgnoreCase(CMD_SHUTDOWNAPPINSTANCE))
    			{
    				System.out.println(args[argOffset]+" "+args[argOffset+1]);
    
    				AppConextName context = new AppConextName(args[argOffset+1], true);
    
    				String connectsName = MBEANNAME+":vHosts=VHosts,vHostName="+context.vhostName+",applications=Applications,applicationName="+context.appName+",name=Application";
    				ObjectName connectsObjName = new ObjectName(connectsName);
    
    				Object[] arguments = {context.appInstName};
    				String[] signature = {"java.lang.String"};
    				doInvoke(connection, connectsObjName, "shutdownAppInstance", arguments, signature);
    			}
    			else if (args[argOffset].equalsIgnoreCase(CMD_STARTMEDIACASTERSTREAM))
    			{
    				System.out.println(args[argOffset]+" "+args[argOffset+1]+" "+args[argOffset+2]+" "+args[argOffset+3]);
    
    				AppConextName context = new AppConextName(args[argOffset+1], true);
    
    				String connectsName = MBEANNAME+":vHosts=VHosts,vHostName="+context.vhostName+",applications=Applications,applicationName="+context.appName+",applicationInstances=ApplicationInstances,applicationInstanceName="+context.appInstName+",name=ApplicationInstance";
    				ObjectName connectsObjName = new ObjectName(connectsName);
    
    				Object[] arguments = {args[argOffset+2], args[argOffset+3]};
    				String[] signature = {"java.lang.String", "java.lang.String"};
    				doInvoke(connection, connectsObjName, "startMediaCasterStream", arguments, signature);
    			}
    			else if (args[argOffset].equalsIgnoreCase(CMD_STOPMEDIACASTERSTREAM))
    			{
    				System.out.println(args[argOffset]+" "+args[argOffset+1]+" "+args[argOffset+2]);
    
    				AppConextName context = new AppConextName(args[argOffset+1], true);
    
    				String connectsName = MBEANNAME+":vHosts=VHosts,vHostName="+context.vhostName+",applications=Applications,applicationName="+context.appName+",applicationInstances=ApplicationInstances,applicationInstanceName="+context.appInstName+",name=ApplicationInstance";
    				ObjectName connectsObjName = new ObjectName(connectsName);
    
    				Object[] arguments = {args[argOffset+2]};
    				String[] signature = {"java.lang.String"};
    				doInvoke(connection, connectsObjName, "stopMediaCasterStream", arguments, signature);
    			}
    			else if (args[argOffset].equalsIgnoreCase(CMD_RESETMEDIACASTERSTREAM))
    			{
    				System.out.println(args[argOffset]+" "+args[argOffset+1]+" "+args[argOffset+2]);
    
    				AppConextName context = new AppConextName(args[argOffset+1], true);
    
    				String connectsName = MBEANNAME+":vHosts=VHosts,vHostName="+context.vhostName+",applications=Applications,applicationName="+context.appName+",applicationInstances=ApplicationInstances,applicationInstanceName="+context.appInstName+",name=ApplicationInstance";
    				ObjectName connectsObjName = new ObjectName(connectsName);
    
    				Object[] arguments = {args[argOffset+2]};
    				String[] signature = {"java.lang.String"};
    				doInvoke(connection, connectsObjName, "resetMediaCasterStream", arguments, signature);
    			}
    			else if (args[argOffset].equalsIgnoreCase(CMD_GETCONNECTIONCOUNTS))
    			{
    				StringBuffer outputBuf = new StringBuffer();
    
    				String streamNamesStr = null;
    				AppConextName context = null;
    				if (args.length > (argOffset+2))
    				{
    					context = new AppConextName(args[argOffset+1], true);
    					streamNamesStr = args[argOffset+2];
    				}
    				else if (args.length > (argOffset+1))
    					context = new AppConextName(args[argOffset+1], false);
    				else
    					context = new AppConextName();
    
    				if (streamNamesStr != null)
    				{
    					String[] streamNames = streamNamesStr.split("[|]");
    
    					String contextStr = context.getObjName();
    					if (contextStr.length() > 0)
    						contextStr += ",";
    					String connectsName = MBEANNAME+":"+contextStr+"name=ApplicationInstance";
    					ObjectName connectsObjName = new ObjectName(connectsName);
    
    					long total = 0;
    					long cupertinoTotal = 0;
    					long smoothTotal = 0;
    					long rtspTotal = 0;
    					long rtmpTotal = 0;
    					for(int i=0;i<streamNames.length;i++)
    					{
    						String streamName = streamNames[i].trim();
    
    						{
    							Object[] arguments = {SESSIONPROTOCOL_CUPERTINOSTREAMING, streamName};
    							String[] signature = {"int", "java.lang.String"};
    							Object attrObj = doInvoke(connection, connectsObjName, "getHTTPStreamerSessionCount", arguments, signature);
    							cupertinoTotal += objToLong(attrObj);
    						}
    						{
    							Object[] arguments = {SESSIONPROTOCOL_SMOOTHSTREAMING, streamName};
    							String[] signature = {"int", "java.lang.String"};
    							Object attrObj = doInvoke(connection, connectsObjName, "getHTTPStreamerSessionCount", arguments, signature);
    							smoothTotal += objToLong(attrObj);
    						}
    						{
    							Object[] arguments = {streamName};
    							String[] signature = {"java.lang.String"};
    							Object attrObj = doInvoke(connection, connectsObjName, "getPlayStreamCount", arguments, signature);
    							rtmpTotal += objToLong(attrObj);
    						}
    						{
    							Object[] arguments = {streamName};
    							String[] signature = {"java.lang.String"};
    							Object attrObj = doInvoke(connection, connectsObjName, "getRTPSessionCount", arguments, signature);
    							rtspTotal += objToLong(attrObj);
    						}
    					}
    
    					total = cupertinoTotal+smoothTotal+rtmpTotal+rtspTotal;
    					System.out.println(STREAMINGTYPES_TOTAL+":"+total+" "+STREAMINGTYPES_CUPERTINO+":"+cupertinoTotal+" "+STREAMINGTYPES_SMOOTH+":"+smoothTotal+" "+STREAMINGTYPES_RTMP+":"+rtmpTotal+" "+STREAMINGTYPES_RTSP+":"+rtspTotal);
    
    				}
    				else
    				{
    					for(int i=0;i<countStrs.length;i++)
    					{
    						String contextStr = context.getObjName();
    						if (contextStr.length() > 0)
    							contextStr += ",";
    						String connectsName = MBEANNAME+":"+contextStr+"name="+countStrs[i][0];
    						ObjectName connectsObjName = new ObjectName(connectsName);
    
    						Object attrObj = doGetAttribute(connection, connectsObjName, "current");
    
    						String valueStr = attrObj==null?"0":attrObj.toString();
    						if (outputBuf.length() > 0)
    							outputBuf.append(" ");
    						outputBuf.append(countStrs[i][1]+":"+valueStr);
    					}
    				}
    
    				System.out.println(outputBuf.toString());
    			}
    			else if (args[argOffset].equalsIgnoreCase(CMD_GETIOOUTBYTERATE) ||
    					args[argOffset].equalsIgnoreCase(CMD_GETIOINBYTERATE))
    			{
    				StringBuffer outputBuf = new StringBuffer();
    
    				AppConextName context = null;
    				if (args.length > (argOffset+1))
    					context = new AppConextName(args[argOffset+1], false);
    				else
    					context = new AppConextName();
    
    				String attrValue = args[argOffset].equalsIgnoreCase(CMD_GETIOOUTBYTERATE)?"messagesOutBytesRate":"messagesInBytesRate";
    
    				for(int i=0;i<ioStrs.length;i++)
    				{
    					String contextStr = context.getObjName();
    					if (contextStr.length() > 0)
    						contextStr += ",";
    					String connectsName = MBEANNAME+":"+contextStr+"name="+ioStrs[i][0];
    					ObjectName connectsObjName = new ObjectName(connectsName);
    
    					Object attrObj = doGetAttribute(connection, connectsObjName, attrValue);
    
    					String valueStr = attrObj==null?"0":attrObj.toString();
    					if (outputBuf.length() > 0)
    						outputBuf.append(" ");
    					outputBuf.append(countStrs[i][1]+":"+valueStr);
    				}
    
    				System.out.println(outputBuf.toString());
    			}
    			else
    				System.out.println("ERROR: Command not recognized: "+args[argOffset]);
    		}
    		catch (Exception e)
    		{
    			System.out.println("ERROR: "+e.toString());
    		}
    	}
    }
    Note: If you're running Wowza Streaming Engine™ software, then your MBEANNAME value should be "WowzaStreamingEngine" and not "WowzaMediaServerPro". Make this substitution in the code segment listed above.
    Compile using the command:

    javac JMXCommandLine.java
    It should generate the class file JMXCommandLine.class (and at least one other internal .class file). You can then create a shell script to wrap around the tool. It would look something like this:

    Windows (jmxcl.bat):
    
    java -cp . JMXCommandLine %*
    
    Linux (jmxcl.sh):
    
    #/bin/sh
    java -cp . JMXCommandLine $@
    It support the following command line usage:

    Usage:

    [command] -[switch [value]...] [command] [params...]

    Switches:

    -jmx [jmx-url]
    -user [jmx-username]
    -pass [jmx-password]

    Commands:

    getServerVersion
    startVHost [vhost]
    stopVHost [vhost]
    reloadVHostConfig
    startAppInstance [vhost:application/appInstance]
    shutdownAppInstance [vhost:application/appInstance]
    startMediaCasterStream [vhost:application/appInstance] [stream-name] [mediacaster-type]
    stopMediaCasterStream [vhost:application/appInstance] [stream-name]
    resetMediaCasterStream [vhost:application/appInstance] [stream-name]
    getConnectionCounts
    getConnectionCounts [vhost:application/appInstance]
    getConnectionCounts [vhost:application/appInstance] [stream-name]
    getIOOutByteRate
    getIOOutByteRate [vhost:application/appInstance]
    getIOInByteRate
    getIOInByteRate [vhost:application/appInstance]
    Examples:

    # Start vhost _defaultVHost_
    jmxcl [jmx-connection-switches] startVHost _defaultVHost_
    
    # To get connection counts to the server
    jmxcl [jmx-connection-switches] getConnectionCounts
    
    # To get connection counts the application vod
    jmxcl [jmx-connection-switches] getConnectionCounts _defaultVHost_:vod
    Where [jmx-connection-switches] is you JMX connection info such as:

    -jmx service:jmx:rmi://localhost:8084/jndi/rmi://localhost:8085/jmxrmi -user admin -pass admin
    You can see how this methodology could be used to create a pretty robust remote command line interface to Wowza Media Server.

    Note: To use the startMediaCasterStream command, the appInstance in which you want to start the stream must first be running before you can execute the startMediaCasterStream command. For example to start the rtp stream myStream.sdp under the application instance live/_definst, you would execute the following commands:

    To start stream:
    jmxcl [jmx-connection-switches] touchAppInstance live
    jmxcl [jmx-connection-switches] startMediaCasterStream live myStream.sdp rtp
    To stop stream:
    jmxcl [jmx-connection-switches] stopMediaCasterStream live myStream.sdp
    To reset stream:
    jmxcl [jmx-connection-switches] resetMediaCasterStream live myStream.sdp

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