【问题标题】:how can i play pcm file如何播放 pcm 文件
【发布时间】:2013-06-09 16:33:03
【问题描述】:

以下代码应录制音频并将其以 PCM 格式存储到 SD 卡中。 代码正在与我一起工作,但 PCM 文件无法播放!!!!

我从这个链接得到了这个代码......Android : recording audio using audiorecord class play as fast forwarded

我需要播放 PCM 文件我该怎么做??????

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);
 }
}

【问题讨论】:

  • 请看我的问题@TechEnd
  • 你如何测试它是否播放?
  • 我去了存储它的路径,当我试图打开它时,它说:“无法找到执行此操作的应用程序”@Ken Wolf

标签: android audio-recording voice-recording


【解决方案1】:

默认情况下,Android 的媒体播放器不播放 PCM 文件。要么

  1. 将其从 SD 卡复制到计算机并在那里播放
  2. 使用AudioTrack编写您自己的播放器
  3. 安装播放 PCM 的应用

这是一个关于如何使用AudioTrack 类播放 PCM 的教程:(http://jongladwin.blogspot.co.uk/2010/03/android-play-pcmwav-audio-buffer-using.html)

Windows Media Player 应该可以播放 PCM,这里提到了一些替代方案:(http://www.makeuseof.com/answers/play-pcm-file-pc/)

我猜大部分 Android 上的大型音乐播放器应用都会支持 PCM。

【讨论】:

  • 我把它复制到我的电脑上,但它没有工作它说“无法渲染这个文件”
  • 很难从这里诊断,但尝试更改为 .wav 并在 windows 媒体播放器中打开(假设您使用的是 windows)
  • 我下载了Audacity程序,它打开了PCM文件,但不是我录制的声音,它像快进一样,像吱吱作响的声音!不知道是什么问题?! @肯狼
  • 听起来播放的采样率与录制的不同
  • 非常感谢,你是对的,原来我使用的采样率与@Ken Wolf 录制的采样率不同
【解决方案2】:

我也使用了您的代码,但我的语音记录就像“zzzzz”记录。所以我修改了一点代码,现在我可以通过智能手机和 PC(在本例中使用 Audacity)毫无问题地收听和扭曲记录。 这是我的代码:

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);
}
}

【讨论】:

  • 感谢您的更改!我录制的音频也有类似的失真问题,您的解决方案解决了失真问题。原始代码截断了录音,因此发生了失真。必须使用“AudioRecord.getMinBufferSize”返回的缓冲区大小。
  • 如何在PlayShortAudioFileViaAudioTrack 函数中使用byteData 访问原始声音数据(可能是整数)?当我尝试打印 byteData 时,我得到了全零,但是当我使用 sublime 编辑器打开 .pcm 文件时,我看到了十六进制值。
【解决方案3】:

这是我的解决方案

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(){

    }
}

【讨论】:

  • 我为您改进了代码缩进。您可以通过稍微解释一下您的代码(包括为什么以及如何解决问题的问题)来进一步改进您的答案。
  • 16000 采样率对于 pcm 音频来说太慢了吧??
【解决方案4】:

私人无效 startRecording() { if(bufferSize == AudioRecord.ERROR_BAD_VALUE) Log.e( TAG, "Bad Value for \"bufferSize\", 硬件不支持记录参数");

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();

}

替换录音代码...

【讨论】:

    猜你喜欢
    • 2015-05-27
    • 2015-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多