zoukankan      html  css  js  c++  java
  • Android录制音频的三种方式

    对于录制音频,Android系统就都自带了一个小小的应用,可是使用起来可能不是特别的灵活。所以有提供了另外的俩种。

    下边来介绍下这三种录制的方式;

    1、通过Intent调用系统的录音器功能,然后在录制完毕保存以后在onActivityResult中返回录制的音频的uri,然后通过Mediaplayer进行播放

    调用系统的录音器

     private final static int REQUEST_RECORDER = 100;
        private Uri uri;
        public void recorder_Intent(){
            Intent intent = new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION);
            startActivityForResult(intent,REQUEST_RECORDER);
        }

    获取返回的信息

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == RESULT_OK && REQUEST_RECORDER == requestCode){
            uri = data.getData();
        }
    }
    <span style=""><span style="font-size:24px;">通过Mediaplayer进行播放</span></span>
      if (uri != null){
                                if (mediaPlayer != null) {
                                    try {
                                        mediaPlayer.reset();
                                        mediaPlayer.setDataSource(RecorderActivity.this, uri);
                                        mediaPlayer.prepare();
    
                                    } catch (IOException e) {
                                        e.printStackTrace();
                                    }
    
                                }else
                                    Toast.makeText(RecorderActivity.this,"没有成功创建Mediaplayer",Toast.LENGTH_SHORT).show();
                            }

    2、通过MediaRecorder来进行音频的录制:

    MediaRecorder 类可用于音频和视频的捕获。再构造了一个MediaRecorder对象之后,为了捕获音频,必须调用setAudioEncoder和setAudioSource这俩个方法。

    假设不调用这些方法,那么将不会录制音频(视频也相同不会),另外,MediaRecorder在准备录制之前通常还会调用setOutputFormat 和setOutputFile,

    在实例化MediaRecorder之后。应该调用的第一个方法是setAudioSource。它採用一个AudioSource内部类中定义的常量作为參数,我们通常使用的常量是MediaRecorder。

    AudioSource.MIC.

    依据顺序,下一个调用的就是setOutputFormat ,这种方法採用在MediaRecorder.OutputFormat内部类中指定的常量作为參数:

    (1)MediaRecorder.OutputFormat.MPEG_4:这个常量指定输出的文件将是一个MPEG_4文件,包括音频跟视频轨

    (2)MediaRecorder.OutputFormat.RAW_AMR;这个常量表示输出一个没有不论什么容器类型的原始文件,仅仅有在捕获没有视频的音频且音频编码器是AMR_NB时才会使用这个常量。

    (3)MediaRecorder.OutputFormat.THREE_GPP:这个常量指定输出的文件将是一个3gpp文件(.3gp)。它可能同一时候包括音频跟视频轨


    MediaRecorder音频编码。在设置输出格式之后,能够调用setAudioEncoder方法来设置应该使用编码器,可能的值指定为MediaRecorder.AudioEncoder类中的常量。出来使用DEFAULT之外,仅仅存在一个其它的值:MediaRecorder.AudioEncoder.AMR_NB,这是自适应多速率窄带编解码器。

    这样的编解码器针对语音进行了优化,因此不适应于语音之外的其它内容。默认情况下他的採样率是8kHz,码率在 4.75~12.2kbps之间。这个俩个数据对于录制语音之外的其它内容而言很低。可是,这是当前可用于MediaRecorder的唯一选择。


    下来就看代码的实现:

    这是录制的代码:

      private MediaRecorder mediaRecorder = new MediaRecorder();
        private File audioFile;
        public void recorder_Media(){
            mediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
            mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
            mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
            File path = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/Android/data/com.example.chengpengfei_d.recorderdemo/files");
            path.mkdirs();
            amplitude = new RecordAmplitude();
            try {
                audioFile = File.createTempFile("recording",".3gp",path);
                mediaRecorder.setOutputFile(audioFile.getAbsolutePath());
                mediaRecorder.prepare();
                mediaRecorder.start();
                isRecording = true;
                amplitude.execute();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    

    这是播放的代码

       case FLAG_MEDIA:
                            isRecording = false;
                            amplitude.cancel(true);
                            mediaRecorder.stop();
                            mediaRecorder.release();
                            mediaPlayer.reset();
                            try {
                                mediaPlayer.setDataSource(audioFile.getAbsolutePath());
                                mediaPlayer.prepare();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                            break;


    3 使用AudioRecord录制原始音频:
    	这就是第三种捕获音频的方法。使用AudioRecord的类。AudioRecord是三个方法中最灵活的(由于他同意訪问原始音频流),可是他是拥有最少的内置功能。如不会自己主动压缩音频等等。
    	使用AudioRecord的基础知识很easy。我们仅仅须要构造一个AudioRecord类型的对象,并传入各种不同配置參数。
    	须要制定的第一个值就是音频源。以下使用值与之前用于MediaRecorder的值同样,其在MediaRecorder.AudioSource 中定义。实际上。这意味着能够使用MediaRecorder.AudioSource.MIC;
    	int audiosource = MediaRecorder.AudioSource.MIC;
    	须要指定的下一个值是录制的採样率,应以赫兹为单位,我们知道。MediaRecorder採样的音频是8000赫兹。

    而CD质量的音频一般是44100赫兹(44100Hz)。Hz或赫兹是每秒的样本数量。

    不同的Android手机硬件将可以以不同的採样率进行採样。对于我的这个样例将以11025Hz的採样率来进行採样,这是一个经常使用的採样率。

    	int sampleRateInHz = 11025;
    	
    	   接下来,须要指定捕获的音频通道的数量,在AudioFormat类中指定了用于此參数的常量。并且可依据名称理解他们。
    
    
    
    

    如今将使用单声道配置。
    	  int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO;
    	随后。须要指定音频格式。

    在AudioFormat类中也指定了一下各种可能的常量。

    	在这四个选择中,我们选择PCM_16位和PCM 8位。

    PCM代表脉冲编码调制(Pulse Code Modulation) 他实际上是原始的音频样本。

    因此能够设置每一个样本的分辨率为16位或8位。16位将占用很多其它的控件和处理能力,但表示的音频将更接近真实。

    	int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
    	   最后将须要指定缓冲区大小。

    时间上能够查询AudioRecord类以获得最小缓冲区大小。查询方式是调用getMinBufferSize的静态方法,同一时候传入採样率,通道配置以及音频格式。

    	int bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRateInHz,channelConfig
    ,audioFormat);
    
    
    	下边就看实际的代码吧:
    	主要分俩个方法,还有些初始化的代码:
      private boolean isPlaying = false;
        private int frequency = 11025;
        int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
        int audiosource = MediaRecorder.AudioSource.MIC;
        int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO;
        File recordingFile = null;
        RecordAudio recordAudio = null;
        PlayAudio playAudio = null;
        public void recorder_Audio() throws IOException {
            //AudioRecord不会直接保存音频。须要自己保存
            File path = new File(Environment.getExternalStorageDirectory().getAbsolutePath());
            path.mkdirs();
    
            try {
                recordingFile = File.createTempFile("recording", ".pcm", path);
            } catch (IOException e) {
                e.printStackTrace();
            }
            recordAudio = new RecordAudio();
            recordAudio.execute();
        }
    
        public void playRecorder() {
            isRecording = false;
            playAudio = new PlayAudio();
            playAudio.execute();
        }
    //播放录制音频的异步任务
        private class PlayAudio extends AsyncTask<Void,Integer,Void>{
            @Override
            protected Void doInBackground(Void... params) {
                isPlaying = true;
                int bufferSize = AudioTrack.getMinBufferSize(frequency,channelConfig,audioFormat);
                short[] buffer = new short[bufferSize / 4];
                DataInputStream dis= null;
                try {
                    dis  = new DataInputStream(new BufferedInputStream(new FileInputStream(recordingFile)));
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
                AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,frequency,channelConfig,audioFormat,bufferSize,AudioTrack.MODE_STREAM);
                audioTrack.play();
                try {
                    while(isPlaying && dis.available() > 0 ){
                        int i = 0;
                        while(dis.available() > 0 && i < buffer.length){
                            buffer[i] = dis.readShort();
                            i++;
                        }
                        audioTrack.write(buffer,0,buffer.length);
                    }
                    dis.close();
    
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return null;
            }
        }
    <span style="white-space:pre">	</span>
    //录制音频的一个异步任务;
        private class RecordAudio extends AsyncTask<Void,Integer,Void>{
            @Override
            protected Void doInBackground(Void... params) {
                isRecording = true;
                DataOutputStream dos = null;
                try {
                    dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(recordingFile)));
                    int bufferSize = AudioRecord.getMinBufferSize(frequency,channelConfig,audioFormat);
                    AudioRecord audioRecord = new AudioRecord(audiosource,frequency,channelConfig,audioFormat,bufferSize);
                    short [] buffer = new short[bufferSize];
                    audioRecord.startRecording();
                    int r = 0;
                    while(isRecording){
                        int bufferReadResult = audioRecord.read(buffer,0,bufferSize);
                        for (int i = 0; i<bufferReadResult; i++){
                            try {
                                dos.writeShort(buffer[i]);
    
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                        publishProgress(new Integer(r));
                        r++;
                    }
                    audioRecord.stop();
                    dos.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
    
                return null;
            }
    
            @Override
            protected void onProgressUpdate(Integer... values) {
                super.onProgressUpdate(values);
                mTv_progress.setText(values[0] + "");
            }
        }
    	至此三种方式也就完了,这是一个关于音频录制的实例。通过三种不同方式的录制来达到同样的目的。可是要了解。三种的优缺点。假设想看实际效果,下载以后执行下看看吧。本实例是在Android studio中开发,假设Ecplise的话那么直接移植代码,以及清单文件的内容,应该就能够,假设不行能够联系我。
    	下载地址:http://download.csdn.net/detail/u012808234/9482926
  • 相关阅读:
    Python3中zipfile模块文件名乱码问题
    python zipfile 文件压缩和文件
    django+celery+rabitmq
    解决 Jumpserver coco 使用登录用户(ldap)进行SSH连接目标主机,忽略系统用户
    日志实时查看、轮询、统计、监控工具 Loggrove
    python django 多级业务树形结构规划及页面渲染
    nginx+uwsgi 部署 django
    python tornado websocket 实时日志展示
    python tornado websocket 多聊天室(返回消息给部分连接者)
    python 实时遍历日志文件
  • 原文地址:https://www.cnblogs.com/Im-Victor/p/9761773.html
Copyright © 2011-2022 走看看