├── .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 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
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 |
104 |
105 |
106 |
107 |
108 |
109 | 1.8
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
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 |
--------------------------------------------------------------------------------