Android下音频录制和播放



今天的项目主要能够 掌握MediaRecorder类录制音频的方法,学会指定输入源,输出格式、编码器。 掌握使用MediaPlayer类播放音频,学会指定输入源。


主要功能包括: 完成音频的录制和播放功能; 界面设计按钮控制音频的录制,停止录制、播放和停止播放; 通过Handler控制进度条,显示播放进度; 音频录制完成后被保存到本地指定路径;音频的播放音量可以被控制。


1. 音频的捕获

       在通常情况下,捕获音频有三种不同方法,每种方法都有优点和弱点。第一种方法是使用意图,这是种最简单的方式,通过一个意图利用已有的、提供录制功能的原生应用程序,它虽然最简单却最不灵活;第二种是使用MediaRecord类,它比较难于使用,但是能在原有类基础上添加更多的灵活性。最后一种方法是使用AudioRecord类,它提供了最大的灵活性,但是也最原始,使用比较复杂。

2. 使用意图捕获音频

       在MediaStore.Audio.Media类中存在的变量RECORD_SOUND_ACTION可用来实现创建该意图的动作:

     

int Mediarecord = 0;
       Intentintent = new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION);
       startActivityForResult(intent,Mediarecord);//通过意图捕获音频



通过使用startActivityForResult方法,触发内置录音机,并当用户录制完成后返回录音。程序中创建了一个名为Mediarecord的常量,并将它传递给startActivityForResult,从而可以确定任何onActivityResult调用的来源。当有startActivityForResult函数触发时,任何活动在返回时都会调用onActivityResult方法,这个常量连同意图一起传入,以此来进行区分。onActivityResult方法是一个用以处理意图返回数据的一个必需的方法,在这里onActivityResult方法可以对意图返回的录音播放。

3. MediaRecord类

       在AndroidSDK中包含了一个Mediarecord类,可以利用它来建立自己的音频录制功能,在创建音频功能的过程中,可以控制录制音频的时间长度等,从而有了更多的灵活性。在完成一个Mediarecord的对象的创建后,为了捕获音频,需要调用setAudioEncoderh、setAudioSource和setOutputFormat、setOutputFile的方法,方法调用顺序也是对结果有很大影响的。下图是MediaRecorder的状态机。

简单的启动mediarecord的方法:

medirecoder= newMediaRecorder();
medirecoder.setAudioSource(MediaRecorder.AudioSource.MIC);
//音频来自于麦克风录制
medirecoder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
//输出格式为3gp
medirecoder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
//编码方式
File path = newFile(Environment.getExternalStorageDirectory().getAbsolutePath()+"/AudioPlay/");
path.mkdirs();//如果目录不存在则创建
try {
    audiofile=File.createTempFile("record_temp",".3gp",path);
//创建临时文件
} catch(IOException e) {
    e.printStackTrace();
}
medirecoder.setOutputFile(audiofile.getAbsolutePath());
try {
    medirecoder.prepare();
} catch(IllegalStateException e) {
    e.printStackTrace();
} catch(IOException e) {
    e.printStackTrace();
}
medirecoder.start();
//启动Mediarecord
 
如何停止录制,调用stop方法,并通过release释放:
medirecoder.stop();
medirecoder.release();





4. AudioRecord类

       借助这个类可以操作原始音频,主要是实现边录边播(AudioRecord+AudioTrack)以及对音频的实时处理,如会说话的汤姆猫。因为类本身没有多少内置功能,所以只需要构造一个AudioRecord类型的对象,对其传入不同的配置参数,来实现语音的实时处理,用代码来实现对音频的封装、编码和压缩。AudioRecord类的输出是PCM语音数据,无法直接保存成音频文件,不能直接被播放器播放,这也就给编程带来了一定难度。

AudioTrack用于管理单个的音频资源。 在构造AudioTrack实例时,会涉及到流类型、采样率、通道配置、音频格式、缓冲大小、播放模式等因素。AudioTrack支持STREAM_VOICE_CALL、STREAM_SYSTEM、STREAM_RING、STREAM_MUSIC和STREAM_ALARM等流类型。AudioTrack支持44100Hz、22050Hz、11025Hz等采样率。AudioTrack支持单声道(CHANNEL_OUT_MONO)、立体声(CHANNEL_OUT_STEREO)等两种通道。AudioTrack支持ENCODING_PCM_16BIT、ENCODING_PCM_8BIT等两种编码格式。AudioTrack支持两种播放模式:静态模式(staticmode)和流模式(Streamingmode)。其中静态模式由于没有从Java层向原生层传递数据造成的延迟,时延很小。当音频流较大不足以在音频缓冲中一次写入时,可采用流模式。AudioTrack的播放状态包括PLAYSTATE_STOPPED、PLAYSTATE_PAUSED、PLAYSTATE_PLAYING等。AudioTrack实例的状态包括STATE_INITIALIZED、STATE_NO_STATIC_DATA、STATE_UNINITIALIZED等。

向音频缓冲中添加数据的方法为write()。在设置音频缓冲时,其大小与采样率、通道和音频格式有关。其计算公式为:缓冲大小=最小帧数×(通道==CHANNEL_OUT_STEREO?2:1)×(音频格式==PCM16?2:1)。而最小帧数则受制于采样率和音频设备的延迟等因素。

 

4.实现播放功能

Android支持多种用于播放的音频文件格式和编解码器。在MediaPlayer中,根据数据源为元数据、音频文件、音频流的不同情况,有着相应的处理过程。基本的过程如下:

1)播放raw中音频文件

如果音频文件位于Android工程的“res/raw”文件夹下。播放音频文件的过程为:

      

<span style="white-space:pre">	</span> MediaPlayer mp=MediaPlayer.create(context, R.raw.sound_file);
         mp.start();



 

2)播放音频文件

如果音频文件的路径为PATH_OF_FILE,播放音频文件的过程为:

 

MediaPlayer mp=newMediaPlayer();
    try {
       mp.setDataSource(PATH_OF_FILE); //设置数据源
       mp.prepare();
    } catch(IllegalArgumentException e) {
       // TODOAuto-generated catch block
       e.printStackTrace();
    } catch(SecurityException e) {
       // TODOAuto-generated catch block
       e.printStackTrace();
    } catch(IllegalStateException e) {
       // TODOAuto-generated catch block
       e.printStackTrace();
    } catch(IOException e) {
       // TODOAuto-generated catch block
       e.printStackTrace();
    }
    mp.start();



3)播放音频流

如果音频文件的URL地址为URL_ADDRESS,播放音频流的过程为:

MediaPlayer mp=newMediaPlayer();
    try {
       mp.setDataSource(URL_ADDRESS);
       mp.prepare();
       }catch (IllegalArgumentException e) {
           e.printStackTrace();
       }catch (SecurityException e) {
           e.printStackTrace();
       }catch (IllegalStateException e) {
           e.printStackTrace();
       }catch (IOException e) {
           e.printStackTrace();
       }   //设置数据源
                
       mp.start();




 

可以通过下面的语句完成对存储完成的临时存储的录音文件的读取。

  

mediplayer.setDataSource(audiofile.getAbsolutePath());



 4)实现音量的控制

将对音量的控制写成了一个独立的方法,并且采用了动态布局,在MainActivity的代码中将控制条添加进布局中。

<span style="color:#0000c0;"> </span><span style="color: rgb(0, 0, 192); white-space: pre;">	</span>        LinearLayout mLayout = new LinearLayout(this);
		mLayout.setOrientation(LinearLayout.VERTICAL);
		LP_MW = new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT);		
		mLayout.setLayoutParams(LP_MW);



protected void audioVolume (){
		setVolumeControlStream(AudioManager.STREAM_MUSIC);
		
		final AudioManager am = ( AudioManager) getSystemService(MainActivity.AUDIO_SERVICE);
		
		final SeekBar volume = new SeekBar(this);
		final TextView textview1 = new TextView(this);
		volume.setLayoutParams(LP_MW);
		volume.setMax(am.getStreamMaxVolume(AudioManager.STREAM_MUSIC));
		volume.setProgress(am.getStreamVolume(AudioManager.STREAM_MUSIC));
		volume.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
			
			@Override
			public void onStopTrackingTouch(SeekBar arg0) {
				
			}
			
			@Override
			public void onStartTrackingTouch(SeekBar arg0) {
				
			}
			
			@Override
			public void onProgressChanged(SeekBar arg0, int arg1, boolean arg2) {
				am.setStreamVolume(AudioManager.STREAM_MUSIC, arg1, 0);//why set am to final type
				textview1.setText("Volume:"+arg1+"%");
			}
		});	
		
		mLayout.addView(textview1);//mLayout是布局文件
		mLayout.addView(volume);

		
	}



项目完成,上效果图:


android 录音 多通道 安卓专业多轨录音_Media

对于这个项目其实还可以深入,我还想研究一下类内部究竟是如何降噪的,播放时的扩音,总之,不能总是习惯类提供给我们的便利,对于一些算法还是值得去研究一下。