返回顶部
首页 > 资讯 > 移动开发 >Android音频开发之录制音频(WAV及MP3格式)
  • 461
分享到

Android音频开发之录制音频(WAV及MP3格式)

2024-04-02 19:04:59 461人浏览 泡泡鱼
摘要

目录一、音频录制权限:二、录音文件的配置:三、音频录制:1、录音对象初始化:2、录制wav音频文件:3、录制MP3音频文件四、音频录制管理【AudioRecordManager】:附

GitHub源码:MultimediaExplore

首先看下音频录制跟播放效果简图:

上面是录音:长按即可录音,支持声波动画,右滑删除等。支持录制pcm、wav、mp3格式音频。

下面是播放:点击左边扬声器icon,开始播放刚录制的本地音频文件【也支持在线音频播放】,支持播放进度,支持切换播放模式(听筒/扬声器/耳机)等。

一、音频录制权限:

无论在做开发任何功能之前,总得先添加及申请相关权限,后续的工作才能正常进行下去。音频录制所需权限如下,而且要在代码中动态申请这些敏感权限,同意后才能正常录制:


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

二、录音文件的配置:

通过第一节讲到音频的基础概念可知,在录制音频前应先进行录制的相关配置,它直接决定了录音文件的音频质量、文件大小、音频格式等。


    
    private void initConfig() {
        recordConfig = new RecordConfig();
        //采样位宽
        recordConfig.setEncodingConfig(AudioFORMat.ENCODING_PCM_16BIT);
        //录音格式
        recordConfig.setFormat(RecordConfig.RecordFormat.MP3);
        // recordConfig.setFormat(RecordConfig.RecordFormat.WAV);
        //采样频率
        recordConfig.setSampleRate(16000);
        String recordDir = String.format(Locale.getDefault(), "%s/Record/zhongyao/",
                Environment.getExternalStorageDirectory().getAbsolutePath());
        //存储目录
        recordConfig.setRecordDir(recordDir);
        AudioRecordManager.getInstance().setCurrentConfig(recordConfig);
    }

三、音频录制:

音频录制类主要有两个封装类:分别是AudioRecorder 、AudioRecordManager。

AudioRecorder:主要是使用系统的AudioRecord来进行录音。并把录制好的音频文件进行合并,转码等,生成我们所需的音频文件。该文件是全局单例的,保证音频录制类只有一个实例。

AudioRecordManager:对AudioRecorder的封装管理,与外界交互均通过此类来完成,包括录音的各种生命周期控制调用等。减少了外界与AudioRecorder的直接交互,已达到对录音类的更好的管理,此类也是一个全局单例类。

1、录音对象初始化:

这里主要根据之前的录音配置,生成 bufferSizeInBytes【缓冲区字节大小】,和audioRecord对象。


    
    public void prepareRecord() {
        // 获得缓冲区字节大小
        if (bufferSizeInBytes == 0) {
            bufferSizeInBytes = AudioRecord.getMinBufferSize(currentConfig.getSampleRate(),
                    currentConfig.getChannelConfig(), currentConfig.getEncodinGConfig());
        }
        if (audioRecord == null) {
            audioRecord = new AudioRecord(AUDIO_INPUT, currentConfig.getSampleRate(),
                    currentConfig.getChannelConfig(), currentConfig.getEncodingConfig(), bufferSizeInBytes);
        }
 
        audioRecordStatus = AudioRecordStatus.AUDIO_RECORD_PREPARE;
    }

2、录制wav音频文件:

wav音频文件是无损的,所以音质会接近原生,但也正是因为是无损的,所以wav音频文件几乎没有压缩,相对来说会比较大。

录制wav音频得先进行录制采用,获得pcm文件,然后把pcm文件合并,最后再转成wav音频文件。

(1)开始录制pcm文件:


    private void startPcmRecorder() {
        audioRecordStatus = AudioRecordStatus.AUDIO_RECORD_START;
        notifyState();
        Logger.d(TAG, "开始录制 Pcm");
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(tmpFile);
            audioRecord.startRecording();
            byte[] byteBuffer = new byte[bufferSizeInBytes];
 
            while (audioRecordStatus == AudioRecordStatus.AUDIO_RECORD_START) {
                int end = audioRecord.read(byteBuffer, 0, byteBuffer.length);
                notifyData(byteBuffer);
                fos.write(byteBuffer, 0, end);
                fos.flush();
            }
            audioRecord.stop();
            files.add(tmpFile);
            if (audioRecordStatus == AudioRecordStatus.AUDIO_RECORD_STOP) {
                makeFile();
            } else {
                Logger.d(TAG, "取消录制...");
            }
        } catch (Exception e) {
            Logger.e(e, TAG, e.getMessage());
            notifyError("录音失败");
        } finally {
            try {
                if (fos != null) {
                    fos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (audioRecordStatus != AudioRecordStatus.AUDIO_RECORD_PAUSE) {
            audioRecordStatus = AudioRecordStatus.AUDIO_RECORD_IDLE;
            notifyState();
            Logger.d(TAG, "录音结束");
        }
    }

(2)合并生成的多个pcm文件:


    
    private void mergePcmFile() {
        boolean mergeSuccess = mergePcmFiles(resultFile, files);
        if (!mergeSuccess) {
            notifyError("合并失败");
        }
    }

(3)将合并好的pcm文件转成wav文件:


    
    private void makeWav() {
        if (!FileUtil.isFile(resultFile) || resultFile.length() == 0) {
            return;
        }
        byte[] header = WavUtils.generateWavFileHeader((int) resultFile.length(), currentConfig.getSampleRate(), currentConfig.getChannelCount(), currentConfig.getEncoding());
        WavUtils.writeHeader(resultFile, header);
    }

3、录制MP3音频文件

相比WAV音频文件而言,MP3音频文件,就更加常见,商业上使用的也比较多,就是因为MP3音频时经过压缩的,文件大小只有WAV的十二分之一,但是音质上几乎没有较大的差异性。当对音质没有极高要求的情况下,如录音文件,MP3格式是极好的选择。

(1)开始录制音频缓存

这里有开启一个线程Mp3EncodeThread,将录音产生的字节数组byteBuffer不断的进行编解码生成MP3文件。


    private void startMp3Recorder() {
        audioRecordStatus = AudioRecordStatus.AUDIO_RECORD_START;
        notifyState();
 
        try {
            audioRecord.startRecording();
            short[] byteBuffer = new short[bufferSizeInBytes];
 
            while (audioRecordStatus == AudioRecordStatus.AUDIO_RECORD_START) {
                int end = audioRecord.read(byteBuffer, 0, byteBuffer.length);
                if (mp3EncodeThread != null) {
                    mp3EncodeThread.addChangeBuffer(new Mp3EncodeThread.ChangeBuffer(byteBuffer, end));
                }
                notifyData(ByteUtils.toBytes(byteBuffer));
            }
            audioRecord.stop();
        } catch (Exception e) {
            Logger.e(e, TAG, e.getMessage());
            notifyError("录音失败");
        }
        if (audioRecordStatus != AudioRecordStatus.AUDIO_RECORD_PAUSE) {
            if (audioRecordStatus == AudioRecordStatus.AUDIO_RECORD_CANCEL) {
                deleteMp3Encoded();
            } else {
                stopMp3Encoded();
            }
        } else {
            Logger.d(TAG, "暂停");
        }
    }

(2)MP3音频编解码:

Android原生的音频录制,支持直接生成WAV文件,但其实是不支持直接生成MP3文件的。这里对应MP3编解码,主要用到了开源的 libmp3lame.so 这个音频编解码库。以下是lame编解码方法及Mp3Encoder类:

MP3编解码方法:


    private void lameData(ChangeBuffer changeBuffer) {
        if (changeBuffer == null) {
            return;
        }
        short[] buffer = changeBuffer.getData();
        int readSize = changeBuffer.getReadSize();
        if (readSize > 0) {
            int encodedSize = Mp3Encoder.encode(buffer, buffer, readSize, mp3Buffer);
            if (encodedSize < 0) {
                Logger.e(TAG, "Lame encoded size: " + encodedSize);
            }
            try {
                os.write(mp3Buffer, 0, encodedSize);
            } catch (IOException e) {
                Logger.e(e, TAG, "Unable to write to file");
            }
        }
    }

Mp3Encoder类:


public class Mp3Encoder {
 
    static {
        System.loadLibrary("mp3lame");
    }
 
    public native static void close();
 
    public native static int encode(short[] buffer_l, short[] buffer_r, int samples, byte[] mp3buf);
 
    public native static int flush(byte[] mp3buf);
 
    public native static void init(int inSampleRate, int outChannel, int outSampleRate, int outBitrate, int quality);
 
    public static void init(int inSampleRate, int outChannel, int outSampleRate, int outBitrate) {
        init(inSampleRate, outChannel, outSampleRate, outBitrate, 7);
    }
}

(3)生成libmp3lame.so:

项目提供的源码中有lame的jni源码,如果想生成libmp3lame.so文件,供自己的项目使用,那么需要对Mp3Encoder.c 和Mp3Encoder.h文件进行修改,然后通过ndk build 生成该so文件。

修改的内容主要是把文件中的Mp3Encoder路径改成自己项目中的Mp3Encoder的路径,否则会找不到相关的native方法。

另外一般情况下,cpu类型支持 armeabi-v7a 、arm64-v8a 两种即可,如果想支持其他的可在Application.mk中添加。

上面文件修改完毕,通过ndk-build指令即可编译生成对应的 libmp3lame.so 文件。

将so不同CPU类型的文件放置 jniLibs 下,或者通过sourceSets配置的路径下,如:


    sourceSets.main {
        jni.srcDirs = []//disable automatic ndk-build call
        jniLibs.srcDirs = ['libs']
    }

即可进行MP3音频格式的录制。

四、音频录制管理【AudioRecordManager】:

通过全局单例模式的AudioRecorderManager与业务进行交互,即保证了音频录制实例的单一性,又能较好的对音频生命周期等进行较好的管理。 



public class AudioRecordManager {
 
    private static final String TAG = "AudioRecordManager";
 
    private AudioRecordManager() {
    }
 
    public static AudioRecordManager getInstance() {
        return AudioRecordManagerHolder.instance;
    }
 
    public static class AudioRecordManagerHolder {
        public static AudioRecordManager instance = new AudioRecordManager();
    }
 
    public void setCurrentConfig(RecordConfig recordConfig) {
        AudioRecorder.getInstance().setCurrentConfig(recordConfig);
    }
 
    public RecordConfig getCurrentConfig() {
        return AudioRecorder.getInstance().getCurrentConfig();
    }
 
    
    public void setRecordStateListener(RecordStateListener listener) {
        AudioRecorder.getInstance().setRecordStateListener(listener);
    }
 
    
    public void setRecordDataListener(RecordDataListener listener) {
        AudioRecorder.getInstance().setRecordDataListener(listener);
    }
 
    
    public void setRecordFftDataListener(RecordFftDataListener recordFftDataListener) {
        AudioRecorder.getInstance().setRecordFftDataListener(recordFftDataListener);
    }
 
    
    public void setRecordResultListener(RecordResultListener listener) {
        AudioRecorder.getInstance().setRecordResultListener(listener);
    }
 
    
    public void setRecordSoundSizeListener(RecordSoundSizeListener listener) {
        AudioRecorder.getInstance().setRecordSoundSizeListener(listener);
    }
 
    public void setStatus(AudioRecordStatus curAudioRecordStatus) {
        switch (curAudioRecordStatus) {
            case AUDIO_RECORD_IDLE:
 
                break;
 
            case AUDIO_RECORD_PREPARE:
                AudioRecorder.getInstance().prepareRecord();
                break;
 
            case AUDIO_RECORD_START:
                AudioRecorder.getInstance().startRecord();
                break;
 
            case AUDIO_RECORD_PAUSE:
                AudioRecorder.getInstance().pauseRecord();
                break;
 
            case AUDIO_RECORD_STOP:
                AudioRecorder.getInstance().stopRecord();
                break;
 
            case AUDIO_RECORD_CANCEL:
                AudioRecorder.getInstance().cancelRecord();
                break;
 
            case AUDIO_RECORD_RELEASE:
                AudioRecorder.getInstance().releaseRecord();
                break;
 
            default:
                break;
        }
    }
 
    public AudioRecordStatus getStatus() {
        return AudioRecorder.getInstance().getAudioRecordStatus();
    }
 
    public String getAudioPath() {
        return AudioRecorder.getInstance().getAudioPath();
    }
}

以上就是Android音频开发之录制音频(WAV及MP3格式)的详细内容,更多关于Android 音频录制的资料请关注编程网其它相关文章!

--结束END--

本文标题: Android音频开发之录制音频(WAV及MP3格式)

本文链接: https://lsjlt.com/news/159325.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Android音频开发之录制音频(WAV及MP3格式)
    目录一、音频录制权限:二、录音文件的配置:三、音频录制:1、录音对象初始化:2、录制wav音频文件:3、录制MP3音频文件四、音频录制管理【AudioRecordManager】:附...
    99+
    2024-04-02
  • Android音视频开发(五)AudioRecord录制音频
    简介 AudioRecord是安卓多媒体框架中用于录制音频的工具。它支持录制原始音频数据,即PCM数据,PCM数据不能被播放器直接播放,需要编码...
    99+
    2022-06-06
    Android
  • Python实现将mp3音频格式转换为wav格式
    最近收到一个朋友委托的需求,要将MP3的音频格式转换成wav的音频格式。于是,使用python写了这个小工具便于批量进行转换操作。 首先,下载需要导入的python模块包。这里选用...
    99+
    2024-04-02
  • java 音频转换wav格式标准音频的操作
    目录简述环境依赖maven依赖ffmpeg依赖工具类代码总结简述 该工具类主要是为了将各类音频转为wav标准格式,其中可以调节采样率、声道数等指标。主要是使用ffmpeg命令进行转换...
    99+
    2024-04-02
  • Amr音频转换Mp3格式
    最近研发部门有一个需求andriod手机端的音频格式amr或wav格式的音频文件需要统一在线转换,为了保证快速并行完成我使用的goroutine和chan,我已经封装好了docker镜像,大家有兴趣的可以下载直接使用: docker pul...
    99+
    2023-01-31
    音频转换 格式 Amr
  • Android音频开发录制音频的方法是什么
    这篇文章主要讲解了“Android音频开发录制音频的方法是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Android音频开发录制音频的方法是什么”吧!首先看下音频录制跟播放效果简图:上...
    99+
    2023-06-21
  • Python实现批量将MP3音频转为WAV格式详解
    目录前言环境依赖代码验证一下前言 本文提供批量将MP3格式的音频转为wav格式的工具代码,一如既往的实用主义。 环境依赖 ffmpeg环境安装,可以参考:windows ffmpeg...
    99+
    2024-04-02
  • mp3格式是html5支持的音频格式吗
    本文小编为大家详细介绍“mp3格式是html5支持的音频格式吗”,内容详细,步骤清晰,细节处理妥当,希望这篇“mp3格式是html5支持的音频格式吗”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起...
    99+
    2024-04-02
  • Android音视频开发(一)音视频基础知识
    前言 最近工作方面没有太多事,所以难得有些空闲时间,针对当前音视频app的流行,为了不让自己淘汰,提升自己的专业能力,于是决定学习安卓平台音视频开发相关知识,然而自己这方面却是...
    99+
    2022-06-06
    Android
  • Android 音视频开发—MediaPlayer音频与视频的播放介绍
    Android多媒体中的——MediaPlayer,我们可以通过这个API来播放音频和视频该类是Androd多媒体框架中的一个重要组件,通过该类,我们可以以最小的步骤来获取,解码和播放音视频。 它支持...
    99+
    2023-09-21
    android 音视频
  • Qt音视频开发之音频播放QAudioOutput的实现
    目录一、前言二、效果图三、体验地址四、相关代码五、功能特点5.1 基础功能5.2 特色功能5.3 视频控件5.4 音频组件一、前言 以前一直以为只有Qt5以后才有QAudioOutp...
    99+
    2023-03-10
    Qt实现音频播放QAudioOutput Qt音频播放QAudioOutput Qt音频播放
  • Android录制声音文件(音频)并播放
    本文实例为大家分享了Android录制音频文件的具体代码,供大家参考,具体内容如下 1、这个demo中没有对多次点击同一个声音文件做详细处理,偶尔会有崩溃,用的时候需要注意。...
    99+
    2022-06-06
    Android
  • Android开发之音视频协议介绍
    目录什么是视频文件什么是264了解音视频协议有啥用?两大电信联盟ITU-TISOITU-T 视频编码发展历程H.26X系列(由ITU[国际电传视讯联盟]主导)其他音视频协议Googl...
    99+
    2024-04-02
  • Android开发之音视频协议分析
    这篇文章主要介绍“Android开发之音视频协议分析”,在日常操作中,相信很多人在Android开发之音视频协议分析问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Android开发之音视频协议分析”的疑惑有所...
    99+
    2023-06-30
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceVi...
    99+
    2022-06-06
    textureview Android
  • Qt音视频开发之音频播放QAudioOutput如何实现
    这篇文章主要介绍了Qt音视频开发之音频播放QAudioOutput如何实现的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Qt音视频开发之音频播放QAudioOutput如何实现文章都会有所收获,下面我们一起来看...
    99+
    2023-07-05
  • Android音频录制MediaRecorder之简易的录音软件实现代码
    使用MediaRecorder的步骤:1、创建MediaRecorder对象2、调用MediRecorder对象的setAudioSource()方法设置声音的来源,一般传入M...
    99+
    2022-06-06
    录音软件 mediarecorder 软件 Android
  • Android音视频开发之MediaPlayer使用教程
    目录MediaPlayer简单使用缺陷AndroidMediaPlayer播放器封装状态机编写内部类初始化函数方法和回调小结MediaPlayer Android多媒体框架支持播放提...
    99+
    2024-04-02
  • Android音视频开发之VideoView使用指南
    目录VideoView介绍MediaController使用源码分析进度显示播放尺寸适配VideoView介绍 之前介绍过使用MediaPlayer+SurfaceView实现播放视...
    99+
    2024-04-02
  • Android音频开发之SurfaceView的使用详解
    目录SurfaceView不同点双缓冲机制SurfaceHolder使用SurfaceView SurfaceView从源码上看继承自View,但在内部实现上SurfaceView和...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作