[Red5devs] Live streaming without swf

SPV s_p_v at mail.ru
Sat May 17 12:25:36 PDT 2008


Hello, Red5 guru's!

Im newbie in Red5 (and in Java:) and I need some help. Im trying to send live stream to server without swf file. With the last SVN sources of Red5 and http://dl.fancycode.com/red5/api/, I wrote this test class:

<code>
import java.io.File;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.apache.mina.common.ByteBuffer;

import org.red5.server.api.service.IPendingServiceCall;
import org.red5.server.api.service.IPendingServiceCallback;
import org.red5.io.flv.impl.FLVReader;
import org.red5.io.ITag;
import org.red5.io.IoConstants;
import org.red5.io.utils.ObjectMap;
import org.red5.server.net.rtmp.RTMPClient;
import org.red5.server.net.rtmp.RTMPClient.INetStreamEventHandler;
import org.red5.server.net.rtmp.RTMPConnection;
import org.red5.server.net.rtmp.Channel;
import org.red5.server.net.rtmp.message.Header;
import org.red5.server.net.rtmp.codec.RTMP;
import org.red5.server.net.rtmp.event.Ping;
import org.red5.server.net.rtmp.event.Notify;
import org.red5.server.net.rtmp.event.AudioData;
import org.red5.server.net.rtmp.event.VideoData;
import org.red5.server.stream.message.RTMPMessage;

public class TestPublisher extends RTMPClient implements
        IPendingServiceCallback, INetStreamEventHandler
{
	private static final Logger logger = LoggerFactory
	        .getLogger(TestPublisher.class);
	
	public static void main(String[] args)
	{
		String host = "localhost";
		String app = "oflaDemo";
		int port = 1935;
		
		final TestPublisher publisher = new TestPublisher();
		logger.debug("Connecting to rtmp://" + host + ":" + port + "/" + app);
		publisher.connect(host, port, app, publisher);
	}
	
	private int streamId;
	
	@Override
	protected void onPing(RTMPConnection conn, Channel channel, Header source,
	        Ping ping)
	{
		// logger.debug("Ping");
	}
	
	@Override
	public void connectionOpened(RTMPConnection conn, RTMP state)
	{
		logger.debug("Connection opened");
		super.connectionOpened(conn, state);
	}
	
	@Override
	public void connectionClosed(RTMPConnection conn, RTMP state)
	{
		logger.debug("Connection closed");
		super.connectionClosed(conn, state);
		System.exit(0);
	}
	
	@Override
	synchronized public void resultReceived(IPendingServiceCall call)
	{
		logger.debug("Service call {" + call + "}");
		if ("connect".equals(call.getServiceMethodName()))
		{
			// invoke("createStream", null, this);
			createStream(this);
		} else if ("createStream".equals(call.getServiceMethodName()))
		{
			streamId = (Integer) call.getResult();
			
			logger.debug("Publishing stream id = " + streamId);
			
			publish(streamId, "red5StreamDemo", "live", this);
		}
	}
	
	@Override
	synchronized public void onStreamEvent(Notify notify)
	{
		ObjectMap map = (ObjectMap) notify.getCall().getArguments()[0];
		String code = (String) map.get("code");
		
		logger.debug("Stream notify: " + notify);
		
		if ("NetStream.Publish.Start".equals(code))
		{
			startPublish();
		}
	}
	
	synchronized public void startPublish()
	{
		File file = new File(
		        "/home/freelander/Programs/red5/webapps~/oflaDemo/streams/IronMan.flv");
		FLVReader reader = null;
		try
		{
			reader = new FLVReader(file);
		} catch (Exception e)
		{
		}
		
		int prevTime = 0;
		while (reader.hasMoreTags())
		{
			ITag tag = reader.readTag();
			int tagTime = tag.getTimestamp();
			int dataType = tag.getDataType();
			
			if (tagTime > prevTime)
				try
				{
					//wait(tagTime - prevTime);
					Thread.sleep(tagTime - prevTime);
				} catch (Exception e)
				{
				}
			prevTime = tagTime;
			
			ByteBuffer frame = tag.getBody();
			RTMPMessage msg = new RTMPMessage();
			if (IoConstants.TYPE_METADATA == dataType)
				msg.setBody(new Notify(frame));
			else if (IoConstants.TYPE_VIDEO == dataType)
				msg.setBody(new VideoData(frame));
			else if (IoConstants.TYPE_AUDIO == dataType)
				msg.setBody(new AudioData(frame));
			else
				logger.debug("Unknown data type: " + dataType);
			publishStreamData(streamId, msg);
		}
		
		disconnect();
	}
}
</code>

Im using "simpleSubscriber.swf" from Red5 examples for viewing this stream and all works fine... but for the first several seconds, when sound goes to silent for ~ 3 seconds and then appears again but with this 3 seconds delay. Disconnect/Connect again in simpleSubscriber.swf removes the delay but all repeats again on short time. I think its because of "Thread.sleep(tagTime - prevTime)" bad solution. I tried to change code from "while()" to special method "readNextTag" and Timer object with (tagTime - prevTime) interval, but situation with the sounds stay the same.

Question: how to synchronize video and audio correctly?

Thanx and sorry for my non-native English.



More information about the Red5devs mailing list