173 lines
4.7 KiB
JavaScript
Executable File
173 lines
4.7 KiB
JavaScript
Executable File
// SPDX-FileCopyrightText: GSConnect Developers https://github.com/GSConnect
|
|
//
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
import Gdk from 'gi://Gdk';
|
|
import Gio from 'gi://Gio';
|
|
import GLib from 'gi://GLib';
|
|
|
|
let GSound = null;
|
|
try {
|
|
GSound = (await import('gi://GSound')).default;
|
|
} catch (e) {}
|
|
|
|
|
|
const Player = class Player {
|
|
|
|
constructor() {
|
|
this._playing = new Set();
|
|
}
|
|
|
|
get backend() {
|
|
if (this._backend === undefined) {
|
|
// Prefer GSound
|
|
if (GSound !== null) {
|
|
this._gsound = new GSound.Context();
|
|
this._gsound.init(null);
|
|
this._backend = 'gsound';
|
|
|
|
// Try falling back to libcanberra, otherwise just re-run the test
|
|
// in case one or the other is installed later
|
|
} else if (GLib.find_program_in_path('canberra-gtk-play') !== null) {
|
|
this._canberra = new Gio.SubprocessLauncher({
|
|
flags: Gio.SubprocessFlags.NONE,
|
|
});
|
|
this._backend = 'libcanberra';
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
return this._backend;
|
|
}
|
|
|
|
_canberraPlaySound(name, cancellable) {
|
|
const proc = this._canberra.spawnv(['canberra-gtk-play', '-i', name]);
|
|
return proc.wait_check_async(cancellable);
|
|
}
|
|
|
|
async _canberraLoopSound(name, cancellable) {
|
|
while (!cancellable.is_cancelled())
|
|
await this._canberraPlaySound(name, cancellable);
|
|
}
|
|
|
|
_gsoundPlaySound(name, cancellable) {
|
|
return new Promise((resolve, reject) => {
|
|
this._gsound.play_full(
|
|
{'event.id': name},
|
|
cancellable,
|
|
(source, res) => {
|
|
try {
|
|
resolve(source.play_full_finish(res));
|
|
} catch (e) {
|
|
reject(e);
|
|
}
|
|
}
|
|
);
|
|
});
|
|
}
|
|
|
|
async _gsoundLoopSound(name, cancellable) {
|
|
while (!cancellable.is_cancelled())
|
|
await this._gsoundPlaySound(name, cancellable);
|
|
}
|
|
|
|
_gdkPlaySound(name, cancellable) {
|
|
if (this._display === undefined)
|
|
this._display = Gdk.Display.get_default();
|
|
|
|
let count = 0;
|
|
|
|
GLib.timeout_add(GLib.PRIORITY_DEFAULT, 200, () => {
|
|
try {
|
|
if (count++ < 4 && !cancellable.is_cancelled()) {
|
|
this._display.beep();
|
|
return GLib.SOURCE_CONTINUE;
|
|
}
|
|
|
|
return GLib.SOURCE_REMOVE;
|
|
} catch (e) {
|
|
logError(e);
|
|
return GLib.SOURCE_REMOVE;
|
|
}
|
|
});
|
|
|
|
return !cancellable.is_cancelled();
|
|
}
|
|
|
|
_gdkLoopSound(name, cancellable) {
|
|
this._gdkPlaySound(name, cancellable);
|
|
GLib.timeout_add(
|
|
GLib.PRIORITY_DEFAULT,
|
|
1500,
|
|
this._gdkPlaySound.bind(this, name, cancellable)
|
|
);
|
|
}
|
|
|
|
async playSound(name, cancellable) {
|
|
try {
|
|
if (!(cancellable instanceof Gio.Cancellable))
|
|
cancellable = new Gio.Cancellable();
|
|
|
|
this._playing.add(cancellable);
|
|
|
|
switch (this.backend) {
|
|
case 'gsound':
|
|
await this._gsoundPlaySound(name, cancellable);
|
|
break;
|
|
|
|
case 'canberra':
|
|
await this._canberraPlaySound(name, cancellable);
|
|
break;
|
|
|
|
default:
|
|
await this._gdkPlaySound(name, cancellable);
|
|
}
|
|
} catch (e) {
|
|
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
|
|
logError(e);
|
|
} finally {
|
|
this._playing.delete(cancellable);
|
|
}
|
|
}
|
|
|
|
async loopSound(name, cancellable) {
|
|
try {
|
|
if (!(cancellable instanceof Gio.Cancellable))
|
|
cancellable = new Gio.Cancellable();
|
|
|
|
this._playing.add(cancellable);
|
|
|
|
switch (this.backend) {
|
|
case 'gsound':
|
|
await this._gsoundLoopSound(name, cancellable);
|
|
break;
|
|
|
|
case 'canberra':
|
|
await this._canberraLoopSound(name, cancellable);
|
|
break;
|
|
|
|
default:
|
|
await this._gdkLoopSound(name, cancellable);
|
|
}
|
|
} catch (e) {
|
|
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
|
|
logError(e);
|
|
} finally {
|
|
this._playing.delete(cancellable);
|
|
}
|
|
}
|
|
|
|
destroy() {
|
|
for (const cancellable of this._playing)
|
|
cancellable.cancel();
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* The service class for this component
|
|
*/
|
|
export default Player;
|
|
|