146 lines
3.7 KiB
TypeScript
146 lines
3.7 KiB
TypeScript
import { Router } from "jsr:@oak/oak@14";
|
|
|
|
// @deno-types="npm:@types/sdp-transform"
|
|
import sdpTransform from "npm:sdp-transform@2.14.2";
|
|
import { encodeHex,} from "https://deno.land/std@0.224.0/encoding/hex.ts";
|
|
import { parseIceCandidate, IceCandidate } from "./src/iceCandiate.ts";
|
|
|
|
const router = new Router({
|
|
prefix: "/api",
|
|
});
|
|
|
|
export {router as router_webrtc};
|
|
|
|
let rxAddress: Deno.Addr | undefined = undefined;
|
|
|
|
const ffmpegSocket = Deno.listenDatagram({
|
|
hostname: "localhost",
|
|
port: 1234,
|
|
transport: "udp"
|
|
});
|
|
|
|
let ffmpegRxRun = true;
|
|
// deno-lint-ignore no-async-promise-executor
|
|
const _ffmpegRxPromose = new Promise(async (resolve, _reject) => {
|
|
while(ffmpegRxRun) {
|
|
const data = new Uint8Array(65536);
|
|
await ffmpegSocket.receive(data);
|
|
|
|
if(rxAddress !== undefined) {
|
|
await ffmpegSocket.send(data, rxAddress);
|
|
}
|
|
}
|
|
|
|
resolve(null);
|
|
});
|
|
|
|
interface RTCIceCandidate {
|
|
candidate: string;
|
|
sdpMid: string;
|
|
sdpMLineIndex: number;
|
|
usernameFragment: string;
|
|
};
|
|
|
|
interface RTCSessionDescription {
|
|
sdp: string;
|
|
type: "offer" | "answer";
|
|
}
|
|
|
|
async function getSDP(): Promise<string> {
|
|
return await Deno.readTextFile("./output.sdp");
|
|
}
|
|
|
|
async function getFingerprint(): Promise<string> {
|
|
const cert = new Uint8Array(32);
|
|
crypto.getRandomValues(cert);
|
|
const hash = encodeHex(await crypto.subtle.digest("SHA-256", cert)).toUpperCase();
|
|
return hash.split(/(..)/g).filter((s: string) => s !== "").join(":");
|
|
}
|
|
|
|
async function modifySDP(sdp: string): Promise<string> {
|
|
//let sdpObj = sdpTransform.parse(sdp);
|
|
const localAddress = "127.0.0.1";
|
|
|
|
let sdpObj: sdpTransform.SessionDescription = {
|
|
fingerprint: {
|
|
"type": "SHA-256",
|
|
"hash": await getFingerprint()
|
|
},
|
|
icePwd : "AAAABBBB",
|
|
iceUfrag: "AAAABBBB",
|
|
origin: {
|
|
username: "-",
|
|
sessionId: (Math.random()*10000000).toFixed(0),
|
|
sessionVersion: 0,
|
|
netType: "IN",
|
|
ipVer: 4,
|
|
address: localAddress,
|
|
},
|
|
timing: {
|
|
start: 0,
|
|
stop: 0
|
|
},
|
|
media: [
|
|
{
|
|
type: "video",
|
|
port: 1235,
|
|
protocol: "RTP/AVP",
|
|
direction: "sendrecv",
|
|
connection: {
|
|
ip: localAddress,
|
|
version: 4,
|
|
|
|
},
|
|
payloads: "126",
|
|
fmtp: [
|
|
|
|
],
|
|
rtp: [
|
|
{
|
|
payload: 126,
|
|
codec: "H264",
|
|
rate: 90000
|
|
}
|
|
]
|
|
}
|
|
|
|
]
|
|
};
|
|
|
|
console.log(sdpObj);
|
|
|
|
return sdpTransform.write(sdpObj);
|
|
}
|
|
|
|
router.post("/webrtc", async (ctx) => {
|
|
const body: {
|
|
ice: RTCIceCandidate[];
|
|
offer: RTCSessionDescription
|
|
} = await ctx.request.body.json();
|
|
|
|
const ice: RTCIceCandidate[] = [];
|
|
const answer: RTCSessionDescription = {
|
|
sdp: await modifySDP(await getSDP()),
|
|
type: "answer"
|
|
};
|
|
|
|
console.log(body.offer);
|
|
|
|
const remoteIce = body.ice.map((candidate: RTCIceCandidate) => parseIceCandidate(candidate.candidate))
|
|
.filter((c: IceCandidate | null) => c !== null)
|
|
.filter((c: IceCandidate | null) => c?.transport === "UDP" && c?.candidateType === "host")
|
|
|
|
//console.log(remoteIce);
|
|
|
|
if (body) {
|
|
ctx.response.status = 200;
|
|
ctx.response.body = {
|
|
ice: ice,
|
|
answer: answer
|
|
};
|
|
} else {
|
|
ctx.response.status = 400;
|
|
ctx.response.body = { error: "Invalid JSON" };
|
|
}
|
|
});
|