基础知识
1.PCM(脉冲编码调制),将物理音频信号转化为数字,信号转变成一个数字阵列,每个数字代表特定时刻声音的能量水平(振幅)。(只讨论线性 PCM,即阵列中的每个数字都是原始振幅的线性表示)
2.采样率,数字声音每秒采样多少次(表示振幅的数字)。一般来说,采样率越高,音质越好。目前消费类音频系统中使用的数字通常为22050、44100和48000Hz(每秒采样次数)。
3.分辨率/采样大小/每采样位数,用于表示振幅的每个数字的大小和格式。例如,如果使用 8 位整数,则只能表示256级振幅,因此原始物理波形将被简化为256个离散级(并会降低音频精度/质量)。如果使用16位,质量就会好得多。事实上,您可能大部分时间都会使用16位音频。其他选项包括24位、32 位(安卓系统暂时不支持这些选项)和使用浮点数。
4.声道 ,单声道(1声道)或立体声(2声道),也可以是任何更大的数字(但在 Android 上不支持)。如果想要立体声音频,则需要为每个声道设置一个单独的 PCM 阵列,这样信息量就会加倍。
AudioManager
使用该类,查看正在使用的音频设备
mAudioManager = (AudioManager)getSystemService(Service.AUDIO_SERVICE);
AudioTrack
在流模式下,应用程序使用 write() 方法,向音轨(audio sink)写入连续的数据流。这些方法是阻塞式的,当数据从 Java 层传输到本地层并排队等待播放时,才返回。流模式在播放音频数据块时最有用,例如以下场景:
1.由于要播放的声音持续时间太长,内存无法容纳
2.由于音频数据的特性(高采样率、每采样位数......),内存无法容纳过大的音频数据块
3.在播放先前排队的音频时接收或生成的音频数据
创建后,AudioTrack对象会初始化其关联的音频缓冲区。该缓冲区的大小是在构建过程中指定的,它决定了AudioTrack在数据用完之前可以播放多长时间。对于流模式,数据将以小于或等于总缓冲区大小的块的形式,写入音频接收器(audio sink,就是播放器?)
针对立即停止播放的情况,需要将线程中断。对于AudioTrack对象,先使用pause(),再使用flush()。详见,stop()函数说明
AudioRecord
AudioRecord类管理Java应用程序的音频资源,从平台的音频输入硬件,记录音频。这是通过从AudioRecord对象中读取数据来实现的,应用程序可以使用以下三种read()方法,使用哪种方法基于对AudioRecord用户最方便的音频数据存储格式。
对于使用 public int read(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes) 方法时,编码方式需要使用8bit格式
public AudioRecord (int audioSource,
int sampleRateInHz,
int channelConfig,
int audioFormat,
int bufferSizeInBytes)
其中,参数audioSource与实体设备无法关联,不能通过枚举的方法获得录音源,只能选择默认的几种(详见官网)。这种架构的设计,就是典型的隔离,用AudioRecord接口,不需要了解底层硬件
添加蓝牙功能
1.遍历输入设备,将内置麦克分设置为音频采集设备。
2.若有蓝牙接入,再将蓝牙设置为音频采集设备,针对蓝牙设备,mAudioManager.getAvailableCommunicationDevices()要和mAudioManager.setCommunicationDevice(speakerDevice)绑定使用(why?)
mAudioManager = (AudioManager)getSystemService(Service.AUDIO_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S){
for(AudioDeviceInfo device:mAudioManager.getDevices(AudioManager.GET_DEVICES_INPUTS))
{
Log.d("device!", String.valueOf(device.getType()));
if (device.getType() == AudioDeviceInfo.TYPE_BUILTIN_MIC)
{
speakerDevice = device;
break;
}
}
for (AudioDeviceInfo btDevice : mAudioManager.getAvailableCommunicationDevices())
//在可以进行通话的设备中寻找
{
Log.d("device!", String.valueOf(btDevice.getType()));
if (btDevice.getType() == AudioDeviceInfo.TYPE_BLUETOOTH_SCO)
{
speakerDevice = btDevice;
mAudioManager.setCommunicationDevice(speakerDevice);
break;
}
}
}
question:手机耳机接入,是不是也默认直接选择手机耳机作为音频输入设备