Unity WebGL Audio Failed to execute 'copyToChannel' on 'AudioBuffer'

Unity 2022.3.7f1
I’m trying to playback an mp3 directly from memory on WebGL.
I’m using NAudio and NLayer for audio decompression (I got it working by importing the scripts directly and deleting anything relating to windows APIs) and so far all this works
now it fails on AudioClip.Create()
Here’s the code

byte[] mp3 = Convert.FromBase64String(response.audioContent);
using (MemoryStream mp3Stream = new MemoryStream(mp3))
{
    var builder = new Mp3FileReader.FrameDecompressorBuilder(wf => new Mp3FrameDecompressor(wf));
    using (Mp3FileReader ms = new Mp3FileReader(mp3Stream))
    {
        float[] output = null;
        output = new float[ms.Length/2];
        ISampleProvider isp = ms.ToSampleProvider();
        outputClip = AudioClip.Create("", output.Length, 1, 44100, false);
        outputClip.SetData(output, 0);
    };
}

Here’s the error message
Error Message

Uncaught TypeError: Failed to execute ‘copyToChannel’ on ‘AudioBuffer’: The provided Float32Array value must not be shared.
at jsAudioCreateUncompressedSoundClipFromPCM (SIMLIWEB.framework.js:10:73224)
at _JS_Sound_Load_PCM (SIMLIWEB.framework.js:10:73563)
at SIMLIWEB.wasm:0x1a7d4fe
at SIMLIWEB.wasm:0x1aabd08
at SIMLIWEB.wasm:0x1aaeb95
at SIMLIWEB.wasm:0x24f0a99
at SIMLIWEB.wasm:0x43d616
at SIMLIWEB.wasm:0x43d4bd
at SIMLIWEB.wasm:0x2598938
at invoke_iiiiiii (SIMLIWEB.framework.js:10:494042)
at SIMLIWEB.wasm:0x1002840
at SIMLIWEB.wasm:0x1003317
at SIMLIWEB.wasm:0x16785b4
at SIMLIWEB.wasm:0x397251
at SIMLIWEB.wasm:0x25988b6
at invoke_viii (SIMLIWEB.framework.js:10:493715)
at SIMLIWEB.wasm:0x13d2b22
at SIMLIWEB.wasm:0x13d7d14
at SIMLIWEB.wasm:0x25988ec
at invoke_viiiii (SIMLIWEB.framework.js:10:495719)
at SIMLIWEB.wasm:0x1678371
at SIMLIWEB.wasm:0x15d22fa
at SIMLIWEB.wasm:0x397251
at SIMLIWEB.wasm:0x25988b6
at invoke_viii (SIMLIWEB.framework.js:10:493715)
at SIMLIWEB.wasm:0x15d1630
at SIMLIWEB.wasm:0x15d14b7
at SIMLIWEB.wasm:0x15cbafe
at SIMLIWEB.wasm:0x15c9271
at SIMLIWEB.wasm:0x148cb5f
at SIMLIWEB.wasm:0x1421435
at SIMLIWEB.wasm:0x1004219
at SIMLIWEB.wasm:0x100423f
at SIMLIWEB.wasm:0x16785b4
at SIMLIWEB.wasm:0x397251
at SIMLIWEB.wasm:0x25988b6
at invoke_viii (SIMLIWEB.framework.js:10:493715)
at SIMLIWEB.wasm:0x13d2b22
at SIMLIWEB.wasm:0x13d7d14
at SIMLIWEB.wasm:0x25988ec
at invoke_viiiii (SIMLIWEB.framework.js:10:495719)
at SIMLIWEB.wasm:0x1678371
at SIMLIWEB.wasm:0x16789ac
at SIMLIWEB.wasm:0x397251
at SIMLIWEB.wasm:0x25988b6
at invoke_viii (SIMLIWEB.framework.js:10:493715)
at SIMLIWEB.wasm:0x118ed78
at SIMLIWEB.wasm:0x118ec8e
at SIMLIWEB.wasm:0x118ef88
at SIMLIWEB.wasm:0x17a0ede
jsAudioCreateUncompressedSoundClipFromPCM @ SIMLIWEB.framework.js:10
_JS_Sound_Load_PCM @ SIMLIWEB.framework.js:10
$func91449 @ SIMLIWEB.wasm:0x1a7d4fe
$func91835 @ SIMLIWEB.wasm:0x1aabd08
$func91879 @ SIMLIWEB.wasm:0x1aaeb95
$func110604 @ SIMLIWEB.wasm:0x24f0a99
$func11778 @ SIMLIWEB.wasm:0x43d616
$func11777 @ SIMLIWEB.wasm:0x43d4bd
$dynCall_iiiiiii @ SIMLIWEB.wasm:0x2598938
invoke_iiiiiii @ SIMLIWEB.framework.js:10
$func53031 @ SIMLIWEB.wasm:0x1002840
$func53033 @ SIMLIWEB.wasm:0x1003317
$func77632 @ SIMLIWEB.wasm:0x16785b4
$func8563 @ SIMLIWEB.wasm:0x397251
$dynCall_viii @ SIMLIWEB.wasm:0x25988b6
invoke_viii @ SIMLIWEB.framework.js:10
$func68358 @ SIMLIWEB.wasm:0x13d2b22
$func68436 @ SIMLIWEB.wasm:0x13d7d14
$dynCall_viiiii @ SIMLIWEB.wasm:0x25988ec
invoke_viiiii @ SIMLIWEB.framework.js:10
$func77630 @ SIMLIWEB.wasm:0x1678371
$func75150 @ SIMLIWEB.wasm:0x15d22fa
$func8563 @ SIMLIWEB.wasm:0x397251
$dynCall_viii @ SIMLIWEB.wasm:0x25988b6
invoke_viii @ SIMLIWEB.framework.js:10
$func75137 @ SIMLIWEB.wasm:0x15d1630
$func75136 @ SIMLIWEB.wasm:0x15d14b7
$func75065 @ SIMLIWEB.wasm:0x15cbafe
$func75017 @ SIMLIWEB.wasm:0x15c9271
$func70975 @ SIMLIWEB.wasm:0x148cb5f
$func69482 @ SIMLIWEB.wasm:0x1421435
$func53036 @ SIMLIWEB.wasm:0x1004219
$func53037 @ SIMLIWEB.wasm:0x100423f
$func77632 @ SIMLIWEB.wasm:0x16785b4
$func8563 @ SIMLIWEB.wasm:0x397251
$dynCall_viii @ SIMLIWEB.wasm:0x25988b6
invoke_viii @ SIMLIWEB.framework.js:10
$func68358 @ SIMLIWEB.wasm:0x13d2b22
$func68436 @ SIMLIWEB.wasm:0x13d7d14
$dynCall_viiiii @ SIMLIWEB.wasm:0x25988ec
invoke_viiiii @ SIMLIWEB.framework.js:10
$func77630 @ SIMLIWEB.wasm:0x1678371
$func77639 @ SIMLIWEB.wasm:0x16789ac
$func8563 @ SIMLIWEB.wasm:0x397251
$dynCall_viii @ SIMLIWEB.wasm:0x25988b6
invoke_viii @ SIMLIWEB.framework.js:10
$func58999 @ SIMLIWEB.wasm:0x118ed78
$func58998 @ SIMLIWEB.wasm:0x118ec8e
$func59003 @ SIMLIWEB.wasm:0x118ef88
$func85452 @ SIMLIWEB.wasm:0x17a0ede
$func86412 @ SIMLIWEB.wasm:0x17b7dbf
$dynCall_iiii @ SIMLIWEB.wasm:0x259886b
invoke_iiii @ SIMLIWEB.framework.js:10
$func86397 @ SIMLIWEB.wasm:0x17b6eb6
$func1343 @ SIMLIWEB.wasm:0x101a06
$func111424 @ SIMLIWEB.wasm:0x253355c
$func108003 @ SIMLIWEB.wasm:0x249cd2e
$func107465 @ SIMLIWEB.wasm:0x246ce93
$func107395 @ SIMLIWEB.wasm:0x246437f
$func107395 @ SIMLIWEB.wasm:0x24643f2
$func112285 @ SIMLIWEB.wasm:0x2578751
$dynCall_v @ SIMLIWEB.wasm:0x2598894
browserIterationFunc @ SIMLIWEB.framework.js:10
callUserCallback @ SIMLIWEB.framework.js:10
runIter @ SIMLIWEB.framework.js:10
Browser_mainLoop_runner @ SIMLIWEB.framework.js:10
requestAnimationFrame (async)
requestAnimationFrame @ SIMLIWEB.framework.js:10
Browser_mainLoop_scheduler_rAF @ SIMLIWEB.framework.js:10
Browser_mainLoop_runner @ SIMLIWEB.framework.js:10
requestAnimationFrame (async)
requestAnimationFrame @ SIMLIWEB.framework.js:10
Browser_mainLoop_scheduler_rAF @ SIMLIWEB.framework.js:10
Browser_mainLoop_runner @ SIMLIWEB.framework.js:10
requestAnimationFrame (async)
requestAnimationFrame @ SIMLIWEB.framework.js:10
Browser_mainLoop_scheduler_rAF @ SIMLIWEB.framework.js:10
Browser_mainLoop_runner @ SIMLIWEB.framework.js:10
requestAnimationFrame (async)
requestAnimationFrame @ SIMLIWEB.framework.js:10
Browser_mainLoop_scheduler_rAF @ SIMLIWEB.framework.js:10
Browser_mainLoop_runner @ SIMLIWEB.framework.js:10
requestAnimationFrame (async)
requestAnimationFrame @ SIMLIWEB.framework.js:10
Browser_mainLoop_scheduler_rAF @ SIMLIWEB.framework.js:10
Browser_mainLoop_runner @ SIMLIWEB.framework.js:10
requestAnimationFrame (async)
requestAnimationFrame @ SIMLIWEB.framework.js:10
Browser_mainLoop_scheduler_rAF @ SIMLIWEB.framework.js:10
Browser_mainLoop_runner @ SIMLIWEB.framework.js:10
requestAnimationFrame (async)
requestAnimationFrame @ SIMLIWEB.framework.js:10
Browser_mainLoop_scheduler_rAF @ SIMLIWEB.framework.js:10
Browser_mainLoop_runner @ SIMLIWEB.framework.js:10
requestAnimationFrame (async)
requestAnimationFrame @ SIMLIWEB.framework.js:10
Browser_mainLoop_scheduler_rAF @ SIMLIWEB.framework.js:10
Browser_mainLoop_runner @ SIMLIWEB.framework.js:10
requestAnimationFrame (async)
requestAnimationFrame @ SIMLIWEB.framework.js:10
Browser_mainLoop_scheduler_rAF @ SIMLIWEB.framework.js:10
Browser_mainLoop_runner @ SIMLIWEB.framework.js:10
requestAnimationFrame (async)
requestAnimationFrame @ SIMLIWEB.framework.js:10
Browser_mainLoop_scheduler_rAF @ SIMLIWEB.framework.js:10
Browser_mainLoop_runner @ SIMLIWEB.framework.js:10
requestAnimationFrame (async)
requestAnimationFrame @ SIMLIWEB.framework.js:10
Browser_mainLoop_scheduler_rAF @ SIMLIWEB.framework.js:10
Browser_mainLoop_runner @ SIMLIWEB.framework.js:10
requestAnimationFrame (async)
requestAnimationFrame @ SIMLIWEB.framework.js:10
Browser_mainLoop_scheduler_rAF @ SIMLIWEB.framework.js:10
Browser_mainLoop_runner @ SIMLIWEB.framework.js:10
requestAnimationFrame (async)
requestAnimationFrame @ SIMLIWEB.framework.js:10
Browser_mainLoop_scheduler_rAF @ SIMLIWEB.framework.js:10
Browser_mainLoop_runner @ SIMLIWEB.framework.js:10
requestAnimationFrame (async)
requestAnimationFrame @ SIMLIWEB.framework.js:10
Browser_mainLoop_scheduler_rAF @ SIMLIWEB.framework.js:10
Browser_mainLoop_runner @ SIMLIWEB.framework.js:10
requestAnimationFrame (async)
requestAnimationFrame @ SIMLIWEB.framework.js:10
Browser_mainLoop_scheduler_rAF @ SIMLIWEB.framework.js:10
Browser_mainLoop_runner @ SIMLIWEB.framework.js:10
requestAnimationFrame (async)
requestAnimationFrame @ SIMLIWEB.framework.js:10
Browser_mainLoop_scheduler_rAF @ SIMLIWEB.framework.js:10
Browser_mainLoop_runner @ SIMLIWEB.framework.js:10
requestAnimationFrame (async)
requestAnimationFrame @ SIMLIWEB.framework.js:10
Browser_mainLoop_scheduler_rAF @ SIMLIWEB.framework.js:10
Browser_mainLoop_runner @ SIMLIWEB.framework.js:10
requestAnimationFrame (async)
requestAnimationFrame @ SIMLIWEB.framework.js:10
Browser_mainLoop_scheduler_rAF @ SIMLIWEB.framework.js:10
Browser_mainLoop_runner @ SIMLIWEB.framework.js:10
requestAnimationFrame (async)
requestAnimationFrame @ SIMLIWEB.framework.js:10
Browser_mainLoop_scheduler_rAF @ SIMLIWEB.framework.js:10
Browser_mainLoop_runner @ SIMLIWEB.framework.js:10
requestAnimationFrame (async)
requestAnimationFrame @ SIMLIWEB.framework.js:10
Browser_mainLoop_scheduler_rAF @ SIMLIWEB.framework.js:10
Browser_mainLoop_runner @ SIMLIWEB.framework.js:10
requestAnimationFrame (async)
requestAnimationFrame @ SIMLIWEB.framework.js:10
Browser_mainLoop_scheduler_rAF @ SIMLIWEB.framework.js:10
Browser_mainLoop_runner @ SIMLIWEB.framework.js:10
requestAnimationFrame (async)
requestAnimationFrame @ SIMLIWEB.framework.js:10
Browser_mainLoop_scheduler_rAF @ SIMLIWEB.framework.js:10
Browser_mainLoop_runner @ SIMLIWEB.framework.js:10
requestAnimationFrame (async)
requestAnimationFrame @ SIMLIWEB.framework.js:10
Browser_mainLoop_scheduler_rAF @ SIMLIWEB.framework.js:10
Browser_mainLoop_runner @ SIMLIWEB.framework.js:10
requestAnimationFrame (async)
requestAnimationFrame @ SIMLIWEB.framework.js:10
Browser_mainLoop_scheduler_rAF @ SIMLIWEB.framework.js:10
Browser_mainLoop_runner @ SIMLIWEB.framework.js:10
requestAnimationFrame (async)
requestAnimationFrame @ SIMLIWEB.framework.js:10
Browser_mainLoop_scheduler_rAF @ SIMLIWEB.framework.js:10
Browser_mainLoop_runner @ SIMLIWEB.framework.js:10
requestAnimationFrame (async)
requestAnimationFrame @ SIMLIWEB.framework.js:10
Browser_mainLoop_scheduler_rAF @ SIMLIWEB.framework.js:10
Browser_mainLoop_runner @ SIMLIWEB.framework.js:10
requestAnimationFrame (async)
requestAnimationFrame @ SIMLIWEB.framework.js:10
Browser_mainLoop_scheduler_rAF @ SIMLIWEB.framework.js:10
Browser_mainLoop_runner @ SIMLIWEB.framework.js:10
requestAnimationFrame (async)
requestAnimationFrame @ SIMLIWEB.framework.js:10
Browser_mainLoop_scheduler_rAF @ SIMLIWEB.framework.js:10
Browser_mainLoop_runner @ SIMLIWEB.framework.js:10
requestAnimationFrame (async)
requestAnimationFrame @ SIMLIWEB.framework.js:10
Browser_mainLoop_scheduler_rAF @ SIMLIWEB.framework.js:10
Browser_mainLoop_runner @ SIMLIWEB.framework.js:10
requestAnimationFrame (async)
requestAnimationFrame @ SIMLIWEB.framework.js:10
Browser_mainLoop_scheduler_rAF @ SIMLIWEB.framework.js:10
Browser_mainLoop_runner @ SIMLIWEB.framework.js:10
requestAnimationFrame (async)
requestAnimationFrame @ SIMLIWEB.framework.js:10
Browser_mainLoop_scheduler_rAF @ SIMLIWEB.framework.js:10
Browser_mainLoop_runner @ SIMLIWEB.framework.js:10
requestAnimationFrame (async)
requestAnimationFrame @ SIMLIWEB.framework.js:10
Browser_mainLoop_scheduler_rAF @ SIMLIWEB.framework.js:10
Browser_mainLoop_runner @ SIMLIWEB.framework.js:10

The array you use to store the decompressed audio data somehow ends up being a SharedArrayBuffer but the JS API AudioBuffer.copyToChannel refuses to accept it.

I suspect this is some interplay between IL2CPP, Emscripten and Unity’s JS-implementation of its APIs. You could try to dig into the generated source/assembly to see if you can figure out wether you can get it to create a non-shared ArrayBuffer but that’s probably not straightforward (Emscripten might be creating a shared buffer because it’s required for multithreading).

I’d report a bug with Unity. They might have to first copy the data out of the shared buffer before passing it to copyToChannel to avoid the error.

I did what you said, stuck the framework.js into vscode for formatting, took the function and error message to ChatGPT and it is working now
This was the unity output

    function jsAudioCreateUncompressedSoundClipFromPCM(channels, length, sampleRate, ptr) {
            var buffer = WEBAudio.audioContext.createBuffer(channels, length, sampleRate);
            for (var i = 0; i < channels; i++) {
                var offs = (ptr >> 2) + length * i;
                var copyToChannel = buffer["copyToChannel"] || function(source, channelNumber, startInChannel) {
                    var clipped = source.subarray(0, Math.min(source.length, this.length - (startInChannel | 0)));
                    this.getChannelData(channelNumber | 0).set(clipped, startInChannel | 0)
                }
                ;
                copyToChannel.apply(buffer, [GROWABLE_HEAP_F32().subarray(offs, offs + length), i, 0])
            }
            return jsAudioCreateUncompressedSoundClip(buffer, false)
        }

This is the working code

function jsAudioCreateUncompressedSoundClipFromPCM(
  channels,
  length,
  sampleRate,
  ptr
) {
  var buffer = WEBAudio.audioContext.createBuffer(
    channels,
    length,
    sampleRate
  );
  for (var i = 0; i < channels; i++) {
    var offs = (ptr >> 2) + length * i;
    var copyToChannel =
      buffer["copyToChannel"] ||
      function (source, channelNumber, startInChannel) {
        var clipped = source.subarray(
          0,
          Math.min(source.length, this.length - (startInChannel | 0))
        );
        this.getChannelData(channelNumber | 0).set(
          clipped,
          startInChannel | 0
        );
      };

    // Create a new Float32Array from the subarray so it's not shared.
    var newArray = new Float32Array(GROWABLE_HEAP_F32().subarray(offs, offs + length));

    copyToChannel.apply(buffer, [
      newArray, // Use the new non-shared Float32Array
      i,
      0,
    ]);
  }
  return jsAudioCreateUncompressedSoundClip(buffer, false);
}

It just creates a copy of the array nothing fancy but idk JavaScript xD

Could it be related to this?

using UnityEditor;
using UnityEngine;

[InitializeOnLoad]
class EnableThreads
{
    static EnableThreads()
    {
        PlayerSettings.WebGL.linkerTarget = WebGLLinkerTarget.Wasm;
        PlayerSettings.WebGL.threadsSupport = true;
        PlayerSettings.WebGL.memorySize = 512;
    }
}

Yeah, looks like data is coming directly from the buffer used for heap memory. To use threading effectively, different threads need to access the same memory concurrently and that’s only possible with SharedArrayBuffer in JavaScript. Heap memory is the general memory, so in a threaded program you want all threads to access the same shared heap. If you turn threading off, Emscripten will probably not use shared memory and this issue won’t come up.

Usually, there’s a security-related reason for why these limitations are put in place in JS. E.g. how shared memory itself requires HTTPS and cross-origin isolation. This is due to the Spectre vulnerability that could otherwise allow websites to access information from other websites, like passwords or credit card information.

It does look like this is an issue with Unity’s code, so creating a bug report would be best. Bug reports are the quickest way to get someone at Unity to look at the issue and queue it up with the right team to fix it.

I am having the same issue on Unity 6000.0.1, using multi-threaded Web build and AudioClip.Create().

Have you reported this issue to Unity, and if yes, did they respond ?

It has been a while but i did file a bug report and i remember that they said this is intended behavior due to security reasons and how WebAudio works.

I remember that i successfully solved it but I have forgotten how as I haven’t touched that codebase in 1.5 years or something
Edit: without multi threaded build

I resolved the error by applying the solution you mentioned : copying array to a temporary JS array, then calling copyToChannel.apply().

I created a build post-processor that will automatically inject Javascript into “framework.js” file which is generated by Unity during a build process, so that it works without having to modify JS files in Unity installation, and so that it also works in Cloud build :

I also submitted bug report to Unity, explaining a 1-line fix. Hopefully they fix it.