Skip to content

Commit

Permalink
fix: stop using Howler
Browse files Browse the repository at this point in the history
  • Loading branch information
zunderscore committed Dec 22, 2024
1 parent 44e92a3 commit edff55c
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
$scope.durationDisplay = "-:--";
$scope.controlsEnabled = false;

/** @type {HTMLAudioElement} sound */
let sound = null;

function pad(num) {
Expand Down Expand Up @@ -62,19 +63,23 @@
let previousSeek = 0;
const seekPositionTimer = $interval(() => {
if (sound != null) {
const currentSeek = sound.seek();
const currentSeek = sound.currentTime;
if (currentSeek !== previousSeek) {
$scope.seekPositionDisplay = getDurationDisplay(currentSeek);
previousSeek = currentSeek;
}
}
}, 250);

function unloadSound() {
sound.pause();
sound.srcObject = null;
sound = null;
}

function loadSound() {
if (sound != null) {
sound.unload();
sound = null;
unloadSound();
}
if ($ctrl.path == null || $ctrl.path.length === 0) {
$scope.seekPositionDisplay = "-:--";
Expand All @@ -95,14 +100,17 @@
}
}

soundService.getHowlSound($ctrl.path, volume, $ctrl.outputDevice)
.then(s => {
soundService.getSound($ctrl.path, volume, $ctrl.outputDevice)
.then((s) => {
sound = s;

sound.on('load', function() {
const soundLoadEventHandler = function() {
sound.removeEventListener("load", soundLoadEventHandler);
$scope.controlsEnabled = true;
$scope.durationDisplay = getDurationDisplay(sound.duration());
});
$scope.durationDisplay = getDurationDisplay(sound.duration);
};

sound.addEventListener("canplay", soundLoadEventHandler);

sound.load();
});
Expand All @@ -113,15 +121,15 @@
return false;
}

return sound.playing();
return !sound.paused;
};

$scope.playOrPause = () => {
if (sound == null || !$scope.controlsEnabled) {
return;
}

if (sound.playing()) {
if (!sound.paused) {
sound.pause();
} else {
sound.play();
Expand All @@ -134,11 +142,12 @@
return;
}

sound.stop();
sound.pause();
sound.currentTime = 0;
};


$ctrl.$onChanges = function (changes) {
$ctrl.$onChanges = function(changes) {
if (changes.path || changes.outputDevice) {
loadSound();
}
Expand All @@ -152,7 +161,7 @@
} else if (newVolume > 0) {
newVolume = newVolume / 10;
}
sound.volume(newVolume);
sound.volume = newVolume;
}
}
}
Expand All @@ -161,12 +170,10 @@
$ctrl.$onDestroy = function() {
$interval.cancel(seekPositionTimer);
if (sound != null) {
sound.unload();
unloadSound();
}
};



$ctrl.$onInit = function() {
loadSound();
};
Expand Down
2 changes: 1 addition & 1 deletion src/gui/app/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@
<script type="text/javascript" src="./directives/controls/sort-tag-dropdown.component.js"></script>
<script type="text/javascript" src="./directives/controls/sort-tag-list.js"></script>
<script type="text/javascript" src="./directives/controls/sort-tags-row.js"></script>
<script type="text/javascript" src="./directives/controls/soundPlayer.js"></script>
<script type="text/javascript" src="./directives/controls/sound-player.js"></script>
<script type="text/javascript" src="./directives/controls/specialized/discord-channel-webhooks.js"></script>
<script type="text/javascript" src="./directives/controls/specialized/discord-file-upload-list.js"></script>
<script type="text/javascript" src="./directives/controls/specialized/gift-receivers-list.js"></script>
Expand Down
100 changes: 53 additions & 47 deletions src/gui/app/services/sound.service.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
"use strict";

(function() {

const { Howl, Howler } = require("howler");

// This provides methods for playing sounds

angular
.module("firebotApp")
.factory("soundService", function(logger, settingsService, listenerService, $q, websocketService, backendCommunicator) {
const service = {};
/** @type {HTMLAudioElement[]} */
const sounds = [];

// Connection Sounds
service.connectSound = function(type) {
Expand Down Expand Up @@ -99,74 +98,74 @@


service.playSound = function(path, volume, outputDevice, fileType = null, maxSoundLength = null) {

if (outputDevice == null) {
outputDevice = settingsService.getSetting("AudioOutputDevice");
}

$q.when(service.getHowlSound(path, volume, outputDevice, fileType))
.then((sound) => {

$q.when(service.getSound(path, volume, outputDevice, fileType))
.then(/** @param {HTMLAudioElement} sound */ (sound) => {
let maxSoundLengthTimeout;
// Clear listener after first call.
sound.once('load', function() {
sounds.push(sound);

const soundEndEventHandler = function() {
// Clear listener after first call.
sound.removeEventListener("ended", soundEndEventHandler);
sound.srcObject = null;
sounds.splice(sounds.indexOf(sound), 1);
clearInterval(maxSoundLengthTimeout);
};

const soundLoadEventHandler = function() {
// Clear listener after first call.
sound.removeEventListener("canplay", soundLoadEventHandler);
sound.play();

const intMaxSoundLength = parseInt(maxSoundLength);
if (intMaxSoundLength > 0) {
maxSoundLengthTimeout = setTimeout(function() {
sound.stop();
sound.unload();
sound.pause();
soundEndEventHandler();
}, maxSoundLength * 1000);
}
});
};

sound.addEventListener("canplay", soundLoadEventHandler);

// Fires when the sound finishes playing.
sound.once('end', function() {
sound.unload();
clearInterval(maxSoundLengthTimeout);
});
sound.addEventListener("ended", soundEndEventHandler);

sound.load();
});
};

service.getHowlSound = function(path, volume, outputDevice = settingsService.getSetting("AudioOutputDevice"), fileType = null) {
return navigator.mediaDevices.enumerateDevices()
.then((deviceList) => {
const filteredDevice = deviceList.filter(d => d.label === outputDevice.label
|| d.deviceId === outputDevice.deviceId);
service.getSound = async function(path, volume, outputDevice = settingsService.getSetting("AudioOutputDevice")) {
const deviceList = await navigator.mediaDevices.enumerateDevices();

const sinkId = filteredDevice.length > 0 ? filteredDevice[0].deviceId : 'default';
const filteredDevice = deviceList.find(d => d.label === outputDevice.label
|| d.deviceId === outputDevice.deviceId);

const sound = new Howl({
src: [path],
volume: volume,
format: fileType,
html5: true,
sinkId: sinkId,
preload: false
});
const sound = new Audio(path);
sound.volume = volume;
await sound.setSinkId(filteredDevice?.deviceId ?? 'default');

return sound;
});
return sound;
};

service.getSoundDuration = function(path, format = undefined) {
/**
* Combination of fix from:
* https://github.com/nmori/Firebot/blob/f53d12fe774059327dadedf4fa8268f4e53cad7f/src/gui/app/services/sound.service.js#L174-L182
*
* While maintaining duration precision from Howler:
* https://github.com/ebiggz/howler.js/blob/0bbfe6623e13bef8e58c789f5f67bfc87d50000b/src/howler.core.js#L2052
*/
service.getSoundDuration = function(path) {
return new Promise((resolve) => {

console.log("duration for", path, format);

const sound = new Howl({
src: [path],
format: format || [],
onload: () => {
resolve(sound.duration());
sound.unload();
},
onloaderror: () => {
resolve(0);
}
const audio = new Audio(path);
audio.addEventListener("loadedmetadata", () => {
resolve(Math.ceil(audio.duration * 10) / 10);
});
audio.addEventListener("error", () => {
resolve(0);
});
});
};
Expand Down Expand Up @@ -212,7 +211,14 @@

service.stopAllSounds = function() {
logger.info("Stopping all sounds...");
Howler.unload();
while (sounds.length > 0) {
let sound = sounds.pop();
if (sound) {
sound.pause();
sound.srcObject = null;
sound = null;
}
}
};

backendCommunicator.on("stop-all-sounds", () => {
Expand Down

0 comments on commit edff55c

Please sign in to comment.