/**
* Copyright (c) 2006 - 2012 Smaxe Ltd (www.smaxe.com).
* All rights reserved.
*/
import com.smaxe.io.ByteArray;
import com.smaxe.uv.client.rtsp.IMessageInterceptor;
import com.smaxe.uv.client.rtsp.IPresentation;
import com.smaxe.uv.client.rtsp.IVideo;
import com.smaxe.uv.client.rtsp.RtspClient;
import com.smaxe.uv.client.rtsp.RtspPlaySession;
import com.smaxe.uv.client.rtsp.RtspRequest;
import com.smaxe.uv.client.rtsp.RtspResponse;
import com.smaxe.uv.client.rtsp.video.AbstractVideo;
import com.smaxe.uv.client.rtsp.video.VideoFactory;
import com.smaxe.uv.media.core.MediaContainer;
import com.smaxe.uv.media.core.MediaTrackInfo;
import com.smaxe.uv.stream.MediaData;
import java.util.Arrays;
/**
* <code>ExRtspPlayStream</code> - {@link RtspClient} usage example.
* <p> Note:
* <br> - The example shows how to 'PLAY' server stream.
* <br> - The played stream is saved to the local file.
*
* @author Andrei Sochirca
* @see <a href="http://www.smaxe.com/product.jsf?id=juv-rtsp-client" target="_blank">JUV RTSP/RTP Client</a>
*/
public final class ExRtspPlayStream extends Object
{
/**
* Entry point.
*
* @param args
* @throws Exception if an exception occurred
*/
public static void main(final String[] args) throws Exception
{
// NOTE:
// you can get Evaluation Key at:
// http://www.smaxe.com/order.jsf#request_evaluation_key
// or buy at:
// http://www.smaxe.com/order.jsf
// Android-specific:
// - please add permission to the AndroidManifest.xml :
// <uses-permission android:name="android.permission.INTERNET" />
// - please use separate thread to connect to the server (not UI thread) :
// RtspClient#connect() connects to the remote server in the invocation thread,
// so it causes NetworkOnMainThreadException on 4.0 (http://developer.android.com/reference/android/os/NetworkOnMainThreadException.html)
com.smaxe.uv.client.rtsp.License.setKey("SET-YOUR-KEY");
// url
final String url = args.length == 0 ? "rtsp://username:password@184.72.239.149/vod/mp4:BigBuckBunny_175k.mov" : args[0];
//
final boolean unicast = true;
// set true to record incoming stream, false - to log incoming data to console
final boolean record = false;
final RtspClient client = new RtspClient();
// configure RtspClient
client.configuration().put(RtspClient.Configuration.DATAGRAM_JITTER_BUFFER_MARGIN, 16 /*packets*/);
client.configuration().put(RtspClient.Configuration.DATAGRAM_SO_ENABLE_CONFIGURATION, true);
client.configuration().put(RtspClient.Configuration.DATAGRAM_SO_RCVBUF, 128 * 1024);
client.configuration().put(RtspClient.Configuration.RESPONSE_TIMEOUT, 10 /*seconds*/);
client.configuration().put(RtspClient.Configuration.MESSAGE_INTERCEPTOR, new IMessageInterceptor()
{
public RtspRequest onRequest(final String source, final RtspRequest request)
{
// NOTE: please use the method below to add custom headers
// request.putHeader("Custom-header", "value");
System.out.println("onRequest: " + source + " " + request);
return request;
}
public RtspResponse onResponse(final String source, final RtspResponse response)
{
System.out.println("onResponse: " + source + " " + response);
return response;
}
});
// set listener
client.addListener(new RtspClient.ListenerAdapter()
{
@Override
public void onConnect()
{
System.out.println("RtspClient.IListener#onConnect(): ");
}
@Override
public void onStateChange(final int from, final int to)
{
System.out.println("RtspClient.IListener#onStateChange(): " +
RtspClient.getStateDescription(from) + " -> " + RtspClient.getStateDescription(to));
}
@Override
public void onDisconnect(final String reason)
{
System.out.println("RtspClient.IListener#onDisconnect(): " + reason);
}
});
// connect
client.connect(url); // or client.connect(url, "username", "password");
try
{
// get and print media stream presentation (SDP)
final IPresentation presentation = client.describe(url);
System.out.println("*** Presentation ***");
System.out.println(presentation);
// NOTE: if you need to get part of presentation media then use RtspClient.createPartOfPresentation*(*) methods
// final IPresentation videoOnlyPartOfPresentation = RtspClient.createPartOfPresentationVideoOnly(presentation);
//
// System.out.println("*** Video only part of presentation ***");
// System.out.println(videoOnlyPartOfPresentation);
// create 'PLAY' session
final RtspPlaySession session = client.createPlaySession(presentation);
// unicast mode
if (unicast)
{
// sets up RTSP session for the INTERLEAVED (RTP/AVP/TCP) mode
if (!RtspClient.isOK(session.setup()))
{
// if RTP/AVP/TCP mode is not supported then use RTP/AVP/UDP
session.setup(23120 /*rtpPort*/);
}
}
else
// multicast mode
{
// session.setProfile("MP2T/H2221/UDP");
final boolean isMulticastAddressDefined = true;
if (isMulticastAddressDefined)
{
session.setMulticastAddress("231.2.23.12");
session.setup(23120);
}
else
{
session.setMulticastAddress("0.0.0.0");
session.setup();
}
}
// set RTCP Handler callback (optional)
session.setCallback(new RtspClient.IRtcpHandler.CallbackAdapter()
{
@Override
public void onApp(final MediaTrackInfo track, final int subtype, final String name, final ByteArray data)
{
// NOTE: please use the method below to send RTCP 'APP' event to the server
// session.sendApp(track, subtype, name, data);
System.out.println("RtspClient.IRtcpHandler.ICallback#onApp: " + track + " " + subtype + " " + name + " " + data.length);
}
});
// set listener (optional)
session.setListener(new RtspPlaySession.ListenerAdapter()
{
@Override
public void onMediaDataTimeout(final MediaTrackInfo track, final int timeout)
{
System.out.println("PlaySession.IListener#onMediaDataTimeout: " + track + " " + timeout);
}
@Override
public void onPacketLoss(final MediaTrackInfo track, final long lost, final long total, final int margin)
{
// NOTE: please use the method below to adjust jitter buffer margin
// session.setJitterBufferMargin(track, 12);
System.out.println("PlaySession.IListener#onPacketLoss: " + track + " " + lost + " " + total);
}
});
final MediaContainer[] containers = VideoFactory.findMediaContainer(presentation);
if (record && containers.length == 0) throw new Exception("Presentation can't be written to the file, no appropriate container found");
final MediaContainer container = record ? containers[0] : null;
if (container != null) System.out.println("Selected media container is " + container);
// NOTE: file extension is added by the "VideoFactory#create(*)" implementation
final IVideo video = record ? VideoFactory.create("d:/rtsp", container) :
new AbstractVideo()
{
@Override
public void onPlay(final MediaTrackInfo[] tracks)
{
System.out.println("IVideo#onPlay: " + Arrays.toString(tracks));
}
@Override
public void onMediaData(final MediaTrackInfo track, final MediaData data)
{
// NOTE: please use the method below to get media data content
// ByteArray payload = MediaDataFactory.getMediaDataPayload(data);
System.out.println("IVideo#onMediaData: " + data + " " + track);
}
@Override
public void onTeardown()
{
System.out.println("IVideo#onTeardown");
}
};
session.play(video); // equivalent to session.play(video, RtspClient.createRangeNpt(0 /*start*/));
Thread.sleep(10 * 1000);
if (session.pause())
{
Thread.sleep(10 * 1000);
session.resume(); // equivalent to session.play(video, (String) null /*range*/);
}
Thread.sleep(10 * 1000);
session.teardown();
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
client.close("ExRtspPlayStream is completed");
}
}
/**
* Constructor.
*/
private ExRtspPlayStream()
{
}
}