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.mzph.cn/bicheng/9058.shtml

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

相关文章

深入解析C++的auto自动类型推导(二)

目录 使用auto的好处 新标准新增功能 使用auto的限制 上一篇详细讲解了使用auto关键字进行自动类型推导时的推导规则&#xff0c;这一篇重点讲解auto的使用以及C14、C17、C20等新标准对auto的功能完善&#xff0c;最后再介绍auto的使用限制。上一篇请从这里阅读&#xff1a;…

线程池核心原理浅析

前言 由于系统资源是有限的&#xff0c;为了降低资源消耗&#xff0c;提高系统的性能和稳定性&#xff0c;引入了线程池对线程进行统一的管理和监控&#xff0c;本文将详细讲解线程池的使用、原理。 为什么使用线程池 池化思想 线程池主要用到了池化思想&#xff0c;池化思想…

【计算机科学速成课】笔记一

文章目录 写在前面1.计算机的早期历史2.电子计算机3.布尔运算和逻辑门4.二进制5.算术逻辑单元-ALU6.寄存器和内存 写在前面 所有的一切源于这样一个网站——CS自学指南。 这是新手小白入门计算机科学必要了解的知识——【计算机科学速成课】[40集全/精校] - Crash Course Comp…

Dragonfly 拓扑的路由算法

Dragonfly 拓扑的路由算法 1. Dragonfly 上的路由 (1)最小路由(2)非最小路由 2. 评估3. 存在问题 (1)吞吐量限制(2)较高的中间延迟 references Dragonfly 拓扑的路由算法 John Kim, William J. Dally 等人在 2008 年的 ISCA 中提出技术驱动、高度可扩展的 Dragonfly 拓扑。而…

在做题中学习(53): 寻找旋转数组中的最小值

153. 寻找旋转排序数组中的最小值 - 力扣&#xff08;LeetCode&#xff09; 解法&#xff1a;O(logn)->很可能就是二分查找 思路&#xff1a;再看看题目要求&#xff0c;可以画出旋转之后数组中元素的大小关系&#xff1a; 首先&#xff0c;数组是具有二段性的(适配二分查…

数据库(MySQL)—— 索引

数据库&#xff08;MySQL&#xff09;—— 索引 什么是索引创建索引使用 CREATE INDEX 语句使用 ALTER TABLE 语句在创建表时定义索引特殊类型索引注意事项 举个例子无索引的情况有索引的情况为什么索引快索引的结构 今天我们来看看MySQL中的索引&#xff1a; 什么是索引 MyS…

财政部、交通运输部:推动北斗导航等新技术与交通基础设施融合

财政部、交通运输部&#xff1a;推动北斗导航等新技术与交通基础设施深度融合 近日&#xff0c;为深入贯彻落实中共中央、国务院关于加快建设交通强国、数字中国等决策部署&#xff0c;推进公路水路交通基础设施数字转型、智能升级、融合创新&#xff0c;加快发展新质生产力&a…

智能BI(后端) -- 智能分析业务

文章目录 业务流程开发接口easyExcel从excel读取数据&#xff0c;数据过滤并进行数据压缩分析接口利用AI生成结论和图表AI提问技巧调用AI直接调用AI大模型官网的接口使用云服务商提供的&#xff0c;封装后的AI接口利用鱼聪明AI提供的开放SDK 智能接口实现 业务流程 用户输入 …

VisualGDB:Linux动态库项目创建、编译及库的使用

此篇接上篇 《VisualGDB:为Linux项目添加系统依赖库》,在本篇中我们重点分享一下如何基于VisualGDB 在VS中创建Linux动态库项目,如何编译及使用创建的动态库。 一、VisualGDB创建Linux动态库项目 如下,我们创建一个Linux下的动态库项目MyMath 二、编译动态库 我们稍微…

哈夫曼编码python算法实现(图片版)

一、问题&#xff1a; 请使用哈夫曼编码方法对给定的字符串&#xff0c;进行编码&#xff0c;以满足发送的编码总长度最小&#xff0c;且方便译码。“AABBCCDDEEABCDDCDBAEEAAA” 二、过程&#xff1a; 三、结果&#xff1a;

二叉树遍历算法

1.树层次遍历算法&#xff0c;返回树深度 #include <iostream> #include <queue>struct TreeNode {int val;TreeNode* left;TreeNode* right;TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} };int maxDepth(TreeNode* root) {if (root nullptr) {r…

代码随想录算法训练营Day33 | 1005.K次取反后最大化的数组和 134. 加油站 135. 分发糖果

代码随想录算法训练营Day33 | 1005.K次取反后最大化的数组和 134. 加油站 135. 分发糖果 LeetCode 1005.K次取反后最大化的数组和 题目链接&#xff1a;LeetCode 1005.K次取反后最大化的数组和 思路&#xff1a; 按绝对值排序 class Solution { public:bool static cmp(int…

手动实现简易版RPC(四)

手动实现简易版RPC(四) 往期内容 手动实现简易版RPC&#xff08;一&#xff09;&#xff1a;RPC简介及系统架构 手动实现简易版RPC&#xff08;二&#xff09;&#xff1a;简单RPC框架实现 手动实现简易版RPC(三)&#xff1a;mock数据生成 前言 接上几篇博客我们实现了最…

C++类和类模板——入门

一、类模板&#xff1a; 1.什么是类模板&#xff1f; template<typename T> class Myclass { public&#xff1a;T index;T func(); };类模板相比于普通的类&#xff0c;实现了对类的复用&#xff0c;这里的T可以作为变量或者函数返回值的类型 2.怎么使用类模板&#…

完美实现vue3异步加载组件

经过几个小时的努力&#xff0c;终于实现了&#xff0c;根据组件名异常加载组件&#xff0c;直接上代码&#xff0c;网上的很多代码方都有坑&#xff0c;先贴出比较坑的代码&#xff1a; <template><view class"main"> <view class"tops"…

【6D位姿估计】FoundationPose 跑通demo 训练记录

前言 本文记录在FoundationPose中&#xff0c;跑通基于CAD模型为输入的demo&#xff0c;输出位姿信息&#xff0c;可视化结果。 然后分享NeRF物体重建部分的训练&#xff0c;以及RGBD图为输入的demo。 1、搭建环境 方案1&#xff1a;基于docker镜像&#xff08;推荐&#xf…

Centos Yum

什么是yum yum&#xff0c;全称为 Yellowdog Updater Modified&#xff0c;是一种基于 RPM 包管理器的开源软件包管理器&#xff0c;主要用于 CentOS、Red Hat Enterprise Linux&#xff08;RHEL&#xff09;和 Fedora 等 Linux 发行版。yum 用来简化软件的安装、更新和管理过…

重置密码之后无法ssh登录

背景描述 我这边有个服务器S&#xff0c;我从ServerA可以ssh上去&#xff0c;但是我从堡垒机B无法ssh上去&#xff1b;一开始以为是密码问题&#xff0c;手动重置密码&#xff0c;但是依然无法登录进去&#xff1b;一直提示密码错误&#xff1b;改了好几次密码都不行 问题原因…

5.9号模拟前端面试10问

5.9号模拟前端面试10问 1.html语义化的理解 HTML语义化是指使用具有明确含义的HTML标签来描述内容&#xff0c;而不仅仅是使用<div>和<span>等通用容器标签。语义化的HTML代码更易于阅读和维护&#xff0c;同时也有助于搜索引擎优化&#xff08;SEO&#xff09;。…

达梦数据库限制用户登录IP测试

达梦数据库创建用户时可以限制登录ip和时间段。 创建测试测试用户 create user test1 identified by Test_1234 ALLOW_IP "192.168.100.101"; 限定该用户只能通过192.168.100.101地址登录数据库 连接测试 上图可见&#xff0c;192.168.100.101客户端可以连接上19…