由音量来决定保存录音和播放

 

具体描述:功能启动后,一直处于录音状态。当玩家对着手机说话(即音量大于某个值),则开始保存玩家说的话;当一段时间之后,玩家不再说话(音量小于某个值),则停止保存音频,并开始播放(即播放玩家说过的话)。

 

public class MainActivity extends Activity {
 
    private short[] mAudioRecordData;	// 录音数据
    private short[] mAudioTrackData;	// 播放数据
 
    private File mAudioFile;	// 录音文件
    private AudioRecord mAudioRecord;	// 录音对象
    private AudioTrack mAudioTrack;	// 播放对象
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        init();
        InitDB();
    }
 
//初始化
    private void init() {
        if (Environment.getExternalStorageState().equals(
                Environment.MEDIA_MOUNTED)) {
            File file = new File(Environment.getExternalStorageDirectory()
                    .getAbsolutePath() + "/audio/");
            if (!file.exists()) {
                file.mkdirs();
            }
            //创建录音文件
            mAudioFile = new File(file, System.currentTimeMillis() + ".pcm");
        }
 
        try {
//            int sampleRateInHz = 44100;//所有Android系统都支持的频率
            int sampleRateInHz = 8000;
            
            //AudioFormat.CHANNEL_IN_MONO单声道输入    AudioFormat.ENCODING_PCM_16BIT这个所有Android系统都支持
            	// 创建AudioRecord实例,用于录音
            int recordBufferSizeInBytes = AudioRecord.getMinBufferSize(
                    sampleRateInHz, AudioFormat.CHANNEL_IN_MONO,
                    AudioFormat.ENCODING_PCM_16BIT);
            Log.d("TAG", "recordBufferSizeInBytes=" + recordBufferSizeInBytes);
            mAudioRecordData = new short[recordBufferSizeInBytes];
             
            mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC,
                    sampleRateInHz, AudioFormat.CHANNEL_IN_MONO,
                    AudioFormat.ENCODING_PCM_16BIT, recordBufferSizeInBytes);
            	
            	// 创建mAudioTrack实例,用于播放
            int trackBufferSizeInBytes = AudioRecord.getMinBufferSize(
                    sampleRateInHz, AudioFormat.CHANNEL_IN_MONO,
                    AudioFormat.ENCODING_PCM_16BIT);
            mAudioTrackData = new short[trackBufferSizeInBytes];
            mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
                    sampleRateInHz, AudioFormat.CHANNEL_OUT_MONO,
                    AudioFormat.ENCODING_PCM_16BIT, trackBufferSizeInBytes,
                    AudioTrack.MODE_STREAM);
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        }
 
    }
    
//  AudioRecord:实时获取分贝
	private static final String TAG = "AudioRecord";
	boolean isGetVoiceRun;
	Object mLock;
	double volume = 0;	// 音量,单位为分贝
	// 平方和除以数据总长度,得到音量大小。
	double mean;

	private boolean isNeedRecord = false; // 标记是否需要存储录制数据
	private boolean isPlaying = false; // 标记是否正在播放
	private boolean isRestart = false;
	Timer mTimer1;
	private boolean isStartVolumeTimer = false;

	public void InitDB() {
		mLock = new Object();
		
		getNoiseLevel();

	}
		// 获取音量,并根据音量来决定是否保存录音到文件和播放已保存的文件
	public void getNoiseLevel() {
		
		if (mAudioRecord == null) {
			Log.e("sound", "mAudioRecord初始化失败");
		}
		isGetVoiceRun = true;

		new Thread(new Runnable() {
			@Override
			public void run() {
				
				mAudioRecord.startRecording();	// 开始录音
				boolean isFirstStart = true;	// 避免第一次的高分贝
				
				try {
					DataOutputStream dos = new DataOutputStream(
					        new BufferedOutputStream(
					                new FileOutputStream(mAudioFile)));
					
					while (isGetVoiceRun) {
							// 如果正在播放,等一小段时间后再继续判断
						if(isPlaying){
							synchronized (mLock) {
								try {
									isRestart = true;
									mLock.wait(100);
									continue;
								} catch (InterruptedException e) {
									e.printStackTrace();
								}
							}
						}
						
						if(isRestart){
							isRestart =	false;
							
//							mAudioRecord.startRecording();	// 开始录音
							dos = new DataOutputStream(
							        new BufferedOutputStream(
							                new FileOutputStream(mAudioFile)));
						}
						
						
						
						// r是实际读取的数据长度,一般而言r会小于buffersize
						int r = mAudioRecord.read(mAudioRecordData, 0, mAudioRecordData.length);	// 
						long v = 0;
						// 将 buffer 内容取出,进行平方和运算
						for (int i = 0; i < mAudioRecordData.length; i++) {
							v += mAudioRecordData[i] * mAudioRecordData[i];
						}
						
						// 避开第一次的高分贝(来源不清楚)
						if(isFirstStart){
							isFirstStart = false;
							continue;
						}
						
						// 平方和除以数据总长度,得到音量大小。
						mean = v / (double) r;
						
							// 如果正在录音,间隔一段时间再修改volume的值
				        if(isNeedRecord){
				        	if(!isStartVolumeTimer){
				        		isStartVolumeTimer = true;
					        	
				        		mTimer1 = new Timer();
								TimerTask mTask1 = new TimerTask() {
						            @Override
						            public void run() {
						            	volume = 10 * Math.log10(mean);
						            }
						        };
						        mTimer1.schedule(mTask1, 2000, 1000);
				        	}
					        
				        }else{
				        	volume = 10 * Math.log10(mean);
				        }
				        Log.d(TAG, "分贝值:" + volume);
						
						
						// 如果音量大于某个值,则把录制的数据存到文件中
						if(volume >= 65){
							if(!isNeedRecord){
								Log.i("apple", "开始存储录制数据StartRecord");
								isNeedRecord = true;
							}
							
							StartRecord(dos, r, mAudioRecordData);
						}
						
						// 如果音量小于某个值,且正在录制,则结束录制并开始播放
						if(volume< 65 && isNeedRecord){
							Log.i("apple", "结束存储录制数据");
							isNeedRecord = false;
//							mAudioRecord.stop();
							try {
								dos.flush();
								dos.close();
							} catch (IOException e) {
								e.printStackTrace();
							}
							mTimer1.cancel();
							isStartVolumeTimer = false;
							
							PlayAudio();
						}
							
						
//						// 大概一秒两次
//						synchronized (mLock) {
//							try {
//								mLock.wait(100);
//							} catch (InterruptedException e) {
//								e.printStackTrace();
//							}
//						}
					}
					
				} catch (FileNotFoundException e1) {
					e1.printStackTrace();
				}
				
				mAudioRecord.stop();
				mAudioRecord.release();
				mAudioRecord = null;
				Log.i("apple", "停止-AudioRecord");
			}
		}).start();
	}

	//把录制的数据存在mAudioFile文件中
	private void StartRecord(DataOutputStream dos,int number, short[] buffer) {
//		Log.i("apple", "存储录制数据StartRecord");
        try {
        	
            for (int i = 0; i < number; i++) {
                dos.writeShort(buffer[i]);
            }
            
        } catch (IOException e) {
            e.printStackTrace();
        }
	}
		// 播放录制的音频文件
	private void PlayAudio() {
		Log.i("apple", "开始播放");
		isPlaying = true;
		new Thread(new Runnable() {
            public void run() {
                try {
                	
//                	try {
//						Thread.sleep(100);
//					} catch (InterruptedException e) {
//						e.printStackTrace();
//					}
                	
                    mAudioTrack.play();
                    DataInputStream dis = new DataInputStream(
                            new BufferedInputStream(
                                    new FileInputStream(mAudioFile)));
                    Log.d("TAG", "dis.available=" + dis.available());
                    while (mAudioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING
                            && dis.available() > 0) {
                        int i = 0;
                        while (dis.available() > 0
                                && i < mAudioTrackData.length) {
                            mAudioTrackData[i] = dis.readShort();
                            i++;
                        }
                        wipe(mAudioTrackData, 0, mAudioTrackData.length);
                        // 然后将数据写入到AudioTrack中
                        mAudioTrack.write(mAudioTrackData, 0,
                                mAudioTrackData.length);
                    }
                    mAudioTrack.stop();
                    dis.close();
                    isPlaying = false;
                    Log.i("apple", "结束播放");
                    
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
	}  
  
	 
    /**
     * 消除噪音
     */
    private void wipe(short[] lin, int off, int len) {
        int i, j;
        for (i = 0; i < len; i++) {
            j = lin[i + off];
            lin[i + off] = (short) (j >> 2);
        }
    }
 
    @Override
    protected void onStop() {
        if (mAudioFile.exists()) {
            mAudioFile.delete();
        }
        if (mAudioRecord != null) {
            mAudioRecord.release();
            mAudioRecord = null;
        }
        if (mAudioTrack != null) {
            mAudioTrack.release();
            mAudioTrack = null;
        }
        super.onStop();
    }
}

其中,录音与播放部分参考了链接:https://www.2cto.com/kf/201704/636266.html

获取音量部分参考了链接的AudioRecord部分:https://blog.csdn.net/greatpresident/article/details/38402147

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值