@aochuang/common 1.0.129 → 1.0.131
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/common/tooltip/popper.js +50 -0
- package/common/tooltip/tooltip.vue +5 -2
- package/common/voice/voice-player-aac.js +51 -88
- package/components/icon/demo_index.html +26 -3
- package/components/icon/iconfont.css +7 -3
- package/components/icon/iconfont.js +1 -1
- package/components/icon/iconfont.json +7 -0
- package/components/icon/iconfont.ttf +0 -0
- package/components/icon/iconfont.woff +0 -0
- package/components/icon/iconfont.woff2 +0 -0
- package/package.json +1 -1
package/common/tooltip/popper.js
CHANGED
|
@@ -4,6 +4,26 @@ import UiTooltip from '../../components/tooltip'
|
|
|
4
4
|
const TooltipConstructor = Vue.extend(UiTooltip)
|
|
5
5
|
|
|
6
6
|
let tooltip = null
|
|
7
|
+
let referenceObserver = null
|
|
8
|
+
let referenceElm = null
|
|
9
|
+
|
|
10
|
+
function isReferenceHidden ($el) {
|
|
11
|
+
if (!$el || !document.body.contains($el)) {
|
|
12
|
+
return true
|
|
13
|
+
}
|
|
14
|
+
if (!$el.getClientRects().length) {
|
|
15
|
+
return true
|
|
16
|
+
}
|
|
17
|
+
const style = window.getComputedStyle($el)
|
|
18
|
+
return style.display === 'none' || style.visibility === 'hidden'
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function checkReferenceVisible () {
|
|
22
|
+
if (isReferenceHidden(referenceElm)) {
|
|
23
|
+
hideTooltip()
|
|
24
|
+
clearTooltipReferenceWatch()
|
|
25
|
+
}
|
|
26
|
+
}
|
|
7
27
|
|
|
8
28
|
export function getTooltip () {
|
|
9
29
|
if (!tooltip) {
|
|
@@ -16,3 +36,33 @@ export function getTooltip () {
|
|
|
16
36
|
}
|
|
17
37
|
return tooltip
|
|
18
38
|
}
|
|
39
|
+
|
|
40
|
+
export function watchTooltipReference ($el) {
|
|
41
|
+
clearTooltipReferenceWatch()
|
|
42
|
+
referenceElm = $el
|
|
43
|
+
if (!referenceElm || typeof MutationObserver === 'undefined') {
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
referenceObserver = new MutationObserver(checkReferenceVisible)
|
|
47
|
+
referenceObserver.observe(document.body, {
|
|
48
|
+
childList: true,
|
|
49
|
+
subtree: true,
|
|
50
|
+
attributes: true,
|
|
51
|
+
attributeFilter: ['class', 'style', 'hidden']
|
|
52
|
+
})
|
|
53
|
+
checkReferenceVisible()
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function clearTooltipReferenceWatch () {
|
|
57
|
+
if (referenceObserver) {
|
|
58
|
+
referenceObserver.disconnect()
|
|
59
|
+
referenceObserver = null
|
|
60
|
+
}
|
|
61
|
+
referenceElm = null
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function hideTooltip () {
|
|
65
|
+
if (tooltip) {
|
|
66
|
+
tooltip.visible = false
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script>
|
|
2
|
-
import { getTooltip } from './popper'
|
|
2
|
+
import { clearTooltipReferenceWatch, getTooltip, watchTooltipReference } from './popper'
|
|
3
3
|
|
|
4
4
|
let _timer = null
|
|
5
5
|
|
|
@@ -29,14 +29,17 @@ export default {
|
|
|
29
29
|
...context.listeners,
|
|
30
30
|
mouseenter (e) {
|
|
31
31
|
clearTimeout(_timer)
|
|
32
|
+
const referenceElm = e.currentTarget || e.target
|
|
32
33
|
const tooltip = getTooltip()
|
|
33
34
|
tooltip.visible = true
|
|
34
35
|
tooltip.content = context.props.text
|
|
35
36
|
tooltip.html = context.props.html
|
|
36
|
-
tooltip.setReferenceElm(
|
|
37
|
+
tooltip.setReferenceElm(referenceElm)
|
|
38
|
+
watchTooltipReference(referenceElm)
|
|
37
39
|
},
|
|
38
40
|
mouseleave () {
|
|
39
41
|
clearTimeout(_timer)
|
|
42
|
+
clearTooltipReferenceWatch()
|
|
40
43
|
const tooltip = getTooltip()
|
|
41
44
|
tooltip.visible = false
|
|
42
45
|
},
|
|
@@ -2,19 +2,7 @@ import { loadScript } from '../../utils/file'
|
|
|
2
2
|
import { getAacCodecParserLibPath } from './util'
|
|
3
3
|
import axios from 'axios'
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
if (sourceBuffer.updating) {
|
|
7
|
-
await new Promise(resolve => {
|
|
8
|
-
sourceBuffer.addEventListener('updateend', resolve, { once: true });
|
|
9
|
-
});
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
sourceBuffer.appendBuffer(buffer);
|
|
13
|
-
|
|
14
|
-
return new Promise(resolve => {
|
|
15
|
-
sourceBuffer.addEventListener('updateend', resolve, { once: true });
|
|
16
|
-
});
|
|
17
|
-
}
|
|
5
|
+
const STREAMING_FILE_SIZE = 1 * 1024 * 1024
|
|
18
6
|
|
|
19
7
|
export default class VoicePlayerAAC {
|
|
20
8
|
constructor(options) {
|
|
@@ -59,12 +47,12 @@ export default class VoicePlayerAAC {
|
|
|
59
47
|
this.bindAudioEvents()
|
|
60
48
|
}
|
|
61
49
|
|
|
62
|
-
//
|
|
50
|
+
// AAC 的 SourceBuffer 配额在不同浏览器差异很大,超过 1MiB 统一走流式追加。
|
|
63
51
|
isUseBigFile (audioData) {
|
|
64
52
|
if (!audioData) {
|
|
65
53
|
return false
|
|
66
54
|
}
|
|
67
|
-
return audioData.byteLength >
|
|
55
|
+
return audioData.byteLength > STREAMING_FILE_SIZE
|
|
68
56
|
}
|
|
69
57
|
|
|
70
58
|
bindAudioEvents() {
|
|
@@ -106,8 +94,7 @@ export default class VoicePlayerAAC {
|
|
|
106
94
|
this.options.onEnded?.()
|
|
107
95
|
})
|
|
108
96
|
|
|
109
|
-
this.$audio.addEventListener('error', (
|
|
110
|
-
console.error('Audio error:', this.$audio.error)
|
|
97
|
+
this.$audio.addEventListener('error', () => {
|
|
111
98
|
this.options.onError?.({
|
|
112
99
|
type: 'aac',
|
|
113
100
|
url: this._url,
|
|
@@ -144,7 +131,6 @@ export default class VoicePlayerAAC {
|
|
|
144
131
|
clearTimeout(this.seekDebounceTimer)
|
|
145
132
|
this.seekDebounceTimer = setTimeout(async () => {
|
|
146
133
|
const targetTime = Math.max(0, Math.min(position, this.estimatedDuration))
|
|
147
|
-
console.log('[setPosition] 防抖后执行跳转:', targetTime)
|
|
148
134
|
await this.seekToTime(targetTime, targetTime < this.$audio.currentTime)
|
|
149
135
|
}, 300)
|
|
150
136
|
} else {
|
|
@@ -191,38 +177,40 @@ export default class VoicePlayerAAC {
|
|
|
191
177
|
try {
|
|
192
178
|
this.clearMediaResources()
|
|
193
179
|
this.audioData = audioData
|
|
194
|
-
|
|
180
|
+
const useStreaming = this.isUseBigFile(this.audioData)
|
|
195
181
|
this.estimatedDuration = this.calculateEstimatedDuration(this.audioData.byteLength)
|
|
196
|
-
console.log('预估总时长:', this.estimatedDuration.toFixed(2), 's | 使用码率:', this.options.bitrateKbps, 'kbps')
|
|
197
182
|
this.mediaSource = new MediaSource()
|
|
198
183
|
this.currentMediaSource = this.mediaSource
|
|
199
184
|
this.mediaSourceSrc = URL.createObjectURL(this.mediaSource)
|
|
200
185
|
this.currentObjectUrl = this.mediaSourceSrc
|
|
201
186
|
this.$audio.src = this.mediaSourceSrc
|
|
202
|
-
if (
|
|
187
|
+
if (useStreaming) {
|
|
203
188
|
this.$audio.addEventListener('waiting', async () => {
|
|
204
189
|
if (!this.isSeeking) {
|
|
205
|
-
console.log('检测到缓冲不足,补充10秒缓冲...')
|
|
206
190
|
await this.forcePreload(10)
|
|
207
191
|
}
|
|
208
192
|
}, { passive: true })
|
|
209
193
|
this.$audio.addEventListener('playing', () => this.isPlaying = true)
|
|
210
194
|
this.$audio.addEventListener('pause', () => this.isPlaying = false)
|
|
211
195
|
this.mediaSource.addEventListener('sourceerror', (e) => {
|
|
212
|
-
console.error('媒体源错误:', e)
|
|
213
196
|
this.options.onError?.({ type: 'mse', url: this._url, message: e })
|
|
214
197
|
})
|
|
215
198
|
this.mediaSource.addEventListener('sourceopen', async () => {
|
|
216
199
|
if (!this._play) return
|
|
217
200
|
try {
|
|
218
|
-
|
|
219
|
-
this.wrapper = new window.MSEAudioWrapper(MIME_TYPE)
|
|
201
|
+
this.wrapper = new window.MSEAudioWrapper('audio/aac')
|
|
220
202
|
this.iterator = this.wrapper.iterator(this.audioData)
|
|
221
|
-
|
|
203
|
+
const firstSegment = this.iterator.next()
|
|
204
|
+
if (firstSegment.done || !firstSegment.value) {
|
|
205
|
+
throw new Error('AAC 解析失败,未生成可播放分片')
|
|
206
|
+
}
|
|
207
|
+
if (!this.wrapper.mimeType) {
|
|
208
|
+
throw new Error('AAC 解析失败,未识别出 MSE mimeType')
|
|
209
|
+
}
|
|
210
|
+
this.sourceBuffer = this.mediaSource.addSourceBuffer(this.wrapper.mimeType)
|
|
222
211
|
this.sourceBuffer.mode = 'sequence'
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
for (let i = 0; i < 15; i++) {
|
|
212
|
+
const initialSegments = [firstSegment.value]
|
|
213
|
+
for (let i = 1; i < 15; i++) {
|
|
226
214
|
const { value, done } = this.iterator.next()
|
|
227
215
|
if (done) break
|
|
228
216
|
initialSegments.push(value)
|
|
@@ -230,7 +218,6 @@ export default class VoicePlayerAAC {
|
|
|
230
218
|
for (const seg of initialSegments) {
|
|
231
219
|
await this.appendBufferSafe(this.sourceBuffer, seg)
|
|
232
220
|
}
|
|
233
|
-
console.log('初始缓冲加载完成 | 缓冲范围:', this.getBufferedRange())
|
|
234
221
|
this.$audio.currentTime = 0
|
|
235
222
|
await this.$audio.play()
|
|
236
223
|
this.isPlaying = true
|
|
@@ -243,8 +230,8 @@ export default class VoicePlayerAAC {
|
|
|
243
230
|
if (bufferStart < cleanEnd && cleanEnd <= bufferEnd) {
|
|
244
231
|
try {
|
|
245
232
|
await this.safeRemoveBuffer(this.sourceBuffer, bufferStart, cleanEnd)
|
|
246
|
-
} catch
|
|
247
|
-
|
|
233
|
+
} catch {
|
|
234
|
+
// 清理失败时跳过本次清理,后续追加失败会走 appendBufferSafe 的配额兜底。
|
|
248
235
|
}
|
|
249
236
|
}
|
|
250
237
|
}
|
|
@@ -255,10 +242,12 @@ export default class VoicePlayerAAC {
|
|
|
255
242
|
if (!done) {
|
|
256
243
|
await this.appendBufferSafe(this.sourceBuffer, segment)
|
|
257
244
|
} else {
|
|
258
|
-
this.mediaSource.
|
|
245
|
+
if (this.mediaSource.readyState === 'open') {
|
|
246
|
+
this.mediaSource.endOfStream()
|
|
247
|
+
}
|
|
259
248
|
}
|
|
260
|
-
} catch
|
|
261
|
-
|
|
249
|
+
} catch {
|
|
250
|
+
// 当前分片加载失败时停止本轮追加,下一轮缓冲检查会继续尝试。
|
|
262
251
|
} finally {
|
|
263
252
|
this.loadNextSegment = false
|
|
264
253
|
}
|
|
@@ -273,48 +262,32 @@ export default class VoicePlayerAAC {
|
|
|
273
262
|
}, 500)
|
|
274
263
|
|
|
275
264
|
} catch (e) {
|
|
276
|
-
console.error('MSE 初始化失败:', e)
|
|
277
265
|
this.options.onError?.({ type: 'mse', url: this._url, message: e })
|
|
278
266
|
}
|
|
279
267
|
}, { once: true })
|
|
280
|
-
this.$audio.play().catch(
|
|
268
|
+
this.$audio.play().catch(() => {})
|
|
281
269
|
} else {
|
|
282
270
|
this.mediaSource.addEventListener('sourceopen', async () => {
|
|
283
271
|
if (!this._play) {
|
|
284
272
|
return
|
|
285
273
|
}
|
|
286
274
|
try {
|
|
287
|
-
this.wrapper = new window.MSEAudioWrapper('audio/aac')
|
|
288
|
-
this.sourceBuffer = null
|
|
289
|
-
let segmentCount = 0;
|
|
290
|
-
let totalBytesProcessed = 0;
|
|
275
|
+
this.wrapper = new window.MSEAudioWrapper('audio/aac')
|
|
276
|
+
this.sourceBuffer = null
|
|
291
277
|
for (const segment of this.wrapper.iterator(this.audioData)) {
|
|
292
|
-
segmentCount++;
|
|
293
|
-
totalBytesProcessed += segment.byteLength;
|
|
294
|
-
console.log(`Processing segment ${segmentCount}, size: ${segment.byteLength}`);
|
|
295
278
|
if (!this.sourceBuffer) {
|
|
296
279
|
if (this.wrapper.mimeType) {
|
|
297
|
-
|
|
298
|
-
this.sourceBuffer =
|
|
299
|
-
console.log('Default SourceBuffer mode:', this.sourceBuffer.mode);
|
|
300
|
-
this.sourceBuffer.mode = 'sequence'; // Critical for timeline placement
|
|
301
|
-
console.log('Set SourceBuffer mode to:', this.sourceBuffer.mode);
|
|
280
|
+
this.sourceBuffer = this.mediaSource.addSourceBuffer(this.wrapper.mimeType)
|
|
281
|
+
this.sourceBuffer.mode = 'sequence' // Critical for timeline placement
|
|
302
282
|
} else {
|
|
303
|
-
throw new Error('MimeType not determined yet')
|
|
283
|
+
throw new Error('MimeType not determined yet')
|
|
304
284
|
}
|
|
305
285
|
}
|
|
306
|
-
await
|
|
307
|
-
}
|
|
308
|
-
console.log(`Finished processing. Total segments: ${segmentCount}, Total bytes: ${totalBytesProcessed}`);
|
|
309
|
-
this.mediaSource.endOfStream();
|
|
310
|
-
if (this.sourceBuffer && this.sourceBuffer.buffered.length > 0) {
|
|
311
|
-
const buffered = this.sourceBuffer.buffered;
|
|
312
|
-
console.log(`Buffered range: ${buffered.start(0)} - ${buffered.end(0)}`);
|
|
313
|
-
console.log(`Audio duration: ${this.$audio.duration}`);
|
|
286
|
+
await this.appendBufferSafe(this.sourceBuffer, segment)
|
|
314
287
|
}
|
|
288
|
+
this.mediaSource.endOfStream()
|
|
315
289
|
this.$audio.play()
|
|
316
290
|
} catch (e) {
|
|
317
|
-
console.error(e);
|
|
318
291
|
this.options.onError && this.options.onError({
|
|
319
292
|
type: 'aac',
|
|
320
293
|
url: this._url,
|
|
@@ -324,7 +297,6 @@ export default class VoicePlayerAAC {
|
|
|
324
297
|
})
|
|
325
298
|
}
|
|
326
299
|
} catch (err) {
|
|
327
|
-
console.error('音频播放全局错误:', err)
|
|
328
300
|
this.options.onError?.({ type: 'global', url: this._url, message: err })
|
|
329
301
|
}
|
|
330
302
|
}).finally(() => {
|
|
@@ -341,21 +313,15 @@ export default class VoicePlayerAAC {
|
|
|
341
313
|
}
|
|
342
314
|
sourceBuffer.remove(start, end)
|
|
343
315
|
await new Promise(resolve => sourceBuffer.addEventListener('updateend', resolve, { once: true }))
|
|
344
|
-
|
|
345
|
-
if (sourceBuffer.buffered.length === 0) {
|
|
346
|
-
console.log(`缓冲清理成功: ${start.toFixed(1)}s -> ${end.toFixed(1)}s | 无残留`)
|
|
347
|
-
return true
|
|
348
|
-
}
|
|
316
|
+
return true
|
|
349
317
|
} catch (err) {
|
|
350
318
|
if (err.name === 'InvalidStateError' && i < retries - 1) {
|
|
351
|
-
console.warn(`缓冲清理重试 ${i + 1}/${retries}:`, err)
|
|
352
319
|
await new Promise(resolve => setTimeout(resolve, delay))
|
|
353
320
|
} else {
|
|
354
|
-
console.error('缓冲清理最终失败:', err)
|
|
355
321
|
// 兜底:强制清空所有缓冲
|
|
356
322
|
try {
|
|
357
323
|
sourceBuffer.remove(0, sourceBuffer.buffered.end(0))
|
|
358
|
-
} catch
|
|
324
|
+
} catch {}
|
|
359
325
|
return false
|
|
360
326
|
}
|
|
361
327
|
}
|
|
@@ -375,16 +341,13 @@ export default class VoicePlayerAAC {
|
|
|
375
341
|
// 重写:适配逻辑仅在缓冲覆盖目标时间后生效,不提前适配到分片起始
|
|
376
342
|
getNearestValidPlayTime(targetTime) {
|
|
377
343
|
if (!this.sourceBuffer || this.sourceBuffer.buffered.length === 0) {
|
|
378
|
-
console.log('[适配位置] 无缓冲,使用目标时间:', targetTime)
|
|
379
344
|
return targetTime
|
|
380
345
|
}
|
|
381
346
|
|
|
382
347
|
const [bufferStart, bufferEnd] = this.getBufferedRange()
|
|
383
|
-
console.log(`[适配位置] 目标时间:${targetTime.toFixed(1)}s | 缓冲范围:${bufferStart.toFixed(1)}~${bufferEnd.toFixed(1)}s`)
|
|
384
348
|
|
|
385
349
|
// 核心修改:如果缓冲未覆盖目标时间,返回目标时间(等待加载),而非跳转到缓冲边界
|
|
386
350
|
if (targetTime > bufferEnd) {
|
|
387
|
-
console.log('[适配位置] 缓冲未覆盖目标时间,等待加载后再定位')
|
|
388
351
|
return targetTime
|
|
389
352
|
}
|
|
390
353
|
if (targetTime < bufferStart) return bufferStart
|
|
@@ -397,7 +360,6 @@ export default class VoicePlayerAAC {
|
|
|
397
360
|
const newTime = this.getNearestValidPlayTime(targetTime)
|
|
398
361
|
|
|
399
362
|
if (newTime !== this.$audio.currentTime) {
|
|
400
|
-
console.log('[自动适配] 调整播放时间为:', newTime.toFixed(1))
|
|
401
363
|
this.$audio.currentTime = newTime
|
|
402
364
|
}
|
|
403
365
|
}
|
|
@@ -416,10 +378,8 @@ export default class VoicePlayerAAC {
|
|
|
416
378
|
preloaded++
|
|
417
379
|
}
|
|
418
380
|
const [start, end] = this.getBufferedRange()
|
|
419
|
-
console.log(`预加载完成,新增${preloaded}秒缓冲 | 当前缓冲:${start.toFixed(1)}~${end.toFixed(1)}s`)
|
|
420
381
|
return [start, end]
|
|
421
|
-
} catch
|
|
422
|
-
console.error('强制预加载失败:', err)
|
|
382
|
+
} catch {
|
|
423
383
|
return [0, 0]
|
|
424
384
|
} finally {
|
|
425
385
|
this.isPreloading = false
|
|
@@ -429,16 +389,14 @@ export default class VoicePlayerAAC {
|
|
|
429
389
|
/**
|
|
430
390
|
* 核心重写:解决定位到分片起始、向后跳转无反应、适配过早问题
|
|
431
391
|
*/
|
|
432
|
-
async seekToTime(targetTime
|
|
392
|
+
async seekToTime(targetTime) {
|
|
433
393
|
if (this.isSeeking) {
|
|
434
|
-
console.log('[seekToTime] 正在执行拖拽,跳过本次请求')
|
|
435
394
|
return
|
|
436
395
|
}
|
|
437
396
|
this.isSeeking = true
|
|
438
397
|
// 锁定最终目标时间,全程不改变
|
|
439
398
|
const finalTargetTime = Math.max(0, Math.min(targetTime, this.estimatedDuration))
|
|
440
399
|
this.lastSeekTarget = finalTargetTime
|
|
441
|
-
console.log(`[seekToTime] 锁定目标时间:${finalTargetTime.toFixed(1)}s | 向后跳转:${isBackwardSeek}`)
|
|
442
400
|
|
|
443
401
|
try {
|
|
444
402
|
// 1. 等待空闲 + 彻底清理旧缓冲
|
|
@@ -453,14 +411,12 @@ export default class VoicePlayerAAC {
|
|
|
453
411
|
// 2. 精准计算字节位置(使用可配置码率),重置迭代器
|
|
454
412
|
const targetBytePosition = Math.max(0, (finalTargetTime / this.estimatedDuration) * this.audioData.length)
|
|
455
413
|
this.iterator = this.wrapper.iterator(this.audioData.slice(targetBytePosition))
|
|
456
|
-
console.log(`[seekToTime] 迭代器定位到字节:${targetBytePosition} | 对应目标时间:${finalTargetTime.toFixed(1)}s`)
|
|
457
414
|
|
|
458
415
|
// 3. 预加载目标缓冲,等待加载完成
|
|
459
|
-
|
|
416
|
+
await this.forcePreload(20) // 增加预加载时长,确保覆盖目标时间
|
|
460
417
|
|
|
461
418
|
// 4. 适配位置(此时缓冲已加载,不会跳转到分片起始)
|
|
462
419
|
const adaptTime = this.getNearestValidPlayTime(finalTargetTime)
|
|
463
|
-
console.log(`[seekToTime] 缓冲加载完成 | 最终定位时间:${adaptTime.toFixed(1)}s`)
|
|
464
420
|
|
|
465
421
|
// 5. 强制设置播放位置,解决向后跳转无反应
|
|
466
422
|
this.$audio.currentTime = adaptTime
|
|
@@ -470,7 +426,7 @@ export default class VoicePlayerAAC {
|
|
|
470
426
|
}
|
|
471
427
|
|
|
472
428
|
} catch (err) {
|
|
473
|
-
|
|
429
|
+
this.options.onError?.({ type: 'mse', url: this._url, message: err })
|
|
474
430
|
} finally {
|
|
475
431
|
// 延迟释放锁,确保缓冲完全加载
|
|
476
432
|
setTimeout(() => {
|
|
@@ -497,12 +453,19 @@ export default class VoicePlayerAAC {
|
|
|
497
453
|
await new Promise(resolve => sourceBuffer.addEventListener('updateend', resolve, { once: true }))
|
|
498
454
|
} catch (err) {
|
|
499
455
|
if (err.name === 'QuotaExceededError') {
|
|
500
|
-
|
|
501
|
-
|
|
456
|
+
const bufferedEnd = sourceBuffer.buffered && sourceBuffer.buffered.length > 0
|
|
457
|
+
? sourceBuffer.buffered.end(0)
|
|
458
|
+
: 0
|
|
459
|
+
if (bufferedEnd > 0) {
|
|
460
|
+
await this.safeRemoveBuffer(sourceBuffer, 0, Math.min(10, bufferedEnd))
|
|
461
|
+
}
|
|
462
|
+
if (sourceBuffer.updating) {
|
|
463
|
+
await new Promise(resolve => sourceBuffer.addEventListener('updateend', resolve, { once: true }))
|
|
464
|
+
}
|
|
502
465
|
sourceBuffer.appendBuffer(buffer)
|
|
503
466
|
await new Promise(resolve => sourceBuffer.addEventListener('updateend', resolve, { once: true }))
|
|
504
467
|
} else {
|
|
505
|
-
|
|
468
|
+
throw err
|
|
506
469
|
}
|
|
507
470
|
}
|
|
508
471
|
}
|
|
@@ -557,11 +520,11 @@ export default class VoicePlayerAAC {
|
|
|
557
520
|
}
|
|
558
521
|
|
|
559
522
|
resume () {
|
|
560
|
-
|
|
523
|
+
// AAC 暂不支持暂停/恢复。
|
|
561
524
|
}
|
|
562
525
|
|
|
563
526
|
pause () {
|
|
564
|
-
|
|
527
|
+
// AAC 暂不支持暂停/恢复。
|
|
565
528
|
}
|
|
566
529
|
|
|
567
530
|
stop (callback) {
|
|
@@ -581,4 +544,4 @@ export default class VoicePlayerAAC {
|
|
|
581
544
|
this.stop()
|
|
582
545
|
this.clearMediaResources()
|
|
583
546
|
}
|
|
584
|
-
}
|
|
547
|
+
}
|
|
@@ -54,6 +54,12 @@
|
|
|
54
54
|
<div class="content unicode" style="display: block;">
|
|
55
55
|
<ul class="icon_lists dib-box">
|
|
56
56
|
|
|
57
|
+
<li class="dib">
|
|
58
|
+
<span class="icon iconfont"></span>
|
|
59
|
+
<div class="name">bookmark-3-line</div>
|
|
60
|
+
<div class="code-name">&#xe6f9;</div>
|
|
61
|
+
</li>
|
|
62
|
+
|
|
57
63
|
<li class="dib">
|
|
58
64
|
<span class="icon iconfont"></span>
|
|
59
65
|
<div class="name">聚合列表</div>
|
|
@@ -2400,9 +2406,9 @@
|
|
|
2400
2406
|
<pre><code class="language-css"
|
|
2401
2407
|
>@font-face {
|
|
2402
2408
|
font-family: 'iconfont';
|
|
2403
|
-
src: url('iconfont.woff2?t=
|
|
2404
|
-
url('iconfont.woff?t=
|
|
2405
|
-
url('iconfont.ttf?t=
|
|
2409
|
+
src: url('iconfont.woff2?t=1785221329948') format('woff2'),
|
|
2410
|
+
url('iconfont.woff?t=1785221329948') format('woff'),
|
|
2411
|
+
url('iconfont.ttf?t=1785221329948') format('truetype');
|
|
2406
2412
|
}
|
|
2407
2413
|
</code></pre>
|
|
2408
2414
|
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
|
|
@@ -2428,6 +2434,15 @@
|
|
|
2428
2434
|
<div class="content font-class">
|
|
2429
2435
|
<ul class="icon_lists dib-box">
|
|
2430
2436
|
|
|
2437
|
+
<li class="dib">
|
|
2438
|
+
<span class="icon iconfont icon-bookmark-3-line"></span>
|
|
2439
|
+
<div class="name">
|
|
2440
|
+
bookmark-3-line
|
|
2441
|
+
</div>
|
|
2442
|
+
<div class="code-name">.icon-bookmark-3-line
|
|
2443
|
+
</div>
|
|
2444
|
+
</li>
|
|
2445
|
+
|
|
2431
2446
|
<li class="dib">
|
|
2432
2447
|
<span class="icon iconfont icon-aggregation-list-line"></span>
|
|
2433
2448
|
<div class="name">
|
|
@@ -5947,6 +5962,14 @@
|
|
|
5947
5962
|
<div class="content symbol">
|
|
5948
5963
|
<ul class="icon_lists dib-box">
|
|
5949
5964
|
|
|
5965
|
+
<li class="dib">
|
|
5966
|
+
<svg class="icon svg-icon" aria-hidden="true">
|
|
5967
|
+
<use xlink:href="#icon-bookmark-3-line"></use>
|
|
5968
|
+
</svg>
|
|
5969
|
+
<div class="name">bookmark-3-line</div>
|
|
5970
|
+
<div class="code-name">#icon-bookmark-3-line</div>
|
|
5971
|
+
</li>
|
|
5972
|
+
|
|
5950
5973
|
<li class="dib">
|
|
5951
5974
|
<svg class="icon svg-icon" aria-hidden="true">
|
|
5952
5975
|
<use xlink:href="#icon-aggregation-list-line"></use>
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
@font-face {
|
|
2
2
|
font-family: "iconfont"; /* Project id 4387417 */
|
|
3
|
-
src: url('iconfont.woff2?t=
|
|
4
|
-
url('iconfont.woff?t=
|
|
5
|
-
url('iconfont.ttf?t=
|
|
3
|
+
src: url('iconfont.woff2?t=1785221329948') format('woff2'),
|
|
4
|
+
url('iconfont.woff?t=1785221329948') format('woff'),
|
|
5
|
+
url('iconfont.ttf?t=1785221329948') format('truetype');
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
.iconfont {
|
|
@@ -13,6 +13,10 @@
|
|
|
13
13
|
-moz-osx-font-smoothing: grayscale;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
.icon-bookmark-3-line:before {
|
|
17
|
+
content: "\e6f9";
|
|
18
|
+
}
|
|
19
|
+
|
|
16
20
|
.icon-aggregation-list-line:before {
|
|
17
21
|
content: "\e6dd";
|
|
18
22
|
}
|