Use event listeners with the Wowza Streaming Engine Java API

Event listeners extend Wowza Streaming Engine™ media server functionality by listening for and acting on events that occur at the server or virtual host level. You can also configure Wowza Streaming Engine Java API event listeners to act on other types of events. This article describes when to use the various types of listeners and provides a basic example of each.

About event listeners


With most event listeners, you can have multiple listeners of the same type. When an event is triggered, each listener is called in the order it was added to the configuration file. For server and virtual host listeners, this is the order that they appear in the [install-dir]/conf/Server.xml file. For other listeners, this is the order that their add*Listener method was called. It's important to remember this when working with multiple listeners, as one listener could set or modify a value and then another listener might modify the previous value. Wowza Streaming Engine always uses the values specified by the last listener that's called.

Other event listeners only have one instance per application instance. These are normally invoked with a Set method instead of an Add method. These listeners are used to override the default action that would occur when an event is triggered.

When Wowza releases a new listener interface version, we retain the original version for backward compatibility. Old listener versions might not be removed. Always use the newer version in any code.

Use a server listener


Server listeners are notified of the server lifecycle and are a great way to invoke functionality when Wowza Streaming Engine is running. Examples of such functionality include:

  • Database configuration
  • Custom code that must run on server startup or shutdown
  • Third-party services such as web services or custom HTTP interfaces

Here's an example of a server listener, IServerNotify2, that logs each server listener call:

package com.mycompany.wms;

import com.wowza.wms.logging.*;
import com.wowza.wms.server.*;

public class MyServerListener implements IServerNotify2
{
	/*
	 * Called after the Server.xml file has been loaded. This is the earliest point where you can access server events.
	 */
	public void onServerConfigLoaded(IServer server)
	{
		WMSLoggerFactory.getLogger(null).info("onServerConfigLoaded");
	}

	/*
	 * Called after the server is created but not initialized.
	 */
	public void onServerCreate(IServer server)
	{
		WMSLoggerFactory.getLogger(null).info("onServerCreate");
	}

	/*
	 * Called after the server is initialized. At this point the server is running, all virtual hosts are initialized, and the server is ready to accept connections.
	 */
	public void onServerInit(IServer server)
	{
		WMSLoggerFactory.getLogger(null).info("onServerInit");
	}

	/*
	 * Called when the server starts to shut down.
	 */
	public void onServerShutdownStart(IServer server)
	{
		WMSLoggerFactory.getLogger(null).info("onServerShutdownStart");
	}

	/*
	 * Called when the server has finished shutting down. This is the last event that is triggered before the Wowza Streaming Engine process exits.
	 */
	public void onServerShutdownComplete(IServer server)
	{
		WMSLoggerFactory.getLogger(null).info("onServerShutdownComplete");
	}

}

To use this listener, compile it, package it into a .jar file, and put in the [install-dir]/lib folder. Then, invoke it by adding an entry to the <ServerListeners> container in [install-dir]/conf/Server.xml, like so:

<ServerListener>
	<BaseClass>com.mycompany.wms.MyServerListener</BaseClass>
</ServerListener>

Use a virtual host listener


Virtual host listeners are notified of the virtual host lifecycle. When the server starts, the listener methods onVHostCreate and onVHostInit are called for each virtual host configured in [install-dir]/conf/VHosts.xml. When these methods are called, the virtual host isn't ready to accept connections, so any configuration that's required after a virtual host is started should be done in onServerInit server call, which is called after the virtual hosts are initialized.

Note: Only one instance of each virtual host listener is running. When running multiple virtual hosts, be careful when using instance-level variables in the listener.

Here's an example of a virtual host listener, IVHostNotify, that logs each virtual host listener call:

package com.mycompany.wms;

import com.wowza.wms.amf.AMFDataList;
import com.wowza.wms.client.IClient;
import com.wowza.wms.logging.WMSLoggerFactory;
import com.wowza.wms.request.RequestFunction;
import com.wowza.wms.vhost.IVHost;
import com.wowza.wms.vhost.IVHostNotify;

public class MyVHostListener implements IVHostNotify
{

	/*
	 * Called when the virtual host is created.
	 */
	@Override
	public void onVHostCreate(IVHost vhost)
	{
		WMSLoggerFactory.getLogger(null).info("onVHostCreate");
	}

	/*
	 * Called when the virtual host is initialized.
	 */
	@Override
	public void onVHostInit(IVHost vhost)
	{
		WMSLoggerFactory.getLogger(null).info("onVHostInit");
	}

	/*
	 * Called when the virtual host starts to shut down.
	 */
	@Override
	public void onVHostShutdownStart(IVHost vhost)
	{
		WMSLoggerFactory.getLogger(null).info("onVHostShutdownStart");
	}

	/*
	 * Called when the virtual host has finished shutting down.
	 */
	@Override
	public void onVHostShutdownComplete(IVHost vhost)
	{
		WMSLoggerFactory.getLogger(null).info("onVHostShutdownComplete");
	}

	/*
	 * Called when an RTMP client connects to the virtual host.
	 */
	@Override
	public void onVHostClientConnect(IVHost vhost, IClient inClient, RequestFunction function, AMFDataList params)
	{
		WMSLoggerFactory.getLogger(null).info("onVHostClientConnect");
	}

}

To use this listener, compile it, package it into a .jar file, and put in the [install-dir]/lib folder. Then, invoke it by adding an entry to the <VHostListeners> container in [install-dir]/conf/Server.xml, like so:

<VHostListener>
	<BaseClass>com.mycompany.wms.MyVHostListener</BaseClass>
</VHostListener>

Use a MediaStream listener


MediaStream listeners listen for stream create and destroy events. They are used in custom classes that aren't Wowza Streaming Engine modules.

Here's an example of a MediaStream listener, IMediaStreamNotify, that logs stream create and destroy events:

package com.mycompany.wms;

import com.wowza.wms.logging.WMSLoggerFactory;
import com.wowza.wms.stream.IMediaStream;
import com.wowza.wms.stream.IMediaStreamNotify;

public class MyMediaStreamListener implements IMediaStreamNotify
{

	@Override
	public void onMediaStreamCreate(IMediaStream stream)
	{
		WMSLoggerFactory.getLogger(null).info("onMediaStreamCreate: " + stream.getSrc());
	}

	@Override
	public void onMediaStreamDestroy(IMediaStream stream)
	{
		WMSLoggerFactory.getLogger(null).info("onMediaStreamDestroy: " + stream.getSrc());
	}
}

Add or remove this listener using the appInstance method:

package com.mycompany.wms;

import com.wowza.wms.application.IApplicationInstance;
import com.wowza.wms.module.*;
import com.wowza.wms.stream.*;

public class MyModule extends ModuleBase
{
	private IMediaStreamNotify mediaStreamListener = new MyMediaStreamListener();

	public void onAppStart(IApplicationInstance appInstance)
	{
		appInstance.addMediaStreamListener(mediaStreamListener);
	}

	public void onAppStop(IApplicationInstance appInstance)
	{
		appInstance.removeMediaStreamListener(mediaStreamListener);
	}
}

There are also Module Stream Event methods that capture the MediaStream Create and Destroy events. Any module that has these methods is also called when the events occur.

package com.mycompany.wms;

import com.wowza.wms.module.*;
import com.wowza.wms.stream.*;

public class MyModule extends ModuleBase
{

	public void onStreamCreate(IMediaStream stream)
	{
		getLogger().info("onStreamCreate: " + stream.getSrc());
	}

	public void onStreamDestroy(IMediaStream stream)
	{
		getLogger().info("onStreamDestroy: " + stream.getSrc());
	}

}

Use a MediaStream action listener


MediaStream action listeners receive publish, codec, and metadata events for all published streams. They don't receive player events from HTTP or RTSP streams.

Here's an example of a MediaStream action listener, IMediaStreamActionNotify3:

package com.mycompany.wms;

import com.wowza.wms.amf.AMFPacket;
import com.wowza.wms.logging.WMSLoggerFactory;
import com.wowza.wms.media.model.MediaCodecInfoAudio;
import com.wowza.wms.media.model.MediaCodecInfoVideo;
import com.wowza.wms.stream.IMediaStream;
import com.wowza.wms.stream.IMediaStreamActionNotify3;

public class MyMediaStreamListener implements IMediaStreamActionNotify3
{

	@Override
	public void onMetaData(IMediaStream stream, AMFPacket metaDataPacket)
	{
		WMSLoggerFactory.getLogger(null).info("onMetaData: " + stream.getName());
	}

	@Override
	public void onPauseRaw(IMediaStream stream, boolean isPause, double location)
	{
		WMSLoggerFactory.getLogger(null).info("onPauseRaw: " + stream.getName());
	}

	@Override
	public void onPlay(IMediaStream stream, String streamName, double playStart, double playLen, int playReset)
	{
		WMSLoggerFactory.getLogger(null).info("onPlay: " + stream.getName());
	}

	@Override
	public void onPublish(IMediaStream stream, String streamName, boolean isRecord, boolean isAppend)
	{
		WMSLoggerFactory.getLogger(null).info("onPublish: " + stream.getName());
	}

	@Override
	public void onUnPublish(IMediaStream stream, String streamName, boolean isRecord, boolean isAppend)
	{
		WMSLoggerFactory.getLogger(null).info("onUnPublish: " + stream.getName());
	}

	@Override
	public void onPause(IMediaStream stream, boolean isPause, double location)
	{
		WMSLoggerFactory.getLogger(null).info("onPause: " + stream.getName());
	}

	@Override
	public void onSeek(IMediaStream stream, double location)
	{
		WMSLoggerFactory.getLogger(null).info("onSeek: " + stream.getName());
	}

	@Override
	public void onStop(IMediaStream stream)
	{
		WMSLoggerFactory.getLogger(null).info("onStop: " + stream.getName());
	}

	@Override
	public void onCodecInfoVideo(IMediaStream stream, MediaCodecInfoVideo codecInfoVideo)
	{
		WMSLoggerFactory.getLogger(null).info("onCodecInfoVideo: " + stream.getName());
	}

	@Override
	public void onCodecInfoAudio(IMediaStream stream, MediaCodecInfoAudio codecInfoAudio)
	{
		WMSLoggerFactory.getLogger(null).info("onCodecInfoAudio: " + stream.getName());
	}
}

To use the listener, compile it, package it into a .jar file, and put in the [install-dir]/lib folder. Then, invoke it by creating an instance of this object and attaching it to an IMediaStream object. You might do this in an onStreamCreate event method and remove it using an onStreamDestroy event method. For example:

package com.mycompany.wms;

import com.wowza.wms.module.*;
import com.wowza.wms.stream.*;

public class MyModule extends ModuleBase
{
	private MyMediaStreamListener actionListener = new MyMediaStreamListener();

	public void onStreamCreate(IMediaStream stream) 
	{
		stream.addClientListener(actionListener);
	}

	public void onStreamDestroy(IMediaStream stream)
	{
		stream.removeClientListener(actionListener);
	}
}

Use a MediaStream name alias provider


A MediaStream name alias provider is an event listener that's called during stream playback and MediaCaster creation events to resolve the name of the stream that should be played or the URL that the MediaCaster should connect to. An application instance can only have one MediaStream name alias provider. When you set it, it replaces the default name provider that uses .stream files.

Here's example of a MediaStream name alias provider listener, IMediaStreamNameAliasProvider2, that returns the same name that's passed into each method:

package com.mycompany.wms;

import com.wowza.wms.application.IApplicationInstance;
import com.wowza.wms.client.IClient;
import com.wowza.wms.httpstreamer.model.IHTTPStreamerSession;
import com.wowza.wms.mediacaster.IMediaCaster;
import com.wowza.wms.rtp.model.RTPSession;
import com.wowza.wms.stream.IMediaStreamNameAliasProvider2;
import com.wowza.wms.stream.livepacketizer.ILiveStreamPacketizer;

public class MyStreamNameAliasProvider implements IMediaStreamNameAliasProvider2
{
	@Override
	public String resolvePlayAlias(IApplicationInstance appInstance, String name)
	{
		return name;
	}

	@Override
	public String resolvePlayAlias(IApplicationInstance appInstance, String name, IClient client)
	{
		return name;
	}

	@Override
	public String resolvePlayAlias(IApplicationInstance appInstance, String name, IHTTPStreamerSession httpSession)
	{
		return name;
	}

	@Override
	public String resolvePlayAlias(IApplicationInstance appInstance, String name, RTPSession rtpSession)
	{
		return name;
	}

	@Override
	public String resolvePlayAlias(IApplicationInstance appInstance, String name, ILiveStreamPacketizer liveStreamPacketizer)
	{
		return name;
	}

	@Override
	public String resolveStreamAlias(IApplicationInstance appInstance, String name)
	{
		return name;
	}

	@Override
	public String resolveStreamAlias(IApplicationInstance appInstance, String name, IMediaCaster mediaCaster)
	{
		return name;
	}
}

Again, set this listener during onAppStart in a custom module:

package com.mycompany.wms;

import com.wowza.wms.application.IApplicationInstance;
import com.wowza.wms.module.*;
import com.wowza.wms.stream.IMediaStreamNameAliasProvider2;

public class MyModule extends ModuleBase
{
	private IMediaStreamNameAliasProvider2 streamNameAliasProvider = new MyStreamNameAliasProvider();

	public void onAppStart(IApplicationInstance appInstance)
	{
		appInstance.setStreamNameAliasProvider(streamNameAliasProvider);
	}
}

Other event listeners


See any of the following articles for examples of other Wowza Streaming Engine Java API event listeners.

More resources