百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

Android音频基础与录制播放_安卓录音播放器

toyiye 2024-04-03 23:10 34 浏览 0 评论

一、音频概览

声音是振动产生的能量(声波),通过介质传播并能被人或动物听觉器官所感知的波动现象。例如人类说话时通过声带振动产生声波,通过空气传播后到达其他人耳朵。

要采集声音,就需要通过麦克风对声音进行录制。录音就是将声音转为模拟信号或机械记录的过程。而数字录音是进一步将模拟信号经由ADC(模拟数字转换器)将类比取样成数字记录到存储设备。

Android开发音频,就是利用AudioRecoderMediaRecoder录音,通过AudioTrackMediaPlayer播放声音,而这一过程会涉及到很多知识点,例如录制声音过程的采样率、位深、编解码MediaCodecFFmpeg等等。

总结来说:

  1. 音频录制与播放(Android相关类的使用,Framework调用原理)
  2. 音频处理(去噪、静音检测、回声消除、音效处理、功放/增强、混音分离)
  3. 音频的编解码和格式转换(MediaCodecFFmpeg
  4. 音频传输协议(SIP\A2DPAVRCP等)

1、PCM

PCM全名叫脉冲编码调制,是一种将模拟信号数字化的方法。PCM将信号的强度依照同样的间距分成数段,然后使用独特的数字记号(二进制)量化。这一过程通常由ADC来实现。作为Android程序员,更多是调用AudioTrack录制音频后,保存为PCM编码格式,也可以再进一步编码,存储成其它格式。

例如下图(正常应该是正弦波):

用绿色圆圈来表示连续的模拟信号,而红色圆点则表示数字信号。PCM过程就是在模拟信号上进行采样和收集,形成断断续续的采样点,也就是数字信号。在X轴方向上,可以理解为对音频的量化是时间,体现在采样率上。在Y轴方向,可以理解为量化是数量,体现为位深。

2、采样率

采样率表示在1秒内对声音的模拟信号采样的次数,假设上面是声音在1秒内的模拟信号,那么采样就只有2次,以频率作为计量单位,所以这里采样率2Hz。由此 ,可以看出采样率越高,采样得到的数字信号数据就越多,声音在播放过程就会越真实越接近原声,但这也占用很大的数据存储。所以需要根据人耳能识别频率的范围和具体的使用场景,将采样率控制在合适的范围内。常用的音频采样率为44.1k Hz48k Hz

人耳能识别的频率在
20~20kHz,根据奈奎斯特·香农采样定理,采样后的音频要还原成人耳可以识别声音,采样率需要为人耳可以识别频率的2倍,而人耳上限是20KHz,2倍就是40kHz。所以常用的音频采样率为44.1k Hz48k Hz。其他常用采样频率:

  • 8k Hz - 电话所用采样率, 对于人的说话已经足够

    11.025k Hz - AM调幅广播所用采样率

    22.050k Hz24.000k Hz - FM调频广播所用采样率

    32k Hz - miniDV 数码视频 camcorder、DAT (LP mode)所用采样率

    44.1k Hz - 音频 CD, 也常用于 MPEG-1 音频(VCD, SVCD, MP3)所用采样率

    47.25k Hz - 商用 PCM 录音机所用采样率

    48k Hz - miniDV、数字电视、DVD、DAT、电影和专业音频所用的数字声音所用采样率

    50k Hz - 商用数字录音机所用采样率

    96k 或者 192k Hz - DVD-Audio、一些 LPCM DVD 音轨、BD-ROM(蓝光盘)音轨、和 HD-DVD (高清晰度 DVD)音轨所用所用采样率

    3、位深
    采样率可以理解为在时间范畴上对模拟信号的量化,如上面X轴上采样数,而位深表示数量上对模拟信号的量化,如上面Y轴的值。例如Android上常用的位深为8位,表示某个采样点上的值,可以用8位进行表示,共有256个值的可能。而声音数据的保存也就是保存每个声音的位数。

    4、声道数

比较常见的概念,例如单声道(mono),立体声(stereo),5.1声道,7.1声道等等。多声道以为在采样时候需要同时采样每个声道,这样就会增加数据量。

5、数据大小

通过对采样率、位深、声道数的理解,可以得到下面公式:

  • 数据大小=采样率x声道数x(位深÷8)x时长,单位为Byte。
  • 采样数 = 采样率 × 音频时长(s)× 声道数
  • 音频时长= 采样数 ÷ 采样率 ÷ 声道数,单位为s。

6、编码格式

在存储和传输过程,通常不使用PCM格式,虽然无损以及可以直接被声卡和DAC解析,但存储大小过大,会造成本地和网络资源的浪费。所以通常会进一步编码,进行压缩和添加额外的信息,这就衍生出其他编码格式,如MP3、AAC、FLAC等。

经过编码后的音频数据,一般包含三种信息:编码格式、容器格式、元数据。

编码格式

编码格式分为有损编码和无损编码格式,PCM格式是无损的,而MP3则是有损的。编码后的音频数据不再表示波形采样值,不能直接通过硬件播放,需要通过编解码器解码后才能正常播放。

容器格式

编码后的音频需要和元数据需要一起进行容器封装,才形成最终的音频文件。容器格式一般和文件名称后缀保持一致。例如.mp3、.wav。编码格式与容器格式是相互独立的,也就说,MP3编码的音频是可以用WAV进行封装。

元数据

在容器中用于描述音频数据,辅助编解码,如采样率、长度等。

相关学习资料推荐,点击下方链接免费报名,先码住不迷路~】

音视频免费学习地址:https://xxetb.xet.tech/s/2cGd0

【免费分享】音视频学习资料包、大厂面试题、技术视频和学习路线图,资料包括(C/C++,Linux,FFmpeg webRTC rtmp hls rtsp ffplay srs 等等)有需要的可以点击788280672加群免费领取~

二、AudioRecord与AudioTrack使用

1. AudioRecord实现录音

在创建AudioRecord实例前,我们需要通过getMinBufferSize函数来获取当前AudioRecord可以使用的最小缓冲区大小。

getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat)

其中sampleRateInHz为采样率,channelConfig为声道,audioFormat位深。

  • sampleRateInHz采样率,因为我们这里是录音,所以采用44.1kHz。可以根据需要选择其他采样率。
  • channelConfig声道数,这里选择单声道AudioFormat.CHANNEL_IN_MONO,而立体声为CHANNEL_IN_STEREO。其他声道可以根据参数结合配置。

  • audioFormat 编码位深,这里选择默认PCM16位编码,AudioFormat.ENCODING_PCM_16BIT。具体根据业务选择不同的编码位深。

接下来是创建AudioRecord实例:

//采样率 44.1kHz
private val sampleRate = 44100

//声道 单声道
private val channel = AudioFormat.CHANNEL_IN_MONO

//位深
private val pcmBit = AudioFormat.ENCODING_PCM_16BIT

//获取最小缓冲区大小
bufferSize = AudioRecord.getMinBufferSize(
    sampleRate, channel, pcmBit
)

//AudioRecord实例
audioRecord = AudioRecord(
    MediaRecorder.AudioSource.MIC, //音频来源,麦克风
    sampleRate,
    channel,
    pcmBit,
    bufferSize
)

这样就可以通过AudioRecord实例进行录音,下面代码将录音内容保存到文件中。

private fun startRecording() {
    if (isRecording) return
    isRecording = true
  	//开始录音
    audioRecord.startRecording()
    GlobalScope.launch(Dispatchers.IO) {
        val buffer = ByteArray(bufferSize)
        val file = application.externalCacheDir
        val saveFile = File(file, "audio_${System.currentTimeMillis()}.pcm")
        val ous = FileOutputStream(saveFile)
        while (isRecording) {
            //音频数据写入缓冲区buffer
            val result = audioRecord.read(buffer, 0, bufferSize)
            //将缓冲区buffer数据写入本地文件
            ous.write(buffer)
        }
        isRecording = false
        ous.close()
        audioRecord.stop()
    }
}

2. AudioTrack实现音频播放

通过AudioRecord录制到的音频缓存在本地,我们通过AudioTrack将本地音频文件读取出来进行播放。

创建AudioTrack实例,大多数参数和AudioRecord的创建一致。

audioTrack = AudioTrack.Builder()
    .setAudioAttributes(
        AudioAttributes.Builder()
            .setUsage(AudioAttributes.USAGE_MEDIA)
            .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
            .build()
    )
    .setAudioFormat(
        AudioFormat.Builder()
            .setEncoding(pcmBit)
            .setSampleRate(sampleRate)
            .setChannelMask(channel)
            .build()
    )
    .setBufferSizeInBytes(bufferSize)
    .build()

其中参数channel要改成AudioFormat.CHANNEL_OUT_MONO,其他可以保持一致。然后利用AudioTrack实例读取本地音频进行播放。

fun startPlay(path: String) {
    if (isPlaying) return
    val sourceFile = File(externalCacheDir,path)
    if (sourceFile.exists()) {
        isPlaying = true
         GlobalScope.launch(Dispatchers.IO) {
           //开始播放音频
           audioTrack!!.play()
           val fileInputStream = FileInputStream(sourceFile)
           val buffer = ByteArray(bufferSize)
            while (isPlaying) {
            	//将音频文件读取缓冲区buffer
                val size = fileInputStream.read(buffer, 0, bufferSize)
                if (size <= 0) {
                    isPlaying = false
                    continue
                }
                //将缓冲区buffer写入audioTrack进行播放
                audioTrack.write(buffer, 0, bufferSize)
            }
            audioTrack.stop()
        }
    } else {
        showToast("当前文件不存在:${path}")
    }
}

通过代码可以看到,音频通过AudioRecord录制和AudioTrack播放是反着来的。同时通过AudioRecordAudioTrack可以看出,作为Android开发者,更多是调用顶层API,配置相关参数,然后交给底层进行录制和播放。所以要熟悉相关音频概念,以便更好的配置参数。

Github Demo路径,包名: com.xxm.mediacodecdemo.audio

本文主要参考学习文章:

Android音频开发(1):基础知识

硬核音频系列

脉冲编码调制


原文 Android音频基础与录制播放 - 掘金

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码