fmod/core/system/
device_selection.rs

1// Copyright (c) 2024 Melody Madeline Lyons
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at https://mozilla.org/MPL/2.0/.
6
7use fmod_sys::*;
8use lanyard::Utf8CString;
9use std::{ffi::c_int, mem::MaybeUninit};
10
11use crate::{FmodResultExt, Result};
12use crate::{Guid, OutputType, SpeakerMode, System, get_string};
13
14#[cfg(doc)]
15use crate::SystemBuilder;
16
17impl System {
18    #[allow(clippy::doc_markdown)]
19    /// Sets the type of output interface used to run the mixer.
20    ///
21    /// This function is typically used to select between different OS specific audio APIs which may have different features.
22    ///
23    /// It is only necessary to call this function if you want to specifically switch away from the default output mode for the operating system.
24    /// The most optimal mode is selected by default for the operating system.
25    ///
26    /// (Windows, UWP, GameCore, Android, MacOS, iOS, Linux Only) This function can be called from outside the builder.
27    ///
28    /// When using the Studio API, switching to an NRT (non-realtime) output type after FMOD is already initialized
29    /// will not behave correctly unless the Studio API was initialized with [`crate::studio::InitFlags::SYNCHRONOUS_UPDATE`].
30    pub fn set_output(&self, output_type: OutputType) -> Result<()> {
31        unsafe { FMOD_System_SetOutput(self.inner.as_ptr(), output_type.into()).to_result() }
32    }
33
34    /// Retrieves the type of output interface used to run the mixer.
35    pub fn get_output_type(&self) -> Result<OutputType> {
36        let mut output_type = 0;
37        unsafe {
38            FMOD_System_GetOutput(self.inner.as_ptr(), &raw mut output_type).to_result()?;
39        }
40        let output_type = output_type.try_into()?;
41        Ok(output_type)
42    }
43
44    /// Retrieves the number of output drivers available for the selected output type.
45    ///
46    /// If [`SystemBuilder::output`]/[`System::set_output`] has not been called,
47    /// this function will return the number of drivers available for the default output type.
48    /// A possible use for this function is to iterate through available sound devices for the current output type,
49    /// and use [`System::get_driver_info`] to get the device's name and other attributes.
50    pub fn get_driver_count(&self) -> Result<c_int> {
51        let mut count = 0;
52        unsafe {
53            FMOD_System_GetNumDrivers(self.inner.as_ptr(), &raw mut count).to_result()?;
54        }
55        Ok(count)
56    }
57
58    /// Retrieves identification information about a sound device specified by its index, and specific to the selected output mode.
59    pub fn get_driver_info(
60        &self,
61        id: c_int,
62    ) -> Result<(Utf8CString, Guid, c_int, SpeakerMode, c_int)> {
63        unsafe {
64            let mut guid = MaybeUninit::zeroed();
65            let mut system_rate = 0;
66            let mut speaker_mode = 0;
67            let mut speaker_mode_channels = 0;
68
69            let name = get_string(|name| {
70                FMOD_System_GetDriverInfo(
71                    self.inner.as_ptr(),
72                    id,
73                    name.as_mut_ptr().cast(),
74                    name.len() as c_int,
75                    guid.as_mut_ptr(),
76                    &raw mut system_rate,
77                    &raw mut speaker_mode,
78                    &raw mut speaker_mode_channels,
79                )
80            })?;
81
82            let guid = guid.assume_init().into();
83            let speaker_mode = speaker_mode.try_into()?;
84
85            Ok((name, guid, system_rate, speaker_mode, speaker_mode_channels))
86        }
87    }
88
89    /// Sets the output driver for the selected output type.
90    ///
91    /// When an output type has more than one driver available, this function can be used to select between them.
92    ///
93    /// When this function is called, the current driver will be shutdown and the newly selected driver will be initialized / started.
94    pub fn set_driver(&self, driver: c_int) -> Result<()> {
95        unsafe { FMOD_System_SetDriver(self.inner.as_ptr(), driver).to_result() }
96    }
97
98    /// Retrieves the output driver for the selected output type.
99    pub fn get_driver(&self) -> Result<c_int> {
100        let mut driver = 0;
101        unsafe {
102            FMOD_System_GetDriver(self.inner.as_ptr(), &raw mut driver).to_result()?;
103        }
104        Ok(driver)
105    }
106}