Skip to content

Commit

Permalink
Starting 2.2.0:
Browse files Browse the repository at this point in the history
- Move from getMediaDevices() to enumerateDevices().
- Start implementation of local video constraints in getUserMedia(): deviceId, width.min, width.max, height.min and height.max.
  • Loading branch information
ibc committed Dec 2, 2015
1 parent 01e7dc0 commit c9dd4db
Show file tree
Hide file tree
Showing 12 changed files with 112 additions and 58 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,12 @@ Methods such as `play()`, `pause()` are not implemented. In order to pause a vid
(since version 1.2.8)


#### Version 2.2.0

* Move from `getMediaDevices()` to `enumerateDevices()`.
* Implement video constraints in `getUserMedia()`: `deviceId`, `width.min`, `width.max`, `height.min` and `height.max`).


#### Version 2.1.0

* Update *libwebrtc* to latest revision (rev 10800).
Expand Down
24 changes: 17 additions & 7 deletions docs/iosrtc.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,25 @@ Implementation of the `getUserMedia()` function as specified by the [W3C Media

The function allows both the old/deprecated callbacks based syntax and the new one based on Promises (depending on the number and type of the given arguments).

*NOTE:* In iOS devices there is a single audio input (mic) and two video inputs (camera). If the given constraints include "video" the device chosen by default is the front camera. However the back camera can be chosen by passing an "optional" or "mandatory" constraint to the function:
*NOTE:* In iOS devices there are a single audio input (mic) and two video inputs (camera). If the given constraints do not include "video.deviceId" the device chosen by default is the front camera.

Constraints can be applied to the local video by using the latest W3C specification. Currently just the following constraints are supported:

* `video.deviceId`
* `video.width.min`
* `video.width.max`
* `video.height.min`
* `video.height.max`

```javascript
cordova.plugins.iosrtc.getUserMedia({
audio: true,
video: {
optional: [
{ sourceId: 'com.apple.avfoundation.avcapturedevice.built-in_video:1' }
]
deviceId: 'com.apple.avfoundation.avcapturedevice.built-in_video:1',
width: {
min: 320,
max: 640
}
}
});
```
Expand All @@ -52,7 +62,7 @@ cordova.plugins.iosrtc.getUserMedia({
* Rich constraints.


### `iosrtc.getMediaDevices()`
### `iosrtc.enumerateDevices()`

Implementation of the `enumerateDevices()` function as specified in the [W3C Media Capture and Streams draft](http://w3c.github.io/mediacapture-main/#enumerating-devices).

Expand All @@ -67,7 +77,7 @@ The success callback is called with a list of `MediaDeviceInfo` objects as defin
* `id` (same as `deviceId`, deprecated)
* `facing` (always an empty string, deprecated)

*NOTE:* The `deviceId` or `id` field is the value to be used in the `sourceId` field of `getUserMedia()` above to choose a specific device.
*NOTE:* The `deviceId` or `id` field is the value to be used in the `deviceId` field of `getUserMedia()` above to choose a specific device.


### `iosrtc.RTCPeerConnection`
Expand Down Expand Up @@ -111,7 +121,7 @@ Exposes the `MediaStream` class as defined in the [spec](http://w3c.github.io/m

Exposes the `MediaStreamTrack` class as defined by the [spec](http://w3c.github.io/mediacapture-main/#mediastreamtrack).

*NOTE:* The only reason to make this class public is to expose the deprecated `MediaStreamTrack.getSources()` class function, which is an "alias" to the `getMediaDevices()` function described above.
*NOTE:* The only reason to make this class public is to expose the deprecated `MediaStreamTrack.getSources()` class function, which is an "alias" to the `enumerateDevices()` function described above.

*TODO:*

Expand Down
4 changes: 2 additions & 2 deletions js/MediaStreamTrack.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ module.exports = MediaStreamTrack;
var
debug = require('debug')('iosrtc:MediaStreamTrack'),
exec = require('cordova/exec'),
getMediaDevices = require('./getMediaDevices'),
enumerateDevices = require('./enumerateDevices'),
EventTarget = require('yaeti').EventTarget;


Expand Down Expand Up @@ -82,7 +82,7 @@ MediaStreamTrack.prototype.stop = function () {
MediaStreamTrack.getSources = function () {
debug('getSources()');

return getMediaDevices.apply(this, arguments);
return enumerateDevices.apply(this, arguments);
};


Expand Down
16 changes: 8 additions & 8 deletions js/getMediaDevices.js → js/enumerateDevices.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
/**
* Expose the getMediaDevices function.
* Expose the enumerateDevices function.
*/
module.exports = getMediaDevices;
module.exports = enumerateDevices;


/**
* Dependencies.
*/
var
debug = require('debug')('iosrtc:getMediaDevices'),
debug = require('debug')('iosrtc:enumerateDevices'),
exec = require('cordova/exec'),
MediaDeviceInfo = require('./MediaDeviceInfo');


function getMediaDevices() {
function enumerateDevices() {
debug('');

var isPromise,
Expand All @@ -29,20 +29,20 @@ function getMediaDevices() {
if (isPromise) {
return new Promise(function (resolve) {
function onResultOK(data) {
debug('getMediaDevices() | success');
debug('enumerateDevices() | success');
resolve(getMediaDeviceInfos(data.devices));
}

exec(onResultOK, null, 'iosrtcPlugin', 'getMediaDevices', []);
exec(onResultOK, null, 'iosrtcPlugin', 'enumerateDevices', []);
});
}

function onResultOK(data) {
debug('getMediaDevices() | success');
debug('enumerateDevices() | success');
callback(getMediaDeviceInfos(data.devices));
}

exec(onResultOK, null, 'iosrtcPlugin', 'getMediaDevices', []);
exec(onResultOK, null, 'iosrtcPlugin', 'enumerateDevices', []);
}


Expand Down
64 changes: 36 additions & 28 deletions js/getUserMedia.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,22 @@ var
MediaStream = require('./MediaStream'),
Errors = require('./Errors');


debugerror.log = console.warn.bind(console);


function isPositiveInteger(number) {
return typeof number === 'number' && number >= 0 && number % 1 === 0;
}


function getUserMedia(constraints) {
debug('[constraints:%o]', constraints);
debug('[original constraints:%o]', constraints);

var isPromise,
var
isPromise,
callback, errback,
audioRequested = false,
videoRequested = false,
videoOptionalConstraints,
videoMandatoryConstraints,
videoDeviceId,
newConstraints = {
audio: false,
video: false
Expand All @@ -47,11 +49,11 @@ function getUserMedia(constraints) {
) {
if (isPromise) {
return new Promise(function (resolve, reject) {
reject(new Errors.MediaStreamError('constraints must be an object with at least "audio" or "video" boolean fields'));
reject(new Errors.MediaStreamError('constraints must be an object with at least "audio" or "video" keys'));
});
} else {
if (typeof errback === 'function') {
errback(new Errors.MediaStreamError('constraints must be an object with at least "audio" or "video" boolean fields'));
errback(new Errors.MediaStreamError('constraints must be an object with at least "audio" or "video" keys'));
}
return;
}
Expand All @@ -71,36 +73,42 @@ function getUserMedia(constraints) {
// getUserMedia({
// audio: true,
// video: {
// optional: [
// { sourceId: 'qwe-asd-zxc-123' }
// ]
// deviceId: 'qwer-asdf-zxcv',
// width: {
// min: 400,
// max: 600
// }
// }
// });

if (videoRequested && Array.isArray(constraints.video.optional)) {
videoOptionalConstraints = constraints.video.optional;

if (videoOptionalConstraints[0]) {
videoDeviceId = videoOptionalConstraints[0].sourceId;
// Get video constraints
if (videoRequested) {
// Get requested video deviceId.
if (typeof constraints.video.deviceId === 'string') {
newConstraints.videoDeviceId = constraints.video.deviceId;
}

if (typeof videoDeviceId === 'string') {
newConstraints.videoDeviceId = videoDeviceId;
// Get requested min/max width/height.
if (typeof constraints.video.width === 'object') {
if (isPositiveInteger(constraints.video.width.min)) {
newConstraints.videoMinWidth = constraints.video.width.min;
}
if (isPositiveInteger(constraints.video.width.max)) {
newConstraints.videoMaxWidth = constraints.video.width.max;
}
}
}

if (videoRequested && Array.isArray(constraints.video.mandatory)) {
videoMandatoryConstraints = constraints.video.mandatory;

if (videoMandatoryConstraints[0]) {
videoDeviceId = videoMandatoryConstraints[0].sourceId;

if (typeof videoDeviceId === 'string') {
newConstraints.videoDeviceId = videoDeviceId;
if (typeof constraints.video.height === 'object') {
if (isPositiveInteger(constraints.video.height.min)) {
newConstraints.videoMinHeight = constraints.video.height.min;
}
if (isPositiveInteger(constraints.video.height.max)) {
newConstraints.videoMaxHeight = constraints.video.height.max;
}
}
}

debug('[computed constraints:%o]', newConstraints);

if (isPromise) {
return new Promise(function (resolve, reject) {
function onResultOK(data) {
Expand Down
7 changes: 4 additions & 3 deletions js/iosrtc.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ var
domready = require('domready'),

getUserMedia = require('./getUserMedia'),
getMediaDevices = require('./getMediaDevices'),
enumerateDevices = require('./enumerateDevices'),
RTCPeerConnection = require('./RTCPeerConnection'),
RTCSessionDescription = require('./RTCSessionDescription'),
RTCIceCandidate = require('./RTCIceCandidate'),
Expand All @@ -38,7 +38,8 @@ var
module.exports = {
// Expose WebRTC classes and functions.
getUserMedia: getUserMedia,
getMediaDevices: getMediaDevices,
enumerateDevices: enumerateDevices,
getMediaDevices: enumerateDevices, // TMP
RTCPeerConnection: RTCPeerConnection,
RTCSessionDescription: RTCSessionDescription,
RTCIceCandidate: RTCIceCandidate,
Expand Down Expand Up @@ -116,7 +117,7 @@ function registerGlobals() {
navigator.getUserMedia = getUserMedia;
navigator.webkitGetUserMedia = getUserMedia;
navigator.mediaDevices.getUserMedia = getUserMedia;
navigator.mediaDevices.enumerateDevices = getMediaDevices;
navigator.mediaDevices.enumerateDevices = enumerateDevices;
window.RTCPeerConnection = RTCPeerConnection;
window.webkitRTCPeerConnection = RTCPeerConnection;
window.RTCSessionDescription = RTCSessionDescription;
Expand Down
3 changes: 2 additions & 1 deletion js/rtcninjaPlugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ module.exports = {

interface: {
getUserMedia: require('./getUserMedia'),
enumerateDevices: require('./enumerateDevices'),
getMediaDevices: require('./enumerateDevices'), // TMP
RTCPeerConnection: require('./RTCPeerConnection'),
RTCSessionDescription: require('./RTCSessionDescription'),
RTCIceCandidate: require('./RTCIceCandidate'),
MediaStreamTrack: require('./MediaStreamTrack'),
getMediaDevices: require('./getMediaDevices'),
attachMediaStream: attachMediaStream,
canRenegotiate: true
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cordova-plugin-iosrtc",
"version": "2.1.0",
"version": "2.2.0-pre",
"description": "Cordova iOS plugin exposing the full WebRTC W3C JavaScript APIs",
"author": "Iñaki Baz Castillo at eFace2Face, inc. (https://eface2face.com)",
"license": "MIT",
Expand Down
4 changes: 2 additions & 2 deletions plugin.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
id="cordova-plugin-iosrtc"
version="2.1.0">
version="2.2.0-pre">

<name>iosrtc</name>
<description>Cordova iOS plugin exposing the full WebRTC W3C JavaScript APIs</description>
Expand Down Expand Up @@ -75,7 +75,7 @@
<source-file src="src/PluginMediaStream.swift" />
<source-file src="src/PluginMediaStreamTrack.swift" />
<source-file src="src/PluginGetUserMedia.swift" />
<source-file src="src/PluginGetMediaDevices.swift" />
<source-file src="src/PluginEnumerateDevices.swift" />
<source-file src="src/PluginUtils.swift" />
<source-file src="src/PluginMediaStreamRenderer.swift" />

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import AVFoundation
*/


class PluginGetMediaDevices {
class PluginEnumerateDevices {
class func call(callback: (data: NSDictionary) -> Void) {
NSLog("PluginGetMediaDevices#call()")
NSLog("PluginEnumerateDevices#call()")

let devices = AVCaptureDevice.devices() as! Array<AVCaptureDevice>

Expand Down
30 changes: 29 additions & 1 deletion src/PluginGetUserMedia.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ class PluginGetUserMedia {
let audioRequested = constraints.objectForKey("audio") as? Bool ?? false
let videoRequested = constraints.objectForKey("video") as? Bool ?? false
let videoDeviceId = constraints.objectForKey("videoDeviceId") as? String
let videoMinWidth = constraints.objectForKey("videoMinWidth") as? Int ?? 0
let videoMaxWidth = constraints.objectForKey("videoMaxWidth") as? Int ?? 0
let videoMinHeight = constraints.objectForKey("videoMinHeight") as? Int ?? 0
let videoMaxHeight = constraints.objectForKey("videoMaxHeight") as? Int ?? 0

var rtcMediaStream: RTCMediaStream
var pluginMediaStream: PluginMediaStream?
Expand All @@ -32,6 +36,8 @@ class PluginGetUserMedia {
var rtcVideoCapturer: RTCVideoCapturer?
var rtcVideoSource: RTCVideoSource?
var videoDevice: AVCaptureDevice?
var mandatoryConstraints: [RTCPair] = []
var constraints: RTCMediaConstraints

if videoRequested == true {
switch AVCaptureDevice.authorizationStatusForMediaType(AVMediaTypeVideo) {
Expand Down Expand Up @@ -105,8 +111,30 @@ class PluginGetUserMedia {

rtcVideoCapturer = RTCVideoCapturer(deviceName: videoDevice!.localizedName)

if videoMinWidth > 0 {
NSLog("PluginGetUserMedia#call() | adding media constraint [minWidth:\(videoMinWidth)]")
mandatoryConstraints.append(RTCPair(key: "minWidth", value: String(videoMinWidth)))
}
if videoMaxWidth > 0 {
NSLog("PluginGetUserMedia#call() | adding media constraint [maxWidth:\(videoMaxWidth)]")
mandatoryConstraints.append(RTCPair(key: "maxWidth", value: String(videoMaxWidth)))
}
if videoMinHeight > 0 {
NSLog("PluginGetUserMedia#call() | adding media constraint [minHeight:\(videoMinHeight)]")
mandatoryConstraints.append(RTCPair(key: "minHeight", value: String(videoMinHeight)))
}
if videoMaxHeight > 0 {
NSLog("PluginGetUserMedia#call() | adding media constraint [maxHeight:\(videoMaxHeight)]")
mandatoryConstraints.append(RTCPair(key: "maxHeight", value: String(videoMaxHeight)))
}

constraints = RTCMediaConstraints(
mandatoryConstraints: mandatoryConstraints,
optionalConstraints: []
)

rtcVideoSource = self.rtcPeerConnectionFactory.videoSourceWithCapturer(rtcVideoCapturer,
constraints: RTCMediaConstraints()
constraints: constraints
)

rtcVideoTrack = self.rtcPeerConnectionFactory.videoTrackWithID(NSUUID().UUIDString,
Expand Down
6 changes: 3 additions & 3 deletions src/iosrtcPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -729,11 +729,11 @@ class iosrtcPlugin : CDVPlugin {
}


func getMediaDevices(command: CDVInvokedUrlCommand) {
NSLog("iosrtcPlugin#getMediaDevices()")
func enumerateDevices(command: CDVInvokedUrlCommand) {
NSLog("iosrtcPlugin#enumerateDevices()")

dispatch_async(self.queue) {
PluginGetMediaDevices.call(
PluginEnumerateDevices.call(
{ (data: NSDictionary) -> Void in
self.emit(command.callbackId,
result: CDVPluginResult(status: CDVCommandStatus_OK, messageAsDictionary: data as [NSObject : AnyObject])
Expand Down

0 comments on commit c9dd4db

Please sign in to comment.