热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

Android实现录音功能实现实例(MediaRecorder)

本文介绍了Android实现录音的实例代码(MediaRecorder),分享给大家,具体如下: Android提供了两个API用于录音的

本文介绍了Android实现录音的实例代码(MediaRecorder),分享给大家,具体如下:

Android提供了两个API用于录音的实现:MediaRecorder 和 AudioRecord,各有优劣。

1、MediaRecorder

已经集成了录音、编码、压缩等,支持少量的录音音频格式,大概有.aac(API = 16) .amr .3gp

优点:大部分已经集成,直接调用相关接口即可,代码量小

缺点:无法实时处理音频;输出的音频格式不是很多,例如没有输出mp3格式文件

2、AudioRecord

主要是实现边录边播(AudioRecord+AudioTrack)以及对音频的实时处理(如会说话的汤姆猫、语音)

优点:语音的实时处理,可以用代码实现各种音频的封装

缺点:输出是PCM语音数据,如果保存成音频文件,是不能够被播放器播放的,所以必须先写代码实现数据编码以及压缩

先说 MediaRecorder : MediaRecorder因为大部分功能已经集成,所以使用起来相对比较简单。

下面是个小demo:

① 界面

界面比较简单,由于MediaRecorder 并不能实现暂停、继续录音的功能

<&#63;xml version="1.0" encoding="utf-8"&#63;>


  

② 相关录音功能

开始录音

  public void startRecord() {
    // 开始录音
    /* ①Initial:实例化MediaRecorder对象 */
    if (mMediaRecorder == null)
      mMediaRecorder = new MediaRecorder();
    try {
      /* ②setAudioSource/setVedioSource */
      mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);// 设置麦克风
      /*
       * ②设置输出文件的格式:THREE_GPP/MPEG-4/RAW_AMR/Default THREE_GPP(3gp格式
       * ,H263视频/ARM音频编码)、MPEG-4、RAW_AMR(只支持音频且音频编码要求为AMR_NB)
       */
      mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
      /* ②设置音频文件的编码:AAC/AMR_NB/AMR_MB/Default 声音的(波形)的采样 */
      mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
      fileName = DateFormat.format("yyyyMMdd_HHmmss", Calendar.getInstance(Locale.CHINA)) + ".m4a";
      if (!FileUtils.isFolderExist(FileUtils.getFolderName(audioSaveDir))) {
        FileUtils.makeFolders(audioSaveDir);
      }
      filePath = audioSaveDir + fileName;
      /* ③准备 */
      mMediaRecorder.setOutputFile(filePath);
      mMediaRecorder.prepare();
      /* ④开始 */
      mMediaRecorder.start();
    } catch (IllegalStateException e) {
      LogUtil.i("call startAmr(File mRecAudioFile) failed!" + e.getMessage());
    } catch (IOException e) {
      LogUtil.i("call startAmr(File mRecAudioFile) failed!" + e.getMessage());
    }
  }

音频编码可以根据自己实际需要自己设定,文件名防止重复,使用了日期_时分秒的结构,audioSaveDir 是文件存储目录,可自行设定。

停止录音

  public void stopRecord() {
    try {
      mMediaRecorder.stop();
      mMediaRecorder.release();
      mMediaRecorder = null;
      filePath = "";
    } catch (RuntimeException e) {
      LogUtil.e(e.toString());
      mMediaRecorder.reset();
      mMediaRecorder.release();
      mMediaRecorder = null;

      File file = new File(filePath);
      if (file.exists())
        file.delete();

      filePath = "";
    }
  }

时长记录

  // 记录录音时长
  private void countTime() {
    while (isRecording) {
        LogUtil.d("正在录音");
        timeCount++;
        Message msg = Message.obtain();
        msg.what = TIME_COUNT;
        msg.obj = timeCount;
        myHandler.sendMessage(msg);
      try {
        timeThread.sleep(1000);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
    LogUtil.d("结束录音");
    timeCount = 0;
    Message msg = Message.obtain();
    msg.what = TIME_COUNT;
    msg.obj = timeCount;
    myHandler.sendMessage(msg);
  }

将录音时长格式化

  // 格式化 录音时长为 时:分:秒
  public static String FormatMiss(int miss) {
    String hh = miss / 3600 > 9 &#63; miss / 3600 + "" : "0" + miss / 3600;
    String mm = (miss % 3600) / 60 > 9 &#63; (miss % 3600) / 60 + "" : "0" + (miss % 3600) / 60;
    String ss = (miss % 3600) % 60 > 9 &#63; (miss % 3600) % 60 + "" : "0" + (miss % 3600) % 60;
    return hh + ":" + mm + ":" + ss;
  }

Activity全部代码

import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.text.format.DateFormat;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import com.zzx.hellokotlin.R;
import com.zzx.hellokotlin.utils.FileUtils;
import com.zzx.hellokotlin.utils.LogUtil;

import java.io.File;
import java.io.IOException;
import java.util.Calendar;
import java.util.Locale;

public class Record2Activity extends AppCompatActivity {


  // 录音界面相关
  Button btnStart;
  Button btnStop;
  TextView textTime;

  // 录音功能相关
  MediaRecorder mMediaRecorder; // MediaRecorder 实例
  boolean isRecording; // 录音状态
  String fileName; // 录音文件的名称
  String filePath; // 录音文件存储路径
  Thread timeThread; // 记录录音时长的线程
  int timeCount; // 录音时长 计数
  final int TIME_COUNT = 0x101;
  // 录音文件存放目录
  final String audioSaveDir = Environment.getExternalStorageDirectory().getAbsolutePath()+"/audiodemo/";

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_record2);

    btnStart = (Button) findViewById(R.id.btn_start);
    btnStop = (Button) findViewById(R.id.btn_stop);
    textTime = (TextView) findViewById(R.id.text_time);

    btnStart.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        // 开始录音
        btnStart.setEnabled(false);
        btnStop.setEnabled(true);

        startRecord();
        isRecording = true;
        // 初始化录音时长记录
        timeThread = new Thread(new Runnable() {
          @Override
          public void run() {
            countTime();
          }
        });
        timeThread.start();
      }
    });

    btnStop.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        // 停止录音
        btnStart.setEnabled(true);
        btnStop.setEnabled(false);

        stopRecord();
        isRecording = false;
      }
    });

  }

  // 记录录音时长
  private void countTime() {
    while (isRecording) {
        LogUtil.d("正在录音");
        timeCount++;
        Message msg = Message.obtain();
        msg.what = TIME_COUNT;
        msg.obj = timeCount;
        myHandler.sendMessage(msg);
      try {
        timeThread.sleep(1000);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
    LogUtil.d("结束录音");
    timeCount = 0;
    Message msg = Message.obtain();
    msg.what = TIME_COUNT;
    msg.obj = timeCount;
    myHandler.sendMessage(msg);
  }


  /**
   * 开始录音 使用amr格式
   * 录音文件
   * @return
   */
  public void startRecord() {
    // 开始录音
    /* ①Initial:实例化MediaRecorder对象 */
    if (mMediaRecorder == null)
      mMediaRecorder = new MediaRecorder();
    try {
      /* ②setAudioSource/setVedioSource */
      mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);// 设置麦克风
      /*
       * ②设置输出文件的格式:THREE_GPP/MPEG-4/RAW_AMR/Default THREE_GPP(3gp格式
       * ,H263视频/ARM音频编码)、MPEG-4、RAW_AMR(只支持音频且音频编码要求为AMR_NB)
       */
      mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
      /* ②设置音频文件的编码:AAC/AMR_NB/AMR_MB/Default 声音的(波形)的采样 */
      mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
      fileName = DateFormat.format("yyyyMMdd_HHmmss", Calendar.getInstance(Locale.CHINA)) + ".m4a";
      if (!FileUtils.isFolderExist(FileUtils.getFolderName(audioSaveDir))) {
        FileUtils.makeFolders(audioSaveDir);
      }
      filePath = audioSaveDir + fileName;
      /* ③准备 */
      mMediaRecorder.setOutputFile(filePath);
      mMediaRecorder.prepare();
      /* ④开始 */
      mMediaRecorder.start();
    } catch (IllegalStateException e) {
      LogUtil.i("call startAmr(File mRecAudioFile) failed!" + e.getMessage());
    } catch (IOException e) {
      LogUtil.i("call startAmr(File mRecAudioFile) failed!" + e.getMessage());
    }
  }

  /**
   * 停止录音
   */
  public void stopRecord() {
    //有一些网友反应在5.0以上在调用stop的时候会报错,翻阅了一下谷歌文档发现上面确实写的有可能会报错的情况,捕获异常清理一下就行了,感谢大家反馈!
    try {
      mMediaRecorder.stop();
      mMediaRecorder.release();
      mMediaRecorder = null;
      filePath = "";

    } catch (RuntimeException e) {
      LogUtil.e(e.toString());
      mMediaRecorder.reset();
      mMediaRecorder.release();
      mMediaRecorder = null;

      File file = new File(filePath);
      if (file.exists())
        file.delete();

      filePath = "";
    }
  }

  // 格式化 录音时长为 时:分:秒
  public static String FormatMiss(int miss) {
    String hh = miss / 3600 > 9 &#63; miss / 3600 + "" : "0" + miss / 3600;
    String mm = (miss % 3600) / 60 > 9 &#63; (miss % 3600) / 60 + "" : "0" + (miss % 3600) / 60;
    String ss = (miss % 3600) % 60 > 9 &#63; (miss % 3600) % 60 + "" : "0" + (miss % 3600) % 60;
    return hh + ":" + mm + ":" + ss;
  }


  Handler myHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
      switch (msg.what) {
        case TIME_COUNT:
          int count = (int) msg.obj;
          LogUtil.d("count == " + count);
          textTime.setText(FormatMiss(count));

          break;
      }
    }
  };
}

总结:MediaRecorder 实现录音还是比较简单的,只是不能暂停。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • Appium + Java 自动化测试中处理页面空白区域点击问题
    在进行移动应用自动化测试时,有时会遇到某些页面没有返回按钮,只能通过点击空白区域返回的情况。本文将探讨如何在Appium + Java环境中有效解决此类问题,并提供详细的解决方案。 ... [详细]
  • 如何清除Chrome浏览器地址栏的特定历史记录
    在使用Chrome浏览器时,你可能会发现地址栏保存了大量浏览记录。有时你可能希望删除某些特定的历史记录而不影响其他数据。本文将详细介绍如何单独删除地址栏中的特定记录以及批量清除所有历史记录的方法。 ... [详细]
  • 利用Selenium与ChromeDriver实现豆瓣网页全屏截图
    本文介绍了一种使用Selenium和ChromeDriver结合Python代码,轻松实现对豆瓣网站进行完整页面截图的方法。该方法不仅简单易行,而且解决了新版Selenium不再支持PhantomJS的问题。 ... [详细]
  • 探索新一代API文档工具,告别Swagger的繁琐
    对于后端开发者而言,编写和维护API文档既繁琐又不可或缺。本文将介绍一款全新的API文档工具,帮助团队更高效地协作,简化API文档生成流程。 ... [详细]
  • 本文探讨了在构建应用程序时,如何对不同类型的数据进行结构化设计。主要分为三类:全局配置、用户个人设置和用户关系链。每种类型的数据都有其独特的用途和应用场景,合理规划这些数据结构有助于提升用户体验和系统的可维护性。 ... [详细]
  • 本文将详细介绍多个流行的 Android 视频处理开源框架,包括 ijkplayer、FFmpeg、Vitamio、ExoPlayer 等。每个框架都有其独特的优势和应用场景,帮助开发者更高效地进行视频处理和播放。 ... [详细]
  • 气象对比分析
    本文探讨了不同地区和时间段的天气模式,通过详细的图表和数据分析,揭示了气候变化的趋势及其对环境和社会的影响。 ... [详细]
  • 通常情况下,修改my.cnf配置文件后需要重启MySQL服务才能使新参数生效。然而,通过特定命令可以在不重启服务的情况下实现配置的即时更新。本文将详细介绍如何在线调整MySQL配置,并验证其有效性。 ... [详细]
  • Android 6.0 切换指定 Wi-Fi 的解决方案
    本文详细介绍了在 Android 6.0 系统中切换到指定 Wi-Fi 的方法,包括常见的问题、原因分析及解决方案。通过官方文档和代码示例,帮助开发者更好地理解和实现这一功能。 ... [详细]
  • Python自动化测试入门:Selenium环境搭建
    本文详细介绍如何在Python环境中安装和配置Selenium,包括开发工具PyCharm的安装、Python环境的设置以及Selenium包的安装方法。此外,还提供了编写和运行第一个自动化测试脚本的步骤。 ... [详细]
  • 本文详细介绍如何在 iOS 7 环境下申请苹果开发者账号,涵盖从访问开发者网站到最终激活账号的完整流程。包括选择个人或企业账号类型、付款方式及注意事项等。 ... [详细]
  • Spring Boot 中静态资源映射详解
    本文深入探讨了 Spring Boot 如何简化 Web 应用中的静态资源管理,包括默认的静态资源映射规则、WebJars 的使用以及静态首页的处理方法。通过本文,您将了解如何高效地管理和引用静态资源。 ... [详细]
  • ListView简单使用
    先上效果:主要实现了Listview的绑定和点击事件。项目资源结构如下:先创建一个动物类,用来装载数据:Animal类如下:packagecom.example.simplelis ... [详细]
  • 本文详细介绍了Java中实现异步调用的多种方式,包括线程创建、Future接口、CompletableFuture类以及Spring框架的@Async注解。通过代码示例和深入解析,帮助读者理解并掌握这些技术。 ... [详细]
  • 丽江客栈选择问题
    本文介绍了一道经典的算法题,题目涉及在丽江河边的n家特色客栈中选择住宿方案。两位游客希望住在色调相同的两家客栈,并在晚上选择一家最低消费不超过p元的咖啡店小聚。我们将详细探讨如何计算满足条件的住宿方案总数。 ... [详细]
author-avatar
chennaiqin854
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有