国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android錄制mp3格式文件

2019-10-22 18:30:09
字體:
來源:轉載
供稿:網友

前言

最近做一個即時通信類的項目,由于要保證pc端,iOS端和Android端的通用性,最終統一為MP3格式,一直擔心MP3格式會不會很大,但是實測還是可以接受的。下面來看看具體步驟:

工具

MP3格式是用一個開源項目轉的,MP3lame,由于該項目用到了jni,所以需要大家配置好ndk環境,環境配置在此就不多說了,大家可以自行百度,最新的應該很好配置。

創建jni

拷貝文件

下載好后(我下載的是3.98.4版本)打開,找到libmp3lame文件,將里面的.h和.c拷貝下來,在自己的工程里創建jni文件夾,在jni文件夾下新建一個文件夾(我的命名為lame-3.98.4_libmp3lame,后面會用到),將剛才拷貝的文件復制進去,然后再把include文件夾里的lame.h也拷貝進去。

創建Android.mk

在jni中創建文件,Android.mk

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LAME_LIBMP3_DIR := lame-3.98.4_libmp3lameLOCAL_MODULE  := mp3lameLOCAL_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.cinclude $(BUILD_SHARED_LIBRARY)

**注意:**LAME_LIBMP3_DIR := lame-3.98.4_libmp3lame 需要將其改為你的項目中的文件名,即上面說的jni下新建的文件夾。

大家應該看到了最后一句的com_maxi_mp3record_MP3Recorder.c
很明顯這是我自己創建的.c文件。用來調用mp3lame中的接口的,對應著我java中的com.maxi.mp3record.MP3Recorder.java。咱們先創建java文件。

創建MP3Recorder.java

對應你的包名建一個MP3Recorder.java文件,該文件是java文件對應你的包名建立即可。

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 style="margin-left:40px;margin-top:-10px"> * MP3實時錄制功能,可暫停,注意因踩用Native開發,不能混淆 */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; /**  * 結束錄音  */ public static final int MSG_REC_STOPPED = 2; /**  * 暫停錄音  */ public static final int MSG_REC_PAUSE = 3; /**  * 繼續錄音  */ public static final int MSG_REC_RESTORE = 4; /**  * 緩沖區掛了,采樣率手機不支持  */ public static final int MSG_ERROR_GET_MIN_BUFFERSIZE = -1; /**  * 創建文件時撲街了  */ 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; /**  * 沒法關閉文件流  */ 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);    // 根據定義好的幾個配置,來獲取合適的緩沖大小    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; // 錄音狀態    isPause = false; // 錄音狀態    try {     try {      audioRecord.startRecording(); // 開啟錄音獲取音頻數據      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--*/       /*--實時錄音寫數據--*/       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 內容取出,進行平方和運算    for (int i = 0; i < buffer.length; i++) {     v += buffer[i] * buffer[i];    }    // 平方和除以數據總長度,得到音量大小。    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卡上創建文件  *   * @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; } /**  * 錄音狀態管理  *   * @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"); } /**  * 初始化錄制參數  */ public static void init(int inSamplerate, int outChannel,   int outSamplerate, int outBitrate) {  init(inSamplerate, outChannel, outSamplerate, outBitrate, 7); } /**  * 初始化錄制參數 quality:0=很好很慢 9=很差很快  */ public native static void init(int inSamplerate, int outChannel,   int outSamplerate, int outBitrate, int quality); /**  * 音頻數據編碼(PCM左進,PCM右進,MP3輸出)  */ public native static int encode(short[] buffer_l, short[] buffer_r,   int samples, byte[] mp3buf); /**  * 據說錄完之后要刷干凈緩沖區  */ public native static int flush(byte[] mp3buf); /**  * 結束編碼  */ public native static void close();}

創建c文件

在創建c文件,創建在jni下,命名就按你的java文件所在的包名命名”.”替換為“_”。例如:com_maxi_mp3record_MP3Recorder.c。當然還得有頭文件: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 __cplusplusextern "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

這倆文件別只復制不看內容啊,里面可都是連接java和c的接口,所以不能有差錯。舉個例子吧,#ifndef _Included_com_maxi_mp3record_MP3Recorder,這個就得替換成你對應的包名,里面所有都得替換成你自己的程序對應的包名。

編譯ndk

創建Application.mk在你的項目文件的jni下,在里面寫入:
APP_ABI := all
如果不加,NDK只會編譯“armeabi”,然而安卓有很多不同類型的處理器,所以我們不止需要arm。相信你們搞到現在了肯定ndk都配置好了,然后打開終端,進入到你的項目(找到你的ndk目錄下的ndk-bulid,最好把它添加到環境變量里,對于以后編譯比較方便,在此默認你沒添加環境變量),執行ndk-bulid。稍等片刻你會發現你的項目里多了一個obj文件夾,obj文件夾下會生成”arm64-v8a”、”armeabi”、”armeabi-v7a”、”mips”、”mips64”、”x86”、”x86_64”。打開它,各個文件夾下會有一個libmp3lame.so。ok,沒錯那就是你要的“滑板鞋”。將它放入你的libs文件下,沒有自行創建,各個平臺便都可以加載了。

使用方法

MP3Recorder recorder = new MP3Recorder(8000);recorder.setFilePath(voicePath);//錄音保存目錄recorder.start();//開始錄音recorder.stop();//錄音結束recorder.getVoiceLevel()//這是我封裝的獲取音頻振幅接口,大家可以用來錄音的時候顯示聲音大小,數據自行調節。

總結

之前一直用MediaRecorder錄音,發現錄出來的只能是amr、acc等格式,用lame轉MP3感覺是不可行的。我試了沒能成功,不知道具體是什么原因,所以大家有時間可以研究研究,沒時間就不要嘗試了。

Mp3lame錄制出來的聲音還是挺靠譜的(不過據聽說iOS就有些莎莎聲),然后錄制出來的大小還是可以接受的,五秒鐘的音頻大概在20k左右的樣子吧。使用還是很方便的。如果有什么疑問或建議請留言哈。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VEVB武林網。


注:相關教程知識閱讀請移步到Android開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 田东县| 彭山县| 乌兰浩特市| 宝清县| 平泉县| 枞阳县| 濮阳市| 平定县| 灵丘县| 兴隆县| 延寿县| 青浦区| 南靖县| 临颍县| 长泰县| 柏乡县| 新龙县| 永城市| 克什克腾旗| 逊克县| 肃南| 牟定县| 湖州市| 中阳县| 屏南县| 平南县| 新和县| 邛崃市| 阿合奇县| 宝丰县| 江门市| 盈江县| 青川县| 梁山县| 盐源县| 贵阳市| 高碑店市| 合山市| 吉水县| 康乐县| 珲春市|