Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Release] 6차 배포 (12.06) #385

Merged
merged 45 commits into from
Dec 5, 2024
Merged
Show file tree
Hide file tree
Changes from 43 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
dc01111
feat: 방 관리자 socketid 추가
begong313 Dec 3, 2024
ab0199a
feat: 방 관리자 socketid 추가
begong313 Dec 3, 2024
68f940a
feat: 함수명 변경, 메모리누수요소 변경
begong313 Dec 3, 2024
34f7133
feat: 방 닫기 로직 정리
begong313 Dec 4, 2024
06cc915
feat: merge develop
begong313 Dec 4, 2024
dd97ebb
feat: 이벤트 횟수 최적화
begong313 Dec 4, 2024
c72050b
fix: MediasoupConfig에 H264 비디오 코덱 추가 및 VP8 코덱의 파라미터 수정
seoko97 Dec 5, 2024
461a53f
fix: 클라이언트 측 코덱 정보와 서버측 코덱 정보가 일치하지 않아 발생하는 버그 수정
seoko97 Dec 5, 2024
715c98a
fix: consumer가 종료된 경우 업데이트 하지 않도록 수정
seoko97 Dec 5, 2024
b8d9616
fix: 네트워크 품질 체크 결과가 없을 경우 처리 추가
seoko97 Dec 5, 2024
bdf17ab
fix: 비디오 프로듀서 옵션의 인코딩 및 코덱 설정 수정
seoko97 Dec 5, 2024
a86c8bd
docs: README.md 업데이트
seoko97 Dec 5, 2024
a706740
fix: 비디오 프로듀서 옵션의 최대 비트 전송률 조정 및 불필요한 scalabilityMode 제거
seoko97 Dec 5, 2024
daba350
fix: 불필요한 scaleResolutionDownBy 제거
seoko97 Dec 5, 2024
81a43aa
fix: 함수 이름 변경 및 consumer 상태 확인 추가
seoko97 Dec 5, 2024
25e22e7
fix: 네트워크 상태에 따라 해상도만 변경하도록 수정
seoko97 Dec 5, 2024
1ee54f7
Merge pull request #372 from boostcampwm-2024/feat/#358/master-exit-r…
simeunseo Dec 5, 2024
c654f4b
fix: 미디어 장치 필터링 로직 개선 및 선택된 장치 ID 초기화 조건 추가
seoko97 Dec 5, 2024
b66ff06
fix: consumer의 선호 레이어 설정에서 null 조건부 연산자 제거
seoko97 Dec 5, 2024
9af890b
feat: AI 요약 dialog UI 수정
simeunseo Dec 5, 2024
99bdbc9
feat: 대시보드 조회시에 summary 여부 판단 추가
Jieun1ee Dec 5, 2024
38fae97
feat: 필요없는 주석 삭제
Jieun1ee Dec 5, 2024
b425bd3
feat: NotSupportedMobile 페이지 컴포넌트 추가
seoko97 Dec 5, 2024
a155040
feat: NotFound 페이지 컴포넌트 추가
seoko97 Dec 5, 2024
0d2b935
feat: 모바일 지원되지 않는 경우 NotSupportedMobile 컴포넌트 추가
seoko97 Dec 5, 2024
3f7ad0a
Merge pull request #376 from boostcampwm-2024/feat/#374/ai-status
Jieun1ee Dec 5, 2024
7dc7b74
feat: Merge branch 'develop' into feat/#368/dashboard-ui
simeunseo Dec 5, 2024
4b2da46
feat: dashboardList response에 summary 필드 추가
simeunseo Dec 5, 2024
1829eab
feat: summary가 존재할 때만 AI 요약 버튼 보이게 하기
simeunseo Dec 5, 2024
19f217d
feat: AI 요약 로딩중 분기 수정
simeunseo Dec 5, 2024
6378217
feat: 대시보드 API 훅에 staleTime 설정 추가
seoko97 Dec 5, 2024
b8431db
feat: ApplicantsDialog에서 ticleId를 사용하여 신청자 데이터를 가져오도록 수정
seoko97 Dec 5, 2024
5906283
feat: 소켓 연결 해제 시 네비게이션 제거
seoko97 Dec 5, 2024
7448f09
feat: 방장이 x버튼을 눌러서 종료시 alert 및 티클 상태 closed로 변경
simeunseo Dec 5, 2024
a429287
feat: isOwner에 따른 분기 처리 수정
simeunseo Dec 5, 2024
da8424c
Merge pull request #378 from boostcampwm-2024/feat/#368/dashboard-ui
simeunseo Dec 5, 2024
c24e15b
Merge pull request #382 from boostcampwm-2024/feat/#381/ticle-end
simeunseo Dec 5, 2024
07076d6
feat: 티클 종료 status 변경 시점 변경
simeunseo Dec 5, 2024
a8b9451
Merge branch 'develop' into feat/#383/ticle-end
simeunseo Dec 5, 2024
ffab126
Merge pull request #384 from boostcampwm-2024/feat/#383/ticle-end
simeunseo Dec 5, 2024
d6fcdf0
Merge pull request #375 from boostcampwm-2024/fix/#367/stream
seoko97 Dec 5, 2024
f270ccb
Merge pull request #377 from boostcampwm-2024/feat/#280/not-found
seoko97 Dec 5, 2024
0ca54b5
Merge pull request #380 from boostcampwm-2024/feat/#379/query-cache
seoko97 Dec 5, 2024
e3ac054
fix: ticle entity
Fixtar Dec 5, 2024
452887b
Merge pull request #386 from boostcampwm-2024/fix/#385/fix-ticle-entity
Fixtar Dec 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@

## 프론트엔드

<h4><a href='https://simeunseo.notion.site/5d4f6f4ab2124d19940e21e19ac3f04b?pvs=4'>🔗 네트워크 상태에 따른 스트림 품질 변경</a></h4>
<h4><a href='https://simeunseo.notion.site/14a599a6f0d2800cb40add7d399525aa?pvs=4'>🔗 스트리밍을 최적화 해보자</a></h4>

> 최대한 많은 유저가 들어와 화상 서비스를 이용하는 것을 목적으로 하는 만큼 소켓 이벤트, 기존 할당된 자원에 대한 관리를 진행하며 최대한 적은 자원으로 나은 환경을 제공하기 위해 최적화를 진행하였습니다.
Expand Down
3 changes: 2 additions & 1 deletion apps/api/src/dashboard/dashboard.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';

import { Applicant } from '@/entity/applicant.entity';
import { Summary } from '@/entity/summary.entity';
import { Ticle } from '@/entity/ticle.entity';

import { DashboardController } from './dashboard.controller';
import { DashboardService } from './dashboard.service';

@Module({
imports: [TypeOrmModule.forFeature([Ticle, Applicant])],
imports: [TypeOrmModule.forFeature([Ticle, Applicant, Summary])],
controllers: [DashboardController],
providers: [DashboardService],
})
Expand Down
30 changes: 26 additions & 4 deletions apps/api/src/dashboard/dashboard.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Repository } from 'typeorm';
import { ErrorMessage, TicleStatus } from '@repo/types';

import { Applicant } from '@/entity/applicant.entity';
import { Summary } from '@/entity/summary.entity';
import { Ticle } from '@/entity/ticle.entity';

@Injectable()
Expand All @@ -12,7 +13,9 @@ export class DashboardService {
@InjectRepository(Ticle)
private readonly ticleRepository: Repository<Ticle>,
@InjectRepository(Applicant)
private readonly applicantRepository: Repository<Applicant>
private readonly applicantRepository: Repository<Applicant>,
@InjectRepository(Summary)
private readonly summaryRepository: Repository<Summary>
) {}

async getCreatedTicleList(
Expand All @@ -25,7 +28,15 @@ export class DashboardService {

const queryBuilder = this.ticleRepository
.createQueryBuilder('ticle')
.select(['ticle.id', 'ticle.title', 'ticle.startTime', 'ticle.endTime', 'ticle.ticleStatus'])
.leftJoin('ticle.summary', 'summary')
.select([
'ticle.id',
'ticle.title',
'ticle.startTime',
'ticle.endTime',
'ticle.ticleStatus',
'summary.id',
])
.where('ticle.speaker = :speakerId', { speakerId })
.skip(skip)
.take(pageSize);
Expand All @@ -40,7 +51,12 @@ export class DashboardService {
}
}

const [ticles, totalItems] = await queryBuilder.getManyAndCount();
const [ticle, totalItems] = await queryBuilder.getManyAndCount();

const ticles = ticle.map((ticle) => ({
...ticle,
summary: ticle.summary ? ticle.summary.id !== null : false,
}));

const totalPages = Math.ceil(totalItems / pageSize);

Expand All @@ -62,6 +78,7 @@ export class DashboardService {
const queryBuilder = this.applicantRepository
.createQueryBuilder('applicant')
.leftJoinAndSelect('applicant.ticle', 'ticle')
.leftJoin('ticle.summary', 'summary')
.select([
'applicant.id',
'ticle.id',
Expand All @@ -70,6 +87,7 @@ export class DashboardService {
'ticle.startTime',
'ticle.endTime',
'ticle.ticleStatus',
'summary.id',
])
.where('applicant.user = :userId', { userId })
.skip(skip)
Expand All @@ -87,7 +105,11 @@ export class DashboardService {

const [applicants, totalItems] = await queryBuilder.getManyAndCount();

const ticles = applicants.map((applicant) => applicant.ticle);
const ticles = applicants.map((applicant) => ({
...applicant.ticle,
summary: applicant.ticle.summary ? applicant.ticle.summary.id !== null : false,
}));

const totalPages = Math.ceil(totalItems / pageSize);

return {
Expand Down
12 changes: 12 additions & 0 deletions apps/media/src/mediasoup/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,22 @@ export class MediasoupConfig {
useinbandfec: 1,
},
},
{
kind: 'video',
mimeType: 'video/H264',
clockRate: 90000,
parameters: {
'packetization-mode': 1,
'profile-level-id': '42e01f',
},
},
{
kind: 'video',
mimeType: 'video/VP8',
clockRate: 90000,
parameters: {
'x-google-start-bitrate': 10000,
},
},
] as RtpCodecCapability[],
};
Expand Down
27 changes: 15 additions & 12 deletions apps/media/src/mediasoup/mediasoup.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export class MediasoupService implements OnModuleInit {
return worker;
}

async createRoom(roomId: string) {
async createRoom(roomId: string, masterSocketId: string) {
const isExistRoom = this.roomService.existRoom(roomId);
if (isExistRoom) {
return roomId;
Expand All @@ -59,7 +59,7 @@ export class MediasoupService implements OnModuleInit {
mediaCodecs: this.mediasoupConfig.router.mediaCodecs,
});

return this.roomService.createRoom(roomId, router);
return this.roomService.createRoom(roomId, router, masterSocketId);
}

joinRoom(roomId: string, socketId: string, nickname: string) {
Expand Down Expand Up @@ -113,10 +113,6 @@ export class MediasoupService implements OnModuleInit {
const peer = room.getPeer(socketId);
const transport = peer.getTransport(transportId);

if (appData.mediaTypes !== 'audio') {
rtpParameters.encodings = server.PRODUCER_OPTIONS.encodings;
}

const producer = await transport.produce({
kind,
rtpParameters,
Expand Down Expand Up @@ -269,6 +265,8 @@ export class MediasoupService implements OnModuleInit {
const peer = room.peers.get(socketId);
const consumer = peer.getConsumer(consumerId);

if (!consumer) return;

consumer?.pause();

return { paused: true, consumerId, producerId: consumer.producerId };
Expand All @@ -279,6 +277,8 @@ export class MediasoupService implements OnModuleInit {
const peer = room.peers.get(socketId);
const consumer = peer.getConsumer(consumerId);

if (!consumer) return;

if (consumer?.producerPaused) {
return { paused: true, consumerId, producerId: consumer.producerId };
}
Expand All @@ -289,11 +289,15 @@ export class MediasoupService implements OnModuleInit {
}

pauseConsumers(socketId: string, roomId: string, consumerIds: string[]) {
return consumerIds.map((consumerId) => this.pauseConsumer(socketId, consumerId, roomId));
return consumerIds
.map((consumerId) => this.pauseConsumer(socketId, consumerId, roomId))
.filter(Boolean);
}

resumeConsumers(socketId: string, roomId: string, consumerIds: string[]) {
return consumerIds.map((consumerId) => this.resumeConsumer(socketId, consumerId, roomId));
return consumerIds
.map((consumerId) => this.resumeConsumer(socketId, consumerId, roomId))
.filter(Boolean);
}

changeConsumerPreferredLayers(
Expand All @@ -307,10 +311,9 @@ export class MediasoupService implements OnModuleInit {

const consumer = peer.getConsumer(consumerId);

consumer?.setPreferredLayers({
spatialLayer: networkQuality,
temporalLayer: networkQuality,
});
if (!consumer || consumer.closed || consumer.paused) return;

consumer.setPreferredLayers({ spatialLayer: networkQuality });
});
}

Expand Down
6 changes: 1 addition & 5 deletions apps/media/src/record/record.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,6 @@ export class RecordService {
return recordInfo;
}

getRecordInfo(roomId: string) {
return this.recordInfos.get(roomId);
}

private async addPlainTransport(recordInfo: RecordInfo, router: types.Router) {
const plainTransport = await this.mediasoupService.createPlainTransport(router);
recordInfo.setPlainTransport(plainTransport);
Expand Down Expand Up @@ -117,7 +113,7 @@ export class RecordService {
return;
}
this.releasePort(recordInfo.port);
recordInfo.stopRecordProcess();
recordInfo.clearStream();
this.recordInfos.delete(roomId);
}

Expand Down
3 changes: 2 additions & 1 deletion apps/media/src/record/recordInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export class RecordInfo {
this.recordConsumer.resume();
}

stopRecordProcess() {
clearStream() {
if (this.recordConsumer) {
this.recordConsumer.close();
this.recordConsumer = null;
Expand Down Expand Up @@ -84,6 +84,7 @@ export class RecordInfo {
this.ncpService.uploadFile(filePath, remoteFileName, roomId);
unlinkSync(sdpFilePath);
this.ffmpegProcess = null;
this.clearStream();
})
.save(filePath);

Expand Down
37 changes: 27 additions & 10 deletions apps/media/src/room/room.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ export class RoomService {

constructor() {}

createRoom(roomId: string, router: Router) {
const room = new Room(roomId, router);
createRoom(roomId: string, router: Router, masterSocketId: string) {
const room = new Room(roomId, router, masterSocketId);
this.rooms.set(roomId, room);
return roomId;
}
Expand All @@ -31,14 +31,7 @@ export class RoomService {

deletePeer(socketId: string) {
for (const [roomId, room] of this.rooms) {
if (!room.removePeer(socketId)) continue;

if (room.peers.size === 0) {
room.close();
this.rooms.delete(roomId);
}

return roomId;
if (room.removePeer(socketId)) return roomId;
}
}

Expand All @@ -48,4 +41,28 @@ export class RoomService {
this.rooms.delete(roomId);
return roomId;
}

checkIsMaster(roomId: string, socketId: string) {
const room = this.rooms.get(roomId);
if (!room) {
return false;
}
return room.masterSocketId === socketId;
}

checkRoomIsOpen(roomId: string) {
const room = this.rooms.get(roomId);
if (!room) {
return false;
}
return room.isOpen;
}

setRoomIsOpen(roomId: string, isOpen: boolean) {
const room = this.rooms.get(roomId);
if (!room) {
return;
}
room.isOpen = isOpen;
}
}
6 changes: 5 additions & 1 deletion apps/media/src/room/room.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,17 @@ import { Peer } from './peer';

export class Room {
id: string;
masterSocketId: string;
router: Router;
peers: Map<string, Peer>;
isOpen: boolean;

constructor(roomId: string, router: Router) {
constructor(roomId: string, router: Router, masterSocketId: string) {
this.id = roomId;
this.router = router;
this.masterSocketId = masterSocketId;
this.peers = new Map();
this.isOpen = true;
}

getRouter() {
Expand Down
24 changes: 16 additions & 8 deletions apps/media/src/signaling/signaling.gateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,29 @@ import type { client, server } from '@repo/mediasoup';

import { MediasoupService } from '@/mediasoup/mediasoup.service';
import { RecordService } from '@/record/record.service';
import { RoomService } from '@/room/room.service';
import { WSExceptionFilter } from '@/wsException.filter';

@WebSocketGateway()
@UseFilters(WSExceptionFilter)
export class SignalingGateway implements OnGatewayDisconnect {
constructor(
private mediasoupService: MediasoupService,
private recordService: RecordService
private recordService: RecordService,
private roomService: RoomService
) {}

@SubscribeMessage(SOCKET_EVENTS.createRoom)
async handleCreateRoom(@MessageBody('roomId') roomId: string) {
await this.mediasoupService.createRoom(roomId);
async handleCreateRoom(@ConnectedSocket() client: Socket, @MessageBody('roomId') roomId: string) {
await this.mediasoupService.createRoom(roomId, client.id);
return { roomId };
}

@SubscribeMessage(SOCKET_EVENTS.joinRoom)
joinRoom(@ConnectedSocket() client: Socket, @MessageBody() joinRoomDto: server.JoinRoomDto) {
const { roomId, nickname } = joinRoomDto;
client.join(roomId);
const rtpCapabilities = this.mediasoupService.joinRoom(roomId, client.id, nickname);
client.join(roomId);
client.to(roomId).emit(SOCKET_EVENTS.newPeer, { peerId: client.id, nickname });
return { rtpCapabilities };
}
Expand Down Expand Up @@ -104,12 +106,18 @@ export class SignalingGateway implements OnGatewayDisconnect {

handleDisconnect(@ConnectedSocket() client: Socket) {
const roomId = this.mediasoupService.disconnect(client.id);
const recordInfo = this.recordService.getRecordInfo(roomId);
if (recordInfo && recordInfo.socketId === client.id) {
const isMaster = this.roomService.checkIsMaster(roomId, client.id);
if (isMaster) {
client.to(roomId).emit(SOCKET_EVENTS.roomClosed);
this.recordService.stopRecord(roomId);
this.mediasoupService.closeRoom(roomId);
return;
}

client.to(roomId).emit(SOCKET_EVENTS.peerLeft, { peerId: client.id });
const isOpen = this.roomService.checkRoomIsOpen(roomId);
if (isOpen) {
client.to(roomId).emit(SOCKET_EVENTS.peerLeft, { peerId: client.id });
}
}

@SubscribeMessage(SOCKET_EVENTS.closeProducer)
Expand Down Expand Up @@ -188,7 +196,7 @@ export class SignalingGateway implements OnGatewayDisconnect {
@SubscribeMessage(SOCKET_EVENTS.closeRoom)
closeMeetingRoom(@ConnectedSocket() client: Socket, @MessageBody('roomId') roomId: string) {
client.to(roomId).emit(SOCKET_EVENTS.roomClosed);
this.mediasoupService.closeRoom(roomId);
this.roomService.setRoomIsOpen(roomId, false);
}

@SubscribeMessage(SOCKET_EVENTS.startRecord)
Expand Down
3 changes: 2 additions & 1 deletion apps/media/src/signaling/signaling.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import { Module } from '@nestjs/common';

import { MediasoupModule } from '@/mediasoup/mediasoup.module';
import { RecordModule } from '@/record/record.module';
import { RoomModule } from '@/room/room.module';

import { SignalingGateway } from './signaling.gateway';

@Module({
imports: [MediasoupModule, RecordModule],
imports: [MediasoupModule, RecordModule, RoomModule],
providers: [SignalingGateway],
exports: [SignalingGateway],
})
Expand Down
Loading
Loading