我正在尝试在Android中制作通话记录应用。我正在使用扬声器录制上行链路和下行链路音频。我面临的唯一问题是音量太低。我已经将使用AudioManager的设备的音量提高到最大,并且不能超出此范围。
我首先使用MediaRecorder,但是由于它的功能有限并且提供了压缩的音频,因此我尝试使用AudioRecorder。我仍然不知道如何增加音频。我也检查了Github上的项目,但这没有用。我已经搜索了过去两周的stackoverflow,但根本找不到任何东西。
我很确定这是有可能的,因为许多其他应用程序正在这样做。例如,自动呼叫记录器可以做到这一点。
我知道我必须对音频缓冲区做一些事情,但是我不确定该做什么。你能指导我吗?
更新:-对不起,我忘了提到我已经在使用增益。我的代码几乎类似于RehearsalAssistant(实际上我是从那里派生的)。增益不能超过10dB,并且不会使音频音量增加太多。我想要的是我应该能够听到音频而无需将我的声音放在扬声器上,而这正是我的代码所欠缺的。
我曾在SoundDesign SE here上询问过类似的音量/响度问题。它提到增益和响度是相关的,但没有设置实际的响度级别。我不确定情况如何,但我决心获得大音量输出。
您显然正在运行AudioRecord
,所以我跳过了sampleRate
和inputSource
的决定。要点是,您需要在记录循环中适当地处理记录数据的每个样本,以增加音量。像这样:
int minRecBufBytes = AudioRecord.getMinBufferSize( sampleRate, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT );
// ...
audioRecord = new AudioRecord( inputSource, sampleRate, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, minRecBufBytes );
// Setup the recording buffer, size, and pointer (in this case quadruple buffering)
int recBufferByteSize = minRecBufBytes*2;
byte[] recBuffer = new byte[recBufferByteSize];
int frameByteSize = minRecBufBytes/2;
int sampleBytes = frameByteSize;
int recBufferBytePtr = 0;
audioRecord.startRecording();
// Do the following in the loop you prefer, e.g.
while ( continueRecording ) {
int reallySampledBytes = audioRecord.read( recBuffer, recBufferBytePtr, sampleBytes );
int i = 0;
while ( i < reallySampledBytes ) {
float sample = (float)( recBuffer[recBufferBytePtr+i ] & 0xFF
| recBuffer[recBufferBytePtr+i+1] << 8 );
// THIS is the point were the work is done:
// Increase level by about 6dB:
sample *= 2;
// Or increase level by 20dB:
// sample *= 10;
// Or if you prefer any dB value, then calculate the gain factor outside the loop
// float gainFactor = (float)Math.pow( 10., dB / 20. ); // dB to gain factor
// sample *= gainFactor;
// Avoid 16-bit-integer overflow when writing back the manipulated data:
if ( sample >= 32767f ) {
recBuffer[recBufferBytePtr+i ] = (byte)0xFF;
recBuffer[recBufferBytePtr+i+1] = 0x7F;
} else if ( sample <= -32768f ) {
recBuffer[recBufferBytePtr+i ] = 0x00;
recBuffer[recBufferBytePtr+i+1] = (byte)0x80;
} else {
int s = (int)( 0.5f + sample ); // Here, dithering would be more appropriate
recBuffer[recBufferBytePtr+i ] = (byte)(s & 0xFF);
recBuffer[recBufferBytePtr+i+1] = (byte)(s >> 8 & 0xFF);
}
i += 2;
}
// Do other stuff like saving the part of buffer to a file
// if ( reallySampledBytes > 0 ) { ... save recBuffer+recBufferBytePtr, length: reallySampledBytes
// Then move the recording pointer to the next position in the recording buffer
recBufferBytePtr += reallySampledBytes;
// Wrap around at the end of the recording buffer, e.g. like so:
if ( recBufferBytePtr >= recBufferByteSize ) {
recBufferBytePtr = 0;
sampleBytes = frameByteSize;
} else {
sampleBytes = recBufferByteSize - recBufferBytePtr;
if ( sampleBytes > frameByteSize )
sampleBytes = frameByteSize;
}
}
简单使用MPEG_4格式
要增加通话记录音量,请使用AudioManager,如下所示:
int deviceCallVol;
AudioManager audioManager;
开始录制:
audioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
//get the current volume set
deviceCallVol = audioManager.getStreamVolume(AudioManager.STREAM_VOICE_CALL);
//set volume to maximum
audioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL, audioManager.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL), 0);
recorder.setAudioSource(MediaRecorder.AudioSource.VOICE_CALL);
recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
recorder.setAudioEncodingBitRate(32);
recorder.setAudioSamplingRate(44100);
停止记录:
//将音量恢复为初始状态
audioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL, deviceCallVol, 0);
感谢Hartmut和Beworker提供解决方案。 Hartmut的代码确实在接近12-14 dB的情况下工作。我确实也合并了声音库中的代码以增加音量,但是这增加了太多的噪音和失真,因此我将音量保持在1.5-2.0,而是尝试增加增益。我得到了不错的音量,在电话中听起来并不太响,但是在PC上收听时听起来足够响亮。看来那是我能走的最远。
我正在发布最终代码以增加响度。请注意,使用增大的mVolume会增加过多的噪声。尝试增加增益。
private AudioRecord.OnRecordPositionUpdateListener updateListener = new AudioRecord.OnRecordPositionUpdateListener() {
@Override
public void onPeriodicNotification(AudioRecord recorder) {
aRecorder.read(bBuffer, bBuffer.capacity()); // Fill buffer
if (getState() != State.RECORDING)
return;
try {
if (bSamples == 16) {
shBuffer.rewind();
int bLength = shBuffer.capacity(); // Faster than accessing buffer.capacity each time
for (int i = 0; i < bLength; i++) { // 16bit sample size
short curSample = (short) (shBuffer.get(i) * gain);
if (curSample > cAmplitude) { // Check amplitude
cAmplitude = curSample;
}
if(mVolume != 1.0f) {
// Adjust output volume.
int fixedPointVolume = (int)(mVolume*4096.0f);
int value = (curSample*fixedPointVolume) >> 12;
if(value > 32767) {
value = 32767;
} else if(value < -32767) {
value = -32767;
}
curSample = (short)value;
/*scaleSamples(outputBuffer, originalNumOutputSamples, numOutputSamples - originalNumOutputSamples,
mVolume, nChannels);*/
}
shBuffer.put(curSample);
}
} else { // 8bit sample size
int bLength = bBuffer.capacity(); // Faster than accessing buffer.capacity each time
bBuffer.rewind();
for (int i = 0; i < bLength; i++) {
byte curSample = (byte) (bBuffer.get(i) * gain);
if (curSample > cAmplitude) { // Check amplitude
cAmplitude = curSample;
}
bBuffer.put(curSample);
}
}
bBuffer.rewind();
fChannel.write(bBuffer); // Write buffer to file
payloadSize += bBuffer.capacity();
} catch (IOException e) {
e.printStackTrace();
Log.e(NoobAudioRecorder.class.getName(), "Error occured in updateListener, recording is aborted");
stop();
}
}
@Override
public void onMarkerReached(AudioRecord recorder) {
// NOT USED
}
};
在我的应用中,我使用开源sonic library。其主要目的是加快/减慢语音,但除此之外,它还可以增加响度。我将其应用于回放,但必须类似地用于记录。压缩它们之前,只需将其通过即可。它也有一个Java接口。希望这会有所帮助。