1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
|
// Copyright The pipewire-rs Contributors.
// SPDX-License-Identifier: MIT
//! This file is a rustic interpretation of the the [PipeWire Tutorial 4][tut]
//!
//! tut: https://docs.pipewire.org/page_tutorial4.html
use pipewire as pw;
use pw::{properties::properties, spa};
use spa::pod::Pod;
pub const DEFAULT_RATE: u32 = 44100;
pub const DEFAULT_CHANNELS: u32 = 2;
pub const DEFAULT_VOLUME: f64 = 0.7;
pub const PI_2: f64 = std::f64::consts::PI + std::f64::consts::PI;
pub const CHAN_SIZE: usize = std::mem::size_of::<i16>();
pub fn main() -> Result<(), pw::Error> {
pw::init();
let mainloop = pw::main_loop::MainLoopRc::new(None)?;
let context = pw::context::ContextRc::new(&mainloop, None)?;
let core = context.connect_rc(None)?;
let data: f64 = 0.0;
let stream = pw::stream::StreamBox::new(
&core,
"audio-src",
properties! {
*pw::keys::MEDIA_TYPE => "Audio",
*pw::keys::MEDIA_ROLE => "Music",
*pw::keys::MEDIA_CATEGORY => "Playback",
*pw::keys::AUDIO_CHANNELS => "2",
},
)?;
let _listener = stream
.add_local_listener_with_user_data(data)
.process(|stream, acc| match stream.dequeue_buffer() {
None => println!("No buffer received"),
Some(mut buffer) => {
let datas = buffer.datas_mut();
let stride = CHAN_SIZE * DEFAULT_CHANNELS as usize;
let data = &mut datas[0];
let n_frames = if let Some(slice) = data.data() {
let n_frames = slice.len() / stride;
for i in 0..n_frames {
*acc += PI_2 * 440.0 / DEFAULT_RATE as f64;
if *acc >= PI_2 {
*acc -= PI_2
}
let val = (f64::sin(*acc) * DEFAULT_VOLUME * 16767.0) as i16;
for c in 0..DEFAULT_CHANNELS {
let start = i * stride + (c as usize * CHAN_SIZE);
let end = start + CHAN_SIZE;
let chan = &mut slice[start..end];
chan.copy_from_slice(&i16::to_le_bytes(val));
}
}
n_frames
} else {
0
};
let chunk = data.chunk_mut();
*chunk.offset_mut() = 0;
*chunk.stride_mut() = stride as _;
*chunk.size_mut() = (stride * n_frames) as _;
}
})
.register()?;
let mut audio_info = spa::param::audio::AudioInfoRaw::new();
audio_info.set_format(spa::param::audio::AudioFormat::S16LE);
audio_info.set_rate(DEFAULT_RATE);
audio_info.set_channels(DEFAULT_CHANNELS);
let mut position = [0; spa::param::audio::MAX_CHANNELS];
position[0] = spa_sys::SPA_AUDIO_CHANNEL_FL;
position[1] = spa_sys::SPA_AUDIO_CHANNEL_FR;
audio_info.set_position(position);
let values: Vec<u8> = pw::spa::pod::serialize::PodSerializer::serialize(
std::io::Cursor::new(Vec::new()),
&pw::spa::pod::Value::Object(pw::spa::pod::Object {
type_: spa_sys::SPA_TYPE_OBJECT_Format,
id: spa_sys::SPA_PARAM_EnumFormat,
properties: audio_info.into(),
}),
)
.unwrap()
.0
.into_inner();
let mut params = [Pod::from_bytes(&values).unwrap()];
stream.connect(
spa::utils::Direction::Output,
None,
pw::stream::StreamFlags::AUTOCONNECT
| pw::stream::StreamFlags::MAP_BUFFERS
| pw::stream::StreamFlags::RT_PROCESS,
&mut params,
)?;
mainloop.run();
Ok(())
}
|