-
-
Notifications
You must be signed in to change notification settings - Fork 756
/
AudioEncoder.java
160 lines (142 loc) · 4.75 KB
/
AudioEncoder.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
package com.pedro.encoder.audio;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.util.Log;
import com.pedro.encoder.input.audio.GetMicrophoneData;
import com.pedro.encoder.input.audio.MicrophoneManager;
import java.io.IOException;
import java.nio.ByteBuffer;
/**
* Created by pedro on 19/01/17.
* Encode PCM audio data to ACC and return in a callback
*/
public class AudioEncoder implements GetMicrophoneData {
private String TAG = "AudioEncoder";
private MediaCodec audioEncoder;
private GetAccData getAccData;
private MediaCodec.BufferInfo audioInfo = new MediaCodec.BufferInfo();
private long mPresentTimeUs;
private boolean running;
//default parameters for encoder
private String mime = "audio/mp4a-latm";
private int bitRate = 128 * 1024; //in kbps
private int sampleRate = 44100; //in hz
private boolean isStereo = true;
public AudioEncoder(GetAccData getAccData) {
this.getAccData = getAccData;
}
/**
* Prepare encoder with custom parameters
*/
public boolean prepareAudioEncoder(int bitRate, int sampleRate, boolean isStereo) {
this.sampleRate = sampleRate;
try {
audioEncoder = MediaCodec.createEncoderByType(mime);
int a = (isStereo) ? 2 : 1;
MediaFormat audioFormat = MediaFormat.createAudioFormat(mime, sampleRate, a);
audioFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);
audioFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, MicrophoneManager.BUFFER_SIZE);
audioFormat.setInteger(MediaFormat.KEY_AAC_PROFILE,
MediaCodecInfo.CodecProfileLevel.AACObjectLC);
audioEncoder.configure(audioFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
running = false;
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
} catch (IllegalStateException e) {
e.printStackTrace();
return false;
}
}
/**
* Prepare encoder with default parameters
*/
public boolean prepareAudioEncoder() {
return prepareAudioEncoder(bitRate, sampleRate, isStereo);
}
public void start() {
mPresentTimeUs = System.nanoTime() / 1000;
audioEncoder.start();
running = true;
Log.i(TAG, "AudioEncoder started");
}
public void stop() {
running = false;
if (audioEncoder != null) {
audioEncoder.stop();
audioEncoder.release();
audioEncoder = null;
}
Log.i(TAG, "AudioEncoder stopped");
}
/**
* Set custom PCM data.
* Use it after prepareAudioEncoder(int sampleRate, int channel).
* Used too with microphone.
*
* @param buffer PCM buffer
* @param size Min PCM buffer size
*/
@Override
public void inputPcmData(final byte[] buffer, final int size) {
if (Build.VERSION.SDK_INT >= 21) {
getDataFromEncoderAPI21(buffer, size);
} else {
getDataFromEncoder(buffer, size);
}
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void getDataFromEncoderAPI21(byte[] data, int size) {
int inBufferIndex = audioEncoder.dequeueInputBuffer(-1);
if (inBufferIndex >= 0) {
ByteBuffer bb = audioEncoder.getInputBuffer(inBufferIndex);
bb.put(data, 0, size);
long pts = System.nanoTime() / 1000 - mPresentTimeUs;
audioEncoder.queueInputBuffer(inBufferIndex, 0, size, pts, 0);
}
for (; ; ) {
int outBufferIndex = audioEncoder.dequeueOutputBuffer(audioInfo, 0);
if (outBufferIndex >= 0) {
//This ByteBuffer is ACC
ByteBuffer bb = audioEncoder.getOutputBuffer(outBufferIndex);
getAccData.getAccData(bb, audioInfo);
audioEncoder.releaseOutputBuffer(outBufferIndex, false);
} else {
break;
}
}
}
private void getDataFromEncoder(byte[] data, int size) {
ByteBuffer[] inputBuffers = audioEncoder.getInputBuffers();
ByteBuffer[] outputBuffers = audioEncoder.getOutputBuffers();
int inBufferIndex = audioEncoder.dequeueInputBuffer(-1);
if (inBufferIndex >= 0) {
ByteBuffer bb = inputBuffers[inBufferIndex];
bb.clear();
bb.put(data, 0, size);
long pts = System.nanoTime() / 1000 - mPresentTimeUs;
audioEncoder.queueInputBuffer(inBufferIndex, 0, size, pts, 0);
}
for (; ; ) {
int outBufferIndex = audioEncoder.dequeueOutputBuffer(audioInfo, 0);
if (outBufferIndex >= 0) {
//This ByteBuffer is ACC
ByteBuffer bb = outputBuffers[outBufferIndex];
getAccData.getAccData(bb, audioInfo);
audioEncoder.releaseOutputBuffer(outBufferIndex, false);
} else {
break;
}
}
}
public void setSampleRate(int sampleRate) {
this.sampleRate = sampleRate;
}
public boolean isRunning() {
return running;
}
}