木瓜妮子多媒体开发教程---第五天---Android下音频录制和播放

来源:互联网 发布:易经入门书籍推荐 知乎 编辑:程序博客网 时间:2024/04/28 00:45

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);//输出格式为3gpmedirecoder.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() {@Overridepublic void onStopTrackingTouch(SeekBar arg0) {}@Overridepublic void onStartTrackingTouch(SeekBar arg0) {}@Overridepublic void onProgressChanged(SeekBar arg0, int arg1, boolean arg2) {am.setStreamVolume(AudioManager.STREAM_MUSIC, arg1, 0);//why set am to final typetextview1.setText("Volume:"+arg1+"%");}});mLayout.addView(textview1);//mLayout是布局文件mLayout.addView(volume);}

项目完成,上效果图:


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


0 0
原创粉丝点击