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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
use crate::{error::Error, PlaySoundParams};
use quad_alsa_sys as sys;
use std::sync::mpsc;
mod consts {
pub const DEVICE: &'static str = "default\0";
pub const RATE: u32 = 44100;
pub const CHANNELS: u32 = 2;
pub const PCM_BUFFER_SIZE: u64 = 4096;
}
unsafe fn setup_pcm_device() -> *mut sys::snd_pcm_t {
let mut pcm_handle = std::ptr::null_mut();
if sys::snd_pcm_open(
&mut pcm_handle,
consts::DEVICE.as_ptr() as _,
sys::SND_PCM_STREAM_PLAYBACK,
0,
) < 0
{
panic!("Can't open PCM device.");
}
let mut hw_params: *mut sys::snd_pcm_hw_params_t = std::ptr::null_mut();
sys::snd_pcm_hw_params_malloc(&mut hw_params);
sys::snd_pcm_hw_params_any(pcm_handle, hw_params);
if sys::snd_pcm_hw_params_set_access(pcm_handle, hw_params, sys::SND_PCM_ACCESS_RW_INTERLEAVED)
< 0
{
panic!("Can't set interleaved mode");
}
if sys::snd_pcm_hw_params_set_format(pcm_handle, hw_params, sys::SND_PCM_FORMAT_FLOAT_LE) < 0 {
panic!("Can't set SND_PCM_FORMAT_FLOAT_LE format");
}
if sys::snd_pcm_hw_params_set_buffer_size(pcm_handle, hw_params, consts::PCM_BUFFER_SIZE) < 0 {
panic!("Cant's set buffer size");
}
if sys::snd_pcm_hw_params_set_channels(pcm_handle, hw_params, consts::CHANNELS) < 0 {
panic!("Can't set channels number.");
}
let mut rate = consts::RATE;
if sys::snd_pcm_hw_params_set_rate_near(pcm_handle, hw_params, &mut rate, std::ptr::null_mut())
< 0
{
panic!("Can't set rate.");
}
if sys::snd_pcm_hw_params(pcm_handle, hw_params) < 0 {
panic!("Can't set harware parameters.");
}
sys::snd_pcm_hw_params_free(hw_params);
let mut sw_params: *mut sys::snd_pcm_sw_params_t = std::ptr::null_mut();
if sys::snd_pcm_sw_params_malloc(&mut sw_params) < 0 {
panic!("cannot allocate software parameters structure");
}
if sys::snd_pcm_sw_params_current(pcm_handle, sw_params) < 0 {
panic!("cannot initialize software parameters structure");
}
if sys::snd_pcm_sw_params_set_start_threshold(pcm_handle, sw_params, 0) < 0 {
panic!("cannot set start mode");
}
if sys::snd_pcm_sw_params(pcm_handle, sw_params) < 0 {
panic!("cannot set software parameters");
}
sys::snd_pcm_sw_params_free(sw_params);
if sys::snd_pcm_prepare(pcm_handle) < 0 {
panic!("cannot prepare audio interface for use");
}
pcm_handle
}
unsafe fn audio_thread(mut mixer: crate::mixer::Mixer) {
let mut buffer: Vec<f32> = vec![0.0; consts::PCM_BUFFER_SIZE as usize * 2];
let pcm_handle = setup_pcm_device();
loop {
let frames_to_deliver = consts::PCM_BUFFER_SIZE as i64;
mixer.fill_audio_buffer(&mut buffer, frames_to_deliver as usize);
let frames_writen = sys::snd_pcm_writei(
pcm_handle,
buffer.as_ptr() as *const _,
frames_to_deliver as _,
);
if frames_writen == -libc::EPIPE as i64 {
println!("Underrun occured: -EPIPE, attempting recover");
sys::snd_pcm_recover(pcm_handle, frames_writen as _, 0);
}
if frames_writen > 0 && frames_writen != frames_to_deliver as _ {
println!("Underrun occured: frames_writen != frames_to_deliver, attempting recover");
sys::snd_pcm_recover(pcm_handle, frames_writen as _, 0);
}
}
}
pub struct AudioContext {
mixer_ctrl: crate::mixer::MixerControl,
}
impl AudioContext {
pub fn new() -> AudioContext {
use crate::mixer::Mixer;
let (mixer, mixer_ctrl) = Mixer::new();
std::thread::spawn(move || unsafe {
audio_thread(mixer);
});
AudioContext { mixer_ctrl }
}
}
pub struct Sound {
id: usize,
}
impl Sound {
pub fn load(ctx: &mut AudioContext, data: &[u8]) -> Sound {
let id = ctx.mixer_ctrl.load(data);
Sound { id }
}
pub fn play(&mut self, ctx: &mut AudioContext, params: PlaySoundParams) {
ctx.mixer_ctrl.play(self.id, params);
}
pub fn stop(&mut self, ctx: &mut AudioContext) {
ctx.mixer_ctrl.stop(self.id);
}
pub fn set_volume(&mut self, ctx: &mut AudioContext, volume: f32) {
ctx.mixer_ctrl.set_volume(self.id, volume);
}
}