Android5.1 录音机 MediaRecorder、微信 AudioRecord
Android提供了两个对象用于录音的实现:MediaRecorder 和AudioRecord
1.MediaRecorder:录制的音频文件是经过压缩后的,需要设置编码器 并且录制的音频文件可以用系统自带的Music播放器播放 MediaRecorder已经集成了录音、编码、压缩等,并支持少量的录音音频格式,但是这也是他的缺点,支持的格式过少并且无法实时处理音频数据
2.AudioRecord:主要实现对音频实时处理以及边录边播功能,相对MediaRecorder比较专业,输出是PCM语音数据 如果保存成音频文件,是不能够被播放器播放的,所以必须先写代码实现数据编码以及压缩
一.录音机
1.1.packages\apps\SoundRecorder\src\com\android\soundrecorder\Recorder.java
mRecorder.prepare(); //准备
mRecorder.start();//开始
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | public void startRecording( int outputfileformat, int recordingType,String extension, Context context) { stop(); if (mSampleFile == null ) { String myExtension = extension + TEMP_SUFFIX; File sampleDir = Environment.getExternalStorageDirectory(); if (!sampleDir.canWrite()) // Workaround for broken sdcard support on the device. sampleDir = new File( "/sdcard/sdcard" ); String sampleDirPath = null ; if (sampleDir != null ) { sampleDirPath = sampleDir.getAbsolutePath() + File.separator + RECORD_FOLDER; } if (sampleDirPath != null ) { sampleDir = new File(sampleDirPath); } if (sampleDir != null && !sampleDir.exists()) { if (!sampleDir.mkdirs()) { Log.i(TAG, "<startRecording> make dirs fail" ); } } try { if ( null != sampleDir) { Log.i(TAG, "SR sampleDir is:" + sampleDir.toString()); } SimpleDateFormat simpleDateFormat = new SimpleDateFormat( "yyyyMMddHHmmss" ); String time = simpleDateFormat.format( new Date(System .currentTimeMillis())); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append(SAMPLE_PREFIX).append( "_" +time) .append(myExtension); String name = stringBuilder.toString(); mSampleFile = new File(sampleDir, name); boolean result = mSampleFile.createNewFile(); if (result) { Log.i(TAG, "creat file success" ); } } catch (IOException e) { setError(SDCARD_ACCESS_ERROR); return ; } } mRecorder = new MediaRecorder(); mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); mRecorder.setOutputFormat(outputfileformat); mRecorder.setOutputFile(mSampleFile.getAbsolutePath()); mRecorder.setAudioSamplingRate(mSamplingRate); |
1.2.frameworks\base\media\java\android\media\MediaRecorder.java
1 2 | public native void start() throws IllegalStateException; public native void stop() throws IllegalStateException; |
1.3.frameworks\base\media\jni\android_media_MediaCodec.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) { ALOGV( "android_media_MediaCodec_start" ); sp<JMediaCodec> codec = getMediaCodec(env, thiz); if (codec == NULL) { throwExceptionAsNecessary(env, INVALID_OPERATION); return ; } status_t err = codec->start(); throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, "start failed" ); } static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) { ALOGV( "android_media_MediaCodec_stop" ); sp<JMediaCodec> codec = getMediaCodec(env, thiz); if (codec == NULL) { throwExceptionAsNecessary(env, INVALID_OPERATION); return ; } status_t err = codec->stop(); throwExceptionAsNecessary(env, err); } |
二.微信
2.1.AudioRecord
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | /** * 开始录音 * * @param listener 音频流的监听 */ public void startRecord( final RecordStreamListener listener) { if (status == Status.STATUS_NO_READY || TextUtils.isEmpty(fileName)) { throw new IllegalStateException( "录音尚未初始化,请检查是否禁止了录音权限~" ); } if (status == Status.STATUS_START) { throw new IllegalStateException( "正在录音" ); } Log.d( "AudioRecorder" , "===startRecord===" + audioRecord.getState()); audioRecord.startRecording(); new Thread( new Runnable() { @Override public void run() { writeDataTOFile(listener); } }).start(); } |
2.2.frameworks\base\media\java\android\media\AudioRecord.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | /** * Starts recording from the AudioRecord instance. * @throws IllegalStateException */ public void startRecording() throws IllegalStateException { if (mState != STATE_INITIALIZED) { throw new IllegalStateException( "startRecording() called on an " + "uninitialized AudioRecord." ); } // start recording synchronized (mRecordingStateLock) { if (native_start(MediaSyncEvent.SYNC_EVENT_NONE, 0 ) == SUCCESS) { handleFullVolumeRec( true ); mRecordingState = RECORDSTATE_RECORDING; } mFileObserver.startWatching(); } } /** * Starts recording from the AudioRecord instance when the specified synchronization event * occurs on the specified audio session. * @throws IllegalStateException * @param syncEvent event that triggers the capture. * @see MediaSyncEvent */ public void startRecording(MediaSyncEvent syncEvent) throws IllegalStateException { if (mState != STATE_INITIALIZED) { throw new IllegalStateException( "startRecording() called on an " + "uninitialized AudioRecord." ); } // start recording synchronized (mRecordingStateLock) { if (native_start(syncEvent.getType(), syncEvent.getAudioSessionId()) == SUCCESS) { handleFullVolumeRec( true ); mRecordingState = RECORDSTATE_RECORDING; } } mFileObserver.startWatching(); } |
分类:
RockChip
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】