# Internet streaming workaround with an OPENUSER sound?

**URL:** <https://qa.fmod.com/t/internet-streaming-workaround-with-an-openuser-sound/22961>\
**Category:** FMOD Engine\
**Tags:** html5\
**Created:** [May 21, 2025, 11:59am UTC](https://qa.fmod.com/t/internet-streaming-workaround-with-an-openuser-sound/22961 "2025-05-21T11:59:21Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![rhys-L](https://yyz2.discourse-cdn.com/flex036/user_avatar/qa.fmod.com/rhys-l/32/6882_2.png) [@rhys-L](https://qa.fmod.com/u/rhys-L)\
**Post date:** [May 21, 2025, 11:59am UTC](https://qa.fmod.com/t/internet-streaming-workaround-with-an-openuser-sound/22961/1 "2025-05-21T11:59:21Z")

</div>

Hi, I’m just wondering if there’s some workaround for streaming audio over the internet on FMOD’s HTML5 implementation by managing the stream in JavaScript, and passing the raw PCM data directly to an FMOD sound?

My idea was to calculate the buffer size outside of FMOD and manually stop playback if there wasn’t a big enough buffer. I get that this may be a long shot, but I think it’d be really cool to send live radio through FMOD in the browser.

I’ve managed to get streamed audio to work without errors by using Sound.lock() and Sound.unlock(), but when I play the sound, it gets stuck in FMOD\_OPENSTATE\_SETPOSITION.

I’ve also tried using `pcmreadcallback` and got the same result.

Here’s an extract of some of the code I’m experimenting with. `Pointer.deref()` is just a wrapper for the whole `outval.val` pattern.

Is there some fundamental barrier to this that I’m missing?

```auto
        const sound = new Pointer<any>();
        const info = FMOD.CREATESOUNDEXINFO();
        info.defaultfrequency = sampleRate;
        info.decodebuffersize = 44100;
        info.numchannels = 2;
        info.length = info.defaultfrequency * info.numchannels * 2 * 5; 
        info.format = FMOD.SOUND_FORMAT_PCM16;
        const mode = FMOD.OPENUSER | FMOD.LOOP_NORMAL;

        const ptr1 = new Pointer<any>();
        const ptr2 = new Pointer<any>();
        const len1 = new Pointer<any>();
        const len2 = new Pointer<any>();
        FMOD.Result = FMOD.Core.createSound('', mode, info, sound);
        FMOD.Result = sound.deref().lock(0, info.length, ptr1, ptr2, len1, len2);
        let offset = 0;
        while (offset < len1.deref()) {
            const { done, value } = await reader.read();
            if (done) break;
            const { channelData, samplesDecoded, errors } = await decoder.decode(value);
            console.log(samplesDecoded, offset, len1.deref());

            const [left, right] = channelData;
            for (let i = offset; i < (samplesDecoded >> 2); i++) {
                let leftIndex = ptr1.deref() + i << 2;
                let rightIndex = leftIndex + 2;
                FMOD.setValue(leftIndex, left[i], 'i16'); // left channel
                FMOD.setValue(rightIndex, right[i], 'i16'); // right channel
            }
            offset += samplesDecoded;
            // break;
        }
        sound.deref().unlock(ptr1.deref(), ptr2.deref(), len1.deref(), len2.deref());
        const openstate = new Pointer<any>();
        const percentbuffered = new Pointer<any>();
        const starving = new Pointer<any>();
        const diskbusy = new Pointer<any>();
        sound.deref().getOpenState(openstate, percentbuffered, starving, diskbusy);
        console.log(openstate, percentbuffered, starving, diskbusy);
        FMOD.Result = FMOD.Core.playSound(sound.deref(), null, null, {});
        setInterval(() => {
            sound.deref().getOpenState(openstate, percentbuffered, starving, diskbusy);
            console.log(openstate, percentbuffered, starving, diskbusy);
        }, 2000);

```

---

<div class="post-metadata">

**Author:** ![Leah\_FMOD](https://yyz2.discourse-cdn.com/flex036/user_avatar/qa.fmod.com/leah_fmod/32/3685_2.png) [@Leah\_FMOD](https://qa.fmod.com/u/Leah_FMOD)\
**Post date:** [June 2, 2025, 6:18am UTC](https://qa.fmod.com/t/internet-streaming-workaround-with-an-openuser-sound/22961/2 "2025-06-02T06:18:09Z")

</div>

Hi, apologies for the delayed response.

A few questions:

- What version of FMOD are you using?
- Is the FMOD system being [updated](https://www.fmod.com/docs/2.02/api/core-api-system.html#system_update) at any point outside of the snippet you’ve posted? If not, this may be the issue.
- Does add `FMOD_NONBLOCKING` to the sound mode make any difference?
- Failing the above, could I get you to swap to the logging version of the FMOD libs (suffixed with “L”), use [Debug\_Initialize](https://www.fmod.com/docs/2.02/api/core-api-common.html#debug_initialize) ahead of system creation and initialization to set your logging level to `FMOD_DEBUG_LOG`, and post a log where the issue occurs?

---

<div class="post-metadata">

**Author:** ![rhys-L](https://yyz2.discourse-cdn.com/flex036/user_avatar/qa.fmod.com/rhys-l/32/6882_2.png) [@rhys-L](https://qa.fmod.com/u/rhys-L)\
**Post date:** [June 21, 2025, 5:46pm UTC](https://qa.fmod.com/t/internet-streaming-workaround-with-an-openuser-sound/22961/3 "2025-06-21T17:46:21Z")

</div>

Hi, no worries at all.

I got it to work!

Thanks for the help! FMOD is being updated in a separate loop. `FMOD_NONBLOCKING` is not supported I believe. I switched to `fmodstudioL.js`, and the logs helped quite a bit.

I still have literally no idea what the issue was. Maybe there was some sort of logical mistake in my code. Either way, it’s now definitely possible to stream audio over the internet into FMOD sounds, even on the Emscripten port.

I switched to using `pcmreadcallback` instead of `Sound.lock()`, so that may have had something to do with it.

The trick was to move all asynchronous stuff away from FMOD, because when `pcmreadcallback` is called, it needs bytes right away. The way I’m doing it now is that `pcmreadcallback` reads from a buffer that’s filled by an `AudioWorkletNode` that does all the decoding and interleaving of the samples.

Here’s what I’ve got so far.

I get that this use case is quite niche, but do you think that HTML5 internet streaming is something that FMOD might officially support any time soon?

```javascript
    async fetch() {
        await gesture.promise;
        const context = new AudioContext();
        const source = context.createMediaElementSource(this.element);
        await context.audioWorklet.addModule('/pcmProcessor.js');
        const node = new AudioWorkletNode(context, 'pcm-processor');
        node.port.onmessage = async (event: MessageEvent<ArrayBuffer>) => {
            const { full } = this.buffer.write(event.data);
            if (full && !this.buffer.loop) {
                // TODO
            }
        };
        source.connect(node);
        this.element.play();
    }

/* ... */
    async load() {
        await this.buffer.ready;

        const sound = new Pointer<any>();
        const info = FMOD.CREATESOUNDEXINFO();
        const { sampleRate, numChannels, bytesPerSample } = this.soundInfo;

        info.length = this.length * numChannels * sampleRate * bytesPerSample;
        info.numchannels = numChannels;
        info.defaultfrequency = sampleRate;
        info.decodebuffersize = sampleRate;
        info.format = FMOD.SOUND_FORMAT_PCM16;

        info.pcmsetposcallback = (
            sound: any,
            subsound: any,
            position: any,
            postype: any
        ) => {
            console.log(this.url, 'seeking', position);
            const { sampleRate } = this.soundInfo;
            this.seek(position / sampleRate);
            return FMOD.OK;
        };

        info.pcmreadcallback = (sound: any, data: any, datalen: number) => {
            const { view, wrappedView, wrap, underflow } = this.buffer.read(
                Math.min(datalen, this.buffer.capacity)
            );

            if (underflow) {
                this.stop();
                this.buffer.ready.then(() => this.restart());
                return FMOD.OK;
            }
            FMOD.HEAPU8.set(view, data);
            if (wrap) {
                FMOD.HEAPU8.set(wrappedView, data + view.length);
            }
            return FMOD.OK;
        };
        FMOD.Result = FMOD.Core.createStream('', FMOD.OPENUSER | FMOD.ACCURATETIME | FMOD.LOOP_NORMAL, info, sound);
        this.handle = sound.deref();
        return true;
    };

```

---

<div class="post-metadata">

**Author:** ![Leah\_FMOD](https://yyz2.discourse-cdn.com/flex036/user_avatar/qa.fmod.com/leah_fmod/32/3685_2.png) [@Leah\_FMOD](https://qa.fmod.com/u/Leah_FMOD)\
**Post date:** [June 26, 2025, 5:41am UTC](https://qa.fmod.com/t/internet-streaming-workaround-with-an-openuser-sound/22961/4 "2025-06-26T05:41:10Z")

</div>

Happy to hear that it’s all working now.

> [@rhys-L](#):
>
> do you think that HTML5 internet streaming is something that FMOD might officially support any time soon?

Unfortunately I don’t have any updates to offer on the status HTML5 net streaming, but I’ve noted your interest on our internal feature tracker.

---

<div class="post-metadata">

**Author:** ![rhys-L](https://yyz2.discourse-cdn.com/flex036/user_avatar/qa.fmod.com/rhys-l/32/6882_2.png) [@rhys-L](https://qa.fmod.com/u/rhys-L)\
**Post date:** [April 8, 2026, 2:30pm UTC](https://qa.fmod.com/t/internet-streaming-workaround-with-an-openuser-sound/22961/5 "2026-04-08T14:30:44Z")

</div>

That’s understandable. I imagine there isn’t a huge demand for it. But thanks for adding it to your internal feature tracker! I can now fully stream FMOD events as long as they don’t jump around on the timeline (although I might not have implemented it very efficiently).
