Android 开发音频录播中媒体录制器MediaRecorder和媒体播放器MediaPlayer的讲解及实战(超详细 附源码)
创始人
2024-02-15 01:08:20
0

需要源码请点赞关注收藏后评论区留下QQ~~~

一、媒体录制器MediaRecorder

MediaRecorder是Android自带的音视频录制工具,它通过操纵摄像头和麦克风完成媒体录制,既可录制视频又可以单独录制音频  下面是它的常用方法

reset 重置录制资源

prepare 准备录制

start 开始录制

stop 结束录制

release 释放录制资源

setOnErrorListener 设置错误监听器

setOnInfoListener 设置信息监听器

setMaxDuration  设置可录制的最大时长

setMaxFileSize 设置可录制的最大文件大小

setOutputFile 设置输出我呢见的存储路径

媒体输出格式如下

amr 窄带格式

aac 高级的音频传输流格式

mp4 MPEG4格式

3gp 3GP格式

注意 录音之前要再AndroidManifest.xml中添加录音权限

    

 二、媒体播放器MediaPlayer

MediaPlayer是Android自带的音视频播放器,可播放MediaRecorder录制的媒体文件,有各种格式

它的常用方法如下

reset 重置播放器

prepareAsync 异步加载媒体文件 播放大文件或者网络媒体时建议使用该方法

setOnPrepareListener 设置准备监听播放器

setOnCompletionListener 设置结束监听播放器

setOnSeekCompleteListener 设置播放拖动监听器

create 创建指定URI的媒体播放器

setDataSource 设置播放数据来源的文件路径

setVolume 设置音量

...

输出效果如下 可在下拉框中选择不同的编码格式和输出格式 录制时长等等

此处连接真机测试更佳  因为模拟机没有麦克风~~

 

 

 

 代码如下

Java类

package com.example.audio;import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;import androidx.appcompat.app.AppCompatActivity;import com.example.audio.util.DateUtil;
import com.example.audio.util.MediaUtil;import java.util.Timer;
import java.util.TimerTask;public class AudioCommonActivity extends AppCompatActivity {private static final String TAG = "AudioCommonActivity";private Button btn_record; // 声明一个按钮对象private LinearLayout ll_record_progress; // 声明一个线性布局对象private ProgressBar pb_record_progress; // 声明一个进度条对象private TextView tv_record_progress; // 声明一个文本视图对象private Button btn_play; // 声明一个按钮对象private LinearLayout ll_play_progress; // 声明一个线性布局对象private ProgressBar pb_play_progress; // 声明一个进度条对象private TextView tv_play_progress; // 声明一个文本视图对象private int mAudioEncoder; // 音频编码private int mOutputFormat; // 输出格式private int mDuration; // 录制时长private String mRecordFilePath; // 录音文件的保存路径private MediaRecorder mMediaRecorder = new MediaRecorder(); // 媒体录制器private boolean isRecording = false; // 是否正在录音private Timer mRecordTimer = new Timer(); // 录音计时器private int mRecordTimeCount; // 录音时间计数private MediaPlayer mMediaPlayer = new MediaPlayer(); // 媒体播放器private boolean isPlaying = false; // 是否正在播音private Timer mPlayTimer = new Timer(); // 录音计时器private int mPlayTimeCount; // 录音时间计数@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_audio_common);btn_record = findViewById(R.id.btn_record);ll_record_progress = findViewById(R.id.ll_record_progress);pb_record_progress = findViewById(R.id.pb_record_progress);tv_record_progress = findViewById(R.id.tv_record_progress);btn_play = findViewById(R.id.btn_play);ll_play_progress = findViewById(R.id.ll_play_progress);pb_play_progress = findViewById(R.id.pb_play_progress);tv_play_progress = findViewById(R.id.tv_play_progress);btn_record.setOnClickListener(v -> {if (!isRecording) { // 未在录音startRecord(); // 开始录音} else { // 正在录音stopRecord(); // 停止录音}});btn_play.setOnClickListener(v -> {if (!isPlaying) { // 未在播音startPlay(); // 开始播音} else { // 正在播音stopPlay(); // 停止播音}});initEncoderSpinner(); // 初始化音频编码的下拉框initFormatSpinner(); // 初始化输出格式的下拉框initDurationSpinner(); // 初始化录制时长的下拉框}// 初始化音频编码的下拉框private void initEncoderSpinner() {ArrayAdapter encoderAdapter = new ArrayAdapter<>(this,R.layout.item_select, encoderDescArray);Spinner sp_encoder = findViewById(R.id.sp_encoder);sp_encoder.setPrompt("请选择音频编码");sp_encoder.setAdapter(encoderAdapter);sp_encoder.setOnItemSelectedListener(new EncoderSelectedListener());sp_encoder.setSelection(0);}private String[] encoderDescArray = {"默认编码","窄带编码","宽带编码","低复杂度的高级编码","高效率的高级编码","增强型低延时的高级编码"};private int[] encoderArray = {MediaRecorder.AudioEncoder.DEFAULT,MediaRecorder.AudioEncoder.AMR_NB,MediaRecorder.AudioEncoder.AMR_WB,MediaRecorder.AudioEncoder.AAC,MediaRecorder.AudioEncoder.HE_AAC,MediaRecorder.AudioEncoder.AAC_ELD};class EncoderSelectedListener implements AdapterView.OnItemSelectedListener {public void onItemSelected(AdapterView arg0, View arg1, int arg2, long arg3) {mAudioEncoder = encoderArray[arg2];}public void onNothingSelected(AdapterView arg0) {}}// 初始化输出格式的下拉框private void initFormatSpinner() {ArrayAdapter formatAdapter = new ArrayAdapter<>(this,R.layout.item_select, formatDescArray);Spinner sp_format = findViewById(R.id.sp_format);sp_format.setPrompt("请选择输出格式");sp_format.setAdapter(formatAdapter);sp_format.setSelection(0);sp_format.setOnItemSelectedListener(new FormatSelectedListener());}private String[] formatDescArray = {"默认格式","窄带格式","宽带格式","高级的音频传输流格式"};private int[] formatArray = {MediaRecorder.OutputFormat.DEFAULT,MediaRecorder.OutputFormat.AMR_NB,MediaRecorder.OutputFormat.AMR_WB,MediaRecorder.OutputFormat.AAC_ADTS};class FormatSelectedListener implements AdapterView.OnItemSelectedListener {public void onItemSelected(AdapterView arg0, View arg1, int arg2, long arg3) {mOutputFormat = formatArray[arg2];}public void onNothingSelected(AdapterView arg0) {}}// 初始化录制时长的下拉框private void initDurationSpinner() {ArrayAdapter durationAdapter = new ArrayAdapter<>(this,R.layout.item_select, durationDescArray);Spinner sp_duration = findViewById(R.id.sp_duration);sp_duration.setPrompt("请选择录制时长");sp_duration.setAdapter(durationAdapter);sp_duration.setSelection(0);sp_duration.setOnItemSelectedListener(new DurationSelectedListener());}private String[] durationDescArray = {"5秒", "10秒", "20秒", "30秒", "60秒"};private int[] durationArray = {5, 10, 20, 30, 60};class DurationSelectedListener implements AdapterView.OnItemSelectedListener {public void onItemSelected(AdapterView arg0, View arg1, int arg2, long arg3) {mDuration = durationArray[arg2];}public void onNothingSelected(AdapterView arg0) {}}// 开始录音private void startRecord() {Log.d(TAG, "startRecord mAudioEncoder="+mAudioEncoder+", mOutputFormat="+mOutputFormat+", mDuration="+mDuration);ll_record_progress.setVisibility(View.VISIBLE);isRecording = !isRecording;btn_record.setText("停止录音");pb_record_progress.setMax(mDuration); // 设置进度条的最大值mRecordTimeCount = 0; // 录音时间计数清零mRecordTimer = new Timer(); // 创建一个录音计时器mRecordTimer.schedule(new TimerTask() {@Overridepublic void run() {pb_record_progress.setProgress(mRecordTimeCount); // 设置进度条的当前进度tv_record_progress.setText(MediaUtil.formatDuration(mRecordTimeCount*1000));mRecordTimeCount++;}}, 0, 1000); // 计时器每隔一秒就更新进度条上的录音进度// 获取本次录制的媒体文件路径mRecordFilePath = String.format("%s/%s.amr",getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString(),DateUtil.getNowDateTime());// 下面是媒体录制器的处理代码mMediaRecorder.reset(); // 重置媒体录制器// 设置媒体录制器的信息监听器mMediaRecorder.setOnInfoListener((mr, what, extra) -> {// 录制达到最大时长,或者达到文件大小限制,都停止录制if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED|| what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED) {stopRecord(); // 停止录音}});// 设置音频源为麦克风mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);mMediaRecorder.setOutputFormat(mOutputFormat); // 设置媒体的输出格式。该方法要先于setAudioEncoder调用mMediaRecorder.setAudioEncoder(mAudioEncoder); // 设置媒体的音频编码器mMediaRecorder.setAudioSamplingRate(8000); // 设置媒体的音频采样率。可选// mMediaRecorder.setAudioChannels(2); // 设置媒体的音频声道数。可选// mMediaRecorder.setAudioEncodingBitRate(1024); // 设置音频每秒录制的字节数。可选mMediaRecorder.setMaxDuration(mDuration * 1000); // 设置媒体的最大录制时长// mMediaRecorder.setMaxFileSize(1024*1024*10); // 设置媒体的最大文件大小// setMaxFileSize与setMaxDuration设置其一即可mMediaRecorder.setOutputFile(mRecordFilePath); // 设置媒体文件的保存路径try {mMediaRecorder.prepare(); // 媒体录制器准备就绪mMediaRecorder.start(); // 媒体录制器开始录制} catch (Exception e) {e.printStackTrace();}}// 停止录音private void stopRecord() {btn_record.setText("开始录音");mRecordTimer.cancel(); // 取消录音定时器if (isRecording) {isRecording = !isRecording;mMediaRecorder.stop(); // 媒体录制器停止录制Toast.makeText(this, "已结束录音,音频文件路径为"+mRecordFilePath, Toast.LENGTH_LONG).show();btn_play.setVisibility(View.VISIBLE);}}// 开始播音private void startPlay() {ll_play_progress.setVisibility(View.VISIBLE);isPlaying = !isPlaying;btn_play.setText("停止播音");mMediaPlayer.reset(); // 重置媒体播放器// 设置媒体播放器的完成监听器mMediaPlayer.setOnCompletionListener(mp -> stopPlay());mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); // 设置音频流的类型为音乐try {mMediaPlayer.setDataSource(mRecordFilePath); // 设置媒体数据的文件路径mMediaPlayer.prepare(); // 媒体播放器准备就绪mMediaPlayer.start(); // 媒体播放器开始播放} catch (Exception e) {e.printStackTrace();}pb_play_progress.setMax(mMediaPlayer.getDuration()/1000); // 设置进度条的最大值mPlayTimeCount = 0; // 播音时间计数清零mPlayTimer = new Timer(); // 创建一个播音计时器mPlayTimer.schedule(new TimerTask() {@Overridepublic void run() {pb_play_progress.setProgress(mPlayTimeCount); // 设置进度条的当前进度tv_play_progress.setText(MediaUtil.formatDuration(mPlayTimeCount*1000));mPlayTimeCount++;}}, 0, 1000); // 计时器每隔一秒就更新进度条上的播音进度}// 停止播音private void stopPlay() {btn_play.setText("开始播音");mPlayTimer.cancel(); // 取消播音定时器if (mMediaPlayer.isPlaying() || isPlaying) { // 如果正在播放isPlaying = !isPlaying;mMediaPlayer.stop(); // 停止播放Toast.makeText(this, "已结束播音", Toast.LENGTH_LONG).show();}}@Overrideprotected void onStop() {super.onStop();stopRecord(); // 停止录音stopPlay(); // 停止播音}@Overrideprotected void onDestroy() {super.onDestroy();mMediaRecorder.release(); // 释放媒体录制器mMediaPlayer.release(); // 释放媒体播放器}
}

XML文件

创作不易 觉得有帮助请点赞关注收藏~~~

相关内容

热门资讯

聚焦小额诉讼!船营法院力推“小... 近日,吉林市船营区人民法院召开小额诉讼审判工作推进会,聚焦小额诉讼程序优化与效能提升,对相关工作进行...
张金明律师受邀为温州企业家讲解... 厚积薄发 启行千里 2025年8月24日,浙江厚启律师事务所合伙人、副主任张金明律师受邀为温州企业家...
四川瓦屋山景区 9 月实行免门... 近日,从四川瓦屋山景区获悉,为进一步回馈广大游客,充分展示景区秋季独特自然风光,该景区于2025年9...
当AI遇上规章制度,彩智科技帮... 图片由AI生成 这次的速访嘉宾是来自北京彩智科技公司CEO徐剑军。彩智科技的核心产品是深知可信知识模...
比亚迪李云飞:本周还有一批黑媒... IT之家 9 月 2 日消息,比亚迪法务部今日发文称,自媒体“龙猪-集车”及其相关账号因长期发布大量...
济宁任城区古槐街道东门社区:宠... 近日,樱花园小区的居民终于迎来了久违的宁静夜晚。此前,小区内一只宠物狗夜间频繁吠叫,严重影响了周边居...
惠企宣讲跨境法律,助力企业“走... 在涉外法治建设与金融开放协同推进的时代背景下,法治已成为企业“走出去”的关键支撑和核心竞争力。为精准...
压岁钱到底属于谁?女子成年后起... 压岁钱到底归谁?既是很多青春期孩子的疑惑,也是很多孩子变成人后的想法。父母经常说“你太小,我帮你存着...
隐身10年的虚假诉讼被揪出 “从立案时的信誓旦旦,到调解时的突然改口,再到撤诉后换理由再诉,整个过程暴露出你对诉讼程序的随意态度...
重庆:瞄准案件“人才荒” “订... 封面新闻记者 罗惟巍 防范和化解金融领域风险,一直是业界与学界共同面对的课题。 近日,由重庆财经学院...