├── .gitignore ├── .idea ├── compiler.xml ├── encodings.xml ├── gradle.xml ├── misc.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── ykbjson │ │ └── app │ │ └── simpledlna │ │ ├── DevicesAdapter.java │ │ ├── MainActivity.java │ │ └── Util.java │ └── res │ ├── drawable-v24 │ └── ic_launcher_foreground.xml │ ├── drawable │ ├── ic_action_dock.png │ ├── ic_launcher_background.xml │ └── no_art_small.png │ ├── layout │ ├── activity_main.xml │ ├── content_main.xml │ └── item_device.xml │ ├── menu │ └── menu_main.xml │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml │ └── xml │ └── file_paths.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── nginxserver ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── assets │ └── nginx │ │ ├── conf │ │ ├── fastcgi.conf │ │ ├── fastcgi.conf.default │ │ ├── fastcgi_params │ │ ├── fastcgi_params.default │ │ ├── koi-utf │ │ ├── koi-win │ │ ├── mime.types │ │ ├── mime.types.default │ │ ├── nginx.conf │ │ ├── nginx.conf.default │ │ ├── scgi_params │ │ ├── scgi_params.default │ │ ├── stat.xsl │ │ ├── uwsgi_params │ │ ├── uwsgi_params.default │ │ └── win-utf │ │ ├── html │ │ ├── 50x.html │ │ └── index.html │ │ ├── logs │ │ ├── error.log │ │ └── nginx.pid │ │ ├── sbin │ │ └── nginx │ │ └── temp │ │ └── hls │ │ └── test.hls │ └── java │ └── com │ └── ykbjson │ └── lib │ └── nginxserver │ └── nginx │ └── NginxHelper.java ├── rtmplibs ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── com │ └── chillingvan │ └── lib │ ├── camera │ ├── CameraInterface.java │ ├── CameraUtils.java │ └── InstantVideoCamera.java │ ├── encoder │ ├── MediaCodecInputStream.java │ ├── audio │ │ └── AACEncoder.java │ └── video │ │ └── H264Encoder.java │ ├── muxer │ ├── BaseMuxer.java │ ├── BufferInfoEx.java │ ├── FramePool.java │ ├── FrameSender.java │ ├── IMuxer.java │ ├── MP4Muxer.java │ ├── RTMPStreamMuxer.java │ └── TimeIndexCounter.java │ └── publisher │ ├── CameraStreamPublisher.java │ └── StreamPublisher.java ├── screening ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── ykbjson │ │ └── lib │ │ └── screening │ │ ├── DLNABrowserService.java │ │ ├── DLNAManager.java │ │ ├── DLNAPlayer.java │ │ ├── RequestMediaProjectionActivity.java │ │ ├── bean │ │ ├── DeviceInfo.java │ │ └── MediaInfo.java │ │ ├── listener │ │ ├── DLNAControlCallback.java │ │ ├── DLNADeviceConnectListener.java │ │ ├── DLNARegistryListener.java │ │ ├── DLNAStateCallback.java │ │ └── OnRequestMediaProjectionResultCallback.java │ │ ├── log │ │ └── AndroidLoggingHandler.java │ │ └── xml │ │ ├── DLNASAXParser.java │ │ └── DLNAUDA10ServiceDescriptorBinderSAXImpl.java │ └── res │ ├── layout │ └── activity_request_media_projection.xml │ └── values │ └── styles.xml ├── screenrecorder ├── .gitignore ├── build.gradle ├── libs │ └── mobile-ffmpeg.aar ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── aidl │ └── com │ │ └── ykbjson │ │ └── lib │ │ └── screenrecorder │ │ ├── AudioEncodeConfig.aidl │ │ ├── ICallback.aidl │ │ ├── IScreenRecorderService.aidl │ │ └── VideoEncodeConfig.aidl │ ├── java │ └── com │ │ └── ykbjson │ │ └── lib │ │ └── screenrecorder │ │ ├── AudioEncodeConfig.java │ │ ├── AudioEncoder.java │ │ ├── BaseEncoder.java │ │ ├── Encoder.java │ │ ├── IRecorderCallback.java │ │ ├── IScreenRecorderService.java │ │ ├── IScreenRecorderServiceProxy.java │ │ ├── MicRecorder.java │ │ ├── Notifications.java │ │ ├── ScreenRecorder.java │ │ ├── ScreenRecorderServiceImpl.java │ │ ├── Utils.java │ │ ├── VideoEncodeConfig.java │ │ └── VideoEncoder.java │ └── res │ ├── drawable-hdpi │ └── ic_stat_recording.png │ ├── drawable-mdpi │ └── ic_stat_recording.png │ ├── drawable-xhdpi │ └── ic_stat_recording.png │ └── drawable-xxhdpi │ └── ic_stat_recording.png ├── settings.gradle ├── simplepermission ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── ykbjson │ │ └── lib │ │ └── simplepermission │ │ ├── Permissions.java │ │ ├── PermissionsManager.java │ │ ├── PermissionsRequestCallback.java │ │ └── PermissionsResultAction.java │ └── res │ └── values │ └── strings.xml └── webserver ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src └── main ├── AndroidManifest.xml ├── java └── org │ ├── nanohttpd │ └── webserver │ │ ├── InternalRewrite.java │ │ ├── SimpleWebServer.java │ │ ├── WebServerPlugin.java │ │ └── WebServerPluginInfo.java │ ├── protocols │ └── http │ │ ├── ClientHandler.java │ │ ├── HTTPSession.java │ │ ├── IHTTPSession.java │ │ ├── NanoHTTPD.java │ │ ├── ServerRunnable.java │ │ ├── content │ │ ├── ContentType.java │ │ ├── Cookie.java │ │ └── CookieHandler.java │ │ ├── request │ │ └── Method.java │ │ ├── response │ │ ├── ChunkedOutputStream.java │ │ ├── IStatus.java │ │ ├── Response.java │ │ └── Status.java │ │ ├── sockets │ │ ├── DefaultServerSocketFactory.java │ │ └── SecureServerSocketFactory.java │ │ ├── tempfiles │ │ ├── DefaultTempFile.java │ │ ├── DefaultTempFileManager.java │ │ ├── DefaultTempFileManagerFactory.java │ │ ├── ITempFile.java │ │ └── ITempFileManager.java │ │ └── threading │ │ ├── DefaultAsyncRunner.java │ │ └── IAsyncRunner.java │ └── util │ ├── IFactory.java │ ├── IFactoryThrowing.java │ ├── IHandler.java │ └── ServerRunner.java └── resources └── META-INF └── nanohttpd ├── default-mimetypes.properties └── mimetypes.properties /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | .DS_Store 5 | /build 6 | /captures 7 | .externalNativeBuild 8 | .idea 9 | /.idea 10 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 24 | 25 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # simpledlna 2 | 1.基于cling实现的Android投屏方案,支持本地图片、视频、音乐等媒体数据投屏。想本地测试的,可以在电脑端或者手机端安装一个kodi软件试试。 3 | 4 | 2.基于本地录屏实时投屏功能开发中,但是RTMP推流一直还在研究中,可以实时同步音频,视频界面不可见,接下来的时间将继续完善这部分功能。 5 | 6 | # 源码解析参考 7 | 8 | >[基于cling实现的Android投屏方案——简书](https://www.jianshu.com/p/9f54d8c4e502) 9 | 10 | >[基于cling实现的Android投屏方案——github博客](https://ykbjson.github.io/2019/07/18/%E5%9F%BA%E4%BA%8Ecling%E5%AE%9E%E7%8E%B0%E7%9A%84Android%E6%8A%95%E5%B1%8F%E6%96%B9%E6%A1%88/) 11 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | .idea 3 | /.idea -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion rootProject.ext.compileSdkVersion 5 | defaultConfig { 6 | applicationId "com.ykbjson.app.simpledlna" 7 | minSdkVersion rootProject.ext.minSdkVersion 8 | targetSdkVersion rootProject.ext.targetSdkVersion 9 | versionCode rootProject.ext.versionCode 10 | versionName rootProject.ext.versionName 11 | 12 | ndk { 13 | abiFilters "armeabi-v7a" 14 | } 15 | } 16 | 17 | compileOptions { 18 | sourceCompatibility 1.8 19 | targetCompatibility 1.8 20 | } 21 | 22 | buildTypes { 23 | release { 24 | minifyEnabled false 25 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 26 | } 27 | } 28 | 29 | //去重复的引用 30 | packagingOptions { 31 | exclude 'META-INF/beans.xml' 32 | } 33 | 34 | lintOptions { 35 | abortOnError false 36 | checkReleaseBuilds false 37 | ignoreWarnings true 38 | disable 'MissingTranslation' 39 | } 40 | } 41 | 42 | dependencies { 43 | implementation fileTree(dir: 'libs', include: ['*.jar']) 44 | implementation "androidx.appcompat:appcompat:$rootProject.ext.supportLibraryVersion" 45 | implementation "androidx.constraintlayout:constraintlayout:$rootProject.ext.constraintlayoutVersion" 46 | implementation "com.google.android.material:material:$rootProject.ext.materialVersion" 47 | implementation project(":simplepermission") 48 | implementation project(":screening") 49 | } 50 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 14 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 30 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /app/src/main/java/com/ykbjson/app/simpledlna/DevicesAdapter.java: -------------------------------------------------------------------------------- 1 | package com.ykbjson.app.simpledlna; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.ArrayAdapter; 8 | import android.widget.ImageView; 9 | import android.widget.TextView; 10 | 11 | import com.ykbjson.lib.screening.bean.DeviceInfo; 12 | 13 | import org.fourthline.cling.model.meta.Device; 14 | 15 | /** 16 | * Description:设备列表适配器 17 | *
18 | * Creator:yankebin 19 | *
20 | * CreatedAt:2019-07-18 21 | */ 22 | 23 | public class DevicesAdapter extends ArrayAdapter { 24 | private LayoutInflater mInflater; 25 | 26 | public DevicesAdapter(Context context) { 27 | super(context, 0); 28 | mInflater = LayoutInflater.from(context); 29 | } 30 | 31 | @Override 32 | public View getView(int position, View convertView, ViewGroup parent) { 33 | if (convertView == null) 34 | convertView = mInflater.inflate(R.layout.item_device, parent, false); 35 | 36 | DeviceInfo item = getItem(position); 37 | if (item == null) { 38 | return convertView; 39 | } 40 | 41 | Device device = item.getDevice(); 42 | 43 | ImageView imageView = convertView.findViewById(R.id.listview_item_image); 44 | imageView.setBackgroundResource(R.drawable.ic_action_dock); 45 | 46 | TextView textView = convertView.findViewById(R.id.listview_item_line_one); 47 | textView.setText(device.getDetails().getFriendlyName()); 48 | 49 | return convertView; 50 | } 51 | } -------------------------------------------------------------------------------- /app/src/main/java/com/ykbjson/app/simpledlna/Util.java: -------------------------------------------------------------------------------- 1 | package com.ykbjson.app.simpledlna; 2 | 3 | import android.content.ContentUris; 4 | import android.content.Context; 5 | import android.database.Cursor; 6 | import android.net.Uri; 7 | import android.provider.DocumentsContract; 8 | import android.provider.MediaStore; 9 | 10 | /** 11 | * Description:工具类 12 | *
13 | * Creator:yankebin 14 | *
15 | * CreatedAt:2019-07-18 16 | */ 17 | public class Util { 18 | 19 | public static String getRealPathFromUriAboveApi19(Context context, Uri uri) { 20 | String filePath = null; 21 | if (DocumentsContract.isDocumentUri(context, uri)) { 22 | // 如果是document类型的 uri, 则通过document id来进行处理 23 | String documentId = DocumentsContract.getDocumentId(uri); 24 | if (isMediaDocument(uri)) { // MediaProvider 25 | // 使用':'分割 26 | String id = documentId.split(":")[1]; 27 | 28 | String selection = MediaStore.Images.Media._ID + "=?"; 29 | String[] selectionArgs = {id}; 30 | filePath = getDataColumn(context, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection, selectionArgs); 31 | } else if (isDownloadsDocument(uri)) { // DownloadsProvider 32 | Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(documentId)); 33 | filePath = getDataColumn(context, contentUri, null, null); 34 | } 35 | } else if ("content".equalsIgnoreCase(uri.getScheme())){ 36 | // 如果是 content 类型的 Uri 37 | filePath = getDataColumn(context, uri, null, null); 38 | } else if ("file".equals(uri.getScheme())) { 39 | // 如果是 file 类型的 Uri,直接获取图片对应的路径 40 | filePath = uri.getPath(); 41 | } 42 | return filePath; 43 | } 44 | 45 | /** 46 | * @param uri the Uri to check 47 | * @return Whether the Uri authority is MediaProvider 48 | */ 49 | private static boolean isMediaDocument(Uri uri) { 50 | return "com.android.providers.media.documents".equals(uri.getAuthority()); 51 | } 52 | 53 | /** 54 | * @param uri the Uri to check 55 | * @return Whether the Uri authority is DownloadsProvider 56 | */ 57 | private static boolean isDownloadsDocument(Uri uri) { 58 | return "com.android.providers.downloads.documents".equals(uri.getAuthority()); 59 | } 60 | 61 | /** 62 | * 获取数据库表中的 _data 列,即返回Uri对应的文件路径 63 | * @return 64 | */ 65 | private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) { 66 | String path = null; 67 | 68 | String[] projection = new String[]{MediaStore.Images.Media.DATA}; 69 | Cursor cursor = null; 70 | try { 71 | cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null); 72 | if (cursor != null && cursor.moveToFirst()) { 73 | int columnIndex = cursor.getColumnIndexOrThrow(projection[0]); 74 | path = cursor.getString(columnIndex); 75 | } 76 | } catch (Exception e) { 77 | if (cursor != null) { 78 | cursor.close(); 79 | } 80 | } 81 | return path; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_action_dock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaertj/simpledlna/b23c824fc83b1b1d1fa337b52301aa41e9a37526/app/src/main/res/drawable/ic_action_dock.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/no_art_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaertj/simpledlna/b23c824fc83b1b1d1fa337b52301aa41e9a37526/app/src/main/res/drawable/no_art_small.png -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 21 | 22 | 23 | 24 | 25 | 26 | 33 | 34 | 41 | 42 | -------------------------------------------------------------------------------- /app/src/main/res/layout/content_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 15 | 16 | 21 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_device.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 17 | 18 | 32 | 33 | 46 | 47 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_main.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 11 | 12 | 17 | 18 | 23 | 24 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaertj/simpledlna/b23c824fc83b1b1d1fa337b52301aa41e9a37526/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaertj/simpledlna/b23c824fc83b1b1d1fa337b52301aa41e9a37526/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaertj/simpledlna/b23c824fc83b1b1d1fa337b52301aa41e9a37526/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaertj/simpledlna/b23c824fc83b1b1d1fa337b52301aa41e9a37526/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaertj/simpledlna/b23c824fc83b1b1d1fa337b52301aa41e9a37526/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaertj/simpledlna/b23c824fc83b1b1d1fa337b52301aa41e9a37526/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaertj/simpledlna/b23c824fc83b1b1d1fa337b52301aa41e9a37526/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaertj/simpledlna/b23c824fc83b1b1d1fa337b52301aa41e9a37526/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaertj/simpledlna/b23c824fc83b1b1d1fa337b52301aa41e9a37526/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaertj/simpledlna/b23c824fc83b1b1d1fa337b52301aa41e9a37526/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3A99D8 4 | #3A99D8 5 | #D81B60 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 16dp 3 | 4 | 5 | 54dp 6 | 9dp 7 | 4dp 8 | 16dp 9 | 50dp 10 | 5dp 11 | 10dp 12 | 80dp 13 | 70dp 14 | 44dp 15 | 4dp 16 | 17 | 18 | 10sp 19 | 12sp 20 | 14sp 21 | 16sp 22 | 18sp 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | SimpleDlna 3 | 选择图片 4 | 选择音频 5 | 选择视频 6 | 投屏手机 7 | 努力搜索设备中,请稍后··· 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 15 | 16 | 12 | 13 | 14 |

An error occurred.

15 |

Sorry, the page you are looking for is currently unavailable.
16 | Please try again later.

17 |

If you are the system administrator of this resource then you should check 18 | the error log for details.

19 |

Faithfully yours, nginx.

20 | 21 | 22 | -------------------------------------------------------------------------------- /nginxserver/src/main/assets/nginx/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Welcome to nginx! 5 | 12 | 13 | 14 |

Welcome to nginx!

15 |

If you see this page, the nginx web server is successfully installed and 16 | working. Further configuration is required.

17 | 18 |

For online documentation and support please refer to 19 | nginx.org.
20 | Commercial support is available at 21 | nginx.com.

22 | 23 |

Thank you for using nginx.

24 | 25 | 26 | -------------------------------------------------------------------------------- /nginxserver/src/main/assets/nginx/logs/error.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaertj/simpledlna/b23c824fc83b1b1d1fa337b52301aa41e9a37526/nginxserver/src/main/assets/nginx/logs/error.log -------------------------------------------------------------------------------- /nginxserver/src/main/assets/nginx/logs/nginx.pid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaertj/simpledlna/b23c824fc83b1b1d1fa337b52301aa41e9a37526/nginxserver/src/main/assets/nginx/logs/nginx.pid -------------------------------------------------------------------------------- /nginxserver/src/main/assets/nginx/sbin/nginx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaertj/simpledlna/b23c824fc83b1b1d1fa337b52301aa41e9a37526/nginxserver/src/main/assets/nginx/sbin/nginx -------------------------------------------------------------------------------- /nginxserver/src/main/assets/nginx/temp/hls/test.hls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaertj/simpledlna/b23c824fc83b1b1d1fa337b52301aa41e9a37526/nginxserver/src/main/assets/nginx/temp/hls/test.hls -------------------------------------------------------------------------------- /nginxserver/src/main/java/com/ykbjson/lib/nginxserver/nginx/NginxHelper.java: -------------------------------------------------------------------------------- 1 | package com.ykbjson.lib.nginxserver.nginx; 2 | 3 | import android.content.Context; 4 | import android.content.res.AssetManager; 5 | import android.util.Log; 6 | 7 | import androidx.annotation.NonNull; 8 | 9 | import com.jrummyapps.android.shell.CommandResult; 10 | import com.jrummyapps.android.shell.Shell; 11 | 12 | import java.io.File; 13 | import java.io.FileOutputStream; 14 | import java.io.IOException; 15 | import java.io.InputStream; 16 | import java.io.OutputStream; 17 | 18 | /** 19 | * Description:Ngiinx服务器帮助类 20 | *
21 | * Creator:yankebin 22 | *
23 | * CreatedAt:2019-08-01 24 | */ 25 | public class NginxHelper { 26 | 27 | private static final String TAG = "NginxHelper"; 28 | private static final String EXE_FILE_RELATIVE_PATH = "/sbin/nginx"; 29 | private static final String CONF_FILE_RELATIVE_PATH = "/conf/nginx.conf"; 30 | 31 | private static String mNginxDir; 32 | 33 | public static CommandResult installNginxServer(@NonNull Context context) { 34 | mNginxDir = getAppDataDir(context) + "/nginx"; 35 | copyFileOrDirFromAsset(context, "nginx"); 36 | CommandResult result = Shell.SH.run("chmod -R 777 " + mNginxDir); 37 | Log.d(TAG, result.exitCode + "\n" + result.stdout + "\n" + result.stderr); 38 | 39 | return result; 40 | } 41 | 42 | public static CommandResult startNginxServer() { 43 | CommandResult result = Shell.SH.run(mNginxDir + EXE_FILE_RELATIVE_PATH + " -p " + mNginxDir + " -c " + mNginxDir + CONF_FILE_RELATIVE_PATH); 44 | Log.d(TAG, result.exitCode + "\n" + result.stdout + "\n" + result.stderr); 45 | return result; 46 | } 47 | 48 | public static CommandResult stopNginxServer() { 49 | CommandResult result = Shell.SH.run(mNginxDir + EXE_FILE_RELATIVE_PATH + " -p " + mNginxDir + " -s quit"); 50 | Log.d(TAG, result.exitCode + "\n" + result.stdout + "\n" + result.stderr); 51 | return result; 52 | } 53 | 54 | 55 | private static String getAppDataDir(@NonNull Context context) { 56 | return context.getApplicationInfo().dataDir; 57 | } 58 | 59 | private static void copyFileOrDirFromAsset(@NonNull Context context, String path) { 60 | AssetManager assetManager = context.getAssets(); 61 | String[] assets; 62 | try { 63 | assets = assetManager.list(path); 64 | if (null == assets || assets.length == 0) { 65 | copyFile(context, path); 66 | } else { 67 | String fullPath = getAppDataDir(context) + "/" + path; 68 | File dir = new File(fullPath); 69 | if (!dir.exists()) 70 | dir.mkdir(); 71 | for (String asset : assets) { 72 | copyFileOrDirFromAsset(context, path + "/" + asset); 73 | } 74 | } 75 | } catch (IOException e) { 76 | e.printStackTrace(); 77 | } 78 | } 79 | 80 | private static void copyFile(@NonNull Context context, String filename) { 81 | Log.d(TAG, "copy file path : " + filename); 82 | AssetManager assetManager = context.getAssets(); 83 | InputStream in = null; 84 | OutputStream out = null; 85 | try { 86 | in = assetManager.open(filename); 87 | String newFileName = getAppDataDir(context) + "/" + filename; 88 | out = new FileOutputStream(newFileName); 89 | 90 | byte[] buffer = new byte[1024]; 91 | int read; 92 | while ((read = in.read(buffer)) != -1) { 93 | out.write(buffer, 0, read); 94 | } 95 | in.close(); 96 | out.flush(); 97 | out.close(); 98 | } catch (Exception e) { 99 | e.printStackTrace(); 100 | } finally { 101 | try { 102 | if (null != out) { 103 | out.close(); 104 | } 105 | if (null != in) { 106 | in.close(); 107 | } 108 | } catch (IOException e) { 109 | //ignored 110 | } 111 | } 112 | } 113 | 114 | public static String getRtmpLiveServerConfig() { 115 | return ":9577/live/"; 116 | } 117 | 118 | public static String getHttpServerConfig() { 119 | return ":9572/"; 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /rtmplibs/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | .idea 3 | /.idea -------------------------------------------------------------------------------- /rtmplibs/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion rootProject.ext.compileSdkVersion 5 | defaultConfig { 6 | minSdkVersion rootProject.ext.minSdkVersion 7 | targetSdkVersion rootProject.ext.targetSdkVersion 8 | versionCode rootProject.ext.versionCode 9 | versionName rootProject.ext.versionName 10 | } 11 | buildTypes { 12 | release { 13 | minifyEnabled false 14 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 15 | } 16 | } 17 | } 18 | 19 | dependencies { 20 | implementation fileTree(dir: 'libs', include: ['*.jar']) 21 | api 'com.github.ChillingVan:android-openGL-canvas:v1.4.0.0' 22 | api 'net.butterflytv.utils:rtmp-client:3.0.1' 23 | api "androidx.appcompat:appcompat:$rootProject.ext.supportLibraryVersion" 24 | api 'com.github.pedroSG94.rtmp-rtsp-stream-client-java:rtplibrary:1.6.6' 25 | } 26 | 27 | -------------------------------------------------------------------------------- /rtmplibs/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\develop-win\android\dev-tools-win\android-studio-windows\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /rtmplibs/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /rtmplibs/src/main/java/com/chillingvan/lib/camera/CameraInterface.java: -------------------------------------------------------------------------------- 1 | package com.chillingvan.lib.camera; 2 | 3 | import android.graphics.SurfaceTexture; 4 | import android.hardware.Camera; 5 | 6 | /** 7 | * Created by Chilling on 2017/5/29. 8 | */ 9 | 10 | public interface CameraInterface { 11 | void setPreview(SurfaceTexture surfaceTexture); 12 | 13 | void openCamera(); 14 | 15 | void switchCamera(); 16 | 17 | void switchCamera(int previewWidth, int previewHeight); 18 | 19 | boolean isOpened(); 20 | 21 | void startPreview(); 22 | 23 | void stopPreview(); 24 | 25 | Camera getCamera(); 26 | 27 | void release(); 28 | } 29 | -------------------------------------------------------------------------------- /rtmplibs/src/main/java/com/chillingvan/lib/camera/CameraUtils.java: -------------------------------------------------------------------------------- 1 | package com.chillingvan.lib.camera; 2 | 3 | import android.hardware.Camera; 4 | import android.util.Log; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * Camera-related utility functions. 10 | */ 11 | public class CameraUtils { 12 | private static final String TAG = "tag"; 13 | 14 | /** 15 | * Attempts to find a preview size that matches the provided width and height (which 16 | * specify the dimensions of the encoded video). If it fails to find a match it just 17 | * uses the default preview size for video. 18 | *

19 | * TODO: should do a best-fit match, e.g. 20 | * https://github.com/commonsguy/cwac-camera/blob/master/camera/src/com/commonsware/cwac/camera/CameraUtils.java 21 | */ 22 | public static void choosePreviewSize(Camera.Parameters parms, int width, int height) { 23 | // We should make sure that the requested MPEG size is less than the preferred 24 | // size, and has the same aspect ratio. 25 | Camera.Size ppsfv = parms.getPreferredPreviewSizeForVideo(); 26 | if (ppsfv != null) { 27 | Log.d(TAG, "Camera preferred preview size for video is " + 28 | ppsfv.width + "x" + ppsfv.height); 29 | } 30 | 31 | //for (Camera.Size size : parms.getSupportedPreviewSizes()) { 32 | // Log.d(TAG, "supported: " + size.width + "x" + size.height); 33 | //} 34 | 35 | for (Camera.Size size : parms.getSupportedPreviewSizes()) { 36 | if (size.width == width && size.height == height) { 37 | parms.setPreviewSize(width, height); 38 | return; 39 | } 40 | } 41 | 42 | Log.w(TAG, "Unable to set preview size to " + width + "x" + height); 43 | if (ppsfv != null) { 44 | parms.setPreviewSize(ppsfv.width, ppsfv.height); 45 | } 46 | // else use whatever the default size is 47 | } 48 | 49 | /** 50 | * Attempts to find a fixed preview frame rate that matches the desired frame rate. 51 | *

52 | * It doesn't seem like there's a great deal of flexibility here. 53 | *

54 | * TODO: follow the recipe from http://stackoverflow.com/questions/22639336/#22645327 55 | * 56 | * @return The expected frame rate, in thousands of frames per second. 57 | */ 58 | public static int chooseFixedPreviewFps(Camera.Parameters parms, int desiredThousandFps) { 59 | List supported = parms.getSupportedPreviewFpsRange(); 60 | 61 | for (int[] entry : supported) { 62 | //Log.d(TAG, "entry: " + entry[0] + " - " + entry[1]); 63 | if ((entry[0] == entry[1]) && (entry[0] == desiredThousandFps)) { 64 | parms.setPreviewFpsRange(entry[0], entry[1]); 65 | return entry[0]; 66 | } 67 | } 68 | 69 | int[] tmp = new int[2]; 70 | parms.getPreviewFpsRange(tmp); 71 | int guess; 72 | if (tmp[0] == tmp[1]) { 73 | guess = tmp[0]; 74 | } else { 75 | guess = tmp[1] / 2; // shrug 76 | } 77 | 78 | Log.d(TAG, "Couldn't find match for " + desiredThousandFps + ", using " + guess); 79 | return guess; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /rtmplibs/src/main/java/com/chillingvan/lib/camera/InstantVideoCamera.java: -------------------------------------------------------------------------------- 1 | package com.chillingvan.lib.camera; 2 | 3 | import android.graphics.SurfaceTexture; 4 | import android.hardware.Camera; 5 | 6 | import java.io.IOException; 7 | 8 | /** 9 | * Created by Chilling on 2016/12/10. 10 | */ 11 | 12 | public class InstantVideoCamera implements CameraInterface { 13 | 14 | private Camera camera; 15 | private boolean isOpened; 16 | private int currentCamera; 17 | private int previewWidth; 18 | private int previewHeight; 19 | 20 | @Override 21 | public void setPreview(SurfaceTexture surfaceTexture) { 22 | try { 23 | camera.setPreviewTexture(surfaceTexture); 24 | } catch (IOException e) { 25 | e.printStackTrace(); 26 | } 27 | } 28 | 29 | public InstantVideoCamera(int currentCamera, int previewWidth, int previewHeight) { 30 | this.currentCamera = currentCamera; 31 | this.previewWidth = previewWidth; 32 | this.previewHeight = previewHeight; 33 | } 34 | 35 | @Override 36 | public void openCamera() { 37 | Camera.CameraInfo info = new Camera.CameraInfo(); 38 | 39 | // Try to find a front-facing camera (e.g. for videoconferencing). 40 | int numCameras = Camera.getNumberOfCameras(); 41 | for (int i = 0; i < numCameras; i++) { 42 | Camera.getCameraInfo(i, info); 43 | if (info.facing == currentCamera) { 44 | camera = Camera.open(i); 45 | break; 46 | } 47 | } 48 | if (camera == null) { 49 | camera = Camera.open(); 50 | } 51 | 52 | Camera.Parameters parms = camera.getParameters(); 53 | 54 | CameraUtils.choosePreviewSize(parms, previewWidth, previewHeight); 55 | isOpened = true; 56 | } 57 | 58 | @Override 59 | public void switchCamera() { 60 | switchCamera(previewWidth, previewHeight); 61 | } 62 | 63 | @Override 64 | public void switchCamera(int previewWidth, int previewHeight) { 65 | this.previewWidth = previewWidth; 66 | this.previewHeight = previewHeight; 67 | release(); 68 | currentCamera = currentCamera == Camera.CameraInfo.CAMERA_FACING_BACK ? Camera.CameraInfo.CAMERA_FACING_FRONT : Camera.CameraInfo.CAMERA_FACING_BACK; 69 | openCamera(); 70 | } 71 | 72 | @Override 73 | public boolean isOpened() { 74 | return isOpened; 75 | } 76 | 77 | @Override 78 | public void startPreview() { 79 | camera.startPreview(); 80 | } 81 | 82 | @Override 83 | public void stopPreview() { 84 | camera.stopPreview(); 85 | } 86 | 87 | @Override 88 | public Camera getCamera() { 89 | return camera; 90 | } 91 | 92 | @Override 93 | public void release() { 94 | if (isOpened) { 95 | camera.stopPreview(); 96 | camera.release(); 97 | camera = null; 98 | isOpened = false; 99 | } 100 | } 101 | 102 | 103 | } 104 | -------------------------------------------------------------------------------- /rtmplibs/src/main/java/com/chillingvan/lib/muxer/BaseMuxer.java: -------------------------------------------------------------------------------- 1 | package com.chillingvan.lib.muxer; 2 | 3 | import android.media.MediaCodec; 4 | 5 | import com.chillingvan.lib.publisher.StreamPublisher; 6 | 7 | /** 8 | * Created by Chilling on 2017/12/23. 9 | */ 10 | 11 | public abstract class BaseMuxer implements IMuxer { 12 | protected StreamPublisher.StreamPublisherParam params; 13 | protected TimeIndexCounter videoTimeIndexCounter = new TimeIndexCounter(); 14 | protected TimeIndexCounter audioTimeIndexCounter = new TimeIndexCounter(); 15 | 16 | @Override 17 | public int open(StreamPublisher.StreamPublisherParam params) { 18 | this.params = params; 19 | videoTimeIndexCounter.reset(); 20 | audioTimeIndexCounter.reset(); 21 | return 0; 22 | } 23 | 24 | @Override 25 | public void writeVideo(byte[] buffer, int offset, int length, MediaCodec.BufferInfo bufferInfo) { 26 | videoTimeIndexCounter.calcTotalTime(bufferInfo.presentationTimeUs); 27 | } 28 | 29 | @Override 30 | public void writeAudio(byte[] buffer, int offset, int length, MediaCodec.BufferInfo bufferInfo) { 31 | audioTimeIndexCounter.calcTotalTime(bufferInfo.presentationTimeUs); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /rtmplibs/src/main/java/com/chillingvan/lib/muxer/BufferInfoEx.java: -------------------------------------------------------------------------------- 1 | package com.chillingvan.lib.muxer; 2 | 3 | import android.media.MediaCodec; 4 | 5 | /** 6 | * Created by Chilling on 2017/12/23. 7 | */ 8 | 9 | public class BufferInfoEx { 10 | private MediaCodec.BufferInfo bufferInfo; 11 | private int totalTime; 12 | 13 | public BufferInfoEx(MediaCodec.BufferInfo bufferInfo, int totalTime) { 14 | this.bufferInfo = bufferInfo; 15 | this.totalTime = totalTime; 16 | } 17 | 18 | public MediaCodec.BufferInfo getBufferInfo() { 19 | return bufferInfo; 20 | } 21 | 22 | public int getTotalTime() { 23 | return totalTime; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /rtmplibs/src/main/java/com/chillingvan/lib/muxer/FrameSender.java: -------------------------------------------------------------------------------- 1 | package com.chillingvan.lib.muxer; 2 | 3 | import android.os.Handler; 4 | import android.os.HandlerThread; 5 | import android.os.Message; 6 | 7 | import java.util.LinkedList; 8 | import java.util.List; 9 | 10 | /** 11 | * Created by Chilling on 2017/12/17. 12 | */ 13 | 14 | public class FrameSender { 15 | 16 | private static final int KEEP_COUNT = 30; 17 | private static final int MESSAGE_READY_TO_CLOSE = 4; 18 | private static final int MSG_ADD_FRAME = 3; 19 | private static final int MSG_START = 2; 20 | 21 | private Handler sendHandler; 22 | private List frameQueue = new LinkedList<>(); 23 | private FramePool framePool = new FramePool(KEEP_COUNT + 10); 24 | private FrameSenderCallback frameSenderCallback; 25 | 26 | 27 | public FrameSender(final FrameSenderCallback frameSenderCallback) { 28 | this.frameSenderCallback = frameSenderCallback; 29 | final HandlerThread sendHandlerThread = new HandlerThread("send_thread"); 30 | sendHandlerThread.start(); 31 | sendHandler = new Handler(sendHandlerThread.getLooper()) { 32 | @Override 33 | public void handleMessage(Message msg) { 34 | super.handleMessage(msg); 35 | 36 | if (msg.what == MESSAGE_READY_TO_CLOSE) { 37 | if (msg.obj != null) { 38 | addFrame((FramePool.Frame) msg.obj); 39 | } 40 | sendFrame(msg.arg1); 41 | 42 | frameSenderCallback.close(); 43 | sendHandlerThread.quitSafely(); 44 | } else if (msg.what == MSG_ADD_FRAME) { 45 | if (msg.obj != null) { 46 | addFrame((FramePool.Frame) msg.obj); 47 | } 48 | sendFrame(msg.arg1); 49 | } else if (msg.what == MSG_START) { 50 | frameSenderCallback.onStart(); 51 | } 52 | } 53 | }; 54 | } 55 | 56 | 57 | private void addFrame(FramePool.Frame frame) { 58 | frameQueue.add(frame); 59 | FramePool.Frame.sortFrame(frameQueue); 60 | } 61 | 62 | private void sendFrame(int keepCount) { 63 | while (frameQueue.size() > keepCount) { 64 | FramePool.Frame sendFrame = frameQueue.remove(0); 65 | if (sendFrame.type == FramePool.Frame.TYPE_VIDEO) { 66 | frameSenderCallback.onSendVideo(sendFrame); 67 | } else if(sendFrame.type == FramePool.Frame.TYPE_AUDIO) { 68 | frameSenderCallback.onSendAudio(sendFrame); 69 | } 70 | framePool.release(sendFrame); 71 | } 72 | } 73 | 74 | public void sendStartMessage() { 75 | Message message = Message.obtain(); 76 | message.what = MSG_START; 77 | sendHandler.sendMessage(message); 78 | } 79 | 80 | public void sendAddFrameMessage(byte[] data, int offset, int length, BufferInfoEx bufferInfo, int type) { 81 | FramePool.Frame frame = framePool.obtain(data, offset, length, bufferInfo, type); 82 | Message message = Message.obtain(); 83 | message.what = MSG_ADD_FRAME; 84 | message.obj = frame; 85 | message.arg1 = KEEP_COUNT; 86 | sendHandler.sendMessage(message); 87 | } 88 | 89 | public void sendCloseMessage() { 90 | Message message = Message.obtain(); 91 | message.arg1 = 0; 92 | message.what = MESSAGE_READY_TO_CLOSE; 93 | sendHandler.sendMessage(message); 94 | } 95 | 96 | public interface FrameSenderCallback { 97 | void onStart(); 98 | void onSendVideo(FramePool.Frame sendFrame); 99 | void onSendAudio(FramePool.Frame sendFrame); 100 | void close(); 101 | 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /rtmplibs/src/main/java/com/chillingvan/lib/muxer/IMuxer.java: -------------------------------------------------------------------------------- 1 | package com.chillingvan.lib.muxer; 2 | 3 | import android.media.MediaCodec; 4 | 5 | import com.chillingvan.lib.publisher.StreamPublisher; 6 | 7 | /** 8 | * Created by Chilling on 2017/5/21. 9 | */ 10 | 11 | public interface IMuxer { 12 | 13 | /** 14 | * 15 | * @return 1 if it is connected 16 | * 0 if it is not connected 17 | */ 18 | int open(StreamPublisher.StreamPublisherParam params); 19 | 20 | void writeVideo(byte[] buffer, int offset, int length, MediaCodec.BufferInfo bufferInfo); 21 | 22 | void writeAudio(byte[] buffer, int offset, int length, MediaCodec.BufferInfo bufferInfo); 23 | 24 | int close(); 25 | 26 | String getMediaPath(); 27 | } 28 | -------------------------------------------------------------------------------- /rtmplibs/src/main/java/com/chillingvan/lib/muxer/RTMPStreamMuxer.java: -------------------------------------------------------------------------------- 1 | package com.chillingvan.lib.muxer; 2 | 3 | import android.media.MediaCodec; 4 | import android.text.TextUtils; 5 | 6 | import com.chillingvan.canvasgl.util.Loggers; 7 | import com.chillingvan.lib.publisher.StreamPublisher; 8 | 9 | import net.butterflytv.rtmp_client.RTMPMuxer; 10 | 11 | import java.util.Locale; 12 | 13 | /** 14 | * Created by Chilling on 2017/5/29. 15 | */ 16 | 17 | public class RTMPStreamMuxer extends BaseMuxer { 18 | private RTMPMuxer rtmpMuxer; 19 | private FrameSender frameSender; 20 | 21 | public RTMPStreamMuxer() { 22 | super(); 23 | } 24 | 25 | /** 26 | * @return 1 if it is connected 27 | * 0 if it is not connected 28 | */ 29 | @Override 30 | public synchronized int open(final StreamPublisher.StreamPublisherParam params) { 31 | super.open(params); 32 | 33 | if (TextUtils.isEmpty(params.outputUrl)) { 34 | throw new IllegalArgumentException("Param outputUrl is empty"); 35 | } 36 | 37 | rtmpMuxer = new RTMPMuxer(); 38 | // -2 Url format error; -3 Connect error. 39 | int open = rtmpMuxer.open(params.outputUrl, params.width, params.height); 40 | Loggers.d("RTMPStreamMuxer", String.format(Locale.CHINA, "open: open: %d", open)); 41 | int connected = rtmpMuxer.isConnected(); 42 | Loggers.d("RTMPStreamMuxer", String.format(Locale.CHINA, "open: isConnected: %d", connected)); 43 | 44 | Loggers.d("RTMPStreamMuxer", String.format("open: %s", params.outputUrl)); 45 | if (!TextUtils.isEmpty(params.outputFilePath)) { 46 | rtmpMuxer.file_open(params.outputFilePath); 47 | rtmpMuxer.write_flv_header(true, true); 48 | } 49 | 50 | frameSender = new FrameSender(new FrameSender.FrameSenderCallback() { 51 | @Override 52 | public void onStart() { 53 | } 54 | 55 | @Override 56 | public void onSendVideo(FramePool.Frame sendFrame) { 57 | int result = rtmpMuxer.writeVideo(sendFrame.data, 0, sendFrame.length, sendFrame.bufferInfo.getTotalTime()); 58 | Loggers.d("RTMPStreamMuxer", "writeVideo result : " + result); 59 | } 60 | 61 | @Override 62 | public void onSendAudio(FramePool.Frame sendFrame) { 63 | int result = rtmpMuxer.writeAudio(sendFrame.data, 0, sendFrame.length, sendFrame.bufferInfo.getTotalTime()); 64 | Loggers.d("RTMPStreamMuxer", "writeAudio result : " + result); 65 | } 66 | 67 | @Override 68 | public void close() { 69 | if (rtmpMuxer != null) { 70 | if (!TextUtils.isEmpty(params.outputFilePath)) { 71 | rtmpMuxer.file_close(); 72 | } 73 | rtmpMuxer.close(); 74 | rtmpMuxer = null; 75 | } 76 | 77 | } 78 | }); 79 | frameSender.sendStartMessage(); 80 | return connected; 81 | } 82 | 83 | @Override 84 | public void writeVideo(byte[] buffer, int offset, int length, MediaCodec.BufferInfo bufferInfo) { 85 | super.writeVideo(buffer, offset, length, bufferInfo); 86 | Loggers.d("RTMPStreamMuxer", "writeVideo: " + " time:" + videoTimeIndexCounter.getTimeIndex() + " offset:" + offset + " length:" + length); 87 | if (null == frameSender) { 88 | return; 89 | } 90 | frameSender.sendAddFrameMessage(buffer, offset, length, new BufferInfoEx(bufferInfo, videoTimeIndexCounter.getTimeIndex()), FramePool.Frame.TYPE_VIDEO); 91 | } 92 | 93 | 94 | @Override 95 | public void writeAudio(byte[] buffer, int offset, int length, MediaCodec.BufferInfo bufferInfo) { 96 | super.writeAudio(buffer, offset, length, bufferInfo); 97 | Loggers.d("RTMPStreamMuxer", "writeAudio: " + " time:" + videoTimeIndexCounter.getTimeIndex() + " offset:" + offset + " length:" + length); 98 | if (null == frameSender) { 99 | return; 100 | } 101 | frameSender.sendAddFrameMessage(buffer, offset, length, new BufferInfoEx(bufferInfo, audioTimeIndexCounter.getTimeIndex()), FramePool.Frame.TYPE_AUDIO); 102 | } 103 | 104 | @Override 105 | public synchronized int close() { 106 | if (frameSender != null) { 107 | frameSender.sendCloseMessage(); 108 | } 109 | 110 | return 0; 111 | } 112 | 113 | @Override 114 | public String getMediaPath() { 115 | return params.outputUrl; 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /rtmplibs/src/main/java/com/chillingvan/lib/muxer/TimeIndexCounter.java: -------------------------------------------------------------------------------- 1 | package com.chillingvan.lib.muxer; 2 | 3 | /** 4 | * Created by Chilling on 2017/5/29. 5 | */ 6 | public class TimeIndexCounter { 7 | private long lastTimeUs; 8 | private int timeIndex; 9 | 10 | public void calcTotalTime(long currentTimeUs) { 11 | if (lastTimeUs <= 0) { 12 | this.lastTimeUs = currentTimeUs; 13 | } 14 | int delta = (int) (currentTimeUs - lastTimeUs); 15 | this.lastTimeUs = currentTimeUs; 16 | timeIndex += Math.abs(delta / 1000); 17 | } 18 | 19 | public void reset() { 20 | lastTimeUs = 0; 21 | timeIndex = 0; 22 | } 23 | 24 | public int getTimeIndex() { 25 | return timeIndex; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /rtmplibs/src/main/java/com/chillingvan/lib/publisher/CameraStreamPublisher.java: -------------------------------------------------------------------------------- 1 | package com.chillingvan.lib.publisher; 2 | 3 | import android.graphics.SurfaceTexture; 4 | 5 | import com.chillingvan.canvasgl.glview.texture.GLMultiTexProducerView; 6 | import com.chillingvan.canvasgl.glview.texture.GLTexture; 7 | import com.chillingvan.canvasgl.glview.texture.gles.EglContextWrapper; 8 | import com.chillingvan.canvasgl.glview.texture.gles.GLThread; 9 | import com.chillingvan.lib.camera.CameraInterface; 10 | import com.chillingvan.lib.encoder.video.H264Encoder; 11 | import com.chillingvan.lib.muxer.IMuxer; 12 | 13 | import java.io.IOException; 14 | import java.util.List; 15 | 16 | /** 17 | * Data Stream: 18 | * Camera -> SurfaceTexture of GLSurfaceTextureProducerView -> Surface of MediaCodec -> encode data(byte[]) -> RTMPMuxer -> Server 19 | * 20 | */ 21 | 22 | public class CameraStreamPublisher { 23 | 24 | private StreamPublisher streamPublisher; 25 | private IMuxer muxer; 26 | private GLMultiTexProducerView cameraPreviewTextureView; 27 | private CameraInterface instantVideoCamera; 28 | private OnSurfacesCreatedListener onSurfacesCreatedListener; 29 | 30 | public CameraStreamPublisher(IMuxer muxer, GLMultiTexProducerView cameraPreviewTextureView, CameraInterface instantVideoCamera) { 31 | this.muxer = muxer; 32 | this.cameraPreviewTextureView = cameraPreviewTextureView; 33 | this.instantVideoCamera = instantVideoCamera; 34 | } 35 | 36 | private void initCameraTexture() { 37 | cameraPreviewTextureView.setOnCreateGLContextListener(new GLThread.OnCreateGLContextListener() { 38 | @Override 39 | public void onCreate(EglContextWrapper eglContext) { 40 | streamPublisher = new StreamPublisher(eglContext, muxer); 41 | } 42 | }); 43 | cameraPreviewTextureView.setSurfaceTextureCreatedListener(new GLMultiTexProducerView.SurfaceTextureCreatedListener() { 44 | @Override 45 | public void onCreated(List producedTextureList) { 46 | if (onSurfacesCreatedListener != null) { 47 | onSurfacesCreatedListener.onCreated(producedTextureList, streamPublisher); 48 | } 49 | GLTexture texture = producedTextureList.get(0); 50 | SurfaceTexture surfaceTexture = texture.getSurfaceTexture(); 51 | streamPublisher.addSharedTexture(new GLTexture(texture.getRawTexture(), surfaceTexture)); 52 | surfaceTexture.setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailableListener() { 53 | @Override 54 | public void onFrameAvailable(SurfaceTexture surfaceTexture) { 55 | cameraPreviewTextureView.requestRenderAndWait(); 56 | streamPublisher.drawAFrame(); 57 | } 58 | }); 59 | 60 | instantVideoCamera.setPreview(surfaceTexture); 61 | instantVideoCamera.startPreview(); 62 | } 63 | }); 64 | } 65 | 66 | public void prepareEncoder(StreamPublisher.StreamPublisherParam param, H264Encoder.OnDrawListener onDrawListener) { 67 | streamPublisher.prepareEncoder(param, onDrawListener); 68 | } 69 | 70 | public void resumeCamera() { 71 | if (instantVideoCamera.isOpened()) return; 72 | 73 | instantVideoCamera.openCamera(); 74 | initCameraTexture(); 75 | cameraPreviewTextureView.onResume(); 76 | } 77 | 78 | public boolean isStart() { 79 | return streamPublisher != null && streamPublisher.isStart(); 80 | } 81 | 82 | public void pauseCamera() { 83 | if (!instantVideoCamera.isOpened()) return; 84 | 85 | instantVideoCamera.release(); 86 | cameraPreviewTextureView.onPause(); 87 | } 88 | 89 | public void startPublish() throws IOException { 90 | streamPublisher.start(); 91 | } 92 | 93 | 94 | public void closeAll() { 95 | streamPublisher.close(); 96 | } 97 | 98 | public void setOnSurfacesCreatedListener(OnSurfacesCreatedListener onSurfacesCreatedListener) { 99 | this.onSurfacesCreatedListener = onSurfacesCreatedListener; 100 | } 101 | 102 | public interface OnSurfacesCreatedListener { 103 | void onCreated(List producedTextureList, StreamPublisher streamPublisher); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /screening/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | .idea 3 | /.idea -------------------------------------------------------------------------------- /screening/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion rootProject.ext.compileSdkVersion 5 | defaultConfig { 6 | minSdkVersion rootProject.ext.minSdkVersion 7 | targetSdkVersion rootProject.ext.targetSdkVersion 8 | versionCode rootProject.ext.versionCode 9 | versionName rootProject.ext.versionName 10 | } 11 | 12 | buildTypes { 13 | release { 14 | minifyEnabled false 15 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 16 | } 17 | } 18 | compileOptions { 19 | sourceCompatibility = '1.8' 20 | targetCompatibility = '1.8' 21 | } 22 | 23 | } 24 | 25 | dependencies { 26 | implementation fileTree(dir: 'libs', include: ['*.jar']) 27 | 28 | implementation "androidx.appcompat:appcompat:$rootProject.ext.supportLibraryVersion" 29 | // Cling library 30 | api "org.fourthline.cling:cling-core:$rootProject.ext.clingVersion" 31 | api "org.fourthline.cling:cling-support:$rootProject.ext.clingVersion" 32 | // Jetty library 33 | api "org.eclipse.jetty:jetty-server:$rootProject.ext.jettyVersion" 34 | api "org.eclipse.jetty:jetty-servlet:$rootProject.ext.jettyVersion" 35 | api "org.eclipse.jetty:jetty-client:$rootProject.ext.jettyVersion" 36 | api "org.slf4j:slf4j-simple:$rootProject.ext.slf4jVersion" 37 | api project(':webserver')//本地文件映射的服务器 38 | api project(":screenrecorder")//录屏服务 39 | } 40 | -------------------------------------------------------------------------------- /screening/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /screening/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /screening/src/main/java/com/ykbjson/lib/screening/DLNABrowserService.java: -------------------------------------------------------------------------------- 1 | package com.ykbjson.lib.screening; 2 | 3 | import com.ykbjson.lib.screening.xml.DLNAUDA10ServiceDescriptorBinderSAXImpl; 4 | 5 | import org.fourthline.cling.UpnpServiceConfiguration; 6 | import org.fourthline.cling.android.AndroidUpnpServiceConfiguration; 7 | import org.fourthline.cling.android.AndroidUpnpServiceImpl; 8 | import org.fourthline.cling.binding.xml.ServiceDescriptorBinder; 9 | import org.fourthline.cling.model.types.ServiceType; 10 | import org.fourthline.cling.model.types.UDAServiceType; 11 | 12 | 13 | /** 14 | * Description:DLNABrowserService 15 | *
16 | * Creator:yankebin 17 | *
18 | * CreatedAt:2019-07-10 19 | */ 20 | public class DLNABrowserService extends AndroidUpnpServiceImpl { 21 | @Override 22 | protected UpnpServiceConfiguration createConfiguration() { 23 | return new AndroidUpnpServiceConfiguration() { 24 | @Override 25 | public ServiceDescriptorBinder createServiceDescriptorBinderUDA10() { 26 | return new DLNAUDA10ServiceDescriptorBinderSAXImpl(); 27 | } 28 | 29 | // @Override 30 | // public ServiceType[] getExclusiveServiceTypes() { 31 | // return new ServiceType[] { 32 | // new UDAServiceType("AVTransport"), 33 | // new UDAServiceType("ContentDirectory"), 34 | // new UDAServiceType("ConnectionManager"), 35 | // new UDAServiceType("RenderingControl"), 36 | // new UDAServiceType("X_MS_MediaReceiverRegistrar") 37 | // }; 38 | // } 39 | }; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /screening/src/main/java/com/ykbjson/lib/screening/RequestMediaProjectionActivity.java: -------------------------------------------------------------------------------- 1 | package com.ykbjson.lib.screening; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.media.projection.MediaProjection; 6 | import android.media.projection.MediaProjectionManager; 7 | import android.os.Bundle; 8 | import android.view.Gravity; 9 | import android.view.Window; 10 | import android.view.WindowManager; 11 | import android.widget.Toast; 12 | 13 | import androidx.annotation.Nullable; 14 | import androidx.appcompat.app.AppCompatActivity; 15 | 16 | import com.ykbjson.lib.screening.listener.OnRequestMediaProjectionResultCallback; 17 | 18 | /** 19 | * Description:获取录屏的MediaProjection的activity,显示一个像素 20 | *
21 | * Creator:yankebin 22 | *
23 | * CreatedAt:2019-08-06 24 | */ 25 | public class RequestMediaProjectionActivity extends AppCompatActivity { 26 | private static final int CODE_REQUEST_MEDIA_PROJECTION = 1012; 27 | static OnRequestMediaProjectionResultCallback resultCallback; 28 | private MediaProjectionManager mMediaProjectionManager; 29 | 30 | @Override 31 | protected void onCreate(@Nullable Bundle savedInstanceState) { 32 | super.onCreate(savedInstanceState); 33 | setContentView(R.layout.activity_request_media_projection); 34 | //window大小设置为1个像素,用户无感知不可见 35 | Window window = getWindow(); 36 | window.setGravity(Gravity.LEFT | Gravity.TOP); 37 | WindowManager.LayoutParams params = window.getAttributes(); 38 | params.x = 0; 39 | params.y = 0; 40 | params.width = 1; 41 | params.height = 1; 42 | window.setAttributes(params); 43 | 44 | mMediaProjectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE); 45 | } 46 | 47 | @Override 48 | protected void onStart() { 49 | super.onStart(); 50 | requestMediaProjection(); 51 | } 52 | 53 | @Override 54 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 55 | super.onActivityResult(requestCode, resultCode, data); 56 | if (requestCode == CODE_REQUEST_MEDIA_PROJECTION) { 57 | 58 | MediaProjection mediaProjection = mMediaProjectionManager.getMediaProjection(resultCode, data); 59 | if (null == mediaProjection) { 60 | Toast.makeText(this, "你拒绝了录屏操作!", Toast.LENGTH_SHORT).show(); 61 | } else if (null != resultCallback) { 62 | resultCallback.onMediaProjectionResult(mediaProjection); 63 | } 64 | finish(); 65 | } 66 | } 67 | 68 | @Override 69 | protected void onDestroy() { 70 | resultCallback = null; 71 | super.onDestroy(); 72 | } 73 | 74 | private void requestMediaProjection() { 75 | Intent captureIntent = mMediaProjectionManager.createScreenCaptureIntent(); 76 | startActivityForResult(captureIntent, CODE_REQUEST_MEDIA_PROJECTION); 77 | } 78 | 79 | static void start(Context context) { 80 | context.startActivity(new Intent(context, RequestMediaProjectionActivity.class) 81 | .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /screening/src/main/java/com/ykbjson/lib/screening/bean/DeviceInfo.java: -------------------------------------------------------------------------------- 1 | package com.ykbjson.lib.screening.bean; 2 | 3 | import com.ykbjson.lib.screening.DLNAPlayer; 4 | 5 | import org.fourthline.cling.model.meta.Device; 6 | 7 | import java.io.Serializable; 8 | 9 | /** 10 | * Description:设备信息 11 | *
12 | * Creator:yankebin 13 | *
14 | * CreatedAt:2019-07-09 15 | */ 16 | public class DeviceInfo implements Serializable { 17 | private Device device; 18 | private String name; 19 | private String mediaID; 20 | private String oldMediaID; 21 | private int state = DLNAPlayer.UNKNOWN; 22 | private boolean connected; 23 | 24 | public DeviceInfo(Device device, String name) { 25 | this.device = device; 26 | this.name = name; 27 | } 28 | 29 | public DeviceInfo() { 30 | } 31 | 32 | public Device getDevice() { 33 | return this.device; 34 | } 35 | 36 | public void setDevice(Device device) { 37 | this.device = device; 38 | } 39 | 40 | public String getName() { 41 | return this.name; 42 | } 43 | 44 | public void setName(String name) { 45 | this.name = name; 46 | } 47 | 48 | public void setMediaID(String mediaId) { 49 | this.mediaID = mediaId; 50 | } 51 | 52 | public String getMediaID() { 53 | return this.mediaID; 54 | } 55 | 56 | public void setOldMediaID(String oldMediaID) { 57 | this.oldMediaID = oldMediaID; 58 | } 59 | 60 | public String getOldMediaID() { 61 | return this.oldMediaID; 62 | } 63 | 64 | public int getState() { 65 | return state; 66 | } 67 | 68 | public void setState(int state) { 69 | this.state = state; 70 | } 71 | 72 | public boolean isConnected() { 73 | return connected; 74 | } 75 | 76 | public void setConnected(boolean connected) { 77 | this.connected = connected; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /screening/src/main/java/com/ykbjson/lib/screening/bean/MediaInfo.java: -------------------------------------------------------------------------------- 1 | package com.ykbjson.lib.screening.bean; 2 | 3 | /** 4 | * Description:多媒体信息 5 | *
6 | * Creator:yankebin 7 | *
8 | * CreatedAt:2019-07-09 9 | */ 10 | public class MediaInfo { 11 | public static final int TYPE_UNKNOWN = 0; 12 | public static final int TYPE_IMAGE = 1; 13 | public static final int TYPE_VIDEO = 2; 14 | public static final int TYPE_AUDIO = 3; 15 | public static final int TYPE_MIRROR = 4; 16 | 17 | private String mediaName; 18 | private String mediaId; 19 | private int mediaType = TYPE_UNKNOWN; 20 | private String uri; 21 | private String filePath; 22 | private long duration; 23 | private String bulbulName; 24 | private String theAlbumName; 25 | private int index; 26 | 27 | public String getMediaName() { 28 | return this.mediaName; 29 | } 30 | 31 | public void setMediaName(String mediaName) { 32 | this.mediaName = mediaName; 33 | } 34 | 35 | public String getMediaId() { 36 | return this.mediaId; 37 | } 38 | 39 | public void setMediaId(String mediaId) { 40 | this.mediaId = mediaId; 41 | } 42 | 43 | public int getMediaType() { 44 | return this.mediaType; 45 | } 46 | 47 | public void setMediaType(int mediaType) { 48 | this.mediaType = mediaType; 49 | } 50 | 51 | public String getUri() { 52 | return this.uri; 53 | } 54 | 55 | public void setUri(String uri) { 56 | this.uri = uri; 57 | } 58 | 59 | public String getFilePath() { 60 | return this.filePath; 61 | } 62 | 63 | public void setFilePath(String filePath) { 64 | this.filePath = filePath; 65 | } 66 | 67 | public long getDuration() { 68 | return this.duration; 69 | } 70 | 71 | public void setDuration(long duration) { 72 | this.duration = duration; 73 | } 74 | 75 | public String getBulbulName() { 76 | return this.bulbulName; 77 | } 78 | 79 | public void setBulbulName(String bulbulName) { 80 | this.bulbulName = bulbulName; 81 | } 82 | 83 | public String getTheAlbumName() { 84 | return this.theAlbumName; 85 | } 86 | 87 | public void setTheAlbumName(String theAlbumName) { 88 | this.theAlbumName = theAlbumName; 89 | } 90 | 91 | public int getIndex() { 92 | return this.index; 93 | } 94 | 95 | public void setIndex(int index) { 96 | this.index = index; 97 | } 98 | } -------------------------------------------------------------------------------- /screening/src/main/java/com/ykbjson/lib/screening/listener/DLNAControlCallback.java: -------------------------------------------------------------------------------- 1 | package com.ykbjson.lib.screening.listener; 2 | 3 | 4 | import androidx.annotation.IntRange; 5 | import androidx.annotation.Nullable; 6 | 7 | import org.fourthline.cling.model.action.ActionInvocation; 8 | 9 | /** 10 | * Description:DLNA执行命令回调接口 11 | *
12 | * Creator:yankebin 13 | *
14 | * CreatedAt:2019-07-10 15 | */ 16 | public interface DLNAControlCallback { 17 | int ERROR_CODE_NO_ERROR = 0; 18 | 19 | int ERROR_CODE_RE_PLAY = 1; 20 | 21 | int ERROR_CODE_RE_PAUSE = 2; 22 | 23 | int ERROR_CODE_RE_STOP = 3; 24 | 25 | int ERROR_CODE_DLNA_ERROR = 4; 26 | 27 | int ERROR_CODE_SERVICE_ERROR = 5; 28 | 29 | int ERROR_CODE_NOT_READY = 6; 30 | 31 | int ERROR_CODE_BIND_SCREEN_RECORDER_SERVICE_ERROR = 7; 32 | 33 | 34 | void onSuccess(@Nullable ActionInvocation invocation); 35 | 36 | void onReceived(@Nullable ActionInvocation invocation, @Nullable Object... extra); 37 | 38 | void onFailure(@Nullable ActionInvocation invocation, 39 | @IntRange(from = ERROR_CODE_NO_ERROR, to = ERROR_CODE_BIND_SCREEN_RECORDER_SERVICE_ERROR) int errorCode, 40 | @Nullable String errorMsg); 41 | } 42 | -------------------------------------------------------------------------------- /screening/src/main/java/com/ykbjson/lib/screening/listener/DLNADeviceConnectListener.java: -------------------------------------------------------------------------------- 1 | package com.ykbjson.lib.screening.listener; 2 | 3 | import com.ykbjson.lib.screening.bean.DeviceInfo; 4 | 5 | /** 6 | * Description:连接设备的回调接口 7 | *
8 | * Creator:yankebin 9 | *
10 | * CreatedAt:2019-07-09 11 | */ 12 | public interface DLNADeviceConnectListener { 13 | 14 | int TYPE_DLNA = 1; 15 | int TYPE_IM = 2; 16 | int TYPE_NEW_LELINK = 3; 17 | int CONNECT_INFO_CONNECT_SUCCESS = 100000; 18 | int CONNECT_INFO_CONNECT_FAILURE = 100001; 19 | int CONNECT_INFO_DISCONNECT = 212000; 20 | int CONNECT_INFO_DISCONNECT_SUCCESS = 212001; 21 | int CONNECT_ERROR_FAILED = 212010; 22 | int CONNECT_ERROR_IO = 212011; 23 | int CONNECT_ERROR_IM_WAITTING = 212012; 24 | int CONNECT_ERROR_IM_REJECT = 212013; 25 | int CONNECT_ERROR_IM_TIMEOUT = 212014; 26 | int CONNECT_ERROR_IM_BLACKLIST = 212015; 27 | 28 | void onConnect(DeviceInfo deviceInfo, int errorCode); 29 | 30 | void onDisconnect(DeviceInfo deviceInfo,int type,int errorCode); 31 | } 32 | -------------------------------------------------------------------------------- /screening/src/main/java/com/ykbjson/lib/screening/listener/DLNAStateCallback.java: -------------------------------------------------------------------------------- 1 | package com.ykbjson.lib.screening.listener; 2 | 3 | /** 4 | * Description:DLNAManager初始化回调接口 5 | *
6 | * Creator:yankebin 7 | *
8 | * CreatedAt:2019-07-09 9 | */ 10 | public interface DLNAStateCallback { 11 | 12 | void onConnected(); 13 | 14 | void onDisconnected(); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /screening/src/main/java/com/ykbjson/lib/screening/listener/OnRequestMediaProjectionResultCallback.java: -------------------------------------------------------------------------------- 1 | package com.ykbjson.lib.screening.listener; 2 | 3 | import android.media.projection.MediaProjection; 4 | 5 | import androidx.annotation.UiThread; 6 | 7 | /** 8 | * Description:获取录屏的MediaProjection的回调 9 | *
10 | * Creator:yankebin 11 | *
12 | * CreatedAt:2019-08-06 13 | */ 14 | public interface OnRequestMediaProjectionResultCallback { 15 | @UiThread 16 | void onMediaProjectionResult(MediaProjection mediaProjection); 17 | } 18 | -------------------------------------------------------------------------------- /screening/src/main/java/com/ykbjson/lib/screening/log/AndroidLoggingHandler.java: -------------------------------------------------------------------------------- 1 | package com.ykbjson.lib.screening.log; 2 | 3 | import android.util.Log; 4 | 5 | import java.util.logging.Handler; 6 | import java.util.logging.Level; 7 | import java.util.logging.LogManager; 8 | import java.util.logging.LogRecord; 9 | import java.util.logging.Logger; 10 | 11 | /** 12 | * Description:How to configure java.util.logging on Android? 13 | *

14 | * see https://stackoverflow.com/questions/4561345/how-to-configure-java-util-logging-on-android/9047282#9047282 15 | *

16 | *
17 | * Creator:yankebin 18 | *
19 | * CreatedAt:2019-07-19 20 | */ 21 | 22 | public final class AndroidLoggingHandler extends Handler { 23 | 24 | public static void injectJavaLogger() { 25 | Logger rootLogger = LogManager.getLogManager().getLogger(""); 26 | Handler[] handlers = rootLogger.getHandlers(); 27 | for (Handler handler : handlers) { 28 | rootLogger.removeHandler(handler); 29 | } 30 | rootLogger.addHandler(new AndroidLoggingHandler()); 31 | Logger.getLogger("my.category").setLevel(Level.FINEST); 32 | } 33 | 34 | @Override 35 | public void close() { 36 | } 37 | 38 | @Override 39 | public void flush() { 40 | } 41 | 42 | @Override 43 | public void publish(LogRecord record) { 44 | if (!super.isLoggable(record)) 45 | return; 46 | 47 | String name = record.getLoggerName(); 48 | int maxLength = 30; 49 | String tag = name.length() > maxLength ? name.substring(name.length() - maxLength) : name; 50 | 51 | try { 52 | int level = getAndroidLevel(record.getLevel()); 53 | Log.println(level, tag, record.getMessage()); 54 | if (record.getThrown() != null) { 55 | Log.println(level, tag, Log.getStackTraceString(record.getThrown())); 56 | } 57 | } catch (RuntimeException e) { 58 | Log.e("AndroidLoggingHandler", "Error logging message.", e); 59 | } 60 | } 61 | 62 | static int getAndroidLevel(Level level) { 63 | int value = level.intValue(); 64 | 65 | if (value >= Level.SEVERE.intValue()) { 66 | return Log.ERROR; 67 | } else if (value >= Level.WARNING.intValue()) { 68 | return Log.WARN; 69 | } else if (value >= Level.INFO.intValue()) { 70 | return Log.INFO; 71 | } else { 72 | return Log.DEBUG; 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /screening/src/main/java/com/ykbjson/lib/screening/xml/DLNASAXParser.java: -------------------------------------------------------------------------------- 1 | package com.ykbjson.lib.screening.xml; 2 | 3 | 4 | import org.seamless.xml.SAXParser; 5 | import org.xml.sax.XMLReader; 6 | 7 | import javax.xml.parsers.SAXParserFactory; 8 | 9 | /** 10 | * Description:DLNASAXParser 11 | *
12 | * Creator:yankebin 13 | *
14 | * CreatedAt:2019-07-10 15 | */ 16 | public class DLNASAXParser extends SAXParser { 17 | 18 | protected XMLReader create() { 19 | try { 20 | SAXParserFactory factory = SAXParserFactory.newInstance(); 21 | 22 | // Configure factory to prevent XXE attacks 23 | factory.setFeature("http://xml.org/sax/features/external-general-entities", false); 24 | factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); 25 | //解决创建解析器报错的问题 26 | // factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); 27 | // //fix bug .see https://stackoverflow.com/questions/10837706/solve-security-issue-parsing-xml-using-sax-parser 28 | // factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); 29 | 30 | // factory.setXIncludeAware(false); 31 | // 32 | // factory.setNamespaceAware(true); 33 | 34 | if (getSchemaSources() != null) { 35 | factory.setSchema(createSchema(getSchemaSources())); 36 | } 37 | 38 | XMLReader xmlReader = factory.newSAXParser().getXMLReader(); 39 | xmlReader.setErrorHandler(getErrorHandler()); 40 | return xmlReader; 41 | } catch (Exception ex) { 42 | throw new RuntimeException(ex); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /screening/src/main/java/com/ykbjson/lib/screening/xml/DLNAUDA10ServiceDescriptorBinderSAXImpl.java: -------------------------------------------------------------------------------- 1 | package com.ykbjson.lib.screening.xml; 2 | 3 | 4 | import com.ykbjson.lib.screening.DLNAManager; 5 | 6 | import org.fourthline.cling.binding.staging.MutableService; 7 | import org.fourthline.cling.binding.xml.DescriptorBindingException; 8 | import org.fourthline.cling.binding.xml.UDA10ServiceDescriptorBinderSAXImpl; 9 | import org.fourthline.cling.model.ValidationException; 10 | import org.fourthline.cling.model.meta.Service; 11 | import org.seamless.xml.SAXParser; 12 | import org.xml.sax.InputSource; 13 | 14 | import java.io.StringReader; 15 | 16 | /** 17 | * Description:DLNAUDA10ServiceDescriptorBinderSAXImpl 18 | *
19 | * Creator:yankebin 20 | *
21 | * CreatedAt:2019-07-10 22 | */ 23 | public class DLNAUDA10ServiceDescriptorBinderSAXImpl extends UDA10ServiceDescriptorBinderSAXImpl { 24 | 25 | private static final String TAG = DLNAUDA10ServiceDescriptorBinderSAXImpl.class.getSimpleName(); 26 | 27 | @Override 28 | public S describe(S undescribedService, String descriptorXml) throws DescriptorBindingException, ValidationException { 29 | if (descriptorXml == null || descriptorXml.length() == 0) { 30 | throw new DescriptorBindingException("Null or empty descriptor"); 31 | } 32 | 33 | try { 34 | 35 | DLNAManager.logD(TAG, "Reading service from XML descriptor, content : \n" + descriptorXml); 36 | 37 | SAXParser parser = new DLNASAXParser(); 38 | 39 | MutableService descriptor = new MutableService(); 40 | 41 | hydrateBasic(descriptor, undescribedService); 42 | 43 | new RootHandler(descriptor, parser); 44 | 45 | parser.parse( 46 | new InputSource( 47 | // TODO: UPNP VIOLATION: Virgin Media Superhub sends trailing spaces/newlines after last XML element, need to trim() 48 | new StringReader(descriptorXml.trim()) 49 | ) 50 | ); 51 | 52 | // Build the immutable descriptor graph 53 | return (S) descriptor.build(undescribedService.getDevice()); 54 | 55 | } catch (ValidationException ex) { 56 | throw ex; 57 | } catch (Exception ex) { 58 | throw new DescriptorBindingException("Could not parse service descriptor: " + ex.toString(), ex); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /screening/src/main/res/layout/activity_request_media_projection.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /screening/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | 16 | -------------------------------------------------------------------------------- /screenrecorder/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | .idea 3 | /.idea -------------------------------------------------------------------------------- /screenrecorder/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | repositories { 4 | flatDir { 5 | dirs 'libs' 6 | } 7 | } 8 | 9 | android { 10 | compileSdkVersion rootProject.ext.compileSdkVersion 11 | 12 | defaultConfig { 13 | minSdkVersion rootProject.ext.minSdkVersion 14 | targetSdkVersion rootProject.ext.targetSdkVersion 15 | versionCode rootProject.ext.versionCode 16 | versionName rootProject.ext.versionName 17 | } 18 | 19 | buildTypes { 20 | release { 21 | minifyEnabled false 22 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 23 | } 24 | } 25 | compileOptions { 26 | sourceCompatibility = '1.8' 27 | targetCompatibility = '1.8' 28 | } 29 | 30 | } 31 | 32 | dependencies { 33 | api fileTree(dir: 'libs', include: ['*.jar', '*.aar']) 34 | implementation "androidx.appcompat:appcompat:$rootProject.ext.supportLibraryVersion" 35 | api project(':rtmplibs')//流媒体推送sdk 36 | api project(':nginxserver')//本地rtmp服务器 37 | } 38 | -------------------------------------------------------------------------------- /screenrecorder/libs/mobile-ffmpeg.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaertj/simpledlna/b23c824fc83b1b1d1fa337b52301aa41e9a37526/screenrecorder/libs/mobile-ffmpeg.aar -------------------------------------------------------------------------------- /screenrecorder/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /screenrecorder/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /screenrecorder/src/main/aidl/com/ykbjson/lib/screenrecorder/AudioEncodeConfig.aidl: -------------------------------------------------------------------------------- 1 | // AudioConfig.aidl 2 | //package com.ykbjson.lib.screenrecorder; 3 | //parcelable AudioEncodeConfig; 4 | -------------------------------------------------------------------------------- /screenrecorder/src/main/aidl/com/ykbjson/lib/screenrecorder/ICallback.aidl: -------------------------------------------------------------------------------- 1 | // IRecorderCallback.aidl 2 | //package com.ykbjson.lib.screenrecorder; 3 | // 4 | //// Declare any non-default types here with import statements 5 | // 6 | //interface IRecorderCallback { 7 | // 8 | // void onStopRecord(in String error); 9 | // 10 | // void onStartRecord(); 11 | // 12 | // void onRecording(in long presentationTimeUs); 13 | //} 14 | -------------------------------------------------------------------------------- /screenrecorder/src/main/aidl/com/ykbjson/lib/screenrecorder/IScreenRecorderService.aidl: -------------------------------------------------------------------------------- 1 | // 2 | //package com.ykbjson.lib.screenrecorder; 3 | //import com.ykbjson.lib.screenrecorder.VideoEncodeConfig; 4 | //import com.ykbjson.lib.screenrecorder.AudioEncodeConfig; 5 | //import com.ykbjson.lib.screenrecorder.IRecorderCallback; 6 | // 7 | //interface IScreenRecorderService { 8 | // 9 | // void registerRecorderCallback(in IRecorderCallback callback); 10 | // 11 | // void prepareRecorder(in int resultCode,in Intent intent,in VideoEncodeConfig videoConfig, 12 | // in AudioEncodeConfig audioCofig,in String savingFilePath); 13 | // 14 | // void startRecorder(); 15 | // 16 | // void stopRecorder(); 17 | // 18 | // void destroy(); 19 | // 20 | // String getSavingFilePath(); 21 | // 22 | // boolean hasPrepared(); 23 | //} 24 | -------------------------------------------------------------------------------- /screenrecorder/src/main/aidl/com/ykbjson/lib/screenrecorder/VideoEncodeConfig.aidl: -------------------------------------------------------------------------------- 1 | //// VideoConfig.aidl 2 | //package com.ykbjson.lib.screenrecorder; 3 | //parcelable VideoEncodeConfig; 4 | -------------------------------------------------------------------------------- /screenrecorder/src/main/java/com/ykbjson/lib/screenrecorder/AudioEncodeConfig.java: -------------------------------------------------------------------------------- 1 | package com.ykbjson.lib.screenrecorder; 2 | 3 | import android.media.MediaCodecInfo; 4 | import android.media.MediaFormat; 5 | 6 | import androidx.annotation.NonNull; 7 | 8 | import java.util.Objects; 9 | 10 | import static com.ykbjson.lib.screenrecorder.ScreenRecorder.AUDIO_AAC; 11 | 12 | /** 13 | * Description:音频编码配置 14 | *
15 | * Creator:yankebin 16 | *
17 | * CreatedAt:2019-07-29 18 | */ 19 | public class AudioEncodeConfig { 20 | final String codecName; 21 | final String mimeType; 22 | final int bitRate; 23 | final int sampleRate; 24 | final int channelCount; 25 | final int profile; 26 | 27 | 28 | private AudioEncodeConfig(Builder builder) { 29 | this(builder.codecName, builder.mimeType, builder.bitrate, builder.simpleRate, 30 | builder.channelCount, builder.profile); 31 | } 32 | 33 | public AudioEncodeConfig(String codecName, String mimeType, 34 | int bitRate, int sampleRate, int channelCount, int profile) { 35 | this.codecName = codecName; 36 | this.mimeType = Objects.requireNonNull(mimeType); 37 | this.bitRate = bitRate; 38 | this.sampleRate = sampleRate; 39 | this.channelCount = channelCount; 40 | this.profile = profile; 41 | } 42 | 43 | 44 | MediaFormat toFormat() { 45 | MediaFormat format = MediaFormat.createAudioFormat(mimeType, sampleRate, channelCount); 46 | format.setInteger(MediaFormat.KEY_AAC_PROFILE, profile); 47 | format.setInteger(MediaFormat.KEY_BIT_RATE, bitRate); 48 | //format.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 4096 * 4); 49 | return format; 50 | } 51 | 52 | @Override 53 | public String toString() { 54 | return "AudioEncodeConfig{" + 55 | "codecName='" + codecName + '\'' + 56 | ", mimeType='" + mimeType + '\'' + 57 | ", bitRate=" + bitRate + 58 | ", sampleRate=" + sampleRate + 59 | ", channelCount=" + channelCount + 60 | ", profile=" + profile + 61 | '}'; 62 | } 63 | 64 | public static final class Builder { 65 | private String codecName; 66 | private String mimeType = AUDIO_AAC; 67 | private int bitrate = 80 * 1000; 68 | private int simpleRate = 44100; 69 | private int channelCount = 2; 70 | private int profile = MediaCodecInfo.CodecProfileLevel.AACObjectMain; 71 | 72 | public Builder() { 73 | final MediaCodecInfo[] infos = Utils.getmAacCodecInfos(); 74 | if (null != infos && infos.length > 0) { 75 | codecName = infos[0].getName(); 76 | } 77 | } 78 | 79 | public static Builder create() { 80 | return new Builder(); 81 | } 82 | 83 | public Builder codecName(@NonNull String codecName) { 84 | this.codecName = codecName; 85 | return this; 86 | } 87 | 88 | public Builder mimeType(@NonNull String mimeType) { 89 | this.mimeType = mimeType; 90 | return this; 91 | } 92 | 93 | public Builder bitrate(int bitrate) { 94 | this.bitrate = bitrate; 95 | return this; 96 | } 97 | 98 | public Builder simpleRate(int simpleRate) { 99 | this.simpleRate = simpleRate; 100 | return this; 101 | } 102 | 103 | public Builder channelCount(int channelCount) { 104 | this.channelCount = channelCount; 105 | return this; 106 | } 107 | 108 | public Builder profile(int profile) { 109 | this.profile = profile; 110 | return this; 111 | } 112 | 113 | public AudioEncodeConfig build() { 114 | return new AudioEncodeConfig(this); 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /screenrecorder/src/main/java/com/ykbjson/lib/screenrecorder/AudioEncoder.java: -------------------------------------------------------------------------------- 1 | package com.ykbjson.lib.screenrecorder; 2 | 3 | import android.media.MediaFormat; 4 | 5 | 6 | /** 7 | * Description:音频编码器 8 | *
9 | * Creator:yankebin 10 | *
11 | * CreatedAt:2019-07-29 12 | */ 13 | class AudioEncoder extends BaseEncoder { 14 | private final AudioEncodeConfig mConfig; 15 | 16 | AudioEncoder(AudioEncodeConfig config) { 17 | super(config.codecName); 18 | this.mConfig = config; 19 | } 20 | 21 | @Override 22 | protected MediaFormat createMediaFormat() { 23 | return mConfig.toFormat(); 24 | } 25 | 26 | AudioEncodeConfig getConfig() { 27 | return mConfig; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /screenrecorder/src/main/java/com/ykbjson/lib/screenrecorder/Encoder.java: -------------------------------------------------------------------------------- 1 | package com.ykbjson.lib.screenrecorder; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * Description:编码器接口 7 | *
8 | * Creator:yankebin 9 | *
10 | * CreatedAt:2019-07-29 11 | */ 12 | interface Encoder { 13 | void prepare() throws IOException; 14 | 15 | void stop(); 16 | 17 | void release(); 18 | 19 | void setCallback(Callback callback); 20 | 21 | interface Callback { 22 | void onError(Encoder encoder, Exception exception); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /screenrecorder/src/main/java/com/ykbjson/lib/screenrecorder/IRecorderCallback.java: -------------------------------------------------------------------------------- 1 | package com.ykbjson.lib.screenrecorder; 2 | 3 | import android.media.MediaCodec; 4 | 5 | /** 6 | * Description:录屏状态回调接口 7 | *
8 | * Creator:yankebin 9 | *
10 | * CreatedAt:2019-07-31 11 | */ 12 | public interface IRecorderCallback { 13 | 14 | void onPrepareRecord(); 15 | 16 | void onStartRecord(); 17 | 18 | void onRecording(long presentationTimeUs); 19 | 20 | void onStopRecord(Throwable error); 21 | 22 | void onDestroyRecord(); 23 | 24 | void onMuxVideo(byte[] buffer, int offset, int length, MediaCodec.BufferInfo bufferInfo); 25 | 26 | void onMuxAudio(byte[] buffer, int offset, int length, MediaCodec.BufferInfo bufferInfo); 27 | } 28 | -------------------------------------------------------------------------------- /screenrecorder/src/main/java/com/ykbjson/lib/screenrecorder/IScreenRecorderService.java: -------------------------------------------------------------------------------- 1 | package com.ykbjson.lib.screenrecorder; 2 | 3 | import android.media.projection.MediaProjection; 4 | 5 | /** 6 | * Description:录屏服务 7 | *
8 | * The default implementation requires permissions in AndroidManifest.xml: 9 | *

10 | *
{@code
11 |  *  
12 |  *  
13 |  *  }
14 | *

15 | * Creator:yankebin 16 | *
17 | * CreatedAt:2019-07-31 18 | */ 19 | public interface IScreenRecorderService { 20 | 21 | void registerRecorderCallback(IRecorderCallback callback); 22 | 23 | void prepareAndStartRecorder(MediaProjection mediaProjection, VideoEncodeConfig videoConfig, 24 | AudioEncodeConfig audioConfig); 25 | 26 | void startRecorder(VideoEncodeConfig videoConfig, AudioEncodeConfig audioConfig); 27 | 28 | void startRecorder(); 29 | 30 | void stopRecorder(); 31 | 32 | void destroyRecorder(); 33 | 34 | String getSavingFilePath(); 35 | 36 | VideoEncodeConfig getVideoEncodeConfig(); 37 | 38 | AudioEncodeConfig getAudioEncodeConfig(); 39 | 40 | boolean hasPrepared(); 41 | } 42 | -------------------------------------------------------------------------------- /screenrecorder/src/main/java/com/ykbjson/lib/screenrecorder/IScreenRecorderServiceProxy.java: -------------------------------------------------------------------------------- 1 | package com.ykbjson.lib.screenrecorder; 2 | 3 | /** 4 | * Description:录屏服务中转接口 5 | *
6 | * Creator:yankebin 7 | *
8 | * CreatedAt:2019-07-31 9 | */ 10 | interface IScreenRecorderServiceProxy extends IScreenRecorderService { 11 | IScreenRecorderService get(); 12 | } 13 | -------------------------------------------------------------------------------- /screenrecorder/src/main/java/com/ykbjson/lib/screenrecorder/Notifications.java: -------------------------------------------------------------------------------- 1 | package com.ykbjson.lib.screenrecorder; 2 | 3 | import android.annotation.TargetApi; 4 | import android.app.Notification; 5 | import android.app.NotificationChannel; 6 | import android.app.NotificationManager; 7 | import android.app.PendingIntent; 8 | import android.content.Context; 9 | import android.content.ContextWrapper; 10 | import android.content.Intent; 11 | import android.os.Build; 12 | import android.os.SystemClock; 13 | import android.text.format.DateUtils; 14 | 15 | import static android.os.Build.VERSION_CODES.O; 16 | 17 | /** 18 | * Description:通知帮助类,录屏属于隐私操作,需要用户时刻注意到 19 | *
20 | * Creator:yankebin 21 | *
22 | * CreatedAt:2019-07-30 23 | */ 24 | public class Notifications extends ContextWrapper { 25 | 26 | public static final String ACTION_STOP = BuildConfig.APPLICATION_ID + ".action.STOP"; 27 | 28 | protected long mLastFiredTime = 0; 29 | protected NotificationManager mManager; 30 | protected Notification.Action mStopAction; 31 | protected Notification.Builder mBuilder; 32 | 33 | public Notifications(Context context) { 34 | super(context); 35 | if (Build.VERSION.SDK_INT >= O) { 36 | createNotificationChannel(); 37 | } 38 | } 39 | 40 | public void recording(long timeMs) { 41 | if (SystemClock.elapsedRealtime() - mLastFiredTime < 1000) { 42 | return; 43 | } 44 | Notification notification = getBuilder() 45 | .setContentText("Length: " + DateUtils.formatElapsedTime(timeMs / 1000)) 46 | .build(); 47 | getNotificationManager().notify(getId(), notification); 48 | mLastFiredTime = SystemClock.elapsedRealtime(); 49 | } 50 | 51 | protected Notification.Builder getBuilder() { 52 | if (mBuilder == null) { 53 | Notification.Builder builder = new Notification.Builder(this) 54 | .setContentTitle("Recording...") 55 | .setOngoing(true) 56 | .setLocalOnly(true) 57 | .setOnlyAlertOnce(true) 58 | .addAction(stopAction()) 59 | .setWhen(System.currentTimeMillis()) 60 | .setSmallIcon(R.drawable.ic_stat_recording); 61 | if (Build.VERSION.SDK_INT >= O) { 62 | builder.setChannelId(getChannelId()) 63 | .setUsesChronometer(true); 64 | } 65 | mBuilder = builder; 66 | } 67 | return mBuilder; 68 | } 69 | 70 | @TargetApi(O) 71 | protected void createNotificationChannel() { 72 | NotificationChannel channel = 73 | new NotificationChannel(getChannelId(), getChannelName(), NotificationManager.IMPORTANCE_LOW); 74 | channel.setShowBadge(false); 75 | getNotificationManager().createNotificationChannel(channel); 76 | } 77 | 78 | protected Notification.Action stopAction() { 79 | if (mStopAction == null) { 80 | Intent intent = new Intent(ACTION_STOP); 81 | PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 1, 82 | intent, PendingIntent.FLAG_ONE_SHOT); 83 | mStopAction = new Notification.Action(android.R.drawable.ic_media_pause, "Stop", pendingIntent); 84 | } 85 | return mStopAction; 86 | } 87 | 88 | public void clear() { 89 | mLastFiredTime = 0; 90 | mBuilder = null; 91 | mStopAction = null; 92 | getNotificationManager().cancelAll(); 93 | } 94 | 95 | protected NotificationManager getNotificationManager() { 96 | if (mManager == null) { 97 | mManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); 98 | } 99 | return mManager; 100 | } 101 | 102 | protected int getId(){ 103 | return 0x1fff; 104 | } 105 | 106 | protected String getChannelId(){ 107 | return "Recording"; 108 | } 109 | 110 | protected String getChannelName(){ 111 | return "Screen Recorder Notifications"; 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /screenrecorder/src/main/java/com/ykbjson/lib/screenrecorder/VideoEncoder.java: -------------------------------------------------------------------------------- 1 | package com.ykbjson.lib.screenrecorder; 2 | 3 | import android.media.MediaCodec; 4 | import android.media.MediaFormat; 5 | import android.util.Log; 6 | import android.view.Surface; 7 | 8 | import java.util.Objects; 9 | 10 | /** 11 | * Description:视频编码器 12 | *
13 | * Creator:yankebin 14 | *
15 | * CreatedAt:2019-07-29 16 | */ 17 | class VideoEncoder extends BaseEncoder { 18 | private static final boolean VERBOSE = false; 19 | private VideoEncodeConfig mConfig; 20 | private Surface mSurface; 21 | 22 | 23 | VideoEncoder(VideoEncodeConfig config) { 24 | super(config.codecName); 25 | this.mConfig = config; 26 | } 27 | 28 | @Override 29 | protected void onEncoderConfigured(MediaCodec encoder) { 30 | mSurface = encoder.createInputSurface(); 31 | if (VERBOSE) Log.i("@@", "VideoEncoder create input surface: " + mSurface); 32 | } 33 | 34 | @Override 35 | protected MediaFormat createMediaFormat() { 36 | return mConfig.toFormat(); 37 | } 38 | 39 | /** 40 | * @throws NullPointerException if prepare() not call 41 | */ 42 | Surface getInputSurface() { 43 | return Objects.requireNonNull(mSurface, "doesn't prepare()"); 44 | } 45 | 46 | @Override 47 | public void release() { 48 | if (mSurface != null) { 49 | mSurface.release(); 50 | mSurface = null; 51 | } 52 | super.release(); 53 | } 54 | 55 | VideoEncodeConfig getConfig() { 56 | return mConfig; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /screenrecorder/src/main/res/drawable-hdpi/ic_stat_recording.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaertj/simpledlna/b23c824fc83b1b1d1fa337b52301aa41e9a37526/screenrecorder/src/main/res/drawable-hdpi/ic_stat_recording.png -------------------------------------------------------------------------------- /screenrecorder/src/main/res/drawable-mdpi/ic_stat_recording.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaertj/simpledlna/b23c824fc83b1b1d1fa337b52301aa41e9a37526/screenrecorder/src/main/res/drawable-mdpi/ic_stat_recording.png -------------------------------------------------------------------------------- /screenrecorder/src/main/res/drawable-xhdpi/ic_stat_recording.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaertj/simpledlna/b23c824fc83b1b1d1fa337b52301aa41e9a37526/screenrecorder/src/main/res/drawable-xhdpi/ic_stat_recording.png -------------------------------------------------------------------------------- /screenrecorder/src/main/res/drawable-xxhdpi/ic_stat_recording.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javaertj/simpledlna/b23c824fc83b1b1d1fa337b52301aa41e9a37526/screenrecorder/src/main/res/drawable-xxhdpi/ic_stat_recording.png -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':screening', ':webserver', ':simplepermission', ':screenrecorder', ':rtmplibs', ':nginxserver' 2 | -------------------------------------------------------------------------------- /simplepermission/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | .idea 3 | /.idea -------------------------------------------------------------------------------- /simplepermission/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | 4 | android { 5 | compileSdkVersion rootProject.ext.compileSdkVersion 6 | 7 | defaultConfig { 8 | minSdkVersion rootProject.ext.minSdkVersion 9 | targetSdkVersion rootProject.ext.targetSdkVersion 10 | versionCode rootProject.ext.versionCode 11 | versionName rootProject.ext.versionName 12 | } 13 | lintOptions { 14 | abortOnError false 15 | } 16 | } 17 | 18 | dependencies { 19 | implementation fileTree(dir: 'libs', include: ['*.jar']) 20 | implementation "androidx.appcompat:appcompat:$rootProject.ext.supportLibraryVersion" 21 | implementation "io.reactivex.rxjava2:rxandroid:$rootProject.ext.rxAndroidVersion" 22 | } 23 | -------------------------------------------------------------------------------- /simplepermission/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /simplepermission/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | -------------------------------------------------------------------------------- /simplepermission/src/main/java/com/ykbjson/lib/simplepermission/Permissions.java: -------------------------------------------------------------------------------- 1 | package com.ykbjson.lib.simplepermission; 2 | 3 | /** 4 | * Desription:Enum class to handle the different states 5 | * of permissions since the PackageManager only 6 | * has a granted and denied state. 7 | * Creator:yankebin 8 | * CreatedAt:2018/11/7 9 | */ 10 | enum Permissions { 11 | GRANTED, 12 | DENIED, 13 | NOT_FOUND, 14 | USER_DENIED_FOREVER 15 | } -------------------------------------------------------------------------------- /simplepermission/src/main/java/com/ykbjson/lib/simplepermission/PermissionsRequestCallback.java: -------------------------------------------------------------------------------- 1 | package com.ykbjson.lib.simplepermission; 2 | 3 | /** 4 | * Description:权限申请结果回调 5 | * Creator:yankebin 6 | * CreatedAt:2018/11/1 7 | */ 8 | public interface PermissionsRequestCallback { 9 | /** 10 | * This method is called when a permission that have been 11 | * requested have been granted by the user. In this method 12 | * you should put your permission(s) sensitive code that can 13 | * only be executed with the required permissions. 14 | */ 15 | void onGranted(int requestCode, String permission); 16 | 17 | /** 18 | * This method is called when a permission has been denied by 19 | * the user. It provides you with the permission that was denied 20 | * and will be executed on the Looper you pass to the constructor 21 | * of this class, or the Looper that this object was created on. 22 | * 23 | * @param permission the permission that was denied. 24 | */ 25 | void onDenied(int requestCode, String permission); 26 | 27 | /** 28 | * This method is called when a permission has been denied by 29 | * the user forever. It provides you with the permission that was denied 30 | * and will be executed on the Looper you pass to the constructor 31 | * of this class, or the Looper that this object was created on. 32 | * 33 | * @param permission the permission that was denied. 34 | */ 35 | void onDeniedForever(int requestCode, String permission); 36 | 37 | /** 38 | * This method is called when all permissions has been check complete 39 | * but some permissions denied. 40 | * 41 | * @param deniedPermissions those denied permissions 42 | */ 43 | void onFailure(int requestCode, String[] deniedPermissions); 44 | 45 | /** 46 | * This method is called when all permissions has been check complete 47 | * and all permissions granted. 48 | */ 49 | void onSuccess(int requestCode); 50 | } 51 | -------------------------------------------------------------------------------- /simplepermission/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | simplePermission 3 | 4 | -------------------------------------------------------------------------------- /webserver/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | .idea 3 | /.idea -------------------------------------------------------------------------------- /webserver/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion rootProject.ext.compileSdkVersion 5 | defaultConfig { 6 | minSdkVersion rootProject.ext.minSdkVersion 7 | targetSdkVersion rootProject.ext.targetSdkVersion 8 | versionCode rootProject.ext.versionCode 9 | versionName rootProject.ext.versionName 10 | } 11 | 12 | buildTypes { 13 | release { 14 | minifyEnabled false 15 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 16 | } 17 | } 18 | 19 | } 20 | 21 | dependencies { 22 | implementation fileTree(dir: 'libs', include: ['*.jar']) 23 | implementation "androidx.appcompat:appcompat:$rootProject.ext.supportLibraryVersion" 24 | api 'com.jrummyapps:android-shell:1.0.0' 25 | } 26 | -------------------------------------------------------------------------------- /webserver/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /webserver/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | -------------------------------------------------------------------------------- /webserver/src/main/java/org/nanohttpd/webserver/InternalRewrite.java: -------------------------------------------------------------------------------- 1 | package org.nanohttpd.webserver; 2 | 3 | /* 4 | * #%L 5 | * NanoHttpd-Webserver 6 | * %% 7 | * Copyright (C) 2012 - 2015 nanohttpd 8 | * %% 9 | * Redistribution and use in source and binary forms, with or without modification, 10 | * are permitted provided that the following conditions are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright notice, this 13 | * list of conditions and the following disclaimer. 14 | * 15 | * 2. Redistributions in binary form must reproduce the above copyright notice, 16 | * this list of conditions and the following disclaimer in the documentation 17 | * and/or other materials provided with the distribution. 18 | * 19 | * 3. Neither the name of the nanohttpd nor the names of its contributors 20 | * may be used to endorse or promote products derived from this software without 21 | * specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 27 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 30 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 32 | * OF THE POSSIBILITY OF SUCH DAMAGE. 33 | * #L% 34 | */ 35 | 36 | import java.io.ByteArrayInputStream; 37 | import java.util.Map; 38 | 39 | import org.protocols.http.NanoHTTPD; 40 | import org.protocols.http.response.Response; 41 | import org.protocols.http.response.Status; 42 | 43 | /** 44 | * @author Paul S. Hawke (paul.hawke@gmail.com) On: 9/15/13 at 2:52 PM 45 | */ 46 | public class InternalRewrite extends Response { 47 | 48 | private final String uri; 49 | 50 | private final Map headers; 51 | 52 | public InternalRewrite(Map headers, String uri) { 53 | super(Status.OK, NanoHTTPD.MIME_HTML, new ByteArrayInputStream(new byte[0]), 0); 54 | this.headers = headers; 55 | this.uri = uri; 56 | } 57 | 58 | public Map getHeaders() { 59 | return this.headers; 60 | } 61 | 62 | public String getUri() { 63 | return this.uri; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /webserver/src/main/java/org/nanohttpd/webserver/WebServerPlugin.java: -------------------------------------------------------------------------------- 1 | package org.nanohttpd.webserver; 2 | 3 | /* 4 | * #%L 5 | * NanoHttpd-Webserver 6 | * %% 7 | * Copyright (C) 2012 - 2015 nanohttpd 8 | * %% 9 | * Redistribution and use in source and binary forms, with or without modification, 10 | * are permitted provided that the following conditions are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright notice, this 13 | * list of conditions and the following disclaimer. 14 | * 15 | * 2. Redistributions in binary form must reproduce the above copyright notice, 16 | * this list of conditions and the following disclaimer in the documentation 17 | * and/or other materials provided with the distribution. 18 | * 19 | * 3. Neither the name of the nanohttpd nor the names of its contributors 20 | * may be used to endorse or promote products derived from this software without 21 | * specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 27 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 30 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 32 | * OF THE POSSIBILITY OF SUCH DAMAGE. 33 | * #L% 34 | */ 35 | 36 | import java.io.File; 37 | import java.util.Map; 38 | 39 | import org.protocols.http.IHTTPSession; 40 | import org.protocols.http.response.Response; 41 | 42 | /** 43 | * @author Paul S. Hawke (paul.hawke@gmail.com) On: 9/14/13 at 8:09 AM 44 | */ 45 | public interface WebServerPlugin { 46 | 47 | boolean canServeUri(String uri, File rootDir); 48 | 49 | void initialize(Map commandLineOptions); 50 | 51 | Response serveFile(String uri, Map headers, IHTTPSession session, File file, String mimeType); 52 | } 53 | -------------------------------------------------------------------------------- /webserver/src/main/java/org/nanohttpd/webserver/WebServerPluginInfo.java: -------------------------------------------------------------------------------- 1 | package org.nanohttpd.webserver; 2 | 3 | /* 4 | * #%L 5 | * NanoHttpd-Webserver 6 | * %% 7 | * Copyright (C) 2012 - 2015 nanohttpd 8 | * %% 9 | * Redistribution and use in source and binary forms, with or without modification, 10 | * are permitted provided that the following conditions are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright notice, this 13 | * list of conditions and the following disclaimer. 14 | * 15 | * 2. Redistributions in binary form must reproduce the above copyright notice, 16 | * this list of conditions and the following disclaimer in the documentation 17 | * and/or other materials provided with the distribution. 18 | * 19 | * 3. Neither the name of the nanohttpd nor the names of its contributors 20 | * may be used to endorse or promote products derived from this software without 21 | * specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 27 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 30 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 32 | * OF THE POSSIBILITY OF SUCH DAMAGE. 33 | * #L% 34 | */ 35 | 36 | /** 37 | * @author Paul S. Hawke (paul.hawke@gmail.com) On: 9/14/13 at 8:09 AM 38 | */ 39 | public interface WebServerPluginInfo { 40 | 41 | String[] getIndexFilesForMimeType(String mime); 42 | 43 | String[] getMimeTypes(); 44 | 45 | WebServerPlugin getWebServerPlugin(String mimeType); 46 | } 47 | -------------------------------------------------------------------------------- /webserver/src/main/java/org/protocols/http/ClientHandler.java: -------------------------------------------------------------------------------- 1 | package org.protocols.http; 2 | 3 | /* 4 | * #%L 5 | * NanoHttpd-Core 6 | * %% 7 | * Copyright (C) 2012 - 2016 nanohttpd 8 | * %% 9 | * Redistribution and use in source and binary forms, with or without modification, 10 | * are permitted provided that the following conditions are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright notice, this 13 | * list of conditions and the following disclaimer. 14 | * 15 | * 2. Redistributions in binary form must reproduce the above copyright notice, 16 | * this list of conditions and the following disclaimer in the documentation 17 | * and/or other materials provided with the distribution. 18 | * 19 | * 3. Neither the name of the nanohttpd nor the names of its contributors 20 | * may be used to endorse or promote products derived from this software without 21 | * specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 27 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 30 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 32 | * OF THE POSSIBILITY OF SUCH DAMAGE. 33 | * #L% 34 | */ 35 | 36 | import java.io.InputStream; 37 | import java.io.OutputStream; 38 | import java.net.Socket; 39 | import java.net.SocketException; 40 | import java.net.SocketTimeoutException; 41 | import java.util.logging.Level; 42 | 43 | import org.protocols.http.tempfiles.ITempFileManager; 44 | 45 | /** 46 | * The runnable that will be used for every new client connection. 47 | */ 48 | public class ClientHandler implements Runnable { 49 | 50 | private final NanoHTTPD httpd; 51 | 52 | private final InputStream inputStream; 53 | 54 | private final Socket acceptSocket; 55 | 56 | public ClientHandler(NanoHTTPD httpd, InputStream inputStream, Socket acceptSocket) { 57 | this.httpd = httpd; 58 | this.inputStream = inputStream; 59 | this.acceptSocket = acceptSocket; 60 | } 61 | 62 | public void close() { 63 | NanoHTTPD.safeClose(this.inputStream); 64 | NanoHTTPD.safeClose(this.acceptSocket); 65 | } 66 | 67 | @Override 68 | public void run() { 69 | OutputStream outputStream = null; 70 | try { 71 | outputStream = this.acceptSocket.getOutputStream(); 72 | ITempFileManager tempFileManager = httpd.getTempFileManagerFactory().create(); 73 | HTTPSession session = new HTTPSession(httpd, tempFileManager, this.inputStream, outputStream, this.acceptSocket.getInetAddress()); 74 | while (!this.acceptSocket.isClosed()) { 75 | session.execute(); 76 | } 77 | } catch (Exception e) { 78 | // When the socket is closed by the client, 79 | // we throw our own SocketException 80 | // to break the "keep alive" loop above. If 81 | // the exception was anything other 82 | // than the expected SocketException OR a 83 | // SocketTimeoutException, print the 84 | // stacktrace 85 | if (!(e instanceof SocketException && "NanoHttpd Shutdown".equals(e.getMessage())) && !(e instanceof SocketTimeoutException)) { 86 | NanoHTTPD.LOG.log(Level.SEVERE, "Communication with the client broken, or an bug in the handler code", e); 87 | } 88 | } finally { 89 | NanoHTTPD.safeClose(outputStream); 90 | NanoHTTPD.safeClose(this.inputStream); 91 | NanoHTTPD.safeClose(this.acceptSocket); 92 | httpd.asyncRunner.closed(this); 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /webserver/src/main/java/org/protocols/http/IHTTPSession.java: -------------------------------------------------------------------------------- 1 | package org.protocols.http; 2 | 3 | /* 4 | * #%L 5 | * NanoHttpd-Core 6 | * %% 7 | * Copyright (C) 2012 - 2016 nanohttpd 8 | * %% 9 | * Redistribution and use in source and binary forms, with or without modification, 10 | * are permitted provided that the following conditions are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright notice, this 13 | * list of conditions and the following disclaimer. 14 | * 15 | * 2. Redistributions in binary form must reproduce the above copyright notice, 16 | * this list of conditions and the following disclaimer in the documentation 17 | * and/or other materials provided with the distribution. 18 | * 19 | * 3. Neither the name of the nanohttpd nor the names of its contributors 20 | * may be used to endorse or promote products derived from this software without 21 | * specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 27 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 30 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 32 | * OF THE POSSIBILITY OF SUCH DAMAGE. 33 | * #L% 34 | */ 35 | 36 | import java.io.IOException; 37 | import java.io.InputStream; 38 | import java.util.List; 39 | import java.util.Map; 40 | 41 | import org.protocols.http.NanoHTTPD.ResponseException; 42 | import org.protocols.http.content.CookieHandler; 43 | import org.protocols.http.request.Method; 44 | 45 | /** 46 | * Handles one session, i.e. parses the HTTP request and returns the response. 47 | */ 48 | public interface IHTTPSession { 49 | 50 | void execute() throws IOException; 51 | 52 | CookieHandler getCookies(); 53 | 54 | Map getHeaders(); 55 | 56 | InputStream getInputStream(); 57 | 58 | Method getMethod(); 59 | 60 | /** 61 | * This method will only return the first value for a given parameter. You 62 | * will want to use getParameters if you expect multiple values for a given 63 | * key. 64 | * 65 | * @deprecated use {@link #getParameters()} instead. 66 | */ 67 | @Deprecated 68 | Map getParms(); 69 | 70 | Map> getParameters(); 71 | 72 | String getQueryParameterString(); 73 | 74 | /** 75 | * @return the path part of the URL. 76 | */ 77 | String getUri(); 78 | 79 | /** 80 | * Adds the files in the request body to the files map. 81 | * 82 | * @param files 83 | * map to modify 84 | */ 85 | void parseBody(Map files) throws IOException, ResponseException; 86 | 87 | /** 88 | * Get the remote ip address of the requester. 89 | * 90 | * @return the IP address. 91 | */ 92 | String getRemoteIpAddress(); 93 | 94 | /** 95 | * Get the remote hostname of the requester. 96 | * 97 | * @return the hostname. 98 | */ 99 | String getRemoteHostName(); 100 | } 101 | -------------------------------------------------------------------------------- /webserver/src/main/java/org/protocols/http/ServerRunnable.java: -------------------------------------------------------------------------------- 1 | package org.protocols.http; 2 | 3 | /* 4 | * #%L 5 | * NanoHttpd-Core 6 | * %% 7 | * Copyright (C) 2012 - 2016 nanohttpd 8 | * %% 9 | * Redistribution and use in source and binary forms, with or without modification, 10 | * are permitted provided that the following conditions are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright notice, this 13 | * list of conditions and the following disclaimer. 14 | * 15 | * 2. Redistributions in binary form must reproduce the above copyright notice, 16 | * this list of conditions and the following disclaimer in the documentation 17 | * and/or other materials provided with the distribution. 18 | * 19 | * 3. Neither the name of the nanohttpd nor the names of its contributors 20 | * may be used to endorse or promote products derived from this software without 21 | * specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 27 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 30 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 32 | * OF THE POSSIBILITY OF SUCH DAMAGE. 33 | * #L% 34 | */ 35 | 36 | import java.io.IOException; 37 | import java.io.InputStream; 38 | import java.net.InetSocketAddress; 39 | import java.net.Socket; 40 | import java.util.logging.Level; 41 | 42 | /** 43 | * The runnable that will be used for the main listening thread. 44 | */ 45 | public class ServerRunnable implements Runnable { 46 | 47 | private NanoHTTPD httpd; 48 | 49 | private final int timeout; 50 | 51 | private IOException bindException; 52 | 53 | private boolean hasBinded = false; 54 | 55 | public ServerRunnable(NanoHTTPD httpd, int timeout) { 56 | this.httpd = httpd; 57 | this.timeout = timeout; 58 | } 59 | 60 | @Override 61 | public void run() { 62 | try { 63 | httpd.getMyServerSocket().bind(httpd.hostname != null ? new InetSocketAddress(httpd.hostname, httpd.myPort) : new InetSocketAddress(httpd.myPort)); 64 | hasBinded = true; 65 | } catch (IOException e) { 66 | this.bindException = e; 67 | return; 68 | } 69 | do { 70 | try { 71 | final Socket finalAccept = httpd.getMyServerSocket().accept(); 72 | if (this.timeout > 0) { 73 | finalAccept.setSoTimeout(this.timeout); 74 | } 75 | final InputStream inputStream = finalAccept.getInputStream(); 76 | httpd.asyncRunner.exec(httpd.createClientHandler(finalAccept, inputStream)); 77 | } catch (IOException e) { 78 | NanoHTTPD.LOG.log(Level.FINE, "Communication with the client broken", e); 79 | } 80 | } while (!httpd.getMyServerSocket().isClosed()); 81 | } 82 | 83 | public IOException getBindException() { 84 | return bindException; 85 | } 86 | 87 | public boolean hasBinded() { 88 | return hasBinded; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /webserver/src/main/java/org/protocols/http/content/ContentType.java: -------------------------------------------------------------------------------- 1 | package org.protocols.http.content; 2 | 3 | /* 4 | * #%L 5 | * NanoHttpd-Core 6 | * %% 7 | * Copyright (C) 2012 - 2016 nanohttpd 8 | * %% 9 | * Redistribution and use in source and binary forms, with or without modification, 10 | * are permitted provided that the following conditions are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright notice, this 13 | * list of conditions and the following disclaimer. 14 | * 15 | * 2. Redistributions in binary form must reproduce the above copyright notice, 16 | * this list of conditions and the following disclaimer in the documentation 17 | * and/or other materials provided with the distribution. 18 | * 19 | * 3. Neither the name of the nanohttpd nor the names of its contributors 20 | * may be used to endorse or promote products derived from this software without 21 | * specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 27 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 30 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 32 | * OF THE POSSIBILITY OF SUCH DAMAGE. 33 | * #L% 34 | */ 35 | 36 | import java.util.regex.Matcher; 37 | import java.util.regex.Pattern; 38 | 39 | public class ContentType { 40 | 41 | private static final String ASCII_ENCODING = "US-ASCII"; 42 | 43 | private static final String MULTIPART_FORM_DATA_HEADER = "multipart/form-data"; 44 | 45 | private static final String CONTENT_REGEX = "[ |\t]*([^/^ ^;^,]+/[^ ^;^,]+)"; 46 | 47 | private static final Pattern MIME_PATTERN = Pattern.compile(CONTENT_REGEX, Pattern.CASE_INSENSITIVE); 48 | 49 | private static final String CHARSET_REGEX = "[ |\t]*(charset)[ |\t]*=[ |\t]*['|\"]?([^\"^'^;^,]*)['|\"]?"; 50 | 51 | private static final Pattern CHARSET_PATTERN = Pattern.compile(CHARSET_REGEX, Pattern.CASE_INSENSITIVE); 52 | 53 | private static final String BOUNDARY_REGEX = "[ |\t]*(boundary)[ |\t]*=[ |\t]*['|\"]?([^\"^'^;^,]*)['|\"]?"; 54 | 55 | private static final Pattern BOUNDARY_PATTERN = Pattern.compile(BOUNDARY_REGEX, Pattern.CASE_INSENSITIVE); 56 | 57 | private final String contentTypeHeader; 58 | 59 | private final String contentType; 60 | 61 | private final String encoding; 62 | 63 | private final String boundary; 64 | 65 | public ContentType(String contentTypeHeader) { 66 | this.contentTypeHeader = contentTypeHeader; 67 | if (contentTypeHeader != null) { 68 | contentType = getDetailFromContentHeader(contentTypeHeader, MIME_PATTERN, "", 1); 69 | encoding = getDetailFromContentHeader(contentTypeHeader, CHARSET_PATTERN, null, 2); 70 | } else { 71 | contentType = ""; 72 | encoding = "UTF-8"; 73 | } 74 | if (MULTIPART_FORM_DATA_HEADER.equalsIgnoreCase(contentType)) { 75 | boundary = getDetailFromContentHeader(contentTypeHeader, BOUNDARY_PATTERN, null, 2); 76 | } else { 77 | boundary = null; 78 | } 79 | } 80 | 81 | private String getDetailFromContentHeader(String contentTypeHeader, Pattern pattern, String defaultValue, int group) { 82 | Matcher matcher = pattern.matcher(contentTypeHeader); 83 | return matcher.find() ? matcher.group(group) : defaultValue; 84 | } 85 | 86 | public String getContentTypeHeader() { 87 | return contentTypeHeader; 88 | } 89 | 90 | public String getContentType() { 91 | return contentType; 92 | } 93 | 94 | public String getEncoding() { 95 | return encoding == null ? ASCII_ENCODING : encoding; 96 | } 97 | 98 | public String getBoundary() { 99 | return boundary; 100 | } 101 | 102 | public boolean isMultipart() { 103 | return MULTIPART_FORM_DATA_HEADER.equalsIgnoreCase(contentType); 104 | } 105 | 106 | public ContentType tryUTF8() { 107 | if (encoding == null) { 108 | return new ContentType(this.contentTypeHeader + "; charset=UTF-8"); 109 | } 110 | return this; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /webserver/src/main/java/org/protocols/http/content/Cookie.java: -------------------------------------------------------------------------------- 1 | package org.protocols.http.content; 2 | 3 | /* 4 | * #%L 5 | * NanoHttpd-Core 6 | * %% 7 | * Copyright (C) 2012 - 2016 nanohttpd 8 | * %% 9 | * Redistribution and use in source and binary forms, with or without modification, 10 | * are permitted provided that the following conditions are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright notice, this 13 | * list of conditions and the following disclaimer. 14 | * 15 | * 2. Redistributions in binary form must reproduce the above copyright notice, 16 | * this list of conditions and the following disclaimer in the documentation 17 | * and/or other materials provided with the distribution. 18 | * 19 | * 3. Neither the name of the nanohttpd nor the names of its contributors 20 | * may be used to endorse or promote products derived from this software without 21 | * specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 27 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 30 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 32 | * OF THE POSSIBILITY OF SUCH DAMAGE. 33 | * #L% 34 | */ 35 | 36 | import java.text.SimpleDateFormat; 37 | import java.util.Calendar; 38 | import java.util.Locale; 39 | import java.util.TimeZone; 40 | 41 | /** 42 | * A simple cookie representation. This is old code and is flawed in many ways. 43 | * 44 | * @author LordFokas 45 | */ 46 | public class Cookie { 47 | 48 | public static String getHTTPTime(int days) { 49 | Calendar calendar = Calendar.getInstance(); 50 | SimpleDateFormat dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US); 51 | dateFormat.setTimeZone(TimeZone.getTimeZone("GMT")); 52 | calendar.add(Calendar.DAY_OF_MONTH, days); 53 | return dateFormat.format(calendar.getTime()); 54 | } 55 | 56 | private final String n, v, e; 57 | 58 | public Cookie(String name, String value) { 59 | this(name, value, 30); 60 | } 61 | 62 | public Cookie(String name, String value, int numDays) { 63 | this.n = name; 64 | this.v = value; 65 | this.e = getHTTPTime(numDays); 66 | } 67 | 68 | public Cookie(String name, String value, String expires) { 69 | this.n = name; 70 | this.v = value; 71 | this.e = expires; 72 | } 73 | 74 | public String getHTTPHeader() { 75 | String fmt = "%s=%s; expires=%s"; 76 | return String.format(fmt, this.n, this.v, this.e); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /webserver/src/main/java/org/protocols/http/request/Method.java: -------------------------------------------------------------------------------- 1 | package org.protocols.http.request; 2 | 3 | /* 4 | * #%L 5 | * NanoHttpd-Core 6 | * %% 7 | * Copyright (C) 2012 - 2016 nanohttpd 8 | * %% 9 | * Redistribution and use in source and binary forms, with or without modification, 10 | * are permitted provided that the following conditions are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright notice, this 13 | * list of conditions and the following disclaimer. 14 | * 15 | * 2. Redistributions in binary form must reproduce the above copyright notice, 16 | * this list of conditions and the following disclaimer in the documentation 17 | * and/or other materials provided with the distribution. 18 | * 19 | * 3. Neither the name of the nanohttpd nor the names of its contributors 20 | * may be used to endorse or promote products derived from this software without 21 | * specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 27 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 30 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 32 | * OF THE POSSIBILITY OF SUCH DAMAGE. 33 | * #L% 34 | */ 35 | 36 | /** 37 | * HTTP Request methods, with the ability to decode a String back 38 | * to its enum value. 39 | */ 40 | public enum Method { 41 | GET, 42 | PUT, 43 | POST, 44 | DELETE, 45 | HEAD, 46 | OPTIONS, 47 | TRACE, 48 | CONNECT, 49 | PATCH, 50 | PROPFIND, 51 | PROPPATCH, 52 | MKCOL, 53 | MOVE, 54 | COPY, 55 | LOCK, 56 | UNLOCK, 57 | NOTIFY, 58 | SUBSCRIBE; 59 | 60 | public static Method lookup(String method) { 61 | if (method == null) 62 | return null; 63 | 64 | try { 65 | return valueOf(method); 66 | } catch (IllegalArgumentException e) { 67 | // TODO: Log it? 68 | return null; 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /webserver/src/main/java/org/protocols/http/response/ChunkedOutputStream.java: -------------------------------------------------------------------------------- 1 | package org.protocols.http.response; 2 | 3 | /* 4 | * #%L 5 | * NanoHttpd-Core 6 | * %% 7 | * Copyright (C) 2012 - 2016 nanohttpd 8 | * %% 9 | * Redistribution and use in source and binary forms, with or without modification, 10 | * are permitted provided that the following conditions are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright notice, this 13 | * list of conditions and the following disclaimer. 14 | * 15 | * 2. Redistributions in binary form must reproduce the above copyright notice, 16 | * this list of conditions and the following disclaimer in the documentation 17 | * and/or other materials provided with the distribution. 18 | * 19 | * 3. Neither the name of the nanohttpd nor the names of its contributors 20 | * may be used to endorse or promote products derived from this software without 21 | * specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 27 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 30 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 32 | * OF THE POSSIBILITY OF SUCH DAMAGE. 33 | * #L% 34 | */ 35 | 36 | import java.io.FilterOutputStream; 37 | import java.io.IOException; 38 | import java.io.OutputStream; 39 | 40 | /** 41 | * Output stream that will automatically send every write to the wrapped 42 | * OutputStream according to chunked transfer: 43 | * http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6.1 44 | */ 45 | public class ChunkedOutputStream extends FilterOutputStream { 46 | 47 | public ChunkedOutputStream(OutputStream out) { 48 | super(out); 49 | } 50 | 51 | @Override 52 | public void write(int b) throws IOException { 53 | byte[] data = { 54 | (byte) b 55 | }; 56 | write(data, 0, 1); 57 | } 58 | 59 | @Override 60 | public void write(byte[] b) throws IOException { 61 | write(b, 0, b.length); 62 | } 63 | 64 | @Override 65 | public void write(byte[] b, int off, int len) throws IOException { 66 | if (len == 0) 67 | return; 68 | out.write(String.format("%x\r\n", len).getBytes()); 69 | out.write(b, off, len); 70 | out.write("\r\n".getBytes()); 71 | } 72 | 73 | public void finish() throws IOException { 74 | out.write("0\r\n\r\n".getBytes()); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /webserver/src/main/java/org/protocols/http/response/IStatus.java: -------------------------------------------------------------------------------- 1 | package org.protocols.http.response; 2 | 3 | /* 4 | * #%L 5 | * NanoHttpd-Core 6 | * %% 7 | * Copyright (C) 2012 - 2016 nanohttpd 8 | * %% 9 | * Redistribution and use in source and binary forms, with or without modification, 10 | * are permitted provided that the following conditions are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright notice, this 13 | * list of conditions and the following disclaimer. 14 | * 15 | * 2. Redistributions in binary form must reproduce the above copyright notice, 16 | * this list of conditions and the following disclaimer in the documentation 17 | * and/or other materials provided with the distribution. 18 | * 19 | * 3. Neither the name of the nanohttpd nor the names of its contributors 20 | * may be used to endorse or promote products derived from this software without 21 | * specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 27 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 30 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 32 | * OF THE POSSIBILITY OF SUCH DAMAGE. 33 | * #L% 34 | */ 35 | 36 | public interface IStatus { 37 | 38 | String getDescription(); 39 | 40 | int getRequestStatus(); 41 | } 42 | -------------------------------------------------------------------------------- /webserver/src/main/java/org/protocols/http/response/Status.java: -------------------------------------------------------------------------------- 1 | //package org.nanohttpd.protocols.http.response; 2 | package org.protocols.http.response; 3 | /* 4 | * #%L 5 | * NanoHttpd-Core 6 | * %% 7 | * Copyright (C) 2012 - 2016 nanohttpd 8 | * %% 9 | * Redistribution and use in source and binary forms, with or without modification, 10 | * are permitted provided that the following conditions are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright notice, this 13 | * list of conditions and the following disclaimer. 14 | * 15 | * 2. Redistributions in binary form must reproduce the above copyright notice, 16 | * this list of conditions and the following disclaimer in the documentation 17 | * and/or other materials provided with the distribution. 18 | * 19 | * 3. Neither the name of the nanohttpd nor the names of its contributors 20 | * may be used to endorse or promote products derived from this software without 21 | * specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 27 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 30 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 32 | * OF THE POSSIBILITY OF SUCH DAMAGE. 33 | * #L% 34 | */ 35 | 36 | /** 37 | * Some HTTP response status codes 38 | */ 39 | public enum Status implements IStatus { 40 | SWITCH_PROTOCOL(101, "Switching Protocols"), 41 | 42 | OK(200, "OK"), 43 | CREATED(201, "Created"), 44 | ACCEPTED(202, "Accepted"), 45 | NO_CONTENT(204, "No Content"), 46 | PARTIAL_CONTENT(206, "Partial Content"), 47 | MULTI_STATUS(207, "Multi-Status"), 48 | 49 | REDIRECT(301, "Moved Permanently"), 50 | /** 51 | * Many user agents mishandle 302 in ways that violate the RFC1945 spec 52 | * (i.e., redirect a POST to a GET). 303 and 307 were added in RFC2616 to 53 | * address this. You should prefer 303 and 307 unless the calling user agent 54 | * does not support 303 and 307 functionality 55 | */ 56 | @Deprecated 57 | FOUND(302, "Found"), 58 | REDIRECT_SEE_OTHER(303, "See Other"), 59 | NOT_MODIFIED(304, "Not Modified"), 60 | TEMPORARY_REDIRECT(307, "Temporary Redirect"), 61 | 62 | BAD_REQUEST(400, "Bad Request"), 63 | UNAUTHORIZED(401, "Unauthorized"), 64 | FORBIDDEN(403, "Forbidden"), 65 | NOT_FOUND(404, "Not Found"), 66 | METHOD_NOT_ALLOWED(405, "Method Not Allowed"), 67 | NOT_ACCEPTABLE(406, "Not Acceptable"), 68 | REQUEST_TIMEOUT(408, "Request Timeout"), 69 | CONFLICT(409, "Conflict"), 70 | GONE(410, "Gone"), 71 | LENGTH_REQUIRED(411, "Length Required"), 72 | PRECONDITION_FAILED(412, "Precondition Failed"), 73 | PAYLOAD_TOO_LARGE(413, "Payload Too Large"), 74 | UNSUPPORTED_MEDIA_TYPE(415, "Unsupported Media Type"), 75 | RANGE_NOT_SATISFIABLE(416, "Requested Range Not Satisfiable"), 76 | EXPECTATION_FAILED(417, "Expectation Failed"), 77 | TOO_MANY_REQUESTS(429, "Too Many Requests"), 78 | 79 | INTERNAL_ERROR(500, "Internal Server Error"), 80 | NOT_IMPLEMENTED(501, "Not Implemented"), 81 | SERVICE_UNAVAILABLE(503, "Service Unavailable"), 82 | UNSUPPORTED_HTTP_VERSION(505, "HTTP Version Not Supported"); 83 | 84 | private final int requestStatus; 85 | 86 | private final String description; 87 | 88 | Status(int requestStatus, String description) { 89 | this.requestStatus = requestStatus; 90 | this.description = description; 91 | } 92 | 93 | public static Status lookup(int requestStatus) { 94 | for (Status status : Status.values()) { 95 | if (status.getRequestStatus() == requestStatus) { 96 | return status; 97 | } 98 | } 99 | return null; 100 | } 101 | 102 | @Override 103 | public String getDescription() { 104 | return "" + this.requestStatus + " " + this.description; 105 | } 106 | 107 | @Override 108 | public int getRequestStatus() { 109 | return this.requestStatus; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /webserver/src/main/java/org/protocols/http/sockets/DefaultServerSocketFactory.java: -------------------------------------------------------------------------------- 1 | package org.protocols.http.sockets; 2 | 3 | /* 4 | * #%L 5 | * NanoHttpd-Core 6 | * %% 7 | * Copyright (C) 2012 - 2016 nanohttpd 8 | * %% 9 | * Redistribution and use in source and binary forms, with or without modification, 10 | * are permitted provided that the following conditions are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright notice, this 13 | * list of conditions and the following disclaimer. 14 | * 15 | * 2. Redistributions in binary form must reproduce the above copyright notice, 16 | * this list of conditions and the following disclaimer in the documentation 17 | * and/or other materials provided with the distribution. 18 | * 19 | * 3. Neither the name of the nanohttpd nor the names of its contributors 20 | * may be used to endorse or promote products derived from this software without 21 | * specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 27 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 30 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 32 | * OF THE POSSIBILITY OF SUCH DAMAGE. 33 | * #L% 34 | */ 35 | 36 | import java.io.IOException; 37 | import java.net.ServerSocket; 38 | 39 | import org.util.IFactoryThrowing; 40 | 41 | /** 42 | * Creates a normal ServerSocket for TCP connections 43 | */ 44 | public class DefaultServerSocketFactory implements IFactoryThrowing { 45 | 46 | @Override 47 | public ServerSocket create() throws IOException { 48 | return new ServerSocket(); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /webserver/src/main/java/org/protocols/http/sockets/SecureServerSocketFactory.java: -------------------------------------------------------------------------------- 1 | package org.protocols.http.sockets; 2 | 3 | /* 4 | * #%L 5 | * NanoHttpd-Core 6 | * %% 7 | * Copyright (C) 2012 - 2016 nanohttpd 8 | * %% 9 | * Redistribution and use in source and binary forms, with or without modification, 10 | * are permitted provided that the following conditions are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright notice, this 13 | * list of conditions and the following disclaimer. 14 | * 15 | * 2. Redistributions in binary form must reproduce the above copyright notice, 16 | * this list of conditions and the following disclaimer in the documentation 17 | * and/or other materials provided with the distribution. 18 | * 19 | * 3. Neither the name of the nanohttpd nor the names of its contributors 20 | * may be used to endorse or promote products derived from this software without 21 | * specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 27 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 30 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 32 | * OF THE POSSIBILITY OF SUCH DAMAGE. 33 | * #L% 34 | */ 35 | 36 | import java.io.IOException; 37 | import java.net.ServerSocket; 38 | 39 | import javax.net.ssl.SSLServerSocket; 40 | import javax.net.ssl.SSLServerSocketFactory; 41 | 42 | import org.util.IFactoryThrowing; 43 | 44 | /** 45 | * Creates a new SSLServerSocket 46 | */ 47 | public class SecureServerSocketFactory implements IFactoryThrowing { 48 | 49 | private SSLServerSocketFactory sslServerSocketFactory; 50 | 51 | private String[] sslProtocols; 52 | 53 | public SecureServerSocketFactory(SSLServerSocketFactory sslServerSocketFactory, String[] sslProtocols) { 54 | this.sslServerSocketFactory = sslServerSocketFactory; 55 | this.sslProtocols = sslProtocols; 56 | } 57 | 58 | @Override 59 | public ServerSocket create() throws IOException { 60 | SSLServerSocket ss = null; 61 | ss = (SSLServerSocket) this.sslServerSocketFactory.createServerSocket(); 62 | if (this.sslProtocols != null) { 63 | ss.setEnabledProtocols(this.sslProtocols); 64 | } else { 65 | ss.setEnabledProtocols(ss.getSupportedProtocols()); 66 | } 67 | ss.setUseClientMode(false); 68 | ss.setWantClientAuth(false); 69 | ss.setNeedClientAuth(false); 70 | return ss; 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /webserver/src/main/java/org/protocols/http/tempfiles/DefaultTempFile.java: -------------------------------------------------------------------------------- 1 | package org.protocols.http.tempfiles; 2 | 3 | /* 4 | * #%L 5 | * NanoHttpd-Core 6 | * %% 7 | * Copyright (C) 2012 - 2016 nanohttpd 8 | * %% 9 | * Redistribution and use in source and binary forms, with or without modification, 10 | * are permitted provided that the following conditions are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright notice, this 13 | * list of conditions and the following disclaimer. 14 | * 15 | * 2. Redistributions in binary form must reproduce the above copyright notice, 16 | * this list of conditions and the following disclaimer in the documentation 17 | * and/or other materials provided with the distribution. 18 | * 19 | * 3. Neither the name of the nanohttpd nor the names of its contributors 20 | * may be used to endorse or promote products derived from this software without 21 | * specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 27 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 30 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 32 | * OF THE POSSIBILITY OF SUCH DAMAGE. 33 | * #L% 34 | */ 35 | 36 | import java.io.File; 37 | import java.io.FileOutputStream; 38 | import java.io.IOException; 39 | import java.io.OutputStream; 40 | 41 | import org.protocols.http.NanoHTTPD; 42 | 43 | /** 44 | * Default strategy for creating and cleaning up temporary files. 45 | *

46 | *

47 | * By default, files are created by File.createTempFile() in the 48 | * directory specified. 49 | *

50 | */ 51 | public class DefaultTempFile implements ITempFile { 52 | 53 | private final File file; 54 | 55 | private final OutputStream fstream; 56 | 57 | public DefaultTempFile(File tempdir) throws IOException { 58 | this.file = File.createTempFile("NanoHTTPD-", "", tempdir); 59 | this.fstream = new FileOutputStream(this.file); 60 | } 61 | 62 | @Override 63 | public void delete() throws Exception { 64 | NanoHTTPD.safeClose(this.fstream); 65 | if (!this.file.delete()) { 66 | throw new Exception("could not delete temporary file: " + this.file.getAbsolutePath()); 67 | } 68 | } 69 | 70 | @Override 71 | public String getName() { 72 | return this.file.getAbsolutePath(); 73 | } 74 | 75 | @Override 76 | public OutputStream open() throws Exception { 77 | return this.fstream; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /webserver/src/main/java/org/protocols/http/tempfiles/DefaultTempFileManager.java: -------------------------------------------------------------------------------- 1 | package org.protocols.http.tempfiles; 2 | 3 | /* 4 | * #%L 5 | * NanoHttpd-Core 6 | * %% 7 | * Copyright (C) 2012 - 2016 nanohttpd 8 | * %% 9 | * Redistribution and use in source and binary forms, with or without modification, 10 | * are permitted provided that the following conditions are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright notice, this 13 | * list of conditions and the following disclaimer. 14 | * 15 | * 2. Redistributions in binary form must reproduce the above copyright notice, 16 | * this list of conditions and the following disclaimer in the documentation 17 | * and/or other materials provided with the distribution. 18 | * 19 | * 3. Neither the name of the nanohttpd nor the names of its contributors 20 | * may be used to endorse or promote products derived from this software without 21 | * specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 27 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 30 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 32 | * OF THE POSSIBILITY OF SUCH DAMAGE. 33 | * #L% 34 | */ 35 | 36 | import java.io.File; 37 | import java.util.ArrayList; 38 | import java.util.List; 39 | import java.util.logging.Level; 40 | 41 | import org.protocols.http.NanoHTTPD; 42 | 43 | /** 44 | * Default strategy for creating and cleaning up temporary files. 45 | *

46 | *

47 | * This class stores its files in the standard location (that is, wherever 48 | * java.io.tmpdir points to). Files are added to an internal list, 49 | * and deleted when no longer needed (that is, when clear() is 50 | * invoked at the end of processing a request). 51 | *

52 | */ 53 | public class DefaultTempFileManager implements ITempFileManager { 54 | 55 | private final File tmpdir; 56 | 57 | private final List tempFiles; 58 | 59 | public DefaultTempFileManager() { 60 | this.tmpdir = new File(System.getProperty("java.io.tmpdir")); 61 | if (!tmpdir.exists()) { 62 | tmpdir.mkdirs(); 63 | } 64 | this.tempFiles = new ArrayList(); 65 | } 66 | 67 | @Override 68 | public void clear() { 69 | for (ITempFile file : this.tempFiles) { 70 | try { 71 | file.delete(); 72 | } catch (Exception ignored) { 73 | NanoHTTPD.LOG.log(Level.WARNING, "could not delete file ", ignored); 74 | } 75 | } 76 | this.tempFiles.clear(); 77 | } 78 | 79 | @Override 80 | public ITempFile createTempFile(String filename_hint) throws Exception { 81 | DefaultTempFile tempFile = new DefaultTempFile(this.tmpdir); 82 | this.tempFiles.add(tempFile); 83 | return tempFile; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /webserver/src/main/java/org/protocols/http/tempfiles/DefaultTempFileManagerFactory.java: -------------------------------------------------------------------------------- 1 | package org.protocols.http.tempfiles; 2 | 3 | /* 4 | * #%L 5 | * NanoHttpd-Core 6 | * %% 7 | * Copyright (C) 2012 - 2016 nanohttpd 8 | * %% 9 | * Redistribution and use in source and binary forms, with or without modification, 10 | * are permitted provided that the following conditions are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright notice, this 13 | * list of conditions and the following disclaimer. 14 | * 15 | * 2. Redistributions in binary form must reproduce the above copyright notice, 16 | * this list of conditions and the following disclaimer in the documentation 17 | * and/or other materials provided with the distribution. 18 | * 19 | * 3. Neither the name of the nanohttpd nor the names of its contributors 20 | * may be used to endorse or promote products derived from this software without 21 | * specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 27 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 30 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 32 | * OF THE POSSIBILITY OF SUCH DAMAGE. 33 | * #L% 34 | */ 35 | 36 | import org.util.IFactory; 37 | 38 | /** 39 | * Default strategy for creating and cleaning up temporary files. 40 | */ 41 | public class DefaultTempFileManagerFactory implements IFactory { 42 | 43 | @Override 44 | public ITempFileManager create() { 45 | return new DefaultTempFileManager(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /webserver/src/main/java/org/protocols/http/tempfiles/ITempFile.java: -------------------------------------------------------------------------------- 1 | package org.protocols.http.tempfiles; 2 | 3 | /* 4 | * #%L 5 | * NanoHttpd-Core 6 | * %% 7 | * Copyright (C) 2012 - 2016 nanohttpd 8 | * %% 9 | * Redistribution and use in source and binary forms, with or without modification, 10 | * are permitted provided that the following conditions are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright notice, this 13 | * list of conditions and the following disclaimer. 14 | * 15 | * 2. Redistributions in binary form must reproduce the above copyright notice, 16 | * this list of conditions and the following disclaimer in the documentation 17 | * and/or other materials provided with the distribution. 18 | * 19 | * 3. Neither the name of the nanohttpd nor the names of its contributors 20 | * may be used to endorse or promote products derived from this software without 21 | * specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 27 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 30 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 32 | * OF THE POSSIBILITY OF SUCH DAMAGE. 33 | * #L% 34 | */ 35 | 36 | import java.io.OutputStream; 37 | 38 | /** 39 | * A temp file. 40 | *

41 | *

42 | * Temp files are responsible for managing the actual temporary storage and 43 | * cleaning themselves up when no longer needed. 44 | *

45 | */ 46 | public interface ITempFile { 47 | 48 | public void delete() throws Exception; 49 | 50 | public String getName(); 51 | 52 | public OutputStream open() throws Exception; 53 | } 54 | -------------------------------------------------------------------------------- /webserver/src/main/java/org/protocols/http/tempfiles/ITempFileManager.java: -------------------------------------------------------------------------------- 1 | package org.protocols.http.tempfiles; 2 | 3 | /* 4 | * #%L 5 | * NanoHttpd-Core 6 | * %% 7 | * Copyright (C) 2012 - 2016 nanohttpd 8 | * %% 9 | * Redistribution and use in source and binary forms, with or without modification, 10 | * are permitted provided that the following conditions are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright notice, this 13 | * list of conditions and the following disclaimer. 14 | * 15 | * 2. Redistributions in binary form must reproduce the above copyright notice, 16 | * this list of conditions and the following disclaimer in the documentation 17 | * and/or other materials provided with the distribution. 18 | * 19 | * 3. Neither the name of the nanohttpd nor the names of its contributors 20 | * may be used to endorse or promote products derived from this software without 21 | * specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 27 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 30 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 32 | * OF THE POSSIBILITY OF SUCH DAMAGE. 33 | * #L% 34 | */ 35 | 36 | /** 37 | * Temp file manager. 38 | *

39 | *

40 | * Temp file managers are created 1-to-1 with incoming requests, to create and 41 | * cleanup temporary files created as a result of handling the request. 42 | *

43 | */ 44 | public interface ITempFileManager { 45 | 46 | void clear(); 47 | 48 | public ITempFile createTempFile(String filename_hint) throws Exception; 49 | } 50 | -------------------------------------------------------------------------------- /webserver/src/main/java/org/protocols/http/threading/DefaultAsyncRunner.java: -------------------------------------------------------------------------------- 1 | package org.protocols.http.threading; 2 | 3 | /* 4 | * #%L 5 | * NanoHttpd-Core 6 | * %% 7 | * Copyright (C) 2012 - 2016 nanohttpd 8 | * %% 9 | * Redistribution and use in source and binary forms, with or without modification, 10 | * are permitted provided that the following conditions are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright notice, this 13 | * list of conditions and the following disclaimer. 14 | * 15 | * 2. Redistributions in binary form must reproduce the above copyright notice, 16 | * this list of conditions and the following disclaimer in the documentation 17 | * and/or other materials provided with the distribution. 18 | * 19 | * 3. Neither the name of the nanohttpd nor the names of its contributors 20 | * may be used to endorse or promote products derived from this software without 21 | * specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 27 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 30 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 32 | * OF THE POSSIBILITY OF SUCH DAMAGE. 33 | * #L% 34 | */ 35 | 36 | import java.util.ArrayList; 37 | import java.util.Collections; 38 | import java.util.List; 39 | 40 | import org.protocols.http.ClientHandler; 41 | 42 | /** 43 | * Default threading strategy for NanoHTTPD. 44 | *

45 | *

46 | * By default, the server spawns a new Thread for every incoming request. These 47 | * are set to daemon status, and named according to the request number. 48 | * The name is useful when profiling the application. 49 | *

50 | */ 51 | public class DefaultAsyncRunner implements IAsyncRunner { 52 | 53 | protected long requestCount; 54 | 55 | private final List running = Collections.synchronizedList(new ArrayList()); 56 | 57 | /** 58 | * @return a list with currently running clients. 59 | */ 60 | public List getRunning() { 61 | return running; 62 | } 63 | 64 | @Override 65 | public void closeAll() { 66 | // copy of the list for concurrency 67 | for (ClientHandler clientHandler : new ArrayList(this.running)) { 68 | clientHandler.close(); 69 | } 70 | } 71 | 72 | @Override 73 | public void closed(ClientHandler clientHandler) { 74 | this.running.remove(clientHandler); 75 | } 76 | 77 | @Override 78 | public void exec(ClientHandler clientHandler) { 79 | ++this.requestCount; 80 | this.running.add(clientHandler); 81 | createThread(clientHandler).start(); 82 | } 83 | 84 | protected Thread createThread(ClientHandler clientHandler) { 85 | Thread t = new Thread(clientHandler); 86 | t.setDaemon(true); 87 | t.setName("NanoHttpd Request Processor (#" + this.requestCount + ")"); 88 | return t; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /webserver/src/main/java/org/protocols/http/threading/IAsyncRunner.java: -------------------------------------------------------------------------------- 1 | package org.protocols.http.threading; 2 | 3 | /* 4 | * #%L 5 | * NanoHttpd-Core 6 | * %% 7 | * Copyright (C) 2012 - 2016 nanohttpd 8 | * %% 9 | * Redistribution and use in source and binary forms, with or without modification, 10 | * are permitted provided that the following conditions are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright notice, this 13 | * list of conditions and the following disclaimer. 14 | * 15 | * 2. Redistributions in binary form must reproduce the above copyright notice, 16 | * this list of conditions and the following disclaimer in the documentation 17 | * and/or other materials provided with the distribution. 18 | * 19 | * 3. Neither the name of the nanohttpd nor the names of its contributors 20 | * may be used to endorse or promote products derived from this software without 21 | * specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 27 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 30 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 32 | * OF THE POSSIBILITY OF SUCH DAMAGE. 33 | * #L% 34 | */ 35 | 36 | import org.protocols.http.ClientHandler; 37 | 38 | /** 39 | * Pluggable strategy for asynchronously executing requests. 40 | */ 41 | public interface IAsyncRunner { 42 | 43 | void closeAll(); 44 | 45 | void closed(ClientHandler clientHandler); 46 | 47 | void exec(ClientHandler code); 48 | } 49 | -------------------------------------------------------------------------------- /webserver/src/main/java/org/util/IFactory.java: -------------------------------------------------------------------------------- 1 | package org.util; 2 | 3 | /* 4 | * #%L 5 | * NanoHttpd-Core 6 | * %% 7 | * Copyright (C) 2012 - 2016 nanohttpd 8 | * %% 9 | * Redistribution and use in source and binary forms, with or without modification, 10 | * are permitted provided that the following conditions are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright notice, this 13 | * list of conditions and the following disclaimer. 14 | * 15 | * 2. Redistributions in binary form must reproduce the above copyright notice, 16 | * this list of conditions and the following disclaimer in the documentation 17 | * and/or other materials provided with the distribution. 18 | * 19 | * 3. Neither the name of the nanohttpd nor the names of its contributors 20 | * may be used to endorse or promote products derived from this software without 21 | * specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 27 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 30 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 32 | * OF THE POSSIBILITY OF SUCH DAMAGE. 33 | * #L% 34 | */ 35 | 36 | /** 37 | * Represents a simple factory 38 | * 39 | * @author LordFokas 40 | * @param 41 | * The Type of object to create 42 | */ 43 | public interface IFactory { 44 | 45 | T create(); 46 | } 47 | -------------------------------------------------------------------------------- /webserver/src/main/java/org/util/IFactoryThrowing.java: -------------------------------------------------------------------------------- 1 | package org.util; 2 | 3 | /* 4 | * #%L 5 | * NanoHttpd-Core 6 | * %% 7 | * Copyright (C) 2012 - 2016 nanohttpd 8 | * %% 9 | * Redistribution and use in source and binary forms, with or without modification, 10 | * are permitted provided that the following conditions are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright notice, this 13 | * list of conditions and the following disclaimer. 14 | * 15 | * 2. Redistributions in binary form must reproduce the above copyright notice, 16 | * this list of conditions and the following disclaimer in the documentation 17 | * and/or other materials provided with the distribution. 18 | * 19 | * 3. Neither the name of the nanohttpd nor the names of its contributors 20 | * may be used to endorse or promote products derived from this software without 21 | * specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 27 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 30 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 32 | * OF THE POSSIBILITY OF SUCH DAMAGE. 33 | * #L% 34 | */ 35 | 36 | /** 37 | * Represents a factory that can throw an exception instead of actually creating 38 | * an object 39 | * 40 | * @author LordFokas 41 | * @param 42 | * The Type of object to create 43 | * @param 44 | * The base Type of exceptions that can be thrown 45 | */ 46 | public interface IFactoryThrowing { 47 | 48 | T create() throws E; 49 | } 50 | -------------------------------------------------------------------------------- /webserver/src/main/java/org/util/IHandler.java: -------------------------------------------------------------------------------- 1 | package org.util; 2 | 3 | /* 4 | * #%L 5 | * NanoHttpd-Core 6 | * %% 7 | * Copyright (C) 2012 - 2016 nanohttpd 8 | * %% 9 | * Redistribution and use in source and binary forms, with or without modification, 10 | * are permitted provided that the following conditions are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright notice, this 13 | * list of conditions and the following disclaimer. 14 | * 15 | * 2. Redistributions in binary form must reproduce the above copyright notice, 16 | * this list of conditions and the following disclaimer in the documentation 17 | * and/or other materials provided with the distribution. 18 | * 19 | * 3. Neither the name of the nanohttpd nor the names of its contributors 20 | * may be used to endorse or promote products derived from this software without 21 | * specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 27 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 30 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 32 | * OF THE POSSIBILITY OF SUCH DAMAGE. 33 | * #L% 34 | */ 35 | 36 | /** 37 | * Defines a generic handler that returns an object of type O when given an 38 | * object of type I. 39 | * 40 | * @author LordFokas 41 | * @param 42 | * The input type. 43 | * @param 44 | * The output type. 45 | */ 46 | public interface IHandler { 47 | 48 | public O handle(I input); 49 | } 50 | -------------------------------------------------------------------------------- /webserver/src/main/java/org/util/ServerRunner.java: -------------------------------------------------------------------------------- 1 | package org.util; 2 | 3 | /* 4 | * #%L 5 | * NanoHttpd-Webserver 6 | * %% 7 | * Copyright (C) 2012 - 2015 nanohttpd 8 | * %% 9 | * Redistribution and use in source and binary forms, with or without modification, 10 | * are permitted provided that the following conditions are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright notice, this 13 | * list of conditions and the following disclaimer. 14 | * 15 | * 2. Redistributions in binary form must reproduce the above copyright notice, 16 | * this list of conditions and the following disclaimer in the documentation 17 | * and/or other materials provided with the distribution. 18 | * 19 | * 3. Neither the name of the nanohttpd nor the names of its contributors 20 | * may be used to endorse or promote products derived from this software without 21 | * specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 27 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 30 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 32 | * OF THE POSSIBILITY OF SUCH DAMAGE. 33 | * #L% 34 | */ 35 | 36 | import java.io.IOException; 37 | import java.util.logging.Level; 38 | import java.util.logging.Logger; 39 | 40 | import org.protocols.http.NanoHTTPD; 41 | 42 | public class ServerRunner { 43 | 44 | /** 45 | * logger to log to. 46 | */ 47 | private static final Logger LOG = Logger.getLogger(ServerRunner.class.getName()); 48 | 49 | public static void executeInstance(NanoHTTPD server) { 50 | try { 51 | server.start(NanoHTTPD.SOCKET_READ_TIMEOUT, false); 52 | } catch (IOException ioe) { 53 | System.err.println("Couldn't start server:\n" + ioe); 54 | System.exit(-1); 55 | } 56 | 57 | System.out.println("Server started, Hit Enter to stop.\n"); 58 | 59 | try { 60 | System.in.read(); 61 | } catch (Throwable ignored) { 62 | } 63 | 64 | server.stop(); 65 | System.out.println("Server stopped.\n"); 66 | } 67 | 68 | public static void run(Class serverClass) { 69 | try { 70 | executeInstance(serverClass.newInstance()); 71 | } catch (Exception e) { 72 | ServerRunner.LOG.log(Level.SEVERE, "Could not create server", e); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /webserver/src/main/resources/META-INF/nanohttpd/default-mimetypes.properties: -------------------------------------------------------------------------------- 1 | #default mime types for nanohttpd, use META-INF/mimetypes.properties for user defined mimetypes 2 | css=text/css 3 | htm=text/html 4 | html=text/html 5 | xml=text/xml 6 | java=text/x-java-source, text/java 7 | md=text/plain 8 | txt=text/plain 9 | asc=text/plain 10 | gif=image/gif 11 | jpg=image/jpeg 12 | jpeg=image/jpeg 13 | png=image/png 14 | svg=image/svg+xml 15 | mp3=audio/mpeg 16 | m3u=audio/mpeg-url 17 | mp4=video/mp4 18 | ogv=video/ogg 19 | flv=video/x-flv 20 | mov=video/quicktime 21 | swf=application/x-shockwave-flash 22 | js=application/javascript 23 | pdf=application/pdf 24 | doc=application/msword 25 | ogg=application/x-ogg 26 | zip=application/octet-stream 27 | exe=application/octet-stream 28 | class=application/octet-stream 29 | m3u8=application/vnd.apple.mpegurl 30 | ts=video/mp2t -------------------------------------------------------------------------------- /webserver/src/main/resources/META-INF/nanohttpd/mimetypes.properties: -------------------------------------------------------------------------------- 1 | #mime types for nanohttpd, use a file like this for user defined mimetypes --------------------------------------------------------------------------------