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?
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);