less broken microphone support

This commit is contained in:
2024-08-30 22:48:49 -06:00
parent 30245b2fb8
commit b0ae26d79a
4 changed files with 180 additions and 22 deletions
+142 -6
View File
@@ -44,6 +44,116 @@ use web_sys::WebTransport;
use web_sys::WebTransportOptions;
use web_sys::WorkletOptions;
mod ass {
use byteorder::{ByteOrder, LittleEndian};
use ogg::PacketWriter;
const VER: &str = "ballz";
const fn to_samples<const S_PS: u32>(ms: u32) -> usize {
((S_PS * ms) / 1000) as usize
}
const fn calc_sr_u64(val: u64, from: u32, to: u32) -> u64 {
(val * to as u64) / from as u64
}
pub fn encode(
pre_encoded_frames: Vec<Vec<u8>>,
frame_size: usize,
skip: u16,
) -> Vec<u8>{
let mut buffer: Vec<u8> = Vec::new();
let mut packet_writer = PacketWriter::new(&mut buffer);
// Hardcoded serial number
let serial = 12345;
let skip_48 = calc_sr_u64(skip.into(), 48000, 48000);
let opus_head: [u8; 19] = [
b'O', b'p', b'u', b's', b'H', b'e', b'a', b'd', 1, 1, // NUM_CHANNELS = 1
0, 0, 0, 0, 0, 0, 0, 0, 0,
];
let mut head = opus_head;
LittleEndian::write_u16(&mut head[10..12], skip_48 as u16);
LittleEndian::write_u32(&mut head[12..16], 48000);
let mut opus_tags: Vec<u8> = Vec::with_capacity(60);
let vendor_str = format!("ogg-opus {}", VER);
opus_tags.extend(b"OpusTags");
let mut len_bf = [0u8; 4];
LittleEndian::write_u32(&mut len_bf, vendor_str.len() as u32);
opus_tags.extend(&len_bf);
opus_tags.extend(vendor_str.bytes());
opus_tags.extend(&[0u8; 4]);
packet_writer.write_packet(&head, serial, ogg::PacketWriteEndInfo::EndPage, 0);
packet_writer.write_packet(
&opus_tags,
serial,
ogg::PacketWriteEndInfo::EndPage,
0,
);
for (i, frame) in pre_encoded_frames.iter().enumerate() {
let is_last = i == pre_encoded_frames.len() - 1;
//let granule_pos = 0;
let granule_pos = calc_sr_u64(
(skip as usize + (i + 1) * frame_size) as u64,
48000,
48000,
);
packet_writer.write_packet(
frame.clone(),
serial,
if is_last {
ogg::PacketWriteEndInfo::EndStream
} else {
ogg::PacketWriteEndInfo::NormalPacket
},
granule_pos,
);
}
buffer
}
}
// Function to download data as a file
pub fn download_data(data: Vec<u8>, filename: &str) -> Result<(), JsValue> {
use wasm_bindgen::prelude::*;
use web_sys::{Blob, Url, HtmlAnchorElement, window};
// Create a new Blob from the data
let array = web_sys::js_sys::Uint8Array::from(&data[..]);
let blob = Blob::new_with_u8_array_sequence(&vec![array].into())?;
// Create a URL for the Blob
let url = Url::create_object_url_with_blob(&blob)?;
// Create an anchor element and set its href to the Blob URL
let document = window().unwrap().document().unwrap();
let a = document.create_element("a")?.dyn_into::<HtmlAnchorElement>()?;
a.set_href(&url);
a.set_download(filename);
// Append the anchor to the document body, click it, and remove it
document.body().unwrap().append_child(&a)?;
a.click();
document.body().unwrap().remove_child(&a)?;
// Revoke the object URL to free resources
Url::revoke_object_url(&url)?;
Ok(())
}
// Borrowed from
// https://github.com/security-union/videocall-rs/blob/main/videocall-client/src/decode/config.rs#L6
fn configure_audio_context() -> AudioContext {
@@ -97,12 +207,25 @@ async fn create_encoder_worklet(
let error: Closure<dyn FnMut(JsValue)> = Closure::new(|e| console::error_1(&e));
let mut download_buffer = std::cell::RefCell::new(Vec::new());
// This knows what MediaStreamTrackGenerator to use as it closes around it
let mut sequence_num = 0;
let output: Closure<dyn FnMut(EncodedAudioChunk)> =
Closure::new(move |audio_data: EncodedAudioChunk| {
let mut array = vec![0u8; audio_data.byte_length() as usize];
audio_data.copy_to_with_u8_array(&mut array);
download_buffer.borrow_mut().push(array.clone());
if download_buffer.borrow().len() > 200 {
//download_data(download_buffer.borrow().to_vec(), "download_buffer.opus");
download_data(ass::encode(download_buffer.borrow().to_vec(), 960, 0), "download_buffer.opus");
download_buffer.borrow_mut().clear();
}
let _ = packets.try_send(ControlPacket::UDPTunnel(Box::new(VoicePacket::Audio {
_dst: std::marker::PhantomData,
target: 0,
@@ -111,7 +234,7 @@ async fn create_encoder_worklet(
payload: VoicePacketPayload::Opus(array.into(), false),
position_info: None,
})));
sequence_num = sequence_num.wrapping_add(1);
sequence_num = sequence_num.wrapping_add(2);
});
let audio_encoder = AudioEncoder::new(&AudioEncoderInit::new(
@@ -123,17 +246,30 @@ async fn create_encoder_worklet(
// This is required to prevent these from being deallocated
error.forget();
output.forget();
let encoder_config = AudioEncoderConfig::new("opus");
encoder_config.set_number_of_channels(1);
encoder_config.set_sample_rate(48000);
encoder_config.set_bitrate(72_000.0);
audio_encoder.configure(
&AudioEncoderConfig::new("opus")
.number_of_channels(1)
.sample_rate(48000),
);
audio_encoder.configure(&encoder_config);
console::log_1(&"Created Audio Encoder".into());
let mut download_buffer = std::cell::RefCell::new(Vec::new());
let onmessage: Closure<dyn FnMut(MessageEvent)> = Closure::new(move |event: MessageEvent| {
match AudioData::new(event.data().unchecked_ref()) {
Ok(data) => {
let x = web_sys::AudioDataCopyToOptions::new(0);
x.set_format(web_sys::AudioSampleFormat::F32);
let mut sub_buffer = vec![0;data.allocation_size(&x).unwrap() as usize];
data.copy_to_with_u8_array(&mut sub_buffer, &x);
download_buffer.borrow_mut().append(&mut sub_buffer);
if download_buffer.borrow().len() > 48000 * 10 * 4 {
//pub fn download_data(data: Vec<u8>, filename: &str) -> Result<(), JsValue> {
//download_data(download_buffer.borrow().to_vec(), "download_buffer.pcm32");
download_buffer.borrow_mut().clear();
}
audio_encoder.encode(&data);
}
Err(err) => {