2013年6月18日火曜日

かくれ音システム 実測結果


かくれ音システムは屋外でどれくらいまで音が届くのかを実測してみた。

まずは再生環境(スマホ+スピーカーを地べたにそのままってどうよと思いつつ ・・ )


ちなみにボリューム設定は約40%の位置に
これ以上ボリュームを上げると、音がひずんで「ういーん」という音が聞こえてくるんです。




 では実際にスマホを片手にテストしてみました。

まずはPanasonic P-01D
距離が離れると、スマホのマイクをスピーカーに向けないと厳しいです。
(だってヤフオクで新品未使用が5000円という値段に釣られたスマホですし ・・ )


でもこんな感じの場所で3秒ほど待機すると、見事受信できました!

引き続きNEC MediasTab N-08D
Panasonicは超えるかなと思ってましたが、これまさに余裕!

結局この位置でスマホのマイクをスピーカーに向けると3秒ほどで受信できました。

実際の位置関係をGoogleMAPより調べるとこうなりました。
以下の写真はGoogle Mapとストリートビューから抜粋した位置関係です。







Panasonic P-01Dでも20m以上!  MediasTabだと40m以上です。
Androidスマホのマイク性能やマイク指向性などによって到達距離は異なることは当然ですが、この結果には自分でも驚きです。

※ ただしスマホのマイク性能や周りの状況によって伝達距離が大きく異なると予想されるため、あくまでも伝達距離は10m程度という仕様にしておきます。

ちなみにこの間にペットの犬が3匹いますが、まったく吠えることありませんでした。
犬に「聞こえた?」って聞いても無視されてしまいました。

かくれ音アプリのダウンロードはこちらから




2013年6月17日月曜日

かくれ音システム

ひさしぶりのブログ更新。
ずっと音を使ってのデータ伝送「かくれ音(かくれおん)」システムの開発を行っていました。

テーマはまさにシンプル「音で伝える」です。



人間には聞こえない音域(18K~20KHz)の音を出し、スマホのマイクで聞き取ります。
スマホ毎に異なるマイクの指向性などをどう克服するか、本当に苦労しました。

現在Google Playに正式リリースする前段階で、最終テストを行っています。
iPhone版はまだ追いついていません(残念)。

こんな使い方を考えています。



他にももっといろいろな使い方ができないかと、知恵をしぼっています。


聞こえない音を再生するスピーカーはONKYO社製、GX-70HDを推奨機種としています。
大きさ、再生周波数、出力パワー、そして値段でベストな機種と判断しました。


http://www.jp.onkyo.com/pcaudio/poweredspeaker/gx70hd/index.htm
(現在Amazonで1万円前後です)

興味がある方はお気軽に連絡ください。
実機デモ、打ち合わせなど対応可能です。

基本的な販売対象は「聞こえない音データ(wavファイル)」と「サーバー使用費」です。
Androidアプリは無料で公開しますが、有料でカスタマイズアプリ開発なども対応します。
またAndroidアプリの聞き取り処理部(オブジェクト)部を提供し、別途アプリに組み込みなども対応します(費用は別途相談)。


かくれ音アプリのダウンロードはこちらから




[2013/06/19追記]
たとえばこんな使い方(メモ書き)

大きな立体駐車場内にあちこちスピーカーを仕込んでおき、GPSの代わりに使用する。
それを使用して、どこに車を止めたか指示するアプリが可能。
・・ 店のサービス向上になっても、売上の向上は難しいかな?

2013年4月10日水曜日

Webカメラ画像のリアルタイム表示


Webカメラの映像をAndroidスマホで表示するデモを何度か受けたことがある。
その際いつも指摘されることが、スマホ側での画像の遅延。

動作環境は以下のようなイメージ。

USBカメラの画像は数秒遅れでAndroid端末に表示される。
ストリーミングソフト=WebCamXPでは3~5秒、YawCamで2秒程度。

USBカメラとAndroid端末が離れている場合は問題ないんですが、デモなどでは絶対指摘されてしまいます。
「この遅れはなんとかならないのか ・・ 」と。

確かにそうなんですよね。
車のバックモニタなどを想定した場合、2~3秒遅延があれば「ゴツン!」間違いなしです。

ストリーミングソフトの自作を想定して、どこまでリアルタイムに近づけるか調べてみた。

USBカメラをDirectShowなどで取り込む場合、取り込みに必要な時間は33mS。
 1/30秒での画像取り込みですね。
 取り込んだ画像サイズは9216154バイト(640*480*3+α:ヘッダ分)でした。

この画像(Bitmap)をメモリ上でjpegに変換した場合(品質40%)
 処理時間に約31mS
 出力画像サイズは25871バイト(原本の約1/35)でした。

 ※ ファイル出力していません。あくまでもメモリ上だけの展開です。

あとはWifiでの転送速度とAndroidの受信~表示の遅れ。
これはJNI(C++)などを使ってがんばるしかないです。

実際には1秒に10枚程度の画像でパラパラ漫画的に、遅延は100mS程度って感じでしょうか。
(これでも2メガBPSの通信速度が必要で、3G回線だととっても無理)。

これで実用レベルに達するなら、DirectShowでの画像取り込み~Jpeg変換~Androidへの転送ってのが実現できそうです。

 MotionJPEGでのパラパラ漫画ストリーミングです。
 最近はやりのストリーミングもリアルタイムには厳しいので ・・

2013年4月8日月曜日

Webカメラの画像表示(Panasonicカメラ)


1年ほど前に調査していたネタ。

PanasonicのWebカメラをAndroidで表示したい。
たとえば ・・
株式会社リネット様
http://180.131.124.38:8101/CgiStart?page=Single&Language=1

株式会社SimPro様
http://simpro.mydns.jp:84/CgiStart?page=Single&Resolution=640x480&Quality=Standard&Mode=JPEG&RPeriod=65535&Size=STD&PresetOperation=Move&SendMethod=1&Language=1

PCのブラウザでは動画を表示できますが、Androidのブラウザでは表示できません。
そしてまたAndroid版FireFoxだけは表示できるのも謎です。
ではこれらの映像をAndroidのアプリで表示するにはどうしたらいいでしょうか?

※ HTMLコードばかりで長くなってしまいますが、ご容赦ください。
 追いかけていく ポイントはこれらの中のほんの少しだけなので。


■ 上記ページのHTMLコードを見てみよう。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Frameset//EN">
<HTML>
<HEAD>
<META HTTP-EQUIV="expires" CONTENT="0">
<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
<META HTTP-EQUIV="Cache-Control" CONTENT="no-cache">
<META NAME="ROBOTS" CONTENT="NONE">
<META NAME="ROBOTS" CONTENT="NOINDEX,NOFOLLOW">
<META HTTP-EQUIV="Content-type" CONTENT="text/html; charset=Shift_JIS">
<TITLE>Network Camera</TITLE>
</HEAD>
<FRAMESET border=0 frameSpacing=0 rows=30,8,* frameBorder=0>
<FRAME name=bar src="CgiTagMenu?page=Single&Language=1" scrolling=no NORESIZE>
<FRAME name=hrbar src="BarFoot.html" scrolling=no NORESIZE>
<FRAME name=body src="ViewerFrame?page=Single&Language=1">
</FRAMESET>
</HTML>
 
これだけ? トップページには確かにこれだけ ・・ 3つのフレームがあるだけです。


■ それではこの内部を追いかけてみる。

映像が含まれていると思われる場所のソース
ViewerFrame?page=Single&Language=1をクリックして出てきたソースを見てみる。

 
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Frameset//EN">
<HTML>
<HEAD>
<META HTTP-EQUIV="expires" CONTENT="0">
<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
<META HTTP-EQUIV="Cache-Control" CONTENT="no-cache">
<META NAME="ROBOTS" CONTENT="NONE">
<META NAME="ROBOTS" CONTENT="NOINDEX,NOFOLLOW">
<META HTTP-EQUIV="Content-type" CONTENT="text/html; charset=Shift_JIS">
<TITLE>ViewerFrame</TITLE>
<SCRIPT Language="JavaScript">
<!--
if(top.location.href.match("/CgiStart") == null) {
 top.location.href = "CgiStart?page=Single&page=Single&Language=1";
}
// -->
</SCRIPT>
</HEAD>
<FRAMESET COLS="123,*" FRAMEBORDER=0 BORDER=0 FRAMESPACING=0>
  <FRAMESET ROWS="26,*">
 <FRAME SCROLLING=no SRC="nphControlCamera?Direction=&Resolution=640x480&Quality=Standard&Size=STD&Width=640&Height=480&NewPosition.x=&NewPosition.y=&PresetOperation=Move&Language=1&RPeriod=0" NAME="Message">
 <FRAME SRC="nphPanTiltControl?Resolution=640x480&Quality=Standard&Size=STD&PresetOperation=Move&Language=1&RPeriod=0" NAME="Control">
  </FRAMESET>
  <FRAMESET ROWS="24,*">
 <FRAME SRC="CgiTitle?Resolution=640x480&Size=STD&Sound=Enable&Language=1" NAME="audio" NORESIZE SCROLLING="NO">
 <FRAME SRC="ImageViewer?Resolution=640x480&Quality=Standard&Size=STD&PresetOperation=Move&Data=0&Frame2=PanTilt&Type=&Language=1&RPeriod=0&Sound=Enable" NAME="right">
  </FRAMESET>
 <NOFRAMES>
  <BODY> </BODY>
 </NOFRAMES>
</FRAMESET>
</HTML>
 
映像データと思われるものはまだない。
でもAndroid版FireFoxでは表示されるので、これらのコードをたどっていくと映像データが存在するはず!
 
■ もう少し追いかけてみよう。
 上記コードの中から、この部分をクリックして出てきたソースを見る。
 ImageViewer?Resolution=640x480&Quality=Standard&Size=STD&PresetOperation=Move&Data=0&Frame2=PanTilt&Type=&Language=1&RPeriod=0&Sound=Enable

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Frameset//EN">
<HTML>
<HEAD>
 <META HTTP-EQUIV="expires" CONTENT="0">
 <META HTTP-EQUIV="Pragma" CONTENT="no-cache">
 <META HTTP-EQUIV="Cache-Control" CONTENT="no-cache">
 <META NAME="ROBOTS" CONTENT="NONE">
 <META NAME="ROBOTS" CONTENT="NOINDEX,NOFOLLOW">
 <META HTTP-EQUIV="Content-type" CONTENT="text/html; charset=Shift_JIS">
 <TITLE>ImageViewer</TITLE>
 <META HTTP-EQUIV="Refresh" CONTENT="1800;URL=ImageViewer?Resolution=640x480&Quality=Standard&RPeriod=3&Size=STD&Sound=Enable&Language=1">
 <META http-equiv="Content-Script-Type" content="text/javascript">
 <META http-equiv="Content-Style-Type" content="text/css">
</HEAD>
<BODY BGCOLOR="#EFEFEF" TEXT="#ffffff" 
      LINK="#ffffff" VLINK="#ffffff" ALINK="#ffffff" TOPMARGIN="0" LEFTMARGIN="0" MARGINHEIGHT="0" MARGINWIDTH="0">
<!-- ** view ** -->
<FORM METHOD="POST" ACTION="nphControlCamera" TARGET="Message">
<INPUT TYPE=hidden NAME="Width" VALUE="640">
<INPUT TYPE=hidden NAME="Height" VALUE="480">
<INPUT TYPE=hidden NAME="Language" VALUE="1">
<INPUT TYPE=hidden NAME="Direction" VALUE="Direct">
<INPUT TYPE=hidden NAME="PermitNo" VALUE="-2104609529">
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0>
 <TR><TD title="マウスでクリックした位置を画面の中央に移動します。"><INPUT TYPE=image NAME="NewPosition" SRC="nphMotionJpeg?Resolution=640x480&Quality=Standard" WIDTH=640 HEIGHT=480 BORDER=0></TD></TR>
</TABLE>
</FORM>
<TABLE BORDER="0" CELLSPACING="0" CELLPADDING="0" style="padding-left: 10px;">
<TR><TD HEIGHT=1></TD></TR>
<TR><TD HEIGHT="24"><FONT Face="Arial" Style="font-size: 11px;" COLOR="blue">音声が聴こえないときはこちらをクリックしてください</FONT></TD></TR>
<TR><TD><A HREF="http://panasonic.biz/netsys/netwkcam/support/technic/sound/index.html" target="_blank"><FONT Face="Arial" Style="font-size: 11px;" COLOR="blue">http://panasonic.biz/netsys/netwkcam/support/technic/sound/index.html</FONT></A></TD></TR>
<TR>
<TD HEIGHT="24">
      <FONT FACE="Arial" STYLE="font-size: 11px" COLOR="black">
        <B>IPv4
         で動作中</B>
      </FONT>
    </TD>
  </TR>
</TABLE>
<!-- ** /view ** -->
</BODY>
</HTML
 
 
!!!! SRC="nphMotionJpeg? ・・・" というのが気になりますね!!!
 
ここをクリックしてみましょう。
 
■ こういう表示になります。
 
--myboundary
Content-length: 31015
Content-type: image/jpeg

リ�#タ� ン      � ��������������������ロ�C� 
       ( 
 (H0  0H`H&(6M`phX::JhpplhXhjpppjoppzzzzz€€€€€€€€€€ロ�C       0  2dB8Dddddddddddddddddddddddddddddddddddddddddddddddddddタ�   � €  "�      ト� ��        ��������         
 ト�オ �           �� }   �    !1A  Qa "q 2¢。 #Bアチ Rム�$3br� 
 
     : 以下、文字化けした記号が続く。
 
やっとたどり着きました! 
文字化けした記号部分を31015バイト分受信して、そのデータをjpeg表示したらカメラ画像が出てきます。

■ Androidアプリで実現するには、こういう手順です。
 
 PanasonicカメラのHTMLコードから上記のコードを追いかけ、SRC="npnMotionJpeg" というキーワードまでたどっていく。
  Content-lengthで取得できるバイト数分のメモリ領域を確保し、その内部に受信データを蓄積する。
 蓄積したデータをjpeg画像表示~メモリ解放を行う。
 
 もう一度ここにアクセスすると、バイト数、データ内容が変化しているため、メモリ確保、jpegデータ取得、jpegデータ表示、メモリ解放を繰り返す。
 この方法でPanasonicカメラの動画表示ができます!
 
 ここまで追いかけて表示してくれるAndroid用ブラウザはFireFoxだけだったんですね。 
 やり方がわかれば実現はさほど難しくありません。

 是非興味がある方、お試しください。
 現段階では都合上ソースの公開は控えておきますが、興味のある方は連絡ください。

 





2013年4月5日金曜日

Windowsでのリアルタイム処理(2)


昨日に引き続き、Windowsでのリアルタイム処理をテストしてみた。

今回のテスト環境は
 CPU Core-i3-2330M
  メモリ 4ギガ
 Windows7 Ultimate 64bit版 ServicePack1
 開発環境 VisualStudio 2008

ソースは変更せず、こちらの環境で再ビルドを行い実行してみた。

下図はバックグラウンドでファイルコピーを行いながら、500マイクロ秒周期での呼び出しができているかを確認している状態を示している。




ほぼ500マイクロ秒で動いているが、途中1600マイクロ秒(1.6ミリ秒)、793マイクロ秒などがちらほら出現している。

※ ディスクコピーを行っていない状態では、500マイクロ秒近辺で安定している。
 
昨日の結果から、単純にハードウェア(CPU)のパフォーマンスによる差だけではなさそう。
CPU使用率が100%に達していないため、強制的にタスク切り替えなどが発生し、そのための遅延のような気がする。


WindowsのOS内部まで入り込んで、リアルタイム制御を実行するというものもあるが、そこまでシステムに入り込まなくても、ある程度リアルタイムを実行できる方法はないものだろうか ・・・

もう少し調査してみよう。

2013年4月4日木曜日

Windowsでのリアルタイム処理


RTL(Real Time Linux)のようなリアルタイム処理がWindowsでできるのだろうか?

テストプログラムを作って確認してみた。

実行マシン
 CPU = Core-i7 870 2.93GHz
  メモリ = 4G
   Windows8 Pro with Media center 32bit版

開発環境 VC++/Express2008




約500マイクロ秒周期でクロック値をバッファリングできていることが表示された。
単純にみると、RT-Linuxと同等のことができている。

ただし背後に隠れているからくりは存在しているのだが。
途中ディスクアクセスなどが発生したらどうなるのだろう ・・・ 

お客さんからはいつもミリ秒単位できちんと関数を呼び出してなどと言われるが、そのたびにWindowsではOSが保障してないから難しいんですよと回答していた。

システム構成、ハードウェア構成を考えたら、こいつは利用できるかもと思う。
もうしばらく落とし穴などを調べてから、提案してみよう。

というわけでソースの公開はもう少し熟考してから(する? しない? 現状不明)。

興味がある方は声をかけてください。

2013年4月1日月曜日

AIDL呼び出しの処理時間

Androidアプリ間連携などで使用できるAIDLの処理時間を調べてみた。

テストに使用したタブレットはNEC N-08D
http://www1.medias.net/jp/sp/n08d/

テストの動作イメージを下図に記載する。

   処理1) AIDL経由でバッファ転送処理を100000回繰り返し呼び出す。
   処理2) AIDL経由でバッファ転送処理を1度のみ呼び出し、内部で10000回繰り返す。

計測した処理時間は以下のようになった。
         処理1    処理2    AIDL実質呼び出し時間
1回目  34.702秒   0.154秒   0.34548ミリ秒
2回目    34.028秒   0.151秒   0.33877ミリ秒
3回目    34.034秒   0.176秒   0.33858ミリ秒
4回目    33.914秒   0.147秒   0.33767ミリ秒
5回目    33.882秒   0.176秒   0.33706ミリ秒
6回目    33.596秒   0.152秒   0.33444ミリ秒
7回目    33.503秒   0.149秒    0.33354ミリ秒
8回目    34.122秒   0.148秒   0.33974ミリ秒
9回目    33.842秒   0.146秒   0.33696ミリ秒
10回目   33.737秒   0.149秒   0.33588ミリ秒

※ AIDL実質呼び出し時間は(処理1時間-処理2時間)/100000で算出した。

この結果から、AIDL経由での呼び出しには約0.33ミリ秒の時間が必要なことがわかる。
一度関数呼び出すだけで0.3ミリ秒かかるということは、Javaだからということを考慮してもかなり遅い。

そこでもう少し考えてみた。
バッファ転送処理はJNI(C++)で128バイトのデータ転送を行っている。
転送のためにGetByteArrayElementsとReleaseByteArrayElementsを呼び出しているため、AIDL呼び出しではなく、実はこの関数ここで時間がかかっているのでは ・・ ?

バッファ転送処理の前後で GetByteArrayElements / ReleaseByteArrayElements関数の呼び出しをなくした処理でテストしてみた。

計測した処理時間は以下のようになった。
         処理3    AIDL実質呼び出し時間
1回目  31.241秒   0.31241ミリ秒
2回目    29.703秒   0.29703ミリ秒
3回目    31.627秒   0.31627ミリ秒
4回目    30.118秒   0.30118ミリ秒
5回目    29.386秒   0.29386ミリ秒
6回目    29.331秒   0.29331ミリ秒
7回目    29.221秒   0.29221ミリ秒
8回目    29.567秒   0.29567ミリ秒
9回目    29.377秒   0.29377ミリ秒
10回目   29.992秒   0.29992ミリ秒


※ AIDL実質呼び出し時間は処理3時間/100000で算出した。

これらの結果から128バイト分のGetByteArrayElements/ReleaseByteArrayElementsには0.03ミリ秒程度かかっていること、そしてAIDL呼び出しには0.3ミリ秒が必要ことがわかる。

やはりAIDL呼び出し処理の負荷はかなり大きいことを前提でシステム構築する必要がありそうだ。



実際のソースコードはここに置いている。
ソース一式はこちらから

 fifo.zip : バッファ転送を行う処理環境一式
 fifotest.zip : AIDL呼び出し側テスト環境一式


 4月1日に計測したが、エイプリルフールネタは含まれていない(まじめ)。