Android多媒体五:MediaRecorder录制音频

Android多媒体五:MediaRecorder录制音频

Android手机一般都提供麦克风的硬件,而Android系统可以利用该硬件来录制音频。
为了在Android应用中录制音频,Android提供了MediaRecorder类,使用MediaRecorder录制音频的过程很简单,步骤如下:

1:创建MediaRecorder对象;
2:调用MediaRecorder对象的setAudioSource()方法设置声音来源,一般传入MediaRecorder.AudioSource.MIC参数指定录制来自麦克风的声音;
3:调用MediaRecorder对象的setOutputFormat()方法设置所录制的音频文件格式;
4:调用MediaRecorder对象的setAudioEncoder()、setAudioEncodingBitRate(int bitRate)、setAudioSamplingRate(int samplingRate)方法设置所录制的声音编码格式、编码位率、采样率等,这些参数将可以控制所录制的声音品质、文件大小。一般来说,声音品质越好,声音文件越大;
5:调用MediaRecorder的setOutputFile(String path)方法设置所录制的音频文件的保存位置;
6:调用MediaRecorder的prepare()方法准备录制;
7:调用MediaRecorder对象的start()方法开始录制。
实例:录制音频

app/src/main/AndroidManifest.xml

	    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
		<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
		<uses-permission android:name="android.permission.RECORD_AUDIO"/>

res/anim/rote.xml

		<?xml version="1.0" encoding="utf-8"?>
		<set xmlns:android="http://schemas.android.com/apk/res/android">
			<rotate
				android:duration="1000"
				android:fromDegrees="0"
				android:interpolator="@android:anim/accelerate_decelerate_interpolator"
				android:pivotX="50%"
				android:pivotY="50%"
				android:repeatCount="-1"
				android:toDegrees="-360" />
		</set>

com/example/administrator/MainActivity.java

		package com.example.administrator;

		import android.Manifest;
		import android.media.MediaPlayer;
		import android.media.MediaRecorder;
		import android.os.Environment;
		import android.support.v7.app.AppCompatActivity;
		import android.os.Bundle;
		import android.view.View;
		import android.view.animation.Animation;
		import android.view.animation.AnimationUtils;
		import android.widget.Button;
		import android.widget.ImageView;
		import android.widget.Toast;

		import com.example.administrator.Permission.PermissionManager;

		import java.io.File;
		import java.io.IOException;
		import java.security.Permission;

		public class MainActivity extends AppCompatActivity implements View.OnClickListener, PermissionManager.PermissionsResultListener {
			// 定义界面的两个按钮
			Button record, stop;
			// 系统的音频文件
			File soundFile;
			MediaRecorder mRecorder;
			private Button play;
			private ImageView iv;
			private Animation animation;

			@Override
			protected void onCreate(Bundle savedInstanceState) {
				super.onCreate(savedInstanceState);
				setContentView(R.layout.activity_main);
				//权限申请
				PermissionManager.requestPermission(this, "读写SD卡", 0, this, Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.RECORD_AUDIO);
				// 获取程序界面中的两个按钮
				record = findViewById(R.id.record);
				stop = findViewById(R.id.stop);
				play = findViewById(R.id.play);
				iv = findViewById(R.id.iv);
				// 为两个按钮的单击事件绑定监听器
				record.setOnClickListener(this);
				stop.setOnClickListener(this);
				play.setOnClickListener(this);

				//初始化动画
				animation = AnimationUtils.loadAnimation(this, R.anim.rote);
			}

			@Override
			public void onClick(View v) {
				// 单击录音按钮
				if (v.getId() == R.id.record) {
					if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
						Toast.makeText(this, "SD卡不存在,请插入SD卡!", Toast.LENGTH_SHORT).show();
						return;
					}
					try {
						// 创建保存录音的音频文件
						soundFile = new File(Environment.getExternalStorageDirectory().getCanonicalFile() + "/sound.mp3");
						mRecorder = new MediaRecorder();
						// 设置录音的声音来源
						mRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
						// 设置录制的声音的输出格式(必须在设置声音编码格式之前设置)
						mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
						// 设置声音编码格式
						mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
						mRecorder.setOutputFile(soundFile.getAbsolutePath());
						mRecorder.prepare();
						// 开始录音
						mRecorder.start();
						iv.startAnimation(animation);
					} catch (Exception e) {
						e.printStackTrace();
					}
				} else if (v.getId() == R.id.stop) {
					// 单击停止按钮
					if (soundFile != null && soundFile.exists()) {
						// 停止录音
						mRecorder.stop();
						// 释放资源
						mRecorder.release();
						mRecorder = null;
						iv.clearAnimation();
					}
				} else if (v.getId() == R.id.play) {
					try {
						MediaPlayer mMediaPlayer = new MediaPlayer();
						String path = Environment.getExternalStorageDirectory().getCanonicalFile() + "/sound.mp3";
						mMediaPlayer.setDataSource(path);
						mMediaPlayer.prepare();
						mMediaPlayer.start();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}

			@Override
			protected void onDestroy() {
				if (soundFile != null && soundFile.exists()) {
					// 停止录音
					mRecorder.stop();
					// 释放资源
					mRecorder.release();
					mRecorder = null;
				}
				if (animation != null) {
					iv.clearAnimation();
				}
				super.onDestroy();
			}

			@Override
			public void onPermissionGranted(int requestCode) {

			}

			@Override
			public void onPermissionDenied(int requestCode) {

			}
		}

com/example/administrator/Permission/PermissionManager.java

		package com.example.administrator.Permission;

		import android.app.Activity;
		import android.content.Context;
		import android.content.DialogInterface;
		import android.content.pm.PackageManager;
		import android.os.Build;
		import android.support.annotation.NonNull;
		import android.support.v4.app.ActivityCompat;
		import android.support.v4.app.Fragment;
		import android.support.v4.content.ContextCompat;
		import android.support.v7.app.AlertDialog;

		import java.util.concurrent.ConcurrentHashMap;

		/**
		 * @time 2017/2/20
		 * @fuction 动态权限管理封装类
		 * @use 1. 在BaseActivity和BaseFragment重写onRequestPermissionsResult ,并实现如下代码PermissionManager.onRequestResult(requestCode, permissions, grantResults);
		 * 2. 然后需要请求权限的时候调用requestPermission方法 即可
		 */
		public class PermissionManager {

			//维护的每个Activity的申请权限的监听
			//便于清除释放
			private static ConcurrentHashMap<Integer, PermissionsResultListener> mListenerMap = new ConcurrentHashMap<>();

			/**
			 * 权限申请
			 *
			 * @param context             Activity
			 * @param desc                再次申请权限的提示语
			 * @param requestCode
			 * @param permissionsListener
			 * @param permissions
			 */
			public static void requestPermission(Activity context,
												 String desc,
												 int requestCode,
												 PermissionsResultListener permissionsListener,
												 String... permissions) {
				if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
					mListenerMap.put(requestCode, permissionsListener);
					if (checkEachSelfPermission(context, permissions)) {
						requestEachPermission(context, desc, permissions, requestCode);
					} else {
						mListenerMap.get(requestCode).onPermissionGranted(requestCode);
					}
				}
			}

			/**
			 * 权限申请
			 *
			 * @param context             Fragment
			 * @param desc                再次申请权限的提示语
			 * @param requestCode
			 * @param permissionsListener
			 * @param permissions
			 */
			public static void requestPermission(Fragment context,
												 String desc,
												 int requestCode,
												 PermissionsResultListener permissionsListener,
												 String... permissions) {
				if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
					mListenerMap.put(requestCode, permissionsListener);

					if (checkEachSelfPermission(context.getActivity(), permissions)) {
						requestEachPermission(context, desc, permissions, requestCode);
					} else {
						mListenerMap.get(requestCode).onPermissionGranted(requestCode);
					}
				}
			}


			/**
			 * 权限请求
			 *
			 * @param context     Activity
			 * @param desc        再次申请权限的提示语
			 * @param permissions
			 * @param requestCode
			 */
			private static void requestEachPermission(final Activity context, String desc, final String[] permissions, final int requestCode) {
				if (shouldShowRequestPermissionRationale(context, permissions)) {
					AlertDialog.Builder builder = new AlertDialog.Builder(context);
					builder.setTitle("权限申请")
							.setMessage(desc)
							.setPositiveButton("确认", new DialogInterface.OnClickListener() {
								@Override
								public void onClick(DialogInterface dialogInterface, int i) {
									ActivityCompat.requestPermissions(context, permissions, requestCode);
								}
							})
							.setNegativeButton("取消", new DialogInterface.OnClickListener() {
								@Override
								public void onClick(DialogInterface dialogInterface, int i) {
									dialogInterface.dismiss();
								}
							})
							.setCancelable(false)
							.show();
				} else {
					ActivityCompat.requestPermissions(context, permissions, requestCode);
				}
			}

			/**
			 * 权限请求
			 *
			 * @param context     Fragment
			 * @param desc        再次申请权限的提示语
			 * @param permissions
			 * @param requestCode
			 */
			private static void requestEachPermission(final Fragment context, String desc, final String[] permissions, final int requestCode) {
				if (shouldShowRequestPermissionRationale(context, permissions)) {
					AlertDialog.Builder builder = new AlertDialog.Builder(context.getActivity());
					builder.setTitle("权限申请")
							.setMessage(desc)
							.setPositiveButton("确认", new DialogInterface.OnClickListener() {
								@Override
								public void onClick(DialogInterface dialogInterface, int i) {
									context.requestPermissions(permissions, requestCode);
								}
							})
							.setNegativeButton("取消", new DialogInterface.OnClickListener() {
								@Override
								public void onClick(DialogInterface dialogInterface, int i) {
									dialogInterface.dismiss();
								}
							})
							.setCancelable(false)
							.show();
				} else {
					context.requestPermissions(permissions, requestCode);
				}
			}

			/**
			 * 再次申请权限时,是否需要声明
			 *
			 * @param context     Activity
			 * @param permissions
			 * @return
			 */
			private static boolean shouldShowRequestPermissionRationale(Activity context, String[] permissions) {
				for (String permission : permissions) {
					if (ActivityCompat.shouldShowRequestPermissionRationale(context, permission)) {
						return true;
					}
				}
				return false;
			}


			/**
			 * 再次申请权限时,是否需要声明
			 *
			 * @param context     Fragment
			 * @param permissions
			 * @return
			 */
			private static boolean shouldShowRequestPermissionRationale(Fragment context, String[] permissions) {
				for (String permission : permissions) {
					if (context.shouldShowRequestPermissionRationale(permission)) {
						return true;
					}
				}
				return false;
			}


			/**
			 * 检察每个权限是否申请
			 *
			 * @param permissions
			 * @return true 需要申请权限,false 已申请权限
			 */
			private static boolean checkEachSelfPermission(Context context, String[] permissions) {
				for (String permission : permissions) {
					if (ContextCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
						return true;
					}
				}
				return false;
			}

			/**
			 * 权限申请处理回调
			 * 写在Activity或者Fragment的onRequestPermissionsResult 方法内
			 *
			 * @param requestCode
			 * @param permissions
			 * @param grantResults
			 */
			public static void onRequestResult(int requestCode,
											   @NonNull String[] permissions,
											   @NonNull int[] grantResults) {
				PermissionsResultListener permissionsResultListener = mListenerMap.get(requestCode);
				if (permissionsResultListener == null) {
					return;
				}
				if (grantResults.length > 0 &&
						grantResults[0] == PackageManager.PERMISSION_GRANTED) {
					permissionsResultListener.onPermissionGranted(requestCode);
				} else {
					permissionsResultListener.onPermissionDenied(requestCode);
				}
			}

			/**
			 * 清除掉已用完的Listner
			 */
			public static void clearListner(int requestCode) {
				if (mListenerMap.get(requestCode) != null) {
					mListenerMap.remove(requestCode);
				}
			}


			public interface PermissionsResultListener {

				/**
				 * 权限申请成功回调
				 */
				void onPermissionGranted(int requestCode);

				/**
				 * 权限申请失败回调
				 */
				void onPermissionDenied(int requestCode);
			}

			/**
			 * 危险权限 授权一个就等于同组都授权了
			 * Manifest.permission.XXX
			 *
			 * group:android.permission-group.CONTACTS
			 permission:android.permission.WRITE_CONTACTS
			 permission:android.permission.GET_ACCOUNTS
			 permission:android.permission.READ_CONTACTS

			 group:android.permission-group.PHONE
			 permission:android.permission.READ_CALL_LOG
			 permission:android.permission.READ_PHONE_STATE
			 permission:android.permission.CALL_PHONE
			 permission:android.permission.WRITE_CALL_LOG
			 permission:android.permission.USE_SIP
			 permission:android.permission.PROCESS_OUTGOING_CALLS
			 permission:com.android.voicemail.permission.ADD_VOICEMAIL

			 group:android.permission-group.CALENDAR
			 permission:android.permission.READ_CALENDAR
			 permission:android.permission.WRITE_CALENDAR

			 group:android.permission-group.CAMERA
			 permission:android.permission.CAMERA

			 group:android.permission-group.SENSORS
			 permission:android.permission.BODY_SENSORS

			 group:android.permission-group.LOCATION
			 permission:android.permission.ACCESS_FINE_LOCATION
			 permission:android.permission.ACCESS_COARSE_LOCATION

			 group:android.permission-group.STORAGE
			 permission:android.permission.READ_EXTERNAL_STORAGE
			 permission:android.permission.WRITE_EXTERNAL_STORAGE

			 group:android.permission-group.MICROPHONE
			 permission:android.permission.RECORD_AUDIO

			 group:android.permission-group.SMS
			 permission:android.permission.READ_SMS
			 permission:android.permission.RECEIVE_WAP_PUSH
			 permission:android.permission.RECEIVE_MMS
			 permission:android.permission.RECEIVE_SMS
			 permission:android.permission.SEND_SMS
			 permission:android.permission.READ_CELL_BROADCASTS
			 */

		}
参考链接http://www.cnblogs.com/Amandaliu/archive/2013/02/04/2891604.html 在链接内容基础上修改了amr编码格式为aac编码格式 Android提供了两个API用于实现录音功能:android.media.AudioRecord、android.media.MediaRecorder。 网上有很多谈论这两个类的资料。现在大致总结下: 1、AudioRecord 主要是实现边录边播(AudioRecord+AudioTrack)以及对音频的实时处理(如会说话的汤姆猫、语音) 优点:语音的实时处理,可以用代码实现各种音频的封装 缺点:输出是PCM语音数据,如果保存成音频文件,是不能够被播放器播放的,所以必须先写代码实现数据编码以及压缩 示例: 使用AudioRecord类录音,并实现WAV格式封装。录音20s,输出的音频文件大概为3.5M左右(已写测试代码) 2、MediaRecorder 已经集成了录音、编码、压缩等,支持少量的录音音频格式,大概有.aac(API = 16) .amr .3gp 优点:大部分以及集成,直接调用相关接口即可,代码量小 缺点:无法实时处理音频;输出的音频格式不是很多,例如没有输出mp3格式文件 示例: 使用MediaRecorder类录音,输出amr格式文件。录音20s,输出的音频文件大概为33K(已写测试代码) 3、音频格式比较 WAV格式:录音质量高,但是压缩率小,文件大 AAC格式:相对于mp3,AAC格式的音质更佳,文件更小;有损压缩;一般苹果或者Android SDK4.1.2(API 16)及以上版本支持播放 AMR格式:压缩比比较大,但相对其他的压缩格式质量比较差,多用于人声,通话录音 至于常用的mp3格式,使用MediaRecorder没有该视频格式输出。一些人的做法是使用AudioRecord录音,然后编码成wav格式,再转换成mp3格式 再贴上一些测试工程。 功能描述: 1、点击“录音WAV文件”,开始录音。录音完成后,生成文件/sdcard/FinalAudio.wav 2、点击“录音AMR文件”,开始录音。录音完成后,生成文件/sdcard/FinalAudio.amr 3、点击“停止录音”,停止录音,并显示录音输出文件以及该文件大小。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值