您的位置:首页 > 其它

简介录音和播放音频实现

2014-04-26 00:48 387 查看
1.MediaRecorder及MediaPlayer:

MediaRecorder类父类是object,位于media包下,是用来录制音频和视频。

下面是录音模型:



看起来很是复杂的样子,当然了解下流程还是有必要的。至少你知道如果想重新初始化的话,可以直接使用 reset()方法,不管在哪个阶段都可以重置,有图有真相是吧!

其他的话,也没啥说的,流程都是规范化了的,改动的空间不大,看api好了。

MediaPlayer也位于media包下,直接继承与object类,可以用来放音频/视频的文件和流。

下面是工作流程:



看起来比录音的流程更复杂了,更深的东西我们暂时就不深究了。相对于录音来说,主要多了暂停,回放的状态,方法中更是添加了循环,进度等东西,更多的就不说了,有兴趣的童鞋可以慢慢研究,可以对下面的实例进行扩展。

首先,我对功能进行了封装。

/**
 * 录音的类,封装了录音/播放的开始停止功能
 */
public class MyRecord {
	/** 录音 */
	private MediaRecorder mRecorder;
	/** 播放 */
	private MediaPlayer mPlayer;

	private String path = "";
	public static MyRecord myRecord = null;
	// 单例
	private MyRecord() {
		mkMyDir();
	};

	public static synchronized MyRecord getInstance() {
		if (myRecord == null) {
			myRecord = new MyRecord();
		}
		return myRecord;
	}

	// 在sdcard上创建文件夹
	public void mkMyDir() {
		File dir = new File(Environment.getExternalStorageDirectory()
				.getAbsolutePath() + "/TestRecord");
		path = dir.getAbsolutePath();
		dir.mkdir();
	}

	// 获取文件夹路径
	public String getPath() {
		return path;
	}

	// 开始录音
	public void startRecord(String filePath) {
		mRecorder = new MediaRecorder();
		mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
		mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
		mRecorder.setOutputFile(filePath);
		mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
		// 设定录音文件大小 ,大概是1s 就是1k的大小
		// mRecorder.setMaxFileSize(10 * 1024);
		// 设定录音的最大时长,貌似这个跟上面的数据差距有点大 ,最大得到的数据是17k多的数据
		// mRecorder.setMaxDuration(10 * 1000);
		try {
			mRecorder.prepare();
		} catch (IllegalStateException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		mRecorder.start();
	}

	// 停止录音
	public void stopRecord() {
		mRecorder.stop();
		mRecorder.release();
		mRecorder = null;
	}

	// 播放录音
	public void startPlay(String fileName) {
		mPlayer = new MediaPlayer();
		try {
			mPlayer.setDataSource(fileName);
			mPlayer.prepare();
			mPlayer.start();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	// 停止播放
	public void stopPlay() {
		mPlayer.stop();
		mPlayer.release();
		mPlayer = null;
	}
}


使用单例,只有一个实例,避免了冗余。文件的路径,其实应该是提供接口的,想想觉得固定了好点,提供给外面的路径就好了。

然后是使用了:

public class TestVoice extends Activity implements OnClickListener {
	private Button startR;
	private Button stopR;
	private Button startP;
	private Button stopP;

	private MyRecord myRecord;
	private String path = "/test.3gp";

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		setContentView(R.layout.acy_testvoice);
		initView();
	}

	public void initView() {
		myRecord = MyRecord.getInstance();
		path = myRecord.getPath() + path;

		startR = (Button) findViewById(R.id.startRecord);
		stopR = (Button) findViewById(R.id.stopRecord);
		startP = (Button) findViewById(R.id.startPlay);
		stopP = (Button) findViewById(R.id.stopPlay);

		startR.setOnClickListener(this);
		stopR.setOnClickListener(this);
		startP.setOnClickListener(this);
		stopP.setOnClickListener(this);
	}

	@Override
	public void onClick(View v) {
		// TODO Auto-generated method stub
		if (v == startR) {
			myRecord.startRecord(path);
		} else if (v == stopR) {
			myRecord.stopRecord();
		} else if (v == startP) {
			myRecord.startPlay(path);
		} else if (v == stopP) {
			myRecord.stopPlay();
		}
	}
}


2.AudioTrack及AudioRecord:

这是通过流读取操作来录制/播放音频文件的,相对于上面的方法来对解码器更加依赖来讲,这是直接读取的是pcm文件。不过好像录音的效果不咋好,通过对流的处理是可以实现降噪的,在网上没找到比较好的办法,在这就不写了,因为我也不懂那个。

public class AltAudioRecorder extends Activity implements OnClickListener {

	private RecordAudio recordTask;
	private PlayAudio playTask;

	private Button startRecordingButton, stopRecordingButton,
			startPlaybackButton, stopPlaybackButton;
	private TextView statusText;

	File recordingFile;
	boolean isRecording = false;
	boolean isPlaying = false;
	// 要确定在人耳的接收频率以内,
	int frequency = 11025;
	int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
	int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.acy_record);

		statusText = (TextView) this.findViewById(R.id.StatusTextView);

		startRecordingButton = (Button) this
				.findViewById(R.id.StartRecordingButton);
		stopRecordingButton = (Button) this
				.findViewById(R.id.StopRecordingButton);
		startPlaybackButton = (Button) this
				.findViewById(R.id.StartPlaybackButton);
		stopPlaybackButton = (Button) this
				.findViewById(R.id.StopPlaybackButton);

		startRecordingButton.setOnClickListener(this);
		stopRecordingButton.setOnClickListener(this);
		startPlaybackButton.setOnClickListener(this);
		stopPlaybackButton.setOnClickListener(this);

		File path = new File(Environment.getExternalStorageDirectory()
				.getAbsolutePath() + "/Android/data/AudioRecorder/files/");
		path.mkdirs();
		try {
			recordingFile = File.createTempFile("recording", ".pcm", path);
		} catch (Exception e) {
			throw new RuntimeException("Couldn't create file on SD card", e);
		}
	}

	public void onClick(View v) {
		if (v == startRecordingButton) {
			record();
		} else if (v == stopRecordingButton) {
			stopRecording();
		} else if (v == startPlaybackButton) {
			play();
		} else if (v == stopPlaybackButton) {
			stopPlaying();
		}
	}
//开始录音
	public void play() {
		playTask = new PlayAudio();
		playTask.execute();
	}
//停止录音
	public void stopPlaying() {
		isPlaying = false;
	}
//开始播放
	public void record() {
		recordTask = new RecordAudio();
		recordTask.execute();
	}
//停止播放
	public void stopRecording() {
		isRecording = false;
	}

	private class PlayAudio extends AsyncTask<Void, Integer, Void> {
		@Override
		protected Void doInBackground(Void... params) {
			isPlaying = true;
			// 返回实例创建后的最好缓冲区
			int bufferSize = AudioTrack.getMinBufferSize(frequency,
					channelConfiguration, audioEncoding);
			short[] audiodata = new short[bufferSize / 4];

			try {
				DataInputStream dis = new DataInputStream(
						new BufferedInputStream(new FileInputStream(
								recordingFile)));

				AudioTrack audioTrack = new AudioTrack(
				// 流类型
						AudioManager.STREAM_MUSIC,
						// 音频数据的采样率
						frequency,
						// 声道 为双声道立体声
						channelConfiguration,
						// 设置音频数据块为16位
						audioEncoding,
						// 在录制过程中,音频数据写入缓冲区的总数(字节)
						bufferSize,
						// 设置模式类型为流
						AudioTrack.MODE_STREAM);

				audioTrack.play();

				while (isPlaying && dis.available() > 0) {
					int i = 0;
					while (dis.available() > 0 && i < audiodata.length) {
						audiodata[i] = dis.readShort();
						i++;
					}
					audioTrack.write(audiodata, 0, audiodata.length);
				}
				dis.close();
			} catch (Throwable t) {
				Log.e("AudioTrack", "Playback Failed");
			}

			return null;
		}
	}

	private class RecordAudio extends AsyncTask<Void, Integer, Void> {
		@Override
		protected Void doInBackground(Void... params) {
			isRecording = true;
			try {
				DataOutputStream dos = new DataOutputStream(
						new BufferedOutputStream(new FileOutputStream(
								recordingFile)));

				int bufferSize = AudioRecord.getMinBufferSize(frequency,
						channelConfiguration, audioEncoding);

				AudioRecord audioRecord = new AudioRecord(
						MediaRecorder.AudioSource.MIC, frequency,
						channelConfiguration, audioEncoding, bufferSize);

				short[] buffer = new short[bufferSize];
				audioRecord.startRecording();

				int r = 0;
				while (isRecording) {
					int bufferReadResult = audioRecord.read(buffer, 0,
							bufferSize);
					for (int i = 0; i < bufferReadResult; i++) {
						dos.writeShort(buffer[i]);
					}

					publishProgress(new Integer(r));
					r++;
				}

				audioRecord.stop();
				dos.close();
			} catch (Throwable t) {
				Log.e("AudioRecord", "Recording Failed");
			}

			return null;
		}

		protected void onProgressUpdate(Integer... progress) {
			statusText.setText(progress[0].toString());
		}

		protected void onPostExecute(Void result) {
		}
	}
}


注意:

1.android.media.MediaPlayer.finalize() timed out after 10 seconds

在onPause()中调用
MediaPlayer.release()
,在onStop()中释放对象:

mPlayer.stop();
		mPlayer.release();
		mPlayer = null;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: