libpulse_binding/stream.rs
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//! Audio streams for input, output and sample upload.
15//!
16//! # Overview
17//!
18//! Audio streams form the central functionality of the sound server. Data is routed, converted and
19//! mixed from several sources before it is passed along to a final output. Currently, there are
20//! three forms of audio streams:
21//!
22//! * Playback streams: Data flows from the client to the server.
23//! * Record streams: Data flows from the server to the client.
24//! * Upload streams: Similar to playback streams, but the data is stored in the sample cache. See
25//! [`context::scache`] for more information about controlling the sample cache.
26//!
27//! # Creating
28//!
29//! To access a stream, a [`Stream`] object must be created using [`Stream::new()`] or
30//! [`Stream::new_extended()`]. `new` is for PCM streams only, while `new_extended` can be used for
31//! both PCM and compressed audio streams. At this point the application must specify what stream
32//! format(s) it supports. See [`sample`] and [`channelmap`] for more information on the stream
33//! format parameters.
34//!
35//! **FIXME**: Those references only talk about PCM parameters, we should also have an overview
36//! page for how the [`Info`] based stream format configuration works.
37//! [Bug filed](https://bugs.freedesktop.org/show_bug.cgi?id=72265).
38//!
39//! This first step will only create a client-side object, representing the stream. To use the
40//! stream, a server-side object must be created and associated with the local object. Depending on
41//! which type of stream is desired, a different function is needed:
42//!
43//! * Playback stream: [`Stream::connect_playback()`]
44//! * Record stream: [`Stream::connect_record()`]
45//! * Upload stream: [`Stream::connect_upload()`] \(see [`context::scache`])
46//!
47//! Similar to how connections are done in contexts, connecting a stream will not generate an
48//! [`Operation`] object. Also like contexts, the application should register a state change
49//! callback, using [`Stream::set_state_callback()`], and wait for the stream to enter an active
50//! state.
51//!
52//! Note: there is a user-controllable slider in mixer applications such as pavucontrol
53//! corresponding to each of the created streams. Multiple (especially identically named) volume
54//! sliders for the same application might confuse the user. Also, the server supports only a
55//! limited number of simultaneous streams. Because of this, it is not always appropriate to create
56//! multiple streams in one application that needs to output multiple sounds. The rough guideline
57//! is: if there is no use case that would require separate user-initiated volume changes for each
58//! stream, perform the mixing inside the application.
59//!
60//! # Buffer Attributes
61//!
62//! Playback and record streams always have a server-side buffer as part of the data flow. The size
63//! of this buffer needs to be chosen in a compromise between low latency and sensitivity for buffer
64//! overflows/underruns.
65//!
66//! The buffer metrics may be controlled by the application. They are described with a
67//! [`BufferAttr`] structure.
68//!
69//! If [`FlagSet::ADJUST_LATENCY`] is set, then the `tlength`/`fragsize` parameters of this
70//! structure will be interpreted slightly differently than otherwise when passed to
71//! [`Stream::connect_record()`] and [`Stream::connect_playback()`]: the overall latency that is
72//! comprised of both the server side playback buffer length, the hardware playback buffer length
73//! and additional latencies will be adjusted in a way that it matches `tlength` resp. `fragsize`.
74//! Set [`FlagSet::ADJUST_LATENCY`] if you want to control the overall playback latency for your
75//! stream. Unset it if you want to control only the latency induced by the server-side, rewritable
76//! playback buffer. The server will try to fulfill the client’s latency requests as good as
77//! possible. However if the underlying hardware cannot change the hardware buffer length or only in
78//! a limited range, the actually resulting latency might be different from what the client
79//! requested. Thus, for synchronization clients always need to check the actual measured latency
80//! via [`Stream::get_latency()`] or a similar call, and not make any assumptions about the latency
81//! available. The function [`Stream::get_buffer_attr()`] will always return the actual size of the
82//! server-side per-stream buffer in `tlength`/`fragsize`, regardless whether
83//! [`FlagSet::ADJUST_LATENCY`] is set or not.
84//!
85//! The server-side per-stream playback buffers are indexed by a write and a read index. The
86//! application writes to the write index and the sound device reads from the read index. The read
87//! index is increased monotonically, while the write index may be freely controlled by the
88//! application. Subtracting the read index from the write index will give you the current fill
89//! level of the buffer. The read/write indexes are 64bit values and measured in bytes, they will
90//! never wrap. The current read/write index may be queried using [`Stream::get_timing_info()`]
91//! \(see below for more information). In case of a buffer underrun the read index is equal or
92//! larger than the write index. Unless the `prebuf` value is `0`, PulseAudio will temporarily pause
93//! playback in such a case, and wait until the buffer is filled up to `prebuf` bytes again. If
94//! `prebuf` is `0`, the read index may be larger than the write index, in which case silence is
95//! played. If the application writes data to indexes lower than the read index, the data is
96//! immediately lost.
97//!
98//! # Transferring Data
99//!
100//! Once the stream is up, data can start flowing between the client and the server. Two different
101//! access models can be used to transfer the data:
102//!
103//! * Asynchronous: The application registers a callback using [`Stream::set_write_callback()`] and
104//! [`Stream::set_read_callback()`] to receive notifications that data can either be written or
105//! read.
106//! * Polled: Query the library for available data/space using [`Stream::writable_size()`] and
107//! [`Stream::readable_size()`] and transfer data as needed. The sizes are stored locally, in the
108//! client end, so there is no delay when reading them.
109//!
110//! It is also possible to mix the two models freely.
111//!
112//! Once there is data/space available, it can be transferred using either [`Stream::write()`] for
113//! playback, or [`Stream::peek()`] / [`Stream::discard()`] for record. Make sure you do not
114//! overflow the playback buffers as data will be dropped.
115//!
116//! # Buffer Control
117//!
118//! The transfer buffers can be controlled through a number of operations:
119//!
120//! * [`Stream::cork()`]: Stop the playback or recording.
121//! * [`Stream::uncork()`]: Start the playback or recording.
122//! * [`Stream::trigger()`]: Start playback immediately and do not wait for the buffer to fill up to
123//! the set trigger level.
124//! * [`Stream::prebuf()`]: Re-enable the playback trigger level.
125//! * [`Stream::drain()`]: Wait for the playback buffer to go empty. Will return an [`Operation`]
126//! object that will indicate when the buffer is completely drained.
127//! * [`Stream::flush()`]: Drop all data from the playback or record buffer. Do not wait for it to
128//! finish playing.
129//!
130//! # Seeking in the Playback Buffer
131//!
132//! A client application may freely seek in the playback buffer. To accomplish that the
133//! [`Stream::write()`] function takes a seek mode and an offset argument. The seek mode is one of:
134//!
135//! * [`SeekMode::Relative`]: seek relative to the current write index.
136//! * [`SeekMode::Absolute`]: seek relative to the beginning of the playback buffer, (i.e. the first
137//! that was ever played in the stream).
138//! * [`SeekMode::RelativeOnRead`]: seek relative to the current read index. Use this to write data
139//! to the output buffer that should be played as soon as possible.
140//! * [`SeekMode::RelativeEnd`]: seek relative to the last byte ever written.
141//!
142//! If an application just wants to append some data to the output buffer, [`SeekMode::Relative`]
143//! and an offset of `0` should be used.
144//!
145//! After a call to [`Stream::write()`] the write index will be left at the position right after the
146//! last byte of the written data.
147//!
148//! # Latency
149//!
150//! A major problem with networked audio is the increased latency caused by the network. To remedy
151//! this, PulseAudio supports an advanced system of monitoring the current latency.
152//!
153//! To get the raw data needed to calculate latencies, call [`Stream::get_timing_info()`]. This will
154//! give you a [`TimingInfo`] structure that contains everything that is known about the server side
155//! buffer transport delays and the backend active in the server. (Besides other things it contains
156//! the write and read index values mentioned above.)
157//!
158//! This structure is updated every time a [`Stream::update_timing_info()`] operation is executed.
159//! (i.e. before the first call to this function the timing information structure is not available!)
160//! Since it is a lot of work to keep this structure up-to-date manually, PulseAudio can do that
161//! automatically for you: if [`FlagSet::AUTO_TIMING_UPDATE`] is passed when connecting the stream
162//! PulseAudio will automatically update the structure every 100ms and every time a function is
163//! called that might invalidate the previously known timing data (such as [`Stream::write()`] or
164//! [`Stream::flush()`]). Please note however, that there always is a short time window when the
165//! data in the timing information structure is out-of-date. PulseAudio tries to mark these
166//! situations by setting the `write_index_corrupt` and `read_index_corrupt` fields accordingly.
167//!
168//! The raw timing data in the [`TimingInfo`] structure is usually hard to deal with. Therefore a
169//! simpler interface is available: you can call [`Stream::get_time()`] or
170//! [`Stream::get_latency()`]. The former will return the current playback time of the hardware
171//! since the stream has been started. The latter returns the overall time a sample that you write
172//! now takes to be played by the hardware. These two functions base their calculations on the same
173//! data that is returned by [`Stream::get_timing_info()`]. Hence the same rules for keeping the
174//! timing data up-to-date apply here. In case the write or read index is corrupted, these two
175//! functions will fail.
176//!
177//! Since updating the timing info structure usually requires a full network round trip and some
178//! applications monitor the timing very often PulseAudio offers a timing interpolation system. If
179//! [`FlagSet::INTERPOLATE_TIMING`] is passed when connecting the stream, [`Stream::get_time()`] and
180//! [`Stream::get_latency()`] will try to interpolate the current playback time/latency by
181//! estimating the number of samples that have been played back by the hardware since the last
182//! regular timing update. It is especially useful to combine this option with
183//! [`FlagSet::AUTO_TIMING_UPDATE`], which will enable you to monitor the current playback
184//! time/latency very precisely and very frequently without requiring a network round trip every
185//! time.
186//!
187//! # Overflow and underflow
188//!
189//! Even with the best precautions, buffers will sometime over - or underflow. To handle this
190//! gracefully, the application can be notified when this happens. Callbacks are registered using
191//! [`Stream::set_overflow_callback()`] and [`Stream::set_underflow_callback()`].
192//!
193//! # Synchronizing Multiple Playback Streams
194//!
195//! PulseAudio allows applications to fully synchronize multiple playback streams that are connected
196//! to the same output device. That means the streams will always be played back sample-by-sample
197//! synchronously. If stream operations like [`Stream::cork()`] are issued on one of the
198//! synchronized streams, they are simultaneously issued on the others.
199//!
200//! To synchronize a stream to another, just pass the “master” stream as the last argument to
201//! [`Stream::connect_playback()`]. To make sure that the freshly created stream doesn’t start
202//! playback right-away, make sure to pass [`FlagSet::START_CORKED`] and, after all streams have
203//! been created, uncork them all with a single call to [`Stream::uncork()`] for the master stream.
204//!
205//! To make sure that a particular stream doesn’t stop to play when a server side buffer underrun
206//! happens on it while the other synchronized streams continue playing and hence deviate, you need
207//! to pass a [`BufferAttr`] with `prebuf` set to `0` when connecting.
208//!
209//! # Disconnecting
210//!
211//! When a stream has served is purpose it must be disconnected with [`Stream::disconnect()`]. If
212//! you only unreference it, then it will live on and eat resources both locally and on the server
213//! until you disconnect the context. This is done automatically upon drop of the stream object.
214//!
215//! [`context::scache`]: mod@crate::context::scache
216//! [`sample`]: mod@crate::sample
217//! [`channelmap`]: mod@crate::channelmap
218//! [`Info`]: crate::format::Info
219//! [`BufferAttr`]: crate::def::BufferAttr
220//! [`TimingInfo`]: crate::def::TimingInfo
221
222use std::os::raw::{c_char, c_void};
223use std::ffi::{CStr, CString};
224use std::ptr::{null, null_mut};
225use std::borrow::Cow;
226use bitflags::bitflags;
227use num_derive::{FromPrimitive, ToPrimitive};
228use capi::pa_stream as StreamInternal;
229use crate::{channelmap, format, def, proplist, sample};
230use crate::callbacks::{self, box_closure_get_capi_ptr, get_su_capi_params, get_su_callback};
231use crate::error::{self, PAErr};
232use crate::format::InfoInternal;
233use crate::proplist::{Proplist, ProplistInternal};
234use crate::{context::Context, volume::ChannelVolumes, operation::Operation, time::MicroSeconds};
235
236pub use capi::pa_seek_mode_t as SeekMode;
237pub use capi::pa_stream_direction_t as Direction;
238
239/// An opaque stream for playback or recording.
240///
241/// Note: Saves a copy of active multi-use closure callbacks, which it frees on drop.
242pub struct Stream {
243 /// The actual C object.
244 ptr: *mut StreamInternal,
245 /// Multi-use callback closure pointers.
246 cb_ptrs: CallbackPointers,
247}
248
249unsafe impl Send for Stream {}
250unsafe impl Sync for Stream {}
251
252/// Holds copies of callback closure pointers, for those that are “multi-use” (may be fired multiple
253/// times), for freeing at the appropriate time.
254#[derive(Default)]
255struct CallbackPointers {
256 read: RequestCb,
257 write: RequestCb,
258 set_state: NotifyCb,
259 overflow: NotifyCb,
260 underflow: NotifyCb,
261 started: NotifyCb,
262 latency_update: NotifyCb,
263 moved: NotifyCb,
264 suspended: NotifyCb,
265 buffer_attr: NotifyCb,
266 event: EventCb,
267}
268
269type RequestCb = callbacks::MultiUseCallback<dyn FnMut(usize),
270 extern "C" fn(*mut StreamInternal, usize, *mut c_void)>;
271
272type NotifyCb = callbacks::MultiUseCallback<dyn FnMut(),
273 extern "C" fn(*mut StreamInternal, *mut c_void)>;
274
275type EventCb = callbacks::MultiUseCallback<dyn FnMut(String, Proplist),
276 extern "C" fn(*mut StreamInternal, name: *const c_char, pl: *mut ProplistInternal, *mut c_void)>;
277
278/// Stream state.
279#[repr(C)]
280#[derive(Debug, Copy, Clone, PartialEq, Eq)]
281#[derive(FromPrimitive, ToPrimitive)]
282pub enum State {
283 /* NOTE: This enum’s variants and variant values **must** remain identical to the `sys` crate
284 (C API) equivalent */
285
286 /// The stream is not yet connected to any sink or source.
287 Unconnected,
288 /// The stream is being created.
289 Creating,
290 /// The stream is established, you may pass audio data to it now.
291 Ready,
292 /// An error occurred that made the stream invalid.
293 Failed,
294 /// The stream has been terminated cleanly.
295 Terminated,
296}
297
298/// Check is equal to `sys` equivalent
299#[test]
300fn state_compare_capi() {
301 assert_eq!(std::mem::size_of::<State>(), std::mem::size_of::<capi::pa_stream_state_t>());
302 assert_eq!(std::mem::align_of::<State>(), std::mem::align_of::<capi::pa_stream_state_t>());
303
304 // Check order and value of variants match
305 // No point checking conversions in both directions since both are a transmute
306 assert_eq!(State::Unconnected, State::from(capi::pa_stream_state_t::Unconnected));
307 assert_eq!(State::Creating, State::from(capi::pa_stream_state_t::Creating));
308 assert_eq!(State::Ready, State::from(capi::pa_stream_state_t::Ready));
309 assert_eq!(State::Failed, State::from(capi::pa_stream_state_t::Failed));
310 assert_eq!(State::Terminated, State::from(capi::pa_stream_state_t::Terminated));
311}
312
313impl From<State> for capi::pa_stream_state_t {
314 #[inline]
315 fn from(s: State) -> Self {
316 unsafe { std::mem::transmute(s) }
317 }
318}
319impl From<capi::pa_stream_state_t> for State {
320 #[inline]
321 fn from(s: capi::pa_stream_state_t) -> Self {
322 unsafe { std::mem::transmute(s) }
323 }
324}
325
326impl State {
327 /// Checks if the passed state is one of the connected states.
328 #[inline]
329 pub fn is_good(self) -> bool {
330 self == State::Creating || self == State::Ready
331 }
332}
333
334bitflags! {
335 /// Flag set.
336 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
337 #[repr(transparent)]
338 pub struct FlagSet: u32 {
339 /// Flag to pass when no specific options are needed.
340 const NOFLAGS = capi::PA_STREAM_NOFLAGS;
341
342 /// Create the stream corked, requiring an explicit [`Stream::uncork()`] call to uncork it.
343 const START_CORKED = capi::PA_STREAM_START_CORKED;
344
345 /// Interpolate the latency for this stream. When enabled, [`Stream::get_latency()`] and
346 /// [`Stream::get_time()`] will try to estimate the current record/playback time based on
347 /// the local time that passed since the last timing info update. Using this option has the
348 /// advantage of not requiring a whole round trip when the current playback/recording time
349 /// is needed. Consider using this option when requesting latency information frequently.
350 /// This is especially useful on long latency network connections. It makes a lot of sense
351 /// to combine this option with [`AUTO_TIMING_UPDATE`].
352 ///
353 /// [`AUTO_TIMING_UPDATE`]: Self::AUTO_TIMING_UPDATE
354 const INTERPOLATE_TIMING = capi::PA_STREAM_INTERPOLATE_TIMING;
355
356 /// Don’t force the time to increase monotonically. If this option is enabled,
357 /// [`Stream::get_time()`] will not necessarily return always monotonically increasing time
358 /// values on each call. This may confuse applications which cannot deal with time going
359 /// ‘backwards’, but has the advantage that bad transport latency estimations that caused
360 /// the time to jump ahead can be corrected quickly, without the need to wait.
361 const NOT_MONOTONIC = capi::PA_STREAM_NOT_MONOTONIC;
362
363 /// If set timing update requests are issued periodically automatically. Combined with
364 /// [`INTERPOLATE_TIMING`] you will be able to query the current time and latency with
365 /// [`Stream::get_time()`] and [`Stream::get_latency()`] at all times without a packet round
366 /// trip.
367 ///
368 /// [`INTERPOLATE_TIMING`]: Self::INTERPOLATE_TIMING
369 const AUTO_TIMING_UPDATE = capi::PA_STREAM_AUTO_TIMING_UPDATE;
370
371 /// Don’t remap channels by their name, instead map them simply by their index. Implies
372 /// [`NO_REMIX_CHANNELS`](Self::NO_REMIX_CHANNELS).
373 const NO_REMAP_CHANNELS = capi::PA_STREAM_NO_REMAP_CHANNELS;
374
375 /// When remapping channels by name, don’t upmix or downmix them to related channels. Copy
376 /// them into matching channels of the device 1:1.
377 const NO_REMIX_CHANNELS = capi::PA_STREAM_NO_REMIX_CHANNELS;
378
379 /// Use the sample format of the sink/device this stream is being connected to, and possibly
380 /// ignore the format the sample spec contains -- but you still have to pass a valid value
381 /// in it as a hint to PulseAudio what would suit your stream best. If this is used you
382 /// should query the used sample format after creating the stream by using
383 /// [`Stream::get_sample_spec()`]. Also, if you specified manual buffer metrics it is
384 /// recommended to update them with [`Stream::set_buffer_attr()`] to compensate for the
385 /// changed frame sizes.
386 ///
387 /// When creating streams with [`Stream::new_extended()`], this flag has no effect. If you
388 /// specify a format with PCM encoding, and you want the server to choose the sample format,
389 /// then you should leave the sample format unspecified in the [`Info`] object. This also
390 /// means that you can’t use [`Info::new_from_sample_spec()`], because that function always
391 /// sets the sample format.
392 ///
393 /// [`Info`]: crate::format::Info
394 /// [`Info::new_from_sample_spec()`]: crate::format::Info::new_from_sample_spec
395 const FIX_FORMAT = capi::PA_STREAM_FIX_FORMAT;
396
397 /// Use the sample rate of the sink, and possibly ignore the rate the sample spec contains.
398 /// Usage similar to [`FIX_FORMAT`].
399 ///
400 /// When creating streams with [`Stream::new_extended()`], this flag has no effect. If you
401 /// specify a format with PCM encoding, and you want the server to choose the sample rate,
402 /// then you should leave the rate unspecified in the [`Info`] object. This also means that
403 /// you can’t use [`Info::new_from_sample_spec()`], because that function always sets the
404 /// sample rate.
405 ///
406 /// [`FIX_FORMAT`]: Self::FIX_FORMAT
407 /// [`Info`]: crate::format::Info
408 /// [`Info::new_from_sample_spec()`]: crate::format::Info::new_from_sample_spec
409 const FIX_RATE = capi::PA_STREAM_FIX_RATE;
410
411 /// Use the number of channels and the channel map of the sink, and possibly ignore the number
412 /// of channels and the map the sample spec and the passed channel map contains. Usage similar
413 /// to [`FIX_FORMAT`].
414 ///
415 /// When creating streams with [`Stream::new_extended()`], this flag has no effect. If you
416 /// specify a format with PCM encoding, and you want the server to choose the channel count
417 /// and/or channel map, then you should leave the channels and/or the channel map
418 /// unspecified in the [`Info`] object. This also means that you can’t use
419 /// [`Info::new_from_sample_spec()`], because that function always sets the channel count
420 /// (but if you only want to leave the channel map unspecified, then
421 /// [`Info::new_from_sample_spec()`] works, because the channel map parameter is optional).
422 ///
423 /// [`FIX_FORMAT`]: Self::FIX_FORMAT
424 /// [`Info`]: crate::format::Info
425 /// [`Info::new_from_sample_spec()`]: crate::format::Info::new_from_sample_spec
426 const FIX_CHANNELS = capi::PA_STREAM_FIX_CHANNELS;
427
428 /// Don’t allow moving of this stream to another sink/device. Useful if you use any of the
429 /// `Fix*` flags and want to make sure that resampling never takes place -- which might
430 /// happen if the stream is moved to another sink/source with a different sample
431 /// spec/channel map.
432 const DONT_MOVE = capi::PA_STREAM_DONT_MOVE;
433
434 /// Allow dynamic changing of the sampling rate during playback with
435 /// [`Stream::update_sample_rate()`].
436 const VARIABLE_RATE = capi::PA_STREAM_VARIABLE_RATE;
437
438 /// Find peaks instead of resampling.
439 const PEAK_DETECT = capi::PA_STREAM_PEAK_DETECT;
440
441 /// Create in muted state. If neither [`START_UNMUTED`] nor this is specified, it is left to
442 /// the server to decide whether to create the stream in muted or in un-muted state.
443 ///
444 /// [`START_UNMUTED`]: Self::START_UNMUTED
445 const START_MUTED = capi::PA_STREAM_START_MUTED;
446
447 /// Try to adjust the latency of the sink/source based on the requested buffer metrics and
448 /// adjust buffer metrics accordingly. Also see [`BufferAttr`]. This option may not be
449 /// specified at the same time as [`EARLY_REQUESTS`].
450 ///
451 /// [`EARLY_REQUESTS`]: Self::EARLY_REQUESTS
452 /// [`BufferAttr`]: crate::def::BufferAttr
453 const ADJUST_LATENCY = capi::PA_STREAM_ADJUST_LATENCY;
454
455 /// Enable compatibility mode for legacy clients that rely on a “classic” hardware device
456 /// fragment-style playback model. If this option is set, the `minreq` value of the buffer
457 /// metrics gets a new meaning: instead of just specifying that no requests asking for less
458 /// new data than this value will be made to the client it will also guarantee that requests
459 /// are generated as early as this limit is reached. This flag should only be set in very
460 /// few situations where compatibility with a fragment-based playback model needs to be kept
461 /// and the client applications cannot deal with data requests that are delayed to the
462 /// latest moment possible. (Usually these are programs that use usleep() or a similar call
463 /// in their playback loops instead of sleeping on the device itself.) Also see
464 /// [`BufferAttr`]. This option may not be specified at the same time as [`ADJUST_LATENCY`].
465 ///
466 /// [`ADJUST_LATENCY`]: Self::ADJUST_LATENCY
467 /// [`BufferAttr`]: crate::def::BufferAttr
468 const EARLY_REQUESTS = capi::PA_STREAM_EARLY_REQUESTS;
469
470 /// If set this stream won’t be taken into account when it is checked whether the device
471 /// this stream is connected to should auto-suspend.
472 const DONT_INHIBIT_AUTO_SUSPEND = capi::PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND;
473
474 /// Create in unmuted state. If neither [`START_MUTED`] nor this is specified, it is left to
475 /// the server to decide whether to create the stream in muted or in unmuted state.
476 ///
477 /// [`START_MUTED`]: Self::START_MUTED
478 const START_UNMUTED = capi::PA_STREAM_START_UNMUTED;
479
480 /// If the sink/source this stream is connected to is suspended during the creation of this
481 /// stream, cause it to fail. If the sink/source is being suspended during creation of this
482 /// stream, make sure this stream is terminated.
483 const FAIL_ON_SUSPEND = capi::PA_STREAM_FAIL_ON_SUSPEND;
484
485 /// If a volume is passed when this stream is created, consider it relative to the sink’s
486 /// current volume, never as absolute device volume. If this is not specified the volume
487 /// will be consider absolute when the sink is in flat volume mode, relative otherwise.
488 const RELATIVE_VOLUME = capi::PA_STREAM_RELATIVE_VOLUME;
489
490 /// Used to tag content that will be rendered by passthrough sinks. The data will be left as
491 /// is and not reformatted, resampled.
492 const PASSTHROUGH = capi::PA_STREAM_PASSTHROUGH;
493 }
494}
495
496impl Default for FlagSet {
497 fn default() -> Self {
498 Self::NOFLAGS
499 }
500}
501
502/// Common event names supplied to the [`Stream::set_event_callback()`] callback.
503pub mod event_names {
504 use capi;
505
506 /// A stream policy/meta event requesting that an application should cork a specific stream.
507 pub const EVENT_REQUEST_CORK: &str = capi::PA_STREAM_EVENT_REQUEST_CORK;
508
509 /// A stream policy/meta event requesting that an application should cork a specific stream.
510 pub const EVENT_REQUEST_UNCORK: &str = capi::PA_STREAM_EVENT_REQUEST_UNCORK;
511
512 /// A stream event notifying that the stream is going to be disconnected because the underlying
513 /// sink changed and no longer supports the format that was originally negotiated. Clients need
514 /// to connect a new stream to renegotiate a format and continue playback.
515 pub const EVENT_FORMAT_LOST: &str = capi::PA_STREAM_EVENT_FORMAT_LOST;
516}
517
518/// Result type for the [`Stream::peek()`] method. See documentation of the method itself for more
519/// information.
520#[derive(Debug)]
521pub enum PeekResult<'a> {
522 /// No data (Null data pointer and size of 0 returned by PA).
523 Empty,
524 /// Data hole with given size (Null pointer with non-zero size returned by PA).
525 Hole(usize),
526 /// Data available, with slice into memory returned by PA.
527 Data(&'a [u8]),
528}
529
530/// Result type for [`Stream::get_latency()`].
531#[derive(Debug, Copy, Clone, PartialEq, Eq)]
532pub enum Latency {
533 /// No latency.
534 None,
535 /// A positive (greater than zero) amount of latency.
536 Positive(MicroSeconds),
537 /// A negative (less than zero) amount of latency.
538 Negative(MicroSeconds),
539}
540
541impl Stream {
542 /// Creates a new, unconnected stream with the specified name and sample type.
543 ///
544 /// It is recommended to use [`new_with_proplist()`] instead and specify some initial
545 /// properties.
546 ///
547 /// # Params
548 ///
549 /// * `ctx`: The context to create this stream in
550 /// * `name`: A name for this stream
551 /// * `ss`: The desired sample format
552 /// * `map`: The desired channel map, or `None` for default
553 ///
554 /// [`new_with_proplist()`]: Self::new_with_proplist
555 pub fn new(ctx: &mut Context, name: &str, ss: &sample::Spec, map: Option<&channelmap::Map>)
556 -> Option<Self>
557 {
558 // Warning: New CStrings will be immediately freed if not bound to a variable, leading to
559 // as_ptr() giving dangling pointers!
560 let c_name = CString::new(name).unwrap();
561
562 let p_map = map.map_or(null::<capi::pa_channel_map>(), |m| m.as_ref());
563
564 let ptr = unsafe { capi::pa_stream_new(ctx.ptr, c_name.as_ptr(), ss.as_ref(), p_map) };
565 match ptr.is_null() {
566 false => Some(Self::from_raw(ptr)),
567 true => None,
568 }
569 }
570
571 /// Creates a new, unconnected stream with the specified name and sample type, and specify the
572 /// initial stream property list.
573 ///
574 /// # Params
575 ///
576 /// * `ctx`: The context to create this stream in
577 /// * `name`: A name for this stream
578 /// * `ss`: The desired sample format
579 /// * `map`: The desired channel map, or `None` for default
580 /// * `proplist`: The initial property list
581 pub fn new_with_proplist(ctx: &mut Context, name: &str, ss: &sample::Spec,
582 map: Option<&channelmap::Map>, proplist: &mut Proplist) -> Option<Self>
583 {
584 // Warning: New CStrings will be immediately freed if not bound to a variable, leading to
585 // as_ptr() giving dangling pointers!
586 let c_name = CString::new(name).unwrap();
587
588 let p_map = map.map_or(null::<capi::pa_channel_map>(), |m| m.as_ref());
589
590 let ptr = unsafe {
591 capi::pa_stream_new_with_proplist(ctx.ptr, c_name.as_ptr(), ss.as_ref(),
592 p_map, proplist.0.ptr)
593 };
594 match ptr.is_null() {
595 false => Some(Self::from_raw(ptr)),
596 true => None,
597 }
598 }
599
600 /// Creates a new, unconnected stream with the specified name, the set of formats this client
601 /// can provide, and an initial list of properties.
602 ///
603 /// While connecting, the server will select the most appropriate format which the client must
604 /// then provide.
605 ///
606 /// Will panic if the `formats` array is longer than can be communicated to the C function.
607 ///
608 /// # Params
609 ///
610 /// * `ctx`: The context to create this stream in
611 /// * `name`: A name for this stream
612 /// * `formats`: The list of formats that can be provided
613 /// * `proplist`: The initial property list
614 pub fn new_extended(ctx: &mut Context, name: &str, formats: &[&format::Info],
615 proplist: &mut Proplist) -> Option<Self>
616 {
617 assert!(formats.len() <= u32::MAX as usize);
618 // Warning: New CStrings will be immediately freed if not bound to a variable, leading to
619 // as_ptr() giving dangling pointers!
620 let c_name = CString::new(name).unwrap();
621
622 // Create array of format::InfoInternal pointers from provided array of `Info` pointers.
623 let mut info_ptrs: Vec<*const capi::pa_format_info> = Vec::with_capacity(formats.len());
624 for format in formats {
625 info_ptrs.push(format.ptr as *const capi::pa_format_info);
626 }
627
628 let ptr = unsafe {
629 capi::pa_stream_new_extended(ctx.ptr, c_name.as_ptr(), info_ptrs.as_ptr(),
630 info_ptrs.len() as u32, proplist.0.ptr)
631 };
632 match ptr.is_null() {
633 false => Some(Self::from_raw(ptr)),
634 true => None,
635 }
636 }
637
638 /// Creates a new `Stream` from an existing [`StreamInternal`] pointer.
639 #[inline]
640 fn from_raw(ptr: *mut StreamInternal) -> Self {
641 assert_eq!(false, ptr.is_null());
642 Self { ptr: ptr, cb_ptrs: Default::default() }
643 }
644
645 /// Gets the current state of the stream.
646 #[inline]
647 pub fn get_state(&self) -> State {
648 unsafe { capi::pa_stream_get_state(self.ptr).into() }
649 }
650
651 /// Gets the sink input resp. source output index this stream is identified in the server with.
652 ///
653 /// This is useful with the introspection functions such as
654 /// [`Introspector::get_sink_input_info()`] or [`Introspector::get_source_output_info()`].
655 ///
656 /// [`Introspector::get_sink_input_info()`]: crate::context::introspect::Introspector::get_sink_input_info
657 /// [`Introspector::get_source_output_info()`]: crate::context::introspect::Introspector::get_source_output_info
658 pub fn get_index(&self) -> Option<u32> {
659 match unsafe { capi::pa_stream_get_index(self.ptr) } {
660 def::INVALID_INDEX => None,
661 r => Some(r),
662 }
663 }
664
665 /// Gets the index of the sink or source this stream is connected to in the server.
666 ///
667 /// This is useful with the introspection functions such as
668 /// [`Introspector::get_sink_info_by_index()`] or [`Introspector::get_source_info_by_index()`].
669 ///
670 /// Please note that streams may be moved between sinks/sources and thus it is recommended to
671 /// use [`set_moved_callback()`] to be notified about this.
672 ///
673 /// [`set_moved_callback()`]: Self::set_moved_callback
674 /// [`Introspector::get_sink_info_by_index()`]: crate::context::introspect::Introspector::get_sink_info_by_index
675 /// [`Introspector::get_source_info_by_index()`]: crate::context::introspect::Introspector::get_source_info_by_index
676 pub fn get_device_index(&self) -> Option<u32> {
677 match unsafe { capi::pa_stream_get_device_index(self.ptr) } {
678 def::INVALID_INDEX => None,
679 r => Some(r),
680 }
681 }
682
683 /// Gets the name of the sink or source this stream is connected to in the server.
684 ///
685 /// This is useful with the introspection functions such as
686 /// [`Introspector::get_sink_info_by_name()`] or [`Introspector::get_source_info_by_name()`].
687 ///
688 /// Please note that streams may be moved between sinks/sources and thus it is recommended to
689 /// use [`set_moved_callback()`] to be notified about this.
690 ///
691 /// [`set_moved_callback()`]: Self::set_moved_callback
692 /// [`Introspector::get_sink_info_by_name()`]: crate::context::introspect::Introspector::get_sink_info_by_name
693 /// [`Introspector::get_source_info_by_name()`]: crate::context::introspect::Introspector::get_source_info_by_name
694 pub fn get_device_name(&self) -> Option<Cow<'static, str>> {
695 let ptr: *const c_char = unsafe { capi::pa_stream_get_device_name(self.ptr) };
696 match ptr.is_null() {
697 false => Some(unsafe { CStr::from_ptr(ptr).to_string_lossy() }),
698 true => None,
699 }
700 }
701
702 /// Checks whether or not the sink or source this stream is connected to has been suspended.
703 pub fn is_suspended(&self) -> Result<bool, PAErr> {
704 match unsafe { capi::pa_stream_is_suspended(self.ptr) } {
705 0 => Ok(false),
706 1 => Ok(true),
707 e => Err(PAErr(e)),
708 }
709 }
710
711 /// Checks whether or not this stream has been corked.
712 pub fn is_corked(&self) -> Result<bool, PAErr> {
713 match unsafe { capi::pa_stream_is_corked(self.ptr) } {
714 0 => Ok(false),
715 1 => Ok(true),
716 e => Err(PAErr(e)),
717 }
718 }
719
720 /// Connects the stream to a sink.
721 ///
722 /// It is strongly recommended to pass `None` in both `dev` and `volume` and to set neither
723 /// [`FlagSet::START_MUTED`] nor [`FlagSet::START_UNMUTED`] -- unless these options are directly
724 /// dependent on user input or configuration.
725 ///
726 /// If you follow this rule then the sound server will have the full flexibility to choose the
727 /// device, volume and mute status automatically, based on server-side policies, heuristics and
728 /// stored information from previous uses. Also the server may choose to reconfigure audio
729 /// devices to make other sinks/sources or capabilities available to be able to accept the
730 /// stream.
731 ///
732 /// Before PA 0.9.20 it was not defined whether the ‘volume’ parameter was interpreted relative
733 /// to the sink’s current volume or treated as an absolute device volume. Since PA 0.9.20 it is
734 /// an absolute volume when the sink is in flat volume mode, and relative otherwise, thus making
735 /// sure the volume passed here has always the same semantics as the volume passed to
736 /// [`Introspector::set_sink_input_volume()`]. It is possible to figure out whether flat volume
737 /// mode is in effect for a given sink by calling [`Introspector::get_sink_info_by_name()`].
738 ///
739 /// Since PA 5.0, it’s possible to specify a single-channel volume even if the stream has
740 /// multiple channels. In that case the same volume is applied to all channels.
741 ///
742 /// # Params
743 ///
744 /// * `dev`: Name of the sink to connect to, or `None` to let the server decide
745 /// * `attr`: Buffering attributes, or `None` for default
746 /// * `flags`: Additional flags, or `0` for default
747 /// * `volume`: Initial volume, or `None` for default
748 /// * `sync_stream`: Synchronize this stream with the specified one, or `None` for a standalone
749 /// stream.
750 ///
751 /// [`Introspector::set_sink_input_volume()`]: crate::context::introspect::Introspector::set_sink_input_volume
752 /// [`Introspector::get_sink_info_by_name()`]: crate::context::introspect::Introspector::get_sink_info_by_name
753 pub fn connect_playback(&mut self, dev: Option<&str>, attr: Option<&def::BufferAttr>,
754 flags: FlagSet, volume: Option<&ChannelVolumes>, sync_stream: Option<&mut Self>)
755 -> Result<(), PAErr>
756 {
757 // Warning: New CStrings will be immediately freed if not bound to a variable, leading to
758 // as_ptr() giving dangling pointers!
759 let c_dev = match dev {
760 Some(dev) => CString::new(dev).unwrap(),
761 None => CString::new("").unwrap(),
762 };
763
764 let p_attr = attr.map_or(null::<capi::pa_buffer_attr>(), |a| a.as_ref());
765 let p_vol = volume.map_or(null::<capi::pa_cvolume>(), |v| v.as_ref());
766 let p_sync = sync_stream.map_or(null_mut::<StreamInternal>(), |s| s.ptr);
767 let p_dev = dev.map_or(null::<c_char>(), |_| c_dev.as_ptr() as *const c_char);
768
769 let r = unsafe {
770 capi::pa_stream_connect_playback(self.ptr, p_dev, p_attr, flags.bits(), p_vol, p_sync)
771 };
772 match r {
773 0 => Ok(()),
774 e => Err(PAErr(e)),
775 }
776 }
777
778 /// Connects the stream to a source.
779 ///
780 /// # Params
781 ///
782 /// * `dev`: Name of the source to connect to, or `None` to let the server decide
783 /// * `attr`: Buffering attributes, or `None` for default
784 /// * `flags`: Additional flags, or `0` for default
785 pub fn connect_record(&mut self, dev: Option<&str>, attr: Option<&def::BufferAttr>,
786 flags: FlagSet) -> Result<(), PAErr>
787 {
788 // Warning: New CStrings will be immediately freed if not bound to a variable, leading to
789 // as_ptr() giving dangling pointers!
790 let c_dev = match dev {
791 Some(dev) => CString::new(dev).unwrap(),
792 None => CString::new("").unwrap(),
793 };
794
795 let p_attr = attr.map_or(null::<capi::pa_buffer_attr>(), |a| a.as_ref());
796 let p_dev = dev.map_or(null::<c_char>(), |_| c_dev.as_ptr() as *const c_char);
797
798 match unsafe { capi::pa_stream_connect_record(self.ptr, p_dev, p_attr, flags.bits()) } {
799 0 => Ok(()),
800 e => Err(PAErr(e)),
801 }
802 }
803
804 /// Makes this stream a sample upload stream.
805 ///
806 /// (See [`scache`](mod@crate::context::scache)).
807 pub fn connect_upload(&mut self, length: usize) -> Result<(), PAErr> {
808 match unsafe { capi::pa_stream_connect_upload(self.ptr, length) } {
809 0 => Ok(()),
810 e => Err(PAErr(e)),
811 }
812 }
813
814 /// Finishes the sample upload, the stream name will become the sample name.
815 ///
816 /// You cancel a sample upload by issuing [`disconnect()`](Self::disconnect).
817 pub fn finish_upload(&mut self) -> Result<(), PAErr> {
818 match unsafe { capi::pa_stream_finish_upload(self.ptr) } {
819 0 => Ok(()),
820 e => Err(PAErr(e)),
821 }
822 }
823
824 /// Disconnects a stream from a source/sink.
825 pub fn disconnect(&mut self) -> Result<(), PAErr> {
826 match unsafe { capi::pa_stream_disconnect(self.ptr) } {
827 0 => Ok(()),
828 e => Err(PAErr(e)),
829 }
830 }
831
832 /// Prepares writing data to the server (for playback streams).
833 ///
834 /// This function may be used to optimize the number of memory copies when doing playback
835 /// (“zero-copy”). It is recommended to call this function before each call to [`write()`]. It
836 /// is used to obtain a chunk of PA internally allocated memory, into which you can directly
837 /// write your data before calling [`write()`] to actually execute the write.
838 ///
839 /// This function should be called with `nbytes` set to the number of bytes you want to write,
840 /// or `None`, in which case the size will be chosen automatically (which is recommended).
841 ///
842 /// The return value is a `Result` type, with the `Ok` variant wrapping an `Option`. `Err` will
843 /// be returned if PA encountered an error; `Ok(None)` will be returned if it appeared to be
844 /// successful, but the pointer returned was `NULL`, otherwise the buffer will be returned as
845 /// `Ok(Some(_))`.
846 ///
847 /// After placing your data in the memory area returned, call [`write()`] with a sub-slice of
848 /// it, to actually execute the write. **Note**, the buffer may only be used once, i.e. if you
849 /// were thinking of getting a large buffer, placing a large chunk of data into it, then perform
850 /// multiple small writes from it, you **cannot** do this. Any attempt at accessing the memory
851 /// returned after the following [`write()`] or [`cancel_write()`] is invalid.
852 ///
853 /// If you want to cancel a previously called `begin_write()` without calling [`write()`] use
854 /// [`cancel_write()`].
855 ///
856 /// The memory should **not** be explicitly freed by the caller.
857 ///
858 /// An invocation of [`write()`] should “quickly” follow a `begin_write()`. It is not
859 /// recommended letting an unbounded amount of time pass after calling `begin_write()` and
860 /// before calling [`write()`]. Calling `begin_write()` twice without calling [`write()`] or
861 /// [`cancel_write()`] in between will return exactly the same `data` pointer and `nbytes`
862 /// values.
863 ///
864 /// [`write()`]: Self::write
865 /// [`cancel_write()`]: Self::cancel_write
866 pub fn begin_write<'a>(&mut self, nbytes: Option<usize>)
867 -> Result<Option<&'a mut [u8]>, PAErr>
868 {
869 let mut data_ptr = null_mut::<c_void>();
870 // If user asks for size to be automatically chosen by PA, we pass in std::usize::MAX
871 // (-1 as size_t) to signal this.
872 let mut nbytes_tmp = nbytes.unwrap_or(std::usize::MAX);
873 match unsafe { capi::pa_stream_begin_write(self.ptr, &mut data_ptr, &mut nbytes_tmp) } {
874 0 => match data_ptr.is_null() {
875 true => Ok(None),
876 false => {
877 let slice =
878 unsafe { std::slice::from_raw_parts_mut(data_ptr as *mut u8, nbytes_tmp) };
879 Ok(Some(slice))
880 },
881 },
882 e => Err(PAErr(e)),
883 }
884 }
885
886 /// Reverses the effect of [`begin_write()`] dropping any data that has already been placed in
887 /// the memory area returned by [`begin_write()`].
888 ///
889 /// Only valid to call after a call to [`begin_write()`] has been made, and neither
890 /// `cancel_write()` nor [`write()`] have been called yet. Accessing the memory previously
891 /// returned by [`begin_write()`] after calling this function is invalid.
892 ///
893 /// [`write()`]: Self::write
894 /// [`begin_write()`]: Self::begin_write
895 pub fn cancel_write(&mut self) -> Result<(), PAErr> {
896 match unsafe { capi::pa_stream_cancel_write(self.ptr) } {
897 0 => Ok(()),
898 e => Err(PAErr(e)),
899 }
900 }
901
902 /// Writes some data to the server (for playback streams).
903 ///
904 /// If `free_cb` is provided, this routine is called when all data has been written out. An
905 /// internal reference to the specified data is kept, the data is not copied. If `None`, the
906 /// data is copied into an internal buffer.
907 ///
908 /// The client may freely seek around in the output buffer. For most applications it is typical
909 /// to pass `0` and [`SeekMode::Relative`] as values for the arguments `offset` and `seek`
910 /// respectively. After a successful write call the write index will be at the position after
911 /// where this chunk of data has been written to.
912 ///
913 /// As an optimization for avoiding needless memory copies you may call [`begin_write()`] before
914 /// this call and then place your audio data directly in the memory area returned by that call.
915 /// Then, pass a pointer to that memory area to `write()`. After the invocation of `write()` the
916 /// memory area may no longer be accessed. Any further explicit freeing of the memory area is
917 /// not necessary. It is OK to write to the memory area returned by [`begin_write()`] only
918 /// partially with this call, skipping bytes both at the end and at the beginning of the
919 /// reserved memory area.
920 ///
921 /// # Params
922 ///
923 /// * `data`: The data to write. The length must be in multiples of the stream’s sample spec
924 /// frame size.
925 /// * `free_cb`: A cleanup routine for the data or `None` to request an internal copy of the
926 /// data.
927 /// * `offset`: Offset for seeking. Must be `0` for upload streams. Must be in multiples of the
928 /// stream’s sample spec frame size.
929 /// * `seek`: Seek mode. Must be [`SeekMode::Relative`] for upload streams.
930 ///
931 /// [`begin_write()`]: Self::begin_write
932 pub fn write(&mut self, data: &[u8], free_cb: Option<def::FreeCb>, offset: i64,
933 seek: SeekMode) -> Result<(), PAErr>
934 {
935 debug_assert_eq!(0, data.len().checked_rem(self.get_sample_spec().unwrap().frame_size())
936 .unwrap());
937 let r = unsafe {
938 capi::pa_stream_write(self.ptr, data.as_ptr() as *const c_void, data.len(), free_cb,
939 offset, seek)
940 };
941 match r {
942 0 => Ok(()),
943 e => Err(PAErr(e)),
944 }
945 }
946
947 /// Writes some data to the server (for playback streams).
948 ///
949 /// This function does exactly the same as [`write()`] as though `None` had been specified for
950 /// the `free_cb` param. I.e. an internal copy will be made of the provided data.
951 ///
952 /// # Params
953 ///
954 /// * `data`: The data to write. The length must be in multiples of the stream’s sample spec
955 /// frame size.
956 /// * `offset`: Offset for seeking. Must be `0` for upload streams. Must be in multiples of the
957 /// stream’s sample spec frame size.
958 /// * `seek`: Seek mode. Must be [`SeekMode::Relative`] for upload streams.
959 ///
960 /// [`write()`]: Self::write
961 #[inline(always)]
962 pub fn write_copy(&mut self, data: &[u8], offset: i64, seek: SeekMode) -> Result<(), PAErr> {
963 self.write(data, None, offset, seek)
964 }
965
966 /// Writes some data to the server (for playback streams).
967 ///
968 /// This function does exactly the same as [`write()`] with the only difference being that a
969 /// void pointer is provided along with the `free_cb` callback pointer, and this void pointer
970 /// will be passed to the callback instead of the `data` pointer.
971 ///
972 /// # Params
973 ///
974 /// * `data`: The data to write. The length must be in multiples of the stream’s sample spec
975 /// frame size.
976 /// * `free_cb`: A cleanup routine for the data or `None` to request an internal copy of the
977 /// data. If provided, the accompanying data pointer will be supplied to the callback.
978 /// * `offset`: Offset for seeking. Must be `0` for upload streams.
979 /// * `seek`: Seek mode, must be [`SeekMode::Relative`] for upload streams.
980 ///
981 /// [`write()`]: Self::write
982 #[cfg(any(doc, feature = "pa_v6"))]
983 #[cfg_attr(docsrs, doc(cfg(feature = "pa_v6")))]
984 pub fn write_ext_free(&mut self, data: &[u8], free_cb: Option<(def::FreeCb, *mut c_void)>,
985 offset: i64, seek: SeekMode) -> Result<(), PAErr>
986 {
987 let (cb_f, cb_d) = match free_cb {
988 Some((f, d)) => (Some(f), d),
989 None => (None, null_mut::<c_void>()),
990 };
991 debug_assert_eq!(0, data.len().checked_rem(self.get_sample_spec().unwrap().frame_size())
992 .unwrap());
993 let r = unsafe {
994 capi::pa_stream_write_ext_free(self.ptr, data.as_ptr() as *const c_void, data.len(),
995 cb_f, cb_d, offset, seek.into())
996 };
997 match r {
998 0 => Ok(()),
999 e => Err(PAErr(e)),
1000 }
1001 }
1002
1003 /// Reads the next fragment from the buffer (for recording streams).
1004 ///
1005 /// This function returns one of the [`PeekResult`] variants - either [`Empty`], [`Hole`] or
1006 /// [`Data`]:
1007 ///
1008 /// * If there is data at the current read index, the [`Data`] variant will be returned, which
1009 /// contains a slice giving a view of the data. (The length of this slice can be less or more
1010 /// than a complete fragment). This is pointing into an internal buffer, so obviously you
1011 /// must make a copy of it if you want to keep it.
1012 /// * If there is no data at the current read index, it means that either the buffer is empty
1013 /// or it contains a hole (that is, the write index is ahead of the read index but there’s no
1014 /// data where the read index points at). If the buffer is empty, the [`Empty`] result
1015 /// variant will be returned. If there is a hole, the [`Hole`] variant will be returned,
1016 /// containing the length of the hole in bytes.
1017 ///
1018 /// Use [`discard()`] to actually remove the data from the buffer and move the read index
1019 /// forward. [`discard()`] should not be called if the buffer is empty, but it should be called
1020 /// if there is a hole.
1021 ///
1022 /// [`Empty`]: PeekResult::Empty
1023 /// [`Hole`]: PeekResult::Hole
1024 /// [`Data`]: PeekResult::Data
1025 /// [`discard()`]: Self::discard
1026 pub fn peek<'a>(&mut self) -> Result<PeekResult<'a>, PAErr> {
1027 let mut data_ptr = null::<c_void>();
1028 let mut nbytes: usize = 0;
1029 // Note, C function returns an i32, but documentation does not mention any use of it, so we
1030 // discard it.
1031 match unsafe { capi::pa_stream_peek(self.ptr, &mut data_ptr, &mut nbytes) } {
1032 0 => {
1033 if data_ptr.is_null() {
1034 match nbytes {
1035 0 => Ok(PeekResult::Empty),
1036 _ => Ok(PeekResult::Hole(nbytes)),
1037 }
1038 }
1039 else {
1040 let slice =
1041 unsafe { std::slice::from_raw_parts(data_ptr as *const u8, nbytes) };
1042 Ok(PeekResult::Data(slice))
1043 }
1044 },
1045 e => Err(PAErr(e)),
1046 }
1047 }
1048
1049 /// Removes the current fragment on record streams.
1050 ///
1051 /// It is invalid to do this without first calling [`peek()`](Self::peek).
1052 ///
1053 /// Note: The original C function name used the term `drop`; We instead use `discard` here to
1054 /// avoid conflict with the Rust `Drop` trait!
1055 pub fn discard(&mut self) -> Result<(), PAErr> {
1056 match unsafe { capi::pa_stream_drop(self.ptr) } {
1057 0 => Ok(()),
1058 e => Err(PAErr(e)),
1059 }
1060 }
1061
1062 /// Gets the number of bytes requested by the server that have not yet been written.
1063 ///
1064 /// It is possible to write more than this amount, up to the stream’s [`buffer_attr.maxlength`]
1065 /// bytes. This is usually not desirable, though, as it would increase stream latency to be
1066 /// higher than requested ([`buffer_attr.tlength`]).
1067 ///
1068 /// [`buffer_attr.maxlength`]: crate::def::BufferAttr.maxlength
1069 /// [`buffer_attr.tlength`]: crate::def::BufferAttr.tlength
1070 pub fn writable_size(&self) -> Option<usize> {
1071 match unsafe { capi::pa_stream_writable_size(self.ptr) } {
1072 std::usize::MAX => None,
1073 r => Some(r),
1074 }
1075 }
1076
1077 /// Gets the number of bytes that may be read using [`peek()`](Self::peek).
1078 ///
1079 /// Returns `None` on error.
1080 pub fn readable_size(&self) -> Option<usize> {
1081 match unsafe { capi::pa_stream_readable_size(self.ptr) } {
1082 std::usize::MAX => None,
1083 r => Some(r),
1084 }
1085 }
1086
1087 /// Drains a playback stream.
1088 ///
1089 /// Use this for notification when the playback buffer is empty after playing all the audio in
1090 /// the buffer. Please note that only one drain operation per stream may be issued at a time.
1091 ///
1092 /// The optional callback must accept a `bool`, which indicates success.
1093 ///
1094 /// Panics if the underlying C function returns a null pointer.
1095 pub fn drain(&mut self, callback: Option<Box<dyn FnMut(bool) + 'static>>)
1096 -> Operation<dyn FnMut(bool)>
1097 {
1098 let (cb_fn, cb_data): (Option<extern "C" fn(_, _, _)>, _) =
1099 get_su_capi_params::<_, _>(callback, success_cb_proxy);
1100 let ptr = unsafe { capi::pa_stream_drain(self.ptr, cb_fn, cb_data) };
1101 Operation::from_raw(ptr, cb_data as *mut Box<dyn FnMut(bool)>)
1102 }
1103
1104 /// Requests a timing info structure update for a stream.
1105 ///
1106 /// Use [`get_timing_info()`] to get access to the raw timing data, or [`get_time()`] or
1107 /// [`get_latency()`] to get cleaned up values.
1108 ///
1109 /// The optional callback must accept a `bool`, which indicates success.
1110 ///
1111 /// Panics if the underlying C function returns a null pointer.
1112 ///
1113 /// [`get_timing_info()`]: Self::get_timing_info
1114 /// [`get_time()`]: Self::get_time
1115 /// [`get_latency()`]: Self::get_latency
1116 pub fn update_timing_info(&mut self, callback: Option<Box<dyn FnMut(bool) + 'static>>)
1117 -> Operation<dyn FnMut(bool)>
1118 {
1119 let (cb_fn, cb_data): (Option<extern "C" fn(_, _, _)>, _) =
1120 get_su_capi_params::<_, _>(callback, success_cb_proxy);
1121 let ptr = unsafe { capi::pa_stream_update_timing_info(self.ptr, cb_fn, cb_data) };
1122 Operation::from_raw(ptr, cb_data as *mut Box<dyn FnMut(bool)>)
1123 }
1124
1125 /// Sets the callback function that is called whenever the state of the stream changes.
1126 pub fn set_state_callback(&mut self, callback: Option<Box<dyn FnMut() + 'static>>) {
1127 let saved = &mut self.cb_ptrs.set_state;
1128 *saved = NotifyCb::new(callback);
1129 let (cb_fn, cb_data) = saved.get_capi_params(notify_cb_proxy);
1130 unsafe { capi::pa_stream_set_state_callback(self.ptr, cb_fn, cb_data); }
1131 }
1132
1133 /// Sets the callback function that is called when new data may be written to the stream.
1134 ///
1135 /// The callback accepts an argument giving the number of bytes.
1136 pub fn set_write_callback(&mut self, callback: Option<Box<dyn FnMut(usize) + 'static>>) {
1137 let saved = &mut self.cb_ptrs.write;
1138 *saved = RequestCb::new(callback);
1139 let (cb_fn, cb_data) = saved.get_capi_params(request_cb_proxy);
1140 unsafe { capi::pa_stream_set_write_callback(self.ptr, cb_fn, cb_data); }
1141 }
1142
1143 /// Sets the callback function that is called when new data is available from the stream.
1144 ///
1145 /// The callback accepts an argument giving the number of bytes.
1146 pub fn set_read_callback(&mut self, callback: Option<Box<dyn FnMut(usize) + 'static>>) {
1147 let saved = &mut self.cb_ptrs.read;
1148 *saved = RequestCb::new(callback);
1149 let (cb_fn, cb_data) = saved.get_capi_params(request_cb_proxy);
1150 unsafe { capi::pa_stream_set_read_callback(self.ptr, cb_fn, cb_data); }
1151 }
1152
1153 /// Sets the callback function that is called when a buffer overflow happens. (Only for playback
1154 /// streams).
1155 pub fn set_overflow_callback(&mut self, callback: Option<Box<dyn FnMut() + 'static>>) {
1156 let saved = &mut self.cb_ptrs.overflow;
1157 *saved = NotifyCb::new(callback);
1158 let (cb_fn, cb_data) = saved.get_capi_params(notify_cb_proxy);
1159 unsafe { capi::pa_stream_set_overflow_callback(self.ptr, cb_fn, cb_data); }
1160 }
1161
1162 /// Gets at what position the latest underflow occurred.
1163 ///
1164 /// `None` is returned if this information is not known (e.g. if no underflow has occurred).
1165 ///
1166 /// This can be used inside the underflow callback to get information about the current
1167 /// underflow. (Only for playback streams).
1168 pub fn get_underflow_index(&self) -> Option<u64> {
1169 match unsafe { capi::pa_stream_get_underflow_index(self.ptr) } {
1170 r if r < 0 => None,
1171 r => Some(r as u64),
1172 }
1173 }
1174
1175 /// Sets the callback function that is called when a buffer underflow happens.
1176 ///
1177 /// (Only for playback streams).
1178 pub fn set_underflow_callback(&mut self, callback: Option<Box<dyn FnMut() + 'static>>) {
1179 let saved = &mut self.cb_ptrs.underflow;
1180 *saved = NotifyCb::new(callback);
1181 let (cb_fn, cb_data) = saved.get_capi_params(notify_cb_proxy);
1182 unsafe { capi::pa_stream_set_underflow_callback(self.ptr, cb_fn, cb_data); }
1183 }
1184
1185 /// Sets the callback function that is called when the server starts playback after an underrun
1186 /// or on initial startup.
1187 ///
1188 /// This only informs that audio is flowing again, it is no indication that audio started to
1189 /// reach the speakers already. (Only for playback streams).
1190 pub fn set_started_callback(&mut self, callback: Option<Box<dyn FnMut() + 'static>>) {
1191 let saved = &mut self.cb_ptrs.started;
1192 *saved = NotifyCb::new(callback);
1193 let (cb_fn, cb_data) = saved.get_capi_params(notify_cb_proxy);
1194 unsafe { capi::pa_stream_set_started_callback(self.ptr, cb_fn, cb_data); }
1195 }
1196
1197 /// Sets the callback function that is called whenever a latency information update happens.
1198 ///
1199 /// Useful on [`FlagSet::AUTO_TIMING_UPDATE`] streams only.
1200 pub fn set_latency_update_callback(&mut self, callback: Option<Box<dyn FnMut() + 'static>>) {
1201 let saved = &mut self.cb_ptrs.latency_update;
1202 *saved = NotifyCb::new(callback);
1203 let (cb_fn, cb_data) = saved.get_capi_params(notify_cb_proxy);
1204 unsafe { capi::pa_stream_set_latency_update_callback(self.ptr, cb_fn, cb_data); }
1205 }
1206
1207 /// Sets the callback function that is called whenever the stream is moved to a different
1208 /// sink/source.
1209 ///
1210 /// Use [`get_device_name()`] or [`get_device_index()`] to query the new sink/source.
1211 ///
1212 /// [`get_device_name()`]: Self::get_device_name
1213 /// [`get_device_index()`]: Self::get_device_index
1214 pub fn set_moved_callback(&mut self, callback: Option<Box<dyn FnMut() + 'static>>) {
1215 let saved = &mut self.cb_ptrs.moved;
1216 *saved = NotifyCb::new(callback);
1217 let (cb_fn, cb_data) = saved.get_capi_params(notify_cb_proxy);
1218 unsafe { capi::pa_stream_set_moved_callback(self.ptr, cb_fn, cb_data); }
1219 }
1220
1221 /// Sets the callback function that is called whenever the sink/source this stream is connected
1222 /// to is suspended or resumed.
1223 ///
1224 /// Use [`is_suspended()`] to query the new suspend status. Please note that the suspend status
1225 /// might also change when the stream is moved between devices. Thus if you call this function
1226 /// you very likely want to call [`set_moved_callback()`] too.
1227 ///
1228 /// [`is_suspended()`]: Self::is_suspended
1229 /// [`set_moved_callback()`]: Self::set_moved_callback
1230 pub fn set_suspended_callback(&mut self, callback: Option<Box<dyn FnMut() + 'static>>) {
1231 let saved = &mut self.cb_ptrs.suspended;
1232 *saved = NotifyCb::new(callback);
1233 let (cb_fn, cb_data) = saved.get_capi_params(notify_cb_proxy);
1234 unsafe { capi::pa_stream_set_suspended_callback(self.ptr, cb_fn, cb_data); }
1235 }
1236
1237 /// Sets the callback function that is called whenever a meta/policy control event is received.
1238 ///
1239 /// The callback is given a name which represents what event occurred. The set of defined events
1240 /// can be extended at any time. Also, server modules may introduce additional message types so
1241 /// make sure that your callback function ignores messages it doesn’t know. Some well known
1242 /// event names can be found in the [`event_names`](mod@self::event_names) submodule. It is also
1243 /// given an (owned) property list.
1244 pub fn set_event_callback(&mut self,
1245 callback: Option<Box<dyn FnMut(String, Proplist) + 'static>>)
1246 {
1247 let saved = &mut self.cb_ptrs.event;
1248 *saved = EventCb::new(callback);
1249 let (cb_fn, cb_data) = saved.get_capi_params(event_cb_proxy);
1250 unsafe { capi::pa_stream_set_event_callback(self.ptr, cb_fn, cb_data); }
1251 }
1252
1253 /// Sets the callback function that is called whenever the buffer attributes on the server side
1254 /// change.
1255 ///
1256 /// Please note that the buffer attributes can change when moving a stream to a different
1257 /// sink/source too, hence if you use this callback you should use [`set_moved_callback()`] as
1258 /// well.
1259 ///
1260 /// [`set_moved_callback()`]: Self::set_moved_callback
1261 pub fn set_buffer_attr_callback(&mut self, callback: Option<Box<dyn FnMut() + 'static>>) {
1262 let saved = &mut self.cb_ptrs.buffer_attr;
1263 *saved = NotifyCb::new(callback);
1264 let (cb_fn, cb_data) = saved.get_capi_params(notify_cb_proxy);
1265 unsafe { capi::pa_stream_set_buffer_attr_callback(self.ptr, cb_fn, cb_data); }
1266 }
1267
1268 /// Pauses playback of this stream temporarily.
1269 ///
1270 /// This simply calls [`set_corked_state()`] with a value of `true`.
1271 ///
1272 /// [`set_corked_state()`]: Self::set_corked_state
1273 #[inline(always)]
1274 pub fn cork(&mut self, callback: Option<Box<dyn FnMut(bool) + 'static>>)
1275 -> Operation<dyn FnMut(bool)>
1276 {
1277 self.set_corked_state(true, callback)
1278 }
1279
1280 /// Resumes playback of this stream.
1281 ///
1282 /// This simply calls [`set_corked_state()`] with a value of `false`.
1283 ///
1284 /// [`set_corked_state()`]: Self::set_corked_state
1285 #[inline(always)]
1286 pub fn uncork(&mut self, callback: Option<Box<dyn FnMut(bool) + 'static>>)
1287 -> Operation<dyn FnMut(bool)>
1288 {
1289 self.set_corked_state(false, callback)
1290 }
1291
1292 /// Pauses or resumes playback of this stream.
1293 ///
1294 /// Available on both playback and recording streams.
1295 ///
1296 /// Set state to `true` to cork (pause) the stream. Set state to `false` to uncork (resume) the
1297 /// stream. Alternatively [`cork()`] and [`uncork()`] helper functions can be used.
1298 ///
1299 /// The operation is executed as quickly as possible. If a cork is very quickly followed by an
1300 /// uncork, or vice versa, this might not actually have any effect on the stream that is output.
1301 /// You can use [`is_corked()`] to find out whether the stream is currently paused or not.
1302 /// Normally a stream will be created in uncorked state. If you pass [`FlagSet::START_CORKED`]
1303 /// as a flag when connecting the stream, it will be created in corked state.
1304 ///
1305 /// The optional callback must accept a `bool`, which indicates success.
1306 ///
1307 /// Panics if the underlying C function returns a null pointer.
1308 ///
1309 /// [`is_corked()`]: Self::is_corked
1310 /// [`cork()`]: Self::cork
1311 /// [`uncork()`]: Self::uncork
1312 pub fn set_corked_state(&mut self, state: bool, callback: Option<Box<dyn FnMut(bool) + 'static>>)
1313 -> Operation<dyn FnMut(bool)>
1314 {
1315 let (cb_fn, cb_data): (Option<extern "C" fn(_, _, _)>, _) =
1316 get_su_capi_params::<_, _>(callback, success_cb_proxy);
1317 let ptr = unsafe { capi::pa_stream_cork(self.ptr, state as i32, cb_fn, cb_data) };
1318 Operation::from_raw(ptr, cb_data as *mut Box<dyn FnMut(bool)>)
1319 }
1320
1321 /// Flushes the playback or record buffer of this stream.
1322 ///
1323 /// This discards any audio data in the buffer. Most of the time you’re better off using the
1324 /// parameter `seek` of [`write()`](Self::write) instead of this function.
1325 ///
1326 /// The optional callback must accept a `bool`, which indicates success.
1327 ///
1328 /// Panics if the underlying C function returns a null pointer.
1329 pub fn flush(&mut self, callback: Option<Box<dyn FnMut(bool) + 'static>>)
1330 -> Operation<dyn FnMut(bool)>
1331 {
1332 let (cb_fn, cb_data): (Option<extern "C" fn(_, _, _)>, _) =
1333 get_su_capi_params::<_, _>(callback, success_cb_proxy);
1334 let ptr = unsafe { capi::pa_stream_flush(self.ptr, cb_fn, cb_data) };
1335 Operation::from_raw(ptr, cb_data as *mut Box<dyn FnMut(bool)>)
1336 }
1337
1338 /// Re-enables prebuffering if specified in the [`BufferAttr`] structure.
1339 ///
1340 /// Available for playback streams only.
1341 ///
1342 /// The optional callback must accept a `bool`, which indicates success.
1343 ///
1344 /// Panics if the underlying C function returns a null pointer.
1345 ///
1346 /// [`BufferAttr`]: crate::def::BufferAttr
1347 pub fn prebuf(&mut self, callback: Option<Box<dyn FnMut(bool) + 'static>>)
1348 -> Operation<dyn FnMut(bool)>
1349 {
1350 let (cb_fn, cb_data): (Option<extern "C" fn(_, _, _)>, _) =
1351 get_su_capi_params::<_, _>(callback, success_cb_proxy);
1352 let ptr = unsafe { capi::pa_stream_prebuf(self.ptr, cb_fn, cb_data) };
1353 Operation::from_raw(ptr, cb_data as *mut Box<dyn FnMut(bool)>)
1354 }
1355
1356 /// Requests immediate start of playback on this stream.
1357 ///
1358 /// This disables prebuffering temporarily if specified in the [`BufferAttr`] structure.
1359 /// Available for playback streams only.
1360 ///
1361 /// The optional callback must accept a `bool`, which indicates success.
1362 ///
1363 /// Panics if the underlying C function returns a null pointer.
1364 ///
1365 /// [`BufferAttr`]: crate::def::BufferAttr
1366 pub fn trigger(&mut self, callback: Option<Box<dyn FnMut(bool) + 'static>>)
1367 -> Operation<dyn FnMut(bool)>
1368 {
1369 let (cb_fn, cb_data): (Option<extern "C" fn(_, _, _)>, _) =
1370 get_su_capi_params::<_, _>(callback, success_cb_proxy);
1371 let ptr = unsafe { capi::pa_stream_trigger(self.ptr, cb_fn, cb_data) };
1372 Operation::from_raw(ptr, cb_data as *mut Box<dyn FnMut(bool)>)
1373 }
1374
1375 /// Renames the stream.
1376 ///
1377 /// The optional callback must accept a `bool`, which indicates success.
1378 ///
1379 /// Panics if the underlying C function returns a null pointer.
1380 pub fn set_name(&mut self, name: &str, callback: Option<Box<dyn FnMut(bool) + 'static>>)
1381 -> Operation<dyn FnMut(bool)>
1382 {
1383 // Warning: New CStrings will be immediately freed if not bound to a
1384 // variable, leading to as_ptr() giving dangling pointers!
1385 let c_name = CString::new(name).unwrap();
1386
1387 let (cb_fn, cb_data): (Option<extern "C" fn(_, _, _)>, _) =
1388 get_su_capi_params::<_, _>(callback, success_cb_proxy);
1389 let ptr = unsafe { capi::pa_stream_set_name(self.ptr, c_name.as_ptr(), cb_fn, cb_data) };
1390 Operation::from_raw(ptr, cb_data as *mut Box<dyn FnMut(bool)>)
1391 }
1392
1393 /// Gets the current playback/recording time.
1394 ///
1395 /// This is based on the data in the timing info structure returned by [`get_timing_info()`].
1396 /// The returned time is in the sound card clock domain, which usually runs at a slightly
1397 /// different rate than the system clock.
1398 ///
1399 /// This function will usually only return new data if a timing info update has been received.
1400 /// Only if timing interpolation has been requested ([`FlagSet::INTERPOLATE_TIMING`]) the data
1401 /// from the last timing update is used for an estimation of the current playback/recording time
1402 /// based on the local time that passed since the timing info structure has been acquired.
1403 ///
1404 /// The time value returned by this function is guaranteed to increase monotonically (the
1405 /// returned value is always greater or equal to the value returned by the last call). This
1406 /// behaviour can be disabled by using [`FlagSet::NOT_MONOTONIC`]. This may be desirable to
1407 /// better deal with bad estimations of transport latencies, but may have strange effects if the
1408 /// application is not able to deal with time going ‘backwards’.
1409 ///
1410 /// The time interpolator activated by [`FlagSet::INTERPOLATE_TIMING`] favours ‘smooth’ time
1411 /// graphs over accurate ones to improve the smoothness of UI operations that are tied to the
1412 /// audio clock. If accuracy is more important to you, you might need to estimate your timing
1413 /// based on the data from [`get_timing_info()`] yourself or not work with interpolated timing
1414 /// at all and instead always query the server side for the most up to date timing with
1415 /// [`update_timing_info()`].
1416 ///
1417 /// If no timing information has been received yet this call will return `Ok(None)`. For more
1418 /// details see [`get_timing_info()`].
1419 ///
1420 /// [`get_timing_info()`]: Self::get_timing_info
1421 /// [`update_timing_info()`]: Self::update_timing_info
1422 pub fn get_time(&self) -> Result<Option<MicroSeconds>, PAErr> {
1423 let mut r_usecs = MicroSeconds(0);
1424 match unsafe { capi::pa_stream_get_time(self.ptr, &mut r_usecs.0) } {
1425 0 => Ok(Some(r_usecs)),
1426 e if e == PAErr::from(error::Code::NoData).0 => Ok(None),
1427 e => Err(PAErr(e)),
1428 }
1429 }
1430
1431 /// Determines the total stream latency.
1432 ///
1433 /// This function is based on [`get_time()`]. The returned time is in the sound card clock
1434 /// domain, which usually runs at a slightly different rate than the system clock.
1435 ///
1436 /// In case the stream is a monitoring stream the result can be negative, i.e. the captured
1437 /// samples are not yet played, in which case `Ok(Latency::Negative(usecs))` will be returned
1438 /// instead of `Ok(Latency::Positive(usecs))`
1439 ///
1440 /// If no timing information has been received yet, this call will return `Ok(Latency::None)`.
1441 ///
1442 /// For more details see [`get_timing_info()`] and [`get_time()`].
1443 ///
1444 /// [`get_time()`]: Self::get_time
1445 /// [`get_timing_info()`]: Self::get_timing_info
1446 pub fn get_latency(&self) -> Result<Latency, PAErr> {
1447 let mut r_usecs = MicroSeconds(0);
1448 let mut negative: i32 = 0;
1449 match unsafe { capi::pa_stream_get_latency(self.ptr, &mut r_usecs.0, &mut negative) } {
1450 0 => match negative {
1451 1 => Ok(Latency::Negative(r_usecs)),
1452 _ => Ok(Latency::Positive(r_usecs)),
1453 },
1454 e if e == PAErr::from(error::Code::NoData).0 => Ok(Latency::None),
1455 e => Err(PAErr(e)),
1456 }
1457 }
1458
1459 /// Gets the latest raw timing data structure.
1460 ///
1461 /// The returned pointer refers to an internal read-only instance of the timing structure. The
1462 /// user should make a copy of this structure if wanting to modify it. An in-place update to
1463 /// this data structure may be requested using [`update_timing_info()`].
1464 ///
1465 /// If no timing information has been received before (i.e. by requesting
1466 /// [`update_timing_info()`] or by using [`FlagSet::AUTO_TIMING_UPDATE`]), this function will
1467 /// return `None` (as it will also if an error occurs).
1468 ///
1469 /// Please note that the `write_index` member field (and only this field) is updated on each
1470 /// [`write()`] call, not just when a timing update has been received.
1471 ///
1472 /// [`update_timing_info()`]: Self::update_timing_info
1473 /// [`write()`]: Self::write
1474 pub fn get_timing_info<'a>(&mut self) -> Option<&'a def::TimingInfo> {
1475 unsafe {
1476 let ptr = capi::pa_stream_get_timing_info(self.ptr);
1477 ptr.as_ref().map(|r| r.as_ref())
1478 }
1479 }
1480
1481 /// Gets a pointer to the stream’s sample specification.
1482 pub fn get_sample_spec<'a>(&mut self) -> Option<&'a sample::Spec> {
1483 unsafe {
1484 let ptr = capi::pa_stream_get_sample_spec(self.ptr);
1485 ptr.as_ref().map(|r| r.as_ref())
1486 }
1487 }
1488
1489 /// Gets a pointer to the stream’s channel map.
1490 pub fn get_channel_map<'a>(&mut self) -> Option<&'a channelmap::Map> {
1491 unsafe {
1492 let ptr = capi::pa_stream_get_channel_map(self.ptr);
1493 ptr.as_ref().map(|r| r.as_ref())
1494 }
1495 }
1496
1497 /// Gets a pointer to the stream’s format.
1498 pub fn get_format_info(&self) -> Option<format::Info> {
1499 let ptr = unsafe { capi::pa_stream_get_format_info(self.ptr) };
1500 match ptr.is_null() {
1501 false => Some(format::Info::from_raw_weak(ptr as *mut InfoInternal)),
1502 true => None,
1503 }
1504 }
1505
1506 /// Gets the per-stream server-side buffer metrics of the stream.
1507 ///
1508 /// Only valid after the stream has been connected successfully. This will return the actual
1509 /// configured buffering metrics, which may differ from what was requested during
1510 /// [`connect_record()`] or [`connect_playback()`]. This call will always return the actual
1511 /// per-stream server-side buffer metrics, regardless whether [`FlagSet::ADJUST_LATENCY`] is set
1512 /// or not.
1513 ///
1514 /// [`connect_record()`]: Self::connect_record
1515 /// [`connect_playback()`]: Self::connect_playback
1516 pub fn get_buffer_attr<'a>(&mut self) -> Option<&'a def::BufferAttr> {
1517 unsafe {
1518 let ptr = capi::pa_stream_get_buffer_attr(self.ptr);
1519 ptr.as_ref().map(|r| r.as_ref())
1520 }
1521 }
1522
1523 /// Changes the buffer metrics of the stream during playback.
1524 ///
1525 /// The server might have chosen different buffer metrics then requested. The selected metrics
1526 /// may be queried with [`get_buffer_attr()`] as soon as the callback is called. Only valid
1527 /// after the stream has been connected successfully. Please be aware of the slightly different
1528 /// semantics of the call depending whether [`FlagSet::ADJUST_LATENCY`] is set or not.
1529 ///
1530 /// The callback must accept a `bool`, which indicates success.
1531 ///
1532 /// Panics if the underlying C function returns a null pointer.
1533 ///
1534 /// [`get_buffer_attr()`]: Self::get_buffer_attr
1535 pub fn set_buffer_attr<F>(&mut self, attr: &def::BufferAttr, callback: F)
1536 -> Operation<dyn FnMut(bool)>
1537 where F: FnMut(bool) + 'static
1538 {
1539 let cb_data = box_closure_get_capi_ptr::<dyn FnMut(bool)>(Box::new(callback));
1540 let ptr = unsafe { capi::pa_stream_set_buffer_attr(self.ptr, attr.as_ref(),
1541 Some(success_cb_proxy), cb_data) };
1542 Operation::from_raw(ptr, cb_data as *mut Box<dyn FnMut(bool)>)
1543 }
1544
1545 /// Changes the stream sampling rate during playback.
1546 ///
1547 /// You need to pass [`FlagSet::VARIABLE_RATE`] in the flags parameter of [`connect_playback()`]
1548 /// if you plan to use this function. Only valid after the stream has been connected
1549 /// successfully.
1550 ///
1551 /// The callback must accept a `bool`, which indicates success.
1552 ///
1553 /// Panics if the underlying C function returns a null pointer.
1554 ///
1555 /// [`connect_playback()`]: Self::connect_playback
1556 pub fn update_sample_rate<F>(&mut self, rate: u32, callback: F) -> Operation<dyn FnMut(bool)>
1557 where F: FnMut(bool) + 'static
1558 {
1559 let cb_data = box_closure_get_capi_ptr::<dyn FnMut(bool)>(Box::new(callback));
1560 let ptr = unsafe { capi::pa_stream_update_sample_rate(self.ptr, rate,
1561 Some(success_cb_proxy), cb_data) };
1562 Operation::from_raw(ptr, cb_data as *mut Box<dyn FnMut(bool)>)
1563 }
1564
1565 /// Updates the property list of the sink input/source output of this stream, adding new
1566 /// entries.
1567 ///
1568 /// Please note that it is highly recommended to set as many properties initially via
1569 /// [`new_with_proplist()`] as possible instead a posteriori with this function, since that
1570 /// information may be used to route this stream to the right device.
1571 ///
1572 /// The callback must accept a `bool`, which indicates success.
1573 ///
1574 /// Panics if the underlying C function returns a null pointer.
1575 ///
1576 /// [`new_with_proplist()`]: Self::new_with_proplist
1577 pub fn update_proplist<F>(&mut self, mode: proplist::UpdateMode, proplist: &mut Proplist,
1578 callback: F) -> Operation<dyn FnMut(bool)>
1579 where F: FnMut(bool) + 'static
1580 {
1581 let cb_data = box_closure_get_capi_ptr::<dyn FnMut(bool)>(Box::new(callback));
1582 let ptr = unsafe { capi::pa_stream_proplist_update(self.ptr, mode, proplist.0.ptr,
1583 Some(success_cb_proxy), cb_data) };
1584 Operation::from_raw(ptr, cb_data as *mut Box<dyn FnMut(bool)>)
1585 }
1586
1587 /// Updates the property list of the sink input/source output of this stream, removing entries.
1588 ///
1589 /// The callback must accept a `bool`, which indicates success.
1590 ///
1591 /// Panics if the underlying C function returns a null pointer.
1592 pub fn remove_proplist<F>(&mut self, keys: &[&str], callback: F) -> Operation<dyn FnMut(bool)>
1593 where F: FnMut(bool) + 'static
1594 {
1595 // Warning: New CStrings will be immediately freed if not bound to a variable, leading to
1596 // as_ptr() giving dangling pointers!
1597 let mut c_keys: Vec<CString> = Vec::with_capacity(keys.len());
1598 for key in keys {
1599 c_keys.push(CString::new(*key).unwrap());
1600 }
1601
1602 // Capture array of pointers to the above CString values
1603 // We also add a null pointer entry on the end, as expected by the C function called here.
1604 let mut c_key_ptrs: Vec<*const c_char> = Vec::with_capacity(c_keys.len() + 1);
1605 for c_key in &c_keys {
1606 c_key_ptrs.push(c_key.as_ptr());
1607 }
1608 c_key_ptrs.push(null());
1609
1610 let cb_data = box_closure_get_capi_ptr::<dyn FnMut(bool)>(Box::new(callback));
1611 let ptr = unsafe {
1612 capi::pa_stream_proplist_remove(self.ptr, c_key_ptrs.as_ptr(),
1613 Some(success_cb_proxy), cb_data)
1614 };
1615 Operation::from_raw(ptr, cb_data as *mut Box<dyn FnMut(bool)>)
1616 }
1617
1618 /// For record streams connected to a monitor source: monitors only a very specific sink input
1619 /// of the sink.
1620 ///
1621 /// This function needs to be called before [`connect_record()`](Self::connect_record) is
1622 /// called.
1623 pub fn set_monitor_stream(&mut self, sink_input_index: u32) -> Result<(), PAErr> {
1624 match unsafe { capi::pa_stream_set_monitor_stream(self.ptr, sink_input_index) } {
1625 0 => Ok(()),
1626 e => Err(PAErr(e)),
1627 }
1628 }
1629
1630 /// Gets the sink input index previously set with [`set_monitor_stream()`].
1631 ///
1632 /// [`set_monitor_stream()`]: Self::set_monitor_stream
1633 pub fn get_monitor_stream(&self) -> Option<u32> {
1634 match unsafe { capi::pa_stream_get_monitor_stream(self.ptr) } {
1635 def::INVALID_INDEX => None,
1636 r => Some(r),
1637 }
1638 }
1639}
1640
1641impl Drop for Stream {
1642 fn drop(&mut self) {
1643 // Throw away the `Result` from disconnecting, it may legitimately be bad if stream failed.
1644 // See https://github.com/jnqnfe/pulse-binding-rust/issues/11
1645 let _ = self.disconnect();
1646 unsafe { capi::pa_stream_unref(self.ptr) };
1647 self.ptr = null_mut::<StreamInternal>();
1648 }
1649}
1650
1651/// Proxy for completion success callbacks.
1652///
1653/// Warning: This is for single-use cases only! It destroys the actual closure callback.
1654extern "C"
1655fn success_cb_proxy(_: *mut StreamInternal, success: i32, userdata: *mut c_void) {
1656 let success_actual = match success { 0 => false, _ => true };
1657 let _ = std::panic::catch_unwind(|| {
1658 // Note, destroys closure callback after use - restoring outer box means it gets dropped
1659 let mut callback = get_su_callback::<dyn FnMut(bool)>(userdata);
1660 (callback)(success_actual);
1661 });
1662}
1663
1664/// Proxy for request callbacks.
1665///
1666/// Warning: This is for multi-use cases! It does **not** destroy the actual closure callback, which
1667/// must be accomplished separately to avoid a memory leak.
1668extern "C"
1669fn request_cb_proxy(_: *mut StreamInternal, nbytes: usize, userdata: *mut c_void) {
1670 let _ = std::panic::catch_unwind(|| {
1671 let callback = RequestCb::get_callback(userdata);
1672 (callback)(nbytes);
1673 });
1674}
1675
1676/// Proxy for notify callbacks.
1677///
1678/// Warning: This is for multi-use cases! It does **not** destroy the actual closure callback, which
1679/// must be accomplished separately to avoid a memory leak.
1680extern "C"
1681fn notify_cb_proxy(_: *mut StreamInternal, userdata: *mut c_void) {
1682 let _ = std::panic::catch_unwind(|| {
1683 let callback = NotifyCb::get_callback(userdata);
1684 (callback)();
1685 });
1686}
1687
1688/// Proxy for event callbacks.
1689///
1690/// Warning: This is for multi-use cases! It does **not** destroy the actual closure callback, which
1691/// must be accomplished separately to avoid a memory leak.
1692extern "C"
1693fn event_cb_proxy(_: *mut StreamInternal, name: *const c_char, proplist: *mut ProplistInternal,
1694 userdata: *mut c_void)
1695{
1696 let _ = std::panic::catch_unwind(|| {
1697 assert!(!name.is_null());
1698 let n = {
1699 let tmp = unsafe { CStr::from_ptr(name) };
1700 tmp.to_string_lossy().into_owned()
1701 };
1702 let pl = Proplist::from_raw_weak(proplist);
1703
1704 let callback = EventCb::get_callback(userdata);
1705 (callback)(n, pl);
1706 });
1707}