• How to use Publisher API and JSpeex to publish an audio stream (VOIP integration)

    The following is a quick example of how to use JSpeex with the Publisher API to send raw audio data to a Wowza media server.

    First, download a sample 16000Hz, stereo wav file and copy it to the [install-dir]/content folder: Extremists.wav

    Note: This file was created from the Extremists.flv file using the following ffmpeg command:
    cd [install-dir]/content
    ffmpeg -i Extremists.flv -vn -ac 2 -ar 16000 Extremists.wav


    Second, Download the JSpeex library jspeex-0.9.7.zip from here http://sourceforge.net/projects/jspeex/files/, unzip and copy the dist/jspeex.jar into the [install-dir]/lib folder of the server.

    Next, create a server listener that is going to start the encoding/publishing process when Wowza Media Server starts:

    package com.wowza.wms.plugin.test.integration;
    
    import com.wowza.wms.server.*;
    
    public class ServerListenerSpeexPublisher implements IServerNotify
    {
    	public void onServerCreate(IServer server)
    	{
    		System.out.println("ServerListenerSpeexPublisher.onServerCreate");
    	}
    
    	public void onServerInit(IServer server)
    	{
    		System.out.println("ServerListenerSpeexPublisher.onServerInit");
    		SpeexPublisher worker = new SpeexPublisher();
    		worker.start();
    	}
    
    	public void onServerShutdownComplete(IServer server)
    	{
    	}
    
    	public void onServerShutdownStart(IServer server)
    	{
    	}
    
    }
    Next, create the class that is going to inject the Speex packets using the Publisher API.

    package com.wowza.wms.plugin.test.integration;
    
    //ffmpeg -i Extremists.flv -vn -ac 2 -ar 16000 Extremists.wav
    
    import java.io.*;
    
    import org.xiph.speex.*;
    
    import com.wowza.wms.bootstrap.*;
    import com.wowza.wms.media.wav.*;
    import com.wowza.wms.stream.publish.*;
    import com.wowza.wms.vhost.*;
    
    public class SpeexPublisher extends Thread
    {
    	public SpeexPublisher()
    	{
    		System.out.println("SpeexPublisher.create");
    	}
    
    	public void run()
    	{
    		String filename = Bootstrap.getServerHome(Bootstrap.APPHOME) + "/content/" + "Extremists.wav";
    
    		try
    		{
    			RandomAccessFile inf = new RandomAccessFile(filename, "r");
    			WAVHeaderInfo wavInfo = WAVUtils.readWAVHeader(inf);
    			System.out.println("wavInfo: " + wavInfo);
    
    			int mode = 1; // wide band
    			int sampleRate = (int) wavInfo.getSampleRate();
    			int channels = wavInfo.getChannelCount();
    			int quality = 10; // high quality
    
    			long fileLen = inf.length();
    			long startTime = System.currentTimeMillis();
    			long timecode = 0;
    			int numSamples = 0;
    			byte headerByte = (byte)((IVHost.CODEC_AUDIO_SPEEX<<4) + 2 /* 16bits per sample */ + (channels - 1));
    			
    			SpeexEncoder speexEncoder = new SpeexEncoder();
    			speexEncoder.init(mode, quality, sampleRate, channels);
    			numSamples = speexEncoder.getFrameSize();
    			System.out.println("numSamples: " + numSamples);
    
    			IVHost vhost = VHostSingleton.getInstance(VHost.VHOST_DEFAULT);
    			Publisher publisher = Publisher.createInstance(vhost, "live");
    
    			publisher.setFileExtension("flv");
    			publisher.setStreamType("live");
    
    			publisher.publish("myStream", "live");
    
    			while (true)
    			{
    				byte[] packet = WAVUtils.readSamples(inf, wavInfo, numSamples);
    
    				if (speexEncoder.processData(packet, 0, packet.length))
    				{
    					int encsize = speexEncoder.getProcessedData(packet, 0);
    
    					byte[] dataPacket = new byte[1 + encsize];
    					dataPacket[0] = headerByte;
    					System.arraycopy(packet, 0, dataPacket, 1, encsize);
    
    					System.out.println("sendPacket: timecode:" + ((timecode * 1000) / sampleRate) + " len:" + dataPacket.length);
    					publisher.addAudioData(dataPacket, dataPacket.length, ((timecode * 1000) / sampleRate));
    				}
    
    				long realTime = startTime + ((timecode * 1000) / sampleRate);
    				long currTime = System.currentTimeMillis();
    
    				int inc = (int) (realTime - currTime);
    				if (inc > 0)
    				{
    					Thread.currentThread().sleep(inc);
    				}
    
    				timecode += numSamples;
    				if (inf.getFilePointer() >= fileLen)
    					break;
    			}
    
    			publisher.unpublish();
    			publisher.close();
    		}
    		catch (Exception e)
    		{
    			System.out.println("Error: " + e.toString());
    		}
    	}
    }
    Next, edit [install-dir]/conf/Server.xml and add the following ServerListener to the <ServerListeners> list:

    <ServerListener>
    	<BaseClass>com.wowza.wms.plugin.test.integration.ServerListenerSpeexPublisher</BaseClass>
    </ServerListener>
    Start Wowza Media Server and you will see it start to publish the stream immediately.

    To play the stream, open:
    [install-dir]/examples/LiveVideoStreaming/FlashRTMPPlayer/player.html (Wowza Media Server 3.5 and later)
    -or-
    [install-dir]/examples/LiveVideoStreaming/client/live.html (prior version of Wowza Media Server)

    Enter the following information and click Connect or Play
    Server: rtmp://[wowza-ip-address]/live
    Stream: myStream

    Note: Be sure to setup a live application as prescribed in the QuickStart.html guide.

    Note: The Flash player can only decode 16000Hz wide-band Speex samples.


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