实现KTV效果:播放歌曲,录音(存储录音文件),并同步播放录音 & 解释4.3以上audio与media资源冲突问题
来源:互联网 发布:阿里云客服待遇怎么算 编辑:程序博客网 时间:2024/05/17 06:56
很多唱歌类型的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资源冲突问题
- [Android] 录音与播放录音实现
- [Android] 录音与播放录音实现
- Android录音与播放录音实现
- Media播放(播放音频,录音等)
- CSoundBase实现录音与播放
- CSoundBase实现录音与播放
- CSoundBase实现录音与播放
- CSoundBase实现录音与播放
- Android 实现录音与播放
- Android 实时录音和回放,边录音边播放 (KTV回音效果)
- Android 实时录音和回放,边录音边播放 (KTV回音效果)
- Android 实时录音和回放,边录音边播放 (KTV回音效果)
- Qt + SDL实现的实时录音并播放的程序,类似KTV唱歌
- Record Audio(录音)
- 【Android】MediaRecorder/MediaPlayer实现录音与播放录音
- ios 录音播放问题
- android录音播放问题
- linux中几个文本文件查看命令
- Groovy 与 DSL
- 位图和矢量图区别,PS和AI的区别
- 非暴力沟通--读书笔记
- java中解析excel(创建与读取)
- 实现KTV效果:播放歌曲,录音(存储录音文件),并同步播放录音 & 解释4.3以上audio与media资源冲突问题
- mysql查看在线以及重启
- 由newInstance()说开的设计模式
- statement 、prepareStatement的用法和解释
- spring schedule定时任务
- notification的简单使用
- Item 22:数据成员应声明为私有 Effective C++笔记
- 初探Qt Opengl【1】
- IMX6Solo启动流程 外传-新建一条Uboot命令