use bevy_app::prelude::*;
use bevy_connect::prelude::*;
use bevy_ecs::prelude::*;
use serde::{Deserialize, Serialize};
use std::net::IpAddr;
use crate::piper::AudioPiper;
pub struct TalkPlugin;
pub struct StartTalk;
pub struct StopTalk;
pub struct ConnectTalk {
ip: IpAddr,
port: u16,
host: bool,
}
pub struct DisconnectTalk;
impl Plugin for TalkPlugin {
fn build(&self, app: &mut App) {
app.add_plugins(SessionPlugin::<AudioMessage>::default());
app.add_systems(
PreUpdate,
send.run_if(
resource_exists::<Channel<AudioMessage>>.and_then(resource_exists::<AudioPiper>),
),
);
app.add_systems(
PostUpdate,
recv.run_if(
resource_exists::<Channel<AudioMessage>>.and_then(resource_exists::<AudioPiper>),
),
);
}
}
impl Command for StartTalk {
type Out = ();
fn apply(self, world: &mut World) {
world.insert_resource(AudioPiper::new());
}
}
impl Command for StopTalk {
type Out = ();
fn apply(self, world: &mut World) {
world.remove_resource::<AudioPiper>();
}
}
impl ConnectTalk {
pub fn host(ip: IpAddr, port: u16) -> Self {
Self {
ip,
port,
host: true,
}
}
pub fn client(ip: IpAddr, port: u16) -> Self {
Self {
ip,
port,
host: false,
}
}
}
impl Command for ConnectTalk {
type Out = ();
fn apply(self, world: &mut World) {
world
.commands()
.queue(SessionConnectCommand::<AudioMessage>::from_config(
SessionConfig::Direct {
addr: Some(self.ip),
port: self.port,
host: self.host,
compress: false,
key: None,
options: Default::default(),
},
));
}
}
impl Command for DisconnectTalk {
type Out = ();
fn apply(self, world: &mut World) {
world
.commands()
.queue(SessionDisconnectCommand::<AudioMessage>::default());
}
}
#[derive(Serialize, Deserialize)]
enum AudioMessage {
Audio(AudioPacket),
}
#[derive(Serialize, Deserialize)]
struct AudioPacket {
data: Vec<f32>,
}
fn recv(ap: Res<AudioPiper>, mut ch: MessageReader<MessageReceivedEvent<AudioMessage>>) {
let mut out = vec![];
for p in ch.read() {
let AudioMessage::Audio(p) = p.message.as_ref();
out.extend_from_slice(&p.data);
}
if !out.is_empty() {
ap.sink(&out);
}
}
fn send(ap: Res<AudioPiper>, mut ch: ResMut<Channel<AudioMessage>>) {
let data = ap.read();
if !data.is_empty() {
ch.broadcast(AudioMessage::Audio(AudioPacket { data }));
}
}