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