Audio in OpenBSD
6月は衣替えの季節。この日本の佳き伝統に倣って、debian機も衣替えをしてあげよう。 と、言っても、ちんけにLXDEのテーマを変えようというのでは、つまらない。もっと大胆にね。
その為のコマンドは、taskselってものらしい。以前、何処かのサイトでお目にかかって、うろ覚えに記憶してたのさ。何でも、このコマンドは、Debianのインストール時に使われて、どんな性格のDebianを作るんかいをユーザーに決定してもらうみたい。
DeskTopが必要?要るなら、KDEにする?Gnomeにする? DeskTopは止めてファイルサーバー(きっと産婆さんが動くのだろう)にする?それともWebサーバーにするっていう、重大な岐路の設定を迫るやつだ。ここで人生決まってしまうんだなあ。
debian:~$ tasksel --list-task i desktop Debian desktop environment u gnome-desktop GNOME u xfce-desktop Xfce u kde-desktop KDE u cinnamon-desktop Cinnamon u mate-desktop MATE i lxde-desktop LXDE u web-server web server u print-server print server u ssh-server SSH server u debian-hamradio Debian Hamradio Pure Blend u hamradio-antenna Debian Hamradio Antenna Packages u hamradio-datamodes Debian Hamradio Data Modes Packages u hamradio-digitalvoice Debian Hamradio Digital Voice Packages u hamradio-logging Debian Hamradio Logging Packages i hamradio-morse Debian Hamradio Morse/CW Packages u hamradio-nonamateur Debian Hamradio Non-Amateur Modes Packages u hamradio-packetmodes Debian Hamradio Packet Mode Packages u hamradio-rigcontrol Debian Hamradio Rig Control Packages u hamradio-satellite Debian Hamradio Satellite Operation Packages u hamradio-sdr Debian Hamradio Software Defined Radio Packages u hamradio-tools Debian Hamradio Tools Packages u hamradio-training Debian Hamradio Training Packages i laptop laptop
あれ? インストール時にhamradio関係なんて、チラッとも出てこなかったけど、morseを過去に入れたおかげで、オイラーの性向を見抜かれてしたったんだろうな。これぞアマゾン流?
で、インストールは、
debian:~$ sudo tasksel install --new-install xfce-desktop
すれば良い。追加が終了したら、rebootする。guiのログインの右上の所でxfceを選び、ログイン。これにて、衣替え終了。
UBITX
ubitx The QRP HF General Coverage Transceiver you can build
129ドルで、インドから送られてくるそうな。
このページへ飛ぶと、送られてくるであろうボードの写真が目についた。オイラーの注目は、 クリスタルが8個並んでいた事。ひょっとしてクリスタルを並べたラダータイプのフィルターを 構成してないかい?
30MHzまでの信号をミキサーで一端45MHzまで上げ、フィルターを通した後、もう一度変換して12MHzにする。その後クリスタルフィルターを通してから検波するとな。いわゆるダブルコンバージョン方式ね。
おお、回路図も公開されてる。
ああ、7MHz専用のお値段控え目バージョンもあって、こちらは59ドル。全てインドの女性達が 手作業で組み立ていますとな。これらを購入する事は、間接的にインドの女性達の暮らしを支援する事になるんですとの事。
ソフトはアルディーノ用のC言語。ソースが公開されてるので、いじり放題か。 と、思ったら、パターンカットして、回路追加してる方がいた。 uBITX AGC追加改造 オイラーも、現役の頃は得意中の得意だったんよ。懐かしいな。
やや、 FT-818よりDC3001またはuBitx がいい こんな事を言ってる方も居たぞ。
audioctl
前回からの続き。audioが上手く動かないので、基本を確認。
ob6$ audioctl name=eap0 mode= pause=1 active=0 nblks=2 blksz=2205 rate=22050 encoding=u8 play.channels=1 play.bytes=0 play.errors=0 record.channels=2 record.bytes=0 record.errors=0 ob6$ audioctl -f /dev/audio0 rate=44100 audioctl: /dev/audio0: Invalid argument ob6$ echo $? 1
なんだか良さそう。でも、最後に出て来るエラー 無効な引数ってのに納得がいかん。audioctlのソースを拝見。システムコールの後、エラーだったら、そのデバイス名を表示させてる。
エラーの場合は詳細な内容がerrnoだかに載ってくるんではなかろうか? そんな訳で、ちょいとコードを修正。
ob6$ diff -u /usr/src/usr.bin/audioctl/audioctl.c audioctl.c --- /usr/src/usr.bin/audioctl/audioctl.c Wed May 31 13:18:58 2017 +++ audioctl.c Fri Jun 1 15:44:10 2018 @@ -24,6 +24,7 @@ #include <unistd.h> #include <string.h> #include <err.h> +#include <errno.h> /* * Default bytes per sample for the given bits per sample. @@ -218,8 +219,11 @@ argv += optind; fd = open(path, O_RDWR); - if (fd < 0) - err(1, "%s", path); + if (fd < 0) { + // err(1, "%s", path); + perror(strerror(errno)); + return errno; + } if (ioctl(fd, AUDIO_GETSTATUS, &rstatus) < 0) err(1, "AUDIO_GETSTATUS"); if (ioctl(fd, AUDIO_GETDEV, &rname) < 0)
errnoをstrerror関数を使って、文字列に変換。それを表示してmainを抜ける。これで実行しても、やはり無効な引数って言われたぞ。と、ここまでやって、元から有ったerr関数の意味を 調べたら、オイラーが書いたコードを一発でやってくれてた。スマソ。
ob6$ ktrace -tc morseplayer morseplayer: Could not open sndio device
システムトレースを取ってみる。
ob6$ kdump | grep open 16508 morseplayer CALL open(0xf713bb0f7b0,0x10000<O_RDONLY|O_CLOEXEC>) 16508 morseplayer RET open 3 : 16508 morseplayer CALL open(0x7f7fffff9bc0,0x10005<O_WRONLY|O_NONBLOCK|O_CLOEXEC>) 16508 morseplayer RET open -1 errno 22 Invalid argument
それの結果から注目のopenだけを抜き出してみる。これいいな。なんでこういう便利な物に気が付いたか? 後で、出てきます。
OpenBSD in qemu
これはもう、裏側と言うかkernel側を覗くしかないな。いつかやった、 OpenBSD 探検 に倣って、vboxに入っているi386版のOpenBSDに入れてみるか。
が、インストールに時間がかかりすぎ。原因はi386な環境でi386をエミュレートしてるから? それともvboxが遅い? 乗り掛かった舟なんで、我慢してインストールが終わるのを待ったよ。
そして起動。これもめちゃくちゃ遅い。しかも最後はDISK FULLとか言われたぞ。DISKは700Mを指定したんで、余裕だと思っていたんだけどな。(勿論、X環境は無しです)
ob6$ du -sh /usr/share/relink/* 183M /usr/share/relink/kernel 21.1M /usr/share/relink/usr
これが伏兵でした。OpenBSD6.1だかから入った、カーネルと基本ライブラリィーのランダム化の機構の材料が置かれてるんだ。
少なくとも、/etc/rc の最後に有る、/usr/libexec/reorder_kernel ぐらいは、コメントアウトしときましょう。インストール時は、最後にshellに落ちて、捜査すればいいな。 まてよ? インストール時の環境では、viとか使える? せめてsedでも有ればいいんだけど、期待薄かな。
しょうがないので、VMWareに入れているamd64の環境下で、qemuを動かす事にした。下記は、各目的に合わせて、数々の起動方法を列挙した。全部まとめてshellに押し込めちゃった方が良かったかしら? それとも手間のかからない、Makefileかな。
ob6$ cat gui #!/bin/sh qemu-system-i386 -m 256 -s \ -net nic -net user,hostfwd=tcp::2022-:22 disk > /dev/null 2>&1
X環境が有る場合。qemuのGUI画面が使える。
ob6$ cat begin #!/bin/sh qemu-system-i386 -m 256 disk -s -S > /dev/null 2>&1
X環境が有る場合。gdbから起動を制御出来る。
ob6$ cat cui #!/bin/sh qemu-system-i386 -m 256 -nographic -s \ -net nic -net user,hostfwd=tcp::2022-:22 disk
Xが無い場合。立ち上がったころ合いを見計らって、sshでログイン
ob6$ cat com #!/bin/sh echo cu -l /dev/ttypN qemu-system-i386 -m 256 -nographic -s \ -serial pty \ -net nic -net user,hostfwd=tcp::2022-:22 disk &
Xが無い場合。立ち上がったころ合いを見計らって、シリアルからログイン。ターゲット側の設定は、 Serial connection を参照。
ss63$ df -h Filesystem Size Used Avail Capacity Mounted on /dev/wd0a 686M 464M 188M 71% /
リリースを重ねる度に容量が増えていくな。
QEMU audio
これで準備が整ったので早速、audioが使えるかFAQに則って確認。
ss63$ audioctl audioctl: /dev/audioctl0: Device not configured
そんなの無いとな。オーディオはネットワークと違ってオプションの高級品なのね。サウンドカードを山田君の所から取り寄せる? QEMUのFAQに説明あるっしょ。
ob6$ qemu-system-i386 -version QEMU emulator version 2.11.1 Copyright (c) 2003-2017 Fabrice Bellard and the QEMU Project developers ob6$ qemu-system-i386 -soundhw help Valid sound card names (comma separated): pcspk PC speaker hda Intel HD Audio cs4231a CS4231A gus Gravis Ultrasound GF1 adlib Yamaha YM3812 (OPL2) ac97 Intel 82801AA AC97 Audio es1370 ENSONIQ AudioPCI ES1370 sb16 Creative Sound Blaster 16 -soundhw all will enable all of the above
これがqemuでサポートしてるハードと言うかボードとな。古いものが主体で、上記のページでは、hdaとか言うインテル製を勧めていたぞ。
ob6$ qemu-system-i386 -audio-help : Options are settable through environment variables. Example: export QEMU_AUDIO_DRV=wav export QEMU_WAV_PATH=$HOME/tune.wav (for csh replace export with setenv in the above) qemu ...
こちらは、隠れ環境変数とかドライバー関係の説明。軟弱なWindowsとかLinux野郎のための解説だな。
オイラーは、インテル嫌いなんで、OpenBSDのサポート具合と勘案して、
ob6$ cat audio #!/bin/sh qemu-system-i386 -m 256 -s \ -soundhw es1370 \ -net nic -net user,hostfwd=tcp::2022-:22 disk > /dev/null 2>&1
こんな、昔ながらの石を選んでみた。dmesgをみると
eap0 at pci0 dev 4 function 0 "Ensoniq AudioPCI" rev 0x00: apic 0 int 11 audio0 at eap0 midi0 at eap0: <AudioPCI MIDI UART>
こんな風に認識してた。早速ユーザーアプリにて確認
ss63$ audioctl name=eap0 mode= pause=0 active=0 nblks=2 blksz=960 rate=48000 encoding=s16le play.channels=2 play.bytes=0 play.errors=0 record.channels=2 record.bytes=0 record.errors=0
なんだか大丈夫そう。morseplayerをコンパイルして、cwって名前のアプリを作った。
ss63$ echo hello | ./cw cw: sio_setpar failed ss63$ echo hello | ./cw cw: Could not open sndio device
なんだか、エラーだな。初回と2回目の実行で違うエラーを吐いてきた。
ss63$ audioctl name=eap0 mode= pause=1 active=0 nblks=2 blksz=2205 rate=22050 encoding=u8 play.channels=1 play.bytes=0 play.errors=0 record.channels=2 record.bytes=0 record.errors=0
もう一度確認すると、少し設定が変わった。気になるのは、pauseってやつ。これって、デバイスがbusyになったままじゃなかろうか?
で、考えた。どのシステムコールで落ちているか調べてみよう。そこで、ktraceですよ。 初回と2回目の結果。
ss63$ kdump -f ktrace.fst : 86691 cw CALL ioctl(3,AUDIO_SETPAR,0xcf7e31a8) 86691 cw RET ioctl -1 errno 22 Invalid argument
ss63$ kdump -f ktrace.snd : 5286 cw CALL open(0xcf7cf539,0x10005<O_WRONLY|O_NONBLOCK|O_CLOEXEC>) 5286 cw RET open -1 errno 22 Invalid argument
不思議な事に、qemu配下のcwを動かすと母艦のVMWare側に入れたOpenBSDのaudioも動いていたっぽい。動作中になってますよ。
ob6$ audioctl name=eap0 mode=play pause=0 active=1 nblks=2 blksz=1024 rate=48000 encoding=s16le play.channels=2 play.bytes=79835136 play.errors=0 record.channels=2 record.bytes=0 record.errors=0
ここで、立ち止まって考えた。qemuの中のaudioボードと言っても所詮は仮想なもの。音を 出したかったら、qemu側が動いて、上位にお願いしなければいけないはず。
Windows 10 Home edition VMWare 12 Player (12.5.9) OpenBSD 6.3 amd64 morseplayer qemu-system-i386 2.11.1 OpenBSD 6.3 i386 cw (morseplayer)
VMWare直下のOpenBSD amd64の中で、morseplayerを動かしても、エラーになる。と言う事は、VMWareがサボっていて、Windows下のボードに音を伝えていない可能性があるな。
同じ事は、Windows10に入れた、virtualboxでも言える。そう言えば、virtualboxはLinux主体でしか動かない中途半端な所があるな。ゲスト側のアドインを入れて、機能が拡張されるしね。VMWareだって、ユーザーツールがサポートされてるのは、Linux、FreeBSD、Solarisぐらいだものなあ。
OpenBSDなんて、その他のOSの扱いですよ。 OpenBSD、1985年に追加されたIntelの最新の誇大広告された機能を使わないことにより脆弱性を華麗に回避 こういう、パラノイアには、誰も付き合ってくれないのね。
証拠固め
VMWareには、Debian9が入っているんだ。そしてqemuも入ってるしね。という事で、i386版の仮想DISKを、Debian側に転送。
動かしたら、無事にモールスさんが聞こえましたよ。
気が付くののが遅いって! ポータブルOpenBSDをThinkPad/SL510に刺したら、何事もなく モールスしてたじゃない。この差に思いがいかなかったって事は、仮想を現実と理解してる節があるな。注意しないとな。
追跡
折角kernelの中まで潜っていけるようにしたんで、追ってみる。/dev/audioが、OpenBSD流のオーディオ界を代表するデバイス。(FreeBSDの場合は、/dev/dsp)
だから、audioopenに網を貼ってまってればいいのさ。同じような名前で、audio_openも有ったので、こちらにも網を張る。そして、cwを起動。
#0 audioopen (dev=10752, flags=<optimized out>, mode=8192, p=0xd16f4598) at /usr/src/sys/dev/audio.c:1599 #1 0xd02a6bad in spec_open (v=<optimized out>) at /usr/src/sys/kern/spec_vnops.c:158 #2 0xd0623302 in VOP_OPEN (vp=0xd165fad0, mode=65542, cred=0xd178aba0, p=0xd1772430) at /usr/src/sys/kern/vfs_vops.c:152 #3 0xd06a9a4e in vn_open (ndp=0xf3758f58, fmode=65542, cmode=<optimized out>) at /usr/src/sys/kern/vfs_vnops.c:165 #4 0xd0532a28 in doopenat (p=<optimized out>, fd=<optimized out>, path=<optimized out>, oflags=<optimized out>, mode=<optimized out>, retval=0xf37590a0) at /usr/src/sys/kern/vfs_syscalls.c:934 #5 0xd05328db in sys_open (p=0xd1772430, v=0xf37590a8, retval=0xf37590a0) at /usr/src/sys/kern/vfs_syscalls.c:873 #6 0xd08eb1b0 in mi_syscall (p=<optimized out>, code=<optimized out>, callp=<optimized out>, argp=<optimized out>, retval=<optimized out>) at /usr/src/sys/sys/syscall_mi.h:78 #7 syscall (frame=<optimized out>) at /usr/src/sys/arch/i386/i386/trap.c:610 #8 0xd07ee0c6 in Xsyscall () #9 0xf37590e8 in ?? ()
追って行くと、audio_openに行きついて
audio_open(struct audio_softc *sc, int flags) { int error; int props; B if (sc->mode) return EBUSY; error = sc->ops->open(sc->arg, flags); if (error) return error; sc->active = 0; sc->pause = 1; sc->rec.blocking = 0; sc->play.blocking = 0; : => error = audio_setpar(sc); if (error) goto bad;
そこから、audio_setparに入って行き
(gdb) bt 3 #0 eap_set_params (addr=0xd17e3200, setmode=1, usemode=<optimized out>, play=0xf3758c98, rec=0xf3758c80) at /usr/src/sys/dev/pci/eap.c:857 #1 0xd034f66d in audio_setpar (sc=<optimized out>) at /usr/src/sys/dev/audio.c:664 #2 0xd035029d in audio_open (sc=0xd17dca00, flags=<optimized out>) at /usr/src/sys/dev/audio.c:1254 (More stack frames follow...)
その中で、アーギュメントのエラーをセットしてる。やっと現場にたどり着いた。現場はPCIバスにぶら下がっている、eapって名前のボードを扱う所だ。
switch (p->encoding) { case AUDIO_ENCODING_SLINEAR_LE: if (p->precision != 16) return EINVAL; break; case AUDIO_ENCODING_ULINEAR_LE: case AUDIO_ENCODING_ULINEAR_BE: if (p->precision != 8) => return EINVAL;
何か無理した設定をしてるんかな?