Skip to content

Commit

Permalink
Rewrite the headless client to not use the admin panel
Browse files Browse the repository at this point in the history
  • Loading branch information
LVala committed Aug 1, 2024
1 parent bdcbe4d commit 7bb1e1e
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 32 deletions.
5 changes: 5 additions & 0 deletions broadcaster/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,8 @@ npm-debug.log
/assets/node_modules/

/_dialyzer/

# artifacts of the headless_client.js
/node_modules
package.json
package-lock.json
90 changes: 58 additions & 32 deletions broadcaster/headless_client.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

const puppeteer = require('puppeteer');

(async () => {
const url = (process.env.URL === undefined) ? 'http://localhost:4000' : process.env.URL;
const token = (process.env.TOKEN === undefined) ? 'example' : process.env.TOKEN;

async function start() {
const browser = await puppeteer.launch({
// headless: false,
args: [
Expand All @@ -11,36 +14,59 @@ const puppeteer = require('puppeteer');
'--use-fake-device-for-media-stream'
]
});

try {
const username = (process.env.USERNAME === undefined) ? 'admin' : process.env.USERNAME;
const password = (process.env.PASSWORD === undefined) ? 'admin' : process.env.PASSWORD;
const url = (process.env.URL === undefined) ? 'http://localhost:4000' : process.env.URL;
const token = (process.env.TOKEN === undefined) ? 'example' : process.env.TOKEN;

const page = await browser.newPage();
await page.setViewport({width: 1280, height: 720});
await page.authenticate({username: username, password: password});
await page.goto(`${url}/admin/player`);

// When button is available and initialized,
// we can safely start streaming.
await page.waitForSelector('button');
await page.waitForFunction(() => {
const button = document.getElementById('button');
console.log(button);
return button.onclick !== null;

const page = await browser.newPage();
// we need a page with secure context in order to access userMedia
await page.goto(`${url}/notfound`);
await page.evaluate(async (url, token) => {
const localStream = await navigator.mediaDevices.getUserMedia({
video: {
width: { ideal: 1280 },
height: { ideal: 720 },
frameRate: { ideal: 24 },
},
audio: true,
});

const pc = new RTCPeerConnection({ iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] });
pc.onconnectionstatechange = async (_) => {
if (pc.connectionState === "failed") {
await browser.close();
start();
}
};

pc.addTrack(localStream.getAudioTracks()[0], localStream);
pc.addTransceiver(localStream.getVideoTracks()[0], {
streams: [localStream],
sendEncodings: [
{ rid: 'h', maxBitrate: 1500 * 1024 },
{ rid: 'm', scaleResolutionDownBy: 2, maxBitrate: 600 * 1024 },
{ rid: 'l', scaleResolutionDownBy: 4, maxBitrate: 300 * 1024 },
],
});

await page.evaluate((url, token) => {
document.getElementById('serverUrl').value = `${url}/api/whip`;
document.getElementById('serverToken').value = token;
}, url, token);

await page.evaluate(() => {
document.getElementById('button').click();

const offer = await pc.createOffer();
await pc.setLocalDescription(offer);

const response = await fetch(`${url}/api/whip`, {
method: 'POST',
cache: 'no-cache',
headers: {
Accept: 'application/sdp',
'Content-Type': 'application/sdp',
Authorization: `Bearer ${token}`,
},
body: offer.sdp,
});
} catch {
await browser.close();
}
})();

if (response.status !== 201) {
throw Error("Unable to connect to the server");
}

const sdp = await response.text();
await pc.setRemoteDescription({ type: 'answer', sdp: sdp });
}, url, token);
}

start();

0 comments on commit 7bb1e1e

Please sign in to comment.