cpal icon indicating copy to clipboard operation
cpal copied to clipboard

cpal + dioxus_desktop: eats memory and dies

Open rMazeiks opened this issue 2 years ago • 3 comments

With latest versions:

cpal = { version = "0.15.2", features=["jack"] }

dioxus = "0.3.2"
dioxus-ssr = "0.3.0"
dioxus-desktop = "0.3.0"

Consider this minimal code:

use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
use cpal::{BufferSize, Device, Stream, StreamConfig, SupportedBufferSize};
use std::cmp::max;

fn main() {
    let _stream = start_cpal();

    loop {}
}

fn start_cpal() -> Stream {
    let device = get_device();
    let config = get_config(&device);

    let stream = device
        .build_output_stream(
            &config,
            move |_: &mut [f32], _: &cpal::OutputCallbackInfo| {},
            move |_| {},
            None,
        )
        .unwrap();

    stream.play().unwrap();
    stream
}

fn get_device() -> Device {
    let host_id = cpal::available_hosts()[0];
    let host = cpal::host_from_id(host_id).unwrap();

    host.default_output_device().unwrap()
}

fn get_config(device: &Device) -> StreamConfig {
    let mut supported_configs_range = device.supported_output_configs().unwrap();
    let supported_config = supported_configs_range
        .next()
        .unwrap()
        .with_max_sample_rate();

    let mut config = supported_config.config();
    config.buffer_size = BufferSize::Fixed(get_some_buffer_size(supported_config.buffer_size()));

    config
}

fn get_some_buffer_size(spec: &SupportedBufferSize) -> u32 {
    match spec {
        SupportedBufferSize::Range { min, .. } => max(*min, 64),
        SupportedBufferSize::Unknown => 64,
    }
}

It works as expected (program runs; nothing happens). I also get sound if I put something in the data callback.

Enter dioxus desktop:

fn main() {
    let _stream = start_cpal();

    dioxus_desktop::launch(app);
}

use dioxus::prelude::*;
fn app(cx: Scope) -> Element {
    cx.render(rsx!("lol"))
}
// .. same code as before

Expected result: cpal still works; Dioxus window shows up.

Actual result: program eats all the memory and the OS kills it. No window shows up.

Resource monitor screenshot: spike in memory usage

The start of the spike is where I run the program. It falls back down after a few seconds when the process is killed.

The issue is not with Dioxus alone, because this program works as expected:

fn main() {
    dioxus_desktop::launch(app);
}

The problem only occurs when I use cpal and Dioxus in the same program.

I don't know if this is an issue with Dioxus or cpal, and I have no idea where to begin debugging this. Any ideas please?

I'm on Ubuntu 22.04.2 LTS. Lemme know if you need any other details. Thank you!!

rMazeiks avatar May 27 '23 06:05 rMazeiks

Use a heap profiler (like valgrind's massif) to see what code is responsible for the allocations.

Ralith avatar May 27 '23 06:05 Ralith

Thanks for the suggestion! Unfortunately, I can't seem to get anything out of valgrind.

If I simply run massif, the program still gets killed, and I get no output.

$ valgrind --tool=massif ./target/debug/hello_cpal 
==249915== Massif, a heap profiler
==249915== Copyright (C) 2003-2017, and GNU GPL'd, by Nicholas Nethercote
==249915== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==249915== Command: ./target/debug/hello_cpal
==249915== 
Killed

I thought of creating a snapshot using gdb before the program is killed. However, as soon as I use continue to actually start the program, gdb becomes unresponsive, and I can't use the monitor snapshot command.

Am I doing this wrong? Sorry I'm new to this valgrind stuff.

rMazeiks avatar May 27 '23 06:05 rMazeiks