how can i play pcm file
Asked Answered
A

4

7

The following code should record audio and store it in to SD card in PCM format. the code is working with me ,but the PCM file doesn't play !!!!

I got this code from this link.... Android : recording audio using audiorecord class play as fast forwarded

I need to play the PCM file How can i do that ??????

public class Audio_Record extends Activity {
private static final int RECORDER_SAMPLERATE = 8000;
private static final int RECORDER_CHANNELS = AudioFormat.CHANNEL_IN_MONO;
private static final int RECORDER_AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;
private AudioRecord recorder = null;
private Thread recordingThread = null;
private boolean isRecording = false;

 @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

setButtonHandlers();
enableButtons(false);

int bufferSize = AudioRecord.getMinBufferSize(RECORDER_SAMPLERATE,
        RECORDER_CHANNELS, RECORDER_AUDIO_ENCODING);

System.out.println("BUFFER SIZE VALUE IS " + bufferSize);

 }

       private void setButtonHandlers() {
 ((Button) findViewById(R.id.btnStart)).setOnClickListener(btnClick);
((Button) findViewById(R.id.btnStop)).setOnClickListener(btnClick);
    }

   private void enableButton(int id, boolean isEnable) {
((Button) findViewById(id)).setEnabled(isEnable);
    }

private void enableButtons(boolean isRecording) {
enableButton(R.id.btnStart, !isRecording);
enableButton(R.id.btnStop, isRecording);
   }

  int BufferElements2Rec = 1024; // want to play 2048 (2K) since 2 bytes we
                            // use only 1024
  int BytesPerElement = 2; // 2 bytes in 16bit format

   private void startRecording() {

recorder = new AudioRecord(MediaRecorder.AudioSource.MIC,
        RECORDER_SAMPLERATE, RECORDER_CHANNELS,
        RECORDER_AUDIO_ENCODING, BufferElements2Rec * BytesPerElement);

recorder.startRecording();
isRecording = true;

recordingThread = new Thread(new Runnable() {

      public void run() {

        writeAudioDataToFile();

    }
}, "AudioRecorder Thread");
recordingThread.start();
    }

private byte[] short2byte(short[] sData) {
int shortArrsize = sData.length;
byte[] bytes = new byte[shortArrsize * 2];

for (int i = 0; i < shortArrsize; i++) {
    bytes[i * 2] = (byte) (sData[i] & 0x00FF);
    bytes[(i * 2) + 1] = (byte) (sData[i] >> 8);
    sData[i] = 0;
}
return bytes;

  }

  private void writeAudioDataToFile() {
// Write the output audio in byte

String filePath = "/sdcard/voice8K16bitmono.pcm";
short sData[] = new short[BufferElements2Rec];

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

while (isRecording) {
    // gets the voice output from microphone to byte format

    recorder.read(sData, 0, BufferElements2Rec);
    System.out.println("Short wirting to file" + sData.toString());
    try {
        // // writes the data to file from buffer
        // // stores the voice buffer

        byte bData[] = short2byte(sData);

        os.write(bData, 0, BufferElements2Rec * BytesPerElement);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

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

private void stopRecording() {
// stops the recording activity
if (null != recorder) {
    isRecording = false;

    recorder.stop();
    recorder.release();

    recorder = null;
    recordingThread = null;
}
 }

private View.OnClickListener btnClick = new View.OnClickListener() {
public void onClick(View v) {
    switch (v.getId()) {
    case R.id.btnStart: {
        enableButtons(true);
        startRecording();
        break;
    }
    case R.id.btnStop: {
        enableButtons(false);
        stopRecording();
        break;
    }
    }
}
 };

  @Override
  public boolean onKeyDown(int keyCode, KeyEvent event) {

if (keyCode == KeyEvent.KEYCODE_BACK) {

    finish();
}
return super.onKeyDown(keyCode, event);
 }
}
Affliction answered 9/6, 2013 at 16:33 Comment(3)
Please See my question @TechEndAffliction
How are you testing whether it plays or not?Restrictive
i went to the path where it was stored ,and when i tried to open it it said: "unable to find application to perform this action" @Ken WolfAffliction
R
4

Android's media player by default doesn't play PCM files. Either

  1. Copy it from your SD card to your computer and play it there
  2. Write your own player using AudioTrack
  3. Install an app that plays PCM

Here's a tutorial on how to play PCM using the AudioTrack class: (http://jongladwin.blogspot.co.uk/2010/03/android-play-pcmwav-audio-buffer-using.html)

Windows Media Player should be able to play PCM, some alternatives are mentioned here: (http://www.makeuseof.com/answers/play-pcm-file-pc/)

I guess most of the big music player apps on Android will support PCM.

Restrictive answered 9/6, 2013 at 16:45 Comment(5)
i copied it on my computer ,but it didn't work it said "can't Render this file"Affliction
Hard to diagnose from here but try changing to .wav and opening in windows media player (assuming you're using windows)Restrictive
I downloaded the program,, Audacity, and it opened the PCM file, but its not the sound of what i recorded, its like a fast forward, like a squeaky sound! i don't know whats the problem?! @Ken WolfAffliction
Sounds like playback is at a different sample rate to what was recordedRestrictive
Thanks so much ,,you are right,it turned out that i was using a different sample rate to what was recorded @Ken WolfAffliction
C
4

I also used your code, but my voice record was like a "zzzzz" record. So I changed a little the code and now I can listen without problems and distortions the record both by smartphone and by PC (in this case with Audacity). This is my code:

public class VoiceActivity extends Activity {
private static final String TAG = "VoiceRecord";

private static final int RECORDER_SAMPLERATE = 8000;     
private static final int RECORDER_CHANNELS_IN = AudioFormat.CHANNEL_IN_MONO;
private static final int RECORDER_CHANNELS_OUT = AudioFormat.CHANNEL_OUT_MONO;
private static final int RECORDER_AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;

private static final int AUDIO_SOURCE = MediaRecorder.AudioSource.MIC;

// Initialize minimum buffer size in bytes.
private int bufferSize = AudioRecord.getMinBufferSize(RECORDER_SAMPLERATE, RECORDER_CHANNELS_IN, RECORDER_AUDIO_ENCODING);

private AudioRecord recorder = null;
private Thread recordingThread = null;
private boolean isRecording = false;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_voice);

    ((Button) findViewById(R.id.start_button)).setOnClickListener(btnClick);
    ((Button) findViewById(R.id.stop_button)).setOnClickListener(btnClick);
    enableButtons(false);   
}

private void enableButton(int id, boolean isEnable) {
    ((Button) findViewById(id)).setEnabled(isEnable);
}

private void enableButtons(boolean isRecording) {
    enableButton(R.id.start_button, !isRecording);
    enableButton(R.id.stop_button, isRecording);
}

private void startRecording() {
    if( bufferSize == AudioRecord.ERROR_BAD_VALUE)
        Log.e( TAG, "Bad Value for \"bufferSize\", recording parameters are not supported by the hardware");

    if( bufferSize == AudioRecord.ERROR )
        Log.e( TAG, "Bad Value for \"bufferSize\", implementation was unable to query the hardware for its output properties");

    Log.e( TAG, "\"bufferSize\"="+bufferSize);

    // Initialize Audio Recorder.    
    recorder = new AudioRecord(AUDIO_SOURCE, RECORDER_SAMPLERATE, RECORDER_CHANNELS_IN, RECORDER_AUDIO_ENCODING, bufferSize);
    // Starts recording from the AudioRecord instance.
    recorder.startRecording();

    isRecording = true;

    recordingThread = new Thread(new Runnable() {
        public void run() {
            writeAudioDataToFile();
        }
    }, "AudioRecorder Thread");
    recordingThread.start();
}

private void writeAudioDataToFile() {
    //Write the output audio in byte
    String filePath = "/sdcard/8k16bitMono.pcm";
    byte saudioBuffer[] = new byte[bufferSize];

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

    while (isRecording) {
        // gets the voice output from microphone to byte format
        recorder.read(saudioBuffer, 0, bufferSize);
        try {
            //  writes the data to file from buffer stores the voice buffer
            os.write(saudioBuffer, 0, bufferSize);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    try {
        os.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

private void stopRecording() throws IOException {
    //  stops the recording activity
    if (null != recorder) {
        isRecording = false;  
        recorder.stop();
        recorder.release();
        recorder = null;
        recordingThread = null;
        PlayShortAudioFileViaAudioTrack("/sdcard/8k16bitMono.pcm");
    }   
}

private void PlayShortAudioFileViaAudioTrack(String filePath) throws IOException{
    // We keep temporarily filePath globally as we have only two sample sounds now..
    if (filePath==null)
        return;

    //Reading the file.. 
    File file = new File(filePath); // for ex. path= "/sdcard/samplesound.pcm" or "/sdcard/samplesound.wav"
    byte[] byteData = new byte[(int) file.length()];
    Log.d(TAG, (int) file.length()+"");

    FileInputStream in = null;
    try {
        in = new FileInputStream( file );
        in.read( byteData );
        in.close(); 
    } catch (FileNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    // Set and push to audio track..
    int intSize = android.media.AudioTrack.getMinBufferSize(RECORDER_SAMPLERATE, RECORDER_CHANNELS_OUT, RECORDER_AUDIO_ENCODING); 
    Log.d(TAG, intSize+"");

    AudioTrack at = new AudioTrack(AudioManager.STREAM_MUSIC, RECORDER_SAMPLERATE, RECORDER_CHANNELS_OUT, RECORDER_AUDIO_ENCODING, intSize, AudioTrack.MODE_STREAM); 
    if (at!=null) { 
        at.play();
        // Write the byte array to the track
        at.write(byteData, 0, byteData.length); 
        at.stop();
        at.release();
    }
    else
        Log.d(TAG, "audio track is not initialised ");

}

private View.OnClickListener btnClick = new View.OnClickListener() {
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.start_button: {
            enableButtons(true);
            startRecording();
            break;
        }
        case R.id.stop_button: {
            enableButtons(false);
            try {
                stopRecording();
            } catch (IOException e) {
                //  TODO Auto-generated catch block
                e.printStackTrace();
            }
            break;
        }
        }
    }   
};

    // onClick of backbutton finishes the activity.
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_BACK) {
        finish();
    }
    return super.onKeyDown(keyCode, event);
}
}
Chide answered 5/9, 2014 at 13:52 Comment(2)
Thanks for the change! I had similar distortion problem with the recorded audio, your solution solved the distortion. The original code truncated the recording so the distortion happens. Must use the buffer size returned by "AudioRecord.getMinBufferSize".Disgorge
How to access the raw sound data (may be in integer) using byteData in PlayShortAudioFileViaAudioTrack function? When I try to print byteData I get all zeroes, however when I open the .pcm file using sublime editor I see hex values.Tallbott
K
3

it's my solution

public class AudioTrackPlayer {
    private String pathAudio;
    private AudioTrack audioPlayer;
    private Thread mThread;
    private int bytesread = 0, ret = 0;
    private int size;
    private FileInputStream in = null;
    private byte[] byteData = null;
    private int count = 512 * 1024; // 512 kb
    private boolean isPlay = true;
    private boolean isLooping = false;
    private static Handler mHandler;

    public AudioTrackPlayer() {

    }

    public void prepare(String pathAudio){
        this.pathAudio = pathAudio;
        mHandler = new Handler();
    }

    public void play(){
        stop();

        isPlay = true;
        bytesread = 0;
        ret = 0;
        if (pathAudio == null)
            return;

        audioPlayer = createAudioPlayer();
        if (audioPlayer == null) return;
        audioPlayer.play();

        mThread = new Thread(new PlayerProcess());
        mThread.start();
    }

    private final Runnable mLopingRunnable = new Runnable() {
        @Override
        public void run() {
            play();
        }
    };

    private AudioTrack createAudioPlayer(){
        int intSize = android.media.AudioTrack.getMinBufferSize(16000, AudioFormat.CHANNEL_CONFIGURATION_MONO,
                AudioFormat.ENCODING_PCM_16BIT);
        AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 16000, AudioFormat.CHANNEL_CONFIGURATION_MONO,
                AudioFormat.ENCODING_PCM_16BIT, intSize, AudioTrack.MODE_STREAM);
        if (audioTrack == null) {
            Log.d("TCAudio", "audio track is not initialised ");
            return null;
        }

        File file = null;
        file = new File(pathAudio);

        byteData = new byte[(int) count];
        try {
            in = new FileInputStream(file);

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        size = (int) file.length();
        return  audioTrack;
    }

    private class PlayerProcess implements Runnable{

        @Override
        public void run() {
            while (bytesread < size && isPlay) {
                if (Thread.currentThread().isInterrupted()) {
                    break;
                }
                try {
                    ret = in.read(byteData, 0, count);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                if (ret != -1) { // Write the byte array to the track
                    audioPlayer.write(byteData,0, ret);
                    bytesread += ret;
                } else break;
            }
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (audioPlayer!=null){
                if (audioPlayer.getState()!=AudioTrack.PLAYSTATE_STOPPED){
                    audioPlayer.stop();
                    audioPlayer.release();
                    mThread = null;
                }
            }
            if (isLooping && isPlay ) mHandler.postDelayed(mLopingRunnable,100);
        }
    }

    public void setLooping(){
        isLooping = !isLooping;
    }

    public void pause(){

    }

    public void stop(){
        isPlay = false;
        if (mThread != null) {
            mThread.interrupt();
            mThread = null;
        }
        if (audioPlayer != null) {
            audioPlayer.stop();
            audioPlayer.release();
            audioPlayer = null;
        }
    }

    public void reset(){

    }
}
Knurly answered 19/11, 2017 at 12:44 Comment(2)
I improved code indentation for you. You can further improve your answer by explaining your code a bit including why and how it fixes the problem(s) of the question.Protect
16000 sample rate is too slow for pcm audio right??Commend
C
0

private void startRecording() { if( bufferSize == AudioRecord.ERROR_BAD_VALUE) Log.e( TAG, "Bad Value for \"bufferSize\", recording parameters are not supported by the hardware");

if( bufferSize == AudioRecord.ERROR )
    Log.e( TAG, "Bad Value for \"bufferSize\", implementation was unable to query the hardware for its output properties");

Log.e( TAG, "\"bufferSize\"="+bufferSize);

// Initialize Audio Recorder.    
recorder = new AudioRecord(AUDIO_SOURCE, RECORDER_SAMPLERATE, AudioFormat.CHANNEL_CONFIGURATION_MONO, RECORDER_AUDIO_ENCODING, bufferSize);
// Starts recording from the AudioRecord instance.
recorder.startRecording();

isRecording = true;

recordingThread = new Thread(new Runnable() {
    public void run() {
        writeAudioDataToFile();
    }
}, "AudioRecorder Thread");
recordingThread.start();

}

Replace Recording Code...

Causeway answered 3/2, 2015 at 6:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.