├── .gitattributes ├── .gitignore ├── .idea ├── .name ├── codeStyles │ └── Project.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── liar │ │ └── testrecorder │ │ ├── App.java │ │ ├── config │ │ └── Constant.java │ │ ├── event │ │ └── RecorderEvent.java │ │ ├── recorder │ │ ├── RecordHelper.java │ │ ├── RecordManager.java │ │ ├── RecordService.java │ │ ├── listener │ │ │ └── RecordStateListener.java │ │ └── mp3 │ │ │ └── Mp3EncodeThread.java │ │ ├── ui │ │ ├── MainActivity.java │ │ ├── SplashActivity.java │ │ └── dialog │ │ │ ├── CheckDialog.java │ │ │ └── InputFileNameDialog.java │ │ ├── utils │ │ ├── NotificationPermissionUtil.java │ │ ├── TimeUtils.java │ │ ├── crash │ │ │ └── CrashHandler.java │ │ ├── download │ │ │ ├── DownloadListener.java │ │ │ └── Downloader.java │ │ ├── file │ │ │ ├── FileManager.java │ │ │ └── FileUtils.java │ │ └── sp │ │ │ ├── SharedPreferencesUtils.java │ │ │ ├── SpConfig.java │ │ │ └── SpManager.java │ │ └── widget │ │ └── AudioView.java │ └── res │ ├── drawable-hdpi │ ├── ic_launcher.png │ ├── ic_launcher_round.png │ ├── icon_pause.png │ ├── icon_start_record.png │ └── icon_stop_record.png │ ├── drawable-mdpi │ ├── ic_launcher.png │ ├── ic_launcher_round.png │ ├── icon_pause.png │ ├── icon_start_record.png │ └── icon_stop_record.png │ ├── drawable-v24 │ └── ic_launcher_foreground.xml │ ├── drawable-xhdpi │ ├── ic_launcher.png │ ├── ic_launcher_round.png │ ├── icon_pause.png │ ├── icon_start_record.png │ └── icon_stop_record.png │ ├── drawable-xxhdpi │ ├── ic_launcher.png │ ├── ic_launcher_round.png │ ├── icon_pause.png │ ├── icon_start_record.png │ └── icon_stop_record.png │ ├── drawable-xxxhdpi │ ├── ic_launcher.png │ ├── ic_launcher_round.png │ ├── icon_pause.png │ ├── icon_start_record.png │ └── icon_stop_record.png │ ├── drawable │ ├── bg_circle_white.xml │ ├── bg_flag_radius_white.xml │ ├── gray_round_bg.xml │ ├── ic_launcher_background.xml │ └── shape_flag_notification_btn.xml │ ├── layout │ ├── activity_main.xml │ ├── activity_splash_layout.xml │ ├── dialog_check_layout.xml │ ├── dialog_input_filename.xml │ └── view_remote_notification.xml │ ├── values │ ├── colors.xml │ ├── strings.xml │ └── styles.xml │ └── xml │ └── file_provider_paths.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── recorderlib ├── .gitignore ├── build.gradle ├── libs │ ├── arm64-v8a │ │ └── libmp3lame.so │ ├── armeabi-v7a │ │ └── libmp3lame.so │ ├── armeabi │ │ └── libmp3lame.so │ ├── mips │ │ └── libmp3lame.so │ ├── mips64 │ │ └── libmp3lame.so │ ├── x86 │ │ └── libmp3lame.so │ └── x86_64 │ │ └── libmp3lame.so ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ ├── com │ │ └── zlw │ │ │ └── main │ │ │ └── recorderlib │ │ │ ├── RecordManager.java │ │ │ ├── recorder │ │ │ ├── RecordConfig.java │ │ │ ├── RecordHelper.java │ │ │ ├── RecordService.java │ │ │ ├── listener │ │ │ │ ├── RecordDataListener.java │ │ │ │ ├── RecordFftDataListener.java │ │ │ │ ├── RecordResultListener.java │ │ │ │ ├── RecordSoundSizeListener.java │ │ │ │ └── RecordStateListener.java │ │ │ ├── mp3 │ │ │ │ ├── Mp3EncodeThread.java │ │ │ │ ├── Mp3Encoder.java │ │ │ │ └── Mp3Utils.java │ │ │ └── wav │ │ │ │ └── WavUtils.java │ │ │ └── utils │ │ │ ├── ByteUtils.java │ │ │ ├── FileUtils.java │ │ │ ├── Logger.java │ │ │ └── RecordUtils.java │ └── fftlib │ │ ├── ByteUtils.java │ │ ├── Complex.java │ │ ├── FFT.java │ │ └── FftFactory.java │ ├── jni │ ├── Android.mk │ ├── Application.mk │ ├── Mp3Encoder.c │ ├── Mp3Encoder.h │ └── lame-3.100_libmp3lame │ │ ├── VbrTag.c │ │ ├── VbrTag.h │ │ ├── bitstream.c │ │ ├── bitstream.h │ │ ├── encoder.c │ │ ├── encoder.h │ │ ├── fft.c │ │ ├── fft.h │ │ ├── gain_analysis.c │ │ ├── gain_analysis.h │ │ ├── id3tag.c │ │ ├── id3tag.h │ │ ├── l3side.h │ │ ├── lame-analysis.h │ │ ├── lame.c │ │ ├── lame.h │ │ ├── lame_global_flags.h │ │ ├── lameerror.h │ │ ├── machine.h │ │ ├── mpglib_interface.c │ │ ├── newmdct.c │ │ ├── newmdct.h │ │ ├── presets.c │ │ ├── psymodel.c │ │ ├── psymodel.h │ │ ├── quantize.c │ │ ├── quantize.h │ │ ├── quantize_pvt.c │ │ ├── quantize_pvt.h │ │ ├── reservoir.c │ │ ├── reservoir.h │ │ ├── set_get.c │ │ ├── set_get.h │ │ ├── tables.c │ │ ├── tables.h │ │ ├── takehiro.c │ │ ├── util.c │ │ ├── util.h │ │ ├── vbrquantize.c │ │ ├── vbrquantize.h │ │ ├── version.c │ │ └── version.h │ └── res │ └── values │ └── strings.xml └── settings.gradle /.gitattributes: -------------------------------------------------------------------------------- 1 | *.css linguist-language=java  2 | *.js linguist-language=java 3 | *.html linguist-language=java 4 | *.c linguist-language=java -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | TestRecorder -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 | 8 | 9 | 10 | xmlns:android 11 | 12 | ^$ 13 | 14 | 15 | 16 |
17 |
18 | 19 | 20 | 21 | xmlns:.* 22 | 23 | ^$ 24 | 25 | 26 | BY_NAME 27 | 28 |
29 |
30 | 31 | 32 | 33 | .*:id 34 | 35 | http://schemas.android.com/apk/res/android 36 | 37 | 38 | 39 |
40 |
41 | 42 | 43 | 44 | .*:name 45 | 46 | http://schemas.android.com/apk/res/android 47 | 48 | 49 | 50 |
51 |
52 | 53 | 54 | 55 | name 56 | 57 | ^$ 58 | 59 | 60 | 61 |
62 |
63 | 64 | 65 | 66 | style 67 | 68 | ^$ 69 | 70 | 71 | 72 |
73 |
74 | 75 | 76 | 77 | .* 78 | 79 | ^$ 80 | 81 | 82 | BY_NAME 83 | 84 |
85 |
86 | 87 | 88 | 89 | .* 90 | 91 | http://schemas.android.com/apk/res/android 92 | 93 | 94 | ANDROID_ATTRIBUTE_ORDER 95 | 96 |
97 |
98 | 99 | 100 | 101 | .* 102 | 103 | .* 104 | 105 | 106 | BY_NAME 107 | 108 |
109 |
110 |
111 |
112 |
113 |
-------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 20 | 21 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 41 | 42 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | Android 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 105 | 106 | 107 | 108 | 109 | 1.8 110 | 111 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 127 | 128 | 129 | 130 | 131 | 132 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TestRecorder 2 | 3 | 安卓 录音功能的Demo,实现了APP在后台和手机息屏长时间录音的功能(在Android9.0和Android 10.0手机测试通过)。 4 | 5 | 录音功能 用了zhaolewei大佬的源码,源码地址:https://github.com/zhaolewei/ZlwAudioRecorder 6 | 7 | 项目框架用的是Lodz大佬的AgileDev,源码地址:https://github.com/LZ9/AgileDev 8 | 9 | 10 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 11 | 2020.05.29 更新 12 | 这次提交解决了Android 9.0系统和Android 10.0系统禁止闲置APP在后台和息屏使用麦克风的问题。 13 | 14 | 思路: 15 | 系统只对后台闲置服务进行闲置,不让后台服务偷偷使用麦克风。目前Android9.0的前台服务中,必须弹出一个通知,告知用户,某个前台服务正在运行。那么只要把后台服务RecordService改成前台服务,就可以解决这个问题。 16 | 17 | 操作: 18 | 1.迁移了录音库recorderlib的部分文件:RecordService,RecordManager,RecordHelper,Mp3EncodeThread,RecordStateListener。 19 | 20 | 2.将录音服务RecordService转成前台服务(将录音通知栏Notification相关代码和迁移到RecordService里,添加后台服务转成前台服务的代码:startForeground(NOTIFI_RECORDER_ID,notification); 21 | 22 | 缺陷: 23 | 此次代码还不完善:通知栏暂停录音和继续录音功能未完成,录音主页MainActivity的线程UI更新录音时间相关代码还未修改,预计改为在RecordService发送eventbus更新MainActivity的UI,减少性能损耗。 24 | 25 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 26 | 2020.05.30 更新 27 | 通知栏暂停录音和继续录音功能完成 28 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android-extensions' 3 | apply plugin: 'kotlin-android' 4 | 5 | android { 6 | compileSdkVersion 29 7 | buildToolsVersion "29.0.3" 8 | 9 | defaultConfig { 10 | applicationId "com.liar.testrecorder" 11 | minSdkVersion 19 12 | targetSdkVersion 29 13 | versionCode 1 14 | versionName "1.0" 15 | multiDexEnabled = true// 启用dex分包 16 | 17 | } 18 | 19 | compileOptions { 20 | sourceCompatibility JavaVersion.VERSION_1_8 21 | targetCompatibility JavaVersion.VERSION_1_8 22 | } 23 | 24 | //日志开关 25 | def LOG_DEBUG = "LOG_DEBUG" 26 | defaultConfig { 27 | buildConfigField "boolean", LOG_DEBUG, "true" 28 | } 29 | 30 | buildTypes { 31 | release { 32 | minifyEnabled false 33 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 34 | } 35 | } 36 | 37 | } 38 | 39 | dependencies { 40 | //录音 41 | implementation project(path: ':recorderlib') 42 | 43 | // 权限申请 44 | implementation 'org.permissionsdispatcher:permissionsdispatcher:4.7.0' 45 | annotationProcessor 'org.permissionsdispatcher:permissionsdispatcher-processor:4.7.0' 46 | 47 | // 组件库 48 | implementation 'cn.lodz:Component:2.1.2' 49 | // butterknife 50 | implementation 'com.jakewharton:butterknife:10.2.1' 51 | annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.1' 52 | // 下载 53 | implementation 'zlc.season:rxdownload2:2.0.4' 54 | //图片加载库 55 | implementation 'cn.lodz:ImagerLoader:2.0.4' 56 | implementation "androidx.core:core-ktx:+" 57 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 58 | 59 | //录音 60 | // implementation 'com.github.zhaolewei:ZlwAudioRecorder:v1.07' 61 | 62 | } 63 | repositories { 64 | mavenCentral() 65 | } 66 | -------------------------------------------------------------------------------- /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 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 30 | 31 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 50 | 51 | 56 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /app/src/main/java/com/liar/testrecorder/App.java: -------------------------------------------------------------------------------- 1 | package com.liar.testrecorder; 2 | 3 | import android.content.Context; 4 | import android.widget.LinearLayout; 5 | 6 | import androidx.multidex.MultiDex; 7 | 8 | import com.liar.testrecorder.utils.file.FileManager; 9 | import com.lodz.android.component.base.application.BaseApplication; 10 | import com.lodz.android.core.cache.ACacheUtils; 11 | import com.lodz.android.core.contract.BackgroundActivityLifecycleCallbacksImpl; 12 | import com.lodz.android.core.log.PrintLog; 13 | import com.lodz.android.core.network.NetworkManager; 14 | import com.lodz.android.core.threadpool.ThreadPoolManager; 15 | import com.lodz.android.core.utils.DensityUtils; 16 | import com.lodz.android.core.utils.UiHandler; 17 | import com.lodz.android.imageloader.ImageloaderManager; 18 | 19 | /** 20 | * application 21 | 22 | */ 23 | 24 | public class App extends BaseApplication { 25 | 26 | private BackgroundActivityLifecycleCallbacksImpl mActivityLifecycleCallbacks; 27 | 28 | public static App getInstance() { 29 | return (App) get(); 30 | } 31 | 32 | @Override 33 | protected void attachBaseContext(Context base) { 34 | super.attachBaseContext(base); 35 | MultiDex.install(this); 36 | } 37 | 38 | @Override 39 | protected void afterCreate() { 40 | // if (LeakCanary.isInAnalyzerProcess(this)) { 41 | // // This process is dedicated to LeakCanary for heap analysis. 42 | // // You should not init your app in this process. 43 | // return; 44 | // } 45 | // LeakCanary.install(this); 46 | FileManager.init(); 47 | PrintLog.setPrint(BuildConfig.LOG_DEBUG);// 配置日志开关 48 | NetworkManager.get().init(this);// 初始化网络管理 49 | initImageLoader(); 50 | initACache(); 51 | configBaseLayout(); 52 | mActivityLifecycleCallbacks = new BackgroundActivityLifecycleCallbacksImpl(); 53 | registerActivityLifecycleCallbacks(mActivityLifecycleCallbacks); 54 | } 55 | 56 | /** 初始化缓存类 */ 57 | private void initACache() { 58 | ACacheUtils.get().newBuilder() 59 | .setCacheDir(this.getApplicationContext().getCacheDir().getAbsolutePath()) 60 | .build(this); 61 | } 62 | 63 | /** 配置基类 */ 64 | private void configBaseLayout() { 65 | configTitleBarLayout(); 66 | configErrorLayout(); 67 | configLoadingLayout(); 68 | configNoDataLayout(); 69 | } 70 | 71 | /** 配置无数据 */ 72 | private void configNoDataLayout() { 73 | getBaseLayoutConfig().getNoDataLayoutConfig().setOrientation(LinearLayout.HORIZONTAL); 74 | getBaseLayoutConfig().getNoDataLayoutConfig().setNeedImg(true); 75 | getBaseLayoutConfig().getNoDataLayoutConfig().setNeedTips(false); 76 | // getBaseLayoutConfig().getNoDataLayoutConfig().setImg(R.drawable.ic_launcher); 77 | // getBaseLayoutConfig().getNoDataLayoutConfig().setTips(getString(R.string.config_base_no_data_tips)); 78 | // getBaseLayoutConfig().getNoDataLayoutConfig().setTipsTextColor(R.color.color_ffa630); 79 | // getBaseLayoutConfig().getNoDataLayoutConfig().setTipsTextSize(22); 80 | // getBaseLayoutConfig().getNoDataLayoutConfig().setBackgroundColor(R.color.color_ea8380); 81 | } 82 | 83 | /** 配置加载页 */ 84 | private void configLoadingLayout() { 85 | getBaseLayoutConfig().getLoadingLayoutConfig().setOrientation(LinearLayout.HORIZONTAL); 86 | getBaseLayoutConfig().getLoadingLayoutConfig().setNeedTips(true); 87 | // getBaseLayoutConfig().getLoadingLayoutConfig().setTips(getString(R.string.config_base_loading_tips)); 88 | // getBaseLayoutConfig().getLoadingLayoutConfig().setTipsTextColor(R.color.white); 89 | // getBaseLayoutConfig().getLoadingLayoutConfig().setTipsTextSize(15); 90 | // getBaseLayoutConfig().getLoadingLayoutConfig().setBackgroundColor(R.color.color_ff4081); 91 | getBaseLayoutConfig().getLoadingLayoutConfig().setIsIndeterminate(true); 92 | // getBaseLayoutConfig().getLoadingLayoutConfig().setIndeterminateDrawable(R.drawable.anims_custom_progress); 93 | getBaseLayoutConfig().getLoadingLayoutConfig().setPbWidth(DensityUtils.dp2px(this, 50)); 94 | getBaseLayoutConfig().getLoadingLayoutConfig().setPbHeight(DensityUtils.dp2px(this, 50)); 95 | } 96 | 97 | /** 配置标题栏 */ 98 | private void configTitleBarLayout() { 99 | getBaseLayoutConfig().getTitleBarLayoutConfig().setNeedBackButton(true); 100 | // getBaseLayoutConfig().getTitleBarLayoutConfig().setReplaceBackBtnResId(R.drawable.ic_launcher); 101 | getBaseLayoutConfig().getTitleBarLayoutConfig().setBackgroundColor(R.color.color_00a0e9); 102 | // getBaseLayoutConfig().getTitleBarLayoutConfig().setBackBtnName("返返"); 103 | // getBaseLayoutConfig().getTitleBarLayoutConfig().setBackBtnTextColor(R.color.color_d9d9d9); 104 | // getBaseLayoutConfig().getTitleBarLayoutConfig().setBackBtnTextSize(14); 105 | getBaseLayoutConfig().getTitleBarLayoutConfig().setTitleTextColor(R.color.white); 106 | // getBaseLayoutConfig().getTitleBarLayoutConfig().setTitleTextSize(18); 107 | // getBaseLayoutConfig().getTitleBarLayoutConfig().setIsShowDivideLine(false); 108 | // getBaseLayoutConfig().getTitleBarLayoutConfig().setDivideLineHeight(10); 109 | // getBaseLayoutConfig().getTitleBarLayoutConfig().setDivideLineColor(R.color.color_2f6dc9); 110 | // getBaseLayoutConfig().getTitleBarLayoutConfig().setIsNeedElevation(true); 111 | // getBaseLayoutConfig().getTitleBarLayoutConfig().setElevationVale(13f); 112 | } 113 | 114 | /** 配置错误页 */ 115 | private void configErrorLayout() { 116 | getBaseLayoutConfig().getErrorLayoutConfig().setOrientation(LinearLayout.VERTICAL); 117 | // getBaseLayoutConfig().getErrorLayoutConfig().setImg(R.drawable.ic_launcher); 118 | // getBaseLayoutConfig().getErrorLayoutConfig().setBackgroundColor(R.color.color_ffa630); 119 | getBaseLayoutConfig().getErrorLayoutConfig().setNeedTips(false); 120 | getBaseLayoutConfig().getErrorLayoutConfig().setNeedImg(true); 121 | // getBaseLayoutConfig().getErrorLayoutConfig().setTips(getString(R.string.config_base_fail_tips)); 122 | // getBaseLayoutConfig().getErrorLayoutConfig().setTipsTextColor(R.color.color_ea413c); 123 | // getBaseLayoutConfig().getErrorLayoutConfig().setTipsTextSize(18); 124 | } 125 | 126 | /** 初始化图片加载库 */ 127 | private void initImageLoader() { 128 | ImageloaderManager.get().newBuilder() 129 | .setPlaceholderResId(R.drawable.ic_launcher)//设置默认占位符 130 | .setErrorResId(R.drawable.ic_launcher)// 设置加载失败图 131 | .setDirectoryFile(this.getApplicationContext().getCacheDir()) 132 | .setDirectoryName("image_cache") 133 | .build(); 134 | } 135 | 136 | /** 应用是否在后台 */ 137 | public boolean isBackground(){ 138 | return mActivityLifecycleCallbacks.isBackground(); 139 | } 140 | 141 | @Override 142 | protected void beforeExit() { 143 | ImageloaderManager.get().clearMemoryCachesWithGC(this);// 退出时清除图片缓存 144 | UiHandler.destroy(); 145 | NetworkManager.get().release(this);// 释放网络管理资源 146 | NetworkManager.get().clearNetworkListener();// 清除所有网络监听器 147 | ThreadPoolManager.get().releaseAll(); 148 | unregisterActivityLifecycleCallbacks(mActivityLifecycleCallbacks); 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /app/src/main/java/com/liar/testrecorder/config/Constant.java: -------------------------------------------------------------------------------- 1 | package com.liar.testrecorder.config; 2 | 3 | /** 4 | * Created by LiarShi on 2020/5/29. 5 | */ 6 | public class Constant { 7 | 8 | 9 | /** 通知组配置 */ 10 | 11 | /** 通知组id */ 12 | public static final String NOTIFI_GROUP_ID = "g0001"; 13 | 14 | /** 主频道id */ 15 | public static final String NOTIFI_CHANNEL_MAIN_ID = "c0001"; 16 | 17 | /** 常驻消息栏ID */ 18 | public static final int NOTIFI_RECORDER_ID = 12345; 19 | 20 | public static final String EXTRA_MSG_DATA = "extra_msg_data"; 21 | 22 | /** 通知栏完成录音 id */ 23 | public static final String NOTIFI_FINISH_MSG = "NOTIFI_FINISH_MSG"; 24 | 25 | 26 | //通知栏 暂停录音 恢复录音 ID 27 | /** 通知栏 暂停录音 恢复录音 ID */ 28 | public static final String NOTIFICATION_START_ID="NOTIFICATION_START_ID"; 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/com/liar/testrecorder/event/RecorderEvent.java: -------------------------------------------------------------------------------- 1 | package com.liar.testrecorder.event; 2 | 3 | /** 4 | * Created by LiarShi on 2020/5/29. 5 | * 暂停录音和继续录音 eventbus 6 | */ 7 | public class RecorderEvent { 8 | 9 | //声音分贝 10 | public String type=""; 11 | 12 | //声音分贝 13 | public int soundSize = 0; 14 | 15 | //录音时长 16 | public long timeCounter = 0L; 17 | 18 | public RecorderEvent(String type,int mSoundSize, long timeCounter) { 19 | this.type = type; 20 | this.soundSize = mSoundSize; 21 | this.timeCounter = timeCounter; 22 | } 23 | 24 | 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/liar/testrecorder/recorder/RecordManager.java: -------------------------------------------------------------------------------- 1 | package com.liar.testrecorder.recorder; 2 | 3 | 4 | import android.annotation.SuppressLint; 5 | import android.app.Application; 6 | 7 | import com.liar.testrecorder.recorder.listener.RecordStateListener; 8 | import com.zlw.main.recorderlib.recorder.RecordConfig; 9 | import com.zlw.main.recorderlib.recorder.listener.RecordDataListener; 10 | import com.zlw.main.recorderlib.recorder.listener.RecordFftDataListener; 11 | import com.zlw.main.recorderlib.recorder.listener.RecordResultListener; 12 | import com.zlw.main.recorderlib.recorder.listener.RecordSoundSizeListener; 13 | import com.zlw.main.recorderlib.utils.Logger; 14 | 15 | /** 16 | * @author zhaolewei on 2018/7/10. 17 | */ 18 | public class RecordManager { 19 | private static final String TAG = RecordManager.class.getSimpleName(); 20 | @SuppressLint("StaticFieldLeak") 21 | private volatile static RecordManager instance; 22 | private Application context; 23 | 24 | private RecordManager() { 25 | } 26 | 27 | public static RecordManager getInstance() { 28 | if (instance == null) { 29 | synchronized (RecordManager.class) { 30 | if (instance == null) { 31 | instance = new RecordManager(); 32 | } 33 | } 34 | } 35 | return instance; 36 | } 37 | 38 | /** 39 | * 初始化 40 | * 41 | * @param application Application 42 | * @param showLog 是否开启日志 43 | */ 44 | public void init(Application application, boolean showLog) { 45 | this.context = application; 46 | Logger.IsDebug = showLog; 47 | } 48 | 49 | public void start() { 50 | if (context == null) { 51 | Logger.e(TAG, "未进行初始化"); 52 | return; 53 | } 54 | Logger.i(TAG, "start..."); 55 | RecordService.startRecording(context); 56 | } 57 | 58 | public void stop() { 59 | if (context == null) { 60 | return; 61 | } 62 | RecordService.stopRecording(context); 63 | } 64 | 65 | public void resume() { 66 | if (context == null) { 67 | return; 68 | } 69 | RecordService.resumeRecording(context); 70 | } 71 | 72 | public void pause() { 73 | if (context == null) { 74 | return; 75 | } 76 | RecordService.pauseRecording(context); 77 | } 78 | 79 | /** 80 | * 录音状态监听回调 81 | */ 82 | public void setRecordStateListener(RecordStateListener listener) { 83 | RecordService.setRecordStateListener(listener); 84 | } 85 | 86 | /** 87 | * 录音数据监听回调 88 | */ 89 | public void setRecordDataListener(RecordDataListener listener) { 90 | RecordService.setRecordDataListener(listener); 91 | } 92 | 93 | /** 94 | * 录音可视化数据回调,傅里叶转换后的频域数据 95 | */ 96 | public void setRecordFftDataListener(RecordFftDataListener recordFftDataListener) { 97 | RecordService.setRecordFftDataListener(recordFftDataListener); 98 | } 99 | 100 | /** 101 | * 录音文件转换结束回调 102 | */ 103 | public void setRecordResultListener(RecordResultListener listener) { 104 | RecordService.setRecordResultListener(listener); 105 | } 106 | 107 | /** 108 | * 录音音量监听回调 109 | */ 110 | public void setRecordSoundSizeListener(RecordSoundSizeListener listener) { 111 | RecordService.setRecordSoundSizeListener(listener); 112 | } 113 | 114 | 115 | public boolean changeFormat(RecordConfig.RecordFormat recordFormat) { 116 | return RecordService.changeFormat(recordFormat); 117 | } 118 | 119 | 120 | public boolean changeRecordConfig(RecordConfig recordConfig) { 121 | return RecordService.changeRecordConfig(recordConfig); 122 | } 123 | 124 | public RecordConfig getRecordConfig() { 125 | return RecordService.getRecordConfig(); 126 | } 127 | 128 | /** 129 | * 修改录音文件存放路径 130 | */ 131 | public void changeRecordDir(String recordDir) { 132 | RecordService.changeRecordDir(recordDir); 133 | } 134 | 135 | /** 136 | * 获取当前的录音状态 137 | * 138 | * @return 状态 139 | */ 140 | public RecordHelper.RecordState getState() { 141 | return RecordService.getState(); 142 | } 143 | 144 | } 145 | -------------------------------------------------------------------------------- /app/src/main/java/com/liar/testrecorder/recorder/listener/RecordStateListener.java: -------------------------------------------------------------------------------- 1 | package com.liar.testrecorder.recorder.listener; 2 | 3 | 4 | import com.liar.testrecorder.recorder.RecordHelper; 5 | 6 | /** 7 | * @author zhaolewei on 2018/7/11. 8 | */ 9 | public interface RecordStateListener { 10 | 11 | /** 12 | * 当前的录音状态发生变化 13 | * 14 | * @param state 当前状态 15 | */ 16 | void onStateChange(RecordHelper.RecordState state); 17 | 18 | /** 19 | * 录音错误 20 | * 21 | * @param error 错误 22 | */ 23 | void onError(String error); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/liar/testrecorder/recorder/mp3/Mp3EncodeThread.java: -------------------------------------------------------------------------------- 1 | package com.liar.testrecorder.recorder.mp3; 2 | 3 | 4 | import com.liar.testrecorder.recorder.RecordService; 5 | import com.zlw.main.recorderlib.recorder.RecordConfig; 6 | import com.zlw.main.recorderlib.recorder.mp3.Mp3Encoder; 7 | import com.zlw.main.recorderlib.utils.Logger; 8 | 9 | import java.io.File; 10 | import java.io.FileNotFoundException; 11 | import java.io.FileOutputStream; 12 | import java.io.IOException; 13 | import java.util.Collections; 14 | import java.util.LinkedList; 15 | import java.util.List; 16 | 17 | /** 18 | * @author zhaolewei on 2018/8/2. 19 | */ 20 | public class Mp3EncodeThread extends Thread { 21 | private static final String TAG = Mp3EncodeThread.class.getSimpleName(); 22 | private List cacheBufferList = Collections.synchronizedList(new LinkedList()); 23 | private File file; 24 | private FileOutputStream os; 25 | private byte[] mp3Buffer; 26 | private EncordFinishListener encordFinishListener; 27 | 28 | /** 29 | * 是否已停止录音 30 | */ 31 | private volatile boolean isOver = false; 32 | 33 | /** 34 | * 是否继续轮询数据队列 35 | */ 36 | private volatile boolean start = true; 37 | 38 | public Mp3EncodeThread(File file, int bufferSize) { 39 | this.file = file; 40 | mp3Buffer = new byte[(int) (7200 + (bufferSize * 2 * 1.25))]; 41 | RecordConfig currentConfig = RecordService.getCurrentConfig(); 42 | int sampleRate = currentConfig.getSampleRate(); 43 | 44 | Logger.w(TAG, "in_sampleRate:%s,getChannelCount:%s ,out_sampleRate:%s 位宽: %s,", 45 | sampleRate, currentConfig.getChannelCount(), sampleRate, currentConfig.getRealEncoding()); 46 | Mp3Encoder.init(sampleRate, currentConfig.getChannelCount(), sampleRate, currentConfig.getRealEncoding()); 47 | } 48 | 49 | @Override 50 | public void run() { 51 | try { 52 | this.os = new FileOutputStream(file); 53 | } catch (FileNotFoundException e) { 54 | Logger.e(e, TAG, e.getMessage()); 55 | return; 56 | } 57 | 58 | while (start) { 59 | ChangeBuffer next = next(); 60 | Logger.v(TAG, "处理数据:%s", next == null ? "null" : next.getReadSize()); 61 | lameData(next); 62 | } 63 | } 64 | 65 | public void addChangeBuffer(ChangeBuffer changeBuffer) { 66 | if (changeBuffer != null) { 67 | cacheBufferList.add(changeBuffer); 68 | synchronized (this) { 69 | notify(); 70 | } 71 | } 72 | } 73 | 74 | public void stopSafe(EncordFinishListener encordFinishListener) { 75 | this.encordFinishListener = encordFinishListener; 76 | isOver = true; 77 | synchronized (this) { 78 | notify(); 79 | } 80 | } 81 | 82 | private ChangeBuffer next() { 83 | for (; ; ) { 84 | if (cacheBufferList == null || cacheBufferList.size() == 0) { 85 | try { 86 | if (isOver) { 87 | finish(); 88 | } 89 | synchronized (this) { 90 | wait(); 91 | } 92 | } catch (Exception e) { 93 | Logger.e(e, TAG, e.getMessage()); 94 | } 95 | } else { 96 | return cacheBufferList.remove(0); 97 | } 98 | } 99 | } 100 | 101 | private void lameData(ChangeBuffer changeBuffer) { 102 | if (changeBuffer == null) { 103 | return; 104 | } 105 | short[] buffer = changeBuffer.getData(); 106 | int readSize = changeBuffer.getReadSize(); 107 | if (readSize > 0) { 108 | int encodedSize = Mp3Encoder.encode(buffer, buffer, readSize, mp3Buffer); 109 | if (encodedSize < 0) { 110 | Logger.e(TAG, "Lame encoded size: " + encodedSize); 111 | } 112 | try { 113 | os.write(mp3Buffer, 0, encodedSize); 114 | } catch (IOException e) { 115 | Logger.e(e, TAG, "Unable to write to file"); 116 | } 117 | } 118 | } 119 | 120 | private void finish() { 121 | start = false; 122 | final int flushResult = Mp3Encoder.flush(mp3Buffer); 123 | if (flushResult > 0) { 124 | try { 125 | os.write(mp3Buffer, 0, flushResult); 126 | os.close(); 127 | } catch (final IOException e) { 128 | Logger.e(TAG, e.getMessage()); 129 | } 130 | } 131 | Logger.d(TAG, "转换结束 :%s", file.length()); 132 | if (encordFinishListener != null) { 133 | encordFinishListener.onFinish(); 134 | } 135 | } 136 | 137 | public static class ChangeBuffer { 138 | private short[] rawData; 139 | private int readSize; 140 | 141 | public ChangeBuffer(short[] rawData, int readSize) { 142 | this.rawData = rawData.clone(); 143 | this.readSize = readSize; 144 | } 145 | 146 | short[] getData() { 147 | return rawData; 148 | } 149 | 150 | int getReadSize() { 151 | return readSize; 152 | } 153 | } 154 | 155 | public interface EncordFinishListener { 156 | /** 157 | * 格式转换完毕 158 | */ 159 | void onFinish(); 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /app/src/main/java/com/liar/testrecorder/ui/dialog/CheckDialog.java: -------------------------------------------------------------------------------- 1 | package com.liar.testrecorder.ui.dialog; 2 | 3 | import android.app.Dialog; 4 | import android.content.Context; 5 | import android.view.View; 6 | import android.widget.TextView; 7 | 8 | import androidx.annotation.NonNull; 9 | import androidx.annotation.StringRes; 10 | 11 | import com.liar.testrecorder.R; 12 | import com.lodz.android.component.widget.dialog.BaseDialog; 13 | 14 | /** 15 | * 核对弹框 16 | * Created by zhouL on 2017/5/19. 17 | */ 18 | 19 | public class CheckDialog extends BaseDialog { 20 | 21 | /** 核对内容 */ 22 | private TextView mContentMsg; 23 | /** 确认按钮 */ 24 | private TextView mPositiveBtn; 25 | /** 取消按钮 */ 26 | private TextView mNegativeBtn; 27 | 28 | private String mContentText; 29 | private String mPositiveText; 30 | private String mNegativeText; 31 | 32 | private Listener mPositiveListener; 33 | private Listener mNegativeListener; 34 | 35 | public CheckDialog(Context context) { 36 | super(context); 37 | } 38 | 39 | @Override 40 | protected int getLayoutId() { 41 | return R.layout.dialog_check_layout; 42 | } 43 | 44 | @Override 45 | protected void findViews() { 46 | mContentMsg = findViewById(R.id.content_msg); 47 | mPositiveBtn = findViewById(R.id.positive_btn); 48 | mNegativeBtn = findViewById(R.id.negative_btn); 49 | } 50 | 51 | private void setBtn(TextView btn, String test, final Listener listener) { 52 | btn.setVisibility(View.VISIBLE); 53 | btn.setText(test); 54 | btn.setOnClickListener(new View.OnClickListener() { 55 | @Override 56 | public void onClick(View v) { 57 | if (listener != null){ 58 | listener.onClick(CheckDialog.this); 59 | } 60 | } 61 | }); 62 | } 63 | 64 | /** 65 | * 设置内容文本 66 | * @param contentMsg 内容文本 67 | */ 68 | public void setContentMsg(@NonNull String contentMsg) { 69 | mContentText = contentMsg; 70 | mContentMsg.setText(mContentText); 71 | } 72 | 73 | /** 74 | * 设置内容文本 75 | * @param resId 内容文本资源id 76 | */ 77 | public void setContentMsg(@StringRes int resId) { 78 | mContentText = getContext().getString(resId); 79 | mContentMsg.setText(mContentText); 80 | } 81 | 82 | /** 83 | * 设置确认按钮文本 84 | * @param positiveText 确认文本 85 | * @param listener 点击监听 86 | */ 87 | public void setPositiveText(String positiveText, final Listener listener) { 88 | mPositiveText = positiveText; 89 | mPositiveListener = listener; 90 | setBtn(mPositiveBtn, mPositiveText, mPositiveListener); 91 | } 92 | 93 | /** 94 | * 设置确认按钮文本 95 | * @param resId 确认文本资源id 96 | * @param listener 点击监听 97 | */ 98 | public void setPositiveText(@StringRes int resId, final Listener listener) { 99 | mPositiveText = getContext().getString(resId); 100 | mPositiveListener = listener; 101 | setBtn(mPositiveBtn, mPositiveText, mPositiveListener); 102 | } 103 | 104 | /** 105 | * 设置取消按钮文本 106 | * @param negativeText 取消文本 107 | * @param listener 点击监听 108 | */ 109 | public void setNegativeText(String negativeText, final Listener listener) { 110 | mNegativeText = negativeText; 111 | mNegativeListener = listener; 112 | setBtn(mNegativeBtn, mNegativeText, mNegativeListener); 113 | } 114 | 115 | /** 116 | * 设置取消按钮文本 117 | * @param resId 取消文本资源id 118 | * @param listener 点击监听 119 | */ 120 | public void setNegativeText(@StringRes int resId, final Listener listener) { 121 | mNegativeText = getContext().getString(resId); 122 | mNegativeListener = listener; 123 | setBtn(mNegativeBtn, mNegativeText, mNegativeListener); 124 | } 125 | 126 | public interface Listener{ 127 | void onClick(Dialog dialog); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /app/src/main/java/com/liar/testrecorder/ui/dialog/InputFileNameDialog.java: -------------------------------------------------------------------------------- 1 | package com.liar.testrecorder.ui.dialog; 2 | 3 | import android.app.Dialog; 4 | import android.content.Context; 5 | import android.text.TextUtils; 6 | import android.view.View; 7 | import android.widget.EditText; 8 | import android.widget.TextView; 9 | 10 | import com.liar.testrecorder.R; 11 | import com.lodz.android.component.widget.dialog.BaseCenterDialog; 12 | import com.lodz.android.core.utils.ToastUtils; 13 | 14 | import butterknife.BindView; 15 | import butterknife.ButterKnife; 16 | 17 | /** 18 | * Created by shizhw on 2019/7/29. 19 | 20 | */ 21 | public class InputFileNameDialog extends BaseCenterDialog { 22 | 23 | 24 | /** 25 | * 取消 26 | */ 27 | @BindView(R.id.tv_cancel_dialog) 28 | TextView tv_cancel_dialog; 29 | /** 30 | * 确定 31 | */ 32 | @BindView(R.id.tv_confirm_dialog) 33 | TextView tv_confirm_dialog; 34 | 35 | /** 36 | * IP地址输入框 37 | */ 38 | @BindView(R.id.edit_file_name) 39 | EditText edit_file_name; 40 | 41 | 42 | 43 | 44 | public InputFileNameDialog(Context context) { 45 | super(context); 46 | } 47 | 48 | @Override 49 | protected int getLayoutId() { 50 | return R.layout.dialog_input_filename; 51 | } 52 | 53 | @Override 54 | protected void initData() { 55 | super.initData(); 56 | 57 | } 58 | 59 | @Override 60 | protected void findViews() { 61 | ButterKnife.bind(this); 62 | 63 | //做Emoji表情过滤 64 | // edit_url_ip.setFilters(new InputFilter[]{new EmojiFilterUtils()}); 65 | // edit_url_port.setFilters(new InputFilter[]{new EmojiFilterUtils()}); 66 | tv_cancel_dialog.setOnClickListener(new View.OnClickListener() { 67 | @Override 68 | public void onClick(View view) { 69 | if (listener != null) { 70 | listener.onCancel(InputFileNameDialog.this); 71 | } 72 | } 73 | }); 74 | 75 | tv_confirm_dialog.setOnClickListener(new View.OnClickListener() { 76 | @Override 77 | public void onClick(View view) { 78 | 79 | if (TextUtils.isEmpty(edit_file_name.getText().toString())) { 80 | ToastUtils.showShort(getContext(), "文件名不能为空"); 81 | return; 82 | 83 | } else { 84 | if (listener != null) { 85 | listener.onConfirm(InputFileNameDialog.this, 86 | edit_file_name.getText().toString().trim()); 87 | } 88 | return; 89 | } 90 | } 91 | }); 92 | } 93 | 94 | 95 | public Listener listener; 96 | 97 | public void setListener(Listener listener) { 98 | this.listener = listener; 99 | } 100 | 101 | public interface Listener { 102 | void onCancel(Dialog dialog); 103 | void onConfirm(Dialog dialog, String fileName); 104 | } 105 | 106 | 107 | } 108 | -------------------------------------------------------------------------------- /app/src/main/java/com/liar/testrecorder/utils/NotificationPermissionUtil.java: -------------------------------------------------------------------------------- 1 | package com.liar.testrecorder.utils; 2 | 3 | import android.app.AppOpsManager; 4 | import android.app.NotificationManager; 5 | import android.content.Context; 6 | import android.content.Intent; 7 | import android.content.pm.ApplicationInfo; 8 | import android.net.Uri; 9 | import android.os.Build; 10 | import android.provider.Settings; 11 | 12 | import androidx.annotation.RequiresApi; 13 | 14 | import java.lang.reflect.Field; 15 | import java.lang.reflect.Method; 16 | 17 | /** 18 | * Created by LiarShi on 2020/5/28. 19 | * 判断是否有开启通知栏权限 20 | */ 21 | public class NotificationPermissionUtil { 22 | 23 | private static final String CHECK_OP_NO_THROW = "checkOpNoThrow"; 24 | private static final String OP_POST_NOTIFICATION = "OP_POST_NOTIFICATION"; 25 | 26 | //调用该方法获取是否开启通知栏权限 27 | public static boolean isNotifyEnabled(Context context) { 28 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { 29 | return isEnableV26(context); 30 | } else { 31 | return isEnabledV19(context); 32 | } 33 | } 34 | 35 | /** 36 | * 8.0以下判断 37 | * 38 | * @param context api19 4.4及以上判断 39 | * @return 40 | */ 41 | @RequiresApi(api = Build.VERSION_CODES.KITKAT) 42 | private static boolean isEnabledV19(Context context) { 43 | 44 | AppOpsManager mAppOps = 45 | (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); 46 | 47 | ApplicationInfo appInfo = context.getApplicationInfo(); 48 | String pkg = context.getApplicationContext().getPackageName(); 49 | int uid = appInfo.uid; 50 | Class appOpsClass = null; 51 | 52 | try { 53 | appOpsClass = Class.forName(AppOpsManager.class.getName()); 54 | 55 | Method checkOpNoThrowMethod = 56 | appOpsClass.getMethod(CHECK_OP_NO_THROW, 57 | Integer.TYPE, Integer.TYPE, String.class); 58 | 59 | Field opPostNotificationValue = appOpsClass.getDeclaredField(OP_POST_NOTIFICATION); 60 | int value = (Integer) opPostNotificationValue.get(Integer.class); 61 | 62 | return ((Integer) checkOpNoThrowMethod.invoke(mAppOps, value, uid, pkg) == 63 | AppOpsManager.MODE_ALLOWED); 64 | } catch (Exception e) { 65 | e.printStackTrace(); 66 | } 67 | return false; 68 | } 69 | 70 | 71 | /** 72 | * 8.0及以上通知权限判断 73 | * 74 | * @param context 75 | * @return 76 | */ 77 | private static boolean isEnableV26(Context context) { 78 | ApplicationInfo appInfo = context.getApplicationInfo(); 79 | String pkg = context.getApplicationContext().getPackageName(); 80 | int uid = appInfo.uid; 81 | try { 82 | NotificationManager notificationManager = (NotificationManager) 83 | context.getSystemService(Context.NOTIFICATION_SERVICE); 84 | Method sServiceField = notificationManager.getClass().getDeclaredMethod("getService"); 85 | sServiceField.setAccessible(true); 86 | Object sService = sServiceField.invoke(notificationManager); 87 | 88 | Method method = sService.getClass().getDeclaredMethod("areNotificationsEnabledForPackage" 89 | , String.class, Integer.TYPE); 90 | method.setAccessible(true); 91 | return (boolean) method.invoke(sService, pkg, uid); 92 | } catch (Exception e) { 93 | return true; 94 | } 95 | } 96 | 97 | 98 | public static void start(Context context){ 99 | Intent localIntent = new Intent(); 100 | //直接跳转到应用通知设置的代码: 101 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {//8.0及以上 102 | localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 103 | localIntent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS"); 104 | localIntent.setData(Uri.fromParts("package", context.getPackageName(), null)); 105 | } else if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {//5.0以上到8.0以下 106 | localIntent.setAction("android.settings.APP_NOTIFICATION_SETTINGS"); 107 | localIntent.putExtra("app_package", context.getPackageName()); 108 | localIntent.putExtra("app_uid", context.getApplicationInfo().uid); 109 | } else if (android.os.Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) {//4.4 110 | localIntent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); 111 | localIntent.addCategory(Intent.CATEGORY_DEFAULT); 112 | localIntent.setData(Uri.parse("package:" + context.getPackageName())); 113 | } else { 114 | //4.4以下没有从app跳转到应用通知设置页面的Action,可考虑跳转到应用详情页面, 115 | localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 116 | if (Build.VERSION.SDK_INT >= 9) { 117 | localIntent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS"); 118 | localIntent.setData(Uri.fromParts("package", context.getPackageName(), null)); 119 | } else if (Build.VERSION.SDK_INT <= 8) { 120 | localIntent.setAction(Intent.ACTION_VIEW); 121 | localIntent.setClassName("com.android.settings", "com.android.setting.InstalledAppDetails"); 122 | localIntent.putExtra("com.android.settings.ApplicationPkgName", context.getPackageName()); 123 | } 124 | } 125 | context.startActivity(localIntent); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /app/src/main/java/com/liar/testrecorder/utils/TimeUtils.java: -------------------------------------------------------------------------------- 1 | package com.liar.testrecorder.utils; 2 | 3 | import java.text.SimpleDateFormat; 4 | import java.util.TimeZone; 5 | 6 | /** 7 | * Created by LiarShi on 2020/5/26. 8 | */ 9 | public class TimeUtils { 10 | 11 | 12 | public static String getGapTime(long time){ 13 | 14 | //使用中国时区的有时差8小时,所以要先扣掉 对应时区的时差 15 | time=time-TimeZone.getDefault().getRawOffset(); 16 | //初始化Formatter的转换格式。 17 | SimpleDateFormat format =new SimpleDateFormat("HH:mm:ss"); 18 | return format.format(time); 19 | // long hours = time / (1000 * 60 * 60); 20 | // long minutes = (time-hours*(1000 * 60 * 60 ))/(1000* 60); 21 | // String diffTime=""; 22 | // if(minutes<10){ 23 | // diffTime=hours+":0"+minutes; 24 | // }else{ 25 | // diffTime=hours+":"+minutes; 26 | // } 27 | // return diffTime; 28 | 29 | } 30 | 31 | 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/com/liar/testrecorder/utils/download/DownloadListener.java: -------------------------------------------------------------------------------- 1 | package com.liar.testrecorder.utils.download; 2 | 3 | import androidx.annotation.IntDef; 4 | 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | 8 | /** 9 | * 下载状态回调 10 | 11 | */ 12 | public interface DownloadListener { 13 | 14 | /** 下载地址为空 */ 15 | public static final int URL_EMPTY = 0; 16 | /** 保存名称为空 */ 17 | public static final int SAVE_NAME_EMPTY = 1; 18 | /** 保存路径为空 */ 19 | public static final int SAVE_PATH_EMPTY = 2; 20 | /** 网络错误 */ 21 | public static final int NETWORK_ERROR = 3; 22 | /** 下在过程错误 */ 23 | public static final int DOWNLOADING_ERROR = 4; 24 | 25 | @IntDef({URL_EMPTY, SAVE_NAME_EMPTY, SAVE_PATH_EMPTY, NETWORK_ERROR, DOWNLOADING_ERROR}) 26 | @Retention(RetentionPolicy.SOURCE) 27 | public @interface ErrorType {} 28 | 29 | /** 开始下载 */ 30 | void onStart(); 31 | 32 | /** 33 | * 进度回调 34 | * @param totalSize 总大小 35 | * @param progress 已下载大小 36 | */ 37 | void onProgress(long totalSize, long progress); 38 | 39 | /** 40 | * 异常回调 41 | * @param errorType 异常类型,包括:{@link #URL_EMPTY}、{@link #NETWORK_ERROR}、{@link #DOWNLOADING_ERROR} 42 | * @param t 错误信息 43 | */ 44 | void onError(@ErrorType int errorType, Throwable t); 45 | /** 下载完成 */ 46 | void onComplete(); 47 | /** 下载暂停 */ 48 | void onPause(); 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/java/com/liar/testrecorder/utils/file/FileManager.java: -------------------------------------------------------------------------------- 1 | package com.liar.testrecorder.utils.file; 2 | 3 | import android.text.TextUtils; 4 | 5 | import com.liar.testrecorder.App; 6 | import com.lodz.android.core.utils.FileUtils; 7 | import com.lodz.android.core.utils.StorageUtils; 8 | 9 | import java.io.File; 10 | 11 | /** 12 | * 文件管理 13 | 14 | */ 15 | public class FileManager { 16 | 17 | private FileManager() {} 18 | 19 | /** 存储卡是否可用 */ 20 | private static boolean isStorageCanUse = false; 21 | /** app主文件夹路径 */ 22 | private static String mAppFolderPath = null; 23 | /** 缓存路径 */ 24 | private static String mCacheFolderPath = null; 25 | /** 下载路径 */ 26 | private static String mDownloadFolderPath = null; 27 | /** 内容路径 */ 28 | private static String mContentFolderPath = null; 29 | /** 崩溃日志路径 */ 30 | private static String mCrashFolderPath = null; 31 | /** 音频文件路径 */ 32 | private static String mAudioFolderPath = null; 33 | 34 | public static void init(){ 35 | initPath(); 36 | if (isStorageCanUse){ 37 | initFolder(); 38 | } 39 | } 40 | 41 | /** 初始化路径 */ 42 | private static void initPath() { 43 | String rootPath = ""; 44 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) { 45 | File file = App.get().getExternalFilesDir(""); 46 | if (file != null){ 47 | rootPath = file.getAbsolutePath(); 48 | } 49 | } 50 | if (TextUtils.isEmpty(rootPath)){ 51 | rootPath = StorageUtils.getInternalStoragePath(App.get());// 先获取内置存储路径 52 | if (TextUtils.isEmpty(rootPath)){// 内置为空再获取外置 53 | rootPath = StorageUtils.getExternalStoragePath(App.get()); 54 | } 55 | } 56 | 57 | if (TextUtils.isEmpty(rootPath)){// 没有存储卡 58 | isStorageCanUse = false; 59 | return; 60 | } 61 | // 成功获取到存储路径 62 | isStorageCanUse = true; 63 | if (!rootPath.endsWith(File.separator)) { 64 | rootPath += File.separator; 65 | } 66 | mAppFolderPath = rootPath + "TestDemo" + File.separator;// 主文件夹路径 67 | mCacheFolderPath = mAppFolderPath + "Cache" + File.separator;// 缓存路径 68 | mDownloadFolderPath = mAppFolderPath + "Download" + File.separator;// 下载路径 69 | mContentFolderPath = mAppFolderPath + "Content" + File.separator;// 内容路径 70 | mCrashFolderPath = mAppFolderPath + "Crash" + File.separator;// 崩溃日志路径 71 | mAudioFolderPath = mAppFolderPath + "Audio" + File.separator;// 音频文件路径 72 | 73 | } 74 | 75 | /** 初始化文件夹 */ 76 | private static void initFolder() { 77 | try { 78 | FileUtils.createFolder(mAppFolderPath);// 主文件夹路径 79 | FileUtils.createFolder(mCacheFolderPath);// 缓存路径 80 | FileUtils.createFolder(mDownloadFolderPath);// 下载路径 81 | FileUtils.createFolder(mContentFolderPath);// 内容路径 82 | FileUtils.createFolder(mCrashFolderPath);// 崩溃日志路径 83 | FileUtils.createFolder(mAudioFolderPath);// 音频文件路径 84 | }catch (Exception e){ 85 | e.printStackTrace(); 86 | } 87 | } 88 | 89 | /** 存储是否可用 */ 90 | public static boolean isStorageCanUse() { 91 | return isStorageCanUse; 92 | } 93 | 94 | /** 获取app主文件夹路径 */ 95 | public static String getAppFolderPath() { 96 | return fixPath(mAppFolderPath); 97 | } 98 | 99 | /** 获取缓存路径 */ 100 | public static String getCacheFolderPath() { 101 | return fixPath(mCacheFolderPath); 102 | } 103 | 104 | /** 获取下载路径 */ 105 | public static String getDownloadFolderPath() { 106 | return fixPath(mDownloadFolderPath); 107 | } 108 | 109 | /** 获取内容路径 */ 110 | public static String getContentFolderPath() { 111 | return fixPath(mContentFolderPath); 112 | } 113 | 114 | /** 获取崩溃日志路径 */ 115 | public static String getCrashFolderPath() { 116 | return fixPath(mCrashFolderPath); 117 | } 118 | /** 音频文件路径 */ 119 | public static String getAudioFolderPath() { 120 | return fixPath(mAudioFolderPath); 121 | } 122 | /** 123 | * 修复文件夹路径 124 | * @param path 文件夹路径 125 | */ 126 | private static String fixPath(String path) { 127 | if (TextUtils.isEmpty(path)) { 128 | // 路径为空说明未初始化 129 | init(); 130 | } 131 | if (isStorageCanUse && !FileUtils.isFileExists(path)) { 132 | //存储可用 && 路径下的文件夹不存在 说明文件夹被删除 133 | initFolder(); 134 | } 135 | return path; 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /app/src/main/java/com/liar/testrecorder/utils/sp/SharedPreferencesUtils.java: -------------------------------------------------------------------------------- 1 | package com.liar.testrecorder.utils.sp; 2 | 3 | import android.content.Context; 4 | import android.content.SharedPreferences; 5 | 6 | import androidx.annotation.Nullable; 7 | 8 | import com.liar.testrecorder.App; 9 | 10 | import java.util.Map; 11 | import java.util.Set; 12 | 13 | /** 14 | * SP帮助类 15 | 16 | */ 17 | public class SharedPreferencesUtils { 18 | 19 | private SharedPreferencesUtils() {} 20 | 21 | /** 22 | * 保存String类型数据 23 | * @param key 键 24 | * @param value 值 25 | */ 26 | public static void putString(String key, @Nullable String value) { 27 | SharedPreferences.Editor editor = App.get().getSharedPreferences(SpConfig.SP_NAME, Context.MODE_PRIVATE).edit(); 28 | editor.putString(key, value); 29 | editor.apply(); 30 | } 31 | 32 | /** 33 | * 保存Boolean类型数据 34 | * @param key 键 35 | * @param value 值 36 | */ 37 | public static void putBoolean(String key, boolean value) { 38 | SharedPreferences.Editor editor = App.get().getSharedPreferences(SpConfig.SP_NAME, Context.MODE_PRIVATE).edit(); 39 | editor.putBoolean(key, value); 40 | editor.apply(); 41 | } 42 | 43 | /** 44 | * 保存Float类型数据 45 | * @param key 键 46 | * @param value 值 47 | */ 48 | public static void putFloat(String key, float value) { 49 | SharedPreferences.Editor editor = App.get().getSharedPreferences(SpConfig.SP_NAME, Context.MODE_PRIVATE).edit(); 50 | editor.putFloat(key, value); 51 | editor.apply(); 52 | } 53 | 54 | /** 55 | * 保存Int类型数据 56 | * @param key 键 57 | * @param value 值 58 | */ 59 | public static void putInt(String key, int value) { 60 | SharedPreferences.Editor editor = App.get().getSharedPreferences(SpConfig.SP_NAME, Context.MODE_PRIVATE).edit(); 61 | editor.putInt(key, value); 62 | editor.apply(); 63 | } 64 | 65 | /** 66 | * 保存Long类型数据 67 | * @param key 键 68 | * @param value 值 69 | */ 70 | public static void putLong(String key, long value) { 71 | SharedPreferences.Editor editor = App.get().getSharedPreferences(SpConfig.SP_NAME, Context.MODE_PRIVATE).edit(); 72 | editor.putLong(key, value); 73 | editor.apply(); 74 | } 75 | 76 | /** 77 | * 保存StringSet类型数据 78 | * @param key 键 79 | * @param values 值 80 | */ 81 | public static void putStringSet(String key, @Nullable Set values) { 82 | SharedPreferences.Editor editor = App.get().getSharedPreferences(SpConfig.SP_NAME, Context.MODE_PRIVATE).edit(); 83 | editor.putStringSet(key, values); 84 | editor.apply(); 85 | } 86 | 87 | /** 获取全部的sp数据,没有返回null */ 88 | public static Map getAll() { 89 | SharedPreferences sp = App.get().getSharedPreferences(SpConfig.SP_NAME, Context.MODE_PRIVATE); 90 | try { 91 | //noinspection unchecked 92 | return (Map) sp.getAll(); 93 | } catch (Exception e) { 94 | e.printStackTrace(); 95 | } 96 | return null; 97 | } 98 | 99 | /** 100 | * 获取Boolean型数据 101 | * @param key 键 102 | * @param defValue 默认值 103 | */ 104 | public static boolean getBoolean(String key, boolean defValue) { 105 | SharedPreferences sp = App.get().getSharedPreferences(SpConfig.SP_NAME, Context.MODE_PRIVATE); 106 | try { 107 | return sp.getBoolean(key, defValue); 108 | } catch (Exception e) { 109 | e.printStackTrace(); 110 | } 111 | return defValue; 112 | } 113 | 114 | /** 115 | * 获取Float型数据 116 | * @param key 键 117 | * @param defValue 默认值 118 | */ 119 | public static float getFloat(String key, float defValue) { 120 | SharedPreferences sp = App.get().getSharedPreferences(SpConfig.SP_NAME, Context.MODE_PRIVATE); 121 | try { 122 | return sp.getFloat(key, defValue); 123 | } catch (Exception e) { 124 | e.printStackTrace(); 125 | } 126 | return defValue; 127 | } 128 | 129 | /** 130 | * 获取Int型数据 131 | * @param key 键 132 | * @param defValue 默认值 133 | */ 134 | public static int getInt(String key, int defValue) { 135 | SharedPreferences sp = App.get().getSharedPreferences(SpConfig.SP_NAME, Context.MODE_PRIVATE); 136 | try { 137 | return sp.getInt(key, defValue); 138 | } catch (Exception e) { 139 | e.printStackTrace(); 140 | } 141 | return defValue; 142 | } 143 | 144 | /** 145 | * 获取Long型数据 146 | * @param key 键 147 | * @param defValue 默认值 148 | */ 149 | public static long getLong(String key, long defValue) { 150 | SharedPreferences sp = App.get().getSharedPreferences(SpConfig.SP_NAME, Context.MODE_PRIVATE); 151 | try { 152 | return sp.getLong(key, defValue); 153 | } catch (Exception e) { 154 | e.printStackTrace(); 155 | } 156 | return defValue; 157 | } 158 | 159 | /** 160 | * 获取String型数据 161 | * @param key 键 162 | * @param defValue 默认值 163 | */ 164 | public static String getString(String key, @Nullable String defValue) { 165 | SharedPreferences sp = App.get().getSharedPreferences(SpConfig.SP_NAME, Context.MODE_PRIVATE); 166 | try { 167 | return sp.getString(key, defValue); 168 | } catch (Exception e) { 169 | e.printStackTrace(); 170 | } 171 | return defValue; 172 | } 173 | 174 | /** 175 | * 获取StringSet型数据 176 | * @param key 键 177 | * @param defValues 默认值 178 | */ 179 | public static Set getStringSet(String key, @Nullable Set defValues) { 180 | SharedPreferences sp = App.get().getSharedPreferences(SpConfig.SP_NAME, Context.MODE_PRIVATE); 181 | try { 182 | return sp.getStringSet(key, defValues); 183 | } catch (Exception e) { 184 | e.printStackTrace(); 185 | } 186 | return defValues; 187 | } 188 | 189 | /** 190 | * 删除指定键的数据 191 | * @param key 键 192 | */ 193 | public static void remove(String key) { 194 | SharedPreferences.Editor editor = App.get().getSharedPreferences(SpConfig.SP_NAME, Context.MODE_PRIVATE).edit(); 195 | editor.remove(key); 196 | editor.apply(); 197 | } 198 | 199 | /** 清空整个sp数据 */ 200 | public static void clear() { 201 | SharedPreferences.Editor editor = App.get().getSharedPreferences(SpConfig.SP_NAME, Context.MODE_PRIVATE).edit(); 202 | editor.clear(); 203 | editor.apply(); 204 | } 205 | 206 | } 207 | -------------------------------------------------------------------------------- /app/src/main/java/com/liar/testrecorder/utils/sp/SpConfig.java: -------------------------------------------------------------------------------- 1 | package com.liar.testrecorder.utils.sp; 2 | 3 | /** 4 | * SharedPreferences配置信息 5 | 6 | */ 7 | public class SpConfig { 8 | 9 | private SpConfig() {} 10 | 11 | /** sp文件名称 */ 12 | public static final String SP_NAME = "sp_setting"; 13 | 14 | //---------------------------- 存储的Key ----------------------------------- 15 | 16 | /** 用户账号 */ 17 | public static final String USER_ACCOUNT = "user_account"; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/liar/testrecorder/utils/sp/SpManager.java: -------------------------------------------------------------------------------- 1 | package com.liar.testrecorder.utils.sp; 2 | 3 | /** 4 | * SharedPreferences管理类 5 | 6 | */ 7 | public class SpManager { 8 | 9 | private static SpManager mInstance = new SpManager(); 10 | 11 | public static SpManager get() { 12 | return mInstance; 13 | } 14 | 15 | private SpManager() {} 16 | 17 | /** 18 | * 设置用户账号 19 | * @param account 账号 20 | */ 21 | public void setUserAccount(String account){ 22 | SharedPreferencesUtils.putString(SpConfig.USER_ACCOUNT, account); 23 | } 24 | 25 | /** 获取用户账号 */ 26 | public String getUserAccount(){ 27 | return SharedPreferencesUtils.getString(SpConfig.USER_ACCOUNT, ""); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiarShi/TestRecorder/b207517aadfa7b87312d44ddaabad94094aab52c/app/src/main/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiarShi/TestRecorder/b207517aadfa7b87312d44ddaabad94094aab52c/app/src/main/res/drawable-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/icon_pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiarShi/TestRecorder/b207517aadfa7b87312d44ddaabad94094aab52c/app/src/main/res/drawable-hdpi/icon_pause.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/icon_start_record.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiarShi/TestRecorder/b207517aadfa7b87312d44ddaabad94094aab52c/app/src/main/res/drawable-hdpi/icon_start_record.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/icon_stop_record.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiarShi/TestRecorder/b207517aadfa7b87312d44ddaabad94094aab52c/app/src/main/res/drawable-hdpi/icon_stop_record.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiarShi/TestRecorder/b207517aadfa7b87312d44ddaabad94094aab52c/app/src/main/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiarShi/TestRecorder/b207517aadfa7b87312d44ddaabad94094aab52c/app/src/main/res/drawable-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/icon_pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiarShi/TestRecorder/b207517aadfa7b87312d44ddaabad94094aab52c/app/src/main/res/drawable-mdpi/icon_pause.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/icon_start_record.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiarShi/TestRecorder/b207517aadfa7b87312d44ddaabad94094aab52c/app/src/main/res/drawable-mdpi/icon_start_record.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/icon_stop_record.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiarShi/TestRecorder/b207517aadfa7b87312d44ddaabad94094aab52c/app/src/main/res/drawable-mdpi/icon_stop_record.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiarShi/TestRecorder/b207517aadfa7b87312d44ddaabad94094aab52c/app/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiarShi/TestRecorder/b207517aadfa7b87312d44ddaabad94094aab52c/app/src/main/res/drawable-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/icon_pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiarShi/TestRecorder/b207517aadfa7b87312d44ddaabad94094aab52c/app/src/main/res/drawable-xhdpi/icon_pause.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/icon_start_record.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiarShi/TestRecorder/b207517aadfa7b87312d44ddaabad94094aab52c/app/src/main/res/drawable-xhdpi/icon_start_record.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/icon_stop_record.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiarShi/TestRecorder/b207517aadfa7b87312d44ddaabad94094aab52c/app/src/main/res/drawable-xhdpi/icon_stop_record.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiarShi/TestRecorder/b207517aadfa7b87312d44ddaabad94094aab52c/app/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiarShi/TestRecorder/b207517aadfa7b87312d44ddaabad94094aab52c/app/src/main/res/drawable-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/icon_pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiarShi/TestRecorder/b207517aadfa7b87312d44ddaabad94094aab52c/app/src/main/res/drawable-xxhdpi/icon_pause.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/icon_start_record.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiarShi/TestRecorder/b207517aadfa7b87312d44ddaabad94094aab52c/app/src/main/res/drawable-xxhdpi/icon_start_record.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/icon_stop_record.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiarShi/TestRecorder/b207517aadfa7b87312d44ddaabad94094aab52c/app/src/main/res/drawable-xxhdpi/icon_stop_record.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiarShi/TestRecorder/b207517aadfa7b87312d44ddaabad94094aab52c/app/src/main/res/drawable-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiarShi/TestRecorder/b207517aadfa7b87312d44ddaabad94094aab52c/app/src/main/res/drawable-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/icon_pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiarShi/TestRecorder/b207517aadfa7b87312d44ddaabad94094aab52c/app/src/main/res/drawable-xxxhdpi/icon_pause.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/icon_start_record.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiarShi/TestRecorder/b207517aadfa7b87312d44ddaabad94094aab52c/app/src/main/res/drawable-xxxhdpi/icon_start_record.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/icon_stop_record.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiarShi/TestRecorder/b207517aadfa7b87312d44ddaabad94094aab52c/app/src/main/res/drawable-xxxhdpi/icon_stop_record.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_circle_white.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_flag_radius_white.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/gray_round_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_flag_notification_btn.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_splash_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_check_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 17 | 18 | 24 | 25 | 32 | 33 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_input_filename.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 17 | 18 | 19 | 33 | 34 | 35 | 36 | 42 | 43 | 56 | 57 | 58 | 63 | 64 | 69 | 70 | 71 | 74 | 75 | 90 | 91 | 96 | 97 | 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /app/src/main/res/layout/view_remote_notification.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 18 | 19 | 20 | 25 | 26 | 27 | 32 | 33 | 45 | 46 | 56 | 57 | 58 | 68 | 69 | 80 | 81 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #6200EE 4 | #3700B3 5 | #03DAC5 6 | 7 | 8 | #00000000 9 | #FFFFFF 10 | #000000 11 | #ff0000 12 | #ffcc00 13 | #ffa500 14 | #008000 15 | #ffffff 16 | #BDBDBD 17 | 18 | #00a0e9 19 | #cccccc 20 | #a8aeb1 21 | #333333 22 | #dcdcdc 23 | #222222 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | TestRecorder 3 | 4 | 5 | 请在权限页面打开应用所有权限 6 | 请确认已打开该应用使用的所有权限 7 | 已确认 8 | 再次确认 9 | 请在设置中打开权限后重启应用 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 16 | 17 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/xml/file_provider_paths.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 13 | 14 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | ext.kotlin_version = '1.3.72' 5 | 6 | repositories { 7 | google() 8 | jcenter() 9 | maven { url 'https://www.jitpack.io' } 10 | 11 | } 12 | dependencies { 13 | classpath 'com.android.tools.build:gradle:3.6.3' 14 | classpath 'com.github.dcendents:android-maven-gradle-plugin:2.0' 15 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 16 | 17 | // NOTE: Do not place your application dependencies here; they belong 18 | // in the individual module build.gradle files 19 | } 20 | } 21 | 22 | allprojects { 23 | repositories { 24 | google() 25 | jcenter() 26 | maven { url 'https://www.jitpack.io' } 27 | } 28 | } 29 | 30 | task clean(type: Delete) { 31 | delete rootProject.buildDir 32 | } 33 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app's APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Automatically convert third-party libraries to use AndroidX 19 | android.enableJetifier=true 20 | 21 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiarShi/TestRecorder/b207517aadfa7b87312d44ddaabad94094aab52c/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon May 25 12:19:28 CST 2020 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-5.6.4-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /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 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 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 Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /recorderlib/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /recorderlib/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'com.github.dcendents.android-maven' 3 | group='com.github.zhaolewei' 4 | 5 | android { 6 | compileSdkVersion 26 7 | 8 | defaultConfig { 9 | minSdkVersion 16 10 | targetSdkVersion 26 11 | versionCode 1 12 | versionName "1.0" 13 | 14 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 15 | } 16 | 17 | buildTypes { 18 | release { 19 | minifyEnabled false 20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 21 | } 22 | } 23 | sourceSets.main { 24 | jni.srcDirs = []//disable automatic ndk-build call 25 | jniLibs.srcDirs = ['libs'] 26 | } 27 | } 28 | 29 | dependencies { 30 | implementation fileTree(dir: 'libs', include: ['*.jar']) 31 | 32 | implementation 'com.android.support:appcompat-v7:26.1.0' 33 | testImplementation 'junit:junit:4.12' 34 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 35 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 36 | } 37 | -------------------------------------------------------------------------------- /recorderlib/libs/arm64-v8a/libmp3lame.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiarShi/TestRecorder/b207517aadfa7b87312d44ddaabad94094aab52c/recorderlib/libs/arm64-v8a/libmp3lame.so -------------------------------------------------------------------------------- /recorderlib/libs/armeabi-v7a/libmp3lame.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiarShi/TestRecorder/b207517aadfa7b87312d44ddaabad94094aab52c/recorderlib/libs/armeabi-v7a/libmp3lame.so -------------------------------------------------------------------------------- /recorderlib/libs/armeabi/libmp3lame.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiarShi/TestRecorder/b207517aadfa7b87312d44ddaabad94094aab52c/recorderlib/libs/armeabi/libmp3lame.so -------------------------------------------------------------------------------- /recorderlib/libs/mips/libmp3lame.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiarShi/TestRecorder/b207517aadfa7b87312d44ddaabad94094aab52c/recorderlib/libs/mips/libmp3lame.so -------------------------------------------------------------------------------- /recorderlib/libs/mips64/libmp3lame.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiarShi/TestRecorder/b207517aadfa7b87312d44ddaabad94094aab52c/recorderlib/libs/mips64/libmp3lame.so -------------------------------------------------------------------------------- /recorderlib/libs/x86/libmp3lame.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiarShi/TestRecorder/b207517aadfa7b87312d44ddaabad94094aab52c/recorderlib/libs/x86/libmp3lame.so -------------------------------------------------------------------------------- /recorderlib/libs/x86_64/libmp3lame.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiarShi/TestRecorder/b207517aadfa7b87312d44ddaabad94094aab52c/recorderlib/libs/x86_64/libmp3lame.so -------------------------------------------------------------------------------- /recorderlib/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 | -------------------------------------------------------------------------------- /recorderlib/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /recorderlib/src/main/java/com/zlw/main/recorderlib/RecordManager.java: -------------------------------------------------------------------------------- 1 | package com.zlw.main.recorderlib; 2 | 3 | 4 | import android.annotation.SuppressLint; 5 | import android.app.Application; 6 | 7 | import com.zlw.main.recorderlib.recorder.RecordConfig; 8 | import com.zlw.main.recorderlib.recorder.RecordHelper; 9 | import com.zlw.main.recorderlib.recorder.RecordService; 10 | import com.zlw.main.recorderlib.recorder.listener.RecordDataListener; 11 | import com.zlw.main.recorderlib.recorder.listener.RecordFftDataListener; 12 | import com.zlw.main.recorderlib.recorder.listener.RecordResultListener; 13 | import com.zlw.main.recorderlib.recorder.listener.RecordSoundSizeListener; 14 | import com.zlw.main.recorderlib.recorder.listener.RecordStateListener; 15 | import com.zlw.main.recorderlib.utils.Logger; 16 | 17 | /** 18 | * @author zhaolewei on 2018/7/10. 19 | */ 20 | public class RecordManager { 21 | private static final String TAG = RecordManager.class.getSimpleName(); 22 | @SuppressLint("StaticFieldLeak") 23 | private volatile static RecordManager instance; 24 | private Application context; 25 | 26 | private RecordManager() { 27 | } 28 | 29 | public static RecordManager getInstance() { 30 | if (instance == null) { 31 | synchronized (RecordManager.class) { 32 | if (instance == null) { 33 | instance = new RecordManager(); 34 | } 35 | } 36 | } 37 | return instance; 38 | } 39 | 40 | /** 41 | * 初始化 42 | * 43 | * @param application Application 44 | * @param showLog 是否开启日志 45 | */ 46 | public void init(Application application, boolean showLog) { 47 | this.context = application; 48 | Logger.IsDebug = showLog; 49 | } 50 | 51 | public void start() { 52 | if (context == null) { 53 | Logger.e(TAG, "未进行初始化"); 54 | return; 55 | } 56 | Logger.i(TAG, "start..."); 57 | RecordService.startRecording(context); 58 | } 59 | 60 | public void stop() { 61 | if (context == null) { 62 | return; 63 | } 64 | RecordService.stopRecording(context); 65 | } 66 | 67 | public void resume() { 68 | if (context == null) { 69 | return; 70 | } 71 | RecordService.resumeRecording(context); 72 | } 73 | 74 | public void pause() { 75 | if (context == null) { 76 | return; 77 | } 78 | RecordService.pauseRecording(context); 79 | } 80 | 81 | /** 82 | * 录音状态监听回调 83 | */ 84 | public void setRecordStateListener(RecordStateListener listener) { 85 | RecordService.setRecordStateListener(listener); 86 | } 87 | 88 | /** 89 | * 录音数据监听回调 90 | */ 91 | public void setRecordDataListener(RecordDataListener listener) { 92 | RecordService.setRecordDataListener(listener); 93 | } 94 | 95 | /** 96 | * 录音可视化数据回调,傅里叶转换后的频域数据 97 | */ 98 | public void setRecordFftDataListener(RecordFftDataListener recordFftDataListener) { 99 | RecordService.setRecordFftDataListener(recordFftDataListener); 100 | } 101 | 102 | /** 103 | * 录音文件转换结束回调 104 | */ 105 | public void setRecordResultListener(RecordResultListener listener) { 106 | RecordService.setRecordResultListener(listener); 107 | } 108 | 109 | /** 110 | * 录音音量监听回调 111 | */ 112 | public void setRecordSoundSizeListener(RecordSoundSizeListener listener) { 113 | RecordService.setRecordSoundSizeListener(listener); 114 | } 115 | 116 | 117 | public boolean changeFormat(RecordConfig.RecordFormat recordFormat) { 118 | return RecordService.changeFormat(recordFormat); 119 | } 120 | 121 | 122 | public boolean changeRecordConfig(RecordConfig recordConfig) { 123 | return RecordService.changeRecordConfig(recordConfig); 124 | } 125 | 126 | public RecordConfig getRecordConfig() { 127 | return RecordService.getRecordConfig(); 128 | } 129 | 130 | /** 131 | * 修改录音文件存放路径 132 | */ 133 | public void changeRecordDir(String recordDir) { 134 | RecordService.changeRecordDir(recordDir); 135 | } 136 | 137 | /** 138 | * 获取当前的录音状态 139 | * 140 | * @return 状态 141 | */ 142 | public RecordHelper.RecordState getState() { 143 | return RecordService.getState(); 144 | } 145 | 146 | } 147 | -------------------------------------------------------------------------------- /recorderlib/src/main/java/com/zlw/main/recorderlib/recorder/RecordConfig.java: -------------------------------------------------------------------------------- 1 | package com.zlw.main.recorderlib.recorder; 2 | 3 | import android.media.AudioFormat; 4 | import android.os.Environment; 5 | 6 | import java.io.Serializable; 7 | import java.util.Locale; 8 | 9 | /** 10 | * @author zhaolewei on 2018/7/11. 11 | */ 12 | public class RecordConfig implements Serializable { 13 | /** 14 | * 录音格式 默认WAV格式 15 | */ 16 | private RecordFormat format = RecordFormat.WAV; 17 | /** 18 | * 通道数:默认单通道 19 | */ 20 | private int channelConfig = AudioFormat.CHANNEL_IN_MONO; 21 | 22 | /** 23 | * 位宽 24 | */ 25 | private int encodingConfig = AudioFormat.ENCODING_PCM_16BIT; 26 | 27 | /** 28 | * 采样率 29 | */ 30 | private int sampleRate = 16000; 31 | 32 | /* 33 | * 录音文件存放路径,默认sdcard/Record 34 | */ 35 | private String recordDir = String.format(Locale.getDefault(), 36 | "%s/Record/", 37 | Environment.getExternalStorageDirectory().getAbsolutePath()); 38 | 39 | public RecordConfig() { 40 | } 41 | 42 | public RecordConfig(RecordFormat format) { 43 | this.format = format; 44 | } 45 | 46 | /** 47 | * @param format 录音文件的格式 48 | * @param channelConfig 声道配置 49 | * 单声道:See {@link AudioFormat#CHANNEL_IN_MONO} 50 | * 双声道:See {@link AudioFormat#CHANNEL_IN_STEREO} 51 | * @param encodingConfig 位宽配置 52 | * 8Bit: See {@link AudioFormat#ENCODING_PCM_8BIT} 53 | * 16Bit: See {@link AudioFormat#ENCODING_PCM_16BIT}, 54 | * @param sampleRate 采样率 hz: 8000/16000/44100 55 | */ 56 | public RecordConfig(RecordFormat format, int channelConfig, int encodingConfig, int sampleRate) { 57 | this.format = format; 58 | this.channelConfig = channelConfig; 59 | this.encodingConfig = encodingConfig; 60 | this.sampleRate = sampleRate; 61 | } 62 | 63 | 64 | public String getRecordDir() { 65 | return recordDir; 66 | } 67 | 68 | public void setRecordDir(String recordDir) { 69 | this.recordDir = recordDir; 70 | } 71 | 72 | /** 73 | * 获取当前录音的采样位宽 单位bit 74 | * 75 | * @return 采样位宽 0: error 76 | */ 77 | public int getEncoding() { 78 | if(format == RecordFormat.MP3){//mp3后期转换 79 | return 16; 80 | } 81 | 82 | if (encodingConfig == AudioFormat.ENCODING_PCM_8BIT) { 83 | return 8; 84 | } else if (encodingConfig == AudioFormat.ENCODING_PCM_16BIT) { 85 | return 16; 86 | } else { 87 | return 0; 88 | } 89 | } 90 | 91 | /** 92 | * 获取当前录音的采样位宽 单位bit 93 | * 94 | * @return 采样位宽 0: error 95 | */ 96 | public int getRealEncoding() { 97 | if (encodingConfig == AudioFormat.ENCODING_PCM_8BIT) { 98 | return 8; 99 | } else if (encodingConfig == AudioFormat.ENCODING_PCM_16BIT) { 100 | return 16; 101 | } else { 102 | return 0; 103 | } 104 | } 105 | 106 | /** 107 | * 当前的声道数 108 | * 109 | * @return 声道数: 0:error 110 | */ 111 | public int getChannelCount() { 112 | if (channelConfig == AudioFormat.CHANNEL_IN_MONO) { 113 | return 1; 114 | } else if (channelConfig == AudioFormat.CHANNEL_IN_STEREO) { 115 | return 2; 116 | } else { 117 | return 0; 118 | } 119 | } 120 | 121 | //get&set 122 | 123 | public RecordFormat getFormat() { 124 | return format; 125 | } 126 | 127 | public RecordConfig setFormat(RecordFormat format) { 128 | this.format = format; 129 | return this; 130 | } 131 | 132 | public int getChannelConfig() { 133 | return channelConfig; 134 | } 135 | 136 | public RecordConfig setChannelConfig(int channelConfig) { 137 | this.channelConfig = channelConfig; 138 | return this; 139 | } 140 | 141 | public int getEncodingConfig() { 142 | if(format == RecordFormat.MP3){//mp3后期转换 143 | return AudioFormat.ENCODING_PCM_16BIT; 144 | } 145 | return encodingConfig; 146 | } 147 | 148 | public RecordConfig setEncodingConfig(int encodingConfig) { 149 | this.encodingConfig = encodingConfig; 150 | return this; 151 | } 152 | 153 | public int getSampleRate() { 154 | return sampleRate; 155 | } 156 | 157 | public RecordConfig setSampleRate(int sampleRate) { 158 | this.sampleRate = sampleRate; 159 | return this; 160 | } 161 | 162 | 163 | @Override 164 | public String toString() { 165 | return String.format(Locale.getDefault(), "录制格式: %s,采样率:%sHz,位宽:%s bit,声道数:%s", format, sampleRate, getEncoding(), getChannelCount()); 166 | } 167 | 168 | public enum RecordFormat { 169 | /** 170 | * mp3格式 171 | */ 172 | MP3(".mp3"), 173 | /** 174 | * wav格式 175 | */ 176 | WAV(".wav"), 177 | /** 178 | * pcm格式 179 | */ 180 | PCM(".pcm"); 181 | 182 | private String extension; 183 | 184 | public String getExtension() { 185 | return extension; 186 | } 187 | 188 | RecordFormat(String extension) { 189 | this.extension = extension; 190 | } 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /recorderlib/src/main/java/com/zlw/main/recorderlib/recorder/RecordService.java: -------------------------------------------------------------------------------- 1 | package com.zlw.main.recorderlib.recorder; 2 | 3 | import android.app.Service; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.os.Bundle; 7 | import android.os.IBinder; 8 | 9 | import com.zlw.main.recorderlib.recorder.listener.RecordDataListener; 10 | import com.zlw.main.recorderlib.recorder.listener.RecordFftDataListener; 11 | import com.zlw.main.recorderlib.recorder.listener.RecordResultListener; 12 | import com.zlw.main.recorderlib.recorder.listener.RecordSoundSizeListener; 13 | import com.zlw.main.recorderlib.recorder.listener.RecordStateListener; 14 | import com.zlw.main.recorderlib.utils.FileUtils; 15 | import com.zlw.main.recorderlib.utils.Logger; 16 | 17 | import java.text.SimpleDateFormat; 18 | import java.util.Locale; 19 | 20 | /** 21 | * 录音服务 22 | * 23 | * @author zhaolewei 24 | */ 25 | public class RecordService extends Service { 26 | private static final String TAG = RecordService.class.getSimpleName(); 27 | 28 | /** 29 | * 录音配置 30 | */ 31 | private static RecordConfig currentConfig = new RecordConfig(); 32 | 33 | private final static String ACTION_NAME = "action_type"; 34 | 35 | private final static int ACTION_INVALID = 0; 36 | 37 | private final static int ACTION_START_RECORD = 1; 38 | 39 | private final static int ACTION_STOP_RECORD = 2; 40 | 41 | private final static int ACTION_RESUME_RECORD = 3; 42 | 43 | private final static int ACTION_PAUSE_RECORD = 4; 44 | 45 | private final static String PARAM_PATH = "path"; 46 | 47 | 48 | public RecordService() { 49 | } 50 | 51 | @Override 52 | public IBinder onBind(Intent intent) { 53 | return null; 54 | } 55 | 56 | @Override 57 | public int onStartCommand(Intent intent, int flags, int startId) { 58 | if (intent == null) { 59 | return super.onStartCommand(intent, flags, startId); 60 | } 61 | Bundle bundle = intent.getExtras(); 62 | if (bundle != null && bundle.containsKey(ACTION_NAME)) { 63 | switch (bundle.getInt(ACTION_NAME, ACTION_INVALID)) { 64 | case ACTION_START_RECORD: 65 | doStartRecording(bundle.getString(PARAM_PATH)); 66 | break; 67 | case ACTION_STOP_RECORD: 68 | doStopRecording(); 69 | break; 70 | case ACTION_RESUME_RECORD: 71 | doResumeRecording(); 72 | break; 73 | case ACTION_PAUSE_RECORD: 74 | doPauseRecording(); 75 | break; 76 | default: 77 | break; 78 | } 79 | return START_STICKY; 80 | } 81 | 82 | return super.onStartCommand(intent, flags, startId); 83 | } 84 | 85 | 86 | public static void startRecording(Context context) { 87 | Intent intent = new Intent(context, RecordService.class); 88 | intent.putExtra(ACTION_NAME, ACTION_START_RECORD); 89 | intent.putExtra(PARAM_PATH, getFilePath()); 90 | context.startService(intent); 91 | } 92 | 93 | public static void stopRecording(Context context) { 94 | Intent intent = new Intent(context, RecordService.class); 95 | intent.putExtra(ACTION_NAME, ACTION_STOP_RECORD); 96 | context.startService(intent); 97 | } 98 | 99 | public static void resumeRecording(Context context) { 100 | Intent intent = new Intent(context, RecordService.class); 101 | intent.putExtra(ACTION_NAME, ACTION_RESUME_RECORD); 102 | context.startService(intent); 103 | } 104 | 105 | public static void pauseRecording(Context context) { 106 | Intent intent = new Intent(context, RecordService.class); 107 | intent.putExtra(ACTION_NAME, ACTION_PAUSE_RECORD); 108 | context.startService(intent); 109 | } 110 | 111 | /** 112 | * 改变录音格式 113 | */ 114 | public static boolean changeFormat(RecordConfig.RecordFormat recordFormat) { 115 | if (getState() == RecordHelper.RecordState.IDLE) { 116 | currentConfig.setFormat(recordFormat); 117 | return true; 118 | } 119 | return false; 120 | } 121 | 122 | /** 123 | * 改变录音配置 124 | */ 125 | public static boolean changeRecordConfig(RecordConfig recordConfig) { 126 | if (getState() == RecordHelper.RecordState.IDLE) { 127 | currentConfig = recordConfig; 128 | return true; 129 | } 130 | return false; 131 | } 132 | 133 | /** 134 | * 获取录音配置参数 135 | */ 136 | public static RecordConfig getRecordConfig() { 137 | return currentConfig; 138 | } 139 | 140 | public static void changeRecordDir(String recordDir) { 141 | currentConfig.setRecordDir(recordDir); 142 | } 143 | 144 | /** 145 | * 获取当前的录音状态 146 | */ 147 | public static RecordHelper.RecordState getState() { 148 | return RecordHelper.getInstance().getState(); 149 | } 150 | 151 | public static void setRecordStateListener(RecordStateListener recordStateListener) { 152 | RecordHelper.getInstance().setRecordStateListener(recordStateListener); 153 | } 154 | 155 | public static void setRecordDataListener(RecordDataListener recordDataListener) { 156 | RecordHelper.getInstance().setRecordDataListener(recordDataListener); 157 | } 158 | 159 | public static void setRecordSoundSizeListener(RecordSoundSizeListener recordSoundSizeListener) { 160 | RecordHelper.getInstance().setRecordSoundSizeListener(recordSoundSizeListener); 161 | } 162 | 163 | public static void setRecordResultListener(RecordResultListener recordResultListener) { 164 | RecordHelper.getInstance().setRecordResultListener(recordResultListener); 165 | } 166 | 167 | public static void setRecordFftDataListener(RecordFftDataListener recordFftDataListener) { 168 | RecordHelper.getInstance().setRecordFftDataListener(recordFftDataListener); 169 | } 170 | 171 | private void doStartRecording(String path) { 172 | Logger.v(TAG, "doStartRecording path: %s", path); 173 | RecordHelper.getInstance().start(path, currentConfig); 174 | } 175 | 176 | private void doResumeRecording() { 177 | Logger.v(TAG, "doResumeRecording"); 178 | RecordHelper.getInstance().resume(); 179 | } 180 | 181 | private void doPauseRecording() { 182 | Logger.v(TAG, "doResumeRecording"); 183 | RecordHelper.getInstance().pause(); 184 | } 185 | 186 | private void doStopRecording() { 187 | Logger.v(TAG, "doStopRecording"); 188 | RecordHelper.getInstance().stop(); 189 | stopSelf(); 190 | } 191 | 192 | public static RecordConfig getCurrentConfig() { 193 | return currentConfig; 194 | } 195 | 196 | public static void setCurrentConfig(RecordConfig currentConfig) { 197 | RecordService.currentConfig = currentConfig; 198 | } 199 | 200 | /** 201 | * 根据当前的时间生成相应的文件名 202 | * 实例 record_20160101_13_15_12 203 | */ 204 | private static String getFilePath() { 205 | 206 | String fileDir = 207 | currentConfig.getRecordDir(); 208 | if (!FileUtils.createOrExistsDir(fileDir)) { 209 | Logger.w(TAG, "文件夹创建失败:%s", fileDir); 210 | return null; 211 | } 212 | String fileName = String.format(Locale.getDefault(), "record_%s", FileUtils.getNowString(new SimpleDateFormat("yyyyMMdd_HH_mm_ss", Locale.SIMPLIFIED_CHINESE))); 213 | return String.format(Locale.getDefault(), "%s%s%s", fileDir, fileName, currentConfig.getFormat().getExtension()); 214 | } 215 | 216 | 217 | } 218 | -------------------------------------------------------------------------------- /recorderlib/src/main/java/com/zlw/main/recorderlib/recorder/listener/RecordDataListener.java: -------------------------------------------------------------------------------- 1 | package com.zlw.main.recorderlib.recorder.listener; 2 | 3 | /** 4 | * @author zhaolewei on 2018/7/11. 5 | */ 6 | public interface RecordDataListener { 7 | 8 | /** 9 | * 当前的录音状态发生变化 10 | * 11 | * @param data 当前音频数据 12 | */ 13 | void onData(byte[] data); 14 | 15 | } 16 | -------------------------------------------------------------------------------- /recorderlib/src/main/java/com/zlw/main/recorderlib/recorder/listener/RecordFftDataListener.java: -------------------------------------------------------------------------------- 1 | package com.zlw.main.recorderlib.recorder.listener; 2 | 3 | /** 4 | * @author zhaolewei on 2019/3/11. 5 | */ 6 | public interface RecordFftDataListener { 7 | 8 | /** 9 | * @param data 录音可视化数据,即傅里叶转换后的数据:fftData 10 | */ 11 | void onFftData(byte[] data); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /recorderlib/src/main/java/com/zlw/main/recorderlib/recorder/listener/RecordResultListener.java: -------------------------------------------------------------------------------- 1 | package com.zlw.main.recorderlib.recorder.listener; 2 | 3 | import java.io.File; 4 | 5 | /** 6 | * 录音完成回调 7 | */ 8 | public interface RecordResultListener { 9 | 10 | /** 11 | * 录音文件 12 | * 13 | * @param result 录音文件 14 | */ 15 | void onResult(File result); 16 | } 17 | -------------------------------------------------------------------------------- /recorderlib/src/main/java/com/zlw/main/recorderlib/recorder/listener/RecordSoundSizeListener.java: -------------------------------------------------------------------------------- 1 | package com.zlw.main.recorderlib.recorder.listener; 2 | 3 | /** 4 | * @author zhaolewei on 2018/7/11. 5 | */ 6 | public interface RecordSoundSizeListener { 7 | 8 | /** 9 | * 实时返回音量大小 10 | * 11 | * @param soundSize 当前音量大小 12 | */ 13 | void onSoundSize(int soundSize); 14 | 15 | } 16 | -------------------------------------------------------------------------------- /recorderlib/src/main/java/com/zlw/main/recorderlib/recorder/listener/RecordStateListener.java: -------------------------------------------------------------------------------- 1 | package com.zlw.main.recorderlib.recorder.listener; 2 | 3 | import com.zlw.main.recorderlib.recorder.RecordHelper; 4 | 5 | /** 6 | * @author zhaolewei on 2018/7/11. 7 | */ 8 | public interface RecordStateListener { 9 | 10 | /** 11 | * 当前的录音状态发生变化 12 | * 13 | * @param state 当前状态 14 | */ 15 | void onStateChange(RecordHelper.RecordState state); 16 | 17 | /** 18 | * 录音错误 19 | * 20 | * @param error 错误 21 | */ 22 | void onError(String error); 23 | 24 | } 25 | -------------------------------------------------------------------------------- /recorderlib/src/main/java/com/zlw/main/recorderlib/recorder/mp3/Mp3EncodeThread.java: -------------------------------------------------------------------------------- 1 | package com.zlw.main.recorderlib.recorder.mp3; 2 | 3 | import com.zlw.main.recorderlib.recorder.RecordConfig; 4 | import com.zlw.main.recorderlib.recorder.RecordService; 5 | import com.zlw.main.recorderlib.utils.Logger; 6 | 7 | import java.io.File; 8 | import java.io.FileNotFoundException; 9 | import java.io.FileOutputStream; 10 | import java.io.IOException; 11 | import java.util.Collections; 12 | import java.util.LinkedList; 13 | import java.util.List; 14 | 15 | /** 16 | * @author zhaolewei on 2018/8/2. 17 | */ 18 | public class Mp3EncodeThread extends Thread { 19 | private static final String TAG = Mp3EncodeThread.class.getSimpleName(); 20 | private List cacheBufferList = Collections.synchronizedList(new LinkedList()); 21 | private File file; 22 | private FileOutputStream os; 23 | private byte[] mp3Buffer; 24 | private EncordFinishListener encordFinishListener; 25 | 26 | /** 27 | * 是否已停止录音 28 | */ 29 | private volatile boolean isOver = false; 30 | 31 | /** 32 | * 是否继续轮询数据队列 33 | */ 34 | private volatile boolean start = true; 35 | 36 | public Mp3EncodeThread(File file, int bufferSize) { 37 | this.file = file; 38 | mp3Buffer = new byte[(int) (7200 + (bufferSize * 2 * 1.25))]; 39 | RecordConfig currentConfig = RecordService.getCurrentConfig(); 40 | int sampleRate = currentConfig.getSampleRate(); 41 | 42 | Logger.w(TAG, "in_sampleRate:%s,getChannelCount:%s ,out_sampleRate:%s 位宽: %s,", 43 | sampleRate, currentConfig.getChannelCount(), sampleRate, currentConfig.getRealEncoding()); 44 | Mp3Encoder.init(sampleRate, currentConfig.getChannelCount(), sampleRate, currentConfig.getRealEncoding()); 45 | } 46 | 47 | @Override 48 | public void run() { 49 | try { 50 | this.os = new FileOutputStream(file); 51 | } catch (FileNotFoundException e) { 52 | Logger.e(e, TAG, e.getMessage()); 53 | return; 54 | } 55 | 56 | while (start) { 57 | ChangeBuffer next = next(); 58 | Logger.v(TAG, "处理数据:%s", next == null ? "null" : next.getReadSize()); 59 | lameData(next); 60 | } 61 | } 62 | 63 | public void addChangeBuffer(ChangeBuffer changeBuffer) { 64 | if (changeBuffer != null) { 65 | cacheBufferList.add(changeBuffer); 66 | synchronized (this) { 67 | notify(); 68 | } 69 | } 70 | } 71 | 72 | public void stopSafe(EncordFinishListener encordFinishListener) { 73 | this.encordFinishListener = encordFinishListener; 74 | isOver = true; 75 | synchronized (this) { 76 | notify(); 77 | } 78 | } 79 | 80 | private ChangeBuffer next() { 81 | for (; ; ) { 82 | if (cacheBufferList == null || cacheBufferList.size() == 0) { 83 | try { 84 | if (isOver) { 85 | finish(); 86 | } 87 | synchronized (this) { 88 | wait(); 89 | } 90 | } catch (Exception e) { 91 | Logger.e(e, TAG, e.getMessage()); 92 | } 93 | } else { 94 | return cacheBufferList.remove(0); 95 | } 96 | } 97 | } 98 | 99 | private void lameData(ChangeBuffer changeBuffer) { 100 | if (changeBuffer == null) { 101 | return; 102 | } 103 | short[] buffer = changeBuffer.getData(); 104 | int readSize = changeBuffer.getReadSize(); 105 | if (readSize > 0) { 106 | int encodedSize = Mp3Encoder.encode(buffer, buffer, readSize, mp3Buffer); 107 | if (encodedSize < 0) { 108 | Logger.e(TAG, "Lame encoded size: " + encodedSize); 109 | } 110 | try { 111 | os.write(mp3Buffer, 0, encodedSize); 112 | } catch (IOException e) { 113 | Logger.e(e, TAG, "Unable to write to file"); 114 | } 115 | } 116 | } 117 | 118 | private void finish() { 119 | start = false; 120 | final int flushResult = Mp3Encoder.flush(mp3Buffer); 121 | if (flushResult > 0) { 122 | try { 123 | os.write(mp3Buffer, 0, flushResult); 124 | os.close(); 125 | } catch (final IOException e) { 126 | Logger.e(TAG, e.getMessage()); 127 | } 128 | } 129 | Logger.d(TAG, "转换结束 :%s", file.length()); 130 | if (encordFinishListener != null) { 131 | encordFinishListener.onFinish(); 132 | } 133 | } 134 | 135 | public static class ChangeBuffer { 136 | private short[] rawData; 137 | private int readSize; 138 | 139 | public ChangeBuffer(short[] rawData, int readSize) { 140 | this.rawData = rawData.clone(); 141 | this.readSize = readSize; 142 | } 143 | 144 | short[] getData() { 145 | return rawData; 146 | } 147 | 148 | int getReadSize() { 149 | return readSize; 150 | } 151 | } 152 | 153 | public interface EncordFinishListener { 154 | /** 155 | * 格式转换完毕 156 | */ 157 | void onFinish(); 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /recorderlib/src/main/java/com/zlw/main/recorderlib/recorder/mp3/Mp3Encoder.java: -------------------------------------------------------------------------------- 1 | package com.zlw.main.recorderlib.recorder.mp3; 2 | 3 | /** 4 | * @author zhaolewei on 2018/8/2. 5 | */ 6 | public class Mp3Encoder { 7 | 8 | static { 9 | System.loadLibrary("mp3lame"); 10 | } 11 | 12 | public native static void close(); 13 | 14 | public native static int encode(short[] buffer_l, short[] buffer_r, int samples, byte[] mp3buf); 15 | 16 | public native static int flush(byte[] mp3buf); 17 | 18 | public native static void init(int inSampleRate, int outChannel, int outSampleRate, int outBitrate, int quality); 19 | 20 | public static void init(int inSampleRate, int outChannel, int outSampleRate, int outBitrate) { 21 | init(inSampleRate, outChannel, outSampleRate, outBitrate, 7); 22 | } 23 | } -------------------------------------------------------------------------------- /recorderlib/src/main/java/com/zlw/main/recorderlib/recorder/mp3/Mp3Utils.java: -------------------------------------------------------------------------------- 1 | package com.zlw.main.recorderlib.recorder.mp3; 2 | 3 | import android.media.MediaExtractor; 4 | import android.media.MediaFormat; 5 | 6 | import com.zlw.main.recorderlib.recorder.RecordConfig; 7 | import com.zlw.main.recorderlib.utils.FileUtils; 8 | import com.zlw.main.recorderlib.utils.Logger; 9 | 10 | import java.io.IOException; 11 | 12 | /** 13 | * @author zhaolewei on 2018/8/3. 14 | */ 15 | public class Mp3Utils { 16 | private static final String TAG = Mp3Utils.class.getSimpleName(); 17 | 18 | /** 19 | * 获取mp3音频的总时长 单位:ms 20 | * 21 | * @param mp3FilePath MP3文件路径 22 | * @return 时长 23 | */ 24 | public static long getDuration(String mp3FilePath) { 25 | if (!FileUtils.isFileExists(mp3FilePath)) { 26 | return 0; 27 | } 28 | if (!mp3FilePath.endsWith(RecordConfig.RecordFormat.MP3.getExtension())) { 29 | return 0; 30 | } 31 | MediaExtractor mex = null; 32 | try { 33 | mex = new MediaExtractor(); 34 | mex.setDataSource(mp3FilePath); 35 | MediaFormat mf = mex.getTrackFormat(0); 36 | long duration = mf.getLong(MediaFormat.KEY_DURATION) / 1000L; 37 | return duration; 38 | } catch (IOException e) { 39 | Logger.e(e, TAG, e.getMessage()); 40 | } finally { 41 | if (mex != null) { 42 | mex.release(); 43 | } 44 | } 45 | return 0; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /recorderlib/src/main/java/com/zlw/main/recorderlib/utils/ByteUtils.java: -------------------------------------------------------------------------------- 1 | package com.zlw.main.recorderlib.utils; 2 | 3 | import java.nio.ByteBuffer; 4 | import java.util.Arrays; 5 | 6 | /** 7 | * @author zhaoleweion 2018/8/3. 8 | */ 9 | public class ByteUtils { 10 | 11 | 12 | /** 13 | * short[] 转 byte[] 14 | */ 15 | public static byte[] toBytes(short[] src) { 16 | int count = src.length; 17 | byte[] dest = new byte[count << 1]; 18 | for (int i = 0; i < count; i++) { 19 | dest[i * 2] = (byte) (src[i]); 20 | dest[i * 2 + 1] = (byte) (src[i] >> 8); 21 | } 22 | 23 | return dest; 24 | } 25 | 26 | 27 | /** 28 | * short[] 转 byte[] 29 | */ 30 | public static byte[] toBytes(short src) { 31 | byte[] dest = new byte[2]; 32 | dest[0] = (byte) (src); 33 | dest[1] = (byte) (src >> 8); 34 | 35 | return dest; 36 | } 37 | 38 | /** 39 | * int 转 byte[] 40 | */ 41 | public static byte[] toBytes(int i) { 42 | byte[] b = new byte[4]; 43 | b[0] = (byte) (i & 0xff); 44 | b[1] = (byte) ((i >> 8) & 0xff); 45 | b[2] = (byte) ((i >> 16) & 0xff); 46 | b[3] = (byte) ((i >> 24) & 0xff); 47 | return b; 48 | } 49 | 50 | 51 | /** 52 | * String 转 byte[] 53 | */ 54 | public static byte[] toBytes(String str) { 55 | return str.getBytes(); 56 | } 57 | 58 | /** 59 | * long类型转成byte数组 60 | */ 61 | public static byte[] toBytes(long number) { 62 | ByteBuffer buffer = ByteBuffer.allocate(8); 63 | buffer.putLong(0, number); 64 | return buffer.array(); 65 | } 66 | 67 | public static int toInt(byte[] src, int offset) { 68 | return ((src[offset] & 0xFF) 69 | | ((src[offset + 1] & 0xFF) << 8) 70 | | ((src[offset + 2] & 0xFF) << 16) 71 | | ((src[offset + 3] & 0xFF) << 24)); 72 | } 73 | 74 | public static int toInt(byte[] src) { 75 | return toInt(src, 0); 76 | } 77 | 78 | /** 79 | * 字节数组到long的转换. 80 | */ 81 | public static long toLong(byte[] b) { 82 | ByteBuffer buffer = ByteBuffer.allocate(8); 83 | buffer.put(b, 0, b.length); 84 | return buffer.getLong(); 85 | } 86 | 87 | /** 88 | * byte[] 转 short[] 89 | * short: 2字节 90 | */ 91 | public static short[] toShorts(byte[] src) { 92 | int count = src.length >> 1; 93 | short[] dest = new short[count]; 94 | for (int i = 0; i < count; i++) { 95 | dest[i] = (short) ((src[i * 2] & 0xff) | ((src[2 * i + 1] & 0xff) << 8)); 96 | } 97 | return dest; 98 | } 99 | 100 | public static byte[] merger(byte[] bt1, byte[] bt2) { 101 | byte[] bt3 = new byte[bt1.length + bt2.length]; 102 | System.arraycopy(bt1, 0, bt3, 0, bt1.length); 103 | System.arraycopy(bt2, 0, bt3, bt1.length, bt2.length); 104 | return bt3; 105 | } 106 | 107 | public static String toString(byte[] b) { 108 | return Arrays.toString(b); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /recorderlib/src/main/java/com/zlw/main/recorderlib/utils/FileUtils.java: -------------------------------------------------------------------------------- 1 | package com.zlw.main.recorderlib.utils; 2 | 3 | 4 | import java.io.File; 5 | import java.util.Date; 6 | 7 | /** 8 | * @author zhaolewei on 2018/7/10. 9 | */ 10 | public class FileUtils { 11 | 12 | public static boolean isFile(final File file) { 13 | return file != null && file.exists() && file.isFile(); 14 | } 15 | 16 | /** 17 | * Create a directory if it doesn't exist, otherwise do nothing. 18 | * 19 | * @param dirPath The path of directory. 20 | * @return {@code true}: exists or creates successfully
{@code false}: otherwise 21 | */ 22 | public static boolean createOrExistsDir(final String dirPath) { 23 | return createOrExistsDir(getFileByPath(dirPath)); 24 | } 25 | 26 | public static boolean createOrExistsDir(final File file) { 27 | return file != null && (file.exists() ? file.isDirectory() : file.mkdirs()); 28 | } 29 | 30 | public static File getFileByPath(final String filePath) { 31 | return isSpace(filePath) ? null : new File(filePath); 32 | } 33 | 34 | private static boolean isSpace(final String s) { 35 | if (s == null) { 36 | return true; 37 | } 38 | for (int i = 0, len = s.length(); i < len; ++i) { 39 | if (!Character.isWhitespace(s.charAt(i))) { 40 | return false; 41 | } 42 | } 43 | return true; 44 | } 45 | 46 | public static String getNowString(final java.text.DateFormat format) { 47 | return millis2String(System.currentTimeMillis(), format); 48 | } 49 | 50 | /** 51 | * Milliseconds to the formatted time string. 52 | * 53 | * @param millis The milliseconds. 54 | * @param format The format. 55 | * @return the formatted time string 56 | */ 57 | public static String millis2String(final long millis, final java.text.DateFormat format) { 58 | return format.format(new Date(millis)); 59 | } 60 | 61 | /** 62 | * Return whether the file exists. 63 | * 64 | * @param filePath The path of file. 65 | * @return {@code true}: yes
{@code false}: no 66 | */ 67 | public static boolean isFileExists(final String filePath) { 68 | return isFileExists(getFileByPath(filePath)); 69 | } 70 | 71 | /** 72 | * Return whether the file exists. 73 | * 74 | * @param file The file. 75 | * @return {@code true}: yes
{@code false}: no 76 | */ 77 | public static boolean isFileExists(final File file) { 78 | return file != null && file.exists(); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /recorderlib/src/main/java/com/zlw/main/recorderlib/utils/RecordUtils.java: -------------------------------------------------------------------------------- 1 | package com.zlw.main.recorderlib.utils; 2 | 3 | import java.nio.ByteBuffer; 4 | import java.nio.ByteOrder; 5 | import java.nio.FloatBuffer; 6 | 7 | /** 8 | * @author zhaolewei on 2018/7/31. 9 | */ 10 | public class RecordUtils { 11 | /** 12 | * 获取录音的声音分贝值 13 | * 计算公式:dB = 20 * log(a / a0); 14 | * @return 声音分贝值 15 | */ 16 | public static long getMaxDecibels(byte[] input) { 17 | short[] amplitudes = ByteUtils.toShorts(input); 18 | if (amplitudes == null) { 19 | return 0; 20 | } 21 | float maxAmplitude = 2; 22 | for (float amplitude : amplitudes) { 23 | if (Math.abs(maxAmplitude) < Math.abs(amplitude)) { 24 | maxAmplitude = amplitude; 25 | } 26 | } 27 | return Math.round(20 * Math.log10(maxAmplitude)); 28 | } 29 | 30 | 31 | public static float[] byteToFloat(byte[] input) { 32 | if (input == null) { 33 | return null; 34 | } 35 | int bytesPerSample = 2; 36 | ByteBuffer buffer = ByteBuffer.wrap(input); 37 | buffer.order(ByteOrder.LITTLE_ENDIAN); 38 | FloatBuffer floatBuffer = FloatBuffer.allocate(input.length / bytesPerSample); 39 | for (int i = 0; i < floatBuffer.capacity(); i++) { 40 | floatBuffer.put(buffer.getShort(i * bytesPerSample)); 41 | } 42 | return floatBuffer.array(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /recorderlib/src/main/java/fftlib/Complex.java: -------------------------------------------------------------------------------- 1 | package fftlib; 2 | 3 | import java.util.Objects; 4 | 5 | /** 6 | * 复数 7 | * 8 | * @author test 9 | */ 10 | public class Complex { 11 | 12 | /** 13 | * 实数部分 14 | */ 15 | private final double real; 16 | 17 | /** 18 | * 虚数部分 imaginary 19 | */ 20 | private final double im; 21 | 22 | public Complex(double real, double imag) { 23 | this.real = real; 24 | im = imag; 25 | } 26 | 27 | @Override 28 | public String toString() { 29 | return String.format("hypot: %s, complex: %s+%si", hypot(), real, im); 30 | } 31 | 32 | public double hypot() { 33 | return Math.hypot(real, im); 34 | } 35 | 36 | public double phase() { 37 | return Math.atan2(im, real); 38 | } 39 | 40 | /** 41 | * 复数求和 42 | */ 43 | public Complex plus(Complex b) { 44 | double real = this.real + b.real; 45 | double imag = this.im + b.im; 46 | return new Complex(real, imag); 47 | } 48 | 49 | // return a new Complex object whose value is (this - b) 50 | public Complex minus(Complex b) { 51 | double real = this.real - b.real; 52 | double imag = this.im - b.im; 53 | return new Complex(real, imag); 54 | } 55 | 56 | // return a new Complex object whose value is (this * b) 57 | public Complex times(Complex b) { 58 | Complex a = this; 59 | double real = a.real * b.real - a.im * b.im; 60 | double imag = a.real * b.im + a.im * b.real; 61 | return new Complex(real, imag); 62 | } 63 | 64 | // return a new object whose value is (this * alpha) 65 | public Complex scale(double alpha) { 66 | return new Complex(alpha * real, alpha * im); 67 | } 68 | 69 | // return a new Complex object whose value is the conjugate of this 70 | public Complex conjugate() { 71 | return new Complex(real, -im); 72 | } 73 | 74 | // return a new Complex object whose value is the reciprocal of this 75 | public Complex reciprocal() { 76 | double scale = real * real + im * im; 77 | return new Complex(real / scale, -im / scale); 78 | } 79 | 80 | // return the real or imaginary part 81 | public double re() { 82 | return real; 83 | } 84 | 85 | public double im() { 86 | return im; 87 | } 88 | 89 | // return a / b 90 | public Complex divides(Complex b) { 91 | Complex a = this; 92 | return a.times(b.reciprocal()); 93 | } 94 | 95 | // return a new Complex object whose value is the complex exponential of this 96 | public Complex exp() { 97 | return new Complex(Math.exp(real) * Math.cos(im), Math.exp(real) * Math.sin(im)); 98 | } 99 | 100 | // return a new Complex object whose value is the complex sine of this 101 | public Complex sin() { 102 | return new Complex(Math.sin(real) * Math.cosh(im), Math.cos(real) * Math.sinh(im)); 103 | } 104 | 105 | // return a new Complex object whose value is the complex cosine of this 106 | public Complex cos() { 107 | return new Complex(Math.cos(real) * Math.cosh(im), -Math.sin(real) * Math.sinh(im)); 108 | } 109 | 110 | // return a new Complex object whose value is the complex tangent of this 111 | public Complex tan() { 112 | return sin().divides(cos()); 113 | } 114 | 115 | 116 | // a static version of plus 117 | public static Complex plus(Complex a, Complex b) { 118 | double real = a.real + b.real; 119 | double imag = a.im + b.im; 120 | Complex sum = new Complex(real, imag); 121 | return sum; 122 | } 123 | 124 | // See Section 3.3. 125 | @Override 126 | public boolean equals(Object x) { 127 | if (x == null) return false; 128 | if (this.getClass() != x.getClass()) return false; 129 | Complex that = (Complex) x; 130 | return (this.real == that.real) && (this.im == that.im); 131 | } 132 | 133 | // See Section 3.3. 134 | @Override 135 | public int hashCode() { 136 | return Objects.hash(real, im); 137 | } 138 | 139 | } -------------------------------------------------------------------------------- /recorderlib/src/main/java/fftlib/FFT.java: -------------------------------------------------------------------------------- 1 | package fftlib; 2 | 3 | 4 | public class FFT { 5 | 6 | // compute the FFT of x[], assuming its length is a power of 2 7 | public static Complex[] fft(Complex[] x) { 8 | int n = x.length; 9 | 10 | // base case 11 | if (n == 1) return new Complex[]{x[0]}; 12 | 13 | // radix 2 Cooley-Tukey FFT 14 | if (n % 2 != 0) { 15 | throw new IllegalArgumentException("n is not a power of 2"); 16 | } 17 | 18 | // fft of even terms 19 | Complex[] even = new Complex[n / 2]; 20 | for (int k = 0; k < n / 2; k++) { 21 | even[k] = x[2 * k]; 22 | } 23 | Complex[] q = fft(even); 24 | 25 | // fft of odd terms 26 | for (int k = 0; k < n / 2; k++) { 27 | even[k] = x[2 * k + 1]; 28 | } 29 | Complex[] r = fft(even); 30 | 31 | // combine 32 | Complex[] y = new Complex[n]; 33 | for (int k = 0; k < n / 2; k++) { 34 | double kth = -2 * k * Math.PI / n; 35 | Complex wk = new Complex(Math.cos(kth), Math.sin(kth)); 36 | y[k] = q[k].plus(wk.times(r[k])); 37 | y[k + n / 2] = q[k].minus(wk.times(r[k])); 38 | } 39 | return y; 40 | } 41 | 42 | public static double[] fft(double[] x, int sc) { 43 | int len = x.length; 44 | if (len == 1) { 45 | return x; 46 | } 47 | Complex[] cs = new Complex[len]; 48 | double[] ds = new double[len / 2]; 49 | for (int i = 0; i < len; i++) { 50 | cs[i] = new Complex(x[i], 0); 51 | } 52 | Complex[] ffts = fft(cs); 53 | 54 | for (int i = 0; i < ds.length; i++) { 55 | ds[i] = Math.sqrt(Math.pow(ffts[i].re(), 2) + Math.pow(ffts[i].im(), 2)) / x.length; 56 | } 57 | return ds; 58 | } 59 | 60 | // compute the inverse FFT of x[], assuming its length is a power of 2 61 | public static Complex[] ifft(Complex[] x) { 62 | int n = x.length; 63 | Complex[] y = new Complex[n]; 64 | 65 | // take conjugate 66 | for (int i = 0; i < n; i++) { 67 | y[i] = x[i].conjugate(); 68 | } 69 | 70 | // compute forward FFT 71 | y = fft(y); 72 | 73 | // take conjugate again 74 | for (int i = 0; i < n; i++) { 75 | y[i] = y[i].conjugate(); 76 | } 77 | 78 | // divide by n 79 | for (int i = 0; i < n; i++) { 80 | y[i] = y[i].scale(1.0 / n); 81 | } 82 | 83 | return y; 84 | 85 | } 86 | 87 | // compute the circular convolution of x and y 88 | public static Complex[] cconvolve(Complex[] x, Complex[] y) { 89 | 90 | // should probably pad x and y with 0s so that they have same length 91 | // and are powers of 2 92 | if (x.length != y.length) { 93 | throw new IllegalArgumentException("Dimensions don't agree"); 94 | } 95 | 96 | int n = x.length; 97 | 98 | // compute FFT of each sequence 99 | Complex[] a = fft(x); 100 | Complex[] b = fft(y); 101 | 102 | // point-wise multiply 103 | Complex[] c = new Complex[n]; 104 | for (int i = 0; i < n; i++) { 105 | c[i] = a[i].times(b[i]); 106 | } 107 | 108 | // compute inverse FFT 109 | return ifft(c); 110 | } 111 | 112 | 113 | // compute the linear convolution of x and y 114 | public static Complex[] convolve(Complex[] x, Complex[] y) { 115 | Complex ZERO = new Complex(0, 0); 116 | 117 | Complex[] a = new Complex[2 * x.length]; 118 | for (int i = 0; i < x.length; i++) a[i] = x[i]; 119 | for (int i = x.length; i < 2 * x.length; i++) a[i] = ZERO; 120 | 121 | Complex[] b = new Complex[2 * y.length]; 122 | for (int i = 0; i < y.length; i++) b[i] = y[i]; 123 | for (int i = y.length; i < 2 * y.length; i++) b[i] = ZERO; 124 | 125 | return cconvolve(a, b); 126 | } 127 | 128 | // display an array of Complex numbers to standard output 129 | public static void show(Complex[] x, String title) { 130 | System.out.println(title); 131 | System.out.println("-------------------"); 132 | for (int i = 0; i < SIZE; i++) { 133 | System.out.println(x[i]); 134 | } 135 | System.out.println(); 136 | } 137 | 138 | private static final int SIZE = 16384 / 4; 139 | 140 | public static double fun(int x) { 141 | return Math.sin(15f * x);//f= 3.142 142 | } 143 | 144 | public static double getY(double[] d) { 145 | double y = 0; 146 | int x = 0; 147 | for (int i = 0; i < d.length; i++) { 148 | if (d[i] > y) { 149 | y = d[i]; 150 | x = i; 151 | } 152 | } 153 | x++; 154 | log(String.format("x: %s , y: %s", x, y)); 155 | log(String.format("频率: %sHz", (float) x / SIZE)); 156 | log(String.format("频率2: %sHz", (float) (SIZE - x) / SIZE)); 157 | log(String.format("振幅: %s", y)); 158 | return y; 159 | } 160 | 161 | public static void log(String s) { 162 | System.out.println(s); 163 | } 164 | 165 | } -------------------------------------------------------------------------------- /recorderlib/src/main/java/fftlib/FftFactory.java: -------------------------------------------------------------------------------- 1 | package fftlib; 2 | 3 | import com.zlw.main.recorderlib.utils.Logger; 4 | 5 | /** 6 | * FFT 数据处理工厂 7 | */ 8 | public class FftFactory { 9 | private static final String TAG = FftFactory.class.getSimpleName(); 10 | private Level level = Level.Original; 11 | 12 | public FftFactory(Level level) { 13 | // this.level = level; 14 | } 15 | 16 | public byte[] makeFftData(byte[] pcmData) { 17 | // Logger.d(TAG, "pcmData length: %s", pcmData.length); 18 | if (pcmData.length < 1024) { 19 | Logger.d(TAG, "makeFftData"); 20 | return null; 21 | } 22 | 23 | double[] doubles = ByteUtils.toHardDouble(ByteUtils.toShorts(pcmData)); 24 | double[] fft = FFT.fft(doubles, 0); 25 | 26 | switch (level) { 27 | case Original: 28 | return ByteUtils.toSoftBytes(fft); 29 | case Maximal: 30 | // return doFftMaximal(fft); 31 | default: 32 | return ByteUtils.toHardBytes(fft); 33 | } 34 | } 35 | 36 | 37 | private byte[] doFftMaximal(double[] fft) { 38 | byte[] bytes = ByteUtils.toSoftBytes(fft); 39 | byte[] result = new byte[bytes.length]; 40 | 41 | for (int i = 0; i < bytes.length; i++) { 42 | 43 | if (isSimpleData(bytes, i)) { 44 | result[i] = bytes[i]; 45 | } else { 46 | result[Math.max(i - 1, 0)] = (byte) (bytes[i] / 2); 47 | result[Math.min(i + 1, result.length - 1)] = (byte) (bytes[i] / 2); 48 | } 49 | } 50 | 51 | return result; 52 | } 53 | 54 | private boolean isSimpleData(byte[] data, int i) { 55 | 56 | int start = Math.max(0, i - 5); 57 | int end = Math.min(data.length, i + 5); 58 | 59 | byte max = 0, min = 127; 60 | for (int j = start; j < end; j++) { 61 | if (data[j] > max) { 62 | max = data[j]; 63 | } 64 | if (data[j] < min) { 65 | min = data[j]; 66 | } 67 | } 68 | 69 | return data[i] == min || data[i] == max; 70 | } 71 | 72 | 73 | /** 74 | * FFT 处理等级 75 | */ 76 | public enum Level { 77 | 78 | /** 79 | * 原始数据,不做任何优化 80 | */ 81 | Original, 82 | 83 | /** 84 | * 对音乐进行优化 85 | */ 86 | Music, 87 | 88 | /** 89 | * 对人声进行优化 90 | */ 91 | People, 92 | 93 | /** 94 | * 极限优化 95 | */ 96 | Maximal 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /recorderlib/src/main/jni/Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH := $(call my-dir) 2 | 3 | include $(CLEAR_VARS) 4 | 5 | LAME_LIBMP3_DIR := lame-3.100_libmp3lame 6 | 7 | LOCAL_MODULE := mp3lame 8 | 9 | LOCAL_SRC_FILES :=\ 10 | $(LAME_LIBMP3_DIR)/bitstream.c \ 11 | $(LAME_LIBMP3_DIR)/fft.c \ 12 | $(LAME_LIBMP3_DIR)/id3tag.c \ 13 | $(LAME_LIBMP3_DIR)/mpglib_interface.c \ 14 | $(LAME_LIBMP3_DIR)/presets.c \ 15 | $(LAME_LIBMP3_DIR)/quantize.c \ 16 | $(LAME_LIBMP3_DIR)/reservoir.c \ 17 | $(LAME_LIBMP3_DIR)/tables.c \ 18 | $(LAME_LIBMP3_DIR)/util.c \ 19 | $(LAME_LIBMP3_DIR)/VbrTag.c \ 20 | $(LAME_LIBMP3_DIR)/encoder.c \ 21 | $(LAME_LIBMP3_DIR)/gain_analysis.c \ 22 | $(LAME_LIBMP3_DIR)/lame.c \ 23 | $(LAME_LIBMP3_DIR)/newmdct.c \ 24 | $(LAME_LIBMP3_DIR)/psymodel.c \ 25 | $(LAME_LIBMP3_DIR)/quantize_pvt.c \ 26 | $(LAME_LIBMP3_DIR)/set_get.c \ 27 | $(LAME_LIBMP3_DIR)/takehiro.c \ 28 | $(LAME_LIBMP3_DIR)/vbrquantize.c \ 29 | $(LAME_LIBMP3_DIR)/version.c \ 30 | MP3Encoder.c 31 | 32 | include $(BUILD_SHARED_LIBRARY) 33 | -------------------------------------------------------------------------------- /recorderlib/src/main/jni/Application.mk: -------------------------------------------------------------------------------- 1 | APP_ABI := armeabi armeabi-v7a arm64-v8a x86 x86_64 mips mips64 2 | APP_MODULES := mp3lame 3 | APP_CFLAGS += -DSTDC_HEADERS 4 | APP_PLATFORM := android-21 5 | -------------------------------------------------------------------------------- /recorderlib/src/main/jni/Mp3Encoder.c: -------------------------------------------------------------------------------- 1 | #include "lame-3.100_libmp3lame/lame.h" 2 | #include "Mp3Encoder.h" 3 | 4 | static lame_global_flags *glf = NULL; 5 | 6 | JNIEXPORT void JNICALL Java_com_zlw_main_recorderlib_recorder_mp3_Mp3Encoder_init( 7 | JNIEnv *env, jclass cls, jint inSamplerate, jint outChannel, 8 | jint outSamplerate, jint outBitrate, jint quality) { 9 | if (glf != NULL) { 10 | lame_close(glf); 11 | glf = NULL; 12 | } 13 | glf = lame_init(); 14 | lame_set_in_samplerate(glf, inSamplerate); 15 | lame_set_num_channels(glf, outChannel); 16 | lame_set_out_samplerate(glf, outSamplerate); 17 | lame_set_brate(glf, outBitrate); 18 | lame_set_quality(glf, quality); 19 | lame_init_params(glf); 20 | } 21 | 22 | JNIEXPORT jint JNICALL Java_com_zlw_main_recorderlib_recorder_mp3_Mp3Encoder_encode( 23 | JNIEnv *env, jclass cls, jshortArray buffer_l, jshortArray buffer_r, 24 | jint samples, jbyteArray mp3buf) { 25 | jshort* j_buffer_l = (*env)->GetShortArrayElements(env, buffer_l, NULL); 26 | 27 | jshort* j_buffer_r = (*env)->GetShortArrayElements(env, buffer_r, NULL); 28 | 29 | const jsize mp3buf_size = (*env)->GetArrayLength(env, mp3buf); 30 | jbyte* j_mp3buf = (*env)->GetByteArrayElements(env, mp3buf, NULL); 31 | 32 | int result = lame_encode_buffer(glf, j_buffer_l, j_buffer_r, 33 | samples, j_mp3buf, mp3buf_size); 34 | 35 | (*env)->ReleaseShortArrayElements(env, buffer_l, j_buffer_l, 0); 36 | (*env)->ReleaseShortArrayElements(env, buffer_r, j_buffer_r, 0); 37 | (*env)->ReleaseByteArrayElements(env, mp3buf, j_mp3buf, 0); 38 | 39 | return result; 40 | } 41 | 42 | JNIEXPORT jint JNICALL Java_com_zlw_main_recorderlib_recorder_mp3_Mp3Encoder_flush( 43 | JNIEnv *env, jclass cls, jbyteArray mp3buf) { 44 | const jsize mp3buf_size = (*env)->GetArrayLength(env, mp3buf); 45 | jbyte* j_mp3buf = (*env)->GetByteArrayElements(env, mp3buf, NULL); 46 | 47 | int result = lame_encode_flush(glf, j_mp3buf, mp3buf_size); 48 | 49 | (*env)->ReleaseByteArrayElements(env, mp3buf, j_mp3buf, 0); 50 | 51 | return result; 52 | } 53 | 54 | JNIEXPORT void JNICALL Java_com_zlw_main_recorderlib_recorder_mp3_Mp3Encoder_close( 55 | JNIEnv *env, jclass cls) { 56 | lame_close(glf); 57 | glf = NULL; 58 | } 59 | -------------------------------------------------------------------------------- /recorderlib/src/main/jni/Mp3Encoder.h: -------------------------------------------------------------------------------- 1 | /* DO NOT EDIT THIS FILE - it is machine generated */ 2 | #include 3 | 4 | #ifndef _Included_Mp3Encoder 5 | #define _Included_Mp3Encoder 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | /* 10 | * Class: com.zlw.main.recorderlib.recorder.mp3.Mp3Encoder 11 | * Method: init 12 | */ 13 | JNIEXPORT void JNICALL Java_com_zlw_main_recorderlib_recorder_mp3_Mp3Encoder_init 14 | (JNIEnv *, jclass, jint, jint, jint, jint, jint); 15 | 16 | JNIEXPORT jint JNICALL Java_com_zlw_main_recorderlib_recorder_mp3_Mp3Encoder_encode 17 | (JNIEnv *, jclass, jshortArray, jshortArray, jint, jbyteArray); 18 | 19 | JNIEXPORT jint JNICALL Java_com_zlw_main_recorderlib_recorder_mp3_Mp3Encoder_flush 20 | (JNIEnv *, jclass, jbyteArray); 21 | 22 | JNIEXPORT void JNICALL Java_com_zlw_main_recorderlib_recorder_mp3_Mp3Encoder_close 23 | (JNIEnv *, jclass); 24 | 25 | #ifdef __cplusplus 26 | } 27 | #endif 28 | #endif 29 | -------------------------------------------------------------------------------- /recorderlib/src/main/jni/lame-3.100_libmp3lame/VbrTag.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Xing VBR tagging for LAME. 3 | * 4 | * Copyright (c) 1999 A.L. Faber 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Library General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Library General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Library General Public 17 | * License along with this library; if not, write to the 18 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 19 | * Boston, MA 02111-1307, USA. 20 | */ 21 | 22 | #ifndef LAME_VRBTAG_H 23 | #define LAME_VRBTAG_H 24 | 25 | 26 | /* ----------------------------------------------------------- 27 | * A Vbr header may be present in the ancillary 28 | * data field of the first frame of an mp3 bitstream 29 | * The Vbr header (optionally) contains 30 | * frames total number of audio frames in the bitstream 31 | * bytes total number of bytes in the bitstream 32 | * toc table of contents 33 | 34 | * toc (table of contents) gives seek points 35 | * for random access 36 | * the ith entry determines the seek point for 37 | * i-percent duration 38 | * seek point in bytes = (toc[i]/256.0) * total_bitstream_bytes 39 | * e.g. half duration seek point = (toc[50]/256.0) * total_bitstream_bytes 40 | */ 41 | 42 | 43 | #define FRAMES_FLAG 0x0001 44 | #define BYTES_FLAG 0x0002 45 | #define TOC_FLAG 0x0004 46 | #define VBR_SCALE_FLAG 0x0008 47 | 48 | #define NUMTOCENTRIES 100 49 | 50 | #ifndef lame_internal_flags_defined 51 | #define lame_internal_flags_defined 52 | struct lame_internal_flags; 53 | typedef struct lame_internal_flags lame_internal_flags; 54 | #endif 55 | 56 | 57 | /*structure to receive extracted header */ 58 | /* toc may be NULL*/ 59 | typedef struct { 60 | int h_id; /* from MPEG header, 0=MPEG2, 1=MPEG1 */ 61 | int samprate; /* determined from MPEG header */ 62 | int flags; /* from Vbr header data */ 63 | int frames; /* total bit stream frames from Vbr header data */ 64 | int bytes; /* total bit stream bytes from Vbr header data */ 65 | int vbr_scale; /* encoded vbr scale from Vbr header data */ 66 | unsigned char toc[NUMTOCENTRIES]; /* may be NULL if toc not desired */ 67 | int headersize; /* size of VBR header, in bytes */ 68 | int enc_delay; /* encoder delay */ 69 | int enc_padding; /* encoder paddign added at end of stream */ 70 | } VBRTAGDATA; 71 | 72 | int GetVbrTag(VBRTAGDATA * pTagData, const unsigned char *buf); 73 | 74 | int InitVbrTag(lame_global_flags * gfp); 75 | int PutVbrTag(lame_global_flags const *gfp, FILE * fid); 76 | void AddVbrFrame(lame_internal_flags * gfc); 77 | void UpdateMusicCRC(uint16_t * crc, const unsigned char *buffer, int size); 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /recorderlib/src/main/jni/lame-3.100_libmp3lame/bitstream.h: -------------------------------------------------------------------------------- 1 | /* 2 | * MP3 bitstream Output interface for LAME 3 | * 4 | * Copyright (c) 1999 Takehiro TOMINAGA 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Library General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Library General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Library General Public 17 | * License along with this library; if not, write to the 18 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 19 | * Boston, MA 02111-1307, USA. 20 | */ 21 | 22 | #ifndef LAME_BITSTREAM_H 23 | #define LAME_BITSTREAM_H 24 | 25 | int getframebits(const lame_internal_flags * gfc); 26 | 27 | int format_bitstream(lame_internal_flags * gfc); 28 | 29 | void flush_bitstream(lame_internal_flags * gfc); 30 | void add_dummy_byte(lame_internal_flags * gfc, unsigned char val, unsigned int n); 31 | 32 | int copy_buffer(lame_internal_flags * gfc, unsigned char *buffer, int buffer_size, 33 | int update_crc); 34 | void init_bit_stream_w(lame_internal_flags * gfc); 35 | void CRC_writeheader(lame_internal_flags const *gfc, char *buffer); 36 | int compute_flushbits(const lame_internal_flags * gfp, int *nbytes); 37 | 38 | int get_max_frame_buffer_size_by_constraint(SessionConfig_t const * cfg, int constraint); 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /recorderlib/src/main/jni/lame-3.100_libmp3lame/encoder.h: -------------------------------------------------------------------------------- 1 | /* 2 | * encoder.h include file 3 | * 4 | * Copyright (c) 2000 Mark Taylor 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Library General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Library General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Library General Public 17 | * License along with this library; if not, write to the 18 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 19 | * Boston, MA 02111-1307, USA. 20 | */ 21 | 22 | 23 | #ifndef LAME_ENCODER_H 24 | #define LAME_ENCODER_H 25 | 26 | /*********************************************************************** 27 | * 28 | * encoder and decoder delays 29 | * 30 | ***********************************************************************/ 31 | 32 | /* 33 | * layer III enc->dec delay: 1056 (1057?) (observed) 34 | * layer II enc->dec delay: 480 (481?) (observed) 35 | * 36 | * polyphase 256-16 (dec or enc) = 240 37 | * mdct 256+32 (9*32) (dec or enc) = 288 38 | * total: 512+16 39 | * 40 | * My guess is that delay of polyphase filterbank is actualy 240.5 41 | * (there are technical reasons for this, see postings in mp3encoder). 42 | * So total Encode+Decode delay = ENCDELAY + 528 + 1 43 | */ 44 | 45 | /* 46 | * ENCDELAY The encoder delay. 47 | * 48 | * Minimum allowed is MDCTDELAY (see below) 49 | * 50 | * The first 96 samples will be attenuated, so using a value less than 96 51 | * will result in corrupt data for the first 96-ENCDELAY samples. 52 | * 53 | * suggested: 576 54 | * set to 1160 to sync with FhG. 55 | */ 56 | 57 | #define ENCDELAY 576 58 | 59 | 60 | 61 | /* 62 | * make sure there is at least one complete frame after the 63 | * last frame containing real data 64 | * 65 | * Using a value of 288 would be sufficient for a 66 | * a very sophisticated decoder that can decode granule-by-granule instead 67 | * of frame by frame. But lets not assume this, and assume the decoder 68 | * will not decode frame N unless it also has data for frame N+1 69 | * 70 | */ 71 | /*#define POSTDELAY 288*/ 72 | #define POSTDELAY 1152 73 | 74 | 75 | 76 | /* 77 | * delay of the MDCT used in mdct.c 78 | * original ISO routines had a delay of 528! 79 | * Takehiro's routines: 80 | */ 81 | 82 | #define MDCTDELAY 48 83 | #define FFTOFFSET (224+MDCTDELAY) 84 | 85 | /* 86 | * Most decoders, including the one we use, have a delay of 528 samples. 87 | */ 88 | 89 | #define DECDELAY 528 90 | 91 | 92 | /* number of subbands */ 93 | #define SBLIMIT 32 94 | 95 | /* parition bands bands */ 96 | #define CBANDS 64 97 | 98 | /* number of critical bands/scale factor bands where masking is computed*/ 99 | #define SBPSY_l 21 100 | #define SBPSY_s 12 101 | 102 | /* total number of scalefactor bands encoded */ 103 | #define SBMAX_l 22 104 | #define SBMAX_s 13 105 | #define PSFB21 6 106 | #define PSFB12 6 107 | 108 | 109 | 110 | /* FFT sizes */ 111 | #define BLKSIZE 1024 112 | #define HBLKSIZE (BLKSIZE/2 + 1) 113 | #define BLKSIZE_s 256 114 | #define HBLKSIZE_s (BLKSIZE_s/2 + 1) 115 | 116 | 117 | /* #define switch_pe 1800 */ 118 | #define NORM_TYPE 0 119 | #define START_TYPE 1 120 | #define SHORT_TYPE 2 121 | #define STOP_TYPE 3 122 | 123 | /* 124 | * Mode Extention: 125 | * When we are in stereo mode, there are 4 possible methods to store these 126 | * two channels. The stereo modes -m? are using a subset of them. 127 | * 128 | * -ms: MPG_MD_LR_LR 129 | * -mj: MPG_MD_LR_LR and MPG_MD_MS_LR 130 | * -mf: MPG_MD_MS_LR 131 | * -mi: all 132 | */ 133 | #if 0 134 | #define MPG_MD_LR_LR 0 135 | #define MPG_MD_LR_I 1 136 | #define MPG_MD_MS_LR 2 137 | #define MPG_MD_MS_I 3 138 | #endif 139 | enum MPEGChannelMode 140 | { MPG_MD_LR_LR = 0 141 | , MPG_MD_LR_I = 1 142 | , MPG_MD_MS_LR = 2 143 | , MPG_MD_MS_I = 3 144 | }; 145 | 146 | #ifndef lame_internal_flags_defined 147 | #define lame_internal_flags_defined 148 | struct lame_internal_flags; 149 | typedef struct lame_internal_flags lame_internal_flags; 150 | #endif 151 | 152 | int lame_encode_mp3_frame(lame_internal_flags * gfc, 153 | sample_t const *inbuf_l, 154 | sample_t const *inbuf_r, unsigned char *mp3buf, int mp3buf_size); 155 | 156 | #endif /* LAME_ENCODER_H */ 157 | -------------------------------------------------------------------------------- /recorderlib/src/main/jni/lame-3.100_libmp3lame/fft.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Fast Fourier Transform include file 3 | * 4 | * Copyright (c) 2000 Mark Taylor 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Library General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Library General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Library General Public 17 | * License along with this library; if not, write to the 18 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 19 | * Boston, MA 02111-1307, USA. 20 | */ 21 | 22 | #ifndef LAME_FFT_H 23 | #define LAME_FFT_H 24 | 25 | void fft_long(lame_internal_flags const *const gfc, FLOAT x_real[BLKSIZE], 26 | int chn, const sample_t *const data[2]); 27 | 28 | void fft_short(lame_internal_flags const *const gfc, FLOAT x_real[3][BLKSIZE_s], 29 | int chn, const sample_t *const data[2]); 30 | 31 | void init_fft(lame_internal_flags * const gfc); 32 | 33 | #endif 34 | 35 | /* End of fft.h */ 36 | -------------------------------------------------------------------------------- /recorderlib/src/main/jni/lame-3.100_libmp3lame/gain_analysis.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ReplayGainAnalysis - analyzes input samples and give the recommended dB change 3 | * Copyright (C) 2001 David Robinson and Glen Sawyer 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | * 19 | * concept and filter values by David Robinson (David@Robinson.org) 20 | * -- blame him if you think the idea is flawed 21 | * coding by Glen Sawyer (mp3gain@hotmail.com) 735 W 255 N, Orem, UT 84057-4505 USA 22 | * -- blame him if you think this runs too slowly, or the coding is otherwise flawed 23 | * 24 | * For an explanation of the concepts and the basic algorithms involved, go to: 25 | * http://www.replaygain.org/ 26 | */ 27 | 28 | #ifndef GAIN_ANALYSIS_H 29 | #define GAIN_ANALYSIS_H 30 | 31 | #ifdef HAVE_INTTYPES_H 32 | # include 33 | #else 34 | # ifdef HAVE_STDINT_H 35 | # include 36 | # endif 37 | #endif 38 | 39 | #ifdef __cplusplus 40 | extern "C" { 41 | #endif 42 | 43 | 44 | typedef sample_t Float_t; /* Type used for filtering */ 45 | 46 | 47 | #define PINK_REF 64.82 /* 298640883795 */ /* calibration value for 89dB */ 48 | 49 | 50 | #define YULE_ORDER 10 51 | #define BUTTER_ORDER 2 52 | #define YULE_FILTER filterYule 53 | #define BUTTER_FILTER filterButter 54 | #define RMS_PERCENTILE 0.95 /* percentile which is louder than the proposed level */ 55 | #define MAX_SAMP_FREQ 48000L /* maximum allowed sample frequency [Hz] */ 56 | #define RMS_WINDOW_TIME_NUMERATOR 1L 57 | #define RMS_WINDOW_TIME_DENOMINATOR 20L /* numerator / denominator = time slice size [s] */ 58 | #define STEPS_per_dB 100 /* Table entries per dB */ 59 | #define MAX_dB 120 /* Table entries for 0...MAX_dB (normal max. values are 70...80 dB) */ 60 | 61 | enum { GAIN_NOT_ENOUGH_SAMPLES = -24601, GAIN_ANALYSIS_ERROR = 0, GAIN_ANALYSIS_OK = 62 | 1, INIT_GAIN_ANALYSIS_ERROR = 0, INIT_GAIN_ANALYSIS_OK = 1 63 | }; 64 | 65 | enum { MAX_ORDER = (BUTTER_ORDER > YULE_ORDER ? BUTTER_ORDER : YULE_ORDER) 66 | , MAX_SAMPLES_PER_WINDOW = ((MAX_SAMP_FREQ * RMS_WINDOW_TIME_NUMERATOR) / RMS_WINDOW_TIME_DENOMINATOR + 1) /* max. Samples per Time slice */ 67 | }; 68 | 69 | struct replaygain_data { 70 | Float_t linprebuf[MAX_ORDER * 2]; 71 | Float_t *linpre; /* left input samples, with pre-buffer */ 72 | Float_t lstepbuf[MAX_SAMPLES_PER_WINDOW + MAX_ORDER]; 73 | Float_t *lstep; /* left "first step" (i.e. post first filter) samples */ 74 | Float_t loutbuf[MAX_SAMPLES_PER_WINDOW + MAX_ORDER]; 75 | Float_t *lout; /* left "out" (i.e. post second filter) samples */ 76 | Float_t rinprebuf[MAX_ORDER * 2]; 77 | Float_t *rinpre; /* right input samples ... */ 78 | Float_t rstepbuf[MAX_SAMPLES_PER_WINDOW + MAX_ORDER]; 79 | Float_t *rstep; 80 | Float_t routbuf[MAX_SAMPLES_PER_WINDOW + MAX_ORDER]; 81 | Float_t *rout; 82 | long sampleWindow; /* number of samples required to reach number of milliseconds required for RMS window */ 83 | long totsamp; 84 | double lsum; 85 | double rsum; 86 | int freqindex; 87 | int first; 88 | uint32_t A[STEPS_per_dB * MAX_dB]; 89 | uint32_t B[STEPS_per_dB * MAX_dB]; 90 | 91 | }; 92 | #ifndef replaygain_data_defined 93 | #define replaygain_data_defined 94 | typedef struct replaygain_data replaygain_t; 95 | #endif 96 | 97 | 98 | 99 | 100 | int InitGainAnalysis(replaygain_t * rgData, long samplefreq); 101 | int AnalyzeSamples(replaygain_t * rgData, const Float_t * left_samples, 102 | const Float_t * right_samples, size_t num_samples, int num_channels); 103 | Float_t GetTitleGain(replaygain_t * rgData); 104 | 105 | 106 | #ifdef __cplusplus 107 | } 108 | #endif 109 | #endif /* GAIN_ANALYSIS_H */ 110 | -------------------------------------------------------------------------------- /recorderlib/src/main/jni/lame-3.100_libmp3lame/id3tag.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef LAME_ID3_H 3 | #define LAME_ID3_H 4 | 5 | 6 | #define CHANGED_FLAG (1U << 0) 7 | #define ADD_V2_FLAG (1U << 1) 8 | #define V1_ONLY_FLAG (1U << 2) 9 | #define V2_ONLY_FLAG (1U << 3) 10 | #define SPACE_V1_FLAG (1U << 4) 11 | #define PAD_V2_FLAG (1U << 5) 12 | 13 | enum { 14 | MIMETYPE_NONE = 0, 15 | MIMETYPE_JPEG, 16 | MIMETYPE_PNG, 17 | MIMETYPE_GIF 18 | }; 19 | 20 | typedef struct FrameDataNode { 21 | struct FrameDataNode *nxt; 22 | uint32_t fid; /* Frame Identifier */ 23 | char lng[4]; /* 3-character language descriptor */ 24 | struct { 25 | union { 26 | char *l; /* ptr to Latin-1 chars */ 27 | unsigned short *u; /* ptr to UCS-2 text */ 28 | unsigned char *b; /* ptr to raw bytes */ 29 | } ptr; 30 | size_t dim; 31 | int enc; /* 0:Latin-1, 1:UCS-2, 2:RAW */ 32 | } dsc , txt; 33 | } FrameDataNode; 34 | 35 | 36 | typedef struct id3tag_spec { 37 | /* private data members */ 38 | unsigned int flags; 39 | int year; 40 | char *title; 41 | char *artist; 42 | char *album; 43 | char *comment; 44 | int track_id3v1; 45 | int genre_id3v1; 46 | unsigned char *albumart; 47 | unsigned int albumart_size; 48 | unsigned int padding_size; 49 | int albumart_mimetype; 50 | char language[4]; /* the language of the frame's content, according to ISO-639-2 */ 51 | FrameDataNode *v2_head, *v2_tail; 52 | } id3tag_spec; 53 | 54 | 55 | /* write tag into stream at current position */ 56 | extern int id3tag_write_v2(lame_global_flags * gfp); 57 | extern int id3tag_write_v1(lame_global_flags * gfp); 58 | /* 59 | * NOTE: A version 2 tag will NOT be added unless one of the text fields won't 60 | * fit in a version 1 tag (e.g. the title string is longer than 30 characters), 61 | * or the "id3tag_add_v2" or "id3tag_v2_only" functions are used. 62 | */ 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /recorderlib/src/main/jni/lame-3.100_libmp3lame/l3side.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Layer 3 side include file 3 | * 4 | * Copyright (c) 1999 Mark Taylor 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Library General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Library General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Library General Public 17 | * License along with this library; if not, write to the 18 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 19 | * Boston, MA 02111-1307, USA. 20 | */ 21 | 22 | #ifndef LAME_L3SIDE_H 23 | #define LAME_L3SIDE_H 24 | 25 | /* max scalefactor band, max(SBMAX_l, SBMAX_s*3, (SBMAX_s-3)*3+8) */ 26 | #define SFBMAX (SBMAX_s*3) 27 | 28 | /* Layer III side information. */ 29 | typedef struct { 30 | int l[1 + SBMAX_l]; 31 | int s[1 + SBMAX_s]; 32 | int psfb21[1 + PSFB21]; 33 | int psfb12[1 + PSFB12]; 34 | } scalefac_struct; 35 | 36 | 37 | typedef struct { 38 | FLOAT l[SBMAX_l]; 39 | FLOAT s[SBMAX_s][3]; 40 | } III_psy_xmin; 41 | 42 | typedef struct { 43 | III_psy_xmin thm; 44 | III_psy_xmin en; 45 | } III_psy_ratio; 46 | 47 | typedef struct { 48 | FLOAT xr[576]; 49 | int l3_enc[576]; 50 | int scalefac[SFBMAX]; 51 | FLOAT xrpow_max; 52 | 53 | int part2_3_length; 54 | int big_values; 55 | int count1; 56 | int global_gain; 57 | int scalefac_compress; 58 | int block_type; 59 | int mixed_block_flag; 60 | int table_select[3]; 61 | int subblock_gain[3 + 1]; 62 | int region0_count; 63 | int region1_count; 64 | int preflag; 65 | int scalefac_scale; 66 | int count1table_select; 67 | 68 | int part2_length; 69 | int sfb_lmax; 70 | int sfb_smin; 71 | int psy_lmax; 72 | int sfbmax; 73 | int psymax; 74 | int sfbdivide; 75 | int width[SFBMAX]; 76 | int window[SFBMAX]; 77 | int count1bits; 78 | /* added for LSF */ 79 | const int *sfb_partition_table; 80 | int slen[4]; 81 | 82 | int max_nonzero_coeff; 83 | char energy_above_cutoff[SFBMAX]; 84 | } gr_info; 85 | 86 | typedef struct { 87 | gr_info tt[2][2]; 88 | int main_data_begin; 89 | int private_bits; 90 | int resvDrain_pre; 91 | int resvDrain_post; 92 | int scfsi[2][4]; 93 | } III_side_info_t; 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /recorderlib/src/main/jni/lame-3.100_libmp3lame/lame-analysis.h: -------------------------------------------------------------------------------- 1 | /* 2 | * GTK plotting routines source file 3 | * 4 | * Copyright (c) 1999 Mark Taylor 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Library General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Library General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Library General Public 17 | * License along with this library; if not, write to the 18 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 19 | * Boston, MA 02111-1307, USA. 20 | */ 21 | 22 | #ifndef LAME_GTKANAL_H 23 | #define LAME_GTKANAL_H 24 | 25 | 26 | #define READ_AHEAD 40 /* number of frames to read ahead */ 27 | #define MAXMPGLAG READ_AHEAD /* if the mpg123 lag becomes bigger than this 28 | we have to stop */ 29 | #define NUMBACK 6 /* number of frames we can back up */ 30 | #define NUMPINFO (NUMBACK+READ_AHEAD+1) 31 | 32 | 33 | 34 | struct plotting_data { 35 | int frameNum; /* current frame number */ 36 | int frameNum123; 37 | int num_samples; /* number of pcm samples read for this frame */ 38 | double frametime; /* starting time of frame, in seconds */ 39 | double pcmdata[2][1600]; 40 | double pcmdata2[2][1152 + 1152 - DECDELAY]; 41 | double xr[2][2][576]; 42 | double mpg123xr[2][2][576]; 43 | double ms_ratio[2]; 44 | double ms_ener_ratio[2]; 45 | 46 | /* L,R, M and S values */ 47 | double energy_save[4][BLKSIZE]; /* psymodel is one ahead */ 48 | double energy[2][4][BLKSIZE]; 49 | double pe[2][4]; 50 | double thr[2][4][SBMAX_l]; 51 | double en[2][4][SBMAX_l]; 52 | double thr_s[2][4][3 * SBMAX_s]; 53 | double en_s[2][4][3 * SBMAX_s]; 54 | double ers_save[4]; /* psymodel is one ahead */ 55 | double ers[2][4]; 56 | 57 | double sfb[2][2][SBMAX_l]; 58 | double sfb_s[2][2][3 * SBMAX_s]; 59 | double LAMEsfb[2][2][SBMAX_l]; 60 | double LAMEsfb_s[2][2][3 * SBMAX_s]; 61 | 62 | int LAMEqss[2][2]; 63 | int qss[2][2]; 64 | int big_values[2][2]; 65 | int sub_gain[2][2][3]; 66 | 67 | double xfsf[2][2][SBMAX_l]; 68 | double xfsf_s[2][2][3 * SBMAX_s]; 69 | 70 | int over[2][2]; 71 | double tot_noise[2][2]; 72 | double max_noise[2][2]; 73 | double over_noise[2][2]; 74 | int over_SSD[2][2]; 75 | int blocktype[2][2]; 76 | int scalefac_scale[2][2]; 77 | int preflag[2][2]; 78 | int mpg123blocktype[2][2]; 79 | int mixed[2][2]; 80 | int mainbits[2][2]; 81 | int sfbits[2][2]; 82 | int LAMEmainbits[2][2]; 83 | int LAMEsfbits[2][2]; 84 | int framesize, stereo, js, ms_stereo, i_stereo, emph, bitrate, sampfreq, maindata; 85 | int crc, padding; 86 | int scfsi[2], mean_bits, resvsize; 87 | int totbits; 88 | }; 89 | #ifndef plotting_data_defined 90 | #define plotting_data_defined 91 | typedef struct plotting_data plotting_data; 92 | #endif 93 | #if 0 94 | extern plotting_data *pinfo; 95 | #endif 96 | #endif 97 | -------------------------------------------------------------------------------- /recorderlib/src/main/jni/lame-3.100_libmp3lame/lameerror.h: -------------------------------------------------------------------------------- 1 | /* 2 | * A collection of LAME Error Codes 3 | * 4 | * Please use the constants defined here instead of some arbitrary 5 | * values. Currently the values starting at -10 to avoid intersection 6 | * with the -1, -2, -3 and -4 used in the current code. 7 | * 8 | * May be this should be a part of the include/lame.h. 9 | */ 10 | 11 | typedef enum { 12 | LAME_OKAY = 0, 13 | LAME_NOERROR = 0, 14 | LAME_GENERICERROR = -1, 15 | LAME_NOMEM = -10, 16 | LAME_BADBITRATE = -11, 17 | LAME_BADSAMPFREQ = -12, 18 | LAME_INTERNALERROR = -13, 19 | 20 | FRONTEND_READERROR = -80, 21 | FRONTEND_WRITEERROR = -81, 22 | FRONTEND_FILETOOLARGE = -82, 23 | 24 | } lame_errorcodes_t; 25 | 26 | /* end of lameerror.h */ 27 | -------------------------------------------------------------------------------- /recorderlib/src/main/jni/lame-3.100_libmp3lame/machine.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Machine dependent defines/includes for LAME. 3 | * 4 | * Copyright (c) 1999 A.L. Faber 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Library General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Library General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Library General Public 17 | * License along with this library; if not, write to the 18 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 19 | * Boston, MA 02111-1307, USA. 20 | */ 21 | 22 | #ifndef LAME_MACHINE_H 23 | #define LAME_MACHINE_H 24 | 25 | #include "version.h" 26 | 27 | #include 28 | #include 29 | 30 | #ifdef STDC_HEADERS 31 | # include 32 | # include 33 | #else 34 | # ifndef HAVE_STRCHR 35 | # define strchr index 36 | # define strrchr rindex 37 | # endif 38 | char *strchr(), *strrchr(); 39 | # ifndef HAVE_MEMCPY 40 | # define memcpy(d, s, n) bcopy ((s), (d), (n)) 41 | # define memmove(d, s, n) bcopy ((s), (d), (n)) 42 | # endif 43 | #endif 44 | 45 | #if defined(__riscos__) && defined(FPA10) 46 | # include "ymath.h" 47 | #else 48 | # include 49 | #endif 50 | #include 51 | 52 | #include 53 | 54 | #ifdef HAVE_ERRNO_H 55 | # include 56 | #endif 57 | #ifdef HAVE_FCNTL_H 58 | # include 59 | #endif 60 | 61 | #if defined(macintosh) 62 | # include 63 | # include 64 | #else 65 | # include 66 | # include 67 | #endif 68 | 69 | #ifdef HAVE_INTTYPES_H 70 | # include 71 | #else 72 | # ifdef HAVE_STDINT_H 73 | # include 74 | # endif 75 | #endif 76 | 77 | #ifdef WITH_DMALLOC 78 | #include 79 | #endif 80 | 81 | /* 82 | * 3 different types of pow() functions: 83 | * - table lookup 84 | * - pow() 85 | * - exp() on some machines this is claimed to be faster than pow() 86 | */ 87 | 88 | #define POW20(x) (assert(0 <= (x+Q_MAX2) && x < Q_MAX), pow20[x+Q_MAX2]) 89 | /*#define POW20(x) pow(2.0,((double)(x)-210)*.25) */ 90 | /*#define POW20(x) exp( ((double)(x)-210)*(.25*LOG2) ) */ 91 | 92 | #define IPOW20(x) (assert(0 <= x && x < Q_MAX), ipow20[x]) 93 | /*#define IPOW20(x) exp( -((double)(x)-210)*.1875*LOG2 ) */ 94 | /*#define IPOW20(x) pow(2.0,-((double)(x)-210)*.1875) */ 95 | 96 | /* in case this is used without configure */ 97 | #ifndef inline 98 | # define inline 99 | #endif 100 | 101 | #if defined(_MSC_VER) 102 | # undef inline 103 | # define inline _inline 104 | #elif defined(__SASC) || defined(__GNUC__) || defined(__ICC) || defined(__ECC) 105 | /* if __GNUC__ we always want to inline, not only if the user requests it */ 106 | # undef inline 107 | # define inline __inline 108 | #endif 109 | 110 | #if defined(_MSC_VER) 111 | # pragma warning( disable : 4244 ) 112 | /*# pragma warning( disable : 4305 ) */ 113 | #endif 114 | 115 | /* 116 | * FLOAT for variables which require at least 32 bits 117 | * FLOAT8 for variables which require at least 64 bits 118 | * 119 | * On some machines, 64 bit will be faster than 32 bit. Also, some math 120 | * routines require 64 bit float, so setting FLOAT=float will result in a 121 | * lot of conversions. 122 | */ 123 | 124 | #if ( defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__) ) 125 | # define WIN32_LEAN_AND_MEAN 126 | # include 127 | # include 128 | # define FLOAT_MAX FLT_MAX 129 | #else 130 | # ifndef FLOAT 131 | typedef float FLOAT; 132 | # ifdef FLT_MAX 133 | # define FLOAT_MAX FLT_MAX 134 | # else 135 | # define FLOAT_MAX 1e37 /* approx */ 136 | # endif 137 | # endif 138 | #endif 139 | 140 | #ifndef FLOAT8 141 | typedef double FLOAT8; 142 | # ifdef DBL_MAX 143 | # define FLOAT8_MAX DBL_MAX 144 | # else 145 | # define FLOAT8_MAX 1e99 /* approx */ 146 | # endif 147 | #else 148 | # ifdef FLT_MAX 149 | # define FLOAT8_MAX FLT_MAX 150 | # else 151 | # define FLOAT8_MAX 1e37 /* approx */ 152 | # endif 153 | #endif 154 | 155 | /* sample_t must be floating point, at least 32 bits */ 156 | typedef FLOAT sample_t; 157 | 158 | #define dimension_of(array) (sizeof(array)/sizeof(array[0])) 159 | #define beyond(array) (array+dimension_of(array)) 160 | #define compiletime_assert(expression) enum{static_assert_##FILE##_##LINE = 1/((expression)?1:0)} 161 | #define lame_calloc(TYPE, COUNT) ((TYPE*)calloc(COUNT, sizeof(TYPE))) 162 | #define multiple_of(CHUNK, COUNT) (\ 163 | ( (COUNT) < 1 || (CHUNK) < 1 || (COUNT) % (CHUNK) == 0 ) \ 164 | ? (COUNT) \ 165 | : ((COUNT) + (CHUNK) - (COUNT) % (CHUNK)) \ 166 | ) 167 | 168 | #if 1 169 | #define EQ(a,b) (\ 170 | (fabs(a) > fabs(b)) \ 171 | ? (fabs((a)-(b)) <= (fabs(a) * 1e-6f)) \ 172 | : (fabs((a)-(b)) <= (fabs(b) * 1e-6f))) 173 | #else 174 | #define EQ(a,b) (fabs((a)-(b))<1E-37) 175 | #endif 176 | 177 | #define NEQ(a,b) (!EQ(a,b)) 178 | 179 | #ifdef _MSC_VER 180 | # if _MSC_VER < 1400 181 | # define fabsf fabs 182 | # define powf pow 183 | # define log10f log10 184 | # endif 185 | #endif 186 | 187 | #endif 188 | 189 | /* end of machine.h */ 190 | -------------------------------------------------------------------------------- /recorderlib/src/main/jni/lame-3.100_libmp3lame/newmdct.h: -------------------------------------------------------------------------------- 1 | /* 2 | * New Modified DCT include file 3 | * 4 | * Copyright (c) 1999 Takehiro TOMINAGA 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Library General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Library General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Library General Public 17 | * License along with this library; if not, write to the 18 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 19 | * Boston, MA 02111-1307, USA. 20 | */ 21 | 22 | #ifndef LAME_NEWMDCT_H 23 | #define LAME_NEWMDCT_H 24 | 25 | void mdct_sub48(lame_internal_flags * gfc, const sample_t * w0, const sample_t * w1); 26 | 27 | #endif /* LAME_NEWMDCT_H */ 28 | -------------------------------------------------------------------------------- /recorderlib/src/main/jni/lame-3.100_libmp3lame/psymodel.h: -------------------------------------------------------------------------------- 1 | /* 2 | * psymodel.h 3 | * 4 | * Copyright (c) 1999 Mark Taylor 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Library General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Library General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Library General Public 17 | * License along with this library; if not, write to the 18 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 19 | * Boston, MA 02111-1307, USA. 20 | */ 21 | 22 | #ifndef LAME_PSYMODEL_H 23 | #define LAME_PSYMODEL_H 24 | 25 | 26 | int L3psycho_anal_ns(lame_internal_flags * gfc, 27 | const sample_t *const buffer[2], int gr, 28 | III_psy_ratio ratio[2][2], 29 | III_psy_ratio MS_ratio[2][2], 30 | FLOAT pe[2], FLOAT pe_MS[2], FLOAT ener[2], int blocktype_d[2]); 31 | 32 | int L3psycho_anal_vbr(lame_internal_flags * gfc, 33 | const sample_t *const buffer[2], int gr, 34 | III_psy_ratio ratio[2][2], 35 | III_psy_ratio MS_ratio[2][2], 36 | FLOAT pe[2], FLOAT pe_MS[2], FLOAT ener[2], int blocktype_d[2]); 37 | 38 | 39 | int psymodel_init(lame_global_flags const* gfp); 40 | 41 | 42 | #define rpelev 2 43 | #define rpelev2 16 44 | #define rpelev_s 2 45 | #define rpelev2_s 16 46 | 47 | /* size of each partition band, in barks: */ 48 | #define DELBARK .34 49 | 50 | 51 | /* tuned for output level (sensitive to energy scale) */ 52 | #define VO_SCALE (1./( 14752*14752 )/(BLKSIZE/2)) 53 | 54 | #define temporalmask_sustain_sec 0.01 55 | 56 | #define NS_PREECHO_ATT0 0.8 57 | #define NS_PREECHO_ATT1 0.6 58 | #define NS_PREECHO_ATT2 0.3 59 | 60 | #define NS_MSFIX 3.5 61 | #define NSATTACKTHRE 4.4 62 | #define NSATTACKTHRE_S 25 63 | 64 | #endif /* LAME_PSYMODEL_H */ 65 | -------------------------------------------------------------------------------- /recorderlib/src/main/jni/lame-3.100_libmp3lame/quantize.h: -------------------------------------------------------------------------------- 1 | /* 2 | * MP3 quantization 3 | * 4 | * Copyright (c) 1999 Mark Taylor 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Library General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Library General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Library General Public 17 | * License along with this library; if not, write to the 18 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 19 | * Boston, MA 02111-1307, USA. 20 | */ 21 | 22 | #ifndef LAME_QUANTIZE_H 23 | #define LAME_QUANTIZE_H 24 | 25 | void CBR_iteration_loop(lame_internal_flags * gfc, const FLOAT pe[2][2], 26 | const FLOAT ms_ratio[2], const III_psy_ratio ratio[2][2]); 27 | 28 | void VBR_old_iteration_loop(lame_internal_flags * gfc, const FLOAT pe[2][2], 29 | const FLOAT ms_ratio[2], const III_psy_ratio ratio[2][2]); 30 | 31 | void VBR_new_iteration_loop(lame_internal_flags * gfc, const FLOAT pe[2][2], 32 | const FLOAT ms_ratio[2], const III_psy_ratio ratio[2][2]); 33 | 34 | void ABR_iteration_loop(lame_internal_flags * gfc, const FLOAT pe[2][2], 35 | const FLOAT ms_ratio[2], const III_psy_ratio ratio[2][2]); 36 | 37 | 38 | #endif /* LAME_QUANTIZE_H */ 39 | -------------------------------------------------------------------------------- /recorderlib/src/main/jni/lame-3.100_libmp3lame/quantize_pvt.h: -------------------------------------------------------------------------------- 1 | /* 2 | * quantize_pvt include file 3 | * 4 | * Copyright (c) 1999 Takehiro TOMINAGA 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Library General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Library General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Library General Public 17 | * License along with this library; if not, write to the 18 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 19 | * Boston, MA 02111-1307, USA. 20 | */ 21 | 22 | #ifndef LAME_QUANTIZE_PVT_H 23 | #define LAME_QUANTIZE_PVT_H 24 | 25 | #define IXMAX_VAL 8206 /* ix always <= 8191+15. see count_bits() */ 26 | 27 | /* buggy Winamp decoder cannot handle values > 8191 */ 28 | /* #define IXMAX_VAL 8191 */ 29 | 30 | #define PRECALC_SIZE (IXMAX_VAL+2) 31 | 32 | 33 | extern const int nr_of_sfb_block[6][3][4]; 34 | extern const int pretab[SBMAX_l]; 35 | extern const int slen1_tab[16]; 36 | extern const int slen2_tab[16]; 37 | 38 | extern const scalefac_struct sfBandIndex[9]; 39 | 40 | extern FLOAT pow43[PRECALC_SIZE]; 41 | #ifdef TAKEHIRO_IEEE754_HACK 42 | extern FLOAT adj43asm[PRECALC_SIZE]; 43 | #else 44 | extern FLOAT adj43[PRECALC_SIZE]; 45 | #endif 46 | 47 | #define Q_MAX (256+1) 48 | #define Q_MAX2 116 /* minimum possible number of 49 | -cod_info->global_gain 50 | + ((scalefac[] + (cod_info->preflag ? pretab[sfb] : 0)) 51 | << (cod_info->scalefac_scale + 1)) 52 | + cod_info->subblock_gain[cod_info->window[sfb]] * 8; 53 | 54 | for long block, 0+((15+3)<<2) = 18*4 = 72 55 | for short block, 0+(15<<2)+7*8 = 15*4+56 = 116 56 | */ 57 | 58 | extern FLOAT pow20[Q_MAX + Q_MAX2 + 1]; 59 | extern FLOAT ipow20[Q_MAX]; 60 | 61 | typedef struct calc_noise_result_t { 62 | FLOAT over_noise; /* sum of quantization noise > masking */ 63 | FLOAT tot_noise; /* sum of all quantization noise */ 64 | FLOAT max_noise; /* max quantization noise */ 65 | int over_count; /* number of quantization noise > masking */ 66 | int over_SSD; /* SSD-like cost of distorted bands */ 67 | int bits; 68 | } calc_noise_result; 69 | 70 | 71 | /** 72 | * allows re-use of previously 73 | * computed noise values 74 | */ 75 | typedef struct calc_noise_data_t { 76 | int global_gain; 77 | int sfb_count1; 78 | int step[39]; 79 | FLOAT noise[39]; 80 | FLOAT noise_log[39]; 81 | } calc_noise_data; 82 | 83 | 84 | int on_pe(lame_internal_flags * gfc, const FLOAT pe[2][2], 85 | int targ_bits[2], int mean_bits, int gr, int cbr); 86 | 87 | void reduce_side(int targ_bits[2], FLOAT ms_ener_ratio, int mean_bits, int max_bits); 88 | 89 | 90 | void iteration_init(lame_internal_flags * gfc); 91 | 92 | 93 | int calc_xmin(lame_internal_flags const *gfc, 94 | III_psy_ratio const *const ratio, gr_info * const cod_info, FLOAT * l3_xmin); 95 | 96 | int calc_noise(const gr_info * const cod_info, 97 | const FLOAT * l3_xmin, 98 | FLOAT * distort, calc_noise_result * const res, calc_noise_data * prev_noise); 99 | 100 | void set_frame_pinfo(lame_internal_flags * gfc, const III_psy_ratio ratio[2][2]); 101 | 102 | 103 | 104 | 105 | /* takehiro.c */ 106 | 107 | int count_bits(lame_internal_flags const *const gfc, const FLOAT * const xr, 108 | gr_info * const cod_info, calc_noise_data * prev_noise); 109 | int noquant_count_bits(lame_internal_flags const *const gfc, 110 | gr_info * const cod_info, calc_noise_data * prev_noise); 111 | 112 | 113 | void best_huffman_divide(const lame_internal_flags * const gfc, gr_info * const cod_info); 114 | 115 | void best_scalefac_store(const lame_internal_flags * gfc, const int gr, const int ch, 116 | III_side_info_t * const l3_side); 117 | 118 | int scale_bitcount(const lame_internal_flags * gfc, gr_info * cod_info); 119 | 120 | void huffman_init(lame_internal_flags * const gfc); 121 | 122 | void init_xrpow_core_init(lame_internal_flags * const gfc); 123 | 124 | FLOAT athAdjust(FLOAT a, FLOAT x, FLOAT athFloor, float ATHfixpoint); 125 | 126 | #define LARGE_BITS 100000 127 | 128 | #endif /* LAME_QUANTIZE_PVT_H */ 129 | -------------------------------------------------------------------------------- /recorderlib/src/main/jni/lame-3.100_libmp3lame/reservoir.h: -------------------------------------------------------------------------------- 1 | /* 2 | * bit reservoir include file 3 | * 4 | * Copyright (c) 1999 Mark Taylor 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Library General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Library General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Library General Public 17 | * License along with this library; if not, write to the 18 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 19 | * Boston, MA 02111-1307, USA. 20 | */ 21 | 22 | #ifndef LAME_RESERVOIR_H 23 | #define LAME_RESERVOIR_H 24 | 25 | int ResvFrameBegin(lame_internal_flags * gfc, int *mean_bits); 26 | void ResvMaxBits(lame_internal_flags * gfc, int mean_bits, int *targ_bits, int *max_bits, 27 | int cbr); 28 | void ResvAdjust(lame_internal_flags * gfc, gr_info const *gi); 29 | void ResvFrameEnd(lame_internal_flags * gfc, int mean_bits); 30 | 31 | #endif /* LAME_RESERVOIR_H */ 32 | -------------------------------------------------------------------------------- /recorderlib/src/main/jni/lame-3.100_libmp3lame/set_get.h: -------------------------------------------------------------------------------- 1 | /* 2 | * set_get.h -- Internal set/get definitions 3 | * 4 | * Copyright (C) 2003 Gabriel Bouvigne / Lame project 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Library General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Library General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Library General Public 17 | * License along with this library; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | #ifndef __SET_GET_H__ 22 | #define __SET_GET_H__ 23 | 24 | 25 | #if defined(__cplusplus) 26 | extern "C" { 27 | #endif 28 | 29 | /* select psychoacoustic model */ 30 | 31 | /* manage short blocks */ 32 | int CDECL lame_set_short_threshold(lame_global_flags *, float, float); 33 | int CDECL lame_set_short_threshold_lrm(lame_global_flags *, float); 34 | float CDECL lame_get_short_threshold_lrm(const lame_global_flags *); 35 | int CDECL lame_set_short_threshold_s(lame_global_flags *, float); 36 | float CDECL lame_get_short_threshold_s(const lame_global_flags *); 37 | 38 | 39 | int CDECL lame_set_maskingadjust(lame_global_flags *, float); 40 | float CDECL lame_get_maskingadjust(const lame_global_flags *); 41 | 42 | int CDECL lame_set_maskingadjust_short(lame_global_flags *, float); 43 | float CDECL lame_get_maskingadjust_short(const lame_global_flags *); 44 | 45 | /* select ATH formula 4 shape */ 46 | int CDECL lame_set_ATHcurve(lame_global_flags *, float); 47 | float CDECL lame_get_ATHcurve(const lame_global_flags *); 48 | 49 | int CDECL lame_set_preset_notune(lame_global_flags *, int); 50 | 51 | /* substep shaping method */ 52 | int CDECL lame_set_substep(lame_global_flags *, int); 53 | int CDECL lame_get_substep(const lame_global_flags *); 54 | 55 | /* scalefactors scale */ 56 | int CDECL lame_set_sfscale(lame_global_flags *, int); 57 | int CDECL lame_get_sfscale(const lame_global_flags *); 58 | 59 | /* subblock gain */ 60 | int CDECL lame_set_subblock_gain(lame_global_flags *, int); 61 | int CDECL lame_get_subblock_gain(const lame_global_flags *); 62 | 63 | 64 | 65 | /*presets*/ 66 | int apply_preset(lame_global_flags *, int preset, int enforce); 67 | 68 | void CDECL lame_set_tune(lame_t, float); /* FOR INTERNAL USE ONLY */ 69 | void CDECL lame_set_msfix(lame_t gfp, double msfix); 70 | 71 | 72 | #if defined(__cplusplus) 73 | } 74 | #endif 75 | #endif 76 | -------------------------------------------------------------------------------- /recorderlib/src/main/jni/lame-3.100_libmp3lame/tables.h: -------------------------------------------------------------------------------- 1 | /* 2 | * MPEG layer 3 tables include file 3 | * 4 | * Copyright (c) 1999 Albert L Faber 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Library General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Library General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Library General Public 17 | * License along with this library; if not, write to the 18 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 19 | * Boston, MA 02111-1307, USA. 20 | */ 21 | 22 | #ifndef LAME_TABLES_H 23 | #define LAME_TABLES_H 24 | 25 | #if 0 26 | typedef struct { 27 | unsigned char no; 28 | unsigned char width; 29 | unsigned char minval_2; 30 | float quiet_thr; 31 | float norm; 32 | float bark; 33 | } type1_t; 34 | 35 | typedef struct { 36 | unsigned char no; 37 | unsigned char width; 38 | float quiet_thr; 39 | float norm; 40 | float SNR; 41 | float bark; 42 | } type2_t; 43 | 44 | typedef struct { 45 | unsigned int no:5; 46 | unsigned int cbw:3; 47 | unsigned int bu:6; 48 | unsigned int bo:6; 49 | unsigned int w1_576:10; 50 | unsigned int w2_576:10; 51 | } type34_t; 52 | 53 | typedef struct { 54 | size_t len1; 55 | const type1_t *const tab1; 56 | size_t len2; 57 | const type2_t *const tab2; 58 | size_t len3; 59 | const type34_t *const tab3; 60 | size_t len4; 61 | const type34_t *const tab4; 62 | } type5_t; 63 | 64 | extern const type5_t table5[6]; 65 | 66 | #endif 67 | 68 | #define HTN 34 69 | 70 | struct huffcodetab { 71 | const unsigned int xlen; /* max. x-index+ */ 72 | const unsigned int linmax; /* max number to be stored in linbits */ 73 | const uint16_t *table; /* pointer to array[xlen][ylen] */ 74 | const uint8_t *hlen; /* pointer to array[xlen][ylen] */ 75 | }; 76 | 77 | extern const struct huffcodetab ht[HTN]; 78 | /* global memory block */ 79 | /* array of all huffcodtable headers */ 80 | /* 0..31 Huffman code table 0..31 */ 81 | /* 32,33 count1-tables */ 82 | 83 | extern const uint8_t t32l[]; 84 | extern const uint8_t t33l[]; 85 | 86 | extern const uint32_t largetbl[16 * 16]; 87 | extern const uint32_t table23[3 * 3]; 88 | extern const uint32_t table56[4 * 4]; 89 | 90 | extern const int scfsi_band[5]; 91 | 92 | extern const int bitrate_table [3][16]; 93 | extern const int samplerate_table [3][ 4]; 94 | 95 | #endif /* LAME_TABLES_H */ 96 | -------------------------------------------------------------------------------- /recorderlib/src/main/jni/lame-3.100_libmp3lame/vbrquantize.h: -------------------------------------------------------------------------------- 1 | /* 2 | * MP3 VBR quantization 3 | * 4 | * Copyright (c) 1999 Mark Taylor 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Library General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Library General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Library General Public 17 | * License along with this library; if not, write to the 18 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 19 | * Boston, MA 02111-1307, USA. 20 | */ 21 | 22 | #ifndef LAME_VBRQUANTIZE_H 23 | #define LAME_VBRQUANTIZE_H 24 | 25 | int VBR_encode_frame(lame_internal_flags * gfc, const FLOAT xr34orig[2][2][576], 26 | const FLOAT l3_xmin[2][2][SFBMAX], const int maxbits[2][2]); 27 | 28 | #endif /* LAME_VBRQUANTIZE_H */ 29 | -------------------------------------------------------------------------------- /recorderlib/src/main/jni/lame-3.100_libmp3lame/version.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Version numbering for LAME. 3 | * 4 | * Copyright (c) 1999 A.L. Faber 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Library General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Library General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Library General Public 17 | * License along with this library; if not, write to the 18 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 19 | * Boston, MA 02111-1307, USA. 20 | */ 21 | 22 | #ifndef LAME_VERSION_H 23 | #define LAME_VERSION_H 24 | 25 | 26 | /* 27 | * To make a string from a token, use the # operator: 28 | */ 29 | #ifndef STR 30 | # define __STR(x) #x 31 | # define STR(x) __STR(x) 32 | #endif 33 | 34 | # define LAME_URL "http://lame.sf.net" 35 | 36 | 37 | # define LAME_MAJOR_VERSION 3 /* Major version number */ 38 | # define LAME_MINOR_VERSION 100 /* Minor version number */ 39 | # define LAME_TYPE_VERSION 2 /* 0:alpha 1:beta 2:release */ 40 | # define LAME_PATCH_VERSION 0 /* Patch level */ 41 | # define LAME_ALPHA_VERSION (LAME_TYPE_VERSION==0) 42 | # define LAME_BETA_VERSION (LAME_TYPE_VERSION==1) 43 | # define LAME_RELEASE_VERSION (LAME_TYPE_VERSION==2) 44 | 45 | # define PSY_MAJOR_VERSION 1 /* Major version number */ 46 | # define PSY_MINOR_VERSION 0 /* Minor version number */ 47 | # define PSY_ALPHA_VERSION 0 /* Set number if this is an alpha version, otherwise zero */ 48 | # define PSY_BETA_VERSION 0 /* Set number if this is a beta version, otherwise zero */ 49 | 50 | #if LAME_ALPHA_VERSION 51 | #define LAME_PATCH_LEVEL_STRING " alpha " STR(LAME_PATCH_VERSION) 52 | #endif 53 | #if LAME_BETA_VERSION 54 | #define LAME_PATCH_LEVEL_STRING " beta " STR(LAME_PATCH_VERSION) 55 | #endif 56 | #if LAME_RELEASE_VERSION 57 | #if LAME_PATCH_VERSION 58 | #define LAME_PATCH_LEVEL_STRING " release " STR(LAME_PATCH_VERSION) 59 | #else 60 | #define LAME_PATCH_LEVEL_STRING "" 61 | #endif 62 | #endif 63 | 64 | # define LAME_VERSION_STRING STR(LAME_MAJOR_VERSION) "." STR(LAME_MINOR_VERSION) LAME_PATCH_LEVEL_STRING 65 | 66 | #endif /* LAME_VERSION_H */ 67 | 68 | /* End of version.h */ 69 | -------------------------------------------------------------------------------- /recorderlib/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | recorderlib 3 | 4 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name='TestRecorder' 2 | include ':app',':recorderlib' 3 | --------------------------------------------------------------------------------