您好,登錄后才能下訂單哦!
Android中怎么錄制mp3格式文件,相信很多沒有經(jīng)驗(yàn)的人對此束手無策,為此本文總結(jié)了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個問題。
工具
MP3格式是用一個開源項(xiàng)目轉(zhuǎn)的,MP3lame,由于該項(xiàng)目用到了jni,所以需要大家配置好ndk環(huán)境,環(huán)境配置在此就不多說了,大家可以自行百度,最新的應(yīng)該很好配置。
創(chuàng)建jni
拷貝文件
下載好后(我下載的是3.98.4版本)打開,找到libmp3lame文件,將里面的.h和.c拷貝下來,在自己的工程里創(chuàng)建jni文件夾,在jni文件夾下新建一個文件夾(我的命名為lame-3.98.4_libmp3lame,后面會用到),將剛才拷貝的文件復(fù)制進(jìn)去,然后再把include文件夾里的lame.h也拷貝進(jìn)去。
創(chuàng)建Android.mk
在jni中創(chuàng)建文件,Android.mk
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LAME_LIBMP3_DIR := lame-3.98.4_libmp3lame LOCAL_MODULE := mp3lame LOCAL_SRC_FILES := $(LAME_LIBMP3_DIR)/bitstream.c $(LAME_LIBMP3_DIR)/fft.c $(LAME_LIBMP3_DIR)/id3tag.c $(LAME_LIBMP3_DIR)/mpglib_interface.c $(LAME_LIBMP3_DIR)/presets.c $(LAME_LIBMP3_DIR)/quantize.c $(LAME_LIBMP3_DIR)/reservoir.c $(LAME_LIBMP3_DIR)/tables.c $(LAME_LIBMP3_DIR)/util.c $(LAME_LIBMP3_DIR)/VbrTag.c $(LAME_LIBMP3_DIR)/encoder.c $(LAME_LIBMP3_DIR)/gain_analysis.c $(LAME_LIBMP3_DIR)/lame.c $(LAME_LIBMP3_DIR)/newmdct.c $(LAME_LIBMP3_DIR)/psymodel.c $(LAME_LIBMP3_DIR)/quantize_pvt.c $(LAME_LIBMP3_DIR)/set_get.c $(LAME_LIBMP3_DIR)/takehiro.c $(LAME_LIBMP3_DIR)/vbrquantize.c $(LAME_LIBMP3_DIR)/version.c com_maxi_mp3record_MP3Recorder.c include $(BUILD_SHARED_LIBRARY)
**注意:**LAME_LIBMP3_DIR := lame-3.98.4_libmp3lame 需要將其改為你的項(xiàng)目中的文件名,即上面說的jni下新建的文件夾。
大家應(yīng)該看到了最后一句的com_maxi_mp3record_MP3Recorder.c
很明顯這是我自己創(chuàng)建的.c文件。用來調(diào)用mp3lame中的接口的,對應(yīng)著我java中的com.maxi.mp3record.MP3Recorder.java。咱們先創(chuàng)建java文件。
創(chuàng)建MP3Recorder.java
對應(yīng)你的包名建一個MP3Recorder.java文件,該文件是java文件對應(yīng)你的包名建立即可。
package cn.ctvonline.android.modules.project.widget; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import android.media.AudioFormat; import android.media.AudioRecord; import android.media.MediaRecorder; import android.os.Handler; /** * <b>類功能描述:</b><div > * MP3實(shí)時錄制功能,可暫停,注意因踩用Native開發(fā),不能混淆 */ public class MP3Recorder { private String filePath; private int sampleRate; private boolean isRecording = false; private boolean isPause = false; private Handler handler; /** * 開始錄音 */ public static final int MSG_REC_STARTED = 1; /** * 結(jié)束錄音 */ public static final int MSG_REC_STOPPED = 2; /** * 暫停錄音 */ public static final int MSG_REC_PAUSE = 3; /** * 繼續(xù)錄音 */ public static final int MSG_REC_RESTORE = 4; /** * 緩沖區(qū)掛了,采樣率手機(jī)不支持 */ public static final int MSG_ERROR_GET_MIN_BUFFERSIZE = -1; /** * 創(chuàng)建文件時撲街了 */ public static final int MSG_ERROR_CREATE_FILE = -2; /** * 初始化錄音器時撲街了 */ public static final int MSG_ERROR_REC_START = -3; /** * 錄緊音的時候出錯 */ public static final int MSG_ERROR_AUDIO_RECORD = -4; /** * 編碼時掛了 */ public static final int MSG_ERROR_AUDIO_ENCODE = -5; /** * 寫文件時掛了 */ public static final int MSG_ERROR_WRITE_FILE = -6; /** * 沒法關(guān)閉文件流 */ public static final int MSG_ERROR_CLOSE_FILE = -7; public MP3Recorder(int sampleRate) { this.sampleRate = sampleRate; } public void setFilePath(String filePath) { this.filePath = filePath; } /** * 開片 */ public void start() { if (isRecording) { return; } new Thread() { @Override public void run() { android.os.Process .setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO); // 根據(jù)定義好的幾個配置,來獲取合適的緩沖大小 final int minBufferSize = AudioRecord.getMinBufferSize( sampleRate, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT); if (minBufferSize < 0) { if (handler != null) { handler.sendEmptyMessage(MSG_ERROR_GET_MIN_BUFFERSIZE); } return; } AudioRecord audioRecord = new AudioRecord( MediaRecorder.AudioSource.MIC, sampleRate, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, minBufferSize * 2); // 5秒的緩沖 short[] buffer = new short[sampleRate * (16 / 8) * 1 * 5]; byte[] mp3buffer = new byte[(int) (7200 + buffer.length * 2 * 1.25)]; FileOutputStream output = null; try { File file = createSDFile(filePath); output = new FileOutputStream(file); } catch (FileNotFoundException e) { if (handler != null) { handler.sendEmptyMessage(MSG_ERROR_CREATE_FILE); } return; } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } MP3Recorder.init(sampleRate, 1, sampleRate, 32); isRecording = true; // 錄音狀態(tài) isPause = false; // 錄音狀態(tài) try { try { audioRecord.startRecording(); // 開啟錄音獲取音頻數(shù)據(jù) if (mListener != null) { mListener.wellPrepared(); } } catch (IllegalStateException e) { // 不給錄音... if (handler != null) { handler.sendEmptyMessage(MSG_ERROR_REC_START); } return; } try { // 開始錄音 if (handler != null) { handler.sendEmptyMessage(MSG_REC_STARTED); } int readSize = 0; boolean pause = false; while (isRecording) { /*--暫停--*/ if (isPause) { if (!pause) { handler.sendEmptyMessage(MSG_REC_PAUSE); pause = true; } continue; } if (pause) { handler.sendEmptyMessage(MSG_REC_RESTORE); pause = false; } /*--End--*/ /*--實(shí)時錄音寫數(shù)據(jù)--*/ readSize = audioRecord.read(buffer, 0, minBufferSize); voiceLevel = getVoiceSize(readSize, buffer); if (readSize < 0) { if (handler != null) { handler.sendEmptyMessage(MSG_ERROR_AUDIO_RECORD); } break; } else if (readSize == 0) { ; } else { int encResult = MP3Recorder.encode(buffer, buffer, readSize, mp3buffer); if (encResult < 0) { if (handler != null) { handler.sendEmptyMessage(MSG_ERROR_AUDIO_ENCODE); } break; } if (encResult != 0) { try { output.write(mp3buffer, 0, encResult); } catch (IOException e) { if (handler != null) { handler.sendEmptyMessage(MSG_ERROR_WRITE_FILE); } break; } } } /*--End--*/ } /*--錄音完--*/ int flushResult = MP3Recorder.flush(mp3buffer); if (flushResult < 0) { if (handler != null) { handler.sendEmptyMessage(MSG_ERROR_AUDIO_ENCODE); } } if (flushResult != 0) { try { output.write(mp3buffer, 0, flushResult); } catch (IOException e) { if (handler != null) { handler.sendEmptyMessage(MSG_ERROR_WRITE_FILE); } } } try { output.close(); } catch (IOException e) { if (handler != null) { handler.sendEmptyMessage(MSG_ERROR_CLOSE_FILE); } } /*--End--*/ } finally { audioRecord.stop(); audioRecord.release(); } } finally { MP3Recorder.close(); isRecording = false; } if (handler != null) { handler.sendEmptyMessage(MSG_REC_STOPPED); } } }.start(); } public void stop() { isRecording = false; } public void pause() { isPause = true; } public void restore() { isPause = false; } public boolean isRecording() { return isRecording; } public boolean isPaus() { if (!isRecording) { return false; } return isPause; } // 獲得聲音的level public int getVoiceSize(int r, short[] buffer) { if (isRecording) { try { long v = 0; // 將 buffer 內(nèi)容取出,進(jìn)行平方和運(yùn)算 for (int i = 0; i < buffer.length; i++) { v += buffer[i] * buffer[i]; } // 平方和除以數(shù)據(jù)總長度,得到音量大小。 double mean = v / (double) r; double volume = 10 * Math.log10(mean); return (((int) volume / 10) - 1); } catch (Exception e) { // TODO Auto-generated catch block } } return 1; } /** * 在SD卡上創(chuàng)建文件 * * @throws IOException */ public static File createSDFile(String fileName) throws IOException { File file = new File(fileName); if (!isFileExists(file)) if (file.isDirectory()) { file.mkdirs(); } else { file.createNewFile(); } return file; } private int voiceLevel; public int getVoiceLevel() { return voiceLevel; } public interface AudioStageListener { void wellPrepared(); } public AudioStageListener mListener; public void setOnAudioStageListener(AudioStageListener listener) { mListener = listener; } /** * 錄音狀態(tài)管理 * * @see RecMicToMp3#MSG_REC_STARTED * @see RecMicToMp3#MSG_REC_STOPPED * @see RecMicToMp3#MSG_REC_PAUSE * @see RecMicToMp3#MSG_REC_RESTORE * @see RecMicToMp3#MSG_ERROR_GET_MIN_BUFFERSIZE * @see RecMicToMp3#MSG_ERROR_CREATE_FILE * @see RecMicToMp3#MSG_ERROR_REC_START * @see RecMicToMp3#MSG_ERROR_AUDIO_RECORD * @see RecMicToMp3#MSG_ERROR_AUDIO_ENCODE * @see RecMicToMp3#MSG_ERROR_WRITE_FILE * @see RecMicToMp3#MSG_ERROR_CLOSE_FILE */ public void setHandle(Handler handler) { this.handler = handler; } /*--以下為Native部分--*/ static { System.loadLibrary("mp3lame"); } /** * 初始化錄制參數(shù) */ public static void init(int inSamplerate, int outChannel, int outSamplerate, int outBitrate) { init(inSamplerate, outChannel, outSamplerate, outBitrate, 7); } /** * 初始化錄制參數(shù) quality:0=很好很慢 9=很差很快 */ public native static void init(int inSamplerate, int outChannel, int outSamplerate, int outBitrate, int quality); /** * 音頻數(shù)據(jù)編碼(PCM左進(jìn),PCM右進(jìn),MP3輸出) */ public native static int encode(short[] buffer_l, short[] buffer_r, int samples, byte[] mp3buf); /** * 據(jù)說錄完之后要刷干凈緩沖區(qū) */ public native static int flush(byte[] mp3buf); /** * 結(jié)束編碼 */ public native static void close(); }
創(chuàng)建c文件
在創(chuàng)建c文件,創(chuàng)建在jni下,命名就按你的java文件所在的包名命名”.”替換為“_”。例如:com_maxi_mp3record_MP3Recorder.c。當(dāng)然還得有頭文件:com_maxi_mp3record_MP3Recorder.h。
com_maxi_mp3record_MP3Recorder.c
#include "lame-3.98.4_libmp3lame/lame.h" #include "com_maxi_mp3record_MP3Recorder.h" static lame_global_flags *glf = NULL; JNIEXPORT void JNICALL Java_com_maxi_mp3record_MP3Recorder_init( JNIEnv *env, jclass cls, jint inSamplerate, jint outChannel, jint outSamplerate, jint outBitrate, jint quality) { if (glf != NULL) { lame_close(glf); glf = NULL; } glf = lame_init(); lame_set_in_samplerate(glf, inSamplerate); lame_set_num_channels(glf, outChannel); lame_set_out_samplerate(glf, outSamplerate); lame_set_brate(glf, outBitrate); lame_set_quality(glf, quality); lame_init_params(glf); } JNIEXPORT jint JNICALL Java_com_maxi_mp3record_MP3Recorder_encode( JNIEnv *env, jclass cls, jshortArray buffer_l, jshortArray buffer_r, jint samples, jbyteArray mp3buf) { jshort* j_buffer_l = (*env)->GetShortArrayElements(env, buffer_l, NULL); jshort* j_buffer_r = (*env)->GetShortArrayElements(env, buffer_r, NULL); const jsize mp3buf_size = (*env)->GetArrayLength(env, mp3buf); jbyte* j_mp3buf = (*env)->GetByteArrayElements(env, mp3buf, NULL); int result = lame_encode_buffer(glf, j_buffer_l, j_buffer_r, samples, j_mp3buf, mp3buf_size); (*env)->ReleaseShortArrayElements(env, buffer_l, j_buffer_l, 0); (*env)->ReleaseShortArrayElements(env, buffer_r, j_buffer_r, 0); (*env)->ReleaseByteArrayElements(env, mp3buf, j_mp3buf, 0); return result; } JNIEXPORT jint JNICALL Java_com_maxi_mp3record_MP3Recorder_flush( JNIEnv *env, jclass cls, jbyteArray mp3buf) { const jsize mp3buf_size = (*env)->GetArrayLength(env, mp3buf); jbyte* j_mp3buf = (*env)->GetByteArrayElements(env, mp3buf, NULL); int result = lame_encode_flush(glf, j_mp3buf, mp3buf_size); (*env)->ReleaseByteArrayElements(env, mp3buf, j_mp3buf, 0); return result; } JNIEXPORT void JNICALL Java_com_maxi_mp3record_MP3Recorder_close( JNIEnv *env, jclass cls) { lame_close(glf); glf = NULL; }
com_maxi_mp3record_MP3Recorder.h
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_maxi_mp3record_MP3Recorder */ #ifndef _Included_com_maxi_mp3record_MP3Recorder #define _Included_com_maxi_mp3record_MP3Recorder #ifdef __cplusplus extern "C" { #endif /* * Class: com_maxi_mp3record_MP3Recorder * Method: init * Signature: (IIIII)V */ JNIEXPORT void JNICALL Java_com_maxi_mp3record_MP3Recorder_init (JNIEnv *, jclass, jint, jint, jint, jint, jint); /* * Class: com_maxi_mp3record_MP3Recorder * Method: encode * Signature: ([S[SI[B)I */ JNIEXPORT jint JNICALL Java_com_maxi_mp3record_MP3Recorder_encode (JNIEnv *, jclass, jshortArray, jshortArray, jint, jbyteArray); /* * Class: com_maxi_mp3record_MP3Recorder * Method: flush * Signature: ([B)I */ JNIEXPORT jint JNICALL Java_com_maxi_mp3record_MP3Recorder_flush (JNIEnv *, jclass, jbyteArray); /* * Class: com_maxi_mp3record_MP3Recorder * Method: close * Signature: ()V */ JNIEXPORT void JNICALL Java_com_maxi_mp3record_MP3Recorder_close (JNIEnv *, jclass); #ifdef __cplusplus } #endif #endif
這倆文件別只復(fù)制不看內(nèi)容啊,里面可都是連接java和c的接口,所以不能有差錯。舉個例子吧,#ifndef _Included_com_maxi_mp3record_MP3Recorder,這個就得替換成你對應(yīng)的包名,里面所有都得替換成你自己的程序?qū)?yīng)的包名。
編譯ndk
創(chuàng)建Application.mk在你的項(xiàng)目文件的jni下,在里面寫入:
APP_ABI := all
如果不加,NDK只會編譯“armeabi”,然而安卓有很多不同類型的處理器,所以我們不止需要arm。相信你們搞到現(xiàn)在了肯定ndk都配置好了,然后打開終端,進(jìn)入到你的項(xiàng)目(找到你的ndk目錄下的ndk-bulid,最好把它添加到環(huán)境變量里,對于以后編譯比較方便,在此默認(rèn)你沒添加環(huán)境變量),執(zhí)行ndk-bulid。稍等片刻你會發(fā)現(xiàn)你的項(xiàng)目里多了一個obj文件夾,obj文件夾下會生成”arm64-v8a”、”armeabi”、”armeabi-v7a”、”mips”、”mips64”、”x86”、”x86_64”。打開它,各個文件夾下會有一個libmp3lame.so。ok,沒錯那就是你要的“滑板鞋”。將它放入你的libs文件下,沒有自行創(chuàng)建,各個平臺便都可以加載了。
使用方法
MP3Recorder recorder = new MP3Recorder(8000); recorder.setFilePath(voicePath);//錄音保存目錄 recorder.start();//開始錄音 recorder.stop();//錄音結(jié)束 recorder.getVoiceLevel()//這是我封裝的獲取音頻振幅接口,大家可以用來錄音的時候顯示聲音大小,數(shù)據(jù)自行調(diào)節(jié)。
看完上述內(nèi)容,你們掌握Android中怎么錄制mp3格式文件的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。