diff --git a/js/getDisplayMedia.js b/js/getDisplayMedia.js new file mode 100644 index 00000000..68354b0c --- /dev/null +++ b/js/getDisplayMedia.js @@ -0,0 +1,55 @@ +/** + * Expose the getDisplayMedia function. + */ +module.exports = getDisplayMedia; + +/** + * Dependencies. + */ +var debug = require('debug')('iosrtc:getDisplayMedia'), + debugerror = require('debug')('iosrtc:ERROR:getDisplayMedia'), + exec = require('cordova/exec'), + MediaStream = require('./MediaStream'), + Errors = require('./Errors'); + +function getDisplayMedia(constraints) { + // Detect callback usage to assist 5.0.1 to 5.0.2 migration + // TODO remove on 6.0.0 + Errors.detectDeprecatedCallbaksUsage('cordova.plugins.iosrtc.getDisplayMedia', arguments); + + debug('[original constraints:%o]', constraints); + + var newConstraints = {}; + + if ( + typeof constraints !== 'object' || + (!constraints.hasOwnProperty('audio') && !constraints.hasOwnProperty('video')) + ) { + return new Promise(function (resolve, reject) { + reject( + new Errors.MediaStreamError( + 'constraints must be an object with at least "audio" or "video" keys' + ) + ); + }); + } + + debug('[computed constraints:%o]', newConstraints); + + return new Promise(function (resolve, reject) { + function onResultOK(data) { + debug('getDisplayMedia() | success'); + var stream = MediaStream.create(data.stream); + resolve(stream); + // Emit "connected" on the stream. + stream.emitConnected(); + } + + function onResultError(error) { + debugerror('getDisplayMedia() | failure: %s', error); + reject(new Errors.MediaStreamError('getDisplayMedia() failed: ' + error)); + } + + exec(onResultOK, onResultError, 'iosrtcPlugin', 'getDisplayMedia', [newConstraints]); + }); +} diff --git a/js/iosrtc.js b/js/iosrtc.js index 52b4d7fd..a8ffef2e 100644 --- a/js/iosrtc.js +++ b/js/iosrtc.js @@ -17,6 +17,7 @@ var // Dictionary of MediaStreamRenderers. exec = require('cordova/exec'), domready = require('domready'), getUserMedia = require('./getUserMedia'), + getDisplayMedia = require('./getDisplayMedia'), enumerateDevices = require('./enumerateDevices'), RTCPeerConnection = require('./RTCPeerConnection'), RTCSessionDescription = require('./RTCSessionDescription'), @@ -33,6 +34,7 @@ var // Dictionary of MediaStreamRenderers. module.exports = { // Expose WebRTC classes and functions. getUserMedia: getUserMedia, + getDisplayMedia: getDisplayMedia, enumerateDevices: enumerateDevices, getMediaDevices: enumerateDevices, // TMP RTCPeerConnection: RTCPeerConnection, @@ -190,6 +192,8 @@ function registerGlobals(doNotRestoreCallbacksSupport) { restoreCallbacksSupport(); } + navigator.getDisplayMedia = getDisplayMedia; + navigator.mediaDevices.getDisplayMedia = getDisplayMedia; navigator.getUserMedia = getUserMedia; navigator.webkitGetUserMedia = getUserMedia; diff --git a/plugin.xml b/plugin.xml index f56a9be9..21adde99 100644 --- a/plugin.xml +++ b/plugin.xml @@ -71,6 +71,7 @@ + diff --git a/src/PluginGetDisplayMedia.swift b/src/PluginGetDisplayMedia.swift new file mode 100644 index 00000000..66b87e20 --- /dev/null +++ b/src/PluginGetDisplayMedia.swift @@ -0,0 +1,94 @@ +import Foundation +import AVFoundation +import ReplayKit + +class PluginGetDisplayMedia { + + var rtcPeerConnectionFactory: RTCPeerConnectionFactory + + init(rtcPeerConnectionFactory: RTCPeerConnectionFactory) { + NSLog("PluginGetDisplayMedia#init()") + self.rtcPeerConnectionFactory = rtcPeerConnectionFactory + } + + deinit { + NSLog("PluginGetDisplayMedia#deinit()") + } + + func call( + _ constraints: NSDictionary, + callback: @escaping (_ data: NSDictionary) -> Void, + errback: @escaping (_ error: String) -> Void, + eventListenerForNewStream: @escaping (_ pluginMediaStream: PluginMediaStream) -> Void + ) { + + NSLog("PluginGetDisplayMedia#call()") + if #available(iOS 11.0, *) { + + let recorder = RPScreenRecorder.shared() + + if (recorder.isRecording) { + recorder.stopCapture(handler: {(error) in + if (error != nil) { + errback(error!.localizedDescription) + } else { + self.startCapture(recorder: recorder, callback: callback, errback: errback, eventListenerForNewStream: eventListenerForNewStream) + } + }) + } else if (recorder.isAvailable) { + self.startCapture(recorder: recorder, callback: callback, errback: errback, eventListenerForNewStream: eventListenerForNewStream) + } else { + errback("Screen recorder is not available!") + } + + } else { + errback("Screen recorder is not available!") + } + } + + @available(iOS 11.0, *) + func startCapture( + recorder: RPScreenRecorder, + callback: @escaping (_ data: NSDictionary) -> Void, + errback: @escaping (_ error: String) -> Void, + eventListenerForNewStream: @escaping (_ pluginMediaStream: PluginMediaStream) -> Void + ) { + + let rtcVideoSource: RTCVideoSource = self.rtcPeerConnectionFactory.videoSource() + let videoCapturer: RTCVideoCapturer = RTCVideoCapturer(delegate: rtcVideoSource) + let rtcMediaStream: RTCMediaStream = self.rtcPeerConnectionFactory.mediaStream(withStreamId: UUID().uuidString) + let rtcVideoTrack: RTCVideoTrack = self.rtcPeerConnectionFactory.videoTrack( + with: rtcVideoSource, trackId: UUID().uuidString) + + let videoCaptureController: PluginRTCScreenCaptureController = PluginRTCScreenCaptureController(capturer: videoCapturer, recorder: recorder, source: rtcVideoSource) + rtcVideoTrack.videoCaptureController = videoCaptureController + + // TODO use startCapture completionHandler + let captureStarted = videoCaptureController.startCapture() + if (!captureStarted) { + errback("constraints failed") + return + } + + // If videoSource state is "ended" it means that constraints were not satisfied so + // invoke the given errback. + if (rtcVideoSource.state == RTCSourceState.ended) { + NSLog("PluginGetDisplayMedia() | rtcVideoSource.state is 'ended', constraints not satisfied") + + errback("constraints not satisfied") + return + } + + rtcMediaStream.addVideoTrack(rtcVideoTrack) + + let pluginMediaStream: PluginMediaStream = PluginMediaStream(rtcMediaStream: rtcMediaStream) + pluginMediaStream.run() + + // Let the plugin store it in its dictionary. + eventListenerForNewStream(pluginMediaStream) + + callback([ + "stream": pluginMediaStream.getJSON() + ]) + } +} diff --git a/src/PluginGetUserMedia.swift b/src/PluginGetUserMedia.swift index 1c3feb1b..35b06761 100644 --- a/src/PluginGetUserMedia.swift +++ b/src/PluginGetUserMedia.swift @@ -98,7 +98,7 @@ class PluginGetUserMedia { // Ignore Simulator cause does not support Camera #if !targetEnvironment(simulator) let videoCapturer: RTCCameraVideoCapturer = RTCCameraVideoCapturer(delegate: rtcVideoSource!) - let videoCaptureController: PluginRTCVideoCaptureController = PluginRTCVideoCaptureController(capturer: videoCapturer) + let videoCaptureController: PluginRTCCameraCaptureController = PluginRTCCameraCaptureController(capturer: videoCapturer) rtcVideoTrack!.videoCaptureController = videoCaptureController let constraintsSatisfied = videoCaptureController.setConstraints(constraints: videoConstraints) diff --git a/src/PluginMediaStreamTrack.swift b/src/PluginMediaStreamTrack.swift index ffa09587..39fd3c43 100644 --- a/src/PluginMediaStreamTrack.swift +++ b/src/PluginMediaStreamTrack.swift @@ -106,9 +106,11 @@ class PluginMediaStreamTrack : NSObject { } } + /* func switchCamera() { self.rtcMediaStreamTrack.videoCaptureController?.switchCamera() } + */ func registerRender(render: PluginMediaStreamRenderer) { if let exist = self.renders[render.id] { diff --git a/src/PluginRTCVideoCaptureController.swift b/src/PluginRTCVideoCaptureController.swift index 05597ce3..616904bc 100644 --- a/src/PluginRTCVideoCaptureController.swift +++ b/src/PluginRTCVideoCaptureController.swift @@ -1,5 +1,6 @@ import Foundation import AVFoundation +import ReplayKit import func ObjectiveC.objc_getAssociatedObject import func ObjectiveC.objc_setAssociatedObject @@ -52,22 +53,123 @@ extension RTCMediaStreamTrack { class PluginRTCVideoCaptureController : NSObject { + var isCapturing: Bool = false; + + // Default to the front camera. + var device: AVCaptureDevice? + var deviceFormat: AVCaptureDevice.Format? + var deviceFrameRate: Int? + + var constraints: NSDictionary = [:] + + func startCapture(completionHandler: ((Error?) -> Void)? = nil) -> Bool { + return isCapturing; + } + + func stopCapture() { + + } +} + +class PluginRTCScreenCaptureController : PluginRTCVideoCaptureController { + + var capturer: RTCVideoCapturer + var source: RTCVideoSource + var recorder: RPScreenRecorder + + init(capturer: RTCVideoCapturer, recorder: RPScreenRecorder, source: RTCVideoSource) { + self.capturer = capturer + self.recorder = recorder; + self.source = source; + } + + override func startCapture(completionHandler: ((Error?) -> Void)? = nil) -> Bool { + + // Stop previous capture in case of setConstraints, followed by startCapture + // aka future applyConstraints + if (isCapturing) { + stopCapture(); + } + + if #available(iOS 11.0, *) { + recorder.isMicrophoneEnabled = false + recorder.startCapture(handler: {(sampleBuffer, bufferType, error) in + if (bufferType == RPSampleBufferType.video) { + self.handleSourceBuffer( + source: self.source, + sampleBuffer: sampleBuffer, + sampleType: bufferType + ) + } + if (completionHandler != nil && error != nil) { + completionHandler!(error) + } + }) { (error) in + if (completionHandler != nil && error != nil) { + completionHandler!(error) + } else { + // TODO Optional closure parameter + //completionHandler!() + } + } + + isCapturing = true + + NSLog("PluginRTCScreenCaptureController#startCapture Capture started"); + } + + return isCapturing; + } + + override func stopCapture() { + // TODO: stopCaptureWithCompletionHandler with DispatchSemaphore + if (isCapturing) { + if #available(iOS 11.0, *) { + recorder.stopCapture {(error) in + // TODO debug error + } + isCapturing = false + + NSLog("PluginRTCScreenCaptureController#stopCapture Capture stopped"); + } + } + } + + func handleSourceBuffer(source: RTCVideoSource, sampleBuffer: CMSampleBuffer, sampleType: RPSampleBufferType) { + if (CMSampleBufferGetNumSamples(sampleBuffer) != 1 || !CMSampleBufferIsValid(sampleBuffer) || + !CMSampleBufferDataIsReady(sampleBuffer)) { + return; + } + + let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); + if (pixelBuffer == nil) { + return; + } + + let width = CVPixelBufferGetWidth(pixelBuffer!); + let height = CVPixelBufferGetHeight(pixelBuffer!); + + source.adaptOutputFormat(toWidth: Int32(width/2), height: Int32(height/2), fps: 8) + + let rtcPixelBuffer = RTCCVPixelBuffer(pixelBuffer: pixelBuffer!) + let timeStampNs = + CMTimeGetSeconds(CMSampleBufferGetPresentationTimeStamp(sampleBuffer)) * Float64(NSEC_PER_SEC) + let videoFrame = RTCVideoFrame(buffer: rtcPixelBuffer, rotation: RTCVideoRotation._0, timeStampNs: Int64(timeStampNs)) + source.capturer(capturer, didCapture: videoFrame) + } +} + +class PluginRTCCameraCaptureController : PluginRTCVideoCaptureController { + private let DEFAULT_HEIGHT : Int32 = 480 private let DEFAULT_WIDTH : Int32 = 640 + private let DEFAULT_FPS : Int = 15 private let DEFAULT_ASPECT_RATIO : Float32 = 4/3 private let FACING_MODE_USER : String = "user"; private let FACING_MODE_ENV : String = "environment"; var capturer: RTCCameraVideoCapturer - var isCapturing: Bool = false; - - // Default to the front camera. - var device: AVCaptureDevice? - var deviceFormat: AVCaptureDevice.Format? - var deviceFrameRate: Int? - - var constraints: NSDictionary = [:] init(capturer: RTCCameraVideoCapturer) { self.capturer = capturer @@ -139,7 +241,7 @@ class PluginRTCVideoCaptureController : NSObject { return device != nil; } - func startCapture() -> Bool { + override func startCapture(completionHandler: ((Error?) -> Void)? = nil) -> Bool { // Stop previous capture in case of setConstraints, followed by startCapture // aka future applyConstraints @@ -167,10 +269,10 @@ class PluginRTCVideoCaptureController : NSObject { NSLog("PluginRTCVideoCaptureController#startCapture Capture started, device:%@, format:%@", device!, deviceFormat!); - return true; + return isCapturing; } - func stopCapture() { + override func stopCapture() { // TODO: stopCaptureWithCompletionHandler with DispatchSemaphore if (isCapturing) { capturer.stopCapture() @@ -294,6 +396,7 @@ class PluginRTCVideoCaptureController : NSObject { return captureDevices.firstObject as? AVCaptureDevice } + /* func switchCamera() -> Bool { if (self.capturer.captureSession.isRunning) { @@ -306,6 +409,7 @@ class PluginRTCVideoCaptureController : NSObject { return self.startCapture() } + */ fileprivate func findAlternativeDevicePosition(currentDevice: AVCaptureDevice?) -> AVCaptureDevice? { let captureDevices: NSArray = RTCCameraVideoCapturer.captureDevices() as NSArray @@ -468,7 +572,7 @@ class PluginRTCVideoCaptureController : NSObject { return selectedFormat } - + // // constraints parsers // diff --git a/src/iosrtcPlugin.swift b/src/iosrtcPlugin.swift index 8bd1e4c0..0f00839a 100644 --- a/src/iosrtcPlugin.swift +++ b/src/iosrtcPlugin.swift @@ -8,6 +8,8 @@ class iosrtcPlugin : CDVPlugin { var rtcPeerConnectionFactory: RTCPeerConnectionFactory! // Single PluginGetUserMedia instance. var pluginGetUserMedia: PluginGetUserMedia! + // Single PluginGetDisplayMedia instance. + var pluginGetDisplayMedia: PluginGetDisplayMedia! // PluginRTCPeerConnection dictionary. var pluginRTCPeerConnections: [Int : PluginRTCPeerConnection]! // PluginMediaStream dictionary. @@ -21,7 +23,6 @@ class iosrtcPlugin : CDVPlugin { // Auto selecting output speaker var audioOutputController: PluginRTCAudioController! - // This is just called if in plugin.xml. @objc(pluginInitialize) override func pluginInitialize() { NSLog("iosrtcPlugin#pluginInitialize()") @@ -47,6 +48,11 @@ class iosrtcPlugin : CDVPlugin { self.pluginGetUserMedia = PluginGetUserMedia( rtcPeerConnectionFactory: rtcPeerConnectionFactory ) + + // Create a PluginGetDisplayMedia instance. + self.pluginGetDisplayMedia = PluginGetDisplayMedia( + rtcPeerConnectionFactory: rtcPeerConnectionFactory + ) // Create a PluginRTCAudioController instance. self.audioOutputController = PluginRTCAudioController() @@ -1197,6 +1203,29 @@ class iosrtcPlugin : CDVPlugin { eventListenerForNewStream: self.saveMediaStream ) } + + @objc(getDisplayMedia:) func getDisplayMedia(_ command: CDVInvokedUrlCommand) { + NSLog("iosrtcPlugin#getDisplayMedia()") + + let constraints = command.argument(at: 0) as! NSDictionary + + self.pluginGetDisplayMedia.call(constraints, + callback: { (data: NSDictionary) -> Void in + self.emit(command.callbackId, + result: CDVPluginResult( + status: CDVCommandStatus_OK, + messageAs: data as? [AnyHashable: Any] + ) + ) + }, + errback: { (error: String) -> Void in + self.emit(command.callbackId, + result: CDVPluginResult(status: CDVCommandStatus_ERROR, messageAs: error) + ) + }, + eventListenerForNewStream: self.saveMediaStream + ) + } @objc(enumerateDevices:) func enumerateDevices(_ command: CDVInvokedUrlCommand) { NSLog("iosrtcPlugin#enumerateDevices()") diff --git a/www/cordova-plugin-iosrtc.js b/www/cordova-plugin-iosrtc.js index 3a80074d..574c5550 100644 --- a/www/cordova-plugin-iosrtc.js +++ b/www/cordova-plugin-iosrtc.js @@ -88,7 +88,7 @@ EventTarget.prototype.dispatchEvent = function (event) { */ module.exports = EventTarget; -},{"yaeti":30}],3:[function(_dereq_,module,exports){ +},{"yaeti":31}],3:[function(_dereq_,module,exports){ /** * Expose the MediaDeviceInfo class. */ @@ -202,7 +202,7 @@ MediaDevices.prototype.getSupportedConstraints = function () { }; }; -},{"./EventTarget":2,"./enumerateDevices":19,"./getUserMedia":20}],5:[function(_dereq_,module,exports){ +},{"./EventTarget":2,"./enumerateDevices":19,"./getUserMedia":21}],5:[function(_dereq_,module,exports){ /** * Expose the MediaStream class. */ @@ -714,7 +714,7 @@ function onEvent(data) { } } -},{"./EventTarget":2,"./MediaStreamTrack":7,"cordova/exec":undefined,"debug":23}],6:[function(_dereq_,module,exports){ +},{"./EventTarget":2,"./MediaStreamTrack":7,"cordova/exec":undefined,"debug":24}],6:[function(_dereq_,module,exports){ /** * Expose the MediaStreamRenderer class. */ @@ -1124,7 +1124,7 @@ function getElementPositionAndSize() { }; } -},{"./EventTarget":2,"./MediaStream":5,"cordova/exec":undefined,"debug":23,"random-number":28}],7:[function(_dereq_,module,exports){ +},{"./EventTarget":2,"./MediaStream":5,"cordova/exec":undefined,"debug":24,"random-number":29}],7:[function(_dereq_,module,exports){ /** * Expose the MediaStreamTrack class. */ @@ -1291,7 +1291,7 @@ function onEvent(data) { } } -},{"./EventTarget":2,"./MediaTrackCapabilities":8,"./MediaTrackSettings":9,"./enumerateDevices":19,"cordova/exec":undefined,"debug":23}],8:[function(_dereq_,module,exports){ +},{"./EventTarget":2,"./MediaTrackCapabilities":8,"./MediaTrackSettings":9,"./enumerateDevices":19,"cordova/exec":undefined,"debug":24}],8:[function(_dereq_,module,exports){ /** * Expose the MediaTrackSettings class. */ @@ -1446,7 +1446,7 @@ function onEvent(data) { } } -},{"./EventTarget":2,"cordova/exec":undefined,"debug":23,"random-number":28}],11:[function(_dereq_,module,exports){ +},{"./EventTarget":2,"cordova/exec":undefined,"debug":24,"random-number":29}],11:[function(_dereq_,module,exports){ (function (setImmediate){ /** * Expose the RTCDataChannel class. @@ -1713,7 +1713,7 @@ function onEvent(data) { } }).call(this,_dereq_("timers").setImmediate) -},{"./EventTarget":2,"cordova/exec":undefined,"debug":23,"random-number":28,"timers":29}],12:[function(_dereq_,module,exports){ +},{"./EventTarget":2,"cordova/exec":undefined,"debug":24,"random-number":29,"timers":30}],12:[function(_dereq_,module,exports){ /** * Expose the RTCIceCandidate class. */ @@ -2913,7 +2913,7 @@ function onEvent(data) { } }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./Errors":1,"./EventTarget":2,"./MediaStream":5,"./MediaStreamTrack":7,"./RTCDTMFSender":10,"./RTCDataChannel":11,"./RTCIceCandidate":12,"./RTCRtpReceiver":14,"./RTCRtpSender":15,"./RTCRtpTransceiver":16,"./RTCSessionDescription":17,"./RTCStatsReport":18,"cordova/exec":undefined,"debug":23,"random-number":28}],14:[function(_dereq_,module,exports){ +},{"./Errors":1,"./EventTarget":2,"./MediaStream":5,"./MediaStreamTrack":7,"./RTCDTMFSender":10,"./RTCDataChannel":11,"./RTCIceCandidate":12,"./RTCRtpReceiver":14,"./RTCRtpSender":15,"./RTCRtpTransceiver":16,"./RTCSessionDescription":17,"./RTCStatsReport":18,"cordova/exec":undefined,"debug":24,"random-number":29}],14:[function(_dereq_,module,exports){ /** * Expose the RTCRtpReceiver class. */ @@ -2948,7 +2948,7 @@ RTCRtpReceiver.prototype.update = function ({ track, params }) { this.params = params; }; -},{"random-number":28}],15:[function(_dereq_,module,exports){ +},{"random-number":29}],15:[function(_dereq_,module,exports){ /** * Expose the RTCRtpSender class. */ @@ -3052,7 +3052,7 @@ RTCRtpSender.prototype.update = function ({ track, params }) { this.params = params; }; -},{"./MediaStreamTrack":7,"cordova/exec":undefined,"random-number":28}],16:[function(_dereq_,module,exports){ +},{"./MediaStreamTrack":7,"cordova/exec":undefined,"random-number":29}],16:[function(_dereq_,module,exports){ const RTCRtpSender = _dereq_('./RTCRtpSender'); const RTCRtpReceiver = _dereq_('./RTCRtpReceiver'); @@ -3209,7 +3209,7 @@ RTCRtpTransceiver.prototype.update = function (data) { this.sender.update(data.sender); }; -},{"./EventTarget":2,"./RTCRtpReceiver":14,"./RTCRtpSender":15,"cordova/exec":undefined,"debug":23,"random-number":28}],17:[function(_dereq_,module,exports){ +},{"./EventTarget":2,"./RTCRtpReceiver":14,"./RTCRtpSender":15,"cordova/exec":undefined,"debug":24,"random-number":29}],17:[function(_dereq_,module,exports){ /** * Expose the RTCSessionDescription class. */ @@ -3304,7 +3304,64 @@ function getMediaDeviceInfos(devices) { return mediaDeviceInfos; } -},{"./Errors":1,"./MediaDeviceInfo":3,"cordova/exec":undefined,"debug":23}],20:[function(_dereq_,module,exports){ +},{"./Errors":1,"./MediaDeviceInfo":3,"cordova/exec":undefined,"debug":24}],20:[function(_dereq_,module,exports){ +/** + * Expose the getDisplayMedia function. + */ +module.exports = getDisplayMedia; + +/** + * Dependencies. + */ +var debug = _dereq_('debug')('iosrtc:getDisplayMedia'), + debugerror = _dereq_('debug')('iosrtc:ERROR:getDisplayMedia'), + exec = _dereq_('cordova/exec'), + MediaStream = _dereq_('./MediaStream'), + Errors = _dereq_('./Errors'); + +function getDisplayMedia(constraints) { + // Detect callback usage to assist 5.0.1 to 5.0.2 migration + // TODO remove on 6.0.0 + Errors.detectDeprecatedCallbaksUsage('cordova.plugins.iosrtc.getDisplayMedia', arguments); + + debug('[original constraints:%o]', constraints); + + var newConstraints = {}; + + if ( + typeof constraints !== 'object' || + (!constraints.hasOwnProperty('audio') && !constraints.hasOwnProperty('video')) + ) { + return new Promise(function (resolve, reject) { + reject( + new Errors.MediaStreamError( + 'constraints must be an object with at least "audio" or "video" keys' + ) + ); + }); + } + + debug('[computed constraints:%o]', newConstraints); + + return new Promise(function (resolve, reject) { + function onResultOK(data) { + debug('getDisplayMedia() | success'); + var stream = MediaStream.create(data.stream); + resolve(stream); + // Emit "connected" on the stream. + stream.emitConnected(); + } + + function onResultError(error) { + debugerror('getDisplayMedia() | failure: %s', error); + reject(new Errors.MediaStreamError('getDisplayMedia() failed: ' + error)); + } + + exec(onResultOK, onResultError, 'iosrtcPlugin', 'getDisplayMedia', [newConstraints]); + }); +} + +},{"./Errors":1,"./MediaStream":5,"cordova/exec":undefined,"debug":24}],21:[function(_dereq_,module,exports){ /** * Expose the getUserMedia function. */ @@ -3765,7 +3822,7 @@ function getUserMedia(constraints) { }); } -},{"./Errors":1,"./MediaStream":5,"cordova/exec":undefined,"debug":23}],21:[function(_dereq_,module,exports){ +},{"./Errors":1,"./MediaStream":5,"cordova/exec":undefined,"debug":24}],22:[function(_dereq_,module,exports){ (function (global){ /** * Variables. @@ -3786,6 +3843,7 @@ var // Dictionary of MediaStreamRenderers. exec = _dereq_('cordova/exec'), domready = _dereq_('domready'), getUserMedia = _dereq_('./getUserMedia'), + getDisplayMedia = _dereq_('./getDisplayMedia'), enumerateDevices = _dereq_('./enumerateDevices'), RTCPeerConnection = _dereq_('./RTCPeerConnection'), RTCSessionDescription = _dereq_('./RTCSessionDescription'), @@ -3802,6 +3860,7 @@ var // Dictionary of MediaStreamRenderers. module.exports = { // Expose WebRTC classes and functions. getUserMedia: getUserMedia, + getDisplayMedia: getDisplayMedia, enumerateDevices: enumerateDevices, getMediaDevices: enumerateDevices, // TMP RTCPeerConnection: RTCPeerConnection, @@ -3959,6 +4018,8 @@ function registerGlobals(doNotRestoreCallbacksSupport) { restoreCallbacksSupport(); } + navigator.getDisplayMedia = getDisplayMedia; + navigator.mediaDevices.getDisplayMedia = getDisplayMedia; navigator.getUserMedia = getUserMedia; navigator.webkitGetUserMedia = getUserMedia; @@ -4057,7 +4118,7 @@ function dump() { } }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./MediaDevices":4,"./MediaStream":5,"./MediaStreamTrack":7,"./RTCIceCandidate":12,"./RTCPeerConnection":13,"./RTCRtpTransceiver":16,"./RTCSessionDescription":17,"./enumerateDevices":19,"./getUserMedia":20,"./videoElementsHandler":22,"cordova/exec":undefined,"debug":23,"domready":25}],22:[function(_dereq_,module,exports){ +},{"./MediaDevices":4,"./MediaStream":5,"./MediaStreamTrack":7,"./RTCIceCandidate":12,"./RTCPeerConnection":13,"./RTCRtpTransceiver":16,"./RTCSessionDescription":17,"./enumerateDevices":19,"./getDisplayMedia":20,"./getUserMedia":21,"./videoElementsHandler":23,"cordova/exec":undefined,"debug":24,"domready":26}],23:[function(_dereq_,module,exports){ /** * Expose a function that must be called when the library is loaded. * And also a helper function. @@ -4444,7 +4505,7 @@ function releaseMediaStreamRenderer(video) { delete video.readyState; } -},{"./MediaStreamRenderer":6,"debug":23}],23:[function(_dereq_,module,exports){ +},{"./MediaStreamRenderer":6,"debug":24}],24:[function(_dereq_,module,exports){ (function (process){ /* eslint-env browser */ @@ -4712,7 +4773,7 @@ formatters.j = function (v) { }; }).call(this,_dereq_('_process')) -},{"./common":24,"_process":27}],24:[function(_dereq_,module,exports){ +},{"./common":25,"_process":28}],25:[function(_dereq_,module,exports){ /** * This is the common logic for both the Node.js and web browser @@ -4980,7 +5041,7 @@ function setup(env) { module.exports = setup; -},{"ms":26}],25:[function(_dereq_,module,exports){ +},{"ms":27}],26:[function(_dereq_,module,exports){ /*! * domready (c) Dustin Diaz 2014 - License MIT */ @@ -5012,7 +5073,7 @@ module.exports = setup; }); -},{}],26:[function(_dereq_,module,exports){ +},{}],27:[function(_dereq_,module,exports){ /** * Helpers. */ @@ -5176,7 +5237,7 @@ function plural(ms, msAbs, n, name) { return Math.round(ms / n) + ' ' + name + (isPlural ? 's' : ''); } -},{}],27:[function(_dereq_,module,exports){ +},{}],28:[function(_dereq_,module,exports){ // shim for using process in browser var process = module.exports = {}; @@ -5362,7 +5423,7 @@ process.chdir = function (dir) { }; process.umask = function() { return 0; }; -},{}],28:[function(_dereq_,module,exports){ +},{}],29:[function(_dereq_,module,exports){ void function(root){ function defaults(options){ @@ -5408,7 +5469,7 @@ void function(root){ module.exports.defaults = defaults }(this) -},{}],29:[function(_dereq_,module,exports){ +},{}],30:[function(_dereq_,module,exports){ (function (setImmediate,clearImmediate){ var nextTick = _dereq_('process/browser.js').nextTick; var apply = Function.prototype.apply; @@ -5487,14 +5548,14 @@ exports.clearImmediate = typeof clearImmediate === "function" ? clearImmediate : delete immediateIds[id]; }; }).call(this,_dereq_("timers").setImmediate,_dereq_("timers").clearImmediate) -},{"process/browser.js":27,"timers":29}],30:[function(_dereq_,module,exports){ +},{"process/browser.js":28,"timers":30}],31:[function(_dereq_,module,exports){ module.exports = { EventTarget : _dereq_('./lib/EventTarget'), Event : _dereq_('./lib/Event') }; -},{"./lib/Event":31,"./lib/EventTarget":32}],31:[function(_dereq_,module,exports){ +},{"./lib/Event":32,"./lib/EventTarget":33}],32:[function(_dereq_,module,exports){ (function (global){ /** * In browsers export the native Event interface. @@ -5503,7 +5564,7 @@ module.exports = module.exports = global.Event; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}],32:[function(_dereq_,module,exports){ +},{}],33:[function(_dereq_,module,exports){ function yaetiEventTarget() { this._listeners = {}; @@ -5638,5 +5699,5 @@ yaetiEventTarget.prototype.dispatchEvent = function(event) module.exports = yaetiEventTarget; -},{}]},{},[21])(21) +},{}]},{},[22])(22) });