安卓开发 录音 时间久了 进程自动挂了 录音没有录制成功怎么办呀
https://cloud.tencent.com/developer/article/1726665
应该是安卓系统“省电”搞的事儿,您在代码中让其加入kill白名单,让录音程序可以一直在后台运行。
您还可以以时间或者文件大小为阈值,分段保存您的录音文件。不至少一点都没保存即使被kill,也只是丢失最后一个片段录音。
由于没有提供具体的录音库和开发平台信息,无法提供精确的解决方案。但是可以从以下几个方面入手解决录音进程崩溃问题:
针对以上几点,可以从以下几个步骤来解决录音进程崩溃问题:
步骤一:检查录音权限是否正确获取,并动态申请权限
在AndroidManifest.xml文件中添加录音权限:
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
在录音开始之前,可以动态申请录音权限:
private void checkPermissionAndRecord() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO)
!= PackageManager.PERMISSION_GRANTED) {
// Permission is not granted
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.RECORD_AUDIO},
MY_PERMISSIONS_REQUEST_RECORD_AUDIO);
} else {
startRecording();
}
}
@Override
public void onRequestPermissionsResult(int requestCode,
String[] permissions, int[] grantResults) {
if (requestCode == MY_PERMISSIONS_REQUEST_RECORD_AUDIO) {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
startRecording();
} else {
// Permission denied
Toast.makeText(this, "Permission denied", Toast.LENGTH_SHORT).show();
}
}
}
步骤二:对录音数据进行压缩处理
可以使用Android自带的MediaCodec进行音频编解码,将原始录音数据进行压缩处理,以减少内存消耗。具体可以参考以下代码:
// 初始化音频编码器
private void initAudioCodec() {
MediaFormat format = MediaFormat.createAudioFormat(MIME_TYPE, SAMPLE_RATE, CHANNEL_COUNT);
format.setInteger(MediaFormat.KEY_BIT_RATE, BIT_RATE);
format.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);
try {
mAudioEncoder = MediaCodec.createEncoderByType(MIME_TYPE);
mAudioEncoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
mAudioEncoder.start();
mAudioInputBuffers = mAudioEncoder.getInputBuffers();
mAudioOutputBuffers = mAudioEncoder.getOutputBuffers();
} catch (IOException e) {
e.printStackTrace();
}
}
// 开始录音并进行压缩处理
private void startRecording() {
// 初始化音频编码器
initAudioCodec();
// 初始化AudioRecord
int bufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE, CHANNEL_CONFIG, AUDIO_FORMAT);
mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, SAMPLE_RATE, CHANNEL_CONFIG, AUDIO_FORMAT, bufferSize);
mAudioRecord.startRecording();
ByteBuffer[] inputBuffers = mAudioEncoder.getInputBuffers();
ByteBuffer[] outputBuffers = mAudioEncoder.getOutputBuffers();
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
boolean isEOS = false;
long startMs = System.currentTimeMillis();
while (!Thread.interrupted()) {
if (!isEOS) {
int inputBufferIndex = mAudioEncoder.dequeueInputBuffer(TIMEOUT_US);
if (inputBufferIndex >= 0) {
ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
int sampleSize = mAudioRecord.read(inputBuffer, BUFFER_SIZE);
if (sampleSize < 0) {
Log.e(TAG, "audio data read error: " + sampleSize);
break;
}
if (sampleSize == 0) {
Log.d(TAG, "audio input EOS");
mAudioEncoder.queueInputBuffer(inputBufferIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
isEOS = true;
} else {
mAudioEncoder.queueInputBuffer(inputBufferIndex, 0, sampleSize, System.nanoTime() / 1000, 0);
}
} else {
Log.e(TAG, "no available input buffer right now");
}
}
int outputBufferIndex = mAudioEncoder.dequeueOutputBuffer(bufferInfo, TIMEOUT_US);
if (outputBufferIndex >= 0) {
ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];
ByteBuffer buffer = ByteBuffer.allocate(bufferInfo.size);
buffer.put(outputBuffer);
mDataList.add(buffer.array());
Log.d(TAG, "audio output: " + buffer.capacity());
mAudioEncoder.releaseOutputBuffer(outputBufferIndex, false);
} else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
// Subsequent data will conform to new format.
Log.i(TAG, "output format changed, new format: " + mAudioEncoder.getOutputFormat());
} else {
Log.e(TAG, "no available output buffer right now");
}
if ((System.currentTimeMillis() - startMs) >= TIMEOUT_MS) {
break;
}
}
stopRecording();
}
步骤三:对录音进程进行后台处理
可以在录音时将录音进程放入后台,并设置合适的保活机制,以避免前台进程挂掉而导致录音无法完成。具体可以参考以下代码:
public class RecordingService extends Service {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
startRecording();
return START_NOT_STICKY;
}
// 开始录音
private void startRecording() {
// ...
// 开始录音,并在子线程中执行
AsyncTask.execute(new Runnable() {
@Override
public void run() {
while (!Thread.interrupted()) {
// 录音处理
}
}
});
}
}
通过将录音操作放在子线程中进行,可以减少前台进程的内存消耗和占用,从而避免前台进程挂掉导致录音失败。
步骤四:对录音缓存和保存进行优化
对录音缓存和保存进行优化,可以采用边录音边压缩的方式,将录音数据直接存储到本地文件或云端存储中,避免录音数据过大导致进程崩溃。具体可以参考以下代码:
// 开始录音并缓存数据到本地文件
private void startRecordingAndCacheToFile() {
FileOutputStream fos = null;
try {
File file = new File(getExternalCacheDir(), RECORD_FILE_NAME);
fos = new FileOutputStream(file);
byte[] buffer = new byte[1024];
int len;
while ((len = mAudioRecord.read(buffer)) != -1) {
// 将录音数据写入本地文件
fos.write(buffer, 0, len);
fos.flush();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
通过将录音数据边录音边缓存到本地文件或云端存储中,可以有效减轻内存压力,避免录音数据过大导致进程崩溃。
步骤五:检查录音库是否有相关的bug,并进行更新或替换
可以根据录音