flutter开发实战-实现音效soundpool播放音频及控制播放暂停停止设置音量

flutter开发实战-实现音效soundpool播放音频

最近开发过程中遇到低配置设备时候,在Media播放音频时候出现音轨限制问题。所以将部分音频采用音效sound来播放。

一、音效类似iOS中的Sound

在iOS中使用sound来播放mp3音频示例如下

// 通过通知的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];
/// 开始播放与震动
- (void)startShakeSound {// 声音AudioServicesPlaySystemSound(soundID);// 震动AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
}
/// 结束播放与震动
- (void)stopShakeSound {AudioServicesDisposeSystemSoundID(soundID);AudioServicesRemoveSystemSoundCompletion(soundID);
}
//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中引入

soundpool: ^2.3.0

2.2、使用soundpool来播放音频

Soundpool的初始化要用到SoundpoolOptions

SoundpoolOptions soundpoolOptions = SoundpoolOptions();
_soundpool = Soundpool.fromOptions(options: soundpoolOptions);
_soundId = await _soundpool!.loadUri(url);

播放控制需要使用AudioStreamControl,比如播放、暂停、停止、设置音量等控制操作

  • 播放
_audioStreamControl = await _soundpool!.playWithControls(_soundId!);
  • 暂停
await _audioStreamControl!.pause();
  • 停止
await _audioStreamControl!.stop();
  • 设置音量
await _audioStreamControl!.setVolume(volume: volume);

2.3、通过播放时长控制是否可以再次播放

由于soundpool没有播放音频完成回调,这里采用通过Media将音频时长获取到之后判断时间。判断当前播放时间与上次播放的时间间隔是否超过了音频时长Duration。

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播放音频的相关代码如下

import 'package:soundpool/soundpool.dart';// 使用SoundPool
class SoundPlayer implements BaseAudioPlayer {// AudioStreamControl// SoundpoolSoundpool? _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;}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;}}}}void pause() async {if (__audioConfig.audioUrl != null &&__audioConfig.audioUrl.isNotEmpty &&_audioStreamControl != null) {try {await _audioStreamControl!.pause();} catch(e) {print("audioStreamControl pause e:${e.toString()}");}}}void stop() async {if (__audioConfig.audioUrl != null &&__audioConfig.audioUrl.isNotEmpty &&_audioStreamControl != null) {try {await _audioStreamControl!.stop();} catch(e) {print("audioStreamControl stop e:${e.toString()}");}}}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()}");}}}// 不需要该播放器,则需要调用该方法void dispose() {if (_soundpool != null) {_soundpool!.dispose();}}
}

三、小结

flutter开发实战-实现音效soundpool播放音频及控制播放、暂停、停止、设置音量等控制操作。

学习记录,每天不停进步。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/23686.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring Boot + Vue3前后端分离实战wiki知识库系统<十一>--文档管理功能开发三

文档内容的显示&#xff1a; 在上一次Spring Boot Vue3前后端分离实战wiki知识库系统&#xff1c;十&#xff1e;--文档管理功能开发二文档管理模块还差文档的显示木有完成&#xff0c;所以接下来先将这块模块给收尾了。 增加单独获取内容的接口&#xff1a; 概述&#xff…

设计模式、Java8新特性实战 - List<T> 抽象统计组件

一、背景 在日常写代码的过程中&#xff0c;针对List集合&#xff0c;统计里面的某个属性&#xff0c;是经常的事情&#xff0c;针对List的某个属性的统计&#xff0c;我们目前大部分时候的代码都是这样写&#xff0c;每统计一个变量&#xff0c;就要定义一个值&#xff0c;且…

ATTCK实战系列-红队评估 (红日靶场3)Vulnstack三层网络域渗透靶场

文章目录 环境配置靶场介绍靶场设置 外网渗透信息收集端口扫描目录扫描 漏洞发现与利用获取ssh账号密码&#xff0c;登录centos 提权 内网渗透建立代理内网信息收集smb暴破&#xff0c;获取本地管理员密码 横向移动使用psexec模块上线msf 环境配置 靶场介绍 靶场地址 http:/…

pid算法C语言实现

理论我就不多说了&#xff0c;网都已经很多了&#xff0c;但能直接看到效果的确不多。这里我就提供一个&#xff23;语言实现的可以看到效果的实际例程。 pid.h #ifndef __PID_H #define __PID_Htypedef struct pid {int error_last;int error_last_last;float kp;float ki;f…

cookie/sessionStorage/localStorage 的区别

cookie/sessionStorage/localStorage 的区别 cookie、sessionStorage、localStorage 都是保存本地数据的方式 其中&#xff0c;cookie 兼容性较好&#xff0c;所有浏览器均支持。浏览器针对 cookie 会有一些默认行为&#xff0c;比如当响应头中出现set-cookie字段时&#xff0c…

剑指Offer 20.表示数值的字符串

20.表示数值的字符串 题目 官方地址 代码&#xff08;正则表达式&#xff09; public boolean isNumeric (String str) {if (str null || str.length() 0)return false;return new String(str).matches("[-]?\\d*(\\.\\d)?([eE][-]?\\d)?"); }在给定的代码…

PCIE链路信息

目录 简介&#xff1a; 目的&#xff1a; 详情&#xff1a; 简介&#xff1a; PCIe有很多寄存器&#xff0c;也有很多控制&#xff0c;包括链路状态信息&#xff0c;上一节我们讲到了PCie的链路训练&#xff0c;这节文章将继续学习PCIe相关知识。 目的&#xff1a; 从设计…

【Python从小白到高手】---函数基础

个人主页&#xff1a;平行线也会相交 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 平行线也会相交 原创 收录于专栏【Python小白从入门到精通】&#x1f388; 本专栏旨在分享学习Python的一点学习心得&#xff0c;欢迎大家在评论区讨论&#x1f48c; 目录…

iPhone 6透明屏是什么?原理、特点、优势

iPhone 6透明屏是一种特殊的屏幕技术&#xff0c;它能够使手机屏幕变得透明&#xff0c;让用户能够透过屏幕看到手机背后的物体。 这种技术在科幻电影中经常出现&#xff0c;给人一种未来科技的感觉。下面将介绍iPhone 6透明屏的原理、特点以及可能的应用。 iPhone 6透明屏的原…

本地 shell无法连接centos 7 ?

1、首先检查是否安装ssh服务&#xff1b; yum list installed | grep openssh-server# 没有安装尝试安装下 yum install openssh-server 2、检查ssh服务是否开启 systemctl status sshd.service# 未开启&#xff0c;开启下 systemctl start sshd.service # 将sshd 服务添…

socker套接字

1.打印错误信息 2.socketaddr_in结构体 结构体&#xff1a; &#xff08;部分库代码&#xff09; (宏中的##) 3.manual TCP: SOCK_STREAM &#xff1a; 提供有序地&#xff0c;可靠的&#xff0c;全双工的&#xff0c;基于连接的流式服务 UDP: 面向数据报

406 · 和大于S的最小子数组

链接&#xff1a;LintCode 炼码 - ChatGPT&#xff01;更高效的学习体验&#xff01; 题解&#xff1a;同向双指针 九章算法 - 帮助更多程序员找到好工作&#xff0c;硅谷顶尖IT企业工程师实时在线授课为你传授面试技巧 class Solution { public:/*** param nums: an array …

《Java面向对象程序设计》学习笔记——第 5 章 继承与接口

​专栏&#xff1a;《Java面向对象程序设计》学习笔记 第 5 章 类与对象 5.1 子类与父类 有新类继承一般类视频讲解的状态和行为&#xff0c;并根据需要增加新的状态和行为。 由继承得到的类称为子类&#xff0c;被继承的类称为父类&#xff08;超类&#xff09;。 Java 不…

【maven】构建项目前clean和不clean的区别

其实很简单&#xff0c;但是百度搜了一下&#xff0c;还是没人能简单说明白。 搬用之前做C项目时总结结论&#xff1a; 所以自己在IDE里一遍遍测试程序能否跑通的时候&#xff0c;不需要clean&#xff0c;因为反正还要改嘛。 但是这个项目测试好了&#xff0c;你要打成jar包给…

element-tree-line el-tree 添加结构线 添加虚线

概览&#xff1a;给element组件添加上虚线&#xff0c;通过使用插件element-tree-line 参考连接&#xff1a; 参考别人的博客 安装插件&#xff1a; # npm npm install element-tree-line -S # yarn yarn add element-tree-line -S main.js全局注册引入插件&#xff1a; imp…

Python批量查字典和爬取双语例句

最近&#xff0c;有网友反映&#xff0c;我的批量查字典工具换到其它的网站就不好用了。对此&#xff0c;我想说的是&#xff0c;互联网包罗万象&#xff0c;网站的各种设置也有所不同&#xff0c;并不是所有的在线字典都可以用Python爬取的。事实上&#xff0c;很多网站为了防…

Linux文本三剑客---grep、sed、awk

目录标题 1、grep1.1 命令格式1.2命令功能1.3命令参数1.4grep实战演练 2、sed2.1 认识sed2.2命令格式2.3常用选项options2.4地址定界2.5 编辑命令command2.6用法演示2.6.1常用选项options演示2.6.2地址界定演示2.6.3编辑命令command演示 3、awk3.1认识awk3.2常用命令选项3.3awk…

向表中随机插入字符串数据

已知表 向该表中插入指定次数的随机字符串&#xff1a; 代码如下: DROP PROCEDURE sc //CREATE PROCEDURE sc(num INT) BEGIN DECLARE str VARCHAR(26) DEFAULT "abcdefghijklmnopqrstuvwxyz"; DECLARE cnt INT DEFAULT 0; DECLARE startIndex INT DEFAULT 1; DE…

线程、进程的区别

线程、进程的区别 在开发中&#xff0c;我们经常听到线程和进程两个概念&#xff0c;它们都是操作系统的基本概念&#xff0c;操作系统以进程为基本单位分配存储器&#xff0c;以线程为基本单位分配CPU。虽然它们有很多相似之处&#xff0c;但是它们也有很大的区别。本文将详细…

msvcp120.dll丢失的解决方法(亲测可修复方的法)

在运行某些软件的时候&#xff0c;计算机提示msvcp120.dll丢失&#xff0c;无法打开运行软件。在第一次遇到这个问题的时候&#xff0c;相信很多人都不知道是怎么回事。下面小编把msvcp120.dll是什么以及如何解决这个问题的详细方法给大家科普一下。 问题描述&#xff1a; 在使…