Android实现语音播放与录音功能
作者:尽人事看天意 发布时间:2022-01-21 15:39:09
标签:Android,语音,录音
本文实例为大家分享了Android实现语音播放与录音的具体代码,供大家参考,具体内容如下
项目用到的技术点和亮点
语音录音 (单个和列表)
语音播放(单个和列表)
语音录音封装
语音播放器封装
语音列表顺序播放
语音列表单个播放 复用问题处理
因为安装原生录音不能录mp3格式文件 而mp3格式是安卓和ios公用的,所以我们需要的是能直接录取mp3文件或者录完的格式转成mp3格式
下面添加这个库 能直接录mp3文件,我觉得是最方便的
compile ‘com.czt.mp3recorder:library:1.0.3'
1. 语音录音封装
代码简单 自己看吧
package com.video.zlc.audioplayer;
import com.czt.mp3recorder.MP3Recorder;
import com.video.zlc.audioplayer.utils.LogUtil;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
/**
* @author zlc
*/
public class AudioManage {
private MP3Recorder mRecorder;
private String mDir; // 文件夹的名称
private String mCurrentFilePath;
private static AudioManage mInstance;
private boolean isPrepared; // 标识MediaRecorder准备完毕
private AudioManage(String dir) {
mDir = dir;
LogUtil.e("AudioManage=",mDir);
}
/**
* 回调“准备完毕”
* @author zlc
*/
public interface AudioStateListenter {
void wellPrepared(); // prepared完毕
}
public AudioStateListenter mListenter;
public void setOnAudioStateListenter(AudioStateListenter audioStateListenter) {
mListenter = audioStateListenter;
}
/**
* 使用单例实现 AudioManage
* @param dir
* @return
*/
public static AudioManage getInstance(String dir) {
if (mInstance == null) {
synchronized (AudioManage.class) { // 同步
if (mInstance == null) {
mInstance = new AudioManage(dir);
}
}
}
return mInstance;
}
/**
* 准备录音
*/
public void prepareAudio() {
try {
isPrepared = false;
File dir = new File(mDir);
if (!dir.exists()) {
dir.mkdirs();
}
String fileName = GenerateFileName(); // 文件名字
File file = new File(dir, fileName); // 路径+文件名字
//MediaRecorder可以实现录音和录像。需要严格遵守API说明中的函数调用先后顺序.
mRecorder = new MP3Recorder(file);
mCurrentFilePath = file.getAbsolutePath();
// mMediaRecorder = new MediaRecorder();
// mCurrentFilePath = file.getAbsolutePath();
// mMediaRecorder.setOutputFile(file.getAbsolutePath()); // 设置输出文件
// mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); // 设置MediaRecorder的音频源为麦克风
// mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.AMR_NB); // 设置音频的格式
// mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); // 设置音频的编码为AMR_NB
// mMediaRecorder.prepare();
// mMediaRecorder.start();
mRecorder.start(); //开始录音
isPrepared = true; // 准备结束
if (mListenter != null) {
mListenter.wellPrepared();
}
} catch (Exception e) {
e.printStackTrace();
LogUtil.e("prepareAudio",e.getMessage());
}
}
/**
* 随机生成文件名称
* @return
*/
private String GenerateFileName() {
// TODO Auto-generated method stub
return UUID.randomUUID().toString() + ".mp3"; // 音频文件格式
}
/**
* 获得音量等级——通过mMediaRecorder获得振幅,然后换算成声音Level
* maxLevel最大为7;
* @return
*/
public int getVoiceLevel(int maxLevel) {
if (isPrepared) {
try {
mRecorder.getMaxVolume();
return maxLevel * mRecorder.getMaxVolume() / 32768 + 1;
} catch (Exception e) {
e.printStackTrace();
}
}
return 1;
}
/**
* 释放资源
*/
public void release() {
if(mRecorder != null) {
mRecorder.stop();
mRecorder = null;
}
}
/**
* 停止录音
*/
public void stop(){
if(mRecorder!=null && mRecorder.isRecording()){
mRecorder.stop();
}
}
/**
* 取消(释放资源+删除文件)
*/
public void delete() {
release();
if (mCurrentFilePath != null) {
File file = new File(mCurrentFilePath);
file.delete(); //删除录音文件
mCurrentFilePath = null;
}
}
public String getCurrentFilePath() {
return mCurrentFilePath;
}
public int getMaxVolume(){
return mRecorder.getMaxVolume();
}
public int getVolume(){
return mRecorder.getVolume();
}
}
2. 语音播放器封装
package com.video.zlc.audioplayer.utils;
import android.content.Context;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
/**
*
* @author zlc
*
*/
public class MediaManager {
private static MediaPlayer mMediaPlayer; //播放录音文件
private static boolean isPause = false;
static {
if(mMediaPlayer==null){
mMediaPlayer=new MediaPlayer();
mMediaPlayer.setOnErrorListener( new MediaPlayer.OnErrorListener() {
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
mMediaPlayer.reset();
return false;
}
});
}
}
/**
* 播放音频
* @param filePath
* @param onCompletionListenter
*/
public static void playSound(Context context,String filePath, MediaPlayer.OnCompletionListener onCompletionListenter){
if(mMediaPlayer==null){
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setOnErrorListener( new MediaPlayer.OnErrorListener() {
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
mMediaPlayer.reset();
return false;
}
});
}else{
mMediaPlayer.reset();
}
try {
//详见“MediaPlayer”调用过程图
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mMediaPlayer.setOnCompletionListener(onCompletionListenter);
mMediaPlayer.setDataSource(filePath);
mMediaPlayer.prepare();
mMediaPlayer.start();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
LogUtil.e("语音error==",e.getMessage());
}
}
/**
* 暂停
*/
public synchronized static void pause(){
if(mMediaPlayer!=null && mMediaPlayer.isPlaying()){
mMediaPlayer.pause();
isPause=true;
}
}
//停止
public synchronized static void stop(){
if(mMediaPlayer!=null && mMediaPlayer.isPlaying()){
mMediaPlayer.stop();
isPause=false;
}
}
/**
* resume继续
*/
public synchronized static void resume(){
if(mMediaPlayer!=null && isPause){
mMediaPlayer.start();
isPause=false;
}
}
public static boolean isPause(){
return isPause;
}
public static void setPause(boolean isPause) {
MediaManager.isPause = isPause;
}
/**
* release释放资源
*/
public static void release(){
if(mMediaPlayer!=null){
isPause = false;
mMediaPlayer.stop();
mMediaPlayer.release();
mMediaPlayer = null;
}
}
public synchronized static void reset(){
if(mMediaPlayer!=null) {
mMediaPlayer.reset();
isPause = false;
}
}
/**
* 判断是否在播放视频
* @return
*/
public synchronized static boolean isPlaying(){
return mMediaPlayer != null && mMediaPlayer.isPlaying();
}
}
3. 语音列表顺序播放
private int lastPos = -1;
//播放语音
private void playVoice(final int position, String from) {
LogUtil.e("playVoice position",position+"");
if(position >= records.size()) {
LogUtil.e("playVoice","全部播放完了");
stopAnimation();
MediaManager.reset();
return;
}
String voicePath = records.get(position).getPath();
LogUtil.e("playVoice",voicePath);
if(TextUtils.isEmpty(voicePath) || !voicePath.contains(".mp3")){
Toast.makeText(this,"语音文件不合法",Toast.LENGTH_LONG).show();
return;
}
if(lastPos != position && "itemClick".equals(from)){
stopAnimation();
MediaManager.reset();
}
lastPos = position;
//获取listview某一个条目的图片控件
int pos = position - id_list_voice.getFirstVisiblePosition();
View view = id_list_voice.getChildAt(pos);
id_iv_voice = (ImageView) view.findViewById(R.id.id_iv_voice);
LogUtil.e("playVoice position",pos+"");
if(MediaManager.isPlaying()){
MediaManager.pause();
stopAnimation();
}else if(MediaManager.isPause()){
startAnimation();
MediaManager.resume();
}else{
startAnimation();
MediaManager.playSound(this,voicePath, new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mediaPlayer) {
//播放完停止动画 重置MediaManager
stopAnimation();
MediaManager.reset();
playVoice(position + 1, "loop");
}
});
}
}
4. 语音列表单个播放 复用问题处理
播放逻辑基本同上
private int lastPosition = -1;
private void playVoice(FendaListInfo.ObjsEntity obj, int position) {
String videoPath = obj.path;
if(TextUtils.isEmpty(videoPath) || !videoPath.contains(".mp3")){
Toast.makeText(this,"语音文件不合法",Toast.LENGTH_LONG).show();
return;
}
if(position != lastPosition){ //点击不同条目先停止动画 重置音频资源
stopAnimation();
MediaManager.reset();
}
if(mAdapter!=null)
mAdapter.selectItem(position, lastPosition);
lastPosition = position;
id_iv_voice.setBackgroundResource(R.drawable.animation_voice);
animationDrawable = (AnimationDrawable) id_iv_voice.getBackground();
if(MediaManager.isPlaying()){
stopAnimation();
MediaManager.pause();
}else if(MediaManager.isPause()){
startAnimation();
MediaManager.resume();
}else{
startAnimation();
MediaManager.playSound(this,videoPath, new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
LogUtil.e("onCompletion","播放完成");
stopAnimation();
MediaManager.stop();
}
});
}
}
//核心方法
//点击了某一个条目 这个条目isSelect=true 上一个条目isSelect需要改为false 防止滑动过程中 帧动画复用问题
public void selectItem(int position, int lastPosition) {
LogUtil.e("selectItem"," ;lastPosition="+lastPosition+" ;position="+position);
if(lastPosition >= 0 && lastPosition < mDatas.size() && lastPosition != position){
FendaListInfo.ObjsEntity bean = mDatas.get(lastPosition);
bean.isSelect = false;
mDatas.set(lastPosition, bean);
notifyDataSetChanged();
}
if(position < mDatas.size() && position != lastPosition){
FendaListInfo.ObjsEntity bean = mDatas.get(position);
bean.isSelect = true;
mDatas.set(position,bean);
}
}
/**
* 适配器图片播放的动画处理
*/
private void setVoiceAnimation(ImageView iv_voice, FendaListInfo.ObjsEntity obj) {
//处理动画复用问题
AnimationDrawable animationDrawable;
if(obj.isSelect){
iv_voice.setBackgroundResource(R.drawable.animation_voice);
animationDrawable = (AnimationDrawable) iv_voice.getBackground();
if(MediaManager.isPlaying() && animationDrawable!=null){
animationDrawable.start();
}else{
iv_voice.setBackgroundResource(R.drawable.voice_listen);
animationDrawable.stop();
}
}else{
iv_voice.setBackgroundResource(R.drawable.voice_listen);
}
}
5.下载地址
Android实现语音播放与录音
来源:https://blog.csdn.net/rjgcszlc/article/details/78036010


猜你喜欢
- 一、TCP/IP简介TCP/IP协议族是互联网使用的协议,也可以用在独立的专用网络中。TCP/IP协议族包括了IP协议、TCP协议和UDP协
- 同学们应该都去麦当劳或肯德基吃过快餐吧?请同学们参考肯德基官网的信息模拟肯德基快餐店的收银系统,合理使用C++/python/Java,结合
- 首先说一下,教科书上的扫描线算法确实是用c++很好实现,而且网上有很多源码,而java实现的基本没有(可能是我没看到),所以肖先生还是打算自
- Android中Property模块的键值设置Prop模块是保存少量的全局共享信息,其保存的数据具有信息量少,跨进程共享数据等特性;每一条信
- 前言终于来到了Maven的插件开发,其实Maven的插件并没有想象的那么难,刚开始讲Maven基础的时候就演示了一下JDK是如何打包的,Ma
- 感想:第一次写博客,感觉编辑器挺复杂厉害的,感觉自己的内容挺简单的。有什么问题请多多指教!思路:1、创建一个扑克牌的实体类Poker,设置了
- 前言现在很多web应用,做过web项目的童鞋都知道,web结果由html+js+css组成,html结构都有一定的规范,数据动态交互可以通过
- 背景在接口请求过程中,传递json对象,springboot转换为实体VO对象后,所有属性都为null。post请求:后台接收请求:当时就懵
- DataGridView 列有三种排序模式。每一列的排序模式是通过该列的 SortMode 属性指定的,该属性可以设置为以下的 DataGr
- 在C#中,得益于强大的GC机制,使得我们开发程序变得非常简单,很多时候我们只需要管使用,而并不需要关心什么时候释放资源。但是,GC有的时并不
- 本文实例为大家分享了Java实现斗地主的具体代码,供大家参考,具体内容如下import java.util.ArrayList;import
- W3C制定了XML DOM标准。很多编程语言中多提供了支持W3C XML DOM标准的API。我在之前的文章中介绍过如何使用Javascri
- 项目场景Spring 的 RestTemplate 是一个健壮的、流行的基于 Java 的 Http客户端。RestTemplate实现re
- 最近在做一个搜索相关的项目,需要爬取网络上的一些链接存储到索引库中,虽然有很多开源的强大的爬虫框架,但本着学习的态度,自己写了一个简单的网络
- 前言字符串分割函数strtok,大家可能都知道他怎么使用,一旦要用的时候就会心生疑惑,不知道它的内部的实现,废话不多说,本篇就来带大家看看s
- Data Annotations是在Asp.Net中用于表单验证的,它通过Attribute直接标记字段的有效性,简单且直观。在非Asp.N
- springmvc控制登录用户session失效后跳转登录页面,废话不多少了,具体如下:第一步,配置 web.xml <session
- 掌握内存操作流输入和输出都是从文件中来的,当然,也可将输出的位置设置在内存上,这就需要ByteArrayInputStream和ByteAr
- 前言社区内容经常会有插入链接的需要,这时就产生了对链接的UI和点击交互的需求,我们在微博中也经常会在列表页面和详情页面看到。下边我们就此功能
- 接口的灵活性就在于“规定一个类必须做什么,而不管你如何做”。我们可以定义一个接口类型的引用变量来引用实现接口的类的实例,当这个引用调用方法时