JavaScriptでスマホのライトを制御したい!
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()でビデオトラックを取り出して、そこに指定してあげる必要があるみたいです。
なんかもっと上手いやり方があるかもしれません。
長々とした文章になってしまいましたがそんな感じです…
参考になったらいいねやフォローしくれると嬉しいです!!
Discussion
その書き方だと track が取得前に lightOff / lightOn されてしまうのでは……?
やるなら getMedia() 内の Promise を return して 呼び出し元で await するべきではないでしょうか……?
コメントありがとうございます!
toggleLight()内でtrackの取得判定をしているので大丈夫なはずなのですが、これだと Promise が解決される前にまたgetMedia()が呼び出されてしまう可能性がありますね…(ボタン連打など)JS始めたばかりの頃に書いたコードなので非同期処理など分かっていないことが多く、今見返してみると改善できそうなところが多いです、、
時間があったらブラッシュアップしたいと思います…!!
getMedia() は非同期なので、 1回目は track が null のまま次に行く為(※Promise.prototype.then は queueMicrotask で 非同期になることが確約されている為)、設定されるまでの間 lightOff / lightOn は track が設定されるまでの間 エラーになるのでは?のニュアンスです。
勘違いしてました、、
trackがnullだった場合何もせずその場でreturnしてるつもりだったのですが全然してませんでした…確かにこれだと
getMedia()した直後に確実にlightOn()が一度呼ばれてエラーになりますねawaitで書き直します!