Three.js Error: Audio is Already Playing

I have 2 sets of sounds, which are supposed to play only when a flag (SndFlg) is set (by toggling the S key). The first set is toggled on/off by the SndFlg. The second set is turned on only if the SndFlg is on and only if the Spacebar is depressed.

If I enable the SndFlg (which starts the first set of sounds) and then press the Spacebar (to start the second set of sounds), I get the following error notice: THREE.Audio: Audio is Already Playing

Is there a way to eliminate this error? Does three.js allow you to use separate sound channels which can be turned on/off seperately?

The two sets of sounds are connected to 2 different objects and the objects are connected to a single visible object. Here is the sample code:

let listener = new THREE.AudioListener();
    camera.add(listener);
// Engine
let EngSnd = new THREE.PositionalAudio(listener);
    EngSnd.setVol(0.5);
let EngMsh = makMsh();	// This makes a basic mesh
    EngMsh.add(EngSnd);
    EngMsh.position.z = -5; // Sound is in front
    AirObj.add(EngMsh);
// Guns
let GunSnd = new THREE.PositionalAudio(listener);
    GunSnd.setVol(0.5);
let GunMsh = makMsh();	// This makes a basic mesh
    GnLMsh.add(GunSnd);
    AirObj.add(GunMsh);

I want to toggle all sounds on or off whenever I press the S key.

I want the first set of sounds to play or stop playing whenever the SndFlg is toggled on or off.

I want the second set of sounds to play only when the SndFlg has been toggled on and when the spacebar is depressed. These sounds will be turned off when the spacebar is released, regardless of whether SndFlg is toggled on or off.

Similarly, when I toggle the SndFlg on, it will only turn the second set of sounds on if the spacebar is already depressed.

Here is the sample code:

//Keyboard Input

// Guns - Spacebar Down
if (event.keyCode == K_Guns) {
   if (SndFlg) GunSnd.play(); // ### This is what causes error (Audio Already Playing)
   GunFlg = 1;
}

// Guns - Spacebar Up
if (event.keyCode == K_Guns) {
   GunSnd.stop(); // Stop - regardless of whether all sounds are on or off
   GunFlg = 0;
}

// Sounds - If S Key Pressed
if (event.keyCode == K_Soun) toglSoun(); // S Key

//. Toggle Sound On and Off
function toglSoun() {
   SndFlg = 1 - SndFlg; // 0 = Sounds Off, 1 = Sounds On
   if (SndFlg) { // Off to On
      EngSnd.play();
      if (GunFlg) GunSnd.play(); // Only play if spacebar already depressed
   }
   else { // On to Off
      EngSnd.stop();
      if (GunFlg) {GunSnd.stop()}; // Only stop if spacebar already depressed
   }
}

Should I be using 2 listeners? (Does three.js have sound channels?)
Should the sound meshes not be attached to the same parent mesh?
(Note that I am using meshes, rather than 3Dobjects - if htat makes a difference.)

THANKS! This works perfectly. No more error messages! :smiley:

The error THREE.Audio: Audio is Already Playing occurs because you’re trying to start the sound with GunSnd.play() when it’s already playing. To resolve this, you need to check whether the sound is already playing before calling play(). You can do this by checking the isPlaying property of the sound object.

Additionally, using multiple listeners isn’t necessary in this case, and Three.js doesn’t have a built-in concept of separate “sound channels.” You can control different sounds independently using the same listener.

Here’s a refactor of your code that checks if the sounds are playing before calling play():

Updated Code

javascript

Copy code

// Create a listener and attach it to the camera
let listener = new THREE.AudioListener();
camera.add(listener);

// Engine sound
let EngSnd = new THREE.PositionalAudio(listener);
EngSnd.setVolume(0.5);

let EngMsh = makMsh(); // Create a basic mesh
EngMsh.add(EngSnd);
EngMsh.position.z = -5; // Position the sound in front of the object
AirObj.add(EngMsh);

// Gun sound
let GunSnd = new THREE.PositionalAudio(listener);
GunSnd.setVolume(0.5);

let GunMsh = makMsh(); // Create a basic mesh
GunMsh.add(GunSnd);
AirObj.add(GunMsh);

// Flags
let SndFlg = 0;
let GunFlg = 0;

// Toggle Sound On and Off with S key
function toglSoun() {
    SndFlg = 1 - SndFlg; // Toggle sound on/off
    if (SndFlg) { // Sound On
        if (!EngSnd.isPlaying) EngSnd.play(); // Play engine sound if not playing
        if (GunFlg && !GunSnd.isPlaying) GunSnd.play(); // Only play gun sound if spacebar is pressed and sound is not already playing
    } else { // Sound Off
        if (EngSnd.isPlaying) EngSnd.stop(); // Stop engine sound if playing
        if (GunFlg && GunSnd.isPlaying) GunSnd.stop(); // Stop gun sound if spacebar is pressed and sound is playing
    }
}

// Keyboard Input

// Guns - Spacebar Down
document.addEventListener('keydown', (event) => {
    if (event.keyCode === K_Guns) {
        if (SndFlg && !GunSnd.isPlaying) GunSnd.play(); // Only play if sound is enabled and not already playing
        GunFlg = 1;
    }
});

// Guns - Spacebar Up
document.addEventListener('keyup', (event) => {
    if (event.keyCode === K_Guns) {
        if (GunSnd.isPlaying) GunSnd.stop(); // Stop gun sound
        GunFlg = 0;
    }
});

// Sounds - If S Key Pressed
document.addEventListener('keydown', (event) => {
    if (event.keyCode === K_Soun) toglSoun(); // Toggle sounds with S key
}); 

Key Changes:

  1. Check isPlaying: Before calling play(), the code checks if the sound is already playing by using if (!GunSnd.isPlaying) and if (!EngSnd.isPlaying). This prevents the Audio is Already Playing error.
  2. Stop Sounds When Necessary: The code ensures that sounds are stopped only when appropriate, e.g., when the spacebar is released or when the SndFlg is toggled off.
  3. Same Listener: You’re using the same AudioListener, which is fine. There’s no need for separate listeners or sound channels. You can control each sound individually, even if they are connected to different objects.
  4. Mesh Usage: Using meshes to attach sounds is fine and doesn’t impact sound control.

With these changes, the sounds should behave as expected:

  • The engine sound (EngSnd) toggles with the S key.
  • The gun sound (GunSnd) plays only when the spacebar is held and SndFlg is enabled, and stops when the spacebar is released.
  • Click Here to know more in details.
1 Like