flutter开发实战-实现音效soundpool播放音频
最近开发过程中遇到低配置设备时候,在Media播放音频时候出现音轨限制问题。所以将部分音频采用音效sound来播放。
一、音效类似iOS中的Sound
在iOS中使用sound来播放mp3音频示例如下
objectivec
// 通过通知的Sound设置为voip_call.caf,这里播放一段空白音频,音频结束后结束震动
NSString *path = [[NSBundle mainBundle] pathForResource:@"blank_call.mp3" ofType:nil];
AudioServicesCreateSystemSoundID((__bridge CFURLRef)[NSURL fileURLWithPath:path], &soundID);
AudioServicesAddSystemSoundCompletion(soundID, NULL, NULL, soundCompleteCallback, NULL);
AudioServicesAddSystemSoundCompletion(kSystemSoundID_Vibrate, NULL, NULL, soundCompleteCallback, NULL);
[self startShakeSound];
objectivec
/// 开始播放与震动
- (void)startShakeSound {
// 声音
AudioServicesPlaySystemSound(soundID);
// 震动
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
}
objectivec
/// 结束播放与震动
- (void)stopShakeSound {
AudioServicesDisposeSystemSoundID(soundID);
AudioServicesRemoveSystemSoundCompletion(soundID);
}
objectivec
//AudioServicesAddSystemSoundCompletion的回调函数
void soundCompleteCallback(SystemSoundID sound,void * clientData) {
if (sound == kSystemSoundID_Vibrate) {
AudioServicesPlayAlertSound(sound);//重复响铃震动
} else {
// 移除
AudioServicesDisposeSystemSoundID(sound);
AudioServicesRemoveSystemSoundCompletion(sound);
AudioServicesDisposeSystemSoundID(kSystemSoundID_Vibrate);
AudioServicesRemoveSystemSoundCompletion(kSystemSoundID_Vibrate);
}
}
在iOS中通过soundID,可以控制播放与暂停,当然iOS中sound播放完成有通知回调callback。soundpool暂时没找到播放完成回调callback。
二、使用soundpool播放音频
2.1、引入soundpool
在pubspec.yaml中引入
dart
soundpool: ^2.3.0
2.2、使用soundpool来播放音频
Soundpool的初始化要用到SoundpoolOptions
dart
SoundpoolOptions soundpoolOptions = SoundpoolOptions();
_soundpool = Soundpool.fromOptions(options: soundpoolOptions);
_soundId = await _soundpool!.loadUri(url);
播放控制需要使用AudioStreamControl,比如播放、暂停、停止、设置音量等控制操作
- 播放
dart
_audioStreamControl = await _soundpool!.playWithControls(_soundId!);
- 暂停
dart
await _audioStreamControl!.pause();
- 停止
dart
await _audioStreamControl!.stop();
- 设置音量
dart
await _audioStreamControl!.setVolume(volume: volume);
2.3、通过播放时长控制是否可以再次播放
由于soundpool没有播放音频完成回调,这里采用通过Media将音频时长获取到之后判断时间。判断当前播放时间与上次播放的时间间隔是否超过了音频时长Duration。
dart
if (lastPlayMilliseconds == null) {
lastPlayMilliseconds = TimeUtil.currentTimeMillis();
_audioStreamControl = await _soundpool!.playWithControls(_soundId!);
} else {
int nowMilliseconds = TimeUtil.currentTimeMillis();
bool shouldPlay = true;
if (audioDurationInMilliseconds != null) {
if (nowMilliseconds - lastPlayMilliseconds! <
audioDurationInMilliseconds!) {
shouldPlay = false;
}
}
if (shouldPlay) {
// 如果上次没有播放完成,不进行播放
// 通过判断播放时长
_audioStreamControl = await _soundpool!.playWithControls(_soundId!);
lastPlayMilliseconds = nowMilliseconds;
}
}
整体使用soundpool播放音频的相关代码如下
dart
import 'package:soundpool/soundpool.dart';
// 使用SoundPool
class SoundPlayer implements BaseAudioPlayer {
// AudioStreamControl
// Soundpool
Soundpool? _soundpool;
String? audioUrl;
// 上次播放时长的毫秒数
int? lastPlayMilliseconds;
// 时长
int? audioDurationInMilliseconds;
// 优先级
late AudioConfig __audioConfig;
late bool _playing = false; // 是否正在播放
int? _soundId;
AudioStreamControl? _audioStreamControl;
SoundPlayer(this.__audioConfig, {Duration? duration}) {
if (duration != null) {
audioDurationInMilliseconds = duration!.inMilliseconds;
}
print("SoundPlayer audioDurationInMilliseconds:${audioDurationInMilliseconds}");
SoundpoolOptions soundpoolOptions = SoundpoolOptions();
_soundpool = Soundpool.fromOptions(options: soundpoolOptions);
setAudioUrl(__audioConfig.audioUrl);
}
Future<void> setAudioUrl(String url) async {
if (_soundpool != null) {
_soundId = await _soundpool!.loadUri(url);
}
}
AudioConfig get_audioConfig() {
return __audioConfig;
}
@override
void play() async {
// Usually you don't want to wait for playback to finish.
if (__audioConfig.audioUrl != null &&
__audioConfig.audioUrl.isNotEmpty &&
_soundId != null &&
_soundpool != null) {
if (lastPlayMilliseconds == null) {
lastPlayMilliseconds = TimeUtil.currentTimeMillis();
_audioStreamControl = await _soundpool!.playWithControls(_soundId!);
} else {
int nowMilliseconds = TimeUtil.currentTimeMillis();
bool shouldPlay = true;
if (audioDurationInMilliseconds != null) {
if (nowMilliseconds - lastPlayMilliseconds! <
audioDurationInMilliseconds!) {
shouldPlay = false;
}
}
if (shouldPlay) {
// 如果上次没有播放完成,不进行播放
// 通过判断播放时长
_audioStreamControl = await _soundpool!.playWithControls(_soundId!);
lastPlayMilliseconds = nowMilliseconds;
}
}
}
}
@override
void pause() async {
if (__audioConfig.audioUrl != null &&
__audioConfig.audioUrl.isNotEmpty &&
_audioStreamControl != null) {
try {
await _audioStreamControl!.pause();
} catch(e) {
print("audioStreamControl pause e:${e.toString()}");
}
}
}
@override
void stop() async {
if (__audioConfig.audioUrl != null &&
__audioConfig.audioUrl.isNotEmpty &&
_audioStreamControl != null) {
try {
await _audioStreamControl!.stop();
} catch(e) {
print("audioStreamControl stop e:${e.toString()}");
}
}
}
@override
void setVolume(double volume) async {
if (__audioConfig.audioUrl != null &&
__audioConfig.audioUrl.isNotEmpty &&
_audioStreamControl != null) {
try {
await _audioStreamControl!.setVolume(volume: volume);
} catch(e) {
print("audioStreamControl setVolume e:${e.toString()}");
}
}
}
// 不需要该播放器,则需要调用该方法
@override
void dispose() {
if (_soundpool != null) {
_soundpool!.dispose();
}
}
}
三、小结
flutter开发实战-实现音效soundpool播放音频及控制播放、暂停、停止、设置音量等控制操作。
学习记录,每天不停进步。