1+ import { parseClassName } from 'react-toastify/dist/utils' ;
12import { Socket } from 'socket.io-client' ;
23import SOCKET_MESSAGE from 'src/constants/socket-message' ;
4+ const MSG = SOCKET_MESSAGE . WORKSPACE ;
5+
6+ type SocketId = string ;
37
48type onMediaConnectedCb = ( socketId : string , remoteStream : MediaStream ) => void ;
59type onMediaDisconnectedCb = ( socketId : string ) => void ;
@@ -28,6 +32,16 @@ class RTC {
2832 this . onMediaDisconnectedCallback = ( ) => { } ; // eslint-disable-line @typescript-eslint/no-empty-function
2933 }
3034
35+ connect ( ) {
36+ this . socket . on ( MSG . RECEIVE_HELLO , this . setDescriptionAndEmitOffer . bind ( this ) ) ;
37+ this . socket . on ( MSG . RECEIVE_OFFER , this . setDescriptionAndEmitAnswer . bind ( this ) ) ;
38+ this . socket . on ( MSG . RECEIVE_ANSWER , this . setDescriptionForAnswer . bind ( this ) ) ;
39+ this . socket . on ( MSG . RECEIVE_ICE , this . addIce . bind ( this ) ) ;
40+ this . socket . on ( MSG . RECEIVE_BYE , this . disconnectPeer . bind ( this ) ) ;
41+
42+ this . socket . emit ( MSG . SEND_HELLO ) ;
43+ }
44+
3145 onMediaConnected ( callback : onMediaConnectedCb ) {
3246 this . onMediaConnectedCallback = callback ;
3347 }
@@ -36,41 +50,87 @@ class RTC {
3650 this . onMediaDisconnectedCallback = callback ;
3751 }
3852
39- #createPeerConnection( remoteSocketId : string ) {
53+ private async setDescriptionAndEmitOffer ( remoteSocketId : SocketId ) {
54+ const pc = this . createPeerConnection ( remoteSocketId ) ;
55+ this . connections . set ( remoteSocketId , pc ) ;
56+
57+ const offer = await pc . createOffer ( ) ;
58+ await pc . setLocalDescription ( offer ) ;
59+
60+ this . socket . emit ( MSG . SEND_OFFER , offer , remoteSocketId ) ;
61+ }
62+
63+ private async setDescriptionAndEmitAnswer ( offer : RTCSessionDescriptionInit , remoteSocketId : SocketId ) {
64+ const pc = this . createPeerConnection ( remoteSocketId ) ;
65+ await pc . setRemoteDescription ( offer ) ;
66+ this . connections . set ( remoteSocketId , pc ) ;
67+
68+ const answer = await pc . createAnswer ( ) ;
69+ await pc . setLocalDescription ( answer ) ;
70+
71+ this . socket . emit ( MSG . SEND_ANSWER , answer , remoteSocketId ) ;
72+ }
73+
74+ private async setDescriptionForAnswer ( answer : RTCSessionDescriptionInit , remoteSocketId : SocketId ) {
75+ const pc = this . connections . get ( remoteSocketId ) ;
76+ if ( ! pc ) {
77+ throw new Error ( 'No RTCPeerConnection on answer received.' ) ;
78+ }
79+
80+ await pc . setRemoteDescription ( answer ) ;
81+ }
82+
83+ private async addIce ( ice : RTCIceCandidate , remoteSocketId : SocketId ) {
84+ const pc = this . connections . get ( remoteSocketId ) ;
85+ if ( ! pc ) {
86+ throw new Error ( 'No RTCPeerConnection on ice candindate received.' ) ;
87+ }
88+
89+ await pc . addIceCandidate ( ice ) ;
90+ }
91+
92+ private async disconnectPeer ( remoteSocketId : SocketId ) {
93+ this . connections . delete ( remoteSocketId ) ;
94+ this . streams . delete ( remoteSocketId ) ;
95+
96+ this . onMediaDisconnectedCallback ( remoteSocketId ) ;
97+ }
98+
99+ private createPeerConnection ( remoteSocketId : string ) {
40100 // initialize
41101 const pcOptions = {
42102 iceServers : [ { urls : this . iceServerUrls } ] ,
43103 } ;
44104 const pc = new RTCPeerConnection ( pcOptions ) ;
45105
46- // add event listeners
47- pc . addEventListener ( 'icecandidate' , ( iceEvent ) => {
48- this . socket . emit (
49- SOCKET_MESSAGE . WORKSPACE . SEND_ICE ,
50- iceEvent . candidate ,
51- remoteSocketId ,
52- ) ;
53- } ) ;
54- pc . addEventListener ( 'track' , async ( event ) => {
55- if ( this . streams . has ( remoteSocketId ) ) {
56- return ;
57- }
58-
59- const [ remoteStream ] = event . streams ;
60-
61- this . streams . set ( remoteSocketId , remoteStream ) ;
62- this . onMediaConnectedCallback ( remoteSocketId , remoteStream ) ;
63- } ) ;
64-
65- // add tracks
66- this . userMediaStream
67- . getTracks ( )
68- . forEach ( ( track ) => pc . addTrack ( track , this . userMediaStream ) ) ;
106+ pc . addEventListener ( 'icecandidate' , event => this . emitIce ( event , remoteSocketId ) ) ;
107+ pc . addEventListener ( 'track' , event => this . addRemoteStream ( event , remoteSocketId ) ) ;
108+ this . addTracksToLocalConnection ( pc ) ;
69109
70110 return pc ;
71111 }
72112
73- async #setVideoBitrate( pc : RTCPeerConnection , bitrate : number ) {
113+ private emitIce ( event : RTCPeerConnectionIceEvent , remoteSocketId : string ) {
114+ this . socket . emit ( MSG . SEND_ICE , event . candidate , remoteSocketId ) ;
115+ }
116+
117+ private addRemoteStream ( event : RTCTrackEvent , remoteSocketId : string ) {
118+ if ( this . streams . has ( remoteSocketId ) ) {
119+ return ;
120+ }
121+
122+ const [ remoteStream ] = event . streams ;
123+
124+ this . streams . set ( remoteSocketId , remoteStream ) ;
125+ this . onMediaConnectedCallback ( remoteSocketId , remoteStream ) ;
126+ }
127+
128+ private addTracksToLocalConnection ( pc : RTCPeerConnection ) {
129+ this . userMediaStream . getTracks ( ) . forEach ( track => pc . addTrack ( track , this . userMediaStream ) ) ;
130+ }
131+
132+ // unused; may be used in the future
133+ private async setVideoBitrate ( pc : RTCPeerConnection , bitrate : number ) {
74134 // fetch video sender
75135 const [ videoSender ] = pc
76136 . getSenders ( )
@@ -81,78 +141,6 @@ class RTC {
81141 params . encodings [ 0 ] . maxBitrate = bitrate ;
82142 await videoSender . setParameters ( params ) ;
83143 }
84-
85- connect ( ) {
86- this . socket . on (
87- SOCKET_MESSAGE . WORKSPACE . RECEIVE_HELLO ,
88- async ( remoteSocketId ) => {
89- const pc = this . #createPeerConnection( remoteSocketId ) ;
90- this . connections . set ( remoteSocketId , pc ) ;
91-
92- const offer = await pc . createOffer ( ) ;
93- await pc . setLocalDescription ( offer ) ;
94-
95- this . socket . emit (
96- SOCKET_MESSAGE . WORKSPACE . SEND_OFFER ,
97- pc . localDescription ,
98- remoteSocketId ,
99- ) ;
100- } ,
101- ) ;
102-
103- this . socket . on (
104- SOCKET_MESSAGE . WORKSPACE . RECEIVE_OFFER ,
105- async ( offer , remoteSocketId ) => {
106- const pc = this . #createPeerConnection( remoteSocketId ) ;
107- this . connections . set ( remoteSocketId , pc ) ;
108-
109- await pc . setRemoteDescription ( offer ) ;
110-
111- const answer = await pc . createAnswer ( ) ;
112- await pc . setLocalDescription ( answer ) ;
113-
114- this . socket . emit (
115- SOCKET_MESSAGE . WORKSPACE . SEND_ANSWER ,
116- answer ,
117- remoteSocketId ,
118- ) ;
119- } ,
120- ) ;
121-
122- this . socket . on (
123- SOCKET_MESSAGE . WORKSPACE . 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- ) ;
133-
134- this . socket . on (
135- SOCKET_MESSAGE . WORKSPACE . RECEIVE_ICE ,
136- ( 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-
147- this . socket . on ( SOCKET_MESSAGE . WORKSPACE . RECEIVE_BYE , ( remoteSocketId ) => {
148- this . connections . delete ( remoteSocketId ) ;
149- this . streams . delete ( remoteSocketId ) ;
150-
151- this . onMediaDisconnectedCallback ( remoteSocketId ) ;
152- } ) ;
153-
154- this . socket . emit ( SOCKET_MESSAGE . WORKSPACE . SEND_HELLO ) ;
155- }
156144}
157145
158146export default RTC ;
0 commit comments