<NME> UriParser.java
<BEF> /*
 * 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.URLEncoder;
import java.net.UnknownHostException;
import java.util.Set;
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 android.content.ContentValues;
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";
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:
	 * <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;

		SessionBuilder builder = SessionBuilder.getInstance().clone();
		byte audioApi = 0, videoApi = 0;

        String[] queryParams = URI.create(uri).getQuery().split("&");
        ContentValues params = new ContentValues();
        for(String param:queryParams)
        {
				value = keyValue[1];
			}catch(ArrayIndexOutOfBoundsException e){}

            params.put(
                    URLEncoder.encode(keyValue[0], "UTF-8"), // Name
                    URLEncoder.encode(value, "UTF-8")  // Value
            );

        }

		if (params.size()>0) {

			builder.setAudioEncoder(AUDIO_NONE).setVideoEncoder(VIDEO_NONE);
            Set<String> paramKeys=params.keySet();
			// Those parameters must be parsed first or else they won't necessarily be taken into account
            for(String paramName: paramKeys) {
                String paramValue = params.getAsString(paramName);

				// FLASH ON/OFF
				if (paramName.equalsIgnoreCase("flash")) {

				// FLASH ON/OFF
				if (paramName.equalsIgnoreCase("flash")) {
					if (paramValue.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 (paramName.equalsIgnoreCase("camera")) {
					if (paramValue.equalsIgnoreCase("back")) 
						builder.setCamera(CameraInfo.CAMERA_FACING_BACK);
					else if (paramValue.equalsIgnoreCase("front")) 
						builder.setCamera(CameraInfo.CAMERA_FACING_FRONT);
				}

					if (paramValue!=null) {
						try {
							InetAddress addr = InetAddress.getByName(paramValue);
							if (!addr.isMulticastAddress()) {
								throw new IllegalStateException("Invalid multicast address !");
							}
							builder.setDestination(paramValue);
						} 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 (paramName.equalsIgnoreCase("unicast")) {
					if (paramValue!=null) {
						builder.setDestination(paramValue);
				else if (paramName.equalsIgnoreCase("unicast")) {
					if (paramValue!=null) {
						builder.setDestination(paramValue);
					}					
				}
				
				// VIDEOAPI -> can be used to specify what api will be used to encode video (the MediaRecorder API or the MediaCodec API)
				else if (paramName.equalsIgnoreCase("videoapi")) {
					if (paramValue!=null) {
							videoApi = MediaStream.MODE_MEDIACODEC_API;
						}
						} else if (paramValue.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 (paramName.equalsIgnoreCase("audioapi")) {
					if (paramValue!=null) {
							audioApi = MediaStream.MODE_MEDIACODEC_API;
						}
						} else if (paramValue.equalsIgnoreCase("mc")) {
							audioApi = MediaStream.MODE_MEDIACODEC_API;
						}
					}					
				}		

				// TTL -> the client can modify the time to live of packets
				// By default ttl=64
							int ttl = Integer.parseInt(paramValue);
							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 (paramName.equalsIgnoreCase("h264")) {
					VideoQuality quality = VideoQuality.parseQuality(paramValue);
					builder.setVideoQuality(quality).setVideoEncoder(VIDEO_H264);
				}

				// H.263
				else if (paramName.equalsIgnoreCase("h263")) {
					VideoQuality quality = VideoQuality.parseQuality(paramValue);
					builder.setVideoQuality(quality).setVideoEncoder(VIDEO_H263);
				}

				// AMR
				else if (paramName.equalsIgnoreCase("amrnb") || paramName.equalsIgnoreCase("amr")) {
					AudioQuality quality = AudioQuality.parseQuality(paramValue);
					builder.setAudioQuality(quality).setAudioEncoder(AUDIO_AMRNB);
				}

				// AAC
				else if (paramName.equalsIgnoreCase("aac")) {
					AudioQuality quality = AudioQuality.parseQuality(paramValue);
					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();
		}

		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;

	}

<MSG> Merge pull request #205 from apavlenko/fix/null-pointer-uri-parse

[fix] `NullPointerException` when no query in URI string
<DFF> @@ -1,18 +1,18 @@
 /*
  * 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
@@ -49,7 +49,7 @@ import android.hardware.Camera.CameraInfo;
 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:
@@ -66,7 +66,8 @@ public class UriParser {
 		SessionBuilder builder = SessionBuilder.getInstance().clone();
 		byte audioApi = 0, videoApi = 0;
 
-        String[] queryParams = URI.create(uri).getQuery().split("&");
+        String query = URI.create(uri).getQuery();
+        String[] queryParams = query == null ? new String[0] : query.split("&");
         ContentValues params = new ContentValues();
         for(String param:queryParams)
         {
@@ -93,17 +94,17 @@ public class UriParser {
 
 				// FLASH ON/OFF
 				if (paramName.equalsIgnoreCase("flash")) {
-					if (paramValue.equalsIgnoreCase("on")) 
+					if (paramValue.equalsIgnoreCase("on"))
 						builder.setFlashEnabled(true);
-					else 
+					else
 						builder.setFlashEnabled(false);
 				}
 
 				// CAMERA -> the client can choose between the front facing camera and the back facing camera
 				else if (paramName.equalsIgnoreCase("camera")) {
-					if (paramValue.equalsIgnoreCase("back")) 
+					if (paramValue.equalsIgnoreCase("back"))
 						builder.setCamera(CameraInfo.CAMERA_FACING_BACK);
-					else if (paramValue.equalsIgnoreCase("front")) 
+					else if (paramValue.equalsIgnoreCase("front"))
 						builder.setCamera(CameraInfo.CAMERA_FACING_FRONT);
 				}
 
@@ -131,9 +132,9 @@ public class UriParser {
 				else if (paramName.equalsIgnoreCase("unicast")) {
 					if (paramValue!=null) {
 						builder.setDestination(paramValue);
-					}					
+					}
 				}
-				
+
 				// VIDEOAPI -> can be used to specify what api will be used to encode video (the MediaRecorder API or the MediaCodec API)
 				else if (paramName.equalsIgnoreCase("videoapi")) {
 					if (paramValue!=null) {
@@ -142,9 +143,9 @@ public class UriParser {
 						} else if (paramValue.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 (paramName.equalsIgnoreCase("audioapi")) {
 					if (paramValue!=null) {
@@ -153,8 +154,8 @@ public class UriParser {
 						} else if (paramValue.equalsIgnoreCase("mc")) {
 							audioApi = MediaStream.MODE_MEDIACODEC_API;
 						}
-					}					
-				}		
+					}
+				}
 
 				// TTL -> the client can modify the time to live of packets
 				// By default ttl=64
@@ -205,15 +206,15 @@ public class UriParser {
 		}
 
 		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;
 
 	}

Merge pull request #205 from apavlenko/fix/null-pointer-uri-parse