Android开发笔记(一百二十六)自定义音乐播放器

这篇博客详细探讨了在Android开发中如何使用MediaRecorder、MediaPlayer、AudioRecord、AudioTrack和SoundPool来创建自定义音乐播放器。通过理解这些音频处理组件的工作原理,开发者可以实现更灵活和高效的音乐播放功能。
摘要由CSDN通过智能技术生成

MediaRecorder/MediaPlayer

在Android手机上面,音频的处理比视频还要复杂,这真是出人意料。在前面的博文《 Android开发笔记(五十七)录像录音与播放》中,介绍了视频/音频的录制与播放,其中录像用的是MediaRecorder类,播放用的是MediaPlayer类。虽然Android还提供了专门的视频视图VideoView,但是该控件并非新的东西,而是继承了MediaRecorder和MediaPlayer,所以严格来说,Android上面只有一种视频的录制和播放方式。可是音频就大不一样了,Android提供了两种录音方式,以及至少三种常用的播音方式。两种录音方式分别是MediaRecorder类和AudioRecord类,而播音方式包括MediaPlayer类、AudioTrack类和SoundPool类,它们的使用场合各有千秋,且待笔者下面细细道来。


首先是MediaRecorder与MediaPlayer,这对组合即可用于录像,也可单独录制音频。它们处理的音频文件是压缩过的编码文件,通常用于录制和播放音乐,是最经常用到的。MediaRecorder与MediaPlayer在处理音频和视频时,整体流程是一样的,只有在部分方法的调用上有所差异,下面分别把录音/播音有关的方法列出来。


MediaRecorder的录音相关方法:
reset : 重置录制资源
prepare : 准备录制
start : 开始录制
stop : 结束录制
release : 释放录制资源
setOnErrorListener : 设置错误监听器。可监听服务器异常以及未知错误的事件。
setOnInfoListener : 设置信息监听器。可监听录制结束事件,包括达到录制时长或者达到录制大小。
setAudioSource : 设置音频来源。一般使用麦克风AudioSource.MIC。
setOutputFormat : 设置媒体输出格式。OutputFormat.AMR_NB表示窄带格式,OutputFormat.AMR_WB表示宽带格式,AAC_ADTS表示高级的音频传输流格式。该方法要在setVideoEncoder之前调用,不然调用setAudioEncoder时会报错“java.lang.IllegalStateException”。
setAudioEncoder : 设置音频编码器。AudioEncoder.AMR_NB表示窄带编码,AudioEncoder.AMR_WB表示宽带编码,AudioEncoder.AAC表示低复杂度的高级编码,AudioEncoder.HE_AAC表示高效率的高级编码,AudioEncoder.AAC_ELD表示增强型低延迟的高级编码。
注意:setAudioEncoder应在setOutputFormat之后执行,否则会出现“setAudioEncoder called in an invalid state(2)”的异常。
setAudioSamplingRate : 设置音频的采样率,单位赫兹(Hz)。该方法为可选,AMRNB默认8khz,AMRWB默认16khz。
setAudioChannels : 设置音频的声道数。1表示单声道,2表示双声道。该方法为可选
setAudioEncodingBitRate : 设置音频每秒录制的字节数。越大则音频越清晰。该方法为可选
setMaxDuration : 设置录制时长。单位毫秒。
setMaxFileSize : 设置录制的媒体大小。单位字节。
setOutputFile : 设置输出文件的路径。


MediaPlayer的播音相关方法:
reset : 重置播放器
prepare : 准备播放
start : 开始播放
pause : 暂停播放
stop : 停止播放
setOnPreparedListener : 设置准备播放监听器。
setOnCompletionListener : 设置结束播放监听器。
setOnSeekCompleteListener : 设置播放拖动监听器。
create : 创建指定Uri的播放器。
setDataSource : 设置播放数据来源。create与setDataSource只需设置其一。
setVolume : 设置音量。第一个参数是左声道,第二个参数是右声道,取值在0-1之间。
setAudioStreamType : 设置音频流的类型。AudioManager.STREAM_MUSIC表示音乐,AudioManager.STREAM_RING表示铃声,AudioManager.STREAM_ALARM表示闹钟,AudioManager.STREAM_NOTIFICATION表示通知。
setLooping : 设置是否循环播放。
isPlaying : 判断是否正在播放。
seekTo : 拖动播放进度到指定位置。
getCurrentPosition : 获取当前播放进度所在的位置。
getDuration : 获取播放时长。


下面是MediaRecorder与MediaPlayer组合处理音频的示例代码:
import java.io.File;

import com.example.exmaudio.util.Utils;

import android.app.Activity;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaRecorder.AudioEncoder;
import android.media.MediaRecorder.AudioSource;
import android.media.MediaRecorder.OnErrorListener;
import android.media.MediaRecorder.OnInfoListener;
import android.media.MediaRecorder;
import android.media.MediaRecorder.OutputFormat;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.util.Log;
import android.view.View.OnClickListener;
import android.view.View;
import android.view.Window;
import android.widget.Button;
import android.widget.TextView;

public class MediaRecordActivity extends Activity 
		implements OnClickListener, OnErrorListener, OnInfoListener {
	private static final String TAG = "MediaRecordActivity";
    private TextView tv_record;
    private Button btn_start;
    private Button btn_stop;
    private MediaRecorder mMediaRecorder;

    private TextView tv_play;
    private Button btn_play;
    private Button btn_pause;
    private MediaPlayer mMediaPlayer;
    private int mPosition;
    private boolean bFirstPlay = true;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_media_record);

        tv_record = (TextView) findViewById(R.id.tv_record);
        btn_start = (Button) findViewById(R.id.btn_start);
        btn_stop = (Button) findViewById(R.id.btn_stop);
        tv_play = (TextView) this.findViewById(R.id.tv_play);
        btn_play = (Button) findViewById(R.id.btn_play);
        btn_pause = (Button) findViewById(R.id.btn_pause);

        btn_start.setOnClickListener(this);
        btn_stop.setOnClickListener(this);
        btn_play.setOnClickListener(this);
        btn_pause.setOnClickListener(this);
        btn_start.setEnabled(true);
        btn_stop.setEnabled(false);
        btn_play.setEnabled(false);
        btn_pause.setEnabled(false);
        initPlay();
    }
    
	private void initPlay() {
        mMediaPlayer = new MediaPlayer();
        mMediaPlayer.setOnCompletionListener(new OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mp) {
        		btn_play.setEnabled(true);
        		btn_pause.setEnabled(false);
        		bFirstPlay = true;
        		mHandler.removeCallbacks(mPlayRun);
        		mPlayTime = 0;
            }
        });
	}

	private void preplay() {
		try {
			mMediaPlayer.reset();
			//mMediaPlayer.setVolume(0.5f, 0.5f);  //设置音量,可选
			mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
			String path = mRecordFile.getAbsolutePath();
			mMediaPlayer.setDataSource(path);
			Log.d(TAG, "audio path = "+path);
			mMediaPlayer.prepare();
		} catch (Exception e) {
			Log.d(TAG, "mMediaPlayer.prepare error: "+e.getMessage());
		}
		mPlayTime = 0;
	}
    
    private void startPlay() {
		try {
			if (bFirstPlay == true) {
				preplay();
				bFirstPlay = false;
			}
			mMediaPlayer.start();
		} catch (Exception e) {
			Log.d(TAG, "mMediaPlayer.start error: " + e.getMessage());
		}
		btn_play.setEnabled(false);
		btn_pause.setEnabled(true);
		mHandler.post(mPlayRun);
    }
    
	@Override
	protected void onPause() {
		// 先判断是否正在播放
		if (mMediaPlayer.isPlaying()) {
			// 如果正在播放我们就先保存这个播放位置
			mPosition = mMediaPlayer.getCurrentPosition();
			mMediaPlayer.stop();
			mHandler.removeCallbacks(mPlayRun);
		}
		super.onPause();
	}

	@Override
	protected void onResume() {
		if (mMediaPlayer!=null && mPosition>0) {
			mMediaPlayer.seekTo(mPosition);
			mMediaPlayer.start();
			mHandler.post(mPlayRun);
		}
		super.onResume();
	}
	
	private void startRecord() {
		createRecordDir();
        mMediaRecorder = new MediaRecorder();
        mMediaRecorder.reset();
        mMediaRecorder.setOnErrorListener(this);
        mMediaRecorder.setOnInfoListener(this);
        mMediaRecorder.setAudioSource(AudioSource.MIC);  //音频源
        mMediaRecorder.setOutputFormat(OutputFormat.AMR_NB);
        mMediaRecorder.setAudioEncoder(AudioEncoder.AMR_NB);  //音频格式
        //mMediaRecorder.setAudioSamplingRate(8);  //音频的采样率。可选
        //mMediaRecorder.setAudioChannels(2);  //音频的声道数。可选
        //mMediaRecorder.setAudioEncodingBitRate(1024);  //音频每秒录制的字节数。可选
        mMediaRecorder.setMaxDuration(10 * 1000);  //设置录制时长
        //mMediaRecorder.setMaxFileSize(1024*1024*10);  //setMaxFileSize与setMaxDuration设置其一即可
        mMediaRecorder.setOutputFile(mRecordFile.getAbsolutePath());
        try {
            mMediaRecorder.prepare();
            mMediaRecorder.start();
        } catch (Exception e) {
			Log.d(TAG, "mMediaRecorder.start error: " + e.getMessage());
        }
		btn_start.setEnabled(false);
		btn_stop.setEnabled(true);
		mRecordTime = 0;
		mHandler.post(mRecordRun);
    }
    
	private File mRecordFile = null;
	private void createRecordDir() {
		File sampleDir = new File(Environment.getExternalStorageDirectory()
				+ File.separator + "Download" + File.separator);
		if (!sampleDir.exists()) {
			sampleDir.mkdirs();
		}
		File recordDir = sampleDir;
		try {
			mRecordF
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值