/** * 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() { } }