enumIpAddr = niFace.getInetAddresses();
764 | while (enumIpAddr.hasMoreElements()) {
765 | InetAddress mInetAddress = enumIpAddr.nextElement();
766 | // 所获取的网络地址不是127.0.0.1时返回得得到的IP
767 | if (!mInetAddress.isLoopbackAddress()
768 | && InetAddressUtils.isIPv4Address(mInetAddress
769 | .getHostAddress())) {
770 | return mInetAddress.getHostAddress().toString();
771 | }
772 | }
773 | }
774 | } catch (SocketException e) {
775 |
776 | }
777 | return null;
778 | }
779 |
780 | }
781 |
--------------------------------------------------------------------------------
/src/com/example/mynanohttpd/NanoHTTPD.java:
--------------------------------------------------------------------------------
1 | package com.example.mynanohttpd;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.ByteArrayInputStream;
5 | import java.io.File;
6 | import java.io.FileInputStream;
7 | import java.io.IOException;
8 | import java.io.InputStream;
9 | import java.io.InputStreamReader;
10 | import java.io.OutputStream;
11 | import java.io.PrintWriter;
12 | import java.net.ServerSocket;
13 | import java.net.Socket;
14 | import java.net.URLEncoder;
15 | import java.util.Date;
16 | import java.util.Enumeration;
17 | import java.util.Vector;
18 | import java.util.Hashtable;
19 | import java.util.Locale;
20 | import java.util.Properties;
21 | import java.util.StringTokenizer;
22 | import java.util.TimeZone;
23 |
24 | import java.io.ByteArrayOutputStream;
25 | import java.io.FileOutputStream;
26 |
27 | /**
28 | * A simple, tiny, nicely embeddable HTTP 1.0 (partially 1.1) server in Java
29 | *
30 | * NanoHTTPD version 1.24,
31 | * Copyright © 2001,2005-2011 Jarno Elonen (elonen@iki.fi, http://iki.fi/elonen/)
32 | * and Copyright © 2010 Konstantinos Togias (info@ktogias.gr, http://ktogias.gr)
33 | *
34 | *
Features + limitations:
35 | *
36 | * - Only one Java file
37 | * - Java 1.1 compatible
38 | * - Released as open source, Modified BSD licence
39 | * - No fixed config files, logging, authorization etc. (Implement yourself if you need them.)
40 | * - Supports parameter parsing of GET and POST methods
41 | * - Supports both dynamic content and file serving
42 | * - Supports file upload (since version 1.2, 2010)
43 | * - Supports partial content (streaming)
44 | * - Supports ETags
45 | * - Never caches anything
46 | * - Doesn't limit bandwidth, request time or simultaneous connections
47 | * - Default code serves files and shows all HTTP parameters and headers
48 | * - File server supports directory listing, index.html and index.htm
49 | * - File server supports partial content (streaming)
50 | * - File server supports ETags
51 | * - File server does the 301 redirection trick for directories without '/'
52 | * - File server supports simple skipping for files (continue download)
53 | * - File server serves also very long files without memory overhead
54 | * - Contains a built-in list of most common mime types
55 | * - All header names are converted lowercase so they don't vary between browsers/clients
56 | *
57 | *
58 | *
59 | * Ways to use:
60 | *
61 | * - Run as a standalone app, serves files and shows requests
62 | * - Subclass serve() and embed to your own program
63 | * - Call serveFile() from serve() with your own base directory
64 | *
65 | *
66 | *
67 | * See the end of the source file for distribution license
68 | * (Modified BSD licence)
69 | */
70 | public class NanoHTTPD
71 | {
72 | // ==================================================
73 | // API parts
74 | // ==================================================
75 |
76 | /**
77 | * Override this to customize the server.
78 | *
79 | * (By default, this delegates to serveFile() and allows directory listing.)
80 | *
81 | * @param uri Percent-decoded URI without parameters, for example "/index.cgi"
82 | * @param method "GET", "POST" etc.
83 | * @param parms Parsed, percent decoded parameters from URI and, in case of POST, data.
84 | * @param header Header entries, percent decoded
85 | * @return HTTP response, see class Response for details
86 | */
87 | public Response serve( String uri, String method, Properties header, Properties parms, Properties files )
88 | {
89 | System.out.println( method + " '" + uri + "' " );
90 |
91 | Enumeration e = header.propertyNames();
92 | while ( e.hasMoreElements())
93 | {
94 | String value = (String)e.nextElement();
95 | System.out.println( " HDR: '" + value + "' = '" +
96 | header.getProperty( value ) + "'" );
97 | }
98 | e = parms.propertyNames();
99 | while ( e.hasMoreElements())
100 | {
101 | String value = (String)e.nextElement();
102 | System.out.println( " PRM: '" + value + "' = '" +
103 | parms.getProperty( value ) + "'" );
104 | }
105 | e = files.propertyNames();
106 | while ( e.hasMoreElements())
107 | {
108 | String value = (String)e.nextElement();
109 | System.out.println( " UPLOADED: '" + value + "' = '" +
110 | files.getProperty( value ) + "'" );
111 | }
112 |
113 | return serveFile( uri, header, myRootDir, true );
114 | }
115 |
116 | /**
117 | * Override this to handle a request is done.
118 | *
119 | * (By default, do nothing)
120 | *
121 | */
122 | public void serveDone(Response r) {
123 | }
124 |
125 | /**
126 | * HTTP response.
127 | * Return one of these from serve().
128 | */
129 | public class Response
130 | {
131 | /**
132 | * Default constructor: response = HTTP_OK, data = mime = 'null'
133 | */
134 | public Response()
135 | {
136 | this.status = HTTP_OK;
137 | }
138 |
139 | /**
140 | * Basic constructor.
141 | */
142 | public Response( String status, String mimeType, InputStream data )
143 | {
144 | this.status = status;
145 | this.mimeType = mimeType;
146 | this.data = data;
147 | }
148 |
149 | /**
150 | * Convenience method that makes an InputStream out of
151 | * given text.
152 | */
153 | public Response( String status, String mimeType, String txt )
154 | {
155 | this.status = status;
156 | this.mimeType = mimeType;
157 | try
158 | {
159 | this.data = new ByteArrayInputStream( txt.getBytes("UTF-8"));
160 | }
161 | catch ( java.io.UnsupportedEncodingException uee )
162 | {
163 | uee.printStackTrace();
164 | }
165 | }
166 |
167 | /**
168 | * Adds given line to the header.
169 | */
170 | public void addHeader( String name, String value )
171 | {
172 | header.put( name, value );
173 | }
174 |
175 | /**
176 | * HTTP status code after processing, e.g. "200 OK", HTTP_OK
177 | */
178 | public String status;
179 |
180 | /**
181 | * MIME type of content, e.g. "text/html"
182 | */
183 | public String mimeType;
184 |
185 | /**
186 | * Data of the response, may be null.
187 | */
188 | public InputStream data;
189 |
190 | /**
191 | * Headers for the HTTP response. Use addHeader()
192 | * to add lines.
193 | */
194 | public Properties header = new Properties();
195 |
196 | /**
197 | * Is streaming mode
198 | */
199 | public boolean isStreaming = false;
200 | }
201 |
202 | /**
203 | * Some HTTP response status codes
204 | */
205 | public static final String
206 | HTTP_OK = "200 OK",
207 | HTTP_PARTIALCONTENT = "206 Partial Content",
208 | HTTP_RANGE_NOT_SATISFIABLE = "416 Requested Range Not Satisfiable",
209 | HTTP_REDIRECT = "301 Moved Permanently",
210 | HTTP_FORBIDDEN = "403 Forbidden",
211 | HTTP_NOTFOUND = "404 Not Found",
212 | HTTP_BADREQUEST = "400 Bad Request",
213 | HTTP_INTERNALERROR = "500 Internal Server Error",
214 | HTTP_NOTIMPLEMENTED = "501 Not Implemented";
215 |
216 | /**
217 | * Common mime types for dynamic content
218 | */
219 | public static final String
220 | MIME_PLAINTEXT = "text/plain",
221 | MIME_HTML = "text/html",
222 | MIME_DEFAULT_BINARY = "application/octet-stream",
223 | MIME_XML = "text/xml";
224 |
225 | // ==================================================
226 | // Socket & server code
227 | // ==================================================
228 |
229 | /**
230 | * Starts a HTTP server to given port.
231 | * Throws an IOException if the socket is already in use
232 | */
233 | public NanoHTTPD( int port, File wwwroot ) throws IOException
234 | {
235 | myTcpPort = port;
236 | this.myRootDir = wwwroot;
237 | myServerSocket = new ServerSocket( myTcpPort );
238 | myThread = new Thread( new Runnable()
239 | {
240 | public void run()
241 | {
242 | try
243 | {
244 | while( true )
245 | new HTTPSession( myServerSocket.accept());
246 | }
247 | catch ( IOException ioe )
248 | {}
249 | }
250 | });
251 | myThread.setDaemon( true );
252 | myThread.start();
253 | }
254 |
255 | /**
256 | * Stops the server.
257 | */
258 | public void stop()
259 | {
260 | try
261 | {
262 | myServerSocket.close();
263 | myThread.join();
264 | }
265 | catch ( IOException ioe ) {}
266 | catch ( InterruptedException e ) {}
267 | }
268 |
269 |
270 | /**
271 | * Starts as a standalone file server and waits for Enter.
272 | */
273 | public static void main( String[] args )
274 | {
275 | System.out.println( "NanoHTTPD 1.24 (C) 2001,2005-2011 Jarno Elonen and (C) 2010 Konstantinos Togias\n" +
276 | "(Command line options: [-p port] [-d root-dir] [--licence])\n" );
277 |
278 | // Defaults
279 | int port = 80;
280 | File wwwroot = new File(".").getAbsoluteFile();
281 |
282 | // Show licence if requested
283 | for ( int i=0; i= 0 && size > 0 )
392 | {
393 | rlen = is.read(buf, 0, 512);
394 | size -= rlen;
395 | if (rlen > 0)
396 | f.write(buf, 0, rlen);
397 | }
398 |
399 | // Get the raw body as a byte []
400 | byte [] fbuf = f.toByteArray();
401 |
402 | // Create a BufferedReader for easily reading it as string.
403 | ByteArrayInputStream bin = new ByteArrayInputStream(fbuf);
404 | BufferedReader in = new BufferedReader( new InputStreamReader(bin));
405 |
406 | // If the method is POST, there may be parameters
407 | // in data section, too, read it:
408 | if ( method.equalsIgnoreCase( "POST" ))
409 | {
410 | String contentType = "";
411 | String contentTypeHeader = header.getProperty("content-type");
412 | StringTokenizer st = new StringTokenizer( contentTypeHeader , "; " );
413 | if ( st.hasMoreTokens()) {
414 | contentType = st.nextToken();
415 | }
416 |
417 | if (contentType.equalsIgnoreCase("multipart/form-data"))
418 | {
419 | // Handle multipart/form-data
420 | if ( !st.hasMoreTokens())
421 | sendError( HTTP_BADREQUEST, "BAD REQUEST: Content type is multipart/form-data but boundary missing. Usage: GET /example/file.html" );
422 | String boundaryExp = st.nextToken();
423 | st = new StringTokenizer( boundaryExp , "=" );
424 | if (st.countTokens() != 2)
425 | sendError( HTTP_BADREQUEST, "BAD REQUEST: Content type is multipart/form-data but boundary syntax error. Usage: GET /example/file.html" );
426 | st.nextToken();
427 | String boundary = st.nextToken();
428 |
429 | decodeMultipartData(boundary, fbuf, in, parms, files);
430 | }
431 | else
432 | {
433 | // Handle application/x-www-form-urlencoded
434 | String postLine = "";
435 | char pbuf[] = new char[512];
436 | int read = in.read(pbuf);
437 | while ( read >= 0 && !postLine.endsWith("\r\n") )
438 | {
439 | postLine += String.valueOf(pbuf, 0, read);
440 | read = in.read(pbuf);
441 | }
442 | postLine = postLine.trim();
443 | decodeParms( postLine, parms );
444 | }
445 | }
446 |
447 | // Ok, now do the serve()
448 | Response r = serve( uri, method, header, parms, files );
449 | if ( r == null )
450 | sendError( HTTP_INTERNALERROR, "SERVER INTERNAL ERROR: Serve() returned a null response." );
451 | else
452 | sendResponse( r.status, r.mimeType, r.header, r.data, r.isStreaming );
453 |
454 | in.close();
455 | is.close();
456 |
457 | // Ok, finish this http request
458 | serveDone(r);
459 | }
460 | catch ( IOException ioe )
461 | {
462 | try
463 | {
464 | sendError( HTTP_INTERNALERROR, "SERVER INTERNAL ERROR: IOException: " + ioe.getMessage());
465 | }
466 | catch ( Throwable t ) {}
467 | }
468 | catch ( InterruptedException ie )
469 | {
470 | // Thrown by sendError, ignore and exit the thread.
471 | }
472 |
473 | }
474 |
475 | /**
476 | * Decodes the sent headers and loads the data into
477 | * java Properties' key - value pairs
478 | **/
479 | private void decodeHeader(BufferedReader in, Properties pre, Properties parms, Properties header)
480 | throws InterruptedException
481 | {
482 | try {
483 | // Read the request line
484 | String inLine = in.readLine();
485 | if (inLine == null) return;
486 | StringTokenizer st = new StringTokenizer( inLine );
487 | if ( !st.hasMoreTokens())
488 | sendError( HTTP_BADREQUEST, "BAD REQUEST: Syntax error. Usage: GET /example/file.html" );
489 |
490 | String method = st.nextToken();
491 | pre.put("method", method);
492 |
493 | if ( !st.hasMoreTokens())
494 | sendError( HTTP_BADREQUEST, "BAD REQUEST: Missing URI. Usage: GET /example/file.html" );
495 |
496 | String uri = st.nextToken();
497 |
498 | // Decode parameters from the URI
499 | int qmi = uri.indexOf( '?' );
500 | if ( qmi >= 0 )
501 | {
502 | decodeParms( uri.substring( qmi+1 ), parms );
503 | uri = decodePercent( uri.substring( 0, qmi ));
504 | }
505 | else uri = decodePercent(uri);
506 |
507 | // If there's another token, it's protocol version,
508 | // followed by HTTP headers. Ignore version but parse headers.
509 | // NOTE: this now forces header names lowercase since they are
510 | // case insensitive and vary by client.
511 | if ( st.hasMoreTokens())
512 | {
513 | String line = in.readLine();
514 | while ( line != null && line.trim().length() > 0 )
515 | {
516 | int p = line.indexOf( ':' );
517 | if ( p >= 0 )
518 | header.put( line.substring(0,p).trim().toLowerCase(), line.substring(p+1).trim());
519 | line = in.readLine();
520 | }
521 | }
522 |
523 | pre.put("uri", uri);
524 | }
525 | catch ( IOException ioe )
526 | {
527 | sendError( HTTP_INTERNALERROR, "SERVER INTERNAL ERROR: IOException: " + ioe.getMessage());
528 | }
529 | }
530 |
531 | /**
532 | * Decodes the Multipart Body data and put it
533 | * into java Properties' key - value pairs.
534 | **/
535 | private void decodeMultipartData(String boundary, byte[] fbuf, BufferedReader in, Properties parms, Properties files)
536 | throws InterruptedException
537 | {
538 | try
539 | {
540 | int[] bpositions = getBoundaryPositions(fbuf,boundary.getBytes());
541 | int boundarycount = 1;
542 | String mpline = in.readLine();
543 | while ( mpline != null )
544 | {
545 | if (mpline.indexOf(boundary) == -1)
546 | sendError( HTTP_BADREQUEST, "BAD REQUEST: Content type is multipart/form-data but next chunk does not start with boundary. Usage: GET /example/file.html" );
547 | boundarycount++;
548 | Properties item = new Properties();
549 | mpline = in.readLine();
550 | while (mpline != null && mpline.trim().length() > 0)
551 | {
552 | int p = mpline.indexOf( ':' );
553 | if (p != -1)
554 | item.put( mpline.substring(0,p).trim().toLowerCase(), mpline.substring(p+1).trim());
555 | mpline = in.readLine();
556 | }
557 | if (mpline != null)
558 | {
559 | String contentDisposition = item.getProperty("content-disposition");
560 | if (contentDisposition == null)
561 | {
562 | sendError( HTTP_BADREQUEST, "BAD REQUEST: Content type is multipart/form-data but no content-disposition info found. Usage: GET /example/file.html" );
563 | }
564 | StringTokenizer st = new StringTokenizer( contentDisposition , "; " );
565 | Properties disposition = new Properties();
566 | while ( st.hasMoreTokens())
567 | {
568 | String token = st.nextToken();
569 | int p = token.indexOf( '=' );
570 | if (p!=-1)
571 | disposition.put( token.substring(0,p).trim().toLowerCase(), token.substring(p+1).trim());
572 | }
573 | String pname = disposition.getProperty("name");
574 | pname = pname.substring(1,pname.length()-1);
575 |
576 | String value = "";
577 | if (item.getProperty("content-type") == null) {
578 | while (mpline != null && mpline.indexOf(boundary) == -1)
579 | {
580 | mpline = in.readLine();
581 | if ( mpline != null)
582 | {
583 | int d = mpline.indexOf(boundary);
584 | if (d == -1)
585 | value+=mpline;
586 | else
587 | value+=mpline.substring(0,d-2);
588 | }
589 | }
590 | }
591 | else
592 | {
593 | if (boundarycount> bpositions.length)
594 | sendError( HTTP_INTERNALERROR, "Error processing request" );
595 | int offset = stripMultipartHeaders(fbuf, bpositions[boundarycount-2]);
596 | String path = saveTmpFile(fbuf, offset, bpositions[boundarycount-1]-offset-4);
597 | files.put(pname, path);
598 | value = disposition.getProperty("filename");
599 | value = value.substring(1,value.length()-1);
600 | do {
601 | mpline = in.readLine();
602 | } while (mpline != null && mpline.indexOf(boundary) == -1);
603 | }
604 | parms.put(pname, value);
605 | }
606 | }
607 | }
608 | catch ( IOException ioe )
609 | {
610 | sendError( HTTP_INTERNALERROR, "SERVER INTERNAL ERROR: IOException: " + ioe.getMessage());
611 | }
612 | }
613 |
614 | /**
615 | * Find the byte positions where multipart boundaries start.
616 | **/
617 | public int[] getBoundaryPositions(byte[] b, byte[] boundary)
618 | {
619 | int matchcount = 0;
620 | int matchbyte = -1;
621 | Vector matchbytes = new Vector();
622 | for (int i=0; i 0)
660 | {
661 | String tmpdir = System.getProperty("java.io.tmpdir");
662 | try {
663 | File temp = File.createTempFile("NanoHTTPD", "", new File(tmpdir));
664 | OutputStream fstream = new FileOutputStream(temp);
665 | fstream.write(b, offset, len);
666 | fstream.close();
667 | path = temp.getAbsolutePath();
668 | } catch (Exception e) { // Catch exception if any
669 | System.err.println("Error: " + e.getMessage());
670 | }
671 | }
672 | return path;
673 | }
674 |
675 |
676 | /**
677 | * It returns the offset separating multipart file headers
678 | * from the file's data.
679 | **/
680 | private int stripMultipartHeaders(byte[] b, int offset)
681 | {
682 | int i = 0;
683 | for (i=offset; i
693 | * For example: "an+example%20string" -> "an example string"
694 | */
695 | private String decodePercent( String str ) throws InterruptedException
696 | {
697 | try
698 | {
699 | StringBuffer sb = new StringBuffer();
700 | for( int i=0; i= 0 )
745 | p.put( decodePercent( e.substring( 0, sep )).trim(),
746 | decodePercent( e.substring( sep+1 )));
747 | }
748 | }
749 |
750 | /**
751 | * Returns an error message as a HTTP response and
752 | * throws InterruptedException to stop further request processing.
753 | */
754 | private void sendError( String status, String msg ) throws InterruptedException
755 | {
756 | sendResponse( status, MIME_PLAINTEXT, null, new ByteArrayInputStream( msg.getBytes()), false);
757 | throw new InterruptedException();
758 | }
759 |
760 | /**
761 | * Sends given response to the socket.
762 | */
763 | private void sendResponse( String status, String mime, Properties header, InputStream data , boolean isStreaming)
764 | {
765 | LogUtils.i("*************sendResponse---data=="+data);
766 | LogUtils.i("*************isStreaming---=="+isStreaming);
767 | try
768 | {
769 | if ( status == null )
770 | throw new Error( "sendResponse(): Status can't be null." );
771 |
772 | OutputStream out = mySocket.getOutputStream();
773 | PrintWriter pw = new PrintWriter( out );
774 | pw.print("HTTP/1.0 " + status + " \r\n");
775 |
776 | if ( mime != null )
777 | pw.print("Content-Type: " + mime + "\r\n");
778 |
779 | if ( header == null || header.getProperty( "Date" ) == null )
780 | pw.print( "Date: " + gmtFrmt.format( new Date()) + "\r\n");
781 |
782 | if ( header != null )
783 | {
784 | Enumeration e = header.keys();
785 | while ( e.hasMoreElements())
786 | {
787 | String key = (String)e.nextElement();
788 | String value = header.getProperty( key );
789 | pw.print( key + ": " + value + "\r\n");
790 | }
791 | }
792 |
793 | pw.print("\r\n");
794 | pw.flush();
795 |
796 | if ( data != null )
797 | {
798 | LogUtils.d("hava data----");
799 | if ( isStreaming == false) {
800 | int pending = data.available(); // This is to support partial sends, see serveFile()
801 | byte[] buff = new byte[2048];
802 | while (pending>0)
803 | {
804 | int read = data.read( buff, 0, ( (pending>2048) ? 2048 : pending ));
805 | if (read <= 0) break;
806 | out.write( buff, 0, read );
807 | pending -= read;
808 | }
809 | } else {
810 | LogUtils.d("isStreaming == hava data----");
811 | byte[] buff = new byte[1024*16];
812 | while (true)
813 | {
814 | int read = data.read( buff, 0, 1024*16);
815 | if (read < 0)
816 | break;
817 | if (read > 0)
818 | out.write( buff, 0, read );
819 | }
820 | }
821 | }
822 | out.flush();
823 | out.close();
824 | if ( data != null )
825 | data.close();
826 | }
827 | catch( IOException ioe )
828 | {
829 | // Couldn't write? No can do.
830 | try { mySocket.close(); } catch( Throwable t ) {}
831 | }
832 | }
833 |
834 | private Socket mySocket;
835 | }
836 |
837 | /**
838 | * URL-encodes everything between "/"-characters.
839 | * Encodes spaces as '%20' instead of '+'.
840 | */
841 | private String encodeUri( String uri )
842 | {
843 | String newUri = "";
844 | StringTokenizer st = new StringTokenizer( uri, "/ ", true );
845 | while ( st.hasMoreTokens())
846 | {
847 | String tok = st.nextToken();
848 | if ( tok.equals( "/" ))
849 | newUri += "/";
850 | else if ( tok.equals( " " ))
851 | newUri += "%20";
852 | else
853 | {
854 | newUri += URLEncoder.encode( tok );
855 | // For Java 1.4 you'll want to use this instead:
856 | // try { newUri += URLEncoder.encode( tok, "UTF-8" ); } catch ( java.io.UnsupportedEncodingException uee ) {}
857 | }
858 | }
859 | return newUri;
860 | }
861 |
862 | private int myTcpPort;
863 | private final ServerSocket myServerSocket;
864 | private Thread myThread;
865 | private File myRootDir;
866 |
867 | // ==================================================
868 | // File server code
869 | // ==================================================
870 |
871 | /**
872 | * Serves file from homeDir and its' subdirectories (only).
873 | * Uses only URI, ignores all headers and HTTP parameters.
874 | */
875 | public Response serveFile( String uri, Properties header, File homeDir,
876 | boolean allowDirectoryListing )
877 | {
878 | Response res = null;
879 |
880 | // Make sure we won't die of an exception later
881 | if ( !homeDir.isDirectory())
882 | res = new Response( HTTP_INTERNALERROR, MIME_PLAINTEXT,
883 | "INTERNAL ERRROR: serveFile(): given homeDir is not a directory." );
884 |
885 | if ( res == null )
886 | {
887 | // Remove URL arguments
888 | uri = uri.trim().replace( File.separatorChar, '/' );
889 | if ( uri.indexOf( '?' ) >= 0 )
890 | uri = uri.substring(0, uri.indexOf( '?' ));
891 |
892 | // Prohibit getting out of current directory
893 | if ( uri.startsWith( ".." ) || uri.endsWith( ".." ) || uri.indexOf( "../" ) >= 0 )
894 | res = new Response( HTTP_FORBIDDEN, MIME_PLAINTEXT,
895 | "FORBIDDEN: Won't serve ../ for security reasons." );
896 | }
897 |
898 | File f = new File( homeDir, uri );
899 | if ( res == null && !f.exists()){
900 | res = new Response( HTTP_NOTFOUND, MIME_PLAINTEXT,
901 | "Error 404, file not found." );
902 | }
903 |
904 | // List the directory, if necessary
905 | if ( res == null && f.isDirectory())
906 | {
907 | // Browsers get confused without '/' after the
908 | // directory, send a redirect.
909 | if ( !uri.endsWith( "/" ))
910 | {
911 | uri += "/";
912 | res = new Response( HTTP_REDIRECT, MIME_HTML,
913 | "Redirected: " +
914 | uri + "");
915 | res.addHeader( "Location", uri );
916 | }
917 |
918 | if ( res == null )
919 | {
920 | // First try index.html and index.htm
921 | if ( new File( f, "index.html" ).exists())
922 | f = new File( homeDir, uri + "/index.html" );
923 | else if ( new File( f, "index.htm" ).exists())
924 | f = new File( homeDir, uri + "/index.htm" );
925 | // No index file, list the directory if it is readable
926 | else if ( allowDirectoryListing && f.canRead() )
927 | {
928 | String[] files = f.list();
929 | String msg = "Directory " + uri + "
";
930 |
931 | if ( uri.length() > 1 )
932 | {
933 | String u = uri.substring( 0, uri.length()-1 );
934 | int slash = u.lastIndexOf( '/' );
935 | if ( slash >= 0 && slash < u.length())
936 | msg += "..
";
937 | }
938 |
939 | if (files!=null)
940 | {
941 | for ( int i=0; i";
948 | files[i] += "/";
949 | }
950 |
951 | msg += "" +
952 | files[i] + "";
953 |
954 | // Show file size
955 | if ( curFile.isFile())
956 | {
957 | long len = curFile.length();
958 | msg += " (";
959 | if ( len < 1024 )
960 | msg += len + " bytes";
961 | else if ( len < 1024 * 1024 )
962 | msg += len/1024 + "." + (len%1024/10%100) + " KB";
963 | else
964 | msg += len/(1024*1024) + "." + len%(1024*1024)/10%100 + " MB";
965 |
966 | msg += ")";
967 | }
968 | msg += "
";
969 | if ( dir ) msg += "";
970 | }
971 | }
972 | msg += "";
973 | res = new Response( HTTP_OK, MIME_HTML, msg );
974 | }
975 | else
976 | {
977 | res = new Response( HTTP_FORBIDDEN, MIME_PLAINTEXT,
978 | "FORBIDDEN: No directory listing." );
979 | }
980 | }
981 | }
982 |
983 | try
984 | {
985 | if ( res == null )
986 | {
987 | // Get MIME type from file name extension, if possible
988 | String mime = null;
989 | int dot = f.getCanonicalPath().lastIndexOf( '.' );
990 | if ( dot >= 0 )
991 | mime = (String)theMimeTypes.get( f.getCanonicalPath().substring( dot + 1 ).toLowerCase());
992 | if ( mime == null )
993 | mime = MIME_DEFAULT_BINARY;
994 |
995 | // Calculate etag
996 | String etag = Integer.toHexString((f.getAbsolutePath() + f.lastModified() + "" + f.length()).hashCode());
997 |
998 | // Support (simple) skipping:
999 | long startFrom = 0;
1000 | long endAt = -1;
1001 | String range = header.getProperty( "range" );
1002 | if ( range != null )
1003 | {
1004 | if ( range.startsWith( "bytes=" ))
1005 | {
1006 | range = range.substring( "bytes=".length());
1007 | int minus = range.indexOf( '-' );
1008 | try {
1009 | if ( minus > 0 )
1010 | {
1011 | startFrom = Long.parseLong( range.substring( 0, minus ));
1012 | endAt = Long.parseLong( range.substring( minus+1 ));
1013 | }
1014 | }
1015 | catch ( NumberFormatException nfe ) {}
1016 | }
1017 | }
1018 |
1019 | // Change return code and add Content-Range header when skipping is requested
1020 | long fileLen = f.length();
1021 | if (range != null && startFrom >= 0)
1022 | {
1023 | if ( startFrom >= fileLen)
1024 | {
1025 | res = new Response( HTTP_RANGE_NOT_SATISFIABLE, MIME_PLAINTEXT, "" );
1026 | res.addHeader( "Content-Range", "bytes 0-0/" + fileLen);
1027 | res.addHeader( "ETag", etag);
1028 | }
1029 | else
1030 | {
1031 | if ( endAt < 0 )
1032 | endAt = fileLen-1;
1033 | long newLen = endAt - startFrom + 1;
1034 | if ( newLen < 0 ) newLen = 0;
1035 |
1036 | final long dataLen = newLen;
1037 | FileInputStream fis = new FileInputStream( f ) {
1038 | public int available() throws IOException { return (int)dataLen; }
1039 | };
1040 | fis.skip( startFrom );
1041 |
1042 | res = new Response( HTTP_PARTIALCONTENT, mime, fis );
1043 | res.addHeader( "Content-Length", "" + dataLen);
1044 | res.addHeader( "Content-Range", "bytes " + startFrom + "-" + endAt + "/" + fileLen);
1045 | res.addHeader( "ETag", etag);
1046 | }
1047 | }
1048 | else
1049 | {
1050 | res = new Response( HTTP_OK, mime, new FileInputStream( f ));
1051 | res.addHeader( "Content-Length", "" + fileLen);
1052 | res.addHeader( "ETag", etag);
1053 | }
1054 | }
1055 | }
1056 | catch( IOException ioe )
1057 | {
1058 | res = new Response( HTTP_FORBIDDEN, MIME_PLAINTEXT, "FORBIDDEN: Reading file failed." );
1059 | }
1060 |
1061 | res.addHeader( "Accept-Ranges", "bytes"); // Announce that the file server accepts partial content requestes
1062 | return res;
1063 | }
1064 |
1065 | /**
1066 | * Hashtable mapping (String)FILENAME_EXTENSION -> (String)MIME_TYPE
1067 | */
1068 | private static Hashtable theMimeTypes = new Hashtable();
1069 | static
1070 | {
1071 | StringTokenizer st = new StringTokenizer(
1072 | "css text/css "+
1073 | "htm text/html "+
1074 | "html text/html "+
1075 | "xml text/xml "+
1076 | "txt text/plain "+
1077 | "asc text/plain "+
1078 | "gif image/gif "+
1079 | "jpg image/jpeg "+
1080 | "jpeg image/jpeg "+
1081 | "png image/png "+
1082 | "mp3 audio/mpeg "+
1083 | "m3u audio/mpeg-url " +
1084 | "mp4 video/mp4 " +
1085 | "ogv video/ogg " +
1086 | "flv video/x-flv " +
1087 | "mov video/quicktime " +
1088 | "swf application/x-shockwave-flash " +
1089 | "js application/javascript "+
1090 | "pdf application/pdf "+
1091 | "doc application/msword "+
1092 | "ogg application/x-ogg "+
1093 | "zip application/octet-stream "+
1094 | "exe application/octet-stream "+
1095 | "class application/octet-stream " );
1096 | while ( st.hasMoreTokens())
1097 | theMimeTypes.put( st.nextToken(), st.nextToken());
1098 | }
1099 |
1100 | /**
1101 | * GMT date formatter
1102 | */
1103 | private static java.text.SimpleDateFormat gmtFrmt;
1104 | static
1105 | {
1106 | gmtFrmt = new java.text.SimpleDateFormat( "E, d MMM yyyy HH:mm:ss 'GMT'", Locale.US);
1107 | gmtFrmt.setTimeZone(TimeZone.getTimeZone("GMT"));
1108 | }
1109 |
1110 | /**
1111 | * The distribution licence
1112 | */
1113 | private static final String LICENCE =
1114 | "Copyright (C) 2001,2005-2011 by Jarno Elonen \n"+
1115 | "and Copyright (C) 2010 by Konstantinos Togias \n"+
1116 | "\n"+
1117 | "Redistribution and use in source and binary forms, with or without\n"+
1118 | "modification, are permitted provided that the following conditions\n"+
1119 | "are met:\n"+
1120 | "\n"+
1121 | "Redistributions of source code must retain the above copyright notice,\n"+
1122 | "this list of conditions and the following disclaimer. Redistributions in\n"+
1123 | "binary form must reproduce the above copyright notice, this list of\n"+
1124 | "conditions and the following disclaimer in the documentation and/or other\n"+
1125 | "materials provided with the distribution. The name of the author may not\n"+
1126 | "be used to endorse or promote products derived from this software without\n"+
1127 | "specific prior written permission. \n"+
1128 | " \n"+
1129 | "THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n"+
1130 | "IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n"+
1131 | "OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n"+
1132 | "IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n"+
1133 | "INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n"+
1134 | "NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"+
1135 | "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"+
1136 | "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"+
1137 | "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"+
1138 | "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.";
1139 | }
1140 |
1141 |
--------------------------------------------------------------------------------
/src/com/example/mynanohttpd/NetInfoAdapter.java:
--------------------------------------------------------------------------------
1 | package com.example.mynanohttpd;
2 |
3 | import java.net.InetAddress;
4 | import java.net.NetworkInterface;
5 | import java.net.SocketException;
6 | import java.util.Enumeration;
7 | import java.util.HashMap;
8 | import java.util.Map;
9 |
10 | import android.content.Context;
11 | import android.net.ConnectivityManager;
12 | import android.net.NetworkInfo;
13 | import android.net.wifi.WifiInfo;
14 | import android.net.wifi.WifiManager;
15 | import android.util.Log;
16 | import android.telephony.TelephonyManager;
17 | import android.telephony.*;
18 |
19 |
20 | public class NetInfoAdapter {
21 |
22 | private static Map infoMap = new HashMap();
23 | private static Map phoneType = new HashMap();
24 | private static Map networkType = new HashMap();
25 |
26 | static {
27 | // Initialise some mappings
28 | phoneType.put(0,"None");
29 | phoneType.put(1,"GSM");
30 | phoneType.put(2,"CDMA");
31 |
32 | networkType.put(0,"Unknown");
33 | networkType.put(1,"GPRS");
34 | networkType.put(2,"EDGE");
35 | networkType.put(3,"UMTS");
36 | networkType.put(4,"CDMA");
37 | networkType.put(5,"EVDO_0");
38 | networkType.put(6,"EVDO_A");
39 | networkType.put(7,"1xRTT");
40 | networkType.put(8,"HSDPA");
41 | networkType.put(9,"HSUPA");
42 | networkType.put(10,"HSPA");
43 | networkType.put(11,"IDEN");
44 |
45 | infoMap.put("Cell", "false");
46 | infoMap.put("Mobile", "false");
47 | infoMap.put("Wi-Fi", "false");
48 | }
49 |
50 | public static void Update(Context context) {
51 | // Initialise the network information mapping
52 | infoMap.put("Cell", "false");
53 | TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
54 | if( tm != null ) {
55 | infoMap.put("Cell", "true");
56 | if ( tm.getCellLocation() != null) {
57 | infoMap.put("Cell location", tm.getCellLocation().toString());
58 | }
59 | infoMap.put("Cell type", getPhoneType(tm.getPhoneType()));
60 | }
61 |
62 | // Find out if we're connected to a network
63 | infoMap.put("Mobile", "false");
64 | infoMap.put("Wi-Fi", "false");
65 | ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
66 | NetworkInfo ni = (NetworkInfo) cm.getActiveNetworkInfo();
67 | if ( ni != null && ni.isConnected() ) {
68 | WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
69 | NetworkInterface intf = getInternetInterface();
70 | infoMap.put("IP", getIPAddress(intf));
71 | String type = (String) ni.getTypeName();
72 | if ( type.equalsIgnoreCase("mobile") ) {
73 | infoMap.put("Mobile", "true");
74 | infoMap.put("Mobile type", getNetworkType(tm.getNetworkType()));
75 | infoMap.put("Signal", "Good!");
76 | } else if ( wifi.isWifiEnabled() ) {
77 | WifiInfo wi = wifi.getConnectionInfo();
78 | infoMap.put("Wi-Fi", "true");
79 | infoMap.put("SSID", wi.getSSID());
80 | infoMap.put("Signal", "Good!");
81 | }
82 | }
83 | }
84 |
85 | public static String getInfo(String key) {
86 | return infoMap.containsKey(key)? infoMap.get(key): "";
87 | }
88 |
89 | private static String getPhoneType(Integer key) {
90 | if( phoneType.containsKey(key) ) {
91 | return phoneType.get(key);
92 | } else {
93 | return "unknown";
94 | }
95 | }
96 |
97 | private static String getNetworkType(Integer key) {
98 | if( networkType.containsKey(key) ) {
99 | return networkType.get(key);
100 | } else {
101 | return "unknown";
102 | }
103 | }
104 |
105 | private static String getIPAddress( NetworkInterface intf) {
106 | String result = "";
107 | for( Enumeration enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
108 | InetAddress inetAddress = enumIpAddr.nextElement();
109 | result = inetAddress.getHostAddress();
110 | }
111 | return result;
112 | }
113 |
114 | private static NetworkInterface getInternetInterface() {
115 | try {
116 | for (Enumeration en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
117 | NetworkInterface intf = en.nextElement();
118 | if( ! intf.equals(NetworkInterface.getByName("lo"))) {
119 | return intf;
120 | }
121 | }
122 | } catch (SocketException ex) {
123 | }
124 | return null;
125 | }
126 |
127 | }
128 |
--------------------------------------------------------------------------------
/src/com/example/mynanohttpd/PlayActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.mynanohttpd;
2 |
3 | import java.util.UUID;
4 |
5 | import org.apache.http.Header;
6 |
7 | import android.app.Activity;
8 | import android.content.SharedPreferences;
9 | import android.graphics.PixelFormat;
10 | import android.media.MediaPlayer;
11 | import android.net.Uri;
12 | import android.os.Bundle;
13 | import android.view.SurfaceHolder;
14 | import android.view.SurfaceView;
15 | import android.view.View;
16 | import android.view.View.OnClickListener;
17 | import android.widget.Button;
18 | import android.widget.Toast;
19 |
20 | import com.loopj.android.http.AsyncHttpResponseHandler;
21 |
22 | public class PlayActivity extends Activity implements SurfaceHolder.Callback {
23 |
24 | private static final String TAG = "com.ineoquest.Sample";
25 | private static final String PREFS = "com.ineoquest.Sample.prefs";
26 | private static final String USERUUID_PREF = "com.ineoquest.Sample.prefs.useruuid";
27 |
28 | private SurfaceView _mediaPlayerSurface;
29 | private SurfaceHolder _mediaPlayerSurfaceHolder;
30 | private MediaPlayer _mediaPlayer;
31 | // private AndroidMediaPlayerAdapter _androidMediaPlayerAdapter;
32 | // private ControlsFragment _controlsFragment;
33 | // private MediaPlayerFragment _mediaPlayerFragment;
34 | private UUID _userUUID;
35 | private String _userName;
36 | private boolean isSurfaveCreated;
37 | private Button playButton;
38 | private Button testNat;
39 |
40 | @Override
41 | protected void onCreate(Bundle savedInstanceState) {
42 | super.onCreate(savedInstanceState);
43 |
44 | setContentView(R.layout.mediaplayer_fragment);
45 | //
46 | _mediaPlayerSurface = (SurfaceView) findViewById(R.id.mediaPlayerSurface);
47 | _mediaPlayerSurfaceHolder = _mediaPlayerSurface.getHolder();
48 | _mediaPlayerSurfaceHolder.addCallback(PlayActivity.this);
49 |
50 | // _androidMediaPlayerAdapter = new AndroidMediaPlayerAdapter();
51 |
52 | //
53 | // retrieve our user uuid
54 | SharedPreferences settings = this.getSharedPreferences(PREFS, 0);
55 | String uuidValue = settings.getString(USERUUID_PREF, null);
56 |
57 | if (uuidValue != null) {
58 | String[] values = uuidValue.split("\\|");
59 |
60 | _userUUID = UUID.fromString(values[0]);
61 | _userName = values[1];
62 | } else {
63 | // _userUUID = UUIDHelper.UInt64ToUUID(0);
64 | _userName = "Default";
65 |
66 | // persist default values
67 | SharedPreferences.Editor settingsEditor = settings.edit();
68 | settingsEditor.putString(USERUUID_PREF,
69 | String.format("%s|%s", _userUUID.toString(), _userName));
70 | settingsEditor.commit();
71 | }
72 |
73 | // /
74 | // initialize the SDK
75 | // IQPegasus
76 | // .Configure()
77 | // .withAMPASM("ampasm-demo.ineoquest.ca", 9997)
78 | // .withAMPASM("iqdamp.ineoquest.ca", 9997)
79 | // // .withAMPASM("nowtv.ineoquest.ca", 9998)
80 | // .withSSLCertificateCheckingDisabled()
81 | // .withMediaPlayerAdapter(_androidMediaPlayerAdapter)
82 | // .withContext(this)
83 | // .withGeoLocation()
84 | // .withNetworkDetection()
85 | // .withAPIKey(
86 | // UUID.fromString("abcdefff-aaaa-bbaa-ffff-329bf39fa1e4"))
87 | // // .withVeriStreaListener(_veriStreamListener)
88 | // // .withHttpErrorListener(_httpErrorListener)
89 | // // .withAMPConnectionListener(_ampConnectionListener)
90 | // .withUserId(_userUUID).start();
91 |
92 | // /
93 | playButton = (Button) findViewById(R.id.paly);
94 | playButton.setOnClickListener(new OnClickListener() {
95 |
96 | @Override
97 | public void onClick(View v) {
98 | if (isSurfaveCreated) {
99 | startPlaying(null);
100 | isSurfaveCreated = false;
101 | }
102 | }
103 | });
104 |
105 | testNat = (Button) findViewById(R.id.testNAT);
106 | testNat.setOnClickListener(new OnClickListener() {
107 |
108 | @Override
109 | public void onClick(View v) {
110 |
111 | String url = "http://172.20.171.2:8080/index3.html";
112 |
113 | try {
114 | // String content =
115 | // CustomHttpClient.PostFromWebByHttpClient(getActivity(),
116 | // url);
117 | // LogUtils.e("the content ="+content);
118 |
119 | HttpGetJsonUtil.get(url, new AsyncHttpResponseHandler() {
120 |
121 | @Override
122 | public void onSuccess(int statueCode, Header[] arg1,
123 | byte[] result) {
124 | String content = new String(result);
125 | LogUtils.e("___________result________________= "
126 | + new String(result));
127 | }
128 |
129 | @Override
130 | public void onFailure(int arg0, Header[] arg1,
131 | byte[] arg2, Throwable arg3) {
132 | // LogUtils.e("___________error_________________="+new String(arg2));
133 | LogUtils.e("error message ="+arg3.getMessage());
134 | }
135 | });
136 |
137 | } catch (Exception e) {
138 | LogUtils.e("error " + e.getMessage());
139 | e.printStackTrace();
140 | }
141 |
142 | }
143 | });
144 |
145 | // LogUtils.e( "start play...");
146 | // try {
147 | // Thread.sleep(5000);
148 | // startPlaying(null);
149 | //
150 | // } catch (Exception e) {
151 | // // TODO: handle exception
152 | // }
153 |
154 | }
155 |
156 | // //////////////////////////////////////////////////////////////////////////
157 | @Override
158 | public void surfaceCreated(SurfaceHolder surfaceHolder) {
159 | LogUtils.e("Surface created.");
160 | }
161 |
162 | @Override
163 | public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i2,
164 | int i3) {
165 | LogUtils.e("Surface changed.");
166 | isSurfaveCreated = true;
167 | }
168 |
169 | @Override
170 | public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
171 | LogUtils.e("Surface destroyed.");
172 | }
173 |
174 | // ///////////////////////////////////////////
175 |
176 | private void startPlaying(final Uri uri) {
177 |
178 | new Thread(new Runnable() {
179 | @Override
180 | public void run() {
181 | try {
182 | // Sample.this.runOnUiThread(new Runnable() {
183 | // @Override
184 | // public void run() {
185 | // _mediaPlayerFragment.setMediaPlaying();
186 | // _controlsFragment.setMediaPlaying(selectedMedia.toString());
187 | // _controlsFragment.setStopMediaButtonText(R.string.please_wait_text);
188 | // _controlsFragment.setStopMediaButtonEnabled(false);
189 | //
190 | // }
191 | // });
192 |
193 | _mediaPlayer = new MediaPlayer();
194 | // _androidMediaPlayerAdapter.setMediaPlayer(_mediaPlayer);
195 |
196 | // add a listener to stop playing when the video is complete
197 | _mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
198 | @Override
199 | public void onCompletion(MediaPlayer mediaPlayer) {
200 | stopPlaying();
201 | }
202 | });
203 |
204 | // add a listener so we know when the media is prepared
205 | _mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
206 | @Override
207 | public void onPrepared(MediaPlayer mediaPlayer) {
208 | // Sample.this.runOnUiThread(new Runnable()
209 | // {
210 | // @Override
211 | // public void run() {
212 | // _controlsFragment.setStopMediaButtonText(R.string.stopPlaybackText);
213 | // _controlsFragment.setStopMediaButtonEnabled(true);
214 | // }
215 | // });
216 |
217 | }
218 | });
219 |
220 | // set our display
221 | _mediaPlayer.setDisplay(
222 | _mediaPlayerSurfaceHolder);
223 |
224 | // lock the screen on
225 | _mediaPlayer.setScreenOnWhilePlaying(true);
226 |
227 | // get our target url
228 | Uri testUri = Uri
229 | .parse("http://asm-origin.ineoquest.ca/hls/origin-asm.m3u8");
230 | // Uri sdcardtestUri =
231 | // Uri.parse("/sdcard/TestLibary2/testm3u8/0/prog_index.m3u8");
232 | // Uri sdcardtestUri =
233 | // Uri.parse("/sdcard/TestLibary2/test.mp4");
234 | String url = "http://172.20.171.1/hls/test.m3u8";
235 | Uri sdcardtestUri = Uri.parse(url);
236 | // Uri targetUri = IQPegasus.getInstance()
237 | // .getMediaUri(testUri);
238 |
239 | LogUtils.d("sdcardtestUri----" + sdcardtestUri.toString());
240 | // set our datasource
241 | _mediaPlayer.setDataSource(
242 | PlayActivity.this, sdcardtestUri);
243 |
244 | // prepare
245 | _mediaPlayer.prepare();
246 |
247 | // start
248 | _mediaPlayer.start();
249 | LogUtils.d("palying.......");
250 | } catch (final Exception ex) {
251 | LogUtils.e("error==" + ex.getMessage());
252 |
253 | // report our playback error
254 | // _mediaPlayer.onMediaPlayerPlaybackError(ex);
255 |
256 | // force a stop
257 | stopPlaying();
258 |
259 | // simply toast the user that an error happened
260 | PlayActivity.this.runOnUiThread(new Runnable() {
261 | @Override
262 | public void run() {
263 | Toast.makeText(
264 | PlayActivity.this.getApplicationContext(),
265 | "Playback error: " + ex.getMessage(),
266 | Toast.LENGTH_LONG).show();
267 | }
268 | });
269 | }
270 | }
271 | }).start();
272 | }
273 |
274 | private void stopPlaying() {
275 | this.runOnUiThread(new Runnable() {
276 | @Override
277 | public void run() {
278 | try {
279 | _mediaPlayer.stop();
280 | } catch (Exception e) {
281 | LogUtils.e("Media Player not set.");
282 | return;
283 | }
284 |
285 | _mediaPlayer.release();
286 | _mediaPlayer = null;
287 |
288 | // _mediaPlayerFragment.setMediaStopped();
289 | // _controlsFragment.setMediaStopped();
290 |
291 | // clear the surface
292 | _mediaPlayerSurfaceHolder.setFormat(PixelFormat.TRANSPARENT);
293 | _mediaPlayerSurfaceHolder.setFormat(PixelFormat.OPAQUE);
294 |
295 | }
296 | });
297 | }
298 |
299 | }
300 |
--------------------------------------------------------------------------------
/src/com/example/mynanohttpd/StreamingServer.java:
--------------------------------------------------------------------------------
1 | package com.example.mynanohttpd;
2 |
3 | import java.io.File;
4 | import java.io.IOException;
5 | import java.io.InputStream;
6 | import java.util.Properties;
7 | import java.util.Random;
8 |
9 | public class StreamingServer extends NanoHTTPD {
10 | public static interface OnRequestListen {
11 | public abstract InputStream onRequest();
12 |
13 | public abstract void requestDone();
14 | }
15 |
16 | private OnRequestListen myRequestListen = null;
17 | private File homeDir;
18 | private Response streamingResponse = null;
19 |
20 | public StreamingServer(int port, String wwwroot) throws IOException {
21 | super(port, new File(wwwroot).getAbsoluteFile());
22 | homeDir = new File(wwwroot);
23 | }
24 |
25 | public void setOnRequestListen(OnRequestListen orl) {
26 | myRequestListen = orl;
27 | }
28 |
29 | public Response serve(String uri, String method, Properties header,
30 | Properties parms, Properties files) {
31 | LogUtils.d("serve== " + method + " '" + uri + "' ");
32 |
33 | if (uri.equalsIgnoreCase("/live.flv")) {
34 |
35 | Response res = new Response(HTTP_NOTFOUND, MIME_PLAINTEXT,
36 | "Error 404, file not found......===");
37 | if (myRequestListen == null) {
38 | return res;
39 | } else {
40 |
41 | InputStream ins;
42 | ins = myRequestListen.onRequest();
43 | if (ins == null) {
44 | return res;
45 | }
46 |
47 | if (streamingResponse == null) {
48 | Random rnd = new Random();
49 | String etag = Integer.toHexString(rnd.nextInt());
50 |
51 | res = new Response(HTTP_OK, "video/x-flv", ins);
52 | res.addHeader("Connection", "Keep-alive");
53 | res.addHeader("ETag", etag);
54 | res.isStreaming = true;
55 | streamingResponse = res;
56 | LogUtils.d("Starting streaming server");
57 | }
58 | return res;
59 | }
60 | } else if (uri.contains("?")) {
61 |
62 | String parem = uri.substring(uri.indexOf("?"), uri.length());
63 | if (parem.equals("test")) {
64 |
65 | return new Response(HTTP_NOTFOUND, MIME_PLAINTEXT,
66 | "Error 404, file not found.");
67 |
68 | }
69 |
70 | } else if (uri.contains("test")) {
71 |
72 | Response res = new Response(HTTP_NOTFOUND, MIME_PLAINTEXT,
73 | "Error 404, file not found.");
74 | if (myRequestListen == null) {
75 | return res;
76 | } else {
77 |
78 | InputStream ins;
79 | ins = myRequestListen.onRequest();
80 | if (ins == null) {
81 | return res;
82 | }
83 |
84 | if (streamingResponse == null) {
85 | Random rnd = new Random();
86 | String etag = Integer.toHexString(rnd.nextInt());
87 |
88 | res = new Response(HTTP_OK, "video/x-flv", ins);
89 | res.addHeader("Connection", "Keep-alive");
90 | res.addHeader("ETag", etag);
91 | res.isStreaming = true;
92 | streamingResponse = res;
93 | LogUtils.d("Starting streaming server");
94 | }
95 | return res;
96 | }
97 |
98 | } else {
99 | LogUtils.e("uri =" + uri);
100 | LogUtils.e("homeDir =" + homeDir);
101 | return serveFile(uri, header, homeDir, true);
102 | }
103 |
104 | return null;
105 | }
106 |
107 | public void serveDone(Response r) {
108 | LogUtils.i("*********serveDone");
109 | if (r.mimeType.equalsIgnoreCase("video/x-flv")
110 | && r == streamingResponse) {
111 | if (myRequestListen != null) {
112 | myRequestListen.requestDone();
113 | streamingResponse = null;
114 | }
115 | }
116 | }
117 |
118 | }
119 |
--------------------------------------------------------------------------------