@cycjimmy/jsmpeg-player 6.1.7 → 6.1.8
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/README.md +1 -1
- package/dist/jsmpeg-player.cjs +217 -30
- package/dist/jsmpeg-player.esm.js +217 -30
- package/dist/jsmpeg-player.umd.js +217 -30
- package/dist/jsmpeg-player.umd.min.js +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* **[jsmpeg-player](https://github.com/cycdpo/jsmpeg-player) has been renamed to @cycjimmy/jsmpeg-player for scoped NPM package.**
|
|
13
13
|
* JSMpeg player is based on [jsmpeg](https://github.com/phoboslab/jsmpeg).
|
|
14
14
|
* The video must be compressed into the TS format of MPEG1 / MP2.
|
|
15
|
-
* Apple device automatically plays without sound, you need to guide the user to click on the video in the lower right corner of the video icon to unlock the sound. (no similar problem in non-autoplay mode)
|
|
15
|
+
* Autoplay with sound is blocked by the browser until the page receives a user gesture: Apple device automatically plays without sound, you need to guide the user to click on the video in the lower right corner of the video icon to unlock the sound. Chrome and Safari follow the same autoplay policy, where the sound stays in sync with the picture and starts as soon as the user interacts with the page, or can be unlocked right away through the same icon. (no similar problem in non-autoplay mode)
|
|
16
16
|
* [Demo][github-pages-url]
|
|
17
17
|
|
|
18
18
|
## How to use
|
package/dist/jsmpeg-player.cjs
CHANGED
|
@@ -235,10 +235,10 @@ var VideoElement = /*#__PURE__*/function () {
|
|
|
235
235
|
this.els.playButton.classList.add(_style.hidden);
|
|
236
236
|
}
|
|
237
237
|
|
|
238
|
-
// Set up the unlock audio button for
|
|
239
|
-
//
|
|
240
|
-
// streaming players we set up a muted speaker
|
|
241
|
-
// others, we can simply use the play button.
|
|
238
|
+
// Set up the unlock audio button for the browsers that do not allow audio
|
|
239
|
+
// before a user action (iOS, and Chrome/Safari under their autoplay
|
|
240
|
+
// policy). For autoplay or streaming players we set up a muted speaker
|
|
241
|
+
// icon as the button. For all others, we can simply use the play button.
|
|
242
242
|
if (this.player.audioOut && !this.player.audioOut.unlocked) {
|
|
243
243
|
var unlockAudioElement = this.els.wrapper;
|
|
244
244
|
if (this.options.autoplay || this.player.options.streaming) {
|
|
@@ -251,6 +251,12 @@ var VideoElement = /*#__PURE__*/function () {
|
|
|
251
251
|
this.unlockAudioBound = this.onUnlockAudio.bind(this, unlockAudioElement);
|
|
252
252
|
unlockAudioElement.addEventListener('touchstart', this.unlockAudioBound, false);
|
|
253
253
|
unlockAudioElement.addEventListener('click', this.unlockAudioBound, true);
|
|
254
|
+
|
|
255
|
+
// Any gesture on the page may unlock the audio, so the icon has to go
|
|
256
|
+
// away even when it was not the element that was clicked.
|
|
257
|
+
this.player.audioOut.onUnlock = function () {
|
|
258
|
+
return _this.onAudioUnlocked(unlockAudioElement);
|
|
259
|
+
};
|
|
254
260
|
}
|
|
255
261
|
};
|
|
256
262
|
_proto.initPlayButton = function initPlayButton() {
|
|
@@ -277,6 +283,15 @@ var VideoElement = /*#__PURE__*/function () {
|
|
|
277
283
|
});
|
|
278
284
|
});
|
|
279
285
|
};
|
|
286
|
+
_proto.onAudioUnlocked = function onAudioUnlocked(element) {
|
|
287
|
+
if (this.els.unmuteButton) {
|
|
288
|
+
this.els.unmuteButton.classList.add(_style.hidden);
|
|
289
|
+
}
|
|
290
|
+
if (element && this.unlockAudioBound) {
|
|
291
|
+
element.removeEventListener('touchstart', this.unlockAudioBound);
|
|
292
|
+
element.removeEventListener('click', this.unlockAudioBound);
|
|
293
|
+
}
|
|
294
|
+
};
|
|
280
295
|
_proto.onUnlockAudio = function onUnlockAudio(element, ev) {
|
|
281
296
|
var _this3 = this;
|
|
282
297
|
if (this.els.unmuteButton) {
|
|
@@ -284,11 +299,7 @@ var VideoElement = /*#__PURE__*/function () {
|
|
|
284
299
|
ev.stopPropagation();
|
|
285
300
|
}
|
|
286
301
|
this.player.audioOut.unlock(function () {
|
|
287
|
-
|
|
288
|
-
_this3.els.unmuteButton.classList.add(_style.hidden);
|
|
289
|
-
}
|
|
290
|
-
element.removeEventListener('touchstart', _this3.unlockAudioBound);
|
|
291
|
-
element.removeEventListener('click', _this3.unlockAudioBound);
|
|
302
|
+
return _this3.onAudioUnlocked(element);
|
|
292
303
|
});
|
|
293
304
|
};
|
|
294
305
|
_proto.onClick = function onClick() {
|
|
@@ -4049,11 +4060,15 @@ var MP2WASM = /*#__PURE__*/function (_BaseDecoder) {
|
|
|
4049
4060
|
_this.bufferSize = options.audioBufferSize || 128 * 1024;
|
|
4050
4061
|
_this.bufferMode = options.streaming ? BitBuffer.MODE.EVICT : BitBuffer.MODE.EXPAND;
|
|
4051
4062
|
_this.sampleRate = 0;
|
|
4063
|
+
_this.destroyed = false;
|
|
4052
4064
|
return _this;
|
|
4053
4065
|
}
|
|
4054
4066
|
_inheritsLoose(MP2WASM, _BaseDecoder);
|
|
4055
4067
|
var _proto = MP2WASM.prototype;
|
|
4056
4068
|
_proto.initializeWasmDecoder = function initializeWasmDecoder() {
|
|
4069
|
+
if (this.destroyed) {
|
|
4070
|
+
return;
|
|
4071
|
+
}
|
|
4057
4072
|
if (!this.module.instance) {
|
|
4058
4073
|
console.warn('JSMpeg: WASM module not compiled yet');
|
|
4059
4074
|
return;
|
|
@@ -4063,10 +4078,23 @@ var MP2WASM = /*#__PURE__*/function (_BaseDecoder) {
|
|
|
4063
4078
|
this.decoder = this.functions._mp2_decoder_create(this.bufferSize, this.bufferMode);
|
|
4064
4079
|
};
|
|
4065
4080
|
_proto.destroy = function destroy() {
|
|
4081
|
+
// A source can still deliver one last chunk inside the very callback that
|
|
4082
|
+
// destroys the player, so nothing may reach the module from now on.
|
|
4083
|
+
this.destroyed = true;
|
|
4066
4084
|
if (!this.decoder) {
|
|
4067
4085
|
return;
|
|
4068
4086
|
}
|
|
4069
4087
|
this.functions._mp2_decoder_destroy(this.decoder);
|
|
4088
|
+
// The pointer refers to a freed block now, and the module may hand the same
|
|
4089
|
+
// address to the decoder of the next player: it must never be used again.
|
|
4090
|
+
this.decoder = null;
|
|
4091
|
+
this.canPlay = false;
|
|
4092
|
+
};
|
|
4093
|
+
_proto.write = function write(pts, buffers) {
|
|
4094
|
+
if (this.destroyed) {
|
|
4095
|
+
return;
|
|
4096
|
+
}
|
|
4097
|
+
_BaseDecoder.prototype.write.call(this, pts, buffers);
|
|
4070
4098
|
};
|
|
4071
4099
|
_proto.bufferGetIndex = function bufferGetIndex() {
|
|
4072
4100
|
if (!this.decoder) {
|
|
@@ -4082,9 +4110,16 @@ var MP2WASM = /*#__PURE__*/function (_BaseDecoder) {
|
|
|
4082
4110
|
this.functions._mp2_decoder_set_index(this.decoder, index);
|
|
4083
4111
|
};
|
|
4084
4112
|
_proto.bufferWrite = function bufferWrite(buffers) {
|
|
4113
|
+
if (this.destroyed) {
|
|
4114
|
+
return 0;
|
|
4115
|
+
}
|
|
4085
4116
|
if (!this.decoder) {
|
|
4086
4117
|
this.initializeWasmDecoder();
|
|
4087
4118
|
}
|
|
4119
|
+
if (!this.decoder) {
|
|
4120
|
+
// The module is not compiled yet; nothing can be written.
|
|
4121
|
+
return 0;
|
|
4122
|
+
}
|
|
4088
4123
|
var totalLength = 0;
|
|
4089
4124
|
for (var i = 0; i < buffers.length; i++) {
|
|
4090
4125
|
totalLength += buffers[i].length;
|
|
@@ -4441,6 +4476,9 @@ var CanvasRenderer = /*#__PURE__*/function () {
|
|
|
4441
4476
|
return CanvasRenderer;
|
|
4442
4477
|
}();
|
|
4443
4478
|
|
|
4479
|
+
// Chrome grants the user activation on pointerup/touchend, not on the
|
|
4480
|
+
// touchstart/pointerdown that precedes them, so the touch events are paired.
|
|
4481
|
+
var UNLOCK_EVENTS = ['pointerdown', 'pointerup', 'keydown', 'touchend'];
|
|
4444
4482
|
var WebAudioOut = /*#__PURE__*/function () {
|
|
4445
4483
|
function WebAudioOut() {
|
|
4446
4484
|
this.context = WebAudioOut.CachedContext = WebAudioOut.CachedContext || new (window.AudioContext || window.webkitAudioContext)();
|
|
@@ -4456,13 +4494,27 @@ var WebAudioOut = /*#__PURE__*/function () {
|
|
|
4456
4494
|
this.wallclockStartTime = 0;
|
|
4457
4495
|
this.volume = 1;
|
|
4458
4496
|
this.enabled = true;
|
|
4459
|
-
this.
|
|
4497
|
+
this.sources = [];
|
|
4498
|
+
this.skippedAudio = false;
|
|
4499
|
+
this.destroyed = false;
|
|
4500
|
+
this.gestureListener = null;
|
|
4501
|
+
this.unlockCallback = null;
|
|
4502
|
+
this.onUnlock = null;
|
|
4503
|
+
this.unlocked = !WebAudioOut.NeedsUnlocking() && WebAudioOut.IsRunning(this.context);
|
|
4460
4504
|
Object.defineProperty(this, 'enqueuedTime', {
|
|
4461
4505
|
get: this.getEnqueuedTime
|
|
4462
4506
|
});
|
|
4507
|
+
if (!this.unlocked) {
|
|
4508
|
+
this.listenForGesture();
|
|
4509
|
+
}
|
|
4463
4510
|
}
|
|
4464
4511
|
var _proto = WebAudioOut.prototype;
|
|
4465
4512
|
_proto.destroy = function destroy() {
|
|
4513
|
+
this.destroyed = true;
|
|
4514
|
+
this.unlockCallback = null;
|
|
4515
|
+
this.onUnlock = null;
|
|
4516
|
+
this.removeGestureListener();
|
|
4517
|
+
this.stopSources();
|
|
4466
4518
|
this.gain.disconnect();
|
|
4467
4519
|
this.context._connections--;
|
|
4468
4520
|
if (this.context._connections === 0) {
|
|
@@ -4471,20 +4523,46 @@ var WebAudioOut = /*#__PURE__*/function () {
|
|
|
4471
4523
|
}
|
|
4472
4524
|
};
|
|
4473
4525
|
_proto.play = function play(sampleRate, left, right) {
|
|
4474
|
-
|
|
4526
|
+
var _this = this;
|
|
4527
|
+
if (!this.enabled || this.destroyed) {
|
|
4475
4528
|
return;
|
|
4476
4529
|
}
|
|
4477
4530
|
|
|
4478
|
-
//
|
|
4479
|
-
//
|
|
4480
|
-
|
|
4531
|
+
// Browsers that need no explicit unlock resume the context by themselves
|
|
4532
|
+
// once the page has been interacted with, so the unlock does not necessarily
|
|
4533
|
+
// go through unlock(). iOS keeps requiring the gesture.
|
|
4534
|
+
if (!this.unlocked && !WebAudioOut.NeedsUnlocking() && WebAudioOut.IsRunning(this.context)) {
|
|
4535
|
+
this.onUnlocked();
|
|
4536
|
+
}
|
|
4537
|
+
|
|
4538
|
+
// A context that is not running, or that has not been unlocked yet, cannot
|
|
4539
|
+
// play anything: the browser autoplay policy keeps it suspended until the
|
|
4540
|
+
// page has received a user gesture, and its currentTime does not advance
|
|
4541
|
+
// meanwhile. Scheduling buffers against it would queue all the audio
|
|
4542
|
+
// decoded in the meantime and play it back from the very beginning once
|
|
4543
|
+
// the context resumes. We simply advance the start time to "fake"
|
|
4544
|
+
// actually playing audio instead. This will keep the video in sync.
|
|
4545
|
+
if (!this.isPlayable()) {
|
|
4546
|
+
this.listenForGesture();
|
|
4481
4547
|
var ts = Now();
|
|
4482
4548
|
if (this.wallclockStartTime < ts) {
|
|
4483
4549
|
this.wallclockStartTime = ts;
|
|
4484
4550
|
}
|
|
4485
4551
|
this.wallclockStartTime += left.length / sampleRate;
|
|
4552
|
+
this.skippedAudio = true;
|
|
4486
4553
|
return;
|
|
4487
4554
|
}
|
|
4555
|
+
|
|
4556
|
+
// The audio is available again: whatever was queued while it could not be
|
|
4557
|
+
// played is dropped and the time base is rebuilt, so the audio joins the
|
|
4558
|
+
// picture at the current point in time instead of staying behind it. The
|
|
4559
|
+
// audio decoded meanwhile is lost once, which is what keeps it in sync
|
|
4560
|
+
// with the picture.
|
|
4561
|
+
if (this.skippedAudio) {
|
|
4562
|
+
this.skippedAudio = false;
|
|
4563
|
+
this.stopSources();
|
|
4564
|
+
this.resetEnqueuedTime();
|
|
4565
|
+
}
|
|
4488
4566
|
this.gain.gain.value = this.volume;
|
|
4489
4567
|
var buffer = this.context.createBuffer(2, left.length, sampleRate);
|
|
4490
4568
|
buffer.getChannelData(0).set(left);
|
|
@@ -4492,6 +4570,13 @@ var WebAudioOut = /*#__PURE__*/function () {
|
|
|
4492
4570
|
var source = this.context.createBufferSource();
|
|
4493
4571
|
source.buffer = buffer;
|
|
4494
4572
|
source.connect(this.destination);
|
|
4573
|
+
source.onended = function () {
|
|
4574
|
+
var index = _this.sources.indexOf(source);
|
|
4575
|
+
if (index !== -1) {
|
|
4576
|
+
_this.sources.splice(index, 1);
|
|
4577
|
+
}
|
|
4578
|
+
};
|
|
4579
|
+
this.sources.push(source);
|
|
4495
4580
|
var now = this.context.currentTime;
|
|
4496
4581
|
var duration = buffer.duration;
|
|
4497
4582
|
if (this.startTime < now) {
|
|
@@ -4503,11 +4588,13 @@ var WebAudioOut = /*#__PURE__*/function () {
|
|
|
4503
4588
|
this.wallclockStartTime += duration;
|
|
4504
4589
|
};
|
|
4505
4590
|
_proto.stop = function stop() {
|
|
4506
|
-
//
|
|
4507
|
-
//
|
|
4508
|
-
//
|
|
4509
|
-
//
|
|
4591
|
+
// Cut off everything that is still queued: the gain alone would only mute
|
|
4592
|
+
// the buffers that are already scheduled, and they would become audible
|
|
4593
|
+
// again as soon as play() restores it. The time base is rebuilt so the
|
|
4594
|
+
// next buffer joins the current context time instead of the old queue.
|
|
4510
4595
|
this.gain.gain.value = 0;
|
|
4596
|
+
this.stopSources();
|
|
4597
|
+
this.resetEnqueuedTime();
|
|
4511
4598
|
};
|
|
4512
4599
|
_proto.getEnqueuedTime = function getEnqueuedTime() {
|
|
4513
4600
|
// The AudioContext.currentTime is only updated every so often, so if we
|
|
@@ -4518,16 +4605,65 @@ var WebAudioOut = /*#__PURE__*/function () {
|
|
|
4518
4605
|
this.startTime = this.context.currentTime;
|
|
4519
4606
|
this.wallclockStartTime = Now();
|
|
4520
4607
|
};
|
|
4608
|
+
_proto.isPlayable = function isPlayable() {
|
|
4609
|
+
return this.unlocked && WebAudioOut.IsRunning(this.context);
|
|
4610
|
+
};
|
|
4611
|
+
_proto.stopSources = function stopSources() {
|
|
4612
|
+
var sources = this.sources;
|
|
4613
|
+
this.sources = [];
|
|
4614
|
+
sources.forEach(function (source) {
|
|
4615
|
+
try {
|
|
4616
|
+
source.stop();
|
|
4617
|
+
} catch (e) {
|
|
4618
|
+
// The source has already ended and cannot be stopped any more.
|
|
4619
|
+
}
|
|
4620
|
+
try {
|
|
4621
|
+
source.disconnect();
|
|
4622
|
+
} catch (e) {
|
|
4623
|
+
// It was never connected to anything.
|
|
4624
|
+
}
|
|
4625
|
+
});
|
|
4626
|
+
};
|
|
4627
|
+
_proto.listenForGesture = function listenForGesture() {
|
|
4628
|
+
var _this2 = this;
|
|
4629
|
+
if (this.gestureListener || this.isPlayable() || this.destroyed || WebAudioOut.NeedsUnlocking() || typeof document === 'undefined') {
|
|
4630
|
+
return;
|
|
4631
|
+
}
|
|
4632
|
+
|
|
4633
|
+
// Chrome and desktop Safari keep the context suspended until it is resumed
|
|
4634
|
+
// inside a user gesture, and they do not resume it by themselves when the
|
|
4635
|
+
// page is tapped somewhere else. iOS keeps requiring the unlock icon.
|
|
4636
|
+
this.gestureListener = function () {
|
|
4637
|
+
return _this2.unlock();
|
|
4638
|
+
};
|
|
4639
|
+
UNLOCK_EVENTS.forEach(function (type) {
|
|
4640
|
+
document.addEventListener(type, _this2.gestureListener, true);
|
|
4641
|
+
});
|
|
4642
|
+
};
|
|
4643
|
+
_proto.removeGestureListener = function removeGestureListener() {
|
|
4644
|
+
var _this3 = this;
|
|
4645
|
+
if (!this.gestureListener) {
|
|
4646
|
+
return;
|
|
4647
|
+
}
|
|
4648
|
+
UNLOCK_EVENTS.forEach(function (type) {
|
|
4649
|
+
document.removeEventListener(type, _this3.gestureListener, true);
|
|
4650
|
+
});
|
|
4651
|
+
this.gestureListener = null;
|
|
4652
|
+
};
|
|
4521
4653
|
_proto.unlock = function unlock(callback) {
|
|
4522
|
-
|
|
4654
|
+
var _this4 = this;
|
|
4655
|
+
// Nothing to do while the audio plays; a context that was suspended again
|
|
4656
|
+
// still has to be resumed, and a destroyed one has nothing left to unlock.
|
|
4657
|
+
if (this.isPlayable() || this.destroyed || this.context.state === 'closed') {
|
|
4523
4658
|
if (callback) {
|
|
4524
4659
|
callback();
|
|
4525
4660
|
}
|
|
4526
4661
|
return;
|
|
4527
4662
|
}
|
|
4528
|
-
this.unlockCallback = callback;
|
|
4663
|
+
this.unlockCallback = callback || this.unlockCallback;
|
|
4529
4664
|
|
|
4530
|
-
// Create empty buffer and play it
|
|
4665
|
+
// Create empty buffer and play it, so the browsers that only start their
|
|
4666
|
+
// audio pipeline from within a user gesture (iOS Safari) really unlock.
|
|
4531
4667
|
var buffer = this.context.createBuffer(1, 1, 22050);
|
|
4532
4668
|
var source = this.context.createBufferSource();
|
|
4533
4669
|
source.buffer = buffer;
|
|
@@ -4539,23 +4675,73 @@ var WebAudioOut = /*#__PURE__*/function () {
|
|
|
4539
4675
|
} else {
|
|
4540
4676
|
source.noteOn(0);
|
|
4541
4677
|
}
|
|
4678
|
+
|
|
4679
|
+
// Chrome and desktop Safari keep the context suspended until it is resumed
|
|
4680
|
+
// explicitly, and resume() only takes effect inside a user gesture - which
|
|
4681
|
+
// is exactly where unlock() is called from.
|
|
4682
|
+
var resumed = null;
|
|
4683
|
+
try {
|
|
4684
|
+
resumed = this.context.resume && this.context.resume();
|
|
4685
|
+
} catch (e) {
|
|
4686
|
+
// An unsupported or interrupted context: fall through to the polling
|
|
4687
|
+
// check, which also covers the browsers that resume on their own.
|
|
4688
|
+
}
|
|
4689
|
+
if (resumed && resumed.then) {
|
|
4690
|
+
resumed.then(function () {
|
|
4691
|
+
return _this4.checkIfUnlocked(source, 0);
|
|
4692
|
+
}, function () {
|
|
4693
|
+
return _this4.checkIfUnlocked(source, 0);
|
|
4694
|
+
});
|
|
4695
|
+
return;
|
|
4696
|
+
}
|
|
4542
4697
|
setTimeout(this.checkIfUnlocked.bind(this, source, 0), 0);
|
|
4543
4698
|
};
|
|
4544
4699
|
_proto.checkIfUnlocked = function checkIfUnlocked(source, attempt) {
|
|
4545
|
-
if (
|
|
4546
|
-
|
|
4547
|
-
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
|
|
4700
|
+
if (this.destroyed || this.context.state === 'closed') {
|
|
4701
|
+
// The player was destroyed while waiting for the unlock.
|
|
4702
|
+
this.unlockCallback = null;
|
|
4703
|
+
return;
|
|
4704
|
+
}
|
|
4705
|
+
|
|
4706
|
+
// `playbackState` and its constants were removed from the Web Audio API,
|
|
4707
|
+
// and comparing two undefined values is always true, so the legacy check
|
|
4708
|
+
// may only be used when the browser actually exposes it.
|
|
4709
|
+
var legacyUnlocked = source.playbackState !== undefined && (source.playbackState === source.PLAYING_STATE || source.playbackState === source.FINISHED_STATE);
|
|
4710
|
+
var unlocked = this.context.state ? this.context.state === 'running' : legacyUnlocked;
|
|
4711
|
+
if (unlocked) {
|
|
4712
|
+
this.onUnlocked();
|
|
4551
4713
|
} else if (attempt < 10) {
|
|
4552
4714
|
// Jeez, what a shit show. Thanks iOS!
|
|
4553
4715
|
setTimeout(this.checkIfUnlocked.bind(this, source, attempt + 1), 100);
|
|
4554
4716
|
}
|
|
4555
4717
|
};
|
|
4718
|
+
_proto.onUnlocked = function onUnlocked() {
|
|
4719
|
+
if (this.destroyed) {
|
|
4720
|
+
return;
|
|
4721
|
+
}
|
|
4722
|
+
this.removeGestureListener();
|
|
4723
|
+
|
|
4724
|
+
// The output may be unlocked again after its context had been suspended, so
|
|
4725
|
+
// a pending callback is always served; only the onUnlock hook, which drives
|
|
4726
|
+
// the unlock UI, is limited to the first time.
|
|
4727
|
+
var firstUnlock = !this.unlocked;
|
|
4728
|
+
this.unlocked = true;
|
|
4729
|
+
var callbacks = [this.unlockCallback, firstUnlock ? this.onUnlock : null];
|
|
4730
|
+
this.unlockCallback = null;
|
|
4731
|
+
callbacks.forEach(function (callback) {
|
|
4732
|
+
if (callback) {
|
|
4733
|
+
callback();
|
|
4734
|
+
}
|
|
4735
|
+
});
|
|
4736
|
+
};
|
|
4556
4737
|
WebAudioOut.NeedsUnlocking = function NeedsUnlocking() {
|
|
4557
4738
|
return /iPhone|iPad|iPod/i.test(navigator.userAgent);
|
|
4558
4739
|
};
|
|
4740
|
+
WebAudioOut.IsRunning = function IsRunning(context) {
|
|
4741
|
+
// Old WebKit versions expose no state at all; there, NeedsUnlocking()
|
|
4742
|
+
// alone decides whether the context has to be unlocked.
|
|
4743
|
+
return !context.state || context.state === 'running';
|
|
4744
|
+
};
|
|
4559
4745
|
WebAudioOut.IsSupported = function IsSupported() {
|
|
4560
4746
|
return window.AudioContext || window.webkitAudioContext;
|
|
4561
4747
|
};
|
|
@@ -4887,10 +5073,11 @@ var Player = /*#__PURE__*/function () {
|
|
|
4887
5073
|
this.isPlaying = false;
|
|
4888
5074
|
this.paused = true;
|
|
4889
5075
|
if (this.audio && this.audio.canPlay) {
|
|
4890
|
-
// Seek to the
|
|
4891
|
-
// further, so
|
|
5076
|
+
// Seek back to the frame that is being heard: stop() drops the queue that
|
|
5077
|
+
// was already enqueued further ahead, so the time has to be read first.
|
|
5078
|
+
var time = this.currentTime;
|
|
4892
5079
|
this.audioOut.stop();
|
|
4893
|
-
this.seek(
|
|
5080
|
+
this.seek(time);
|
|
4894
5081
|
}
|
|
4895
5082
|
if (this.hooks.pause) {
|
|
4896
5083
|
this.hooks.pause();
|