使用MediaRecorder录制音频作品的常见情况如下:

MediaRecorder recorder = new MediaRecorder();
 recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
 recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
 recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
 recorder.setOutputFile(PATH_NAME);
 recorder.prepare();
 recorder.start();   // 现在开始录制
 recorder.stop();
 recorder.reset();   //通过返回setAudioSource()步骤,可以重用该对象
 recorder.release(); // 现在该对象无法重用
  • 音频通道数(setAudioChannels ): 1(单声道)或 2(立体声)。
  • 音频编码比特率(setAudioEncodingBitRate ):以每秒比特数为单位的音频编码比特率。
  • 音频采样率(setAudioSamplingRate) :每秒采样数的音频采样率。
  • fps(setCaptureRate ) :以每秒帧数为单位捕获帧的速率。
  • setOrientationHint :以度为单位顺时针旋转的角度。支持的角度为 0、90、180 和 270 度。
  • 视频编码比特率(setVideoEncodingBitRate )秒比特数为单位的视频编码比特率。
  • 视频帧率(setVideoFrameRate) :每秒捕获的视频帧数
  • 视频大小(setVideoSize ):宽度和高度
  • public void addOnRoutingChangedListener (AudioRouting.OnRoutingChangedListener listener, 
                    Handler handler)
    

    添加AudioRouting.OnRoutingChangedListener以接收此MediaRecorder上的路由更改通知。

    public List<MicrophoneInfo> getActiveMicrophones ()
    

    返回活动话筒的话筒信息列表。通过查询每个活动麦克风的通道映射,开发人员可以知道每个通道或捕获流如何使用麦克风。

    public AudioRecordingConfiguration getActiveRecordingConfiguration ()
    

    返回此录音机的当前活动音频录制。

    public static final int getAudioSourceMax ()
    

    获取音频源的最大值。

    public LogSessionId getLogSessionId ()
    

    返回MediaRecorder的LogSessionId。

    public int getMaxAmplitude ()
    

    返回自上次调用此方法以来采样的最大绝对振幅。仅在setAudioSource()之后调用此函数。

    public PersistableBundle getMetrics ()
    

    返回有关当前Mediarecorder实例的度量数据。

    public AudioDeviceInfo getPreferredDevice ()
    

    返回setPreferredDevice(AudioDeviceInfo)指定的选定输入设备。请注意,这并不保证与用于记录的实际设备相对应。

    public AudioDeviceInfo getRoutedDevice ()
    

    返回用于标识此MediaRecorder当前路由的AudioDeviceInfo 注意:仅当MediaRecorder当前正在录制时,查询才有效。如果记录器未录制,则返回的设备可能为空或与记录器上次激活时先前选择的设备相对应。

    public Surface getSurface ()
    

    获取使用表面视频源时要从中录制的表面。

    只能在prepare()之后调用。在start()之前渲染到曲面的帧将被丢弃。

    public boolean isPrivacySensitive ()
    

    返回此MediaRecorder在音频捕获方面是否标记为隐私敏感。

    public void pause ()
    

    暂停录制。在start()之后调用此函数。您可以使用resume()恢复录制,而无需重新配置,与stop()相反。如果录制已暂停,则不会执行任何操作。当录制暂停并恢复时,结果输出将如同暂停期间没有发生任何事情一样,立即切换到恢复的场景。

    public void prepare ()
    

    准备记录器以开始捕获和编码数据。必须在设置所需的音频和视频源、编码器、文件格式等之后,但在start()之前调用此方法。

    public void registerAudioRecordingCallback (Executor executor, 
                    AudioManager.AudioRecordingCallback cb)
    

    注册一个回调,以便通过AudioManager.AudioRecordingCallback通知音频捕获更改。当捕获路径配置更改(预处理、格式、采样率…)或捕获被系统静音/取消静音时,将收到回调。

    public void release ()
    

    释放与此MediaRecorder对象关联的资源。使用MediaRecorder后调用此方法是一种很好的做法。特别是,每当应用程序的某个活动暂停(调用其onPause()方法)或停止(调用其onStop()方法)时,都应调用此方法以释放MediaRecorder对象,除非应用程序特别需要保留该对象。除了保留不必要的资源(如内存和编解码器实例),如果不再需要MediaRecorder对象,如果不立即调用此方法,还可能导致移动设备持续消耗电池,如果设备上不支持同一编解码器的多个实例,则其他应用程序的录制失败。即使支持同一编解码器的多个实例,如果同时使用不必要的多个实例,也可能会导致性能下降。

    public void removeOnRoutingChangedListener (AudioRouting.OnRoutingChangedListener listener)
    

    删除AudioRouting.OnRoutingChangedListener,该文件先前已添加以接收重新路由通知。

    public void reset ()
    

    将MediaRecorder重新启动到其空闲状态。调用此方法后,您必须再次配置它,就像它刚被构造一样。

    public void resume ()
    

    恢复录制。在start()之后调用此函数。如果录制未暂停,则不会执行任何操作。

    public void setAudioChannels (int numChannels)
    

    设置要录制的音频通道数。在prepare()之前调用此方法。Prepare()可以对参数执行附加检查,以确保指定数量的音频通道是否适用。

    通常它是 1(单声道)或 2(立体声)。

    public void setAudioEncoder (int audio_encoder)
    

    设置用于录制的音频编码器。如果未调用此方法,则输出文件将不包含音轨。在setOutputFormat()之后但在prepare()之前调用此函数。

    public void setAudioEncodingBitRate (int bitRate)
    

    设置录制的音频编码比特率。在prepare()之前调用此方法。Prepare()可以对参数执行额外的检查,以确保指定的比特率是否适用,有时会对传递的比特率进行内部剪裁,以确保音频录制可以根据平台的功能顺利进行。

    public void setAudioProfile (EncoderProfiles.AudioProfile profile)
    

    使用音频配置文件中的设置进行录制。 此方法应在设置视频和音频源后,在setOutputFile()之前调用。 使用编码器配置文件时,可以使用此方法代替setProfile(CamcorderProfile)

    public void setAudioSamplingRate (int samplingRate)
    

    设置录制的音频采样率。 在prepare()之前调用此方法。Prepare()可以对参数执行附加检查,以确保指定的音频采样率是否适用。采样率实际上取决于音频录制的格式以及平台的功能。例如,AAC音频编码标准支持的采样率范围为8至96 kHz,AMRNB支持的采样率为8 kHz,AMRWB支持的采样率为16 kHz。有关支持的音频采样率,请咨询相关的音频编码标准。

    public void setAudioSource (int audioSource)
    

    设置要用于录制的音频源。如果未调用此方法,则输出文件将不包含音轨。在设置录制参数或编码器之前,需要指定源。仅在setOutputFormat()之前调用此函数。

    public void setCamera (Camera c)
    

    设置用于录制的摄影机。

    使用此功能可以在预览和捕获模式之间快速切换,而无需拆卸摄影机对象。在此之前应调用Camera.unlock()。必须在prepare()之前调用。

    此方法在API级别21中被弃用。

    改用getSurface()android.hardware.camera2 API

    public void setCaptureRate (double fps)
    

    设置视频帧捕获速率。这可用于设置与录制视频的播放速率不同的视频帧捕获速率。此方法还将录制模式设置为“延时”。在延时录像中,只记录视频。如果应用程序设置音频相关参数,则在延时录制会话启动时将忽略这些参数。

    public void setInputSurface (Surface surface)
    

    将记录器配置为在使用表面视频源时使用持久表面。

    只能在prepare()之前调用。如果调用,则不应使用getSurface(),并将抛出IllegalStateException。在start()之前渲染到曲面的帧将被丢弃。

    public void setLocation (float latitude,  float longitude)
    

    在输出文件中设置并存储地理数据(纬度和经度)。应在prepare()之前调用此方法。如果输出格式为OutputFormat.THREE_GPPOutputFormat.MPEG_4,则地理数据存储在udta框中,而对于其他输出格式则忽略。地理数据根据ISO-6709标准存储。

    public void setLogSessionId (LogSessionId id)
    

    设置MediaRecorder的LogSessionId。

    public void setMaxDuration (int max_duration_ms)
    

    设置录制会话的最大持续时间(毫秒)。在setOutputFormat()之后但在prepare()之前调用此函数。录制达到指定的持续时间后,将向MediaRecorder.onInfoListener发送通知,其中包含“what”代码的媒体MEDIA_RECORDER_INFO_MAX_DURATION_REACHED 已达到,录制将停止。停止是异步发生的,不能保证在通知侦听器时记录器已经停止。

    当使用MPEG-4容器(setOutputFormat(int)OutputFormat#MPEG_4)时,建议设置适合用例的最大持续时间。设置大于所需的持续时间可能会导致输出文件大于所需的时间,因为MOOV box在该录制会话中需要较大的电影数据,所以会保留空间。MOOV-box的未使用空间在输出文件中变为空闲框。

    public void setMaxFileSize (long max_filesize_bytes)
    

    设置录制会话的最大文件大小(以字节为单位)。在setOutputFormat()之后但在prepare()之前调用此函数。录制达到指定的文件大小后,将向MediaRecorder.onInfo Listener发送一个通知,其中包含“what”代码的媒体  MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED,录制将停止。停止是异步发生的,不能保证在通知侦听器时记录器已经停止。

    当使用MPEG-4容器(setOutputFormat(int)OutputFormat#MPEG_4)时,建议设置适合用例的最大文件大小。设置大于所需的文件大小可能会导致输出文件大于所需的大小,因为MOOV box在此录制会话中需要较大的电影数据,所以会保留空间。MOOV-box的未使用空间在输出文件中变为空闲框。

    public void setNextOutputFile (File file)
    

    设置上一个输出达到最大文件大小时要使用的下一个输出文件.文件应该是可查找的。设置下一个输出文件后,应用程序在stop()之前不应使用该文件。应用程序必须在MediaRecorder.onInfo侦听器上接收到媒体MEDIA_RECORDER_INFO_MAX_FILESIZE_APPROACHING的“what”代码后调用此函数,然后才能接收到媒体 MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED的“what”代码。在切换到该输出之前,不会使用该文件。当使用下一个输出文件时,应用程序将接收媒体MEDIA_RECORDER_INFO_NEXT_OUTPUT_FILE_STARTED。如果以前的输出文件未被使用,应用程序将无法设置新的输出文件。应用程序负责在调用stop()后清理未使用的文件。

    public void setNextOutputFile (FileDescriptor fd)
    

    设置上一个输出setOutputFile(文件)或setNextOutputFile(文件))达到最大文件大小时要使用的下一个输出文件描述符。文件描述符必须是可查找和可写的。设置下一个输出文件后,应用程序在stop()之前不应使用此文件描述符引用的文件。应用程序负责关闭文件描述符。只要此呼叫返回,就可以安全地执行此操作。应用程序必须在MediaRecorder.onInfo侦听器上接收到媒体 MEDIA_RECORDER_INFO_MAX_FILESIZE_APPROACHING的“what”代码后调用此函数,然后才能接收到媒体 MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED的“what”代码。在切换到该输出之前,不会使用该文件。当使用下一个输出文件时,应用程序将接收媒体MEDIA_RECORDER_INFO_NEXT_OUTPUT_FILE_STARTED。如果以前的输出文件未被使用,应用程序将无法设置新的输出文件。应用程序负责在调用stop()后清理未使用的文件。

    public void setOnErrorListener (MediaRecorder.OnErrorListener l)
    

    注册在录制过程中发生错误时调用的回调。

    public void setOnInfoListener (MediaRecorder.OnInfoListener listener)
    

    在录制过程中发生信息性事件时注册要调用的回调。

    public void setOrientationHint (int degrees)
    

    设置输出视频播放的方向提示。应在prepare()之前调用此方法。此方法不会在视频录制期间触发源视频帧旋转,而是在输出格式为OutputFormat.THREE_GPPOutputFormat.MPEG_4的情况下,在输出视频中添加包含旋转角度的合成矩阵,以便视频播放器可以选择适当的播放方向。请注意,一些视频播放器可能会选择在播放过程中忽略视频中的合成矩阵。

    public void setOutputFile (FileDescriptor fd)
    

    传入要写入的文件的文件描述符。在setOutputFormat()之后但在prepare()之前调用此函数。

    public void setOutputFile (String path)
    

    设置要生成的输出文件的路径。在setOutputFormat()之后但在prepare()之前调用此函数。

    public void setOutputFile (File file)
    

    传入要写入的文件对象。在setOutputFormat()之后但在prepare()之前调用此函数。文件应该是可查找的。设置下一个输出文件后,应用程序在stop()之前不应使用该文件。应用程序负责在调用stop()后清理未使用的文件。

    public void setOutputFormat (int output_format)
    

    设置录制期间生成的输出文件的格式。在setAudioSource()/setVideoSource()之后但在prepare()之前调用此函数。

    在使用H.263视频编码器和AMR音频编码器时,建议始终使用3GP格式。使用MPEG-4容器格式可能会混淆一些桌面播放器。

    public boolean setPreferredDevice (AudioDeviceInfo deviceInfo)
    

    指定音频设备(通过AudioDeviceInfo对象)以路由来自此MediaRecorder的输入。

    public boolean setPreferredMicrophoneDirection (int direction)
    

    指定逻辑麦克风(用于处理)。

    public boolean setPreferredMicrophoneFieldDimension (float zoom)
    

    指定选定麦克风(用于处理)的缩放因子(即场尺寸)。所选麦克风由流的用例决定。

    public void setPreviewDisplay (Surface sv)
    

    设置曲面以显示录制媒体(视频)的预览。在prepare()之前调用此函数以确保设置了所需的预览显示。如果使用了setCamera(android.hardware.Camera),并且曲面已设置为摄影机,则应用程序不需要调用此函数。如果使用非空曲面调用此函数,则摄影机的预览曲面将替换为新曲面。如果使用空曲面调用此方法或根本不调用此方法,media recorder将不会更改相机的预览曲面。

    public void setPrivacySensitive (boolean privacySensitive)
    

    表示此捕获请求对隐私敏感,不允许任何并发捕获。

    默认设置不区分隐私,除非使用setAudioSource(int)设置的音频源是AudioSource#VOICE#COMMUNICATIONAudioSource#CAMCORDER

    当显式设置时,始终优先于音频源的默认值。

    仅当音频源为以下之一时,才允许使用此API:

    AudioSource#MIC 音频源#话筒

    AudioSource#CAMCORDER 音频源#摄像机

    AudioSource#VOICE_RECOGNITION 音频源#语音#识别

    AudioSource#VOICE_COMMUNICATION 音频源#语音#通信

    AudioSource#UNPROCESSED 音频源#未处理

    AudioSource#VOICE_PERFORMANCE 音频源#语音#性能

    如果不满足此条件,调用prepare()将引发IOException。

    必须在setAudioSource(int)之后和setOutputFormat(int)之前调用。

    public void setProfile (CamcorderProfile profile)
    

    使用CamcorderProfile对象中的设置进行录制。此方法应在设置视频和音频源后,在setOutputFile()之前调用。如果使用延时摄像机配置文件,将忽略与音频相关的源或录制参数

    public void setVideoEncoder (int video_encoder)
    

    设置用于录制的视频编码器。如果未调用此方法,则输出文件将不包含视频曲目。在setOutputFormat()之后和prepare()之前调用此函数。

    public void setVideoEncodingBitRate (int bitRate)
    

    设置录制的视频编码比特率。在prepare()之前调用此方法。Prepare()可以对参数执行额外的检查,以确保指定的比特率是否适用,有时会对传递的比特率进行内部剪裁,以确保视频录制可以根据平台的功能顺利进行。

    注意:实际比特率和其他编码特性可能会受到Build.VERSION_CODES.S中引入的最低质量地板行为的影响。在MediaCodec页面和“质量底线”(靠近页面顶部)中可以找到更多关于这对视频编码的影响方式和位置的详细信息。

    public void setVideoEncodingProfileLevel (int profile, int level)
    

    设置录制所需的视频编码配置文件和级别。配置文件和级别必须对setVideoEncoder(int)设置的视频编码器有效。此方法可以在setVideoEncoder(int)之前或之后调用,但必须在prepare()之前调用。prepare()可以对参数执行附加检查,以确保指定的配置文件和级别适用,有时由于编解码器能力或确保视频录制可以根据平台的功能顺利进行,传递的配置文件或级别将被丢弃。

    应用程序还可以使用MediaCodeInfo.CodeCapabilities#ProfileLevel查询相应格式的适用配置文件和级别组合。请注意,此MediaRecorder实例实际使用的编解码器可能不支持请求的配置文件/级别。

    public void setVideoFrameRate (int rate)
    

    设置要捕获的视频的帧速率。必须在setVideoSource()之后调用。在setOutputFormat()之后但在prepare()之前调用此函数。

    public void setVideoProfile (EncoderProfiles.VideoProfile profile)
    

    使用VideoProfile对象中的设置进行录制。

    此方法应在设置视频和音频源后,在setOutputFile()之前调用。

    使用编码器配置文件时,可以使用此方法代替setProfile(CamcorderProfile)。

    public void setVideoSize (int width, int height)
    

    设置要捕获的视频的宽度和高度。必须在setVideoSource()之后调用。在setOutputFormat()之后但在prepare()之前调用此函数。

    public void setVideoSource (int video_source)
    

    设置要用于录制的视频源。如果未调用此方法,则输出文件将不包含视频曲目。在设置录制参数或编码器之前,需要指定源。仅在setOutputFormat()之前调用此函数。

    public void start ()
    

    开始捕获数据并将其编码到用setOutputFile()指定的文件中。在prepare()之后调用此函数。

    由于API级别为13,如果应用程序通过setCamera(android.hardware.camera)设置摄像头,则应用程序可以在此方法调用后使用摄像头。这些应用不需要再次锁定相机。但是,如果此方法失败,应用程序仍应锁定相机。录制期间,应用程序不应启动另一个录制会话。

    public void stop ()
    

    停止录制。在start()之后调用此函数。一旦停止录制,您将不得不重新配置它,就像它刚刚构建一样。请注意,如果调用stop()时未收到有效的音频/视频数据,则会故意向应用程序抛出RuntimeException。如果在start()之后立即调用stop(),则会发生这种情况。该故障使应用程序可以相应地采取措施清理输出文件(例如,删除输出文件),因为发生这种情况时输出文件的构造不正确。

    public void unregisterAudioRecordingCallback (AudioManager.AudioRecordingCallback cb)
    

    注销以前在registerAudioRecordingCallback(java.util.concurrent.Executor,android.media.AudioManager.AudioRecordingCallback)注册的录音回调。

    Android 多媒体框架支持捕获和编码各种常见的音频和视频格式。如果设备硬件支持,您可以使用 MediaRecorder API。

    本文档介绍如何使用MediaRecorder编写一个应用程序,从设备麦克风捕获音频,保存音频并使用MediaPlayer播放。要录制视频,您需要使用设备的摄像头和MediaRecorder

    注意:Android 模拟器无法录制音频。请务必在能够录制音频的真实设备上测试您的代码。

    请求录制音频的权限

     <uses-permission android:name="android.permission.RECORD_AUDIO" />
    

    创建并运行 MediaRecorder

    初始化 MediaRecorder 的新实例:

  • 使用 setAudioSource() 设置音频源。您可能会使用 MIC
  • 注意:大部分音频源(包括 DEFAULT)都会对音频信号进行处理。要录制原始音频,请选择 UNPROCESSED。有些设备不支持未经处理的输入。请先调用 AudioManager.getProperty(AudioManager.PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED) 以验证其是否可用。如果不可用,请尝试使用 VOICE_RECOGNITION,VOICE_RECOGNITION 不会采用 AGC 或噪音抑制。即使在不支持该属性的情况下,您也可以将 UNPROCESSED 用作音频源,但不能保证在这种情况下信号是否未经处理。

  • 使用 setOutputFormat() 设置输出文件格式。请注意,从 Android 8.0(API 级别 26)开始,MediaRecorder 支持 MPEG2_TS 格式,这对流式传输非常有用:
  •  mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_2_TS);
    
  • 使用 setOutputFile() 设置输出文件名。您必须指定代表实际文件的文件描述符。
  • 使用 setAudioEncoder() 设置音频编码器。
  • 通过调用 prepare() 完成初始化。
  • 通过分别调用 start() 和 stop() 来启动和停止录音功能。

    使用完 MediaRecorder 实例后,请尽快调用 release() 来释放其资源。

    注意:在搭载 Android 9(API 级别 28)或更高版本的设备上,在后台运行的应用将无法访问麦克风。因此,您的应用只在以下两种情况下才应录制音频:当其位于前台时,或者您在前台服务中添加了 MediaRecorder 实例时。

    使用 MediaMuxer 来录制多个声道

    从 Android 8.0(API 级别 26)开始,您可以使用 MediaMuxer 来录制多个同步的音频和视频串流。在更低版本的 Android 中,您一次只能录制一个音轨和/或一个视频轨道。

    使用 addTrack() 方法可以将多个轨道混录在一起。

    您还可以为每个帧添加一个或多个带有自定义信息的元数据轨道,但只能添加到 MP4 容器中。您的应用将定义元数据的格式和内容。

    添加元数据

    元数据对于离线处理非常有用。例如,从陀螺仪传感器捕获的数据可用于执行视频稳定。

    当您添加元数据轨道时,轨道的 MIME 格式必须以前缀 application/ 开头。写入元数据与写入视频或音频数据相同,只是数据不是来自 MediaCodec,而是由应用将带有关联时间戳的 ByteBuffer 传递给 writeSampleData() 方法。该时间戳的时间基准必须与视频和音频轨道的时间基准相同。

    生成的 MP4 文件使用 ISO BMFF 规范第 12.3.3.2 节中定义的 TextMetaDataSampleEntry 来指示元数据的 MIME 格式。当您使用 MediaExtractor 来提取包含元数据轨道的文件时,元数据的 MIME 格式会显示为 MediaFormat 的实例。

    MediaRecorder 示例说明了如何使用 MediaRecorder 和 Camera API 进行视频录制。

    以下 Activity 示例展示了如何使用 MediaRecorder 录制音频文件。它还使用 MediaPlayer 来播放音频。

    KotlinJava

        package com.android.audiorecordtest;
        import android.Manifest;
        import android.content.Context;
        import android.content.pm.PackageManager;
        import android.media.MediaPlayer;
        import android.media.MediaRecorder;
        import android.os.Bundle;
        import android.support.annotation.NonNull;
        import android.support.v4.app.ActivityCompat;
        import android.support.v7.app.AppCompatActivity;
        import android.util.Log;
        import android.view.View;
        import android.view.ViewGroup;
        import android.widget.Button;
        import android.widget.LinearLayout;
        import java.io.IOException;
        public class AudioRecordTest extends AppCompatActivity {
            private static final String LOG_TAG = "AudioRecordTest";
            private static final int REQUEST_RECORD_AUDIO_PERMISSION = 200;
            private static String fileName = null;
            private RecordButton recordButton = null;
            private MediaRecorder recorder = null;
            private PlayButton   playButton = null;
            private MediaPlayer   player = null;
            // Requesting permission to RECORD_AUDIO
            private boolean permissionToRecordAccepted = false;
            private String [] permissions = {Manifest.permission.RECORD_AUDIO};
            @Override
            public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
                super.onRequestPermissionsResult(requestCode, permissions, grantResults);
                switch (requestCode){
                    case REQUEST_RECORD_AUDIO_PERMISSION:
                        permissionToRecordAccepted  = grantResults[0] == PackageManager.PERMISSION_GRANTED;
                        break;
                if (!permissionToRecordAccepted ) finish();
            private void onRecord(boolean start) {
                if (start) {
                    startRecording();
                } else {
                    stopRecording();
            private void onPlay(boolean start) {
                if (start) {
                    startPlaying();
                } else {
                    stopPlaying();
            private void startPlaying() {
                player = new MediaPlayer();
                try {
                    player.setDataSource(fileName);
                    player.prepare();
                    player.start();
                } catch (IOException e) {
                    Log.e(LOG_TAG, "prepare() failed");
            private void stopPlaying() {
                player.release();
                player = null;
            private void startRecording() {
                recorder = new MediaRecorder();
                recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
                recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
                recorder.setOutputFile(fileName);
                recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
                try {
                    recorder.prepare();
                } catch (IOException e) {
                    Log.e(LOG_TAG, "prepare() failed");
                recorder.start();
            private void stopRecording() {
                recorder.stop();
                recorder.release();
                recorder = null;
            class RecordButton extends Button {
                boolean mStartRecording = true;
                OnClickListener clicker = new OnClickListener() {
                    public void onClick(View v) {
                        onRecord(mStartRecording);
                        if (mStartRecording) {
                            setText("Stop recording");
                        } else {
                            setText("Start recording");
                        mStartRecording = !mStartRecording;
                public RecordButton(Context ctx) {
                    super(ctx);
                    setText("Start recording");
                    setOnClickListener(clicker);
            class PlayButton extends Button {
                boolean mStartPlaying = true;
                OnClickListener clicker = new OnClickListener() {
                    public void onClick(View v) {
                        onPlay(mStartPlaying);
                        if (mStartPlaying) {
                            setText("Stop playing");
                        } else {
                            setText("Start playing");
                        mStartPlaying = !mStartPlaying;
                public PlayButton(Context ctx) {
                    super(ctx);
                    setText("Start playing");
                    setOnClickListener(clicker);
            @Override
            public void onCreate(Bundle icicle) {
                super.onCreate(icicle);
                // Record to the external cache directory for visibility
                fileName = getExternalCacheDir().getAbsolutePath();
                fileName += "/audiorecordtest.3gp";
                ActivityCompat.requestPermissions(this, permissions, REQUEST_RECORD_AUDIO_PERMISSION);
                LinearLayout ll = new LinearLayout(this);
                recordButton = new RecordButton(this);
                ll.addView(recordButton,
                        new LinearLayout.LayoutParams(
                                ViewGroup.LayoutParams.WRAP_CONTENT,
                                ViewGroup.LayoutParams.WRAP_CONTENT,
                                0));
                playButton = new PlayButton(this);
                ll.addView(playButton,
                        new LinearLayout.LayoutParams(
                                ViewGroup.LayoutParams.WRAP_CONTENT,
                                ViewGroup.LayoutParams.WRAP_CONTENT,
                                0));
                setContentView(ll);
            @Override
            public void onStop() {
                super.onStop();
                if (recorder != null) {
                    recorder.release();
                    recorder = null;
                if (player != null) {
                    player.release();
                    player = null;
    复制代码
    分类:
    Android
    标签: