Recorded audio Using AndroidRecord API fails to play

霸气de小男生 提交于 2019-12-11 08:39:46

问题


Am developing an android app that has the feature to record the user speech. For this I have used the AndroidRecord Audio API.

Currently the pcm file(recorded audio file - recordedAudio.pcm) getting generated successfully in the sd card. But am not able to play that file. I tried in PC also with windows media palyer and some other players. But nothing helps.

Following are my code snippet.

private int minBufSize;
private AudioRecord recorder;
private int sampleRate = 44100;
private int channelConfig = AudioFormat.CHANNEL_IN_MONO;
private int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
private boolean status;

minBufSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig,
            audioFormat);
status = true;
startStreaming();

public void startStreaming() {
Thread streamThread = new Thread(new Runnable() {
    @Override
    public void run() {
        try {
            String filePath = Environment.getExternalStorageDirectory()
                    .getPath() + "/audioRecord.pcm";
            FileOutputStream fileOutputStreamObj = null;
            try {
                fileOutputStreamObj = new FileOutputStream(filePath);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
                Log.e(TAG, "Exception" + e.getMessage());
            }

                // short[] sData = new short[minBufSize];
                byte[] buffer = new byte[minBufSize];

                // recorder = findAudioRecord();
                recorder = new AudioRecord(MediaRecorder.AudioSource.MIC,
                        sampleRate, channelConfig, audioFormat, minBufSize);
                Log.d(TAG, "Recorder initialized");

                recorder.startRecording();

                while (status) {
                    // reading data from MIC into buffer
                    minBufSize = recorder.read(buffer, 0, buffer.length);
                    try {
                        // writes the data to file from buffer
                        // stores the voice buffer
                        // byte bData[] = short2byte(sData);

                        fileOutputStreamObj.write(buffer, 0, buffer.length);
                    } catch (IOException e) {
                        e.printStackTrace();
                        Log.e(TAG, "Exception" + e.getMessage());
                    }
                    // mConnection.sendBinaryMessage(buffer);
                    System.out.println("MinBufferSize: " + minBufSize);
                }

            } catch (Exception e) {
                e.printStackTrace();
                Log.e(TAG, "Exception" + e.getMessage());
            }
        }

    });
    streamThread.start();
}

Please help me on this. Thanks in advance.


回答1:


You don't have to convert it into WAV and Play.
AudioTrack can directly play the recorded Audio.

Following is a Code snippet to Record audio into a file using AudioRecord and playback the same using AudioTrack API.

The operation is controlled from User using Buttons.


Code

private int BufferSize;
byte[] buffer = new byte[BufferSize];

/* AudioRecord and AudioTrack Object */
private AudioRecord record = null;
private AudioTrack track = null;

/* Audio Configuration */
private int sampleRate = 44100;
private int channelConfig = AudioFormat.CHANNEL_IN_MONO;
private int audioFormat = AudioFormat.ENCODING_PCM_16BIT;

private boolean isRecording = true;
private Thread recordingThread = null;

The Audio Configuration can change as per device.
Refer to this question.


GUI has three buttons, Record, Stop and Play

protected void onCreate(Bundle savedInstanceState) 
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    setButtonHandlers();

    /* Set Button Visibility */
    enableButton(R.id.btnStartRec,true);
    enableButton(R.id.btnStopRec,false);
    enableButton(R.id.btnStartPlay,false);

    BufferSize = AudioRecord.getMinBufferSize(sampleRate, 
                       channelConfig, audioFormat); 
}

/* Function to Enable/Disable Buttons */
private void enableButton(int id,boolean isEnable){
    ((Button)findViewById(id)).setEnabled(isEnable);
}

/* Assign OnClickListener to Buttons */
private void setButtonHandlers() {
    ((Button)findViewById(R.id.btnStartRec)).setOnClickListener(btnClick);
    ((Button)findViewById(R.id.btnStopRec)).setOnClickListener(btnClick);
    ((Button)findViewById(R.id.btnStartPlay)).setOnClickListener(btnClick);
}

Handling Button click:

private View.OnClickListener btnClick = new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        switch(v.getId()){
        case R.id.btnStartRec:{
            Log.d(TAG, "Start Recording");
            enableButton(R.id.btnStartRec,false);
            enableButton(R.id.btnStopRec,true);
            startRecording();
            break;
        }
        case R.id.btnStopRec:{
            Log.d(TAG, "Stop Recording");
            enableButton(R.id.btnStartRec,true);
            enableButton(R.id.btnStopRec,false);
            stopRecording();
            enableButton(R.id.btnStartPlay,true);
            break;
        }
        case R.id.btnStartPlay:{
            Log.d(TAG, "Play Recording");
            enableButton(R.id.btnStartRec,false);
            enableButton(R.id.btnStopRec,false);
            StartPlaying();
            break;
        }
        }
    }
};

Code for Start Recording

private void startRecording()
{
    record = new AudioRecord(AudioSource.DEFAULT, sampleRate, 
                                channelConfig, audioFormat, BufferSize);
    if (AudioRecord.STATE_INITIALIZED == record.getState())
        record.startRecording();

    isRecording = true;

    /* Run a thread for Recording */
    recordingThread = new Thread(new Runnable() {
        @Override
        public void run() {
            writeAudioDataToFile();
        }
    },"AudioRecorder Thread");
    recordingThread.start();
}


private void writeAudioDataToFile()
{
    byte data[] = new byte[BufferSize];

    /* Record audio to following file */
    String filename = "/sdcard/audiofile.pcm";
    FileOutputStream os = null;

    try {
        os = new FileOutputStream(filename);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }

    int read_bytes = 0;

    if(null != os){
        while(isRecording)
        {
            read_bytes = record.read(data, 0, BufferSize);

            if(AudioRecord.ERROR_INVALID_OPERATION != read_bytes){
                try {
                    os.write(data);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        try {
            os.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Code for Stop Recording

private void stopRecording()
{
    if(null != record)
    {
        isRecording = false;

        if (AudioRecord.STATE_INITIALIZED == record.getState()) 
        {
            record.stop();
            record.release();
            Log.d(TAG, "===== Recording Audio Completed ===== ");
        }

        record = null;
        recordingThread = null;
    }
}   

Code for Playing the Audio file:

public void startPlaying()
{
    enableButton(R.id.btnStartPlay,false);

    int minBufferSize = AudioTrack.getMinBufferSize(sampleRate, 
            AudioFormat.CHANNEL_OUT_MONO, 
            AudioFormat.ENCODING_PCM_16BIT);

    track = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate, 
                            AudioFormat.CHANNEL_OUT_MONO, 
                            AudioFormat.ENCODING_PCM_16BIT, minBufferSize, 
                            AudioTrack.MODE_STREAM);

    int i = 0;
    byte[] temp = new byte[minBufferSize];

    try {
        FileInputStream fin = new FileInputStream("/sdcard/audiofile.pcm");
        Log.d(TAG, "===== Opening File for Playing : /sdcard/audiofile.pcm ===== ");

        DataInputStream dis = new DataInputStream(fin); 

        track.play();
        while((i = dis.read(temp, 0, minBufferSize)) > -1)
        {
            track.write(temp, 0, i);
        }

        Log.d(TAG, "===== Playing Audio Completed ===== ");
        track.stop();
        track.release();
        dis.close();
        fin.close();

    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    enableButton(R.id.btnStartRec,true);
}

Please include the following in AndroidManifest.xml

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" > </uses-permission>
<uses-permission android:name="android.permission.RECORD_AUDIO" >  </uses-permission>

The activity_main.xml looks like this.
The string.xml looks like this.

The above code is working and tested.

You can also do the same, without a file and using a intermediate buffer.
See: Audio Recording and Streaming in Android




回答2:


Yes finally I found the answer with the clue of Michael's Comment above.

Am posting here the working code.

The Client Side Code as Follow's, From the client side am streaming the audio data to the web socket server.

private int minBufSize;
private AudioRecord recorder;
private int sampleRate = 44100;
private int channelConfig = AudioFormat.CHANNEL_IN_MONO;
private int audioFormat = AudioFormat.ENCODING_PCM_16BIT;

minBufSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig,
                audioFormat);
startStreaming();

public void startStreaming() {
        Thread streamThread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {

                    byte[] buffer = new byte[minBufSize];

                    recorder = new AudioRecord(MediaRecorder.AudioSource.MIC,
                            sampleRate, channelConfig, audioFormat, minBufSize);
                    Log.d(TAG, "Recorder initialized");

                    recorder.startRecording();

                    while (status) {

                        // reading data from MIC into buffer
                        minBufSize = recorder.read(buffer, 0, buffer.length);

                        mConnection.sendBinaryMessage(buffer);
                        System.out.println("MinBufferSize: " + minBufSize);
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                    Log.e(TAG, "Exception" + e.getMessage());
                }
            }

        });
        streamThread.start();
    }

The Server Side Code added implementation as follows, First the server will create the .pcm from the streamed data. Then from that pcm file it will create the wave file by adding header.

  @OnMessage
  public void onMessage(byte[] data, boolean arg1)
  {
    if ((!this.currentCommand.equals("stop")) && 
      (this.currentCommand.equals("start")))
      try {
        System.out.println("Starting new recording.");
        FileOutputStream fOut = new FileOutputStream(this.f2, true);
        fOut.write(data);
        fOut.close();

        properWAV(this.f2, 111133.0F);
      }
      catch (Exception e) {
        e.printStackTrace();
      }
  }

private void properWAV(File fileToConvert, float newRecordingID)
  {
    try {
      long mySubChunk1Size = 16L;
      int myBitsPerSample = 16;
      int myFormat = 1;
      long myChannels = 1L;
      long mySampleRate = 44100L;
      long myByteRate = mySampleRate * myChannels * myBitsPerSample / 8L;
      int myBlockAlign = (int)(myChannels * myBitsPerSample / 8L);

      byte[] clipData = getBytesFromFile(fileToConvert);

      long myDataSize = clipData.length;
      long myChunk2Size = myDataSize * myChannels * myBitsPerSample / 8L;
      long myChunkSize = 36L + myChunk2Size;

      OutputStream os = new FileOutputStream(new File("D:/audio/" + newRecordingID + ".wav"));
      BufferedOutputStream bos = new BufferedOutputStream(os);
      DataOutputStream outFile = new DataOutputStream(bos);

      outFile.writeBytes("RIFF");
      outFile.write(intToByteArray((int)myChunkSize), 0, 4);
      outFile.writeBytes("WAVE");
      outFile.writeBytes("fmt ");
      outFile.write(intToByteArray((int)mySubChunk1Size), 0, 4);
      outFile.write(shortToByteArray((short)myFormat), 0, 2);
      outFile.write(shortToByteArray((short)(int)myChannels), 0, 2);
      outFile.write(intToByteArray((int)mySampleRate), 0, 4);
      outFile.write(intToByteArray((int)myByteRate), 0, 4);
      outFile.write(shortToByteArray((short)myBlockAlign), 0, 2);
      outFile.write(shortToByteArray((short)myBitsPerSample), 0, 2);
      outFile.writeBytes("data");
      outFile.write(intToByteArray((int)myDataSize), 0, 4);
      outFile.write(clipData);

      outFile.flush();
      outFile.close();
    }
    catch (IOException e) {
      e.printStackTrace();
    }
  }

  private static byte[] intToByteArray(int i)
  {
    byte[] b = new byte[4];
    b[0] = (byte)(i & 0xFF);
    b[1] = (byte)(i >> 8 & 0xFF);
    b[2] = (byte)(i >> 16 & 0xFF);
    b[3] = (byte)(i >> 24 & 0xFF);
    return b;
  }

  public static byte[] shortToByteArray(short data)
  {
    return new byte[] { (byte)(data & 0xFF), (byte)(data >>> 8 & 0xFF) };
  }

  public byte[] getBytesFromFile(File file)
    throws IOException
  {
    byte[] buffer = new byte[(int)file.length()];
    InputStream ios = null;
    try {
      ios = new FileInputStream(file);
      if (ios.read(buffer) == -1)
        throw new IOException("EOF reached while trying to read the whole file");
    }
    finally {
      try {
        if (ios != null)
          ios.close();
      }
      catch (IOException localIOException)
      {
      }
    }
    try
    {
      if (ios != null)
        ios.close();
    }
    catch (IOException localIOException1)
    {
    }
    return buffer;
  }

Hope this one saves many of the developer's time.



来源:https://stackoverflow.com/questions/25970430/recorded-audio-using-androidrecord-api-fails-to-play

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!