AI销管
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

630 rivejä
18 KiB

  1. "use strict";
  2. var __awaiter = (this && this.__awaiter) || function(thisArg, _arguments, P, generator) {
  3. function adopt(value) {
  4. return value instanceof P ? value : new P(function(resolve) {
  5. resolve(value);
  6. });
  7. }
  8. return new(P || (P = Promise))(function(resolve, reject) {
  9. function fulfilled(value) {
  10. try {
  11. step(generator.next(value));
  12. } catch (e) {
  13. reject(e);
  14. }
  15. }
  16. function rejected(value) {
  17. try {
  18. step(generator["throw"](value));
  19. } catch (e) {
  20. reject(e);
  21. }
  22. }
  23. function step(result) {
  24. result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
  25. }
  26. step((generator = generator.apply(thisArg, _arguments || [])).next());
  27. });
  28. };
  29. Object.defineProperty(exports, "__esModule", {
  30. value: true
  31. });
  32. var zaudioCbName;
  33. (function(zaudioCbName) {
  34. zaudioCbName["onWaiting"] = "waiting";
  35. zaudioCbName["onError"] = "error";
  36. zaudioCbName["onTimeUpdate"] = "playing";
  37. zaudioCbName["onCanplay"] = "canPlay";
  38. zaudioCbName["onPause"] = "pause";
  39. zaudioCbName["onEnded"] = "ended";
  40. zaudioCbName["setAudio"] = "setAudio";
  41. zaudioCbName["updateAudio"] = "updateAudio";
  42. zaudioCbName["seek"] = "seek";
  43. zaudioCbName["onStop"] = "stop";
  44. zaudioCbName["syncStateOn"] = "syncStateOn";
  45. })(zaudioCbName || (zaudioCbName = {}));
  46. let zaudioCbNameArr = [];
  47. for (const key in zaudioCbName) {
  48. if (Object.prototype.hasOwnProperty.call(zaudioCbName, key)) {
  49. const item = zaudioCbName[key];
  50. zaudioCbNameArr.push(item);
  51. }
  52. }
  53. const util_1 = require("./util");
  54. /**
  55. * ZAudio类
  56. * @class ZAudio
  57. * @constructor
  58. * @param {String} defaultCover 音频默认封面
  59. * @param {Boolean} continuePlay 继续播放,错误播放或结束播放后执行
  60. * @param {Boolean} autoPlay 自动播放,部分浏览器不支持
  61. * @property {Number} renderIndex 当前渲染索引
  62. * @property {<audioinfo>} renderinfo 当前渲染数据
  63. * @property {Array<audio>} audiolist 音频列表数组
  64. * @property {<audioinfo>} playinfo 当前播放数据
  65. * @property {Boolean} paused 音频暂停状态
  66. * @property {Number} playIndex 当前播放索引
  67. * @property {Boolean} renderIsPlay 渲染与播放是否一致
  68. *
  69. * @method on(event, action, fn) 回调函数注册业务事件
  70. * @method off(event, action) 回调函数中卸载业务事件
  71. * @method setRender(data) 指定音频, 渲染到zaudio组件
  72. * @method syncRender() 同步并渲染当前的播放状态
  73. * @method operate(index) 播放或暂停指定索引的音频
  74. * @method setAudio(list) 覆盖音频列表
  75. * @method updateAudio(list) 添加音频列表
  76. * @method stop() 强制暂停当前播放音频
  77. * @method stepPlay(count) 快进快退
  78. * @method syncStateOn(action, cb) 注册一个用于同步获取当前播放状态的事件
  79. * @method syncStateOff(action) 卸载用于同步获取当前播放状态的事件
  80. *
  81. *
  82. * **/
  83. class ZAudio extends util_1.EventBus {
  84. constructor(options) {
  85. super();
  86. this.loading = false;
  87. this.renderIndex = 0;
  88. this.audiolist = [];
  89. this.renderinfo = {
  90. current: "00:00:00",
  91. duration: "00:00:00",
  92. duration_value: 0,
  93. current_value: 0,
  94. src: "",
  95. title: "",
  96. singer: "",
  97. coverImgUrl: "",
  98. };
  99. this.playinfo = {
  100. current: "00:00:00",
  101. duration: "00:00:00",
  102. duration_value: 0,
  103. current_value: 0,
  104. src: "",
  105. title: "",
  106. singer: "",
  107. coverImgUrl: "",
  108. };
  109. this.paused = true;
  110. this.uPause = false;
  111. this.autoPlay = false;
  112. this.defaultCover = "";
  113. this.continuePlay = true;
  114. //fix: 防抖触发音频播放中事件
  115. this.throttlePlaying = util_1.throttle(() => {
  116. this.emit(zaudioCbName.onTimeUpdate, this.playinfo);
  117. this.syncStateEmit();
  118. }, 1000);
  119. let {
  120. defaultCover,
  121. autoPlay,
  122. continuePlay
  123. } = options;
  124. this.defaultCover = defaultCover;
  125. this.autoPlay = autoPlay;
  126. this.continuePlay = continuePlay;
  127. this.init();
  128. }
  129. init() {
  130. // #ifndef H5
  131. var audioCtx = uni.getBackgroundAudioManager();
  132. // #endif
  133. // #ifdef H5
  134. var audioCtx = uni.createInnerAudioContext();
  135. audioCtx.autoplay = this.autoPlay;
  136. // #endif
  137. this.audioCtx = audioCtx;
  138. this.audioCtx.onWaiting(this.onWaitingHandler.bind(this));
  139. this.audioCtx.onCanplay(this.onCanplayHandler.bind(this));
  140. this.audioCtx.onPlay(this.onPlayHandler.bind(this));
  141. this.audioCtx.onPause(this.onPauseHandler.bind(this));
  142. this.audioCtx.onStop(this.onStopHandler.bind(this));
  143. this.audioCtx.onEnded(this.onEndedHandler.bind(this));
  144. this.audioCtx.onTimeUpdate(this.onTimeUpdateHandler.bind(this));
  145. this.audioCtx.onError(this.onErrorHandler.bind(this));
  146. //fix: 修复iOS原生音频切换不起作用
  147. // #ifdef APP-PLUS
  148. if (uni.getSystemInfoSync().platform == "ios") {
  149. const bgMusic = plus.audio.createPlayer();
  150. bgMusic.addEventListener("prev", () => {
  151. this.changeplay(-1);
  152. });
  153. bgMusic.addEventListener("next", () => {
  154. this.changeplay(1);
  155. });
  156. }
  157. // #endif
  158. // #ifndef H5
  159. setTimeout(() => {
  160. if (this.autoPlay) {
  161. this.operate();
  162. }
  163. }, 500);
  164. // #endif
  165. this.appCheckReplay();
  166. }
  167. //检测on off的参数
  168. checkEventParams(event, action, fn) {
  169. if (zaudioCbNameArr.indexOf(event) < 0) {
  170. console.error(`参数${event}错误, 必须为${zaudioCbNameArr.join(" | ")}中某一项`);
  171. return false;
  172. }
  173. if (typeof action !== "string" && typeof action !== "symbol") {
  174. console.error(`参数${action}错误, 参数必须为string或symbol类型`);
  175. return false;
  176. }
  177. if (fn && typeof fn !== "function") {
  178. console.error("fn参数错误");
  179. return false;
  180. }
  181. return true;
  182. }
  183. /**
  184. * @description 回调中卸载业务事件
  185. * @param {<zaudioCbName>} event 回调名称枚举值
  186. * @param {Sting|Symbol} action 业务函数名,用于区分不同业务
  187. * @returns undefined
  188. * **/
  189. off(event, action) {
  190. if (!this.checkEventParams(event, action))
  191. return;
  192. super.off(event, action);
  193. }
  194. /**
  195. * @description 回调中注册业务事件
  196. * @param {<zaudioCbName>} event 回调名称枚举值
  197. * @param {Sting|Symbol} action 业务函数名,用于区分不同业务
  198. * @param {function(object|string|number|undefined):undefined} fn 业务函数, 参数或为音频状态
  199. * @returns undefined
  200. * **/
  201. on(event, action, fn) {
  202. if (!this.checkEventParams(event, action))
  203. return;
  204. super.on(event, action, fn);
  205. }
  206. /**
  207. * @description 订阅触发音频回调
  208. * @param {<zaudioCbName>} event 回调名称枚举值,具体看zaudioCbName
  209. * @param {object|string|number|undefined} data 订阅触发回调时,传的音频属性
  210. * @returns undefined
  211. * **/
  212. emit(event, data) {
  213. super.emit(event, data);
  214. }
  215. commit(action, data) {
  216. typeof this[action] === "function" && this[action](data);
  217. }
  218. onWaitingHandler() {
  219. this.commit("setLoading", true);
  220. this.emit(zaudioCbName.onWaiting, true);
  221. this.syncStateEmit();
  222. }
  223. onCanplayHandler() {
  224. this.emit(zaudioCbName.onCanplay, this.playinfo);
  225. this.commit("setLoading", false);
  226. this.syncStateEmit();
  227. }
  228. onPlayHandler() {
  229. // #ifdef APP-PLUS
  230. this.commit("setPlayinfo", {
  231. duration: util_1.formatSeconds(this.audioCtx.duration),
  232. duration_value: this.audioCtx.duration,
  233. });
  234. // #endif
  235. this.commit("setPause", false);
  236. this.commit("setUnnormalPause", false);
  237. }
  238. onPauseHandler() {
  239. this.commit("setPause", true);
  240. this.emit(zaudioCbName.onPause);
  241. this.syncStateEmit();
  242. }
  243. onStopHandler() {
  244. this.commit("setPause", true);
  245. this.emit(zaudioCbName.onStop);
  246. this.syncStateEmit();
  247. }
  248. onEndedHandler() {
  249. this.commit("setPause", true);
  250. this.audioCtx.startTime = 0;
  251. this.commit("setPlayinfo", {
  252. current: "00:00:00",
  253. current_value: 0,
  254. src: "",
  255. });
  256. this.emit(zaudioCbName.onEnded);
  257. this.syncStateEmit();
  258. //续播
  259. if (this.continuePlay) {
  260. this.changeplay(1);
  261. } else {
  262. let nextkey = this.getNextKey(1);
  263. this.commit("setRender", nextkey);
  264. }
  265. }
  266. onTimeUpdateHandler() {
  267. if (this.renderIsPlay) {
  268. //fix: 解决播放进度大于总进度问题
  269. let currentTime = this.audioCtx.currentTime > this.audioCtx.duration ?
  270. this.audioCtx.duration :
  271. this.audioCtx.currentTime;
  272. this.commit("setPlayinfo", {
  273. current: util_1.formatSeconds(currentTime),
  274. current_value: currentTime,
  275. });
  276. // #ifndef APP-PLUS
  277. //fix: 解决小程序与h5无法获取总进度的问题
  278. if (this.audioCtx.duration != this.playinfo.duration_value) {
  279. this.commit("setPlayinfo", {
  280. duration: util_1.formatSeconds(this.audioCtx.duration),
  281. duration_value: this.audioCtx.duration,
  282. });
  283. }
  284. // #endif
  285. }
  286. this.throttlePlaying();
  287. }
  288. onErrorHandler() {
  289. this.commit("setPause", true);
  290. this.commit("setRender", {
  291. src: "",
  292. title: "",
  293. singer: "",
  294. coverImgUrl: "",
  295. });
  296. this.commit("setPlayinfo", {
  297. current: "00:00:00",
  298. current_value: 0,
  299. duration: "00:00:00",
  300. duration_value: 0,
  301. title: "",
  302. src: "",
  303. });
  304. this.emit(zaudioCbName.onError);
  305. this.syncStateEmit();
  306. if (this.continuePlay) {
  307. this.changeplay(1);
  308. }
  309. }
  310. /**
  311. * @description 实时渲染当前状态
  312. * @returns undefined
  313. * **/
  314. syncRender() {
  315. this.setRender(this.playIndex);
  316. }
  317. /**
  318. * @description 注册一个实时获取ZAudio属性的方法
  319. * @param {String} action 自定义业务名
  320. * @param {Funtion} fn 实时获取ZAudio属性回调
  321. * @returns undefined
  322. * **/
  323. syncStateOn(action, fn) {
  324. typeof fn === "function" && this.on(zaudioCbName.syncStateOn, action, fn);
  325. }
  326. /**
  327. * @description 卸载实时获取ZAudio属性的方法
  328. * @param {String} action 自定义业务名
  329. * @returns undefined
  330. * **/
  331. syncStateOff(action) {
  332. this.off(zaudioCbName.syncStateOn, action);
  333. }
  334. /**
  335. * @description 订阅实时获取ZAudio属性的方法
  336. * @returns undefined
  337. * **/
  338. syncStateEmit() {
  339. this.emit(zaudioCbName.syncStateOn, {
  340. renderIndex: this.renderIndex,
  341. audiolist: this.audiolist,
  342. renderinfo: this.renderinfo,
  343. playinfo: this.playinfo,
  344. paused: this.paused,
  345. playIndex: this.playIndex,
  346. renderIsPlay: this.renderIsPlay,
  347. loading: this.loading,
  348. });
  349. }
  350. /**
  351. * @description 跳转播放
  352. * @param {Number} value 跳转位置
  353. * @returns undefined
  354. * **/
  355. seek(value) {
  356. let val = value > this.audioCtx.duration ? this.audioCtx.duration : value;
  357. this.audioCtx.seek(val);
  358. this.commit("setPlayinfo", {
  359. current: util_1.formatSeconds(val),
  360. current_value: val,
  361. });
  362. // setTimeout(() => {
  363. // this.emit(zaudioCbName.seek, this.playinfo.current);
  364. // }, 0);
  365. this.emit(zaudioCbName.seek, this.playinfo.current);
  366. }
  367. /**
  368. * @description 快进
  369. * @param {Number} value 跳转位置
  370. * @returns undefined
  371. * **/
  372. stepPlay(value) {
  373. if (this.renderIsPlay) {
  374. let pos = this.playinfo.current_value + value;
  375. this.seek(pos);
  376. }
  377. }
  378. /**
  379. * @description 获取下一首歌曲索引(用于渲染和播放)
  380. * @param {Number} count 切换数量
  381. * @returns number
  382. * **/
  383. getNextKey(count) {
  384. let nextkey = this.renderIndex;
  385. nextkey += count;
  386. nextkey =
  387. nextkey < 0 ?
  388. this.audiolist.length - 1 :
  389. nextkey > this.audiolist.length - 1 ?
  390. 0 :
  391. nextkey;
  392. return nextkey;
  393. }
  394. /**
  395. * @description 切歌
  396. * @param {Number} count 数量
  397. * @returns undefined
  398. * **/
  399. changeplay(count) {
  400. let nextkey = this.getNextKey(count);
  401. this.commit("setPause", true);
  402. this.operate(nextkey);
  403. }
  404. /**
  405. * @description 手动播放或暂停, 并渲染对应的数据
  406. * @param {Number|String|<audioInfo>|undefined} key 索引或音频对象
  407. * @returns undefined
  408. * **/
  409. operate(key) {
  410. key !== undefined && this.commit("setRender", key);
  411. this.operation();
  412. }
  413. /**
  414. * @description 强制暂停播放
  415. * @returns undefined
  416. * **/
  417. stop() {
  418. this.audioCtx.pause();
  419. this.commit("setPause", true);
  420. this.commit("setUnnormalPause", true);
  421. this.emit(zaudioCbName.onStop);
  422. }
  423. //播放,暂停事件判断,
  424. //播放数据与渲染数据相同时: 播放->暂停, 暂停->播放
  425. //播放数据与渲染数据不相同时: 播放渲染音频
  426. operation() {
  427. return __awaiter(this, void 0, void 0, function*() {
  428. const {
  429. duration,
  430. current,
  431. duration_value,
  432. current_value,
  433. src,
  434. } = this.playinfo;
  435. const {
  436. src: renderSrc,
  437. title: renderTitle,
  438. singer: renderSinger,
  439. coverImgUrl: renderCoverImgUrl,
  440. } = this.renderinfo;
  441. let renderIsPlay = this.renderIsPlay;
  442. let paused = this.paused;
  443. if (!renderIsPlay) {
  444. //渲染与播放地址 不同
  445. this.audioCtx.src = renderSrc;
  446. this.audioCtx.title = renderTitle;
  447. this.audioCtx.singer = renderSinger;
  448. this.audioCtx.coverImgUrl = renderCoverImgUrl || this.defaultCover;
  449. this.audioCtx.startTime = 0;
  450. this.audioCtx.seek(0);
  451. this.audioCtx.play();
  452. this.commit("setPause", false);
  453. this.commit("setPlayinfo", {
  454. src: renderSrc,
  455. title: renderTitle,
  456. singer: renderSinger,
  457. coverImgUrl: renderCoverImgUrl,
  458. });
  459. } else {
  460. if (paused) {
  461. //渲染与播放地址相同
  462. this.audioCtx.play();
  463. this.audioCtx.startTime = current_value;
  464. // this.audioCtx.seek(current_value);
  465. this.commit("setPause", false);
  466. this.commit("setPlayinfo", {
  467. src: renderSrc,
  468. title: renderTitle,
  469. singer: renderSinger,
  470. coverImgUrl: renderCoverImgUrl,
  471. });
  472. } else {
  473. this.audioCtx.pause();
  474. this.commit("setPause", true);
  475. this.commit("setUnnormalPause", true);
  476. }
  477. }
  478. });
  479. }
  480. /**
  481. * @description 覆盖音频
  482. * @param {Array<audio>} data 音频数组
  483. * @returns undefined
  484. * **/
  485. setAudio(data) {
  486. this.audiolist = [...data];
  487. this.emit(zaudioCbName.setAudio, this.audiolist);
  488. this.syncStateEmit();
  489. }
  490. /**
  491. * @description 添加音频
  492. * @param {Array<audio>} data 音频数组
  493. * @returns undefined
  494. * **/
  495. updateAudio(data) {
  496. this.audiolist.push(...data);
  497. this.emit(zaudioCbName.updateAudio, this.audiolist);
  498. this.syncStateEmit();
  499. }
  500. /**
  501. * @description 设置当前播放信息
  502. * @param {<audioInfo>} data 音频对象
  503. * @returns undefined
  504. * **/
  505. setPlayinfo(data) {
  506. for (let i in data) {
  507. this.playinfo[i] = data[i];
  508. }
  509. }
  510. /**
  511. * @description 设置暂停状态
  512. * @param {boolean} data 布尔值
  513. * @returns undefined
  514. * **/
  515. setPause(data) {
  516. this.paused = data;
  517. }
  518. /**
  519. * @description 设置loading
  520. * @param {boolean} data 布尔值
  521. * @returns undefined
  522. * **/
  523. setLoading(data) {
  524. this.loading = data;
  525. }
  526. /**
  527. * @description 设置通话时暂停状态
  528. * @param {boolean} data 布尔值
  529. * @returns undefined
  530. * **/
  531. setUnnormalPause(data) {
  532. this.uPause = data;
  533. }
  534. /**
  535. * @description 设置渲染
  536. * @param {number | string | audioInfo} data 索引或渲染信息
  537. * @returns undefined
  538. * **/
  539. setRender(data) {
  540. if (this.audiolist.length == 0)
  541. return;
  542. if (typeof data === "number" || typeof data === "string") {
  543. this.renderIndex = typeof data === "string" ? parseInt(data) : data;
  544. this.renderinfo = {
  545. src: this.audiolist[this.renderIndex].src,
  546. title: this.audiolist[this.renderIndex].title,
  547. singer: this.audiolist[this.renderIndex].singer,
  548. coverImgUrl: this.audiolist[this.renderIndex].coverImgUrl,
  549. current: "00:00:00",
  550. duration: "00:00:00",
  551. current_value: 0,
  552. duration_value: 100,
  553. };
  554. } else {
  555. this.renderinfo = data;
  556. let renderIndex = this.audiolist.findIndex((i) => i.src == data.src);
  557. if (renderIndex >= 0) {
  558. this.renderIndex = renderIndex;
  559. }
  560. }
  561. this.syncStateEmit();
  562. }
  563. //当前索引
  564. get playIndex() {
  565. let index = this.audiolist.findIndex((i) => i.src == this.playinfo.src);
  566. return index <= 0 ? 0 : index;
  567. }
  568. //渲染与播放是否一致
  569. get renderIsPlay() {
  570. return this.renderinfo.src == this.playinfo.src;
  571. }
  572. //app端判断电话来电后, 音频意外中断之后的继续播放
  573. appCheckReplay() {
  574. let _t = this;
  575. // #ifdef APP-PLUS
  576. try {
  577. if (uni.getSystemInfoSync().platform == "android") {
  578. var main = plus.android.runtimeMainActivity();
  579. var Context = plus.android.importClass("android.content.Context");
  580. var telephonyManager = plus.android.importClass("android.telephony.TelephonyManager");
  581. var telephonyManager = plus.android
  582. .runtimeMainActivity()
  583. .getSystemService(Context.TELEPHONY_SERVICE);
  584. var receiver = plus.android.implements("io.dcloud.android.content.BroadcastReceiver", {
  585. onReceive: function(intent) {
  586. //实现onReceiver回调函数
  587. plus.android.importClass(intent);
  588. var telephonyManager = plus.android.importClass(
  589. "android.telephony.TelephonyManager");
  590. var telephonyManager = plus.android
  591. .runtimeMainActivity()
  592. .getSystemService(Context.TELEPHONY_SERVICE);
  593. var phonetype = telephonyManager.getCallState();
  594. var phoneNumber = intent.getStringExtra(telephonyManager
  595. .EXTRA_INCOMING_NUMBER);
  596. if (phonetype == 0 && !_t.uPause) {
  597. _t.audioCtx.play();
  598. }
  599. },
  600. });
  601. var IntentFilter = plus.android.importClass("android.content.IntentFilter");
  602. var filter = new IntentFilter();
  603. filter.addAction(telephonyManager.ACTION_PHONE_STATE_CHANGED); //监听开关
  604. main.registerReceiver(receiver, filter); //注册监听
  605. } else if (uni.getSystemInfoSync().platform == "ios") {
  606. var callstatus = false;
  607. var CTCall = plus.ios.importClass("CTCall");
  608. var CTCallCenter = plus.ios.importClass("CTCallCenter");
  609. var center = new CTCallCenter();
  610. center.init();
  611. center.setCallEventr(function(ctCall) {
  612. callstatus = !callstatus;
  613. if (!callstatus && !_t.uPause) {
  614. _t.audioCtx.play();
  615. } else {
  616. _t.audioCtx.pause();
  617. }
  618. });
  619. }
  620. } catch (err) {
  621. console.warn(err);
  622. }
  623. // #endif
  624. }
  625. }
  626. exports.default = ZAudio;
  627. ZAudio.version = "2.2.51";