AudioRecord在Android L开发者预览中录制间歇性声音
我用PCM16LE格式的录音带录音,8000Hz,1声道。它在Android版本2.3.3-4.4中录制ok,但在Android L(5.0)开发者预览版(在nexus 5、nexus 7和emulator上)中录制奇怪的间歇声音 以下是录制的声音样本(前半段录音,后半段回放): 我试着用不同的采样率(400016000)和8比特播放录制的声音,但声音总是断断续续的。这个声音有什么问题 我正在使用此AudioRecordTask使用getAudioRecord()录制音频以初始化输入(操作期间没有返回错误;接收大小与internalBufferSize值相等的音频块):AudioRecord在Android L开发者预览中录制间歇性声音,android,audio,android-5.0-lollipop,audiorecord,Android,Audio,Android 5.0 Lollipop,Audiorecord,我用PCM16LE格式的录音带录音,8000Hz,1声道。它在Android版本2.3.3-4.4中录制ok,但在Android L(5.0)开发者预览版(在nexus 5、nexus 7和emulator上)中录制奇怪的间歇声音 以下是录制的声音样本(前半段录音,后半段回放): 我试着用不同的采样率(400016000)和8比特播放录制的声音,但声音总是断断续续的。这个声音有什么问题 我正在使用此AudioRecordTask使用getAudioRecord()录制音频以初始化输入(操作期间
公共最终整数抽样率=8000;
私人录音getAudioRecord(){
int internalBufferSize=AudioRecord.getMinBufferSize(采样率,
单声道中的AudioFormat.CHANNEL\u,
AudioFormat.ENCODING_PCM_16BIT);//返回640
internalBufferSize=8000;//还尝试了返回值(640)和值256030000-无更改
最终int源;
if(Build.VERSION.SDK_INT<11){
SOURCE=MediaRecorder.AudioSource.MIC;
}否则{
SOURCE=MediaRecorder.AudioSource.VOICE_通信;
}
音频记录=新的音频记录(来源,
抽样率,
单声道中的AudioFormat.CHANNEL\u,
AudioFormat.ENCODING_PCM_16位,
内部缓冲区大小);
int state=record.getState();
if(state!=AudioRecord.state_已初始化){
试一试{
record.release();
}捕获(例外e){
}
返回null;
}
if(record.getState()==android.media.AudioRecord.STATE\u已初始化){
record.startRecording();
}否则{
record.release();
返回null;
}
返回记录;
}
私有类AudioRecordTask扩展了AsyncTask{
最终整数部分缓冲区大小=采样率;
最终整数必需缓冲区大小=15*部分缓冲区大小*Short.SIZE/8;
final int FULL\u BUFFER\u SIZE=必要的\u BUFFER\u SIZE*2;//XXX:*2用于系统返回的数据超过需要的情况
短发;
int mTotalSize;
int mTotalSizeInBytes;
布尔mResult;
私有对象mLock=新对象();
@凌驾
受保护的void onPreExecute()
{
错误记录=正确;
mBuffer=新短[满缓冲区大小];
mTotalSize=0;
mTotalSizeInBytes=0;
mResult=false;
}
@凌驾
受保护的Void doInBackground(Void…arg0){
已同步(mLock){
android.os.Process.setThreadPriority(android.os.Process.THREAD\u PRIORITY\u emergency\u AUDIO);
AudioRecord=getAudioRecord();
if(记录==null){
mResult=false;
返回null;
}
用于(int i=0;i<15*100;i++){//XXX:*100以记录足够的数据(系统可以返回小于所需的数据)
int datalen=record.read(mBuffer、mTotalSize、部分缓冲区大小);
如果(数据长度>0){
mTotalSize+=datalen;
mTotalSizeInBytes=mTotalSize*2;
}否则{
Log.w(“,”error“+datalen+”,在AudioRecord.read中);
}
如果(isCancelled()| | mTotalSizeInBytes>必要的缓冲区大小){
打破
}
}
if(record.getRecordingState()==AudioRecord.RECORDSTATE\u录制){
record.stop();
}
record.release();
mResult=true;
返回null;
}
}
@凌驾
受保护的void onPostExecute(void r){
已同步(mLock){
错误记录=错误;
鳍();
}
}
@凌驾
受保护的void onCancelled(){
//XXX:在旧的机器人(如2.3.3)上,当doInBackground仍在运行时被取消调用
已同步(mLock){
错误记录=错误;
如果(马波特){
返回;
}
鳍();
}
}
私人财务部(){
如果(mResult&&mTotalSizeInBytes>0){
SendRecordedAudioServer(mBuffer、mTotalSize、mTotalSizeInBytes);
}否则{
错误(空);
}
}
}
这是Android L开发者预览版中的一个bug:
AudioRecord.read for short[]缓冲区参数以字节为单位返回值,而不是以short为单位返回值
作为一种解决方法,请使用AudioRecord.read和byte[]buffer。这在5.0版中似乎已修复,但存在一个相关问题,即偏移量参数错误地加倍-请参阅尝试提交修补程序时,我被告知该修补程序在内部也已修复,但不知道它何时会出现在发行版中。我刚刚陷入了这个问题(我想)在5.0.2中。这是否意味着,如果使用byte[]缓冲区读取,包括offset参数,所有都可以正常工作,还是仍然加倍了?当使用byte[]缓冲区时,包括offset,所有都可以(在5.0和5.0.1中是这样,在5.0.2上还没有测试)偏移量参数的不同问题存在于5.0-5.02之间,但在5.1中似乎已修复
public final int SAMPLING_RATE = 8000;
private AudioRecord getAudioRecord() {
int internalBufferSize = AudioRecord.getMinBufferSize(SAMPLING_RATE,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT); //returns 640
internalBufferSize = 8000; //also tried returned value (640) and values 2560, 30000 - no changes
final int SOURCE;
if (Build.VERSION.SDK_INT < 11) {
SOURCE = MediaRecorder.AudioSource.MIC;
} else {
SOURCE = MediaRecorder.AudioSource.VOICE_COMMUNICATION;
}
AudioRecord record = new AudioRecord(SOURCE,
SAMPLING_RATE,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT,
internalBufferSize);
int state = record.getState();
if (state != AudioRecord.STATE_INITIALIZED) {
try {
record.release();
} catch (Exception e) {
}
return null;
}
if (record.getState() == android.media.AudioRecord.STATE_INITIALIZED) {
record.startRecording();
} else {
record.release();
return null;
}
return record;
}
private class AudioRecordTask extends AsyncTask<Void, Void, Void> {
final int PARTIAL_BUFFER_SIZE = SAMPLING_RATE;
final int NECESSARY_BUFFER_SIZE = 15 * PARTIAL_BUFFER_SIZE * Short.SIZE / 8;
final int FULL_BUFFER_SIZE = NECESSARY_BUFFER_SIZE * 2; //XXX: * 2 for the case when system returns more data than needed
short[] mBuffer;
int mTotalSize;
int mTotalSizeInBytes;
boolean mResult;
private Object mLock = new Object();
@Override
protected void onPreExecute()
{
mIsRecording = true;
mBuffer = new short[FULL_BUFFER_SIZE];
mTotalSize = 0;
mTotalSizeInBytes = 0;
mResult = false;
}
@Override
protected Void doInBackground(Void... arg0) {
synchronized (mLock) {
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
AudioRecord record = getAudioRecord();
if (record == null) {
mResult = false;
return null;
}
for (int i = 0; i < 15 * 100; i++) { //XXX: * 100 to record enough data (system can return lesser than needed)
int datalen = record.read(mBuffer, mTotalSize, PARTIAL_BUFFER_SIZE);
if (datalen > 0) {
mTotalSize += datalen;
mTotalSizeInBytes = mTotalSize*2;
} else {
Log.w("", "error " + datalen + " in AudioRecord.read");
}
if (isCancelled() || mTotalSizeInBytes > NECESSARY_BUFFER_SIZE) {
break;
}
}
if (record.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING) {
record.stop();
}
record.release();
mResult = true;
return null;
}
}
@Override
protected void onPostExecute(Void r) {
synchronized (mLock) {
mIsRecording = false;
fin();
}
}
@Override
protected void onCancelled() {
//XXX: on old Androids (e.g. 2.3.3) onCancelled being called while doInBackground is still running
synchronized (mLock) {
mIsRecording = false;
if (mAbort) {
return;
}
fin();
}
}
private void fin() {
if (mResult && mTotalSizeInBytes > 0) {
sendRecordedAudioToServer(mBuffer, mTotalSize, mTotalSizeInBytes);
} else {
showError(null);
}
}
}