Merge branch 'audiorecorder-1.0.8'
This commit is contained in:
commit
957208380f
9 changed files with 214 additions and 124 deletions
|
|
@ -8,8 +8,8 @@ android {
|
|||
applicationId "com.github.axet.audiorecorder"
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 23
|
||||
versionCode 8
|
||||
versionName "1.0.7"
|
||||
versionCode 9
|
||||
versionName "1.0.8"
|
||||
}
|
||||
signingConfigs {
|
||||
release {
|
||||
|
|
|
|||
|
|
@ -52,6 +52,8 @@ import java.util.Map;
|
|||
import java.util.TreeMap;
|
||||
|
||||
public class MainActivity extends AppCompatActivity implements AbsListView.OnScrollListener {
|
||||
public final static String TAG = MainActivity.class.getSimpleName();
|
||||
|
||||
static final int TYPE_COLLAPSED = 0;
|
||||
static final int TYPE_EXPANDED = 1;
|
||||
static final int TYPE_DELETED = 2;
|
||||
|
|
@ -104,6 +106,8 @@ public class MainActivity extends AppCompatActivity implements AbsListView.OnScr
|
|||
mp.release();
|
||||
duration.put(f, d);
|
||||
add(f);
|
||||
} else {
|
||||
Log.e(TAG, f.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -170,6 +174,7 @@ public class MainActivity extends AppCompatActivity implements AbsListView.OnScr
|
|||
builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
playerStop();
|
||||
dialog.cancel();
|
||||
RemoveItemAnimation.apply(list, base, new Runnable() {
|
||||
@Override
|
||||
|
|
@ -271,6 +276,10 @@ public class MainActivity extends AppCompatActivity implements AbsListView.OnScr
|
|||
|
||||
void playerPlay(View v, File f) {
|
||||
player = MediaPlayer.create(getContext(), Uri.fromFile(f));
|
||||
if (player == null) {
|
||||
Toast.makeText(MainActivity.this, "File not found", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
player.start();
|
||||
|
||||
updatePlayer(v, f);
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ import com.github.axet.audiorecorder.app.Storage;
|
|||
import com.github.axet.audiorecorder.encoders.Encoder;
|
||||
import com.github.axet.audiorecorder.encoders.EncoderInfo;
|
||||
import com.github.axet.audiorecorder.encoders.FileEncoder;
|
||||
import com.github.axet.audiorecorder.encoders.Format3GP;
|
||||
import com.github.axet.audiorecorder.encoders.FormatM4A;
|
||||
import com.github.axet.audiorecorder.encoders.FormatWAV;
|
||||
import com.github.axet.audiorecorder.widgets.PitchView;
|
||||
|
|
@ -175,7 +176,7 @@ public class RecordingActivity extends AppCompatActivity {
|
|||
|
||||
updateBufferSize(false);
|
||||
|
||||
updateSamples(0);
|
||||
updateSamples(getSamples(storage.getTempRecording().length()));
|
||||
|
||||
View cancel = findViewById(R.id.recording_cancel);
|
||||
cancel.setOnClickListener(new View.OnClickListener() {
|
||||
|
|
@ -220,10 +221,6 @@ public class RecordingActivity extends AppCompatActivity {
|
|||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (permitted()) {
|
||||
record();
|
||||
}
|
||||
}
|
||||
|
||||
boolean isEmulator() {
|
||||
|
|
@ -244,6 +241,14 @@ public class RecordingActivity extends AppCompatActivity {
|
|||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
// start once
|
||||
if (thread == null) {
|
||||
if (permitted()) {
|
||||
record();
|
||||
}
|
||||
}
|
||||
|
||||
Log.d(TAG, "onResume");
|
||||
updateBufferSize(false);
|
||||
pitch.resume();
|
||||
|
|
@ -355,18 +360,7 @@ public class RecordingActivity extends AppCompatActivity {
|
|||
AudioRecord recorder = null;
|
||||
try {
|
||||
File tmp = storage.getTempRecording();
|
||||
|
||||
{
|
||||
long ss = tmp.length();
|
||||
if (AUDIO_FORMAT == AudioFormat.ENCODING_PCM_16BIT) {
|
||||
ss = ss / 2;
|
||||
}
|
||||
if (CHANNEL_CONFIG == AudioFormat.CHANNEL_IN_STEREO) {
|
||||
ss = ss / 2;
|
||||
}
|
||||
|
||||
samplesTime = ss;
|
||||
}
|
||||
samplesTime = getSamples(tmp.length());
|
||||
|
||||
os = new DataOutputStream(new BufferedOutputStream(storage.open(tmp)));
|
||||
|
||||
|
|
@ -461,6 +455,16 @@ public class RecordingActivity extends AppCompatActivity {
|
|||
thread.start();
|
||||
}
|
||||
|
||||
long getSamples(long len) {
|
||||
if (AUDIO_FORMAT == AudioFormat.ENCODING_PCM_16BIT) {
|
||||
len = len / 2;
|
||||
}
|
||||
if (CHANNEL_CONFIG == AudioFormat.CHANNEL_IN_STEREO) {
|
||||
len = len / 2;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
// calcuale buffer length dynamically, this way we can reduce thread cycles when activity in background
|
||||
// or phone screen is off.
|
||||
void updateBufferSize(boolean pause) {
|
||||
|
|
@ -472,7 +476,6 @@ public class RecordingActivity extends AppCompatActivity {
|
|||
}
|
||||
|
||||
bufferSize = CHANNEL_CONFIG == AudioFormat.CHANNEL_IN_MONO ? samplesUpdate : samplesUpdate * 2;
|
||||
Log.d(TAG, "BufferSize: " + bufferSize);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -604,6 +607,9 @@ public class RecordingActivity extends AppCompatActivity {
|
|||
if (ext.equals("m4a")) {
|
||||
e = new FormatM4A(info, out);
|
||||
}
|
||||
if (ext.equals("3gp")) {
|
||||
e = new Format3GP(info, out);
|
||||
}
|
||||
|
||||
encoder = new FileEncoder(this, in, e);
|
||||
|
||||
|
|
|
|||
|
|
@ -144,11 +144,13 @@ public class Storage {
|
|||
return list;
|
||||
|
||||
for (File f : ff) {
|
||||
String[] ee = context.getResources().getStringArray(R.array.encodings_values);
|
||||
String n = f.getName().toLowerCase();
|
||||
for (String e : ee) {
|
||||
if (n.endsWith("." + e))
|
||||
list.add(f);
|
||||
if (f.length() > 0) {
|
||||
String[] ee = context.getResources().getStringArray(R.array.encodings_values);
|
||||
String n = f.getName().toLowerCase();
|
||||
for (String e : ee) {
|
||||
if (n.endsWith("." + e))
|
||||
list.add(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@ import java.nio.ByteBuffer;
|
|||
import java.nio.ByteOrder;
|
||||
|
||||
public class FileEncoder {
|
||||
public static final String TAG = FileEncoder.class.getSimpleName();
|
||||
|
||||
Context context;
|
||||
Handler handler;
|
||||
|
||||
|
|
@ -23,8 +25,6 @@ public class FileEncoder {
|
|||
Thread thread;
|
||||
long samples;
|
||||
long cur;
|
||||
Runnable progress;
|
||||
Runnable done;
|
||||
Throwable t;
|
||||
|
||||
public FileEncoder(Context context, File in, Encoder encoder) {
|
||||
|
|
@ -53,6 +53,7 @@ public class FileEncoder {
|
|||
byte[] buf = new byte[(RecordingActivity.AUDIO_FORMAT == AudioFormat.ENCODING_PCM_16BIT ? 2 : 1) * 1000];
|
||||
|
||||
int len = is.read(buf);
|
||||
Log.d("123", "len " + len);
|
||||
if (len <= 0) {
|
||||
handler.post(done);
|
||||
return;
|
||||
|
|
@ -66,7 +67,12 @@ public class FileEncoder {
|
|||
}
|
||||
}
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
Log.e(TAG, "Exception", e);
|
||||
t = e;
|
||||
handler.post(error);
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Exception", e);
|
||||
t = e;
|
||||
handler.post(error);
|
||||
} finally {
|
||||
|
|
|
|||
37
app/src/main/java/com/github/axet/audiorecorder/encoders/Format3GP.java
Executable file
37
app/src/main/java/com/github/axet/audiorecorder/encoders/Format3GP.java
Executable file
|
|
@ -0,0 +1,37 @@
|
|||
package com.github.axet.audiorecorder.encoders;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.media.MediaCodecList;
|
||||
import android.media.MediaFormat;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@TargetApi(21)
|
||||
public class Format3GP extends MuxerMP4 {
|
||||
|
||||
public Format3GP(EncoderInfo info, File out) {
|
||||
MediaFormat format = new MediaFormat();
|
||||
|
||||
// for high bitrate AMR_WB
|
||||
{
|
||||
// final int kBitRates[] = {6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850};
|
||||
|
||||
// format.setString(MediaFormat.KEY_MIME, "audio/amr-wb");
|
||||
// format.setInteger(MediaFormat.KEY_SAMPLE_RATE, info.sampleRate);
|
||||
// format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, info.channels);
|
||||
// format.setInteger(MediaFormat.KEY_BIT_RATE, 23850); // set maximum
|
||||
}
|
||||
|
||||
// for low bitrate, AMR_NB
|
||||
{
|
||||
// final int kBitRates[] = {4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200};
|
||||
|
||||
format.setString(MediaFormat.KEY_MIME, "audio/3gpp");
|
||||
format.setInteger(MediaFormat.KEY_SAMPLE_RATE, info.sampleRate); // 8000 only supported
|
||||
format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, info.channels);
|
||||
format.setInteger(MediaFormat.KEY_BIT_RATE, 12200); // set maximum
|
||||
}
|
||||
|
||||
create(info, format, out);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,112 +1,22 @@
|
|||
package com.github.axet.audiorecorder.encoders;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.media.MediaCodec;
|
||||
import android.media.MediaCodecInfo;
|
||||
import android.media.MediaFormat;
|
||||
import android.media.MediaMuxer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
@TargetApi(21)
|
||||
public class FormatM4A implements Encoder {
|
||||
EncoderInfo info;
|
||||
MediaCodec encoder;
|
||||
MediaMuxer muxer;
|
||||
int audioTrackIndex;
|
||||
long NumSamples;
|
||||
|
||||
public FormatM4A() {
|
||||
}
|
||||
public class FormatM4A extends MuxerMP4 {
|
||||
|
||||
public FormatM4A(EncoderInfo info, File out) {
|
||||
this.info = info;
|
||||
|
||||
MediaFormat format = new MediaFormat();
|
||||
format.setString(MediaFormat.KEY_MIME, "audio/mp4a-latm");
|
||||
format.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectHE);
|
||||
format.setInteger(MediaFormat.KEY_SAMPLE_RATE, info.sampleRate);
|
||||
format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, info.channels);
|
||||
format.setInteger(MediaFormat.KEY_BIT_RATE, 64 * 1024);
|
||||
format.setInteger(MediaFormat.KEY_BIT_RATE, 64000);
|
||||
|
||||
try {
|
||||
encoder = MediaCodec.createEncoderByType("audio/mp4a-latm");
|
||||
encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
|
||||
encoder.start();
|
||||
|
||||
muxer = new MediaMuxer(out.getAbsolutePath(), MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
create(info, format, out);
|
||||
}
|
||||
|
||||
public void encode(short[] buf) {
|
||||
int len = buf.length * 2;
|
||||
int inputIndex = encoder.dequeueInputBuffer(-1);
|
||||
if (inputIndex >= 0) {
|
||||
ByteBuffer input = encoder.getInputBuffer(inputIndex);
|
||||
input.clear();
|
||||
for (int i = 0; i < buf.length; i++)
|
||||
input.putShort(buf[i]);
|
||||
encoder.queueInputBuffer(inputIndex, 0, len, getCurrentTimeStamp(), 0);
|
||||
}
|
||||
|
||||
NumSamples += buf.length / info.channels;
|
||||
|
||||
encode();
|
||||
}
|
||||
|
||||
void encode() {
|
||||
MediaCodec.BufferInfo outputInfo = new MediaCodec.BufferInfo();
|
||||
int outputIndex = encoder.dequeueOutputBuffer(outputInfo, 0);
|
||||
if (outputIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
|
||||
audioTrackIndex = muxer.addTrack(encoder.getOutputFormat());
|
||||
muxer.start();
|
||||
}
|
||||
|
||||
while (outputIndex >= 0) {
|
||||
ByteBuffer output = encoder.getOutputBuffer(outputIndex);
|
||||
output.position(outputInfo.offset);
|
||||
output.limit(outputInfo.offset + outputInfo.size);
|
||||
|
||||
// byte[] out = new byte[outputInfo.size];
|
||||
// output.get(out);
|
||||
|
||||
muxer.writeSampleData(audioTrackIndex, output, outputInfo);
|
||||
|
||||
encoder.releaseOutputBuffer(outputIndex, false);
|
||||
outputIndex = encoder.dequeueOutputBuffer(outputInfo, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
end();
|
||||
encode();
|
||||
|
||||
encoder.stop();
|
||||
encoder.release();
|
||||
|
||||
muxer.stop();
|
||||
muxer.release();
|
||||
}
|
||||
|
||||
long getCurrentTimeStamp() {
|
||||
return NumSamples * 1000 * 1000 / info.sampleRate;
|
||||
}
|
||||
|
||||
void end() {
|
||||
int inputIndex = encoder.dequeueInputBuffer(-1);
|
||||
if (inputIndex >= 0) {
|
||||
ByteBuffer input = encoder.getInputBuffer(inputIndex);
|
||||
input.clear();
|
||||
encoder.queueInputBuffer(inputIndex, 0, 0, getCurrentTimeStamp(), MediaCodec.BUFFER_FLAG_END_OF_STREAM);
|
||||
}
|
||||
}
|
||||
|
||||
public EncoderInfo getInfo() {
|
||||
return info;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,9 +16,6 @@ public class FormatWAV implements Encoder {
|
|||
|
||||
ByteOrder order = ByteOrder.LITTLE_ENDIAN;
|
||||
|
||||
public FormatWAV() {
|
||||
}
|
||||
|
||||
public FormatWAV(EncoderInfo info, File out) {
|
||||
this.info = info;
|
||||
NumSamples = 0;
|
||||
|
|
|
|||
123
app/src/main/java/com/github/axet/audiorecorder/encoders/MuxerMP4.java
Executable file
123
app/src/main/java/com/github/axet/audiorecorder/encoders/MuxerMP4.java
Executable file
|
|
@ -0,0 +1,123 @@
|
|||
package com.github.axet.audiorecorder.encoders;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.media.MediaCodec;
|
||||
import android.media.MediaCodecInfo;
|
||||
import android.media.MediaFormat;
|
||||
import android.media.MediaMuxer;
|
||||
import android.util.Log;
|
||||
|
||||
import com.github.axet.audiorecorder.activities.SettingsActivity;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
@TargetApi(21)
|
||||
public class MuxerMP4 implements Encoder {
|
||||
EncoderInfo info;
|
||||
MediaCodec encoder;
|
||||
MediaMuxer muxer;
|
||||
int audioTrackIndex;
|
||||
long NumSamples;
|
||||
|
||||
public void create(EncoderInfo info, MediaFormat format, File out) {
|
||||
this.info = info;
|
||||
|
||||
try {
|
||||
encoder = MediaCodec.createEncoderByType(format.getString(MediaFormat.KEY_MIME));
|
||||
encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
|
||||
encoder.start();
|
||||
|
||||
muxer = new MediaMuxer(out.getAbsolutePath(), MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void encode(short[] buf) {
|
||||
Log.d("123", "encode " + buf.length);
|
||||
for (int offset = 0; offset < buf.length; ) {
|
||||
int len = buf.length - offset;
|
||||
|
||||
int inputIndex = encoder.dequeueInputBuffer(-1);
|
||||
if (inputIndex < 0)
|
||||
throw new RuntimeException("unable to open encoder input buffer");
|
||||
|
||||
ByteBuffer input = encoder.getInputBuffer(inputIndex);
|
||||
input.clear();
|
||||
|
||||
len = Math.min(len, input.limit() / 2);
|
||||
|
||||
for (int i = 0; i < len; i++)
|
||||
input.putShort(buf[i]);
|
||||
|
||||
int bytes = len * 2;
|
||||
|
||||
encoder.queueInputBuffer(inputIndex, 0, bytes, getCurrentTimeStamp(), 0);
|
||||
Log.d("123", "put " + bytes);
|
||||
NumSamples += len / info.channels;
|
||||
offset += len;
|
||||
|
||||
while (encode())
|
||||
;// do encode()
|
||||
}
|
||||
}
|
||||
|
||||
boolean encode() {
|
||||
MediaCodec.BufferInfo outputInfo = new MediaCodec.BufferInfo();
|
||||
int outputIndex = encoder.dequeueOutputBuffer(outputInfo, 0);
|
||||
if (outputIndex == MediaCodec.INFO_TRY_AGAIN_LATER)
|
||||
return false;
|
||||
|
||||
if (outputIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
|
||||
Log.d("123", "output set " + encoder.getOutputFormat());
|
||||
audioTrackIndex = muxer.addTrack(encoder.getOutputFormat());
|
||||
muxer.start();
|
||||
}
|
||||
|
||||
if (outputIndex >= 0) {
|
||||
ByteBuffer output = encoder.getOutputBuffer(outputIndex);
|
||||
output.position(outputInfo.offset);
|
||||
output.limit(outputInfo.offset + outputInfo.size);
|
||||
|
||||
Log.d("123", "get " + outputInfo.size);
|
||||
|
||||
muxer.writeSampleData(audioTrackIndex, output, outputInfo);
|
||||
|
||||
encoder.releaseOutputBuffer(outputIndex, false);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
end();
|
||||
encode();
|
||||
|
||||
encoder.stop();
|
||||
encoder.release();
|
||||
|
||||
muxer.stop();
|
||||
muxer.release();
|
||||
}
|
||||
|
||||
long getCurrentTimeStamp() {
|
||||
return NumSamples * 1000 * 1000 / info.sampleRate;
|
||||
}
|
||||
|
||||
void end() {
|
||||
int inputIndex = encoder.dequeueInputBuffer(-1);
|
||||
if (inputIndex >= 0) {
|
||||
ByteBuffer input = encoder.getInputBuffer(inputIndex);
|
||||
input.clear();
|
||||
encoder.queueInputBuffer(inputIndex, 0, 0, getCurrentTimeStamp(), MediaCodec.BUFFER_FLAG_END_OF_STREAM);
|
||||
Log.d("123", "set end ");
|
||||
}
|
||||
}
|
||||
|
||||
public EncoderInfo getInfo() {
|
||||
return info;
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue