Assign <audio> HTMLElement to SoundSlot

Hi,

i need to connect an already existing
audio element to a SoundSlot, i did read trough the api but could not find anything related to it. before digging trough the source, i just wanted to ask if someone did something like that before or knows if its possible.

BR :slight_smile:

Hi @Sinlyu,

Check this, I think it can be of help:

You basically create and register a new pc.Asset, then create your pc.SoundSlot and reference it, and at the end add it to your pc.SoundComponent.

Thanks for that, will take a look.

So i am creating a new Sound with an Auido Element. After that i do create an asset and put the sound as the resource. then i assign the stuff to my AudioSlot “Voice”. but when i try to start it an error gets thrown in some part of the soundcomponent code, “this.source.start(0, offset);”

the error says that source is null which would mean that the assigned sound is null because the function checks if source is null and then creates the source out of the assigend sound. “_createSource()” _createSource returns null if _sound is null, so i guess there is something wrong with my setup.

Hi @Sinlyu,

Slots is an array, you can’t assign to it directly as you do. Check the following code example on how to add a new slot to a sound component:

Well i found the issue,

_createSource checks if there is an buffer object in the sound object. which in my case, is false because i passed an AudioElement. in the docs it says i can pass an HTMLAudioElement as resource. I am a bit confused.

Already changed that, but its the same result.

Do you have a sample project that you can share to take a look?

Yea sure, is Leonidas also your PlayCanvas Username ?

Yes, leonidas.

1 Like

Added you to the Project.

1 Like

@Sinlyu apart from what we said in the direct chat, check this reply and example project as well, it be an alternative in using the pc.SoundComponent:

1 Like

Alright, thank you for your help and research :slight_smile:

1 Like

Will try that, and post my results here.

1 Like

well i implemented the example, but now i dont hear any sound at all.

var AudioEmitter3d = pc.createScript('audioEmitter3d');

AudioEmitter3d.prototype.initWithTrack = function(remoteTrack) {
    var pos = this.entity.getPosition();
     var pannerModel = 'HRTF';
    var innerCone = 80;
    var outerCone = 120;
    var outerGain = 0.4;
    var distanceModel = 'linear';
    var maxDistance = 20;
    var refDistance = 5;
    var rollOff = 20;
    var orientationX = 1.0;
    var orientationY = 0.0;
    var orientationZ = 0.0;
    var context = this.app.systems.sound.context;
    var listener = context.listener;
    
    var panner = new PannerNode(context, {
        panningModel: pannerModel,
        distanceModel: distanceModel,
        positionX: pos.x,
        positionY: pos.y,
        positionZ: pos.z,
        orientationX: orientationX,
        orientationY: orientationY,
        orientationZ: orientationZ,
        refDistance: refDistance,
        maxDistance: maxDistance,
        rolloffFactor: rollOff,
        coneInnerAngle: innerCone,
        coneOuterAngle: outerCone,
        coneOuterGain: outerGain
    });
    
    var gainNode = context.createGain();
    var pannerOptions = { pan: 0 };
    var stereoPanner = new StereoPannerNode(context, pannerOptions);
    var audioSource = new Audio();
    
    this.context = context;
    this.audioSource = audioSource;
    this.stereoPanner = stereoPanner;
    this.panner = panner;
    this.gainNode = gainNode;
    var track = this.context.createMediaElementSource(remoteTrack.containers[0]);
    console.log(track);
    track.connect(this.gainNode)
        .connect(this.stereoPanner)
        .connect(this.panner)
        .connect(this.context.destination);
    
    this.initialized = true;
};

AudioEmitter3d.prototype.play = function()
{
    if(!this.audioSource) return;
    this.audioSource.play();  
};

// update code called every frame
AudioEmitter3d.prototype.update = function(dt) {
        if (!this.initialized) return;
        if (!this.context) return;
        
        var localPlayer = this.app.root.findByName("LocalPlayer");
    
        var listener = this.context.listener;
        var pos = localPlayer.children[0].getPosition();
        var up = localPlayer.children[0].up;
        var forward = localPlayer.children[0].forward;
        
        listener.positionX.value = pos.x;
        listener.positionY.value = pos.y;
        listener.positionZ.value = pos.z;
        
        listener.forwardX.value = forward.x;
        listener.forwardY.value = forward.y;
        listener.forwardZ.value = forward.z;
        
        listener.upX.value = up.x;
        listener.upY.value = up.y;
        listener.upZ.value = up.z;
};

am i doing something super wrong here? i checked the examples and i dont see any big difference.

Calling @LeXXik, the author of the original example.

switched from createMediaElementSource to createMediaStreamSource and it works now, the only thing that is wrong is the distance but i think i might setup the listener wrong.

1 Like

Mm, called? :slight_smile:
So, yeah, the element node is suitable if you use the HTML elements, while the stream one can be used to read data from streams API or WebRTC. Well, I guess you already figured. Regarding the position of the listener, make sure you are reading and setting the position correctly. What can help is to create a dummy primitive object and set its position to the position of the listener. If the listener is the camera, you can add another camera for debugging.

1 Like

Well my Listener is the camera of the local player. the emitter is the network entity. if i change the maxDistance to a lower value and move out of the distance, the sound suddenly stops but there is no fall off of the sound.

Well, it is hard to say what is happening in your case, but I would start from looking into the values you use for the panner. You can simplify it at start, e.g. don’t use directional sound, but instead create an omni point, where the sound would be of equal value, regardless of the direction the source is facing. You can set the inner cone to 360 degrees and outer one to 0. Check your distance and rolloff ratios. You can start with rolloff value of 1.