WebRTC Rooms

5729 ワード

app.js
const frontendsocket = io();

const myface = document.getElementById("myface");
const mute = document.getElementById("mute");
const camera = document.getElementById("camera");
const camerasSelect = document.getElementById("cameras");

const call = document.getElementById("call");

call.hidden = true;

let myStream;
let muted = false;
let cameraOff = false;
let roomName;

async function getCamera() {
  try {
    const devices = await navigator.mediaDevices.enumerateDevices();
    //장치 리스트 가져오기
    const cameras = devices.filter((device) => device.kind ==="videoinput"); 
    >	//videoinput만 필터링
    const CurrentCamera = myStream.getVideoTracks()[0];

cameras.forEach((camera) => {
  const option = document.createElement("option");
  option.value = camera.deviceId; //카메라의 고유 값을 value에 넣기
  option.innerText = camera.label; //사용자가 선택할 때는 label을 보고 선택 가능하게 하기
  if (CurrentCamera.lable === camera.label) {
    option.selected = true;
  }
  camerasSelect.appendChild(option); //카메라 정보를 option 항목에 넣어주기
});
  } catch (e) {
    console.log(e);
  }
}

async function getMedia(deviceId) {
  const initialConstraints = {
    //deviceId가 없을 때 실행
    audio: true,
    video: { facingMode: "environment" }, 
    //카메라가 전후면에 달려있을 경우 후면 카메라의 정보를 받음
  };
  const cameraConstraints = {
//deviceId가 있을 때 실행
    audio: true,
    video: { deviceId: { exact: deviceId } },
  };
  try {
    myStream = await navigator.mediaDevices.getUserMedia(
      deviceId ? cameraConstraints : initialConstraints
    );
    myface.srcObject = myStream;
    if (!deviceId) {
  //처음 딱 1번만 실행(getMedia를 실행할 때만)
      await getCamera();
    }
  } catch (e) {
    console.log(e);
  }
}

function handleMuteButton() {
  myStream
    .getAudioTracks()
    .forEach((track) => (track.enabled = !track.enabled));
  if (!muted) {
    mute.innerText = "Unmute";
    muted = true;
  } else {
    mute.innerText = "Mute";
    muted = false;
  }
}
function handleCameraButton() {
  console.log(myStream.getVideoTracks());
  myStream
    .getVideoTracks()
    .forEach((track) => (track.enabled = !track.enabled));
  if (!cameraOff) {
    camera.innerText = "Turn Camera On";
    cameraOff = true;
  } else {
    camera.innerText = "Turn Camera Off";
    cameraOff = false;
  }
}

async function handleCameraChange() {
  await getMedia(camerasSelect.value);
}
mute.addEventListener("click", handleMuteButton);
camera.addEventListener("click", handleCameraButton);
camerasSelect.addEventListener("input", handleCameraChange); //카메라 변경 확인

//Welcome Form (choose a room)
const welcome = document.getElementById("welcome");
const welcomeForm = welcome.querySelector("form");

function startMedia() {
  welcome.hidden = true;
  call.hidden = false;
  getMedia();
}

function handleWelcomeSubmit(event) {
  event.preventDefault();
  const input = welcomeForm.querySelector("input");
  frontendsocket.emit("join_room", input.value, startMedia);
  //서버로 input.value 보내기
  roomName = input.value; //방에 참가했을 때 나중에 쓸 수 있도록 방 이름 변수에 저장
  input.value = "";
}

welcomeForm.addEventListener("submit", handleWelcomeSubmit);

// Socket Code
frontendsocket.on("welcome", () => {
  console.log("someone joined");
});
server.js
import http from "http";
import SocketIO from "socket.io";
import { instrument } from "@socket.io/admin-ui";
import express from "express";

const app = express();

const PORT = 3000;

app.set("view engine", "pug");
app.set("views", __dirname + "/views");
// 기본 path를 /public으로 설정
app.use("/public", express.static(__dirname + "/public"));
app.get("/", (_, res) => res.render("home"));
app.get("/*", (_, res) => res.redirect("/"));

const httpServer = http.createServer(app);
const wsServer = SocketIO(httpServer);

wsServer.on("connection", (backendsocket) => {
  backendsocket.on("join_room", (roomName, done) => {
    backendsocket.join(roomName);
    done();
    backendsocket.to(roomName).emit("welcome");
  });
});

const handleListen = () => console.log(`Listening on >	http://localhost:${PORT}`);
httpServer.listen(PORT, handleListen);
home.pug
doctype html
html(lang="en")
    head
        meta(charset="UTF-8")
        meta(http-equiv="X-UA-Compatible", content="IE=edge")
        meta(name="viewport", content="width=device-width, initial-scale=1.0")
        title Noom
        link(rel="stylesheet", href="https://unpkg.com/mvp.css")
    body 
        header
            h1 Noom
        main
            div#welcome
                form
                    input(placeholder="room >	name",required,type="text")
                    button Enter Room 
            div#call
                div#mystream
                    //playsline은 모바일 브라우저가 필요로 하는 property
                    //모바일 기기로 재생하면 비디오가 전체화면이 되기 때문에 playsline으로 이를 방지
                    >	video#myface(autoplay,playsinline,width="100",height="100")
                    button#mute Mute
                    button#camera Turn Camera Off
                    select#cameras 
                        option(value="device") Face Camera 
        script(src="/socket.io/socket.io.js")
        script(src="/public/js/app.js")