├── app
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── values
│ │ │ │ ├── strings.xml
│ │ │ │ ├── colors.xml
│ │ │ │ └── styles.xml
│ │ │ ├── mipmap-hdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── drawable-v24
│ │ │ │ ├── draw_picture_ic_flowers.png
│ │ │ │ └── ic_launcher_foreground.xml
│ │ │ ├── mipmap-anydpi-v26
│ │ │ │ ├── ic_launcher.xml
│ │ │ │ └── ic_launcher_round.xml
│ │ │ ├── layout
│ │ │ │ └── activity_main.xml
│ │ │ └── drawable
│ │ │ │ └── ic_launcher_background.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ └── com
│ │ │ └── bacchus
│ │ │ └── audiovideo
│ │ │ ├── draw_picture
│ │ │ ├── CustomView.kt
│ │ │ └── MainActivity.kt
│ │ │ └── audio_record
│ │ │ └── AudioDemo.kt
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── bacchus
│ │ │ └── audiovideo
│ │ │ └── ExampleUnitTest.kt
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── bacchus
│ │ └── audiovideo
│ │ └── ExampleInstrumentedTest.kt
├── proguard-rules.pro
└── build.gradle
├── notelib
├── .gitignore
├── src
│ └── main
│ │ └── java
│ │ └── com
│ │ └── bacchus
│ │ └── notelib
│ │ ├── Note.java
│ │ ├── image
│ │ ├── imooc_cdn.png
│ │ ├── imooc_tone.png
│ │ ├── cnblog_pull.png
│ │ ├── cnblog_push.png
│ │ ├── imooc_masking.png
│ │ ├── imooc_process.png
│ │ ├── imooc_realtime.png
│ │ ├── imooc_soundwave.png
│ │ ├── imooc_quantificat.png
│ │ └── imooc_entertainment.png
│ │ ├── imooc
│ │ ├── 音频入门.md
│ │ └── 万人直播架构与CDN网络.md
│ │ └── cnblog
│ │ └── Android 音视频开发(二):使用 AudioRecord 采集音频PCM并保存到文件(学习笔记).md
└── build.gradle
├── settings.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .idea
├── codeStyles
│ ├── codeStyleConfig.xml
│ └── Project.xml
├── vcs.xml
├── misc.xml
├── runConfigurations.xml
└── gradle.xml
├── .gitignore
├── gradle.properties
├── README.md
├── gradlew.bat
└── gradlew
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/notelib/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':notelib'
2 | rootProject.name='AudioVideo'
3 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | AudioVideo
3 |
4 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bacchuc/AudioVideo/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/notelib/src/main/java/com/bacchus/notelib/Note.java:
--------------------------------------------------------------------------------
1 | package com.bacchus.notelib;
2 |
3 | public class Note {
4 | }
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bacchuc/AudioVideo/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bacchuc/AudioVideo/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bacchuc/AudioVideo/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bacchuc/AudioVideo/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bacchuc/AudioVideo/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bacchuc/AudioVideo/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bacchuc/AudioVideo/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bacchuc/AudioVideo/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bacchuc/AudioVideo/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bacchuc/AudioVideo/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/draw_picture_ic_flowers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bacchuc/AudioVideo/HEAD/app/src/main/res/drawable-v24/draw_picture_ic_flowers.png
--------------------------------------------------------------------------------
/notelib/src/main/java/com/bacchus/notelib/image/imooc_cdn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bacchuc/AudioVideo/HEAD/notelib/src/main/java/com/bacchus/notelib/image/imooc_cdn.png
--------------------------------------------------------------------------------
/notelib/src/main/java/com/bacchus/notelib/image/imooc_tone.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bacchuc/AudioVideo/HEAD/notelib/src/main/java/com/bacchus/notelib/image/imooc_tone.png
--------------------------------------------------------------------------------
/notelib/src/main/java/com/bacchus/notelib/image/cnblog_pull.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bacchuc/AudioVideo/HEAD/notelib/src/main/java/com/bacchus/notelib/image/cnblog_pull.png
--------------------------------------------------------------------------------
/notelib/src/main/java/com/bacchus/notelib/image/cnblog_push.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bacchuc/AudioVideo/HEAD/notelib/src/main/java/com/bacchus/notelib/image/cnblog_push.png
--------------------------------------------------------------------------------
/notelib/src/main/java/com/bacchus/notelib/image/imooc_masking.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bacchuc/AudioVideo/HEAD/notelib/src/main/java/com/bacchus/notelib/image/imooc_masking.png
--------------------------------------------------------------------------------
/notelib/src/main/java/com/bacchus/notelib/image/imooc_process.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bacchuc/AudioVideo/HEAD/notelib/src/main/java/com/bacchus/notelib/image/imooc_process.png
--------------------------------------------------------------------------------
/notelib/src/main/java/com/bacchus/notelib/image/imooc_realtime.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bacchuc/AudioVideo/HEAD/notelib/src/main/java/com/bacchus/notelib/image/imooc_realtime.png
--------------------------------------------------------------------------------
/notelib/src/main/java/com/bacchus/notelib/image/imooc_soundwave.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bacchuc/AudioVideo/HEAD/notelib/src/main/java/com/bacchus/notelib/image/imooc_soundwave.png
--------------------------------------------------------------------------------
/notelib/src/main/java/com/bacchus/notelib/image/imooc_quantificat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bacchuc/AudioVideo/HEAD/notelib/src/main/java/com/bacchus/notelib/image/imooc_quantificat.png
--------------------------------------------------------------------------------
/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/notelib/src/main/java/com/bacchus/notelib/image/imooc_entertainment.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Bacchuc/AudioVideo/HEAD/notelib/src/main/java/com/bacchus/notelib/image/imooc_entertainment.png
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/notelib/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java-library'
2 |
3 | dependencies {
4 | implementation fileTree(dir: 'libs', include: ['*.jar'])
5 | }
6 |
7 | sourceCompatibility = "7"
8 | targetCompatibility = "7"
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #008577
4 | #00574B
5 | #D81B60
6 |
7 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Aug 20 15:53:03 CST 2019
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.4.1-all.zip
7 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/test/java/com/bacchus/audiovideo/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.bacchus.audiovideo
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/bacchus/audiovideo/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.bacchus.audiovideo
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.bacchus.audiovideo", appContext.packageName)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/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/java/com/bacchus/audiovideo/draw_picture/CustomView.kt:
--------------------------------------------------------------------------------
1 | package com.bacchus.audiovideo.draw_picture
2 |
3 | import android.content.Context
4 | import android.graphics.Bitmap
5 | import android.graphics.BitmapFactory
6 | import android.graphics.Canvas
7 | import android.graphics.Paint
8 | import android.view.View
9 | import com.bacchus.audiovideo.R
10 |
11 | class CustomView(context: Context?) : View (context){
12 |
13 | private val paint = Paint()
14 | var bitmap: Bitmap
15 |
16 | init {
17 | paint.isAntiAlias = true
18 | paint.style = Paint.Style.STROKE
19 | bitmap = BitmapFactory.decodeResource(resources, R.drawable.draw_picture_ic_flowers)
20 | }
21 |
22 | override fun onDraw(canvas: Canvas?) {
23 | super.onDraw(canvas)
24 | canvas?.drawBitmap(bitmap, 0f, 0f, paint)
25 | }
26 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
14 |
15 |
20 |
21 |
26 |
27 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | apply plugin: 'kotlin-android'
4 |
5 | apply plugin: 'kotlin-android-extensions'
6 |
7 | android {
8 | compileSdkVersion 28
9 | defaultConfig {
10 | applicationId "com.bacchus.audiovideo"
11 | minSdkVersion 18
12 | targetSdkVersion 28
13 | versionCode 1
14 | versionName "1.0"
15 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
16 | }
17 | buildTypes {
18 | release {
19 | minifyEnabled false
20 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
21 | }
22 | }
23 | }
24 |
25 | dependencies {
26 | implementation fileTree(dir: 'libs', include: ['*.jar'])
27 | implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
28 | implementation 'androidx.appcompat:appcompat:1.0.2'
29 | implementation 'androidx.core:core-ktx:1.0.2'
30 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
31 | testImplementation 'junit:junit:4.12'
32 | androidTestImplementation 'androidx.test.ext:junit:1.1.0'
33 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
34 | }
35 |
--------------------------------------------------------------------------------
/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 | # Kotlin code style for this project: "official" or "obsolete":
21 | kotlin.code.style=official
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AudioVideo: 音视频资料整理、笔记、Demo By Kotlin
2 | **欢迎 Star 和帮忙改进, 有任何意见或建议,到这里提出 [Create New Issue](https://github.com/Bacchuc/AudioVideo/issues/new)**
3 |
4 | ## 个人笔记
5 |
6 | #### 音频基础
7 | - [音频入门](https://github.com/Bacchuc/AudioVideo/blob/master/notelib/src/main/java/com/bacchus/notelib/imooc/%E9%9F%B3%E9%A2%91%E5%85%A5%E9%97%A8.md)
8 | - [万人直播架构与CDN网络](https://github.com/Bacchuc/AudioVideo/blob/master/notelib/src/main/java/com/bacchus/notelib/imooc/%E4%B8%87%E4%BA%BA%E7%9B%B4%E6%92%AD%E6%9E%B6%E6%9E%84%E4%B8%8ECDN%E7%BD%91%E7%BB%9C.md)
9 | - [使用 AudioRecord 采集音频 PCM 并保存到文件](https://github.com/Bacchuc/AudioVideo/blob/master/notelib/src/main/java/com/bacchus/notelib/cnblog/Android%20%E9%9F%B3%E8%A7%86%E9%A2%91%E5%BC%80%E5%8F%91(%E4%BA%8C)%EF%BC%9A%E4%BD%BF%E7%94%A8%20AudioRecord%20%E9%87%87%E9%9B%86%E9%9F%B3%E9%A2%91PCM%E5%B9%B6%E4%BF%9D%E5%AD%98%E5%88%B0%E6%96%87%E4%BB%B6%EF%BC%88%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%89.md)
10 |
11 |
12 | ## 资源文章
13 | - [Jhuster的专栏](https://blog.51cto.com/ticktick/category15.html)
14 | - [雷霄骅的专栏](https://blog.csdn.net/leixiaohua1020)
15 | - [Android 音视频开发学习思路 - 灰色飘零 - 博客园](https://www.cnblogs.com/renhui/p/7452572.html)
16 | - [Home - Sharry Blog](https://sharrychoo.github.io/blog/)
17 | - [LearnOpenGL-CN](https://learnopengl-cn.readthedocs.io/zh/latest/)
18 | - [Android Graphic 架构](https://source.android.com/devices/graphics/)
19 |
20 | ## 联系方式
21 | - [Blog](https://blog.csdn.net/qq_35699070)
22 |
--------------------------------------------------------------------------------
/app/src/main/java/com/bacchus/audiovideo/audio_record/AudioDemo.kt:
--------------------------------------------------------------------------------
1 | package com.bacchus.audiovideo.audio_record
2 |
3 | import android.media.AudioRecord
4 | import android.util.Log
5 |
6 | /**
7 | * 使用 AudioRecord 实现录音,并生成 wav
8 | * @time : 2019/08/20
9 | * @author : Bacchus
10 | */
11 | class AudioDemo private constructor() {
12 |
13 | companion object {
14 | val instance: AudioDemo by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
15 | AudioDemo()
16 | }
17 | }
18 |
19 | // 缓冲区字节大小
20 | private var mBufferSizeInBytes = 0
21 |
22 | // AudioRecord 录音对象
23 | private lateinit var mAudioRecord: AudioRecord
24 |
25 | init {
26 | createDefaultAudio()
27 | }
28 |
29 | /**
30 | * 创建默认的录音对象
31 | */
32 | private fun createDefaultAudio() {
33 | // 获得缓冲区字节大小,AudioRecord 能接受的最小的 buffer 大小
34 | mBufferSizeInBytes = AudioRecord.getMinBufferSize(
35 | Constants.AUDIO_SAMPLE_RATE,
36 | Constants.AUDIO_CHANNEL,
37 | Constants.AUDIO_ENCODING
38 | )
39 | mAudioRecord = AudioRecord(
40 | Constants.AUDIO_INPUT,
41 | Constants.AUDIO_SAMPLE_RATE,
42 | Constants.AUDIO_CHANNEL,
43 | Constants.AUDIO_ENCODING,
44 | mBufferSizeInBytes
45 | )
46 | }
47 |
48 | fun startRecord() {
49 | Log.i("startRecord", "startRecord")
50 |
51 | }
52 |
53 | fun stopRecord() {
54 | Log.i("stopRecord", "stopRecord")
55 | }
56 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/bacchus/audiovideo/draw_picture/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.bacchus.audiovideo.draw_picture
2 |
3 | import android.graphics.BitmapFactory
4 | import android.graphics.Canvas
5 | import android.graphics.Paint
6 | import androidx.appcompat.app.AppCompatActivity
7 | import android.os.Bundle
8 | import android.util.TypedValue
9 | import android.view.SurfaceHolder
10 | import kotlinx.android.synthetic.main.activity_main.*
11 | import android.graphics.Bitmap
12 | import android.graphics.drawable.Drawable
13 | import android.os.Build
14 | import com.bacchus.audiovideo.R
15 |
16 | class MainActivity : AppCompatActivity() {
17 |
18 | override fun onCreate(savedInstanceState: Bundle?) {
19 | super.onCreate(savedInstanceState)
20 | setContentView(R.layout.activity_main)
21 | setImageView()
22 | setSurfaceView()
23 | }
24 |
25 | fun setImageView() {
26 | iv.setImageBitmap(BitmapFactory.decodeResource(resources, R.drawable.draw_picture_ic_flowers))
27 | }
28 |
29 | fun setSurfaceView() {
30 | sv.holder.addCallback(object : SurfaceHolder.Callback {
31 | override fun surfaceCreated(surfaceHolder: SurfaceHolder) {
32 | val paint = Paint()
33 | paint.isAntiAlias = true
34 | paint.style = Paint.Style.STROKE
35 |
36 | val canvas = surfaceHolder.lockCanvas()
37 | canvas.drawBitmap(BitmapFactory.decodeResource(resources, R.drawable.draw_picture_ic_flowers), 0f, 0f, paint)
38 |
39 | surfaceHolder.unlockCanvasAndPost(canvas)
40 | }
41 |
42 | override fun surfaceChanged(surfaceHolder: SurfaceHolder, i: Int, i1: Int, i2: Int) {
43 |
44 | }
45 |
46 | override fun surfaceDestroyed(surfaceHolder: SurfaceHolder) {
47 |
48 | }
49 | })
50 | }
51 |
52 | fun setCustomView(){
53 |
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/notelib/src/main/java/com/bacchus/notelib/imooc/音频入门.md:
--------------------------------------------------------------------------------
1 | #### 声音三要素
2 | - 音调:就是音频,男生 -> 女生 -> 儿童。声音越高,音频越快
3 | - 音量:振动的幅度,幅度越大,声音越大
4 | - 音色:它与材质有很大关系,本质是谐波
5 |
6 | 
7 |
8 | 声音在说话时会产生一个正弦波,同时会存在一些小的谐波,但是正弦波是比较理想的情况下,通常会伴随着一些畸形波,畸形波一般来说就是噪音,
9 | 越接近正弦,声音越好听
10 |
11 | 
12 |
13 | #### 人类听觉范围
14 | - 次声波 -> (20 Hz) 可听声波 (20 KHz) -> 超声波
15 | 所以取音频时,我们只取可听声波的赫兹范围内的声波,可以减少数据存储
16 |
17 | #### 量化基本概念
18 | - 采样大小:(即下图的振幅的量化高度的值)一个采样用多少 bit 存放,常用的是16 bit。声音的振幅基本上16够用了,声音没有负值。
19 | - 采样率:采样频率 8k(一秒采集8千次,此处跟音频无关,但是可以通过音频大小与采样率计算出一个正弦波中的采样次数)、16k、32k、44.1k、48k,
20 | - 声道数:单声道、双声道、多声道(喇叭数量)
21 | - 音频帧:音频跟视频很不一样,视频每一帧就是一张图像,而从下面的正玄波可以看出,音频数据是流式的,本身没有明确的一帧帧的概念,在实际的应用中,为了音频算法处理/传输的方便,一般约定俗成取2.5ms~60ms为单位的数据量为一帧音频。这个时间被称之为“采样时间”,其长度没有特别的标准,它是根据具体应用的需求来决定的
22 |
23 | 
24 |
25 | #### 计算
26 | - 码率计算: 采样率 * 采样大小 * 声道数
27 |
28 | ```
29 | 例如: 采样率为 44.1 KHz
30 | 采样大小为 16 bit
31 | 双声道的 PCM(音频流) 编码的 WAV 文件
32 | 它的率码为 44.1K * 16 * 2 = 1411.2kb/s
33 | ```
34 |
35 | - 一帧音频帧的大小: 采样率 * 采样大小 * 音频帧 * 声道数
36 |
37 | ```
38 | 例如: 采样率为 8 KHz
39 | 采样大小为 16 bit
40 | 20ms一帧
41 | 双声道
42 | 它的大小为 8000 * 16 * 0.02 * 2 = 5120 bit = 640 byte
43 | ```
44 |
45 | #### 音频压缩技术
46 | - 消除冗余数据,有损压缩(直接删除不能复原)
47 | - 哈夫曼无损编码,无损压缩(将冗余数据进行编码后可以进行复原)
48 | - 音频冗余信息
49 | - 压缩的主要方法是去除采集到的音频冗余信息,所谓冗余信息包括
50 | 人耳听觉范围外的音频信号以及被掩蔽掉的音频信号
51 | - 信号的掩蔽可以分为 **频域掩蔽** 和 **时域掩蔽**
52 |
53 | 
54 |
55 | ```
56 | 频谱掩蔽效应: 人耳所能察觉的声音信号的频率范围为20Hz~20KHz,在这个频率范围以外的音频信号属于冗余信号
57 | 一般来说,弱纯音离强纯音越近就越容易被掩蔽;低频纯音可以有效地掩蔽高频纯音,但高频纯音对
58 | 低频纯音的掩蔽作用则不明显
59 |
60 | 时域掩蔽效应: 除了同时发出的声音之间有掩蔽现象之外,在时间上相邻的声音之间也有掩蔽现象,并且称为时域掩蔽
61 | 时域掩蔽又分为超前掩蔽(pre-masking)和滞后掩蔽(post-masking),产生时域掩蔽的主要原因是
62 | 人的大脑处理信息需要花费一定的时间。一般来说,超前掩蔽很短,只有大约5~20ms,而滞后掩蔽
63 | 可以持续50~200ms。当强音信号和弱音信号同时出现时,弱信号会听不到,因此,弱音信号也属于
64 | 冗余信号。
65 | ```
66 | #### 音频编码过程
67 |
68 | 
69 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/notelib/src/main/java/com/bacchus/notelib/imooc/万人直播架构与CDN网络.md:
--------------------------------------------------------------------------------
1 | ## CDN网络介绍
2 |
3 | #### 泛娱乐化直播架构
4 | - 共享端(美女直播端:电脑、手机)发起信令到信令服务器,信令服务器进行逻辑处理(例如:创建房间、聊天、礼物都是以信令的方式进行传输处理的),
5 | - 流媒体云( CDN ):对音视频流( RTMP )进行转发,将信号转发给收看用户
6 | 
7 |
8 | 流程描述
9 | - 共享端
10 | - 共享端发送信令到信令服务器,请求创建房间
11 | - 信令服务器收到信令后,创建房间,然后给共享端返回一个流媒体云的地址
12 | - 共享端采集自己的音视频数据,形成 RTMP 流上传到流媒体云网络
13 | - 用户收看端
14 | - 用户发送请求加入房间的信令给信令服务器
15 | - 信令服务器将此用户加入到房间,然后返回此用户请求的该美女主播房间的 CDN 流地址
16 | - 用户通过此地址拉取此流从而观看该节目
17 |
18 | 可能会有很多架构变形,但是基本上万变不离其宗,大致都是这个样子
19 |
20 | #### 实时互动直播架构
21 | - TCP 协议:通过确认、超时、重发来使包的传输可以准确无误,但是也使其无法更好的进行实时传输,所以实时互动直播架构采用的是 UDP 协议,使用 UDP 协议就需要用到自有网络,不能只使用 CDN 网络了
22 | - 音视频数据有时效性,所以允许丢包,但是丢包了就会影响质量
23 | - 有多个服务节点,一旦某个节点有问题就会转移到其余节点,对于用户来说是无感知的
24 | ,也能保证负载均衡
25 | - 由于有多个节点,所以有一个控制中心,控制中心与节点之间是通过心跳包来联系的,隔一段时间,节点都会向控制中心发送此刻的:CPU 占用情况,IO 占用情况、网络占用情况等等
26 | - 控制中心会根据这些信息来调拨这些节点,例如将数据交给 CPU 占用较低的节点处理
27 | - 心跳包是通过内总线进行传输的,内总线的容量更高
28 | - 以上就为实时互动架构,而通过媒体服务器进行转换给 CDN 网络,即将 UDP 协议转化为 RTMP 协议
29 | 
30 |
31 | #### CDN 网络
32 | - CDN 网络是为了解决用户访问网络资源慢而出现的技术
33 | - 网络资源慢的原因
34 | - 数据链路长:海南访问北京的用户的数据,数据传输过程中还可能有节点会出现一些错误情况,如果将北京的服务直接搬到海南的服务中,就可以直接访问海南的服务了
35 | - 运营商之间为了利益不允许其他运营商的网络访问自己的网络,例如联通的不让访问电信的
36 | - CDN 构成
37 | - 边缘节点:用户从边缘节点(指的是网络,不是物理距离)上获取数据
38 | - 二级节点:二级节点就是主干网节点,主要用于缓存大量数据,减轻源站压力。例如当边缘节点有数据时会直接返回给用户,无数据时,会向上访问主干节点,将数据拉取到自己的边缘节点再传输给用户,
39 | - 源站:CP (内容提供方)将内容放到源站,当主干节点也没数据时就会到源站节点获取数据
40 | - 有一些大型公司可能会因为数据很大,会分为更多层节点,但是大体上是这么一个结构
41 | - CDN 网络
42 | - 在各大运营商中间设立主打节点,通过光纤将两个节点打通,这样就可以解决不同运营商之间的数据传输问题
43 | - 用户访问流程
44 | - 用户访问时会先访问 CDN 网络,然后 CDN 网络会判断该用户是什么运营商,然后找到最近的边缘节点,若边缘节点无数据,则向上请求主干节点,若主干节点依然没有数据则继续请求源站
45 | - 每次请求到达每一个节点,若是第一次,则会进行缓存,酱紫下一次请求或者其他用户请求时速度就会加快
46 | - CDN 网络的两种类型
47 | - 传统网络:热点型,若请求多次的会存在主干中,超时后删除
48 | - 直播类型:对延时性要求比较高,所以源站会一次性将所有数据 Push 到主干节点中,边缘节点直接从主干节点中进行拉取
49 | 
50 |
51 | #### 工具
52 | - FFmpeg:
53 | - 只需要一个命令就可以将一个视频格式转换为其他视频格式
54 | - 音视频的抽取
55 | - 视频上打水印
56 | - FFPlay
57 | - 使用命令行,不是图形化,是基于 FFmpeg 进行二次化开发的工具
58 | - FlashPlayer
59 | - 用于对 RTMP 协议进行分析
60 |
61 | #### 搭建流媒体服务
62 | - 准备流媒体服务器(商业最好是 Linux,不建议用 Windows,所以平时用 Mac)
63 | - 编译并安装 Nginx 服务( Web 服务器)
64 | - 配置 RTMP 服务并启动 Nginx 服务
65 |
66 | #### 安装配置步骤
67 | - 到 iTerm 中输入:brew install nginx
68 | - 此处可以直接百度搜索 nginx 的下载安装过程
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | xmlns:android
14 |
15 | ^$
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | xmlns:.*
25 |
26 | ^$
27 |
28 |
29 | BY_NAME
30 |
31 |
32 |
33 |
34 |
35 |
36 | .*:id
37 |
38 | http://schemas.android.com/apk/res/android
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | .*:name
48 |
49 | http://schemas.android.com/apk/res/android
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 | name
59 |
60 | ^$
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | style
70 |
71 | ^$
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 | .*
81 |
82 | ^$
83 |
84 |
85 | BY_NAME
86 |
87 |
88 |
89 |
90 |
91 |
92 | .*
93 |
94 | http://schemas.android.com/apk/res/android
95 |
96 |
97 | ANDROID_ATTRIBUTE_ORDER
98 |
99 |
100 |
101 |
102 |
103 |
104 | .*
105 |
106 | .*
107 |
108 |
109 | BY_NAME
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
--------------------------------------------------------------------------------
/notelib/src/main/java/com/bacchus/notelib/cnblog/Android 音视频开发(二):使用 AudioRecord 采集音频PCM并保存到文件(学习笔记).md:
--------------------------------------------------------------------------------
1 | #### 关于 AudioRecord
2 | Android SDK 提供了两套音频采集的API,分别是:MediaRecorder 和 AudioRecord,前者是一个更加上层一点的API,它可以直接把手机麦克风录入的音频数据进行编码压缩(如AMR、MP3等)并存成文件,而后者则更接近底层,能够更加自由灵活地控制,可以得到原始的一帧帧PCM音频数据。
3 |
4 | 如果想简单地做一个录音机,录制成音频文件,则推荐使用 MediaRecorder,而如果需要对音频做进一步的算法处理、或者采用第三方的编码库进行压缩、以及网络传输等应用,则建议使用 AudioRecord,其实 MediaRecorder 底层也是调用了 AudioRecord 与 Android Framework 层的 AudioFlinger 进行交互的。
5 |
6 | 音频的开发,更广泛地应用不仅仅局限于本地录音,因此,我们需要重点掌握如何利用更加底层的 AudioRecord API 来采集音频数据(注意,使用它采集到的音频数据是原始的PCM格式,想压缩为mp3,aac等格式的话,还需要专门调用编码器进行编码)。
7 |
8 | #### AudioRecord 的参数配置
9 | - **audioSource:音频采集的输入源**
10 |
11 | 可选的值以常量的形式定义在 MediaRecorder.AudioSource 类中,常用的值包括:
12 | - [x] 1. DEFAULT (默认)
13 | - [x] 2. VOICE_RECOGNITION (用于语音识别,等同于 DEFAULT )
14 | - [x] 3. MIC (由手机麦克风输入)
15 | - [x] 4. VOICE_COMMUNICATION (用于 VoIP 应用)等等
16 |
17 | - **sampleRateInHz: 采样率**
18 |
19 | 目前 44100Hz 是唯一可以保证兼容所有 Android 手机的采样率。
20 |
21 | - **channelConfig: 通道数**
22 |
23 | 可选的值以常量的形式定义在 AudioFormat 类中,常用的是
24 | - [x] 1. CHANNEL_IN_MONO (单通道)
25 | - [x] 2. CHANNEL_IN_STEREO(双通道)
26 |
27 | - **audioFormat: 数据位宽**
28 |
29 | 可选的值以常量的形式定义在 AudioFormat 类中,常用的是( 1 是可以保证兼容所有Android手机的)
30 | - [x] 1. ENCODING_PCM_16BIT(16bit)
31 | - [x] 2. ENCODING_PCM_8BIT(8bit)
32 |
33 | - **bufferSizeInBytes:AudioRecord 内部的音频缓冲区的大小**
34 |
35 | 该缓冲区的值不能低于一帧“音频帧”(Frame)的大小:
36 |
37 | > int size = 采样率 x 位宽 x 采样时间 x 通道数
38 |
39 | 采样时间一般取 2.5ms~120ms 之间,由厂商或者具体的应用决定,我们其实可以推断,每一帧的采样时间取得越短,产生的延时就应该会越小,当然,碎片化的数据也就会越多。
40 |
41 | 在Android开发中,AudioRecord 类提供了一个帮助你确定这个 bufferSizeInBytes 的函数,原型如下:
42 |
43 | > int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat);
44 |
45 | 不同的厂商的底层实现是不一样的,但无外乎就是根据上面的计算公式得到一帧的大小,音频缓冲区的大小则必须是一帧大小的2~N倍。实际开发中,强烈建议由该函数计算出需要传入的 bufferSizeInBytes,而不是自己手动计算。
46 |
47 | #### 流程
48 |
49 | - **设置所有 AudioRecord 参数**
50 |
51 | ```
52 | // 音频输入-麦克风
53 | private final static int AUDIO_INPUT = MediaRecorder.AudioSource.MIC;
54 | // 采样频率 一般共分为 22.05KHz、44.1KHz、48KHz 三个等级
55 | // 44100 是目前的标准,但是某些设备仍然支持 22050,16000,11025
56 | private final static int AUDIO_SAMPLE_RATE = 44100;
57 | // 声道 单声道
58 | private final static int AUDIO_CHANNEL = AudioFormat.CHANNEL_IN_MONO;
59 | // 编码
60 | private final static int AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;
61 | // 缓冲区字节大小
62 | private int bufferSizeInBytes = 0;
63 | // 录音对象
64 | private AudioRecord audioRecord;
65 | ```
66 | - **创建 AudioRecord 并且获取缓冲区字节大小**
67 |
68 | ```
69 | /**
70 | * 创建默认的录音对象
71 | *
72 | * @param fileName 文件名
73 | */
74 | public void createDefaultAudio(String fileName) {
75 | // 获得缓冲区字节大小,AudioRecord 能接受的最小的 buffer 大小
76 | bufferSizeInBytes = AudioRecord.getMinBufferSize(AUDIO_SAMPLE_RATE, AUDIO_CHANNEL, AUDIO_ENCODING);
77 | // 创建默认的录音对象并且设置一系列配置
78 | audioRecord = new AudioRecord(AUDIO_INPUT, AUDIO_SAMPLE_RATE, AUDIO_CHANNEL, AUDIO_ENCODING, bufferSizeInBytes);
79 | this.fileName = fileName;
80 | }
81 | ```
82 | - **创建 buffer (用于保存新的声音数据),设置 buffer 大小(录制声音数据容量大小)**
83 |
84 | ```
85 | // new 一个 byte 数组用来存一些字节数据,大小为缓冲区大小
86 | byte[] audiodata = new byte[bufferSizeInBytes];
87 | ```
88 |
89 | - **开始录音**
90 |
91 | ```
92 | audioRecord.startRecording();
93 | // 标志位, 用于控制停止数据流读写循环
94 | isRecording = true;
95 | ```
96 | - **开始采集,一边从AudioRecord中读取声音数据到初始化的buffer,一边将buffer中数据导入数据流**
97 |
98 | ```
99 | // 开个子线程将录音的数据放入pcm文件
100 | new Thread(new Runnable() {
101 | @Override
102 | public void run() {
103 | writeDataTOFile(listener);
104 | }
105 | }).start();
106 |
107 | // 如何将音频写入文件是重点,我写个伪代码,说明这个代码运行顺序
108 | // 首先创建 pcm 文件,得到他的 FileOutputStream,然后不断循环 AudioRecord 通过 read 将录音的数据放入字节数组里,
109 | // 当录音结束的时候要记得停止这个循环
110 | FileOutputStream fos = null;
111 | int readsize = 0;
112 | try {
113 | File file = new File(currentFileName);
114 | if (file.exists()) {
115 | file.delete();
116 | }
117 | // 建立一个可存取字节的文件
118 | fos = new FileOutputStream(file);
119 | } catch (IllegalStateException e) {
120 | Log.e("AudioRecorder", e.getMessage());
121 | throw new IllegalStateException(e.getMessage());
122 | } catch (FileNotFoundException e) {
123 | Log.e("AudioRecorder", e.getMessage());
124 | }
125 | while (isRecording) {
126 | readsize = audioRecord.read(audiodata, 0, bufferSizeInBytes);
127 | if (AudioRecord.ERROR_INVALID_OPERATION != readsize && fos != null) {
128 | try {
129 | fos.write(audiodata);
130 | } catch (IOException e) {
131 | Log.e("AudioRecorder", e.getMessage());
132 | }
133 | }
134 | }
135 | ```
136 | - **关闭数据流**
137 |
138 | 修改标志位:isRecording 为false,上面的while循环就自动停止了,数据流也就停止流动了,Stream也就被关闭了。
139 | ```
140 | isRecording = false;
141 | ```
142 | - **停止录音**
143 |
144 | 只要AudioRecord.stop就可以暂停录音了,然后当继续录音时在AudioRecord.start就好了,但是要另创建一个pcm记录,当录音结束时我们要将这些pcm一起转换为一个wav,
145 |
146 | 至于pcm转换为wav的代码是固定的
147 | 停止录音之后,注意要释放资源。
148 |
149 | ```
150 | if (null != audioRecord) {
151 | audioRecord.stop();
152 | audioRecord.release();
153 | audioRecord = null;
154 | recordingThread = null;
155 | }
156 | ```
157 | #### 流程走向
158 | - buffer 从 AudioRecord 中拉取声音数据
159 |
160 | 
161 |
162 | - 创建一个数据流,开启一个线程,一边从 AudioRecord 中读取数据,一边将数据导入到数据流中
163 |
164 | 
165 |
166 | #### 参考文献
167 | - [Android音频开发(2):如何采集一帧音频](https://blog.51cto.com/ticktick/1749719)
168 | - [Android 音视频开发(二):使用 AudioRecord 采集音频PCM并保存到文件](https://www.cnblogs.com/renhui/p/7457321.html)
169 | - [Android 音视频深入](https://www.cnblogs.com/jianpanwuzhe/p/8403784.html)
170 |
171 |
172 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------