2014-09-28 92 views
7

我想在Android中制作通话录音应用程序。我使用扬声器记录上行和下行音频。我面临的唯一问题是音量太低。我已经将使用AudioManager的设备音量增加到最大,并且不能超出此范围。增加录制音频的音量输出

我已经第一次使用MediaRecorder,但由于它的功能有限并且提供了压缩音频,所以我尝试了AudioRecorder。但我还没有想出如何增加音频。我也检查过Github上的项目,但它没用。我已经搜索了最近两周的stackoverflow,但找不到任何东西。

我很确定这是可能的,因为许多其他应用程序正在这样做。例如自动呼叫记录器这样做。

我知道我必须对音频缓冲区做些什么,但我不太确定需要做什么。你能指导我吗?

更新: -
对不起,我忘记提及我已经在使用增益。我的代码几乎类似于RehearsalAssistant(实际上我从那里得到它)。增益不会超过10dB,并且不会增加音频音量。我想要的是我应该能够听到音频,而不用将耳朵放在扬声器上,这正是我的代码所缺乏的。

我在SoundDesign SE here上提出了类似的音量/响度功能问题。它提到增益和响度是相关的,但它没有设置实际的响度水平。我不确定事情是如何工作的,但我决定得到大量的输出。

回答

12

你显然有AudioRecord运行的东西,所以我跳过sampleRateinputSource的决定。主要的一点是,您需要在录音循环中适当地操作您录制的每个数据样本以增加音量。像这样:

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; 
     } 
    } 
+0

其实我已经在使用增益了,但增幅不超过10dB。我正在使用此URL中的代码 - http://sourceforge.net/p/rehearsalassist/code/HEAD/tree/android/branches/pause_and_gain/src/urbanstew/RehearsalAssistant/RehearsalAudioRecorder.java – noob 2014-10-03 09:52:45

+0

请检查有关该问题的更新信息太。谢谢。 – noob 2014-10-03 10:00:09

+0

你说它不工作超过10dB?你说12或20dB时你究竟看到了什么? – 2014-10-03 16:55:41

0

简单的使用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); 
+0

感谢您的回答。我已经尝试过各种格式。 MediaRecorder绝对不能解决我的目的(除非有黑客或解决办法)。我期待某种算法可以应用于音频缓冲区以提高响度。 – noob 2014-10-02 13:20:14

+0

感谢您的回答。我有类似的问题,并且从3GPP/AMR_NB更改MPEG_4/AAC可显着提高质量和音量。 – tpaczesny 2017-12-04 12:01:25

1

在我的应用程序中,我使用开放源码sonic library。它的主要目的是加快/减慢讲话速度,但除此之外,它还可以增加响度。我将它应用于播放,但它必须适用于类似的录制。只需在压缩它们之前将样品通过它。它也有一个Java接口。希望这可以帮助。

+0

谢谢,我会检查它。 – noob 2014-10-06 11:38:40

2

感谢Hartmut和beworker的解决方案。哈特穆特的代码在接近12-14分贝处工作。我也合并了声音库中的代码以增加音量,但是这会增加太多的噪音和失真,所以我将音量保持在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 
     } 
    };