Skip to content

Commit aa50c2e

Browse files
authored
Merge pull request #9 from OpenTelecom/video-support
Video support
2 parents c760a0f + ef39071 commit aa50c2e

43 files changed

Lines changed: 3588 additions & 557 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,4 @@ Carthage/Build
3434
# Note: if you ignore the Pods directory, make sure to uncomment
3535
# `pod install` in .travis.yml
3636
#
37-
# Pods/
37+
Pods/

Example/WKWebViewRTC/Info.plist

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
<dict>
55
<key>NSMicrophoneUsageDescription</key>
66
<string>WKWebViewRTC requires acess to mic.</string>
7+
<key>NSCameraUsageDescription</key>
8+
<string>WKWebViewRTC requires acess to cam.</string>
79
<key>CFBundleDevelopmentRegion</key>
810
<string>en</string>
911
<key>CFBundleExecutable</key>

Example/WKWebViewRTC/ViewController.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class ViewController: UIViewController {
2020
// Do any additional setup after loading the view, typically from a nib.
2121
WKWebViewRTC(wkwebview: webView, contentController: webView.configuration.userContentController)
2222

23-
webView.load(URLRequest(url: URL(string: "https://sip-phone-test.reper.io/?name=Display%20Name&websocket=wss://domain.com:5065&sipuri=sip_user@domain.com&password=password")!))
23+
webView.load(URLRequest(url: URL(string: "https://cordova-rtc.github.io/cordova-plugin-iosrtc-sample/index.html")!))
2424
}
2525
}
2626

WKWebViewRTC.podspec

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
Pod::Spec.new do |s|
1010
s.name = 'WKWebViewRTC'
11-
s.version = '0.2.0'
11+
s.version = '0.3.0'
1212
s.summary = 'WebRTC library for WKWebView for Swift on iOS'
1313

1414
# This description is used to generate tags and improve search results.
@@ -22,22 +22,17 @@ Pod::Spec.new do |s|
2222
DESC
2323

2424
s.homepage = 'https://github.com/OpenTelecom/WKWebViewRTC'
25-
# s.screenshots = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2'
2625
s.license = { :type => 'MIT', :file => 'LICENSE' }
2726
s.author = { 'OpenTelecom' => 'contact@OpenTele.com' }
2827
s.source = { :git => 'https://github.com/OpenTelecom/WKWebViewRTC.git', :tag => s.version.to_s }
29-
# s.social_media_url = 'https://twitter.com/<TWITTER_USERNAME>'
3028

3129
s.swift_version = '4.2'
3230
s.ios.deployment_target = '11.0'
3331

3432
s.source_files = 'WKWebViewRTC/Classes/**/*'
3533
s.resources = 'WKWebViewRTC/Js/jsWKWebViewRTC.js'
36-
# s.resource_bundles = {
37-
# 'WKWebViewRTC' => ['WKWebViewRTC/Js/jsWKWebViewRTC.js']
38-
# }
3934

40-
# s.public_header_files = 'Pod/Classes/**/*.h'
41-
# s.frameworks = 'AVFoundation'
4235
s.dependency 'GoogleWebRTC', '1.1.29229'
36+
37+
s.xcconfig = { 'ENABLE_BITCODE' => 'NO', 'ONLY_ACTIVE_ARCH' => 'Yes' }
4338
end

WKWebViewRTC/Classes/WKWebViewRTC.swift

Lines changed: 125 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -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)")

WKWebViewRTC/Classes/iEnumerateDevices.swift

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* cordova-plugin-iosrtc v6.0.12
2+
* cordova-plugin-iosrtc v6.0.17
33
* Cordova iOS plugin exposing the ̶f̶u̶l̶l̶ WebRTC W3C JavaScript APIs.
44
* Copyright 2015-2017 eFace2Face, Inc. (https://eface2face.com)
55
* Copyright 2015-2019 BasqueVoIPMafia (https://github.com/BasqueVoIPMafia)
@@ -60,8 +60,18 @@ class iEnumerateDevices {
6060
fileprivate func getAllVideoDevices() -> [MediaDeviceInfo] {
6161

6262
var videoDevicesArr : [MediaDeviceInfo] = []
63+
var deviceTypes: [AVCaptureDevice.DeviceType] = [.builtInTelephotoCamera, .builtInWideAngleCamera]
64+
if #available(iOS 10.2, *) {
65+
deviceTypes.append(.builtInDualCamera)
66+
67+
// Disabled tp prevent duplicate front camera
68+
//if #available(iOS 11.1, *) {
69+
// deviceTypes.append(.builtInTrueDepthCamera)
70+
//}
71+
}
72+
6373
let videoDevices: [AVCaptureDevice] = AVCaptureDevice.DiscoverySession.init(
64-
deviceTypes: [AVCaptureDevice.DeviceType.builtInWideAngleCamera, AVCaptureDevice.DeviceType.builtInDualCamera],
74+
deviceTypes: deviceTypes,
6575
mediaType: AVMediaType.video,
6676
position: AVCaptureDevice.Position.unspecified
6777
).devices
@@ -124,9 +134,7 @@ fileprivate func getAllAudioDevices() -> [MediaDeviceInfo] {
124134
var audioDevicesArr : [MediaDeviceInfo] = []
125135
let audioInputDevices: [AVAudioSessionPortDescription] = audioSession.availableInputs!
126136
var bluetoothDevice: AVAudioSessionPortDescription? = nil
127-
var isBluetoothConnected : Bool = false
128137
var wiredDevice: AVAudioSessionPortDescription? = nil
129-
var isWiredConnected : Bool = false
130138
var builtMicDevice: AVAudioSessionPortDescription? = nil
131139

132140
for audioInput in audioInputDevices {
@@ -146,21 +154,19 @@ fileprivate func getAllAudioDevices() -> [MediaDeviceInfo] {
146154

147155
if audioInput.portType == .bluetoothHFP || audioInput.portType == .bluetoothA2DP {
148156
bluetoothDevice = audioInput
149-
isBluetoothConnected = true
150157
}
151158

152159
if audioInput.portType == .usbAudio || audioInput.portType == .headsetMic {
153160
wiredDevice = audioInput
154-
isWiredConnected = true
155161
}
156162
}
157163

158164
// Initialize audioInputSelected. Priority: [Wired - Wireless - Built-In Microphone]
159-
if isWiredConnected {
165+
if wiredDevice != nil {
160166
iRTCAudioController.saveInputAudioDevice(inputDeviceUID: wiredDevice!.uid)
161-
} else if isBluetoothConnected {
167+
} else if bluetoothDevice != nil {
162168
iRTCAudioController.saveInputAudioDevice(inputDeviceUID: bluetoothDevice!.uid)
163-
} else {
169+
} else if builtMicDevice != nil {
164170
iRTCAudioController.saveInputAudioDevice(inputDeviceUID: builtMicDevice!.uid)
165171
}
166172
return audioDevicesArr

WKWebViewRTC/Classes/iGetUserMedia.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* cordova-plugin-iosrtc v6.0.12
2+
* cordova-plugin-iosrtc v6.0.17
33
* Cordova iOS plugin exposing the ̶f̶u̶l̶l̶ WebRTC W3C JavaScript APIs.
44
* Copyright 2015-2017 eFace2Face, Inc. (https://eface2face.com)
55
* Copyright 2015-2019 BasqueVoIPMafia (https://github.com/BasqueVoIPMafia)

0 commit comments

Comments
 (0)