欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

HarmonyOS之深入解析音频的功能和使用

程序员文章站 2022-05-12 10:34:32
...

一、简介

① 基本概念
  • HarmonyOS 音频模块支持音频业务的开发,提供音频相关的功能,主要包括音频播放、音频采集、音量管理和短音播放等。
  • 采样:采样是指将连续时域上的模拟信号按照一定的时间间隔采样,获取到离散时域上离散信号的过程。
  • 采样率:采样率为每秒从连续信号中提取并组成离散信号的采样次数,单位用赫兹(Hz)来表示。通常人耳能听到频率范围大约在 20Hz~20kHz 之间的声音。常用的音频采样频率有:8kHz、11.025kHz、22.05kHz、16kHz、37.8kHz、44.1kHz、48kHz、96kHz、192kHz 等。
  • 声道:声道是指声音在录制或播放时在不同空间位置采集或回放的相互独立的音频信号,所以声道数也就是声音录制时的音源数量或回放时相应的扬声器数量。
  • 音频帧:音频数据是流式的,本身没有明确的一帧帧的概念,在实际的应用中,为了音频算法处理/传输的方便,一般约定俗成取 2.5ms~60ms 为单位的数据量为一帧音频。这个时间被称之为“采样时间”,其长度没有特别的标准,它是根据编解码器和具体应用的需求来决定的。
  • PCM:PCM(Pulse Code Modulation),即脉冲编码调制,是一种将模拟信号数字化的方法,是将时间连续、取值连续的模拟信号转换成时间离散、抽样值离散的数字信号的过程。
  • 短音:使用源于应用程序包内的资源或者是文件系统里的文件为样本,将其解码成一个 16bit 单声道或者立体声的 PCM 流并加载到内存中,这使得应用程序可以直接用压缩数据流同时摆脱 CPU 加载数据的压力和播放时重解压的延迟。
  • tone 音:根据特定频率生成的波形,比如拨号盘的声音。
  • 系统音:系统预置的短音,比如按键音,删除音等。
② 约束与限制
  • 在使用完 AudioRenderer 音频播放类和 AudioCapturer 音频采集类后,需要调用 release() 方法进行资源释放。
  • 音频采集所使用的最终采样率与采样格式取决于输入设备,不同设备支持的格式及采样率范围不同,可以通过 AudioManager 类的 getDevices 接口查询。
  • 在进行开发之前,需要申请相关权限,保证应用使用音频相关能力的权限,涉及权限如下表:
权限名 说明
ohos.permission.MICROPHONE 允许应用使用麦克风进行录音
ohos.permission.READ_MEDIA 允许应用读取用户外部存储中的媒体文件信息
ohos.permission.WRITE_MEDIA 允许应用读写用户外部存储中的媒体文件信息

二、音频播放

① 音频播放 API
  • 音频播放的主要工作是将音频数据转码为可听见的音频模拟信号并通过输出设备进行播放,同时对播放任务进行管理。
  • 音频播放类 AudioRenderer 的主要接口:
接口名 描述
AudioRenderer(AudioRendererInfo audioRendererInfo, PlayMode pm) 构造函数,设置播放相关音频参数和播放模式,使用默认播放设备
AudioRenderer(AudioRendererInfo audioRendererInfo, PlayMode pm, AudioDeviceDescriptor outputDevice) 构造函数,设置播放相关音频参数、播放模式和播放设备
start() 播放音频流
write(byte[] data, int offset, int size) 将音频数据以byte流写入音频接收器以进行播放
write(short[] data, int offset, int size) 将音频数据以short流写入音频接收器以进行播放
write​(float[] data, int offset, int size) 将音频数据以float流写入音频接收器以进行播放
write​(java.nio.ByteBuffer data, int size) 将音频数据以ByteBuffer流写入音频接收器以进行播放
pause() 暂停播放音频流
stop() 停止播放音频流
release() 释放播放资源
getCurrentDevice() 获取当前工作的音频播放设备
setPlaybackSpeed(float speed) 设置播放速度
setPlaybackSpeed​(AudioRenderer.SpeedPara speedPara) 设置播放速度与音调
setVolume(ChannelVolume channelVolume) 设置指定声道上的输出音量
setVolume(float vol) 设置所有声道上的输出音量
getMinBufferSize​(int sampleRate, AudioStreamInfo.EncodingFormat format, AudioStreamInfo.ChannelMask channelMask) 获取Stream播放模式所需的buffer大小
getState() 获取音频播放的状态
getRendererSessionId() 获取音频播放的session ID
getSampleRate() 获取采样率
getPosition() 获取音频播放的帧数位置
setPosition​(int position) 设置起始播放帧位置
getRendererInfo​() 获取音频渲染信息
duckVolume​() 降低音量并将音频与另一个拥有音频焦点的应用程序混合
unduckVolume​() 恢复音量
getPlaybackSpeed() 获取播放速度、音调参数
setSpeed(SpeedPara speedPara) 设置播放速度、音调参数
getAudioTime() 获取播放时间戳信息
flush() 刷新当前的播放流数据队列
getMaxVolume() 获取播放流可设置的最大音量
getMinVolume() 获取播放流可设置的最小音量
getStreamType() 获取播放流的音频流类型
② 播放音频
  • 步骤A:构造音频流参数的数据结构 AudioStreamInfo,推荐使用 AudioStreamInfo.Builder 类来构造,模板如下,模板中设置的均为 AudioStreamInfo.Builder 类的默认值,根据音频流的具体规格来设置具体参数。
	AudioStreamInfo audioStreamInfo = new AudioStreamInfo.Builder()
	    .sampleRate(AudioStreamInfo.SAMPLE_RATE_UNSPECIFIED)
	    .audioStreamFlag(AudioStreamInfo.AudioStreamFlag.AUDIO_STREAM_FLAG_NONE)
	    .encodingFormat(AudioStreamInfo.EncodingFormat.ENCODING_INVALID)
	    .channelMask(AudioStreamInfo.ChannelMask.CHANNEL_INVALID)
	    .streamUsage(AudioStreamInfo.StreamUsage.STREAM_USAGE_UNKNOWN)
	    .build();
    • 以真实的播放 pcm 流为例:
	AudioStreamInfo audioStreamInfo = new AudioStreamInfo.Builder().sampleRate(44100) // 44.1kHz
	    .audioStreamFlag(AudioStreamInfo.AudioStreamFlag.AUDIO_STREAM_FLAG_MAY_DUCK) // 混音
	    .encodingFormat(AudioStreamInfo.EncodingFormat.ENCODING_PCM_16BIT) // 16-bit PCM
	    .channelMask(AudioStreamInfo.ChannelMask.CHANNEL_OUT_STEREO) // 双声道输出
	    .streamUsage(AudioStreamInfo.StreamUsage.STREAM_USAGE_MEDIA) // 媒体类音频
	    .build();
  • 步骤B:使用创建的音频流构建音频播放的参数结构 AudioRendererInfo,推荐使用 AudioRendererInfo.Builder 类来构造,模板如下,模板中设置的均为 AudioRendererInfo.Builder 类的默认值,根据音频播放的具体规格来设置具体参数。
	AudioRendererInfo audioRendererInfo = new AudioRendererInfo.Builder().audioStreamInfo(audioStreamInfo)
	    .audioStreamOutputFlag(AudioRendererInfo.AudioStreamOutputFlag.AUDIO_STREAM_OUTPUT_FLAG_NONE)
	    .bufferSizeInBytes(0)
	    .isOffload(false)
	    .sessionID(AudioRendererInfo.SESSION_ID_UNSPECIFIED)
	    .build();
    • 以真实的播放 pcm 流为例:
	AudioRendererInfo audioRendererInfo = new AudioRendererInfo.Builder().audioStreamInfo(audioStreamInfo)
	    .audioStreamOutputFlag(AudioRendererInfo.AudioStreamOutputFlag.AUDIO_STREAM_OUTPUT_FLAG_DIRECT_PCM) // pcm格式的输出流
	    .bufferSizeInBytes(100)
	    .isOffload(false) // false表示分段传输buffer并播放,true表示整个音频流一次性传输到HAL层播放
	    .build();
  • 步骤C:根据要播放音频流指定 PlayMode,不同的 PlayMode 在写数据时存在差异,详情见步骤G,其余播放流程是无区别的。并通过构造函数获取 AudioRenderer 类的实例化对象。
  • 步骤D:使用构造函数获取 AudioRenderer 类的实例化对象,其中步骤B,步骤C中的数据为构造函数的必选参数,指定播放设备为可选参数,根据使用场景选择不同的构造函数。
  • 步骤E:(可选)构造音频播放回调,首先构造对象 AudioInterrupt,其中 setInterruptListener 方法的入参需要实现接口类 InterruptListener,setStreamInfo 方法使用步骤A的 AudioStreamInfo 作为入参,然后调用 AudioManager 类的 activateAudioInterrupt(AudioInterrupt interrupt) 方法进行音频播放回调注册。代码示例如下:
	AudioRenderer renderer = new AudioRenderer(audioRendererInfo, AudioRenderer.PlayMode.MODE_STREAM);
	AudioInterrupt audioInterrupt = new AudioInterrupt();
	AudioManager audioManager = new AudioManager();
	audioInterrupt.setStreamInfo(streamInfo);
	audioInterrupt.setInterruptListener(new AudioInterrupt.InterruptListener() {
	    @Override
	    public void onInterrupt(int type, int hint) {
	        if (type == AudioInterrupt.INTERRUPT_TYPE_BEGIN
	                && hint == AudioInterrupt.INTERRUPT_HINT_PAUSE) {
	            renderer.pause();
	        } else if (type == AudioInterrupt.INTERRUPT_TYPE_BEGIN
	                && hint == AudioInterrupt.INTERRUPT_HINT_NONE) {
	
	        } else if (type == AudioInterrupt.INTERRUPT_TYPE_END && (
	                hint == AudioInterrupt.INTERRUPT_HINT_NONE
	                        || hint == AudioInterrupt.INTERRUPT_HINT_RESUME)) {
	            renderer.start();
	        } else {
	            HiLog.warn(TAG, "unexpected type or hint");
	        }
	    }
	});
	audioManager.activateAudioInterrupt(audioInterrupt);
  • 步骤F:调用 AudioRenderer 实例化对象的 start() 方法启动播放任务。
  • 步骤G:将要播放的音频数据读取为 byte 流或 short 流,对于选择 MODE_STREAM 模式的 PlayMode,需要循环调用 write 方法进行数据写入。对于选择 MODE_STATIC 模式的 PlayMode,只能通过调用一次 write 方法将要播放的音频数据全部写入,因此该模式限制在文件规格较小的音频数据播放场景下才能使用。
  • 步骤H:(可选)当需要对音频播放进行暂停或停止时,调用 AudioRenderer 实例化对象的 pause() 或 stop() 方法进行暂停或停止播放。
  • 步骤I:(可选)调用 AudioRenderer 实例化对象的 setSpeed 调节播放速度, setVolume 调节播放音量。
  • 步骤J:播放任务结束后,调用 AudioRenderer 实例化对象的 release() 释放资源。

三、音频采集

① 音频采集 API
  • 音频采集的主要工作是通过输入设备将声音采集并转码为音频数据,同时对采集任务进行管理。
  • 音频采集类 AudioCapturer 的主要接口:
接口名 描述
AudioCapturer(AudioCapturerInfo audioCapturerInfo) throws IllegalArgumentException 构造函数,设置录音相关音频参数,使用默认录音设备
AudioCapturer(AudioCapturerInfo audioCapturerInfo, AudioDeviceDescriptor devInfo) throws IllegalArgumentException 构造函数,设置录音相关音频参数并指定录音设备
getMinBufferSize(int sampleRate, int channelCount, int audioFormat) 获取指定参数条件下所需的最小缓冲区大小
addSoundEffect(UUID type, String packageName) 增加录音的音频音效
start() 开始录音
read(byte[] data, int offset, int size) 读取音频数据
read​(byte[] data, int offset, int size, boolean isBlocking) 读取音频数据并写入传入的byte数组中
read​(float[] data, int offsetInFloats, int sizeInFloats) 阻塞式读取音频数据并写入传入的float数组中
read​(float[] data, int offsetInFloats, int sizeInFloats, boolean isBlocking) 读取音频数据并写入传入的float数组中
read​(short[] data, int offsetInShorts, int sizeInShorts) 阻塞式读取音频数据并写入传入的short数组中
read​(short[] data, int offsetInShorts, int sizeInShorts, boolean isBlocking) 读取音频数据并写入传入的short数组中
read​(java.nio.ByteBuffer buffer, int sizeInBytes) 阻塞式读取音频数据并写入传入的ByteBuffer对象中
read​(java.nio.ByteBuffer buffer, int sizeInBytes, boolean isBlocking) 读取音频数据并写入传入的ByteBuffer对象中
stop() 停止录音
release() 释放录音资源
getSelectedDevice() 获取输入设备信息
getCurrentDevice() 获取当前正在录制音频的设备信息
getCapturerSessionId() 获取录音的session ID
getSoundEffects() 获取已经**的音频音效列表
getState() 获取音频采集状态
getSampleRate() 获取采样率
getAudioInputSource() 获取录音的输入设备信息
getBufferFrameCount​() 获取以帧为单位的缓冲区大小
getChannelCount​() 获取音频采集通道数
getEncodingFormat​() 获取音频采集的音频编码格式
getAudioTime(Timestamp timestamp, Timestamp.Timebase timebase) 获取一个即时的捕获时间戳
② 采集音频
  • 步骤A:构造音频流参数的数据结构 AudioStreamInfo,推荐使用 AudioStreamInfo.Builder 类来构造,模板如下,模板中设置的均为 AudioStreamInfo.Builder 类的默认值,根据音频流的具体规格来设置具体参数。
	AudioStreamInfo audioStreamInfo = new AudioStreamInfo.Builder()
	    .sampleRate(AudioStreamInfo.SAMPLE_RATE_UNSPECIFIED)
	    .audioStreamFlag(AudioStreamInfo.AudioStreamFlag.AUDIO_STREAM_FLAG_NONE)
	    .encodingFormat(AudioStreamInfo.EncodingFormat.ENCODING_INVALID)
	    .channelMask(AudioStreamInfo.ChannelMask.CHANNEL_INVALID)
	    .streamUsage(AudioStreamInfo.StreamUsage.STREAM_USAGE_UNKNOWN)
	    .build();
  • 步骤B:(可选)通过采集的采样率、声道数和数据格式,调用 getMinBufferSize 方法获取采集任务所需的最小 buffer,参照该 buffer 值设置步骤C中 AudioCapturerInfo 的 bufferSizeInBytes。
  • 步骤C:使用步骤A创建的音频流构建音频采集的参数结构 AudioCapturerInfo,推荐使用 AudioCapturerInfo.Builder 类来构造,根据音频采集的具体规格来设置具体参数。以真实的录制 pcm 流为例:
	AudioStreamInfo audioStreamInfo = new AudioStreamInfo.Builder()
	    .encodingFormat(AudioStreamInfo.EncodingFormat.ENCODING_PCM_16BIT) // 16-bit PCM
	    .channelMask(AudioStreamInfo.ChannelMask.CHANNEL_IN_STEREO) // 双声道输入
	    .sampleRate(44100) // 44.1kHz
	    .build();
	AudioCapturerInfo audioCapturerInfo = new AudioCapturerInfo.Builder().audioStreamInfo(audioStreamInfo)
	    .build();
  • 步骤D:(可选)设置采集设备,如麦克风、耳机等。通过 AudioManager.getDevices(AudioDeviceDescriptor.DeviceFlag.INPUT_DEVICES_FLAG) 获取到设备支持的输入设备,然后依照 AudioDeviceDescriptor.DeviceType 选择要选用的输入设备类型。
  • 步骤E:通过构造方法获取 AudioCapturer 类的实例化对象,其中步骤C的参数为必选参数,通过步骤D获取的指定录音设备为可选参数。
  • 步骤F:(可选)设置采集音效,如降噪、回声消除等。使用 addSoundEffect(UUID type, String packageName) 进行音效设置,其中 UUID 参考类 SoundEffect中 提供的静态变量。
  • 步骤G:(可选)构造音频采集回调,首先继承抽象类 AudioCapturerCallback,并实现抽象方法 onCapturerConfigChanged(List configs),然后调用 AudioManager 类的 registerAudioCapturerCallback(AudioCapturerCallback cb) 方法进行音频采集回调注册。代码示例如下:
	private AudioManager audioManager = new AudioManager();
	
	public void main() {
	    AudioCapturerCallback cb = new AudioCapturerCallback() {
	        @Override
	        public void onCapturerConfigChanged(List<AudioCapturerConfig> configs) {
	            configs.forEach(config -> doSomething(config));
	        }
	    };
	    audioManager.registerAudioCapturerCallback(cb);
	}
	
	private void doSomething(AudioCapturerConfig config) {
	    ...
	}
  • 步骤H:调用 AudioCapturer 实例化对象的 start() 方法启动采集任务。
  • 步骤I:采集的音频数据读取为 byte 流,循环调用 read 方法进行数据读取。
  • 步骤J:调用 AudioCapturer 实例化对象的 stop() 方法停止采集。
  • 步骤K:采集任务结束后,调用 AudioCapturer 实例化对象的 release() 释放资源。

四、音量管理

① 音量管理 API
  • 音量管理的主要工作是音量调节,输入/输出设备管理,注册音频中断、音频采集中断的回调等。
  • 音量管理类 AudioManager 的主要接口:
接口名 描述
AudioManager() 构造函数
AudioManager​(Context context) 构造函数,由使用者指定应用上下文Context
AudioManager(String packageName) 构造函数,由使用者指定包信息
activateAudioInterrupt(AudioInterrupt interrupt) **音频中断状态检测
deactivateAudioInterrupt(AudioInterrupt interrupt) 去**音频中断状态检测
getAudioParameter(String key) 获取音频硬件中指定参数keys所对应的参数值
getDevices(DeviceFlag flag) 获取设备信息
getMaxVolume(AudioVolumeType volumeType) 获取指定音频流音量最大档位
getMinVolume(AudioVolumeType volumeType) 获取指定音频流音量最小档位
getRingerMode() 获取铃声模式
getVersion() 获取音频套件版本
getVolume(AudioVolumeType volumeType) 获取指定音频流的音量档位
isDeviceActive(int deviceType) 判断设备的开关状态
isMute(AudioVolumeType volumeType) 特定的流是否处于静音状态
mute(AudioVolumeType volumeType) 将特定流设置为静音状态
setAudioParameter(String key, String value) 为音频硬件设置可变数量的参数值
setDeviceActive(int deviceType, boolean state) 设置设备的开关状态
setRingerMode(AudioRingMode mode) 设置铃声模式
setVolume(AudioVolumeType volumeType, int volume) 设置特定流的音量档位
unmute(AudioVolumeType volumeType) 将特定流设置为非静音状态
setMasterMute(boolean isMute) 将主音频输出设备设置为静音或取消静音状态
setMicrophoneMute(boolean isMute) 将麦克风设置为静音或取消静音状态
isMicrophoneMute() 判断麦克风是否处于静音状态
getActiveCapturerConfigs() 获取设备当前**的音频采集任务的配置信息
registerAudioCapturerCallback(AudioCapturerCallback cb) 注册音频采集参数变更回调
unregisterAudioCapturerCallback​(AudioCapturerCallback cb) 去注册音频采集参数变更回调
getRingerUri(Context context, RingToneType type) 获取指定铃声类型的Uri
setRingerUri(Context context, RingToneType type, Uri uri) 设置指定铃声类型的Uri
getCommunicationState​() 获取当前的通话模式
setCommunicationState​(AudioManager.CommunicationState communicationState) 设置当前的通话模式
changeVolumeBy​(AudioVolumeType volumeType, int index) 将当前音量增加或减少一定量
connectBluetoothSco​() 连接到蓝牙SCO通道
disconnectBluetoothSco​() 断开与蓝牙SCO通道的连接
getActiveRendererConfigs​() 获取有关活动音频流信息,包括使用类型、内容类型和标志
getMasterOutputFrameCount​() 获取主输出设备缓冲区中的帧数
getMasterOutputSampleRate​() 获取主输出设备的采样率
isMasterMute​() 检查音频流是否全局静音
isStreamActive​(AudioVolumeType volumeType) 检查指定类型的音频流是否处于活动状态
makeSessionId​() 创建一个会话ID,AudioRendererInfo.Builder.sessionID(int)将使用该会话ID来设置音频播放参数,而AudioCapturerInfo.Builder.sessionID(int)将使用该会话ID来设置记录参数
registerAudioRendererCallback​(AudioRendererCallback cb) 注册音频播放参数变更回调
unregisterAudioRendererCallback​(AudioRendererCallback cb) 去注册音频播放参数变更回调
② 管理音量
  • 音量管理提供的都是独立的功能,一般作为音频播放和音频采集的功能补充来使用。
  • 音频中断状态检测和音频采集中断状态检测的使用样例,类似音频播放和音频采集的开发步骤。

五、短音播放

① 短音播放 API
  • 短音播放主要负责管理音频资源的加载与播放、tone 音的生成与播放以及系统音播放。
  • 短音播放开放能力分为音频资源、tone 音和系统音三部分,均定义在 SoundPlayer 类。
  • 音频资源的加载与播放类 SoundPlayer 的主要接口:
接口名 描述
SoundPlayer(int taskType) 构造函数,仅用于音频资源
createSound(String path) 从指定的路径加载音频数据生成短音资源
createSound​(Context context, int resourceId) 根据应用程序上下文合音频资源ID加载音频数据生成短音资源
createSound​(AssetFD assetFD) 从指定的AssetFD实例加载音频数据生成短音资源
createSound​(java.io.FileDescriptor fd, long offset, long length) 根据文件描述符从文件加载音频数据生成音频资源
createSound​(java.lang.String path, AudioRendererInfo rendererInfo) 根据从指定路径和播放信息加载音频数据生成短音资源
setOnCreateCompleteListener​(SoundPlayer.OnCreateCompleteListener listener) 设置声音创建完成的回调
setOnCreateCompleteListener​(SoundPlayer.OnCreateCompleteListener listener, boolean isDiscarded) 设置用于声音创建完成的回调,并根据指定的isDiscarded标志位确定是否丢弃队列中的原始回调通知消息
deleteSound(int soundID) 删除短音同时释放短音所占资源
pause(int taskID) 根据播放任务ID暂停对应的短音播放
play(int soundID) 使用默认参数播放短音
play(int soundID, SoundPlayerParameters parameters) 使用指定参数播放短音
resume(int taskID) 恢复短音播放任务
setLoop(int taskID, int loopNum) 设置短音播放任务的循环次数
setPlaySpeedRate(int taskID, float speedRate) 设置短音播放任务的播放速度
setPriority(int taskID, int priority) 设置短音播放任务的优先级
setVolume(int taskID, AudioVolumes audioVolumes) 设置短音播放任务的播放音量
setVolume(int taskID, float volume) 设置短音播放任务的所有音频声道的播放音量
stop(int taskID) 停止短音播放任务
pauseAll​() 暂停所有正在播放的任务
resumeAll() 恢复虽有已暂停的播放任务
  • tone 音的生成与播放 API 接口:
接口名 描述
SoundPlayer() 构造函数,仅用于tone音
createSound(ToneDescriptor.ToneType type, int durationMs) 创建具有音调频率描述和持续时间(毫秒)的tone音
createSound​(AudioStreamInfo.StreamType streamType, float volume) 根据音量和音频流类型创建tone音
play​(ToneDescriptor.ToneType toneType, int durationMs) 播放指定时长和tone音类型的tone音
pause() 暂停tone音播放
play() 播放创建好的tone音
release() 释放tone音资源
  • 系统音的播放 API 接口:
接口名 描述
SoundPlayer(String packageName) 构造函数,仅用于系统音
playSound(SoundType type) 播放系统音
playSound(SoundType type, float volume) 指定音量播放系统音
② 音频资源的加载与播放
  • 通过 SoundPlayer(int) 构造方法获取 SoundPlayer 类的实例化对象,其中入参 taskType 的取值范围和含义参考枚举类 AudioManager.AudioStreamType 的定义。
  • 调用 createSound(String) 方法从指定路径加载音频资源,并生成短音 ID,后续可使用通过短音 ID 进行短音资源的播放和删除等操作。
  • 使用默认播放参数的 play(int) 方法进行播放,并通过播放成功后返回任务 ID 进行音量、循环次数、播放速度和优先级等参数的设置。
  • 短音资源使用完毕需要调用 deleteSound(int) 完成对资源的释放。
  • 音频资源的加载与播放如下:
	public void demo() {
	    // 步骤1:实例化对象
	    SoundPlayer soundPlayer = new SoundPlayer(AudioManager.AudioVolumeType.STREAM_MUSIC.getValue());
	    // 步骤2:指定音频资源加载并创建短音
	    int soundId = soundPlayer.createSound("/system/xxx");
	    soundPlayer.setOnCreateCompleteListener((soundPlayer1, cacheId, status) -> {
	        // 步骤3:短音播放,设置音量、循环次数和播放速度
	        if (status == 0) {
	            int taskId = soundPlayer.play(cacheId);
	            soundPlayer.setVolume(taskId, 1.0f);
	            soundPlayer.setLoop(taskId, -1); // “-1”表示一直循环播放
	            soundPlayer.setPlaySpeedRate(taskId, 1.0f);
	        }
	    });
	    // 步骤4:释放短音资源
	    soundPlayer.deleteSound(soundId);
	}
③ tone 音的生成与播放
  • 通过 SoundPlayer() 构造方法获取 SoundPlayer 类的实例化对象。
  • 使用 SoundPlayer 的实例化对象,通过 createSound(ToneDescriptor.ToneType, int) 方法,指定 tone 音类型和 tone 音播放时长来创建 tone 音资源。
  • 使用 SoundPlayer 的实例化对象,通过 play、pause、release 方法完成 tone 音播放,tone 音暂停和 tone 音资源释放。
  • tone 音的生成与播放如下:
	public void demo() {
	    // 步骤1:实例化对象
	    SoundPlayer soundPlayer = new SoundPlayer();
	    // 步骤2:创建DTMF_0(高频1336Hz,低频941Hz)持续时间1000ms的tone音
	    soundPlayer.createSound(ToneDescriptor.ToneType.DTMF_0, 1000);
	    // 步骤3:tone音播放,暂停和资源释放
	    soundPlayer.play();
	    soundPlayer.pause();
	    soundPlayer.release();
	}
④ 系统音的播放
  • 通过 SoundPlayer(String) 构造方法获取 SoundPlayer 类的实例化对象。
  • 使用 SoundPlayer 的实例化对象,通过 playSound(SoundType) 或 playSound(SoundType, float) 方法指定系统音类型和音量,并进行系统音播放。
  • 系统音的播放如下:
	public void demo() {
	    // 步骤1:实例化对象
	    SoundPlayer soundPlayer = new SoundPlayer("packageName");
	    // 步骤2:播放键盘敲击音,音量为1.0
	    soundPlayer.playSound(SoundPlayer.SoundType.KEY_CLICK, 1.0f);
	}