Android录音并播放(mp3或amr格式)

Android项目中媒体是很多人头疼的一个问题,不仅仅因为处理起来很麻烦,而且不同的手机差别很大(和硬件,系统都有关系),今天就总结一下Android中的录音和播放,可保存成mp3或amr格式。

小米1s,三星,酷派8721移动版 测试通过

1、首先说一下amr格式和mp3格式的区别

----------------------------------------------------------------------------------------------

amr由欧洲通信标准化委员会提出,是在移动通信系统中使用最广泛的语音标准。它是被各大手机厂商认可的一种保存手机录音的格式。由于amr文件容量很小,因此即便是长达一分钟的音频文件,也能符合中国移动现行的彩信不超过50KB容量的技术规范,所以amr也是实现在彩信中加载人声的唯一格式。但是受体积所限,amr在音质方面不太乐观。


mp3是一个实用的有损音频压缩编码,以此获得较高的压缩和较小的体积。


所以录音优先选择amr格式,微信生成的语音文件就是amr格式的。


2、录音播放的步骤

---------------------------------------------------------------------------------------

Android api中可以录音并播放的类主要有2个,一个是AudioRecord,另一个是MediaRecorder,这篇文章我们用AudioRecord,至于他们的区别,在什么情况下用那个,大家可以自行百度。

  1)实例化一个AudioRecord

  2)设置录音频率,录制通道,编码格式等参数

  3)设置录制缓存区大小

  4)创建一个文件,用于保存录制的内容

  5)打开一个流,指向创建的文件

  6)开始录制


先定义一些音频录制的参数

private boolean isRecording = true, isPlaying = false; // 标记
private int frequence = 16000;// 8000;
private int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO;
private int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;
在录制之前,先要判断一个sd卡是否存在:

if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))// 手机有SD卡的情况
		{
			// 在这里我们创建一个文件,用于保存录制内容
			fpath = new File(Environment.getExternalStorageDirectory()
					.getAbsolutePath() + "/test_record/");
			fpath.mkdirs();// 创建文件夹
		} else// 手机无SD卡的情况
		{
			//返回在文件系统上应用程序特定的缓存目录的绝对路径
			fpath = this.getCacheDir();
		}

		try {
			// 创建临时文件,注意这里的格式为.pcm  .amr  .mp3
			audioFile = File.createTempFile("recording", ".amr", fpath);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}


这儿我们将事先定义好的参数作为AudioRecord的构造方法的参数传递进去,你也可以先new一个AudioRecord对象,然后设置它的录制参数。

class RecordTask extends AsyncTask {
		@Override
		protected Void doInBackground(Void... arg0) {
			isRecording = true;
			try {
				// 开通输出流到指定的文件
				DataOutputStream dos = new DataOutputStream(
						new BufferedOutputStream(
								new FileOutputStream(audioFile)));
				// 根据定义好的几个配置,来获取合适的缓冲大小
				int bufferSize = AudioRecord.getMinBufferSize(frequence,
						channelConfig, audioEncoding);
				// 实例化AudioRecord
				AudioRecord record = new AudioRecord(
						MediaRecorder.AudioSource.MIC, frequence,
						channelConfig, audioEncoding, bufferSize);
				// 定义缓冲
				short[] buffer = new short[bufferSize];

				// 开始录制
				record.startRecording();

				int r = 0; // 存储录制进度
				// 定义循环,根据isRecording的值来判断是否继续录制
				while (isRecording) {
					// 从bufferSize中读取字节,返回读取的short个数
					// 这里老是出现buffer overflow,不知道是什么原因,试了好几个值,都没用,TODO:待解决
					int bufferReadResult = record
							.read(buffer, 0, buffer.length);
					// 循环将buffer中的音频数据写入到OutputStream中
					for (int i = 0; i < bufferReadResult; i++) {
						dos.writeShort(buffer[i]);
					}
					publishProgress(new Integer(r)); // 向UI线程报告当前进度
					r++; // 自增进度值
				}
				// 录制结束
				record.stop();
				Log.v("The DOS available:", "::" + audioFile.length());
				dos.close();
			} catch (Exception e) {
				// TODO: handle exception
			}
			return null;
		}

		// 当在上面方法中调用publishProgress时,该方法触发,该方法在I线程中被执行
		protected void onProgressUpdate(Integer... progress) {
			stateView.setText(progress[0].toString());
		}

		protected void onPostExecute(Void result) {
			btnStop.setEnabled(false);
			btnStart.setEnabled(true);
			btnPlay.setEnabled(true);
			btnFinish.setEnabled(false);
		}

		protected void onPreExecute() {
			// stateView.setText("正在录制");
			btnStart.setEnabled(false);
			btnPlay.setEnabled(false);
			btnFinish.setEnabled(false);
			btnStop.setEnabled(true);
		}

	}

将音频录制的过程放到线程中取执行,然后更新ui给用户。接下来就是播放了,仍然在线程中播放

class PlayTask extends AsyncTask {
		@Override
		protected Void doInBackground(Void... arg0) {
			isPlaying = true;
			int bufferSize = AudioTrack.getMinBufferSize(frequence,
					channelConfig, audioEncoding);
			short[] buffer = new short[bufferSize / 4];
			try {
				// 定义输入流,将音频写入到AudioTrack类中,实现播放
				DataInputStream dis = new DataInputStream(
						new BufferedInputStream(new FileInputStream(audioFile)));
				// 实例AudioTrack
				AudioTrack track = new AudioTrack(AudioManager.STREAM_MUSIC,
						frequence, channelConfig, audioEncoding, bufferSize,
						AudioTrack.MODE_STREAM);
				// 开始播放
				track.play();
				// 由于AudioTrack播放的是流,所以,我们需要一边播放一边读取
				while (isPlaying && dis.available() > 0) {
					int i = 0;
					while (dis.available() > 0 && i < buffer.length) {
						buffer[i] = dis.readShort();
						i++;
					}
					// 然后将数据写入到AudioTrack中
					track.write(buffer, 0, buffer.length);

				}

				// 播放结束
				track.stop();
				dis.close();
			} catch (Exception e) {
				// TODO: handle exception
			}
			return null;
		}

		protected void onPostExecute(Void result) {
			btnPlay.setEnabled(true);
			btnFinish.setEnabled(false);
			btnStart.setEnabled(true);
			btnStop.setEnabled(false);
		}

		protected void onPreExecute() {
			btnStart.setEnabled(false);
			btnStop.setEnabled(false);
			btnPlay.setEnabled(false);
			btnFinish.setEnabled(true);
		}
	}

到此一个音频录制,播放的demo就完成了,在对amr和mp3的格式进行比较时,分别录制了2段10分钟的视频,但是发现他们的大小是一样的?这就和我们上面说的矛盾了?其实不是,检查整个过程发现,生成音频文件的代码都是一样的,只是最终保存的格式不一样,它的大小肯定是一样的了,至于amr的文件的生成规则,没有做进一步的研究,但是肯定的是用它独特的方法生成的音频文件肯定要小,不然微信的录音也不会用amr的格式了。如果有人知道的话可以贴出来给大家分享。

你可能感兴趣的:(android)