1#[doc(inline)]
8pub use self::platform_impl::*;
9
10#[cfg(feature = "custom")]
11pub use crate::host::custom::{Device as CustomDevice, Host as CustomHost, Stream as CustomStream};
12
13macro_rules! impl_platform_host {
39 ($($(#[cfg($feat: meta)])? $HostVariant:ident => $Host:ty),* $(,)?) => {
40 pub const ALL_HOSTS: &'static [HostId] = &[
42 $(
43 $(#[cfg($feat)])?
44 HostId::$HostVariant,
45 )*
46 ];
47
48 pub struct Host(HostInner);
58
59 #[derive(Clone)]
62 pub struct Device(DeviceInner);
63
64 pub struct Devices(DevicesInner);
67
68 #[must_use = "If the stream is not stored it will not play."]
71 pub struct Stream(StreamInner);
72
73 #[derive(Clone)]
76 pub struct SupportedInputConfigs(SupportedInputConfigsInner);
77
78 #[derive(Clone)]
81 pub struct SupportedOutputConfigs(SupportedOutputConfigsInner);
82
83 #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
130 pub enum HostId {
131 $(
132 $(#[cfg($feat)])?
133 $(#[cfg_attr(docsrs, doc(cfg($feat)))])?
134 $HostVariant,
135 )*
136 }
137
138 #[derive(Clone)]
140 pub enum DeviceInner {
141 $(
142 $(#[cfg($feat)])?
143 $HostVariant(<$Host as crate::traits::HostTrait>::Device),
144 )*
145 }
146
147 pub enum DevicesInner {
149 $(
150 $(#[cfg($feat)])?
151 $HostVariant(<$Host as crate::traits::HostTrait>::Devices),
152 )*
153 }
154
155 pub enum HostInner {
157 $(
158 $(#[cfg($feat)])?
159 $HostVariant($Host),
160 )*
161 }
162
163 pub enum StreamInner {
165 $(
166 $(#[cfg($feat)])?
167 $HostVariant(<<$Host as crate::traits::HostTrait>::Device as crate::traits::DeviceTrait>::Stream),
168 )*
169 }
170
171 #[derive(Clone)]
172 enum SupportedInputConfigsInner {
173 $(
174 $(#[cfg($feat)])?
175 $HostVariant(<<$Host as crate::traits::HostTrait>::Device as crate::traits::DeviceTrait>::SupportedInputConfigs),
176 )*
177 }
178
179 #[derive(Clone)]
180 enum SupportedOutputConfigsInner {
181 $(
182 $(#[cfg($feat)])?
183 $HostVariant(<<$Host as crate::traits::HostTrait>::Device as crate::traits::DeviceTrait>::SupportedOutputConfigs),
184 )*
185 }
186
187 impl HostId {
188 pub fn name(&self) -> &'static str {
189 match self {
190 $(
191 $(#[cfg($feat)])?
192 HostId::$HostVariant => stringify!($HostVariant),
193 )*
194 }
195 }
196 }
197
198 impl std::fmt::Display for HostId {
199 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
200 write!(f, "{}", self.name().to_lowercase())
201 }
202 }
203
204 impl std::str::FromStr for HostId {
205 type Err = crate::HostUnavailable;
206
207 fn from_str(s: &str) -> Result<Self, Self::Err> {
208 $(
209 $(#[cfg($feat)])?
210 if stringify!($HostVariant).eq_ignore_ascii_case(s) {
211 return Ok(HostId::$HostVariant);
212 }
213 )*
214 Err(crate::HostUnavailable)
215 }
216 }
217
218 impl Devices {
219 pub fn as_inner(&self) -> &DevicesInner {
222 &self.0
223 }
224
225 pub fn as_inner_mut(&mut self) -> &mut DevicesInner {
228 &mut self.0
229 }
230
231 pub fn into_inner(self) -> DevicesInner {
233 self.0
234 }
235 }
236
237 impl Device {
238 pub fn as_inner(&self) -> &DeviceInner {
241 &self.0
242 }
243
244 pub fn as_inner_mut(&mut self) -> &mut DeviceInner {
247 &mut self.0
248 }
249
250 pub fn into_inner(self) -> DeviceInner {
252 self.0
253 }
254 }
255
256 impl Host {
257 pub fn id(&self) -> HostId {
259 match self.0 {
260 $(
261 $(#[cfg($feat)])?
262 HostInner::$HostVariant(_) => HostId::$HostVariant,
263 )*
264 }
265 }
266
267 pub fn as_inner(&self) -> &HostInner {
270 &self.0
271 }
272
273 pub fn as_inner_mut(&mut self) -> &mut HostInner {
276 &mut self.0
277 }
278
279 pub fn into_inner(self) -> HostInner {
281 self.0
282 }
283 }
284
285 impl Stream {
286 pub fn as_inner(&self) -> &StreamInner {
289 &self.0
290 }
291
292 pub fn as_inner_mut(&mut self) -> &mut StreamInner {
295 &mut self.0
296 }
297
298 pub fn into_inner(self) -> StreamInner {
300 self.0
301 }
302 }
303
304 impl Iterator for Devices {
305 type Item = Device;
306
307 fn next(&mut self) -> Option<Self::Item> {
308 match self.0 {
309 $(
310 $(#[cfg($feat)])?
311 DevicesInner::$HostVariant(ref mut d) => {
312 d.next().map(DeviceInner::$HostVariant).map(Device::from)
313 }
314 )*
315 }
316 }
317
318 fn size_hint(&self) -> (usize, Option<usize>) {
319 match self.0 {
320 $(
321 $(#[cfg($feat)])?
322 DevicesInner::$HostVariant(ref d) => d.size_hint(),
323 )*
324 }
325 }
326 }
327
328 impl Iterator for SupportedInputConfigs {
329 type Item = crate::SupportedStreamConfigRange;
330
331 fn next(&mut self) -> Option<Self::Item> {
332 match self.0 {
333 $(
334 $(#[cfg($feat)])?
335 SupportedInputConfigsInner::$HostVariant(ref mut s) => s.next(),
336 )*
337 }
338 }
339
340 fn size_hint(&self) -> (usize, Option<usize>) {
341 match self.0 {
342 $(
343 $(#[cfg($feat)])?
344 SupportedInputConfigsInner::$HostVariant(ref d) => d.size_hint(),
345 )*
346 }
347 }
348 }
349
350 impl Iterator for SupportedOutputConfigs {
351 type Item = crate::SupportedStreamConfigRange;
352
353 fn next(&mut self) -> Option<Self::Item> {
354 match self.0 {
355 $(
356 $(#[cfg($feat)])?
357 SupportedOutputConfigsInner::$HostVariant(ref mut s) => s.next(),
358 )*
359 }
360 }
361
362 fn size_hint(&self) -> (usize, Option<usize>) {
363 match self.0 {
364 $(
365 $(#[cfg($feat)])?
366 SupportedOutputConfigsInner::$HostVariant(ref d) => d.size_hint(),
367 )*
368 }
369 }
370 }
371
372 impl crate::traits::DeviceTrait for Device {
373 type SupportedInputConfigs = SupportedInputConfigs;
374 type SupportedOutputConfigs = SupportedOutputConfigs;
375 type Stream = Stream;
376
377 #[allow(deprecated)]
378 fn name(&self) -> Result<String, crate::DeviceNameError> {
379 match self.0 {
380 $(
381 $(#[cfg($feat)])?
382 DeviceInner::$HostVariant(ref d) => d.name(),
383 )*
384 }
385 }
386
387 fn description(&self) -> Result<crate::DeviceDescription, crate::DeviceNameError> {
388 match self.0 {
389 $(
390 $(#[cfg($feat)])?
391 DeviceInner::$HostVariant(ref d) => d.description(),
392 )*
393 }
394 }
395
396 fn id(&self) -> Result<crate::DeviceId, crate::DeviceIdError> {
397 match self.0 {
398 $(
399 $(#[cfg($feat)])?
400 DeviceInner::$HostVariant(ref d) => d.id(),
401 )*
402 }
403 }
404
405 fn supports_input(&self) -> bool {
406 match self.0 {
407 $(
408 $(#[cfg($feat)])?
409 DeviceInner::$HostVariant(ref d) => d.supports_input(),
410 )*
411 }
412 }
413
414 fn supports_output(&self) -> bool {
415 match self.0 {
416 $(
417 $(#[cfg($feat)])?
418 DeviceInner::$HostVariant(ref d) => d.supports_output(),
419 )*
420 }
421 }
422
423 fn supported_input_configs(&self) -> Result<Self::SupportedInputConfigs, crate::SupportedStreamConfigsError> {
424 match self.0 {
425 $(
426 $(#[cfg($feat)])?
427 DeviceInner::$HostVariant(ref d) => {
428 d.supported_input_configs()
429 .map(SupportedInputConfigsInner::$HostVariant)
430 .map(SupportedInputConfigs)
431 }
432 )*
433 }
434 }
435
436 fn supported_output_configs(&self) -> Result<Self::SupportedOutputConfigs, crate::SupportedStreamConfigsError> {
437 match self.0 {
438 $(
439 $(#[cfg($feat)])?
440 DeviceInner::$HostVariant(ref d) => {
441 d.supported_output_configs()
442 .map(SupportedOutputConfigsInner::$HostVariant)
443 .map(SupportedOutputConfigs)
444 }
445 )*
446 }
447 }
448
449 fn default_input_config(&self) -> Result<crate::SupportedStreamConfig, crate::DefaultStreamConfigError> {
450 match self.0 {
451 $(
452 $(#[cfg($feat)])?
453 DeviceInner::$HostVariant(ref d) => d.default_input_config(),
454 )*
455 }
456 }
457
458 fn default_output_config(&self) -> Result<crate::SupportedStreamConfig, crate::DefaultStreamConfigError> {
459 match self.0 {
460 $(
461 $(#[cfg($feat)])?
462 DeviceInner::$HostVariant(ref d) => d.default_output_config(),
463 )*
464 }
465 }
466
467 fn build_input_stream_raw<D, E>(
468 &self,
469 config: &crate::StreamConfig,
470 sample_format: crate::SampleFormat,
471 data_callback: D,
472 error_callback: E,
473 timeout: Option<std::time::Duration>,
474 ) -> Result<Self::Stream, crate::BuildStreamError>
475 where
476 D: FnMut(&crate::Data, &crate::InputCallbackInfo) + Send + 'static,
477 E: FnMut(crate::StreamError) + Send + 'static,
478 {
479 match self.0 {
480 $(
481 $(#[cfg($feat)])?
482 DeviceInner::$HostVariant(ref d) => d
483 .build_input_stream_raw(
484 config,
485 sample_format,
486 data_callback,
487 error_callback,
488 timeout,
489 )
490 .map(StreamInner::$HostVariant)
491 .map(Stream::from),
492 )*
493 }
494 }
495
496 fn build_output_stream_raw<D, E>(
497 &self,
498 config: &crate::StreamConfig,
499 sample_format: crate::SampleFormat,
500 data_callback: D,
501 error_callback: E,
502 timeout: Option<std::time::Duration>,
503 ) -> Result<Self::Stream, crate::BuildStreamError>
504 where
505 D: FnMut(&mut crate::Data, &crate::OutputCallbackInfo) + Send + 'static,
506 E: FnMut(crate::StreamError) + Send + 'static,
507 {
508 match self.0 {
509 $(
510 $(#[cfg($feat)])?
511 DeviceInner::$HostVariant(ref d) => d
512 .build_output_stream_raw(
513 config,
514 sample_format,
515 data_callback,
516 error_callback,
517 timeout,
518 )
519 .map(StreamInner::$HostVariant)
520 .map(Stream::from),
521 )*
522 }
523 }
524 }
525
526 impl crate::traits::HostTrait for Host {
527 type Devices = Devices;
528 type Device = Device;
529
530 fn is_available() -> bool {
531 $(
532 $(#[cfg($feat)])?
533 if <$Host>::is_available() { return true; }
534 )*
535 false
536 }
537
538 fn devices(&self) -> Result<Self::Devices, crate::DevicesError> {
539 match self.0 {
540 $(
541 $(#[cfg($feat)])?
542 HostInner::$HostVariant(ref h) => {
543 h.devices().map(DevicesInner::$HostVariant).map(Devices::from)
544 }
545 )*
546 }
547 }
548
549 fn default_input_device(&self) -> Option<Self::Device> {
550 match self.0 {
551 $(
552 $(#[cfg($feat)])?
553 HostInner::$HostVariant(ref h) => {
554 h.default_input_device().map(DeviceInner::$HostVariant).map(Device::from)
555 }
556 )*
557 }
558 }
559
560 fn default_output_device(&self) -> Option<Self::Device> {
561 match self.0 {
562 $(
563 $(#[cfg($feat)])?
564 HostInner::$HostVariant(ref h) => {
565 h.default_output_device().map(DeviceInner::$HostVariant).map(Device::from)
566 }
567 )*
568 }
569 }
570 }
571
572 impl crate::traits::StreamTrait for Stream {
573 fn play(&self) -> Result<(), crate::PlayStreamError> {
574 match self.0 {
575 $(
576 $(#[cfg($feat)])?
577 StreamInner::$HostVariant(ref s) => {
578 s.play()
579 }
580 )*
581 }
582 }
583
584 fn pause(&self) -> Result<(), crate::PauseStreamError> {
585 match self.0 {
586 $(
587 $(#[cfg($feat)])?
588 StreamInner::$HostVariant(ref s) => {
589 s.pause()
590 }
591 )*
592 }
593 }
594 }
595
596 impl From<DeviceInner> for Device {
597 fn from(d: DeviceInner) -> Self {
598 Device(d)
599 }
600 }
601
602 impl From<DevicesInner> for Devices {
603 fn from(d: DevicesInner) -> Self {
604 Devices(d)
605 }
606 }
607
608 impl From<HostInner> for Host {
609 fn from(h: HostInner) -> Self {
610 Host(h)
611 }
612 }
613
614 impl From<StreamInner> for Stream {
615 fn from(s: StreamInner) -> Self {
616 Stream(s)
617 }
618 }
619
620 $(
621 $(#[cfg($feat)])?
622 impl From<<$Host as crate::traits::HostTrait>::Device> for Device {
623 fn from(h: <$Host as crate::traits::HostTrait>::Device) -> Self {
624 DeviceInner::$HostVariant(h).into()
625 }
626 }
627
628 $(#[cfg($feat)])?
629 impl From<<$Host as crate::traits::HostTrait>::Devices> for Devices {
630 fn from(h: <$Host as crate::traits::HostTrait>::Devices) -> Self {
631 DevicesInner::$HostVariant(h).into()
632 }
633 }
634
635 $(#[cfg($feat)])?
636 impl From<$Host> for Host {
637 fn from(h: $Host) -> Self {
638 HostInner::$HostVariant(h).into()
639 }
640 }
641
642 $(#[cfg($feat)])?
643 impl From<<<$Host as crate::traits::HostTrait>::Device as crate::traits::DeviceTrait>::Stream> for Stream {
644 fn from(h: <<$Host as crate::traits::HostTrait>::Device as crate::traits::DeviceTrait>::Stream) -> Self {
645 StreamInner::$HostVariant(h).into()
646 }
647 }
648 )*
649
650 pub fn available_hosts() -> Vec<HostId> {
652 let mut host_ids = vec![];
653 $(
654 $(#[cfg($feat)])?
655 if <$Host as crate::traits::HostTrait>::is_available() {
656 host_ids.push(HostId::$HostVariant);
657 }
658 )*
659 host_ids
660 }
661
662 pub fn host_from_id(id: HostId) -> Result<Host, crate::HostUnavailable> {
664 match id {
665 $(
666 $(#[cfg($feat)])?
667 HostId::$HostVariant => {
668 <$Host>::new()
669 .map(HostInner::$HostVariant)
670 .map(Host::from)
671 }
672 )*
673 }
674 }
675
676 impl Default for Host {
677 fn default() -> Host {
678 default_host()
679 }
680 }
681 };
682}
683
684#[cfg(any(
686 target_os = "linux",
687 target_os = "dragonfly",
688 target_os = "freebsd",
689 target_os = "netbsd"
690))]
691mod platform_impl {
692 #[cfg_attr(
693 docsrs,
694 doc(cfg(any(
695 target_os = "linux",
696 target_os = "dragonfly",
697 target_os = "freebsd",
698 target_os = "netbsd"
699 )))
700 )]
701 pub use crate::host::alsa::Host as AlsaHost;
702 #[cfg(feature = "jack")]
703 #[cfg_attr(
704 docsrs,
705 doc(cfg(all(
706 any(
707 target_os = "linux",
708 target_os = "dragonfly",
709 target_os = "freebsd",
710 target_os = "netbsd"
711 ),
712 feature = "jack"
713 )))
714 )]
715 pub use crate::host::jack::Host as JackHost;
716
717 impl_platform_host!(
718 #[cfg(feature = "jack")] Jack => JackHost,
719 Alsa => AlsaHost,
720 #[cfg(feature = "custom")] Custom => super::CustomHost
721 );
722
723 pub fn default_host() -> Host {
725 AlsaHost::new()
726 .expect("the default host should always be available")
727 .into()
728 }
729}
730
731#[cfg(any(target_os = "macos", target_os = "ios"))]
732mod platform_impl {
733 #[cfg_attr(docsrs, doc(cfg(any(target_os = "macos", target_os = "ios"))))]
734 pub use crate::host::coreaudio::Host as CoreAudioHost;
735 #[cfg(all(feature = "jack", target_os = "macos"))]
736 #[cfg_attr(docsrs, doc(cfg(all(feature = "jack", target_os = "macos"))))]
737 pub use crate::host::jack::Host as JackHost;
738
739 impl_platform_host!(
740 CoreAudio => CoreAudioHost,
741 #[cfg(all(feature = "jack", target_os = "macos"))] Jack => JackHost,
742 #[cfg(feature = "custom")] Custom => super::CustomHost
743 );
744
745 pub fn default_host() -> Host {
747 CoreAudioHost::new()
748 .expect("the default host should always be available")
749 .into()
750 }
751}
752
753#[cfg(target_os = "emscripten")]
754mod platform_impl {
755 #[cfg_attr(docsrs, doc(cfg(target_os = "emscripten")))]
756 pub use crate::host::emscripten::Host as EmscriptenHost;
757 impl_platform_host!(
758 Emscripten => EmscriptenHost,
759 #[cfg(feature = "custom")] Custom => super::CustomHost
760 );
761
762 pub fn default_host() -> Host {
764 EmscriptenHost::new()
765 .expect("the default host should always be available")
766 .into()
767 }
768}
769
770#[cfg(all(target_arch = "wasm32", feature = "wasm-bindgen"))]
771mod platform_impl {
772 #[cfg_attr(
773 docsrs,
774 doc(cfg(all(target_arch = "wasm32", feature = "wasm-bindgen")))
775 )]
776 pub use crate::host::webaudio::Host as WebAudioHost;
777
778 #[cfg(feature = "audioworklet")]
779 #[cfg_attr(
780 docsrs,
781 doc(cfg(all(
782 target_arch = "wasm32",
783 feature = "wasm-bindgen",
784 feature = "audioworklet"
785 )))
786 )]
787 pub use crate::host::audioworklet::Host as AudioWorkletHost;
788
789 impl_platform_host!(
790 WebAudio => WebAudioHost,
791 #[cfg(feature = "audioworklet")] AudioWorklet => AudioWorkletHost,
792 #[cfg(feature = "custom")] Custom => super::CustomHost
793 );
794
795 pub fn default_host() -> Host {
797 WebAudioHost::new()
798 .expect("the default host should always be available")
799 .into()
800 }
801}
802
803#[cfg(windows)]
804mod platform_impl {
805 #[cfg(feature = "asio")]
806 #[cfg_attr(docsrs, doc(cfg(all(windows, feature = "asio"))))]
807 pub use crate::host::asio::Host as AsioHost;
808 #[cfg(feature = "jack")]
809 #[cfg_attr(docsrs, doc(cfg(all(windows, feature = "jack"))))]
810 pub use crate::host::jack::Host as JackHost;
811 #[cfg_attr(docsrs, doc(cfg(windows)))]
812 pub use crate::host::wasapi::Host as WasapiHost;
813
814 impl_platform_host!(
815 #[cfg(feature = "asio")] Asio => AsioHost,
816 Wasapi => WasapiHost,
817 #[cfg(feature = "jack")] Jack => JackHost,
818 #[cfg(feature = "custom")] Custom => super::CustomHost,
819 );
820
821 pub fn default_host() -> Host {
823 WasapiHost::new()
824 .expect("the default host should always be available")
825 .into()
826 }
827}
828
829#[cfg(target_os = "android")]
830mod platform_impl {
831 #[cfg_attr(docsrs, doc(cfg(target_os = "android")))]
832 pub use crate::host::aaudio::Host as AAudioHost;
833 impl_platform_host!(
834 AAudio => AAudioHost,
835 #[cfg(feature = "custom")] Custom => super::CustomHost
836 );
837
838 pub fn default_host() -> Host {
840 AAudioHost::new()
841 .expect("the default host should always be available")
842 .into()
843 }
844}
845
846#[cfg(not(any(
847 windows,
848 target_os = "linux",
849 target_os = "dragonfly",
850 target_os = "freebsd",
851 target_os = "netbsd",
852 target_os = "macos",
853 target_os = "ios",
854 target_os = "emscripten",
855 target_os = "android",
856 all(target_arch = "wasm32", feature = "wasm-bindgen"),
857)))]
858mod platform_impl {
859 #[cfg_attr(
860 docsrs,
861 doc(cfg(not(any(
862 windows,
863 target_os = "linux",
864 target_os = "dragonfly",
865 target_os = "freebsd",
866 target_os = "netbsd",
867 target_os = "macos",
868 target_os = "ios",
869 target_os = "emscripten",
870 target_os = "android",
871 all(target_arch = "wasm32", feature = "wasm-bindgen")
872 ))))
873 )]
874 pub use crate::host::null::Host as NullHost;
875
876 impl_platform_host!(
877 Null => NullHost,
878 #[cfg(feature = "custom")] Custom => super::CustomHost,
879 );
880
881 pub fn default_host() -> Host {
883 NullHost::new()
884 .expect("the default host should always be available")
885 .into()
886 }
887}