/**
 * Copyright (c) 2006 - 2014 Smaxe Ltd (www.smaxe.com).
 * All rights reserved.
 */

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.UnicastUdpTransport;
import com.smaxe.uv.client.rtsp.video.AbstractVideo;
import com.smaxe.uv.media.core.MediaTrackInfo;
import com.smaxe.uv.stream.MediaData;

import java.util.Arrays;

/**
 * <code>ExRtspPlayStreamsWithUdpPortsDemux</code> - {@link RtspClient} usage example.
 * <p> Note:
 * <br> - The example 'plays' many streams using the same UDP ports.
 * <br> - The example uses STUN protocol to define public UDP ports.
 * 
 * @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 ExRtspPlayStreamsWithUdpPortsDemux 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 =
        {
            "rtsp://username:password@184.72.239.149/vod/mp4:BigBuckBunny_175k.mov",
            "rtsp://username:password@184.72.239.149/vod/mp4:BigBuckBunny_175k.mov",
            "rtsp://username:password@184.72.239.149/vod/mp4:BigBuckBunny_175k.mov",
        };
        
        final RtspClient client = new RtspClient();
        
        // configure client
        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, 256 * 1024);
        
        client.configuration().put(RtspClient.Configuration.RESPONSE_TIMEOUT, 10 /*seconds*/);
        client.configuration().put(RtspClient.Configuration.STUN_SERVERS, "stun.easyvoip.com,numb.viagenie.ca,stun.bluesip.net");
        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;
            }
        });
        
        final UnicastUdpTransport transport = client.prepareUnicastUdpTransport();
        
        System.out.println("UnicastUdpTransport#publicAddresses: " + Arrays.toString(transport.getPublicAddresses()));
        
        for (int i = 0; i < url.length; i++)
        {
            final String id = "RtspClient" + i;
            
            playRtspStreamInSeparateThread(id, client, url[i], transport, new LogVideo(id));
            
            Thread.sleep(5 * 1000);
        }
        
        Thread.sleep(30 * 1000);
        
        client.release();
    }
    
    /**
     * Plays the stream in a separate thread.
     * 
     * @param id client id
     * @param client
     * @param url
     * @param transport
     * @param video
     */
    public static void playRtspStreamInSeparateThread(final String id, final RtspClient client, final String url,
            final UnicastUdpTransport transport, final IVideo video)
    {
        new Thread(new Runnable()
        {
            public void run()
            {
                // UDP port sharing is possible by using 'new RtspClient(RtspClient parent)' constructor
                // that shares RtspClient resources
                playRtspStream(new RtspClient(client), transport, url, new LogVideo(id));
            }
        }, "ExRtspPlayStreamsWithUdpPortsDemux-" + id).start();
    }
    
    /**
     * Plays the stream.
     * 
     * @param client
     * @param transport
     * @param url
     * @param video
     */
    public static void playRtspStream(final RtspClient client, final UnicastUdpTransport transport,
            final String url, final IVideo video)
    {
        try
        {
            // connect
            client.connect(url);
            
            // get and print media stream presentation (SDP)
            final IPresentation presentation = client.describe(url);
            
            System.out.println("*** Presentation ***");
            System.out.println(presentation);
            
            // create 'PLAY' session
            final RtspPlaySession session = client.createPlaySession(presentation);
            
            if (!RtspClient.isOK(session.setup(transport)))
            {
                session.setup();
            }
            
            session.play(video);
            
            Thread.sleep(10 * 60 * 1000);
            
            session.teardown();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        finally
        {
            client.close("ExRtspPlayStreamsWithUdpPortsDemux '" + url + "'  is completed");
        }
    }
    
    /**
     * <code>LogVideo</code>
     */
    public static class LogVideo extends AbstractVideo
    {
        // fields
        private final String prefix;
        
        /**
         * Constructor.
         * 
         * @param prefix
         */
        public LogVideo(final String prefix)
        {
            this.prefix = prefix;
        }
        
        // IVideo implementation
        
        @Override
        public void onPlay(final MediaTrackInfo[] tracks)
        {
            System.out.println(prefix + "-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(prefix + "-IVideo#onMediaData: "  + data + " " + track);
        }
        
        @Override
        public void onTeardown()
        {
            System.out.println(prefix + "-IVideo#onTeardown");
        }
    }
    
    /**
     * Constructor.
     */
    private ExRtspPlayStreamsWithUdpPortsDemux()
    {
    }
}