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

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

PulseAudio上の音声をWAVE保存するためのコードをVala言語で作成(仮)

以前「PulseAudio上の録音に関する覚え書き(WAVE形式での保存)」でPulseAudio上の音声データをGStreamerプラグイン経由でWAVE形式で保存する作業を扱ったのだが、Vala言語のGStreamerの例を何気なく見ていたら、GStreamerを使用したオーディオ処理はかなりシンプルに書けることが分かったので、そのコードをもとに「PulseAudio上の録音に関する覚え書き(WAVE形式での保存)」のgst-launchの処理と同等のことを行えるかどうか試してみた。

  1. メモ
  2. コードと制約など

メモ

  • GStreamerはデータをある要素(プラグイン)*1から別の要素に渡し、また次の要素へと渡していくという「流れ」で処理を行う
  • その流れの「道」に近いのが「パイプライン」で、パイプライン上に「要素」を順番に並べていく・具体的には、Gst.Pipelineオブジェクトのメンバ関数add_many()の引数に、事前に静的メンバ関数Gst.ElementFactory.make()により生成した各Gst.Elementオブジェクト(要素)を並べていく
  • 要素を並べただけではデータは要素から要素へと渡されないので、それぞれの要素から次の要素へと「リンク」(接続)を行う・具体的には各Gst.Elementオブジェクトのメンバ関数link()で次の要素を指定
  • 要素にはパラメータ(入出力ファイル名など)が設定できるものがあるが、これは各Gst.Elementオブジェクトのメンバ関数(実際にはこのクラスが継承しているGLib.Objectオブジェクトのもの)set()*2により指定
  • 準備が終わったらGst.Pipelineオブジェクト(パイプライン)のメンバ関数set_state()で「Gst.State.PLAYING」を指定してデータを流せるようにする

コードと制約など

GStreamerのプログラムを書いたことがないこともあり、足りない部分もあるものの、実行するとPulseAudioのALSAへの出力の音声(alsa_output.default.monitor)をout.wavとして保存する。
下のコードではメインループを止めることはできないため、Ctrl+Cで強制終了する。
コンパイルにはGLibとGStreamerの開発パッケージが必要。
[任意]ファイル名: parecwavetest.vala

using Gst;
using GLib;

/*
 * valac --pkg gstreamer-0.10 -o parecwavetest parecwavetest.vala
 */

namespace PaRecWaveTest
{
  class MainClass
  {
    public static int main (string[] args)
    {
      Gst.Element src, queue, conv, wavenc, sink;
      Gst.Pipeline pipeline;
      Gst.init (ref args);
      /* 要素を配置する道(パイプライン) */
      pipeline = new Gst.Pipeline ("parecwave");
      /* 各要素(プラグイン) */
      src = Gst.ElementFactory.make ("pulsesrc", null);
      queue = Gst.ElementFactory.make ("queue", null);
      conv = Gst.ElementFactory.make ("audioconvert", null);
      wavenc = Gst.ElementFactory.make ("wavenc", null);
      sink = Gst.ElementFactory.make ("filesink", null);
      /* 要素を並べる */
      pipeline.add_many (src, queue, conv, wavenc, sink);
      /* 並べた要素をそれぞれつなぐ・それぞれ真偽値で成功/失敗を返すが今回はチェックしない */
      src.link (queue);
      queue.link (conv);
      conv.link (wavenc);
      wavenc.link (sink);
      /* 幾つかの要素を設定 */
      src.set ("device", "alsa_output.default.monitor");
      sink.set ("location", "out.wav");
      /* データを流せるようにする */
      pipeline.set_state (Gst.State.PLAYING);
      /* メインループ */
      GLib.MainLoop loop = new MainLoop (null, false);
      loop.run ();
      return 0;
    }
  }
}

上のコードのままではWAVEファイルの中の細かいフォーマットが指定/変更できない。
また、起動したらすぐにファイルへの記録が開始されて強制終了するまで止められない点や各種パラメータがハードコーディングされている点、幾つかの失敗する可能性のある処理についての失敗した場合の対処がされていない点など、改善の余地は多い。

使用したバージョン:

  • Vala 0.7.2
  • GLib 2.20.1
  • GStreamer 0.10.22
  • PulseAudio 0.9.15
  • GStreamer PulseAudioプラグイン 0.10.14

*1:各要素は機能を1つ持ち、「sink」に入力されたデータに何かしらの加工処理を行い、「source」に出力する・要素によってはsinkとsourceのいずれか一方のみのものもある

*2:実際、生成されるC言語のコードにおいてはg_object_set()が使用されている