BONXを支える音声信号処理開発のウラガワ

皆様はじめまして、BONXで技術顧問をやっている粟飯原と言います。BONXでは、開発領域では音声信号処理アルゴリズム開発とVoIPシステムに関するソフトウェアレベルでの音声通話品質向上だったりが主ですが、他いろいろやってます。技術顧問という肩書を頂いては居ますが、VoIPサーバをgolangで書いたり、組み込み向けの音声処理ライブラリをC++で実際に書いてます。

BONXは、御存知の通りアウトドアにかぎらず複数人で行う様々なアクティビティをより楽しくするためのコミュニケーションツールとして、ウェアラブルトランシーバとそれに付随するアプリケーションの開発を行っています。今回は、その中でもBONXを支える技術の一つである、音声信号処理アルゴリズムの開発過程をまとめさせて頂きます。

BONXと音声信号処理

BONXは、アウトドアスポーツ等を行っている間に利用するトランシーバーであるので、通常のトランシーバーと異なり、ボタンを押してから話し始めると言うのではなく、人の発話を自動的に検知して手による操作をなしに会話が出来る(自動発話検知)ということがkey featureの一つとなっています。(接客等の周囲の人間と会話しつつ、離れた人とも会話したいというユースケース向けに、ボタンを押して音声送信を始めるPush-to-talkモードでも利用可能です。)

bonx-head.png

BONXのユースケースは、メインとなるアクティビティの補助であるので、電話と異なって常に会話を行うというものでもありませんし、利用シーンとして周辺環境の騒音が大きい場所で利用することになります。一般的な電話機なんかでも発話検出やノイズ除去の機能を持ったチップは乗っていたりするのですが、もともと想定されているユースケースが異なるのでそのまま使えるわけではありません。

BONXを利用している間、会話自体はまれにしかしないのに常に音声を送信し続けてしまうと非常に耳障りなだけではなく、電話代・パケット代が大変なことになってしまいますので、UXだけではなくコスト的にも非常に重要な機能となっています。

また自動発話検知を実現するために、アプリケーションレベルの様々なアルゴリズムの適用だけではなく、ハードウェアレベルの音質向上の取り組みや、ファームウェアレベルの音響調整と音質向上のためのセッティングなども同時に進める事になります。

発話区間検出

発話区間検出について

BONXにおける音声信号処理アルゴリズム開発

BONXでの音声信号処理アルゴルズム開発以下のような流れで今に至っています。

  1. 標準的なセッティング
  2. 実地テスト・ユーザからの要望が上がる
  3. アクティビティ中の生音の収集
  4. 集めた生音でPython + Jupyter Notebookによるアルゴリズム検討
  5. モバイル向け実装の開発
  6. ファームウェアの最終チューニング
  7. 実地テストという名の社内アウトドアイベント
  8. 2に戻る

基本的には、一般的なWebサービス等のプロダクトにおけるUI/UX改善のデータ分析業務と同じようなものだと思っていますが、体験が音声会話であり、扱うデータが音声であることという部分に特殊性があると思います。

標準的なセッティングの実施

BONXは、Bluetoothヘッドセットデバイスと、スマートフォンアプリを連携させて初めて真価を生むプロダクトです。音声信号処理についても、まずハードウェアレベルでの前処理が上手く動いているお陰で、アプリケーション側だけでは実現不可能なノイズ除去や発話検出を実現しています。

ハードウェアチップには標準音響処理エンジンが入っているのでマイクの配置の調整と、ビームフォーミングによる口元の音声の強調や、定常ノイズの除去とイコライジング等のセッティングを実施します。それの設定によって音の質(スペクトルの分布や波形の歪み)が変わってきますので、その音声に合わせて、パラメータを調整した発話検出のための標準的なアルゴリズムを実装して、まず(社内)リリースを行いました。

実地テスト・ユーザからの要望が上がる

しかし、いざ(社内)リリースしてみると、ランニング中の息遣いが荒い時うるさいからなんとかしてほしいであったり、スケボーでオーリーした時の衝撃音を無視したい特定の音が耳に刺さる等のいろんな要望が上がってきます。

www.instagram.com

音響的なものについては、社内にいるプロのオーディオエンジニアの方にハード・ソフト両面に色々処理を追加してもらうのですが、デザイン性もプロダクトの価値として非常に重要であるので、S/N比を稼ぐためにマイクを口元に持ってこれない以上、音声信号処理のレイヤーで頑張るしか無いので、やることはとにかくなんでも試す必要がありました。

アクティビティ中の会話の生音を集める

定性的な感想から、実際にその環境を再現して音データを見ないと行けないわけですが、再現するとなると実際にアクティビティをやって音を集めてこなければなりません。マイク(ハードウェア特性)、空間特性、環境音、声によって音は変わってくるのでとにかく体当たりで集めに行くのが一番はやいです。

自分自身も、オフィスの近くの駒沢公園をランニングしながら、自分のブレス音と環境音を録音してみたり、やったことのないスケボーを自分でも初めて、スケートパーク内でスケートしながらボードが立てる騒音を録音してみたりしています。もちろん、他の社員も日常的に山に行ったり釣りに行ったりするので、録音アプリを持たせて直してほしかったら音取ってこいやととにかくいろんな環境音を集めています。

Python + Jupyter Notebookによるアルゴリズム検討

f:id:argmax:20170308154239p:plain

検証用の音声が集まったあとは、普通のデータ分析仕事と同様、Python + Jupyter Notebookを用いてインタラクティブアルゴリズム検証を行います。Pythonには、numpy、scipyといった基本的な数値計算のためのものから、音楽分析と可視化用のlibrosaや、音声分析のためのpysptk,等音声信号処理アルゴリズムの検証を低コストで回す環境は一通り揃っています。音声データをスペクトルの可視化等をしながら検証出来るのはとても効率的です。

また、個人的にも、これまでの数年間の中で、音声信号処理に関する研究開発の仕事もやってきていますので、そのための検証や、ノイズ除去アルゴリズム等の基本的な実装をまとめています。

github.com

直接BONXの製品に入っているアルゴリズムが入っているわけではないのと実装的に動かないものもあるのであくまでご参考まで。

モバイル向け実装の開発

アルゴリズムが固まったら、スマートフォン上で実行出来るようにC++で再実装します。この部分は特に話すことは無いのですが、iOS/Android両方で利用出来るように、C++による共通実装をライブラリ化して開発しています。

リアルタイム性が求められるアプリケーションであり、計算遅延の発生は許されないため、メモリアロケーションを最小限にすると言った基本的な高速化から、ARMのSIMD拡張であるNEONを利用するなどの効率的な実装が求められます。iOSだけであればAccelerate Framework(vDSP)があるので、そこまで頑張らなくても十分早くなったりするのですが共通化を目指すと組み込み系素人にはなかなかにハードルの高い取り組みでした。

実地テストという名の社内アウトドアイベント

ある程度機能が固まり、録音音声での検証が済むと、最後は実地検証として実際にBONXを試す会を実施します。業務なのでスノボや釣り等のアウトドアアクティビティへ繰り出すしかないのです。

f:id:argmax:20170307162042j:plain

この写真は、深夜にまったく明かりが無い、坊岬の沖合2kmぐらいで腰まで海に浸かってウェーディングをしたときの様子です。初めてのウェーディングという環境で、同僚と二人で数百メートル離れて釣りをしていたのですが、風速15mぐらいの風が吹いていても手を使わずに話した分だけ音声が届いて、初心者でも同行者の手をあまり煩わせずウェーディングを楽しむことが出来ました。。このシチュエーションはハンズフリーで長時間会話出来るソリューションが無いとかなり不安になるような環境だったので、そこで安定して動作をしたの確認できて非常に安心したというリリース前ギリギリの話でした。

大体は、こんな音絶対非発話として判定できねーよとなって打ちひしがれることが多いので、上手く行ったときの喜びは一入であります。

おわりに

BONXにおける音声信号処理アルゴリズム開発プロセスについてまとめさせていただきました。まだまだ問題は出ているプロダクトでありますが、Dogfoodingを厭わないチームとして動いています。End-to-Endでのアルゴリズム開発からアプリへの適用、そしてそれをリリースしたプロダクトで自分たちを含めたアウトドアスポーツを楽しむ人達の趣味がより楽しくなるという素晴らしい環境であると思うので、音声信号処理の仕事としては非常に楽しいプロダクトだと思います。

www.wantedly.com

golangVoIPシステムを書いたり音声信号処理の基盤ライブラリを書いたりする仲間はいつでも探してますのでよろしくお願いいたします(そもそも音声信号処理の組み込みライブラリをベンチャーで書いてる人がいればいろいろ話聞きたいのでそれはそれで仲良くしてください)。

HWスタートアップの見たCES②

CTO楢崎です。前回に続いて、CES体験記を上げたいと思います。 前回エントリーはこちら。

HWスタートアップの見たCES① - bonx tech blog

今回は現地で見た印象に残ったプロダクトやブースの紹介とかと、訪問して思ったことの雑感となります。

印象に残ったもの

OSSIC

今回のCESで一番の発見だと個人的に思っていますが、平たく言うと 「超すごいVRヘッドフォン」です。(語彙がやばい・・・)

詳細はプロダクト紹介ページを見て頂ければと思いますが、 装着した人に最適化された立体音響を動的に再生してくれるヘッドフォン ですね。サンディエゴのスタートアップがやっているみたいです。日本のメディアで取り上げられているのをまだほとんど見たことがないですが、個人的には間違いなくVR/ARブームの中で、HMDの次に来るジャンルじゃないかと思います。

そもそも人間の聴覚は、左右に2つの耳があることで「どちらの方向から聞こえてきた音かなのか?」を感覚的に理解できるようになっています。これは、同じ音源から聞こえてきた音波であっても左右の鼓膜に波動として伝わるまでに生まれる微妙な違いによるものです。単純な音量の差よりも位相差によって生じるものだと考えられています。

  • 音源との相対的な角度・位置によって、頭の幅分だけ行路差が生まれ位相がずれる
  • 鼓膜に到達するまでに、顔や耳介・耳の穴の中に何回も反射するため、そこでも位相がずれる

さらに、空間的な広がりも聴覚で感じることが出来ます。目をつぶっていても、今狭い空間にいるのか開けた大空間にいるのかはなんとなくわかりますよね?これは直接耳に届く音ではなく、部屋の中を何回も反射する中で生まれる 「残響成分」 によるものです。残響の強さは空間を構成する素材にも寄るため、例えば人間は経験的に「今は非常に狭いコンクリート空間にいる」みたいなことも聴覚情報から理解できるのです。

まあ細かいことはおいておくと、「聴覚はVRの没入感を高めるために超重要」ということです。(もっと興味ある方は 「頭部伝達関数 とか バイノーラル録音 とかの言葉でググったりするとより理解が深まるかと思います)

一方、非常に難しい問題として「個人ごとに最適化をするのが難しい」というのがあります。先ほど書いたとおり、左右の耳で聞く音にどんな差がでるかは「頭の大きさ」や「耳の形」なんかに左右されてしまうため、誰でも同じように立体音響を体験することが出来ないのです。(なお、HMDの場合、目と目の間隔はそこまで大きな個人差がないため、比較的簡単に視差による立体感を生み出すことが出来ます)

そんななか!このOSSICは「個人ごとの違いをキャリブレーションして最適な立体音響を動的に再生可能」という謳い文句でした。詳細は省きますが、頭の形とかを計測しておくことで、装着している人に最適な位相差を計算し、センサーをつかって装着している人の向きに合わせて動的に立体音響を出力してくれるみたいです。これが実現できているのであれば、非常に素晴らしいプロダクトだと思います。実際HMDをかぶってOSSICを付けてVR空間をウロウロするというデモも体験しましたが、非常に精度の高い立体音響が実現されていて高い没入感を感じることが出来ました。昨今VRゲームを筆頭にAR/VR業界も盛り上がってきていますが、映像だけではなく音についてもVR化が出来るようになるのではないでしょうか。

現在preorder中で、Unityで実装も可能みたいなので、VRゲーム業界の方なんかは是非注目して頂ければと思います。僕も買って色々勉強するつもりです。

SONY Xperia Projecter

大手メーカーさんの商品で今更紹介するのも恥ずかしい感がありますが、これはすごかったと思いました。詳細はこちらの記事 なんかと見て頂ければ。 テーブルの上に15cmくらいのプロジェクターを置くだけで、そのテーブルが「タッチパネルスクリーン」に早変わりする!という商品です。コンセプト自体はよくあるかと思いますが、焦点距離の短さと画角」「台形補正の精度」「操作の応答性」 という3つのクオリティが非常に高く、さすがはSONYさんだなーと思わせるプロダクトでした。 f:id:bonx:20170203094348j:plain

実際にはもちろんタッチセンサーではなく、ジェスチャーセンサーと深度センサーを組み合わせて、プロジェクター手前の空間のどこに指先があるのかをトラッキングしているのかと思います。とにかく応答速度がはやく、技術に詳しくない人であれば普通にタッチセンサーを使ってるのでは?と間違えてしまうかも。

一方、プロジェクターが小さいので仕方ないのかもしれませんが、ある程度暗い空間でないとまだ使えないっぽかったです。もう少し出力が出るようになれば、部屋の中で普通に使えるくらいまで行くのではないでしょうか?普通に欲しいです(多分超高いんでしょうが・・・・)

Gibsonブース

大手メディアが報道しているのを見たことが無いですが、ギターメーカーのGibsonはCESで超デカイ単独パビリオンを出展しています(去年もあったし今年もありました)。なんと!出展してあるギター・ベース、全て時間無制限で試奏し放題。音楽好きにはたまらないブースとなっています。一応Gibsonブランドで出しているヘッドフォンなどの体験コーナーもあり家電製品の展示の体はとっていますが、、、

f:id:bonx:20170204113333j:plain

ステージがついていてスタジオ・ミュージシャンが四六時中ライブしていたり、お金を払えばブースの中でお酒まで飲めたりと、かなり尖ったブースになっていて面白いです。ステージ脇で酒飲みながら普通に盛り上がっているおっちゃんとかもいて、お前らCESに何しに来た感が満載。時間さえあればずっとここでまったりしてるんですが、会場が広すぎてあんまり長居できないんですよね。。。

余談ですが、同様に単独で非常にデカイブースを出しているのがBMWです。なんと新車の試乗会をCES期間中にやっていて、予約すればi7を運転してラスベガスを流すことも出来ます。そういう楽しみ方もあるのかもしれません。

超薄型テレビ

ここまで来るともはや板だよね(雑) f:id:bonx:20170204113838j:plain

雑感

プロダクトの栄枯盛衰

去年のCESは絶世のドローンブームで、中国メーカー中心に非常に多数のドローン企業が出展していました。DJIも非常にでかいブースを出していて、50台くらいのドローンを制御しながら飛ばすショーみたいなデモもやっていたのを覚えています。ところが、今年はどこ歩いてもドローンの展示を見ませんでした(会場全体あわせても4-5社みたか見てないか・・・)。ドローンを作ってた企業たちは今何を作っているんでしょうか・・・

また、同様に全然見なくなったのが曲面ディスプレイ。先ほど超薄型の話を出しましたが、そういえば去年は猫も杓子もちょっと曲がったTVを出していたように思います。

かたや車メーカーの展示を思い出すと、昨年は「自動運転」フォーカスだったのに対し、今年は「AI」フォーカスだったように感じました。例えば昨年のトヨタブースは、ミニチュアサイズの交差点をミニチュアの車5-6台がぶつからないように自動運転している、みたいな自動運転デモがメインだったのを覚えていますが、今年は コンセプト愛i ですからね。

f:id:bonx:20170204131306j:plain

IT技術を中心に技術進化が進む中で、商品のライフサイクルもどんどん短くなっているんでしょうね。同時に、うっかりトレンドを見逃す・読み違えてしまうと、次の年には一気に置いてきぼりになってしまうのかと思います。開発側の人間として、この辺の危機意識をしっかり保つ必要があるなー、と強く感じました。

とはいえ、ここまで一気にAlexaがくると誰が思ってたでしょうか・・・。いやーすごい。

f:id:bonx:20170204131407j:plain (わかりにくいですが、VWブースの中にあったAlexa体験コーナーです)

AirBNBUber と Googlemap と。

本当に便利すぎます。今回CES期間もその後のLA出張も含めて、宿は全てAirBNBで予約したんですが、AirBNBアプリから「宿まで行く」を選び、google mapで道順が表示され、「Uberでここまで行く」を選んだら配車までやってくれるという便利さ。恥ずかしながらまともにUberを使ったのは今回の出張がはじめてだったんですが、本当にすごいですね。しかも、もはやインフラとして当たり前になっていて、CESの会場でも空港でもタクシー乗り場と別に「Ride Share乗り場」がちゃんと用意されていて、そこにさえ行けばいいという風になっています。

日本にいる限りにおいてUberの凄さをなかなか体験できなかったので、個人的には非常にいい体験でした。VIVAシェアリングエコノミー。

CES期間のホテル事情

ラスベガスの一番メインの通りは(確か)Stripと呼ばれる通り沿いで、この周辺にカジノ付きの高級ホテルが多数並んでいます。ただ高いし予約が全然取れない。Uberドライバーさんが言っていましたが、観光地のラスベガスであってもCES期間が一番混むのだとか。直前でホテル予約取ろうとすると、一泊3万とか5万とかザラに出てきて焦りました・・・。

なので、今回はラスベガスから車で25分くらい走った郊外の地域に小さな一軒家を借りて、3人でシェアしました。一泊一人あたり5,000円もしなかったかな?移動は全てUberUber Eatsも使えるので食事にも困りません。夜に中心部に出かけて、いわゆるラスベガス観光ができないのが唯一の難点ですが、時差ボケあるなかCES会場を一日中歩き回ってとにかく疲れるので、観光する体力的な余裕もなく特に問題ありませんでした笑

f:id:bonx:20170204115312j:plain

とまった家の前でのプロダクトデザイナーM氏。

とにかくUberがどこでも拾いに来てくれるので、市街地から多少離れていても不便さは感じませんでした。安上がりに済ませようという方は、郊外の一軒家を探してみてもいいかも。割りとギリギリまでいろんな物件もあいてました。

お約束

CES探訪記を直接聞いてみたい方はぜひBONXオフィスに遊びに来てくださいねー!ビールがあなたをお待ちしています! いろんなポジションで人探しもしていますので、気になった方はぜひご連絡を!

www.wantedly.com

HWスタートアップの見たCES①

f:id:bonx:20170129232842j:plain

皆様明けましておめでとうございます!BONX CTOの楢崎です。 今更恥ずかしげもなくあけまして云々って書きましたが、新年一発目のご挨拶はあけましておめでとうであるべきなので仕方が無いですね。1月も終わりかけで新年一発目の投稿という更新頻度。今年はどうにかしたいなぁ(遠い目)。多分でんでんとは読まないです。

さてさて、前回の投稿から二ヶ月あき、さらにCES自体からも3週間近く空いていますが、今年も1/5〜1/8にラスベガスで開催されたCESに参加してきましたので、その模様でもお伝えできればと思います。なお、BONXは出展者ではなく純粋に参加者なので、CESの舞台裏等の話は一切なく、純粋に現地に参加してきた感想・肌感覚を共有できればと思います。

CES自体について

CESにおけるスタートアップの位置付け

日本の大手メディアでは「世界最大の見本市」というタイトルで紹介されることが多いですが、実は世界各地からスタートアップが多数ブース出展しているグローバルスタートアップの祭典という側面も非常に強いと思います。私が参加するようになったのは昨年からなのでその前の模様についてはわかりませんが、 L.V.C.C(Las Vegas Convention Center)Sans Expoという2つのメイン会場のうち、Sans Expoの一階部分は“Eureka Parkとよばれ、全てのブースがスタートアップだけで埋められています。大手メーカーブースは巨大な画面に建築物、きれいなお姉さんがデモしてくれたりと、いわゆる展示会っぽい雰囲気ですが(日本のCEATECなんかとはかけてるお金が桁違いなんでしょうが・・・)、Eureka Parkのブースはほぼ全企業がテーブル1つにパネル一枚程度、あとは自分たちのプロダクトだけ、という潔い展示の方法です。ただ、やはりどの会社もCESにかける思いがつよく、非常に熱意あるデモをいたるところで繰り広げています。また、大手メーカーの方や投資家と思われる方も多数来場しており、熱気がムンムンしていてお祭りみたいで非常に面白い空間です。自分がスタートアップ側だから、全会場回った中でももう一度行こうか考えたのは唯一Eureka Parkでした。

f:id:bonx:20170129232831j:plainf:id:bonx:20170129232939j:plain 会場のイメージはこんな感じで、各ブースが狭い分混雑具合もすごいです。 非常に話題になっているFOVEさんのブースも至ってシンプルな感じでした。

ハードウェア>ソフトウェア?

CESのイメージとしてハードウェアメーカーばかり、という風に思われがちですが、ソフトウェアやソリューションのスタートアップも非常に多数参戦しています。パット見た感じですが、特にヘルスケアアプリ、ビックデータ系、VR系なんかは多かったように思います。もちろんB2Cのプロダクトが中心なので、B2Bソリューションはあまり見ませんでしたが、ソフトウェア畑のひとも行ってみると思わぬ競合・パートナーが見つかって、面白いかも?(写真あんまり取らなかったな・・・)

国別スタートアップ選手権?

Eureka Parkの中はいくつかのコーナーに分かれていて、VRやWearableなどプロダクトカテゴリごとに別れているほかに国別コーナー というのがあります。ここを見ると各国のスタートアップコミュニティに対する熱の入れようがわかるような気がしますが、ダントツででかいコーナーを持っているのがフランスです。FrenchTechというタイトルをつけて、ハード・ソフト問わず20〜30程度の自国出身スタートアップを展示させていました。昨年来たときもフランスは非常に大きなコーナーを唯一持っており、政策的な取組も含めて、非常にスタートアップに投資をかけてきているのだと思います。その他、国別にコーナーを持っていたのは覚えている限りだとイスラエル、オランダ、韓国(と言うかSamsungのAcceralator?)だったかと思います。個人的にオランダにはスタートアップのイメージが全く無かったので少し驚きました(プロダクトとしてはデカイスピーカーくらいしか覚えてませんが・・・)

なお我らが日本はというと、SansExpoの2FにJETROブースと銘打っていくつかのスタートアップを出展させていました。ただ、やはり スタートアップはEureka Parkでこそ輝くのでは無いかと思います。世界中から来場する人全員がスタートアップならではのWowを期待している展示会というのはCESくらいしか無いのではないでしょうか? 仮に日本の政府関係者の方がこのブログを見られたら、 ぜひEureka ParkにJapanese Startupブースを!!! ここ以外だと大金をかけた大手メーカーブースの近くとなってしまうため、あんまりROI高くないかもしれませんよー。(そしてBONXもそっとおいておいて頂けるとなおありがたいですmm)

マーケットについて感じたこと

True Wireless Earphoneの勃興

さて、BONXは Hearable というプロダクトカテゴリーにくくられます。これは Hear(聞く) + Wearable(身につける) を組み合わせた造語で、平たく言えば耳に装着する音に関係したプロダクト、という意味です。日本だとまだあまり馴染みのないプロダクトカテゴリですが、海外だと非常に注目され始めております。この記事なんかを見とくとマーケットがわかっていいかも。

ただ、この「注目され始めてる」という言葉、今まで僕もメディアでしか知らなかったので実感としてはなかなか持ちづらかったのですが・・・・やばいよ、来てるよHearable。すぐそこまで。

間違いなくAppleのAirpodのせい(おかげ?)だと思うのですが、今回のCESは大手・スタートアップ問わず True Wireless Earphone(いわゆる完全ワイヤレスで耳栓型のイヤフォン)が至る所に出ていました。SONYさんも完全ワイヤレスタイプのプロトを出展されていましたし、その他にもネットメディアやクラウドファンディングでみたプロダクトの実機が多数出展されていました。 f:id:bonx:20170130000817j:plain  f:id:bonx:20170130000903j:plain

製品の機能としては音楽聴取が中心ですが、間違いなくこれらのプロダクトはHearable。今年は後年Hearable元年と呼ばれるような、次々新たなプロダクトが市場に出てくる年になるのかもしれません。BONXとしては、市場の拡大期でもありつつ競合候補が出て来るような、勝負の年になりそうですね。気合い入れなきゃ。

なお、昨年のCESであれだけ見たドローンは、今年は殆ど見られませんでした。中国系メーカーですらほとんどなかった気がします。何かが流行るということは、何かが廃れるということなんですねぇ。。。

家電は外で使う時代?

その他昨年からの変化として感じた点だと、アウトドア訴求のプロダクトが非常に増えていたように感じます。カシオさんのアウトドアスポーツ向けスマートウォッチやNew Balance X Jabra X Intelのトリプルコラボスポーツイヤフォンなど、ブースのパネル画像も含めてアウトドアを意識したものが増えていました。アンダーアーマーブースも去年に比べて心持ちデカくなってたし。やはり世界中健康志向がましてきているんでしょうか?元々GoProが切り開いたアクションカムがアウトドア家電の走りじゃないかと思いますが、今年はカメラ以外のジャンルでもアクションスポーツ向けが拡大するのかもしれません。Intelのブースでデモとして延々トレッドミルを走らせられるモデルさんは不憫でしたが、、、 f:id:bonx:20170130003916j:plainf:id:bonx:20170130003913j:plain 延々このモデルさんのバイタルデータ+走る姿を見るというマニアックなデモの様子。

Alexa Available in everywhere!

さきほどのヒアラブルの話につづいて音声関連ですが、今年のCESは何でもかんでもAlexa Availableでした。スマート冷蔵庫(液晶付き)もスマートテレビ(薄い)も新型スポーツカーも、誰も彼もAlexa Available。音声UXが来る未来は個人的にそう遠くないとは思っていましたが、デファクトまで決まるほど急激に進むとは驚きです。こちらについてはメディアに様々な記事が出ているので個人的には割愛。 f:id:bonx:20170130001948j:plain

今回はここまで。 勢いで①ってタイトルつけたから、もう一回このネタで頑張って書きます。。。

Android Akkaの話

はじめまして、BONX Androidエンジニアの麻植です。

さて、BONX Android版は6月にリニューアルをしまして、その前後でUIだけでなく内部の設計も変更しています。 まだまだ機種依存バグへの対策などは継続中で、一部端末をお使いの方にはご不便をおかけしていて申し訳ありませんが、βの頃から比べると通話品質などについて大きく改善しています。

具体的には内部設計をEvent Driven APIと、Thread / lockによる明示的な排他制御から、Akkaによるメッセージ駆動の設計に変更しました。

AndroidでAkka?

Androidエンジニアは、Akkaの名前を初めて聞かれる方も多いかもしれません。 Scalaエンジニアにはお馴染みのAkkaでも、Androidで使うとなると、どうやっていいのかわからず二の足を踏まれるかもしれません。

しかし、ユースケースによってはAndroidでもAkkaが有力な選択肢になりえますし、おそらく使用方法もご想像されてるより簡単です。

Akkaとメッセージ駆動

Lightbend社CTOのJonas Bonér氏が開発した、メッセージ駆動による並行・分散処理のtoolkitです。 Actorと呼ばれる並行処理の基礎単位と、Actor間のメッセージによる相互作用を基に設計します。

まずは雰囲気を掴んでいただくために、VoIPのクライアントアプリにおける、最も単純な再生側のActorの構成を見てみましょう。

TCP接続を管理するTCPActor、プロトコルに基づき解釈をするReceiveActor、音声バイト列のデコード処理を担うDecodeActor、音声PCMデータの再生を担うPlayActorから構成されます。 各々のアクターは、!関数を利用して、他のActorへメッセージを送ることができます。

※ ここでは解説しやすいようにTCPを使っていますが、一般的なVoIPではUDPが採用されることが多いでしょう。なお、akka.ioはUDPに対応しています。

class TCPActor(inetAddress: InetSocketAddress, receiveActor: ActorRef) extends Actor {
  override def preStart = {
    IO(Tcp) ! Connect(inetAddress, timeout = Option(5000 millis))
  }

  def receive: Receive = {
    case c: Connected =>
      sender ! Register(self)
      context become receiveAfterConnection(sender)
    /* 実際にはその他のエラーハンドリングなどが色々 */
  }

  def receiveAfterConnection(conn: ActorRef): Receive = {
    case Received(bytes) => receiveActor ! bytes
    case bs: ByteString => conn ! Write(bs)
    /* 実際にはその他のエラーハンドリングなどが色々 */
  }
}
class ReceiveActor() extends Actor {
  lazy val decodeTag = "decode"

  override def preStart = {
    context.actorOf(Props(classOf[DecodeActor]), decodeTag)
  }

  def receive = {
    case bytes: ByteString =>
      for {
        decodeActor <- context.child(decodeTag)
        byteArray <- checkProtocol(bytes)
      } decodeActor ! AudioPacket(byteArray)
  }

  //受信バイト列のparse
  private def checkProtocol(bytes: ByteString): Seq[Array[Byte]] = ???
}
class DecodeActor() extends Actor {
  private var decoder: Option[Decoder] = None
  lazy val playTag = "play"

  override def preStart = {
    decoder = Option(new Decoder())
    context.actorOf(Props(classOf[PlayActor], YOUR_SAMPLE_RATE, YOUR_BUFFER_SIZE), playTag)
  }

  def receive = {
    case AudioPacket(bytes) =>
      for {
        playActor <- context.child(playTag)
        dec <- decoder
      } playActor ! PCM(dec.decode(bytes))
  }

  override def postStop = {
    decoder.foreach(_.release())
    decoder = None
  }
}
class PlayActor(samplingRate: Int, trackBufSize: Int) extends Actor {
  private var track: Option[AudioTrack] = None

  override def preStart = {
    track = Option(new AudioTrack(android.media.AudioManager.STREAM_VOICE_CALL, samplingRate, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, trackBufSize, AudioTrack.MODE_STREAM, AudioManager.AUDIO_SESSION_ID_GENERATE))
    track.foreach(_.play)
  }

  def receive = {
    case PCM(pcms) => track.foreach(_.write(pcms, 0, pcms.length))
  }

  override def postStop = {
    track.foreach {
      tr =>
        tr.flush()
        tr.stop()
        tr.release()
    }
    track = None
  }
}
//何かしらのcodecのDecoder
class Decoder {
  def decode(bytes: Array[Byte]): Array[Short] = ???

  def release(): Unit = ???
}

case class AudioPacket(byte: Array[Byte])

case class PCM(data: Array[Short])
val system = ActorSystem("bonx")
val receiveActor = system.actorOf(Props(classOf[ReceiveActor]))
val tcpActor = system.actorOf(Props(classOf[TCPActor], yourInetAddress, receiveActor))

TCPActorでは、akka.ioパッケージを利用してサーバーとTCP接続し、byte列の送受信を管理します。実際のプロダクトではreceive関数ではエラー処理など他にも様々なことが必要なりますが、簡単のために端折っています。

ReceiveActorは送られてきたパケットを解釈し、後続のDecode、そして再生へ回します。 また、このActorは後述のDecodeActorとPlayActorの親Actorにしており、それぞれの子Actor内でエラーが起きた場合のハンドリングも行います。

DecodeActorでは、Actor内部でDecoderオブジェクトを初期化し、かつ隠蔽しています。 ここで重要なのが、Actorの実行モデルとして、基本的に1Actorインスタンスは1スレッドで逐次処理をするということです。 このため、DecoderがThreadセーフでなくても、明示的な排他制御が不要となります。

PlayActorでも、Actor内部でAudioTrackオブジェクトを初期化し、かつ隠蔽しています。 AudioTrackもDecoder同様にThreadセーフである必要がありません。

各々のActorが担う処理を終えた後、次のアクターへメッセージを送信します。このメッセージの後続処理に成功するかどうかは、基本的には送り手のActorは気にする必要がありません(Fire and Forget)。代わりにエラーが発生した場合などには親ActorのsupervisorStrategyに応じて自動的にRestartをさせたり、必要な場合にはTimeoutを設定することができます。

Actor間の通信も直接Actorインスタンスの扱ったメソッド呼び出しではなく、Actorへの参照を表すActorRefに対しメッセージを送信し、受信側のActorもメールボックスから逐次取り出すため、結合が疎に保つことができます。

これらのメッセージ駆動特徴により、複雑な並行処理になりがちな音声ストリーム処理でも、Actorの実行モデルが別途toolkitにて適切に管理されており、かつ不変なメッセージオブジェクトを利用しActorの内部構造を露出させない限りにおいて、明示的な排他制御から開放された見通しの良いコードを実現できます。

Why Akka?

Actorはメッセージに反応するReceive関数やライフサイクル管理のための関数のほか、重要なコンポーネントとしてmailboxを持ちます。

Akkaにおいては、Receive関数は当然ながら、mailboxもカスタマイズ可能です。 また、Actorの実行モデルであるdispatcherの設定を変更できます。

Androidでは端末スペックの向上により、オクタコアCPU、3GB RAMを積んだ端末も珍しくなくなりました。 しかしながら、まだまだサーバーに比べCPUリソースもメモリ量も少ない実行環境に配慮したmailboxと実行モデルの採用が必須です。

その点、Akkaは柔軟なカスタマイズが可能である点が優れています。

Androidで使う上での制限

Akkaのversion

Android SDKJava 6相当のJava bytecodeをdex(Dalvik Executable)に変換します。 そのため、Akkaは(Java 8向けである)最新版2.4系ではなく、2.3系を使う必要が有ります。

Proguard

AndroidScalaを扱う上では、Proguardは(少なくともプロダクションにおいては)必須です。 Akkaは application.conf や、Propsとリフレクションによるインスタンス化ししばしば行うため、Proguardと相性が悪いです。

実際のProguardの設定は、MacroidのAkka integrationの項目が詳しいでしょう。

それでは。

AWSのリージョン間でconsulを使用

チケイ株式会社改め株式会社BONXのスケーター齊藤です。
(社名が株式会社BONXに変わりました)
バックサイドディザスターはメイク出来てませんが、猛暑とゲリラ豪雨の隙を突いてスケート業務に勤しんでおります。

f:id:bonx:20160818193729g:plain

前回から大分時間が空いてますが、今回はconsulをAWSのリージョン間で繋いだ話を書きます。
弊社でのconsulの使いどころに関しては前回の記事を参照して下さい。

背景

  • BONXのUSでのサービス展開に備えてVoIPサーバを遅延対策の一つとしてUSリージョンにも構築することにしました。
  • APIサーバからVoIPサーバの検出にconsulを使用しておりVoIPサーバとconsulサーバ間で通信が必要なため、そこだけVPC間の接続が必要となり通信方法を検討。
  • リージョン間のVPCピア接続がオフィシャルでは未だサポートされてなくVPN接続で対応をすることにしました。

USのリージョン選定

VPN接続をするルーターの選定

  • 最初オフィスのルーターを使おうかとか冗談で話していたのですが、AWSで動かしている実績があるソフトウェアルータのVyOSを採用することにしました。

VyOS

  • 詳細はこちらを参照して頂くとして、設定などはログインしてゴリゴリとコマンドで実施する感じです。
  • AWS マーケットプレイスのものを使用してインスタンス起動をしましたが、v1.1.0には不具合がありv1.1.6にupgradeして使っております。
  • バージョンアップは以下の方法で実施しました。
vyos@VyOS-AMI:~$ add system image http://packages.vyos.net/iso/release/1.1.6/vyos-1.1.6-amd64.iso
vyos@VyOS-AMI:~$ reboot

その他EIPの付与やsource dest checkの無効化などを実施して準備は完了です。

構成

  • USリージョン以外にもリージョンを増やす可能性があり、その都度リージョンにVyOSを構築するのは運用が煩雑になるためTokyoリージョンをシステム構成的にはカスタマーゲートウェイとしてVyOSを構築することにしました(TokyoをRootにしたツリー型)。
  • 障害等でVPNが切断された場合はTokyoリージョンのVoIPサーバのみ検出するようにしているのでVPN切断してもサービス停止とは成らない仕組みとなっております。

構築時に気を付けたポイントなど

  • ap-northeast-1とus-west-2のVPCを繋ぐのに同一のCIDRは指定出来ないので、ap-northeast-1は172.16.0.0/16としus-west-2は172.17.0.0/16VPCを構築。
  • us-west-2のセキュリティグループで8301(TCP/UDP)を172.16.0.0/16から許可する
    consulが通信で使用するポートでこれだけ開けておけば要件を満たせる(満たせた)
  • VyOSにVPNの設定を反映するのに、vyos_config.pyスクリプトを使用することで手作業の負荷を軽減させました。

雑感

  • たまにVPNが落ちるので(BGPで冗長化しているのに同時に落ちたりする)クリティカルなサービスやトラフィックがあるサービスには使いたくないが、consulでのサーバ検出程度であれば十分に役立っております。
  • VyOSを冗長化する方法を検討しておりますが、今現在は手動対応可能な範囲なので当面はアラートが飛ぶ仕組みだけ作り運用をする様にしております。
    VyOSのtask-schedulerにダウン検知したらrestart vpnコマンドを走らせる簡単なスクリプトを仕込んでみたが、上手く起動しないことがあり時間を見て対応したいと考えております。
  • AWSが早くリージョン間のVPCピア接続を対応してくれればなーー

最後に

現在、世界的クラウドファンディングサイト「Indiegogo」で実施中のBONXのキャンペーンに、たくさんのご支援をいただき、ありがとうございます。
キャンペーンは引き続き進行中です!!
https://www.indiegogo.com/projects/bonx-outdoor-sports-group-talk-technology/x/14601326#/

DIYで風洞試験装置を作っている話

どうも皆様、CTOの楢崎です。前回の更新から少し時間が立ってしまいましたが、いかがお過ごしでしょうか。僕はついに念願のドロップイン→インターフェイキーの一連の動きが出来るようになりました。次回更新までにテールロックを練習しようと思います。

 

さてさて、今回はハードウェアスタートアップならではの取り組みについてご紹介できればと思います。

 

BONXのハードウェア的なポイントのうち、大事な要素として「複合的な風切音対策」というものがあります。スキーやロードバイクなど、アクションスポーツは時速数十キロというスピードが出ることがザラです。これに対しBONXは、特殊なハードウェア構造、風切音を防ぐパーツの埋め込みなど、様々な工夫で風切音対策に取り組んでいます。

ただ、開発している中でぶつかった壁が「実際風速何mの時にどの程度の性能が出ているか」を定量的に検証することでした。これまでは気合でロードバイクで走って会話が成立するか検証するといったユースケースを軸にした検証がほとんどでしたが、一定のスピードで長時間走れるわけもなく、また向かい風の状況等も刻々と変わるため、定量的な実験には向きませんでした。なにより体力しんどいし。

 

というわけで、今回我々はお手製の風洞実験設備を開発し、体力のないエンジニアでも気軽に風洞試験をできる環境を構築しました!

 

f:id:bonx:20160619201653j:plain

どうですかこのDIY感。スタートアップならではですね。

かなりわかりづらいですが、簡単に仕組みを説明すると、緑色のブロワーから高速の風が灰色のパイプを通って透明なアクリルの中に送られます。で、パイプ経由で送られた風を受ける位置にBONXをセットしておきます。これによって、ブロワーから送られた風が細い管を通って加速し、かなりの風速でBONXを直撃するわけです。ちなみにブロワーとは、公園の落ち葉を風の力でふっとばすあいつです。

 

f:id:bonx:20160619201922j:plain

で透明なアクリルの内部には、BONXだけでなく風速計も一緒に仕込まれています。なので、実験装置内部にどの程度の風が吹いているかをリアルタイムに測定することが可能。風速の測定と同時に、内部に仕込んだBONXのマイクから直接音を拾って録音用のスマホに出力。さらにアクリルの実験ケースをモフモフした吸音材でぐるっと囲っておき、余計な音が実験室に入らないようにしておきます。

これらによって、ブロワーのモーター駆動音など余計なノイズを吸音材で排除しつつ、一定速の風を風速を測定しながら流し、その時にどんな音をBONXが拾うかをすべて録音することが可能に!見た目のチープさはともかく、かなりスバラシイ実験設備と言えるでしょう!

 


・・・とまあテンションあげつつ組み上げたわけですが、初めてテストしたところブロワーの風が強すぎて、最弱でも風速125km/hというモンスターマシンが出来上がってしまいました。BONXはモータースポーツ向けギアではないので、あまりにオーバースペック。というわけでもう少し風速を抑えられるように修正。

 

f:id:bonx:20160619203606j:plain

わかりづらくて恐縮ですが、3Dプリンターで作ったブロワーとパイプの接合部に穴を開け、風の一部が外に逃げるようにしました。またパイプ内部に綿を詰めて、風の通りを悪くしました。ここまでやって、ようやく風速40-50km/hを安定して出せるようになりました。

 

 

以上、とてもITスタートアップと思えない日曜大工感満載の写真ばかりでしたが、なんとかいちいち自転車を走らせなくても風洞試験ができる環境が整えられました。この実験器具を使った性能アップはまさに現在取り組んでいますが、なんとかいい結果に繋げられればなーと思っています。

 

 

・・・とはいえユースケースを考えると、ロードバイク走行中に風速測定が出来ることも大事なので、自分のロードバイクも実験ができるよう、簡単に改造しました。

 

f:id:bonx:20160619204342j:plain

 

ロードバイクのハンドルにセルフィー棒を括りつけ、その先端に風速計がついています。見た目のダサさはともかく、これさえあればいつでも向かい風込みの風速がわかるので、外を走りながらの実験にも最適。決して走行中の自分を自撮りしたいわけではありません。

 

以上、まだまだ試行錯誤中ではありますが、実験装置をDIYで作る話をお送りしました。日本全国で風洞試験がやりたかったけど出来なかった皆様の一助になれば幸いです。

 

 

さてさて、そんな実験装置の開発も含めて、BONXのハードウェア開発に関わっていただけるエンジニアの方を引き続き募集しています。興味ある方は気軽にポチッと!

 

メカニカルエンジニア | チケイ 株式会社 | IT/Web業界の求人・採用情報に強い転職サイトGreen(グリーン) | 2016/04/18 10:58:24更新 | id:39860

 

BONXはconsulを使ってます

はじめまして、チケイのスケーター齊藤と申します。
昼食前に駒沢公園のスケートパークに滑りにくのが日課となっております。
今月は小さいクウォーターパイプでバックサイドディザスターを決めるのを目標に日々汗を流しております。

f:id:bonx:20160518103537g:plain

  

今日は雨のためスケートに繰り出せなかったのでBONXのインフラで使用しているconsulに関しての記事を書いてみることにしました。

consulとは、Service Discovery and Configuration made easy. (サービスの検出と設定を容易に行える仕組み) 

www.consul.io

 

以下、このconsulをBONXでどう活用しているかを書きたいと思います。

 

BONXのインフラ概要

AWSにどっぷり浸かっています。
AWSで稼働させているのは、主にサービスで使用しているAPIサーバ,VoIPサーバの2つとwebサイトのbonx.coです。
APIサーバはRoRVoIPサーバはGO言語でスクラッチビルド。
deploy環境を統一することで運用負荷を減らすためにAPIサーバVoIPサーバはElastic Beanstalkに乗せており、webサイトはS3にコンテンツを置いて素のEC2インスタンスから参照させています。
全体的な構成はRDS,Elasticacheなどを使用した一般的な感じとなっております。

APIサーバはユーザ情報やルーム情報といった会話に必要な機能を担い、VoIPサーバは通話部分の機能を担っております。

BONXでのconsulの使いどころ

  •  APIサーバからVoIPサーバを検出(抽出)する
    VoIPサーバのscoreを保持しておりルーム数が一番少ないVoIPサーバを検出し新規ルーム作成時に割当を行う
    マルチリージョンでVoIPサーバを稼働させるときは、これにGeoIPの判定が加わります
  •  VoIPサーバのダウンを検知してフェイルオーバーする
    バッチサーバからconsul watchを起動してVoIPサーバのダウンを検知したらフェイルオーバータスクが起動

consulの構成

  • serverは2台で1台は専用サーバでもう一台はバッチサーバに相乗りをさせている
    推奨サーバ数は3台ですが今現在は2台で稼働
  • APIサーバ、VoIPサーバがclientとなる
  • VoIPサーバの検出ができるように、VoIPサーバはサービス登録を行っている
    AWSのマルチリージョンにも対応させるためにtagsにリージョンを入れて割当時にフィルタリング出来るようにしている
    checksにはVoIPサーバの死活監視コンテンツを入れる

    gist5eb39c2d7f0a2813b2a286ae2838d383

 

所感

BONXの肝となる通話を担うVoIPサーバの検出と死活監視をconsulを使うことで比較的に簡単に行なえ、ダウン検知も素早く弊社のサービスを運用するには今現在最適なソリューションとなっております。

まだまだ使い倒してはおりませんが、今後はもう少し踏み込んでサービスに役立てていけると思っております。

 

最後に

チケイは開発チームにジョインしてくれる方を継続的に募集しております!興味がある方はぜひ一度話を聞くだけでもー!ソフトウェアエンジニアだけでなく、ハード側も含めて多数の職種を募集中です!

チケイ 株式会社の採用/求人 | 転職サイトGreen(グリーン)

jobs.forkwell.com

jobs.forkwell.com