desktop: Move cpal audio backend to frontend-utils
This commit is contained in:
parent
ac3f8991ea
commit
0f2b66a808
|
@ -4397,6 +4397,8 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"async-channel",
|
||||
"async-io",
|
||||
"bytemuck",
|
||||
"cpal",
|
||||
"futures-lite",
|
||||
"macro_rules_attribute",
|
||||
"reqwest",
|
||||
|
|
|
@ -52,6 +52,7 @@ naga = { version = "22.1.0", features = ["wgsl-out"] }
|
|||
wgpu = "22.1.0"
|
||||
egui = { git = "https://github.com/emilk/egui.git", rev = "f4697bc007447c6c2674beb4e25f599fb7afa093" }
|
||||
clap = { version = "4.5.17", features = ["derive"] }
|
||||
cpal = "0.15.3"
|
||||
anyhow = "1.0"
|
||||
slotmap = "1.0.7"
|
||||
async-channel = "2.3.1"
|
||||
|
|
|
@ -12,7 +12,7 @@ workspace = true
|
|||
|
||||
[dependencies]
|
||||
clap = { workspace = true }
|
||||
cpal = "0.15.3"
|
||||
cpal = { workspace = true }
|
||||
egui = { workspace = true }
|
||||
egui_extras = { git = "https://github.com/emilk/egui.git", rev = "f4697bc007447c6c2674beb4e25f599fb7afa093", default-features = false, features = ["image"] }
|
||||
egui-wgpu = { git = "https://github.com/emilk/egui.git", rev = "f4697bc007447c6c2674beb4e25f599fb7afa093", features = ["winit"] }
|
||||
|
@ -24,7 +24,7 @@ ruffle_render = { path = "../render", features = ["clap"] }
|
|||
ruffle_render_wgpu = { path = "../render/wgpu", features = ["clap"] }
|
||||
ruffle_video_software = { path = "../video/software", optional = true }
|
||||
ruffle_video_external = { path = "../video/external", optional = true }
|
||||
ruffle_frontend_utils = { path = "../frontend-utils" }
|
||||
ruffle_frontend_utils = { path = "../frontend-utils", features = ["cpal"] }
|
||||
tracing = { workspace = true }
|
||||
tracing-subscriber = { workspace = true }
|
||||
tracing-appender = "0.2.3"
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
mod audio;
|
||||
mod external_interface;
|
||||
mod fscommand;
|
||||
mod navigator;
|
||||
mod ui;
|
||||
|
||||
pub use audio::CpalAudioBackend;
|
||||
pub use external_interface::DesktopExternalInterfaceProvider;
|
||||
pub use fscommand::DesktopFSCommandProvider;
|
||||
pub use navigator::DesktopNavigatorInterface;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::backends::{
|
||||
CpalAudioBackend, DesktopExternalInterfaceProvider, DesktopFSCommandProvider,
|
||||
DesktopNavigatorInterface, DesktopUiBackend,
|
||||
DesktopExternalInterfaceProvider, DesktopFSCommandProvider, DesktopNavigatorInterface,
|
||||
DesktopUiBackend,
|
||||
};
|
||||
use crate::custom_event::RuffleEvent;
|
||||
use crate::gui::{FilePicker, MovieView};
|
||||
|
@ -11,6 +11,7 @@ use ruffle_core::backend::navigator::{OpenURLMode, SocketMode};
|
|||
use ruffle_core::config::Letterbox;
|
||||
use ruffle_core::events::{GamepadButton, KeyCode};
|
||||
use ruffle_core::{DefaultFont, LoadBehavior, Player, PlayerBuilder, PlayerEvent};
|
||||
use ruffle_frontend_utils::backends::audio::CpalAudioBackend;
|
||||
use ruffle_frontend_utils::backends::executor::{AsyncExecutor, PollRequester};
|
||||
use ruffle_frontend_utils::backends::navigator::ExternalNavigatorBackend;
|
||||
use ruffle_frontend_utils::bundle::source::BundleSourceError;
|
||||
|
@ -134,7 +135,7 @@ impl ActivePlayer {
|
|||
) -> Self {
|
||||
let mut builder = PlayerBuilder::new();
|
||||
|
||||
match CpalAudioBackend::new(&preferences) {
|
||||
match CpalAudioBackend::new(preferences.output_device_name().as_deref()) {
|
||||
Ok(audio) => {
|
||||
builder = builder.with_audio(audio);
|
||||
}
|
||||
|
|
|
@ -10,6 +10,9 @@ version.workspace = true
|
|||
[lints]
|
||||
workspace = true
|
||||
|
||||
[features]
|
||||
cpal = ["dep:cpal", "dep:bytemuck"]
|
||||
|
||||
[dependencies]
|
||||
toml_edit = { version = "0.22.20", features = ["parse"] }
|
||||
url = { workspace = true }
|
||||
|
@ -23,8 +26,16 @@ async-channel = { workspace = true }
|
|||
slotmap = { workspace = true }
|
||||
async-io = "2.3.4"
|
||||
futures-lite = "2.3.0"
|
||||
reqwest = { version = "0.12.7", default-features = false, features = ["rustls-tls", "cookies", "charset", "http2", "macos-system-configuration"] }
|
||||
reqwest = { version = "0.12.7", default-features = false, features = [
|
||||
"rustls-tls",
|
||||
"cookies",
|
||||
"charset",
|
||||
"http2",
|
||||
"macos-system-configuration",
|
||||
] }
|
||||
tokio = { workspace = true, features = ["net"] }
|
||||
cpal = { workspace = true, optional = true }
|
||||
bytemuck = { workspace = true, optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3"
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#[cfg(feature = "cpal")]
|
||||
pub mod audio;
|
||||
pub mod executor;
|
||||
pub mod navigator;
|
||||
pub mod storage;
|
||||
|
|
|
@ -1,12 +1,29 @@
|
|||
use crate::preferences::GlobalPreferences;
|
||||
use anyhow::{anyhow, Context, Error};
|
||||
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
|
||||
use cpal::SampleFormat;
|
||||
use ruffle_core::backend::audio::{
|
||||
swf, AudioBackend, AudioMixer, DecodeError, RegisterError, SoundHandle, SoundInstanceHandle,
|
||||
SoundStreamInfo, SoundTransform,
|
||||
};
|
||||
use ruffle_core::impl_audio_mixer_backend;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum CpalError {
|
||||
#[error("No audio devices available")]
|
||||
NoDevices,
|
||||
|
||||
#[error("Failed to get default output config")]
|
||||
DefaultStream(#[from] cpal::DefaultStreamConfigError),
|
||||
|
||||
#[error("Unsupported sample format {0:?}")]
|
||||
UnsupportedSampleFormat(SampleFormat),
|
||||
|
||||
#[error("Couldn't play the audio stream")]
|
||||
Play(#[from] cpal::PlayStreamError),
|
||||
|
||||
#[error("Failed to construct audio stream")]
|
||||
Build(#[from] cpal::BuildStreamError),
|
||||
}
|
||||
|
||||
pub struct CpalAudioBackend {
|
||||
#[allow(dead_code)]
|
||||
device: cpal::Device,
|
||||
|
@ -17,16 +34,16 @@ pub struct CpalAudioBackend {
|
|||
}
|
||||
|
||||
impl CpalAudioBackend {
|
||||
pub fn new(preferences: &GlobalPreferences) -> Result<Self, Error> {
|
||||
pub fn new(preferred_device_name: Option<&str>) -> Result<Self, CpalError> {
|
||||
// Create CPAL audio device.
|
||||
let host = cpal::default_host();
|
||||
let device = get_suitable_output_device(preferences, &host)
|
||||
.ok_or_else(|| anyhow!("No audio devices available"))?;
|
||||
let device =
|
||||
get_suitable_output_device(preferred_device_name, &host).ok_or(CpalError::NoDevices)?;
|
||||
|
||||
// Create audio stream for device.
|
||||
let config = device
|
||||
.default_output_config()
|
||||
.context("Failed to get default output config")?;
|
||||
.map_err(CpalError::DefaultStream)?;
|
||||
let sample_format = config.sample_format();
|
||||
let config = cpal::StreamConfig::from(config);
|
||||
let mixer = AudioMixer::new(config.channels as u8, config.sample_rate.0);
|
||||
|
@ -63,11 +80,11 @@ impl CpalAudioBackend {
|
|||
error_handler,
|
||||
None,
|
||||
),
|
||||
_ => anyhow::bail!("Unsupported sample format {sample_format:?}"),
|
||||
_ => return Err(CpalError::UnsupportedSampleFormat(sample_format)),
|
||||
}?
|
||||
};
|
||||
|
||||
stream.play().context("Couldn't play the audio stream")?;
|
||||
stream.play().map_err(CpalError::Play)?;
|
||||
|
||||
Ok(Self {
|
||||
device,
|
||||
|
@ -91,14 +108,14 @@ impl AudioBackend for CpalAudioBackend {
|
|||
}
|
||||
|
||||
fn get_suitable_output_device(
|
||||
preferences: &GlobalPreferences,
|
||||
preferred_device_name: Option<&str>,
|
||||
host: &cpal::Host,
|
||||
) -> Option<cpal::Device> {
|
||||
// First let's check for any user preference...
|
||||
if let Some(preferred_device_name) = preferences.output_device_name() {
|
||||
if let Some(preferred_device_name) = preferred_device_name {
|
||||
if let Ok(mut devices) = host.output_devices() {
|
||||
if let Some(device) =
|
||||
devices.find(|device| device.name().ok().as_deref() == Some(&preferred_device_name))
|
||||
devices.find(|device| device.name().ok().as_deref() == Some(preferred_device_name))
|
||||
{
|
||||
return Some(device);
|
||||
}
|
Loading…
Reference in New Issue