(Android) / Chrome getUserMedia() 约束应该如何格式化?

Posted

技术标签:

【中文标题】(Android) / Chrome getUserMedia() 约束应该如何格式化?【英文标题】:How should (Android) / Chrome getUserMedia() constraints be formatted? 【发布时间】:2016-04-14 06:51:15 【问题描述】:

我一直在尝试访问运行 Chrome 的 LG G4 android 手机上的后置摄像头。我能够从MediaStreamTrack.getSources() 中过滤掉视频源,但是当我尝试设置一个约束以偏爱后置摄像头时,我收到错误TypeError: Failed to execute 'webkitGetUserMedia' on 'Navigator': Malformed constraints object. 下面我有用于过滤视频源的代码:

if (navigator.getUserMedia) 
  if (MediaStreamTrack.getSources) 
    MediaStreamTrack.getSources(function(sourceInfos) 
      var sources = [];
      _.forEach(sourceInfos, function(info) 
        if (info.kind === 'video') 
          sources.push(info);
                      
      )
      handleSources(sources);
    )
  

然后我尝试在上面提到的handleSources函数中选择一个源:

function handleSources(sources) 
  var constraints = 
    video: 
      facingMode: 'environment' // Yeah, this definitely doesn't work.
    
  
  getMedia(constraints); // This calls getUserMedia with the selected contraints

我已经为约束对象尝试了很多不同的格式,但它们似乎都不起作用。我知道我可以遍历所有源并从那里选择环境摄像机,但我很想知道它的实际语法是如何工作的。谷歌搜索答案只会出现https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia#Parameters,其语法不起作用。

【问题讨论】:

【参考方案1】:

似乎较早/不同版本的 Android 浏览器实现了不同的 API 用于相机发现。我发现我可以访问的每部手机(模拟器和物理)似乎都尊重一组不同的选项。更糟糕的是,这似乎是各种文档存储库坚持忽略或删除先前实现的 API 的领域(即使我们仍然需要知道如何使用它们,如果我们要能够在除最新手机之外的任何东西上实现的话)。

我发现的 API 的两种主要风格是当前记录的一种(您参考上面的 API)和a version of the WebRTC specification from October 2013 中记录的一种。这种风格具有显着不同的约束规范,包括强制和可选属性。在旧规范下,您对 getMedia 的调用如下所示:

var constraints = 
  video: 
    mandatory: 
      facingMode: 'environment'
    
  

getMedia(constraints);

或者,您可以使用可选设置,它们以数组的形式提供,因此您可以有多个选择(这些是按顺序计算的):

var constraints = 
  video: 
    optional: [
      facingMode: 'environment'
    ]
  

getMedia(constraints);

话虽如此,在寻找有效的过滤器时,您的努力可能会有所不同。例如,上面的 facingMode 过滤器在我的 Android 5.0 模拟器中不起作用(它不会抛出错误,但也不会显示面向环境的摄像头);但是,使用设备 ID 确实有效(映射到您的示例时看起来像这样):

var constraints = 
  video: 
    mandatory: 
      sourceId: '<your source ID here>'
    
  

getMedia(constraints);

对于我进行了一些测试的 Android 5.0 模拟设备,我可以使用 MediaStreamTrack.getSources() 找到我想要的设备(它会为每个摄像头返回 facing 属性)。请注意,此模拟设备中不存在“推荐”替换方法navigator.mediaDevices.enumerateDevices()

在使用不同的模拟设备和物理设备时,您会看到许多其他问题,在现实世界中实现这些 API 时,每个问题都给我带来了很大的问题。我强烈建议使用多个物理设备的组合(如果您在可以访问它们的工作环境中),BrowserStack(为您提供大量真实和模拟设备进行测试),console.log()和Vorlon.js(从所有这些模拟设备实时查看console.log() 输出,以便您了解实际情况)。

我目前正在解决这个确切的问题 - 如果我发现任何关于需要支持的不同 API 风格的其他信息,我将在此处发布更新。

【讨论】:

感谢您的深入回复!我已经实现了一个解决方案,用户可以在其中选择一个可用的来源,但这是一个额外的步骤,才能显示实际的相机流,因此不是最佳的。如果我再次在相机上工作,我一定会稍后在这里签到。【参考方案2】:

如果您查看链接到的 MDN 页面的 Browser Compatibility 部分,您会看到:

Chrome 使用过时的约束语法,但此处描述的语法可通过 adapter.js polyfill 获得。

您会很高兴知道 adapter.js 现在支持 Android 版 Chrome 上的 facingMode 约束(对 Chrome 使用 https fiddle):

var gum = mode => 
  navigator.mediaDevices.getUserMedia(video: facingMode: exact: mode)
  .then(stream => (video.srcObject = stream))
  .catch(e => log(e));

var stop = () => video.srcObject && video.srcObject.getTracks().map(t => t.stop());

var log = msg => div.innerhtml += msg + "<br>";
<button onclick="stop();gum('user')">Front</button>
<button onclick="stop();gum('environment')">Back</button>
<div id="div"></div><br>
<video id="video"  autoplay></video>
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>

exact: 语法意味着约束是必需的,如果用户没有正确的相机,事情就会失败。如果您将其省略,则该约束是可选的(尽管在这种情况下,Firefox for Android 将允许用户在权限提示中覆盖相机选择器中的选择)。

adapter.js 还支持navigator.mediaDevices.enumerateDevices(),它已经取代了MediaStreamTrack.getSources

【讨论】:

以上是关于(Android) / Chrome getUserMedia() 约束应该如何格式化?的主要内容,如果未能解决你的问题,请参考以下文章

关于 Twitter API 速率限制的问题 - GET users/show

Symfony getUser 类型提示

错误类型错误:无法读取未定义的属性“getUsers”

facebook->getUser() 返回 0

Auth0 规则 - 从 getUser() 读取元数据

PHP Getusers当前页面