openFrameworksのofxOSCでデカい(65KB以上くらい)データを送る

openFramworksのofxOSCでは画像を送ることが可能だが、サンプルにも書かれている通り、一定以上のサイズはサンプルのコードでは送る事ができない。具体的には大体65000Byte以上くらいなのだが、これはOSCが利用しているUDPペイロードサイズの制限(より正確にはIPパケット)によるものだ。ちょうどよい解説が@ITにあったので引用しておく。

1つのUDPパケットで運ぶことのできるデータ(「ペイロード(荷物)」という)の長さは、下位層のIPパケットの長さの制約を受ける。(標準の)IPパケットでは、1回の送信で、最大では65515bytes(65535bytesから、IPヘッダの最低サイズ20bytesを引いたもの)までのデータを送信することができる(IPヘッダ・オプションが付くと、さらに小さくなる)。そのため、1つのUDPパケットで送信することのできる最大ペイロード・サイズは、65515bytesからUDPヘッダのサイズ(8bytes)を減算した、65507bytesまでとなる。このため、この「長さ」フィールドの値は、8(データが空の場合)~65515となる。
基礎から学ぶWindowsネットワーク:第13回 データグラム通信を実現するUDPプロトコル (3/4) - @IT

今回、これを超える大きさのデータのやり取りをしたいと思って実装したので詳細を書いておく。oFのバージョンは0.9.8。

方法の概略

送信側でデータをサイズ制限以下に分割してOSCメッセージにして送信、受信側でデータを結合する。
OSCメッセージには、データ自体とデータの開始フラグと終了フラグをつけておくことで、受信側でデータをどのように結合すればいいか分かるようにした。

コード

全体のファイルはGithubに置いた。macOS 10.12.4 のXcode 8.3 で開発した。相手先のIPアドレスはsettings.xmlで設定する。
GitHub - torukawanabe/oscImageTransferExample

送信

ofBuffer型の変数imgAsBufferに画像データが読み込まれている。他のデータを考慮しても確実に上記サイズ制限に収まるであろう60000バイトで分割している。

void ofApp::sendImage(){
    img.load(imgAsBuffer);
    
    static const int dividingSize = 60000;
    int numOfSend = (imgAsBuffer.size() / dividingSize) + 1;
    cout << "NOW POST IMG SIZE:" << imgAsBuffer.size() << " ,NUM OF SEND:" << numOfSend << endl;
    
    if (numOfSend == 1) {
        ofxOscMessage m;
        m.setAddress("/image");
        m.addBoolArg(true);
        m.addBoolArg(true);
        
        vector<char> sendBuff = vector<char>(imgAsBuffer.begin(), imgAsBuffer.end());
        m.addBlobArg(ofBuffer(sendBuff.data(), sendBuff.size()));
        
        sender.sendMessage(m, false);
    }else{
        vector<char>::iterator it = imgAsBuffer.begin();
        for (int i=0; i<numOfSend; i++) {
            ofxOscMessage m;
            
            vector<char> sendBuff;
            sendBuff.clear();
            
            m.setAddress("/image");
            if(i == 0){
                m.addBoolArg(true);
                m.addBoolArg(false);
            }else if(i == (numOfSend - 1)){
                m.addBoolArg(false);
                m.addBoolArg(true);
            }else{
                m.addBoolArg(false);
                m.addBoolArg(false);
            }
            
            for(int j=0; j<dividingSize; j++){
                sendBuff.push_back(*it);
                if(it == imgAsBuffer.end()) break;
                it++;
            }
            cout << "sendBuff" << i << ":" << sendBuff.size() << endl;
            m.addBlobArg(ofBuffer(sendBuff.data(), sendBuff.size()));
            sender.sendMessage(m, false);
        }
        
    }
    
    cout << "ofApp:: sending image with size: " << imgAsBuffer.size() << endl;
}

受信側

vector型の変数receivedBufferにOSCメッセージからパースしたデータをいれていく仕組みで実装した.

void ofApp::updateOSC(){
    while(receiver.hasWaitingMessages()){
        // get the next message
        ofxOscMessage m;
        receiver.getNextMessage(m);
        if(m.getAddress() == "/image" ){
            bool isFirst = m.getArgAsBool(0);
            bool isLast = m.getArgAsBool(1);
            
            if(isFirst){
                receivedBuffer.clear();
            }
            
            ofBuffer buff = m.getArgAsBlob(2);
            for (char c: buff){
                receivedBuffer.push_back(c);
            }
            
            // ofBufferが最後に0を挿入するので末尾を削除
            receivedBuffer.pop_back();
            
            if(isLast){
                ofBuffer imgBuff = ofBuffer(receivedBuffer.data(), receivedBuffer.size());
                receivedImg.load(imgBuff);
            }
        }
    }
}

注意点

ofBufferは内部で持つvectorで最後に0を勝手に挿入する*1ので、データの結合時に削除する必要がある。また、UDPはパケットの送達確認や到着順序は保証されないが、今回の実装ではパケットの不着や順序の入れ替わりの可能性を考慮していないので、注意してほしい。またパフォーマンスも考慮していない。

*1:NULL終端のため

Mac対応大型タッチパネルについて

Windowsが8でタッチを打ち出して以来、小型-中型ディスプレイはタッチのラインナップが存在して当たり前の状況だが、デジタルサイネージ向けサイズ(=大型)になると少し状況が異なる上に、Mac対応しているものは少なかったのでまとめた。

デジタルサイネージ向けディスプレイの主要なメーカー

NECSHARP、Pansonicの3社。その他にも東芝SONYなどもやっているが、フルラインナップといえるのはこの3社。4K、屋外向けの超高輝度(1000cd/㎡以上)、タッチパネルのディスプレイを持っているので探しやすい。2017年3月現在、他のスペックはほぼ横並びである。

デジタルサイネージ向けパブリックディスプレイ: ディスプレイ | NEC
トップページ|インフォメーションディスプレイ:シャープ
業務用ディスプレイ | Panasonic

NECは直販しており、SHARPは小売店から買える一方、Pansonicは日本国内では代理店を通さないと購入出来ないようだ。
この中ではMacに対応したタッチモニタがあるのはSHARPだけだったが小型なものしか扱っていなかった。

Mac対応のタッチパネル

メーカー公式に対応しているのは確認出来たのはSHARPとグローバルディスプレイ、3M(shigeodayo氏に教えてもらった)の3社のみだった。Apple社さん、OSとしてタッチパネルに対応してもらえないですかね。
SHARPは仕様ページの対応OSにMacは書いてないが、Mac用ドライバを用意している。グローバルディスプレイは公式サイトに対応OSが記載されてないので問い合わせたところ、ドライバがあるとのことだった。

LL-S201A|インフォメーションディスプレイ:シャープ
中大型タッチモニター|グローバルディスプレイ株式会社
Electronics Product Catalog 3M™ Multi-Touch Display C5567PW (55%22): Electronic Solutions : 3M United States

Mac用ドライバの挙動

最終的に弊社(アートアンドプログラム社)では開発用にグローバルディスプレイ社の43インチのものを購入した。ドライバをインストールしない状態ではタッチパネルはマウスとして反応し、インストールするとトラックパッド的振る舞いをする。なおopenFrameworksで書いたアプリケーションと同時にドライバを利用すると競合して不安定な挙動になった。ドライバを利用せず、マウス的振る舞いをさせる場合は挙動に問題はなかった。
SHARPの方も説明書を見る限り、ドライバを入れるとトラックパッド的振る舞いをするとのこと。

Amazonで買えるラインナップ

20、32(4K)、32、43、55、60インチから選べる。1機種のみ4Kであとは全てフルHD

シャープ 20V型フルHDタッチディスプレイ LL-S201A

シャープ 20V型フルHDタッチディスプレイ LL-S201A

シャープ 32型4K2Kタッチディスプレイ ブラック PN-K322B

シャープ 32型4K2Kタッチディスプレイ ブラック PN-K322B

グローバルディスプレイ 32インチ10点タッチモニター

グローバルディスプレイ 32インチ10点タッチモニター

グローバルディスプレイ 43型 10点タッチモニター

グローバルディスプレイ 43型 10点タッチモニター

グローバルディスプレイ 55型 10点タッチモニター

グローバルディスプレイ 55型 10点タッチモニター

3M Multi-Touch Display C5567PW

3M Multi-Touch Display C5567PW

非公式に使えると噂のモニタ

下記記事のようにドライバなしで使えるモニタもあるらしい。
ameblo.jp

Gechic モバイルモニター On-Lap 1002 10.1インチ/タッチパネル対応

Gechic モバイルモニター On-Lap 1002 10.1インチ/タッチパネル対応

2016年度の社会貢献活動報告

経緯

2016年の3月からフルタイマーになったし、20歳はとっくに過ぎていたので大人の責務を果たすかと思い、今年度は社会貢献をいくつかしました。昔からOSSの使い方はブログに書いて貢献しているのですが、アフィリエイトなどの実益もあるのであまりコントリビューション感がないので、新しい試みとして寄付とボランティアをしました。

社会貢献の軸はOSSと教育に置きました。

OSSに関してはそれで仕事になっているから、仕事の道具に感謝ってところですね。巨人の肩の上ってやつです。

教育についてですが、僕は冗談で田中角栄の孫って言ってるんですが、なぜかというと、僕は学部を慶應修士を早稲田というお金のかかる教育*1を受けたのですが、その教育費が出たのは、両親共働きの公立の教員なためで、僕の両親は学費が安かった頃に大学を卒業し、田中角栄による人材確保法で上がった給料で教育費を稼いでくれたからなのです。
今ではすっかり国が教育に金をかけなくなってしまった*2
ので、選挙では教育に金をかけてくれる政策に対して投票しているのですが、なかなか政策は実現しないし、せっかく私学の雌雄を出たので在野の精神で改善がんばるかと思って、寄付とボランティアをし始めました。

寄付

収入の1%を寄付しました。

対象 種類 金額
Processing OSS $50
Arduino OSS $50
Free Software Foundation OSS $50
赤十字 国際NGO 5000円
国境なき医師団 国際NGO 5000円
CARE 国際NGO 5000円
ユニセフ 国連機関 5000円
UNHCR 国連機関 5000円
キッズドア 国内NPO 5000円
ストップいじめナビ! 国内NPO 5000円

OSSの方ではOpenCVにもしようとしたらPaypalがJPからの寄付は受け付けとらん!って断られてしまいました。Arudinoは寄付したらこんな画面でかわいい。あ、Arduinoの場合ソフトに限らないからOSHでもありますね。
f:id:miso_engine:20170331211427p:plain
国際NGO国連機関は戦後の日本に援助してくれた機関を中心に寄付してみました。最近だとまた違った機関があると思いますが、選択しやすかったので。日本の戦後復興と国際援助に関しては以下にまとまっています。
外務省: [ODA] ODAとは? ODAちょっといい話 第二話戦後の灰燼からの脱却
OSSだと寄付金控除にならないのですが*3、それ以外の機関は大体対応していて、おおざっぱに40%程度返ってきてしまうらしいです。オトクだ。

ボランティア

内容 回数
中学生向け学習支援ボランティア 15回
小学生向け学習支援ボランティア 1回
高認試験受験者向け学習支援ボランティア 1回
乙女電芸部ワークショップ*4 10回

もっぱら子供向けボランティアをしていました。表にまとめてみたら結構してますね。学習支援ボランティアはどれもマンツーマンで2コマ程度(1コマ50分程度)教える感じです。実はこれをやってるときに取材が来てプレジデントファミリーに背中が写った写真が載りました。一生縁がないと思ってたプレジデントファミリー……。理系科目を教えられる人が常に足りないので、エンジニアの人とかは是非どうぞ。都内ならある程度紹介できます。
乙女電芸部は大体「かわいい」を電気で作るぞ!という子供向けワークショップをやってました。これはおゆまるで作るオリジナルのLEDブレスレットですね。
f:id:miso_engine:20170331221830j:plain

今年書いたOSSの記事

おわりに

結構ボランティアしたなと思ってたんですが、まさか週末の半分はボランティアしてとは思わなかったです。大変か?というと人生のルーチンに組み込まれたのでそんなに大変じゃないし自己肯定感上がりました。あと寄付先を絞り込むのすごく苦労しました。次はチェックもしていかないと。
来年度はインタラクション技術周辺のエンジニアを集めたコミュニティやカンファレンスなどの実現を狙ってるので、興味ある人はご連絡ください。

*1:あと個人的には世界最高の教育だったなと思ってます

*2:OECDの中ではトルコについでワースト2位 第1章 家計負担の現状と教育投資の水準:文部科学省

*3:国外のOSSに寄付するための認定NPOや財団があると助かります

*4:乙女電芸部は営利でもやっているのですが、大体持ち出しのボランティアです