jsmpeg组件包
This commit is contained in:
145
public/static/jsmpeg-master/src/webaudio.js
Normal file
145
public/static/jsmpeg-master/src/webaudio.js
Normal file
@@ -0,0 +1,145 @@
|
||||
JSMpeg.AudioOutput.WebAudio = (function() { "use strict";
|
||||
|
||||
var WebAudioOut = function(options) {
|
||||
this.context = WebAudioOut.CachedContext =
|
||||
WebAudioOut.CachedContext ||
|
||||
new (window.AudioContext || window.webkitAudioContext)();
|
||||
|
||||
this.gain = this.context.createGain();
|
||||
this.destination = this.gain;
|
||||
|
||||
// Keep track of the number of connections to this AudioContext, so we
|
||||
// can safely close() it when we're the only one connected to it.
|
||||
this.gain.connect(this.context.destination);
|
||||
this.context._connections = (this.context._connections || 0) + 1;
|
||||
|
||||
this.startTime = 0;
|
||||
this.buffer = null;
|
||||
this.wallclockStartTime = 0;
|
||||
this.volume = 1;
|
||||
this.enabled = true;
|
||||
|
||||
this.unlocked = !WebAudioOut.NeedsUnlocking();
|
||||
|
||||
Object.defineProperty(this, 'enqueuedTime', {get: this.getEnqueuedTime});
|
||||
};
|
||||
|
||||
WebAudioOut.prototype.destroy = function() {
|
||||
this.gain.disconnect();
|
||||
this.context._connections--;
|
||||
|
||||
if (this.context._connections === 0) {
|
||||
this.context.close();
|
||||
WebAudioOut.CachedContext = null;
|
||||
}
|
||||
};
|
||||
|
||||
WebAudioOut.prototype.play = function(sampleRate, left, right) {
|
||||
if (!this.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the context is not unlocked yet, we simply advance the start time
|
||||
// to "fake" actually playing audio. This will keep the video in sync.
|
||||
if (!this.unlocked) {
|
||||
var ts = JSMpeg.Now()
|
||||
if (this.wallclockStartTime < ts) {
|
||||
this.wallclockStartTime = ts;
|
||||
}
|
||||
this.wallclockStartTime += left.length / sampleRate;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
this.gain.gain.value = this.volume;
|
||||
|
||||
var buffer = this.context.createBuffer(2, left.length, sampleRate);
|
||||
buffer.getChannelData(0).set(left);
|
||||
buffer.getChannelData(1).set(right);
|
||||
|
||||
var source = this.context.createBufferSource();
|
||||
source.buffer = buffer;
|
||||
source.connect(this.destination);
|
||||
|
||||
var now = this.context.currentTime;
|
||||
var duration = buffer.duration;
|
||||
if (this.startTime < now) {
|
||||
this.startTime = now;
|
||||
this.wallclockStartTime = JSMpeg.Now();
|
||||
}
|
||||
|
||||
source.start(this.startTime);
|
||||
this.startTime += duration;
|
||||
this.wallclockStartTime += duration;
|
||||
};
|
||||
|
||||
WebAudioOut.prototype.stop = function() {
|
||||
// Meh; there seems to be no simple way to get a list of currently
|
||||
// active source nodes from the Audio Context, and maintaining this
|
||||
// list ourselfs would be a pain, so we just set the gain to 0
|
||||
// to cut off all enqueued audio instantly.
|
||||
this.gain.gain.value = 0;
|
||||
};
|
||||
|
||||
WebAudioOut.prototype.getEnqueuedTime = function() {
|
||||
// The AudioContext.currentTime is only updated every so often, so if we
|
||||
// want to get exact timing, we need to rely on the system time.
|
||||
return Math.max(this.wallclockStartTime - JSMpeg.Now(), 0)
|
||||
};
|
||||
|
||||
WebAudioOut.prototype.resetEnqueuedTime = function() {
|
||||
this.startTime = this.context.currentTime;
|
||||
this.wallclockStartTime = JSMpeg.Now();
|
||||
};
|
||||
|
||||
WebAudioOut.prototype.unlock = function(callback) {
|
||||
if (this.unlocked) {
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this.unlockCallback = callback;
|
||||
|
||||
// Create empty buffer and play it
|
||||
var buffer = this.context.createBuffer(1, 1, 22050);
|
||||
var source = this.context.createBufferSource();
|
||||
source.buffer = buffer;
|
||||
source.connect(this.destination);
|
||||
source.start(0);
|
||||
|
||||
setTimeout(this.checkIfUnlocked.bind(this, source, 0), 0);
|
||||
};
|
||||
|
||||
WebAudioOut.prototype.checkIfUnlocked = function(source, attempt) {
|
||||
if (
|
||||
source.playbackState === source.PLAYING_STATE ||
|
||||
source.playbackState === source.FINISHED_STATE
|
||||
) {
|
||||
this.unlocked = true;
|
||||
if (this.unlockCallback) {
|
||||
this.unlockCallback();
|
||||
this.unlockCallback = null;
|
||||
}
|
||||
}
|
||||
else if (attempt < 10) {
|
||||
// Jeez, what a shit show. Thanks iOS!
|
||||
setTimeout(this.checkIfUnlocked.bind(this, source, attempt+1), 100);
|
||||
}
|
||||
};
|
||||
|
||||
WebAudioOut.NeedsUnlocking = function() {
|
||||
return /iPhone|iPad|iPod/i.test(navigator.userAgent);
|
||||
};
|
||||
|
||||
WebAudioOut.IsSupported = function() {
|
||||
return (window.AudioContext || window.webkitAudioContext);
|
||||
};
|
||||
|
||||
WebAudioOut.CachedContext = null;
|
||||
|
||||
return WebAudioOut;
|
||||
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user