Android 音频采集(原始音频)

752 阅读6分钟

Android 音频简介

常见的音频编解码的类型:AAC  OPUS MP3  AMR  Ogg  PCM  

AAC: 高级音频编码  对应  .m4a(audio/m4a)或者.3pg(audio/3gpp)文件   HEAAC:高级AAC,使用的比较多。

OPUS:有损声音编码的格式,由互联网工程任务组(IETF)进来开发,适用于网络上的实时声音传输,如:语音通话

MP3: 使用的最广泛的音频编解码器  对应 .mp3(audio/mp3) 各种音乐网站一般用这种。

AMR:自适应多速率音频编解码器,一般用于语音呼叫程序。

Ogg:开发的无专利的音频编解码器,其质量可与商业的和手专利保护的MP3以及AAC编解码相媲美。

PCM :原始音频,在android平台上由audio record直接录用下来的,未经过编码的。

视频直播,语音通话中一般使用AAC或者OPUS ,如果对声音要进行处理就需要使用PCM原始音频加工处理,然后再进行编码.

####Android音频采集(捕获)

android平台上的音频采集一般就三种:1.利用android内置的应用程序   2.使用MediaRecorder进行音频捕获   3.使用AudioRecord进行音频捕获。此3种方式的灵活性逐渐增大,相应的所需要做的工作也逐渐增多。

一、Android 内置的应用程序。

Intent intent=new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION); startActivityForResult(intent,0); //通过startActivityForResult获取音频录制的结果的路径 这种方式灵活度最差,一般就是做着演示下,开发中基本不用这种方案。

二、使用MediaRecorder进行音频的捕获。

这种方案相较于调用系统内置的用用程序,灵活度要高很多,便于开发者在UI界面上布局,而且系统封装的很好,便于使用,唯一的缺点是使用它录下来的音频是经过编码的,没有办法的得到原始的音频。同时MediaRecorder即可用于音频的捕获也可以用于视频的捕获相当的强大。实际开发中没有特殊需求的话,用的是比较多的!

使用步骤:

创建MediaRecorder对象,调用如下方法(Ps:调用顺序顺序对结果的影响是非常的大。)
MediaRecorder recorder=new MediaRecorder();//创建MediaRecoder对象

1. recorder.setAudioSource(MediaRecorder.AudioSource.MIC); //调用setAudioSource方法 (调用的第一个方法) 
MediaRecorder.AudioSource.CAMCORDER和MediaRecorder.AudioSource.VOICE_RECOGNITION当设备具有。>=2个麦克风的时候就可以使用它们。
MediaRecorder.AudioSource.VOICE_CALL从电话中录音

2. recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);//setOutputFormat方法(调用的第二个方法)
MediaRecorder.OutputFormat.THREE_GPP 输出文件将是一个扩展名为(.3gp)的文件。它可能包含音频和视频。MediaRecorder.OutputFormat.MPEG_4 输出一个MPEG_4文件,它可能包含音频和视频。

3. recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); //setAudioEncoder方法 (这是调用的第三个方法)

4. recorder.setOutputFile(url); //setOutputFile方法 url是目标文件路径(这是调用的第四个方法)
以上四个方法一次调用完成之后,就可以像MediaPlayer一样控制录制和暂停录制了。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#fff"
    android:gravity="center">

    <Button 
        android:text="开始录音" 
        android:id="@+id/StartRecording" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content"/>
   
    <Button 
        android:text="停止录音" 
        android:id="@+id/StopRecording" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content"/>
    
</LinearLayout>
public class MainActivity extends Activity implements OnClickListener{
   
	Button startRecording, stopRecording;//开始录音、停止录音、释放资源
	MediaRecorder recorder;
	File audioFile; //录音保存的文件
	boolean isRecoding=false;// true 表示正在录音
 
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
	    requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.main);
		init();
		initListener();
	}
	
	//初始化
	public void init(){
		stopRecording = (Button) this.findViewById(R.id.StopRecording);
		startRecording = (Button) this.findViewById(R.id.StartRecording);
		
		recorder = new MediaRecorder();
		recorder.setAudioSource(MediaRecorder.AudioSource.MIC);//设置播放源 麦克风
		recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); //设置输入格式 3gp
		recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); //设置编码 AMR
	}
	
	//设置监听器
	public void initListener(){
		startRecording.setOnClickListener(this);
		stopRecording.setOnClickListener(this);
	}
	   
	//录音	
	public void recod(){    
			
			//此处还应该对手机进行下判断,判断下手机里面有没有内存卡
		    //保存在SD卡下MediaRecorderTest文件夹中
			File path = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+ "/MediaRecorderTest"); 
			if(!path.exists())
			{
				path.mkdirs();
			}
			
			try {
				audioFile=new File(path,"test.3gp");
				if(audioFile.exists())
				{
					audioFile.delete();
				}
				audioFile.createNewFile();//创建文件
				
			   } catch (Exception e) {
				throw new RuntimeException("Couldn't create recording audio file", e);
			}
 
			recorder.setOutputFile(audioFile.getAbsolutePath()); //设置输出文件
 
			try {
				recorder.prepare();
			} catch (IllegalStateException e) {
				throw new RuntimeException("IllegalStateException on MediaRecorder.prepare", e);
			} catch (IOException e) {
				throw new RuntimeException("IOException on MediaRecorder.prepare", e);
			}
			isRecoding=true;
			recorder.start();
	}
	
	
	public void onClick(View v) {
		
		switch (v.getId())
		{   
		    //开始录音
		    case R.id.StartRecording:
		    {  
		    	Toast.makeText(MainActivity.this,"开始录音",Toast.LENGTH_SHORT).show();
		    	recod();
		    	break;
		    }
		    
		    //停止录音
		    case R.id.StopRecording:
		    {   
		    	if(isRecoding)
		    	{
		    	 Toast.makeText(MainActivity.this,"停止录音",Toast.LENGTH_SHORT).show();
		    	 recorder.stop();
				 recorder.release();
		    	}
		    	break;
		    }
		    
		   default:
			  break;
		}
	}
	
}
MediaRecoder的其他API方法:
//设置录制允许的最大时长 单位是毫秒。必须在setOutFormat方法之后,prepare方法之前使用。
setMaxDuration(int);
//设置文件录制的存放文件的最大值,单位是字节 。必须在setOutFormat方法之后,prepare方法之前使用。 
setMaxFileSize(long)
//允许录制的音频通道数,通常是一个通道(单声道,2个通道双声道,立体声)。必须在调用prepare方法之前调用。
setAudioChannels(int)
//允许制定捕获和编码音频的采样率。硬件和使用的编码器将会决定合适的采样率。必须在调用prepare方法之前调用。
setAudioSamplingRate(int)
//允许指定当压缩音频时编码器所使用的每秒位数(位/秒)。必须在调用prepare方法之前调用。
setAudioEncodingBitRate在(int
三、使用AudioRecord 进行音频捕获。

这种方法是3种之中最为灵活的,能让开发者最大限度的处理采集的音频,同时它捕获到的音频是原始音频PCM格式的!像做变声处理的需要就必须要用它收集音频。在实际开发中,它也是最常用来采集音频的手段。也是本文介绍的重点。

1. 指定音频源 这个和MediaRecorder是相同的 
int audioSource=MediaRecorder.AudioSource.MIC;

2. 指定采样率 (MediaRecoder 的采样率通常是8000Hz CD的通常是44100Hz 不同的Android手机硬件将能够以不同的采样率进行采样。其中11025是一个常见的采样率)
int sampleRateInHz=11025 ;

3. 指定捕获音频的通道数目。在AudioFormat类中指定用于此的常量  
int channelConfig=AudioFormat.CHANNEL_CONFIGURATION_MONO;

4. 指定音频量化位数 ,在AudioFormaat类中指定了以下各种可能的常量。通常我们选择ENCODING_PCM_16BIT和ENCODING_PCM_8BIT PCM代表的是脉冲编码调制,它实际上是原始音频样本。
//因此可以设置每个样本的分辨率为16位或者8位,16位将占用更多的空间和处理能力,表示的音频也更加接近真实。
int audioFormat=AudioFormat.ENCODING_PCM_16BIT;
指定缓冲区大小。调用AudioRecord类的getMinBufferSize方法可以获得。
//创建AudioRecord。AudioRecord类实际上不会保存捕获的音频,因此需要手动创建文件并保存下载。
AudioRecord record=new AudioRecord(audioSource,sampleRateInHz,channelConfig,audioFormat,bufferSizeInBytes)

布局xml文件和MediaRecorder Demo中一样,2个按钮而已!就不贴了,下面贴出AudioRecord的Demo的源代码.

public class MainActivity extends Activity implements OnClickListener {
	Button startRecordingButton, stopRecordingButton;//开始录音、停止录音
	File recordingFile;//储存AudioRecord录下来的文件
	boolean isRecording = false; //true表示正在录音
	AudioRecord audioRecord=null;
	File parent=null;//文件目录
	int bufferSize=0;//最小缓冲区大小
	int sampleRateInHz = 11025;//采样率
	int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO; //单声道
	int audioFormat = AudioFormat.ENCODING_PCM_16BIT; //量化位数
	String TAG="AudioRecord";
 
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.main);
		init();
		initListener();
	}
	
	//初始化
	public void init(){
		startRecordingButton = (Button)findViewById(R.id.StartRecordingButton);
		stopRecordingButton = (Button)findViewById(R.id.StopRecordingButton);
		
		bufferSize = AudioRecord.getMinBufferSize(sampleRateInHz,channelConfig, audioFormat);//计算最小缓冲区
		audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC,sampleRateInHz,channelConfig, audioFormat, bufferSize);//创建AudioRecorder对象
		
		parent = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+ "/AudiioRecordTest");
		if(!parent.exists())
			parent.mkdirs();//创建文件夹
	}
	
    //初始化监听器
	public void initListener(){
		startRecordingButton.setOnClickListener(this);
		stopRecordingButton.setOnClickListener(this);
	}
	
	public void onClick(View v) {
		switch (v.getId()) {
		//开始录音
		case R.id.StartRecordingButton:
		{
			record();
			break;
		}
	    
		//停止录音
		case R.id.StopRecordingButton:
		{
			stopRecording();
			break;
		}
	}
		
 }
 
    //开始录音
	public void record() {
		isRecording = true;
		new Thread(new Runnable() {
			@Override
			public void run() {
				isRecording = true;
				
				recordingFile = new File(parent,"audiotest.pcm");
				if(recordingFile.exists()){
					recordingFile.delete();
				}
				
				try {
					 recordingFile.createNewFile();
				    } 
				catch (IOException e) {
					 e.printStackTrace();
					 Log.e(TAG,"创建储存音频文件出错");
				    }
				
				
				try {
				DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(recordingFile)));
			    byte[] buffer = new byte[bufferSize];
				audioRecord.startRecording();//开始录音
					int r = 0;
					while (isRecording) {
						int bufferReadResult = audioRecord.read(buffer,0,bufferSize);
						for (int i = 0; i < bufferReadResult; i++) 
						{
							dos.write(buffer[i]); 
						}
						r++;
					}
					audioRecord.stop();//停止录音
					dos.close();
				} catch (Throwable t) {
					Log.e(TAG, "Recording Failed");
				}
				
			}
		}).start();
 
	}
    
    //停止录音
	public void stopRecording() 
	{
		isRecording = false;
	}
 
	
}

注意这几个Demo都要添加以下权限:

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

MediaRecorder采集音频的Demo源码

AudioRecord采集音频的Demo源码

原始音频PCM播放器 :使用方法 : 文件->导入->裸数据 然后根据你录音时的配置填写相应参数 就可以播放了!

五.关注我的公众号 (CodeEngine) 最新文章一览.