在本文中,我们将详细介绍androidAudioRecorder简单心得分享的各个方面,并为您提供关于安卓audiorecord的相关解答,同时,我们也将为您带来关于Android4.4中AudioR
在本文中,我们将详细介绍android AudioRecorder简单心得分享的各个方面,并为您提供关于安卓 audiorecord的相关解答,同时,我们也将为您带来关于Android 4.4中AudioRecord用例 - 录制系统内置声音、Android AudioRecord 的使用、Android AudioRecord初始化延迟、Android AudioRecord到文件,然后使用AudioTrack进行播放的有用知识。
本文目录一览:- android AudioRecorder简单心得分享(安卓 audiorecord)
- Android 4.4中AudioRecord用例 - 录制系统内置声音
- Android AudioRecord 的使用
- Android AudioRecord初始化延迟
- Android AudioRecord到文件,然后使用AudioTrack进行播放
android AudioRecorder简单心得分享(安卓 audiorecord)
1.如何创建一个有效的AudioRecorder实例Android各种设备的采样频率不同,输入的声道数也不同,如果采用固定的采样频率和声道数,那么得到的AudioRecorder不一定能够正常初始化。
为了正常使用,需要尝试各种不同的参数,得到在此设备上可以用的AudioRecorder实例。代码如下:
private void createAudioRecord() {
for (int sampleRate : new int[]{44100,8000,11025,16000,22050,32000,
47250,48000}) {
for (short audioFormat : new short[]{
AudioFormat.ENCODING_PCM_16BIT,
AudioFormat.ENCODING_PCM_8BIT}) {
for (short channelConfig : new short[]{
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.CHANNEL_IN_STEREO}) {
// Try to initialize
try {
recBufSize = AudioRecord.getMinBufferSize(sampleRate,
channelConfig,audioFormat);
if (recBufSize < 0) {
continue;
}
audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC,
sampleRate,channelConfig,audioFormat,
recBufSize * 2);
if (audioRecord.getState() == AudioRecord.STATE_INITIALIZED) {
return;
}
audioRecord.release();
audioRecord = null;
} catch (Exception e) {
// Do nothing
}
}
}
}
throw new IllegalStateException(
"getInstance() Failed : no suitable audio configurations on this device.");
}
2.常见错误
1.有些设备上面,即使你得到了有效的AudioRecorder实例,在audioRecord.startRecording()的时候还会报ERROR_BAD_VALUE错误。
这有可能是你使用了AudioManager而没有释放导致的。
其他错误都可以在网络上找到答案。
您可能感兴趣的文章:
- Android音频录制MediaRecorder之简易的录音软件实现代码
- Android使用AudioRecord实现暂停录音功能实例代码
- Android录音--AudioRecord、MediaRecorder的使用
- Android使用AudioRecord判断是否有音频输入
- Android音频处理之通过AudioRecord去保存PCM文件进行录制,播放,停止,删除功能
- Android提高之AudioRecord实现助听器的方法
- Android利用AudioRecord类实现音频录制程序
Android 4.4中AudioRecord用例 - 录制系统内置声音
通过API 19新加的MediaRecorder.AudioSource.REMOTE_SUBMIX參数能够让系统App录制系统内置的声音,也就是扬声器的声音。以下是一个巨简单的样例来演示样例怎样通过AudioRecord配合REMOTE_SUBMIX參数进行录制。
1. 编译apk
MainActivity.java:
package com.example.audiotest;
import java.io.FileOutputStream;
import java.io.IOException;
import android.app.Activity;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
public class MainActivity extends Activity {
private static String TAG = "JZJ";
AudioRecord mRecord = null;
boolean mReqStop = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
(new Thread() {
@Override
public void run() {
recordAndPlay();
}
}).start();
}
private final int kSampleRate = 44100;
private final int kChannelMode = AudioFormat.CHANNEL_IN_STEREO;
private final int kEncodeFormat = AudioFormat.ENCODING_PCM_16BIT;
private void init() {
int minBufferSize = AudioRecord.getMinBufferSize(kSampleRate, kChannelMode,
kEncodeFormat);
mRecord = new AudioRecord(MediaRecorder.AudioSource.REMOTE_SUBMIX,
kSampleRate, kChannelMode, kEncodeFormat, minBufferSize * 2);
}
private final int kFrameSize = 2048;
private String filePath = "/sdcard/voice.pcm";
private void recordAndPlay() {
FileOutputStream os = null;
mRecord.startRecording();
try {
os = new FileOutputStream(filePath);
byte[] buffer = new byte[kFrameSize];
int num = 0;
while (!mReqStop) {
num = mRecord.read(buffer, 0, kFrameSize);
Log.d(TAG, "buffer = " + buffer.toString() + ", num = " + num);
os.write(buffer, 0, num);
}
Log.d(TAG, "exit loop");
os.close();
} catch (IOException e) {
e.printStackTrace();
Log.e(TAG, "Dump PCM to file failed");
}
mRecord.stop();
mRecord.release();
mRecord = null;
Log.d(TAG, "clean up");
}
public void stop(View view) {
mReqStop = true;
Button stopBtn = (Button) findViewById(R.id.stopBtn);
stopBtn.setText("Stopped");
stopBtn.setEnabled(false);
}
}
布局文件activity_main.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<Button
android:id="@+id/stopBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="stop"
android:text="Stop" />
</RelativeLayout>
配置文件AndroidManifest.xml,注意要加上的几个权限:
<?xml version="1.0" encoding="utf-8"?
> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.audiotest" android:versionCode="1" android:versionName="1.0" > <uses-permission android:name="android.permission.CAPTURE_AUDIO_OUTPUT" /> <uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT"/> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="19" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.example.audiotest.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
编译生成Test.apk。
2. 加系统签名
java -jar signapk.jar platform.x509.pem platform.pk8 ./Test.apk final.apk
platform.x509.pem和platform.pk8在Android源代码的build/target/product/security文件夹下。
signapk.jar能够从https://code.google.com/p/signapk/下载。
3. 安装签名好的apk,执行
启动时即開始採集系统声音数据,结束时点击Stopbutton停止。这时採集数据会导出到/sdcard/voice.pcm文件。
4. 取出音频採样数据,播放
adb pull /sdcard/voice.pcm
vlc --demux=rawaud --rawaud-channels 2 --rawaud-samplerate 44100 voice.pcm
这样就開始播放刚才录制的声音了。vlc是一个多媒体播放器(http://www.videolan.org/vlc/index.html)。支持播放PCM数据。当然也能够用其他支持播放PCM的播放器。
总结来说。这样的方法的缺点是录制时扬声器就不能输出,长处是不用改系统层。假设要两个同一时候输出能够參考这篇文章:http://xzpeter.org/?p=254。
Android AudioRecord 的使用
AudioRecord
本工程实现pcm多配置(采样率、文件格式可选)的录音和播放工具,可用户音频的录制。
工程代码:https://github.com/worson/AudioRecord.git
录音参数
在安卓应用中,使用AudioRecord可实现更灵活的录音配置,AudioRecord录制的是原始的pcm数据。
AudioRecord的构造方法如下:
AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes)
audioSource: 音频录制的音原,具体如下
MediaRecorder.AudioSource.CAMCORDER
设定录音来源于同方向的相机麦克风相同,若相机无内置相机或无法识别,则使用预设的麦克风
MediaRecorder.AudioSource.DEFAULT 默认音频源
MediaRecorder.AudioSource.MIC
设定录音来源为主麦克风。
MediaRecorder.AudioSource.VOICE_CALL
设定录音来源为语音拨出的语音与对方说话的声音
MediaRecorder.AudioSource.VOICE_COMMUNICATION
摄像头旁边的麦克风
MediaRecorder.AudioSource.VOICE_DOWNLINK
下行声音
MediaRecorder.AudioSource.VOICE_RECOGNITION
语音识别
MediaRecorder.AudioSource.VOICE_UPLINK
上行声音
sampleRateInHz:音频采样率,即可每秒中采集多少个音频数据
channelConfig: 录音通道,单通道为 AudioFormat.CHANNEL_CONfigURATION_MONO,双通道为AudioFormat.CHANNEL_CONfigURATION_STEREO
audioFormat: 音频每个采样点的位数,即音频的精度,通道选用AudioFormat.ENCODING_PCM_16BIT即pcm 16位即可
bufferSizeInBytes: 音频数据写入缓冲区的总数,通过 AudioRecord.getMinBufferSize 获取最小的缓冲区。
关于音频数据量的计算
对于采样率为16k位深有16bit的录制参数,每秒钟的byte数为:16000*2=32000,即每分钟为:32000*60 byte/min= 1.875 MB/min的数据量
录音流程
创建录音机
public PcmRecorder(int audioSource, int sampleRate, int channelCnt, Context context, RecordListener listener) {
mListener = listener;
int channelConfig = channelCnt == 1 ? AudioFormat.CHANNEL_CONfigURATION_MONO : AudioFormat.CHANNEL_CONfigURATION_STEREO;
int minBufSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, AUdio_FORMAT);
mBufSize = minBufSize;
int bufferSizeInBytes = minBufSize;
AILog.i(TAG, "PcmRecorder: bufferSizeInBytes " + bufferSizeInBytes);
mAudioRecord = new AudioRecord(audioSource, sampleRate, channelConfig, AUdio_FORMAT, bufferSizeInBytes);
AILog.d(TAG, "state: " + mAudioRecord.getState());
}
开始录音
开始录音,并创建数据读取线程
public void start() {
AILog.d(TAG, "onStartRecord");
mAudioRecord.startRecording();
mRecording = true;
mRecordThread = new RecordThread("RecordThread");
mRecordThread.start();
if (mListener != null) {
mListener.onStartRecord();
} else {
AILog.w(TAG, "start: mListener is null");
}
}
读取音频数据
不断读取 Buffer 中声音数据,并回调上层应用处理
class RecordThread extends Thread {
public RecordThread(String name) {
super(name);
}
@Override
public void run() {
AILog.v(TAG, "thread run");
Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_AUdio);
if (mAudioRecord.getState() == AudioRecord.STATE_UNINITIALIZED) {
AILog.d(TAG, "unInit");
return;
}
byte[] buffer = new byte[mBufSize];
while (!mStopFlag) {
int len = mAudioRecord.read(buffer, 0, buffer.length);
if (len != mBufSize) {
AILog.e(TAG, "record read error:" + len);
}
if (mListener != null) {
mListener.onRecordData(buffer);
continue;
}
}
AILog.v(TAG, "thread end");
}
}
停止录音
停止录音并释放相关资源
public void stop() {
AILog.d(TAG, "stopRecord");
mStopFlag = true;
mRecording = false;
try {
mRecordThread.join();
} catch (InterruptedException e) {
AILog.d(TAG, "InterruptedException " + e.getMessage());
} finally {
if (mListener != null) {
mListener.onStopRecord();
} else {
AILog.d(TAG, "stop: mListener is null");
}
mAudioRecord.stop();
mAudioRecord.release();
}
mListener = null;
}
上层应用调用
private void startRecord() {
AILog.i(TAG, "startRecord: ");
checkEnvirement();
if (rb_channel_dual.isChecked()) {
mRecorder = new PcmRecorder(getAudioSource(), getAudioFrequecy(), 2);
} else {
mRecorder = new PcmRecorder(getAudioSource(), getAudioFrequecy(), 1);
}
try {
mOutputStream = new FileOutputStream(mTempRecordFile);
mRecorder.setRecordListener(mRecordListener);
mRecorder.start();
tv_tips.setText("正在录音...");
bt_recorder.setText("结束录音");
bt_play.setVisibility(View.INVISIBLE);
bt_delete.setVisibility(View.INVISIBLE);
} catch (FileNotFoundException e) {
e.printstacktrace();
tv_tips.setText("录音启动失败...");
}
}
private RecordListener mRecordListener = new RecordListener() {
@Override
public void onStartRecord() {
AILog.i(TAG, "onStartRecord: ");
}
@Override
public void onRecordData(byte[] bytes) {
try {
mOutputStream.write(bytes);
} catch (IOException e) {
e.printstacktrace();
}
}
@Override
public void onStopRecord() {
AILog.i(TAG, "onStopRecord: ");
//保存文件
}
};
Android AudioRecord初始化延迟
这是正在处理的相关代码的示例:
AudioRecord recorder = setupAudio();
recorder.startRecording();
SetupAudio方法:
public AudioRecord setupAudio() {
AudioRecord recorder;
minBufferSizeInBytes = AudioRecord.getMinBufferSize(
RECORDER_SAMPLERATE, AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT);
Log.e("MoverAudio","BufferSize: " + minBufferSizeInBytes);
recorder = new AudioRecord(MediaRecorder.AudioSource.CAMCORDER,
RECORDER_SAMPLERATE, AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT, minBufferSizeInBytes);
return recorder;
}
RECORDER_SAMPLERATE = 8000;
我试图找出是否有任何方法可以缩短初始化时间.
目前,我正在3种设备上对其进行即时测试,结果如下:
银河S3
> setupAudio:〜200ms
> startRecording():〜280ms
galaxy S3 mini
> setupAudio:〜10ms
> startRecording():〜290ms
galaxy Nexus
> setupAudio:〜10ms
> startRecording():〜235ms
缓冲区大小:
>连结:704
> s3:1024
> s3 mini:640
但是,仅来自银河系联系的数据可用.
对于我的应用程序,我必须能够尽快获取音频数据.使用当前值,只有Nexus在可接受的时间内.
S3 mini看起来速度较快,因为它仅比Nexus花费更多,但是前200毫秒的示例被列为0,因此它不可用.
根据我对收集到的数据进行分析后的了解,S3和S3 mini上的音频似乎已经过某种程度的滤波,因为所得到的FFT更加干净,低频声音总是不那么明显.
这是S3mini和galaxy Nexus录制的音频的示例:
http://img41.imageshack.us/img41/4177/ox7h.png
S3迷你
http://img690.imageshack.us/img690/8717/iya6.png
galaxy Nexus
解决方法:
如果请求长缓冲区,则必须等待操作系统以当前采样率填充它.如果您要求的采样率不是硬件ADC正在运行的采样率,则必须另外等待重采样器滤波器的延迟.不同的Android设备和操作系统版本可能支持不同的最小缓冲区大小和本机硬件采样率.
隐藏延迟的一种技术是在应用程序的生命周期中尽早开始录制,并不断丢弃音频样本,直到应用程序需要它们为止.这样就没有启动开销.
补充:在某些设备/操作系统版本上,数据可能确实会以某种硬件采样率(例如在44.1k或48kHz时为4096)捕获到更长的OS驱动程序缓冲区中,并且仅在填充了其中一些缓冲区之后,才转换为另一个采样速率,然后切成较短的请求缓冲区长度,然后音频命令开始向应用发送数据.要绕过,即使有可能,您可能需要修改操作系统并编写自己的ADC驱动程序.但是,请尝试使用较高的采样率(44.1k或48k),并首先请求较短的缓冲区.
Android AudioRecord到文件,然后使用AudioTrack进行播放
基本上,我使用AudioRecord将声音文件录制到sdcard目录中.录制5秒钟,然后使用AudioTrack播放.
好吧,对我来说,录制的文件不存在.可能录制失败.录制时我做错了什么?播放部分呢?
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
int minBufferSize = AudioTrack.getMinBufferSize(44100, AudioFormat.CHANNEL_CONfigURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT);
audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_CONfigURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT, minBufferSize, AudioTrack.MODE_STREAM);
recordSound();
}
private void recordSound(){
File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/"+"recordsound");
// /mnt/sdcard/recordsound
// Delete any prevIoUs recording.
if (file.exists())
file.delete();
try {
file.createNewFile();
// Create a DataOuputStream to write the audio data into the saved file.
OutputStream os = new FileOutputStream(file);
bufferedoutputstream bos = new bufferedoutputstream(os);
dos = new DataOutputStream(bos);
// Create a new AudioRecord object to record the audio.
int bufferSize = audioRecord.getMinBufferSize(FREQUENCY, CHANNEL_CONfigURATION, AUdio_ENCODING);
audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, FREQUENCY, CHANNEL_CONfigURATION, AUdio_ENCODING, bufferSize);
short[] buffer = new short[bufferSize];
audioRecord.startRecording();
new Timer().schedule(stop(), 5000); //time in miliseconds
// while (audioRecord.RECORDSTATE_RECORDING==1)
{
int bufferReadResult = audioRecord.read(buffer, 0, bufferSize);
for (int i = 0; i < bufferReadResult; i++)
dos.writeShort(buffer[i]);
}
// dos.close();
} catch (FileNotFoundException e) {
// Todo Auto-generated catch block
e.printstacktrace();
} catch (IllegalArgumentException e) {
// Todo Auto-generated catch block
e.printstacktrace();
} catch (IllegalStateException e) {
// Todo Auto-generated catch block
e.printstacktrace();
} catch (IOException e) {
// Todo Auto-generated catch block
e.printstacktrace();
}
}
private TimerTask stop()
{
TimerTask t = new TimerTask() {
@Override
public void run() {
// Todo Auto-generated method stub
audioTrack.stop();
audioTrack.release();
try {
dos.close();
} catch (IOException e) {
// Todo Auto-generated catch block
e.printstacktrace();
}
try {
playfilesound();
} catch (IOException e) {
// Todo Auto-generated catch block
e.printstacktrace();
}
}
};
return t;
}
private void playfilesound() throws IOException
{
int count = 512 * 1024; // 512 kb
//Reading the file..
byte[] byteData = null;
File file = null;
file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/"+"recordsound"); //filePath
if (file.exists())
{
int a=0;
}
byteData = new byte[(int)count];
FileInputStream in = null;
try {
in = new FileInputStream( file );
} catch (FileNotFoundException e) {
// Todo Auto-generated catch block
e.printstacktrace();
}
int bytesread = 0, ret = 0;
int size = (int) file.length();
audioTrack.play();
while (bytesread < size) { // Write the byte array to the track
ret = in.read( byteData,0, count); //ret =size in bytes
if (ret != -1) {
audioTrack.write(byteData,0, ret);
bytesread += ret; } //ret
else break; } //while
in.close(); audioTrack.stop(); audioTrack.release();
}
解决方法:
如果您的要求是在录制时应该播放(意味着循环播放音频),则在while循环线程中,您正在存储录制的数据(audioData bufer),您可以在while循环中将其本身复制到播放器对象( player.write(audioData,0,numShortsRead);).您说您的UI线程被卡住了,这可能是因为您给Audio Record线程赋予了更高的优先级.
检查以下我用于上述回送要求的代码:
boolean m_isRun=true;
public void loopback() {
// Prepare the AudioRecord & AudioTrack
try {
buffersize = AudioRecord.getMinBufferSize(SAMPLE_RATE,
AudioFormat.CHANNEL_CONfigURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT);
if (buffersize <= BUF_SIZE) {
buffersize = BUF_SIZE;
}
Log.i(LOG_TAG,"Initializing Audio Record and Audio Playing objects");
m_record = new AudioRecord(MediaRecorder.AudioSource.MIC,
SAMPLE_RATE, AudioFormat.CHANNEL_CONfigURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT, buffersize * 1);
m_track = new AudioTrack(AudioManager.STREAM_ALARM,
SAMPLE_RATE, AudioFormat.CHANNEL_CONfigURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT, buffersize * 1,
AudioTrack.MODE_STREAM);
m_track.setPlaybackRate(SAMPLE_RATE);
} catch (Throwable t) {
Log.e("Error", "Initializing Audio Record and Play objects Failed "+t.getLocalizedMessage());
}
m_record.startRecording();
Log.i(LOG_TAG,"Audio Recording started");
m_track.play();
Log.i(LOG_TAG,"Audio Playing started");
while (m_isRun) {
m_record.read(buffer, 0, BUF_SIZE);
m_track.write(buffer, 0, buffer.length);
}
Log.i(LOG_TAG, "loopback exit");
}
private void do_loopback() {
m_thread = new Thread(new Runnable() {
public void run() {
loopback();
}
});
还有一件事,如果您的要求是先录制几秒钟然后播放,则在播放时应该重新开始录制,您可以使用带有超时的延迟处理程序线程来执行此操作,在该线程中您可以停止录制并复制缓冲区,然后开始录制.
今天关于android AudioRecorder简单心得分享和安卓 audiorecord的讲解已经结束,谢谢您的阅读,如果想了解更多关于Android 4.4中AudioRecord用例 - 录制系统内置声音、Android AudioRecord 的使用、Android AudioRecord初始化延迟、Android AudioRecord到文件,然后使用AudioTrack进行播放的相关知识,请在本站搜索。
本文标签: