// Path: src/main/java/xpertss/media/MediaChannel.java
// public class MediaChannel implements Comparable<MediaChannel> {
// 
//    private final MediaDescription desc;
//    private final Range<Integer> channels;
// 
//    public MediaChannel(MediaDescription desc, Range<Integer> channels)
//    {
//       this.desc = Objects.notNull(desc);
//       this.channels = Objects.notNull(channels);
//    }
// 
//    /**
//     * The full media description of the data this channel will
//     * process.
//     */
//    public MediaDescription getMedia()
//    {
//       return desc;
//    }
// 
//    /**
//     * A control identifier for the channel.
//     */
//    public String getControl()
//    {
//       Attribute attr = desc.getAttribute("control");
//       return (attr != null) ? attr.getValue() : null;
//    }
// 
// 
//    /**
//     * The media type this channel will process.
//     */
//    public MediaType getType()
//    {
//       return MediaType.parse(desc);
//    }
// 
//    /**
//     * The channel identifiers over which this media will be transmitted.
//     * <p/>
//     * The media data is usually transmitted over the lower of the two
//     * channel identifiers while control information for the channel is
//     * transmitted over the higher channel.
//     */
//    public Range<Integer> getChannels()
//    {
//       return channels;
//    }
// 
// 
//    /**
//     * Compares this media channel to another based on its channel identifiers.
//     */
//    @Override
//    public int compareTo(MediaChannel o)
//    {
//       return channels.compareTo(o.channels);
//    }
// 
// }
// 
// Path: src/main/java/xpertss/media/MediaConsumer.java
// public interface MediaConsumer {
// 
//    /**
//     * Given a session description return the media descriptions the
//     * consumer wishes to be setup for playback.
//     */
//    public MediaDescription[] select(SessionDescription sdp);
// 
// 
//    /**
//     * For each media description desired this will be called by the
//     * player to inform it that the channel has been successfully
//     * setup and to identify the channel identifiers associated with
//     * it.
//     */
//    public void createChannel(MediaChannel channel);
// 
//    /**
//     * Called to indicate that the previously created channels should
//     * be destroyed as they are no longer valid.
//     */
//    public void destroyChannels();
// 
// 
// 
//    /**
//     * Once playback has begun the actual channel data will be delivered
//     * to the consumer via this method. The channelId will be one of the
//     * identifiers previously communicated to the newChannel callback.
//     */
//    public void consume(int channelId, ByteBuffer data);
// 
// 
//    /**
//     * Called to notify the consumer of an error that has terminated
//     * playback.
//     */
//    public void handle(Throwable t);
// 
// }
// 
// Path: src/main/java/xpertss/media/MediaType.java
// public enum MediaType {
// 
//    Audio, Video, Text, Application, Message;
// 
// 
//    public static MediaType parse(MediaDescription desc)
//    {
//       String mediaType = desc.getMedia().getType();
//       if("Audio".equalsIgnoreCase(mediaType)) {
//          return Audio;
//       } else if("Video".equalsIgnoreCase(mediaType)) {
//          return Video;
//       } else if("Text".equalsIgnoreCase(mediaType)) {
//          return Text;
//       } else if("Application".equalsIgnoreCase(mediaType)) {
//          return Application;
//       } else if("Message".equalsIgnoreCase(mediaType)) {
//          return Message;
//       }
//       return null;
//    }
// }


import org.junit.Test;
import xpertss.function.Consumer;
import xpertss.lang.Range;
import xpertss.media.MediaChannel;
import xpertss.media.MediaConsumer;
import xpertss.media.MediaType;
import xpertss.sdp.MediaDescription;
import xpertss.sdp.SessionDescription;
import xpertss.threads.Threads;
import java.net.ConnectException;
import java.net.URI;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import static org.junit.Assert.*;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.same;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static xpertss.nio.ReadyState.Closed;
import static xpertss.nio.ReadyState.Closing;
import static xpertss.nio.ReadyState.Connected;
import static xpertss.nio.ReadyState.Connecting;
import static xpertss.nio.ReadyState.Open;
   }





   @Test
   public void testRtspPlayer()
   {
      RtspClient client = new RtspClient();
      RtspPlayer player = new RtspPlayer(client, new MediaConsumer() {

         private Map<Integer,Consumer<ByteBuffer>> channels = new HashMap<>();

         @Override
         public MediaDescription[] select(SessionDescription sdp)
         {
            return sdp.getMediaDescriptions();
         }

         @Override
         public void createChannel(MediaChannel channel)
         {
            final MediaType type = channel.getType();
            Range<Integer> range = channel.getChannels();
            channels.put(range.getLower(), new Consumer<ByteBuffer>() {
               long start = System.nanoTime();
               @Override public void apply(ByteBuffer data) {
                  long millis = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
                  int seq = (int) (data.getShort(2) & 0xffff);
// Path: src/main/java/xpertss/media/MediaChannel.java
// public class MediaChannel implements Comparable<MediaChannel> {
// 
//    private final MediaDescription desc;
//    private final Range<Integer> channels;
// 
//    public MediaChannel(MediaDescription desc, Range<Integer> channels)
//    {
//       this.desc = Objects.notNull(desc);
//       this.channels = Objects.notNull(channels);
//    }
// 
//    /**
//     * The full media description of the data this channel will
//     * process.
//     */
//    public MediaDescription getMedia()
//    {
//       return desc;
//    }
// 
//    /**
//     * A control identifier for the channel.
//     */
//    public String getControl()
//    {
//       Attribute attr = desc.getAttribute("control");
//       return (attr != null) ? attr.getValue() : null;
//    }
// 
// 
//    /**
//     * The media type this channel will process.
//     */
//    public MediaType getType()
//    {
//       return MediaType.parse(desc);
//    }
// 
//    /**
//     * The channel identifiers over which this media will be transmitted.
//     * <p/>
//     * The media data is usually transmitted over the lower of the two
//     * channel identifiers while control information for the channel is
//     * transmitted over the higher channel.
//     */
//    public Range<Integer> getChannels()
//    {
//       return channels;
//    }
// 
// 
//    /**
//     * Compares this media channel to another based on its channel identifiers.
//     */
//    @Override
//    public int compareTo(MediaChannel o)
//    {
//       return channels.compareTo(o.channels);
//    }
// 
// }
// 
// Path: src/main/java/xpertss/media/MediaConsumer.java
// public interface MediaConsumer {
// 
//    /**
//     * Given a session description return the media descriptions the
//     * consumer wishes to be setup for playback.
//     */
//    public MediaDescription[] select(SessionDescription sdp);
// 
// 
//    /**
//     * For each media description desired this will be called by the
//     * player to inform it that the channel has been successfully
//     * setup and to identify the channel identifiers associated with
//     * it.
//     */
//    public void createChannel(MediaChannel channel);
// 
//    /**
//     * Called to indicate that the previously created channels should
//     * be destroyed as they are no longer valid.
//     */
//    public void destroyChannels();
// 
// 
// 
//    /**
//     * Once playback has begun the actual channel data will be delivered
//     * to the consumer via this method. The channelId will be one of the
//     * identifiers previously communicated to the newChannel callback.
//     */
//    public void consume(int channelId, ByteBuffer data);
// 
// 
//    /**
//     * Called to notify the consumer of an error that has terminated
//     * playback.
//     */
//    public void handle(Throwable t);
// 
// }
// 
// Path: src/main/java/xpertss/media/MediaType.java
// public enum MediaType {
// 
//    Audio, Video, Text, Application, Message;
// 
// 
//    public static MediaType parse(MediaDescription desc)
//    {
//       String mediaType = desc.getMedia().getType();
//       if("Audio".equalsIgnoreCase(mediaType)) {
//          return Audio;
//       } else if("Video".equalsIgnoreCase(mediaType)) {
//          return Video;
//       } else if("Text".equalsIgnoreCase(mediaType)) {
//          return Text;
//       } else if("Application".equalsIgnoreCase(mediaType)) {
//          return Application;
//       } else if("Message".equalsIgnoreCase(mediaType)) {
//          return Message;
//       }
//       return null;
//    }
// }


// Path: src/test/java/xpertss/rtsp/RtspClientTest.java
import org.junit.Test;
import xpertss.function.Consumer;
import xpertss.lang.Range;
import xpertss.media.MediaChannel;
import xpertss.media.MediaConsumer;
import xpertss.media.MediaType;
import xpertss.sdp.MediaDescription;
import xpertss.sdp.SessionDescription;
import xpertss.threads.Threads;
import java.net.ConnectException;
import java.net.URI;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import static org.junit.Assert.*;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.same;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static xpertss.nio.ReadyState.Closed;
import static xpertss.nio.ReadyState.Closing;
import static xpertss.nio.ReadyState.Connected;
import static xpertss.nio.ReadyState.Connecting;
import static xpertss.nio.ReadyState.Open;

   }





   @Test
   public void testRtspPlayer()
   {
      RtspClient client = new RtspClient();
      RtspPlayer player = new RtspPlayer(client, new MediaConsumer() {

         private Map<Integer,Consumer<ByteBuffer>> channels = new HashMap<>();

         @Override
         public MediaDescription[] select(SessionDescription sdp)
         {
            return sdp.getMediaDescriptions();
         }

         @Override
         public void createChannel(MediaChannel channel)
         {
            final MediaType type = channel.getType();
            Range<Integer> range = channel.getChannels();
            channels.put(range.getLower(), new Consumer<ByteBuffer>() {
               long start = System.nanoTime();
               @Override public void apply(ByteBuffer data) {
                  long millis = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
                  int seq = (int) (data.getShort(2) & 0xffff);
                  long ts = (long) (data.getInt(4) & 0xffffffff);