@@ -38,6 +38,7 @@ public class WKWebViewRTC : NSObject {
3838 super. init ( )
3939
4040 // Make the web view transparent
41+
4142 pluginMediaStreams = [ : ]
4243 pluginMediaStreamTracks = [ : ]
4344 pluginMediaStreamRenderers = [ : ]
@@ -79,6 +80,8 @@ public class WKWebViewRTC : NSObject {
7980 func setWebView( webview: WKWebView ? )
8081 {
8182 self . webView = webview
83+ self . webView!. isOpaque = false
84+ self . webView!. backgroundColor = UIColor . clear
8285
8386 }
8487
@@ -104,12 +107,14 @@ public class WKWebViewRTC : NSObject {
104107 }
105108 }
106109
107- func onReset( ) {
110+ @ objc ( onReset ) func onReset( ) {
108111 NSLog ( " WKWebViewRTC#onReset() | doing nothing " )
112+ cleanup ( ) ;
109113 }
110114
111- func onAppTerminate( ) {
115+ @ objc ( onAppTerminate ) func onAppTerminate( ) {
112116 NSLog ( " WKWebViewRTC#onAppTerminate() | doing nothing " )
117+ cleanup ( ) ;
113118 }
114119
115120 @objc ( new_RTCPeerConnection: ) func new_RTCPeerConnection( _ command: WkWebviewCommand ) {
@@ -142,7 +147,9 @@ public class WKWebViewRTC : NSObject {
142147 self . emit ( command. callbackId, result: result)
143148 } ,
144149 eventListenerForAddStream: self . saveMediaStream,
145- eventListenerForRemoveStream: self . deleteMediaStream
150+ eventListenerForRemoveStream: self . deleteMediaStream,
151+ eventListenerForAddTrack: self . saveMediaStreamTrack,
152+ eventListenerForRemoveTrack: self . deleteMediaStreamTrack
146153 )
147154
148155 // Store the pluginRTCPeerConnection into the dictionary.
@@ -407,21 +414,14 @@ public class WKWebViewRTC : NSObject {
407414 @objc ( RTCPeerConnection_removeTrack: ) func RTCPeerConnection_removeTrack( _ command: WkWebviewCommand ) {
408415 let pcId = command. argument ( at: 0 ) as! Int
409416 let trackId = command. argument ( at: 1 ) as! String
410- let streamId = command. argument ( at: 2 ) as! String
411417 let pluginRTCPeerConnection = self . pluginRTCPeerConnections [ pcId]
412- let pluginMediaStream = self . pluginMediaStreams [ streamId]
413418 let pluginMediaStreamTrack = self . pluginMediaStreamTracks [ trackId]
414419
415420 if pluginRTCPeerConnection == nil {
416421 NSLog ( " WKWebViewRTC#RTCPeerConnection_removeTrack() | ERROR: pluginRTCPeerConnection with pcId=%@ does not exist " , String ( pcId) )
417422 return ;
418423 }
419424
420- if pluginMediaStream == nil {
421- NSLog ( " WKWebViewRTC#RTCPeerConnection_removeTrack() | ERROR: pluginMediaStream with id=%@ does not exist " , String ( streamId) )
422- return ;
423- }
424-
425425 if pluginMediaStreamTrack == nil {
426426 NSLog ( " WKWebViewRTC#RTCPeerConnection_removeTrack() | ERROR: pluginMediaStreamTrack with id= \( trackId) does not exist " )
427427 return ;
@@ -430,7 +430,7 @@ public class WKWebViewRTC : NSObject {
430430 self . queue. async { [ weak pluginRTCPeerConnection, weak pluginMediaStreamTrack] in
431431 pluginRTCPeerConnection? . removeTrack ( pluginMediaStreamTrack!)
432432 // TODO remove only if not used by other stream
433- self . deleteMediaStreamTrack ( trackId )
433+ // self.deleteMediaStreamTrack(pluginMediaStreamTrack! )
434434 }
435435 }
436436
@@ -720,7 +720,7 @@ public class WKWebViewRTC : NSObject {
720720
721721 if self . pluginMediaStreams [ streamId] == nil {
722722 let rtcMediaStream : RTCMediaStream = self . rtcPeerConnectionFactory. mediaStream ( withStreamId: streamId)
723- let pluginMediaStream = iMediaStream ( rtcMediaStream: rtcMediaStream)
723+ let pluginMediaStream = iMediaStream ( rtcMediaStream: rtcMediaStream, streamId : streamId )
724724 pluginMediaStream. run ( )
725725
726726 self . saveMediaStream ( pluginMediaStream)
@@ -824,6 +824,43 @@ public class WKWebViewRTC : NSObject {
824824 self . pluginMediaStreams [ id] = nil
825825 }
826826
827+ @objc ( MediaStreamTrack_clone: ) func MediaStreamTrack_clone( _ command: WkWebviewCommand ) {
828+ NSLog ( " WKWebViewRTC#MediaStreamTrack_clone() " )
829+
830+ let existingTrackId = command. argument ( at: 0 ) as! String
831+ let newTrackId = command. argument ( at: 1 ) as! String
832+ let pluginMediaStreamTrack = self . pluginMediaStreamTracks [ existingTrackId]
833+
834+ if pluginMediaStreamTrack == nil {
835+ NSLog ( " WKWebViewRTC#MediaStreamTrack_clone() | ERROR: pluginMediaStreamTrack with id=%@ does not exist " , String ( existingTrackId) )
836+ return ;
837+ }
838+
839+ if self . pluginMediaStreams [ newTrackId] == nil {
840+ var rtcMediaStreamTrack = self . pluginMediaStreamTracks [ existingTrackId] !. rtcMediaStreamTrack;
841+ // twilio uses the sdp local description to map the track ids to the media id.
842+ // if the original rtcMediaStreamTrack is not cloned, the rtcPeerConnection
843+ // will not add the track and as such will not be found by Twilio.
844+ // it is unable to do the mapping and find track and thus
845+ // will not publish the local track.
846+ if pluginMediaStreamTrack? . kind == " video " {
847+ if let rtcVideoTrack = rtcMediaStreamTrack as? RTCVideoTrack {
848+ NSLog ( " WKWebViewRTC#MediaStreamTrack_clone() cloning video source " ) ;
849+ rtcMediaStreamTrack = self . rtcPeerConnectionFactory. videoTrack ( with: rtcVideoTrack. source, trackId: newTrackId) ;
850+ }
851+ } else if pluginMediaStreamTrack? . kind == " audio " {
852+ if let rtcAudioTrack = rtcMediaStreamTrack as? RTCAudioTrack {
853+ NSLog ( " WKWebViewRTC#MediaStreamTrack_clone() cloning audio source " ) ;
854+ rtcMediaStreamTrack = self . rtcPeerConnectionFactory. audioTrack ( with: rtcAudioTrack. source, trackId: newTrackId) ;
855+ }
856+ }
857+ let newPluginMediaStreamTrack = iMediaStreamTrack ( rtcMediaStreamTrack: rtcMediaStreamTrack, trackId: newTrackId)
858+
859+ self . saveMediaStreamTrack ( newPluginMediaStreamTrack)
860+ } else {
861+ NSLog ( " WKWebViewRTC#MediaStreamTrack_clone() | ERROR: pluginMediaStreamTrack with id=%@ already exist " , String ( newTrackId) )
862+ }
863+ }
827864
828865 @objc ( MediaStreamTrack_setListener: ) func MediaStreamTrack_setListener( _ command: WkWebviewCommand ) {
829866 NSLog ( " WKWebViewRTC#MediaStreamTrack_setListener() " )
@@ -851,7 +888,7 @@ public class WKWebViewRTC : NSObject {
851888 } ,
852889 eventListenerForEnded: { ( ) -> Void in
853890 // Remove the track from the container.
854- self . pluginMediaStreamTracks [ pluginMediaStreamTrack!. id ] = nil
891+ self . deleteMediaStreamTrack ( pluginMediaStreamTrack!) ;
855892 }
856893 )
857894 }
@@ -977,13 +1014,26 @@ public class WKWebViewRTC : NSObject {
9771014 return ;
9781015 }
9791016
980- let based64 = pluginMediaStreamRenderer!. save ( )
981- self . emit ( command. callbackId,
982- result: WkWebviewCmdResult (
983- status: . WkWebviewCmdStatus_OK,
984- messageAs: based64
1017+ // Perform the task on a background queue.
1018+ DispatchQueue . global ( ) . async {
1019+ pluginMediaStreamRenderer!. save (
1020+ callback: { ( data: String ) -> Void in
1021+ DispatchQueue . main. async {
1022+ self . emit ( command. callbackId,
1023+ result: WkWebviewCmdResult (
1024+ status: . WkWebviewCmdStatus_OK,
1025+ messageAs: data
1026+ )
1027+ )
1028+ }
1029+ } ,
1030+ errback: { ( error: String ) -> Void in
1031+ self . emit ( command. callbackId,
1032+ result: WkWebviewCmdResult ( status: . WkWebviewCmdStatus_ERROR, messageAs: error)
1033+ )
1034+ }
9851035 )
986- )
1036+ }
9871037 }
9881038
9891039 @objc ( MediaStreamRenderer_close: ) func MediaStreamRenderer_close( _ command: WkWebviewCommand ) {
@@ -1114,7 +1164,7 @@ public class WKWebViewRTC : NSObject {
11141164 iRTCAudioController. selectAudioOutputSpeaker ( )
11151165 }
11161166
1117- func dump( _ command: WkWebviewCommand ) {
1167+ @ objc ( dump : ) func dump( _ command: WkWebviewCommand ) {
11181168 NSLog ( " WKWebViewRTC#dump() " )
11191169
11201170 for (id, _) in self . pluginRTCPeerConnections {
@@ -1156,20 +1206,22 @@ public class WKWebViewRTC : NSObject {
11561206 }
11571207
11581208 // Store its PluginMediaStreamTracks' into the dictionary.
1159- for (id, track) in pluginMediaStream. audioTracks {
1160- if self . pluginMediaStreamTracks [ id] == nil {
1161- self . pluginMediaStreamTracks [ id] = track
1162- }
1209+ for (_, pluginMediaStreamTrack) in pluginMediaStream. audioTracks {
1210+ saveMediaStreamTrack ( pluginMediaStreamTrack) ;
11631211 }
1164- for (id, track) in pluginMediaStream. videoTracks {
1165- if self . pluginMediaStreamTracks [ id] == nil {
1166- self . pluginMediaStreamTracks [ id] = track
1167- }
1212+
1213+ for (_, pluginMediaStreamTrack) in pluginMediaStream. videoTracks {
1214+ saveMediaStreamTrack ( pluginMediaStreamTrack) ;
11681215 }
11691216 }
11701217
1171- fileprivate func deleteMediaStream( _ id: String ) {
1172- self . pluginMediaStreams [ id] = nil
1218+ fileprivate func deleteMediaStream( _ pluginMediaStream: iMediaStream ) {
1219+ if ( self . pluginMediaStreams [ pluginMediaStream. id] != nil ) {
1220+ self . pluginMediaStreams [ pluginMediaStream. id] = nil
1221+
1222+ // deinit should call stop by itself
1223+ //pluginMediaStream.stop();
1224+ }
11731225 }
11741226
11751227 fileprivate func saveMediaStreamTrack( _ pluginMediaStreamTrack: iMediaStreamTrack ) {
@@ -1178,10 +1230,51 @@ public class WKWebViewRTC : NSObject {
11781230 }
11791231 }
11801232
1181- fileprivate func deleteMediaStreamTrack( _ id: String ) {
1182- self . pluginMediaStreamTracks [ id] = nil
1233+ fileprivate func deleteMediaStreamTrack( _ pluginMediaStreamTrack: iMediaStreamTrack ) {
1234+ if ( self . pluginMediaStreamTracks [ pluginMediaStreamTrack. id] != nil ) {
1235+ self . pluginMediaStreamTracks [ pluginMediaStreamTrack. id] = nil
1236+
1237+ // deinit should call stop by itself
1238+ //pluginMediaStreamTrack.stop();
1239+ }
11831240 }
11841241
1242+ fileprivate func cleanup( ) {
1243+
1244+ // Close all RTCPeerConnections
1245+ for (pcId, pluginRTCPeerConnection) in self . pluginRTCPeerConnections {
1246+ pluginRTCPeerConnection. close ( )
1247+ self . pluginRTCPeerConnections [ pcId] = nil ;
1248+ }
1249+
1250+ // Close all StreamRenderers
1251+ for (id, pluginMediaStreamRenderer) in self . pluginMediaStreamRenderers {
1252+ pluginMediaStreamRenderer. close ( )
1253+ self . pluginMediaStreamRenderers [ id] = nil ;
1254+ }
1255+
1256+ // Close All MediaStream
1257+ for (streamId, pluginMediaStream) in self . pluginMediaStreams {
1258+ // Store its PluginMediaStreamTracks' into the dictionary.
1259+ for (trackId, pluginMediaStreamTrack) in pluginMediaStream. audioTracks {
1260+ pluginMediaStream. removeTrack ( pluginMediaStreamTrack) ;
1261+ deleteMediaStreamTrack ( pluginMediaStreamTrack) ;
1262+ }
1263+
1264+ for (trackId, pluginMediaStreamTrack) in pluginMediaStream. videoTracks {
1265+ pluginMediaStream. removeTrack ( pluginMediaStreamTrack) ;
1266+ deleteMediaStreamTrack ( pluginMediaStreamTrack) ;
1267+ }
1268+
1269+ deleteMediaStream ( pluginMediaStream) ;
1270+ }
1271+
1272+ // Close All MediaStreamTracks without MediaStream
1273+ for (trackId, pluginMediaStreamTrack) in self . pluginMediaStreamTracks {
1274+ deleteMediaStreamTrack ( pluginMediaStreamTrack) ;
1275+ }
1276+ }
1277+
11851278 func native_console_log( didReceive message: WKScriptMessage )
11861279 {
11871280 print ( " console.log: \( message. body) " )
0 commit comments