// app.js
socket.on("createWebRtcTransport", async ({ consumer }, callback) => {
try {
// get Room Name from Peer's properties
const roomName = peers[socket.id].roomName;
Algorithm
이분탐색(하), (중)Algorithm
이분탐색*대본*
1. 준영이는 입장하여 인셉션에서 설명을 듣는다.
1. 직원 : 안녕하세요~ 여기는 엄유정 작가님의 전시관입니다. 1층엔 일반 전시와 파노라마 관이 있고, 2층엔 3D 전시관이 따로 준비되어있습니다. 작가님이 2층에 심혈을 기울이셨어요...2층까지 둘러보시면 좋을거같아요. 자세한 내용은 팜플렛을 참고하세요~
2. 준영 : 네 감사합니다.
2. 준영이는 발표를 한다.
3. 대기하고 있던 NPC는 2층으로 올라간다.
4. (일반 전시관으로 향하며)
준영: 1층에 작품있는 작품을 다 보고 2층으로 올라가보겠습니다.
준영: 실제 오프라인과 같이 미술작품이 전시되어있고 작품 앞으로 가서 x버튼을 누르게 되면 작품을 감상하실 수 있습니다.
5. (일반 전시 앞에서) 친구들(2명)이 모여있고, 영상 대화에 참여한다. (총 3명)
준영: (친구1에게) 잘 지냈어? 뭐 보고있어? 나도 공유해줘
친구1: (준영에게) 좋아! (잠깐 등장)
준영: 여기 전시되어 있는 작품을 보도록 하겠습니다.
준영: 그리고 특정 유저들을 선택하고 공유하기 버튼을 누르면 친구들과 작품을 함께 공유할 수 있습니다. 각 유저들의 마우스가 표시되어 친구들과 작품을 보며 수다를 떨거나 도슨트와 관람객과의 상호작용을 할 수 있게 도와줍니다.
6. ~~(도슨트와 무리로 (총 9명) 다가가며) 그리고 총 10명이상의 사람들과 함께 영상통화가 가능합니다. 영상통화 시그널링 방식을 적절하게 조합하였으니 포스트세션에서 많은 질문 부탁드립니다.~~
7. (파노라마 전시관을 향하며)
준영: 두번째로 파노라마 전시관으로 가보겠습니다. 파노라마는 이미지간의 각도를 주어 작품을 조금더 광활한 느낌을 주기 위한 방입니다.
8. (파노라마 전시관 안)
준영: 이런 느낌으로 작품을 감상할 수 있습니다.
9. (3D 전시관으로 향하며)
준영: 다음은 3D 전시관으로 2층으로 가보겠습니다.
10. (3D 전시관 안)
준영: 다음은 3D전시관입니다. 캐릭터들간의 Y좌표 차이로 캐릭터들의 스케일을 조절하며 원근감을 줄 수 있도록 설계했고, Q, E key로 좌우 전환하여 작품을 감상할 수 있습니다. 꽤나 멋지죠?
11. (방을 나가며)
준영: 여기까지 시연을 마치도록 하겠습니다.
Algorithm
XAlgorithm
XAlgorithm
X기술적 고민
최적화중..
connect() already called
에러
When two producers or consumers are created at the same time and over the same transport in the client side then the
transport.on('connect')
event is fired twice. Thus, two simultaneous requests are sent to the server and as a result, dual call to thetransport.connect()
happens. 출처 : https://mediasoup.discourse.group/t/error-connect-already-called/59/9
우선, 관련 코드들에 async-await 걸어주었다
에러2
에러3
그다음 계속 서버가 터질 때마다 해당되는 코드에 ?
, try-catch, async-await 달아줌
5명 동시접속도 성공
disconnect 에러 찾음 (ID→Id) 글자 오타로 인자를 잘못 받아오고 있었다. 🥲
오디오
let params_audio = {
codecOptions: {
opusStereo: 1,
opusDtx: 1,
},
};
let params_video = {
// mediasoup params
encodings: [
{
rid: "r0",
maxBitrate: 100000,
scalabilityMode: "S1T3",
},
{
rid: "r1",
maxBitrate: 300000,
scalabilityMode: "S1T3",
},
{
rid: "r2",
maxBitrate: 900000,
scalabilityMode: "S1T3",
},
],
codecOptions: {
videoGoogleStartBitrate: 1000,
},
};
myStream // mute default
.getAudioTracks()
.forEach((track) => (track.enabled = true));
const video_track = myStream.getVideoTracks()[0]
const audio_track = myStream.getAudioTracks()[0]
params_video = {
video_track,
...params_video,
};
params_audio = {
audio_track,
...params_audio,
};
Algorithm
X producer_video = await producerTransport.produce(params_video);
**producer_audio = await producerTransport.produce(params_audio);**
producer_video.on("trackended", () => {
console.log("producer의 trackended 이벤트 실행");
console.log("track ended");
// close video track
});
producer_video.on("transportclose", () => {
console.log("producer의 transportclose 이벤트 실행");
console.log("transport ended");
// close video track
});
producer_audio.on("trackended", () => {
console.log("producer의 trackended 이벤트 실행");
console.log("track ended");
// close audio track
});
producer_audio.on("transportclose", () => {
console.log("producer의 transportclose 이벤트 실행");
console.log("transport ended");
// close audio track
});
};
// 음성 connect
async function setAudio(peerStream, socketId){
console.log("audio tag만들자")
const streams = document.querySelector("#streams");
const div = document.querySelector(`#${socketId}`);
let elem = document.createElement('audio')
elem.srcObject = peerStream
elem.playsinline = false
elem.autoplay = true
div.appendChild(elem)
streams.appendChild(div);
}
const { track } = consumer;
// console.log("--------- consumer : ", consumer);
// console.log("--------- params : ", params)
const peerStream = new MediaStream([track]);
if (track.kind === 'video') {
let cnt = 0
reduplication.forEach(objectId => {
if (remoteSocketId === objectId){
cnt += 1
}
})
if (cnt === 0) {
reduplication.push(remoteSocketId);
console.log("only one", reduplication)
await paintPeerFace(peerStream, remoteSocketId);
}
} else {
let cnt = 0
audio_reduplication.forEach(objectId => {
if (remoteSocketId === objectId){
cnt += 1
}
})
if (cnt === 0) {
audio_reduplication.push(remoteSocketId);
console.log("only one", audio_reduplication)
await setAudio(peerStream, remoteSocketId);
}
}
Algorithm
X기술적 고민
removePeerFace가 한 사람만 삭제하고, 나머지 한 사람은 들고있게 되는 현상
leavesucc가 각자 실행되지 않고 있음
→ reduplication을 초기화 해줌으로써 임시 해결
2명 - consumer 4, producer 2, transport 5
consumers [object Object],[object Object],[object Object],[object Object], producers [object Object],[object Object], transports [object Object],[object Object],[object Object],[object Object],[object Object]
3명 - consumer 16, producer 4, transport 18
consumers [object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object], producers [object Object],[object Object],[object Object],[object Object], transports [object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]