試験運用中なLinux備忘録・旧記事

はてなダイアリーで公開していた2007年5月-2015年3月の記事を保存しています。

PulseAudio上のオーディオをWAVE保存するツールの続き(詳細なオーディオ形式の指定とエラーメッセージの処理についてのメモ)

PulseAudio上の音声をWAVE保存するためのコードをVala言語で作成(仮)」でとりあえずPulseAudio上のオーディオ(ストリーム)をWAVE形式で保存できるところまで作成したツールをその後改良して

  • サンプルレートなどの詳細オーディオ形式を変更可能にする
  • ファイル書き出し時などにエラーが出た場合にそれを処理できるようにする
  • GTK+GUIで操作できる

というところまで進めることに成功した。
本記事ではその途中段階でのメモを扱う。

オーディオフォーマットの変更

サンプルレート(サンプリング周波数)/チャンネル/量子化ビット数(ビット深度)を変更するにはGst.Capsオブジェクトを(Gst.Caps.simple()のコンストラクタから)作成した上で、要素(Gst.Elementオブジェクト)のリンク時にlink()の代わりにlink_filtered()を用いて2番目の引数に指定する。
この変更を「PulseAudio上の音声をWAVE保存するためのコードをVala言語で作成(仮)」のコードとの差分として下に貼り付ける。ただし、コードを簡単にするために48000Hz/ステレオ/16bitの固定とする。また、前回同様、ALSAへの出力に対するモニタデバイスの録音となる。

--- parecwavetest.vala
+++ parecwavetest2.vala
@@ -2,10 +2,10 @@
 using GLib;
 
 /*
- * valac --pkg gstreamer-0.10 -o parecwavetest parecwavetest.vala
+ * valac --pkg gstreamer-0.10 -o parecwavetest2 parecwavetest2.vala
  */
 
-namespace PaRecWaveTest
+namespace PaRecWaveTest2
 {
   class MainClass
   {
@@ -13,6 +13,7 @@
     {
       Gst.Element src, queue, conv, wavenc, sink;
       Gst.Pipeline pipeline;
+      Gst.Caps caps;
       Gst.init (ref args);
       /* 要素を配置する道(パイプライン) */
       pipeline = new Gst.Pipeline ("parecwave");
@@ -22,12 +23,17 @@
       conv = Gst.ElementFactory.make ("audioconvert", null);
       wavenc = Gst.ElementFactory.make ("wavenc", null);
       sink = Gst.ElementFactory.make ("filesink", null);
+      /* 変換フィルタ */
+      caps = new Gst.Caps.simple ("audio/x-raw-int",
+                                  "rate", typeof (int), 48000,
+                                  "channels", typeof (int), 2,
+                                  "depth", typeof (int), 16);
       /* 要素を並べる */
       pipeline.add_many (src, queue, conv, wavenc, sink);
       /* 並べた要素をそれぞれつなぐ・それぞれ真偽値で成功/失敗を返すが今回はチェックしない */
       src.link (queue);
       queue.link (conv);
-      conv.link (wavenc);
+      conv.link_filtered (wavenc, caps);  // フィルタ付き
       wavenc.link (sink);
       /* 幾つかの要素を設定 */
       src.set ("device", "alsa_output.default.monitor");

コンストラクタ引数については「string media_type, string fieldname, ...」となっていてよく分からなかったが、C言語gst_caps_new_simple()の関数名で検索すると使用例が幾つか出てきたので、それにならって上のように書いた*1ところ、うまくいった。

GStreamerのパイプライン上のエラーを処理する

もし出力ファイルが書き込めなかったり入力側のPulseAudioと接続できなかったりした場合、エラーはGStreamerパイプラインの中のメッセージ通知用の道「バス」から通知される。これを処理できるようにするには、まずパイプライン(Gst.Pipeline)オブジェクトのメンバbusのadd_signal_watch()を呼んでから「message」シグナルに対するハンドラの関連付けを行う。

(Gst.Pipelineクラスを継承したパイプラインクラスのコンストラクタ内)
/* メッセージ通知用の通り道(バス)上のメッセージを取得 */
this.bus.add_signal_watch ();
this.bus.message += this.on_bus_message;

ハンドラではGst.Messageオブジェクトを受け取り、そのメンバtypeが「Gst.MessageType.ERROR」となったときがエラーとなる。このオブジェクトのメンバ関数parse_error()により、別途用意したGLib.Errorオブジェクトと文字列(string)オブジェクトを「out」付きで引数に渡すことでこれらに値が入り、GLib.Errorオブジェクトのメンバ変数messageとして詳細なエラーメッセージが得られる。

/* パイプライン内のメッセージ・バス上にメッセージが流れたときの処理 */
void on_bus_message (Gst.Message message)
{
  if (message.type == Gst.MessageType.ERROR)
  {
    GLib.Error gerror;
    string debug;
    message.parse_error (out gerror, out debug);  // それぞれ中身がセットされる
    (エラー詳細が「gerror.message」として使用可能)
  }
}

これらを踏まえた上で、GTK+を用いてサンプルレートなどのパラメータやPulseAudioのモニタデバイス名・出力ファイル名などをGUIで指定できるようにしつつ、エラーが発生したときにダイアログで表示するようなところまで進めたコードを次回貼り付ける。

関連記事:

使用したバージョン:

  • Vala 0.7.3
  • GStreamer 0.10.22
  • PulseAudio 0.9.15
  • GStreamer PulseAudioプラグイン 0.10.14

*1:「[名前],typeof([データ型],[データ値])」のまとまりを繰り返す形