很多唱歌类型的APP(比如唱吧),都在寻求实现好的用户体验,其中一个就是能够一边边播放歌曲一边唱(声音会被录下来),有人便想进一步实现播放录的声音(就像拿着麦克风唱歌的感觉,自己可以听见自己的声音),这个想法是好的,也可行。

具体方案是:MediaPlayer播放音乐,MediaRecorder录音并保存; AudioTrack和AudioRecord两个配合实现实时语音流的记录和同步播放(可认为是轻量级的MediaPlayer和MediaRecorder,细节还有有差别请自行检索)

但是要是你去下载唱吧,却发现它并没有实现“可以听见自己唱歌的声音”的效果,经过我在做一个项目中的尝试、研究发现,原来android4.3(API18)以上不支持MediaRecorder与AudioRecord的共用,即:只要同时使用两者,则只能实现存储录音文件(MediaRecorder),不能实时获取语音流(AudioRecord)。

具体代码可见下方:

public class MainActivity extends Activity{private MediaPlayer mediaPlayer;private MediaRecorder mediaRecorder;private AudioTrack audioTrack;private AudioRecord audioRecord;private int recBufSize, playBufSize;private static final int sampleRateInHz = 44100;private static final int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_STEREO;private static final int audioFormat = AudioFormat.ENCODING_PCM_16BIT;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initMediaPlayer();initMediaRecord();initAudioTrack();initAudioRecord();new RecordPlayThread().start();}/*** 初始化记录音频流资源*/private void initAudioRecord() {recBufSize = audioRecord.getMinBufferSize(sampleRateInHz,channelConfig, audioFormat);audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC,sampleRateInHz, channelConfig, audioFormat, recBufSize);}/*** 初始化播放音频流资源*/private void initAudioTrack() {playBufSize = audioTrack.getMinBufferSize(sampleRateInHz,channelConfig, audioFormat);audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRateInHz,channelConfig, audioFormat, playBufSize,AudioTrack.MODE_STREAM);}//音乐播放路径:需要在手机里的"1yzz"文件夹中放一个名为"test1.mp3"的文件(可自行修改)private String playpath1 = Environment.getExternalStorageDirectory()+ "/1yzz/test1.mp3";  /*** 初始化音乐播放*/private void initMediaPlayer(){if (mediaPlayer!=null){mediaPlayer.stop();mediaPlayer.release();mediaPlayer = null;}mediaPlayer = new MediaPlayer();try {mediaPlayer.setDataSource(playpath1);mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);mediaPlayer.setLooping(true);mediaPlayer.prepare();mediaPlayer.start();} catch (Exception e) {e.printStackTrace();}}private String recordpath; private File audioFile;private boolean isrecording;/*** 初始化录音*/private void initMediaRecord() {if (mediaRecorder != null) {mediaRecorder.stop();mediaRecorder.release();mediaRecorder = null;}SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyyMMddhhmmss");String date = sDateFormat.format(new java.util.Date());//录音文件保存路径:手机中的"1yzz"文件夹(可自行修改)String Fpath = Environment.getExternalStorageDirectory() + "/1yzz";File file = new File(Fpath);if (!file.exists()) {file.mkdir();}//录音文件命名方式:"时间"+"record"+".mp3"(可自行修改)recordpath = Fpath + "/" + date + "record.mp3";audioFile = new File(recordpath);mediaRecorder = new MediaRecorder();mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);//从麦克风采集mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);mediaRecorder.setAudioSamplingRate(44100);  //采样率mediaRecorder.setAudioChannels(1);          //单声道mediaRecorder.setAudioEncodingBitRate(128000);//比特率mediaRecorder.setOutputFile(audioFile.getAbsolutePath());mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);//声音编码格式try {isrecording = true;mediaRecorder.prepare();mediaRecorder.start();} catch (Exception e) {e.printStackTrace();}}/*** 边录音边播放线程*/class RecordPlayThread extends Thread {public void run() {byte[] data = new byte[recBufSize];int num = 0;audioRecord.startRecording();audioTrack.play();while (isrecording) {num = audioRecord.read(data, 0, recBufSize);byte[] tmpBuf = new byte[num];System.arraycopy(data, 0, tmpBuf, 0, num);audioTrack.write(tmpBuf, 0, tmpBuf.length);}}}@Overridepublic void onDestroy() {isrecording = false;if (mediaPlayer != null) {mediaPlayer.stop();mediaPlayer.release();mediaPlayer = null;}if (mediaRecorder != null) {mediaRecorder.stop();mediaRecorder.release();mediaRecorder = null;}if (audioTrack!=null) {audioTrack.stop();audioTrack.release();audioTrack = null;}if (audioRecord!=null) {audioRecord.stop();audioRecord.release();audioRecord = null;}super.onDestroy();}@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) {if (keyCode == KeyEvent.KEYCODE_BACK ) { finish();return true;} else {return super.onKeyDown(keyCode, event);}}}

注意需要添加以下权限:

 <uses-permission android:name="android.permission.RECORD_AUDIO" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

在4.3以下运行以上代码,发现可以播放歌曲、录音、同步播放自己声音,体验很好(具体参数也可以调整)

可是在4.3(API18)以及以上的手机就会发现:不能播放自己的声音!(不会抛错,功放只播歌曲而没有自己从麦克风唱歌的声音);经调试可以发现,若在MediaRecorder使用时,要从AudioRecord获取语音流是获取不到的(读出来是0),也就是说,受API的限制,两者资源不能同时使用(可能是考虑到资源调用安全性问题,深层原因待进一步研究,水平有限望见谅)

简单说明:AudioRecord可以从麦克风记录短时长的语音流,之后AudioTrack可以从中读取出来并通过功放播放出来;若只用以上两个资源而不使用MediaPlayer和MediaRecorder,则能够实现一个麦克风加功放的简单效果(这时因为未使用MediaRecorder,在4.3以上也是可以正常实现的,因为4.3只限制MediaRecorder与AudioRecord的同时使用,只使用其中一个是没问题的)

欢迎建议、补充、指正!

demo下载地址 :http://download.csdn.net/detail/duguju/9082813

实现KTV效果:播放歌曲,录音(存储录音文件),并同步播放录音 解释4.3以上audio与media资源冲突问题相关推荐

  1. MIUI13和MIUI12的录音存储位置

    MIUI13和MIUI12的录音存储位置 1.电话录音存储位置 2.自带录音软件存储位置 1.电话录音存储位置 在桌面找到并打开[文件管理],点击[MIUI]文件夹 点击[sound_recorder ...

  2. php 音频顺序播放,MP3播放器音频文件不按顺序播放的解决方法,简单实用

    MP3播放器对于现在的我们来说很多已经是过去了,但是我们总会有用到它的时候:当你听一些录音课程或者评书故事,亦或者使用迷你音响播放歌曲时常会发现拷贝进MP3播放器中的音频文件根本不按照你自己的想象进行 ...

  3. html音乐唱片自动转,HTML5音乐播放器(四):播放列表与播放方式

    发现播放列表和播放方式切换两个功能是连在一起的,单独一个拿出来说不太合适,所以就都一块弄完了.废话不多说,进入主题,功能的逻辑我是这么设计的: 把整个歌曲文件的信息都写在 json 文件里,获取并生成 ...

  4. HTML5音乐播放器(四):播放列表与播放方式

    2019独角兽企业重金招聘Python工程师标准>>> 发现播放列表和播放方式切换两个功能是连在一起的,单独一个拿出来说不太合适,所以就都一块弄完了.废话不多说,进入主题,功能的逻辑 ...

  5. sync-player:使用websocket实现异地同步播放视频

    本文作者:星空无限 原文链接:https://liyangzone.com/2020/09/20/%E5%89%8D%E7%AB%AF/sync-player/ GoEasy已获作者授权转载,GoEa ...

  6. 如何同步播放asf和vga文件的教学视频

    (1)文件夹结构 教学视频很多是在一个网页窗口下显示三个子窗口: 一个是asf的(frmleftup.htm),Media Player播放,一般在左上,为主讲人: 一个是PPT目录(frmleftd ...

  7. c#winform演练 ktv项目 播放歌曲同时显示歌曲名称与歌手

    c#winform演练 ktv项目 播放歌曲同时显示歌曲名称与歌手 为什么需要歌曲对象 歌曲的路径是一个字符串 如何知道一个路径对应哪一首歌? 用对象最合适 设置对象的name为歌名 对象的src为路 ...

  8. 上传声音 微信小程序_微信小程序录音文件保存,播放

    最近做微信小程序需要把录音文件保存起来然后在另一个地方再播放,录音用的是wx.startRecord接口返回的是录音文件的临时路径,开始以为是和选择图片保存图片没什么两样的操作,结果和后端同事一起折腾 ...

  9. 什么录音软件可以录制电脑内部播放的声音

    什么录音软件可以录制电脑内部播放的声音 说起录音,我们应该都不陌生,多多少少都会使用到录音这个功能,不管是商业还是日常的工作学习中,录音已经成为人们生活中不可或缺的一项小功能,可能很多人使用录音这个功 ...

最新文章

  1. Python实战 | 送亲戚,送长辈,月饼可视化大屏来帮忙!
  2. PP部分主数据导出SQVI设置
  3. Intel Realsense D435 pyrealsense set_option() rs.option 可配置参数翻译
  4. 场景数据的动态更新setDataVariance(osg::Object::DYNAMIC) (转)
  5. 推荐几个配色和图标网站
  6. (一)STL体系结构基础介绍
  7. 解决securecrt rz 上传rar,gif文件不正确问题【转】
  8. vue ---- webpack -插件 html-webpack-plugin
  9. 牛!GitHub标星Python项目实战,附赠:学习图谱
  10. Agile Web Application Development with Yii 1.1 and PHP5
  11. UnityShader1:渲染流水线
  12. 侠客行手游如何用电脑玩 侠客行手游PC电脑版教程
  13. 使用Python基于BibTeX引用格式自动生成文献的IEEE引用格式
  14. python数据挖掘学习路线图
  15. 实验六 教务管理数据库的设计
  16. 淘宝联盟API对接过程记录(1)
  17. 小乌龟git如何同步远程分支_在git远程之间同步分支的过程
  18. 计蒜客 农场看守(欧拉回路)
  19. IO操作(Java版)
  20. 大师级管理人物盘点:“颠覆性技术“提出者-克里斯坦森

热门文章

  1. 系统计划任务服务器,计划任务
  2. 区块链智能合约超长解决办法
  3. DAMA试题分析:主键有什么特性?
  4. 高通Android平台下zoom4X实验原理分析
  5. <2021SC@SDUSC>【Overload游戏引擎】OvCore源码模块分析(二)—— ESC
  6. Visual Assist Trial 的补丁安装和破解
  7. 教你怎样把一个价值0.5元苹果卖到100万元
  8. 人工智能如何助力银行更“智慧”?
  9. Linux CentOS系统 图形模式下,鼠标键盘操作没有响应
  10. [2021.11.14]UPC-计算机2021随堂测验第四场-21234 Problem G 买房子