Linux 版 flashplayer で任意の capture デバイスから録音するには?

Linux で使用できる良い Webcam として Qcam Pro 9000 を購入しました.これで,私も自宅 ustreamer に再度仲間入りできるぞと思っていました.しかしながら,人生はとても厳しいものです.luvcview で映像は取れてるし,arecord で音声も取れているので大丈夫だと思いきや,flashplayer が色々とやらかしてくれています.なんと,flashplayer の最新版 (9.0.115) では,ビデオ入力は V4L1,音声入力は ALSA のデフォルトデバイスに固定されていました.uvcvideo は V4L2 なのでこのままではカメラからの映像を flash が取り込めませんし,USB Audio はデフォルトデバイスではないので音声も取り込めません ><

いろいろと調べていたところ,Screencast4Linux というプロジェクトを発見しました.このプロジェクトは,Linux でスクリーンキャストするため,V4L の仮想デバイスを作っています.素晴しいです!この Screencast4Linux と luvcvideo を組み合わせれば,ManyCam みたいな事もできちゃうんですね!とても面白そうなので,早速 RTM に「Screencast4Linux + luvcview を作る」っていうタスクを作成しておきました.まだタスクを作っただけなので解決してはいませんね ><

次に音声です.こいつぁちと厄介なんです.でも,とても素直な方法で解決できました!


まず環境条件について整理します.私の計算機環境にはオンボードのサウンドデバイスとして HDA Intel があります.これに加えて,新たに Qcam Pro 9000 が持っているマイクが USB Audio として認識されました.ALSA から見ると,CARD0 が HDA Intel,CARD1 が USB Audio になっていて,CARD0 は playback と capture の両 PCM デバイスがあり,CARD1 には capture PCM デバイスしかない状態です.

flashplayer が Linux Microphone としてどの capture デバイスを認識しているのか最初は不明でした.そこで,strings libflashplayer.so をやってみたところ,「plug:hw0,0」という文字列が埋め込まれている事が分かりました.これから,Linux Microphone が plug:hw0,0 を指していることが推測できます(しかし実際には違っていて,後述のように Linux Microphone は ALSA のデフォルト capture デバイスであることが分かっています).そこで,CARD0 と CARD1 を入れ替えてやろうと画策しました.

複数のサウンドデバイスが存在するとき,ALSA から見た場合のカード番号がどのように割り当てられるのでしょうか.特に設定していなければ,デバイスドライバをロードした順番に番号が割り当てられます[MultipleCards - ALSA wiki].そうではなく,特定のデバイスを特定の番号へ割り当てるには,モジュールのエイリアスを設定します.例えば,私の環境で CARD0 に USB Audio,CARD1 に HDA Intel を割り当てるには次のように /etc/modprobe.d/sound を書き換えます*1.

# Logicool Qcam Pro 9000
alias sound-slot-0 snd-card-0

alias snd-card-0 snd-usb-audio
options snd-usb-audio index=0 vid=0x46d pid=0x990

# HDA Intel
alias sound-slot-1 snd-card-1
alias sound-service-1-0 snd-mixer-oss
alias sound-service-1-1 snd-seq-oss
alias sound-service-1-3 snd-pcm-oss
alias sound-service-1-8 snd-seq-oss
alias sound-service-1-12 snd-pcm-osshree

alias snd-card-1 snd-hda-intel
options snd-hda-intel index=1

このような設定を行い,サウンド関連のデバイスをすべて rmmod し,もう一度 modprobe することで,CARD0 が USB Audio になり,CARD1 が HDA Intel になります.

この状態で,flashplayer がきちんと Qcam Pro 9000 のマイクから音を拾ってくれるかどうか確かめたのですが,おかしなノイズが録音されるだけで上手く行きませんでした.それだけでなく,CARD0 に playback PCM デバイスが存在しないため,いちいち CARD1 を出力先として指定しなければ音が鳴らなくなってしまったのです >< この状態はとても不便なので,次のような ~/.asoundrc を書いて,デフォルトデバイスを dmixer にしました.

pcm.!default {
  type plug
  slave.pcm "dmixer"
}
pcm.dmixer {
  type dmix
  ipc_key 838861
  ipc_key_add_uid true
  slave {
    pcm "hw:1,0"
    period_size 1024
    buffer_size 8192
    rate 48000
    periods 0
    period_time 0
  }
  bindings {
    0 0
    1 1
  }
}

こうして,出力先を特に指定せずとも勝手に CARD1 から出力してくれるようになりました.ところが,この設定をして以降は,flashplayer は音を全く拾わなくなってしまいました >< なぜこのような現象が起こったのか考えてみましたが,理由は一つしか思い当たりません.それは,デフォルトの PCM デバイスが dmixer に固定されていることです.dmixer は再生専用のプラグインですから,録音で使えるわけがないのです.

色々調べたところ,dmixer の録音版とも言える dsnoop というプラグインの存在と,playback と capture を別個で指定可能な asym プラグインの存在を知ることができました.dsnoop を用いて USB Audio から録音する仮想デバイスを作り,デフォルトデバイスでは playback の場合に dmix を,capture に対しては dsnoop を指定してあげれば良いのだと思われます.そこで,次のように ~/.asoundrc を書き換えました.

pcm.!default {
  type asym
  playback.pcm {
    type plug
    slave.pcm "dmixer"
  }
  capture.pcm {
    type plug
    slave.pcm "dsnooped"
  }
}
pcm.dmixer {
  type dmix
  ipc_key 838861
  ipc_key_add_uid true
  slave {
    pcm "hw:1,0"
    period_size 1024
    buffer_size 8192
    rate 48000
    periods 0
    period_time 0
  }
  bindings {
    0 0
    1 1
  }
}
pcm.dsnooped {
  type dsnoop
  ipc_key 5150
  ipc_key_add_uid true
  slave {
    pcm "hw:0,0"
    channels 1
    period_size 1024
    buffer_size 8192
    rate 4800
    periods 0
    period_time 0
  }
}

この設定の下で arecord を実行すると,デバイスを指定せずとも Qcam Pro 9000 のマイクから音を拾ってくれました.そして aplay ではきちんとオンボードデバイスから音が鳴っています!素晴しいです.flashplayer で試してみたところ,ustream で Qcam Pro 9000 のマイクを用いて録音することができました!!!

ここまで来て,最初に設定した CARD0 と CARD1 の順番を入れ替える設定は必要無いことに気づきました.オンボードデバイスが CARD1 で,USB Audio が CARD0 という状態はなんだか気持ちが悪いです.したがって次のように /etc/modprobe.d/sound を書き換えました.

# HDA Intel
alias sound-slot-0 snd-card-0
alias sound-service-0-0 snd-mixer-oss
alias sound-service-0-1 snd-seq-oss
alias sound-service-0-3 snd-pcm-oss
alias sound-service-0-8 snd-seq-oss
alias sound-service-0-12 snd-pcm-osshree

alias snd-card-0 snd-hda-intel
options snd-hda-intel index=0

# Logicool Qcam Pro 9000
alias sound-slot-1 snd-card-1

alias snd-card-1 snd-usb-audio
options snd-usb-audio index=1 id=QCAM-200S vid=0x46d pid=0x990

最後の行の options に「id=QCAM-200S」という引数を増やしました.これを指定すると,今迄 Ux46dx900 だったカード名が QCAM-200S に変わります.この方が分かりやすいですよね.この変更に伴って,~/.asoundrc が次のように書き変わります.

pcm.!default {
  type asym
  playback.pcm {
    type plug
    slave.pcm "dmixer"
  }
  capture.pcm {
    type plug
    slave.pcm "dsnooped"
  }
}
pcm.dmixer {
  type dmix
  ipc_key 838861
  ipc_key_add_uid true
  slave {
    pcm "hw:0,0"
    period_size 1024
    buffer_size 8192
    rate 48000
    periods 0
    period_time 0
  }
  bindings {
    0 0
    1 1
  }
}
pcm.dsnooped {
  type dsnoop
  ipc_key 5150
  ipc_key_add_uid true
  slave {
    pcm "hw:1,0"
    channels 2
    period_size 1024
    buffer_size 8192
    rate 4800
    periods 0
    period_time 0
  }
}

こうしてめでたく,flashplayer で任意の capture デバイスから録音できるようになりました.しかし,このままでは,録音元を変更したい場合に,いちいち ~/.asoundrc を書き換えて firefox を再起動しなければなりません >< これを解決するには,複数の capture デバイスをまとめた一つの仮想デバイスを作成できれば良いはずです.その方法については,またの機会に調べてみたいと思います.

*1:Debian lenny での設定です