版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
【移動應用開發(fā)技術】Android中怎么錄制mp3格式文件
Android中怎么錄制mp3格式文件,相信很多沒有經驗的人對此束手無策,為此本文總結了問題出現的原因和解決方法,通過這篇文章希望你能解決這個問題。工具MP3格式是用一個開源項目轉的,MP3lame,由于該項目用到了jni,所以需要大家配置好ndk環(huán)境,環(huán)境配置在此就不多說了,大家可以自行百度,最新的應該很好配置。創(chuàng)建jni拷貝文件下載好后(我下載的是3.98.4版本)打開,找到libmp3lame文件,將里面的.h和.c拷貝下來,在自己的工程里創(chuàng)建jni文件夾,在jni文件夾下新建一個文件夾(我的命名為lame-3.98.4_libmp3lame,后面會用到),將剛才拷貝的文件復制進去,然后再把include文件夾里的lame.h也拷貝進去。創(chuàng)建Android.mk在jni中創(chuàng)建文件,Android.mkLOCAL_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需要將其改為你的項目中的文件名,即上面說的jni下新建的文件夾。大家應該看到了最后一句的com_maxi_mp3record_MP3Recorder.c很明顯這是我自己創(chuàng)建的.c文件。用來調用mp3lame中的接口的,對應著我java中的com.maxi.mp3record.MP3Recorder.java。咱們先創(chuàng)建java文件。創(chuàng)建MP3Recorder.java對應你的包名建一個MP3Recorder.java文件,該文件是java文件對應你的包名建立即可。package
ject.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實時錄制功能,可暫停,注意因踩用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;
/**
*
結束錄音
*/
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ū)掛了,采樣率手機不支持
*/
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;
/**
*
沒法關閉文件流
*/
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;
//
錄音狀態(tài)
isPause
=
false;
//
錄音狀態(tài)
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卡上創(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");
}
/**
*
初始化錄制參數
*/
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);
/**
*
據說錄完之后要刷干凈緩沖區(qū)
*/
public
native
static
int
flush(byte[]
mp3buf);
/**
*
結束編碼
*/
public
native
static
void
close();
}創(chuàng)建c文件在創(chuàng)建c文件,創(chuàng)建在jni下,命名就按你的java文件所在的包名命名”.”替換為“_”。例如:com_maxi_mp3record_MP3Recorder.c。當然還得有頭文件:com_maxi_mp3record_MP3R_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
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2024年度云南省高校教師資格證之高等教育心理學題庫練習試卷B卷附答案
- 2023年異噻唑啉酮投資申請報告
- 加氫工藝理論考試題庫及答案
- 福建師范大學《移動通信系統優(yōu)化》2021-2022學年第一學期期末試卷
- 福建師范大學《體育統計學》2023-2024學年第一學期期末試卷
- 果園虧損財務分析報告示例
- 福建師范大學《環(huán)境監(jiān)測實驗》2023-2024學年第一學期期末試卷
- 福建師范大學《關系管理》2023-2024學年第一學期期末試卷
- 第二章 能量和營養(yǎng)素第一節(jié)基本概念課件
- 機械加工常用材料的熱處理工藝表
- oracle數據庫巡檢內容
- 鐵路安全管理試題庫含答案全套
- 2022-2023學年貴州省貴陽市九年級(上)期中數學試題及答案解析
- 下白雨合唱簡譜
- 世界各國國家代號、區(qū)號、時差
- 自由貿易試驗區(qū)的發(fā)展策略
- 安全生產的理論與實踐培訓
- MSA-GRR數據自動生成工具演示教學
- 工程水文學題庫及題解(全)
- 個人征信承諾書
- 藥劑科靜配中心院內感染預防與控制考核標準表格2022版
評論
0/150
提交評論