国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統(tǒng) > Android > 正文

Android音頻處理之通過AudioRecord去保存PCM文件進(jìn)行錄制,播放,停止,刪除功能

2019-12-12 04:45:47
字體:
供稿:網(wǎng)友

音頻這方面很博大精深,我這里肯定講不了什么高級的東西,最多也只是一些基礎(chǔ)類知識,首先,我們要介紹一下Android他提供的錄音類,實際上他有兩個,一個是MediaRecorder,還有一個就是我們今天要用到的AudioRecord,那他們有什么區(qū)別呢?

一.區(qū)別

MediaRecorder和AudioRecord都可以錄制音頻,區(qū)別是MediaRecorder錄制的音頻文件是經(jīng)過壓縮后的,需要設(shè)置編碼器。并且錄制的音頻文件可以用系統(tǒng)自帶的Music播放器播放。

而AudioRecord錄制的是PCM格式的音頻文件,需要用AudioTrack來播放,AudioTrack更接近底層。

PCM可能更加可以理解為音頻的源文件

二.優(yōu)缺點(diǎn)

AudioRecord

主要是實現(xiàn)邊錄邊播以及對音頻的實時處理,這個特性讓他更適合在語音方面有優(yōu)勢

優(yōu)點(diǎn):語音的實時處理,可以用代碼實現(xiàn)各種音頻的封裝

缺點(diǎn):輸出是PCM格式文件,如果保存成音頻文件,是不能夠被播放器播放的,所以必須先寫代碼實現(xiàn)數(shù)據(jù)編碼以及壓縮

MediaRecorder

已經(jīng)集成了錄音、編碼、壓縮等,支持少量的錄音音頻格式,大概有,aac,amr,3gp等

優(yōu)點(diǎn):集成,直接調(diào)用相關(guān)接口即可,代碼量小

缺點(diǎn):無法實時處理音頻;輸出的音頻格式不是很多,例如沒有輸出mp3格式文件

三.準(zhǔn)備工作

我們要實現(xiàn)的是一個實時的去錄音,播放,停止等功能的測試案例,那我們肯定要準(zhǔn)備點(diǎn)什么,比如說,我這里先創(chuàng)建一個項目――PCMSample

然后寫個布局

layout_main.xml

<?xml version="1.0" encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:padding="10dp"><Buttonandroid:id="@+id/startAudio"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@drawable/button_bg"android:text="開始錄音"android:textColor="@android:color/white"/><Buttonandroid:id="@+id/stopAudio"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginBottom="10dp"android:layout_marginTop="5dp"android:background="@drawable/button_bg"android:enabled="false"android:text="停止錄音"android:textColor="@android:color/white"/><Buttonandroid:id="@+id/playAudio"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@drawable/button_bg"android:enabled="false"android:text="播放音頻"android:textColor="@android:color/white"/><Buttonandroid:id="@+id/deleteAudio"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="5dp"android:background="@drawable/button_bg"android:text="刪除PCM"android:textColor="@android:color/white"/><ScrollViewandroid:id="@+id/mScrollView"android:layout_width="match_parent"android:layout_height="0dp"android:layout_marginTop="5dp"android:layout_weight="1"><TextViewandroid:id="@+id/tv_audio_succeess"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="初始化完成...."android:textColor="@color/colorAccent"/></ScrollView></LinearLayout>

可以預(yù)覽一下

這里寫圖片描述

這里我給按鈕加了一個扁平的效果,實際上寫了一個xml,很簡單

button_bg.xml

<?xml version="1.0" encoding="utf-8"?><selector xmlns:android="http://schemas.android.com/apk/res/android"><item android:state_pressed="true"><shape><corners android:radius="30dp"/><solid android:color="@color/colorPrimary"/></shape></item><item android:state_pressed="false"><shape><corners android:radius="30dp"/><solid android:color="@color/colorPrimaryDark"/></shape></item></selector>

好的,回到正題,我們這里有四個按鈕,分別是開始。停止,播放,和刪除,我們就是要實現(xiàn)這四個功能,在此之前,我們還需要做的事情就是添加權(quán)限,因為我們要錄音和寫內(nèi)存卡文件,所有需要這兩個權(quán)限即可

<!--錄音--><uses-permission android:name="android.permission.RECORD_AUDIO" /><!--讀取SD卡--><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

這里初始化什么的就不說了,我們直接進(jìn)入正題

四.開始錄音

開始錄音的話,這里,我們定義一個變量isRecording去控制,這樣就比較好結(jié)束了,而且要注意的是,錄音是不能放在UI線程的,你懂的,所以我們可以寫一個開始錄音的方法

//開始錄音public void StartRecord() {Log.i(TAG,"開始錄音");//16K采集率int frequency = 16000;//格式int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;//16Bitint audioEncoding = AudioFormat.ENCODING_PCM_16BIT;//生成PCM文件file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/reverseme.pcm");Log.i(TAG,"生成文件");//如果存在,就先刪除再創(chuàng)建if (file.exists())file.delete();Log.i(TAG,"刪除文件");try {file.createNewFile();Log.i(TAG,"創(chuàng)建文件");} catch (IOException e) {Log.i(TAG,"未能創(chuàng)建");throw new IllegalStateException("未能創(chuàng)建" + file.toString());}try {//輸出流OutputStream os = new FileOutputStream(file);BufferedOutputStream bos = new BufferedOutputStream(os);DataOutputStream dos = new DataOutputStream(bos);int bufferSize = AudioRecord.getMinBufferSize(frequency, channelConfiguration, audioEncoding);AudioRecord audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, frequency, channelConfiguration, audioEncoding, bufferSize);short[] buffer = new short[bufferSize];audioRecord.startRecording();Log.i(TAG, "開始錄音");isRecording = true;while (isRecording) {int bufferReadResult = audioRecord.read(buffer, 0, bufferSize);for (int i = 0; i < bufferReadResult; i++) {dos.writeShort(buffer[i]);}}audioRecord.stop();dos.close();} catch (Throwable t) {Log.e(TAG, "錄音失敗");}}

首先,這里我們了解一下采樣率,編碼,音頻流等基本的概念,剩下的大多是讀寫流的操作了,我們通過創(chuàng)建一個AudioRecord去寫pcm文件,定義一個while循環(huán),用我們剛才定義的isRecording控制,所以,我們的點(diǎn)擊事件就

case R.id.startAudio:Thread thread = new Thread(new Runnable() {@Overridepublic void run() {StartRecord();Log.e(TAG,"start");}});thread.start();printLog("開始錄音");ButtonEnabled(false, true, false);break;

這里要注意一下thread.start();開啟線程,同時打印出log,具體代碼如下

//打印logprivate void printLog(final String resultString) {tv_audio_succeess.post(new Runnable() {@Overridepublic void run() {tv_audio_succeess.append(resultString + "/n");mScrollView.fullScroll(ScrollView.FOCUS_DOWN);}});}

這里,我為了防止ANR,所以控制了一下按鈕的焦點(diǎn)

//獲取/失去焦點(diǎn)private void ButtonEnabled(boolean start, boolean stop, boolean play) {startAudio.setEnabled(start);stopAudio.setEnabled(stop);playAudio.setEnabled(play);}

好的,我們運(yùn)行一下

這里寫圖片描述

看起來沒什么變化,但是你去內(nèi)存卡中就會發(fā)現(xiàn)多了一個pcm文件

這里寫圖片描述

當(dāng)然,你只是點(diǎn)擊啟動錄音是不會生成這個pcm文件的,你需要點(diǎn)擊停止停止錄音的按鈕

五.停止錄音

停止錄音很簡單,我們控制通過改變寫入流就好了

case R.id.stopAudio:isRecording = false;ButtonEnabled(true, false, true);printLog("停止錄音");break;

這樣才會生成PCM

六播放音頻

現(xiàn)在有了PCM我們可以試著去播放了,寫一個播放的方法

//播放文件public void PlayRecord() {if(file == null){return;}//讀取文件int musicLength = (int) (file.length() / 2);short[] music = new short[musicLength];try {InputStream is = new FileInputStream(file);BufferedInputStream bis = new BufferedInputStream(is);DataInputStream dis = new DataInputStream(bis);int i = 0;while (dis.available() > 0) {music[i] = dis.readShort();i++;}dis.close();AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,16000, AudioFormat.CHANNEL_CONFIGURATION_MONO,AudioFormat.ENCODING_PCM_16BIT,musicLength * 2,AudioTrack.MODE_STREAM);audioTrack.play();audioTrack.write(music, 0, musicLength);audioTrack.stop();} catch (Throwable t) {Log.e(TAG, "播放失敗");}}

正如上面所說,我們播放需要用到AudioTrack,調(diào)用他的play方法以及設(shè)置一些參數(shù)即可

七.刪除音頻

刪除音頻只需要刪除這個pcm文件就行

//刪除文件private void deleFile() {if(file == null){return;}file.delete();printLog("文件刪除成功");}

這就是大致的錄音邏輯,雖然看起來很簡單,但是這正是現(xiàn)在很多語音和音頻的最基礎(chǔ)部分,特別是語音,如果你從事語音的工作,我相信你會感謝我的!

好了,最后放上完整的代碼:

MainActivity

package com.liuguilin.pcmsample;import android.media.AudioFormat;import android.media.AudioManager;import android.media.AudioRecord;import android.media.AudioTrack;import android.media.MediaRecorder;import android.os.Bundle;import android.os.Environment;import android.support.v7.app.AppCompatActivity;import android.util.Log;import android.view.View;import android.widget.Button;import android.widget.ScrollView;import android.widget.TextView;import java.io.BufferedInputStream;import java.io.BufferedOutputStream;import java.io.DataInputStream;import java.io.DataOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;public class MainActivity extends AppCompatActivity implements View.OnClickListener {public static final String TAG = "PCMSample";//是否在錄制private boolean isRecording = false;//開始錄音private Button startAudio;//結(jié)束錄音private Button stopAudio;//播放錄音private Button playAudio;//刪除文件private Button deleteAudio;private ScrollView mScrollView;private TextView tv_audio_succeess;//pcm文件private File file;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initView();}//初始化Viewprivate void initView() {mScrollView = (ScrollView) findViewById(R.id.mScrollView);tv_audio_succeess = (TextView) findViewById(R.id.tv_audio_succeess);printLog("初始化成功");startAudio = (Button) findViewById(R.id.startAudio);startAudio.setOnClickListener(this);stopAudio = (Button) findViewById(R.id.stopAudio);stopAudio.setOnClickListener(this);playAudio = (Button) findViewById(R.id.playAudio);playAudio.setOnClickListener(this);deleteAudio = (Button) findViewById(R.id.deleteAudio);deleteAudio.setOnClickListener(this);}//點(diǎn)擊事件@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.startAudio:Thread thread = new Thread(new Runnable() {@Overridepublic void run() {StartRecord();Log.e(TAG,"start");}});thread.start();printLog("開始錄音");ButtonEnabled(false, true, false);break;case R.id.stopAudio:isRecording = false;ButtonEnabled(true, false, true);printLog("停止錄音");break;case R.id.playAudio:PlayRecord();ButtonEnabled(true, false, false);printLog("播放錄音");break;case R.id.deleteAudio:deleFile();break;}}//打印logprivate void printLog(final String resultString) {tv_audio_succeess.post(new Runnable() {@Overridepublic void run() {tv_audio_succeess.append(resultString + "/n");mScrollView.fullScroll(ScrollView.FOCUS_DOWN);}});}//獲取/失去焦點(diǎn)private void ButtonEnabled(boolean start, boolean stop, boolean play) {startAudio.setEnabled(start);stopAudio.setEnabled(stop);playAudio.setEnabled(play);}//開始錄音public void StartRecord() {Log.i(TAG,"開始錄音");//16K采集率int frequency = 16000;//格式int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;//16Bitint audioEncoding = AudioFormat.ENCODING_PCM_16BIT;//生成PCM文件file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/reverseme.pcm");Log.i(TAG,"生成文件");//如果存在,就先刪除再創(chuàng)建if (file.exists())file.delete();Log.i(TAG,"刪除文件");try {file.createNewFile();Log.i(TAG,"創(chuàng)建文件");} catch (IOException e) {Log.i(TAG,"未能創(chuàng)建");throw new IllegalStateException("未能創(chuàng)建" + file.toString());}try {//輸出流OutputStream os = new FileOutputStream(file);BufferedOutputStream bos = new BufferedOutputStream(os);DataOutputStream dos = new DataOutputStream(bos);int bufferSize = AudioRecord.getMinBufferSize(frequency, channelConfiguration, audioEncoding);AudioRecord audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, frequency, channelConfiguration, audioEncoding, bufferSize);short[] buffer = new short[bufferSize];audioRecord.startRecording();Log.i(TAG, "開始錄音");isRecording = true;while (isRecording) {int bufferReadResult = audioRecord.read(buffer, 0, bufferSize);for (int i = 0; i < bufferReadResult; i++) {dos.writeShort(buffer[i]);}}audioRecord.stop();dos.close();} catch (Throwable t) {Log.e(TAG, "錄音失敗");}}//播放文件public void PlayRecord() {if(file == null){return;}//讀取文件int musicLength = (int) (file.length() / 2);short[] music = new short[musicLength];try {InputStream is = new FileInputStream(file);BufferedInputStream bis = new BufferedInputStream(is);DataInputStream dis = new DataInputStream(bis);int i = 0;while (dis.available() > 0) {music[i] = dis.readShort();i++;}dis.close();AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,16000, AudioFormat.CHANNEL_CONFIGURATION_MONO,AudioFormat.ENCODING_PCM_16BIT,musicLength * 2,AudioTrack.MODE_STREAM);audioTrack.play();audioTrack.write(music, 0, musicLength);audioTrack.stop();} catch (Throwable t) {Log.e(TAG, "播放失敗");}}//刪除文件private void deleFile() {if(file == null){return;}file.delete();printLog("文件刪除成功");}}

如果你想去調(diào)試這些pcm文件做音頻測試的話,我推薦使用Audacity這個軟件,可以看到,我直接點(diǎn)擊左上角的file-導(dǎo)入-源文件,然后設(shè)置16K

這里寫圖片描述

這樣就可以調(diào)試了

這里寫圖片描述

最后,放一張完整的截圖

這里寫圖片描述

以上所述是小編給大家介紹的Android音頻處理之通過AudioRecord去保存PCM文件進(jìn)行錄制,播放,停止,刪除功能,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對武林網(wǎng)網(wǎng)站的支持!

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 财经| 泾川县| 新田县| 南丹县| 逊克县| 晋城| 铁岭市| 蓬溪县| 治多县| 海安县| 隆林| 阿鲁科尔沁旗| 抚顺市| 桂林市| 诸城市| 金华市| 碌曲县| 汝南县| 米林县| 龙南县| 浦城县| 千阳县| 九龙坡区| 五台县| 莲花县| 汕尾市| 金山区| 高邮市| 甘南县| 乐业县| 潜山县| 丹阳市| 田阳县| 巴东县| 牡丹江市| 合山市| 柘城县| 黔江区| 霞浦县| 晋中市| 霍山县|