58. 【Android教程】音频录制:MediaRecord

在第 57 节我们使用 MediaPlayer 实现了一个 mp3 播放器,除了播放 Android 还提供了 MediaRecorder 用于录音。Android 设备基本都会有一个麦克风,通过 MediaRecorder 可以打开麦克风进行语音采集,这一节我们就来学习如何在 Android 系统上实现一个录音功能。

1. MediaRecorder 常用接口

  • setAudioSource():
    设置录制的音频源
  • setVideoSource():
    设置录制的视频源
  • setOutputFormat():
    设置输出格式
  • setAudioEncoder():
    设置音频编码器
  • setOutputFile():
    配置录制的音频存储文件路径
  • stop():
    停止录制
  • release():
    释放 MediaRecorder 实例,回收其所占资源

2. MediaRecorder 的使用步骤

  1. 创建 MediaRecorder
    直接通过无参构造器创建即可:
MediaRecorder myAudioRecorder = new MediaRecorder();
  1. 配置录音参数
    创建好之后,再对 MediaRecorder 实例进行参数配置,配置项有很多,一般需要设置音频输入源、音频输出格式、音频编码方式以及输出文件目录,如下:
myAudioRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
myAudioRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
myAudioRecorder.setAudioEncoder(MediaRecorder.OutputFormat.AMR_NB);
myAudioRecorder.setOutputFile(outputFile);
  1. 开始录音
    在确定了录音配置和输出目录之后,我们就可以调用一下两个方法开始录音了:
myAudioRecorder.prepare();
myAudioRecorder.start();
  1. 停止录音
    录音结束调用stop()停止录制,如果不再使用还要记得调用release()释放 MediaRecorder 所占用的资源

3. 录音示例

本节使用 MediaRecorder 实现一个录音机:

3.1 MediaRecorder 控制逻辑

作为一个完整的录音功能,当然在录音结束之后也得要能回放录音。所以整个的控制要分为录音控制和播放控制,我们按照上一小节讲述的步骤用 MediaRecorder 完成录音,然后调用 MediaPlayer 来完成录音回放:


package com.emercy.myapplication;import android.app.Activity;
import android.content.pm.PackageManager;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;import java.io.IOException;
import java.util.Random;import static android.Manifest.permission.RECORD_AUDIO;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;public class MainActivity extends Activity {Button buttonStart, buttonStop, buttonPlayLastRecordAudio,buttonStopPlayingRecording;String AudioSavePathInDevice = null;MediaRecorder mediaRecorder;Random random;String RandomAudioFileName = "emercy";public static final int RequestPermissionCode = 1;MediaPlayer mediaPlayer;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);buttonStart = findViewById(R.id.button);buttonStop = findViewById(R.id.button2);buttonPlayLastRecordAudio = findViewById(R.id.button3);buttonStopPlayingRecording = findViewById(R.id.button4);buttonStop.setEnabled(false);buttonPlayLastRecordAudio.setEnabled(false);buttonStopPlayingRecording.setEnabled(false);random = new Random();buttonStart.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {if (checkPermission()) {AudioSavePathInDevice =Environment.getExternalStorageDirectory().getAbsolutePath() + "/" +CreateRandomAudioFileName(5) + "AudioRecording.3gp";MediaRecorderReady();try {mediaRecorder.prepare();mediaRecorder.start();} catch (IllegalStateException | IOException e) {e.printStackTrace();}buttonStart.setEnabled(false);buttonStop.setEnabled(true);Toast.makeText(MainActivity.this, "Recording started",Toast.LENGTH_LONG).show();} else {requestPermission();}}});buttonStop.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {mediaRecorder.stop();buttonStop.setEnabled(false);buttonPlayLastRecordAudio.setEnabled(true);buttonStart.setEnabled(true);buttonStopPlayingRecording.setEnabled(false);Toast.makeText(MainActivity.this, "Recording Completed", Toast.LENGTH_LONG).show();}});buttonPlayLastRecordAudio.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) throws IllegalArgumentException,SecurityException, IllegalStateException {buttonStop.setEnabled(false);buttonStart.setEnabled(false);buttonStopPlayingRecording.setEnabled(true);mediaPlayer = new MediaPlayer();try {mediaPlayer.setDataSource(AudioSavePathInDevice);mediaPlayer.prepare();} catch (IOException e) {e.printStackTrace();}mediaPlayer.start();Toast.makeText(MainActivity.this, "录音完毕", Toast.LENGTH_LONG).show();}});buttonStopPlayingRecording.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {buttonStop.setEnabled(false);buttonStart.setEnabled(true);buttonStopPlayingRecording.setEnabled(false);buttonPlayLastRecordAudio.setEnabled(true);if (mediaPlayer != null) {mediaPlayer.stop();mediaPlayer.release();MediaRecorderReady();}}});}public void MediaRecorderReady() {mediaRecorder = new MediaRecorder();mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);mediaRecorder.setAudioEncoder(MediaRecorder.OutputFormat.AMR_NB);mediaRecorder.setOutputFile(AudioSavePathInDevice);}public String CreateRandomAudioFileName(int string) {StringBuilder stringBuilder = new StringBuilder(string);int i = 0;while (i < string) {stringBuilder.append(RandomAudioFileName.charAt(random.nextInt(RandomAudioFileName.length())));i++;}return stringBuilder.toString();}private void requestPermission() {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {requestPermissions(new String[]{WRITE_EXTERNAL_STORAGE, RECORD_AUDIO}, RequestPermissionCode);}}@Overridepublic void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {if (requestCode == RequestPermissionCode) {if (grantResults.length > 0) {boolean StoragePermission = grantResults[0] ==PackageManager.PERMISSION_GRANTED;boolean RecordPermission = grantResults[1] ==PackageManager.PERMISSION_GRANTED;if (StoragePermission && RecordPermission) {Toast.makeText(MainActivity.this, "Permission Granted", Toast.LENGTH_LONG).show();} else {Toast.makeText(MainActivity.this, "Permission Denied", Toast.LENGTH_LONG).show();}}}}public boolean checkPermission() {int storagePermission = 0;int recordPermission = 0;if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {storagePermission = checkSelfPermission(WRITE_EXTERNAL_STORAGE);recordPermission = checkSelfPermission(RECORD_AUDIO);}return storagePermission == PackageManager.PERMISSION_GRANTED &&recordPermission == PackageManager.PERMISSION_GRANTED;}
}

和拍照一样,录音也需要获取权限(注意 Android 6.0 以上还需要动态获取权限),除此之外只需要按照步骤进行录音就可以实现功能了。

3.2 录音布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:padding="30dp"><Buttonandroid:id="@+id/button"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentStart="true"android:layout_marginTop="37dp"android:text="录音" /><Buttonandroid:id="@+id/button2"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignTop="@+id/button"android:layout_centerHorizontal="true"android:text="停止" /><Buttonandroid:id="@+id/button3"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignTop="@+id/button2"android:layout_alignParentEnd="true"android:layout_alignParentRight="true"android:text="回放" /><Buttonandroid:id="@+id/button4"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_below="@+id/button2"android:layout_centerHorizontal="true"android:layout_marginTop="10dp"android:text="结束回放" />
</RelativeLayout>

对于两大功能:“录音”和“回放”,各提供两个按键控制,分别对应开始和结束。

最终编译效果:

4. 小结

MediaRecorder 很多时候都是配合 MediaPlayer 或者其他播放器一起使用,而两者之间也有很多相似之处。当然本节提到的只是最基本的录音及音频输出功能,如果需要进一步研究音视频相关的内容就得深入到底层编解码原理。不过对于大多数非专业音视频制作 App 而言已经足够。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/681223.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

燃气电力瓶装气行业入户安检小程序开发

我们开发的小区业主入户安检小程序&#xff0c;旨在满足燃气、电力以及其他需要入户安检的行业需求。该程序支持自定义安检项目&#xff0c;实现线下实地安检与线上数据保存的完美结合。在安检过程中&#xff0c;我们可以拍照或录像&#xff0c;以确保安检的透明性和可追溯性&a…

CTF 竞赛训练题

1.N种方法解决 发现文件头后面有个base64 解码出来提示是png了&#xff0c;那把它解码之后的数据转成图片&#xff1a; 扫码得到flag。 2.大白 根据提示和大佬的wp得知是修改了文件的高度&#xff0c;因此还原文件高度就行。 这里把1图片用winhex打开&#xff1a; 这里放一下…

latex algorithm2e 库学习总结

案例1 \documentclass{article}\usepackage{xeCJK} \usepackage[]{algorithm2e} %\usepackage{ctex} % 中文包\begin{document}\renewcommand{\algorithmcfname}{算法} % 把标题设置为“算法” \begin{algorithm…

自动镭雕机价格是多少?

自动镭雕机是一种高精度、高效率的激光雕刻设备&#xff0c;广泛应用于手机、电脑、玻璃等产品表面的图案雕刻。那么&#xff0c;自动镭雕机多少钱一台呢&#xff1f;本文将为您详细解析各种因素对自动镭雕机价格的影响。 一、影响自动镭雕机价格的因素 1. 品牌和质量 自动镭…

【优选算法】——Leetcode——LCR 179. 查找总价格为目标值的两个商品

1.题目 2. 解法⼀&#xff08;暴⼒解法&#xff0c;会超时&#xff09;&#xff1a; 1.算法思路&#xff1a; 2.图解 3. 代码实现 3. 解法⼆&#xff08;双指针-对撞指针&#xff09;&#xff1a; 1.算法思路&#xff1a; 2.图解 3.代码实现 1.C语言 2…

Vuex 和 Pinia 两个状态管理模式的区别

Pinia和Vuex一样都是是vue的全局状态管理器。其实Pinia就是Vuex5&#xff0c;只不过为了尊重原作者的贡献就沿用了这个看起来很甜的名字Pinia。&#xff08;实际项目中千万不要即用Vuex又用Pinia&#xff0c;不然你会被同事‘’请去喝茶的‘’。 一、安装&#xff08;常用命令安…

mysql其它补充

exist和in的区别 exists 用于对外表记录做筛选。 exists 会遍历外表&#xff0c;将外查询表的每一行&#xff0c;代入内查询进行判断。 当 exists 里的条件语句能够返回记录行时&#xff0c;条件就为真&#xff0c;返回外表当前记录。反之如果 exists 里的条件语句不能返回记…

【数据结构与算法】力扣 226. 翻转二叉树

题目描述 给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。 示例 1&#xff1a; 输入&#xff1a; root [4,2,7,1,3,6,9] 输出&#xff1a; [4,7,2,9,6,3,1]示例 2&#xff1a; 输入&#xff1a; root [2,1,3] 输出&#xff1a; [2,3,1…

【C++】Visual Studio 2019 给 C++ 文件添加头部注释说明

使用代码片段管理器&#xff0c;添加快捷插入代码文件说明 1. 效果 2. header.snippet 新建 header.snippet 文件&#xff0c;存放到某个文件夹 内容&#xff0c;自行更新 快捷名称&#xff0c;修改 Header 里面内容注释内容&#xff0c;修改 Code 里面内容 <?xml ver…

每日一题 第九十七期 洛谷 [NOIP2000 提高组] 方格取数

[NOIP2000 提高组] 方格取数 题目背景 NOIP 2000 提高组 T4 题目描述 设有 N N N \times N NN 的方格图 ( N ≤ 9 ) (N \le 9) (N≤9)&#xff0c;我们将其中的某些方格中填入正整数&#xff0c;而其他的方格中则放入数字 0 0 0。如下图所示&#xff08;见样例&#xf…

umi6.x + react + antd的项目增加403(无权限页面拦截),404,错误处理页面

首先在src/pages下创建403&#xff0c;404&#xff0c;ErrorBoundary 403 import { Button, Result } from antd; import { history } from umijs/max;const UnAccessible () > (<Resultstatus"403"title"403"subTitle"抱歉&#xff0c;您无权…

C++ | Leetcode C++题解之第70题爬楼梯

题目&#xff1a; 题解&#xff1a; class Solution { public:int climbStairs(int n) {double sqrt5 sqrt(5);double fibn pow((1 sqrt5) / 2, n 1) - pow((1 - sqrt5) / 2, n 1);return (int)round(fibn / sqrt5);} };