• How to use IPublishingProvider API to publish server-side live streams

    The IPublishingProvider API is a low level publishing API which enables creation of a server-side live stream that can be a mixture of live and video-on-demand content. The Stream class is built on top of this API. This lower level API does not provide any scheduling or playlists. It's a raw API for publishing live or video-on-demand content into a live stream.

    Below is an example of a class which uses this API to publish the live stream named publishstream to the application named live. The class runs as a thread in the background and switches every 10 seconds between the video-on-demand clip sample.mp4 and the live stream myStream.

    package com.wowza.wms.plugin.test.integration;
    
    import com.wowza.wms.stream.publish.*;
    import com.wowza.wms.vhost.*;
    import com.wowza.wms.logging.*;
    
    public class ServerPublisherWorker extends Thread
    {
    	private long sleepTime = 75;
    	private boolean running = true;
    	private Object lock = new Object();
    	
    	private String applicationName = "live";
    	private String vodStreamName = "mp4:sample.mp4";
    	private String liveStreamName = "myStream";
    	private String publishStreamName = "publishstream";
    	private int cycleTime = 10000;
    	
    	public synchronized void quit()
    	{
    		synchronized(lock)
    		{
    			running = false;
    		}
    	}
    
    	public void run()
    	{
    		WMSLoggerFactory.getLogger(ServerPublisherWorker.class).info("ServerPublisherWorker.run: START");
    
    		long startTime = System.currentTimeMillis();
    		long playStartTime = startTime;
    
    		try
    		{
    			IVHost vhost = VHostSingleton.getInstance(VHost.VHOST_DEFAULT);
    			Publisher publisher = Publisher.createInstance(vhost, applicationName);
    			
    			publisher.publish(publishStreamName);
    
    			long nextSwitch = playStartTime + cycleTime;
    			long nextType = 0;
    			IPublishingProvider provider = new PublishingProviderMediaReader(publisher, playStartTime, vodStreamName);
    			//provider.seek(20000);
    			provider.setRealTimeStartTime(startTime);
    
    			WMSLoggerFactory.getLogger(ServerPublisherWorker.class).info("ServerPublisherWorker.run: Start with vod stream: "+vodStreamName);
    			
    			while(true)
    			{
    				boolean moreInFile = provider!=null?provider.play(publisher):false;
    				
    				long currentTime = System.currentTimeMillis();
    				if (!moreInFile || currentTime > nextSwitch)
    				{
    					if (provider != null)
    						provider.close();
    					provider = null;
    					
    					if ((nextType % 2) == 0)
    					{
    						provider = new PublishingProviderLive(publisher, publisher.getMaxTimecode(), liveStreamName);
    						//((PublishingProviderLive)provider).setStartOnPreviousKeyFrame(false);
    						provider.setRealTimeStartTime(currentTime);
    
    						WMSLoggerFactory.getLogger(ServerPublisherWorker.class).info("ServerPublisherWorker.run: Switch to live stream: "+liveStreamName);
    					}
    					else
    					{
    						provider = new PublishingProviderMediaReader(publisher, publisher.getMaxTimecode(), vodStreamName);
    						//provider.seek(20000);
    						provider.setRealTimeStartTime(currentTime);
    
    						WMSLoggerFactory.getLogger(ServerPublisherWorker.class).info("ServerPublisherWorker.run: Switch to vod stream: "+vodStreamName);
    					}
    					
    					nextSwitch = currentTime + cycleTime;
    					nextType++;
    					
    					if (nextType == 100)
    						break;
    				}
    				else
    					sleep(sleepTime);
    				
    				synchronized(lock)
    				{
    					if (!running)
    						break;
    				}
    			}
    			
    			provider.close();
    			
    			publisher.publish(null);
    			
    			synchronized(lock)
    			{
    				running = false;
    			}
    		}
    		catch (Exception e)
    		{
    			WMSLoggerFactory.getLogger(ServerPublisherWorker.class).error("ServerPublisherWorker.run: "+e.toString());
    			e.printStackTrace();
    		}
    		
    		WMSLoggerFactory.getLogger(ServerPublisherWorker.class).info("ServerPublisherWorker.run: STOP");
    	}
    }
    To see this example in action, create a server side listener that is invoked on server startup and stopped on server shutdown. Here is an example:

    package com.wowza.wms.plugin.test.integration;
    
    import com.wowza.wms.server.*;
    
    public class ServerPublisherServerListener implements IServerNotify
    {
    	ServerPublisherWorker worker = null;
    	
    	public void onServerCreate(IServer server)
    	{
    	}
    
    	public void onServerInit(IServer server)
    	{
    		worker = new ServerPublisherWorker();
    		worker.start();
    	}
    
    	public void onServerShutdownComplete(IServer server)
    	{
    	}
    
    	public void onServerShutdownStart(IServer server)
    	{
    		if (worker != null)
    			worker.quit();
    		worker = null;
    	}
    
    }
    Then add this server listener to the <ServerListeners> list in [install-dir]/conf/Server.xml:

    <ServerListener>
    	<BaseClass>com.wowza.wms.plugin.test.integration.ServerPublisherServerListener</BaseClass>
    </ServerListener>
    With this running, publish a live stream named myStream to the application named live. If you play the live stream publishstream you'll see every 10 seconds it will switch from the video-on-demand clip to the live stream.


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