2019-05-21 18:15:02 +02:00
|
|
|
namespace audio.player {
|
2018-10-28 18:25:43 +01:00
|
|
|
let _globalContext: AudioContext;
|
2019-04-29 18:49:01 +02:00
|
|
|
let _global_destination: GainNode;
|
|
|
|
|
2018-10-28 18:25:43 +01:00
|
|
|
let _globalContextPromise: Promise<void>;
|
|
|
|
let _initialized_listener: (() => any)[] = [];
|
2019-04-29 18:49:01 +02:00
|
|
|
let _master_volume: number = 1;
|
2019-08-21 10:00:01 +02:00
|
|
|
let _no_device = false;
|
2018-10-28 18:25:43 +01:00
|
|
|
|
|
|
|
export function initialize() : boolean {
|
|
|
|
context();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function initialized() : boolean {
|
|
|
|
return !!_globalContext && _globalContext.state === 'running';
|
|
|
|
}
|
|
|
|
|
|
|
|
function fire_initialized() {
|
2019-08-30 23:06:39 +02:00
|
|
|
log.info(LogCategory.AUDIO, tr("File initialized for %d listeners"), _initialized_listener.length);
|
2018-10-28 18:25:43 +01:00
|
|
|
while(_initialized_listener.length > 0)
|
|
|
|
_initialized_listener.pop_front()();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export function context() : AudioContext {
|
|
|
|
if(_globalContext && _globalContext.state != "suspended") return _globalContext;
|
|
|
|
|
|
|
|
if(!_globalContext)
|
|
|
|
_globalContext = new (window.webkitAudioContext || window.AudioContext)();
|
2019-04-29 18:49:01 +02:00
|
|
|
|
|
|
|
_initialized_listener.unshift(() => {
|
|
|
|
_global_destination = _globalContext.createGain();
|
2019-08-21 10:00:01 +02:00
|
|
|
_global_destination.gain.value = _no_device ? 0 : _master_volume;
|
2019-04-29 18:49:01 +02:00
|
|
|
_global_destination.connect(_globalContext.destination);
|
|
|
|
});
|
2018-10-28 18:25:43 +01:00
|
|
|
if(_globalContext.state == "suspended") {
|
|
|
|
if(!_globalContextPromise) {
|
|
|
|
(_globalContextPromise = _globalContext.resume()).then(() => {
|
|
|
|
fire_initialized();
|
|
|
|
}).catch(error => {
|
2019-08-30 23:06:39 +02:00
|
|
|
loader.critical_error("Failed to initialize global audio context! (" + error + ")");
|
2018-10-28 18:25:43 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
_globalContext.resume(); //We already have our listener
|
2019-08-21 10:00:01 +02:00
|
|
|
return _globalContext;
|
2018-10-28 18:25:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if(_globalContext.state == "running") {
|
|
|
|
fire_initialized();
|
|
|
|
return _globalContext;
|
|
|
|
}
|
2019-08-21 10:00:01 +02:00
|
|
|
return _globalContext;
|
2018-10-28 18:25:43 +01:00
|
|
|
}
|
|
|
|
|
2019-04-29 18:49:01 +02:00
|
|
|
export function get_master_volume() : number {
|
|
|
|
return _master_volume;
|
|
|
|
}
|
|
|
|
export function set_master_volume(volume: number) {
|
|
|
|
_master_volume = volume;
|
2019-08-21 10:00:01 +02:00
|
|
|
if(_global_destination)
|
|
|
|
_global_destination.gain.value = _no_device ? 0 : _master_volume;
|
2019-04-29 18:49:01 +02:00
|
|
|
}
|
|
|
|
|
2018-10-28 18:25:43 +01:00
|
|
|
export function destination() : AudioNode {
|
2019-01-28 20:36:11 +01:00
|
|
|
const ctx = context();
|
|
|
|
if(!ctx) throw tr("Audio player isn't initialized yet!");
|
|
|
|
|
2019-04-29 18:49:01 +02:00
|
|
|
return _global_destination;
|
2018-10-28 18:25:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
export function on_ready(cb: () => any) {
|
|
|
|
if(initialized())
|
|
|
|
cb();
|
|
|
|
else
|
|
|
|
_initialized_listener.push(cb);
|
|
|
|
}
|
|
|
|
|
2019-08-21 13:50:21 +02:00
|
|
|
export const WEB_DEVICE: Device = {
|
|
|
|
device_id: "default",
|
|
|
|
name: "default playback",
|
|
|
|
driver: 'Web Audio'
|
|
|
|
};
|
2018-10-28 18:25:43 +01:00
|
|
|
|
|
|
|
export function available_devices() : Promise<Device[]> {
|
|
|
|
return Promise.resolve([WEB_DEVICE])
|
|
|
|
}
|
|
|
|
|
|
|
|
export function set_device(device_id: string) : Promise<void> {
|
2019-08-21 10:00:01 +02:00
|
|
|
_no_device = !device_id;
|
|
|
|
_global_destination.gain.value = _no_device ? 0 : _master_volume;
|
|
|
|
|
2018-10-28 18:25:43 +01:00
|
|
|
return Promise.resolve();
|
|
|
|
}
|
|
|
|
|
|
|
|
export function current_device() : Device {
|
|
|
|
return WEB_DEVICE;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function initializeFromGesture() {
|
|
|
|
context();
|
|
|
|
}
|
|
|
|
}
|