Android实现边录边播功能
程序员文章站
2022-04-14 11:35:44
android可以通过mediarecorder和audiorecord这两个工具来实现录音,mediarecorder直接把麦克风的数据存到文件,并且能够直接进行编码(如amr,mp3等),而aud...
android可以通过mediarecorder和audiorecord这两个工具来实现录音,mediarecorder直接把麦克风的数据存到文件,并且能够直接进行编码(如amr,mp3等),而audiorecord则是读取麦克风的音频流。本文使用audiorecord读取音频流,使用audiotrack播放音频流,通过“边读边播放”以及增大音量的方式来实现一个简单的助听器程序。
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 写入缓冲区大小 */ protected int m_in_buf_size; /** * 录制音频对象 */ private audiorecord m_in_rec; /** * 录入的字节数组 */ private byte[] m_in_bytes; /** * 存放录入字节数组的大小 */ private linkedlist<byte[]> m_in_q; /** * audiotrack 播放缓冲大小 */ private int m_out_buf_size; /** * 播放音频对象 */ private audiotrack m_out_trk; /** * 播放的字节数组 */ private byte[] m_out_bytes; /** * 录制音频线程 */ private thread record; /** * 播放音频线程 */ private thread play; /** * 让线程停止的标志 */ 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 得到录制最小缓冲区的大小 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); // 实例化一个字节数组,长度为最小缓冲区的长度 m_in_bytes = new byte[m_in_buf_size]; // 实例化一个链表,用来存放字节组数 m_in_q = new linkedlist<byte[]>(); // audiotrack 得到播放最小缓冲区的大小 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); // 实例化一个长度为播放最小缓冲大小的字节数组 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(); } } } } /** * 录音哦动态权限 */ 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, "" + "权限" + 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>
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: sql server如何利用开窗函数over()进行分组统计
下一篇: SQL数据库存储过程示例解析