├── .DS_Store ├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── libraries │ └── libp2p_1_3_3.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml ├── vcs.xml └── workspace.xml ├── LICENSE ├── README.md ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── libp2pimpl-android-github.iml ├── libp2pimpl ├── build.gradle ├── libp2pimpl.iml ├── lint.xml └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ ├── cn │ │ └── vbyte │ │ │ └── p2p │ │ │ ├── BaseController.java │ │ │ ├── LiveController.java │ │ │ ├── LoggerCallback.java │ │ │ ├── VbyteHandler.java │ │ │ ├── VbyteP2PModule.java │ │ │ ├── VodController.java │ │ │ └── v2 │ │ │ └── P2PModuleImpl.java │ └── com │ │ └── vbyte │ │ ├── p2p │ │ ├── IController.java │ │ ├── OnLoadedListener.java │ │ ├── P2PHandler.java │ │ ├── P2PModule.java │ │ ├── SecurityUrl.java │ │ └── UrlGenerator.java │ │ └── update │ │ ├── DynamicLibManager.java │ │ └── MD5Util.java │ └── jniLibs │ ├── arm64-v8a │ ├── libevent.so │ ├── libp2pmodule.so │ └── libstun.so │ ├── armeabi-v7a │ ├── libevent.so │ ├── libp2pmodule.so │ └── libstun.so │ ├── armeabi │ ├── libevent.so │ ├── libp2pmodule.so │ └── libstun.so │ ├── x86 │ ├── libevent.so │ ├── libp2pmodule.so │ └── libstun.so │ └── x86_64 │ ├── libevent.so │ ├── libp2pmodule.so │ └── libstun.so └── settings.gradle /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vbytes/libp2pimpl-android/9ee431402abdb51448a55fcda17c5e294a1fc869/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | */.DS_Store 6 | .ieda/ 7 | # Files for the ART/Dalvik VM 8 | *.dex 9 | 10 | # Java class files 11 | *.class 12 | 13 | # Generated files 14 | bin/ 15 | gen/ 16 | out/ 17 | 18 | # Gradle files 19 | .gradle/ 20 | build/ 21 | 22 | # Local configuration file (sdk path, etc) 23 | local.properties 24 | gradle.properties 25 | 26 | 27 | # Proguard folder generated by Eclipse 28 | proguard/ 29 | 30 | # Log Files 31 | *.log 32 | 33 | # Android Studio Navigation editor temp files 34 | .navigation/ 35 | 36 | # Android Studio captures folder 37 | captures/ 38 | projectFilesBackup/ 39 | 40 | # Intellij 41 | *.iml 42 | .idea/workspace.xml 43 | 44 | # Keystore files 45 | *.jks 46 | .idea/ 47 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /.idea/libraries/libp2p_1_3_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | 47 | 48 | 49 | 50 | 1.8 51 | 52 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Vbyte P2P Android SDK 2 | === 3 | 4 | vbyte云视频解决方案,可帮助用户直接使用经过大规模验证的直播流媒体分发服务,通过vbyte成熟的P2P技术大幅节省带宽,提供更优质的用户体验。开发者可通过SDK中简洁的接口快速同自有应用集成,实现Android设备上的视频P2P加速功能。 5 | 6 | ## 功能 7 | 8 | - 直播、点播基本功能+P2P 9 | - 直播时移支持 10 | - HLS P2P原生支持 11 | - 防盗播支持 12 | 13 | ## 依赖安装 14 | 15 | #### gradle编译(推荐) 16 | 17 | Android SDK托管于第三方android lib平台[jcenter][9]上,依赖部署是非常简单的。凭借这设计良好的接口,在使用上也非常方便。如果您的项目是一个使用gradle编译的AndroidStudio项目,那么集成是非常简单的。 18 | 19 | 添加如下依赖,随后等gradle同步之后,即可使用该SDK的各种接口: 20 | 21 | ``` 22 | android.defaultConfig.ndk { 23 | // 如果需要设置想用的abi,设置以下编译选项 24 | abiFilters 'armeabi-v7a' //,'x86','armeabi','x86_64','arm64-v8a' 25 | } 26 | 27 | dependencies { 28 | // 加入下面依赖 29 | compile 'cn.vbyte.p2p:libp2pimpl:1.3.21' 30 | } 31 | ``` 32 | 33 | #### 传统的Eclipse编译 34 | 35 | 如果您的项目是一个传统的Eclipse项目,首先建议您转换到Android Studio上面去,否则可能要麻烦一点: 36 | 37 | - 首先,下载[archive][7],将libs下的内容放在项目根目录的libs/下面 38 | - 添加到编译依赖libp2p.jar、libp2pimpl.jar 39 | - 以上完成后,即可使用该SDK里面的API 40 | 41 | ## 开始使用 42 | 43 | - 首先参考[资源管理][8]在[开发者中心][1]上注册帐号,创建应用,创建应用时要写对包名,并创建频道。然后得到app id,app key与app secret key 44 | - 在应用启动之初,启动VbyteP2PModule 45 | ```java 46 | // 初始化VbyteP2PModule的相关变量,这是Android sample的样例 47 | final String APP_ID = "577cdcabe0edd1325444c91f"; 48 | final String APP_KEY = "G9vjcbxMYZ5ybgxy"; 49 | final String APP_SECRET = "xdAEKlyF9XIjDnd9IwMw2b45b4Fq9Nq9"; 50 | 51 | protected void onCreate(Bundle savedInstanceState) { 52 | super.onCreate(savedInstanceState); 53 | 54 | // 初始化P2P模块 55 | try { 56 | VbyteP2PModule.create(this.getBaseContext(), APP_ID, APP_KEY, APP_SECRET); 57 | } catch (Exception e) { 58 | e.printStackTrace(); 59 | } 60 | 61 | // ... 62 | 63 | } 64 | ``` 65 | 66 | #### 使用直播 67 | 68 | 直播大家都很熟悉,观众一进来都是直接看到最新的直播内容,本是没有暂停、随机播放(回看)功能。但是应时移回看需求的增长,我们的SDK也提供了时移回看的方式,详细见[API文档][2]。 69 | 70 | - 启动一个直播频道的过程如下,其中第2个参数是写死的,必须为UHD;未来多码率支持可能会有HD等更多参数选择: 71 | ```java 72 | try { 73 | LiveController.getInstance().load("your channel id", "UHD", new OnLoadedListener() { 74 | @Override 75 | public void onLoaded(Uri uri) { 76 | mVideoPath = uri.toString(); 77 | mVideoView.setVideoURI(uri); 78 | mVideoView.start(); 79 | } 80 | }); 81 | } catch (Exception e) { 82 | // 如果打印了此exception,说明load/unload没有成对出现 83 | e.printStackTrace(); 84 | } 85 | ``` 86 | - 退出当前直播播放频道,只需要调用unload即可 87 | ```java 88 | LiveController.getInstance().unload(); 89 | ``` 90 | 91 | #### 使用点播 92 | 93 | 点播与直播最大的不同是点播视频是固定的,包括文件大小固定、视频时长固定,有暂停、恢复、随机播放等操作。 94 | 95 | - 启动一个点播频道的过程如下: 96 | ```java 97 | try { 98 | /** 99 | * 考虑到vod的资源大部分都是防盗链,这个函数设置防盗链的url生成规则, 100 | * 开发者需要根据自己的加密规则自行实现 101 | * SecurityUrl可以设置url、method,并能传入防盗链需要的http头信息 102 | * 103 | * 提示: 设置UrlGenerator应用生命周期内设置一次即可 104 | */ 105 | Vodcontroller.getInstance().setUrlGenerator(new UrlGenerator() { 106 | 107 | @Override 108 | public SecurityUrl createSecurityUrl(String sourceId) { 109 | // TODO: 实现sourceId对应防盗链url的生成规则 110 | String url = getSecurityUrlById(sourceId); 111 | 112 | SecurityUrl securityUrl = new SecurityUrl(url); 113 | securityUrl.setMethod("GET") // 默认就是GET 114 | .addHeader("User-Agent", "xxx_player1.1") // 有需要根据请求头设置防盗链的可在此设置 115 | .addHeader("Authorization", "Basic a2jeh="); 116 | return securityUrl; 117 | } 118 | 119 | }); 120 | VodController.getInstance().load("your vod channel id", "UHD", 0, new OnLoadedListener() { 121 | 122 | @Override 123 | public void onLoaded(Uri uri) { 124 | mVideoPath = uri.toString(); 125 | mVideoView.setVideoURI(uri); 126 | mVideoView.start(); 127 | } 128 | 129 | }); 130 | } catch (Exception e) { 131 | // 如果打印了此exception,说明load/unload没有成对出现 132 | e.printStackTrace(); 133 | } 134 | ``` 135 | - 暂停和恢复当前点播节目: 136 | ```java 137 | // 暂停当前节目 138 | VodController.getInstance().pause(); 139 | // 恢复播放当前节目 140 | VodController.getInstance().resume(); 141 | ``` 142 | - 点播视频支持在不重启播放器的情况下随机位置播放,这在观众滑动进度条时发生,此时播放器会从进度条位置重新加载,而P2P模块能自动感知这样的seek行为,您不用为此做什么。 143 | - 退出当前点播播放频道,只需要调用unload即可 144 | ```java 145 | VodController.getInstance().unload(); 146 | ``` 147 | 148 | #### 高级功能 149 | 150 | 更多高级功能诸如开启debug开关、事件监听、直播时移等请参见[Android版API][2]文档,然后就可以尽情地使用P2P SDK带来的便利功能吧! 151 | 152 | ## 扩展链接 153 | 154 | * **[Github][3]**: SDK的开源代码仓库 155 | * **[AndroidSample][4]**: 一个使用ijkplayer的简单样例 156 | * **[API Doc][2]**: 更加详细的API文档,其中包含如直播时移的高级功能 157 | * **[jcenter][5]**: Android SDK在jcenter上的位置 158 | * **[demo下载][6]**: 此即为AndroidSample已编译完成的版本,里面的内容属于[开发者中心][1]测试帐号的,欢迎试用 159 | 160 | ## 技术支持 161 | 162 | 感谢阅读本篇文档,希望能帮您尽快上手Android SDK的用法,再次欢迎您使用月光石P2P加速SDK! 163 | 164 | *温馨提示*:如果你需要任何帮助,或有任何疑问,请[联系我们](mailto:contact@exatech.cn)。 165 | 166 | [1]: http://devcenter.vbyte.cn 167 | [2]: http://docs.vbyte.cn/api/android/ 168 | [3]: https://github.com/Vbytes/libp2pimpl-android 169 | [4]: https://github.com/Vbytes/android-sample 170 | [5]: https://bintray.com/vbyte/maven/libp2pimpl 171 | [6]: http://data1.vbyte.cn/apk/vbyte-demo.20160921.apk 172 | [7]: http://data1.vbyte.cn/pkg/20160921.tar.gz 173 | [8]: http://docs.vbyte.cn/manage/base/ 174 | [9]: https://bintray.com/ 175 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:1.0.0' 10 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.0' 11 | classpath 'com.github.dcendents:android-maven-plugin:1.2' 12 | 13 | // NOTE: Do not place your application dependencies here; they belong 14 | // in the individual module build.gradle files 15 | } 16 | } 17 | 18 | allprojects { 19 | repositories { 20 | jcenter() 21 | } 22 | } 23 | 24 | task clean(type: Delete) { 25 | delete rootProject.buildDir 26 | } 27 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | ## Project-wide Gradle settings. 2 | # 3 | # For more details on how to configure your build environment visit 4 | # http://www.gradle.org/docs/current/userguide/build_environment.html 5 | # 6 | # Specifies the JVM arguments used for the daemon process. 7 | # The setting is particularly useful for tweaking memory settings. 8 | # Default value: -Xmx1024m -XX:MaxPermSize=256m 9 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 10 | # 11 | # When configured, Gradle will run in incubating parallel mode. 12 | # This option should only be used with decoupled projects. More details, visit 13 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 14 | # org.gradle.parallel=true 15 | #Thu Sep 14 18:09:16 CST 2017 16 | systemProp.http.proxyHost=dev-proxy.oa.com 17 | systemProp.http.proxyPort=8080 18 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vbytes/libp2pimpl-android/9ee431402abdb51448a55fcda17c5e294a1fc869/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Dec 21 19:25:57 CST 2016 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.2-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /libp2pimpl-android-github.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /libp2pimpl/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'com.github.dcendents.android-maven' 3 | apply plugin: 'com.jfrog.bintray' 4 | 5 | group = 'cn.vbyte.p2p' 6 | version = '1.3.21' 7 | 8 | android { 9 | compileSdkVersion 23 10 | buildToolsVersion "23.0.3" 11 | 12 | defaultConfig { 13 | minSdkVersion 8 14 | targetSdkVersion 8 15 | } 16 | 17 | buildTypes { 18 | release { 19 | minifyEnabled false 20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' 21 | } 22 | } 23 | } 24 | 25 | dependencies { 26 | // compile 'com.android.support:support-v4:21.0.3' 27 | compile fileTree(dir: 'libs', include: ['*.jar']) 28 | } 29 | 30 | Properties properties = new Properties() 31 | properties.load(project.rootProject.file('local.properties').newDataInputStream()) 32 | bintray { 33 | user = properties.getProperty("bintray.user") 34 | key = properties.getProperty("bintray.apikey") 35 | 36 | configurations = ['archives'] 37 | pkg { 38 | repo = 'maven' 39 | name = project.name 40 | desc = 'libp2p impl for android' 41 | websiteUrl = "https://github.com/Vbytes/libp2pimpl-android" 42 | issueTrackerUrl = "https://github.com/Vbytes/libp2pimpl-android/issues" 43 | vcsUrl = "https://github.com/Vbytes/libp2pimpl-android.git" 44 | licenses = ['Apache-2.0'] 45 | labels = ['aar', 'android', 'p2p'] 46 | publicDownloadNumbers = true 47 | } 48 | } 49 | 50 | install { 51 | repositories.mavenInstaller { 52 | pom.project { 53 | name = project.name 54 | packaging = 'aar' 55 | url = 'https://github.com/Vbytes/libp2pimpl-android' 56 | licenses { 57 | license { 58 | name = 'The Apache Software License, Version 2.0' 59 | url = 'http://www.apache.org/licenses/LICENSE-2.0.txt' 60 | } 61 | } 62 | developers { 63 | developer { 64 | id 'vbytes' 65 | name 'Vbytes tech' 66 | email 'repository@exatech.cn' 67 | } 68 | } 69 | scm { 70 | connection 'https://github.com/Vbytes/libp2pimpl-android.git' 71 | developerConnection 'https://github.com/Vbytes/libp2pimpl-android.git' 72 | url 'https://github.com/Vbytes/libp2pimpl-android' 73 | } 74 | } 75 | } 76 | } 77 | 78 | task sourcesJar(type: Jar) { 79 | from android.sourceSets.main.java.srcDirs 80 | classifier = 'sources' 81 | } 82 | 83 | task javadoc(type: Javadoc) { 84 | source = android.sourceSets.main.java.srcDirs 85 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) 86 | failOnError false 87 | } 88 | 89 | task javadocJar(type: Jar, dependsOn: javadoc) { 90 | classifier = 'javadoc' 91 | from javadoc.destinationDir 92 | } 93 | artifacts { 94 | archives javadocJar 95 | archives sourcesJar 96 | } 97 | 98 | task findConventions << { 99 | println project.getConvention() 100 | } 101 | 102 | -------------------------------------------------------------------------------- /libp2pimpl/libp2pimpl.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /libp2pimpl/lint.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /libp2pimpl/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /libp2pimpl/src/main/java/cn/vbyte/p2p/BaseController.java: -------------------------------------------------------------------------------- 1 | package cn.vbyte.p2p; 2 | 3 | import android.net.Uri; 4 | 5 | import com.vbyte.p2p.IController; 6 | import com.vbyte.p2p.OnLoadedListener; 7 | 8 | import java.util.Collections; 9 | import java.util.LinkedList; 10 | import java.util.List; 11 | 12 | /** 13 | * Created by passion on 16-1-14. 14 | */ 15 | public abstract class BaseController implements IController { 16 | 17 | // load => unload => load 操作的异步转同步 18 | public static final int VIDEO_LIVE = 0; 19 | public static final int VIDEO_VOD = 1; 20 | //同步总的次数是50次 21 | public static final int syncRetryCount = 50; 22 | //同步等待时间为100ms 23 | public static final long syncWaitTime = 100; 24 | 25 | public static class LoadEvent { 26 | public int videoType; 27 | public String channel; 28 | public String resolution; 29 | public double startTime; 30 | public OnLoadedListener listener; 31 | 32 | public LoadEvent(int videoType, String channel, String resolution, OnLoadedListener listener) { 33 | this(videoType, channel, resolution, 0, listener); 34 | } 35 | 36 | public LoadEvent(int videoType, String channel, String resolution, double startTime, OnLoadedListener listener) { 37 | this.videoType = videoType; 38 | this.channel = channel; 39 | this.resolution = resolution; 40 | this.startTime = startTime; 41 | this.listener = listener; 42 | } 43 | } 44 | 45 | protected static List loadQueue = Collections.synchronizedList(new LinkedList()); 46 | protected static LoadEvent curLoadEvent = null; 47 | 48 | /** 49 | * 这2个工具函数能让LiveController和VodController能事先对P2P线程反应的事件进行预处理 50 | * @param code 事件码 51 | * @param msg 事件说明 52 | */ 53 | protected void onEvent(int code, String msg) {} 54 | protected void onError(int code, String msg) {} 55 | 56 | /** 57 | * 为方便子类实现 58 | * @param channel 对直播是频道ID,对点播是资源链接 59 | * @param resolution 统一为 "UHD" 60 | * @param listener 当成功load时的回调函数 61 | * @throws Exception 当load/unload没有成对调用时,会抛出异常提示 62 | */ 63 | @Override 64 | public void load(String channel, String resolution, OnLoadedListener listener) throws Exception { 65 | load(channel, resolution, 0, listener); 66 | } 67 | 68 | 69 | protected volatile Uri mUri = null; 70 | /** 71 | * 同步获取uri接口 72 | * @param channel 对直播是频道ID,对点播是资源链接 73 | * @param resolution 统一为 "UHD" 74 | * @return 取得的uri 75 | * @throws Exception 当load/unload没有成对调用时,会抛出异常提示 76 | */ 77 | @Override 78 | public Uri loadAsync(String channel, String resolution) throws Exception { 79 | OnLoadedListener listener = new OnLoadedListener() { 80 | @Override 81 | public void onLoaded(Uri uri) { 82 | mUri = uri; 83 | } 84 | }; 85 | this.load(channel, resolution, listener); 86 | int retryCount = syncRetryCount; 87 | 88 | while (mUri == null && (retryCount--) > 0) { 89 | Thread.sleep(syncWaitTime); 90 | } 91 | if (retryCount == 0) { 92 | this.unload(); 93 | } 94 | return mUri; 95 | } 96 | 97 | /** 98 | * 同步获取uri接口 99 | * @param channel 对直播是频道ID,对点播是资源链接 100 | * @param resolution 统一为 "UHD" 101 | * @param startTime 起始时间,直播是时移,点播即开始时间偏移 102 | * @return 取得的uri 103 | * @throws Exception 当load/unload没有成对调用时,会抛出异常提示 104 | */ 105 | @Override 106 | public Uri loadAsync(String channel, String resolution, double startTime) throws Exception { 107 | OnLoadedListener listener = new OnLoadedListener() { 108 | @Override 109 | public void onLoaded(Uri uri) { 110 | mUri = uri; 111 | } 112 | }; 113 | this.load(channel, resolution, startTime, listener); 114 | int retryCount = syncRetryCount; 115 | 116 | while (mUri == null && (retryCount--) > 0) { 117 | Thread.sleep(syncWaitTime); 118 | } 119 | if (retryCount == 0) { 120 | this.unload(); 121 | } 122 | return mUri; 123 | } 124 | 125 | /** 126 | * 直接调用native层的load 127 | * @param channel 对直播是频道ID,对点播是资源链接 128 | * @param resolution 统一为 "UHD" 129 | * @param startTime 起始时间,直播是时移,点播即开始时间偏移 130 | */ 131 | protected void loadDirectly(String channel, String resolution, double startTime) {} 132 | 133 | /** 134 | * 对直播而言,seek函数并无意义 135 | * @param startTime 随机点播时的起始时间点 136 | */ 137 | @Override 138 | public void seek(double startTime) { 139 | return; 140 | } 141 | 142 | @Override 143 | public void pause() { 144 | return; 145 | } 146 | 147 | @Override 148 | public void resume() { return; } 149 | 150 | @Override 151 | public void unload() { 152 | mUri = null; 153 | } 154 | 155 | @Override 156 | public String playStreamInfo() { 157 | return ""; 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /libp2pimpl/src/main/java/cn/vbyte/p2p/LiveController.java: -------------------------------------------------------------------------------- 1 | package cn.vbyte.p2p; 2 | 3 | import android.net.Uri; 4 | import android.util.Log; 5 | 6 | import com.vbyte.p2p.IController; 7 | import com.vbyte.p2p.OnLoadedListener; 8 | 9 | /** 10 | * Created by passion on 16-1-14. 11 | */ 12 | public final class LiveController extends BaseController implements IController { 13 | private static final String TAG = "cn.vbyte.p2p.live"; 14 | 15 | public static class Event { 16 | /** 17 | * 启动一个直播流 18 | */ 19 | public static final int START = 10010000; 20 | /** 21 | * 告诉应用直播流已经启动 22 | */ 23 | public static final int STARTED = 10010001; 24 | /** 25 | * 停止一个直播流 26 | */ 27 | public static final int STOP = 10010002; 28 | /** 29 | * 告诉应用直播流已被停止 30 | */ 31 | public static final int STOPPED = 10010003; 32 | 33 | /** 34 | * 告诉应用直播流播放异常,需要回源播放 35 | */ 36 | public static final int BACK_TO_ORIGIN = 10010005; 37 | } 38 | 39 | public static class Error { 40 | /** 41 | * 此错误因传入的频道ID为空所引起 42 | */ 43 | public static final int CHANNEL_EMPTY = 10011000; 44 | /** 45 | * 此错误是因为该频道ID不存在,或者已被删除 46 | */ 47 | public static final int NO_SUCH_CHANNEL = 10011001; 48 | /** 49 | * 此错误表明传入的分辨率不对 50 | */ 51 | public static final int RESOLUTION_INVALID = 10011001; 52 | } 53 | 54 | private static LiveController instance; 55 | 56 | /** 57 | * 获取直播控制器 58 | * @return 直播控制器的唯一接口 59 | */ 60 | public static LiveController getInstance() { 61 | if (instance == null) { 62 | instance = new LiveController(); 63 | } 64 | return instance; 65 | } 66 | 67 | private long _pointer; 68 | 69 | private LiveController() { 70 | _pointer = _construct(); 71 | } 72 | 73 | /** 74 | * 加载一个直播流。针对时移,该接口只为flv使用 75 | * @param channel 直播流频道ID 76 | * @param resolution 统一为 "UHD" 77 | * @param startTime 视频的起始位置,以秒为单位,支持一天之内的视频时移回放 78 | * @param listener 当成功load时的回调函数 79 | * @throws Exception 当load/unload没有成对调用时,会抛出异常提示 80 | */ 81 | @Override 82 | public void load(String channel, String resolution, double startTime, OnLoadedListener listener) 83 | throws Exception { 84 | if (!loadQueue.isEmpty()) { 85 | loadQueue.clear(); 86 | throw new Exception("You must forget unload last channel!"); 87 | } 88 | 89 | LoadEvent loadEvent = new LoadEvent(VIDEO_LIVE, channel, resolution, startTime, listener); 90 | loadQueue.add(loadEvent); 91 | Log.i(TAG, "loadQueue size is " + loadQueue.size()); 92 | if (curLoadEvent == null) { 93 | curLoadEvent = loadQueue.get(0); 94 | loadQueue.remove(0); 95 | this._load(_pointer, channel, resolution, startTime); 96 | } 97 | } 98 | 99 | @Override 100 | protected void loadDirectly(String channel, String resolution, double startTime) { 101 | this._load(_pointer, channel, resolution, startTime); 102 | } 103 | 104 | /** 105 | * 卸载当前直播流频道 106 | */ 107 | @Override 108 | public void unload() { 109 | //当前有事件的时候, 才unload, 屏蔽空unload 110 | if(curLoadEvent != null) { 111 | super.unload(); 112 | this._unload(_pointer); 113 | } 114 | } 115 | 116 | /** 117 | * 获取当前播放时间,仅对flv格式有效 118 | * @return 当前播放的时间点 119 | */ 120 | public int getCurrentPlayTime() { 121 | return _getCurrentPlayTime(_pointer); 122 | } 123 | 124 | @Override 125 | protected void onEvent(int code, String msg) { 126 | switch (code) { 127 | case Event.STARTED: 128 | if (curLoadEvent != null) { 129 | Uri uri = Uri.parse(msg); 130 | curLoadEvent.listener.onLoaded(uri); 131 | } 132 | break; 133 | } 134 | } 135 | 136 | private native long _construct(); 137 | 138 | private native void _load(long pointer, String channel, String resolution, double startTime); 139 | 140 | private native void _unload(long pointer); 141 | 142 | private native int _getCurrentPlayTime(long pointer); 143 | } -------------------------------------------------------------------------------- /libp2pimpl/src/main/java/cn/vbyte/p2p/LoggerCallback.java: -------------------------------------------------------------------------------- 1 | package cn.vbyte.p2p; 2 | 3 | public abstract class LoggerCallback { 4 | 5 | abstract public void v(String tag, String msg); 6 | abstract public void d(String tag, String msg); 7 | abstract public void i(String tag, String msg); 8 | abstract public void w(String tag, String msg); 9 | abstract public void e(String tag, String msg); 10 | 11 | private static LoggerCallback logger = null; 12 | public static void setLoggerCallback(LoggerCallback aLoggerCallback) { 13 | logger = aLoggerCallback; 14 | } 15 | 16 | public static void verbose(String tag, String msg) { 17 | if (logger != null) { 18 | logger.v(tag, msg); 19 | } 20 | } 21 | 22 | public static void info(String tag, String msg) { 23 | if (logger != null) { 24 | logger.i(tag, msg); 25 | } 26 | } 27 | 28 | public static void debug(String tag, String msg) { 29 | if (logger != null) { 30 | logger.d(tag, msg); 31 | } 32 | } 33 | 34 | public static void warn(String tag, String msg) { 35 | if (logger != null) { 36 | logger.w(tag, msg); 37 | } 38 | 39 | } 40 | 41 | public static void error(String tag, String msg) { 42 | if (logger != null) { 43 | logger.e(tag, msg); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /libp2pimpl/src/main/java/cn/vbyte/p2p/VbyteHandler.java: -------------------------------------------------------------------------------- 1 | package cn.vbyte.p2p; 2 | 3 | import android.os.Handler; 4 | import android.os.Message; 5 | 6 | /** 7 | * Created by passion on 16-8-23. 8 | */ 9 | public class VbyteHandler extends Handler { 10 | 11 | @Override 12 | public void handleMessage(Message msg) { 13 | int code = msg.what; 14 | int prefixOfCode = code / 1000; 15 | String description = (String) msg.obj; 16 | switch (prefixOfCode) { 17 | case 10010: 18 | LiveController.getInstance().onEvent(code, description); 19 | break; 20 | case 10011: 21 | LiveController.getInstance().onError(code, description); 22 | break; 23 | case 10020: 24 | VodController.getInstance().onEvent(code, description); 25 | break; 26 | case 10021: 27 | VodController.getInstance().onError(code, description); 28 | break; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /libp2pimpl/src/main/java/cn/vbyte/p2p/VbyteP2PModule.java: -------------------------------------------------------------------------------- 1 | package cn.vbyte.p2p; 2 | 3 | import android.content.Context; 4 | import android.os.Environment; 5 | import android.os.Message; 6 | import android.os.Handler; 7 | import android.util.Log; 8 | 9 | import java.util.List; 10 | 11 | import com.vbyte.update.*; 12 | 13 | import static cn.vbyte.p2p.BaseController.curLoadEvent; 14 | 15 | /** 16 | * Created by passion on 15-11-5. 17 | */ 18 | public final class VbyteP2PModule { 19 | private static final String DYNAMIC_LIB_NAME = "libp2pmodule"; 20 | 21 | public static class Event { 22 | /** 23 | * 公共的,告诉应用已经初始化完毕 24 | */ 25 | public static final int INITED = 10000000; 26 | 27 | public static final int EXIT = 10000001; 28 | /** 29 | * 公共的,告诉应用正在退出 30 | */ 31 | public static final int EXITING = 10000002; // 32 | /** 33 | * 公共的,告诉应用已经完全退出 34 | */ 35 | public static final int EXITED = 10000003; 36 | /** 37 | * 公共的,告诉应用流已经准备就绪 38 | */ 39 | public static final int STREAM_READY = 10000004; // 公共的,流已经准备就绪 40 | /** 41 | * 公共的,告诉应用配置已经就绪 42 | */ 43 | public static final int CONF_READY = 10000005; // 公共的,配置已经就绪 44 | public static final int STUN_CONNECTED = 10000006; // 公共的,点播,直播都在监听一个,且同一时刻,只能有一个监听此信号 45 | /** 46 | * 公共的,告诉应用已经加入P2P 47 | */ 48 | public static final int JOINED = 10000007; // 公共的,属于tracker的 49 | /** 50 | * 公共的,告诉应用伙伴已经就绪 51 | */ 52 | public static final int PARTNER_READY = 10000008; // 公共的,伙伴已经就绪 53 | /** 54 | * 公共的,告诉应用有一个新伙伴加入你 55 | */ 56 | public static final int NEW_PARTNER = 10000009; // 公共的,有一个新的伙伴 57 | /** 58 | * 公共的,表明P2P稳定 59 | */ 60 | public static final int P2P_STABLE = 10000010; // 公共的,表明P2P稳定 61 | /** 62 | * 公共的,表明一次上报统计事件 63 | */ 64 | public static final int REPORTED = 10000011; // 公共的,监听的上报信号 65 | 66 | /** 67 | * 公共的,表明卡播恢复 68 | */ 69 | public static final int DATA_UNBLOCK = 10000012; // 公共的,监听的上报信号 70 | } 71 | 72 | public static class Error { 73 | /** 74 | * 表明配置服务不可用,此时加载失败 75 | */ 76 | public static final int CONF_UNAVAILABLE = 10001000; // 公共的,配置服务的 77 | /** 78 | * 表明认证失败,请检查传入的appId,appKey,appSecretKey是否正确, 79 | * 以及是否与当前应用对应得上。 80 | */ 81 | public static final int AUTH_FAILED = 10001001; // 公共的,配置服务的 82 | /** 83 | * 表示conf的内容错误,不能被解析 84 | */ 85 | public static final int CONF_INVALID = 10001002; // 公共的,配置服务的 86 | /** 87 | * 表明下载资源时网络太差,这很有可能是资源服务器的带宽不足引起的 88 | */ 89 | public static final int SRC_UNSTABLE = 10001003; // 资源网络不好 90 | /** 91 | * 流媒体解析错误,请确认要播放的流是正确的能被解析的流媒体。 92 | */ 93 | public static final int MEDIA_ERROR = 10001004; // 多媒体格式不对 94 | /** 95 | * 网络不好 96 | */ 97 | public static final int BAD_NETWORK = 10001005; // 公共的 98 | /** 99 | * 这个说明穿透不成功,此错误通常因客户端所在网络限制造成的,将导致没有P2P加速。 100 | */ 101 | public static final int STUN_FAILED = 10001006; // 公共的 102 | /** 103 | * 此错误说明某次获取伙伴失败了,不过不用太担心,它会一段时间后重试 104 | */ 105 | public static final int JOIN_FAILED = 10001007; // 公共的,属于tracker的 106 | /** 107 | * 此错误事件表明一次上报事件失败,不会有其他影响 108 | */ 109 | public static final int REPORT_FAILED = 10001008; // 公共的,上报服务的 110 | /** 111 | * 此错误表明收到未知类型的包,将忽略,一般很少发生 112 | */ 113 | public static final int UNKNOWN_PACKET = 10001009; // 公共的,收发包逻辑 114 | /** 115 | * 此错误表明收到包数据签名不对,将忽略,一般很少发生 116 | */ 117 | public static final int INVALID_PACKET = 10001010; // 公共的,收发包 118 | /** 119 | * 此错误表明数据不够,发生卡播 120 | */ 121 | public static final int DATA_BLOCK = 10001011; // 公共的 122 | } 123 | 124 | // 持久保存SDK版本号 125 | private static String SDK_VERSION; 126 | private static String ARCH_ABI; 127 | private static VbyteP2PModule instance; 128 | 129 | /** 130 | * 新启动一个p2p模块,注意四个参数绝对不能为null,在程序启动时调用 131 | * @param context 上下文 132 | * @param appId 应用唯一标识 133 | * @param appKey 应用密钥 134 | * @param appSecretKey 应用加密混淆字段,可选 135 | * @return P2PModule的唯一实例 136 | * @throws Exception 当参数为null或者p2p模块加载不成功时抛出异常 137 | */ 138 | public static VbyteP2PModule create(Context context, String appId, String appKey, String appSecretKey) 139 | throws Exception { 140 | if (instance == null) { 141 | instance = new VbyteP2PModule(context, appId, appKey, appSecretKey); 142 | } 143 | return instance; 144 | } 145 | 146 | public static VbyteP2PModule getInstance() { 147 | return instance; 148 | } 149 | 150 | /** 151 | * 获取native应用的版本号 152 | * @return P2PModule SDK的版本号 153 | */ 154 | public static String getVersion() { 155 | if (SDK_VERSION == null) { 156 | SDK_VERSION = VbyteP2PModule._version(); 157 | } 158 | return SDK_VERSION; 159 | } 160 | 161 | /** 162 | * 获取native应用的abi arch 163 | * @return armeabi|armeabi-v7a|arm64-v8a|x86|x86_64 164 | */ 165 | private static String getArchABI() { 166 | if (ARCH_ABI == null) { 167 | ARCH_ABI = VbyteP2PModule._targetArchABI(); 168 | } 169 | return ARCH_ABI; 170 | } 171 | 172 | /** 173 | * 启用调试模式,该模式会输出一些调试信息,对测试版本尤其有效 174 | */ 175 | public static void enableDebug() { 176 | VbyteP2PModule._enableDebug(); 177 | } 178 | 179 | /** 180 | * 关闭调试模式。默认调试功能是关闭的,发布应用时也应该关闭调试模式。 181 | */ 182 | public static void disableDebug() { 183 | VbyteP2PModule._disableDebug(); 184 | } 185 | 186 | public static void setLoggerCallback(LoggerCallback logger) { 187 | LoggerCallback.setLoggerCallback(logger); 188 | VbyteP2PModule._setLoggerCallback(); 189 | } 190 | 191 | /** 192 | * 获取P2P模块的版本号 193 | * @return P2P模块的版本号 194 | */ 195 | private static native String _version(); 196 | 197 | /** 198 | * 获取当前运行的ABI名称 199 | * @return 当前运行的ABI名称 200 | */ 201 | private static native String _targetArchABI(); 202 | 203 | /** 204 | * 打开调试模式,默认是关闭调试模式的 205 | */ 206 | private static native void _enableDebug(); 207 | 208 | /** 209 | * 关闭调试模式,应用上线时应关闭调试模式 210 | */ 211 | private static native void _disableDebug(); 212 | 213 | /** 214 | * 设置自定义logger打印回调函数 215 | */ 216 | private static native void _setLoggerCallback(); 217 | 218 | 219 | ///////////////////////////////////////////////////////////// 220 | /*=========================================================*/ 221 | 222 | // 事件监听gut 223 | private Handler eventHandler = null; 224 | private Handler errorHandler = null; 225 | private Handler vbyteHandler = new VbyteHandler(); 226 | private DynamicLibManager dynamicLibManager; 227 | // native代码对应的对象实例,标准做法 228 | private long _pointer; 229 | 230 | private VbyteP2PModule(Context context, String appId, String appKey, String appSecretKey) 231 | throws Exception { 232 | if (context == null || appId == null || appKey == null || appSecretKey == null) { 233 | throw new NullPointerException("context or appId or appKey or appSecretKey can't be null when init p2p live stream!"); 234 | } 235 | 236 | System.loadLibrary("stun"); 237 | System.loadLibrary("event"); 238 | 239 | dynamicLibManager = new DynamicLibManager(context); 240 | String soFilePath = null; 241 | try { 242 | soFilePath = dynamicLibManager.locate(DYNAMIC_LIB_NAME); 243 | } catch (Exception e) { 244 | // 因获取不到程序版本号而导致的自动升级失败,默认使用安装时自带的 245 | } 246 | if(soFilePath == null) { 247 | System.loadLibrary("p2pmodule"); 248 | } else { 249 | System.load(soFilePath); 250 | } 251 | dynamicLibManager.checkUpdate(DYNAMIC_LIB_NAME, getVersion(), getArchABI()); 252 | 253 | _pointer = this._construct(); 254 | if (_pointer == 0) { 255 | throw new RuntimeException("Can not init P2P"); 256 | } 257 | 258 | // TODO: 获取包名、cacheDir、diskDir等信息传入instance 259 | this._setContext(_pointer, context); 260 | String cacheDir = context.getCacheDir().getAbsolutePath(); 261 | try { 262 | String diskDir = Environment.getExternalStorageDirectory().getAbsolutePath(); 263 | this._setDiskDir(_pointer, diskDir); 264 | } catch (Exception e) { 265 | this._setDiskDir(_pointer, cacheDir); 266 | } 267 | this._setCacheDir(_pointer, cacheDir); 268 | this._setAppId(_pointer, appId); 269 | this._setAppKey(_pointer, appKey); 270 | this._setAppSecretKey(_pointer, appSecretKey); 271 | } 272 | 273 | /** 274 | * 设置EventHandler,注意该handler不能叠加,之前设置的handler将无效 275 | * @param handler 要设置的EventHandler实例 276 | */ 277 | public void setEventHandler(Handler handler) { 278 | this.eventHandler = handler; 279 | } 280 | 281 | /** 282 | * 设置ErrorHandler,注意该handler不能叠加,之前设置的handler将无效 283 | * @param handler 要设置的ErrorHandler实例 284 | */ 285 | public void setErrorHandler(Handler handler) { 286 | this.errorHandler = handler; 287 | } 288 | 289 | private void onEvent(int code, String msg) { 290 | List loadQueue = BaseController.loadQueue; 291 | if (code == LiveController.Event.STOPPED || code == VodController.Event.STOPPED) { 292 | if (curLoadEvent != null) { 293 | curLoadEvent = null; 294 | } 295 | if (!loadQueue.isEmpty()) { 296 | curLoadEvent = loadQueue.get(0); 297 | loadQueue.remove(0); 298 | if (curLoadEvent.videoType == BaseController.VIDEO_LIVE) { 299 | LiveController.getInstance().loadDirectly(curLoadEvent.channel, curLoadEvent.resolution, curLoadEvent.startTime); 300 | } else { 301 | VodController.getInstance().loadDirectly(curLoadEvent.channel, curLoadEvent.resolution, curLoadEvent.startTime); 302 | } 303 | } 304 | } 305 | Message message = vbyteHandler.obtainMessage(); 306 | message.what = code; 307 | message.obj = msg; 308 | vbyteHandler.sendMessage(message); 309 | if (eventHandler != null) { 310 | message = eventHandler.obtainMessage(); 311 | message.what = code; 312 | message.obj = msg; 313 | eventHandler.sendMessage(Message.obtain(message)); 314 | } 315 | } 316 | 317 | private void onError(int code, String msg) { 318 | Message message = vbyteHandler.obtainMessage(); 319 | message.what = code; 320 | message.obj = msg; 321 | vbyteHandler.sendMessage(message); 322 | if (errorHandler != null) { 323 | message = errorHandler.obtainMessage(); 324 | message.what = code; 325 | message.obj = msg; 326 | errorHandler.sendMessage(Message.obtain(message)); 327 | } 328 | } 329 | 330 | /** 331 | * native应用初始化 332 | * @return 成功返回native代码里面对应对象的指针,失败返回0 333 | */ 334 | private native long _construct(); 335 | 336 | /** 337 | * 设置context 338 | * @param context 339 | * @param pointer native层对应对象的指针 340 | */ 341 | private native void _setContext(long pointer, Context context); 342 | 343 | /** 344 | * 设置可写缓存目录 345 | * @param cacheDir 应用缓存目录 346 | * @param pointer native层对应对象的指针 347 | */ 348 | private native void _setCacheDir(long pointer, String cacheDir); 349 | 350 | /** 351 | * 设置永久磁盘目录 352 | * @param diskDir 应用无关的外存储器可写目录, 353 | * 如果设备没用外存储器,那将与cacheDir相同 354 | * @param pointer native层对应对象的指针 355 | */ 356 | private native void _setDiskDir(long pointer, String diskDir); 357 | 358 | /** 359 | * 设置appId 360 | * @param appId 应用Id,为此应用唯一标识 361 | * @param pointer native层对应对象的指针 362 | */ 363 | private native void _setAppId(long pointer, String appId); 364 | 365 | /** 366 | * 设置appKey 367 | * @param appKey 应用密钥 368 | * @param pointer native层对应对象的指针 369 | */ 370 | private native void _setAppKey(long pointer, String appKey); 371 | 372 | /** 373 | * 设置appSecretKey 374 | * @param appSecretKey 应用混淆密钥 375 | * @param pointer native层对应对象的指针 376 | */ 377 | private native void _setAppSecretKey(long pointer, String appSecretKey); 378 | } 379 | -------------------------------------------------------------------------------- /libp2pimpl/src/main/java/cn/vbyte/p2p/VodController.java: -------------------------------------------------------------------------------- 1 | package cn.vbyte.p2p; 2 | 3 | import android.net.Uri; 4 | import android.os.AsyncTask; 5 | 6 | import com.vbyte.p2p.IController; 7 | import com.vbyte.p2p.OnLoadedListener; 8 | import com.vbyte.p2p.SecurityUrl; 9 | import com.vbyte.p2p.UrlGenerator; 10 | 11 | /** 12 | * Created by passion on 16-1-14. 13 | */ 14 | public final class VodController extends BaseController implements IController { 15 | 16 | private static final String TAG = "cn.vbyte.p2p.vod"; 17 | 18 | public static class Event { 19 | /** 20 | * 告诉应用启动一个点播资源 21 | */ 22 | public static final int START = 10020000; 23 | /** 24 | * 告诉应用媒体已分析完毕 25 | */ 26 | public static final int STARTED = 10020001; 27 | /** 28 | * 停止 29 | */ 30 | public static final int STOP = 10020002; 31 | /** 32 | * 告诉应用,点播频道已经被停止 33 | */ 34 | public static final int STOPPED = 10020003; 35 | /** 36 | * 点播专有,暂停 37 | */ 38 | public static final int PAUSE = 10020004; 39 | /** 40 | * 点播专有,恢复 41 | */ 42 | public static final int RESUME = 10020005; 43 | /** 44 | * 通知应用层要重新获取防盗链url 45 | */ 46 | public static final int RETRIEVE_URL = 10020006; 47 | /** 48 | *应用层已经重新生成url 49 | */ 50 | public static final int RETRIEVED_URL = 10020007; 51 | /** 52 | * 告诉应用已经探测到最后一片数据,即将结束 53 | */ 54 | public static final int FINISHED = 10020008; 55 | public static final int HEADER_READY = 10020009; // 媒体数据的header解析完毕 56 | 57 | } 58 | 59 | public static class Error { 60 | /** 61 | * 此错误表明传入的URI为空,请检查。 62 | */ 63 | public static final int URI_EMPTY = 10021000; // URI为空 64 | /** 65 | * 此错误表明点播资源不能被成功下载,请检查资源是否存在,以及带宽是否足够 66 | */ 67 | public static final int DOWNLOAD_FAILED = 10021000; // SOURCE下载失败 68 | /** 69 | * 此错误表明媒体的格式不被支持 70 | */ 71 | public static final int FORMAT_INVALID = 10021000; // 文件格式不支持 72 | } 73 | 74 | public static class MEDIAFORMAT { 75 | public static final int UNKNOWN = 0; 76 | public static final int FLV = 1; 77 | public static final int MP4 = 2; 78 | public static final int TS = 3; 79 | public static final int M3U8 = 4; 80 | } 81 | 82 | private static VodController instance; 83 | 84 | /** 85 | * 获取Vod点播控制器 86 | * @return Vod点播控制器的唯一实例 87 | */ 88 | public static VodController getInstance() { 89 | if (instance == null) { 90 | instance = new VodController(); 91 | } 92 | return instance; 93 | } 94 | 95 | private long _pointer; 96 | private UrlGenerator urlGenerator; 97 | 98 | private VodController() { 99 | _pointer = _construct(); 100 | 101 | // urlGenerator给出一个默认值,能够直接传url就能播放 102 | urlGenerator = new UrlGenerator() { 103 | @Override 104 | public SecurityUrl createSecurityUrl(String originUrl) { 105 | return new SecurityUrl(originUrl); 106 | } 107 | }; 108 | } 109 | 110 | /** 111 | * 从随机的某时间点加载播放点播视频 112 | * @param channel 资源链接,主要为点播调用 113 | * @param resolution 资源的清晰度,现在统一为"UHD" 114 | * @param startTime 视频的起始位置,以秒为单位 115 | * @param listener 当成功load时的回调函数 116 | * @throws Exception 当load/unload没有成对调用时,会抛出异常提示 117 | */ 118 | @Override 119 | public void load(String channel, String resolution, double startTime, OnLoadedListener listener) 120 | throws Exception { 121 | if (!loadQueue.isEmpty()) { 122 | loadQueue.clear(); 123 | throw new Exception("You must forget to unload last channel!"); 124 | } 125 | LoadEvent loadEvent = new LoadEvent(VIDEO_VOD, channel, resolution, startTime, listener); 126 | loadQueue.add(loadEvent); 127 | if (curLoadEvent == null) { 128 | curLoadEvent = loadQueue.get(0); 129 | loadQueue.remove(0); 130 | this._load(_pointer, channel, resolution, startTime); 131 | } 132 | } 133 | 134 | protected void onEvent(int code, String msg) { 135 | switch (code) { 136 | case Event.STARTED: 137 | if (curLoadEvent != null) { 138 | Uri uri = Uri.parse(msg); 139 | curLoadEvent.listener.onLoaded(uri); 140 | } 141 | break; 142 | case Event.RETRIEVE_URL: 143 | if (urlGenerator != null) { 144 | final String sourceId = msg; 145 | new Thread(new Runnable() { 146 | @Override 147 | public void run() { 148 | SecurityUrl securityUrl = urlGenerator.createSecurityUrl(sourceId); 149 | if (securityUrl != null) { 150 | _setNewUrl(_pointer, securityUrl.toString()); 151 | } 152 | } 153 | }).start(); 154 | } 155 | break; 156 | } 157 | } 158 | 159 | @Override 160 | protected void loadDirectly(String url, String resolution, double startTime) { 161 | this._load(_pointer, url, resolution, startTime); 162 | } 163 | 164 | /** 165 | * 获取点播视频的总时长 166 | */ 167 | public int getDuration() { 168 | return this._getDuration(_pointer); 169 | } 170 | 171 | /** 172 | * 设置防盗链url生成器,这在播放时url因时间超时失效时发挥作用,重新获取新的防盗链url去播放 173 | * @param urlGenerator 传入的url生成器实例 174 | */ 175 | public void setUrlGenerator(UrlGenerator urlGenerator) { 176 | this.urlGenerator = urlGenerator; 177 | } 178 | 179 | /** 180 | * 获取防盗链url生成器 181 | * @return 防盗链url生成器 182 | */ 183 | public UrlGenerator getUrlGenerator() { 184 | return urlGenerator; 185 | } 186 | 187 | /** 188 | * 随机播放当前点播视频的某一时间点,注意调用之后,要让播放器重新加载uri 189 | * @param startTime 随机点播时的起始时间点 190 | */ 191 | @Override 192 | public void seek(double startTime) { 193 | this._seek(_pointer, startTime); 194 | } 195 | 196 | /** 197 | * 播放暂停 198 | */ 199 | @Override 200 | public void pause() { 201 | this._pause(_pointer); 202 | } 203 | 204 | /** 205 | * 暂停后恢复播放 206 | */ 207 | @Override 208 | public void resume() { 209 | this._resume(_pointer); 210 | } 211 | 212 | /** 213 | * 卸载此点播资源 214 | */ 215 | @Override 216 | public void unload() { 217 | //当前有事件的时候, 才unload, 屏蔽空unload 218 | if(curLoadEvent != null) { 219 | super.unload(); 220 | this._unload(_pointer); 221 | } 222 | } 223 | 224 | @Override 225 | public String playStreamInfo() { 226 | return this._playStreamInfo(_pointer); 227 | } 228 | 229 | private native long _construct(); 230 | 231 | private native String _load(long pointer, String url, String resolution, double startTime); 232 | 233 | private native int _getDuration(long pointer); 234 | 235 | private native void _seek(long pointer, double startTime); 236 | 237 | private native void _pause(long pointer); 238 | 239 | private native void _resume(long pointer); 240 | 241 | private native void _unload(long pointer); 242 | 243 | private native void _setNewUrl(long pointer, String newUrl); 244 | 245 | private native String _playStreamInfo(long pointer); 246 | } 247 | -------------------------------------------------------------------------------- /libp2pimpl/src/main/java/cn/vbyte/p2p/v2/P2PModuleImpl.java: -------------------------------------------------------------------------------- 1 | package cn.vbyte.p2p.v2; 2 | 3 | import android.content.Context; 4 | import android.net.Uri; 5 | import android.os.Handler; 6 | import android.os.Message; 7 | 8 | import com.vbyte.p2p.OnLoadedListener; 9 | import com.vbyte.p2p.P2PHandler; 10 | import com.vbyte.p2p.P2PModule; 11 | 12 | import cn.vbyte.p2p.VbyteP2PModule; 13 | import cn.vbyte.p2p.LiveController; 14 | 15 | /** 16 | * Created by passion on 16-5-13. 17 | */ 18 | public class P2PModuleImpl implements P2PModule { 19 | private static P2PModule instance; 20 | 21 | 22 | public static P2PModule getInstance(String appId, String appKey, String appSecret, Context context) { 23 | if (instance == null) { 24 | instance = new P2PModuleImpl(appId, appKey, appSecret, context); 25 | } 26 | return instance; 27 | } 28 | 29 | /** 30 | * is Nullable 31 | * @return P2PModule的全局唯一实例,可能为null 32 | */ 33 | public static P2PModule getInstance() { 34 | return instance; 35 | } 36 | 37 | /////////////////////////////////////////////////////////////// 38 | /* 39 | * 代理模式,为了兼容老版本的API 40 | */ 41 | private VbyteP2PModule proxy; 42 | private Handler handler; 43 | private String statistic; 44 | 45 | public P2PModuleImpl(String appId, String appKey, String appSecret, Context context) { 46 | try { 47 | proxy = VbyteP2PModule.create(context, appId, appKey, appSecret); 48 | } catch (Exception e) { 49 | e.printStackTrace(); 50 | } 51 | } 52 | 53 | @Override 54 | public String getPlayPath(String channel) { 55 | return null; 56 | } 57 | 58 | @Override 59 | public void getPlayPath(String channel, OnLoadedListener listener) { 60 | try { 61 | LiveController.getInstance().load(channel, "UHD", listener); 62 | } catch (Exception e) { 63 | e.printStackTrace(); 64 | } 65 | } 66 | 67 | @Override 68 | public String getSDKVersion() { 69 | return VbyteP2PModule.getVersion(); 70 | } 71 | 72 | @Override 73 | public String getStatistics() { 74 | return statistic; 75 | } 76 | 77 | @Override 78 | public int getCurrentPlayTime() { 79 | // return LiveController.getInstance(); 80 | return 0; 81 | } 82 | 83 | @Override 84 | public void closeModule() { 85 | LiveController.getInstance().unload(); 86 | proxy = null; 87 | } 88 | 89 | @Override 90 | public void setP2PHandler(final P2PHandler handler) { 91 | this.handler = handler; 92 | /** 93 | * aHander就是为了满足俊哥而弄的代理 94 | */ 95 | Handler aHandler = new Handler(new Handler.Callback() { 96 | @Override 97 | public boolean handleMessage(Message msg) { 98 | Message message = Message.obtain(); 99 | message.obj = msg.obj; 100 | switch (msg.what) { 101 | case VbyteP2PModule.Event.REPORTED: 102 | P2PModuleImpl.this.statistic = (String)msg.obj; 103 | break; 104 | case VbyteP2PModule.Event.STREAM_READY: 105 | message.what = P2PHandler.p2p_FirstDataSuccess; 106 | P2PModuleImpl.this.handler.sendMessage(message); 107 | break; 108 | case VbyteP2PModule.Event.CONF_READY: 109 | message.what = P2PHandler.p2p_ChannelInfoSuccess; 110 | P2PModuleImpl.this.handler.sendMessage(message); 111 | break; 112 | case VbyteP2PModule.Event.DATA_UNBLOCK: 113 | message.what = P2PHandler.p2p_WriteDataUnblock; 114 | P2PModuleImpl.this.handler.sendMessage(message); 115 | break; 116 | case VbyteP2PModule.Error.CONF_INVALID: 117 | message.what = P2PHandler.p2p_ChannelInfoFail; 118 | P2PModuleImpl.this.handler.sendMessage(message); 119 | break; 120 | case VbyteP2PModule.Error.BAD_NETWORK: 121 | message.what = P2PHandler.cdn_DownLoadFail; 122 | P2PModuleImpl.this.handler.sendMessage(message); 123 | break; 124 | case VbyteP2PModule.Error.DATA_BLOCK: 125 | message.what = P2PHandler.p2p_WriteDataBlock; 126 | P2PModuleImpl.this.handler.sendMessage(message); 127 | break; 128 | default: 129 | break; 130 | } 131 | return true; 132 | } 133 | }); 134 | if (proxy != null) { 135 | proxy.setEventHandler(aHandler); 136 | proxy.setErrorHandler(aHandler); 137 | } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /libp2pimpl/src/main/java/com/vbyte/p2p/IController.java: -------------------------------------------------------------------------------- 1 | package com.vbyte.p2p; 2 | 3 | import android.net.Uri; 4 | 5 | /** 6 | * Created by passion on 16-1-14. 7 | */ 8 | public interface IController { 9 | 10 | /** 11 | * 加载一个频道,此函数没有起始时间参数 12 | * @param channel 对直播是频道ID,对点播是资源链接 13 | * @param resolution 统一为 "UHD" 14 | * @param listener 当成功load时的回调函数 15 | * @throws Exception 当load/unload没有成对调用时,会抛出异常 16 | */ 17 | void load(String channel, String resolution, OnLoadedListener listener) throws Exception; 18 | 19 | /** 20 | * 加载一个频道 21 | * @param channel 资源链接,主要为点播调用 22 | * @param resolution 统一为 "UHD" 23 | * @param startTime 视频的起始位置,以秒为单位 24 | * @param listener 当成功load时的回调函数 25 | * @throws Exception 当load/unload没有成对调用时,会抛出异常 26 | */ 27 | void load(String channel, String resolution, double startTime, OnLoadedListener listener) throws Exception; 28 | 29 | /** 30 | * 同步加载一个频道 31 | * @param channel 对直播是频道ID,对点播是资源链接 32 | * @param resolution 统一为 "UHD" 33 | * @return 34 | * @throws Exception 当load/unload没有成对调用时,会抛出异常 35 | */ 36 | Uri loadAsync(String channel, String resolution) throws Exception; 37 | 38 | /** 39 | * 同步加载一个频道 40 | * @param channel 资源链接,主要为点播调用 41 | * @param resolution 统一为 "UHD" 42 | * @param startTime 视频的起始位置,以秒为单位 43 | * @return 44 | * @throws Exception 当load/unload没有成对调用时,会抛出异常 45 | */ 46 | Uri loadAsync(String channel, String resolution, double startTime) throws Exception; 47 | 48 | /** 49 | * 对点播有用 50 | * @param startTime 随机点播时的起始时间点 51 | */ 52 | void seek(double startTime); 53 | 54 | void pause(); 55 | 56 | void resume(); 57 | 58 | /** 59 | * 卸载一个频道或者卸载一个vod视频,释放其占用的资源 60 | */ 61 | void unload(); 62 | 63 | /** 64 | * 获取播放统计信息 65 | * @return 66 | */ 67 | String playStreamInfo(); 68 | 69 | } 70 | -------------------------------------------------------------------------------- /libp2pimpl/src/main/java/com/vbyte/p2p/OnLoadedListener.java: -------------------------------------------------------------------------------- 1 | package com.vbyte.p2p; 2 | 3 | import android.net.Uri; 4 | 5 | /** 6 | * Created by passion on 16-8-23. 7 | */ 8 | public interface OnLoadedListener { 9 | 10 | void onLoaded(Uri uri); 11 | } 12 | -------------------------------------------------------------------------------- /libp2pimpl/src/main/java/com/vbyte/p2p/P2PHandler.java: -------------------------------------------------------------------------------- 1 | package com.vbyte.p2p; 2 | 3 | import android.os.Handler; 4 | 5 | public class P2PHandler extends Handler { 6 | public static final int p2p_ChannelInfoSuccess = 0x00; 7 | public static final int p2p_FirstDataSuccess = 0x01; 8 | public static final int p2p_SecondDataSuccess = 0x02; 9 | public static final int p2p_FourthDataSuccess = 0x03; 10 | 11 | public static final int p2p_WriteDataBlock = 0x10; 12 | public static final int p2p_WriteDataUnblock = 0x11; 13 | 14 | public static final int p2p_ChannelInfoFail = 0x20; 15 | public static final int cdn_DownLoadFail = 0x30; 16 | } 17 | -------------------------------------------------------------------------------- /libp2pimpl/src/main/java/com/vbyte/p2p/P2PModule.java: -------------------------------------------------------------------------------- 1 | package com.vbyte.p2p; 2 | 3 | /** 4 | * Created by passion on 16-5-10. 5 | */ 6 | public interface P2PModule { 7 | 8 | String getPlayPath(String channel); 9 | 10 | void getPlayPath(String channel, OnLoadedListener listener); 11 | 12 | String getSDKVersion(); 13 | 14 | String getStatistics(); 15 | 16 | int getCurrentPlayTime(); 17 | 18 | void closeModule(); 19 | 20 | void setP2PHandler(P2PHandler handler); 21 | } 22 | -------------------------------------------------------------------------------- /libp2pimpl/src/main/java/com/vbyte/p2p/SecurityUrl.java: -------------------------------------------------------------------------------- 1 | package com.vbyte.p2p; 2 | 3 | import org.json.JSONObject; 4 | 5 | import java.util.HashMap; 6 | import java.util.Iterator; 7 | import java.util.Map; 8 | 9 | /** 10 | * Created by passion on 16-12-23. 11 | */ 12 | 13 | public class SecurityUrl { 14 | private String url = ""; 15 | private String method = "GET"; 16 | private HashMap headers = new HashMap(); 17 | 18 | /** 19 | * 构造函数 20 | */ 21 | public SecurityUrl() { 22 | 23 | } 24 | 25 | /** 26 | * 构造函数 27 | * @param url 防盗链请求的url 28 | */ 29 | public SecurityUrl(String url) { 30 | this.url = url; 31 | } 32 | 33 | /** 34 | * 构造函数 35 | * @param url 防盗链请求的url 36 | * @param method 防盗链请求的方法 37 | */ 38 | public SecurityUrl(String url, String method) { 39 | this.url = url; 40 | this.method = method; 41 | } 42 | 43 | /** 44 | * 设置防盗链请求的url 45 | * @param url 要设置的防盗链的url 46 | * @return 对象本身,可以链式调用 47 | */ 48 | public SecurityUrl setUrl(String url) { 49 | this.url = url; 50 | return this; 51 | } 52 | 53 | /** 54 | * 获取防盗链请求的url 55 | * @return 防盗链请求的url 56 | */ 57 | public String getUrl() { 58 | return url; 59 | } 60 | 61 | /** 62 | * 设置防盗链请求的http方法 63 | * @param method 要设置的防盗链请求的http方法 64 | * @return 对象本身,可以链式调用 65 | */ 66 | public SecurityUrl setMethod(String method) { 67 | this.method = method; 68 | return this; 69 | } 70 | 71 | /** 72 | * 获取防盗链请求的http方法 73 | * @return 防盗链请求的http方法,默认是"GET" 74 | */ 75 | public String getMethod() { 76 | return method; 77 | } 78 | 79 | /** 80 | * 为防盗链请求添加自定义header 81 | * @param header header的名字,如"User-Agent"、"Authorization" 82 | * @param value header的值 83 | * @return 对象本身,可以链式调用 84 | */ 85 | public SecurityUrl addHeader(String header, String value) { 86 | headers.put(header, value); 87 | return this; 88 | } 89 | 90 | /** 91 | * 获取所有自定义的防盗链请求的请求头 92 | * @return 所有自定义的防盗链请求的请求头 93 | */ 94 | public HashMap getHeaders() { 95 | return headers; 96 | } 97 | 98 | /** 99 | * 将设置好的防盗链请求以json格式序列化 100 | * @return 防盗链请求以json格式序列化的字符串 101 | */ 102 | public String toString() { 103 | try { 104 | JSONObject obj = new JSONObject(); 105 | obj.put("url", url); 106 | obj.put("method", method); 107 | 108 | JSONObject headersObj = new JSONObject(); 109 | Iterator iter = headers.entrySet().iterator(); 110 | while (iter.hasNext()) { 111 | Map.Entry entry = (Map.Entry) iter.next(); 112 | String headerName = (String) entry.getKey(); 113 | String headerValue = (String) entry.getValue(); 114 | headersObj.put(headerName, headerValue); 115 | } 116 | obj.put("headers", headersObj); 117 | 118 | return obj.toString(); 119 | } catch (Exception e) { 120 | e.printStackTrace(); 121 | } 122 | 123 | return null; 124 | } 125 | 126 | } 127 | -------------------------------------------------------------------------------- /libp2pimpl/src/main/java/com/vbyte/p2p/UrlGenerator.java: -------------------------------------------------------------------------------- 1 | package com.vbyte.p2p; 2 | 3 | /** 4 | * Created by passion on 16-12-20. 5 | */ 6 | 7 | public interface UrlGenerator { 8 | 9 | /** 10 | * 防盗链请求策略的实现 11 | * @param sourceId 点播资源的id 12 | * @return 防盗链请求结果 13 | */ 14 | SecurityUrl createSecurityUrl(String sourceId); 15 | } 16 | -------------------------------------------------------------------------------- /libp2pimpl/src/main/java/com/vbyte/update/DynamicLibManager.java: -------------------------------------------------------------------------------- 1 | package com.vbyte.update; 2 | 3 | import android.content.Context; 4 | import android.content.pm.PackageInfo; 5 | import android.content.pm.PackageManager; 6 | 7 | import org.json.JSONObject; 8 | 9 | import java.io.BufferedInputStream; 10 | import java.io.BufferedReader; 11 | import java.io.File; 12 | import java.io.FileFilter; 13 | import java.io.InputStreamReader; 14 | import java.io.RandomAccessFile; 15 | import java.net.HttpURLConnection; 16 | import java.net.URL; 17 | import java.util.Locale; 18 | 19 | /** 20 | * Created by passion on 16-9-20. 21 | */ 22 | public class DynamicLibManager { 23 | private static final String UPDATE_HOST = "http://update.qvb.qcloud.com/checkupdate"; 24 | 25 | private Context context; 26 | private String libDirPath; 27 | private static String jniVersion = "v2"; 28 | 29 | public DynamicLibManager(Context context) { 30 | this.context = context; 31 | libDirPath = context.getFilesDir().getAbsolutePath() + File.separator + "vlib"; 32 | } 33 | 34 | public String locate(final String fileid) throws Exception { 35 | // 删掉不必要的之前app版本的文件夹 36 | File libDir = new File(libDirPath); 37 | if (!libDir.exists()) { 38 | libDir.mkdirs(); 39 | } 40 | final String appVersion = getAppVersion(); 41 | File[] dirs = libDir.listFiles(new FileFilter() { 42 | @Override 43 | public boolean accept(File file) { 44 | return file.isDirectory() && !file.getName().equals(appVersion); 45 | } 46 | }); 47 | for (File dir: dirs) { 48 | deleteDir(dir); 49 | } 50 | 51 | String appLibPath = libDirPath + File.separator + getAppVersion() + File.separator + jniVersion; 52 | File appLibDir = new File(appLibPath); 53 | if (!appLibDir.exists()) { 54 | appLibDir.mkdirs(); 55 | } 56 | File destFile = null; 57 | String maxVersion = ""; 58 | for (File file: appLibDir.listFiles(new FileFilter() { 59 | @Override 60 | public boolean accept(File file) { 61 | return (file.getName().startsWith(fileid) && file.getName().endsWith(".so")); 62 | } 63 | })) { 64 | /** 65 | * e.g. 66 | * libp2pmodule_armeabi-v7a_v1.2.0_3a4e2bdc231.so 67 | * libvbyte-v7a_arm64-v8a_V2.2.6_3a4e2bdc231.so 68 | */ 69 | String[] info = file.getName().split("_"); 70 | if (info.length > 2 && info[info.length - 2].compareTo(maxVersion) > 0) { 71 | if (destFile != null) { 72 | destFile.delete(); 73 | } 74 | maxVersion = info[info.length - 2]; 75 | destFile = file; 76 | } 77 | } 78 | return (destFile == null ? null : destFile.getAbsolutePath()); 79 | } 80 | 81 | public void checkUpdate(final String fileId, final String version, final String abi) { 82 | new Thread(new Runnable() { 83 | @Override 84 | public void run() { 85 | try { 86 | String token = MD5Util.MD5((fileId + "ventureinc").getBytes()); 87 | StringBuffer sb = new StringBuffer(); 88 | sb.append(UPDATE_HOST) 89 | .append("?fileId=").append(fileId) 90 | .append("&abi=").append(abi) 91 | .append("&fifoVersion=").append(version) 92 | .append("&token=").append(token) 93 | .append("&jniVersion=").append(jniVersion) 94 | .append("&packageName=").append(context.getPackageName()); 95 | URL url = new URL(sb.toString()); 96 | HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 97 | conn.setConnectTimeout(30_000); 98 | conn.setReadTimeout(10_000); 99 | conn.setRequestMethod("GET"); 100 | if (conn.getResponseCode() == 200) { 101 | BufferedReader input = new BufferedReader(new InputStreamReader( 102 | conn.getInputStream())); 103 | String jsonStr = ""; 104 | String line; 105 | while ((line = input.readLine()) != null) { 106 | jsonStr += line; 107 | } 108 | 109 | JSONObject jsonObj = new JSONObject(jsonStr); 110 | boolean needUpdate = jsonObj.getBoolean("update"); 111 | if (needUpdate) { 112 | // 此时需要更新 113 | String downloadUrl = jsonObj.getString("downloadUrl"); 114 | String newVersion = jsonObj.getString("version"); 115 | String fingerprint = jsonObj.getString("md5token"); 116 | updateDynamicLib(fileId, downloadUrl, newVersion, abi, fingerprint); 117 | } 118 | } 119 | } catch (Exception e) { 120 | e.printStackTrace(); 121 | } 122 | } 123 | 124 | private void updateDynamicLib(String fileId, String downloadUrl, String newVersion, 125 | String abi, String fingerprint) throws Exception { 126 | // vlib/7.0.3/libp2pmodule_armeabi-v7a_v1.2.0_3a4e2bdc231.tmp 127 | String tmpFileName = fileId + "_" + abi + "_" + newVersion + "_" + fingerprint + ".tmp"; 128 | String tmpDirPath = libDirPath + File.separator + getAppVersion() + File.separator + jniVersion; 129 | File tmpDir = new File(tmpDirPath); 130 | // 删除无用的tmp文件 131 | for (File file: tmpDir.listFiles(new FileFilter() { 132 | @Override 133 | public boolean accept(File file) { 134 | return file.getName().endsWith(".tmp"); 135 | } 136 | })) { 137 | if (!file.getName().equals(tmpFileName)) { 138 | file.delete(); 139 | } 140 | } 141 | 142 | // 开始能断点式地下载 143 | String tmpFilePath = tmpDirPath + File.separator + tmpFileName; 144 | File tmpFile = new File(tmpFilePath); 145 | if (!tmpFile.exists()) { 146 | tmpFile.createNewFile(); 147 | } 148 | long finishedSize = tmpFile.length(); 149 | 150 | URL url = new URL(downloadUrl); 151 | HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 152 | conn.setConnectTimeout(30_000); 153 | conn.setReadTimeout(30_000); 154 | conn.setRequestMethod("GET"); 155 | conn.setRequestProperty("Range", "bytes=" + finishedSize + "-"); 156 | if (conn.getResponseCode() == 206 || conn.getResponseCode() == 200) { 157 | BufferedInputStream bis = new BufferedInputStream(conn.getInputStream()); 158 | RandomAccessFile raf = new RandomAccessFile(tmpFile, "rw"); 159 | try { 160 | byte[] bytes = new byte[1024]; 161 | int count; 162 | while ((count = bis.read(bytes)) != -1) { 163 | raf.seek(finishedSize); 164 | raf.write(bytes, 0, count); 165 | finishedSize += count; 166 | } 167 | 168 | // 对比指纹是否正确 169 | String md5sum = MD5Util.MD5(tmpFile); 170 | if (md5sum.toLowerCase(Locale.US).equals(fingerprint.toLowerCase())) { 171 | String filePath = libDirPath + File.separator + getAppVersion() + File.separator + jniVersion 172 | + File.separator + fileId + "_" + abi + "_" 173 | + newVersion + "_" + fingerprint + ".so"; 174 | tmpFile.renameTo(new File(filePath)); 175 | } 176 | tmpFile.delete(); 177 | } finally { 178 | raf.close(); 179 | bis.close(); 180 | } 181 | } 182 | } 183 | }).start(); 184 | } 185 | 186 | private String getAppVersion () throws Exception { 187 | PackageManager packageManager = context.getPackageManager(); 188 | PackageInfo packInfo = packageManager.getPackageInfo(context.getPackageName(), 0); 189 | String version = packInfo.versionName; 190 | return version; 191 | } 192 | 193 | private boolean deleteDir(File dir) { 194 | if (dir.isDirectory()) { 195 | String[] children = dir.list(); 196 | for (int i = 0; i < children.length; i++) { 197 | boolean success = deleteDir(new File(dir, children[i])); 198 | if (!success) { 199 | return false; 200 | } 201 | } 202 | } 203 | return dir.delete(); 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /libp2pimpl/src/main/java/com/vbyte/update/MD5Util.java: -------------------------------------------------------------------------------- 1 | package com.vbyte.update; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.File; 5 | import java.io.FileInputStream; 6 | import java.io.FileNotFoundException; 7 | import java.io.IOException; 8 | import java.security.MessageDigest; 9 | 10 | public class MD5Util { 11 | 12 | public final static String MD5(byte[] bytes) { 13 | char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 14 | 'A', 'B', 'C', 'D', 'E', 'F' }; 15 | try { 16 | byte[] btInput = bytes; 17 | MessageDigest mdInst = MessageDigest.getInstance("MD5"); 18 | mdInst.update(btInput); 19 | byte[] md = mdInst.digest(); 20 | int j = md.length; 21 | char str[] = new char[j * 2]; 22 | int k = 0; 23 | for (int i = 0; i < j; i++) { 24 | byte byte0 = md[i]; 25 | str[k++] = hexDigits[byte0 >>> 4 & 0xf]; 26 | str[k++] = hexDigits[byte0 & 0xf]; 27 | } 28 | return new String(str); 29 | } catch (Exception e) { 30 | e.printStackTrace(); 31 | return null; 32 | } 33 | } 34 | 35 | public final static String MD5(File file) { 36 | String res = null; 37 | FileInputStream fileInputStream = null; 38 | ByteArrayOutputStream outStream = new ByteArrayOutputStream(); 39 | try { 40 | fileInputStream = new FileInputStream(file); 41 | byte[] buffer = new byte[8192]; 42 | int length; 43 | while ((length = fileInputStream.read(buffer)) != -1) { 44 | outStream.write(buffer, 0, length); 45 | } 46 | res = MD5(outStream.toByteArray()); 47 | } catch (FileNotFoundException e) { 48 | e.printStackTrace(); 49 | return null; 50 | } catch (IOException e) { 51 | e.printStackTrace(); 52 | return null; 53 | } finally { 54 | try { 55 | if (fileInputStream != null) { 56 | fileInputStream.close(); 57 | } 58 | if (outStream != null) { 59 | outStream.close(); 60 | } 61 | } catch (IOException e) { 62 | e.printStackTrace(); 63 | } 64 | } 65 | return res; 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /libp2pimpl/src/main/jniLibs/arm64-v8a/libevent.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vbytes/libp2pimpl-android/9ee431402abdb51448a55fcda17c5e294a1fc869/libp2pimpl/src/main/jniLibs/arm64-v8a/libevent.so -------------------------------------------------------------------------------- /libp2pimpl/src/main/jniLibs/arm64-v8a/libp2pmodule.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vbytes/libp2pimpl-android/9ee431402abdb51448a55fcda17c5e294a1fc869/libp2pimpl/src/main/jniLibs/arm64-v8a/libp2pmodule.so -------------------------------------------------------------------------------- /libp2pimpl/src/main/jniLibs/arm64-v8a/libstun.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vbytes/libp2pimpl-android/9ee431402abdb51448a55fcda17c5e294a1fc869/libp2pimpl/src/main/jniLibs/arm64-v8a/libstun.so -------------------------------------------------------------------------------- /libp2pimpl/src/main/jniLibs/armeabi-v7a/libevent.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vbytes/libp2pimpl-android/9ee431402abdb51448a55fcda17c5e294a1fc869/libp2pimpl/src/main/jniLibs/armeabi-v7a/libevent.so -------------------------------------------------------------------------------- /libp2pimpl/src/main/jniLibs/armeabi-v7a/libp2pmodule.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vbytes/libp2pimpl-android/9ee431402abdb51448a55fcda17c5e294a1fc869/libp2pimpl/src/main/jniLibs/armeabi-v7a/libp2pmodule.so -------------------------------------------------------------------------------- /libp2pimpl/src/main/jniLibs/armeabi-v7a/libstun.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vbytes/libp2pimpl-android/9ee431402abdb51448a55fcda17c5e294a1fc869/libp2pimpl/src/main/jniLibs/armeabi-v7a/libstun.so -------------------------------------------------------------------------------- /libp2pimpl/src/main/jniLibs/armeabi/libevent.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vbytes/libp2pimpl-android/9ee431402abdb51448a55fcda17c5e294a1fc869/libp2pimpl/src/main/jniLibs/armeabi/libevent.so -------------------------------------------------------------------------------- /libp2pimpl/src/main/jniLibs/armeabi/libp2pmodule.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vbytes/libp2pimpl-android/9ee431402abdb51448a55fcda17c5e294a1fc869/libp2pimpl/src/main/jniLibs/armeabi/libp2pmodule.so -------------------------------------------------------------------------------- /libp2pimpl/src/main/jniLibs/armeabi/libstun.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vbytes/libp2pimpl-android/9ee431402abdb51448a55fcda17c5e294a1fc869/libp2pimpl/src/main/jniLibs/armeabi/libstun.so -------------------------------------------------------------------------------- /libp2pimpl/src/main/jniLibs/x86/libevent.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vbytes/libp2pimpl-android/9ee431402abdb51448a55fcda17c5e294a1fc869/libp2pimpl/src/main/jniLibs/x86/libevent.so -------------------------------------------------------------------------------- /libp2pimpl/src/main/jniLibs/x86/libp2pmodule.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vbytes/libp2pimpl-android/9ee431402abdb51448a55fcda17c5e294a1fc869/libp2pimpl/src/main/jniLibs/x86/libp2pmodule.so -------------------------------------------------------------------------------- /libp2pimpl/src/main/jniLibs/x86/libstun.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vbytes/libp2pimpl-android/9ee431402abdb51448a55fcda17c5e294a1fc869/libp2pimpl/src/main/jniLibs/x86/libstun.so -------------------------------------------------------------------------------- /libp2pimpl/src/main/jniLibs/x86_64/libevent.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vbytes/libp2pimpl-android/9ee431402abdb51448a55fcda17c5e294a1fc869/libp2pimpl/src/main/jniLibs/x86_64/libevent.so -------------------------------------------------------------------------------- /libp2pimpl/src/main/jniLibs/x86_64/libp2pmodule.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vbytes/libp2pimpl-android/9ee431402abdb51448a55fcda17c5e294a1fc869/libp2pimpl/src/main/jniLibs/x86_64/libp2pmodule.so -------------------------------------------------------------------------------- /libp2pimpl/src/main/jniLibs/x86_64/libstun.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vbytes/libp2pimpl-android/9ee431402abdb51448a55fcda17c5e294a1fc869/libp2pimpl/src/main/jniLibs/x86_64/libstun.so -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':libp2pimpl' 2 | --------------------------------------------------------------------------------