Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,14 @@ private int processData() {
if (mTasks.size() > 0) {
Task task = mTasks.remove(0);
short[] buffer = task.getData();
short[] rightData = task.getRightData();
int readSize = task.getReadSize();
int encodedSize = LameUtil.encode(buffer, buffer, readSize, mMp3Buffer);
if(task.getRightData() != null && task.getRightData().length > 0){
rightData = task.getRightData();
}else{
rightData = task.getData();
}
int encodedSize = LameUtil.encode(buffer, rightData, readSize, mMp3Buffer);
if (encodedSize > 0){
try {
mFileOutputStream.write(mMp3Buffer, 0, encodedSize);
Expand All @@ -116,6 +122,7 @@ private int processData() {
return 0;
}


/**
* Flush all data left in lame buffer to file
*/
Expand Down Expand Up @@ -143,16 +150,30 @@ private void flushAndRelease() {
public void addTask(short[] rawData, int readSize){
mTasks.add(new Task(rawData, readSize));
}
public void addTask(short[] rawData,short[] rightData, int readSize){
mTasks.add(new Task(rawData, rightData,readSize));
}
private class Task{
private short[] rawData;
private int readSize;
private short[] rightData;
public Task(short[] rawData, int readSize){
this.rawData = rawData.clone();
this.readSize = readSize;
}
public Task(short[] leftData, short[] rightData,int readSize){
this.rawData = leftData.clone();
this.rightData = rightData.clone();
this.readSize = readSize;
}
public short[] getData(){
return rawData;
}

public short[] getRightData(){
return rightData;
}

public int getReadSize(){
return readSize;
}
Expand Down
28 changes: 28 additions & 0 deletions RecordTest/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.laba.recordtest"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk
android:minSdkVersion="11"
android:targetSdkVersion="21" />

<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@android:style/Theme.Holo.Light" >
<activity
android:name=".MainActivity"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>


</manifest>
20 changes: 20 additions & 0 deletions RecordTest/proguard-project.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# To enable ProGuard in your project, edit project.properties
# to define the proguard.config property as described in that file.
#
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in ${sdk.dir}/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the ProGuard
# include property in project.properties.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# Add any project specific keep options here:

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
15 changes: 15 additions & 0 deletions RecordTest/project.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system edit
# "ant.properties", and override values to adapt the script to your
# project structure.
#
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt

# Project target.
target=android-21
android.library.reference.1=../AndroidMP3RecorderLibrary
Binary file added RecordTest/res/drawable-hdpi/ic_launcher.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added RecordTest/res/drawable-mdpi/ic_launcher.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added RecordTest/res/drawable-xhdpi/ic_launcher.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added RecordTest/res/drawable-xxhdpi/ic_launcher.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
38 changes: 38 additions & 0 deletions RecordTest/res/layout/main.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
>

<Button
android:id="@+id/btn_record_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="开始录音"
/>
<Button
android:id="@+id/btn_record_pause"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="暂停录音"
/>
<Button
android:id="@+id/btn_record_stop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="停止录音"
/>


<Button
android:id="@+id/btn_play"
android:layout_marginTop="50dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="播放"
android:visibility="visible"
/>

</LinearLayout>
5 changes: 5 additions & 0 deletions RecordTest/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<resources>

<string name="app_name">RecordTest</string>

</resources>
233 changes: 233 additions & 0 deletions RecordTest/src/com/laba/recordtest/AudioRecorder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
package com.laba.recordtest;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;

import com.czt.mp3recorder.DataEncodeThread;
import com.czt.mp3recorder.util.LameUtil;

import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.os.Message;
import android.util.Log;

public class AudioRecorder extends Thread {

private static final String TAG = "AudioRecorder";

private final int sampleRates[] = {44100,22050, 11025, 8000};
private final int configs[] = { AudioFormat.CHANNEL_IN_MONO,AudioFormat.CHANNEL_IN_STEREO};
private final int formats[] = { AudioFormat.ENCODING_PCM_16BIT, AudioFormat.ENCODING_PCM_8BIT };

// ======================Lame Default Settings=====================
private static final int DEFAULT_LAME_MP3_QUALITY = 7;
/**
* Encoded bit rate. MP3 file will be encoded with bit rate 128kbps
*/
private static final int DEFAULT_LAME_MP3_BIT_RATE = 128;

private AudioRecord audioRecord = null;
int bufsize = AudioRecord.ERROR_BAD_VALUE;
private boolean mShouldRun = false;
private boolean mShouldRecord = false;

/**
* 自定义 每220帧作为一个周期,通知一下需要进行编码
*/
private static final int FRAME_COUNT = 220;
private short[] mPCMBuffer;
private DataEncodeThread mEncodeThread;

private File outputFile;
private double mDuration;//录音时间

public AudioRecorder(File file) {
outputFile = file;
}


public void startRecording(){
mShouldRecord = true;
}

public void resumeRecord(){
mShouldRecord = true;
}

public void pauseRecord(){
mShouldRecord = false;
}

public void stopRecord(){
mShouldRecord = false;
mShouldRun = false;
if(audioRecord != null){
audioRecord.stop();
audioRecord.release();
audioRecord = null;
}
// stop the encoding thread and try to wait until the thread finishes its job
Message msg = Message.obtain(mEncodeThread.getHandler(),
DataEncodeThread.PROCESS_STOP);
msg.sendToTarget();
}

private int mapFormat(int format){
switch (format) {
case AudioFormat.ENCODING_PCM_8BIT:
return 8;
case AudioFormat.ENCODING_PCM_16BIT:
return 16;
default:
return 0;
}
}

public int getDuration(){
return (int)mDuration;
}

@Override
public void run() {
super.run();
if(!isFound()){
Log.e(TAG, "Sample rate, channel config or format not supported!");
return;
}
init();
mShouldRun = true;
boolean oldShouldRecord = false;

int bytesPerSecond = audioRecord.getSampleRate() * mapFormat(audioRecord.getAudioFormat()) / 8 * audioRecord.getChannelCount();
mDuration = 0.0;
while (mShouldRun) {
if(mShouldRecord != oldShouldRecord){
if(mShouldRecord){
audioRecord.startRecording();
}else{
audioRecord.stop();
}
oldShouldRecord = mShouldRecord;
}

if(mShouldRecord){
int readSize = audioRecord.read(mPCMBuffer, 0, bufsize);
if (readSize > 0) {
double read_ms = (1000.0 * readSize * 2) / bytesPerSecond;
mDuration += read_ms;

if(audioRecord.getChannelCount()==1){
mEncodeThread.addTask(mPCMBuffer, readSize);
}else if(audioRecord.getChannelCount() == 2){
short[] leftData = new short[readSize / 2];
short[] rightData = new short[readSize / 2];
for(int i = 0;i< readSize /2; i = i + 2){
leftData[i] = mPCMBuffer[2 * i];
if( 2 * i + 1 < readSize){
leftData[i+1] = mPCMBuffer[2 * i + 1];
}
if(2 * i + 2 < readSize){
rightData[i] = mPCMBuffer[2 * i + 2];
}
if(2 * i + 3 < readSize){
rightData[i + 1] = mPCMBuffer[2 * i + 3];
}
}
mEncodeThread.addTask(leftData,rightData, readSize / 2);
}
}
}
}
}


public boolean isRecording(){
return mShouldRecord;
}

private void init() {
int bytesPerFrame = audioRecord.getAudioFormat() == AudioFormat.ENCODING_PCM_16BIT ? 2
: 1;
int frameSize = bufsize / bytesPerFrame;
if (frameSize % FRAME_COUNT != 0) {
frameSize += (FRAME_COUNT - frameSize % FRAME_COUNT);
bufsize = frameSize * bytesPerFrame;
}
mPCMBuffer = new short[bufsize];
/*
* Initialize lame buffer
* mp3 sampling rate is the same as the recorded pcm sampling rate
* The bit rate is 128kbps
*/
LameUtil.init(audioRecord.getSampleRate(), audioRecord.getChannelCount(), audioRecord.getSampleRate(), DEFAULT_LAME_MP3_BIT_RATE, DEFAULT_LAME_MP3_QUALITY);
// Create and run thread used to encode data
// The thread will
try {
if(!outputFile.exists()){
outputFile.createNewFile();
}
mEncodeThread = new DataEncodeThread(outputFile, bufsize);
} catch (FileNotFoundException e) {
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}
mEncodeThread.start();
audioRecord.setRecordPositionUpdateListener(mEncodeThread, mEncodeThread.getHandler());
audioRecord.setPositionNotificationPeriod(FRAME_COUNT);
}

/**
* get the available AudioRecord
* @return
*/
private boolean isFound(){
boolean isFound = false;

int sample_rate = -1;
int channel_config = -1;
int format = -1;

for(int x=0;!isFound &&x<formats.length;x++){
format = formats[x];
for(int y=0;!isFound && y<sampleRates.length;y++){
sample_rate = sampleRates[y];
for (int z = 0 ; !isFound && z < configs.length ; z++) {
channel_config = configs[z];

Log.i(TAG, "Trying to create AudioRecord use: " + format + "/" + channel_config + "/" + sample_rate);
bufsize = AudioRecord.getMinBufferSize(sample_rate, channel_config, format);
Log.i(TAG, "Bufsize: " + bufsize);
if (AudioRecord.ERROR_BAD_VALUE == bufsize) {
Log.i(TAG, "invaild params!");
continue;
}
if(AudioRecord.ERROR == bufsize){
Log.i(TAG, "Unable to query hardware!");
continue;
}

try {
audioRecord = new AudioRecord(
MediaRecorder.AudioSource.MIC, sample_rate,
channel_config, format, bufsize);
int state = audioRecord.getState();
if (state != AudioRecord.STATE_INITIALIZED) {
continue;
}
} catch (IllegalStateException e) {
Log.i(TAG, "Failed to set up recorder!");
audioRecord = null;
continue;
}
isFound = true;
break;
}
}
}

return isFound;
}
}
Loading