[0] getUserMedia()를 통해 stream이 성공적으로 받아와 진다.
[1] 각 클라이언트는 new Device()를 통해 객체를 생성, 라우터로부터 rtpCapabilities를 받아 device.load() 실행
const createDevice = async () => {
try {
device = new mediasoupClient.Device();
await device.load({
routerRtpCapabilities: rtpCapabilities,
});
// webRTCTransport 생성
createSendTransport();
[2] 서버에선 webRTCTransport 를 producer, consumer 쪽으로 하나씩 생성. 이를 위해서는 listenIPs나 enableUdp 등등의 options 정보가 필요 함
@SubscribeMessage('createWebRtcTransport')
async handleCreateTransport(): Promise<void> {
const initialAvailableOutgoingBitrate = config.mediasoup.WebRtcTransport.initialAvailableOutgoingBitrate;
try {
const transport = await router.createWebRtcTransport({
listenIps: config.mediasoup.WebRtcTransport.listenIps,
enableUdp: true,
enableTcp: true,
preferUdp: true,
initialAvailableOutgoingBitrate,
});
console.log(`transport_id, ${transport.id}`);
// 생성한 Transport 정보 클라이언트에 반환
this.server.emit('createWebRtcTransport', {
transport,
params: {
id: transport.id,
iceParameters: transport.iceParameters,
iceCandidates: transport.iceCandidates,
dtlsParameters: transport.dtlsParameters,
},
});
} catch (error) {
console.error('Error creating transport:', error);
}
}
[3] 양쪽의 webRTCTransport로부터 parameter들을 받아와 Client로 전송 → SEND Transport와 RECV Transport를 생성
[4] producer 클라이언트가 SEND Transport에서 produce 메서드를 호출하는 경우 인자로 encodings, codecOptions 와 같은 파라미터들을 넣어주고, 이 메서드는 producer 를 반환
const createSendTransport = async () => {
socket.emit('createWebRtcTransport');
await socket.on('createWebRtcTransport', data => {
const { transport, params } = data;
if (params.error) {
console.log(params.error);
return;
}
producerTransport = device.createSendTransport(params);
console.log('createSendTransport ~ producerTransport:', producerTransport);
producerTransport.on('connect', async ({ dtlsParameters }, callback, errback) => {
try {
// 로컬 DTLS 매개변수를 서버 측 transport에 신호 전달
socket.emit('transport-connect', { dtlsParameters });
// transport에 parameters들이 전송되었다는 것을 알려주는 역할!
callback();
} catch (error) {
errback(error);
}
});
producerTransport.on('produce', async (parameters, callback, errback) => {
try {
// 서버에게 파라미터와 함께 Producer 생성 요청.
// 생성하고 서버 측 Producer id받기
socket.emit(
'transport-produce',
{
kind: parameters.kind,
rtpParameters: parameters.rtpParameters,
appData: parameters.appData,
},
({ id }) => {
callback({ id });
},
);
} catch (error) {
errback(error);
}
});
connectSendTransport();
다음 로직은 구현하지 못해 추후 구현 후 기술 예정
참고 자료
WebRTC: mediasoup (SFU) introduction - Part 1
MediaSoup 을 사용해서 SFU방식으로 VideoChat 구현하기(1/2) 이론
mediasoup-client documentation