Skip to content

Commit c4322d2

Browse files
committed
[*] refactor: webrtc http body type from String to Vec<u8>
1 parent 0cb2456 commit c4322d2

File tree

6 files changed

+41
-153
lines changed

6 files changed

+41
-153
lines changed

lib/wrtc/data/stunserverlist.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
stun.nextcloud.com:443
12
stun.1und1.de:3478
23
stun.gmx.net:3478
34
stun.l.google.com:19302

lib/wrtc/src/common/http.rs

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub trait Unmarshal {
1717
}
1818

1919
pub trait Marshal {
20-
fn marshal(&self) -> String;
20+
fn marshal(&self) -> Vec<u8>;
2121
}
2222

2323
#[derive(Debug, Clone, Default)]
@@ -80,16 +80,15 @@ impl Unmarshal for Uri {
8080
}
8181

8282
impl Marshal for Uri {
83-
fn marshal(&self) -> String {
83+
fn marshal(&self) -> Vec<u8> {
8484
let path_with_query = if let Some(query) = &self.query {
8585
format!("{}?{}", self.path, query)
8686
} else {
8787
self.path.clone()
8888
};
8989

9090
match self.schema {
91-
Schema::WEBRTC => path_with_query,
92-
Schema::UNKNOWN => path_with_query,
91+
Schema::WEBRTC | Schema::UNKNOWN => path_with_query.as_bytes().to_vec(),
9392
}
9493
}
9594
}
@@ -101,7 +100,7 @@ pub struct HttpRequest {
101100
pub query_pairs: IndexMap<String, String>,
102101
pub version: String,
103102
pub headers: IndexMap<String, String>,
104-
pub body: Option<String>,
103+
pub body: Option<Vec<u8>>,
105104
}
106105

107106
impl HttpRequest {
@@ -193,19 +192,19 @@ impl Unmarshal for HttpRequest {
193192
);
194193

195194
if request_data.len() > header_end_idx {
196-
http_request.body = Some(request_data[header_end_idx..].to_string());
195+
http_request.body = Some(request_data[header_end_idx..].as_bytes().to_vec());
197196
}
198197

199198
Some(http_request)
200199
}
201200
}
202201

203202
impl Marshal for HttpRequest {
204-
fn marshal(&self) -> String {
203+
fn marshal(&self) -> Vec<u8> {
205204
let mut request_str = format!(
206205
"{} {} {}\r\n",
207206
self.method,
208-
self.uri.marshal(),
207+
String::from_utf8(self.uri.marshal()).unwrap_or_default(),
209208
self.version
210209
);
211210

@@ -220,10 +219,13 @@ impl Marshal for HttpRequest {
220219
}
221220

222221
request_str += "\r\n";
222+
223+
let mut req = request_str.as_bytes().to_vec();
223224
if let Some(body) = &self.body {
224-
request_str += body;
225+
req.extend_from_slice(&body);
225226
}
226-
request_str
227+
228+
req
227229
}
228230
}
229231

@@ -233,7 +235,7 @@ pub struct HttpResponse {
233235
pub status_code: u16,
234236
pub reason_phrase: String,
235237
pub headers: IndexMap<String, String>,
236-
pub body: Option<String>,
238+
pub body: Option<Vec<u8>>,
237239
}
238240

239241
impl HttpResponse {
@@ -280,15 +282,15 @@ impl Unmarshal for HttpResponse {
280282
};
281283

282284
if request_data.len() > header_end_idx {
283-
http_response.body = Some(request_data[header_end_idx..].to_string());
285+
http_response.body = Some(request_data[header_end_idx..].as_bytes().to_vec());
284286
}
285287

286288
Some(http_response)
287289
}
288290
}
289291

290292
impl Marshal for HttpResponse {
291-
fn marshal(&self) -> String {
293+
fn marshal(&self) -> Vec<u8> {
292294
let mut response_str = format!(
293295
"{} {} {}\r\n",
294296
self.version, self.status_code, self.reason_phrase
@@ -305,10 +307,12 @@ impl Marshal for HttpResponse {
305307
}
306308

307309
response_str += "\r\n";
310+
311+
let mut resp = response_str.as_bytes().to_vec();
308312
if let Some(body) = &self.body {
309-
response_str += body;
313+
resp.extend_from_slice(&body);
310314
}
311-
response_str
315+
resp
312316
}
313317
}
314318

@@ -373,7 +377,7 @@ mod tests {
373377

374378
if let Some(parser) = HttpRequest::unmarshal(request) {
375379
println!("parser: {parser:?}");
376-
let marshal_result = parser.marshal();
380+
let marshal_result = String::from_utf8(parser.marshal()).unwrap();
377381
print!("\n\n{marshal_result}\n");
378382
assert_eq!(request, marshal_result);
379383
}
@@ -524,7 +528,7 @@ mod tests {
524528

525529
if let Some(parser) = HttpRequest::unmarshal(request) {
526530
println!(" parser: {parser:?}");
527-
let marshal_result = parser.marshal();
531+
let marshal_result = String::from_utf8(parser.marshal()).unwrap();
528532
println!("\n\n{marshal_result}");
529533
assert_eq!(request, marshal_result);
530534
}
@@ -587,7 +591,7 @@ mod tests {
587591

588592
if let Some(parser) = HttpResponse::unmarshal(response) {
589593
println!("parser: {parser:?}");
590-
let marshal_result = parser.marshal();
594+
let marshal_result = String::from_utf8(parser.marshal()).unwrap();
591595
println!("\n\n{marshal_result}\n");
592596
assert_eq!(response, marshal_result);
593597
}

lib/wrtc/src/session.rs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -122,9 +122,11 @@ impl WebRTCServerSession {
122122
let request_method = http_request.method.as_str();
123123
if request_method == http_method_name::GET {
124124
let response = match http_request.uri.path.as_str() {
125-
"/" => Self::gen_file_response(WEB_WHEP_INDEX),
126-
"/whep.js" => Self::gen_file_response(WEB_WHEP_JS),
127-
// "/favicon.con" => Self::gen_file_response(WEB_FAVICON),
125+
"/" => Self::gen_file_response(WEB_WHEP_INDEX.as_bytes(), "text/html"),
126+
"/favicon.ico" => Self::gen_file_response(WEB_FAVICON, "mage/x-icon"),
127+
"/whep.js" => {
128+
Self::gen_file_response(WEB_WHEP_JS.as_bytes(), "application/javascript")
129+
}
128130
_ => {
129131
log::warn!(
130132
"the http get path: {} is not supported.",
@@ -159,7 +161,9 @@ impl WebRTCServerSession {
159161
};
160162

161163
self.session_id = Some(Uuid::new(RandomDigitCount::Zero));
162-
let offer = RTCSessionDescription::offer(sdp_data.clone())?;
164+
let offer = RTCSessionDescription::offer(
165+
String::from_utf8(sdp_data.clone()).unwrap_or_default(),
166+
)?;
163167

164168
let path = format!(
165169
"{}?{}session_id={}",
@@ -313,7 +317,7 @@ impl WebRTCServerSession {
313317
.headers
314318
.insert("Content-Type".to_string(), "application/sdp".to_string());
315319
response.headers.insert("Location".to_string(), path);
316-
response.body = Some(session_description.sdp);
320+
response.body = Some(session_description.sdp.as_bytes().to_vec());
317321
response
318322
}
319323
Err(err) => {
@@ -353,17 +357,17 @@ impl WebRTCServerSession {
353357
response
354358
}
355359

356-
fn gen_file_response(contents: &str) -> HttpResponse {
360+
fn gen_file_response(contents: &[u8], content_type: &str) -> HttpResponse {
357361
let mut response = Self::gen_response(http::StatusCode::OK);
358362
response
359363
.headers
360-
.insert("Content-Type".to_string(), "text/html".to_string());
361-
response.body = Some(contents.to_string());
364+
.insert("Content-Type".to_string(), content_type.to_string());
365+
response.body = Some(contents.to_vec());
362366
response
363367
}
364368

365369
async fn send_response(&mut self, response: &HttpResponse) -> Result<(), SessionError> {
366-
self.writer.write(response.marshal().as_bytes())?;
370+
self.writer.write(&response.marshal())?;
367371
self.writer.flush().await?;
368372
Ok(())
369373
}

lib/wrtc/web-whep-client/index.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -973,6 +973,11 @@ <h1>Wayshot 屏幕共享</h1>
973973
var player = document.getElementById("localVideo");
974974
player.srcObject = event.streams[0];
975975
player.controls = false; // Disable default controls
976+
977+
// Get volume slider value and set volume before playing
978+
const volumeValue = volumeSlider.value / 100;
979+
player.volume = volumeValue;
980+
976981
player.muted = false; // Enable audio
977982
playBtn.textContent = "❚❚";
978983

lib/wrtc/web-whep-client/whep.js

Lines changed: 0 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -254,132 +254,6 @@ class WHEPClient extends EventTarget {
254254

255255
async trickle() {
256256
return;
257-
//Clear timeout
258-
this.iceTrickeTimeout = null;
259-
260-
//Check if there is any pending data
261-
if (
262-
!(this.candidates.length || this.endOfcandidates || this.restartIce) ||
263-
!this.resourceURL
264-
)
265-
//Do nothing
266-
return;
267-
268-
//Get data
269-
const candidates = this.candidates;
270-
let endOfcandidates = this.endOfcandidates;
271-
const restartIce = this.restartIce;
272-
273-
//Clean pending data before async operation
274-
this.candidates = [];
275-
this.endOfcandidates = false;
276-
this.restartIce = false;
277-
278-
//If we need to restart
279-
if (restartIce) {
280-
//Restart ice
281-
this.pc.restartIce();
282-
//Create a new offer
283-
const offer = await this.pc.createOffer({ iceRestart: true });
284-
//Update ice
285-
this.iceUsername = offer.sdp.match(/a=ice-ufrag:(.*)\r\n/)[1];
286-
this.icePassword = offer.sdp.match(/a=ice-pwd:(.*)\r\n/)[1];
287-
//Set it
288-
await this.pc.setLocalDescription(offer);
289-
//Clean end of candidates flag as new ones will be retrieved
290-
endOfcandidates = false;
291-
}
292-
//Prepare fragment
293-
let fragment =
294-
"a=ice-ufrag:" +
295-
this.iceUsername +
296-
"\r\n" +
297-
"a=ice-pwd:" +
298-
this.icePassword +
299-
"\r\n";
300-
//Get peerconnection transceivers
301-
const transceivers = this.pc.getTransceivers();
302-
//Get medias
303-
const medias = {};
304-
//If doing something else than a restart
305-
if (candidates.length || endOfcandidates)
306-
//Create media object for first media always
307-
medias[transceivers[0].mid] = {
308-
mid: transceivers[0].mid,
309-
kind: transceivers[0].receiver.track.kind,
310-
candidates: [],
311-
};
312-
//For each candidate
313-
for (const candidate of candidates) {
314-
//Get mid for candidate
315-
const mid = candidate.sdpMid;
316-
//Get associated transceiver
317-
const transceiver = transceivers.find((t) => t.mid == mid);
318-
//Get media
319-
let media = medias[mid];
320-
//If not found yet
321-
if (!media)
322-
//Create media object
323-
media = medias[mid] = {
324-
mid,
325-
kind: transceiver.receiver.track.kind,
326-
candidates: [],
327-
};
328-
//Add candidate
329-
media.candidates.push(candidate);
330-
}
331-
//For each media
332-
for (const media of Object.values(medias)) {
333-
//Add media to fragment
334-
fragment +=
335-
"m=" + media.kind + " 9 RTP/AVP 0\r\n" + "a=mid:" + media.mid + "\r\n";
336-
//Add candidate
337-
for (const candidate of media.candidates)
338-
fragment += "a=" + candidate.candidate + "\r\n";
339-
if (endOfcandidates) fragment += "a=end-of-candidates\r\n";
340-
}
341-
342-
//Request headers
343-
const headers = {
344-
"Content-Type": "application/trickle-ice-sdpfrag",
345-
};
346-
347-
//If token is set
348-
if (this.token) headers["Authorization"] = "Bearer " + this.token;
349-
350-
//Do the post request to the WHEP resource
351-
const fetched = await fetch(this.resourceURL, {
352-
method: "PATCH",
353-
body: fragment,
354-
headers,
355-
});
356-
if (!fetched.ok)
357-
throw new Error("Request rejected with status " + fetched.status);
358-
359-
//If we have got an answer
360-
if (fetched.status == 200) {
361-
//Get the SDP answer
362-
const answer = await fetched.text();
363-
//Get remote icename and password
364-
const iceUsername = answer.match(/a=ice-ufrag:(.*)\r\n/)[1];
365-
const icePassword = answer.match(/a=ice-pwd:(.*)\r\n/)[1];
366-
367-
//Get current remote rescription
368-
const remoteDescription = this.pc.remoteDescription;
369-
370-
//Patch
371-
remoteDescription.sdp = remoteDescription.sdp.replaceAll(
372-
/(a=ice-ufrag:)(.*)\r\n/gm,
373-
"$1" + iceUsername + "\r\n",
374-
);
375-
remoteDescription.sdp = remoteDescription.sdp.replaceAll(
376-
/(a=ice-pwd:)(.*)\r\n/gm,
377-
"$1" + icePassword + "\r\n",
378-
);
379-
380-
//Set it
381-
await this.pc.setRemoteDescription(remoteDescription);
382-
}
383257
}
384258

385259
async mute(muted) {

0 commit comments

Comments
 (0)