@@ -7,6 +7,7 @@ type onMediaDisconnectedCb = (socketId: string) => void;
77
88class RTC {
99 static BITRATE = Number ( env . WEBRTC_VIDEO_BITRATE ) ;
10+
1011 private socket : Socket ;
1112 private iceServerUrls : string [ ] ;
1213 private userMediaStream : MediaStream ;
@@ -27,6 +28,28 @@ class RTC {
2728 this . streams = new Map ( ) ;
2829 this . onMediaConnectedCallback = ( ) => { } ; // eslint-disable-line @typescript-eslint/no-empty-function
2930 this . onMediaDisconnectedCallback = ( ) => { } ; // eslint-disable-line @typescript-eslint/no-empty-function
31+
32+ this . socket . on (
33+ WORKSPACE_EVENT . RECEIVE_HELLO ,
34+ this . sendOfferOnHello . bind ( this ) ,
35+ ) ;
36+ this . socket . on (
37+ WORKSPACE_EVENT . RECEIVE_OFFER ,
38+ this . sendAnswerOnOffer . bind ( this ) ,
39+ ) ;
40+ this . socket . on (
41+ WORKSPACE_EVENT . RECEIVE_ANSWER ,
42+ this . setRemotePeerOnAnswer . bind ( this ) ,
43+ ) ;
44+ this . socket . on ( WORKSPACE_EVENT . RECEIVE_ICE , this . addIce . bind ( this ) ) ;
45+ this . socket . on (
46+ WORKSPACE_EVENT . RECEIVE_BYE ,
47+ this . cleanUpRemoteAndEmitMediaDisconnectedEvent . bind ( this ) ,
48+ ) ;
49+ }
50+
51+ connect ( ) {
52+ this . socket . emit ( WORKSPACE_EVENT . SEND_HELLO ) ;
3053 }
3154
3255 onMediaConnected ( callback : onMediaConnectedCb ) {
@@ -37,41 +60,110 @@ class RTC {
3760 this . onMediaDisconnectedCallback = callback ;
3861 }
3962
40- #createPeerConnection( remoteSocketId : string ) {
63+ private async sendOfferOnHello ( remoteSocketId : string ) {
64+ const pc = this . createPeerConnection ( remoteSocketId ) ;
65+
66+ const offer = await pc . createOffer ( ) ;
67+ await pc . setLocalDescription ( offer ) ;
68+
69+ this . socket . emit ( WORKSPACE_EVENT . SEND_OFFER , offer , remoteSocketId ) ;
70+ }
71+
72+ private async sendAnswerOnOffer (
73+ offer : RTCSessionDescriptionInit ,
74+ remoteSocketId : string ,
75+ ) {
76+ const pc = this . createPeerConnection ( remoteSocketId ) ;
77+ await pc . setRemoteDescription ( offer ) ;
78+
79+ const answer = await pc . createAnswer ( ) ;
80+ await pc . setLocalDescription ( answer ) ;
81+
82+ this . setVideoBitrate ( pc , RTC . BITRATE ) ;
83+
84+ this . socket . emit ( WORKSPACE_EVENT . SEND_ANSWER , answer , remoteSocketId ) ;
85+ }
86+
87+ private async setRemotePeerOnAnswer (
88+ answer : RTCSessionDescriptionInit ,
89+ remoteSocketId : string ,
90+ ) {
91+ const pc = this . connections . get ( remoteSocketId ) ;
92+ if ( ! pc ) {
93+ throw new Error ( 'No RTCPeerConnection on answer received.' ) ;
94+ }
95+
96+ await pc . setRemoteDescription ( answer ) ;
97+
98+ this . setVideoBitrate ( pc , RTC . BITRATE ) ;
99+ }
100+
101+ private addIce ( ice : RTCIceCandidateInit , remoteSocketId : string ) {
102+ const pc = this . connections . get ( remoteSocketId ) ;
103+ if ( ! pc ) {
104+ throw new Error ( 'No RTCPeerConnection on ice candindate received.' ) ;
105+ }
106+
107+ pc . addIceCandidate ( ice ) ;
108+ }
109+
110+ private cleanUpRemoteAndEmitMediaDisconnectedEvent ( remoteSocketId : string ) {
111+ this . connections . delete ( remoteSocketId ) ;
112+ this . streams . delete ( remoteSocketId ) ;
113+
114+ this . onMediaDisconnectedCallback ( remoteSocketId ) ;
115+ }
116+
117+ private createPeerConnection ( remoteSocketId : string ) {
41118 // initialize
42119 const pcOptions = {
43120 iceServers : [ { urls : this . iceServerUrls } ] ,
44121 } ;
45122 const pc = new RTCPeerConnection ( pcOptions ) ;
46123
47124 // add event listeners
48- pc . addEventListener ( 'icecandidate' , ( iceEvent ) => {
49- this . socket . emit (
50- WORKSPACE_EVENT . SEND_ICE ,
51- iceEvent . candidate ,
52- remoteSocketId ,
53- ) ;
54- } ) ;
55- pc . addEventListener ( 'track' , async ( event ) => {
56- if ( this . streams . has ( remoteSocketId ) ) {
57- return ;
58- }
59-
60- const [ remoteStream ] = event . streams ;
61-
62- this . streams . set ( remoteSocketId , remoteStream ) ;
63- this . onMediaConnectedCallback ( remoteSocketId , remoteStream ) ;
64- } ) ;
125+ const emitIce : ( iceEvent : RTCPeerConnectionIceEvent ) => void =
126+ this . emitIce . bind ( this , remoteSocketId ) ;
127+ pc . addEventListener ( 'icecandidate' , emitIce ) ;
128+
129+ const setRemoteTrack : ( trackEvent : RTCTrackEvent ) => void =
130+ this . setRemoteTrackAndEmitMediaConnectedEvent . bind ( this , remoteSocketId ) ;
131+ pc . addEventListener ( 'track' , setRemoteTrack ) ;
65132
66133 // add tracks
67134 this . userMediaStream
68135 . getTracks ( )
69136 . forEach ( ( track ) => pc . addTrack ( track , this . userMediaStream ) ) ;
70137
138+ // register connection
139+ this . connections . set ( remoteSocketId , pc ) ;
140+
71141 return pc ;
72142 }
73143
74- async #setVideoBitrate( pc : RTCPeerConnection , bitrate : number ) {
144+ private emitIce ( remoteSocketId : string , iceEvent : RTCPeerConnectionIceEvent ) {
145+ this . socket . emit (
146+ WORKSPACE_EVENT . SEND_ICE ,
147+ iceEvent . candidate ,
148+ remoteSocketId ,
149+ ) ;
150+ }
151+
152+ private setRemoteTrackAndEmitMediaConnectedEvent (
153+ remoteSocketId : string ,
154+ trackEvent : RTCTrackEvent ,
155+ ) {
156+ if ( this . streams . has ( remoteSocketId ) ) {
157+ return ;
158+ }
159+
160+ const [ remoteStream ] = trackEvent . streams ;
161+
162+ this . streams . set ( remoteSocketId , remoteStream ) ;
163+ this . onMediaConnectedCallback ( remoteSocketId , remoteStream ) ;
164+ }
165+
166+ private async setVideoBitrate ( pc : RTCPeerConnection , bitrate : number ) {
75167 // fetch video sender
76168 const videoSender = pc
77169 . getSenders ( )
@@ -86,72 +178,6 @@ class RTC {
86178 params . encodings [ 0 ] . maxBitrate = bitrate ;
87179 await videoSender . setParameters ( params ) ;
88180 }
89-
90- connect ( ) {
91- this . socket . on ( WORKSPACE_EVENT . RECEIVE_HELLO , async ( remoteSocketId ) => {
92- const pc = this . #createPeerConnection( remoteSocketId ) ;
93- this . connections . set ( remoteSocketId , pc ) ;
94-
95- const offer = await pc . createOffer ( ) ;
96- await pc . setLocalDescription ( offer ) ;
97-
98- this . socket . emit (
99- WORKSPACE_EVENT . SEND_OFFER ,
100- pc . localDescription ,
101- remoteSocketId ,
102- ) ;
103- } ) ;
104-
105- this . socket . on (
106- WORKSPACE_EVENT . RECEIVE_OFFER ,
107- async ( offer , remoteSocketId ) => {
108- const pc = this . #createPeerConnection( remoteSocketId ) ;
109- this . connections . set ( remoteSocketId , pc ) ;
110-
111- await pc . setRemoteDescription ( offer ) ;
112-
113- const answer = await pc . createAnswer ( ) ;
114- await pc . setLocalDescription ( answer ) ;
115-
116- this . #setVideoBitrate( pc , RTC . BITRATE ) ;
117-
118- this . socket . emit ( WORKSPACE_EVENT . SEND_ANSWER , answer , remoteSocketId ) ;
119- } ,
120- ) ;
121-
122- this . socket . on (
123- WORKSPACE_EVENT . RECEIVE_ANSWER ,
124- async ( answer , remoteSocketId ) => {
125- const pc = this . connections . get ( remoteSocketId ) ;
126- if ( ! pc ) {
127- throw new Error ( 'No RTCPeerConnection on answer received.' ) ;
128- }
129-
130- await pc . setRemoteDescription ( answer ) ;
131-
132- this . #setVideoBitrate( pc , RTC . BITRATE ) ;
133- } ,
134- ) ;
135-
136- this . socket . on ( WORKSPACE_EVENT . RECEIVE_ICE , ( ice , remoteSocketId ) => {
137- const pc = this . connections . get ( remoteSocketId ) ;
138-
139- if ( ! pc ) {
140- throw new Error ( 'No RTCPeerConnection on ice candindate received.' ) ;
141- }
142-
143- pc . addIceCandidate ( ice ) ;
144- } ) ;
145-
146- this . socket . on ( WORKSPACE_EVENT . RECEIVE_BYE , ( remoteSocketId ) => {
147- this . connections . delete ( remoteSocketId ) ;
148- this . streams . delete ( remoteSocketId ) ;
149-
150- this . onMediaDisconnectedCallback ( remoteSocketId ) ;
151- } ) ;
152-
153- this . socket . emit ( WORKSPACE_EVENT . SEND_HELLO ) ;
154- }
155181}
156182
157183export default RTC ;
0 commit comments