Get device labels onpageshow












1















I'm coding a web app, where user can use his camera (and choose which one to use). The problem is that I want user to be available to choose the camera before it is enabled. In the current code, when user turns on a page, he sees an empty list of cameras and when he enables the camera stream, dropdown list populates with camera names. I want the dropdown list populate when he turns on that web page.



P.S. when I stop() the camera, it disables camera and gives just a black screen. Why it is black instead of background colour?



CameraStreamView.cshtml



@using Api.Models
@{
ViewBag.Title = "Smart Vision";
Layout = "~/Views/Shared/_Layout.cshtml";
}

<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="~/Content/Contact-Form-Clean.css">
</head>

<body onpageshow="Init()">
<div id="container">
<video id="video" style="display: block; margin: 0 auto; margin-top: 30px;" width="300" height="400" autoplay></video>
<button id="enableStream" style="display: block; margin: 0 auto; margin-top: 20px; height: 70px; width: 200px" onclick="start()">Enable camera</button>
<button id="disableStream" style="display: block; margin: 0 auto; margin-top: 20px; height: 70px; width: 200px" onclick="stop()">Disable camera</button>
<label for="videoSource">Video source: </label><select id="videoSource"></select>
</div>

<script src="~/Scripts/GetCameraFeed.js"></script>
</body>
</html>


GetCameraFeed.js



const videoSelect = document.querySelector('select#videoSource');
const selectors = [videoSelect];

function gotDevices(deviceInfos) {
// Handles being called several times to update labels. Preserve values.
const values = selectors.map(select => select.value);
selectors.forEach(select => {
while (select.firstChild) {
select.removeChild(select.firstChild);
}
});
for (let i = 0; i !== deviceInfos.length; ++i) {
const deviceInfo = deviceInfos[i];
const option = document.createElement('option');
option.value = deviceInfo.deviceId;
if (deviceInfo.kind === 'videoinput') {
option.text = deviceInfo.label;
videoSelect.appendChild(option);
}
}
selectors.forEach((select, selectorIndex) => {
if (Array.prototype.slice.call(select.childNodes).some(n => n.value === values[selectorIndex])) {
select.value = values[selectorIndex];
}
});
}

function Init() {
navigator.mediaDevices.enumerateDevices().then(gotDevices).catch(handleError);
}


function gotStream(stream) {
window.stream = stream; // make stream available to console
video.srcObject = stream;
// Refresh button list in case labels have become available
return navigator.mediaDevices.enumerateDevices();
}

function handleError(error) {
console.log('navigator.getUserMedia error: ', error);
}

function start() {
const videoSource = videoSelect.value;
const constraints = {
video: { deviceId: videoSource ? { exact: videoSource } : undefined }
};
navigator.mediaDevices.getUserMedia(constraints).then(gotStream).then(gotDevices).catch(handleError);
}

function stop() {
video.pause();
video.src = "";
stream.getTracks().forEach(track => track.stop());
console.log("Stopping stream");
}









share|improve this question





























    1















    I'm coding a web app, where user can use his camera (and choose which one to use). The problem is that I want user to be available to choose the camera before it is enabled. In the current code, when user turns on a page, he sees an empty list of cameras and when he enables the camera stream, dropdown list populates with camera names. I want the dropdown list populate when he turns on that web page.



    P.S. when I stop() the camera, it disables camera and gives just a black screen. Why it is black instead of background colour?



    CameraStreamView.cshtml



    @using Api.Models
    @{
    ViewBag.Title = "Smart Vision";
    Layout = "~/Views/Shared/_Layout.cshtml";
    }

    <html>
    <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="~/Content/Contact-Form-Clean.css">
    </head>

    <body onpageshow="Init()">
    <div id="container">
    <video id="video" style="display: block; margin: 0 auto; margin-top: 30px;" width="300" height="400" autoplay></video>
    <button id="enableStream" style="display: block; margin: 0 auto; margin-top: 20px; height: 70px; width: 200px" onclick="start()">Enable camera</button>
    <button id="disableStream" style="display: block; margin: 0 auto; margin-top: 20px; height: 70px; width: 200px" onclick="stop()">Disable camera</button>
    <label for="videoSource">Video source: </label><select id="videoSource"></select>
    </div>

    <script src="~/Scripts/GetCameraFeed.js"></script>
    </body>
    </html>


    GetCameraFeed.js



    const videoSelect = document.querySelector('select#videoSource');
    const selectors = [videoSelect];

    function gotDevices(deviceInfos) {
    // Handles being called several times to update labels. Preserve values.
    const values = selectors.map(select => select.value);
    selectors.forEach(select => {
    while (select.firstChild) {
    select.removeChild(select.firstChild);
    }
    });
    for (let i = 0; i !== deviceInfos.length; ++i) {
    const deviceInfo = deviceInfos[i];
    const option = document.createElement('option');
    option.value = deviceInfo.deviceId;
    if (deviceInfo.kind === 'videoinput') {
    option.text = deviceInfo.label;
    videoSelect.appendChild(option);
    }
    }
    selectors.forEach((select, selectorIndex) => {
    if (Array.prototype.slice.call(select.childNodes).some(n => n.value === values[selectorIndex])) {
    select.value = values[selectorIndex];
    }
    });
    }

    function Init() {
    navigator.mediaDevices.enumerateDevices().then(gotDevices).catch(handleError);
    }


    function gotStream(stream) {
    window.stream = stream; // make stream available to console
    video.srcObject = stream;
    // Refresh button list in case labels have become available
    return navigator.mediaDevices.enumerateDevices();
    }

    function handleError(error) {
    console.log('navigator.getUserMedia error: ', error);
    }

    function start() {
    const videoSource = videoSelect.value;
    const constraints = {
    video: { deviceId: videoSource ? { exact: videoSource } : undefined }
    };
    navigator.mediaDevices.getUserMedia(constraints).then(gotStream).then(gotDevices).catch(handleError);
    }

    function stop() {
    video.pause();
    video.src = "";
    stream.getTracks().forEach(track => track.stop());
    console.log("Stopping stream");
    }









    share|improve this question



























      1












      1








      1








      I'm coding a web app, where user can use his camera (and choose which one to use). The problem is that I want user to be available to choose the camera before it is enabled. In the current code, when user turns on a page, he sees an empty list of cameras and when he enables the camera stream, dropdown list populates with camera names. I want the dropdown list populate when he turns on that web page.



      P.S. when I stop() the camera, it disables camera and gives just a black screen. Why it is black instead of background colour?



      CameraStreamView.cshtml



      @using Api.Models
      @{
      ViewBag.Title = "Smart Vision";
      Layout = "~/Views/Shared/_Layout.cshtml";
      }

      <html>
      <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
      <link rel="stylesheet" href="~/Content/Contact-Form-Clean.css">
      </head>

      <body onpageshow="Init()">
      <div id="container">
      <video id="video" style="display: block; margin: 0 auto; margin-top: 30px;" width="300" height="400" autoplay></video>
      <button id="enableStream" style="display: block; margin: 0 auto; margin-top: 20px; height: 70px; width: 200px" onclick="start()">Enable camera</button>
      <button id="disableStream" style="display: block; margin: 0 auto; margin-top: 20px; height: 70px; width: 200px" onclick="stop()">Disable camera</button>
      <label for="videoSource">Video source: </label><select id="videoSource"></select>
      </div>

      <script src="~/Scripts/GetCameraFeed.js"></script>
      </body>
      </html>


      GetCameraFeed.js



      const videoSelect = document.querySelector('select#videoSource');
      const selectors = [videoSelect];

      function gotDevices(deviceInfos) {
      // Handles being called several times to update labels. Preserve values.
      const values = selectors.map(select => select.value);
      selectors.forEach(select => {
      while (select.firstChild) {
      select.removeChild(select.firstChild);
      }
      });
      for (let i = 0; i !== deviceInfos.length; ++i) {
      const deviceInfo = deviceInfos[i];
      const option = document.createElement('option');
      option.value = deviceInfo.deviceId;
      if (deviceInfo.kind === 'videoinput') {
      option.text = deviceInfo.label;
      videoSelect.appendChild(option);
      }
      }
      selectors.forEach((select, selectorIndex) => {
      if (Array.prototype.slice.call(select.childNodes).some(n => n.value === values[selectorIndex])) {
      select.value = values[selectorIndex];
      }
      });
      }

      function Init() {
      navigator.mediaDevices.enumerateDevices().then(gotDevices).catch(handleError);
      }


      function gotStream(stream) {
      window.stream = stream; // make stream available to console
      video.srcObject = stream;
      // Refresh button list in case labels have become available
      return navigator.mediaDevices.enumerateDevices();
      }

      function handleError(error) {
      console.log('navigator.getUserMedia error: ', error);
      }

      function start() {
      const videoSource = videoSelect.value;
      const constraints = {
      video: { deviceId: videoSource ? { exact: videoSource } : undefined }
      };
      navigator.mediaDevices.getUserMedia(constraints).then(gotStream).then(gotDevices).catch(handleError);
      }

      function stop() {
      video.pause();
      video.src = "";
      stream.getTracks().forEach(track => track.stop());
      console.log("Stopping stream");
      }









      share|improve this question
















      I'm coding a web app, where user can use his camera (and choose which one to use). The problem is that I want user to be available to choose the camera before it is enabled. In the current code, when user turns on a page, he sees an empty list of cameras and when he enables the camera stream, dropdown list populates with camera names. I want the dropdown list populate when he turns on that web page.



      P.S. when I stop() the camera, it disables camera and gives just a black screen. Why it is black instead of background colour?



      CameraStreamView.cshtml



      @using Api.Models
      @{
      ViewBag.Title = "Smart Vision";
      Layout = "~/Views/Shared/_Layout.cshtml";
      }

      <html>
      <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
      <link rel="stylesheet" href="~/Content/Contact-Form-Clean.css">
      </head>

      <body onpageshow="Init()">
      <div id="container">
      <video id="video" style="display: block; margin: 0 auto; margin-top: 30px;" width="300" height="400" autoplay></video>
      <button id="enableStream" style="display: block; margin: 0 auto; margin-top: 20px; height: 70px; width: 200px" onclick="start()">Enable camera</button>
      <button id="disableStream" style="display: block; margin: 0 auto; margin-top: 20px; height: 70px; width: 200px" onclick="stop()">Disable camera</button>
      <label for="videoSource">Video source: </label><select id="videoSource"></select>
      </div>

      <script src="~/Scripts/GetCameraFeed.js"></script>
      </body>
      </html>


      GetCameraFeed.js



      const videoSelect = document.querySelector('select#videoSource');
      const selectors = [videoSelect];

      function gotDevices(deviceInfos) {
      // Handles being called several times to update labels. Preserve values.
      const values = selectors.map(select => select.value);
      selectors.forEach(select => {
      while (select.firstChild) {
      select.removeChild(select.firstChild);
      }
      });
      for (let i = 0; i !== deviceInfos.length; ++i) {
      const deviceInfo = deviceInfos[i];
      const option = document.createElement('option');
      option.value = deviceInfo.deviceId;
      if (deviceInfo.kind === 'videoinput') {
      option.text = deviceInfo.label;
      videoSelect.appendChild(option);
      }
      }
      selectors.forEach((select, selectorIndex) => {
      if (Array.prototype.slice.call(select.childNodes).some(n => n.value === values[selectorIndex])) {
      select.value = values[selectorIndex];
      }
      });
      }

      function Init() {
      navigator.mediaDevices.enumerateDevices().then(gotDevices).catch(handleError);
      }


      function gotStream(stream) {
      window.stream = stream; // make stream available to console
      video.srcObject = stream;
      // Refresh button list in case labels have become available
      return navigator.mediaDevices.enumerateDevices();
      }

      function handleError(error) {
      console.log('navigator.getUserMedia error: ', error);
      }

      function start() {
      const videoSource = videoSelect.value;
      const constraints = {
      video: { deviceId: videoSource ? { exact: videoSource } : undefined }
      };
      navigator.mediaDevices.getUserMedia(constraints).then(gotStream).then(gotDevices).catch(handleError);
      }

      function stop() {
      video.pause();
      video.src = "";
      stream.getTracks().forEach(track => track.stop());
      console.log("Stopping stream");
      }






      javascript webrtc getusermedia






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 12 '18 at 18:54







      Deivyyyy

















      asked Nov 12 '18 at 18:44









      DeivyyyyDeivyyyy

      85




      85
























          1 Answer
          1






          active

          oldest

          votes


















          0














          What you want is explicitly disallowed, due to fingerprinting concerns. Details about a user's setup let web sites identify them uniquely on the web, a privacy concern.



          Once users trust your site with their camera and microphone, this information is considered relevant to share.



          The working group determined this to be a reasonable trade-off, for several reasons:




          1. Most desktop users have only one camera or none.

          2. Most phone users have two, but you can use the facingMode constraint to pick.

          3. Given 1 and 2, an up-front choice is arguably an inferior user experience for most.


          I would consider changing your code to ask for the default camera the first time, and give users a choice to change it after the fact, should they need to. It's what most WebRTC sites do.



          Note that this should only be a problem the first time a user visits your site. Provided they've granted camera or microphone just once in the past, you should be able to see the labels, at least in Chrome.



          Unlike Chrome, Firefox does not persist permission implicitly, so you'd need a little more work to get labels on page-load on repeat visits:



          enumerateDevices returns a deviceId for each device, which is persisted for your site provided the user has granted (or will grant within this session) camera or microphone at least once. You can use cookies or local storage to correlate deviceIds to device labels. This also survives people manually revoking permission in Chrome.






          share|improve this answer



















          • 1





            Thanks! Definitely keeping this in mind when updating the script!

            – Deivyyyy
            Nov 13 '18 at 19:43











          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53268269%2fget-device-labels-onpageshow%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          0














          What you want is explicitly disallowed, due to fingerprinting concerns. Details about a user's setup let web sites identify them uniquely on the web, a privacy concern.



          Once users trust your site with their camera and microphone, this information is considered relevant to share.



          The working group determined this to be a reasonable trade-off, for several reasons:




          1. Most desktop users have only one camera or none.

          2. Most phone users have two, but you can use the facingMode constraint to pick.

          3. Given 1 and 2, an up-front choice is arguably an inferior user experience for most.


          I would consider changing your code to ask for the default camera the first time, and give users a choice to change it after the fact, should they need to. It's what most WebRTC sites do.



          Note that this should only be a problem the first time a user visits your site. Provided they've granted camera or microphone just once in the past, you should be able to see the labels, at least in Chrome.



          Unlike Chrome, Firefox does not persist permission implicitly, so you'd need a little more work to get labels on page-load on repeat visits:



          enumerateDevices returns a deviceId for each device, which is persisted for your site provided the user has granted (or will grant within this session) camera or microphone at least once. You can use cookies or local storage to correlate deviceIds to device labels. This also survives people manually revoking permission in Chrome.






          share|improve this answer



















          • 1





            Thanks! Definitely keeping this in mind when updating the script!

            – Deivyyyy
            Nov 13 '18 at 19:43
















          0














          What you want is explicitly disallowed, due to fingerprinting concerns. Details about a user's setup let web sites identify them uniquely on the web, a privacy concern.



          Once users trust your site with their camera and microphone, this information is considered relevant to share.



          The working group determined this to be a reasonable trade-off, for several reasons:




          1. Most desktop users have only one camera or none.

          2. Most phone users have two, but you can use the facingMode constraint to pick.

          3. Given 1 and 2, an up-front choice is arguably an inferior user experience for most.


          I would consider changing your code to ask for the default camera the first time, and give users a choice to change it after the fact, should they need to. It's what most WebRTC sites do.



          Note that this should only be a problem the first time a user visits your site. Provided they've granted camera or microphone just once in the past, you should be able to see the labels, at least in Chrome.



          Unlike Chrome, Firefox does not persist permission implicitly, so you'd need a little more work to get labels on page-load on repeat visits:



          enumerateDevices returns a deviceId for each device, which is persisted for your site provided the user has granted (or will grant within this session) camera or microphone at least once. You can use cookies or local storage to correlate deviceIds to device labels. This also survives people manually revoking permission in Chrome.






          share|improve this answer



















          • 1





            Thanks! Definitely keeping this in mind when updating the script!

            – Deivyyyy
            Nov 13 '18 at 19:43














          0












          0








          0







          What you want is explicitly disallowed, due to fingerprinting concerns. Details about a user's setup let web sites identify them uniquely on the web, a privacy concern.



          Once users trust your site with their camera and microphone, this information is considered relevant to share.



          The working group determined this to be a reasonable trade-off, for several reasons:




          1. Most desktop users have only one camera or none.

          2. Most phone users have two, but you can use the facingMode constraint to pick.

          3. Given 1 and 2, an up-front choice is arguably an inferior user experience for most.


          I would consider changing your code to ask for the default camera the first time, and give users a choice to change it after the fact, should they need to. It's what most WebRTC sites do.



          Note that this should only be a problem the first time a user visits your site. Provided they've granted camera or microphone just once in the past, you should be able to see the labels, at least in Chrome.



          Unlike Chrome, Firefox does not persist permission implicitly, so you'd need a little more work to get labels on page-load on repeat visits:



          enumerateDevices returns a deviceId for each device, which is persisted for your site provided the user has granted (or will grant within this session) camera or microphone at least once. You can use cookies or local storage to correlate deviceIds to device labels. This also survives people manually revoking permission in Chrome.






          share|improve this answer













          What you want is explicitly disallowed, due to fingerprinting concerns. Details about a user's setup let web sites identify them uniquely on the web, a privacy concern.



          Once users trust your site with their camera and microphone, this information is considered relevant to share.



          The working group determined this to be a reasonable trade-off, for several reasons:




          1. Most desktop users have only one camera or none.

          2. Most phone users have two, but you can use the facingMode constraint to pick.

          3. Given 1 and 2, an up-front choice is arguably an inferior user experience for most.


          I would consider changing your code to ask for the default camera the first time, and give users a choice to change it after the fact, should they need to. It's what most WebRTC sites do.



          Note that this should only be a problem the first time a user visits your site. Provided they've granted camera or microphone just once in the past, you should be able to see the labels, at least in Chrome.



          Unlike Chrome, Firefox does not persist permission implicitly, so you'd need a little more work to get labels on page-load on repeat visits:



          enumerateDevices returns a deviceId for each device, which is persisted for your site provided the user has granted (or will grant within this session) camera or microphone at least once. You can use cookies or local storage to correlate deviceIds to device labels. This also survives people manually revoking permission in Chrome.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 13 '18 at 15:18









          jibjib

          20.4k64389




          20.4k64389








          • 1





            Thanks! Definitely keeping this in mind when updating the script!

            – Deivyyyy
            Nov 13 '18 at 19:43














          • 1





            Thanks! Definitely keeping this in mind when updating the script!

            – Deivyyyy
            Nov 13 '18 at 19:43








          1




          1





          Thanks! Definitely keeping this in mind when updating the script!

          – Deivyyyy
          Nov 13 '18 at 19:43





          Thanks! Definitely keeping this in mind when updating the script!

          – Deivyyyy
          Nov 13 '18 at 19:43


















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53268269%2fget-device-labels-onpageshow%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Full-time equivalent

          さくらももこ

          13 indicted, 8 arrested in Calif. drug cartel investigation