本文目录 点击直达
- Android 开发一个耳返程序
- 程序编写
- 1. 配置 `AndroidManifast.xml`
- 2.编写耳返管理器
- 3. 录音权限申请
- 4. 使用
- 注意
- 最后我还有一句话要说
- 怕相思,已相思,轮到相思没处辞,眉间露一丝
Android 开发一个耳返程序
耳返程序是声音录入设备实时播放的一种程序,理论上实现方案是通过手机录音功能录制音频的同时播放音频,这样就可以简单达到耳返的目的。
分析完毕之后通过了解Android官方API和文档,决定采用AudioRecord/AudioTrack
的方式实现简单的PCM编码录制和播放来实现耳返,接下来我们直接进入正题
程序编写
1. 配置 AndroidManifast.xml
录音需要使用录音权限,将以下代码写入AndroidManifast.xml
文件中
<uses-permission android:name="android.permission.RECORD_AUDIO" />
效果如下
2.编写耳返管理器
这里我们创建一个类IEMSManager.kt
,用来处理音频录制和播放
object IEMSManager {
//录音来源使用通话语音,这样可以防止啸叫的同时拥有系统降噪
private const val AUDIO_SOURCE = MediaRecorder.AudioSource.VOICE_COMMUNICATION
// 采样频率:44100Hz是唯一目前所有Android设备都保证支持的采样频率
private const val SAMPLE_RATE = 44100
// 音频通道使用双声道输入
private const val CHANNEL_IN = AudioFormat.CHANNEL_IN_STEREO
// 音频通道使用双声道输出
private const val CHANNEL_OUT = AudioFormat.CHANNEL_OUT_STEREO
// PCM 16bits每个样本,所有设备保证支持
private const val AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT
// 录音时音频数据写入的buffer的大小
private var recordBufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE, CHANNEL_IN, AUDIO_FORMAT)
// 播放时音频数据读取的buffer的大小
private val trackBufferSize =
AudioTrack.getMinBufferSize(SAMPLE_RATE, CHANNEL_OUT, AUDIO_FORMAT);
//构建描述音频属性的对象
private val attributes by lazy {
AudioAttributes.Builder()
//设置音频流的用途属性
.setUsage(AudioAttributes.USAGE_ASSISTANT)
//设置音频内容属性
.setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
.build()
}
//构建描述音频格式的对象
private val format = AudioFormat.Builder()
//设置采样频率
.setSampleRate(SAMPLE_RATE)
//设置音频格式的编码方式
.setEncoding(AUDIO_FORMAT)
//设置通道掩码
.setChannelMask(CHANNEL_OUT)
.build()
//控制耳返的状态
private var isRunning = false
//音频录制器,可以录制音频裸数据PCM
private var audioRecorder: AudioRecord? = null
//音频播放器,支持PCM裸数据渲染
private var audioTrack: AudioTrack? = null
@RequiresPermission(android.Manifest.permission.RECORD_AUDIO)
fun start() {
if (isRunning) return
isRunning = true
//初始化音频录制器
audioRecorder = AudioRecord(
AUDIO_SOURCE,
SAMPLE_RATE,
CHANNEL_IN,
AUDIO_FORMAT,
recordBufferSize
)
//初始化音频播放器
audioTrack = AudioTrack(
attributes,
format,
trackBufferSize,
AudioTrack.MODE_STREAM,
AudioManager.AUDIO_SESSION_ID_GENERATE
)
//开启线程
thread {
//创建字节数组存储PCM的二进制数据
val data = ByteArray(recordBufferSize)
//开始录制
audioRecorder?.startRecording()
//开始播放
audioTrack?.play()
while (isRunning) {
//录音数据是根据录制缓冲区大小试试读取的
val byteSize = audioRecorder?.read(data, 0, recordBufferSize) ?: 0
//检查到录制数据正常
if (byteSize >= AudioRecord.SUCCESS) {
//AudioTrack实时渲染刚刚录制的部分
audioTrack?.write(data, 0, byteSize)
}
}
//释放资源
audioRecorder?.stop()
audioRecorder?.release()
audioTrack?.stop()
audioTrack?.release()
audioRecorder = null
audioTrack = null
}
}
fun stop() {
isRunning = false
}
}
3. 录音权限申请
在使用耳返功能前,需要检查权限,并且授予RECORD_AUDIO
权限,否则会闪退
if (ActivityCompat.checkSelfPermission(
this,
Manifest.permission.RECORD_AUDIO
) != PackageManager.PERMISSION_GRANTED
) {
requestPermissions(arrayOf(Manifest.permission.RECORD_AUDIO), 0x1)
return@setOnClickListener
}
4. 使用
代码已经编写完成,只需要调用IEMSManager.kt
使用即可听到自己发出的声音
IEMSManager.start()
IEMSManager.stop()
注意
因为使用通话的双通道麦克风实现了降噪,所以使用时可能声音较小,如果没有声音,请将声音调到最大,然后凑近麦克风吼两句"感谢博主,我会一键三连的"
最后我还有一句话要说
怕相思,已相思,轮到相思没处辞,眉间露一丝
明·俞彦《长相思·折花枝》