Complete first release candidate audit (#107)
Some checks failed
API and SemVer surface / api-surface (push) Failing after 1m34s
Native code generation / deterministic (push) Has been cancelled
Concurrency and resource soak audit / soak (push) Has been cancelled
Documentation / documentation (push) Has been cancelled
performance evidence / audit (push) Has been cancelled
First release candidate / non-fuzz-release-gate (push) Has been cancelled
Release platform and feature matrix / audit (push) Has been cancelled
Release platform and feature matrix / matrix (false, linux-stable-minimal, x86_64-unknown-linux-gnu, stable) (push) Has been cancelled
Release platform and feature matrix / matrix (false, macos-stable-portable, x86_64-apple-darwin, stable) (push) Has been cancelled
Release platform and feature matrix / matrix (false, windows-stable-portable, x86_64-pc-windows-gnu, stable) (push) Has been cancelled
Release platform and feature matrix / matrix (true, linux-msrv-portable, x86_64-unknown-linux-gnu, 1.96.0) (push) Has been cancelled
Release platform and feature matrix / matrix (true, linux-stable-default, x86_64-unknown-linux-gnu, stable) (push) Has been cancelled
Release platform and feature matrix / matrix (true, linux-stable-features, x86_64-unknown-linux-gnu, stable) (push) Has been cancelled
Release platform and feature matrix / matrix (true, linux-stable-release-surface, x86_64-unknown-linux-gnu, stable) (push) Has been cancelled
Dependency and supply-chain audit / audit (push) Has been cancelled
Native release artifact audit / audit (push) Has been cancelled
Imaging and meshing gate / native (push) Failing after 53s
JPEG 2000 feature / linux (push) Successful in 2m49s
Native Rust workspace compile / compile (push) Failing after 59s
Skia feature / linux (push) Has been cancelled

This commit is contained in:
2026-08-12 14:44:28 +00:00
parent dceb394378
commit c9a1170a27
140 changed files with 82175 additions and 27179 deletions

View File

@@ -453,7 +453,7 @@ struct Playback {
/// Owned native WebRTC voice session.
pub struct WebRtcVoiceSession {
command: mpsc::Sender<Command>,
events: mpsc::Receiver<VoiceEvent>,
events: Option<mpsc::Receiver<VoiceEvent>>,
snapshot: Arc<Mutex<SessionSnapshot>>,
signaling: Arc<dyn VoiceSignaling>,
viewer_session: UUID,
@@ -461,6 +461,8 @@ pub struct WebRtcVoiceSession {
credentials: Option<VoiceSecret>,
task: Option<JoinHandle<()>>,
timeout: Duration,
local_sdp: String,
remote_sdp: String,
#[cfg(feature = "real-audio")]
hardware_audio: Option<RealAudioBridge>,
}
@@ -493,10 +495,11 @@ impl WebRtcVoiceSession {
let (offer, pending) = change.apply().ok_or(WebRtcError::Protocol(
"SDP changes did not produce an offer",
))?;
let local_sdp = offer.to_sdp_string();
let request = ProvisionRequest {
jsep: Jsep {
kind: "offer".into(),
sdp: offer.to_sdp_string(),
sdp: local_sdp.clone(),
},
channel_type: "local".into(),
voice_server_type: "webrtc".into(),
@@ -509,7 +512,8 @@ impl WebRtcVoiceSession {
abandon_provisioned(&signaling, &mut response, config.timeout).await;
return Err(WebRtcError::Protocol("SDP answer exceeds 1 MiB"));
}
let answer = match SdpAnswer::from_sdp_string(&sanitize_remote_sdp(&response.answer_sdp)) {
let remote_sdp = sanitize_remote_sdp(&response.answer_sdp);
let answer = match SdpAnswer::from_sdp_string(&remote_sdp) {
Ok(answer) => answer,
Err(error) => {
abandon_provisioned(&signaling, &mut response, config.timeout).await;
@@ -578,7 +582,7 @@ impl WebRtcVoiceSession {
});
Ok(Self {
command: command_tx,
events: event_rx,
events: Some(event_rx),
snapshot,
signaling,
viewer_session: response.viewer_session,
@@ -586,13 +590,21 @@ impl WebRtcVoiceSession {
credentials: response.credentials,
task: Some(task),
timeout: config.timeout,
local_sdp,
remote_sdp,
#[cfg(feature = "real-audio")]
hardware_audio: Some(hardware_audio),
})
}
pub async fn next_event(&mut self) -> Option<VoiceEvent> {
self.events.recv().await
self.events.as_mut()?.recv().await
}
/// Transfers the event stream to a facade task while retaining the session's
/// command and teardown handles.
pub fn take_events(&mut self) -> Option<mpsc::Receiver<VoiceEvent>> {
self.events.take()
}
#[must_use]
@@ -615,6 +627,49 @@ impl WebRtcVoiceSession {
reply_rx.await.map_err(|_| WebRtcError::Closed)?
}
/// Queues a bounded data-channel message without blocking the caller.
pub fn try_send_data(&self, message: impl Into<String>) -> Result<bool, WebRtcError> {
let message = message.into();
if message.len() > MAX_DATA_BYTES {
return Err(WebRtcError::InvalidInput(
"data-channel message exceeds 64 KiB",
));
}
let (reply_tx, _reply_rx) = oneshot::channel();
match self.command.try_send(Command::Data(message, reply_tx)) {
Ok(()) => Ok(true),
Err(mpsc::error::TrySendError::Full(_)) => Ok(false),
Err(mpsc::error::TrySendError::Closed(_)) => Err(WebRtcError::Closed),
}
}
#[must_use]
pub fn viewer_session(&self) -> UUID {
self.viewer_session
}
#[must_use]
pub fn channel(&self) -> Option<String> {
self.channel.clone()
}
#[must_use]
pub fn credentials(&self) -> Option<String> {
self.credentials
.as_ref()
.map(|credentials| credentials.expose().to_owned())
}
#[must_use]
pub fn local_sdp(&self) -> String {
self.local_sdp.clone()
}
#[must_use]
pub fn remote_sdp(&self) -> String {
self.remote_sdp.clone()
}
pub async fn set_peer_mute(&self, peer: UUID, mute: bool) -> Result<bool, WebRtcError> {
self.send_data(json!({"m": {peer.to_string(): mute}}).to_string())
.await