如何播放 pcm 文件
Posted
技术标签:
【中文标题】如何播放 pcm 文件【英文标题】:how can i play pcm file 【发布时间】: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 【参考方案1】:默认情况下,Android 的媒体播放器不播放 PCM 文件。要么
-
将其从 SD 卡复制到计算机并在那里播放
使用
AudioTrack
编写您自己的播放器
安装播放 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();
替换录音代码...
【讨论】:
以上是关于如何播放 pcm 文件的主要内容,如果未能解决你的问题,请参考以下文章