non vorrei lavorare

昔はおもにプログラミングやガジェット系、今は?

gRPCでmojaveに勝利してリモートからWebカメラを利用した

おはようございます。長男は忘れ物がひどく、よく奥さんに怒られて、マイクラ禁止になっています。@kjunichiです。

背景

macOSのMojaveからFaceTime HDカメラや、Webカメラ等のカメラデバイスへのアクセスが厳しくなり、 アプリ毎に設定が必要となってしまい、これまでのようにssh越しにリモートから利用することができなくなってしまった。

対策

あらかじめ、Termina.appでカメラにアクセスするコードを含むサーバプロセスを実行しておき、 SSHでリモートからアクセスした際はこのサーバプロセスにアクセスするクライアントを動かすことで、 Mojaveに怒られないようにする。

ちなみに、アクセス許可のないアプリ等からカメラデバイスにアクセスすると 以下の記事のようなことになる。

abrakatabura.hatenablog.com

クライアントとサーバ間の通信方式にgRPCを採用

クライアントとサーバ間の通信方式にgRPCを使えば、今時な実装でイケてるのでは?という安易な選択で いざ実装。

gRPCでストリームを使う

これまで Raspberry Piの温度をgRPCを使ってElectronで作ったデスクトップマスコットに表示させたmacOSのCPU温度をgRPCを使ってElectronで作ったデスクトップマスコットに表示させた と複数のgRPCをつかったリポジトリ保有しているものの、 .protoファイルがHelloWorldを流用してやり過ごしていた。

今回一念発起して、独自の.protoファイルかつStreamをつかったgRPCにチャレンジした。

gRPCでstreamを使うポイント

HelloWorldとともに公開されているRoute_guideのソースを見れば、大体わかる。 特にNode.js実装だと自分が慣れているのもあり、

  • サーバ側からstreamを返すパターン
  • クライアント側からstreamを送るパターン
  • クライアント、サーバともにstreamを送るパターン

のパターンがあり、これらのそれぞれのパターンに対応するメソッドがサンプルに 書かれている。

今回はクライアントからは通常のリクエスト、サーバ側からストリームというパターンで 作るのでサンプルの

function listFeatures(call) {

の関数を参考に作業を進めた。

クライアントからのリクエストを空にすることも可能

今回のアプリはWebカメラの画像を貰うだけなので、特にクライアントからサーバに渡すデータは 不要だったが、サンプルは何かしら入れているので、どうしたものかと一瞬悩んだが、

message Request {
}

という指定で.protoファイルを作ることが出来たので、スッキリした。

試行錯誤の末できた.protoファイル

こうして完成したのが、以下の.protoファイル

syntax = "proto3";

package camtype;

message Request {
}

message Response {
    bytes ppm = 1;
}

service Camtype {
    rpc Camtype (Request) returns (stream Response) {}
}

勘違いしていたStream

自分の中にはストリームというとバイトストリームのイメージが強く、 JSONが分割して送信されると誤解していたが、 .protoファイルで定義した構造体がNode.js実装の場合にはJSON形式でぼこぼこ返されるのだった。

message Response {
    bytes ppm = 1;
}

というppmという定義は、PPMファイルを適当にぶった切ってバイト列をで送るものだと決めつけていたが、PPMファイルをまるまる一回の

call.write({ ppm: data })

で送ることが出来てしまった。

当初はgRPCでStream指定をしたら、gRPC側で適当に細切れにして、クライアントに送信することを 来していたが、裏でどうなっているかは知らないが、表面的なAPIとしては、 サーバで1個streamを送信したら、クライアント側で1個受け取れる模様。

ちなみにクライアント側のでstreamを受け取るのは以下。

call.on('data',(response)=>{
    parsePpm(response.ppm)
})

サーバ側からStreamを送る際の注意

サーバ側

一連のstreamをwriteしたらendメソッドを呼び出す必要がある模様。

call.end()

クライアント側は

call.on('end',()=> {
    console.log(`end`)
})

として、サーバ側からのendを受け取ることができる。

成果物

github.com

学んだこと

これまでにgRPCには触ってはいたが、Helloworldの.protoファイルをそのまま流用しており、 今回初めて、自分のアプリ向けに.protoファイルを作成することを経験した。

Node.jsは動的に.protoファイルを扱えるので、試行錯誤しながら.protoファイルを作って 実装していくような今回のケースでは手軽で便利!

気になった事

サーバ側で、Webカメラの映像が安定することを期待してウェイトを入れているが、 これがどの程度長くしても怒られないのか、また、怒られる場合は、gRPCのタイムアウト になるのだろうか。

関連記事

7年前の記事

こどものマイクラで占領された自作Xeon PCをリモートから操作してIJuliaを入れてブラウザからJuliaを使うまで

こんばんは。今年も花粉症がひどくて沖縄や北海道にしばらく行っていたいです。次男も花粉症の疑いがあり、一緒に耳鼻科に行って花粉症対策の薬を処方してもらって二人で飲んでいます。@kjunichiです。

背景

Xoenで8コア積んでる自作PCを子供のマインクラフトに占領されている。

Jupyter経由でJuliaを動かせるようにして、貴重な計算機資源を奪回する

公式でOpenSSHがWindows10でも利用できるようになったので、これを利用する事で、 かなりのことがマインクラフトで占領されている自作PCに対して遠隔操作できるはず。

Juliaのインストール

これはこどもが起きてこないうちにさくっと実施。

以降はsshで繋いで作業

IJuliaのインストール

cd %homepath%
AppData\Local\Julia-1.1.0\bin\julia.exe
using Pkg;Pkg.add("IJulia")

などで、普通にインストール

IJuliaを入れた際に入るjupyterを探す

リモートからjupyterにアクセスできるようにする。 その為には、まず、IJuliaをインストールした際に一緒にインストールされたjupyterを探しておく。

cd %homepath%
fd jupyter.exe$ .julia

ここで、fdコマンドはrust実装の21世紀版find(UNIX版の意)コマンド。

.julia\conda\3\Scripts\jupyter.exe                                                                                      
.julia\conda\3\pkgs\jupyter_core-4.4.0-py36_0\Scripts\jupyter.exe                                                       

のように見つかるはず、今後利用するのは、この例では、一番上のバージョンを含まない

.julia\conda\3\Scripts\jupyter.exe

を使っていく。

jupyter.exeが呼び出すサブコマンドが見つからないと怒られるので、以下のように パスを通しておく。

set path=%path%;%homepath%\.julia\conda\3\Scripts

デフォルトのjupyterの設定ファイルの雛形を生成

以下のコマンドで、デフォルトのjupyterの設定ファイル(%homepath%.jupyter\jupyter_notebook_config.py)の雛形を生成する。

jupyter notebook --generate-config

jupyterをリモートからアクセス出来るように設定

先ほど生成したjupyterの設定ファイルを編集して、リモートからjupyterにアクセス出来るようにする。

変更が必要な項目は以下の項目の模様。

c.NotebookApp.allow_remote_access = True 
c.NotebookApp.ip = '*' 
c.NotebookApp.local_hostnames = ['localhost','192.168.0.123'] 

192.168.0.123は子供に占領されてる自作PCIPアドレスを指定。 (もしかするとlocalhostのみでもOKかも)

以上で、準備完了となる。

IJuliaをリモートから起動

cd %homepath%
AppData\Local\Julia-1.1.0\bin\julia.exe
using IJulia
notebook(detached=true)

ここでdetached=trueの指定が無いと、プロンプトが戻ってこないので、別のsshで繋ぐ必要がある。

Ijuliaのデフォルトの状態ではjupyterがパスワード運用ではないようなので、jupyterコマンドで

jupyter notebook list
Currently running servers:                                                                                              
http://localhost:8888/?token=c0fc9b6d0e7684b58a1018eb2197603b0eb028a8c23883a9 :: C:\Users\kjunichi                         

として動かしているURLを取得して、これをローカルのブラウザに貼り付ける必要がある。 この際、localhostとホスト名がなっている場合、これを対象のPCのホスト名やIPアドレスに置きかる必要がある。

f:id:kjw_junichi:20190228233602p:plain

おわりに

Xeonといっても4万程度のCPUなので、2GHz以下のクロックで新しくしたいMac Book Pro 初代Retinaより 1コアあたりの処理は遅いことを思い出した。

関連記事

こどもつながり

14年前の記事

9年前の記事

4年前の記事

だれもがターミナルにWebカメラ映像を表示を使うことができる時代なのに……

こんばんは。日曜日、自分のYシャツのアイロンをかけ終わり、翌朝の阻止馬出しのPTAの当番の為に早く寝るか。というタイミングで、長男が、金曜日に持ち帰って来ていた給食の白衣が残っている事が発覚、速攻で洗濯機を回し、アイロンをかけた@kjunichiです。

背景

だれもがターミナルにWebカメラ映像を表示を使うことができる時代なのに、Mojave以降その風景はガラリと変わってしまった。

Mojave以前

ssh越しにフツーに以下の自作アプリが使えた。

Mojave以降

カメラを利用するには許可を与えないといけない sshdに許可を与えれば解決しそうだが、これは.appに対してしか許可できなそう。

f:id:kjw_junichi:20190125202307p:plain

そこで、 カメラにアクセスするアプリはデスクトップ起動し、このアプリで ソケットを受け付け、接続してきたクライアントに対して撮影した画像を ソケット通信で返すという流れにすることで実現出来そう

図にすると以下のようなイメージ

f:id:kjw_junichi:20190218212357p:plain

やってみた

成果物

github.com

使い方

git clone https://github.com/kjunichi/camtyped
cd camtyped
npm i
node main.js &
node --experimental-modules client.mjs

関連記事

7年前の記事

5年前の記事