├── .gitignore ├── README.md ├── TestRecord.iml ├── app ├── .gitignore ├── build.gradle ├── libs │ └── armeabi │ │ ├── libAacEncoder.so │ │ └── libVoAACEncoder.so ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── example │ │ └── chencheng │ │ └── testrecord │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ ├── com │ │ │ ├── example │ │ │ │ └── chencheng │ │ │ │ │ └── testrecord │ │ │ │ │ └── MainActivity.java │ │ │ └── sinaapp │ │ │ │ └── bashell │ │ │ │ ├── AacEncoder.java │ │ │ │ └── VoAACEncoder.java │ │ └── lwx │ │ │ └── linin │ │ │ └── aac │ │ │ ├── AAC.java │ │ │ └── VoAAC.java │ └── res │ │ ├── layout │ │ └── activity_main.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── example │ └── chencheng │ └── testrecord │ └── ExampleUnitTest.java ├── build.gradle ├── default.gitignore ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── local.properties └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AndroidRecordAAC 2 | Android上录制AAC格式的音频 3 | -------------------------------------------------------------------------------- /TestRecord.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.2" 6 | 7 | defaultConfig { 8 | applicationId "com.example.chencheng.testrecord" 9 | minSdkVersion 19 10 | targetSdkVersion 23 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | 21 | sourceSets { 22 | main { 23 | jniLibs.srcDirs = ['libs'] 24 | } 25 | } 26 | } 27 | 28 | dependencies { 29 | compile fileTree(dir: 'libs', include: ['*.jar']) 30 | testCompile 'junit:junit:4.12' 31 | compile 'com.android.support:appcompat-v7:23.1.1' 32 | } 33 | -------------------------------------------------------------------------------- /app/libs/armeabi/libAacEncoder.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shaoyuan1943/AndroidRecordAAC/27c19ca5770c5bd95fb85c08e86e1084e04b7ebd/app/libs/armeabi/libAacEncoder.so -------------------------------------------------------------------------------- /app/libs/armeabi/libVoAACEncoder.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shaoyuan1943/AndroidRecordAAC/27c19ca5770c5bd95fb85c08e86e1084e04b7ebd/app/libs/armeabi/libVoAACEncoder.so -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\Users\chencheng\AppData\Local\Android\Sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/example/chencheng/testrecord/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.example.chencheng.testrecord; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/chencheng/testrecord/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.chencheng.testrecord; 2 | 3 | import android.content.DialogInterface; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.os.Bundle; 6 | import android.widget.TextView; 7 | import android.widget.Button; 8 | import android.util.Log; 9 | import android.view.View; 10 | import android.view.View.OnClickListener; 11 | import android.os.Build; 12 | import android.os.Environment; 13 | import java.io.IOException; 14 | import java.io.File; 15 | import lwx.linin.aac.AAC; 16 | import lwx.linin.aac.VoAAC; 17 | 18 | import android.media.MediaPlayer; 19 | import android.media.MediaRecorder; 20 | 21 | public class MainActivity extends AppCompatActivity 22 | { 23 | private Button btnSpeak; 24 | private Button btnEnd; 25 | private Button btnPlay; 26 | 27 | private TextView content; 28 | private String fileName; 29 | 30 | private MediaRecorder recorder; 31 | private MediaPlayer player; 32 | 33 | private int sampleRateInHz = 16000; 34 | 35 | private AAC aac; 36 | private VoAAC voaac; 37 | @Override 38 | protected void onCreate(Bundle savedInstanceState) 39 | { 40 | super.onCreate(savedInstanceState); 41 | setContentView(R.layout.activity_main); 42 | 43 | fileName = Environment.getExternalStorageDirectory().getAbsolutePath(); 44 | fileName += "/fuckworld.aac"; 45 | 46 | btnSpeak = (Button)findViewById(R.id.BtnSpeak); 47 | btnEnd = (Button)findViewById(R.id.BtnEnd); 48 | btnPlay = (Button)findViewById(R.id.BtnPlay); 49 | 50 | content = (TextView)findViewById(R.id.msg); 51 | 52 | btnSpeak.setOnClickListener(new StartRecord()); 53 | btnEnd.setOnClickListener(new StopListener()); 54 | btnPlay.setOnClickListener(new StartPlay()); 55 | } 56 | 57 | class StartRecord implements OnClickListener 58 | { 59 | @Override 60 | public void onClick(View v) 61 | { 62 | aac = new AAC(fileName); 63 | aac.sampleRateInHz(sampleRateInHz); 64 | aac.start(); 65 | 66 | /*recorder = new MediaRecorder(); 67 | recorder.setAudioSource(MediaRecorder.AudioSource.MIC); 68 | recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); 69 | recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); 70 | recorder.setAudioChannels(1); 71 | recorder.setOutputFile(fileName); 72 | 73 | try 74 | { 75 | recorder.prepare(); 76 | } 77 | catch(IOException ex) 78 | { 79 | Log.e("chencheng", "prepare() failed!" + ex.getMessage()); 80 | } 81 | content.setText("录音中..." + fileName); 82 | recorder.start();*/ 83 | } 84 | } 85 | 86 | class StopListener implements OnClickListener 87 | { 88 | @Override 89 | public void onClick(View v) 90 | { 91 | if (aac != null) 92 | { 93 | aac.stop(); 94 | aac = null; 95 | } 96 | /*if (recorder != null) 97 | { 98 | content.setText(R.string.ends); 99 | recorder.stop(); 100 | recorder.release(); 101 | recorder = null; 102 | } 103 | 104 | if (player != null) 105 | { 106 | content.setText(R.string.ends); 107 | player.stop(); 108 | player.release(); 109 | player = null; 110 | }*/ 111 | } 112 | } 113 | 114 | 115 | class StartPlay implements OnClickListener 116 | { 117 | @Override 118 | public void onClick(View v) 119 | { 120 | player = new MediaPlayer(); 121 | try 122 | { 123 | File file = new File(fileName); 124 | boolean exists = file.exists(); 125 | long size = file.length(); 126 | if (exists) 127 | { 128 | Log.e("XY", "文件大小:" + size); 129 | } 130 | player.setDataSource(fileName); 131 | player.prepare(); 132 | player.start(); 133 | } 134 | catch(IOException ex) 135 | { 136 | Log.e("XY", "player failed!" + ex.getMessage()); 137 | } 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /app/src/main/java/com/sinaapp/bashell/AacEncoder.java: -------------------------------------------------------------------------------- 1 | package com.sinaapp.bashell; 2 | 3 | public class AacEncoder { 4 | /* MPEG ID's */ 5 | private final int MPEG2 = 1; 6 | private final int MPEG4 = 0; 7 | 8 | /* AAC object types */ 9 | private final int MAIN = 1; 10 | private final int LOW = 2; 11 | private final int SSR = 3; 12 | private final int LTP = 4; 13 | 14 | /* Bitstream output format */ 15 | private final int RAW = 0; 16 | private final int ADTS = 1; 17 | 18 | /* Input Formats */ 19 | private final int FAAC_INPUT_NULL = 0; 20 | private final int FAAC_INPUT_16BIT = 1; 21 | private final int FAAC_INPUT_24BIT = 2; 22 | private final int FAAC_INPUT_32BIT = 3; 23 | private final int FAAC_INPUT_FLOAT = 4; 24 | 25 | public int inputSamples = 0; 26 | public int maxOutputBytes = 0; 27 | public int bitRate = 32000; 28 | public int quantqual = 100; 29 | public int bandWidth = 7200; 30 | public int aacObjectType = LOW; 31 | public int outputFormat = ADTS; 32 | public int mpegVersion = MPEG4; 33 | public int inputFormat = FAAC_INPUT_16BIT; 34 | static 35 | { 36 | System.loadLibrary("AacEncoder"); 37 | } 38 | 39 | public native int AACEncoderOpen(int sampleRate, int channels); 40 | 41 | public native byte[] AACEncoderEncode(int hEncoder, byte[] inputBuffer, int inputBufferSize); 42 | 43 | public native int AACEncoderClose(int hEncoder); 44 | } 45 | -------------------------------------------------------------------------------- /app/src/main/java/com/sinaapp/bashell/VoAACEncoder.java: -------------------------------------------------------------------------------- 1 | package com.sinaapp.bashell; 2 | 3 | public class VoAACEncoder 4 | { 5 | static 6 | { 7 | System.loadLibrary("VoAACEncoder"); 8 | } 9 | 10 | public native int Init(int sampleRate, int bitRate, short nChannels,short adtsUsed); 11 | 12 | public native byte[] Enc(byte[] inputBuffer); 13 | 14 | public native int Uninit(); 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/lwx/linin/aac/AAC.java: -------------------------------------------------------------------------------- 1 | package lwx.linin.aac; 2 | 3 | import java.io.FileNotFoundException; 4 | import java.io.FileOutputStream; 5 | import java.io.IOException; 6 | 7 | import android.media.AudioFormat; 8 | import android.media.AudioRecord; 9 | import android.media.MediaRecorder; 10 | 11 | import com.sinaapp.bashell.AacEncoder; 12 | 13 | public class AAC implements Runnable 14 | { 15 | 16 | /**从默认的16000开始,若失败则会用其余的采样率*/ 17 | private static int[] sampleRates = { 16000, 44100, 22050, 11025, 8000, 4000 }; 18 | 19 | private boolean isStart = false; 20 | private FileOutputStream fos; 21 | private AudioRecord recordInstance; 22 | private int hAac; 23 | private AacEncoder aacEncoder; 24 | private int bufferSize,minBufferSize; 25 | private byte[] tempBuffer; 26 | 27 | public AAC(String fileName) 28 | { 29 | try 30 | { 31 | fos = new FileOutputStream(fileName); 32 | } 33 | catch (FileNotFoundException e) 34 | { 35 | e.printStackTrace(); 36 | } 37 | } 38 | 39 | /**设置默认采样率,默认16000*/ 40 | public AAC sampleRateInHz(int sampleRateInHz) 41 | { 42 | sampleRates[0] = sampleRateInHz; 43 | return this; 44 | } 45 | 46 | public void start() 47 | { 48 | isStart = true; 49 | Thread t = new Thread(this); 50 | t.start(); 51 | } 52 | 53 | public void stop() 54 | { 55 | isStart = false; 56 | } 57 | 58 | @Override 59 | public void run() 60 | { 61 | for (int i = 0; i < sampleRates.length; i++) 62 | { 63 | try 64 | { 65 | aacEncoder = new AacEncoder(); 66 | hAac = aacEncoder.AACEncoderOpen(sampleRates[i], 1); 67 | minBufferSize = AudioRecord.getMinBufferSize(sampleRates[i], AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT); 68 | if(minBufferSize < 2048) 69 | minBufferSize = 2048; 70 | bufferSize = aacEncoder.inputSamples * 16 / 8; 71 | tempBuffer = new byte[minBufferSize]; 72 | recordInstance = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRates[i], AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, minBufferSize);//bufferSize); 73 | recordInstance.startRecording(); 74 | break; 75 | } 76 | catch (Exception e) 77 | { 78 | e.printStackTrace(); 79 | } 80 | } 81 | 82 | while (isStart) 83 | { 84 | int bufferRead = recordInstance.read(tempBuffer, 0, minBufferSize);//bufferSize); 85 | if (bufferRead > 0) 86 | { 87 | int n = minBufferSize/bufferSize;//算出需要循环几次取值 88 | for (int i = 0; i < n; i++) 89 | { 90 | byte[] temp = new byte[bufferSize]; 91 | System.arraycopy(tempBuffer, i*bufferSize, temp, 0, bufferSize); 92 | byte[] ret = aacEncoder.AACEncoderEncode(hAac, temp, temp.length); 93 | try 94 | { 95 | fos.write(ret); 96 | } 97 | catch (IOException e) 98 | { 99 | e.printStackTrace(); 100 | } 101 | } 102 | } 103 | //计算出音量分贝值 104 | if (bufferRead>0) 105 | { 106 | long v = 0; 107 | for (int i = 0; i < tempBuffer.length; i++) 108 | { 109 | v += tempBuffer[i] * tempBuffer[i];//计算平方和 110 | } 111 | double mean = v/(double)bufferRead;//平方和/总长度,得到音量大小 112 | volume = 10*Math.log10(mean);//转换公式 113 | //L.e("volume","分贝值:"+volume); 114 | } 115 | } 116 | 117 | try 118 | { 119 | recordInstance.stop(); 120 | recordInstance.release(); 121 | recordInstance = null; 122 | } 123 | catch (Exception e) 124 | { 125 | e.printStackTrace(); 126 | } 127 | aacEncoder.AACEncoderClose(hAac); 128 | try 129 | { 130 | fos.close(); 131 | } 132 | catch (IOException e) 133 | { 134 | e.printStackTrace(); 135 | } 136 | } 137 | 138 | private double volume = 0; 139 | /**实时获取音量大小*/ 140 | public double getVolume() 141 | { 142 | return volume; 143 | } 144 | 145 | } 146 | -------------------------------------------------------------------------------- /app/src/main/java/lwx/linin/aac/VoAAC.java: -------------------------------------------------------------------------------- 1 | package lwx.linin.aac; 2 | 3 | import java.io.FileNotFoundException; 4 | import java.io.FileOutputStream; 5 | import java.io.IOException; 6 | 7 | import android.media.AudioFormat; 8 | import android.media.AudioRecord; 9 | import android.media.MediaRecorder; 10 | 11 | import com.sinaapp.bashell.VoAACEncoder; 12 | 13 | public class VoAAC implements Runnable 14 | { 15 | 16 | /**从默认的16000开始,若失败则会用其余的采样率*/ 17 | private static int[] sampleRates = { 16000, 44100, 22050, 11025, 8000, 4000 }; 18 | 19 | private boolean isStart = false; 20 | private FileOutputStream fos; 21 | private AudioRecord recordInstance; 22 | 23 | public VoAAC(String fileName) 24 | { 25 | try 26 | { 27 | fos = new FileOutputStream(fileName); 28 | } 29 | catch (FileNotFoundException e) 30 | { 31 | e.printStackTrace(); 32 | } 33 | } 34 | 35 | /**设置默认采样率,默认16000*/ 36 | public VoAAC sampleRateInHz(int sampleRateInHz) 37 | { 38 | sampleRates[0] = sampleRateInHz; 39 | return this; 40 | } 41 | 42 | public void start() 43 | { 44 | isStart = true; 45 | Thread t = new Thread(this); 46 | t.start(); 47 | } 48 | 49 | public void stop() 50 | { 51 | isStart = false; 52 | } 53 | 54 | @Override 55 | public void run() 56 | { 57 | VoAACEncoder vo = new VoAACEncoder(); 58 | byte[] tempBuffer = new byte[2048]; 59 | for (int i = 0; i < sampleRates.length; i++) 60 | { 61 | try 62 | { 63 | // 采样率:44100,bitRate:32k,声道数:1,编码:0.raw 1.ADTS 64 | vo.Init(sampleRates[i], 32000, (short)1, (short)1); 65 | int min = AudioRecord.getMinBufferSize(sampleRates[i], AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT); 66 | if(min<2048) 67 | { 68 | min=2048; 69 | } 70 | recordInstance = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRates[i], AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, min); 71 | recordInstance.startRecording(); 72 | break; 73 | } 74 | catch (Exception e) 75 | { 76 | e.printStackTrace(); 77 | } 78 | } 79 | while (isStart) 80 | { 81 | int bufferRead = recordInstance.read(tempBuffer, 0, 2048); 82 | byte[] ret = vo.Enc(tempBuffer); 83 | if (bufferRead > 0) 84 | { 85 | System.out.println("ret:"+ret.length); 86 | try 87 | { 88 | fos.write(ret); 89 | } 90 | catch (IOException e) 91 | { 92 | e.printStackTrace(); 93 | } 94 | } 95 | //计算出音量分贝值 96 | if (bufferRead>0) 97 | { 98 | long v = 0; 99 | for (int i = 0; i < tempBuffer.length; i++) 100 | { 101 | v += tempBuffer[i] * tempBuffer[i];//计算平方和 102 | } 103 | double mean = v/(double)bufferRead;//平方和/总长度,得到音量大小 104 | volume = 10*Math.log10(mean);//转换公式 105 | //L.e("volume","分贝值:"+volume); 106 | } 107 | } 108 | recordInstance.stop(); 109 | recordInstance.release(); 110 | recordInstance = null; 111 | vo.Uninit(); 112 | try 113 | { 114 | fos.close(); 115 | } 116 | catch (IOException e) 117 | { 118 | e.printStackTrace(); 119 | } 120 | } 121 | 122 | private double volume = 0; 123 | /**实时获取音量大小*/ 124 | public double getVolume() 125 | { 126 | return volume; 127 | } 128 | 129 | } 130 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 20 | 21 |