Strip out metadata prior to republishing in Wowza module

Hi,

We have a audio only stream coming from a Shoutcast producer into Wowza.

We use the PushPublish module to restream to a flash media server.

We have problems with the flow when the metadata changes so we are trying to strip out the metadatas in Wowza to see if that helps.

I started with some sample code which shows how to remove some metadata from the metadata packet.

We modified it to remove the offending metadata item, even tried nullifying the entire packet (see commented lines in source below).

2014-07-11 11:52:15 CEST comment server INFO 200 - ModuleOnMetadataRemoveTrackinfo#OnMetadataModifier.onMetaData[todobaladas/definst/todobaladas.stream]: BEFORE:

AMFDataList:

[0] onMetaData

[1] object

{Obj: StreamTitle: “Bridge Over Troubled Water - Simon & Garfunkel”}

      • 1144.726 - - - - - - - - - - - - - - - - - - - - - - - - -

2014-07-11 11:52:15 CEST comment server INFO 200 - ModuleOnMetadataRemoveTrackinfo#OnMetadataModifier.onMetaData[todobaladas/definst/todobaladas.stream]: Remove StreamTitle - - - 1144.726 - - - - - - - - - - - - - - - - - - - - - - - - -

2014-07-11 11:52:15 CEST comment server INFO 200 - ModuleOnMetadataRemoveTrackinfo#OnMetadataModifier.onMetaData[todobaladas/definst/todobaladas.stream]: AFTER:

AMFDataList:

[0] onMetaData

[1] object

{Obj: }

However, it seems that the changes we make in our module do not get persisted as the PushPublish module sends the original unmodified metadata item (or we receive it at our end at least)

I assumed that the module list was some kind of a pipeline (because it has an ordering) and that modifying the metadata object in our module would persist the modified object into the next module. Sorry if this sounds naive, but I’m just starting out here. I’ve seen the javadocs but I have been looking for some kind of overview of the Wowza module architecture to understand how best to do what we are trying to do, think of new approaches, etc.

Does such a doc exist? Alternatively has anyone got any ideas how we might try to implement this stripping of metadata from the flow or just prevent the PushPull module from resending the metadata?

Could we for example subclass the PushPull module and override some method?

We tried the suggestion in the following post - Remove metadata from shoutcast source

However from the lack of logs it seems that this function never gets invoked. Its a shame as this seems like the cleanest solution.

Full source below:

package com.wowza.wms.plugin.onmetadataremovetrackinfo;
import com.wowza.wms.media.model.*;
import com.wowza.wms.mediacaster.IMediaCaster;
import com.wowza.wms.mediacaster.shoutcast.ShoutCastReceiver;
import com.wowza.wms.module.*;
import com.wowza.wms.stream.*;
import com.wowza.wms.amf.*;
public class ModuleOnMetadataRemoveTrackinfo extends ModuleBase
{
	class OnMetadataModifier implements IMediaStreamActionNotify3
	{
		IMediaStream stream = null;
		
		public OnMetadataModifier(IMediaStream stream)
		{
			this.stream = stream;
		}
		
		public void onMetaData(IMediaStream stream, AMFPacket metaDataPacket)
		{
			try
			{
				getLogger().info("Just called the onMetaData method of the onMetaDataModifier inner class");
				while (true)
				{
					byte[] dataDataBytes = metaDataPacket.getData();
					if (dataDataBytes == null)
						break;
					
					if (dataDataBytes.length <= 0)
						break;
					
					int dataStart = 0;
					if (dataDataBytes[0] == 0x00)
						dataStart++;
					
					AMFDataList dataList = new AMFDataList(dataDataBytes, dataStart, dataDataBytes.length-dataStart);
					if (dataList.size() <= 1)
						break;
					
					int dataIndex = 1;
					if (dataList.get(dataIndex-1).getType() != AMFData.DATA_TYPE_STRING)
						break;
				
					String metaDataStr = dataList.getString(dataIndex-1);
					
					if (metaDataStr.equals("@setDataFrame"))
						dataIndex++;
					if (dataList.size() <= dataIndex)
						break;
					
					if (dataList.get(dataIndex-1).getType() != AMFData.DATA_TYPE_STRING)
						break;
					
					metaDataStr = dataList.getString(dataIndex-1);
					if (!metaDataStr.equalsIgnoreCase("onMetaData"))
						break;
					
					getLogger().info("ModuleOnMetadataRemoveTrackinfo#OnMetadataModifier.onMetaData["+stream.getContextStr()+"]: BEFORE: \n"+dataList.toString());
					int dataType = dataList.get(dataIndex).getType();
											
					if (dataType != AMFData.DATA_TYPE_OBJECT)
						break;
										
					AMFDataObj amfObj = (AMFDataObj)dataList.get(dataIndex);
					if (amfObj == null)
						break;
					
					if (amfObj.containsKey("trackinfo"))
					{
						getLogger().info("ModuleOnMetadataRemoveTrackinfo#OnMetadataModifier.onMetaData["+stream.getContextStr()+"]: Remove trackinfo");
						amfObj.remove("trackinfo");
					}
					if (amfObj.containsKey("StreamTitle"))
					{
						getLogger().info("ModuleOnMetadataRemoveTrackinfo#OnMetadataModifier.onMetaData["+stream.getContextStr()+"]: Remove StreamTitle");
						amfObj.remove("StreamTitle");
					}
					else {
						getLogger().info("No StreamTitle metadata present!!!");
					}
					getLogger().info("ModuleOnMetadataRemoveTrackinfo#OnMetadataModifier.onMetaData["+stream.getContextStr()+"]: AFTER: \n"+dataList.toString());
					//getLogger().info("Wee experiment...lets remove everything from the metadata packet and see if it serializes...");
					//for (int i = 0; i < dataList.size(); i++) {
						//getLogger().info("Removing item at index: " + i);
						//dataList.remove(i);
					//}
					//getLogger().info("Affter removing everything we have: .onMetaData["+stream.getContextStr()+"]: AFTER: \n"+dataList.toString());
					byte[] metaDataData = dataList.serialize();
					metaDataPacket.setDataBuffer(metaDataData);
					// The below doesn't get rid of the metadata... really?
					//getLogger().info("Alternate approach... generate empty packet instead...");
					//metaDataPacket = new AMFPacket();
					break;
				}
			}
			catch(Exception e)
			{
				getLogger().error("ModuleOnMetadataRemoveTrackinfo#OnMetadataModifier.onMetaData["+stream.getContextStr()+"]: "+e.toString());
			}
		}
		public void onPauseRaw(IMediaStream stream, boolean isPause, double location)
		{
		}
		public void onPlay(IMediaStream stream, String streamName, double playStart, double playLen, int playReset)
		{
		}
		public void onPublish(IMediaStream stream, String streamName, boolean isRecord, boolean isAppend)
		{
		}
		public void onUnPublish(IMediaStream stream, String streamName, boolean isRecord, boolean isAppend)
		{
		}
		public void onPause(IMediaStream stream, boolean isPause, double location)
		{
		}
		public void onSeek(IMediaStream stream, double location)
		{
		}
		public void onStop(IMediaStream stream)
		{
		}
		public void onCodecInfoVideo(IMediaStream stream, MediaCodecInfoVideo codecInfoVideo)
		{
		}
		public void onCodecInfoAudio(IMediaStream stream, MediaCodecInfoAudio codecInfoAudio)
		{
		}
	}
	
	public void onMediaCasterCreate(IMediaCaster mediaCaster)
	{
		try
		{
			getLogger().info("In the onMediaCasterCreate method");
			if (mediaCaster instanceof ShoutCastReceiver)
			{
				getLogger().info("Setting send metadata events to false!!");
				((ShoutCastReceiver)mediaCaster).setSendOnMetaDataEvents(false);
			}
		}
		catch (Exception e)
		{
			getLogger().error("onMediaCasterCreate ", e);
		}
	}
	
	public void onStreamCreate(IMediaStream stream)
	{
		stream.addClientListener(new OnMetadataModifier(stream));
	}
}

Any ideas/suggestions/corrections greatly appreciated.

Cheers,

John

John,

The problem you are having might really be about changes in the audio and/or video codec, which is accompanied by metadata but is not really causing the problem. Many players do not handle changes in video and especially audio well, and each player has different tolerance and limits.

Richard