package com.example.wang.audiorecordermp3;
import android.Manifest;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.KeyEvent;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import com.buihha.audiorecorder.Mp3Recorder;
import com.example.wang.audiorecordermp3.util.FileUtils;
import java.io.IOException;
public class MainActivity extends AppCompatActivity implements Mp3Recorder.RecorderListener {
Mp3Recorder mp3Recorder;
private String path = Environment.getExternalStorageDirectory()
+ "/AudioRecorderMp3/recorder/";
String[] permiss = new String[]{Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.RECORD_AUDIO};
int REQUEST_CODE = 1002;
String filePath;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(!checkMyPermission(permiss)){
ActivityCompat.requestPermissions(this,permiss,REQUEST_CODE);
}
findViewById(R.id.start).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
if(mp3Recorder == null){
filePath = path + FileUtils.getFileNameByTime() + ".mp3";
mp3Recorder = new Mp3Recorder(filePath);
mp3Recorder.setListener(MainActivity.this);
}
if(mp3Recorder.isRecording()){
mp3Recorder.pasueRecording();
((Button)v).setText("Start Recorder");
Toast.makeText(MainActivity.this,"暂停录音!",Toast.LENGTH_SHORT).show();
}else{
mp3Recorder.startRecording();
((Button)v).setText("Pasue Recorder");
Toast.makeText(MainActivity.this,"开始录音!",Toast.LENGTH_SHORT).show();
}
} catch (IOException e) {
e.printStackTrace();
}
}
});
findViewById(R.id.stop).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
if (mp3Recorder == null) {
Toast.makeText(MainActivity.this,"您还未开始录音呢!",Toast.LENGTH_SHORT).show();
} else {
mp3Recorder.stopRecording();
Toast.makeText(MainActivity.this,"结束录音!",Toast.LENGTH_SHORT).show();
((Button)findViewById(R.id.start)).setText("Start Recorder");
mp3Recorder = null;
}
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
private boolean checkMyPermission(String[] permiss){
if(permiss !=null && permiss.length > 0 ){
for(String per : permiss) {
if (ContextCompat.checkSelfPermission(this,per) != PackageManager.PERMISSION_GRANTED){
return false;
}
}
}
return true;
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults){
if (requestCode == REQUEST_CODE) {
boolean isAllGranted = true;
// 判断是否所有的权限都已经授予了
for (int grant : grantResults) {
if (grant != PackageManager.PERMISSION_GRANTED) {
isAllGranted = false;
break;
}
}
if (isAllGranted) {
} else {
// 弹出对话框告诉用户需要权限的原因, 并引导用户去应用权限管理中手动打开权限按钮
openAppDetails();
}
}
}
/**
* 打开 APP 的详情设置
*/
private void openAppDetails() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("录音需要访问 “外部存储器”,请到 “应用信息 -> 权限” 中授予!");
builder.setPositiveButton("去手动授权", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent();
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setData(Uri.parse("package:" + getPackageName()));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
startActivity(intent);
}
});
builder.setNegativeButton("取消", null);
builder.show();
}
/**
* 完成录制触发的函数,可进行文件上传操作
*/
@Override
public void stop() {
Toast.makeText(MainActivity.this,"录音文件保存完毕,文件保存在:" + filePath,Toast.LENGTH_SHORT).show();
}
@Override
protected void onDestroy() {
super.onDestroy();
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if(keyCode == KeyEvent.KEYCODE_BACK) {
if (mp3Recorder != null && mp3Recorder.isRecording()) {
new AlertDialog.Builder(this).setTitle("提示").setMessage("正在录音中,是否保存正在录制的音频?").setPositiveButton("是", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
try {
mp3Recorder.stopRecording();
Toast.makeText(MainActivity.this, "结束录音!", Toast.LENGTH_SHORT).show();
mp3Recorder = null;
} catch (IOException e) {
e.printStackTrace();
}
MainActivity.this.finish();
System.exit(0);
}
}).setNegativeButton("否", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
try {
mp3Recorder.stopRecording();
Toast.makeText(MainActivity.this, "结束录音!", Toast.LENGTH_SHORT).show();
mp3Recorder = null;
FileUtils.deleteFile(filePath);
} catch (IOException e) {
e.printStackTrace();
}
MainActivity.this.finish();
System.exit(0);
}
}).create().show();
}
return false;
}
return super.onKeyDown(keyCode, event);
}
}
Android实时录制音频为Mp3格式

在Android平台上,实时录制音频并将其保存为MP3格式是一个常见的需求,这涉及到对音频处理和文件编码的理解。本文将详细解析如何通过`AudioRecord`类实现音频录制,并结合编码库将其转换为MP3格式。
`AudioRecord`是Android SDK提供的一种原生API,用于捕获设备麦克风的音频数据。它需要设置如采样率、通道数和音频格式等参数。例如,通常我们选择44100Hz的采样率,立体声(2通道)和16位的PCM格式,这些参数应与播放音频时使用的`AudioTrack`类相匹配,以确保音频质量和兼容性。
```java
int sampleRate = 44100; // 采样率
int channelConfig = AudioFormat.CHANNEL_IN_STEREO; // 立体声
int audioFormat = AudioFormat.ENCODING_PCM_16BIT; // 16位PCM格式
int bufferElements2Rec = 1024; // 缓冲区大小
int bufferSize = bufferElements2Rec * 2 * channelConfig * audioFormat / 8;
AudioRecord recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRate, channelConfig, audioFormat, bufferSize);
```
接下来,我们需要开启录音并处理音频数据。`AudioRecord.startRecording()`启动录音,然后在一个循环中读取缓冲区的数据。为了实时保存为MP3,我们需要一个编码库,如Lame MP3编码器。Lame是一个广泛使用的开源MP3编码库,可以在Java中通过JNI(Java Native Interface)调用。
```java
recorder.startRecording();
short[] buffer = new short[bufferSize];
while (isRecording) {
int readSize = recorder.read(buffer, 0, bufferSize);
if (readSize > 0) {
// 将PCM数据编码为MP3
encodePcmToMp3(buffer, readSize);
}
}
recorder.stop();
```
`encodePcmToMp3`函数涉及将PCM数据传递给Lame库进行编码。由于Lame库是C/C++实现,需要通过JNI桥接。在C++部分编写编码逻辑,然后在Java端创建一个JNI方法声明。在编码完成后,将生成的MP3数据写入到文件中。
```cpp
JNIEXPORT void JNICALL Java_com_example_AudioRecorderMp3_encodePcmToMp3(JNIEnv *env, jobject thiz, jshortArray pcmData, jint length) {
// 获取PCM数据
short *pcm = env->GetShortArrayElements(pcmData, NULL);
// ... Lame编码逻辑 ...
// 将编码后的MP3数据写入文件
// ...
env->ReleaseShortArrayElements(pcmData, pcm, 0);
}
```
在实际应用中,还需要考虑暂停和恢复录音功能。可以通过设置`isRecording`标志来控制`AudioRecord`的读取循环。当需要暂停时,设置`isRecording`为`false`;恢复时,将其设置回`true`。
此外,为了保证用户界面的响应性和避免内存泄漏,录音过程通常在后台线程执行,而UI操作(如开始、暂停、停止按钮的点击事件)在主线程处理。通过`Handler`或`AsyncTask`等机制,可以在不同线程间传递控制命令。
别忘了在应用中处理权限。在Android 6.0及以上版本,需要动态请求`RECORD_AUDIO`权限。
总结,实现Android实时录制音频为MP3格式涉及使用`AudioRecord`进行音频采集,通过JNI调用Lame库进行MP3编码,并在适当的时候开始、暂停和停止录音。这个过程涵盖了音频处理、文件编码、多线程编程以及权限管理等多个Android开发的关键知识点。

非洲的企鹅0_0
- 粉丝: 13
最新资源
- 数据库实验2:表的创建与管理.docx
- 专起本《工程项目管理》C试卷.doc
- 国家开放大学电大《桥梁工程技术》《会计学概论》网络课形考网考作业(合集)答案.docx
- 字形字体处理C语言课程设计范文.doc
- 网络游戏市场分析及媒体投放分析报告.pptx
- 最新毕业论文基于PLC的自动卷帘门控制系统.doc
- 制冷系统安全技术操作规程.doc
- 机械自动化设备优化策略分析获奖科研报告论文.docx
- 基于PLC与触摸屏的恒压供水电气系统设计.doc
- 告别网络游戏PPT课件.ppt
- 计算机体系结构实验报告二.doc
- 小程序如何运营?.docx
- 综合布线工程竣工验收报告样本.doc
- 2023年职称计算机试题及答案.doc
- 选煤工艺流程软件开发平台的选择.doc
- 综合楼综合布线系统方案.doc
- 1
- 2
前往页