戻る


2013/07/25 20:23

つまるところ、これはまた作り直しですねぇ。

C++でクラスをそのままエクスポートするとかだめだな。これはだめだ。

newを使わずに直接実体を作ると、使用するメモリ領域が固定されてしまうし、new使っても領域サイズが分かってないといかんので同じことだ。

結局、ライブラリのデータ構造は、全てポインタでやりとりすべきだった。newやdeleteをラッピングした関数を作るべきだったのだ。実装をいじくった後、ライブラリ利用プログラムを再ビルドしないと正常に動作しない場合がある、という時点でなぜ気付かなかったのか。気付くのが遅いと思った。

これは作り直しですねぇ。処理は大体そのまま使えると思うが、コンストラクタ失敗時に例外投げているところとかは、nullを返すようにしたい。他に方法ないしとりあえず例外投げときゃいいか、的に考えていたような気がするし。本当に必要でない限り、例外は使いたくないと思った。

核は関数と構造体から成る、ごく普通のライブラリを作ることになるわけだが、なんとか利便性を上げたいなぁ。

というのは、構造体の内部にアクセスすることが全くできなくなるわけなので、メンバ関数とか使うことが基本的にできない。同じようなことを関数の第1引数に構造体のポインタを渡すとかしてするわけだけど、それだとどうしても、関数名が構造体名を含んだなかなか長いものになってしまう。

なので、構造体のポインタをメンバとして持つ、ラッパークラスのようなものを作ろうかと思うのだが、std::unique_ptrとかと絡めて、うまいこと少ないコードで扱いやすいものにしたいもんだ。


2013/07/19 05:35

pulseaudioいじくってた。

ストリームAPIの使い方がようやく分かった気がする。

pa_stream_write()で波形データを書き込むというのは分かっていたのだが、ループでそれを呼び出しまくり、WAVファイルの音楽を再生しようとしてもうまくいかなかった。

最初はうまくいっているように見えるのだが、10、20秒程度すると再生が途中で終わってしまう。pa_stream_write()で書き込んでも再生されない。

色々試した結果、一言で言うならpa_stream_drain()を呼び出す必要があるという結論に達した。

だがしかし、ただ呼び出すだけでは不十分。pa_stream_drain()の処理は非同期に実行されるため、pa_stream_drain()を呼び出し、処理が返ってきたからといって、処理が完了しているわけではないのだ。

そこで、pa_stream_drain()を呼び出してから、次にpa_stream_write()を呼び出すまでに、pa_stream_drain()の処理が完了させる必要があり、つまり待機処理が必要になる。

具体的には、pa_threaded_mainloop_lock()とpa_threaded_mainloop_unlock()をpa_stream_write()、pa_stream_drain()の前後に入れ、pa_stream_drain()の後にpa_threaded_mainloop_wait()で処理を待機させる。

で、pa_stream_drain()の処理が完了…したかは知らないが、正確にはバッファに空きができればいいわけなので、pa_stream_set_write_callback()で、ストリーム書き込み時のコールバック関数設定をあらかじめ行なっておく。そして、そのコールバック関数内でpa_threaded_mainloop_signal()を呼ぶ。

というわけで、pa_stream_write()、pa_stream_drain()、pa_threaded_mainloop_wait()と呼び出し、pa_threaded_mainloop_signal()をストリーム書き込み時に呼び出す、という流れになる。

しかしながら、これは検証のためにそれなりに適当にやったので、実際にはチェック処理とか入れるべきだと思う。

例えば、pa_threaded_mainloop_wait()とかpa_threaded_mainloop_signal()とかは、引数がpa_threaded_mainloop_mainloopのポインタしかない。つまり、ロックが1つしか存在しないため、pa_threaded_mainloop_wait()から処理が復帰した時に、チェック処理を入れ、場合によっては再度待機するとか、そういう風なことをする必要がある。

今回の場合は、バッファに空きがあるかどうかが問題なので、pa_stream_writable_size()を呼び出し、書き込めるかどうか確認する必要がある。

そもそも、pa_threaded_mainloop_wait()を使わなくても、std::mutexとstd::condition_variableでいいんじゃないか、という気がしないでもない。C++11以前は環境非依存な同期処理がなかったから、用意されたもんだと思うし。C++11の環境非依存同期処理を使える今、わざわざ使う必要もなさそう。

pa_threaded_mainloop_lockの処理、見てみたけど、結局pthread_mutex_lock()呼び出してるだけだったわ。waitとかもpthread_cond_wait()呼び出してるだけだった。じゃあいいわC++11のやつで。

とまぁ、これ調べるのも一苦労だ。サンプルねぇし。audaciousやらvlcやらmplayer2やらのソースを読んだが、今回の問題には大した助けにならなかったし。


2013/07/11 12:46

疲れた。

androidアプリ作るの疲れた。飽きた。優先順位は低いわけだし、そろそろdpの方に戻るべきか。

dpよりもビルドに時間がかかるのと、できたものの動作確認をするのに時間がかかるのがとてもめんどくさい。すごい勢いでモチベーションが削がれていく。

しかも、XMLとかいじくると稀によく、ビルドして動作確認しようとしても不正終了する。そういう場合、1回クリーンしてビルドし直さないと直らない。ただでさえ時間がかかるのにめんどくさすぎる。

というわけでまた今度。

前回の日記から1週間以上経っているなぁ。さすがに時間使い過ぎた感。


2013/07/03 22:28

antroidは機能縮小した。

で、androidのサービスをアクティビティからバインドしてどうのこうのというのを試してみたんだけど、今回は使えなさそう。

サービスは使うけど、通信はソケット通信かな。アクティビティからのバインドは、アクティビティからサービスの機能を使う、ということが目的なら便利に使えそうなんだけど、1対1の通信を確立するとか、そういうのには向いてなさそうな空気。

アンバインドした時に、どのバインドをアンバインドしたのか、それが判別できない。putExtra()とか使って、IDみたいのを作ればできないこともないだろうけど、絶対に被らないという保証がどこにもない。

また、既にバインド済みの時に別のバインドを確立すると、サービス側にバインドしたことが通知されないっぽい。もちろんアンバインドも通知されない。

そんな感じ。

あーでも、リモコンとの通信には使わないけど、バインド自体は使うかな。サービスと通信するためのものは別のライブラリプロジェクトにまとめるけど、通信処理の実装はライブラリプロジェクトに含めない。含めるのはインターフェースだけで、実装はサービスから取得する形にしたい。通信処理に修正が入ったから、ライブラリプロジェクトを使ったプロジェクトに再ビルドが必要、とか嫌だし。

なんとなくまとまってきたぞ。


2013/07/02 19:24

antroid、機能縮小しようかなぁ。

ビルドとかクリーンとか、SDKに付属してるbuild.xmlに搭載されている機能を再実装するのは無駄だと思った。現時点でリリースビルドすら実装できていないし、実装してもSDKの更新で処理が変更されるかもしれないし。それにいちいち追随するのはめんどくさすぎる。

でも、プロジェクト作成ウィザードやアプリの実行、logcatの開始など、SDKに付属しているbuild.xmlに存在しないが自動化でより便利、簡単に扱える機能は使いたい。なので、そういった機能だけに絞ろうかなと。

今までビルドやクリーンもサポートしていたのはなんでだったかなと思ったら、デバッグビルドとリリースビルドの出力先を分けることが目的なんだった。しかし、最近依存するライブラリプロジェクトとリンクできるようにしたところ、クソみたいな原因で正常に動作しなくなったため、出力先を分けられなくなったんだった。

思い出したらまた嫌な気分になった。なんだよあのクソ実装は。antの独自タスクに、出力先がbinとハードコーディングされてやがる。定数が使われてるからハードコーディングとはちょっと違うが、実質的に同じようなもんだ。build/debugとbuild/releaseに分けたかったのだが、bin以下にライブラリのjarがねぇよとか言い出してこける。忌々しい。

独自タスク内はさすがにどうしようもない気がする。なんとかして定数を、リフレクションとか使って書き換えられないかなぁ。

androidからいじくるために、wiiのクラシックコントローラを買ってきた。中古。

なぜかLとRがアナログらしい。あとZLとZRの位置がすごい。人差し指が疲れそうだ。PROも入手したいところだが、PROじゃない方でも大体同じように使えるだろうし、まぁいいかといった感じ。欲しくないわけではないが。

androidのアプリ間通信、アクティビティとサービスは接続できるらしいなぁ。その辺知らんかった、というかサービスについて詳しく知らない。なにやら、接続してデータをやりとりできるようだ。アクティビティからサービスのメソッドを呼んだりできるらしい?

ソケット通信にしようかと思っていたが、アクティビティとサービスの連携がうまいこと使えそうなら採用しようかな。ポート番号とかのめんどうなことを決めなくてもよくなるだろうし。

その辺、検証してみよう。


2013/07/01 15:44

1ヶ月毎に別ファイルにすることにした。

昨日あんなことを書いておきながら今日もandroidからwiiリモコンをいじくろうとしている。

BluezIMEのソースを読んで接続方法は把握した。ペアリング?そんなものはなかった。

想像はできていたが、なかなか無理矢理な方法だった。android.bluetooth.BluetoothSocketの非公開なコンストラクタを、リフレクションで呼び出す。SDKのリファレンスにも当然コンストラクタの仕様なんぞ載ってないし、その辺の実装が変わったら簡単に動かなくなりそうだ。

私の使っている環境はandroid4.1.2だけど、4.2からは内部で使っているBluetoothのライブラリが別物になるらしい。その辺の変更でインターフェースが変わってたら動かなくなるなぁ。

で、接続して、LEDの制御をするところまでできた。あとは入力データの解析とかすればいいわけだが、かなりいい加減に作っていたので、この先を進めるにはちょっと整えないとめんどうなことになりそうだ。

入力データの処理は別スレッドでやるべきだと思うが、スレッド分割することを全く考慮していないので、ひどいことになりそう。何をどうすればいいのかも分かってきたし、本格的に作り始めるべきか。

そういえば、BluezIMEのソース読んでたら、LEDの点灯は右端の1つを点灯させるの固定になってて残念な気分になった。せっかく4つあるのに。まぁ、BluezIMEはwiiリモコンだけを制御するわけじゃないし、LEDの点灯が全部同じだったからといってソフト側にはなんの不自由もないわけだし、いいんだけど。


戻る