@aochuang/common 1.0.129 → 1.0.130

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.
@@ -2,19 +2,7 @@ import { loadScript } from '../../utils/file'
2
2
  import { getAacCodecParserLibPath } from './util'
3
3
  import axios from 'axios'
4
4
 
5
- async function appendBuffer(sourceBuffer, buffer) {
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
- // 大于18M走分片解析逻辑
50
+ // AAC 的 SourceBuffer 配额在不同浏览器差异很大,超过 1MiB 统一走流式追加。
63
51
  isUseBigFile (audioData) {
64
52
  if (!audioData) {
65
53
  return false
66
54
  }
67
- return audioData.byteLength > 18 * 1024 * 1024; // 18MB字节阈值
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', (e) => {
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
- console.log('音频数据加载完成,大小:', this.audioData.byteLength)
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 (this.isUseBigFile(this.audioData)) {
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
- const MIME_TYPE = 'audio/aac; codecs=mp4a.40.2'
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
- this.sourceBuffer = this.mediaSource.addSourceBuffer(this.wrapper.mimeType || MIME_TYPE)
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
- console.log('SourceBuffer 初始化完成,模式:', this.sourceBuffer.mode)
224
- const initialSegments = []
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 (err) {
247
- console.warn('清理缓冲失败,跳过本次操作:', err)
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.endOfStream()
245
+ if (this.mediaSource.readyState === 'open') {
246
+ this.mediaSource.endOfStream()
247
+ }
259
248
  }
260
- } catch (err) {
261
- console.error('加载分片失败:', err)
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(err => console.log('等待缓冲中:', err.message))
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
- console.log('Creating SourceBuffer with mimeType:', this.wrapper.mimeType);
298
- this.sourceBuffer = this.mediaSource.addSourceBuffer(this.wrapper.mimeType);
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 appendBuffer(this.sourceBuffer, segment);
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 (e) {}
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 (err) {
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, isBackwardSeek = false) {
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
- const [bufferStart, bufferEnd] = await this.forcePreload(20) // 增加预加载时长,确保覆盖目标时间
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
- console.error('定位失败:', err)
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
- console.warn('缓冲区已满,清理最旧的10秒缓冲...')
501
- await this.safeRemoveBuffer(sourceBuffer, 0, Math.min(10, sourceBuffer.buffered.end(0)))
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
- console.error('追加缓冲失败:', err)
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
- console.log('aac不支持')
523
+ // AAC 暂不支持暂停/恢复。
561
524
  }
562
525
 
563
526
  pause () {
564
- console.log('aac不支持')
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
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aochuang/common",
3
- "version": "1.0.129",
3
+ "version": "1.0.130",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "publishConfig": {