Skip to content

Provide a Host API? (A path towards supporting alt-backends like ASIO, Windows Exclusive Mode, PulseAudio, Jack) #204

Closed

Description

@mitchmindtree

PortAudio (a C library with similar goals to CPAL) provide what they call a Host API for choosing between different audio APIs that might exist on a single system.

Any operating system may have any number of Host APIs to the system's audio devices. E.g. on Linux this might include Alsa, Jack and PulseAudio. In the case of Windows, perhaps Asio, Shared and Exclusive hosts could be included. In the case of macOS and iOS, CoreAudio would likey be the only host in most cases.

I imagine general use might look something like this:

let host = cpal::default_host();
let device = host.default_output_device().unwrap();
// etc

Selecting a specific host might look something like this:

let host = cpal::hosts()
    .find(|host| host.name().contains("jack"))
    .expect("cannot find jack audio backend");
let device = host.default_input_device().unwrap();
// etc

This way a low-latency application could attempt to select low-latency supporting hosts with something like this:

let host = if cfg!(target_os = "linux") {
    cpal::hosts().find(|h| h.name().contains("jack")).unwrap_or_else(cpal::default_host)
} else if cfg!(target_os = "windows") {
    cpal::hosts().find(|h| h.name().contains("asio")).unwrap_or_else(cpal::default_host)
} else {
    cpal::default_host()
};

Activity

  1. mitchmindtree commented on Feb 13, 2018

    @mitchmindtree
    MemberAuthor

    It's looking like my current project may need support for ASIO soon. @tomaka it would be great to get some feedback from you on this API as I'd like to go ahead and begin implementing it soon (along with the ASIO backend) if you agree it sounds like a decent approach?

  2. tomaka commented on Feb 13, 2018

    @tomaka
    Collaborator

    I'm really not a fan of this. The "host" is supposed to be cpal because cpal is supposed to be as low-level as possible.

    However I'm ok with adding platform-specific methods that allow choosing a backend, similar to what winit/glutin do.

  3. mitchmindtree commented on Feb 13, 2018

    @mitchmindtree
    MemberAuthor

    OK I see where you're coming from, I'll refer to winit's approach when attempting to implement this.

  4. mitchmindtree commented on Jun 5, 2019

    @mitchmindtree
    MemberAuthor

    OK, I've been reflecting a lot on this over the past year and a half since opening this issue and I'm convinced that providing some sort of Hosts API is the correct approach for CPAL.

    The "host" is supposed to be cpal because cpal is supposed to be as low-level as possible.

    I totally agree that CPAL should be as low-level as possible, however I don't think it is possible for CPAL to be "the" host (singular) unless two conditions are met:

    • There is only one, clear, standard host API (for interfacing with devices, spawning streams, etc) for each platform.
    • Users do not need the ability to switch between multiple hosts at run-time.

    Unfortunately, neither of these are the case, especially in the pro-audio community, e.g. VST, DAW, Multimedia workstation, etc, developers. On Windows, the default WDM API lacks support for many popular audio workstations and audio devices. E.g. in a recent commercial installation with @freesig we had to add ASIO support (#221) just to interface with Dante in a manner that allowed for more than 2 channels. It is also common for DAWs and other multimedia workstations to allow for selecting between multiple available hosts on the system in order to ensure users can access their hardware devices and achieve the desired latency that they require. Again, this is especially the case on Windows (ASIO, WDM) and Linux (ALSA, Pulse, Jack, who knows). Bitwig and Reaper come to mind as examples I use regularly on Linux, though I'm sure there are many more examples on both platforms.

    Thoughts on the API

    While this would be a breaking change, the changes should be trivial. Rather than enumerating and selecting devices via a global function, the user instead retrieves devices via a host instance.

    The host instance would take care of ensuring the API is initialised and de-initialised correclty via RAII (ASIO for example needs an initialisation and termination process).

    Perhaps a Host trait could be used to:

    1. Ensure API consistency across the different hosts and
    2. Allow for the user to select between different Hosts at runtime.

    Host / Device Exclusivity?

    In most cases, a host API requires exclusive access to the device(s) with which it has established streams, etc. Should we restrict the API to only allow for one host instance at any point in time? Or perhaps we should try to provide a more fine-grained API that works on a per-device basis (e.g. allowing host "foo" to connect to device "A" while host "bar" connects to device "B")? I guess the final option is to not enfoce this API-wise, and instead document the behaviour?


    I'd like to get around to addressing this issue within the next week or two - I'll continue to add thoughts related to the design and progress here.

  5. ishitatsuyuki commented on Jun 6, 2019

    @ishitatsuyuki
    Collaborator

    the user instead retrieves devices via a host instance.

    I think this is good.

    A few thoughts:

    1. WASAPI is a host, Shared and Exclusive is not. They're API options, and also stream options.
    2. I think host should be selected with concrete types, not string filtering. I currently don't have a big picture of how this would fit into API, but as we may need to set backend specific options, it should be type safe.

    I guess the final option is to not enforce this API-wise, and instead document the behavior?

    Agreed.

  6. mitchmindtree commented on Jun 6, 2019

    @mitchmindtree
    MemberAuthor

    WASAPI is a host, Shared and Exclusive is not. They're API options, and also stream options.

    Yes agreed, not sure what I was thinking here exactly in my OP.

    I think host should be selected with concrete types, not string filtering.

    Yes this sounds good to me!

  7. mitchmindtree commented on Jun 28, 2019

    @mitchmindtree
    MemberAuthor

    Closed by #289.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions