安卓手机麦克风测试应用开发
2015-11-17 16:57
471 查看
之前接了一个开发测试手机麦克风寿命apk的任务,主要要求是:1、可以控制手机麦克风的开启与关闭;2、麦克风接收的声音从听筒发出;3、可设置测试时间。下面我对该应用的开发做一相关讲解并附上代码。
开发难点:1、在话筒与听筒均开启的情况下,进入话筒的声音无法直接从听筒发出,需要做相关转换输出处理;
2、时间任务的启动与停止;
3、时间设置与数据类型的转换。
解决方法:1、引入音频缓冲区作为音频接收与播放的中专(Buffer),以音频声音作为对象由缓冲区接收存储(音频录制),以缓冲区的对象作为播放对象由听筒播放出来;
2、将麦克风开启方法以线程体来定义和调用;
3、以EditText作为时间输入的控件来设置测试时长,并前值转换为长整型。
以下是代码:
主类:AndroidMikeTestActivity.java
Run_Methed.java
Track_Methed,java
main.xml
注意添加相关权限
到此,麦克风测试程序就可以运行了,在编辑框内输入小时数,再点击开始即可运行麦克风,这时可以从听筒中听到麦克风里的声音,当时间到达设定时间时会自动停止,同时计时器也会暂停。当按停止按钮时,时间设置和计时器会同时置为00:00,以便新的测试。
开发难点:1、在话筒与听筒均开启的情况下,进入话筒的声音无法直接从听筒发出,需要做相关转换输出处理;
2、时间任务的启动与停止;
3、时间设置与数据类型的转换。
解决方法:1、引入音频缓冲区作为音频接收与播放的中专(Buffer),以音频声音作为对象由缓冲区接收存储(音频录制),以缓冲区的对象作为播放对象由听筒播放出来;
2、将麦克风开启方法以线程体来定义和调用;
3、以EditText作为时间输入的控件来设置测试时长,并前值转换为长整型。
以下是代码:
主类:AndroidMikeTestActivity.java
package com.cfzz.amt; import com.android.methed.Run_Methed; import android.os.Bundle; import android.app.Activity; import android.view.KeyEvent; import android.view.View; import android.widget.Button; import android.view.View.OnClickListener; import android.widget.EditText; import android.widget.TextView; import android.view.WindowManager; import android.os.SystemClock; import android.widget.Chronometer; import java.util.Timer; import java.util.TimerTask; public class AndroidMikeTestActivity extends Activity implements OnClickListener { Run_Methed run_Metned = new Run_Methed(); Thread thread = null; private EditText timelength; Button playbutton, stopbutton; private Timer timer; private Chronometer time; private long recordingTime = 0; public void onRecordStart()// time start { time.setBase(SystemClock.elapsedRealtime() - recordingTime);// 跳过已经记录了的时间,起到继续计时的作用 time.start(); } public void onRecordPause()// time pause { time.stop(); recordingTime = SystemClock.elapsedRealtime() - time.getBase();// 保存这次记录了的时间 } public void onRecordStop()// time stop { recordingTime = 0; time.setBase(SystemClock.elapsedRealtime()); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); timelength = (EditText) this.findViewById(R.id.timelength); timelength.setText("0"); time = (Chronometer) this.findViewById(R.id.chronometer);//引入计时器控件 time.setBase(SystemClock.elapsedRealtime());//初始化时间 // 按键监听 playbutton = (Button) findViewById(R.id.playbutton); stopbutton = (Button) findViewById(R.id.stopbutton); playbutton.setOnClickListener(this); stopbutton.setOnClickListener(this); } public void onClick(View v) { switch (v.getId()) { case R.id.playbutton: // 按钮【开】 long t = Long.parseLong("" + timelength.getText());//以小时为单位设置时间 if (t != 0) { Thread thread = new Thread(run_Metned);//将麦克风开启方法加入线程体中 thread.start(); onRecordStart(); long s = 1000 * 3600 * t ;//将小时数转化为毫秒数 timer = new Timer(true); TimerTask task = new TimerTask()// 计时任务设置 { public void run() { run_Metned.no(); onRecordPause(); timer.cancel(); } }; timer.schedule(task, s, 1);//s毫秒后停止 } else if (t == 0) { run_Metned.no(); } else if (timelength.getText() == null) { run_Metned.no(); timelength.setText("0"); } break; case R.id.stopbutton: // 按钮【关】 run_Metned.no(); timer.cancel(); onRecordStop(); onRecordPause(); timelength.setText("0"); break; } } int i = 0; public boolean onKeyDown(int keyCode, KeyEvent event) //双击返回键退出
{ if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) { long t = Long.parseLong("" + timelength.getText()); i++; if (i == 2 && t != 0) { run_Metned.no(); timer.cancel(); onRecordStop(); onRecordPause(); } if (i == 3) { finish(); } } return true; } /* * @Override protected void onDestroy() { * * thread.interrupt(); run_Metned.no(); timer.cancel(); onRecordStop(); * super.onDestroy(); } */ }方法类:
Run_Methed.java
package com.android.methed; import android.media.AudioFormat; import android.media.AudioManager; import android.media.AudioRecord; import android.media.AudioTrack; import android.media.MediaRecorder; public class Run_Methed implements Runnable { // 是否录放的标记 boolean isRecording = false; static final int frequency = 44100; @SuppressWarnings("deprecation") static final int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO; static final int audioEncoding = AudioFormat.ENCODING_PCM_16BIT; // 定义录放音缓冲区大小 int recBufSize, playBufSize; // 实例化录音对象 AudioRecord audioRecord; // 实例化播放对象 AudioTrack audioTrack; public Run_Methed() { // 调用getMinBufferSize方法获得录音的最小缓冲空间 recBufSize = AudioRecord.getMinBufferSize(frequency, channelConfiguration, audioEncoding); // 调用getMinBufferSize方法获得放音最小的缓冲区大小 playBufSize = AudioTrack.getMinBufferSize(frequency, channelConfiguration, audioEncoding); // -----------------------------------------、 // 调用构造函数实例化录音对象 audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, frequency, channelConfiguration, audioEncoding, recBufSize); // 调用构造函数实例化放音对象,以听筒模式播放 audioTrack = new AudioTrack(AudioManager.<span style="background-color: rgb(51, 204, 255);">STREAM_VOICE_CALL</span>, frequency, channelConfiguration, audioEncoding, playBufSize, AudioTrack.MODE_STREAM); } // 线程体 public void run() { try { byte[] buffer = new byte[recBufSize]; audioRecord.startRecording();// 开始录制 audioTrack.play();// 开始播放 this.isRecording = true; while (isRecording) { // 从MIC保存数据到缓冲区 int bufferReadResult = audioRecord.read(buffer, 0, recBufSize); byte[] tmpBuf = new byte[bufferReadResult]; System.arraycopy(buffer, 0, tmpBuf, 0, bufferReadResult); // 写入数据就播放 audioTrack.write(tmpBuf, 0, tmpBuf.length); } audioTrack.stop(); audioRecord.stop(); } catch (Throwable t) { } } // 停止方法 public void no() { isRecording = false; } }
Track_Methed,java
package com.android.methed; import android.media.AudioFormat; import android.media.AudioManager; import android.media.AudioTrack; public class Track_Methed implements Runnable { // 播放暂存 int out_size; // 放音对象 AudioTrack track = null; public void run() { } // 播送方法 public void track() { out_size = android.media.AudioTrack.getMinBufferSize(8000, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT); track = new AudioTrack(AudioManager.STREAM_VOICE_CALL, 8000, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, out_size, AudioTrack.MODE_STREAM); } }布局文件:
main.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:layout_marginTop="24dp" android:text="测试时间(小时/H)" android:textAppearance="?android:attr/textAppearanceLarge" android:textSize="12pt" /> <EditText android:id="@+id/timelength" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_below="@+id/textView1" android:layout_marginTop="20dp"
<!-- 未输入值时会显示的内容,作为输入提示--> android:hint="请输入测试小时数!" android:layout_gravity="center_horizontal" android:textSize="12pt"
<!-- 限定输入值为整数 --> android:inputType="number" android:singleLine="true" /> <Button android:id="@+id/playbutton" android:layout_width="100dip" android:layout_height="60dip" android:layout_below="@+id/timelength" android:layout_marginTop="120dp" android:onClick="onClick" android:text="@string/playbutton" android:textSize="12pt" /> <Button android:id="@+id/stopbutton" android:layout_width="100dip" android:layout_height="60dip" android:layout_alignBaseline="@+id/playbutton" android:layout_alignBottom="@+id/playbutton" android:layout_alignParentRight="true" android:onClick="onClick" android:text="@string/stopbutton" android:textSize="12pt" /> <Chronometer android:id="@+id/chronometer" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_above="@+id/stopbutton" android:layout_centerHorizontal="true" android:layout_marginBottom="28dp" android:format="%s" android:textColor="#00FF00" android:textSize="80px" /> </RelativeLayout>AndroidManifest.xml
注意添加相关权限
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.cfzz.amt" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="15" /> <span style="background-color: rgb(102, 255, 255);"><uses-permission android:name="android.permission.RECORD_AUDIO" /></span> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <activity android:name="org.achartengine.GraphicalActivity" /> <activity android:name="com.cfzz.amt.AndroidMikeTestActivity" android:screenOrientation="portrait" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>运行效果图:
到此,麦克风测试程序就可以运行了,在编辑框内输入小时数,再点击开始即可运行麦克风,这时可以从听筒中听到麦克风里的声音,当时间到达设定时间时会自动停止,同时计时器也会暂停。当按停止按钮时,时间设置和计时器会同时置为00:00,以便新的测试。
相关文章推荐
- 九、使用Maven创建Web应用程序项目
- java程序员第十课 javaweb之request&response
- iOS日期的比较
- STM32 USB OTG官方库移植
- php 乱码解决
- CMapStringToPtr添加与释放
- u3d性能优化
- android游戏开发初学之SurfaceView绘制界面
- SQLSERVER 获取手机号码归属地
- 程序启动原理
- Ⅰ.2.6.3.3 如何测试 QTableWidgets 中的 Items
- android Toast大全(五种情形)建立属于你自己的Toast
- 设置dialog的大小,位置
- 【黑马程序员】C语言—推箱子游戏实现
- POJ 3617 Best Cow Line(贪心,字典序比较)
- 安装mongodb centos6.5 x86_64
- objective-c 中3种随机数的用法:arc4random( ) random( ) CCRANDOM_0_1( )
- RPG游戏(一)——环境搭建、地图显示
- 封装常用的js(Base.js)——【01】理解库,获取节点,连缀,
- java中接口