Skip to content

Commit

Permalink
Fix crash on Web / Wasm when 'atomics' flag is enabled (#837)
Browse files Browse the repository at this point in the history
  • Loading branch information
kettle11 authored Feb 17, 2024
1 parent 52c7a9d commit 8d50e6a
Showing 1 changed file with 49 additions and 3 deletions.
52 changes: 49 additions & 3 deletions src/host/webaudio/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,16 @@ impl DeviceTrait for Device {
let mut temporary_buffer = vec![0f32; buffer_size_samples];
let mut temporary_channel_buffer = vec![0f32; buffer_size_frames];

#[cfg(target_feature = "atomics")]
let temporary_channel_array_view: js_sys::Float32Array;
#[cfg(target_feature = "atomics")]
{
let temporary_channel_array = js_sys::ArrayBuffer::new(
(std::mem::size_of::<f32>() * buffer_size_frames) as u32,
);
temporary_channel_array_view = js_sys::Float32Array::new(&temporary_channel_array);
}

// Create a webaudio buffer which will be reused to avoid allocations.
let ctx_buffer = ctx
.create_buffer(
Expand Down Expand Up @@ -316,9 +326,31 @@ impl DeviceTrait for Device {
temporary_channel_buffer[i] =
temporary_buffer[n_channels * i + channel];
}
ctx_buffer
.copy_to_channel(&mut temporary_channel_buffer, channel as i32)
.expect("Unable to write sample data into the audio context buffer");

#[cfg(not(target_feature = "atomics"))]
{
ctx_buffer
.copy_to_channel(&mut temporary_channel_buffer, channel as i32)
.expect(
"Unable to write sample data into the audio context buffer",
);
}

// copyToChannel cannot be directly copied into from a SharedArrayBuffer,
// which WASM memory is backed by if the 'atomics' flag is enabled.
// This workaround copies the data into an intermediary buffer first.
// There's a chance browsers may eventually relax that requirement.
// See this issue: https://github.com/WebAudio/web-audio-api/issues/2565
#[cfg(target_feature = "atomics")]
{
temporary_channel_array_view.copy_from(&mut temporary_channel_buffer);
ctx_buffer
.unchecked_ref::<ExternalArrayAudioBuffer>()
.copy_to_channel(&temporary_channel_array_view, channel as i32)
.expect(
"Unable to write sample data into the audio context buffer",
);
}
}

// Create an AudioBufferSourceNode, schedule it to playback the reused buffer
Expand Down Expand Up @@ -480,3 +512,17 @@ fn valid_config(conf: &StreamConfig, sample_format: SampleFormat) -> bool {
fn buffer_time_step_secs(buffer_size_frames: usize, sample_rate: SampleRate) -> f64 {
buffer_size_frames as f64 / sample_rate.0 as f64
}

#[cfg(target_feature = "atomics")]
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_name = AudioBuffer)]
type ExternalArrayAudioBuffer;

# [wasm_bindgen(catch, method, structural, js_class = "AudioBuffer", js_name = copyToChannel)]
pub fn copy_to_channel(
this: &ExternalArrayAudioBuffer,
source: &js_sys::Float32Array,
channel_number: i32,
) -> Result<(), JsValue>;
}

0 comments on commit 8d50e6a

Please sign in to comment.