Send metadata to flash client thru serverside API

I am very new to WOWZA (1 day with it)

What i intend to do is to add custom metadata to my live audio stream.

I already created a custom module that when a stream is created starts adding the meta data using this code:

IMediaStream stream = client.getAppInstance().getStreams().getStream(streamname);

AMFDataMixedArray data = new AMFDataMixedArray();

data.put(“duration”, new AMFDataItem(240);

stream.sendDirect(“@setDataFrame”,“onMetaData”,data);

What example and with wich code can i now check from the client side if the stream is arriving with the metadata?

Many Thanks

Pedro

Hi Rchard,

Sorry for the delay replying to you.

It is working but i have a problem on the client side player.

So far:

  1. Wowza server starts a thread when a new stream is created, that gets theXML data from a Webservice and attaches this as a metadata fiel (dynamicmetadata in my case). The server sends new metadata every 5 sec.
					   	  data.put("dynamicMetadata", new AMFDataItem(metadata));
					   	  auxStream.sendDirect("@setDataFrame","onMetaData",data);
					  }
					  Thread.sleep(5000L);
  1. The Flash player client gets all metadata fields, from that extracts dynamicmetadata, and then parses the XML. All this is working but only happens once.
function playLiveStream()
{
	nsPlay = new NetStream(nc);
	
	nsPlay.client = nsPlayClientObj;
	
	nsPlayClientObj.onMetaData = function(infoObject:Object) 
	{
		trace("Dynamic Metadata from WOWZA:");
		for (var propName:String in infoObject)
		{
			if(propName == "dynamicMetadata"){
				bufferXML =  filterXML(correctCharacters(infoObject[propName]));
				updatePlayerInfo();
				updatePlayer();
				}
		}
	};

Also, i can close and open the player and no new metadata is sent. Only when o Stop and Start Abobe Flash Media Encoder, it shows new info on the player

How can i get the player to update dynamicmetata?

playLiveStream is an adaptation.

Do i need to reform this and make the client always request metadata from server?

Thanks

I made more tests and it seems that when the client player connect to the server the flash encoder stops sending data. The player seems to update as i put trace the onmetadata and it runs more than once.

I am very confused with this situation

Richard,

The client does catch new metadata updates, but this is why i could not see it.

If i put flash media live encoder capturing my audio device for 4 minutes for example. After that i start the player, and instead of getting a live stream i get audio from the fisrt instant of that 4 minutes, and only those 4 minutes. Since i was previously starting the client right after the encoder i only got a few seconds and that is why i tought i wasn’t updating.

By delaying the start of the client by a few minutes i can now see the info beeing updated.

My question is, why, when i start the client the encoder stops sending to the server (in the encoder is continues)?

And why don’t i get a live stream, as each time i start the client i get the same period that i captured before in the encoder?

Thanks (and sorry for my english or if i am beeing clear in my explanation, if it helps i can capture all that is happening with camtasia and show you)

Pedro

Hi Richard,

Turning the application to live solve the previous problem but now i have this situation:

  • if it runs live, i have no metadata update (i get the first metadata and the musics change but nothing new arrives to the player)

  • if i run it as recorded i get only the record from beginning to instant of player start on that period (i tested with a few minutes) i get metadata updates when the music changes

Can you help?

Thanks

Pedro

Richard,

From tracing the server i constantly [stream.sendDirect();] send updated metadata because i use a thread to to so.

On Live mode the player only gets the metadata (i add a counter ti see it) once and no more.

But on record (same code on player with same counter) i get all senDirect from the server (every second it gets new metadata).

Are you saying that on live mode i need to trigger a new metadata collection from the client side? If so, how can i do i? why doesn’t it behave in the same way as record mode if the code is the same for both sending on server and receiving on player ?

If you want i can post a detailed screen cast of all that i am doing for full understanding of my doubt

code on server

public void onStreamCreate(IMediaStream stream){
		getLogger().info("onStreamCreate: " + stream.getSrc());
		
		auxStream = stream;
		
		Runnable updateMetadata = new Runnable() {
			  public void run() {
			    try {
			      while (true) {
			    	  AMFDataMixedArray data = new AMFDataMixedArray();
			    	  String strLine = "";
			    	  String strLineAux = "";
			    	  //ler ficheiro de configuração geraç
			    	  //se o nome da aplicação esta na linha lida lida, tira o nome: e tenta abrir o ficehiro resto
			    	  try{
			    		  FileInputStream fstream = new FileInputStream("C:\\WOWZA_METADATA_CONFIG.txt");
			    		  DataInputStream in = new DataInputStream(fstream);
			    		  BufferedReader br = new BufferedReader(new InputStreamReader(in));
			    		  
			    		  while ((strLine = br.readLine()) != null)   {
			    			  strLineAux = strLine.replaceAll("radiocomercial", "");
			    			  if(strLineAux.contains(name)){
				    			  strLine = strLine.replaceAll(name + ":", "");
				    			  break;
			    			  }
			    		    }
			    		  in.close();
			    		  System.out.println("Ficheiro lido. Service: " + strLine);
			    		  }
			    	  catch (Exception e){
			    		  getLogger().info("onStreamCreate: Error: " + e.getMessage());
			    	  }			    	  
					  if(!strLine.equals("")){
					   	  String metadata = getMetadata(strLine);
					   	  System.out.println("Webservice: " + strLine);
					   	  data.put("dynamicMetadata", new AMFDataItem(metadata));
					   	  auxStream.sendDirect("onMetaData",data);
					   	  
					   	  
					   	String streamname = params.getString(PARAM1);
						String caption =  params.getString(PARAM2);
						IMediaStream stream = client.getAppInstance().getStreams().getStream(streamname);
					  }
					  Thread.sleep(5000L);
			      }
			    }
			     catch (InterruptedException iex) {}		
			  }
			};
			update = new Thread(updateMetadata);
			update.start();
		
	}

Client side

//Function that play the stream
function playLiveStream()
{
	nsPlay = new NetStream(nc);
	
	var nsPlayClientObj:Object = new Object();
	nsPlay.client = nsPlayClientObj;
	
	nsPlayClientObj.onMetaData = function(infoObject:Object) 
	{
		trace("NOVO TESTE: " + infoObject.dynamicMetadata);
		for (var propName:String in infoObject)
		{
			if(propName == "dynamicMetadata"){
				trace("a ler metadata------------------------------- " + voltas);
				voltas++;
				bufferXML =  filterXML(correctCharacters(infoObject[propName]));
				updatePlayerInfo();
				updatePlayer();
				}
		}
	};		
	
	// subscribe to the named stream
	nsPlay.play(streamName);
	
	// attach to the stream
	videoObj.attachNetStream(nsPlay);
}

I am using the same code you showed

On VOD mode é can get “voltas” (lap in portuguese) incremented each second but running it as LIVE i only goes to 1 and i have no more update of metadata

Thanks in advance

Pedro

Richard,

I am just sending (yesterday i just pasted the code to compare and forgot to remove it before pasting it here - previous post edited). Anyway i will this last post in consider and reply soon with the results

Many Thanks

Pedro

Hi Richard,

With this change on server

public void onStreamCreate(IMediaStream stream){
		getLogger().info("onStreamCreate: " + stream.getSrc());
		
		auxStream = stream;
		
		Runnable updateMetadata = new Runnable() {
			  public void run() {
			    try {
			      while (true) {
			    	  AMFDataMixedArray data = new AMFDataMixedArray();
			    	  String strLine = "";
			    	  String strLineAux = "";
			    	  //ler ficheiro de configuração geraç
			    	  //se o nome da aplicação esta na linha lida lida, tira o nome: e tenta abrir o ficehiro resto
			    	  try{
			    		  FileInputStream fstream = new FileInputStream("C:\\WOWZA_METADATA_CONFIG.txt");
			    		  DataInputStream in = new DataInputStream(fstream);
			    		  BufferedReader br = new BufferedReader(new InputStreamReader(in));
			    		  
			    		  while ((strLine = br.readLine()) != null)   {
			    			  strLineAux = strLine.replaceAll("radiocomercial", "");
			    			  if(strLineAux.contains(name)){
				    			  strLine = strLine.replaceAll(name + ":", "");
				    			  break;
			    			  }
			    		    }
			    		  in.close();
			    		  System.out.println("Ficheiro lido. Service: " + strLine);
			    		  }
			    	  catch (Exception e){
			    		  getLogger().info("onStreamCreate: Error: " + e.getMessage());
			    	  }			    	  
					  if(!strLine.equals("")){
					   	  String metadata = getMetadata(strLine);
					   	  System.out.println("Webservice: " + strLine);
					   	  data.put("caption", new AMFDataItem(metadata));
					   	  auxStream.sendDirect("setCaption",data);
					  }
					  Thread.sleep(5000L);
			      }
			    }
			     catch (InterruptedException iex) {}		
			  }
			};
			update = new Thread(updateMetadata);
			update.start();
		
	}

And this on client

function playLiveStream()
{
	nsPlay = new NetStream(nc);
	
	var nsPlayClientObj:Object = new Object();
	
	nsPlayClientObj.setCaption = function(infoObject:Object) 
	{
		trace ("HERE");
		trace("NOVO TESTE: " + infoObject.caption);
		for (var propName:String in infoObject)
		{
			if(propName == "caption"){
				trace("a ler metadata------------------------------- " + voltas);
				voltas++;
				bufferXML =  filterXML(correctCharacters(infoObject[propName]));
				updatePlayerInfo();
				updatePlayer();
				}
		}
	};		
	nsPlay.client = nsPlayClientObj;
	
	
	
	// subscribe to the named stream
	nsPlay.play(streamName);
	
	// attach to the stream
	videoObj.attachNetStream(nsPlay);
}

i never reach the first trace

if i go back to onMetadata i get the same i got before

LiveVideoStreaming was my starting point that is why i stayed with the cuepoint onMetadata

do i need to do something more for setCaption? Should not it appear in the same way as onMetadata?

Thanks

Pedro

Hi Richard,

I’d also tough about if onStreamCreate was the best choice. I have some questions:

The onPublish runs once for connection?

Already porting the code, so all that was made on creating a stream (create thread for constant update) will now be made on onPublish method. Late today i will report the results

Regards

Pedro

Hi Richard,

Just finished testing it with flying colors. I will later on post a generic version of my code for others that need an app that updates metadata from time to time.

Many thanks for the you provided (even on Sunday)

Regards

Pedro

Richard,

as i now enter the final stage of mu developments one final question:

  • the publish method is independent for each stream the app handles right? this means each stream will have it’s metadata injector. or do i need to have a clone app to handle the second stream?

i Richard

first of all the module i created for WOWZA has been working fine. the thing is now another developers are making apps for iOS and Android. what do they need to have to catch my costum metadata. i only work with flash so i do not know waht is different in terms if reading metadata in iOS and Android. is there any player i can use as an example?

regards

Hello again Richard,

i have been reading the Adding Poster Frames to iOS Streams (ID3 Metadata) article that is used to VOD

So is it possible to do something similar? to inject (maniopulate) ID3 tags for a live audio-only stream? If yes, is that example module a good starting point or do you have a better reference?

regards

Hi Richard,

I finnaly have some time available to conclude this job. I am glad to say that with Flash CS5.5 the previous flash player that i used before was deployed to iphone and android and is working fine. So now RTMP to iPhone is not a problem except for older versions os iPhone.

After reading this:

Adding Poster Frames to iOS Streams (ID3 Metadata)

Adding Multi-bitrate Audio-only Rendition to iOS Streams (AppStore 64Kbps)

i created a simple application that only uses these settings. The server is as standard, only vhost.xml was edited to accept port 80.

i access the stream with the following link:

 x.x.x.x/autometadata/stream/playlist.m3u8?wowzaaudioonly

on the server log i get:

WARN server comment stream MediaReaderH264.open[1]: java.io.FileNotFoundException: C:\Program Files\Wowza Media Systems\Wowza Media Server 2.2.4\content\stream (Access is denied)
ERROR server comment - MediaReaderH264Cupertino.indexFile:java.lang.NullPointerException

What can i be missing? I even have a stream.png image on the content folder and inside a stream folder (inside content folder) too

Thanks