9898//! # Ok(())
9999//! # }
100100//! ```
101+ //!
102+ //! # Storing & Loading Output
103+ //!
104+ //! ```no_run
105+ //! use cpal::DeviceId;
106+ //! # fn main() -> Result<(), Box<dyn std::error::Error>> {
107+ //! // load
108+ //! let device_id = DeviceId::from_str("Some stored input")?;
109+ //! let output = AvailableOutput::try_from(device_id)?;
110+ //!
111+ //! // store
112+ //! let device_id = output.device_id()?;
113+ //! let device_id = device_id.to_string();
114+ //! # }
115+ //! ```
101116
102117use core:: fmt;
103-
104118use cpal:: traits:: { DeviceTrait , HostTrait } ;
119+ use cpal:: DeviceId ;
105120
106121use crate :: common:: assert_error_traits;
107122
@@ -117,14 +132,46 @@ pub use config::{BufferSize, OutputConfig};
117132pub struct ListError ( #[ source] cpal:: DevicesError ) ;
118133assert_error_traits ! { ListError }
119134
135+ #[ derive( Debug , thiserror:: Error ) ]
136+ pub enum NotAvailable {
137+ #[ error(
138+ "The OS audio API the saved output used ({expected}) while supported on this system is not available."
139+ ) ]
140+ Host { expected : String } ,
141+ #[ error( "There is not device with id: {device_id} available on this system." ) ]
142+ NoDevice { device_id : DeviceId } ,
143+ }
144+
145+ impl TryFrom < DeviceId > for AvailableOutput {
146+ type Error = NotAvailable ;
147+
148+ fn try_from ( device_id : DeviceId ) -> Result < Self , NotAvailable > {
149+ let host_id = device_id. 0 ;
150+ let host = cpal:: platform:: host_from_id ( host_id) . map_err ( |_| NotAvailable :: Host {
151+ expected : host_id. to_string ( ) ,
152+ } ) ?;
153+ let device = host
154+ . device_by_id ( & device_id)
155+ . ok_or_else ( || NotAvailable :: NoDevice {
156+ device_id : device_id. clone ( ) ,
157+ } ) ?;
158+ let default_id = host. default_output_device ( ) . map ( |d| d. id ( ) ) ;
159+
160+ Ok ( Self {
161+ inner : device,
162+ default : default_id. is_some_and ( |id| id. is_ok_and ( |id| id == device_id) ) ,
163+ } )
164+ }
165+ }
166+
120167/// An output device
121168#[ derive( Clone ) ]
122- pub struct Output {
169+ pub struct AvailableOutput {
123170 inner : cpal:: Device ,
124171 default : bool ,
125172}
126173
127- impl Output {
174+ impl AvailableOutput {
128175 /// Whether this output is the default sound output for the OS
129176 pub fn is_default ( & self ) -> bool {
130177 self . default
@@ -133,9 +180,13 @@ impl Output {
133180 pub ( crate ) fn into_inner ( self ) -> cpal:: Device {
134181 self . inner
135182 }
183+
184+ pub fn device_id ( & self ) -> Result < DeviceId , cpal:: DeviceIdError > {
185+ self . inner . id ( )
186+ }
136187}
137188
138- impl fmt:: Debug for Output {
189+ impl fmt:: Debug for AvailableOutput {
139190 fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
140191 f. debug_struct ( "Device" )
141192 . field (
@@ -149,7 +200,7 @@ impl fmt::Debug for Output {
149200 }
150201}
151202
152- impl fmt:: Display for Output {
203+ impl fmt:: Display for AvailableOutput {
153204 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
154205 write ! (
155206 f,
@@ -162,12 +213,15 @@ impl fmt::Display for Output {
162213}
163214
164215/// Returns a list of available output devices on the system.
165- pub fn available_outputs ( ) -> Result < Vec < Output > , ListError > {
216+ pub fn available_outputs ( ) -> Result < Vec < AvailableOutput > , ListError > {
166217 let host = cpal:: default_host ( ) ;
167218 let default = host. default_output_device ( ) . map ( |d| d. id ( ) ) ;
168- let devices = host. output_devices ( ) . map_err ( ListError ) ?. map ( |dev| Output {
169- default : Some ( dev. id ( ) ) == default,
170- inner : dev,
171- } ) ;
219+ let devices = host
220+ . output_devices ( )
221+ . map_err ( ListError ) ?
222+ . map ( |dev| AvailableOutput {
223+ default : Some ( dev. id ( ) ) == default,
224+ inner : dev,
225+ } ) ;
172226 Ok ( devices. collect ( ) )
173227}
0 commit comments