[FIX] Callback hell of AudioDevice construction while opening audio settings window.

This commit is contained in:
Sheldon Knuth
2019-07-23 09:54:41 +00:00
committed by Joshua Barretto
parent 0091419ace
commit c2fa8bd615
3 changed files with 46 additions and 59 deletions

View File

@ -230,13 +230,18 @@ impl Jukebox {
} }
} }
pub struct AudioDevice { struct MonoEmitter {
device: Device, device: Device,
devices: Vec<Device>, stream: Sink,
} }
impl AudioDevice { // struct StereoEmitter {
pub(crate) fn new(settings: &AudioSettings) -> Self { // device: Device,
// stream: SpatialSink,
// }
impl MonoEmitter {
fn new(settings: &AudioSettings) -> Self {
let device = match &settings.audio_device { let device = match &settings.audio_device {
Some(dev) => rodio::output_devices() Some(dev) => rodio::output_devices()
.find(|x| &x.name() == dev) .find(|x| &x.name() == dev)
@ -244,46 +249,7 @@ impl AudioDevice {
.expect("No Audio devices found!"), .expect("No Audio devices found!"),
None => rodio::default_output_device().expect("No Audio devices found!"), None => rodio::default_output_device().expect("No Audio devices found!"),
}; };
let sink = Sink::new(&device);
Self {
device,
devices: list_devices_raw(),
}
}
/// Returns a vec of the audio devices available.
/// Does not return rodio Device struct in case our audio backend changes.
pub(crate) fn list_devices(&self) -> Vec<String> {
self.devices.iter().map(|x| x.name()).collect()
}
/// Caches vec of devices for later reference
// pub(crate) fn update_devices(&mut self) {
// self.devices = list_devices_raw()
// }
/// Returns the name of the current audio device.
/// Does not return rodio Device struct in case our audio backend changes.
pub(crate) fn get_device(&self) -> String {
self.device.name()
}
}
struct MonoEmitter {
device: AudioDevice,
stream: Sink,
}
// struct StereoEmitter {
// device: AudioDevice,
// stream: SpatialSink,
// }
impl MonoEmitter {
fn new(settings: &AudioSettings) -> Self {
let device = AudioDevice::new(settings);
let sink = Sink::new(&device.device);
sink.set_volume(settings.music_volume); sink.set_volume(settings.music_volume);
Self { Self {
@ -292,6 +258,12 @@ impl MonoEmitter {
} }
} }
// /// Returns the name of the current audio device.
// /// Does not return rodio Device struct in case our audio backend changes.
// fn get_device(&self) -> String {
// self.device.name()
// }
fn play_from(&mut self, path: &str) { fn play_from(&mut self, path: &str) {
let bufreader = load_from_path(path).unwrap(); let bufreader = load_from_path(path).unwrap();
let src = Decoder::new(bufreader).unwrap(); let src = Decoder::new(bufreader).unwrap();
@ -309,16 +281,21 @@ impl AudioConfig for MonoEmitter {
/// If the string is an invalid audio device, then no change is made. /// If the string is an invalid audio device, then no change is made.
fn set_device(&mut self, name: String) { fn set_device(&mut self, name: String) {
if let Some(dev) = rodio::output_devices().find(|x| x.name() == name) { if let Some(dev) = rodio::output_devices().find(|x| x.name() == name) {
self.device.device = dev; self.device = dev;
self.stream = Sink::new(&self.device.device); self.stream = Sink::new(&self.device);
} }
} }
} }
// impl StereoEmitter { // impl StereoEmitter {
// fn new(settings: &AudioSettings) -> Self { // fn new(settings: &AudioSettings) -> Self {
// let device = AudioDevice::new(settings); // let device = match &settings.audio_device {
// Some(dev) => rodio::output_devices()
// .find(|x| &x.name() == dev)
// .or_else(rodio::default_output_device)
// .expect("No Audio devices found!"),
// None => rodio::default_output_device().expect("No Audio devices found!"),
// };
// let sink = SpatialSink::new( // let sink = SpatialSink::new(
// &device.device, // &device.device,
// [0.0, 0.0, 0.0], // [0.0, 0.0, 0.0],
@ -350,9 +327,9 @@ impl AudioConfig for MonoEmitter {
// /// If the string is an invalid audio device, then no change is made. // /// If the string is an invalid audio device, then no change is made.
// fn set_device(&mut self, name: String) { // fn set_device(&mut self, name: String) {
// if let Some(dev) = rodio::output_devices().find(|x| x.name() == name) { // if let Some(dev) = rodio::output_devices().find(|x| x.name() == name) {
// self.device.device = dev; // self.device = dev;
// self.stream = SpatialSink::new( // self.stream = SpatialSink::new(
// &self.device.device, // &self.device,
// [0.0, 0.0, 0.0], // [0.0, 0.0, 0.0],
// [1.0, 0.0, 0.0], // [1.0, 0.0, 0.0],
// [-1.0, 0.0, 0.0], // [-1.0, 0.0, 0.0],
@ -419,9 +396,10 @@ pub(crate) fn select_random_music(genre: &Genre) -> String {
soundtracks[index].clone() soundtracks[index].clone()
} }
fn send_msg(tx: &mut Sender<AudioPlayerMsg>, msg: AudioPlayerMsg) { /// Returns a vec of the audio devices available.
tx.send(msg) /// Does not return rodio Device struct in case our audio backend changes.
.expect("Failed on attempting to send a message into audio channel."); pub(crate) fn list_devices() -> Vec<String> {
list_devices_raw().iter().map(|x| x.name()).collect()
} }
/// Returns vec of devices /// Returns vec of devices
@ -429,6 +407,11 @@ fn list_devices_raw() -> Vec<Device> {
rodio::output_devices().collect() rodio::output_devices().collect()
} }
fn send_msg(tx: &mut Sender<AudioPlayerMsg>, msg: AudioPlayerMsg) {
tx.send(msg)
.expect("Failed on attempting to send a message into audio channel.");
}
#[test] #[test]
fn test_load_soundtracks() { fn test_load_soundtracks() {
use crate::audio::base::{load_soundtracks, Genre}; use crate::audio::base::{load_soundtracks, Genre};

View File

@ -3,12 +3,16 @@ use base::{Genre, Jukebox};
pub struct AudioFrontend { pub struct AudioFrontend {
pub(crate) model: Jukebox, pub(crate) model: Jukebox,
pub(crate) default_device: String,
pub(crate) device_list: Vec<String>,
} }
impl AudioFrontend { impl AudioFrontend {
pub(crate) fn new() -> Self { pub(crate) fn new() -> Self {
Self { Self {
model: Jukebox::new(Genre::Bgm), model: Jukebox::new(Genre::Bgm),
default_device: base::get_default_device(),
device_list: base::list_devices(),
} }
} }
@ -30,6 +34,8 @@ impl AudioFrontend {
pub(crate) fn no_audio() -> Self { pub(crate) fn no_audio() -> Self {
Self { Self {
model: Jukebox::new(Genre::None), model: Jukebox::new(Genre::None),
default_device: "None".to_owned(),
device_list: Vec::new(),
} }
} }
} }

View File

@ -1,7 +1,6 @@
use super::{img_ids::Imgs, CrosshairType, Fonts, Show, TEXT_COLOR}; use super::{img_ids::Imgs, CrosshairType, Fonts, Show, TEXT_COLOR};
use crate::{ use crate::{
audio::base::{AudioDevice, Genre}, audio::base::Genre,
settings::AudioSettings,
ui::{ImageSlider, ToggleButton}, ui::{ImageSlider, ToggleButton},
GlobalState, GlobalState,
}; };
@ -906,9 +905,8 @@ impl<'a> Widget for SettingsWindow<'a> {
// Audio Device Selector -------------------------------------------- // Audio Device Selector --------------------------------------------
match self.global_state.audio.model.get_genre() { match self.global_state.audio.model.get_genre() {
Genre::Bgm => { Genre::Bgm => {
let init = AudioDevice::new(&AudioSettings::default()); let device = &self.global_state.audio.default_device;
let device = init.get_device(); let device_list = &self.global_state.audio.device_list;
let device_list = init.list_devices();
Text::new("Volume") Text::new("Volume")
.down_from(state.ids.audio_volume_slider, 10.0) .down_from(state.ids.audio_volume_slider, 10.0)
.font_size(14) .font_size(14)
@ -917,7 +915,7 @@ impl<'a> Widget for SettingsWindow<'a> {
.set(state.ids.audio_device_text, ui); .set(state.ids.audio_device_text, ui);
// Get which device is currently selected // Get which device is currently selected
let selected = device_list.iter().position(|x| x.contains(&device)); let selected = device_list.iter().position(|x| x.contains(device));
if let Some(clicked) = DropDownList::new(&device_list, selected) if let Some(clicked) = DropDownList::new(&device_list, selected)
.w_h(400.0, 22.0) .w_h(400.0, 22.0)