Skip to content

Commit 3cedca0

Browse files
committed
feat: audio player thread that plays audio
1 parent d410615 commit 3cedca0

3 files changed

Lines changed: 136 additions & 86 deletions

File tree

player/src/audio.rs

Lines changed: 60 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
1-
use std::sync::Arc;
1+
use std::mem::MaybeUninit;
2+
use std::sync::{Arc, Mutex};
23

34
use opus::{Decoder, Encoder};
45
use protocol::AudioFrame;
5-
use ringbuf::{HeapRb, Rb};
6-
use symphonia::core::audio::{SampleBuffer};
7-
use symphonia::core::codecs::{DecoderOptions};
6+
use ringbuf::{LocalRb, Rb};
7+
use symphonia::core::audio::SampleBuffer;
8+
use symphonia::core::codecs::DecoderOptions;
89
use symphonia::core::errors::Error as SymphoniaError;
910
use symphonia::core::formats::FormatOptions;
1011
use symphonia::core::io::MediaSourceStream;
1112
use symphonia::core::meta::MetadataOptions;
1213
use symphonia::core::probe::Hint;
1314

1415
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
15-
use cpal::{Data, PlayStreamError, Sample, SampleFormat};
16-
use rubato::{Resampler, FftFixedIn};
16+
use cpal::{Data, PlayStreamError, Sample, SampleFormat, Stream};
17+
use rubato::{FftFixedIn, Resampler};
18+
1719
pub struct Track {
1820
pub samples: Arc<Vec<f32>>,
1921
pub sample_rate: u32,
@@ -80,10 +82,10 @@ impl Track {
8082

8183
samples.copy_interleaved_ref(decoded);
8284
for frame in samples.samples().chunks(spec.channels.count()) {
83-
for (chan, sample) in frame.iter().enumerate() {
84-
song_samples[chan].push(*sample)
85-
}
86-
}
85+
for (chan, sample) in frame.iter().enumerate() {
86+
song_samples[chan].push(*sample)
87+
}
88+
}
8789
} else {
8890
eprintln!("Empty packet encountered while loading song!");
8991
}
@@ -95,23 +97,20 @@ impl Track {
9597

9698
// resample to standard 48000 if needed
9799
let samples_correct_rate = if sample_rate != 48000 {
98-
99100
let l = samples_not_interleaved.as_ref().unwrap()[0].len().clone();
100-
let mut resampler = FftFixedIn::<f32>::new(
101-
sample_rate as usize,
102-
48000,
103-
l,
104-
100,
105-
2
106-
).unwrap();
107-
108-
resampler.process(&samples_not_interleaved.unwrap(), None).unwrap()
101+
let mut resampler =
102+
FftFixedIn::<f32>::new(sample_rate as usize, 48000, l, 100, 2).unwrap();
103+
104+
resampler
105+
.process(&samples_not_interleaved.unwrap(), None)
106+
.unwrap()
109107
} else {
110108
samples_not_interleaved.unwrap()
111109
};
112110

113111
// now we have to interleave it since we had to use the resampling thing
114-
let samples: Vec<f32> = samples_correct_rate[0].chunks(1)
112+
let samples: Vec<f32> = samples_correct_rate[0]
113+
.chunks(1)
115114
.zip(samples_correct_rate[1].chunks(1))
116115
.flat_map(|(a, b)| a.into_iter().chain(b))
117116
.copied()
@@ -121,7 +120,8 @@ impl Track {
121120
// but since we read like.. 2 samples at a time idk how
122121
// the way it is it's just too slow for anything realistically-sized
123122

124-
let mut encoder = opus::Encoder::new(48000, opus::Channels::Stereo, opus::Application::Audio).unwrap();
123+
let mut encoder =
124+
opus::Encoder::new(48000, opus::Channels::Stereo, opus::Application::Audio).unwrap();
125125
//encoder.set_bitrate(opus::Bitrate::Bits(256)).unwrap();
126126
Ok(Self {
127127
samples: Arc::new(samples),
@@ -150,43 +150,32 @@ impl Track {
150150
}
151151
}
152152

153+
type Ringbuf = LocalRb<f32, Vec<MaybeUninit<f32>>>;
154+
153155
pub struct Player {
154156
decoder: Decoder,
155-
buffer: HeapRb<Vec<u8>>,
157+
buffer: Arc<Mutex<Ringbuf>>,
158+
stream: Option<Stream>,
156159
}
157160
impl Player {
158161
pub fn new() -> Self {
159162
Self {
160163
decoder: Decoder::new(48000, opus::Channels::Stereo).unwrap(),
161-
buffer:HeapRb::<Vec<u8>>::new(1000),
164+
buffer: Arc::new(Mutex::new(Ringbuf::new(48000 * 10))), // 10s??
165+
stream: None,
162166
}
163167
}
164-
pub fn receive(&mut self, data: Vec<u8>) {
165-
self.buffer.push(data).unwrap();
166-
}
167-
pub fn decode_frame(&mut self) -> [f32; 960] {
168-
let mut pcm = [0.0; 960];
169-
let frame = self.buffer.pop().unwrap();
170-
let x = self.decoder.decode_float(&frame, &mut pcm, false).unwrap();
171-
pcm
172-
}
173168

174-
pub fn debug_export(&mut self) {
175-
let spec = hound::WavSpec {
176-
channels: 2,
177-
sample_rate: 48000,
178-
bits_per_sample: 32,
179-
sample_format: hound::SampleFormat::Float,
180-
};
181-
let mut writer = hound::WavWriter::create("blah.wav", spec).unwrap();
182-
loop {
183-
let frame = self.decode_frame();
184-
for s in frame {
185-
writer.write_sample(s).unwrap();
186-
}
187-
}
169+
// decode opus data when received and buffer the samples
170+
pub fn receive(&mut self, frame: Vec<u8>) {
171+
// allocate and decode into here
172+
let mut pcm = vec![0.0; 960];
173+
self.decoder.decode_float(&frame, &mut pcm, false).unwrap();
174+
175+
// copy to ringbuffer
176+
self.buffer.lock().unwrap().push_slice(&pcm);
188177
}
189-
/*
178+
190179
pub fn play(&mut self) {
191180
println!("Initialising local audio...");
192181
let host = cpal::default_host();
@@ -200,25 +189,38 @@ impl Player {
200189
let supported_config = supported_configs_range
201190
.next()
202191
.expect("no supported config?!")
203-
.with_max_sample_rate();
192+
.with_sample_rate(cpal::SampleRate(48000));
193+
// .with_max_sample_rate(); //???
204194

205195
let err_fn = |err| eprintln!("an error occurred on the output audio stream: {}", err);
206196
let sample_format = supported_config.sample_format();
197+
println!("sample format is {:?}", sample_format); //?? do we care about other sample formats
207198
let config = supported_config.into();
208199

209-
let stream = device.build_output_stream(
200+
let buffer_handle = self.buffer.clone();
201+
202+
let stream = device
203+
.build_output_stream(
210204
&config,
211-
move |data, info| Self::write_audio::<f32>(data, info, &self.buffer),
205+
move |data, info| write_audio::<f32>(data, info, &buffer_handle),
212206
err_fn,
213-
None
214-
).unwrap();
207+
None,
208+
)
209+
.unwrap();
215210

216-
println!("Starting audio stream");
217211
stream.play().unwrap();
212+
println!("Starting audio stream");
213+
214+
// dont let it be dropped
215+
self.stream = Some(stream);
218216
}
217+
}
219218

220-
fn write_audio<T: Sample>(data: &mut [f32], _: &cpal::OutputCallbackInfo, rb_audio: &HeapRb<Vec<u8>>) {
221-
println!("Len {}", data.len());
222-
// here you'd basically just
223-
} */
219+
// callback when the audio output needs more data
220+
fn write_audio<T: Sample>(
221+
out_data: &mut [f32],
222+
_: &cpal::OutputCallbackInfo,
223+
buffer: &Arc<Mutex<Ringbuf>>,
224+
) {
225+
buffer.lock().unwrap().pop_slice(out_data);
224226
}

player/src/main.rs

Lines changed: 75 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use futures::StreamExt;
22
use protocol::network::FrameStream;
3-
use protocol::{AuthenticateRequest, GetInfo, Message, PlaybackState, PlayingState};
3+
use protocol::{AudioFrame, AuthenticateRequest, GetInfo, Message, PlaybackState, PlayingState};
44
use tokio::time::timeout;
55
use tokio::{net::TcpStream, sync::mpsc};
66

@@ -24,7 +24,10 @@ async fn main() -> std::io::Result<()> {
2424
frames.send(bytes).await?; */
2525

2626
// handshake
27-
stream.send(&Message::Handshake("meow".to_string())).await.unwrap();
27+
stream
28+
.send(&Message::Handshake("meow".to_string()))
29+
.await
30+
.unwrap();
2831

2932
let hs_timeout = std::time::Duration::from_millis(1000);
3033
if let Ok(hsr) = timeout(hs_timeout, stream.get_inner().next()).await {
@@ -57,52 +60,97 @@ async fn main() -> std::io::Result<()> {
5760
id: my_id.clone(),
5861
name: my_id.clone().repeat(5), // TODO temp
5962
}))
60-
.await.unwrap();
61-
62-
let track = protocol::Track {
63-
path: "blah".to_string(),
64-
owner: 0,
65-
queue_position: 0,
66-
};
63+
.await
64+
.unwrap();
6765

68-
stream.send(&Message::QueuePush(track)).await.unwrap();
69-
stream.send(&Message::GetInfo(GetInfo::QueueList)).await.unwrap();
66+
let (message_tx, mut message_rx) = mpsc::unbounded_channel::<Message>();
7067

71-
let (tx, mut rx) = mpsc::unbounded_channel::<Message>();
68+
let (audio_tx, mut audio_rx) = std::sync::mpsc::channel::<AudioFrame>();
7269

73-
tokio::spawn(async move {
74-
// these would be the two sides of it
75-
// todo.. how do we coordinate that?
76-
let mut t = Track::load("./test.mp3").unwrap();
70+
// audio player thread
71+
std::thread::spawn(move || {
72+
// temp: each track needs its own player somehow
7773
let mut p = audio::Player::new();
7874

79-
dbg!(&t.samples.len());
80-
for _ in 0..200 {
81-
let f = t.encode_frame();
82-
tx.send(Message::AudioFrame(f.clone())).unwrap();
83-
p.receive(f.data);
84-
}
85-
p.debug_export();
75+
let mut temp = 0;
8676

8777
loop {
88-
//tx.send(Message::AudioFrame(f)).unwrap();
89-
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
78+
if let Ok(frame) = audio_rx.recv() {
79+
println!("player thread got {:?}", frame);
80+
p.receive(frame.data);
81+
temp += 1;
82+
}
83+
84+
if temp == 200 {
85+
p.play();
86+
}
9087
}
9188
});
9289

90+
if my_id == "1" {
91+
println!("id is '1', sending track");
92+
93+
let track = protocol::Track {
94+
path: "blah".to_string(),
95+
owner: my_id.clone(),
96+
queue_position: 0,
97+
};
98+
99+
stream.send(&Message::QueuePush(track)).await.unwrap();
100+
stream
101+
.send(&Message::GetInfo(GetInfo::QueueList))
102+
.await
103+
.unwrap();
104+
105+
let audio_tx_2 = audio_tx.clone();
106+
tokio::spawn(async move {
107+
// these would be the two sides of it
108+
// todo.. how do we coordinate that?
109+
let mut t: Track = Track::load("../test.mp3").unwrap();
110+
111+
dbg!(&t.samples.len());
112+
for _ in 0..200 {
113+
let f = t.encode_frame();
114+
115+
// send to our own audio thread
116+
audio_tx_2.send(f.clone()).unwrap();
117+
118+
// send to server
119+
message_tx.send(Message::AudioFrame(f)).unwrap();
120+
}
121+
122+
loop {
123+
// todo: keep sending frames
124+
125+
//tx.send(Message::AudioFrame(f)).unwrap();
126+
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
127+
}
128+
});
129+
} else {
130+
println!("id is not '1', not sending anything")
131+
}
132+
93133
loop {
94134
tokio::select! {
95135
// something to send
96-
Some(msg) = rx.recv() => {
136+
Some(msg) = message_rx.recv() => {
97137
stream.send(&msg).await.unwrap();
98-
},
138+
}
99139

100140
// tcp message
101141
result = stream.get_inner().next() => match result {
102142
Some(Ok(bytes)) => {
103143
let msg: Message =
104144
bincode::deserialize(&bytes).expect("failed to deserialize message");
105145
println!("received message: {:?}", msg);
146+
147+
match msg {
148+
Message::AudioFrame(f) => {
149+
audio_tx.send(f).unwrap();
150+
}
151+
152+
_ => {}
153+
}
106154
}
107155

108156
Some(Err(e)) => {

protocol/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ pub struct PlaybackState {
1818

1919
#[derive(Serialize, Deserialize, Clone, Debug)]
2020
pub struct Track {
21-
pub owner: usize,
21+
pub owner: String,
2222
pub path: String,
2323
pub queue_position: usize,
2424
}

0 commit comments

Comments
 (0)