getusermedia.js 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. /*
  2. * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
  3. *
  4. * Use of this source code is governed by a BSD-style license
  5. * that can be found in the LICENSE file in the root of the source
  6. * tree.
  7. */
  8. /* eslint-env node */
  9. 'use strict';
  10. Object.defineProperty(exports, "__esModule", {
  11. value: true
  12. });
  13. exports.shimGetUserMedia = shimGetUserMedia;
  14. var utils = _interopRequireWildcard(require("../utils.js"));
  15. function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
  16. function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
  17. function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
  18. var logging = utils.log;
  19. function shimGetUserMedia(window, browserDetails) {
  20. var navigator = window && window.navigator;
  21. if (!navigator.mediaDevices) {
  22. return;
  23. }
  24. var constraintsToChrome_ = function constraintsToChrome_(c) {
  25. if (_typeof(c) !== 'object' || c.mandatory || c.optional) {
  26. return c;
  27. }
  28. var cc = {};
  29. Object.keys(c).forEach(function (key) {
  30. if (key === 'require' || key === 'advanced' || key === 'mediaSource') {
  31. return;
  32. }
  33. var r = _typeof(c[key]) === 'object' ? c[key] : {
  34. ideal: c[key]
  35. };
  36. if (r.exact !== undefined && typeof r.exact === 'number') {
  37. r.min = r.max = r.exact;
  38. }
  39. var oldname_ = function oldname_(prefix, name) {
  40. if (prefix) {
  41. return prefix + name.charAt(0).toUpperCase() + name.slice(1);
  42. }
  43. return name === 'deviceId' ? 'sourceId' : name;
  44. };
  45. if (r.ideal !== undefined) {
  46. cc.optional = cc.optional || [];
  47. var oc = {};
  48. if (typeof r.ideal === 'number') {
  49. oc[oldname_('min', key)] = r.ideal;
  50. cc.optional.push(oc);
  51. oc = {};
  52. oc[oldname_('max', key)] = r.ideal;
  53. cc.optional.push(oc);
  54. } else {
  55. oc[oldname_('', key)] = r.ideal;
  56. cc.optional.push(oc);
  57. }
  58. }
  59. if (r.exact !== undefined && typeof r.exact !== 'number') {
  60. cc.mandatory = cc.mandatory || {};
  61. cc.mandatory[oldname_('', key)] = r.exact;
  62. } else {
  63. ['min', 'max'].forEach(function (mix) {
  64. if (r[mix] !== undefined) {
  65. cc.mandatory = cc.mandatory || {};
  66. cc.mandatory[oldname_(mix, key)] = r[mix];
  67. }
  68. });
  69. }
  70. });
  71. if (c.advanced) {
  72. cc.optional = (cc.optional || []).concat(c.advanced);
  73. }
  74. return cc;
  75. };
  76. var shimConstraints_ = function shimConstraints_(constraints, func) {
  77. if (browserDetails.version >= 61) {
  78. return func(constraints);
  79. }
  80. constraints = JSON.parse(JSON.stringify(constraints));
  81. if (constraints && _typeof(constraints.audio) === 'object') {
  82. var remap = function remap(obj, a, b) {
  83. if (a in obj && !(b in obj)) {
  84. obj[b] = obj[a];
  85. delete obj[a];
  86. }
  87. };
  88. constraints = JSON.parse(JSON.stringify(constraints));
  89. remap(constraints.audio, 'autoGainControl', 'googAutoGainControl');
  90. remap(constraints.audio, 'noiseSuppression', 'googNoiseSuppression');
  91. constraints.audio = constraintsToChrome_(constraints.audio);
  92. }
  93. if (constraints && _typeof(constraints.video) === 'object') {
  94. // Shim facingMode for mobile & surface pro.
  95. var face = constraints.video.facingMode;
  96. face = face && (_typeof(face) === 'object' ? face : {
  97. ideal: face
  98. });
  99. var getSupportedFacingModeLies = browserDetails.version < 66;
  100. if (face && (face.exact === 'user' || face.exact === 'environment' || face.ideal === 'user' || face.ideal === 'environment') && !(navigator.mediaDevices.getSupportedConstraints && navigator.mediaDevices.getSupportedConstraints().facingMode && !getSupportedFacingModeLies)) {
  101. delete constraints.video.facingMode;
  102. var matches;
  103. if (face.exact === 'environment' || face.ideal === 'environment') {
  104. matches = ['back', 'rear'];
  105. } else if (face.exact === 'user' || face.ideal === 'user') {
  106. matches = ['front'];
  107. }
  108. if (matches) {
  109. // Look for matches in label, or use last cam for back (typical).
  110. return navigator.mediaDevices.enumerateDevices().then(function (devices) {
  111. devices = devices.filter(function (d) {
  112. return d.kind === 'videoinput';
  113. });
  114. var dev = devices.find(function (d) {
  115. return matches.some(function (match) {
  116. return d.label.toLowerCase().includes(match);
  117. });
  118. });
  119. if (!dev && devices.length && matches.includes('back')) {
  120. dev = devices[devices.length - 1]; // more likely the back cam
  121. }
  122. if (dev) {
  123. constraints.video.deviceId = face.exact ? {
  124. exact: dev.deviceId
  125. } : {
  126. ideal: dev.deviceId
  127. };
  128. }
  129. constraints.video = constraintsToChrome_(constraints.video);
  130. logging('chrome: ' + JSON.stringify(constraints));
  131. return func(constraints);
  132. });
  133. }
  134. }
  135. constraints.video = constraintsToChrome_(constraints.video);
  136. }
  137. logging('chrome: ' + JSON.stringify(constraints));
  138. return func(constraints);
  139. };
  140. var shimError_ = function shimError_(e) {
  141. if (browserDetails.version >= 64) {
  142. return e;
  143. }
  144. return {
  145. name: {
  146. PermissionDeniedError: 'NotAllowedError',
  147. PermissionDismissedError: 'NotAllowedError',
  148. InvalidStateError: 'NotAllowedError',
  149. DevicesNotFoundError: 'NotFoundError',
  150. ConstraintNotSatisfiedError: 'OverconstrainedError',
  151. TrackStartError: 'NotReadableError',
  152. MediaDeviceFailedDueToShutdown: 'NotAllowedError',
  153. MediaDeviceKillSwitchOn: 'NotAllowedError',
  154. TabCaptureError: 'AbortError',
  155. ScreenCaptureError: 'AbortError',
  156. DeviceCaptureError: 'AbortError'
  157. }[e.name] || e.name,
  158. message: e.message,
  159. constraint: e.constraint || e.constraintName,
  160. toString: function toString() {
  161. return this.name + (this.message && ': ') + this.message;
  162. }
  163. };
  164. };
  165. var getUserMedia_ = function getUserMedia_(constraints, onSuccess, onError) {
  166. shimConstraints_(constraints, function (c) {
  167. navigator.webkitGetUserMedia(c, onSuccess, function (e) {
  168. if (onError) {
  169. onError(shimError_(e));
  170. }
  171. });
  172. });
  173. };
  174. navigator.getUserMedia = getUserMedia_.bind(navigator);
  175. // Even though Chrome 45 has navigator.mediaDevices and a getUserMedia
  176. // function which returns a Promise, it does not accept spec-style
  177. // constraints.
  178. if (navigator.mediaDevices.getUserMedia) {
  179. var origGetUserMedia = navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);
  180. navigator.mediaDevices.getUserMedia = function (cs) {
  181. return shimConstraints_(cs, function (c) {
  182. return origGetUserMedia(c).then(function (stream) {
  183. if (c.audio && !stream.getAudioTracks().length || c.video && !stream.getVideoTracks().length) {
  184. stream.getTracks().forEach(function (track) {
  185. track.stop();
  186. });
  187. throw new DOMException('', 'NotFoundError');
  188. }
  189. return stream;
  190. }, function (e) {
  191. return Promise.reject(shimError_(e));
  192. });
  193. });
  194. };
  195. }
  196. }