java - 音频记录和播放失败-Android AudioRecord&AudioTrack

标签 java android audio audiorecord audiotrack

我正在编写一个Android应用程序,用于记录和循环播放音频。
就像回声一样(记录,播放,循环运行)。

我已经使用临时文件成功地编写了用于录制和播放的应用程序(写入文件,从同一文件读取)。
使用中间缓冲区执行相同操作失败。

这是我的代码:

public class BufferMain extends ActionBarActivity {
private String TAG = "AUDIO_RECORD_PLAYBACK_SAURABH_BUFFER";

private boolean isRunning = false;

private AudioRecord recorder = null;
private AudioTrack track = null;

/* Buffer used to record and Playback Audio */
byte buffer[] = new byte[640];
int bufferSize;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_buffer_main);

    enableButton(R.id.StartButton,true);
    enableButton(R.id.StopButton,false);

    /* Assign Button Click Handlers */
    ((Button)findViewById(R.id.StartButton)).setOnClickListener(btnClick);
    ((Button)findViewById(R.id.StopButton)).setOnClickListener(btnClick);

    Log.d(TAG, "\n ==Starting Application.. ==");
}

/* Method for Recording and Playing in a loop */
public void run_loop (boolean isRunning)
{
    int readbytes, writebytes, state;
    Log.d(TAG, "===== Entering Loop ===== ");

    if (isRunning == true) {
        do {
            bufferSize = 640; /* since configuration would return 640 size in buffer */
            recorder = findAudioRecord(recorder);
            if (recorder == null) {
                Log.e(TAG, "====== findAudioRecord : Returned Error! =======");
                return;
            }

            if (recorder.STATE_INITIALIZED == recorder.getState())
            {
                recorder.startRecording();

                readbytes = 0;              /* Reset read for next Iteration */
                readbytes = recorder.read(buffer, 0, bufferSize);

                /* Error Checking Code for AudioRecord */
                if(-1 == checkAudioRecordforError(readbytes)) 
                {
                    Log.d(TAG, "========= Read Error =========");
                    return;
                }

                Log.d(TAG, "\n\n===== Read : Sizeof Buffer:"+buffer.length+"=== readbytes: ["+readbytes+"]=====");
                recorder.stop();
                recorder.release();

            }else {
                state = recorder.getState();
                Log.d(TAG, "========= Else Part : state : "+state+"=========");
            }

            Log.d(TAG, "========= Reading Completed =========");


            /** ======== API for Playing ===========  **/

            track = findAudioTrack(track);
            if (track == null) {
                Log.e(TAG, "========= findAudioTrack : Returned Error! ========== ");
                return;
            }

            if (track.STATE_INITIALIZED == track.getState()) 
            {
                writebytes = 0;                             /* Reset write bytes for next Iteration */
                track.play();

                writebytes = track.write(buffer, 0, bufferSize);
                Log.d(TAG, "\n\n===== Write : Sizeof Buffer:"+ bufferSize +"==== writebytes: ["+writebytes+"]======== ");

                /* Error Checking Code for AudioRecord */
                if (-1 == checkAudioTrackforError(writebytes)) 
                {
                    Log.d(TAG, "========= Write Error =========");
                    return;
                }

                track.stop();
                track.release();
            }
            else {
                state = track.getState();
                Log.d(TAG, "========= Else Part : state : "+state+"=========");
            }

        } while(true);
    }
    return;
}
/* Method for Initializing   AudioTrack for Playing Purpose */
public AudioTrack findAudioTrack (AudioTrack track)
{
    Log.d(TAG, "========== Initialising Playing API ============");

    bufferSize = AudioTrack.getMinBufferSize(8000, 
            AudioFormat.CHANNEL_OUT_MONO, 
            AudioFormat.ENCODING_PCM_16BIT);        /* Return 640 */

    Log.d(TAG, "========= AudioTrack ==> bufferSize : "+bufferSize+"=========");

    if (bufferSize != AudioTrack.ERROR_BAD_VALUE) 
    {
        track = new AudioTrack(AudioManager.STREAM_MUSIC, 8000, 
                AudioFormat.CHANNEL_OUT_MONO, 
                AudioFormat.ENCODING_PCM_16BIT, bufferSize, 
                AudioTrack.MODE_STREAM);

        if (track.getState() == AudioTrack.STATE_UNINITIALIZED) {
            Log.e(TAG, "=========== AudioTrack UnInitilaised ===========");
            return null;
        }
    }
    return track;
}

/* Method for Initializing AudioRecord for Recording Purpose */
public AudioRecord findAudioRecord (AudioRecord recorder)
{
    Log.d(TAG, "======== Initializing Record API ==========");

    bufferSize = AudioRecord.getMinBufferSize(8000,
            AudioFormat.CHANNEL_IN_MONO,
            AudioFormat.ENCODING_PCM_16BIT);


    if (bufferSize != AudioRecord.ERROR_BAD_VALUE) 
    {
        recorder = new AudioRecord(AudioSource.DEFAULT, 8000, 
                AudioFormat.CHANNEL_IN_MONO,
                AudioFormat.ENCODING_PCM_16BIT, bufferSize);

        if (recorder.getState() == AudioRecord.STATE_UNINITIALIZED) {
            Log.e(TAG, "========= AudioRecord UnInitilaised ============= ");
            return null;
        }
    }
    return recorder;
}

/* Method for Error Checking - AudioRecord */
public int checkAudioRecordforError(int readbytes)
{
    if (readbytes ==  recorder.ERROR_INVALID_OPERATION || readbytes ==  recorder.ERROR_BAD_VALUE) 
    {
        if(readbytes == AudioRecord.ERROR_INVALID_OPERATION)
            Log.d(TAG, "========= read Error : ERROR_INVALID_OPERATION ===========");
        else if (readbytes == AudioRecord.ERROR_BAD_VALUE)
            Log.d(TAG, "========= read Error : ERROR_BAD_VALUE ===========");
        else if (readbytes == AudioRecord.ERROR)
            Log.d(TAG, "========= read Error : ERROR Unknown ===========");
        return -1;
    }
    return readbytes;
}

/* Method for Error Checking - AudioTrack */
public int checkAudioTrackforError(int writebytes)
{
    if (writebytes ==  track.ERROR_INVALID_OPERATION || writebytes ==  track.ERROR_BAD_VALUE)
    {
        if(writebytes == track.ERROR_INVALID_OPERATION)
            Log.d(TAG, "========= read Error : ERROR_INVALID_OPERATION ===========");
        else if (writebytes == track.ERROR_BAD_VALUE)
            Log.d(TAG, "========= read Error : ERROR_BAD_VALUE ===========");
        else if (writebytes == track.ERROR)
            Log.d(TAG, "========= read Error : ERROR Unknown ===========");
        return -1;
    }
    return writebytes;
}

/* Method for Mapping Button Click */
private View.OnClickListener btnClick = new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        switch(v.getId()){
        case R.id.StartButton:
        {
            Log.d(TAG, "======= Start Recording =======");
            isRunning = true;
            Log.d(TAG, "========== isRunning = true =============");
            run_loop (isRunning);
            enableButton(R.id.StartButton,false);
            enableButton(R.id.StopButton,true);
            break;
        }
        case R.id.StopButton:
        {
            Log.d(TAG, "======== Stop Recording =========");
            isRunning = false;
            Log.d(TAG, "========== isRunning = false =============");
            run_loop (isRunning);
            enableButton(R.id.StopButton,false);
            enableButton(R.id.StartButton,true);
            break;
        }
        }
    }
}; 
/* Function to Enable/Disable Buttons */
private void enableButton(int id,boolean isEnable){
    ((Button)findViewById(id)).setEnabled(isEnable);
}
}

任何地方都没有读写失败。

Logcat输出:
D/AUDIO_RECORD_PLAYBACK_SAURABH_BUFFER( 3885): ==Starting Application.. ==
D/AUDIO_RECORD_PLAYBACK_SAURABH_BUFFER( 3885): ========Start Recording========
D/AUDIO_RECORD_PLAYBACK_SAURABH_BUFFER( 3885): ========== isRunning = true =============
D/AUDIO_RECORD_PLAYBACK_SAURABH_BUFFER( 3885): ===== Entering Loop ===== 
D/AUDIO_RECORD_PLAYBACK_SAURABH_BUFFER( 3885): =========== Initializing Record API =======
E/ACDB-LOADER(  213): Error: ACDB AudProc vol returned = -19
D/AUDIO_RECORD_PLAYBACK_SAURABH_BUFFER( 3885): ===== Read : Sizeof Buffer:640=== readbytes: [640]=====
D/AUDIO_RECORD_PLAYBACK_SAURABH_BUFFER( 3885): ========= Reading Completed =========
D/AUDIO_RECORD_PLAYBACK_SAURABH_BUFFER( 3885): ========== Initializing Playing API     ========
D/AUDIO_RECORD_PLAYBACK_SAURABH_BUFFER( 3885): ========= AudioTrack ==> bufferSize : 640=========
D/AUDIO_RECORD_PLAYBACK_SAURABH_BUFFER( 3885): ===== Write : Sizeof Buffer:640==== writebytes: [640]======== 
D/AUDIO_RECORD_PLAYBACK_SAURABH_BUFFER( 3885): =========Initialising Record API =========
E/ACDB-LOADER(  213): Error: ACDB AudProc vol returned = -19

我需要验证E/ACDB-LOADER( 213): Error: ACDB AudProc vol returned = -19是否对此负责。
上面的音频配置适用于Google Nexus 5。可能无法在其他设备上初始化。

Android GUI包含两个按钮StartStop

请帮助我解决上述问题。

最佳答案

上述问题已修复。

问题不在于:E/ACDB-LOADER( 213): Error: ACDB AudProc vol returned = -19
我已更正代码并在此答案中对其进行了更新:
Audio Recording and Streaming in Android

代码更改:

  • 无需多次初始化AudioRecordAudioTrack对象
    (一定不能成为循环的一部分)。
  • 读取和写入不应有任何延迟。
    只有“读/写”应该在循环中运行。

  • 这样,我可以使用缓冲区录制音频并循环播放相同的音频。

    关于java - 音频记录和播放失败-Android AudioRecord&AudioTrack,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25505682/

    相关文章:

    Android SDK 与 Adob​​e AIR : Pros and cons?

    audio - ffmpeg剪辑音频间隔与开始和结束时间

    python - 通过声音的相似性来确定弦之间的距离

    java - TIME_WAIT 中的 Netty 连接

    java - Clojure 中的类型化持久数据结构,用 Java 完成?

    如果对象是可打包的,Android JUnit 不会编译

    java - 抽屉导航打开不同的网页 View

    java - Kotlin 的智能转换未能通过简单的不可空性推导

    java - 为什么我想使用 java.io.Console 而不是标准流?

    ios - 国际化 UIButton