Android實現(xiàn)邊錄邊播功能
Android可以通過MediaRecorder和AudioRecord這兩個工具來實現(xiàn)錄音,MediaRecorder直接把麥克風(fēng)的數(shù)據(jù)存到文件,并且能夠直接進(jìn)行編碼(如AMR,MP3等),而AudioRecord則是讀取麥克風(fēng)的音頻流。本文使用AudioRecord讀取音頻流,使用AudioTrack播放音頻流,通過“邊讀邊播放”以及增大音量的方式來實現(xiàn)一個簡單的助聽器程序。
PS:由于目前的Android模擬器還不支持AudioRecord,因此本程序需要編譯之后放到真機運行。
Activity_layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<Button
android:id="@+id/bt_yinpinhuilu_testing_exit"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Close"
/>
</LinearLayout>
MainActivity:
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import android.Manifest;
import android.content.pm.PackageManager;
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.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import java.util.LinkedList;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private static final String TAG = "ktv";
/**
* 按鈕
*/
private Button bt_exit;
/**
* AudioRecord 寫入緩沖區(qū)大小
*/
protected int m_in_buf_size;
/**
* 錄制音頻對象
*/
private AudioRecord m_in_rec;
/**
* 錄入的字節(jié)數(shù)組
*/
private byte[] m_in_bytes;
/**
* 存放錄入字節(jié)數(shù)組的大小
*/
private LinkedList<byte[]> m_in_q;
/**
* AudioTrack 播放緩沖大小
*/
private int m_out_buf_size;
/**
* 播放音頻對象
*/
private AudioTrack m_out_trk;
/**
* 播放的字節(jié)數(shù)組
*/
private byte[] m_out_bytes;
/**
* 錄制音頻線程
*/
private Thread record;
/**
* 播放音頻線程
*/
private Thread play;
/**
* 讓線程停止的標(biāo)志
*/
private boolean flag = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.setTitle("音頻回路");
requestAllPower();
Log.d("dfdfd", "333333333333");
init();
record = new Thread(new recordSound());
play = new Thread(new playRecord());
// 啟動錄制線程
record.start();
// 啟動播放線程
play.start();
}
private void init() {
bt_exit = findViewById(R.id.bt_yinpinhuilu_testing_exit);
Log.i(TAG, "bt_exit====" + bt_exit);
bt_exit.setOnClickListener(this);
// AudioRecord 得到錄制最小緩沖區(qū)的大小
m_in_buf_size = AudioRecord.getMinBufferSize(8000,
AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT);
// 實例化播放音頻對象
m_in_rec = new AudioRecord(MediaRecorder.AudioSource.MIC, 8000,
AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT, m_in_buf_size);
// 實例化一個字節(jié)數(shù)組,長度為最小緩沖區(qū)的長度
m_in_bytes = new byte[m_in_buf_size];
// 實例化一個鏈表,用來存放字節(jié)組數(shù)
m_in_q = new LinkedList<byte[]>();
// AudioTrack 得到播放最小緩沖區(qū)的大小
m_out_buf_size = AudioTrack.getMinBufferSize(8000,
AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT);
// 實例化播放音頻對象
m_out_trk = new AudioTrack(AudioManager.STREAM_MUSIC, 8000,
AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT, m_out_buf_size,
AudioTrack.MODE_STREAM);
// 實例化一個長度為播放最小緩沖大小的字節(jié)數(shù)組
m_out_bytes = new byte[m_out_buf_size];
}
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.bt_yinpinhuilu_testing_exit:
flag = false;
m_in_rec.stop();
m_in_rec = null;
m_out_trk.stop();
m_out_trk = null;
this.finish();
}
}
/**
* 錄音線程
*/
class recordSound implements Runnable {
@Override
public void run() {
Log.i(TAG, "........recordSound run()......");
byte[] bytes_pkg;
// 開始錄音
m_in_rec.startRecording();
while (flag) {
m_in_rec.read(m_in_bytes, 0, m_in_buf_size);
bytes_pkg = m_in_bytes.clone();
Log.i(TAG, "........recordSound bytes_pkg==" + bytes_pkg.length);
if (m_in_q.size() >= 2) {
m_in_q.removeFirst();
}
m_in_q.add(bytes_pkg);
}
}
}
/**
* 播放線程
*/
class playRecord implements Runnable {
@Override
public void run() {
// TODO Auto-generated method stub
Log.i(TAG, "........playRecord run()......");
byte[] bytes_pkg = null;
// 開始播放
m_out_trk.play();
while (flag) {
try {
m_out_bytes = m_in_q.getFirst();
bytes_pkg = m_out_bytes.clone();
m_out_trk.write(bytes_pkg, 0, bytes_pkg.length);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
/**
* 錄音哦動態(tài)權(quán)限
*/
public void requestAllPower() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.RECORD_AUDIO)) {
} else {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO,
Manifest.permission.READ_EXTERNAL_STORAGE}, 1);
}
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 1) {
for (int i = 0; i < permissions.length; i++) {
Toast.makeText(this, "" + "權(quán)限" + permissions[i] + "申請成功", Toast.LENGTH_SHORT).show();
}
}
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.test.speex">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android學(xué)習(xí)教程之日歷控件使用(7)
這篇文章主要為大家詳細(xì)介紹了Android學(xué)習(xí)教程之日歷控件操作代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-11-11
Android 5.0+ 屏幕錄制實現(xiàn)的示例代碼
這篇文章主要介紹了Android 5.0+ 屏幕錄制實現(xiàn)的示例代碼,從 5.0 開始,系統(tǒng)提供給了 app 錄制屏幕的一系列方法,不需要 root 權(quán)限,只需要用戶授權(quán)即可錄屏,相對來說較為簡單,感興趣的小伙伴們可以參考一下2018-05-05
Android 如何實現(xiàn)彈窗順序&優(yōu)先級控制
這篇文章主要介紹了Android 如何實現(xiàn)彈窗順序&優(yōu)先級控制,幫助大家更好的理解和學(xué)習(xí)使用Android,感興趣的朋友可以了解下2021-03-03
Android dip,px,pt,sp 的區(qū)別詳解
本篇文章是對Android中dip,px,pt,sp的區(qū)別進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06
Android 中 Swipe、Scroll 和 Fling 的區(qū)別解
Swipe、Scroll和Fling是Android中常見的觸摸手勢,它們在用戶體驗和技術(shù)實現(xiàn)上各有特點,Swipe用于快速切換,Scroll用于連續(xù)滾動,Fling用于實現(xiàn)慣性滾動,開發(fā)者可以根據(jù)需求選擇合適的手勢類型,并結(jié)合GestureDetector等工具實現(xiàn)各種交互效果,感興趣的朋友跟隨小編一起看看吧2024-12-12

