Alexaアプリ開発:Lambdaからネットワークにアクセスできない!?

Amazon Echoを購入したので自分でちょっとしたAlexaアプリを作って遊び始めました。Alexaアプリではバックエンド側にAmazon Lambda上でNode.jsのコードを作成しています。
Lambda上からネットアクセス(http get)を使用としたのですが上手く動作しません。実行時のエラーなどは出ないのですが、ネットワークアクセス部分の出力がログに記録されません。

色々試しているうちに、ネットワークへのアクセス部分のコードの直後にthis.emit(’tell…’)を実施するのではなく、ある程度の時間を待ってからthis.emitを実施することによってログにネットワークアクセスの結果が書き込まれるようになりました。
個人的な理解ですが、AlexaからのTriggerで実行されるLambda関数自体がCallbackでその中にネットワークアクセスのコードがResponse処理のCallbackを設定しているため、this.emit()がAlexaから起動されたCallback自体を終了してしまい、ネットワークアクセス部分の終了前にLambda関数全体が終了してしまうだと思います。
ネットワークアクセスの結果をチェックするループにいれて結果をみてからthis.emit()の内容を変化させるのが好ましいロジックかなぁと思います。

 

コード例1:

 

コード例2:

 

新PCでのXwindow環境の設定

会社の業務用のPCが新しくなり、また環境の引越しです。
少し苦労したのがX-Winodw
CygwinのX11のパッケージをインストールして、Windows FirewallにもWin.exeを設定して動くはずと思い、PC側でX-serverを起動。Unix側でclientを実行するのですが待てど暮らせど画面が現れません。
Wiresharkで確認するとポート6000にパケットは来ていますがPC側のX-serverが反応していません。netstat -aで確認するとポート6000がListen状態になっていません。
どのVersionから変わったのかはわかりませんが、CygwinのX-serverを立ち上げる際に、
Start MenuのCygwin-XからXWin Serverを選ぶとX-serverは立ち上がりますがポート6000にバインドしないみたいです。
結局、XLaunchを実行するとポート6000がオープンされPC上のX-clientが立ち上がりました。
X-Windowの設定の説明はどこかに再度アップしておこうと思います。
忘れないようにね……

 

AWS S3 bucketのdelete

このサイトの諸々のバックアップをdailyでS3に保存しています。
毎日バックアップしていますので、2週間も何もしないとフォルダ数も増えますし、最近はデイリーでのバックアップ量も増えてきましたのでS3上での使用領域も心配になります。1週間に1回程度適当にパージを手動で実施していたのですが、これを自動化するためにjavaでツールを作りました。
私のバックアップの仕組みは毎日、PreFixとしてbackupに日付の文字列をつけ、さらにUUIDを生成したstringをバケット名として作成し、その日のバックアップデータをそのバケットに格納する仕組みです。
ですから、パージの仕組みもS3上でバケット名をサーチしながら、バケット名からバックアップの日付を確認し、条件にマッチすればそのバケット内のオブジェクトを全て削除した上でバケットも削除という仕組みです。
そのようなツールを作成してバケットとオブジェクトの削除を実施しました。削除自体はうまく動作したようでGUIのManagement Consoleでは該当バケットが削除されているのを確認しました。

しかし….バケットの削除を実行したのち、似たようなツールでS3上のバケット及びオブジェクトの検索をおこなったところ以下のようなエラーが出てしまいました。

[root@ip-10-162-38-78 purger]# ./dailyPurger.ksh
===========================================
Getting Started with Amazon S3
===========================================

Listing buckets
Purge Threshlod PreFix: backup20130113

 - backup20120808-8720d155-036e-4aaa-8515-c89a22821d3d
..older than Threshold…
..Neither MMD0/MMD5…Candidate for purge
..Listing objects in this bucket
Caught an AmazonServiceException, which means your request made it to Amazon S3, but was rejected with an error response for some reason.
Error Message:    The specified bucket does not exist
HTTP Status Code: 404
AWS Error Code:   NoSuchBucket
Error Type:       Client
Request ID:       2526BFC1E7F3EAF8

最初の行で出力されているのは今回削除したバケット名です。
パージツールの実行で削除されたバケットの名前がなぜか、S3のバケットのリストの取得を実行すると名前だけは残っているようです。バケット名があるので、そのバケット内のオブジェクトを確認に行ったルーチンで、バケットが実際には存在しないのでこのようなエラーになっている様に思われます。
うーん、現時点では理由が分かりません。実体の更新がAPI上の情報を同時には反映しないのかも知れません。ToolはワンショットのJavaのアプリケーションで実行しているのでClient側にキャッシュがあるわけではありません。AWS全体の仕組みのどこかに時間差があるのでしょうか?

 追記:
とりあえず、解決策と思われる部分を見つけました。
以前、S3のバックアップツールを作成した際に、デフォルトでバケットを作成すると日本ではなくUSになってしまうことを発見。そのため、S3のオブジェクトにendpointを明示的に設定しています。
s3.setEndpoint(“s3-ap-northeast-1.amazonaws.com”);
この設定によって、バケットは期待通りに日本のエリアに作成されたのですが、AWSのManagement Consoleでみると、S3に関してはRegionの設定はありません。
おそらく、S3に関してはManagementはGlobalのデータをRegionごとのデータが存在し、Globalのデータは瞬時に反映されるのに対し、各RegionごとのManagement dataには若干時差があるのかも知れません。
とりあえず、この部分を修正して安定したツールにしたいと思います。

UDP Radioアプリの公開

UDP Radioプロジェクトのアーカイブ公開しました。リンクは以下
http://www.nantoka7.com/software/
ブログで説明してきたようにサーバ側ではUDPポートにパケットの受信を待ち、パケットが受信されるとそのパケットの送信元に対してプログラム(wavファイル)を再生するというものです。
私の試験環境ではJames Brownを使用していましたが、それを使うわけにはいきませんので、1KHzのトーンのファイルを付属させています。
私はまだスマホを持っていないのですが、そのあたりでもどんな感じか試験してみたいところです。

UDP上での音声処理 バッファとパケットロス

Raidoプロジェクト進行中です。
放送局側はUDPポートにパケットを受信するとその送信元にプログラム(Wavファイルの再生)をパケットに分割して送信します。
一方Raido側では特定のUDPポートにパケットを送信しつつ、受信したパケットを音声再生します。
基本的に単純な仕組みですが、実際に作ってみると色々見えてきます。
まず、以前も触れたプチプチ音。
もし、ネットワークの遅延がなければ受信したパケットをスピーカ側に送り込めば何も問題がないはずですが、送信側、ネットワーク、受信側の処理で最終的にスピーカ側に到達するパケットが音声再生よりも遅くなってしまうタイミングが発生する可能性があります。その場合、スピーカ側では何かを再生しなければなりませんので、「無音」を再生します。その後、本来のパケットが到着して正規の音声を再生しますが、正規のパケットの再生の間に「無音」部分が発生してしまいます。これがプチ音の原因になります。電話アプリの場合のように無音部分が多い場合にはそれほど気になりませんが、逆に音楽の場合には非常に耳障りになります。
この問題を回避するためには、受信側でのバッファリングが効果的です。受信パケットを直ぐにスピーカ側に送り込んで再生するのではなく、バッファに溜めてからスピーカ側が再生するようにします。個別のパケットの到着時刻が若干前後しても、バッファに適当な数のパケットが既に格納してありますので、それを順次再生すれば無音部分が発生することはありません。
はじめ、このバッファを自分で実装しようと思ったのですが、書き込み側と読み出し側の競合の問題があって、単純ではないことが分かりました。いくつかアイディアはあるのですが実装するには集中力が必要なのでスキップ。
実はスピーカ側に送信する際に使用するSourceDataLineには実はバッファが組み込まれているのでとりあえず、それを利用して、パケットの受信開始から1秒置いてSourceDataLineへの書き込みを開始するようにしてみました。1秒間分のパケットをバッファしてから再生が開始されるのでプチ音に関しえては改善されました。

改善はされましたが、問題はのこりました。再生時間が長くなるとバッファが空になってしまい、また、プチ音が発生してしまいます。おそらく、パケットのロスが発生するたびに、バッファ内のパケット数が減ってしまい、最終的にはバッファがなくなってしまうような現象のようです。
この部分については、本来はパケットに連番をふって、その連番がスキップされた場合にはその部分に直前に受信したパケットで補完するような仕組みが必要と思われますが、今回のプロジェクトではRTPと異なりPayloadは音声サンプルのみですので、UDPのパケット情報だけで何か工夫ができるかは検討課題です。
この問題に関しても、とりあえず、送信側で送信周期を少し早くしてとりあえず対応しています。現在のサンプリングレートをパケットサイズを考えると送信側では50msec周期でパケットを送信する必要がありますが、数回に1回49msec周期で送るような仕組みを入れてみました。この場合、パケットロスがなければ今度は受信側のバッファが最終的にオーバーフローを初めてしまいます。試験環境でのチューニングで適当な値を設定しています。

バッファを利用するところが、結局TCPのストリーミングと何が違うのか?ということになってしまいますが、UDPゆえの軽さもありますし、例えば災害用の緊急放送とかネットワークが輻輳していて、遅延したり、ロスが多発してもそこそこ音声を聞き取れるようなシステムとしては利用価値があるのではと考えています。TCPではパケットのロスや遅延が大きくなると実際上使えなくなると思います。

RTP音声再生時のプチプチノイズ

昨日のRTPでの音楽再生時のプチプチ音の理由が大体分かりました。
マイクからの入力をスピーカで流す場合、マイクの音声をデジタルサンプリングする際に自動的にサンプリング周期にしたがってパケット化されます。さらに受信側ではそのパケットを受信してサンプリングと同様の周期で再生します。ネットワーク経由の場合、たまにパケットの到着の遅延やジッタなどが発生しても送信側と再生側の周期が同じなので長期的には安定します。
一方で送信側が既に録音されたファイルの場合、その再生スピードはアプリ上で任意に決定できます。もちろん録音されたサンプリング周期を考慮してそのスピードを決めますが、意外にこのスピードは難しいです。
8Khzx8bitなので8Kbytes/sec をRTPのpayload size 160bytesで割ると50パケット、周期は20msecになります。
そこで20msecに1パケットずつ送る仕組みを作らなければなりません。パケットの処理時間があるので単に20msecのsleepを入れるわけにはいきません。
そこでロジックとしては20msecごとのパケットを送る時刻を決めてしまい、一つのパケットを送信するごとに次の時刻との差分だけsleepを入れています。とりあえず、送信側としてはこれで20msecごとに送信可能です。
一方受信側ですが、G711 u-lawで受信してそれを通常の8bitx8khzのlinearのPCMに変換しなければなりません。これはJavaのcode上ではこんな感じです。

    byteArrayInputStream = new ByteArrayInputStream(packet.getData(),12,160);
    
    ulawStream = new AudioInputStream(byteArrayInputStream,ulaw,160);
    // G.711 u-law からリニアPCM 16bit 8000Hzへ変換
    linearStream = AudioSystem.getAudioInputStream(linear,ulawStream);
    linearStream.read(voice,0,voice.length);

RTPのPayloadを一つ受信するごとにulawのStreamをlinerのStreamに変換して音声パケットを受信する。そこからバッファ分を読み出して、その後、スピーカ側に書き込むわけですが、RTPのパケットを受信する部分はblockでパケットが受信できなければそこはプログラムは「待つ」訳です。しかし、スピーカ側の再生側ではリアルタイムで再生しているので「待て」ません。もし、RTPパケットの受信が少しでも遅くなればスピーカ側がおそらく「無音」を再生するしかありません。そして、遅れてきたRTPパケットを処理するので二つのRTPパケットの再生の間に「無音」が入ってしまいます。ここがプチプチ音の原因のようです。
とりあえず、応急処置として送信側のパケットの送信間隔を20msecではなく、19msecにしてみました。するとプチプチ音は消えました。もちろん送信側のパケットの送信が早すぎるのでどこかで受信側のバッファがオーバーフローしてパケットが破棄させてしまうとは思います。
試験する前にはあまり考えていませんでしたが、音楽やビデオなどのデータをストリーミングする際にバッファリングすることの重要性を理解しました。
一方で電話ソフトの場合、この問題は発生すると思うのですが問題が露呈しなかったのはなぜでしょうか?私の推測ですが、電話のような会話の場合、無音部分がかなり多いのでパケット到着の遅延で「無音」が再生されてもそれが認識できるタイミングで発生するケースは少ないのだと思います。
実際にやってみると色々学ぶことが多いです。
良いお年を!

Linux serverのJava Audio System

ご無沙汰してしまいました。
ラジオプロジェクトのパーツとして、WAVファイルを再生してG711 U-lawに変換してRTPで送信するClassを作っていますが、PC上ではとりあえず動作するのですがAWSのLinuxサーバ上で起動すると以下のようなエラーが出てしまいます。
java.lang.IllegalArgumentException: No line matching interface TargetDataLine supporting format PCM_SIGNED 8000.0 Hz, 16 bit, mono, 2 bytes/frame, little-endian is supported.
        at javax.sound.sampled.AudioSystem.getLine(AudioSystem.java:476)
        at SendRtp.main(SendRtp.java:30)
まだ、確認はしていないのですが、もしかしたら、Linux server上にはAudio Systemが存在しないのかなと思い始めています。単に音声処理のパッケージなどを入れればいいのかも知れませんが、サーバですので、通常マイクもスピーカも存在しないのでそのようなパッケージも基本存在しないのでしょう。
というわけで、とりあえず、音声ファイルの変換ツールをネットから手に入れて音源をG711u-lawフォーマットに変換。このファイルを単に読み出してRTPのパケットのPayloadに入れて送るだけのClassを作ってみました。音楽で実験してみたのですが、音質の悪いAMラジオのようになってしまいました。音質が悪いのは仕方が無いとしてなぜかプチプチというノイズが入りました。きっとどこか私のプログラムが悪いのでしょう。
それをおいても、ラジオを意識するのであればG711では音質がきつそうです。もう少し広い帯域で実現するほうがよさそうです。それからサーバ側で音声変換ができないのであれば送り元のPC側で実施するというのも一つの方法かも知れません。サーバを電波を出す放送所、送り手のPCを放送スタジオとして、スタジオ側で音質を決めてサーバに送信、サーバ側は音声パケットに関しては単に再放送するだけの仕組みでどうでしょう。

妄想プロジェクト 番外編 年賀状アプリ

2012年も年の瀬がせまってきました。年賀状を書かれている方も多いかと思います。
メールがこれだけ普及してもまだ、年賀状を送る人は多いようです。
もちろん、直筆の年賀状や手紙は確かに心が心がこもっていてもらって嬉しいものですが、実際には多くの年賀状が印刷されたものです。
それでもなぜ、メールではなく、手紙が使われるのか考えてみるとやはり、二つのポイントがあるのかなと思います。一つはリアリティ、紙とはいえやはり手で触れるリアリティは電子的なものとは違います。もう一つははがきというフォーマット。メールでどんなに手の込んだ趣向を凝らすよりも、今までの年賀状というフォーマットに対する愛着とか慣れがあるのではと思います。人間の行動や判断を考えると今までと同じ…というのは色々な物事を決定するときの大きなファクターになっています。
そこで思うのですが、メールではなく、年賀状用のアプリを開発したらどうかなということです。ターゲットとしてはもちろんスマホとかタブレッド。単にアプリ上ではリアルの年賀状と同じ様に見えるものを作成したり、送信できるアプリを作る。もちろん送信しても配達されるのは1月1日になってから。スマホやタブレットのタッチ機能やたとえばペン入力をサポートすれば年賀状の手書きの文字にも対応できると思います。
実際の年賀状でも多くの場合、宛名までも印刷されているわけす。しかも個人の場合、実はPCで作成した画像を印刷していたりします。それをそのままこの年賀状アプリの入力にすればあとはあて先を指定して送信するだけです。リアルな「紙」の部分を除けば年賀状と変わりません。
むしろ、正月に旅行中でも年賀状を見れたり、12月31日に送信しても相手に元旦に届けることが可能です。実際のデータの転送に関しては専用のプロトコルを使っても良いし、ユーザに見えない範囲でメールをベースにしても実現は簡単と思います。
メールが普及し始めたときに、年賀状なんて直ぐになくなると思ったのですが、実際には年賀状はなくなりませんでした。メールは便利ゆえに、年賀状のように相手に挨拶するものとしては質が低い、あるいは失礼なイメージがあるのかも知れません。また、1人1人にメールで年賀状を書く場合には全て同じ文言では余りにも間抜けに見えるように思うのかも知れません。いずれにせよ、人間は経験や習慣の奴隷みたいなところがあるので、一気にジャンプするのは難しいのだと思います。この年賀状アプリによって少しだけ年賀状からメールへのジャンプの橋渡しができるかも知れません。

 翌日の追記:
その後、世の中に年賀状アプリなるものが存在することを理解しました。私の理解ではWebやあるいはダウンロードしたソフトで年賀状をオーサリングする。そしてそれをネット上、おそらくソーシャルメディアで相手に送る。受け取った人は自分の住所を入力するとそのリアルの年賀状が受け取れる…というもののようです。
この年賀状アプリのポイントとして、相手の住所やアドレスを知らなくても年賀状が出せるということのようです。
私の感覚ではなぜ、そこまでしてリアルの年賀状にこだわるのかなということです。このシステムでは既に送り手側は100%デジタル、Virtual化されているのに受け手側だけがリアルのカードが残ります。確かに、カードゲームのレアカードのように特定の人から受け取った年賀状を人生の記念にとっておくのは分からないでもありませんが、送り手側は既にリアスではないわけですし、デジタルで受信して満足していれば良いのにと思わないでもありません。

妄想 電話プロジェクト 番外編 ラジオ

電話のことを考えていましたが、同じような仕組みでラジオ局も開設できるなと思いました。
既にインターネットラジオがあるじゃんという突っ込みもあるとは思いますが、とりあえず、妄想を続けます。
現在のインターネットラジオはTCPによるストリーミングを使っていると理解してます。一方通行の音声ですので、遅延を気にしなくていいのでこれはデザインとしては全く正しい考え方です。適当なバッファを確保することによってパケットの到達の遅延や揺らぎを吸収できます。しかし、場合によっては始めのバッファリングでスイッチオンで音声再生とはいきません。また、結局回線の品質が悪くなるとTCP自体が切れてしまって肝心の番組を聴くことができません。そして、再度新規の接続ということになります。
一方で本来のラジオをかんがてみるとたとえば電波が悪くなれば聞こえなくなるのは当然ですし、内容にもよりますが、ちょっと位聞こえなくてもまあ、全体の流れで番組を楽しんでいる面があります。結局、ストリーミングを使うのであればファイルをダウンロードして再生するのと変わらないような気がします。

というわけでUDPベースでのラジオサービスを考えて見ます。
まず、基本的な音声部分は簡単です。マイク入力でもかまいませんし、テープの入力をただ決められたUDPのポートに送り出す仕組みを作りこみます。クライアント側でのバッファリングを考えるとRTPの方が好ましそうですが、単にサンプリングしたデータを送り出すだけでもいいかも知れません。
さて、ラジオ局は音声を送る方法は確立していますが、どのアドレスのどのポートにパケットを送れば良いかが分かりません。もちろん、それはClientからのリクエストによってそのアドレスとポートにRTPなりの音声パケットを送ることになります。
ここで電話プロジェクトで出てきたNATの話が出てきます。もし、Clientが自分のアドレスとポート番号をHTTPなどの方法でサーバに伝えたとしてもそれはClient側のローカルの情報の可能性があります。しかし、ここでClient側がUDPのしかも音声を送ってもらいたいポート番号からリクエストをサーバ側に送ります。すると以下のような変換が行われてサーバに到着します。
Client —-UDP —————–> FW (NAT)———UDP——-> Server
 Target Address:Server IP                     TargetAddress:Server IP 
 Target Port:Server Port                        TargetAddress:Server Port  
Source Address:Client IP(private)         SourceAddress:NAT address(global) 
Source Address:Client Port                    SourceAddress:NAT Port
このようにUDP自体でリクエストを送ることによってサーバ側は単にその受信したパケットのアドレス+ポートに音声を送り始めればいいわけです。
さらに、Clientは番組を聴いている間はサーバ側の同じポート番号に定期的にKeep Aliveのパケットを送り続けることができます。サーバ側でのこのKeep Aliveが到着している限り番組を送り続け、Keep Aliveが切れたときに送信を終了すれば切断側の仕組みも組み込むことができます。

簡単にまとめると
①Client側は事前に自分の聴きたい番組のIP AddressとPort番号を確認する。
②Client側は自分が受信可能のUDPポートをソースとしてサーバのアドレスにパケットを
送り始める
③サーバ側はUDPポートにパケットを受信したら、そのパケットの送信元(Addess+Port)に対して番組を流し始める。
④さらにサーバは受信するUDPパケットの情報から現在の聴取者のリストを保持し、最新のUDPパケットの受信によりリストを更新する。
⑤Clientは番組の聴取を終了する場合はUDPのパケットの送信を止める。実際にはこれはアプリケーションの終了で自動的に達成することも可能。

今、まとめながら気がつきましたが、アプリ側にサーバ側のIPアドレスやポート番号を組み込んでしまえば、単にClient側では単にアプリを起動するだけで、特定の番組と接続して聴取することも簡単です。
これはAKBのようなアイドルタレントのファンクラブや宗教団体、学校、あるいは特別なイベントプロモーションでもつかえるのでは思います。

妄想 電話プロジェクト④ JavaによるRTPの実装

さて、脱線ついでに先日ネットで見つけたRTPによる音声通信のコードを使って試験をしてみる。基本的なクラスのほかにu-lawで録音してauファイルに書き込むサンプルプログラムなどが付随していてコードを書いた人のJavaでの音声処理に精通していることが分かります。
サンプルコードには8bitx8Khz u-lawのRTPによる音声通話用のサンプルがありました。
使ってみたのですが、音声繋がりませんでした。
一体何が悪いのかWireSharkでトレースを取ってみると、本来20msec毎に1パケットを送信するはずが、大体120msec間隔でRTPパケットが6個バースト上に送信されていました。おそらく、受信側ではこのバーストパケットをバッファできないので1/6程度のパケットしか再生できないため、音声が聞こえなかったのだと思います。
なぜ、このようになってしまうかですが、おそらくマイクからの16bitx8khzの音声ストリームを8bitx8khのu-lawのストリームに変換する部分で期待するタイミングで変換が行われていないからだと考えています。オリジナルのコードでは以下の流れで8bitx8hhz u-lawのデータを取得しています。
   AudioInputStream linearStream = new AudioInputStream(targetDataLine);
   // リニアPCM 16bit 8000Hz から G.711 u-lawへ変換
   AudioInputStream ulawStream = AudioSystem.getAudioInputStream(ulawFormat,linearStream);

さらにこのulawStreamからループの中で160byteを取得するごとに送信しています。
while(true){
     ulawStream.read(voicePacket,0,voicePacket.length);
     // RTPヘッダーを付ける
     rtpPacket = this.addRtpHeader(voicePacket);
     packet = new DatagramPacket(rtpPacket,rtpPacket.length,address);
     // 相手へ送信
     this.socket.send(packet);
}
私のマイクからのサンプリングされたデータを直接送信するコードもこのロジックで処理しています。マイクからの単純な16bit x 8khzであれば殆ど大きな遅延もなく、スムーズにデータが変換されているのだと思いますが、その出力をu-lawに変換する際にはJavaのモジュール内のバッファなどの関係で20msecx6 120msec程度のデータの塊としてしか処理できないのだと思います。
本来、処理遅延に関しては出力データをさらにバッファに入れてそのバッファから正確な間隔で読み出すのが正しいRTPの実装になりますが、結局は受信側の音声再生の時点で細かい時間の変動は処理されてしまうと思いますので、とりあえずはループにdelayを入れることで問題を回避することができました。単にsleepを1行入れただけです。
while(true){
     ulawStream.read(voicePacket,0,voicePacket.length);
     // RTPヘッダーを付ける
     rtpPacket = this.addRtpHeader(voicePacket);
     packet = new DatagramPacket(rtpPacket,rtpPacket.length,address);
     // 相手へ送信
     this.socket.send(packet);
  Thread.sleep(18);
}

やはり、この手の処理のちょっとした複雑さや遅延の増加を考えるとRTPを使うよりも単なる音声のストリームを相互に流し合うほうがシステム的には優れているような気がします。もちろん、現在のIPネットワークの品質が前提の話です。