Android多媒体功能开发(11)——使用AudioRecord类录制音频

这篇具有很好参考价值的文章主要介绍了Android多媒体功能开发(11)——使用AudioRecord类录制音频。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

AudioRecord类优点是能录制到缓冲区,能够实现边录边播(AudioRecord + AudioTrack)以及对音频的实时处理(如QQ电话)。缺点是输出是PCM格式的原始采集数据,如果直接保存成音频文件,不能够被播放器播放,所以必须用代码实现数据编码以及压缩。

使用AudioRecord录音的基本步骤是:确定录音参数、申请缓冲区、创建AudioRecord对象、开始录制、循环读取数据到缓冲区并处理数据、停止录制、释放资源。

需要确定的录音参数包括:采样率、声道、格式。申请缓冲区时需要根据录音参数计算最小缓冲区大小。有了缓冲区以后才能创建AudioRecord对象。录制过程中,需要不停地读取采样到的音频数据,并进行处理。流程和对应的代码如下图:

Android多媒体功能开发(11)——使用AudioRecord类录制音频

下面编写一个例子,用AudioRecord采集音频数据,并以原始PCM格式存入文件。读取数据和处理数据是需要循环进行的操作,所以放入单独线程执行。例子运行在Android8.0以上。

例子界面和主要代码如下:

Android多媒体功能开发(11)——使用AudioRecord类录制音频

因为要录音,所以在配置文件里需要声明录音权限。同时,Android将文件写入应用在外部存储上的私有目录不需要再申请读写存储的权限。

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


同时,使用AudioRecord录音需要动态申请权限,即在实际录音时需要检查用户是否允许应用使用录音权限。如果没有允许,就弹出一个对话框询问用户。代码如下:

if (ActivityCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
      ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO}, 1);
      return;
}

这里用到的AudioRecord类的主要方法有:

1)构造函数:AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes) 

  • audioSource:音频来源,一般取麦克风MediaRecorder.AudioSource.MIC
  • sampleRateInHz:采样率
  • channelConfig:声道配置,一般取AudioFormat.CHANNEL_IN_MONO 、CHANNEL_IN_DEFAULT、CHANNEL_IN_STEREO等
  • audioFormat:音频格式,取AudioFormat.ENCODING_PCM_16BIT、AudioFormat.ENCODING_PCM_8BIT
  • bufferSizeInBytes:缓冲区字节数,不得小于getMinBufferSize计算出的最小缓冲区大小

2)static int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat):计算最小缓冲区大小,参数同构造函数中三个参数。

3)从硬件读取音频数据保存到缓冲区有三个方法,都返回读取的数据个数

  • int read(byte[] audioData, int offsetInBytes, int sizeInBytes) 
  • int read(ByteBuffer audioBuffer, int sizeInBytes) 
  • int read(short[] audioData, int offsetInShorts, int sizeInShorts)

4)void startRecording():开始录制

5)void stop():停止录制

6)void release():释放资源

从AudioRecord读取的数据是PCM格式,可以用AudioTrack类播放。用AudioTrack类播放音频的基本流程是:创建AudioTrack对象、开始播放、循环写入数据到缓冲区、停止播放、释放资源。创建AudioTrack对象时需给出参数:采样率、声道、格式。流程和对应的代码如下图:

Android多媒体功能开发(11)——使用AudioRecord类录制音频

下面就为前面的例子加上播放音频的功能。用AudioTrack播放AudioRecord录制的PCM音频文件时需要注意:写入数据后不能马上release,因为播放是异步的,此时还刚开始播放,一旦release就不播放了。用AudioTrack还可以实现变音效果:以采样率a录制,以采样率b播放。主要代码如下:

Android多媒体功能开发(11)——使用AudioRecord类录制音频

AudioTrack类的主要方法有:

1)构造函数:AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes, int mode) 

  • streamType: 流类型,取值为AudioManager.STREAM_VOICE_CALL, AudioManager.STREAM_SYSTEM, AudioManager.STREAM_RING, AudioManager.STREAM_MUSIC, AudioManager.STREAM_ALARM
  • sampleRateInHz:采样率
  • channelConfig:声道配置,一般取AudioFormat.CHANNEL_OUT_DEFAULT、CHANNEL_OUT_STEREO等
  • audioFormat:音频格式,取AudioFormat.ENCODING_PCM_16BIT、AudioFormat.ENCODING_PCM_8BIT
  • bufferSizeInBytes:缓冲区字节数,不得小于getMinBufferSize计算出的最小缓冲区大小
  • mode:缓冲区类型,MODE_STATIC、MODE_STREAM 

2)void play() :开始播放

3)写入音频数据到硬件有两个方法,返回成功写入的数据个数

  • int write(byte[] audioData, int offsetInBytes, int sizeInBytes) 
  • int write(short[] audioData, int offsetInShorts, int sizeInShorts) 

4)void stop() :停止播放

5)void pause():暂停播放

6)void release():释放资源

例子的完整代码如下:

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;

import android.Manifest;
import android.content.pm.PackageManager;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
import android.media.AudioTrack;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.*;

import java.io.*;

public class MainActivity extends AppCompatActivity {
    File soundFile;                // 存放录音的文件
    boolean isRecording;
    int frequency = 11025;
    int inChannelConfig = AudioFormat.CHANNEL_IN_MONO;
    int outChannelConfig = AudioFormat.CHANNEL_OUT_MONO;
    int audioFormat = AudioFormat.ENCODING_PCM_16BIT;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        LinearLayout ll = new LinearLayout(this);
        ll.setOrientation(LinearLayout.VERTICAL);
        setContentView(ll);

        //  录制到文件:Android/data/<package-name>/files/audioRecord.pcm
        soundFile = new File(getExternalFilesDir(null), "audioRecord.pcm");

        Button btnRecord = new Button(this);
        btnRecord.setText("Record");
        ll.addView(btnRecord);
        btnRecord.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View arg0) {
                Thread t = new Thread() {
                    public void run() {
                        try {
                            record();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                };
                t.start();
            }
        });
        Button btnStop = new Button(this);
        btnStop.setText("Stop");
        ll.addView(btnStop);
        btnStop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View arg0) {
                isRecording = false;
            }
        });

        Button btnPlay = new Button(this);
        btnPlay.setText("Play");
        ll.addView(btnPlay);
        btnPlay.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View arg0) {
                if (soundFile.exists()) {
                    try {
                        play(frequency);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        });

        Button btnPlayFast = new Button(this);
        btnPlayFast.setText("Play Fast");
        ll.addView(btnPlayFast);
        btnPlayFast.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View arg0) {
                if (soundFile.exists()) {
                    try {
                        play(frequency * 4 / 3);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        });

        Button btnPlaySlow = new Button(this);
        btnPlaySlow.setText("Play Slow");
        ll.addView(btnPlaySlow);
        btnPlaySlow.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View arg0) {
                if (soundFile.exists()) {
                    try {
                        play(frequency * 3 / 4);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        });

        Button btnSpeak = new Button(this);
        btnSpeak.setText("Press to Speak");
        ll.addView(btnSpeak);
        btnSpeak.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View arg0, MotionEvent arg1) {
                switch (arg1.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        Thread t = new Thread() {
                            public void run() {
                                try {
                                    record();
                                } catch (IOException e) {
                                    e.printStackTrace();
                                }
                            }
                        };
                        t.start();
                        break;
                    case MotionEvent.ACTION_UP:
                        isRecording = false;
                        break;
                }
                return false;
            }
        });
    }

    void record() throws IOException {
        // 动态权限申请
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO}, 1);
            return;
        }

        if (soundFile.exists()) soundFile.delete();
        soundFile.createNewFile();

        FileOutputStream fos = new FileOutputStream(soundFile);
        BufferedOutputStream bos = new BufferedOutputStream(fos);
        DataOutputStream dos = new DataOutputStream(bos);

        int bufferSize = AudioRecord.getMinBufferSize(frequency, inChannelConfig, audioFormat);
        short[] buffer = new short[bufferSize];
        AudioRecord audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, frequency, inChannelConfig, audioFormat, bufferSize);

        audioRecord.startRecording();
        isRecording = true;
        while(isRecording){
            int bufferRead = audioRecord.read(buffer, 0, bufferSize);
            for(int i=0; i<bufferRead; i++){
                dos.writeShort(buffer[i]);
            }
        }
        audioRecord.stop();
        audioRecord.release();

        dos.close();
        bos.close();
        fos.close();
    }

    void play(int frq) throws IOException{
        int length = (int)soundFile.length()/2;
        if(!soundFile.exists() || length==0) {
            Toast.makeText(getBaseContext(), "音频文件不存在或为空", Toast.LENGTH_SHORT).show();
            return;
        }
        short[] data = new short[length];
        FileInputStream fis = new FileInputStream(soundFile);
        BufferedInputStream bis = new BufferedInputStream(fis);
        DataInputStream dis = new DataInputStream(bis);
        int i=0;
        while(dis.available()>0) {
            data[i] = dis.readShort();
            i++;
        }
        dis.close();
        bis.close();
        fis.close();

        AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, frq, outChannelConfig, audioFormat, length*2, AudioTrack.MODE_STREAM);
        audioTrack.play();
        audioTrack.write(data, 0, length);
        audioTrack.stop();
        //audioTrack.release();		// 不能马上release,因为write后是异步播放,此时还刚开始播放,release就不播放了
    }
}

Android多媒体功能开发-使用AudioRecord类录制音频的例子 文章来源地址https://www.toymoban.com/news/detail-407146.html

到了这里,关于Android多媒体功能开发(11)——使用AudioRecord类录制音频的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • HarmonyOS学习路之开发篇—多媒体开发(相机开发 一)

    HarmonyOS相机模块支持相机业务的开发,开发者可以通过已开放的接口实现相机硬件的访问、操作和新功能开发,最常见的操作如:预览、拍照、连拍和录像等。 相机静态能力 用于描述相机的固有能力的一系列参数,比如朝向、支持的分辨率等信息。 物理相机 物理相机就是独

    2024年02月10日
    浏览(67)
  • HarmonyOS学习路之开发篇—多媒体开发(图像开发 一)

    HarmonyOS图像模块支持图像业务的开发,常见功能如图像解码、图像编码、基本的位图操作、图像编辑等。当然,也支持通过接口组合来实现更复杂的图像处理逻辑。 图像解码 图像解码就是不同的存档格式图片(如JPEG、PNG等)解码为无压缩的位图格式,以方便在应用或者系统

    2024年02月11日
    浏览(49)
  • HarmonyOS学习路之开发篇—多媒体开发(相机开发 二)

    Camera操作类,包括相机预览、录像、拍照等功能接口。 接口名 描述 triggerSingleCapture​(FrameConfig frameConfig) 启动相机帧的单帧捕获。 triggerMultiCapture​(ListFrameConfig frameConfigs) 启动相机帧的多帧捕获。 configure​(CameraConfig config) 配置相机。 flushCaptures​() 停止并清除相机帧的捕获

    2024年02月11日
    浏览(55)
  • HarmonyOS学习路之开发篇—多媒体开发(图像开发 二)

    图像编码就是将PixelMap图像编码成不同存档格式图片,用于后续其他处理,比如保存、传输等。当前仅支持JPEG格式。 ImagePacker主要用于图像编码。 接口名 描述 create() 创建图像打包器实例。 initializePacking(byte[] data, PackingOptions opts) 初始化打包任务,将字节数组设置为打包后输

    2024年02月11日
    浏览(58)
  • Ubuntu 多媒体播放器——KMPlayer Linux:功能强大的视频播放工具

    KMPlayer Linux是一款功能强大的多媒体播放器,专为Ubuntu操作系统设计。它提供了丰富的功能和用户友好的界面,使得在Ubuntu上观看视频变得更加方便和愉快。本文将介绍KMPlayer Linux的安装过程,并提供一些示例代码来演示其功能。 安装KMPlayer Linux 要安装KMPlayer Linux,请按照以下

    2024年02月04日
    浏览(85)
  • qt6 多媒体开发代码分析(二、录音)

    常见的音频编码格式包括MP3、AAC、OGG、WMA、FLAC等,它们之间具有以下区别: 编码方式不同:这些编码格式采用的编码算法不同,例如MP3和AAC使用有损压缩算法,而FLAC使用无损压缩算法。 压缩率和文件大小不同:由于采用的编码算法不同,不同格式的音频文件压缩率和文件大

    2024年02月07日
    浏览(39)
  • HarmonyOS学习路之开发篇—多媒体开发(音频开发 二(1)

    接口说明 接口名 描述 AudioCapturer(AudioCapturerInfo audioCapturerInfo) throws IllegalArgumentException 构造函数,设置录音相关音频参数,使用默认录音设备。 AudioCapturer(AudioCapturerInfo audioCapturerInfo, AudioDeviceDescriptor devInfo) throws IllegalArgumentException 构造函数,设置录音相关音频参数并指定录音

    2024年04月23日
    浏览(56)
  • SDL库入门:掌握跨平台游戏开发和多媒体编程

    SDL (Simple DirectMedia Layer) 是一个跨平台的开源多媒体库,它提供了访问音频、键盘、鼠标、操纵杆以及图形硬件的底层接口。SDL 可用于开发游戏、仿真器、媒体播放器等多种类型的应用程序。 1.1 SDL 的背景与应用领域 SDL 由 Sam Lantinga 开发,最早发布于 1998 年。SDL 的设计目标是

    2024年02月02日
    浏览(46)
  • [任务书+论文+PPT+源码]基于Android与多媒体的英文学习APP的设计与实现

    第1页 毕业设计(论文)题目:基于ANDROID与多媒体技术的英文学习APP的设计与实现设计(论文)要求及原始数据(资料):1.综述国内外移动互联现状及前景;2.了解ANDROID系统,理解ANDROID应用程序的开发方法和步骤;3.分析该ANDROID应用程序的模块结构和主要算法;4.熟悉

    2024年01月22日
    浏览(91)
  • 【C++】开源:多媒体SFML库使用入门

    😏 ★,° :.☆( ̄▽ ̄)/$: .°★ 😏 这篇文章主要介绍SFML库使用。 学其所用,用其所学。——梁启超 欢迎来到我的博客,一起学习知识,共同进步。 喜欢的朋友可以关注一下,下次更新不迷路🥞 SFML (Simple and Fast Multimedia Library) 是一个开源的、跨平台的C++多媒体库,它提供了

    2024年02月16日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包