portaudio.rs 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. use super::{Open, Sink};
  2. use portaudio_rs;
  3. use portaudio_rs::device::{get_default_output_index, DeviceIndex, DeviceInfo};
  4. use portaudio_rs::stream::*;
  5. use std::io;
  6. use std::process::exit;
  7. use std::time::Duration;
  8. pub struct PortAudioSink<'a>(
  9. Option<portaudio_rs::stream::Stream<'a, i16, i16>>,
  10. StreamParameters<i16>,
  11. );
  12. fn output_devices() -> Box<dyn Iterator<Item = (DeviceIndex, DeviceInfo)>> {
  13. let count = portaudio_rs::device::get_count().unwrap();
  14. let devices = (0..count)
  15. .filter_map(|idx| portaudio_rs::device::get_info(idx).map(|info| (idx, info)))
  16. .filter(|&(_, ref info)| info.max_output_channels > 0);
  17. Box::new(devices)
  18. }
  19. fn list_outputs() {
  20. let default = get_default_output_index();
  21. for (idx, info) in output_devices() {
  22. if Some(idx) == default {
  23. println!("- {} (default)", info.name);
  24. } else {
  25. println!("- {}", info.name)
  26. }
  27. }
  28. }
  29. fn find_output(device: &str) -> Option<DeviceIndex> {
  30. output_devices()
  31. .find(|&(_, ref info)| info.name == device)
  32. .map(|(idx, _)| idx)
  33. }
  34. impl<'a> Open for PortAudioSink<'a> {
  35. fn open(device: Option<String>) -> PortAudioSink<'a> {
  36. debug!("Using PortAudio sink");
  37. portaudio_rs::initialize().unwrap();
  38. let device_idx = match device.as_ref().map(AsRef::as_ref) {
  39. Some("?") => {
  40. list_outputs();
  41. exit(0)
  42. }
  43. Some(device) => find_output(device),
  44. None => get_default_output_index(),
  45. }
  46. .expect("Could not find device");
  47. let info = portaudio_rs::device::get_info(device_idx);
  48. let latency = match info {
  49. Some(info) => info.default_high_output_latency,
  50. None => Duration::new(0, 0),
  51. };
  52. let params = StreamParameters {
  53. device: device_idx,
  54. channel_count: 2,
  55. suggested_latency: latency,
  56. data: 0i16,
  57. };
  58. PortAudioSink(None, params)
  59. }
  60. }
  61. impl<'a> Sink for PortAudioSink<'a> {
  62. fn start(&mut self) -> io::Result<()> {
  63. if self.0.is_none() {
  64. self.0 = Some(
  65. Stream::open(
  66. None,
  67. Some(self.1),
  68. 44100.0,
  69. FRAMES_PER_BUFFER_UNSPECIFIED,
  70. StreamFlags::empty(),
  71. None,
  72. )
  73. .unwrap(),
  74. );
  75. }
  76. self.0.as_mut().unwrap().start().unwrap();
  77. Ok(())
  78. }
  79. fn stop(&mut self) -> io::Result<()> {
  80. self.0.as_mut().unwrap().stop().unwrap();
  81. self.0 = None;
  82. Ok(())
  83. }
  84. fn write(&mut self, data: &[i16]) -> io::Result<()> {
  85. match self.0.as_mut().unwrap().write(data) {
  86. Ok(_) => (),
  87. Err(portaudio_rs::PaError::OutputUnderflowed) => error!("PortAudio write underflow"),
  88. Err(e) => panic!("PA Error {}", e),
  89. };
  90. Ok(())
  91. }
  92. }
  93. impl<'a> Drop for PortAudioSink<'a> {
  94. fn drop(&mut self) {
  95. portaudio_rs::terminate().unwrap();
  96. }
  97. }