diff --git a/js/RTCPeerConnection.js b/js/RTCPeerConnection.js index 196a6b48..896307f4 100644 --- a/js/RTCPeerConnection.js +++ b/js/RTCPeerConnection.js @@ -7,7 +7,7 @@ module.exports = RTCPeerConnection; /** * Dependencies. */ -var +var debug = require('debug')('iosrtc:RTCPeerConnection'), debugerror = require('debug')('iosrtc:ERROR:RTCPeerConnection'), exec = require('cordova/exec'), @@ -29,7 +29,7 @@ function deprecateWarning(method, newMethod) { if (!newMethod) { console.warn(method + ' is deprecated.'); } else { - console.warn(method + ' method is deprecated, use ' + newMethod + ' instead.'); + console.warn(method + ' method is deprecated, use ' + newMethod + ' instead.'); } } @@ -46,10 +46,11 @@ function RTCPeerConnection(pcConfig, pcConstraints) { // Object.defineProperties(this, RTCPeerConnection.prototype_descriptor); // Fix webrtc-adapter bad SHIM on addTrack causing error when original does support multiple streams. - // NotSupportedError: The adapter.js addTrack polyfill only supports a single stream which is associated with the specified track. + // NotSupportedError: The adapter.js addTrack, addStream polyfill only supports a single stream which is associated with the specified track. Object.defineProperty(this, 'addTrack', RTCPeerConnection.prototype_descriptor.addTrack); + Object.defineProperty(this, 'addStream', RTCPeerConnection.prototype_descriptor.addStream); Object.defineProperty(this, 'getLocalStreams', RTCPeerConnection.prototype_descriptor.getLocalStreams); - + // Public atributes. this._localDescription = null; this.remoteDescription = null; @@ -74,17 +75,17 @@ RTCPeerConnection.prototype = Object.create(EventTarget.prototype); RTCPeerConnection.prototype.constructor = RTCPeerConnection; Object.defineProperties(RTCPeerConnection.prototype, { - 'localDescription': { + 'localDescription': { // Fix webrtc-adapter TypeError: Attempting to change the getter of an unconfigurable property. configurable: true, - get: function() { + get: function() { return this._localDescription; } }, - 'connectionState': { - get: function() { + 'connectionState': { + get: function() { return this.iceConnectionState; - } + } }, 'onicecandidate': { // Fix webrtc-adapter TypeError: Attempting to change the getter of an unconfigurable property. @@ -209,8 +210,8 @@ RTCPeerConnection.prototype.setLocalDescription = function (desc) { }); } - // "This is no longer necessary, however; RTCPeerConnection.setLocalDescription() and other - // methods which take SDP as input now directly accept an object conforming to the RTCSessionDescriptionInit dictionary, + // "This is no longer necessary, however; RTCPeerConnection.setLocalDescription() and other + // methods which take SDP as input now directly accept an object conforming to the RTCSessionDescriptionInit dictionary, // so you don't have to instantiate an RTCSessionDescription yourself."" // Source: https://developer.mozilla.org/en-US/docs/Web/API/RTCSessionDescription/RTCSessionDescription#Example // Still we do instnanciate RTCSessionDescription, so internal object is used properly. @@ -260,8 +261,8 @@ RTCPeerConnection.prototype.setRemoteDescription = function (desc) { debug('setRemoteDescription() [desc:%o]', desc); - // "This is no longer necessary, however; RTCPeerConnection.setLocalDescription() and other - // methods which take SDP as input now directly accept an object conforming to the RTCSessionDescriptionInit dictionary, + // "This is no longer necessary, however; RTCPeerConnection.setLocalDescription() and other + // methods which take SDP as input now directly accept an object conforming to the RTCSessionDescriptionInit dictionary, // so you don't have to instantiate an RTCSessionDescription yourself."" // Source: https://developer.mozilla.org/en-US/docs/Web/API/RTCSessionDescription/RTCSessionDescription#Example // Still we do instnanciate RTCSessionDescription so internal object is used properly. @@ -439,7 +440,7 @@ RTCPeerConnection.prototype.addTrack = function (track, stream) { for (id in this.localStreams) { if (this.localStreams.hasOwnProperty(id)) { // Target provided stream argument or first added stream to group track - if (!stream || (stream && stream.id === id)) { + if (!stream || (stream && stream.id === id)) { stream = this.localStreams[id]; stream.addTrack(track); exec(null, null, 'iosrtcPlugin', 'RTCPeerConnection_addTrack', [this.pcId, track.id, id]); diff --git a/src/PluginMediaStream.swift b/src/PluginMediaStream.swift index 0a18378f..3233dfae 100644 --- a/src/PluginMediaStream.swift +++ b/src/PluginMediaStream.swift @@ -17,7 +17,14 @@ class PluginMediaStream : NSObject { NSLog("PluginMediaStream#init()") self.rtcMediaStream = rtcMediaStream - self.id = rtcMediaStream.streamId + "_" + UUID().uuidString; + + // Handle possible duplicate remote streamId with janus name + // See: https://github.com/cordova-rtc/cordova-plugin-iosrtc/issues/432 + if (rtcMediaStream.streamId.starts(with: "janus")) { + self.id = rtcMediaStream.streamId + "_" + UUID().uuidString; + } else { + self.id = rtcMediaStream.streamId; + } for track: RTCMediaStreamTrack in (self.rtcMediaStream.audioTracks as Array) { let pluginMediaStreamTrack = PluginMediaStreamTrack(rtcMediaStreamTrack: track, streamId: id) diff --git a/src/PluginMediaStreamTrack.swift b/src/PluginMediaStreamTrack.swift index 4bf7a3a6..8a8e1453 100644 --- a/src/PluginMediaStreamTrack.swift +++ b/src/PluginMediaStreamTrack.swift @@ -15,7 +15,15 @@ class PluginMediaStreamTrack : NSObject { NSLog("PluginMediaStreamTrack#init()") self.rtcMediaStreamTrack = rtcMediaStreamTrack - self.id = rtcMediaStreamTrack.trackId + "_" + UUID().uuidString; + + // Handle possible duplicate remote trackId with janus name + // See: https://github.com/cordova-rtc/cordova-plugin-iosrtc/issues/432 + if (rtcMediaStreamTrack.trackId.starts(with: "janus")) { + self.id = rtcMediaStreamTrack.trackId + "_" + UUID().uuidString; + } else { + self.id = rtcMediaStreamTrack.trackId; + } + self.kind = rtcMediaStreamTrack.kind self.renders = [:] self.streamId = streamId; diff --git a/src/iosrtcPlugin.swift b/src/iosrtcPlugin.swift index 3ceac42e..976a8f62 100644 --- a/src/iosrtcPlugin.swift +++ b/src/iosrtcPlugin.swift @@ -25,7 +25,7 @@ class iosrtcPlugin : CDVPlugin { // This is just called if in plugin.xml. @objc(pluginInitialize) override func pluginInitialize() { NSLog("iosrtcPlugin#pluginInitialize()") - + // Make the web view transparent self.webView!.isOpaque = false self.webView!.backgroundColor = UIColor.clear @@ -42,7 +42,7 @@ class iosrtcPlugin : CDVPlugin { // Create a RTCPeerConnectionFactory. self.initPeerConnectionFactory(); - + // Create a PluginGetUserMedia instance. self.pluginGetUserMedia = PluginGetUserMedia( rtcPeerConnectionFactory: rtcPeerConnectionFactory @@ -51,7 +51,7 @@ class iosrtcPlugin : CDVPlugin { // Create a PluginRTCAudioController instance. self.audioOutputController = PluginRTCAudioController() } - + private func initPeerConnectionFactory() { let encoderFactory = RTCDefaultVideoEncoderFactory() let decoderFactory = RTCDefaultVideoDecoderFactory() @@ -62,7 +62,7 @@ class iosrtcPlugin : CDVPlugin { decoderFactory: decoderFactory ) } - + private func getSupportedVideoEncoder(factory: RTCDefaultVideoEncoderFactory) -> RTCVideoCodecInfo { let supportedCodecs: [RTCVideoCodecInfo] = RTCDefaultVideoEncoderFactory.supportedCodecs() if supportedCodecs.contains(RTCVideoCodecInfo.init(name: kRTCH264CodecName)){ @@ -334,46 +334,46 @@ class iosrtcPlugin : CDVPlugin { pluginRTCPeerConnection?.removeStream(pluginMediaStream!) } } - + @objc(RTCPeerConnection_addTrack:) func RTCPeerConnection_addTrack(_ command: CDVInvokedUrlCommand) { - + let pcId = command.argument(at: 0) as! Int let trackId = command.argument(at: 1) as! String var streamIds : [String] = []; let pluginRTCPeerConnection = self.pluginRTCPeerConnections[pcId] let pluginMediaStreamTrack = self.pluginMediaStreamTracks[trackId] - + if pluginRTCPeerConnection == nil { NSLog("iosrtcPlugin#RTCPeerConnection_addTrack() | ERROR: pluginRTCPeerConnection with pcId=%@ does not exist", String(pcId)) return; } - + if command.argument(at: 2) != nil { let id = command.argument(at: 2) as! String let pluginMediaStream = self.pluginMediaStreams[id] - + if pluginMediaStream == nil { NSLog("iosrtcPlugin#RTCPeerConnection_addTrack() | ERROR: pluginMediaStream with id=%@ does not exist", String(id)) return; } - + let streamId = pluginMediaStream!.rtcMediaStream.streamId; streamIds.append(streamId) self.saveMediaStream(pluginMediaStream!) } - + if pluginMediaStreamTrack == nil { NSLog("iosrtcPlugin#RTCPeerConnection_addTrack() | ERROR: pluginMediaStreamTrack with id=\(trackId) does not exist") return; } - + self.queue.async { [weak pluginRTCPeerConnection, weak pluginMediaStreamTrack] in if pluginRTCPeerConnection?.addTrack(pluginMediaStreamTrack!, streamIds) == true { self.saveMediaStreamTrack(pluginMediaStreamTrack!) } } } - + @objc(RTCPeerConnection_removeTrack:) func RTCPeerConnection_removeTrack(_ command: CDVInvokedUrlCommand) { let pcId = command.argument(at: 0) as! Int let trackId = command.argument(at: 1) as! String @@ -381,22 +381,22 @@ class iosrtcPlugin : CDVPlugin { let pluginRTCPeerConnection = self.pluginRTCPeerConnections[pcId] let pluginMediaStream = self.pluginMediaStreams[streamId] let pluginMediaStreamTrack = self.pluginMediaStreamTracks[trackId] - + if pluginRTCPeerConnection == nil { NSLog("iosrtcPlugin#RTCPeerConnection_removeTrack() | ERROR: pluginRTCPeerConnection with pcId=%@ does not exist", String(pcId)) return; } - + if pluginMediaStream == nil { NSLog("iosrtcPlugin#RTCPeerConnection_removeTrack() | ERROR: pluginMediaStream with id=%@ does not exist", String(streamId)) return; } - + if pluginMediaStreamTrack == nil { NSLog("iosrtcPlugin#RTCPeerConnection_removeTrack() | ERROR: pluginMediaStreamTrack with id=\(trackId) does not exist") return; } - + self.queue.async { [weak pluginRTCPeerConnection, weak pluginMediaStreamTrack] in pluginRTCPeerConnection?.removeTrack(pluginMediaStreamTrack!) // TODO remove only if not used by other stream @@ -684,15 +684,18 @@ class iosrtcPlugin : CDVPlugin { } @objc(MediaStream_init:) func MediaStream_init(_ command: CDVInvokedUrlCommand) { - + NSLog("iosrtcPlugin#MediaStream_init()") + let streamId = command.argument(at: 0) as! String - + if self.pluginMediaStreams[streamId] == nil { let rtcMediaStream : RTCMediaStream = self.rtcPeerConnectionFactory.mediaStream(withStreamId: streamId) let pluginMediaStream = PluginMediaStream(rtcMediaStream: rtcMediaStream) pluginMediaStream.run() - + self.saveMediaStream(pluginMediaStream) + } else { + NSLog("iosrtcPlugin#MediaStream_init() | ERROR: pluginMediaStream with id=%@ already exist", String(streamId)) } } @@ -769,7 +772,7 @@ class iosrtcPlugin : CDVPlugin { self.queue.async { [weak pluginMediaStream, weak pluginMediaStreamTrack] in pluginMediaStream?.removeTrack(pluginMediaStreamTrack!) - + // TODO only stop if no more pluginMediaStream attached only // currently pluginMediaStreamTrack can be attached to more than one pluginMediaStream // use track.stop() or stream.stop() to stop tracks @@ -856,7 +859,7 @@ class iosrtcPlugin : CDVPlugin { pluginMediaStreamTrack?.stop() } } - + @objc(new_MediaStreamRenderer:) func new_MediaStreamRenderer(_ command: CDVInvokedUrlCommand) { NSLog("iosrtcPlugin#new_MediaStreamRenderer()") @@ -935,15 +938,15 @@ class iosrtcPlugin : CDVPlugin { @objc(MediaStreamRenderer_save:) func MediaStreamRenderer_save(_ command: CDVInvokedUrlCommand) { NSLog("iosrtcPlugin#MediaStreamRenderer_save()") - + let id = command.argument(at: 0) as! Int let pluginMediaStreamRenderer = self.pluginMediaStreamRenderers[id] - + if pluginMediaStreamRenderer == nil { NSLog("iosrtcPlugin#MediaStreamRenderer_save() | ERROR: pluginMediaStreamRenderer with id=%@ does not exist", String(id)) return; } - + let based64 = pluginMediaStreamRenderer!.save() self.emit(command.callbackId, result: CDVPluginResult( @@ -1009,13 +1012,13 @@ class iosrtcPlugin : CDVPlugin { ) } } - + @objc(RTCRequestPermission:) func RTCRequestPermission(_ command: CDVInvokedUrlCommand) { DispatchQueue.main.async { let audioRequested: Bool = CBool(command.arguments[0] as! Bool) let videoRequested: Bool = CBool(command.arguments[1] as! Bool) var status: Bool = true - + if videoRequested == true { switch AVCaptureDevice.authorizationStatus(for: AVMediaType.video) { case AVAuthorizationStatus.notDetermined: @@ -1023,7 +1026,7 @@ class iosrtcPlugin : CDVPlugin { case AVAuthorizationStatus.authorized: NSLog("PluginGetUserMedia#call() | video authorization: authorized") case AVAuthorizationStatus.denied: - + NSLog("PluginGetUserMedia#call() | video authorization: denied") status = false case AVAuthorizationStatus.restricted: @@ -1031,7 +1034,7 @@ class iosrtcPlugin : CDVPlugin { status = false } } - + if audioRequested == true { switch AVCaptureDevice.authorizationStatus(for: AVMediaType.audio) { case AVAuthorizationStatus.notDetermined: @@ -1046,7 +1049,7 @@ class iosrtcPlugin : CDVPlugin { status = false } } - + if (status) { self.emit(command.callbackId,result: CDVPluginResult(status: CDVCommandStatus_OK)) } else { @@ -1062,7 +1065,7 @@ class iosrtcPlugin : CDVPlugin { self.emit(command.callbackId, result: CDVPluginResult(status: CDVCommandStatus_OK)) } } - + @objc(selectAudioOutputEarpiece:) func selectAudioOutputEarpiece(_ command: CDVInvokedUrlCommand) { NSLog("iosrtcPlugin#selectAudioOutputEarpiece()") @@ -1071,7 +1074,7 @@ class iosrtcPlugin : CDVPlugin { @objc(selectAudioOutputSpeaker:) func selectAudioOutputSpeaker(_ command: CDVInvokedUrlCommand) { NSLog("iosrtcPlugin#selectAudioOutputSpeaker()") - + PluginRTCAudioController.selectAudioOutputSpeaker() }