content: /*
   * Copyright (C) 2011-2014 GUIGUI Simon, fyhertz@gmail.com
   * 
   * This file is part of libstreaming (https://github.com/fyhertz/libstreaming)
   * 
   * Spydroid is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 3 of the License, or
   * (at your option) any later version.
   * 
   * This source code is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   * 
   * You should have received a copy of the GNU General Public License
   * along with this source code; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   */
  
  package net.majorkernelpanic.streaming.rtsp;
  
  import static net.majorkernelpanic.streaming.SessionBuilder.AUDIO_AAC;
  import static net.majorkernelpanic.streaming.SessionBuilder.AUDIO_AMRNB;
  import static net.majorkernelpanic.streaming.SessionBuilder.AUDIO_NONE;
  import static net.majorkernelpanic.streaming.SessionBuilder.VIDEO_H263;
  import static net.majorkernelpanic.streaming.SessionBuilder.VIDEO_H264;
  import static net.majorkernelpanic.streaming.SessionBuilder.VIDEO_NONE;
  
  import java.io.IOException;
  import java.net.InetAddress;
  import java.net.URI;
  import java.net.UnknownHostException;
  import java.util.Iterator;
  import java.util.List;
  
  import net.majorkernelpanic.streaming.MediaStream;
  import net.majorkernelpanic.streaming.Session;
  import net.majorkernelpanic.streaming.SessionBuilder;
  import net.majorkernelpanic.streaming.audio.AudioQuality;
  import net.majorkernelpanic.streaming.video.VideoQuality;
  
  import org.apache.http.NameValuePair;
  import org.apache.http.client.utils.URLEncodedUtils;
  
  import android.hardware.Camera.CameraInfo;
  
  /**
   * This class parses URIs received by the RTSP server and configures a Session accordingly.
   */
  public class UriParser {
  
  	public final static String TAG = "UriParser";
  	
  	/**
  	 * Configures a Session according to the given URI.
  	 * Here are some examples of URIs that can be used to configure a Session:
  	 * <ul><li>rtsp://xxx.xxx.xxx.xxx:8086?h264&flash=on</li>
  	 * <li>rtsp://xxx.xxx.xxx.xxx:8086?h263&camera=front&flash=on</li>
  	 * <li>rtsp://xxx.xxx.xxx.xxx:8086?h264=200-20-320-240</li>
  	 * <li>rtsp://xxx.xxx.xxx.xxx:8086?aac</li></ul>
  	 * @param uri The URI
  	 * @throws IllegalStateException
  	 * @throws IOException
  	 * @return A Session configured according to the URI
  	 */
  	public static Session parse(String uri) throws IllegalStateException, IOException {		
  		SessionBuilder builder = SessionBuilder.getInstance().clone();
  		byte audioApi = 0, videoApi = 0;
  
  		List<NameValuePair> params = URLEncodedUtils.parse(URI.create(uri),"UTF-8");
  		if (params.size()>0) {
  
  			builder.setAudioEncoder(AUDIO_NONE).setVideoEncoder(VIDEO_NONE);
  
  			// Those parameters must be parsed first or else they won't necessarily be taken into account
  			for (Iterator<NameValuePair> it = params.iterator();it.hasNext();) {
  				NameValuePair param = it.next();
  
  				// FLASH ON/OFF
  				if (param.getName().equalsIgnoreCase("flash")) {
  					if (param.getValue().equalsIgnoreCase("on")) 
  						builder.setFlashEnabled(true);
  					else 
  						builder.setFlashEnabled(false);
  				}
  
  				// CAMERA -> the client can choose between the front facing camera and the back facing camera
  				else if (param.getName().equalsIgnoreCase("camera")) {
  					if (param.getValue().equalsIgnoreCase("back")) 
  						builder.setCamera(CameraInfo.CAMERA_FACING_BACK);
  					else if (param.getValue().equalsIgnoreCase("front")) 
  						builder.setCamera(CameraInfo.CAMERA_FACING_FRONT);
  				}
  
  				// MULTICAST -> the stream will be sent to a multicast group
  				// The default mutlicast address is 228.5.6.7, but the client can specify another
  				else if (param.getName().equalsIgnoreCase("multicast")) {
  					if (param.getValue()!=null) {
  						try {
  							InetAddress addr = InetAddress.getByName(param.getValue());
  							if (!addr.isMulticastAddress()) {
  								throw new IllegalStateException("Invalid multicast address !");
  							}
  							builder.setDestination(param.getValue());
  						} catch (UnknownHostException e) {
  							throw new IllegalStateException("Invalid multicast address !");
  						}
  					}
  					else {
  						// Default multicast address
  						builder.setDestination("228.5.6.7");
  					}
  				}
  
  				// UNICAST -> the client can use this to specify where he wants the stream to be sent
  				else if (param.getName().equalsIgnoreCase("unicast")) {
  					if (param.getValue()!=null) {
  						builder.setDestination(param.getValue());
  					}					
  				}
  				
  				// VIDEOAPI -> can be used to specify what api will be used to encode video (the MediaRecorder API or the MediaCodec API)
  				else if (param.getName().equalsIgnoreCase("videoapi")) {
  					if (param.getValue()!=null) {
  						if (param.getValue().equalsIgnoreCase("mr")) {
  							videoApi = MediaStream.MODE_MEDIARECORDER_API;
  						} else if (param.getValue().equalsIgnoreCase("mc")) {
  							videoApi = MediaStream.MODE_MEDIACODEC_API;
  						}
  					}					
  				}
  				
  				// AUDIOAPI -> can be used to specify what api will be used to encode audio (the MediaRecorder API or the MediaCodec API)
  				else if (param.getName().equalsIgnoreCase("audioapi")) {
  					if (param.getValue()!=null) {
  						if (param.getValue().equalsIgnoreCase("mr")) {
  							audioApi = MediaStream.MODE_MEDIARECORDER_API;
  						} else if (param.getValue().equalsIgnoreCase("mc")) {
  							audioApi = MediaStream.MODE_MEDIACODEC_API;
  						}
  					}					
  				}		
  
  				// TTL -> the client can modify the time to live of packets
  				// By default ttl=64
  				else if (param.getName().equalsIgnoreCase("ttl")) {
  					if (param.getValue()!=null) {
  						try {
  							int ttl = Integer.parseInt(param.getValue());
  							if (ttl<0) throw new IllegalStateException();
  							builder.setTimeToLive(ttl);
  						} catch (Exception e) {
  							throw new IllegalStateException("The TTL must be a positive integer !");
  						}
  					}
  				}
  
  				// H.264
  				else if (param.getName().equalsIgnoreCase("h264")) {
  					VideoQuality quality = VideoQuality.parseQuality(param.getValue());
  					builder.setVideoQuality(quality).setVideoEncoder(VIDEO_H264);
  				}
  
  				// H.263
  				else if (param.getName().equalsIgnoreCase("h263")) {
  					VideoQuality quality = VideoQuality.parseQuality(param.getValue());
  					builder.setVideoQuality(quality).setVideoEncoder(VIDEO_H263);
  				}
  
  				// AMR
  				else if (param.getName().equalsIgnoreCase("amrnb") || param.getName().equalsIgnoreCase("amr")) {
  					AudioQuality quality = AudioQuality.parseQuality(param.getValue());
  					builder.setAudioQuality(quality).setAudioEncoder(AUDIO_AMRNB);
  				}
  
  				// AAC
  				else if (param.getName().equalsIgnoreCase("aac")) {
  					AudioQuality quality = AudioQuality.parseQuality(param.getValue());
  					builder.setAudioQuality(quality).setAudioEncoder(AUDIO_AAC);
  				}
  
  			}
  
  		}
  
  		if (builder.getVideoEncoder()==VIDEO_NONE && builder.getAudioEncoder()==AUDIO_NONE) {
  			SessionBuilder b = SessionBuilder.getInstance();
  			builder.setVideoEncoder(b.getVideoEncoder());
  			builder.setAudioEncoder(b.getAudioEncoder());
  		}
  
  		Session session = builder.build();
  		
  		if (videoApi>0 && session.getVideoTrack() != null) {
  			session.getVideoTrack().setStreamingMethod(videoApi);
  		}
  		
  		if (audioApi>0 && session.getAudioTrack() != null) {
  			session.getAudioTrack().setStreamingMethod(audioApi);
  		}
  		
  		return session;
  
  	}
  
  }
  