diff --git a/assets/index.html b/assets/index.html
index 3fe62b13..6d028c6b 100644
--- a/assets/index.html
+++ b/assets/index.html
@@ -158,7 +158,7 @@
.enumerateDevices()
.then((devices) => {
const videoDevices = devices.filter(
- (device) => device.kind === "videoinput" && device.label !== "OBS Virtual Camera",
+ (device) => device.kind === "videoinput",
);
// Decide whether to request video based on the presence of the camera device
@@ -351,10 +351,127 @@
});
}
};
+
+
+ //
+ function onRemoteAnswer(answer) {
+ const answer_modified = editAnswer(
+ answer,
+ document.getElementById("video_codec").value,
+ document.getElementById("audio_codec").value,
+ document.getElementById("video_bitrate").value,
+ document.getElementById("audio_bitrate").value,
+ document.getElementById("audio_voice").value,
+ );
+ return answer_modified;
+ };
+ //
+ const editAnswer = (answer, videoCodec, audioCodec, videoBitrate, audioBitrate, audioVoice) => {
+ const sections = answer.split("m=");
+ for (let i = 0; i < sections.length; i++) {
+ const section = sections[i];
+ if (section.startsWith("video")) {
+ sections[i] = setVideoBitrate(setCodec(section, videoCodec), videoBitrate);
+ } else if (section.startsWith("audio")) {
+ sections[i] = setAudioBitrate(setCodec(section, audioCodec), audioBitrate, audioVoice);
+ }
+ }
+
+ const answer_modified = sections.join("m=");
+ return answer_modified;
+ };
+ //
+ const setVideoBitrate = (section, bitrate) => {
+ let lines = section.split("\r\n");
+
+ for (let i = 0; i < lines.length; i++) {
+ if (lines[i].startsWith("c=")) {
+ lines = [
+ ...lines.slice(0, i + 1),
+ "b=TIAS:" + (parseInt(bitrate) * 1024).toString(),
+ ...lines.slice(i + 1),
+ ];
+ break;
+ }
+ }
+
+ return lines.join("\r\n");
+ };
+ //
+ const setAudioBitrate = (section, bitrate, voice) => {
+ let opusPayloadFormat = "";
+ let lines = section.split("\r\n");
+
+ for (let i = 0; i < lines.length; i++) {
+ if (lines[i].startsWith("a=rtpmap:") && lines[i].toLowerCase().includes("opus/")) {
+ opusPayloadFormat = lines[i].slice("a=rtpmap:".length).split(" ")[0];
+ break;
+ }
+ }
+
+ if (opusPayloadFormat === "") {
+ return section;
+ }
+
+ for (let i = 0; i < lines.length; i++) {
+ if (lines[i].startsWith("a=fmtp:" + opusPayloadFormat + " ")) {
+ if (voice) {
+ lines[i] =
+ "a=fmtp:" +
+ opusPayloadFormat +
+ " minptime=10;useinbandfec=1;maxaveragebitrate=" +
+ (parseInt(bitrate) * 1024).toString();
+ } else {
+ lines[i] =
+ "a=fmtp:" +
+ opusPayloadFormat +
+ " maxplaybackrate=48000;stereo=1;sprop-stereo=1;maxaveragebitrate" +
+ (parseInt(bitrate) * 1024).toString();
+ }
+ }
+ }
+
+ return lines.join("\r\n");
+ };
+ //
+ const setCodec = (section, codec) => {
+ const lines = section.split("\r\n");
+ const lines2 = [];
+ const payloadFormats = [];
+
+ for (const line of lines) {
+ if (!line.startsWith("a=rtpmap:")) {
+ lines2.push(line);
+ } else {
+ if (line.toLowerCase().includes(codec)) {
+ payloadFormats.push(line.slice("a=rtpmap:".length).split(" ")[0]);
+ lines2.push(line);
+ }
+ }
+ }
+
+ const lines3 = [];
+
+ for (const line of lines2) {
+ if (line.startsWith("a=fmtp:")) {
+ if (payloadFormats.includes(line.slice("a=fmtp:".length).split(" ")[0])) {
+ lines3.push(line);
+ }
+ } else if (line.startsWith("a=rtcp-fb:")) {
+ if (payloadFormats.includes(line.slice("a=rtcp-fb:".length).split(" ")[0])) {
+ lines3.push(line);
+ }
+ } else {
+ lines3.push(line);
+ }
+ }
+
+ return lines3.join("\r\n");
+ };
// onTransmitSVC
+
const onTransmitSVC = (stream) => {
document.getElementById("video").srcObject = stream;
- console.log(stream);
const resource = document.getElementById("resource").value;
//get svc_level
const rid_value = document.getElementById("svc_level").value;
@@ -382,7 +499,19 @@
const whip = new WHIPClient();
const url = location.origin + "/whip/" + resource;
const token = document.getElementById("token").value;
- whip.publish(pc, url, token);
+ //whip.publish(pc, url, token);
+ whip.publish(pc, url, token)
+ .then((answer) => {
+ const edit_answer = onRemoteAnswer(answer);
+ return { pc, edit_answer };
+ })
+ .then(({pc,edit_answer}) => {
+ pc.setRemoteDescription({ type: "answer", sdp: edit_answer });
+ })
+ .catch(error => {
+ console.error("Error publishing:", error);
+ });
+
};
// startWhip
async function startWhip() {
diff --git a/assets/whip.js b/assets/whip.js
index a19fa08a..a876599b 100644
--- a/assets/whip.js
+++ b/assets/whip.js
@@ -1,5 +1,3 @@
-//import { EventEmitter } from "events";
-
class WHIPClient {
constructor() {
//Ice properties
@@ -11,123 +9,7 @@ class WHIPClient {
this.id = "";
}
- async publish(pc, url, token) {
- // edit answer_sdp
- const onRemoteAnswer = (answer_sdp) => {
- const answer_modified = editAnswer(
- answer_sdp,
- document.getElementById("video_codec").value,
- document.getElementById("audio_codec").value,
- document.getElementById("video_bitrate").value,
- document.getElementById("audio_bitrate").value,
- document.getElementById("audio_voice").value,
- );
- return answer_modified;
- };
-
- const editAnswer = (answer_sdp, videoCodec, audioCodec, videoBitrate, audioBitrate, audioVoice) => {
- const sections = answer_sdp.split("m=");
- for (let i = 0; i < sections.length; i++) {
- const section = sections[i];
- if (section.startsWith("video")) {
- sections[i] = setVideoBitrate(setCodec(section, videoCodec), videoBitrate);
- } else if (section.startsWith("audio")) {
- sections[i] = setAudioBitrate(setCodec(section, audioCodec), audioBitrate, audioVoice);
- }
- }
-
- const answer_modified = sections.join("m=");
- console.log(answer_modified);
- return answer_modified;
- };
-
- const setVideoBitrate = (section, bitrate) => {
- let lines = section.split("\r\n");
-
- for (let i = 0; i < lines.length; i++) {
- if (lines[i].startsWith("c=")) {
- lines = [
- ...lines.slice(0, i + 1),
- "b=TIAS:" + (parseInt(bitrate) * 1024).toString(),
- ...lines.slice(i + 1),
- ];
- break;
- }
- }
-
- return lines.join("\r\n");
- };
-
- const setAudioBitrate = (section, bitrate, voice) => {
- let opusPayloadFormat = "";
- let lines = section.split("\r\n");
-
- for (let i = 0; i < lines.length; i++) {
- if (lines[i].startsWith("a=rtpmap:") && lines[i].toLowerCase().includes("opus/")) {
- opusPayloadFormat = lines[i].slice("a=rtpmap:".length).split(" ")[0];
- break;
- }
- }
-
- if (opusPayloadFormat === "") {
- return section;
- }
-
- for (let i = 0; i < lines.length; i++) {
- if (lines[i].startsWith("a=fmtp:" + opusPayloadFormat + " ")) {
- if (voice) {
- lines[i] =
- "a=fmtp:" +
- opusPayloadFormat +
- " minptime=10;useinbandfec=1;maxaveragebitrate=" +
- (parseInt(bitrate) * 1024).toString();
- } else {
- lines[i] =
- "a=fmtp:" +
- opusPayloadFormat +
- " maxplaybackrate=48000;stereo=1;sprop-stereo=1;maxaveragebitrate" +
- (parseInt(bitrate) * 1024).toString();
- }
- }
- }
-
- return lines.join("\r\n");
- };
-
- const setCodec = (section, codec) => {
- const lines = section.split("\r\n");
- const lines2 = [];
- const payloadFormats = [];
-
- for (const line of lines) {
- if (!line.startsWith("a=rtpmap:")) {
- lines2.push(line);
- } else {
- if (line.toLowerCase().includes(codec)) {
- payloadFormats.push(line.slice("a=rtpmap:".length).split(" ")[0]);
- lines2.push(line);
- }
- }
- }
-
- const lines3 = [];
-
- for (const line of lines2) {
- if (line.startsWith("a=fmtp:")) {
- if (payloadFormats.includes(line.slice("a=fmtp:".length).split(" ")[0])) {
- lines3.push(line);
- }
- } else if (line.startsWith("a=rtcp-fb:")) {
- if (payloadFormats.includes(line.slice("a=rtcp-fb:".length).split(" ")[0])) {
- lines3.push(line);
- }
- } else {
- lines3.push(line);
- }
- }
-
- return lines3.join("\r\n");
- };
+ async publish(pc, url, token) {
//If already publishing
if (this.pc) throw new Error("Already publishing");
@@ -169,7 +51,6 @@ class WHIPClient {
};
//Create SDP offer
const offer = await pc.createOffer();
-
//Request headers
const headers = {
"Content-Type": "application/sdp",
@@ -238,7 +119,6 @@ class WHIPClient {
}
}
}
-
//Get current config
const config = pc.getConfiguration();
@@ -276,6 +156,8 @@ class WHIPClient {
//Get the SDP answer
const answer = await fetched.text();
+ //const edit_answer = await onRemoteAnswer(answer);
+
this.id = fetched.headers.get("E-tag");
//Schedule trickle on next tick
if (!this.iceTrickeTimeout) this.iceTrickeTimeout = setTimeout(() => this.trickle(), 0);
@@ -295,11 +177,9 @@ class WHIPClient {
this.iceUsername = offer.sdp.match(/a=ice-ufrag:(.*)\r\n/)[1];
this.icePassword = offer.sdp.match(/a=ice-pwd:(.*)\r\n/)[1];
//}
-
+ return answer;
//And set remote description
- const answer_sdp = onRemoteAnswer(answer);
- console.log(answer_sdp);
- await pc.setRemoteDescription({ type: "answer", sdp: answer_sdp });
+ await pc.setRemoteDescription({ type: "answer", sdp: edit_answer });
}
restart() {