1 // Copyright 2017 Lyndon Brown
2 //
3 // This file is part of the PulseAudio Rust language binding.
4 //
5 // Licensed under the MIT license or the Apache license (version 2.0), at your option. You may not
6 // copy, modify, or distribute this file except in compliance with said license. You can find copies
7 // of these licenses either in the LICENSE-MIT and LICENSE-APACHE files, or alternatively at
8 // <http://opensource.org/licenses/MIT> and <http://www.apache.org/licenses/LICENSE-2.0>
9 // respectively.
10 //
11 // Portions of documentation are copied from the LGPL 2.1+ licensed PulseAudio C headers on a
12 // fair-use basis, as discussed in the overall project readme (available in the git repository).
13 
14 //! A binding for the PulseAudio binding ‘simple’ interface (`libpulse-simple` system library).
15 //!
16 //! # About
17 //!
18 //! This binding enables Rust projects to make use of the ‘simple’ interface of the [PulseAudio]
19 //! client system library. It builds upon the [separate raw FFI crate][sys] to provide a more
20 //! “Rusty” interface.
21 //!
22 //! The ‘simple’ interface provides a simple but limited synchronous playback and recording API. It
23 //! is a synchronous, simplified wrapper around the standard asynchronous API.
24 //!
25 //! Note that you will need components of the primary [`libpulse-binding`] crate to make use of
26 //! this.
27 //!
28 //! # Introduction
29 //!
30 //! The simple API is designed for applications with very basic sound playback or capture needs. It
31 //! can only support a single stream per connection and has no support for handling of complex
32 //! features like events, channel mappings and volume control. It is, however, very simple to use
33 //! and quite sufficient for many programs.
34 //!
35 //! # Usage
36 //!
37 //! Start by adding a dependency on the crate, along with the main binding crate, in your program’s
38 //! `Cargo.toml` file. Note that it is recommended that you rename the crates such that you can
39 //! refer to them by shorter names within your code (such as `pulse` and `psimple` as used below).
40 //! Such renaming can be done [within your `Cargo.toml` file][rename] with cargo version 1.31 or
41 //! newer, or otherwise with `extern crate` statements.
42 //!
43 //! Finally, establish a connection, as below.
44 //!
45 //! # Connecting
46 //!
47 //! The first step before using the sound system is to connect to the server. This is normally done
48 //! this way:
49 //!
50 //! ```rust
51 //! # extern crate libpulse_binding as pulse;
52 //! # extern crate libpulse_simple_binding as psimple;
53 //! #
54 //! use psimple::Simple;
55 //! use pulse::stream::Direction;
56 //! use pulse::sample::{Spec, Format};
57 //!
58 //! # fn main() {
59 //! let spec = Spec {
60 //!     format: Format::S16NE,
61 //!     channels: 2,
62 //!     rate: 44100,
63 //! };
64 //! assert!(spec.is_valid());
65 //!
66 //! let s = Simple::new(
67 //!     None,                // Use the default server
68 //!     "FooApp",            // Our application’s name
69 //!     Direction::Playback, // We want a playback stream
70 //!     None,                // Use the default device
71 //!     "Music",             // Description of our stream
72 //!     &spec,               // Our sample format
73 //!     None,                // Use default channel map
74 //!     None                 // Use default buffering attributes
75 //! ).unwrap();
76 //! # }
77 //! ```
78 //!
79 //! # Transferring data
80 //!
81 //! Once the connection is established to the server, data can start flowing. Using the connection
82 //! is very similar to the normal read() and write() system calls using [`Simple::read()`] and
83 //! [`Simple::write()`] methods of the [`Simple`] object. Note that these operations always block.
84 //!
85 //! # Buffer control
86 //!
87 //! * [`Simple::get_latency()`]: Will return the total latency of the playback or record pipeline,
88 //!   respectively.
89 //! * [`Simple::flush()`]: Will throw away all data currently in buffers.
90 //!
91 //! If a playback stream is used then the following operation is available:
92 //!
93 //! * [`Simple::drain()`]: Will wait for all sent data to finish playing.
94 //!
95 //! # Cleanup
96 //!
97 //! Once playback or capture is complete, the connection should be closed and resources freed. This
98 //! is done automatically once the [`Simple`] object is dropped.
99 //!
100 //! [sys]: https://docs.rs/libpulse-simple-sys
101 //! [`libpulse-binding`]: https://docs.rs/libpulse-binding
102 //! [PulseAudio]: https://en.wikipedia.org/wiki/PulseAudio
103 //! [rename]: https://doc.rust-lang.org/1.31.0/cargo/reference/specifying-dependencies.html#renaming-dependencies-in-cargotoml
104 
105 #![doc(
106     html_logo_url = "https://github.com/jnqnfe/pulse-binding-rust/raw/master/logo.svg",
107     html_favicon_url = "https://github.com/jnqnfe/pulse-binding-rust/raw/master/favicon.ico"
108 )]
109 
110 #![warn(missing_docs)]
111 
112 #![cfg_attr(docsrs, feature(doc_cfg))]
113 
114 extern crate libpulse_binding as pulse;
115 extern crate libpulse_sys as pcapi;
116 extern crate libpulse_simple_sys as capi;
117 
118 use std::os::raw::{c_char, c_void};
119 use std::{ffi::CString, ptr::null};
120 use std::mem;
121 use pulse::{error::PAErr, time::MicroSeconds};
122 use pulse::{stream, sample, channelmap, def};
123 
124 use capi::pa_simple as SimpleInternal;
125 
126 /// An opaque simple connection object.
127 pub struct Simple {
128     /// The actual C object.
129     ptr: *mut SimpleInternal,
130 }
131 
132 unsafe impl Send for Simple {}
133 unsafe impl Sync for Simple {}
134 
135 impl Simple {
136     /// Creates a new connection to the server.
137     ///
138     /// # Params
139     ///
140     /// * `server`: Server name, or `None` for default.
141     /// * `name`: A descriptive name for this client (application name, ...).
142     /// * `dir`: Open this stream for recording or playback?
143     /// * `dev`: Sink (resp. source) name, or `None` for default.
144     /// * `stream_name`: A descriptive name for this stream (application name, song title, ...).
145     /// * `ss`: The sample type to use.
146     /// * `map`: The channel map to use, or `None` for default.
147     /// * `attr`: Buffering attributes, or `None` for default.
148     pub fn new(server: Option<&str>, name: &str, dir: stream::Direction, dev: Option<&str>,
149         stream_name: &str, ss: &sample::Spec, map: Option<&channelmap::Map>,
150         attr: Option<&def::BufferAttr>) -> Result<Self, PAErr>
151     {
152         // Warning: New CStrings will be immediately freed if not bound to a variable, leading to
153         // as_ptr() giving dangling pointers!
154         let c_server = match server {
155             Some(server) => CString::new(server.clone()).unwrap(),
156             None => CString::new("").unwrap(),
157         };
158         let c_dev = match dev {
159             Some(dev) => CString::new(dev.clone()).unwrap(),
160             None => CString::new("").unwrap(),
161         };
162 
163         let p_map = map.map_or(null::<pcapi::pa_channel_map>(), |m| m.as_ref());
164         let p_attr = attr.map_or(null::<pcapi::pa_buffer_attr>(), |a| a.as_ref());
165         let p_server = server.map_or(null::<c_char>(), |_| c_server.as_ptr() as *const c_char);
166         let p_dev = dev.map_or(null::<c_char>(), |_| c_dev.as_ptr() as *const c_char);
167         let c_name = CString::new(name.clone()).unwrap();
168         let c_stream_name = CString::new(stream_name.clone()).unwrap();
169 
170         let mut error: i32 = 0;
171         let ptr = unsafe {
172             capi::pa_simple_new(
173                 p_server,
174                 c_name.as_ptr(),
175                 dir,
176                 p_dev,
177                 c_stream_name.as_ptr(),
178                 mem::transmute(ss),
179                 p_map,
180                 p_attr,
181                 &mut error
182             )
183         };
184         match ptr.is_null() {
185             false => Ok(Self::from_raw(ptr)),
186             true => Err(PAErr(error)),
187         }
188     }
189 
190     /// Creates a new `Simple` from an existing [`SimpleInternal`] pointer.
191     fn from_raw(ptr: *mut SimpleInternal) -> Self {
192         assert_eq!(false, ptr.is_null());
193         Self { ptr }
194     }
195 
196     /// Writes some data to the server.
197     pub fn write(&self, data: &[u8]) -> Result<(), PAErr> {
198         let mut error: i32 = 0;
199         match unsafe { capi::pa_simple_write(self.ptr, data.as_ptr() as *mut c_void, data.len(),
200             &mut error) }
201         {
202             0 => Ok(()),
203             _ => Err(PAErr(error)),
204         }
205     }
206 
207     /// Waits until all data already written is played by the daemon.
208     pub fn drain(&self) -> Result<(), PAErr> {
209         let mut error: i32 = 0;
210         match unsafe { capi::pa_simple_drain(self.ptr, &mut error) } {
211             0 => Ok(()),
212             _ => Err(PAErr(error)),
213         }
214     }
215 
216     /// Reads some data from the server.
217     ///
218     /// This function blocks until `data.len()` amount of data has been received from the server,
219     /// or until an error occurs.
220     pub fn read(&self, data: &mut [u8]) -> Result<(), PAErr> {
221         let mut error: i32 = 0;
222         match unsafe { capi::pa_simple_read(self.ptr, data.as_mut_ptr() as *mut c_void, data.len(),
223             &mut error) }
224         {
225             0 => Ok(()),
226             _ => Err(PAErr(error)),
227         }
228     }
229 
230     /// Gets the playback or record latency.
231     pub fn get_latency(&self) -> Option<MicroSeconds> {
232         let mut error: i32 = 0;
233         let ret = unsafe { capi::pa_simple_get_latency(self.ptr, &mut error) };
234         if error != 0 {
235             return None;
236         }
237         Some(MicroSeconds(ret))
238     }
239 
240     /// Flushes the playback or record buffer.
241     ///
242     /// This discards any audio in the buffer.
243     pub fn flush(&self) -> Result<(), PAErr> {
244         let mut error: i32 = 0;
245         match unsafe { capi::pa_simple_flush(self.ptr, &mut error) } {
246             0 => Ok(()),
247             _ => Err(PAErr(error)),
248         }
249     }
250 }
251 
252 impl Drop for Simple {
253     fn drop(&mut self) {
254         // Close and free the connection to the server.
255         unsafe { capi::pa_simple_free(self.ptr) };
256         self.ptr = null::<SimpleInternal>() as *mut SimpleInternal;
257     }
258 }
259