JavaScriptでスマホのライトを制御したい!

に公開4

JavaScriptでカメラ系の開発をする際に、カメラのライトを使いたいことが度々あったのですが、情報が少ないのでまとめておきます🔦
書こう書こうと思っててずっと放置してた記事です。JS初心者なので温かい目で見ていただければ嬉しいです🔰

サンプル

見てもらった方が早いと思うのでサンプルです。Zenn上ではカメラへアクセスができないので、右上の「EDIT ON CODEPEN」からCodePen上で見てください。

JSが全然スマートじゃない…

解説

軽く解説します📹
getUserMedia()でカメラへアクセスして、getVideoTracks()で取得したトラックに対してapplyConstraints()で値を切り替えています。ライトを操っているのは{ advanced: [{ torch: true }] }ですね。

いくつか注意点があります。

まず、背面カメラの指定が必要です。当然といえば当然ですが、ライトは背面カメラにしかついていないので{facingMode: "environment"}を指定して、背面カメラを使用する必要があります。僕は見たことないけど内カメにライトがついてる機種もあるのかも()てかそもそもブラウザ側が対応してくれるか

次に、ブラウザの対応状況が曖昧な点です。調べれば出てくるのかもしれませんが、Android版Chromeでは確認できました。スマホ前提で話してきましたが、Windows版ChromeとEdgeでもサポートされているのは確認しました。ライトがないので実際の確認はできてないです…そもそもタブレットPCとかじゃないとカメラにライトがない件
そもそもtorch自体が、advancedの値なので[1]実際に使用するときは、getSupportedConstraints()などで対応を確認した方が良いかもしれません。

あとは何故かMediaStreamオブジェクトに直接{ torch: true }を指定できない点です。getUserMediaで返されたMediaStreamからgetVideoTracks()でビデオトラックを取り出して、そこに指定してあげる必要があるみたいです。
なんかもっと上手いやり方があるかもしれません。


長々とした文章になってしまいましたがそんな感じです…
参考になったらいいねやフォローしくれると嬉しいです!!

脚注
  1. https://developer.mozilla.org/ja/docs/Web/API/Media_Capture_and_Streams_API/Constraints#高度な制約 ↩︎

Discussion

junerjuner

その書き方だと track が取得前に lightOff / lightOn されてしまうのでは……?

やるなら getMedia() 内の Promise を return して 呼び出し元で await するべきではないでしょうか……?

https://codepen.io/juner/full/poMgpON

natsunenatsune

コメントありがとうございます!
toggleLight() 内で track の取得判定をしているので大丈夫なはずなのですが、これだと Promise が解決される前にまた getMedia() が呼び出されてしまう可能性がありますね…(ボタン連打など)

JS始めたばかりの頃に書いたコードなので非同期処理など分かっていないことが多く、今見返してみると改善できそうなところが多いです、、

時間があったらブラッシュアップしたいと思います…!!

junerjuner

getMedia() は非同期なので、 1回目は track が null のまま次に行く為(※Promise.prototype.then は queueMicrotask で 非同期になることが確約されている為)、設定されるまでの間 lightOff / lightOn は track が設定されるまでの間 エラーになるのでは?のニュアンスです。

natsunenatsune

勘違いしてました、、
tracknull だった場合何もせずその場で return してるつもりだったのですが全然してませんでした…
確かにこれだと getMedia() した直後に確実に lightOn() が一度呼ばれてエラーになりますね
await で書き直します!